diff options
author | polwex <polwex@sortug.com> | 2025-06-27 22:53:52 +0700 |
---|---|---|
committer | polwex <polwex@sortug.com> | 2025-06-27 22:53:52 +0700 |
commit | 328ebe85135912678bdacd3381126ffd66ef2761 (patch) | |
tree | 365962bf45302f2a440f766a4f3c9e0a962dbe47 |
init
158 files changed, 42643 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a7c01e1 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +bulky diff --git a/desk/app/boke.hoon b/desk/app/boke.hoon new file mode 100644 index 0000000..5b3231a --- /dev/null +++ b/desk/app/boke.hoon @@ -0,0 +1,1145 @@ +/- *boke, tp=trill-post, c=tlon-channels, ch=tlon-chat, cnt=contact, pols=polls +/+ dbug, js=json, plib=trill-utils, kaji, lib=boke, ui=trill-ui, mm=mmast, sr=sortug, const=constants, wall +/= nav /web/layout/nav +/= router /web/router +|% +++ page-size 10 ++$ read-post +$: title=@t + =path + contents=content-list:tp + date=@da + tags=(set @t) + id=@ud +== ++$ read-comment +$: author=@t + date=@da + contents=content-list:tp + pa=@t + parent=@da + post=@da + title=@t +== ++$ read-boardpost +$: author=@t + op=@t + thread=@da + date=@da + title=@t + content=content-list:tp + id=@ud + tid=@ud +== ++$ versioned-state +$% state-0 +== ++$ card card:agent:gall +-- +%- agent:dbug +=| state-0 +=* state - +^- agent:gall +=< +|_ =bowl:gall ++* this . + hd ~(. +> bowl) + kaj (init:kaji bowl _state kaji-req) +:: +++ on-fail |~(* `this) +++ on-leave |~(* `this) +++ on-save !>(state) +++ on-init +^- (quip card _this) +=. state init-state:hd +:_ this init-cards:hd + +++ on-load |= old=vase +:_ this(state !<(versioned-state old)) ~ +++ on-watch +|= =(pole knot) +~& >> on-watch=pole + ?+ pole !! + [%ui ~] `this + [%http-response id=@ ~] `this + [%tv type=@t author=@t ~] `this + [%chat host=@t name=@t ~] `this + [%sse tab=@t ~] `this + == +++ on-poke +|= [=mark =vase] +?: (~(has in banned-ships:const) src.bowl) `this +|^ +?+ mark `this +%handle-http-request serve +%noun (on-poke-noun !<(* vase)) +%kaji run:handle-ui +== + ++ handle-ui + =/ fd !<(form-data:kaji vase) + =/ i input.fd + =/ tab-id (~(got by input.fd) 'tab') + =/ ui-card ~(. ui:kaji tab-id) + =/ origin (~(got by input.fd) 'origin') + |% + ++ run + ?+ action.fd `this + :: polls + %vote-poll + =/ soption (~(got by input.fd) 'option') + =/ uoption (dec:kaji soption ,[p=@p time=@da index=@ud]) + ?~ uoption (send-error 'format error') + =/ =pid:tp [p.u.uoption time.u.uoption] + =/ index index.u.uoption + =. polls (vote-poll:hd pid index) + :_ this + %- route:kaj [route:router [%kaji tab-id %redi (~(got by input.fd) 'origin')] state] + :: radio + %add-radio-chat + =/ input (~(got by input.fd) 'input') + ?: .=('' input) (send-error 'no input') + =/ stype (~(got by input.fd) 'type') + ?: .=(stype 'urb') + =/ sowner (~(got by input.fd) 'owner') + =/ sip (slaw %p sowner) + ?~ sip ~& "error-parsing-radio-owner" `this + (radio-chat u.sip input) + ?: .=(stype 'our') + =/ station (~(got by input.fd) 'name') + (bstv-chat station input) + `this + + %change-radio + =/ jon=json + [%s 'lol'] + + :_ this :_ ~ + %+ ui-fact:kaji tab-id :_ ~ + [%custom *manx jon] + %add-chat + :_ this :_ ~ + =/ input (~(get by input.fd) 'input') + ?~ input (alert:ui-card "No input, please report to site@spandrell.ch or ~docteg-mothep") + =/ parsed (text-to-content:hd u.input) + ?~ parsed (alert:ui-card "Text parsing failed, please report to site@spandrel.ch or ~docteg-mothep") + (send-message:hd u.parsed) + %add-thread + =/ is-blog ?= ^ (~(get by input.fd) 'is-blog') + =/ is-edit ?= ^ (~(get by input.fd) 'editing') + =/ try-title ?: is-blog validate-blog validate-thread + ?: ?=(%err -.try-title) (send-error +.try-title) + =/ [title=@t tags=(set @t)] +.try-title + =/ try-post (post-or-edit tags) + ?: ?=(%err -.try-post) + (send-error +.try-post) + (go-save-thread title +.try-post is-blog is-edit) + %add-reply + =/ is-blog ?= ^ (~(get by input.fd) 'is-blog') + =/ parents (dec-i:kaji i 'parents' ,[pid:tp pid:tp]) + ?~ parents (send-error 'parent cue error, please report to ~docteg-mothep or site@spandrell.ch') + =/ try-post (post-or-edit ~) + ?: ?=(%err -.try-post) + (send-error +.try-post) + (go-save-reply +.try-post -.u.parents +.u.parents is-blog) + + %del-thread + =/ is-blog ?= %~ (~(get by input.fd) 'is-blog') + =/ pid (dec-i:kaji input.fd 'pid' pid:tp) + ?~ pid (send-error 'no id to delete') + =/ ted (get:torm:tp threads u.pid) + ?~ ted (send-error 'thread-not-found') + =. feed +:(del:gorm:tp feed u.pid) + =. threads +:(del:torm:tp threads u.pid) + =/ last-reply ?~ replies.u.ted u.pid i.replies.u.ted + =. active-threads + +:(del:porm:tp active-threads last-reply) + =. feed +:(del:gorm:tp feed u.pid) + =. paths (~(del by paths) path.u.ted) + =. tags (del-in-tags:hd tags.u.ted u.pid) + :_ this + ?: is-blog + %- route:kaj [route:router [%kaji tab-id %redi '/'] state] + %- route:kaj [route:router [%kaji tab-id %redi '/board'] state] + + %del-reply + =/ pid (dec-i:kaji input.fd 'pid' pid:tp) + ?~ pid (send-error 'no id to delete') + =/ p (get:gorm:tp feed u.pid) + ?~ p (send-error 'post-not-found') + ?~ parent.u.p (send-error 'comment parent not set') + =. feed +:(del:gorm:tp feed u.pid) + =/ par (get:gorm:tp feed u.parent.u.p) + =. feed ?~ par feed + =/ nc (~(del in children.u.par) u.pid) + =/ np u.par(children nc) + (put:gorm:tp feed u.parent.u.p np) + :: branch whether it's the last reply or not as it affects the active-threads + =/ ted (get:torm:tp threads thread.u.p) + ?~ ted (send-error 'thread-not-found') + =/ nr %+ skip replies.u.ted |= p=pid:tp .=(u.pid p) + ?~ replies.u.ted (send-error 'weird') + =/ last i.replies.u.ted + =/ is-last=? .=(last u.pid) + ?. is-last + =/ nted u.ted(replies nr) + =. threads (put:torm:tp threads thread.u.p nted) + :_ this + %- route:kaj [route:router [%kaji tab-id %redi (~(got by input.fd) 'origin')] state] + :: + =/ nr t.replies.u.ted + =/ nted u.ted(replies nr) + =/ penultimo ?~ nr thread.u.p i.nr + =. threads (put:torm:tp threads thread.u.p nted) + =. active-threads +:(del:porm:tp active-threads u.pid) + =. active-threads (put:porm:tp active-threads penultimo thread.u.p) + :_ this + %- route:kaj [route:router [%kaji tab-id %redi (~(got by input.fd) 'origin')] state] + == + ++ validate-blog + =/ stitle (~(get by input.fd) 'title') + ?~ stitle :- %err 'Please enter a title for the thread' + ?: .=('' u.stitle) :- %err 'Please enter a title for the thread' + =/ stags (~(get by input.fd) 'tags') + ?~ stags :- %err 'No tags, please report to ~docteg-mothep or site@spandrell.ch' + =/ ntags (parse-tags:ui u.stags) + ?~ ntags :- %err 'Error parsing tags, please report' + =/ ttags (~(put in u.ntags) 'blog') + =. ttags (~(del in ttags) '') + [%ok u.stitle ttags] + + ++ validate-thread + =/ stitle (~(get by input.fd) 'title') + ?~ stitle :- %err 'Please enter a title for the thread' + ?: .=('' u.stitle) :- %err 'Please enter a title for the thread' + =/ sboard (~(get by input.fd) 'board') + ?~ sboard :- %err 'No board, please report' + =/ stags (~(get by input.fd) 'tags') + ?~ stags :- %err 'No tags, please report to ~docteg-mothep or site@spandrell.ch' + =/ ntags (parse-tags:ui u.stags) + ?~ ntags :- %err 'Error parsing tags, please report' + =/ board (~(get by categories:const) u.sboard) + ?~ board :- %err 'No category, please report' + =/ ttags (~(put in u.ntags) u.sboard) + =. ttags (~(del in ttags) '') + [%ok u.stitle ttags] + + ++ post-or-edit + |= ntags=(set @t) + =/ stext (~(get by input.fd) 'text') + =/ upoll find-poll + =/ cl (build-content stext upoll) + ?: ?=(%err -.cl) cl + =/ sedit (~(get by input.fd) 'editing') + ?~ sedit :- %ok + :: TODO title! + (build-post:lib +.cl ntags [src.bowl now.bowl]) + + =/ edit-pid (dec:kaji u.sedit pid:tp) + ?~ edit-pid :- %err 'Edit cue error, please report to ~docteg-mothep or site@spandrell.ch' + =/ pedit (get:gorm:tp feed u.edit-pid) + ?~ pedit :- %err 'Post to edit not found, please report to ~docteg-mothep or site@spandrell.ch' + :- %ok (edit-post:lib u.pedit +.cl ntags now.bowl) + :: + ++ build-content + |= [text=(unit @t) poll=(unit poll:pols)] ^- (maybe:sr content-list:tp) + ?~ text + ?~ poll [%err 'no content!'] + :: only poll + =/ cl=content-list:tp (insert-poll:hd ~ u.poll) [%ok cl] + ?: .=(u.text '') ?~ poll [%err 'no content!'] + =/ cl=content-list:tp (insert-poll:hd ~ u.poll) [%ok cl] + :: have text + =/ contents (tokenize:ui u.text) + ?~ contents :- %err 'Parsing error, please report to ~docteg-mothep or site@spandrell.ch' + ?~ poll [%ok contents] + =/ cl=content-list:tp + (insert-poll:hd contents u.poll) [%ok cl] + + ++ send-error + |= [text=@t] + :_ this :_ ~ + =/ =manx ;span:"{(trip text)}" + %+ ui-fact:kaji tab-id + + =/ div (~(get by input.fd) 'error-div') + :_ ~ + ?~ div + [%alert manx 1.000] + [%swap manx u.div .y] + :: + ++ go-save-thread + |= [title=@t p=post:tp is-blog=? is-edit=?] + =/ s (save-thread:hd title p is-blog is-edit) + ?: ?=(%err -.s) (send-error +.s) + =. state +.s + =/ upoll find-poll + =. polls ?~ upoll polls (save-poll:hd u.upoll) + :_ this + %- route:kaj [route:router [%kaji tab-id %board-redi p] state] + :: TODO notify mentions + :: would need an agent for remote hark tho + ++ go-save-reply + |= [p=post:tp thread=pid:tp parent=pid:tp is-blog=?] + =. p (set-parents:lib p thread parent) + =/ s (save-reply:hd p thread parent is-blog) + ?: ?=(%err -.s) (send-error +.s) + =. state +.s + =/ upoll find-poll + =. polls ?~ upoll polls (save-poll:hd u.upoll) + :_ this + ?: is-blog + %- route:kaj [route:router [%kaji tab-id %blog-redi p] state] + %- route:kaj [route:router [%kaji tab-id %board-redi p] state] + :: TODO notify ships of their replies + :: + ++ bstv-chat + |= [name=@t input=@t] + =/ tower (~(get by here.tv) name) + ?~ tower `this + =/ contents (tokenize:ui input) + =/ post (build-post:lib contents ~ [src.bowl now.bowl]) + =/ station (~(get by schedule.u.tower) started.current.u.tower) + ?~ station `this + =. chat.u.station [post chat.u.station] + =. schedule.u.tower (~(put by schedule.u.tower) started.current.u.tower u.station) + =. here.tv (~(put by here.tv) name u.tower) + :_ this + %- route:kaj [route:router [%kaji tab-id %tv-chat name post] state] + ++ radio-chat + |= [p=@p t=@t] + =/ tower (~(get by urbit.tv) p) + ?~ tower `this + `this + + :: + ++ find-poll ^- (unit poll:pols) + :: =/ wal ~(. wall src.bowl) + :: ?~ (subscription-type:wal now.bowl) ~ + =/ stitle (~(get by input.fd) 'poll-title') + ?~ stitle ~ + ?: .=('' u.stitle) ~ + =/ opts=(list @t) + =| acc=(list @t) =| i=@ud + |- + =/ key %- crip "poll-opt-{(scow %ud i)}" + =/ opt (~(get by input.fd) key) + ?~ opt (flop acc) + =/ nacc [u.opt acc] + $(i +(i), acc nacc) + ?~ opts ~ + =/ smin-bet (~(get by input.fd) 'poll-min-bet') + ?~ smin-bet ~ + :: =/ min-bet ~ + :: TODO parse this + =/ sexpiry (~(get by input.fd) 'poll-expiry') + :: ?~ sexpiry ~ + =/ expiry ?~ sexpiry (add now.bowl ~d1) + =/ parsed (rush u.sexpiry html-datetime:parsing:sr) + ?~ parsed ~& "some weird html fuckery" (add now.bowl ~d1) + u.parsed + + =/ multiple=? + =/ smultiple (~(get by input.fd) 'poll-multiple') + :: actually this doesn't get sent at all if unchecked? + ?~ smultiple .n ?: .=(u.smultiple 'on') .y .n + + %- some %- new-poll:pols :* [src.bowl now.bowl] u.stitle expiry opts multiple == + + -- + + + + :: + ++ on-poke-noun + |= a=* + ?: ?=([%data-dump *] a) (sync-dump +.a) + ?: ?=(%gib a) give-batdev + ?> .=(src.bowl our.bowl) + :: ?: ?=(%sync a) poke-tasdev + ?: ?=(%tv-fix a) tv-fix + ?: ?=(%backup a) :_ this :_ ~ dump-state:hd + ?: ?=(%restore a) :- ~ this(state restore:hd) + ?: ?=(%sync-last a) :- ~ this(state read-last:hd) + ?: ?=(%kaji a) print-kaji + ?: ?=(%kick a) kick-kaji + :: loading blog data + ?: ?=(%rblog a) %- wrap load-blog:hd + ?: ?=(%rblog2 a) %- wrap load-blog-comments:hd + :: loading tianming data + ?: ?=(%rboard a) %- wrap load-tianming + ?: ?=(%rboard2 a) %- wrap load-tianming-replies + :: ?: ?=(%count a) log + ?: ?=(%check a) check + ?: ?=(%threads a) check-threads + ?: ?=(%athreads a) check-athreads + ?: ?=(%tags a) check-tags + ?: ?=([%tag tag=@t] a) (check-tag tag.a) + :: ?: ?=(%chcom a) check-comment + :: ?: ?=(%sample a) sample + ?: ?=(%pats a) pats + ?: ?=(%feed a) check-feed + ?: ?=(%radio a) get-radio + ?: ?=(%tw a) try-tw + ?: ?=([%check-thread *] a) (check-thread +.a) + :: fixes + ?: ?=([%fix-thread *] a) (fix-thread +.a) + ?: ?=([%dedup *] a) (dedup +.a) + ?: ?=([%scrub-ded *] a) (scrub +.a) + ?: ?=([%fix-active *] a) (fix-active +.a) + + ?: ?=(%sqlite a) dump-to-sqlite + ?: ?=(%licki a) init-lick + ?: ?=(%slick a) stop-lick + ?: ?=([%lick *] a) (send-lick +.a) + `this + :: + ++ init-lick + ~& "init lick" + :_ this :_ ~ + =/ note=note-arvo [%l %spin /'licker.sock'] + [%pass /lick/init %arvo note] + ++ stop-lick + :_ this :_ ~ + =/ note=note-arvo [%l %shut /'licker.sock'] + [%pass /lick/init %arvo note] + ++ send-lick + |= a=* + :_ this :_ ~ + =/ note=note-arvo [%l %spit /'licker.sock' %noun a] + [%pass /lick/init %arvo note] + + :: ++ insert-sql + :: """ + :: INSERT INTO posts(ts,author_id, title, content, snippet, url) + :: VALUES({tsn}, {author-idn}, {title}, {content}, {snippet}, {url}); + :: """ + :: ++ insert-sql2 + :: """ + :: INSERT INTO comments(ts,user_id, content, approved, comment_type, post_id, parent_id) + :: VALUES({tsn}, {user-idn}, {content}, {approved-n}, {type}, {post-idn}, {parent-idn}); + :: """ + :: ++ insert-sql3 + :: """ + :: INSERT INTO tags(tag) + :: VALUES({tsn}, {user-idn}, {content}, {approved-n}, {type}, {post-idn}, {parent-idn}); + :: """ + ++ dump-to-sqlite + :: posts + =/ count 0 + :: =/ l (tap:gorm:tp feed) + :: =/ res + :: |- + :: ?~ l ~ + :: ?: (gte count 20) ~ + :: =/ entry i.l + :: =/ poast val.entry + :: =/ is-blog (~(has in tags.poast) 'blog') + :: ?: is-blog + :: ~& >> poast=poast + :: =. count +(count) + :: $(l t.l) + :: $(l t.l) + :: threads + =/ l (tap:torm:tp threads) + =/ res + |- + ?~ l ~ + ?: (gte count 20) ~ + =/ entry i.l + =/ ted val.entry + =/ is-blog (~(has in tags.ted) 'blog') + ?: is-blog + ~& >> ted=ted + =. count +(count) + $(l t.l) + $(l t.l) + :: TODO prov + :: =/ tv-chat + :: =/ tvs (~(got by here.tv) 'spandrell-tv') + :: =/ sta (~(got by schedule.tvs) started.current.tvs) + :: chat.sta + :: =/ data=dump-type [(tap:gorm:tp feed) (tap:torm:tp threads) active-threads paths tags tv-chat] + :: =/ vase !>((jam data)) + :: =/ =soba:clay :_ ~ [/data/site-dump/(scot %da now.bowl)/jam %ins %noun vase] + :: =/ =nori:clay [%& soba] + :: =/ =task:clay [%info %blog nori] + :: init + :: =/ note=note-arvo [%l %spit /'licker.sock' %noun 'ligma'] + + :: [%pass /lick/spit %arvo note] + `this + :: + ++ sync-dump + |= a=* + ~& dump-received=src.bowl + ?> .=(our.bowl ~batdev-docteg-mothep) + =/ data=dump-type (dump-type a) + =. feed (gas:gorm:tp *gfeed:tp feed.data) + =. threads (gas:torm:tp *threadsf threads.data) + =. active-threads at.data + =. paths paths.data + =. tags tt.data + `this + ++ give-batdev + ~& sync-req-received=src.bowl + ?> .=(our.bowl ~tasdev-docteg-mothep) + ?> .=(src.bowl ~batdev-docteg-mothep) + ~& sync-req-received=src.bowl + =/ tv-chat + =/ tvs (~(got by here.tv) 'spandrell-tv') + =/ sta (~(got by schedule.tvs) started.current.tvs) + chat.sta + ~& "tv" + =/ data=dump-type [(tap:gorm:tp feed) (tap:torm:tp threads) active-threads paths tags tv-chat] + :_ this :_ ~ + [%pass /gib %agent [~batdev-docteg-mothep %boke] %poke %noun !>([%data-dump data])] + ++ poke-tasdev + ~& "poking tasdev" + :_ this :_ ~ + [%pass /gib %agent [~tasdev-docteg-mothep %boke] %poke %noun !>(%gib)] + ++ tv-fix + =/ muh (~(got by here.tv) 'Spandrell TV') + =. here.tv (~(del by here.tv) 'Spandrell TV') + =. here.tv (~(put by here.tv) 'spandrell-tv' muh) + `this + ++ fix-thread |= a=* + =/ =pid:tp ;; pid:tp a + =/ thread (got:torm:tp threads pid) + =/ post (got:gorm:tp feed pid) + =/ fn=full-node:tp (node-to-full:plib post feed) + =/ flat (flatten-fn:plib fn) + =/ pids %+ turn flat |= p=post:tp [author.p id.p] + =/ ordered %+ sort pids |= [a=pid:tp b=pid:tp] (gth id.a id.b) + =. replies.thread ordered + =. threads (put:torm:tp threads pid thread) + `this + ++ fix-active |= a=* + =/ =pid:tp ;; pid:tp a + =. active-threads +:(del:porm:tp active-threads pid) + `this + ++ check-thread |= a=* + =/ =pid:tp ;; pid:tp a + =/ ted (get:torm:tp threads pid) + ~& >> ted=ted + `this + ++ scrub |= a=* + =/ =pid:tp ;; pid:tp a + =/ ted (got:torm:tp threads pid) + ~& >> ted=ted + =. replies.ted + =/ l replies.ted + =| nl=(list pid:tp) + |- + ?~ l (flop nl) + =/ muh i.l + =/ pst (get:gorm:tp feed muh) + ?~ pst $(l t.l) + $(l t.l, nl [muh nl]) + =. threads (put:torm:tp threads pid ted) + `this + ++ dedup |= a=* + =/ =pid:tp ;; pid:tp a + =/ ted (got:torm:tp threads pid) + ~& >> ted=ted + =. replies.ted + =/ l replies.ted + =| nl=(list pid:tp) + |- + ?~ l (flop nl) + =/ muh i.l + =/ pidset (silt t.l) + ?: (~(has in pidset) muh) $(l t.l) + $(l t.l, nl [muh nl]) + ~& new=replies.ted + `this +++ try-tw + :_ this :_ ~ + [%pass /tw-test %arvo %k %fard q.byk.bowl %tw %noun !>([%user 'spandrell4'])] + ++ get-radio + :_ this :_ ~ watch-radio-card:hd + ++ print-kaji + =/ a %+ turn ~(tap by sup.bowl) + |= [=duct [=ship =path]] + ~& > duct + ~& >>> ship + ~& >> path + duct + `this + ++ wrap + |= s=_state =. state s `this + ++ kick-kaji + :: =/ cards %+ turn ~(tap by sup.bowl) + + :: |= [=duct [=ship =path]] + :: ~& > duct + :: ~& >>> ship + :: ~& >> path + =/ paths=(list path) ~[/ui /sse/(scot %p our.bowl)] + =/ cards :_ ~ [%give %kick paths ~] + ~& kicking=cards + [cards this] + ++ check-feed + ~& %+ roll (tap:gorm:tp feed) |= [[=pid:tp =post:tp] a=(list pid:tp)] + ?. (~(has in tags.post) 'blog') a [pid a] + `this + ++ pats + ~& > paths + `this + ++ check-tags + ~& tags=tags + `this + ++ check-tag + |= t=@t + :: ~& (~(get by tags) t) + =/ pids (~(get by tags) t) + ?~ pids ~& "not found" `this + =/ a %+ turn (tap:porm:tp u.pids) |= [=pid:tp p=pid:tp] + =/ ted (get:torm:tp threads pid) + ?~ ted ~& ted-not-found=pid ~ + ~& > thread=[title.u.ted] + ~ + `this + ++ check + =/ last (pry:gorm:tp feed) + ~& > last=last + `this + ++ check-threads + =/ t %+ turn (scag 10 (tap:torm:tp threads)) |= [pid:tp thread:tp] + ~& > thread=[title path (lent replies)] ~ + `this + ++ check-athreads + =/ t %+ turn (scag 2 (tap:torm:tp threads)) |= [pid:tp thread:tp] + ~& > thread=[title (lent replies)] ~ + `this + ++ check-comment + :: =/ last (pry:orm:tp blog) + :: ?~ last `this + :: ?~ parent.val.u.last `this + :: =/ parent (get:orm:tp blog u.parent.val.u.last) + :: ~& > last=last + :: ~& >> parent=parent + `this + ++ sample + :: ~& >> %+ scag 3 %+ skim (tap:orm:tp blog) + :: |= [=id:tp =post:tp] ?=(%~ parent.post) + `this + ++ log + :: ~& %- lent (tap:orm:tp blog) + `this + ++ load-tianming + =/ j .^(json %cx /(scot %p our.bowl)/blog/(scot %da now.bowl)/data/threads/json) + =/ jjj (boardpost:de:js j) + |- + ?~ jjj state + =/ a=read-boardpost i.jjj + =/ author ?: .=((cass (trip author.a)) "spandrell") ~docteg-mothep + (add (bex 64) author.a) + =/ pid [author date.a] + =/ c (put:corm:tp *content-map:tp date.a content.a) + =| p=post:tp + =. p %= p + id date.a + author -.pid + thread pid + parent ~ + contents c + tags (silt `(list @t)`~['oldtianming']) + == + =/ s (save-thread:hd title.a p .n .n) + =. state ?: ?=(%err -.s) state +.s + $(jjj t.jjj) + + ++ load-tianming-replies + =/ j .^(json %cx /(scot %p our.bowl)/boke/(scot %da now.bowl)/data/replies/json) + =/ jjj (boardpost:de:js j) + |- + ?~ jjj state + =/ a=read-boardpost i.jjj + =/ author ?: .=((cass (trip author.a)) "spandrell") ~docteg-mothep + (add (bex 64) author.a) + =/ pid [author date.a] + =/ thread-author ?: .=((cass (trip op.a)) "spandrell") ~docteg-mothep + (add (bex 64) op.a) + =/ thread-pid [thread-author thread.a] + =/ c (put:corm:tp *content-map:tp date.a content.a) + =| p=post:tp + =. p %= p + id date.a + author author + thread thread-pid + parent `thread-pid + contents c + == + =. state + =/ s (save-reply:hd p thread-pid thread-pid .y) + ?: ?=(%err -.s) state +.s + $(jjj t.jjj) + :: + + :: =/ one (put:gorm:tp feed pid p) + :: =. feed ?~ parent-post one + :: =/ parent-pid [author.u.parent-post parent.a] + :: =/ full-parent (get:gorm:tp feed parent-pid) + :: ?~ full-parent one + :: =/ oc children.u.full-parent + :: =/ nc (~(put in oc) pid) + :: =/ np u.full-parent(children nc) + :: (put:gorm:tp one parent-pid np) + :: =. tags =/ curr (~(get by tags) 'blog-comment') + :: =/ nl ?~ curr ~[pid] (snoc u.curr pid) + :: (~(put by tags) 'blog-comment' nl) + :: =/ l (tap:torm:tp threads) + :: |- + :: ?~ l `this + :: =/ t=thread:tp +.i.l + :: ?~ replies.t $(l t.l) + :: =/ del (del:torm:tp active-threads -.i.l) + :: =. active-threads ?~ -.del threads + :: (put:torm:tp +.del -.replies.t t) + :: $(l t.l) + + + ++ serve + ^- (quip card _this) + =/ order !<(eyre-order:kaji vase) + =/ address address.req.order + ~& >> address=address + ~& > req=url.request.req.order + ?: (~(has in banned-ips:const) address) `this + :: ~& >>> malicious-request-alert=req.order `this + :_ this + %- route:kaj + [route:router [%eyre order] state] +-- +++ on-peek +|= =(pole knot) +?+ pole ~ + [%x %manx %nav sip=@t ~] + =/ sip (slav %p sip.pole) + =. bowl bowl(src sip) + :- ~ :- ~ :- %noun !> + =/ nv nav(bowl bowl) ext:nv + [%x %chads sip=@t ~] + :- ~ :- ~ :- %noun !> + =/ sip (slav %p sip.pole) + =/ wal ~(. wall sip) + ?~ (subscription-type:wal now.bowl) .n .y +== +:: ~& on-peek=pole +:: =/ blog (~(got by feeds) %blog) +:: ?+ pole ~ +:: [%x %index ~] +:: =/ posts=(list full-node:tp) +:: %+ scag page-size +:: %- flop +:: %+ roll (tap:orm:tp blog) +:: |= [i=[=id:tp =post:tp] a=(list full-node:tp)] +:: ?~ parent.post.i [(node-to-full:plib post.i blog) a] a +:: ``[%noun !>(posts)] +:: [%x %post rest=*] +:: ~& > rest=rest.pole +:: =/ p (~(get by paths) rest.pole) +:: ?~ p ~ +:: =/ poast (got:orm:tp blog id.u.p) +:: =/ fn (node-to-full:plib poast blog) +:: ``[%noun !>(fn)] +:: :: [%x %search query=@ comments=@] +:: :: =/ with-comments .=(comments '1') +:: :: ~ +:: == +++ on-agent +|= [=wire =sign:agent:gall] +|^ + ?: ?=(%kick -.sign) resub + ?: ?=([%radio ~] wire) handle-radio + ?. ?=(%fact -.sign) `this + ?: ?=(%dm p.cage.sign) (handle-dm !<(memo:c q.cage.sign)) + ?. ?=(%channel-response p.cage.sign) `this + =/ res !<(r-channels:c q.cage.sign) + ?. ?=(%post +<.res) `this + =/ =flag:tlonc ->.res + :_ this + =/ r r-post.r-channel.res + ?- -.r + %set ?~ post.r ~ (route:kaj [route:router [%kaji '' %chat-msg flag +<.u.post.r] state]) + %reply ~ :: reply-count.reply-meta.r id-reply.r + %reacts ~ :: reacts.r :: map + %essay ~ :: wtf + == + ++ handle-dm + |= m=memo:c + :: validate TOTP and set cookie if so + `this + ++ handle-radio + ?. ?=(%fact -.sign) `this + =/ e !<(radio-event q.cage.sign) + ?. ?=(%response -.e) `this + =. urbit.tv minitowers.e `this + + ++ resub + :_ this + ?+ wire ~ + [%radio ~] :~(watch-radio-card:hd) + [%chat %updates ~] :~(watch-chat-card:hd) + == + + +-- +++ on-arvo + |= [=(pole knot) =sign-arvo] + |^ + ?: ?=([%lick %soak *] sign-arvo) + ?+ [mark noun]:sign-arvo `this + [%connect ~] ((slog 'socket connected' ~) `this) + [%disconnected ~] ((slog 'socket disconnected' ~) `this) + [%error *] ((slog leaf+"socket error {(trip ;;(@t noun.sign-arvo))}" ~) `this) + [%noun *] ((slog leaf+"socket noun {(trip ;;(@t noun.sign-arvo))}" ~) `this) + == + :: + ?: ?=([%arow *] +.sign-arvo) (handle-thread +>.sign-arvo) + ?. ?=([%behn %wake *] sign-arvo) `this + ?. ?=([%backup ~] pole) `this + :_ this :_ ~ dump-state:hd + :: + ++ handle-thread + |= s=(avow:khan cage) + ?: ?=(%| -.s) ~& "thread failed" `this + =/ devase !<(* +>.s) + :: ?: ?=(%& -.p.sign-arvo) `this + `this + -- +-- +|_ =bowl:gall +:: saving to state ++$ save-res +$% [%err err=@t] + [%ok p=_state] +== +++ save-thread +|= [title=@t p=post:tp is-blog=? is-edit=?] ^- save-res + =/ post-pid [author.p id.p] + =. feed (put:gorm:tp feed post-pid p) + =/ pat ?: is-blog + (make-blogpost-path:lib id.p title) + (make-board-path:lib paths title tags.p) + =/ t ?. is-edit *thread:tp (got:torm:tp threads post-pid) + =/ snip-size ?: is-blog 500 200 + =/ snip (abbreviate-post:plib contents.p snip-size) + =. t t(title title, path pat, pid post-pid, tags tags.p, snip snip) :: TODO remove titles from posts + =. threads (put:torm:tp threads post-pid t) + =. active-threads (put:porm:tp active-threads post-pid post-pid) + =. tags (save-tags tags.p post-pid) + =. paths (~(put by paths) pat post-pid) + :- %ok state +++ save-reply +|= [p=post:tp thread=pid:tp parent=pid:tp blog=?] ^- save-res + =. p (set-parents:lib p thread parent) + =/ post-pid [author.p id.p] + =/ pop (get:torm:tp threads thread) + ?~ pop [%err 'thread op not found please report to ~docteg-mothep or site@spandrell.ch'] + =/ ppar (get:gorm:tp feed parent) + ?~ ppar [%err 'parent not found, please report to ~docteg-mothep or site@spandrell.ch'] + =. feed (put:gorm:tp feed post-pid p) + =/ npar u.ppar(children (~(put in children.u.ppar) post-pid)) + =. feed (put:gorm:tp feed parent npar) + =/ has-reply (~(has in (silt replies.u.pop)) post-pid) + =/ nr ?: has-reply replies.u.pop [post-pid replies.u.pop] + =/ npop u.pop(replies nr) + =. threads (put:torm:tp threads thread npop) + =/ replies replies.u.pop + =/ last-reply ?~ replies thread i.replies + =/ delt (del:porm:tp active-threads last-reply) + =/ mmm ?~ -.delt ~& >>> thread-not-found-under-last-reply=post-pid ~ ~ + =. active-threads +:delt + =. active-threads (put:porm:tp active-threads post-pid thread) + :- %ok state +:: +++ save-tags +|= [ntags=(set @t) =pid:tp] ^- tags-table + =/ tag-list ~(tap in ntags) + |- ^- tags-table + ?~ tag-list tags + =/ curr (~(get by tags) i.tag-list) + =/ npids ?~ curr + (put:porm:tp *pidmap pid pid) + (put:porm:tp u.curr pid pid) + =/ nmap (~(put by tags) i.tag-list npids) + $(tag-list t.tag-list, tags nmap) + +++ del-in-tags +|= [ntags=(set @t) =pid:tp] ^+ tags + =/ tag-list ~(tap in ntags) + |- ^+ tags + ?~ tag-list tags + =/ curr (~(get by tags) i.tag-list) + =/ npids ?~ curr ~ +:(del:porm:tp u.curr pid) + =/ nmap (~(put by tags) i.tag-list npids) + $(tag-list t.tag-list, tags nmap) + +:: polls + +++ save-poll + |= p=poll:pols ^+ polls + (~(put by polls) [author.p time.p] p) + +++ insert-poll + |= [c=content-list:tp =poll:pols] ^+ c + =/ ref=block:tp :- %ref :+ %polls src.bowl + /(scot %p author.poll)/(scot %da time.poll) + (snoc c ref) + +++ vote-poll + |= [=pid:tp option=@ud] + =/ upoll (~(get by polls) pid) + ?~ upoll polls + =/ =poll:pols (add-vote u.upoll option) + (~(put by polls) pid poll) +++ add-vote + |= [=poll:pols option=@ud] ^+ poll + ?: ?=(%exc -.votes.poll) + =. p.votes.poll + (~(put by p.votes.poll) src.bowl option) + poll + :: + =. p.votes.poll + =/ curr (~(get by p.votes.poll) option) + =/ nmap=(map @p (set @ud)) + ?~ curr + %- malt ~[[src.bowl (silt ~[option])]] + :: + =/ my-votes=(unit (set @ud)) (~(get by u.curr) src.bowl) + ?~ my-votes + (~(put by u.curr) src.bowl `(set @ud)`(silt ~[option])) + (~(put by u.curr) src.bowl `(set @ud)`(~(put in u.my-votes) option)) + + (~(put by p.votes.poll) option nmap) + poll + :: + +:: +++ dump-state ^- card + :: TODO prov + =/ tv-chat + =/ tvs (~(got by here.tv) 'spandrell-tv') + =/ sta (~(got by schedule.tvs) started.current.tvs) + chat.sta + =/ data=dump-type [(tap:gorm:tp feed) (tap:torm:tp threads) active-threads paths tags tv-chat] + =/ vase !>((jam data)) + =/ =soba:clay :_ ~ [/data/site-dump/(scot %da now.bowl)/jam %ins %noun vase] + =/ =nori:clay [%& soba] + =/ =task:clay [%info %blog nori] + =/ note=note-arvo [%c task] + [%pass /dump/[dap.bowl] %arvo note] ++$ dump-type + $: feed=(list feed-pair) + threads=(list thread-pair) + at=pidmap + paths=pathmap + tt=tags-table + tv-chat=(list post:tp) + == + ++$ feed-pair [pid:tp post:tp] ++$ thread-pair [pid:tp thread:tp] +++ read-last ^+ state + ~& > "restoring" + =/ bp /(scot %p our.bowl)/blog/(scot %da now.bowl) + =/ f .^((list path) %ct (weld bp /data/site-dump)) + ?~ f state + =/ filename (rear f) + ~& [f filename] + =/ j .^(@ %cx (weld bp filename)) + ~& read-file=(end [0 100] j) + =/ cued (cue j) + =/ data ;;(dump-type cued) + ~& >>> lengths=[(lent feed.data) (lent threads.data)] + =/ tvs (~(got by here.tv) 'spandrell-tv') + =/ sta (~(got by schedule.tvs) started.current.tvs) + =. chat.sta tv-chat.data + =. schedule.tvs (~(put by schedule.tvs) started.current.tvs sta) + =. here.tv (~(put by here.tv) 'spandrell-tv' tvs) + %= state + feed (gas:gorm:tp *gfeed:tp feed.data) + threads (gas:torm:tp *threadsf threads.data) + active-threads at.data + paths paths.data + tags tt.data + == +++ restore ^+ state + ~& > "restoring" + =/ j .^(@ %cx /(scot %p our.bowl)/blog/(scot %da now.bowl)/data/site-dump/jam) + ~& read-file=(end [0 100] j) + =/ cued (cue j) + =/ data ;;(dump-type cued) + ~& >>> lengths=[(lent feed.data) (lent threads.data)] + =/ tvs (~(got by here.tv) 'spandrell-tv') + =/ sta (~(got by schedule.tvs) started.current.tvs) + =. chat.sta tv-chat.data + =. schedule.tvs (~(put by schedule.tvs) started.current.tvs sta) + =. here.tv (~(put by here.tv) 'spandrell-tv' tvs) + %= state + feed (gas:gorm:tp *gfeed:tp feed.data) + threads (gas:torm:tp *threadsf threads.data) + active-threads at.data + paths paths.data + tags tt.data + == +:: Cards +++ watch-radio-card ^- card +[%pass /radio %agent [~docteg-mothep %tower] %watch /towers] +++ watch-chat-card ^- card +[%pass /chat/updates %agent [our.bowl %channels] %watch /chat/(scot %p our.bowl)/chat] +++ watch-dms-card ^- card +[%pass /dm-root %agent [our.bowl %chat] %watch /] +++ watch-cards ^- (list card) +:~ watch-radio-card + watch-chat-card +== +++ root-path-card ^- card + [%pass /mmm %arvo %e %connect [~ /] dap.bowl] +++ init-cards ^- (list card) +:~ watch-radio-card + watch-chat-card + watch-dms-card + root-path-card + schedule-backup-card +== +++ schedule-backup-card ^- card + [%pass /backup %arvo %b %wait (add now.bowl ~h6)] + +++ init-state ^+ state +=. tv init-tv +:: =. state load-blog +:: =. state load-blog-comments +state +++ init-tv ^+ tv +=/ starting=@da now.bowl +=/ sta=tv-station :* + 'Dune Month!' + 'https://hydrogen.finnem.net/hls/live.m3u8' + starting + ~ + ~ + chat-welcome-post^~ + ~ +== +=/ schedule %- malt :_ ~ [starting sta] +=/ =bstv ['Spandrell TV' ~docteg-mothep ['Dune Month!' starting] schedule] +=. here.tv (~(put by here.tv) 'spandrell-tv' bstv) +tv + +++ chat-welcome-post ^- post:tp +=/ contents (tokenize:ui 'Welcome to Spandrell TV! Make yourself cozy') +(build-post:lib contents ~ [~docteg-mothep now.bowl]) +++ load-blog + =/ j .^(json %cx /(scot %p our.bowl)/blog/(scot %da now.bowl)/data/posts/json) + =/ jjj (poast:de:js j) + |- + ?~ jjj state + =/ a=read-post i.jjj + =/ pid [~docteg-mothep date.a] + =/ c (put:corm:tp *content-map:tp date.a contents.a) + =/ tgs (~(put in tags.a) 'blog') + =| p=post:tp + =. p %= p + id date.a + author -.pid + thread pid + contents c + tags tgs + == + =/ s (save-thread title.a p .y .n) + =. state ?: ?=(%err -.s) state +.s + $(jjj t.jjj) + +++ load-blog-comments + =/ j .^(json %cx /(scot %p our.bowl)/boke/(scot %da now.bowl)/data/comments/json) + =/ jj %+ sort (comment:de:js j) |= [a=read-comment b=read-comment] + (lth date.a date.b) + |- + ?~ jj state + =/ a=read-comment i.jj + =/ c (put:corm:tp *content-map:tp date.a contents.a) + =/ author ?: .=((cass (trip author.a)) "spandrell") ~docteg-mothep + (add (bex 64) author.a) + =/ pa ?: .=((cass (trip pa.a)) "spandrell") ~docteg-mothep + (add (bex 64) pa.a) + =/ pid [author date.a] + =/ ppid [pa parent.a] + =/ parent-post (get:gorm:tp feed ppid) + =/ parent=(unit pid:tp) ?~ parent-post ~& > no-parent=[author.a date.a pa.a parent.a title.a] ~ + `ppid + =/ op [~docteg-mothep post.a] + =| p=post:tp + =. p %= p + id date.a + author `@p`author + contents c + tags (sy ~['blog-comment']) + == + =. state ?~ parent state + =/ s (save-reply p op u.parent .y) + ?: ?=(%err -.s) state +.s + $(jj t.jj) + + +++ hi bowl +:: cards +:: ++ send-dm +:: |= who=@p +:: =/ input %- crip "Show me what you got" +:: =/ parsed (text-to-content input) +:: ~& parsed=parsed +:: ?~ parsed (alert-card:kaj "Text parsing failed") +:: =/ content=story:c +:: :_ ~ :- %inline :_ ~ u.parsed +:: =/ id [our.bowl now.bowl] +:: =/ =memo:c [content our.bowl now.bowl] +:: =/ delta [%add memo ~ ~] +:: =/ diff [id delta] +:: =/ a [who diff] +:: :* %pass +:: /send +:: %agent +:: [our.bowl %chat] +:: %poke +:: %chat-dm-action +:: !> a +:: == + +++ send-message +|= input=inline:c +=/ content=story:c +:_ ~ :- %inline :_ ~ input +=/ =memo:c [content src.bowl now.bowl] +=/ =kind-data:c [%chat ~] +=/ =essay:c [memo kind-data] +=/ cp=c-post:c [%add essay] +=/ cc=c-channel:c [%post cp] +=/ =nest:c [%chat our.bowl %chat] +=/ a=c-channels:c [%channel nest cc] +:* %pass + /send + %agent + [our.bowl %channels] + %poke + %channel-action + !> a +== + ++ text-to-content + %+ curr rush + |^ ;~ pose + (cook |=(=@t [%link t t]) turl) + text + == + ++ turl + =- (sear - text) + |= t=cord + ^- (unit cord) + ?~((rush t aurf:de-purl:html) ~ `t) + :: +text: text message body + :: + ++ text + (cook crip (plus next)) + -- +-- diff --git a/desk/app/chat.hoon b/desk/app/chat.hoon new file mode 100644 index 0000000..1dcfadd --- /dev/null +++ b/desk/app/chat.hoon @@ -0,0 +1,497 @@ +:: chat-stream: chat proxy for earthlings +:: +:: makes specified chats accessible over unauthenticated http requests. +:: GET at /stream/chat-name.json to receive json updates as messages happen. +:: POST at /stream/chat-name with a body to send a chat message. +:: +:: hands out temporary identities (using fakeid) using which stream viewers +:: can post to exposed chats. +:: NOTE that the cookie it gives out is marked Secure and SameSite=None! +:: +:: when streaming a chat, any messages sent into it (by real identities) +:: of the form "!ban ~ship" will result in an ip ban for that ship, +:: denying them posting privileges in all local streams. +:: +:: usage: poke with an action. ie :chat-stream [%stream %urbit-help] +:: +/- chat +/+ chat-json, + default-agent, verb, dbug, + fid=fakeid, *server +:: +|% ++$ state-0 + $: %0 + streams=(set source) + viewers=(jug source eyre-id) + ::TODO we need to expire these to avoid a space-leak + :: probably clean up expired ids every +identity-duration + ::TODO shouldn't this live in fakeid-store instead? but how update? + guests=(map ship (set address:eyre)) + banned=(set address:eyre) + == +:: +::NOTE we could support _streaming_ foreign chats fairly easily, +:: but posting to them is a way different story, +:: so we just go full local-only for now. ++$ source term +:: ++$ eyre-id @ta +:: ++$ action + $% [%stream =source] + [%stop =source] + [%ban name=@p] + [%unban =address:eyre] + == +:: ++$ card card:agent:gall +-- +:: +=| state-0 +=* state - +:: +%- agent:dbug +%+ verb | +:: +^- agent:gall +=< + |_ =bowl:gall + +* this . + do ~(. +> bowl) + def ~(. (default-agent this %|) bowl) + :: + ++ on-init + ^- (quip card _this) + ::NOTE careful! install currently proceeds fine if this crashes. + :: you'll need to |uninstall the desk and |nuke the app. + |^ =+ (check-dependency %fakeid-store) + =+ (check-dependency %chat) + :_ this + :~ [%pass /connect %arvo %e %connect [~ /stream] dap.bowl] + kick-heartbeat:do + == + :: + ++ check-dependency + |= app=dude:gall + ~| [%missing-dependency %app app] + ?> .^(? %gu /(scot %p our.bowl)/[app]/(scot %da now.bowl)/$) + ~ + -- + :: + ++ on-save !>(state) + :: + ++ on-load + |= old=vase + ^- (quip card _this) + [~ this(state !<(state-0 old))] + :: + ++ on-poke + |= [=mark =vase] + ^- (quip card _this) + ?+ mark (on-poke:def mark vase) + %noun $(mark %stream-action) + :: + %stream-action + =/ =action !<(action vase) + =^ cards state + ?- -.action + %stream (start-stream:do +.action) + %stop (stop-stream:do +.action) + %ban (ban-comet:do +.action) + %unban (unban-ip:do +.action) + == + [cards this] + :: + %handle-http-request + =^ cards state + %- handle-http-request:do + !<([=eyre-id =inbound-request:eyre] vase) + [cards this] + == + :: + ++ on-watch + |= =path + ?: ?=([%http-response @ ~] path) + [~ this] + (on-watch:def path) + :: + ++ on-leave + |= =path + ^- (quip card _this) + ?. ?=([%http-response @ ~] path) + (on-leave:def path) + =/ who=eyre-id i.t.path + :- ~ + =- this(viewers -) + ::NOTE we really only delete from one, but we don't want to keep a + :: reverse lookup just for that optimization. + %- ~(run by viewers) + |= v=(set eyre-id) + (~(del in v) who) + :: + ++ on-agent + |= [=wire =sign:agent:gall] + ^- (quip card _this) + ?: ?=(%poke-ack -.sign) + ?~ p.sign [~ this] + %- (slog leaf+"failed poke on {(spud wire)}" u.p.sign) + [~ this] + ?. ?=([%listen @ ~] wire) (on-agent:def wire sign) + =* source i.t.wire + ?+ -.sign (on-agent:def wire sign) + %kick + [[(watch-chat:do our.bowl source)]~ this] + :: + %fact + =* mark p.cage.sign + =* vase q.cage.sign + ?+ mark (on-agent:def wire sign) + %writ-diff + =^ cards state + (handle-chat-update:do source !<(diff:writs:chat vase)) + [cards this] + == + == + :: + ++ on-arvo + |= [=wire =sign-arvo] + ^- (quip card _this) + ?+ sign-arvo (on-arvo:def wire sign-arvo) + [%eyre %bound *] + ~? !accepted.sign-arvo + [dap.bowl 'bind rejected!' binding.sign-arvo] + [~ this] + :: + [%behn %wake *] + ?. ?=([%heartbeat ~] wire) (on-arvo:def wire sign-arvo) + [send-heartbeat:do this] + == + :: + ++ on-peek on-peek:def + ++ on-fail on-fail:def + -- +:: +|_ =bowl:gall ++* fakeid ~(. fid bowl) +:: +:: config +:: +++ identity-duration ~d7 +++ initial-messages 25 +++ max-message-length 280 +++ heartbeat-timer ~s30 +:: +:: card builders +:: +++ kick-heartbeat + ^- card + [%pass /heartbeat %arvo %b %wait (add now.bowl heartbeat-timer)] +:: +++ send-heartbeat + ^- (list card) + :- kick-heartbeat + =/ viewers=(list eyre-id) + %~ tap in + %+ roll ~(val by viewers) + |= [s=(set eyre-id) o=(set eyre-id)] + (~(uni in o) s) + ?: =(0 (lent viewers)) ~ + :_ ~ + :* %give + %fact + :: + %+ turn viewers + |= =eyre-id + /http-response/[eyre-id] + :: + %http-response-data + !> ^- (unit octs) + `[1 '\0a'] ::TODO prefix with : ? + == +:: +++ watch-chat + |= [our=ship =term] + ^- card + :* %pass + /listen/[term] + %agent + [our %chat] + %watch + /chat/(scot %p our)/[term]/ui/writs + == +:: +++ leave-chat + |= [our=ship =term] + ^- card + [%pass /listen/[term] %agent [our %chat] %leave ~] +:: +++ send-to-viewers + |= [=source =json] + ^- (list card) + =/ ids=(set eyre-id) + (~(get ju viewers) source) + ?: =(~ ids) ~ + :_ ~ + :* %give + %fact + :: + %+ turn ~(tap in ids) + |= =eyre-id + /http-response/[eyre-id] + :: + %http-response-data + !> ^- (unit octs) + %- some + (make-stream-data json) + == +:: +++ make-stream-data + |= =json + ^- octs + %- as-octs:mimes:html + (rap 3 'data:' (en:json:html json) '\0a\0a' ~) +:: +:: actions +:: +++ start-stream + |= =source + ^- (quip card _state) + ?: ?| ?=(~ source) + (~(has in streams) source) + == + [~ state] + :- [(watch-chat our.bowl source)]~ + state(streams (~(put in streams) source)) +:: +++ stop-stream + |= =source + ^- (quip card _state) + ?. (~(has in streams) source) + [~ state] + :- [(leave-chat our.bowl source)]~ + %_ state + streams (~(del in streams) source) + viewers (~(del by viewers) source) + == +:: +++ ban-comet + |= who=ship + ^- (quip card _state) + :- ~ + %_ state + guests (~(del by guests) who) + banned (~(uni in banned) (~(get ju guests) who)) + == +:: +++ unban-ip + |= =address:eyre + ^- (quip card _state) + :- ~ + %_ state + banned (~(del in banned) address.action) + == +:: +:: outgoing flows +:: +++ handle-chat-update + |= [=source =diff:writs:chat] + ^- (quip card _state) + ?. ?=(%add -.q.diff) + [~ state] + ?. (~(has in streams) source) + ~& [dap.bowl %unexpected-diff-for source] + [~ state] + :: accept !ban commands from real identites, + :: as plaintext "!ban " followed by a mention + :: + =/ banning=(unit @p) + ?. (lte (met 3 author.p.q.diff) 8) ~ + =/ body=(list inline:chat) + ?+ -.content.p.q.diff ~ + %story q.p.content.p.q.diff + == + ?. ?=([%'!ban ' [%ship @] *] body) ~ + `p.i.t.body + =^ caz state + ?~ banning [~ state] + (ban-comet u.banning) + :_ state + :: forward posts to all viewers + :: + %+ send-to-viewers source + (memo:enjs:chat-json p.q.diff) +:: +:: incoming flows +:: +++ handle-http-request + |= [=eyre-id =inbound-request:eyre] + ^- (quip card _state) + ?+ method.request.inbound-request + [(give-simple-payload:app eyre-id not-found:gen) state] + :: + %'GET' (handle-get eyre-id inbound-request) + %'POST' (handle-post eyre-id inbound-request) + == +:: +::TODO find a better way to structure this logic +++ handle-get + |= [=eyre-id =inbound-request:eyre] + ^- (quip card _state) + =- =^ [card=(unit card) simple-payload:http] state + - + =. headers.response-header + :* 'Content-Type'^'text/event-stream' + 'Cache-Control'^'no-cache' + 'Connection'^'keep-alive' + headers.response-header + == + :_ state + =/ header=cage [%http-response-header !>(response-header)] + =/ data=cage [%http-response-data !>(data)] + =/ =path /http-response/[eyre-id] + :* [%give %fact ~[path] header] + [%give %fact ~[path] data] + :: + %+ weld (drop card) + ^- (list ^card) + ?: =(200 status-code.response-header) ~ + [%give %kick ~[path] ~]~ + == + ^- [[(unit card) simple-payload:http] _state] + =/ [[ext=(unit @ta) site=(list @t)] *] + %- parse-request-line + url.request.inbound-request + :: ignore requests that point to unsupported resources + :: + ?. &(?=([%stream @ ~] site) ?=([~ %json] ext)) + [[~ not-found:gen] state] + =/ =source i.t.site + ?. (~(has in streams) source) + [[~ not-found:gen] state] + :: add eyre-id as viewer for requested source + :: + =. viewers + (~(put ju viewers) source eyre-id) + :: find or create session for request + :: + =/ who=(unit session:fakeid) + (session-from-request:fakeid inbound-request) + =/ [out=(unit card) =session-key:fakeid =session:fakeid] + ?^ who [~ *session-key:fakeid u.who] + =< [`card session-key session] + (new-session:fakeid identity-duration) + =/ =header-list:http + ?^ who ~ + ::TODO don't need samesite=none in some contexts, but how can we tell? + (set-session-cookie:fakeid session-key until.session &) + :: keep track of all addresses this session has connected from, + :: but never track localhost requests + :: + =? guests !=(.127.0.0.1 address.inbound-request) + %+ ~(put ju guests) + name.session + address.inbound-request + :_ state + :- out + :: build response from some recent messages + :: + ^- simple-payload:http + :- [200 header-list] + %- some + %- make-stream-data + :- %a + =- (turn - |=([* * m=memo:chat] (memo:enjs:chat-json m))) + ^- (list [time writ:chat]) + %- tap:((on time writ:chat) lte) + .^ ((mop time writ:chat) lte) + %gx + (scot %p our.bowl) + %chat + (scot %da now.bowl) + %chat + (scot %p our.bowl) + source + /writs/newest/(scot %ud initial-messages)/chat-writs + == +:: +++ handle-post + |= [=eyre-id =inbound-request] + ^- (quip card _state) + :_ state + =; [out=(unit card) =simple-payload:http] + %+ weld (drop out) + (give-simple-payload:app eyre-id simple-payload) + :: request must have sane target + :: + =/ [[ext=(unit @ta) site=(list @t)] *] + %- parse-request-line + url.request.inbound-request + ?. &(?=([%stream @ ~] site) ?=(~ ext)) + `not-found:gen + =/ =source i.t.site + :: request must have some content + :: + =/ body=@t + q:(fall body.request.inbound-request *octs) + ?: =(~ body) + `[[400 ~] ~] + :: reject requests from banned addresses + :: + ?: (~(has in banned) address.inbound-request) + `[[403 ~] `(as-octs:mimes:html 'ur banned, fool!')] + :: reject requests without fakeid sessions + :: + =/ who=(unit ship) + (identity-from-request:fakeid inbound-request) + ?~ who + `[[403 ~] `(as-octs:mimes:html 'no session cookie')] + :: + :_ [[200 ~] ~] + %- some + %^ send-message + source + u.who + :+ %story ~ + :_ ~ + %- text-to-content + (end 3^max-message-length body) +:: +++ text-to-content + %+ curr rash + ::NOTE we intentionally don't do #expression parsing + |^ ;~ pose + (cook |=(=@t [%link t t]) turl) + text + == + :: +turl: url parser + :: + ++ turl + =- (sear - text) + |= t=cord + ^- (unit cord) + ?~((rush t aurf:de-purl:html) ~ `t) + :: +text: text message body + :: + ++ text + (cook crip (plus next)) + -- +:: +++ send-message + |= [=source as=ship =content:chat] + ^- card + :* %pass + /send/[source] + %agent + [our.bowl %chat] + %poke + %chat-action-0 + :: + !> ^- action:chat + :- [our.bowl source] + :+ now.bowl %writs + ^- diff:writs:chat + ::TODO as in place of our for msg id? + [[our.bowl now.bowl] %add [~ as now.bowl content]] + == +-- diff --git a/desk/app/pals.hoon b/desk/app/pals.hoon new file mode 100644 index 0000000..5a50743 --- /dev/null +++ b/desk/app/pals.hoon @@ -0,0 +1,385 @@ +:: pals: manual peer discovery +:: +:: acts as a "friendlist" of sorts, letting one add arbitrary ships to +:: arbitrary lists. upon doing so, the other party is informed of this. +:: this lets the app expose "friend requests" and mutuals, in addition +:: to user-defined sets of friends. +:: +:: intended use case is as simple, bare-bones peer discovery and +:: permissioning for truly peer-to-peer applications, in place of +:: (or as supplement to) group-based peer discovery. +:: for example, a game wanting to stay abreast of high scores, +:: or filesharing service giving selective access. +:: +:: "leeches" are ships who added us. +:: "targets" are ships we have added. +:: "mutuals" is the intersection of "leeches" and "targets". +:: +:: reading +:: external applications likely want to read from this via scries or +:: watches, both of which are outlined below. +:: finding interaction targets or mutuals to poke or subscribe to, using +:: mutual status as permission check, etc. +:: to scry data out of this app, please use /lib/pals. +:: one might be tempted to use list names for namespacing (ie %yourapp +:: would only retrieve targets from the ~.yourapp list), but beware that +:: this overlaps with user-facing organizational purposes. if lists feel +:: opaque or inaccessible, it's to discourage this. but the right balance +:: might not have been found yet... +:: +:: writing +:: poke this app with a $command. +:: %meet adds a ship. it is also added to any list names specified. +:: %part removes a ship from either all or the specified lists. +:: the ~. list name is reserved and cannot be added to. +:: managing pals without an interface that lets users control that behavior +:: is bad manners. managing pals without informing the user is evil. +:: +:: scry endpoints (all %noun marks) +::NOTE %y at / doesn't actually work because gall eats it ): +:: y / arch [%leeches %targets %mutuals ~] +:: y /[status] arch non-empty lists listing +:: +:: x / records full pals state +:: x /leeches (set ship) foreign one-sided friendships +:: x /targets(/[list]) (set ship) local one-sided friendships +:: x /mutuals(/[list]) (set ship) mutual friendships +:: +:: x /leeches/[ship] ? is ship a leeche? +:: x /targets/[list]/[ship] ? is ship a target? list may be ~. for all +:: x /mutuals/[list]/[ship] ? is ship a mutual? list may be ~. for all +:: +:: subscription endpoints (local ship only, all %pals-effect marks) +:: /targets target-effect effect for every addition/removal +:: /leeches leeche-effect effect for every addition/removal +:: +/- *pals +/+ rudder, dbug, verb, default-agent +:: +/~ pages (page:rudder records command) /app/pals/webui +:: +|% ++$ state-1 [%1 records] +:: ++$ card card:agent:gall +-- +:: +=| state-1 +=* state - +:: +%- agent:dbug +%+ verb | +^- agent:gall +:: +|_ =bowl:gall ++* this . + def ~(. (default-agent this %|) bowl) +:: +++ on-init + ^- (quip card _this) + =^ cards this + (on-poke %pals-command !>(`command`[%meet ~paldev ~])) + :_ this + :+ [%pass /jael/pubs %arvo %j %public-keys ~] + [%pass /eyre/connect %arvo %e %connect [~ /[dap.bowl]] dap.bowl] + cards +:: +++ on-save !>(state) +:: +++ on-load + |= ole=vase + |^ ^- (quip card _this) + =/ old=state-n !<(state-n ole) + =^ caz=(list card) old + ?. ?=(%0 -.old) [~ old] + =. state [%1 +.old] + =^ caz this + ::TODO run this again some time in the future, to solve for + :: the "breached & never re-added you" case, where they + :: might not know you need to hear a %bye. + (on-poke %noun !>(%resend)) + [[[%pass /jael/pubs %arvo %j %public-keys ~] caz] state] + ?> ?=(%1 -.old) + [caz this(state old)] + :: + +$ state-n $%(state-1 state-0) + +$ state-0 [%0 records] + -- +:: +++ on-poke + |= [=mark =vase] + ^- (quip card _this) + ?+ mark (on-poke:def mark vase) + %noun + ?+ q.vase $(mark %pals-command) + %resend + =/ out=(set ship) ~(key by outgoing) + =. receipts + =/ out=(list ship) ~(tap in out) + |- + ?~ out receipts + =. receipts (~(del by receipts) i.out) + $(out t.out) + :_ this + %+ weld + %+ turn ~(tap in out) + |= o=ship + [%pass /hey %agent [o dap.bowl] %poke %pals-gesture !>([%hey ~])] + %+ turn ~(tap in (~(dif in incoming) out)) + |= i=ship + [%pass /bye %agent [i dap.bowl] %poke %pals-gesture !>([%bye ~])] + == + :: + :: %pals-command: local app control + :: + %pals-command + ?> =(our src):bowl + =+ !<(cmd=command vase) + ?: (~(has in in.cmd) ~.) + ~| [%illegal-empty-list-name in=-.cmd] + !! + ?: =(our.bowl ship.cmd) + [~ this] + :: + =/ known=? (~(has by outgoing) ship.cmd) + =; [yow=? =_outgoing] + ^- (quip card _this) + =? receipts yow + :: if we're sending a new %hey, clear any existing receipt. + :: if we're sending a %bye, no need to track the old receipt. + :: + (~(del by receipts) ship.cmd) + :_ this(outgoing.state outgoing) + ?. yow ~ + :~ =/ =gesture ?-(-.cmd %meet [%hey ~], %part [%bye ~]) + =/ =cage [%pals-gesture !>(gesture)] + [%pass /[-.gesture] %agent [ship.cmd dap.bowl] %poke cage] + :: + =/ =effect ?-(-.cmd %meet [- ship]:cmd, %part [- ship]:cmd) + =/ =cage [%pals-effect !>(effect)] + [%give %fact [/targets]~ cage] + == + :: + ?- -.cmd + %meet + :- !known + %+ ~(put by outgoing) ship.cmd + %- ~(uni in in.cmd) + (~(gut by outgoing) ship.cmd ~) + :: + %part + ?: =(~ in.cmd) + :: remove target entirely + :: + [known (~(del by outgoing) ship.cmd)] + :: remove from specified lists + :: + :- | + =. outgoing + =/ liz=(list @ta) ~(tap in in.cmd) + |- ^+ outgoing + ?~ liz outgoing + $(liz t.liz, outgoing (~(del ju outgoing) ship.cmd i.liz)) + ::NOTE we could account for this above, but +del:ju is just easier there + =? outgoing !(~(has by outgoing) ship.cmd) + (~(put by outgoing) ship.cmd ~) + outgoing + == + :: + :: %pals-gesture: foreign %pals signals + :: + %pals-gesture + ?< =(our src):bowl + =* ship src.bowl + =+ !<(=gesture vase) + =/ [yow=? =_incoming] + =* has (~(has in incoming) ship) + ?- -.gesture + %hey :- !has (~(put in incoming) ship) + %bye :- has (~(del in incoming) ship) + == + :_ this(incoming.state incoming) + ^- (list card) + ?. yow ~ + :* =/ =effect ?-(-.gesture %hey [%near ship], %bye [%away ship]) + =/ =cage [%pals-effect !>(effect)] + [%give %fact [/leeches]~ cage] + :: + ?. .^(? %gu /(scot %p our.bowl)/hark/(scot %da now.bowl)/$) ~ + =/ body + =- [ship+ship - ~] + ?- -.gesture + %hey ' added you as a pal.' + %bye ' no longer considers you a pal.' + == + =/ id (end 7 (shas %pals-notification eny.bowl)) + =/ rope [~ ~ q.byk.bowl /(scot %p ship)/[-.gesture]] + =/ action [%add-yarn & & id rope now.bowl body /pals ~] + =/ =cage [%hark-action !>(action)] + [%pass /hark %agent [our.bowl %hark] %poke cage]~ + == + :: + :: %handle-http-request: incoming from eyre + :: + %handle-http-request + =; out=(quip card _+.state) + [-.out this(+.state +.out)] + %. [bowl !<(order:rudder vase) +.state] + %- (steer:rudder _+.state command) + :^ pages + (point:rudder /[dap.bowl] & ~(key by pages)) + (fours:rudder +.state) + |= cmd=command + ^- $@ brief:rudder + [brief:rudder (list card) _+.state] + =^ caz this + (on-poke %pals-command !>(cmd)) + ['Processed succesfully.' caz +.state] + == +:: +++ on-watch + |= =path + ^- (quip card _this) + ?> =(our.bowl src.bowl) + ?+ path (on-watch:def path) + [%http-response *] [~ this] + :: + [%targets ~] + :_ this + %+ turn ~(tap in ~(key by outgoing)) + |=(=@p [%give %fact ~ %pals-effect !>(`effect`[%meet p])]) + :: + [%leeches ~] + :_ this + %+ turn ~(tap in incoming) + |=(=@p [%give %fact ~ %pals-effect !>(`effect`[%near p])]) + :: + ::TODO consider adding a subscription endpoint that includes tags? + :: shouldn't become too legible to applications though... + == +:: +++ on-agent + |= [=wire =sign:agent:gall] + ^- (quip card _this) + ?+ wire ~&([dap.bowl %strange-wire wire] [~ this]) + [%hark ~] + ?. ?=(%poke-ack -.sign) (on-agent:def wire sign) + ?~ p.sign [~ this] + ((slog 'pals: failed to notify' u.p.sign) [~ this]) + :: + [%bye ~] [~ this] ::TODO also retry if nack? + [%hey ~] + :: for %pals-gesture pokes, record the result + ::TODO should we slowly retry for nacks? + :: + =- [~ this(receipts -)] + ?+ -.sign ~|([%unexpected-agent-sign wire -.sign] !!) + %poke-ack (~(put by receipts) src.bowl ?=(~ p.sign)) + == + == +:: +++ on-arvo + |= [=wire =sign-arvo] + ^- (quip card _this) + ?+ wire ~|([dap.bowl %strange-wire wire] !!) + [%eyre %connect ~] + ?. ?=([%eyre %bound *] sign-arvo) + (on-arvo:def wire sign-arvo) + ~? !accepted.sign-arvo + [dap.bowl 'eyre bind rejected!' binding.sign-arvo] + [~ this] + :: + [%jael %pubs ~] + ?. ?=([%jael %public-keys *] sign-arvo) + (on-arvo:def wire sign-arvo) + =/ who=(unit ship) + =* pkr public-keys-result.sign-arvo + ?+ -.public-keys-result.sign-arvo ~ + %breach `who.pkr + == + ?~ who [~ this] + :_ %_ this + incoming (~(del in incoming) u.who) + receipts (~(del by receipts) u.who) + == + =; caz=(list (unit card)) + (murn caz same) + :~ :: if they liked us, for now that's no longer true + :: + ?. (~(has in incoming) u.who) ~ + =/ =cage [%pals-effect !>(`effect`[%away u.who])] + `[%give %fact [/leeches]~ cage] + :: + :: if we liked them, assume they come back and remind them + :: + ?. (~(has by outgoing) u.who) ~ + =/ =cage [%pals-gesture !>(`gesture`[%hey ~])] + `[%pass /hey %agent [u.who dap.bowl] %poke cage] + == + == +:: +++ on-peek + |= =path + ^- (unit (unit cage)) + ?> =(our src):bowl + |^ ?+ path [~ ~] + [%x ~] ``noun+!>(`records`+.state) + [%y ~] (arc %leeches %targets %mutuals ~) + [%y %leeches ~] (arc ~) + [%y %targets ~] (arc (las targets)) + [%y %mutuals ~] (arc (las mutuals)) + [%x %leeches ~] (alp leeches) + [%x %leeches @ ~] (ask (bind (slaw %p i.t.t.path) (sin leeches))) + [%x %targets ~] (alp targets) + [%x %targets ~ ~] [~ ~] + [%x %targets @ta ~] (alp (lap targets i.t.t.path)) + [%x %targets @ta @ ~] (ask (bind (wat t.t.path) (hal targets))) + [%x %mutuals ~] (alp mutuals) + [%x %mutuals ~ ~] [~ ~] + [%x %mutuals @ta ~] (alp (lap mutuals i.t.t.path)) + [%x %mutuals @ta @ ~] (ask (bind (wat t.t.path) (hal mutuals))) + :: + [%x %json ~] ::NOTE dumb hack, subject to change + =; =json ``json+!>(json) + =, enjs:format + %- pairs + :~ :- 'outgoing' + %- pairs + %+ turn ~(tap by outgoing) + |= [=^ship lists=(set @ta)] + :- (rsh 3 (scot %p ship)) + %- pairs + :~ 'lists'^a+(turn ~(tap in lists) (lead %s)) + 'ack'^(fall (bind (~(get by receipts) ship) (lead %b)) ~) + == + :: + :- 'incoming' + %- pairs + %+ turn ~(tap in incoming) + |=(=^^ship [(rsh 3 (scot %p ship)) b+&]) + == + == + :: scry results + ++ arc |= l=(list @ta) ``noun+!>(`arch`~^(malt (turn l (late ~)))) + ++ alp |= s=(set @p) ``noun+!>(s) + ++ alf |= f=? ``noun+!>(f) + ++ ask |= u=(unit ?) ?^(u (alf u.u) [~ ~]) + :: data wrestling + ++ wat |=([l=@ta p=@ta ~] ?~(p=(slaw %p p) ~ (some [l u.p]))) + ++ nab ~(got by outgoing) + ++ las |=(s=(set @p) (zing (turn (sit s) |=(=@p (sit (nab p)))))) + ++ lap |=([s=(set @p) l=@ta] (ski s |=(=@p ((sin (nab p)) l)))) + ++ hal |=(s=(set @p) |=([l=@ta =@p] ((sin ?~(l s (lap s l))) p))) + :: set shorthands + ++ sin |*(s=(set) ~(has in s)) + ++ sit |*(s=(set) ~(tap in s)) + ++ ski |*([s=(set) f=$-(* ?)] (sy (skim (sit s) f))) + :: pals + ++ leeches incoming + ++ targets ~(key by outgoing) + ++ mutuals (~(int in targets) leeches) + -- +:: +++ on-leave on-leave:def +++ on-fail on-fail:def +-- diff --git a/desk/app/polls.hoon b/desk/app/polls.hoon new file mode 100644 index 0000000..433de58 --- /dev/null +++ b/desk/app/polls.hoon @@ -0,0 +1,358 @@ +/- *polls +/+ dbug +|% ++$ versioned-state + $% state-0 + == ++$ state-0 + $: %0 + polls=(map pid poll) + == +:: ++$ card card:agent:gall +:: +-- +%- agent:dbug +=| versioned-state +=* state - +^- agent:gall +=< +|_ =bowl:gall ++* this . + hd ~(. +> bowl) +++ on-fail |~(* `this) +++ on-leave |~(* `this) +:: +++ on-init +:_ this `this +++ on-save !>(state) +++ on-load +|= old-state=vase +^- (quip card _this) +=/ prev !<(versioned-state old-state) +:- ~ +%= this state prev == +++ on-agent +|= [=wire =sign:agent:gall] +^- (quip card _this) +|^ +?: ?=([%tracking-polls @ ~] wire) +?: ?=(%kick -.sign) +=/ id (slaw %ud i.t.wire) +?~ id `this +=/ pol (~(get by polls) [src.bowl u.id]) +?~ pol `this +=/ exp expiry.u.pol +?: (gth now.bowl exp) `this +:_ this (track-card:hd [src.bowl u.id])^~ +?. ?=(%fact -.sign) `this +(handle-update (update +.q.cage.sign)) +?. ?=([%poll-watch @ ~] wire) `this +?: ?=(%kick -.sign) :_ this :_ ~ watch-card:hd +?. ?=(%fact -.sign) `this +=/ u=pull-agent:comms (pull-agent:comms +.q.cage.sign) +?. ?=(%post -.u) `this +?. ?=(%poll +<.u) `this +(handle-update +>.u) +++ handle-update +|= u=update +^- (quip card _this) +:_ %= this state +?+ -.u state +%new-poll (save-new-poll:hd +.u) +%ded-poll (save-del-poll:hd p.u) +%old-poll (handle-poll-update +.u) +== == +:_ ~ (ui-card:hd u) +++ handle-poll-update +|= [p=poll u=upd] +%= state polls +(~(put by polls) [host.p time.p] p) +== +-- +++ on-poke +|= =cage +^- (quip card _this) +|^ +?+ p.cage `this +%trill (handle-ui !<(action:ui q.cage)) +%noun (poke-noun !<(* q.cage)) +== +++ poke-noun +|= arg=* +^- (quip card _this) +?: ?=([%cli *] arg) +(handle-terminal +.arg) +(handle-poke arg) +++ handle-terminal +|= arg=* +^- (quip card _this) +?. .=(src.bowl our.bowl) `this +?+ arg `this +[%new @] `this +== +++ handle-poke +|= arg=* +^- (quip card _this) +=/ a=action (action arg) +?- -.a +%vote (handle-vote +.a) +%peek (handle-peek +.a) +%res (handle-res +.a) +== +++ handle-res +|= [=pid pr=peek-res] +?. ?=(%peek-ok -.pr) :_ this :_ ~ +(ui-card:hd [%peek-res pid pr]) +:- :~ +(ui-card:hd [%peek-res pid pr]) +(track-card:hd pid) +== +%= this state +=/ nps (~(put by polls) [host.poll.pr time.poll.pr] poll.pr) +state(polls nps) +== +++ handle-peek +|= =id +=/ pid [our.bowl id] +:_ this :_ ~ +=/ pol (~(get by polls) pid) +:: TODO check lock +=/ pr=peek-res +?~ pol [%no-poll ~] :- %peek-ok +?. private.u.pol u.pol +u.pol(votes (mask-votes votes.u.pol)) :: TODO check this when it moves around +(peek-res-card:hd src.bowl pid pr) +++ is-valid +|= [s=signature hsh=@uvH comment=@t] ^- ? +?: %+ gte (lent (trip comment)) 100 .n +?. (is-signature-valid:signatures our.bowl s hsh now.bowl) +~& >>> fraudulent-vote-by=src.bowl +.n +?. .=(src.bowl q.s) +~& >>> impersonation-attempt-by=src.bowl +.n .y +++ handle-vote +|= [=pid option=@ s=signature comment=@t] +^- (quip card _this) +?. (is-valid s (sham [pid option]) comment) `this +=^ cards state (save-new-vote:hd pid option s comment) +[cards this] +++ handle-ui +|= u=action:ui +^- (quip card _this) +?. ?=(%poll -.u) `this +=/ a=ui-action +.u +?. .=(our.bowl src.bowl) `this +?- -.a +:: our polls +%propose (propose +.a) +%cancel (cancel +.a) +%change-expiry (change-expiry +.a) +:: other people's +%vote (go-vote +.a) +%peek (peek +.a) +== +++ propose +|= [id=@ text=@t expiry=@da options=(list @t) hidden=? private=? exc=?] +^- (quip card _this) +=/ hid ?: hidden (some eny.bowl) ~ +=/ =pid [our.bowl id] +=/ =poll (new-poll pid text expiry options hid private exc) +:_ this(state (save-new-poll:hd poll)) +:: mask the entropy when sending it to people? +=/ =update [%new-poll poll] +?. ?=(%hid -.votes.poll) +(spread-cards:hd update) +:- (wipe-eny-card:hd id expiry) + (spread-cards:hd update) +++ cancel +|= =id +^- (quip card _this) +:_ this(state (save-del-poll:hd [our.bowl id])) +=/ update [%ded-poll [our.bowl id]] +(spread-cards:hd update) +++ change-expiry +|= [=id expiry=@da] +^- (quip card _this) +=/ pol (~(get by polls) [our.bowl id]) +?~ pol `this +=^ np state (save-exp-change u.pol expiry) +:_ this +=/ update [%old-poll np %expiry-changed expiry] +(spread-cards:hd update) +:: +++ go-vote +|= [=pid option=@ comment=@t] +^- (quip card _this) +:: we sign and poke the guy +:_ this :_ ~ +=/ s=signature (sign:signatures our.bowl now.bowl (sham [pid option])) +=/ vot [option s comment] +=/ =action [%vote pid vot] +(action-card:hd -.pid action) +++ peek +|= =pid +=/ a=action [%peek +.pid] +:_ this +(action-card:hd -.pid a)^~ +-- +++ on-watch +|= =(pole knot) +?+ pole `this +[%ui ~] ?> .=(our.bowl src.bowl) `this +[%poll-sub id=@ ~] `this +== +++ on-peek +|= p=(pole knot) ^- (unit (unit cage)) +|^ +?+ p ~ +[%x %j rest=*] +``[%trill !>([%scry %poll (scry rest.p)])] +[%x %n rest=*] +``[%noun !>((scry rest.p))] +== +++ scry +|= =(pole knot) ^- poll-scry:scry:ui +?+ pole [%ng ~] +[%poll ship=@ id=@ ~] +=/ ship (slav %p ship.pole) +=/ id (rush id.pole dem) +?~ id [%ng ~] +=/ p (~(get by polls) [ship `@da`u.id]) +?~ p [%ng ~] +[%poll u.p] +[%done ~] +=/ d %+ roll ~(tap by polls) +|= [i=[=pid =poll] acc=(set poll)] +?: (gte now.bowl expiry.poll.i) acc +(~(put in acc) poll.i) +[%done d] +[%cur ~] +=/ d %+ roll ~(tap by polls) +|= [i=[=pid =poll] acc=(set poll)] +?. (gte now.bowl expiry.poll.i) acc +(~(put in acc) poll.i) +[%cur d] +== +-- +++ on-arvo |~(* `this) +-- +|_ =bowl:gall +:::: savers +++ save-new-poll +|= =poll ^- _state +=/ nps (~(put by polls) [host.poll time.poll] poll) +state(polls nps) +++ save-del-poll +|= =pid ^- _state +=/ np (~(del by polls) pid) +state(polls np) +++ save-exp-change +|= [p=poll expiry=@da] ^- [poll _state] +=/ np p(expiry expiry) +=/ nps (~(put by polls) [host.p time.p] np) +:- np +state(polls nps) +++ handle-exc-vote +|= [vot=vote v=excl] ^- [upd excl] +=/ crr (~(get by p.v) q.p.q.vot) +?~ crr +:_ [%exc (~(put by p.v) q.p.q.vot vot)] + [%new-vote vot] +?: .=(p.u.crr p.vot) +:_ [%exc (~(del by p.v) q.p.q.vot)] + [%vote-canceled q.p.q.vot p.vot] +:_ [%exc (~(put by p.v) q.p.q.vot vot)] + [%vote-changed q.p.q.vot p.u.crr p.vot] +++ handle-inc-vote +|= [vot=vote v=incl] ^- [upd incl] +=/ crr (~(get by p.v) p.vot) +?~ crr +=/ b *(map @p comv) +=/ nc (~(put by b) q.p.q.vot q.vot) +:- [%new-vote vot] +[%inc (~(put by p.v) p.vot nc)] +:: +?: (~(has by u.crr) q.p.q.vot) +=/ nc (~(del by u.crr) q.p.q.vot) +:- +[%vote-canceled q.p.q.vot p.vot] +[%inc (~(put by p.v) p.vot nc)] +:: +=/ nc (~(put by u.crr) q.p.q.vot q.vot) +:- [%new-vote vot] +[%inc (~(put by p.v) p.vot nc)] +++ handle-hid-vote +|= [vot=vote v=hidd] ^- [upd hidd] +:: we hash the vote first +=/ hsh (hash-vote q.p.q.vot eny.v) +:: find +=/ same-votes (~(get by p.v) p.vot) +=/ nsv ?~ same-votes (sy ~[hsh]) (~(put in u.same-votes) hsh) +:: check our votes at present. could be many (if inc) +=/ zji=(set @) %+ roll ~(tap by p.v) +|= [i=[o=@ud s=(set @uw)] acc=(set @)] +?: (~(has in s.i) hsh) (~(put in acc) o.i) acc +:: if current vote is same as before, means cancelation +?: (~(has in zji) p.vot) +=/ dlt (~(del in nsv) hsh) +=/ nm (~(put by p.v) p.vot dlt) +:_ v(p nm) [%vote-canceled q.p.q.vot p.vot] +?: exc.v +:: exclusive and has previous post, must delete the previous one first +=/ ov -:~(tap in zji) +=/ current-set (~(got by p.v) ov) :: mmm +=/ ncr (~(del in current-set) hsh) +=+ (~(put by p.v) ov ncr) +=/ nm (~(put by -) p.vot nsv) +:_ v(p nm) +[%vote-changed q.p.q.vot ov p.vot] +:: inclusive and has previous post +=/ nm (~(put by p.v) p.vot nsv) +:_ v(p nm) +[%new-vote vot] +++ save-new-vote +|= [=pid vot=vote] ^- [(list card) _state] +=/ pol=(unit poll) (~(get by polls) pid) +?~ pol `state +?: (gth now.bowl expiry.u.pol) `state +=/ v=votes votes.u.pol +=^ u=upd v +?- -.v +%exc (handle-exc-vote vot v) +%inc (handle-inc-vote vot v) +%hid (handle-hid-vote vot v) +== +=/ np=poll u.pol(votes v) +:- (spread-cards [%old-poll np u]) +state(polls (~(put by polls) pid np)) +:: cards +++ watch-card +[%pass /poll-watch/(scot %p our.bowl) %agent [our.bowl %feed-push-hook] %watch /trill-sub] +++ track-card +|= =pid +[%pass /tracking-polls/(scot %ud id.pid) %agent [ship.pid %trill-polls] %watch /poll-sub/(scot %ud id.pid)] +++ peek-res-card +|= [target=@p =pid p=peek-res] ^- card +[%pass /poll/peek-res %agent [target %trill-polls] %poke [%noun !>([%res pid p])]] +++ action-card +|= [target=@p =action] ^- card +[%pass [%poll -.action ~] %agent [target %trill-polls] %poke [%noun !>(action)]] +++ spread-cards +|= =update ^- (list card) +:~ (spread-card update) + (ui-card update) + (fact-card update) +== +++ fact-card +|= u=update ^- card +=/ id ?- -.u +%new-poll time.poll.u +%old-poll time.p.u +%ded-poll id.p.u +%peek-res id.p.u +== +[%give %fact ~[/poll-sub/(scot %ud id)] [%noun !>(u)]] +-- + diff --git a/desk/desk.bill b/desk/desk.bill new file mode 100644 index 0000000..74192b9 --- /dev/null +++ b/desk/desk.bill @@ -0,0 +1,2 @@ +:~ %boke +== diff --git a/desk/desk.ship b/desk/desk.ship new file mode 100644 index 0000000..1393457 --- /dev/null +++ b/desk/desk.ship @@ -0,0 +1 @@ +~zod
\ No newline at end of file diff --git a/desk/lib/boke.hoon b/desk/lib/boke.hoon new file mode 100644 index 0000000..aecfabb --- /dev/null +++ b/desk/lib/boke.hoon @@ -0,0 +1,207 @@ +/- *boke, tp=trill-post, c=tlon-channels +/+ sr=sortug, kaji, sigil=sigil-sigil, plib=trill-utils, ui=trill-ui, const=constants, kaji, cjk, wall +|% +:: state data structures +++ get-name +|= p=@p ^- tape +?: (lth p (bex 64)) + ?: (is-admin p) "Spandrell" + (scow %p p) +=/ oldie (sub p (bex 64)) +?: ((sane %t) oldie) (trip oldie) +"anon" + + + :: +++ tags-by-size +|= [tt=tags-table who=@p] ^- (list [@t count=@ud]) + =/ wal ~(. wall who) + =/ l %+ roll ~(tap by tt) |= [[tag=@t p=pidmap] acc=(list [@t @ud])] + ?. (tag-filter:wal tag) acc :_ acc + :- tag (wyt:porm:tp p) + %+ sort l |= [a=[tag=@t c=@ud] b=[tag=@t c=@ud]] + (gte c.a c.b) + +++ tags-by-date +|= [tt=tags-table who=@p] ^- (list [@t pidmap]) + =/ wal ~(. wall who) + =/ l %+ skim ~(tap by tt) |= [tag=@t *] (tag-filter:wal tag) + %+ sort l |= $: + a=[tag=@t pids=pidmap] + b=[tag=@t pids=pidmap] == + =/ first-a (pry:porm:tp pids.a) + =/ first-b (pry:porm:tp pids.b) + ?~ first-a .n + ?~ first-b .y + =/ id-a=@da +>.u.first-a + =/ id-b=@da +>.u.first-b + (gth id-a id-b) + + +++ is-admin +|= p=@p ^- ? +?| .=(p ~docteg-mothep) + .=((^sein:title p) ~docteg-mothep) +== +++ is-subscribed +|= p=@p ^- ? +?| (is-admin p) + (~(has in subscribers:const) p) +== +++ is-blog +|= t=thread:tp ^- ? + (~(has in tags.t) 'blog') +:: +++ get-path +|= [pat=path blog-view=? is-blog=?] ^- path +?: is-blog + ?: blog-view pat (weld /board/blog pat) + ?: blog-view (weld /blog/b pat) (weld /board pat) + +++ board-path +|= =thread:tp ^- path + ?. (is-blog thread) (weld /board path.thread) + (weld /board/blog path.thread) +++ blog-path +|= =thread:tp ^- path + ?: (is-blog thread) path.thread + (weld /blog/b path.thread) + +++ naive-board-path +|= [title=@t tags=(set @t)] ^- [@t @t] + =/ boards ~(key by categories:const) + =/ int (~(int in tags) boards) + =/ lint ~(tap in int) + =/ first-tag ?~ lint 'public' i.lint + =/ kebab (crip (enkebab3:string:sr title)) + [first-tag kebab] + +++ find-board-path +|= [pm=pathmap =post:tp] ^- tape + =/ max 5 + =/ [tag=@t kebab=@t] (naive-board-path title.post tags.post) + =/ pat=path [tag kebab ~] + =/ ok=? + =/ has (~(get by pm) pat) ?~ has .n + .=(u.has [author.post id.post]) + ?: ok (trip kebab) + =/ num 2 + |- + ?: .=(num max) "esc/{(enc:kaji [author.post id.post])}" + ~& incrementing-find-board-path=[title.post num] + =/ nclean (enkebab2:string:sr (cat 3 title.post (cat 3 '-' (scot %ud num)))) + =/ npat=path ~[(crip nclean)] + =/ ok=? + =/ has (~(get by pm) npat) ?~ has .n + .=(u.has [author.post id.post]) + ?: ok nclean + $(num +(num)) + +++ make-board-path +|= [pm=pathmap title=@t tags=(set @t)] ^- path + =/ [tag=@t kebab=@t] (naive-board-path title tags) + =/ pat=path [tag kebab ~] + =/ has (~(get by pm) pat) + ?~ has pat + =/ num 2 + |- + =/ nkebab (cat 3 kebab (cat 3 '-' (scot %ud num))) + =/ npat=path [tag nkebab ~] + =/ has (~(get by pm) npat) + ?~ has npat + $(num +(num)) + +:: ++ board-path +:: |= =post:tp ^- tape +:: =/ uid (scow:parsing:sr %uw (jam [author.post id.post])) +:: =/ title (enkebab2:string:sr title.post) +:: "{uid}--{title}" +++ title-to-path + |= [title=@t date=@da] ^- path + =/ pat1 (date-to-path:string:sr date) + =/ pat2 (enpath:string:sr title) + =/ pat-string %^ foldi:sr pat2 '' |= [i=@ud it=@t acc=@t] + =/ s=@t ?: .=(i (dec (lent pat2))) it + (rap 3 ~[it '-']) + =/ a=(list @t) ~[acc s] + (rap 3 a) + (weld pat1 ~[pat-string]) + +++ make-blogpost-path + |= [tim=@da t=@t] ^- path + =/ dat=path (date-to-path:string:sr tim) + (snoc dat (crip (enkebab2:string:sr t))) +:: +++ edit-post + |= [p=post:tp ncontents=content-list:tp tags=(set @t) now=@da] + ^- post:tp + =/ contents (put:corm:tp contents.p now ncontents) + %= p + contents contents + tags tags + == +++ build-thread +|= [title=@t =post:tp paths=pathmap is-blog=?] ^- thread:tp + =/ pat ?: is-blog + (make-blogpost-path id.post title) + (make-board-path paths title tags.post) + =/ snip-size ?: is-blog 500 200 + =/ snip (abbreviate-post:plib contents.post snip-size) + =| t=thread:tp + %= t + pid [author.post id.post] + title title + path pat + tags tags.post + snip snip + == +++ build-post + |= [contents=content-list:tp tags=(set @t) =pid:tp] + ^- post:tp + =/ contents (gas:corm:tp *content-map:tp [id.pid contents]~) + =/ p *post:tp + %= p + id id.pid + thread pid + author ship.pid + contents contents + tags tags + == +++ set-parents + |= [p=post:tp thread=pid:tp parent=pid:tp] + %= p + parent (some parent) + thread thread + == +++ random-avatar +|= hash=@ ^- tape +=/ top (dec (lent soyjaks:const)) +=/ ind (mod hash top) +=/ file (snag ind soyjaks:const) +"{s3.const}/soyjaks/{file}" + +++ is-anon +|= p=@p ^- ? +?= %pawn (clan:title p) +:: Fetch posts by tag or board + +++ post-date-ago +|= [d=@da now=@da length=?(%tam %yau)] ^- tape +=/ diff=@dr (sub now d) +?: (lth diff ~m1) %+ weld (scow:parsing:sr %ud (div diff ~s1)) +?: ?=(%tam length) "m" " seconds" +?: (lth diff ~h1) %+ weld (scow:parsing:sr %ud (div diff ~m1)) +?: ?=(%tam length) "m" " minutes" +?: (lth diff ~d1) %+ weld (scow:parsing:sr %ud (div diff ~h1)) +?: ?=(%tam length) "h" " hours" +?: (lth diff ~d30) %+ weld (scow:parsing:sr %ud (div diff ~d1)) +?: ?=(%tam length) "d" " days" +?: (lth diff ~d365) %+ weld (scow:parsing:sr %ud (div diff ~d30)) +?: ?=(%tam length) "mo" " months" + %+ weld (scow:parsing:sr %ud (div diff ~d365)) +?: ?=(%tam length) "y" " years" +++ last-reply +|= p=full-node:tp ^- (unit pid:tp) + =/ pry (pry:form:tp children.p) + ?~ pry ~ `key.u.pry +-- diff --git a/desk/lib/chat.hoon b/desk/lib/chat.hoon new file mode 100644 index 0000000..9390c35 --- /dev/null +++ b/desk/lib/chat.hoon @@ -0,0 +1,88 @@ +/- chat +|% ++$ eyre-id @ta ++$ card card:agent:gall +:: cards +++ watch-chat + |= [our=ship =term] + ^- card + :* %pass + /listen/[term] + %agent + [our %chat] + %watch + /chat/(scot %p our)/[term]/ui/writs + == +++ leave-chat + |= [our=ship =term] + ^- card + [%pass /listen/[term] %agent [our %chat] %leave ~] +++ handle-msg + |= [=wire =sign:agent:gall] + ^- (quip card _this) + ?. ?=(%fact -.sign) `this + =* mark p.cage.sign + =* vase q.cage.sign + ?. ?=(%writ-diff p.cage.sign) `this + =^ cards state + (handle-chat-update:do source !<(diff:writs:chat vase)) + [cards this] + == +== +++ handle-chat-update +|= =diff:writs:chat ^- (list card) +:: TODO other stuff +?. ?=(%add -.q.diff) `this +(send-to-viewers p.q.diff) +++ send-to-viewers +|= =memo:chat +=/ ids=(set eyre-id) (sy ~['lol']) +:_ ~ +:* %give + %fact + :: + %+ turn ~(tap in ids) + |= =eyre-id + /http-response/[eyre-id] + :: + %http-response-data + !> ^- (unit octs) + %- some + (make-stream-data (scot %uw (jam memo))) +== ++$ channel-event + $% $>(%poke-ack sign:agent:gall) + $>(%watch-ack sign:agent:gall) + $>(%kick sign:agent:gall) + [%fact =desk =mark =noun] + == +++ channel-event-to-tape +|= [request-id=@ud =channel-event] +=+ [request-id channel-event] +(scow %uw (jam -)) +++ make-stream-data + |= =cord + ^- octs + %- as-octs:mimes:html + (rap 3 'data:' cord '\0a\0a' ~) + +:: user management + +:: ++ ban-comet +:: |= who=ship +:: ^- (quip card _state) +:: :- ~ +:: %_ state +:: guests (~(del by guests) who) +:: banned (~(uni in banned) (~(get ju guests) who)) +:: == +:: :: +:: ++ unban-ip +:: |= =address:eyre +:: ^- (quip card _state) +:: :- ~ +:: %_ state +:: banned (~(del in banned) address.action) +:: == + +--
\ No newline at end of file diff --git a/desk/lib/cjk.hoon b/desk/lib/cjk.hoon new file mode 100644 index 0000000..2d34896 --- /dev/null +++ b/desk/lib/cjk.hoon @@ -0,0 +1,107 @@ +/+ sr=sortug +/* raw %json /data/unihan/json +|% +++ generic +|= jon=json + =, dejs:format + ?: ?=(%n -.jon) (ni jon) + ?: ?=(%s -.jon) (so jon) + ?: ?=(%o -.jon) ((om generic) jon) + ?: ?=(%a -.jon) ((ar generic) jon) :: only question here is whether to do ar or as + '' +++ dejs +=, dejs:format + %- om |= jon=json + ?. ?=(%o -.jon) !! :: mmm + (~(run by p.jon) generic) + :: ?: .= k 'kAccountingNumeric' (ni v) + :: ?: .= k 'kGB0' (ni v) + :: ?: .= k 'kGB1' (ni v) + :: ?: .= k 'kGradeLevel' (ni v) + :: ?: .= k 'kFrequency' (so v) + :: ?: .= k 'kBigFive' (so v) + :: ?: .= k 'kCCCII' (so v) + :: ?: .= k 'kCNS1986' (so v) + :: ?: .= k 'kCNS1992' (so v) + :: ?: .= k 'kCangjie' (so v) + :: ?: .= k 'kCowles' (so v) + :: ?: .= k 'kDaeJaweon' (so v) + :: ?: .= k 'kDefinition' (so v) + :: ?: .= k 'kEACC' (so v) + :: ?: .= k 'kFenn' (so v) + :: ?: .= k 'kFennIndex' (so v) + :: ?: .= k 'kFourCornerCode' (so v) + :: ?: .= k 'kHKGlyph' (so v) + :: ?: .= k 'kHanYu' (so v) + :: ?: .= k 'kIICore' (so v) + :: ?: .= k 'kIRGDaeJaweon' (so v) + :: ?: .= k 'kIRGDaiKanwaZiten' (so v) + :: ?: .= k 'kIRGHanyuDaZidian' (so v) + :: ?: .= k 'kIRGKangXi' (so v) + :: ?: .= k 'kIRG_GSource' (so v) + :: ?: .= k 'kIRG_HSource' (so v) + :: ?: .= k 'kIRG_JSource' (so v) + :: ?: .= k 'kIRG_KPSource' (so v) + :: ?: .= k 'kIRG_KSource' (so v) + :: ?: .= k 'kIRG_TSource' (so v) + :: ?: .= k 'kJis0' (so v) + :: ?: .= k 'kKPS0' (so v) + :: ?: .= k 'kKSC0' (so v) + :: ?: .= k 'kKangXi' (so v) + :: ?: .= k 'kKorean' (so v) + :: ?: .= k 'kKoreanName' (so v) + :: ?: .= k 'kMainlandTelegraph' (so v) + :: ?: .= k 'kMandarin' (so v) + :: ?: .= k 'kMatthews' (so v) + :: ?: .= k 'kMeyerWempe' (so v) + :: ?: .= k 'kMorohashi' (so v) + :: ?: .= k 'kPhonetic' (so v) + :: ?: .= k 'kRSAdobe_Japan1_6' (so v) + :: ?: .= k 'kRSKangXi' (so v) + :: ?: .= k 'kRSUnicode' (so v) + :: ?: .= k 'kSBGY' (so v) + :: ?: .= k 'kSemanticVariant' (so v) + :: ?: .= k 'kSpecializedSemanticVariant' (so v) + :: ?: .= k 'kTGH' (so v) + :: ?: .= k 'kXHC1983' (so v) + :: ?: .= k 'kXerox' (so v) + :: ?: .= k 'kZVariant' (so v) + :: ?: .= k 'kCantonese' ((as so) v) + :: ?: .= k 'kHangul' ((om so) v) + :: ?: .= k 'kHanyuPinyin' ((om (as so)) v) + :: ?: .= k 'kJapaneseKun' ((as so) v) + :: ?: .= k 'kJapaneseOn' ((as so) v) + :: ?: .= k 'kLau' ((as ni) v) + :: ?: .= k 'kNelson' ((as ni) v) + :: ?: .= k 'kTaiwanTelegraph' ((as ni) v) + :: ?: .= k 'kTotalStrokes' ((as ni) v) '' +++ get-map + (dejs raw) +++ is-cjk +|= char=@t ^- ? + =/ start 0x4e00 + =/ end 0x9fff + =/ codepoint (taft char) + ?& (gte codepoint start) (lte codepoint end) == + +++ has +|= t=tape ^- ? + |- + ?~ t .n + ?: .=(3 (met 3 i.t)) .y + $(t t.t) +++ romanize +|= t=@t ^- tape + =/ dict get-map + =/ size (div (met 3 t) 3) + =/ l (rip [3 size] t) + |- + ?~ l ~ + =/ data (~(get by dict) i.l) + ?~ data $(l t.l) + =/ mand (~(get by u.data) 'kMandarin') + ?~ mand $(l t.l) + =/ cord ((soft @t) u.mand) + ?~ cord $(l t.l) + :- u.cord $(l t.l) +-- diff --git a/desk/lib/constants.hoon b/desk/lib/constants.hoon new file mode 100644 index 0000000..ecadba9 --- /dev/null +++ b/desk/lib/constants.hoon @@ -0,0 +1,164 @@ +|% +++ board-page-size 20 +++ thread-page-size 20 +++ search-page-size 30 +++ blog-page-size 20 +++ tianming-users ^- (list @p) +:~ ~locpyl-tidnyd + ~torwes-minput + ~bacrul-ridbes +== +++ subscribers ^- (set @p) +%- silt +:~ ~polwex +== + +++ vip +:~ ~docteg-mothep + ~polwex + ~locpyl-tidnyd + ~wispem-wantex + ~sorwet + ~tiller-tolbus +== +++ categories +^- (map term (set cord)) +%- malt ^- (list [term (set cord)]) :~ +:- %theory +%- silt ~['theory' 'philosophy' 'deep'] +:- %orient +%- silt ~['orient' 'china' 'japan' 'korea' 'vietnam' 'thailand'] +:- %politics +%- silt ~['politics' 'pol'] +:- %food +%- silt ~['food' 'cooking' 'recipes' 'eating' 'restaurants'] +:- %business +%- silt ~['business' 'entrepreneurship' 'hustle'] +:- %money +%- silt ~['money' 'banking' 'finance' 'stocks' 'investment' 'bonds'] +:- %crypto +%- silt ~['crypto' 'bitcoin' 'ethereum' 'eth' 'btc'] +:- %travel +%- silt ~['travel' 'trips' 'abroad'] +:- %health +%- silt ~['health' 'medicine' 'pharma'] +:- %family +%- silt ~['family' 'kids' 'childcare' 'education'] +:- %music +%- silt ~['music'] +:- %film +%- silt ~['film' 'movies' 'tv' 'shows'] +:- %books +%- silt ~['books' 'literature' 'fiction' 'non-fiction'] +:- %religion +%- silt ~['religion' 'god' 'faith'] +:- %gmi +%- silt ~['gmi' 'nice' 'whitepill' 'cozy'] +:- %ngmi +%- silt ~['ngmi' 'cringe' 'libs' 'blackpill'] +:- %physiognomy +%- silt ~['physiognomy' 'hbd' 'ethnic' 'anthropology' 'genetics'] +:- %tech +%- silt ~['tech' 'technology'] +:- %science +%- silt ~['science' 'chemistry' 'physics'] +:- %computing +%- silt ~['computing' 'computers' 'programming' 'coding'] +:- %ai +%- silt ~['ai' 'openai' 'gpt' 'ml' 'llm' 'image-generation' 'midjourney'] +:- %urbit +%- silt ~['urbit' 'tlon' 'sortug'] +:- %art +%- silt ~['art' 'arts' 'beauty' 'beautiful'] +:- %humor +%- silt ~['humor' 'funny' 'jokes'] +:- %links +%- silt ~['links'] +:- %sex +%- silt ~['sex' 'women' 'wahmen' 'dating'] +:- %history +%- silt ~['history'] +:- %war +%- silt ~['war' 'military' 'army' 'battle'] +:- %wyb +%- silt ~['wyb'] +:- %vip +%- silt ~['oldtianming' 'vip'] +:- %public ~ +:: :- %oldtianming ~ +== +++ s3 +"https://s3.spandrell.ch/assets" +++ avatars ^- (list tape) +:~ +"Affirmative-Fed-Boi-Chad.png" +"Bashar-Al-Assad-Chad.png" +"Buddhist-Chad.png" +"Chad-No-Nut.png" +"chad.png" +"Crusade-Chad.png" +"Frenchman-Chad.png" +"German-Soldier-Chad.png" +"gigachad.png" +"Hitler-Chad.png" +"Hype-Beast-Chad.png" +"Jew-Chad.png" +"Joker-Chad.png" +"King-Harkinian-Chad.png" +"Military-Chad.png" +"NazBol-Chad.png" +"Nordic-Chad-No-Beard-Black-HEadset.png" +"Portugeuse-Chad.png" +"Red-Headed-Gamer-Chad.png" +"Saudi-Arabian-Chad.png" +"Suited-Chad.png" +"Trump-Chad.png" +"wojak-cry.jpeg" +== +++ soyjaks ^- (list tape) +:~ +"addict.png" +"adulterer.png" +"billions.png" +"bloomer.png" +"chudcry.jpeg" +"chudjak.png" +"chudsmile.png" +"coomer.png" +"crychud.png" +"cuck.png" +"eunuch.png" +"fatjak.png" +"friendzoned.png" +"furry.png" +"gay.png" +"griller.png" +"grinsoy.jpg" +"groomer.png" +"grooomer.png" +"husband.png" +"improover.png" +"incel.png" +"mouthjak.png" +"normal.png" +"partner.png" +"paypig.png" +"pervert.png" +"polygamist.png" +"pua.png" +"pussyhound.png" +"redditjak.png" +"smartjak.jpeg" +"soyjak.png" +"sugardaddy.png" +"tranny.png" +"troon.png" +"twink.png" +"volcel.png" +"weeb.png" +== +++ banned-ships ^- (set @p) +~ +++ banned-ips ^- (set address:eyre) +~ +-- diff --git a/desk/lib/cram.hoon b/desk/lib/cram.hoon new file mode 100644 index 0000000..9081fae --- /dev/null +++ b/desk/lib/cram.hoon @@ -0,0 +1,62 @@ +|% +++ static :: freeze .mdh hoon subset + |= gen=hoon ^- [inf=(map term dime) elm=manx] + ?+ -.gen + =/ gen ~(open ap gen) + ~& >> gen=gen + ?: =(gen ^gen) ~|([%cram-dynamic -.gen] !!) + $(gen gen) + :: + %xray [~ (single (shut gen))] + ^ [(malt (frontmatter p.gen)) (single (shut q.gen))] + == +:: +++ single :: unwrap one-elem marl + |= xml=marl ^- manx + ?: ?=([* ~] xml) i.xml + ~|(%many-elems !!) +:: +++ shut-mart :: xml attrs + |=([n=mane v=(list beer:hoot)] [n (turn v |=(a=beer:hoot ?^(a !! a)))]) +:: +++ shut :: as xml constant + |= gen=hoon ^- marl + ?+ -.gen ~|([%bad-xml -.gen] !!) + %dbug $(gen q.gen) + :: + %xray + [[n.g.p.gen (turn a.g.p.gen shut-mart)] $(gen [%mcts c.p.gen])]~ + :: + %mcts + ?~ p.gen ~ + =- (weld - $(p.gen t.p.gen)) + ?^ -.i.p.gen $(gen [%xray i.p.gen]) + ~| [%shut-tuna -.i.p.gen] + ?+ -.i.p.gen !! + %manx ?>(?=(%xray -.p.i.p.gen) $(gen p.i.p.gen)) + %marl ?>(?=(%mcts -.p.i.p.gen) $(gen p.i.p.gen)) + == + == +:: +:: +++ frontmatter :: parse ~[[%foo 1] [%bar ~s2]] + |= gen=hoon ^- (list [term dime]) + ?: ?=([%bust %null] gen) ~ + ?: ?=(%dbug -.gen) $(gen q.gen) + ?. ?=(%clsg -.gen) ~|([%bad-frontmatter -.gen] !!) + %+ turn p.gen + |= gen=hoon + ?. ?=(^ -.gen) + =/ gen ~(open ap gen) + ?: =(gen ^gen) ~|([%bad-frontmatter-elem -.gen] !!) + $(gen gen) + =/ hed (as-dime p.gen) + ?. =(%tas p.hed) ~|([%bad-frontmatter-key-type p.hed] !!) + [q.hed (as-dime q.gen)] +:: +++ as-dime :: %foo ~.foo 0vbar etc + |= gen=hoon ^- dime + ?: ?=(%dbug -.gen) $(gen q.gen) + ?. ?=([?(%rock %sand) @ @] gen) ~|([%bad-literal gen] !!) + +.gen +-- diff --git a/desk/lib/dbug.hoon b/desk/lib/dbug.hoon new file mode 100644 index 0000000..ce98619 --- /dev/null +++ b/desk/lib/dbug.hoon @@ -0,0 +1,155 @@ +:: dbug: agent wrapper for generic debugging tools +:: +:: usage: %-(agent:dbug your-agent) +:: +|% ++$ poke + $% [%bowl ~] + [%state grab=cord] + [%incoming =about] + [%outgoing =about] + == +:: ++$ about + $@ ~ + $% [%ship =ship] + [%path =path] + [%wire =wire] + [%term =term] + == +:: +++ agent + |= =agent:gall + ^- agent:gall + !. + |_ =bowl:gall + +* this . + ag ~(. agent bowl) + :: + ++ on-poke + |= [=mark =vase] + ^- (quip card:agent:gall agent:gall) + ?. ?=(%dbug mark) + =^ cards agent (on-poke:ag mark vase) + [cards this] + =/ dbug + !<(poke vase) + =; =tang + ((%*(. slog pri 1) tang) [~ this]) + ?- -.dbug + %bowl [(sell !>(bowl))]~ + :: + %state + =? grab.dbug =('' grab.dbug) '-' + =; product=^vase + [(sell product)]~ + =/ state=^vase + :: if the underlying app has implemented a /dbug/state scry endpoint, + :: use that vase in place of +on-save's. + :: + =/ result=(each ^vase tang) + (mule |.(q:(need (need (on-peek:ag /x/dbug/state))))) + ?:(?=(%& -.result) p.result on-save:ag) + %+ slap + (slop state !>([bowl=bowl ..zuse])) + (ream grab.dbug) + :: + %incoming + =; =tang + ?^ tang tang + [%leaf "no matching subscriptions"]~ + %+ murn + %+ sort ~(tap by sup.bowl) + |= [[* a=[=ship =path]] [* b=[=ship =path]]] + (aor [path ship]:a [path ship]:b) + |= [=duct [=ship =path]] + ^- (unit tank) + =; relevant=? + ?. relevant ~ + `>[path=path from=ship duct=duct]< + ?: ?=(~ about.dbug) & + ?- -.about.dbug + %ship =(ship ship.about.dbug) + %path ?=(^ (find path.about.dbug path)) + %wire %+ lien duct + |=(=wire ?=(^ (find wire.about.dbug wire))) + %term !! + == + :: + %outgoing + =; =tang + ?^ tang tang + [%leaf "no matching subscriptions"]~ + %+ murn + %+ sort ~(tap by wex.bowl) + |= [[[a=wire *] *] [[b=wire *] *]] + (aor a b) + |= [[=wire =ship =term] [acked=? =path]] + ^- (unit tank) + =; relevant=? + ?. relevant ~ + `>[wire=wire agnt=[ship term] path=path ackd=acked]< + ?: ?=(~ about.dbug) & + ?- -.about.dbug + %ship =(ship ship.about.dbug) + %path ?=(^ (find path.about.dbug path)) + %wire ?=(^ (find wire.about.dbug wire)) + %term =(term term.about.dbug) + == + == + :: + ++ on-peek + |= =path + ^- (unit (unit cage)) + ?. ?=([@ %dbug *] path) + (on-peek:ag path) + ?+ path [~ ~] + [%u %dbug ~] ``noun+!>(&) + [%x %dbug %state ~] ``noun+!>(on-save:ag) + [%x %dbug %subscriptions ~] ``noun+!>([wex sup]:bowl) + == + :: + ++ on-init + ^- (quip card:agent:gall agent:gall) + =^ cards agent on-init:ag + [cards this] + :: + ++ on-save on-save:ag + :: + ++ on-load + |= old-state=vase + ^- (quip card:agent:gall agent:gall) + =^ cards agent (on-load:ag old-state) + [cards this] + :: + ++ on-watch + |= =path + ^- (quip card:agent:gall agent:gall) + =^ cards agent (on-watch:ag path) + [cards this] + :: + ++ on-leave + |= =path + ^- (quip card:agent:gall agent:gall) + =^ cards agent (on-leave:ag path) + [cards this] + :: + ++ on-agent + |= [=wire =sign:agent:gall] + ^- (quip card:agent:gall agent:gall) + =^ cards agent (on-agent:ag wire sign) + [cards this] + :: + ++ on-arvo + |= [=wire =sign-arvo] + ^- (quip card:agent:gall agent:gall) + =^ cards agent (on-arvo:ag wire sign-arvo) + [cards this] + :: + ++ on-fail + |= [=term =tang] + ^- (quip card:agent:gall agent:gall) + =^ cards agent (on-fail:ag term tang) + [cards this] + -- +-- diff --git a/desk/lib/fetch.hoon b/desk/lib/fetch.hoon new file mode 100644 index 0000000..bd74deb --- /dev/null +++ b/desk/lib/fetch.hoon @@ -0,0 +1,546 @@ +/- *boke, tp=trill-post, tlonc=tlon-channels +/+ sr=sortug, plib=trill-utils, kaji, const=constants, wall +|_ [s=state =bowl:gall] ++* wal ~(. wall src.bowl) +++ bulk-post-by-pid +|= pids=(list pid:tp) ^- (list post:tp) + %+ roll pids |= [=pid:tp acc=(list post:tp)] + =/ post (get:gorm:tp feed.s pid) + ?~ post acc :_ acc u.post + +++ thread-children +=| start=@ud +|= ted=thread:tp ^- cpage:tp + =| i=@ud + =/ lim (add thread-page-size:const start) + =/ cp=cpage:tp [~ start thread-page-size:const] + =/ pids (flop replies.ted) + =/ r=cpage:tp + |- + ?~ pids cp + ?: (lth i start) $(pids t.pids, i +(i)) + ?: (gte i lim) cp + =/ post (get:gorm:tp feed.s i.pids) + ?~ post $(pids t.pids) + =/ np [u.post p.cp] + =. cp cp(p np, bot i) + $(pids t.pids, i +(i)) + + r(p (flop p.r)) + +++ older-children +|= [ted=thread:tp ind=@ud] ^- cpage:tp + %. ted + %* . thread-children start ind == + +++ newer-children +|= [ted=thread:tp ind=@ud] ^- cpage:tp + =/ lim thread-page-size:const + =/ start ?: (lte ind lim) 0 (sub ind lim) + %. ted + %* . thread-children start start == + +++ gated-post + |= =pid:tp ^- (unit post:tp) + =/ upost (get:gorm:tp feed.s pid) + ?~ upost ~ + ?: (post-filter:wal tags.u.upost) upost ~ +++ by-path + |= pat=path ^- (unit post:tp) + =/ pid (~(get by paths.s) pat) + ?~ pid ~ + (gated-post u.pid) +++ post + |= hash=@t ^- (unit post:tp) + =/ pid (dec:kaji hash pid:tp) + ?~ pid ~ (gated-post u.pid) +++ fn-by-pid +|= =pid:tp ^- (unit full-node:tp) + =/ post (gated-post pid) + ?~ post ~ + %- some (node-to-full:plib u.post feed.s) +++ fn-by-hash +|= hash=@t ^- (unit full-node:tp) + =/ pid (dec:kaji hash pid:tp) + ?~ pid ~ + =/ post (gated-post u.pid) + ?~ post ~ + %- some (node-to-full:plib u.post feed.s) +++ thread-by-hash + |= hash=@t ^- (unit [thread:tp post:tp]) + =/ pid (dec:kaji hash pid:tp) + ?~ pid ~ + =/ ted (get:torm:tp threads.s u.pid) + ?~ ted ~ + =/ post (gated-post u.pid) + ?~ post ~ + %- some [u.ted u.post] +++ op-by-hash + |= hash=@t ^- (unit [thread:tp full-node:tp]) + =/ pid (dec:kaji hash pid:tp) + ?~ pid ~ + =/ ted (get:torm:tp threads.s u.pid) + ?~ ted ~ + =/ post (gated-post u.pid) + ?~ post ~ + %- some :- u.ted (node-to-full:plib u.post feed.s) +++ op-by-pid + |= =pid:tp ^- (unit [thread:tp full-node:tp]) + =/ ted (get:torm:tp threads.s pid) + ?~ ted ~ + =/ post (gated-post pid) + ?~ post ~ + %- some :- u.ted (node-to-full:plib u.post feed.s) +++ thread + |= =path + ^- (unit thread:tp) + =/ pid (~(get by paths.s) path) + ?~ pid ~ + (get:torm:tp threads.s u.pid) +++ op-by-path :: blog posts or thread ops + |= =path + ^- (unit [thread:tp full-node:tp]) + =/ pid (~(get by paths.s) path) + ?~ pid ~ + =/ ted (get:torm:tp threads.s u.pid) + ?~ ted ~ + =/ poast (gated-post u.pid) + ?~ poast ~ + %- some :- u.ted (node-to-full:plib u.poast feed.s) +++ tag-search + |= q=@t ^- (list [@t count=@ud]) + %+ roll ~(tap by tags.s) |= [i=[tag=@t =pidmap] acc=(list [@t @ud])] + ?. (tag-filter:wal tag.i) acc + ?: .=('' tag.i) acc + ?. (cfind:sr q tag.i .n) acc :_ acc + :- tag.i (wyt:porm:tp pidmap.i) + +++ thread-page-no-wall +|= [r=page-req:tp f=(unit tfilter:tp)] ^- tpage:tp + =/ l (tap:torm:tp threads.s) + =| =tpage:tp + |- + ?~ l tpage(p (flop p.tpage)) + ?: (gte count.tpage count.r) tpage(p (flop p.tpage)) + =/ t=thread:tp +.i.l + =. tpage (collect-thread-no-wall t tpage r f) + $(l t.l) +:: +++ thread-page-all +|= [r=page-req:tp f=(unit tfilter:tp)] ^- tpage:tp + =/ l (tap:torm:tp threads.s) + =| =tpage:tp + |- + ?~ l tpage(p (flop p.tpage)) + ?: (gte count.tpage count.r) tpage(p (flop p.tpage)) + =/ t=thread:tp +.i.l + =. tpage (collect-thread t tpage r f) + $(l t.l) +++ active-thread-page-all +|= [r=page-req:tp f=(unit tfilter:tp)] ^- tpage:tp + =/ l (tap:porm:tp active-threads.s) + =| =tpage:tp + |- + ?~ l tpage(p (flop p.tpage)) + ?: (gte count.tpage count.r) tpage(p (flop p.tpage)) + =/ =pid:tp +.i.l + =/ ut (get:torm:tp threads.s pid) + ?~ ut $(l t.l) + =/ t=thread:tp u.ut + =. tpage (collect-thread t tpage r f) + $(l t.l) + +++ thread-page-by-board + |= [cat=@tas r=page-req:tp f=(unit tfilter:tp)] ^- tpage:tp + =/ tag-set (~(get by categories:const) cat) + ?~ tag-set [~ r] + %^ thread-page-by-tags ~(tap in u.tag-set) r f +++ active-thread-page-by-board + |= [cat=@tas r=page-req:tp f=(unit tfilter:tp)] ^- tpage:tp + =/ tag-set (~(get by categories:const) cat) + ?~ tag-set [~ r] + %^ active-thread-page-by-tags ~(tap in u.tag-set) r f + +++ thread-page-by-tags +|= [tags=(list @t) r=page-req:tp f=(unit tfilter:tp)] ^- tpage:tp + :: =. tags (tags:wal tags) + ~> %bout.[0 %filter-tags-first] + =/ pids %+ roll tags |= [t=@t acc=pidmap] + =/ pids (~(get by tags.s) t) + ?~ pids acc + (uni:porm:tp acc u.pids) + ?: .=((wyt:porm:tp pids) 0) [~ r] + =/ l (fetch-threads-2 (tap:porm:tp pids)) + =| =tpage:tp + |- + ?~ l tpage(p (flop p.tpage)) + ?: (gte count.tpage count.r) tpage(p (flop p.tpage)) + =/ t=thread:tp i.l + =. tpage (collect-thread t tpage r f) + $(l t.l) + +++ active-thread-page-by-tags +|= [tags=(list @t) r=page-req:tp f=(unit tfilter:tp)] ^- tpage:tp + :: =. tags (tags:wal tags) + ~> %bout.[0 %filter-tags-first] + =/ pids %+ roll tags |= [t=@t acc=pidmap] + =/ pids (~(get by tags.s) t) + ?~ pids acc + (uni:porm:tp acc u.pids) + ?: .=((wyt:porm:tp pids) 0) [~ r] + =/ l (fetch-last-replies (tap:porm:tp pids)) + =| =tpage:tp + |- + ?~ l tpage(p (flop p.tpage)) + ?: (gte count.tpage count.r) tpage(p (flop p.tpage)) + =/ t=thread:tp i.l + =. tpage (collect-thread t tpage r f) + $(l t.l) + + + +++ thread-page-by-tags2 +|= [tags=(list @t) r=page-req:tp f=(unit tfilter:tp)] ^- tpage:tp + =. tags (tags:wal tags) + ~> %bout.[0 %filter-threads-first] + =/ l (tap:torm:tp threads.s) + ?~ l [~ r] + =/ ff |= t=thread:tp ?= ^ (~(int in tags.t) (silt tags)) + =/ l=(list [pid:tp thread:tp]) l + =| =tpage:tp + |- + ?~ l tpage(p (flop p.tpage)) + ?: (gte count.tpage count.r) tpage(p (flop p.tpage)) + =/ t=thread:tp +.i.l + =. tpage (collect-thread t tpage r `ff) + $(l t.l) +:: +++ fetch-last-replies +|= lp=(list [pid:tp pid:tp]) ^- (list thread:tp) + :: %- flop + %- sort :_ |= [a=thread:tp b=thread:tp] + =/ last-a ?~ replies.a pid.a i.replies.a + =/ last-b ?~ replies.b pid.b i.replies.b + (gte id.last-a id.last-b) + %+ roll lp |= [[* =pid:tp] acc=(list thread:tp)] + =/ t (get:torm:tp threads.s pid) + ?~ t acc + [u.t acc] + +++ fetch-threads-2 +|= lp=(list [pid:tp pid:tp]) ^- (list thread:tp) + %- flop + %+ roll lp |= [[* =pid:tp] acc=(list thread:tp)] + =/ t (get:torm:tp threads.s pid) + ?~ t acc [u.t acc] +++ fetch-threads +|= lp=(list pid:tp) ^- (list thread:tp) + %- flop + %+ roll lp |= [=pid:tp acc=(list thread:tp)] + =/ t (get:torm:tp threads.s pid) + ?~ t acc [u.t acc] + +++ thread-page +|= [l=(list thread:tp) r=page-req:tp f=(unit tfilter:tp)] ^- tpage:tp + =| =tpage:tp + |- + ?~ l tpage(p (flop p.tpage)) + ?: (gte count.tpage count.r) tpage(p (flop p.tpage)) + =/ t=thread:tp i.l + =. tpage (collect-thread t tpage r f) + $(l t.l) + +++ collect-thread +|= [t=thread:tp =tpage:tp r=page-req:tp f=(unit tfilter:tp)] ^- tpage:tp + =/ id=@da id.pid.t + ?. (post-filter:wal tags.t) tpage + ?. (page-cond id r) tpage + ?: ?& ?=(^ f) + =/ fres (u.f t) ?!(fres) == tpage + :: :: + =/ oldest ?~ older.tpage `id + ?: (lth id u.older.tpage) `id older.tpage + =/ newest ?~ newer.tpage `id + ?: (gth id u.newer.tpage) `id newer.tpage + %= tpage + p [t p.tpage] + older oldest + newer newest + count +(count.tpage) + == +++ collect-thread-no-wall +|= [t=thread:tp =tpage:tp r=page-req:tp f=(unit tfilter:tp)] ^- tpage:tp + =/ id=@da id.pid.t + ?. (page-cond id r) tpage + ?: ?& ?=(^ f) + =/ fres (u.f t) ?!(fres) == tpage + :: :: + =/ oldest ?~ older.tpage `id + ?: (lth id u.older.tpage) `id older.tpage + =/ newest ?~ newer.tpage `id + ?: (gth id u.newer.tpage) `id newer.tpage + %= tpage + p [t p.tpage] + older oldest + newer newest + count +(count.tpage) + == + + + +++ check-age +|= [id=@da newer=cursor:tp older=cursor:tp] ^- ? + ?~ newer + ?~ older .y + (lth id u.older) + ?~ older + (gth id u.newer) + ?&((gth id u.newer) (lth id u.older)) + +++ page-cond +|= [id=@da r=page-req:tp] ^- ? +?~ newer.r + :: newest not bound + ?~ older.r + :: neither oldest or newest is bound + .y + :: oldest is bound, newest isn't + (lth id u.older.r) + :: newest bound + ?~ older.r + :: newest is bound, oldest isn't + (gth id u.newer.r) + :: both are bound + ?&((lth id u.older.r) (gth id u.newer.r)) +++ get-post-page + |= [req=page-req:tp filter=(unit $-(post:tp ?))] ^- spage:tp + :: ~> %bout.[0 %get-post-page-rec] + =/ from-bottom=? ?& ?=(%~ older.req) ?!(?=(%~ newer.req)) == + =/ l ?. from-bottom (tap:gorm:tp feed.s) (flop (tap:gorm:tp feed.s)) + :: =| max=@da :: need to define the max and minimum + :: =| min=@da + :: this is what we return + =| p=spage:tp + |- + ?~ l p :: end of iteration + =/ [[=ship =id:tp] =post:tp] i.l + ?. (page-cond id req) p :: exit condition + =/ ok ?~ filter .y (u.filter post) + ?. ok $(l t.l) + :: =/ max ?: (gth id max) id max + :: =/ min ?: ?|((lth id min) .=(min *@da)) id min + =/ oldest ?~ older.p `id + ?: (lth id u.older.p) `id older.p + =/ newest ?~ newer.p `id + ?: (gth id u.newer.p) `id newer.p + %= $ + l t.l + p.p [post p.p] + older.p oldest + newer.p newest + count.p +(count.p) + == +++ get-fn-page + |= [req=page-req:tp filter=(unit $-(post:tp ?))] ^- page:tp + :: ~> %bout.[0 %get-fn-page-rec] + =/ from-bottom=? ?& ?=(%~ older.req) ?!(?=(%~ newer.req)) == + =/ l ?. from-bottom (tap:gorm:tp feed.s) (flop (tap:gorm:tp feed.s)) + :: =| max=@da :: need to define the max and minimum + :: =| min=@da + :: this is what we return + =| p=page:tp + |- + ?~ l p :: end of iteration + =/ [[=ship =id:tp] =post:tp] i.l + ?. (page-cond id req) p :: exit condition + =/ ok ?~ filter .y (u.filter post) + ?. ok $(l t.l) + :: =/ max ?: (gth id max) id max + :: =/ min ?: ?|((lth id min) .=(min *@da)) id min + =/ oldest ?~ older.p `id + ?: (lth id u.older.p) `id older.p + =/ newest ?~ newer.p `id + ?: (gth id u.newer.p) `id newer.p + =/ fn (node-to-full:plib post feed.s) + %= $ + l t.l + p.p [fn p.p] + older.p oldest + newer.p newest + count.p +(count.p) + == + :: Search +++ get-chat-id +|= r=reference:tlonc ^- @da + ?- -.r + %post id.post.r + %reply id-post.r + == +++ search +|= [s=section query=@t tags=(list @t) r=page-req:tp] ^- search-res + ?: ?=(%chat s) :- %chat (search-chat query r) + :- %trill (search-dap s query r) + +++ sort-fn +|= p=(list [full-node:tp @t]) ^- (list [full-node:tp @t]) + %+ sort p |= [a=[full-node:tp @t] b=[full-node:tp @t]] (gth id.p.-.a id.p.-.b) +:: +++ collect-search +|= [sp=search-page query=@t =post:tp req=page-req:tp filter=(unit pfilter:tp)] +^- search-page + =/ id id.post + ?. (check-age id newer.req older.req) sp + ?. (post-filter:wal tags.post) sp + ?: ?& ?=(^ filter) + =/ fres (u.filter post) ?!(fres) == sp + =/ content-snip=@t (text-search-ind:plib query 150 post .n) + ?: .=(content-snip '') sp + =/ oldest ?~ older.sp `id + ?: (lth id u.older.sp) `id older.sp + =/ newest ?~ newer.sp `id + ?: (gth id u.newer.sp) `id newer.sp + =/ fn (node-to-full:plib post feed.s) + %= sp + res [[fn content-snip] res.sp] + older oldest + newer newest + == + +++ search-feed +|= [query=@t req=page-req:tp filter=(unit pfilter:tp)] ^- search-page + =/ bottom ?~ newer.req ~ `[~zod u.newer.req] + =/ top ?~ older.req ~ `[~zod u.older.req] + =/ subfeed (lot:gorm:tp feed.s top bottom) + =/ l (tap:gorm:tp subfeed) + (search-tap query l req filter) + +++ search-tap +|= [query=@t l=(list [=pid:tp =post:tp]) req=page-req:tp filter=(unit pfilter:tp)] + ^- search-page + =| p=search-page + |- + ?~ l p(res (sort-fn res.p)) + ?: (gte (lent res.p) count.req) p(res (sort-fn res.p)) + =/ =post:tp post.i.l + =. p (collect-search p query post req filter) + $(l t.l) + + +++ search-pids-full +|= [query=@t l=(list pid:tp) req=page-req:tp filter=(unit pfilter:tp)] ^- search-page + =| p=search-page + |- + ?~ l p(res (sort-fn res.p)) + ?: (gte (lent res.p) count.req) p(res (sort-fn res.p)) + =/ post (get:gorm:tp feed.s i.l) + ?~ post $(l t.l) + =. p (collect-search p query u.post req filter) + $(l t.l) + ++$ dpage [by-title=(list [full-node:tp @t]) by-content=(list [full-node:tp @t]) newer=cursor:tp older=cursor:tp] + +++ collect-thread-search +|= [dp=dpage query=@t t=thread:tp =post:tp req=page-req:tp f=(unit bfilter:tp)] ^- dpage + ?: ?& ?=(^ f) + =/ fres (u.f [t post]) ?!(fres) == dp + =/ id id.pid.t + ?. (page-cond id req) dp + ?. (post-filter:wal tags.post) dp + =/ title-match=? (cfind:sr query title.t .n) + ?: title-match + =/ fn (node-to-full:plib post feed.s) + =/ nc (update-cursors id older.dp newer.dp) + dp(by-title [[fn ''] by-title.dp], older -.nc, newer +.nc) + =/ content-snip=@t (text-search-ind:plib query 200 post .n) + ?. .=('' content-snip) + =/ fn (node-to-full:plib post feed.s) + =/ nc (update-cursors id older.dp newer.dp) + dp(by-content [[fn content-snip] by-content.dp], older -.nc, newer +.nc) + :: no match + dp +++ consolidate-search +|= d=dpage ^- search-page + :+ (weld (sort-fn by-title.d) (sort-fn by-content.d)) + newer.d older.d + +++ update-cursors +|= [id=@da older=cursor:tp newer=cursor:tp] ^- [older=cursor:tp newer=cursor:tp] + =/ o ?~ older `id + ?: (lth id u.older) `id older + =/ n ?~ newer `id + ?: (gth id u.newer) `id newer + [o n] +++ search-blog +|= [query=@t req=page-req:tp] ^- search-page + =/ pidm (~(get by tags.s) 'blog') + ?~ pidm *search-page + =/ l (tap:porm:tp u.pidm) + %- consolidate-search + =| p=dpage + |- + ?~ l p + =/ =pid:tp +.i.l + =/ count (add (lent by-title.p) (lent by-content.p)) + ?: (gte count count.req) p + =/ post (get:gorm:tp feed.s pid) + ?~ post $(l t.l) + =/ ted (get:torm:tp threads.s pid) + ?~ ted $(l t.l) + =. p (collect-thread-search p query u.ted u.post req ~) + $(l t.l) +:: +++ search-comments +|= [query=@t r=page-req:tp] ^- search-page + =/ pids %+ roll (tap:torm:tp threads.s) |= [[* thread:tp] acc=(list pid:tp)] + (weld acc replies) + (search-pids-full query pids r ~) + +++ search-threads +|= [query=@t req=page-req:tp] ^- search-page + =/ l (tap:torm:tp threads.s) + =/ filter |= [=thread:tp =post:tp] + ?& !(~(has in tags.post) 'blog') + !(~(has in tags.post) 'blog-comment') + == + %- consolidate-search + =| p=dpage + |- + ?~ l p + =/ t=thread:tp +.i.l + =/ count (add (lent by-title.p) (lent by-content.p)) + ?: (gte count count.req) p + =/ post (get:gorm:tp feed.s pid.t) + ?~ post $(l t.l) + =. p (collect-thread-search p query t u.post req `filter) + $(l t.l) +++ search-replies +|= [query=@t r=page-req:tp] ^- search-page + =/ filter |= =post:tp + ?& !(~(has in tags.post) 'blog') + !(~(has in tags.post) 'blog-comment') + ?=(^ parent.post) + == + (search-feed query r `filter) + +++ search-dap +|= [s=$?(%blog %comments %threads %replies) query=@t r=page-req:tp] ^- search-page + ?- s + %blog (search-blog query r) + %comments (search-comments query r) + %threads (search-threads query r) + %replies (search-replies query r) + == +++ search-chat +|= [query=@t req=page-req:tp] ^- chat-page + =/ flag /chat/(scot %p our.bowl)/chat + =/ pat /search/text/(scot %ud 0)/(scot %ud count.req)/[query] + =/ chat-scry (~(scry io:sr bowl) %channels (weld flag pat) scan:tlonc) + ?~ chat-scry *chat-page + =/ rev (flop chat-scry) + ?~ rev *chat-page + =/ head i.chat-scry + =/ tail i.rev + =/ newer (some (get-chat-id head)) + =/ older (some (get-chat-id tail)) + [chat-scry older newer (lent chat-scry)] +-- diff --git a/desk/lib/json.hoon b/desk/lib/json.hoon new file mode 100644 index 0000000..37ecb03 --- /dev/null +++ b/desk/lib/json.hoon @@ -0,0 +1,179 @@ +/+ sortug +|% +++ de +=, dejs:format +|% +++ boardpost +%- ar %- ot +:~ author+so + op+so + thread+de-date + date+de-date + title+so + content+(ar content) + id+ni + tid+ni +== +++ comment +%- ar %- ot +:~ author+so + date+de-date + content+(ar content) + pa+so + parent+de-date + post+de-date + title+so +== +++ soo +|= jon=json +?~ jon '' +?>(?=([%s *] jon) p.jon) +++ poast +%- ar +%- ot +:~ title+so + url+de-url + content+(ar content) + date+di + tags+de-tags + id+ni +== +++ de-tags +|= j=json ^- (set @t) +?> ?=(%s -.j) +=/ ret (rush +.j (split:parsing:sortug hep)) +%- sy +?~ ret ~[+.j] %+ roll u.ret |= [=tape acc=(list @t)] ?~ tape acc [(crip tape) acc] +++ de-date :: just use di? +|= j=json ^- @da +?> ?=(%n -.j) +=/ n (rash +.j dem) +(from-unix-ms:chrono:userlib n) +++ off +|* wer=(pole [cord fist]) + |= jon=json + ?> ?=([%o [@ *] ~ ~] jon) + |- + ?- wer + :: [[key=@t wit=*] t=*] + [[key=@t *] t=*] + => .(wer [[* wit] *]=wer) + ?: =(key.wer p.n.p.jon) + [key.wer ~|(key+key.wer (wit.wer q.n.p.jon))] + ?~ t.wer ~|(bad-key+p.n.p.jon !!) + ((of t.wer) jon) + == +++ content +%- of +:~ paragraph+(ar inline) + blockquote+(ar inline) + heading+heading + list+clists + media+media + codeblock+dcode + tasklist+(ar de-task) + eval+so + ref+ref + json+external +== +++ inline +|= jon=json %. jon +%- of +:~ text+so + italic+so + bold+so + strike+so + ship+(se %p) + date+di + note+de-note + codespan+so + link+link + break+ul + underline+so + sup+so + sub+so + ruby+de-ruby +== +++ de-task +%- ot +:~ text+(ar inline) + done+bo +== +++ de-note +%- ot +:~ id+so + text+(ar inline) +== +++ de-ruby +%- ot +:~ p+so + q+so +== +++ dcode +%- ot +:~ code+so + lang+so +== +++ link +%- ot +:~ href+so + show+so +== +++ heading +%- ot +:~ text+so + :- %num + |= j=json + ?> ?=(%n -.j) + =/ n (rash +.j dem) + ?: .=(1 n) %h1 + ?: .=(2 n) %h2 + ?: .=(3 n) %h3 + ?: .=(4 n) %h4 + ?: .=(5 n) %h5 + ?: .=(6 n) %h6 %h6 +== +++ clists +|= jon=json +%. jon +%- ot +:~ :- %text + |= j=json =/ i ((ar inline) j) + ~[~[[%paragraph i]]] + ordered+bo +== +++ media +%- of +:~ images+(ar de-image) + video+so + audio+so +== +++ de-image +%- ot +:~ url+so + caption+so +== +++ ref +%- ot +:~ type+(se %tas) + ship+(se %p) + path+dpath +== +++ external +%- ot +:~ origin+(se %tas) + content+so +== +++ dpath :: from resource +%- su +%+ cook +|= l=(list @t) `path`+.l +(more fas urs:ab) +++ de-url :: from resource +%- su +%+ cook +|= l=(list @t) `path`l +=/ f (cook |=(a=tape (crip a)) (star ;~(less fas next))) +(more fas f) +-- +-- diff --git a/desk/lib/kaji-min.js b/desk/lib/kaji-min.js new file mode 100644 index 0000000..f683846 --- /dev/null +++ b/desk/lib/kaji-min.js @@ -0,0 +1 @@ +const t=`${Date.now()}${Math.floor(100*Math.random())}`,e=`/~/channel/${`kaji-${t}`}`;let n=0;const o=new DOMParser;function i(t,e){t.innerHTML=e,r(t)}function r(t){const e=t instanceof HTMLElement;if(!t)return;const n=t.querySelectorAll("[kaji]");e&&t.getAttribute("kaji")&&h(t),n.forEach((t=>h(t)))}async function a(t){console.log({channelPath:e,bodies:t},"put body");const n=await fetch(e,{method:"PUT",body:JSON.stringify(t)});return await n}function subscribe(t){document.addEventListener("DOMContentLoaded",(()=>{a([P(window.ship,window.app,t)])}))}function c(t){const n=JSON.parse(t.data);if("diff"!==n.response)return;!async function(t){await fetch(e,{method:"PUT",body:$(t)})}(n.id);const i=n.json;if(i&&0!==i?.length)for(let t of i)if(console.log(t,"sse command"),"refresh"in t&&window.location.reload(!0),"redi"in t&&d(t.redi),"focus"in t&&s(t.focus),"scroll"in t&&l(t.scroll),"url"in t&&u(t.url),"custom"in t)f(t.custom);else{const e=t[Object.keys(t)[0]].manx,n=o.parseFromString(e,"text/html").body.firstChild;"swap"in t&&N(null,n,t.swap.sel,t.swap.inner),"add"in t&&E(null,n,t.add.container,t.add.where),"modal"in t&&p(n),"alert"in t&&m(n,t.alert.duration)}}function s(t){const e=document.querySelector(t);e&&e.focus()}function l(t){const e=document.querySelector(t);e&&e.scrollIntoView()}function u(t){window.history.pushState(null,null,t)}function d(t){console.log(t,"redirecting"),window.location.href=t}function f(t){const e=new CustomEvent("kaji-fact",{detail:t});document.dispatchEvent(e)}function p(t){const e=document.createElement("div");e.id="kaji-modal-bg";const n=document.createElement("div");n.id="kaji-modal-fg",i(n,t),e.appendChild(n),document.body.appendChild(e),window.onclick=function(t){t.target==e&&e.remove()}}function m(t,e){const n=document.createElement("div");n.id="kaji-alert",n.appendChild(t),document.body.appendChild(n),setTimeout((()=>document.body.removeChild(n)),e)}function g(t,e){for(let n of t.attributes){const t=n.name,o=n.value;if("class"===t||"id"===t)continue;const i=e.getAttribute(t);o&&!i&&e.setAttribute(t,o)}}function h(n){const c=n.getAttribute("kaji");if("mobile"===c)!async function(t){const e=t.getAttribute("path");if(!(window.innerWidth<768))return;const n=await fetch(e),i=await n.text(),a=o.parseFromString(i,"text/html").body.firstChild;r(a),t.replaceWith(a)}(n);else if("fetch"===c)!async function(t){const e=await fetch(t.getAttribute("src")),n=await e.text(),i=o.parseFromString(n,"text/html").body.firstChild;t.replaceWith(i)}(n);else if("iscroll"===c)!function(t){let e=new IntersectionObserver(((e,n)=>{e.forEach((e=>{if(e.isIntersecting){const o=function(t){const e=document.createElement("img");return e.src="spinner.svg",e.classList.add("iscroll-spinner"),t.replaceWith(e),e}(e.target);y(C(t)).then((n=>{if(!n)return;const i=e.target.getAttribute("cont");E(t,n,i,v(t)),A({swapMode:"add",container:i,element:n}),o.remove()})),n.unobserve(e.target)}}))}));e.observe(t)}(n);else if("search"===c)!function(t){const e=t.getAttribute("bounce"),n=Number(e||0);if(Number.isNaN(n))return w("bounce setting NaN");const o=e=>async function(t,e){console.log(t,"scry event"),t.preventDefault();const n=C(e);console.log(n,"url"),k(e,!0);const o=e.getAttribute("swap"),i=await y(n);if(!i)return;const r=e.getAttribute("show-params");r&&S(n);let a;if("swap"===o){j(e);const t=e.getAttribute("targ"),n=e.getAttribute("where");a=N(e,i,t,!n||"inner"===n)}else if("add"===o){const t=e.getAttribute("cont");a=await E(e,i,t,v(e))}k(e,!1),a&&A({swapMode:o,container:a})}(e,t),i=((t,e)=>{let n;return(...o)=>{clearTimeout(n),n=setTimeout((()=>t(...o)),e)}})(o,n);t.addEventListener("keyup",i)}(n);else if("clickaway"===c)!function(t){window.onclick=function(e){t.contains(e.target)||(t.hidden=!0)}}(n);else{const o=n.getAttribute("trigger")||function(t){const e=t.tagName.toLowerCase();if("form"===e)return"submit";return"input"===e||"textarea"===e||"select"===e?"change":"click"}(n);n.addEventListener(o,(o=>{!function(n,o,r){"navi"===r&&async function(t,e){t.preventDefault();const n=e.getAttribute("path"),o=L(t.target),r=n||o;if(!r)throw new Error("no fetch path found");const a=await fetch(r),c=await a.text(),s=t.target.closest("#kaji-modal-fg");i(s||document.querySelector("body"),c)}(n,o);"modal"===r&&async function(t,e){const n=e.getAttribute("path"),o=L(t.target),i=n||o;if(!i)throw new Error("no fetch path found");const r=await fetch(i);p(await r.text())}(n,o);"toggle"===r&&function(t,e){t.stopPropagation();const n=t.target.getAttribute("targ");if(!n)return;const o=n.split("/").map((e=>b(t.target,e)));o.forEach((e=>{t.target.getAttribute("modal")&&function(t){const e=document.createElement("div");e.id="kaji-modal-bg";const n=document.createElement("div");n.id="kaji-modal-fg",n.appendChild(t),e.appendChild(n),document.body.appendChild(e),window.onclick=function(t){t.target==e&&e.remove()}}(e),e&&(e.hidden=!e.hidden)}))}(n);"destroy"===r&&function(t,e){t.stopPropagation();const n=t.target.getAttribute("targ");if(!n)return;const o=n.split("/").map((e=>b(t.target,e)));for(let t of o)t&&t.parentElement.removeChild(t)}(n);"scry"===r&&async function(t){console.log(t,"scry event");const e=t.target;!function(t){let e=t.parentElement;for(;e;)g(e,t),e=e.parentElement}(e);const n=e.getAttribute("path")||window.location.href,o=new URLSearchParams(window.location.search),[i,r]=n.split("?");if(r){const t=new URLSearchParams(r);for(let[e,n]of t.entries())o.set(e,n)}const a=e.getAttribute("name");a&&o.set(a,e.value);const c=`${n}?${o.toString()}`;t.preventDefault();const s=e.getAttribute("swap")||"swap";k(e,!0);const l=await y(c);if(console.log(l,"nel"),!l)return;const u=e.getAttribute("show-params");u&&S(c);let d;if("swap"===s){j(e);const t=e.getAttribute("targ"),n=e.getAttribute("where");d=N(e,l,t,!n||"inner"===n)}else if("add"===s){const t=e.getAttribute("cont");d=await E(e,l,t,v(e))}k(e,!1),d&&A({swapMode:s,container:d})}(n);"watch"===r&&async function(t,n){const o=n.getAttribute("ship"),i=n.getAttribute("app"),r=n.getAttribute("path"),a=P(o,i,r);await fetch(e,{method:"PUT",body:a})}(0,o);"poke"===r&&async function(e,n){e.preventDefault();n.getAttribute("ship"),n.getAttribute("app");const o=n.getAttribute("mark")||"kaji",i=n.getAttribute("json");console.log(n.params,"poke params?");const r=e.currentTarget,c=r.getAttribute("action"),s=r.getAttribute("name"),l=r.getAttribute("payload"),u=i||("FORM"===r.tagName?{action:c,...x(r)}:c?{action:c,[s]:l}:{action:s,[s]:l});e.stopPropagation(),"FORM"===r.tagName&&function(t){if(!t.getAttribute("wipe"))return;const e=[...t.getElementsByTagName("input"),...t.getElementsByTagName("textarea")];for(let t of e)"text"===t.type.toLowerCase()&&(t.value=""),"TEXTAREA"===t.tagName&&(t.value="")}(r);const d={...u,origin:window.location.pathname,tab:t};console.log(d,"poke params");const f=[T(window.ship,window.app,o,d)];await a(f)}(n,o);"thread"===r&&async function(t,e){console.log(e.params,"thread params?");const n=e.getAttribute("desk"),o=e.getAttribute("thread"),i=e.getAttribute("input-mark")||"kaji",r=e.getAttribute("output-mark")||"kaji",a=e.getAttribute("noun");fetch(`/spider/${n}/${i}/${o}/${r}.kaji`,{headers:{"Content-type":"application/x-urb-jam"},method:"POST",body:a})}(0,o)}(o,n,c)}))}}function w(t){console.log(t)}function b(t,e){if(console.log(t,"looking above"),console.log(e,"sel"),!e)return console.log(e,"selector not found"),null;if("#"===e[0])return document.getElementById(e.slice(1));if(!t)return null;const n=t.querySelector(e);return n||b(t.parentElement,e)}async function y(t){console.log(t,"router scry");const e=await fetch(t),n=await e.text(),i=o.parseFromString(n,"text/html").body.firstChild;return function(t,e){if(!e)return console.log(t,"No element found scrying"),!0;if("kaji-alert"===e.id){const t=e.getAttribute("dur");return m(e,Number(t)),!0}return!!e.getAttribute("kaji-error")}(n,i)?null:(r(i),function(t){const e=t.querySelectorAll("script");for(let t of e){const e=document.createElement("script");t.src?e.src=t.src:t.textContent&&(e.textContent=t.textContent),document.body.appendChild(e)}}(i),i)}function A(t){const e=new CustomEvent("kaji-scry",{detail:t});document.dispatchEvent(e)}function v(t){const e=t.getAttribute("where");if(!e)return{bottom:null};if("bottom"===e)return{bottom:null};if("top"===e)return{top:null};if("before"===e){const e=t.getAttribute("sibling");return e?{before:e}:null}return null}function E(t,e,n,o){o||w("no where given to addEls");const i=t?b(t,n):document.querySelector(n);for(i||w("no container given to addEls");e.firstChild;)if("top"in o)i.prepend(e.firstChild);else if("bottom"in o)i.appendChild(e.firstChild);else if("before"in o){const t=document.querySelector(o.before);t||w("sibling at addEls doesn't exist"),i.insertBefore(e.firstChild,t)}}function k(t,e){const n=t.getAttribute("indicator"),o=document.querySelector(n);o&&(o.style.display=e?"block":"none")}function C(t){!function(t){const e=function(t){const e=t.tagName.toLowerCase();return"input"===e||"select"===e||"option"===e||"textarea"===e||"button"===e}(t);if(!e)return;let n,o=t.parentElement;for(;!n&&o;)g(o,t),"form"===o.tagName.toLowerCase()?n=o:o=o.parentElement;n&&(t.params=x(n))}(t);const e=t.getAttribute("path")||window.location.href,n=new URLSearchParams(window.location.search),[o,i]=e.split("?");if(i){const t=new URLSearchParams(i);for(let[e,o]of t.entries())n.set(e,o)}const r=t.getAttribute("name"),a=t.params?t.params:"FORM"===t.tagName?x(t):{},c=new URLSearchParams(a),s=new URLSearchParams;for(let[t,e]of n.entries())s.set(t,e);r&&t.value&&s.set(r,t.value);for(let[t,e]of c.entries())s.set(t,e);return`${o}?${s.toString()}`}function S(t){const e=t.split("?")[1]||"";u(`${window.location.pathname}?${e}`)}function L(t){const e=t.closest("a");return e?e.href:null}function j(t){if(!t.classList.contains("tab"))return;t.parentElement;if(!t.classList.contains("active")){t.parentElement.querySelector(".active").classList.remove("active"),t.classList.add("active")}}function N(t,e,n,o){const i=t?b(t,n):document.querySelector(n);if(i){if(o)for(i.innerHTML="";e.firstChild;)i.appendChild(e.firstChild);else i.parentElement.replaceChild(e,i);return i}console.log("no container",n)}function x(t){const e=new FormData(t);return Object.fromEntries(e)}function P(t,e,o){return n++,{id:n,action:"subscribe",ship:t.slice(1),app:e,path:o}}function T(t,e,o,i){return n++,{id:n,action:"poke",ship:t.slice(1),app:e,mark:o,json:i}}function $(t){return n++,JSON.stringify([{id:n,action:"ack","event-id":t}])}addEventListener("DOMContentLoaded",(async()=>{await async function(){console.log(window.ship,"opening channel");const n=P(window.ship,window.app,window.liveUI),o=`/sse/${t}`,i=P(window.ship,window.app,o),r=T(window.ship,"hood","helm-hi","hai"),a=JSON.stringify([n,i,r]);await fetch(e,{method:"PUT",body:a}),eventSource=new EventSource(e),eventSource.addEventListener("message",c)}(),r(document),function(){const t=new URLSearchParams(window.location.search).get("goto");if(t){const e=document.getElementById(t);e?e.scrollIntoView({block:"center"}):console.log(t,"target not found")}}()}));
\ No newline at end of file diff --git a/desk/lib/kaji.css b/desk/lib/kaji.css new file mode 100644 index 0000000..c41d0d7 --- /dev/null +++ b/desk/lib/kaji.css @@ -0,0 +1,79 @@ +@keyframes fadeIn { + from { + opacity: 0; + } + + to { + opacity: 1; + } +} + +@keyframes fadeOut { + from { + opacity: 1; + } + + to { + opacity: 0; + } +} + +/* The Modal (background) */ +#kaji-modal-bg { + position: fixed; + z-index: 1; + left: 0; + top: 0; + width: 100%; + height: 100%; + overflow: auto; + background-color: rgba(0, 0, 0, 0.4); + z-index: 998; +} + +/* Modal Content */ +#kaji-modal-fg { + background-color: var(--background-color); + position: fixed; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + padding: 20px; + width: 80%; + z-index: 999; + max-height: 90vh; + max-width: 90vw; + overflow: auto; +} + +[kaji="modal"] { + cursor: pointer; +} + +#kaji-alert { + background-color: var(--background-color); + border: 2px solid var(--hong); + z-index: 999; + position: fixed; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + padding: 0.5rem; +} + +button { + cursor: pointer; +} + +.hide { + display: none; +} + +.not-hide { + display: block; +} + +.iscroll-spinner { + display: block; + margin: 1rem auto; +}
\ No newline at end of file diff --git a/desk/lib/kaji.hoon b/desk/lib/kaji.hoon new file mode 100644 index 0000000..113fd84 --- /dev/null +++ b/desk/lib/kaji.hoon @@ -0,0 +1,379 @@ +/+ sr=sortug +/* kaji-js %js /lib/kaji-min/js +/* kaji-css %css /lib/kaji/css +|% ++$ kbowl + $: src=@p + now=@da + mob=? + == ++$ eyre-order [id=@ta req=inbound-request:eyre] ++$ req-line + $: pat=(pole knot) :: path + ext=(unit @ta) :: extension + par=(map @t @t) :: params + mob=? :: is-mobile + == ++$ form-data [action=@t input=(map @t @t)] +++ enc |= a=* ^- tape (scow:parsing:sr %uw (jam a)) +++ dec |* [a=@t m=mold] ^- (unit m) + =/ hash (slaw:parsing:sr %uw a) + ?~ hash ~ + ((soft m) (cue u.hash)) +++ dec-i |* [i=(map @t @t) key=@t =mold] ^- (unit mold) + =/ val (~(get by i) key) ?~ val ~ + =/ atm (slaw:parsing:sr %uw u.val) ?~ atm ~ + ((soft mold) (cue u.atm)) + + +:: ++ dec-form |* [=form-data d=(list [key=@t =mold])] +:: =| res=* +:: |- +:: ?~ d res +:: =/ val (~(get by in) key.i.d) +:: ?~ val ~ +:: =/ uw (scow %uw u.val) +:: ?~ uw +:: =/ is-t ((sane @t) (crip u.val)) +:: ?. is-t ~| "%kaji.- passed value {u.val} of wrong format" ~ +:: it's a @t +:: ${res [res (crip u.val), d t.d] +:: =/ dec-res ((soft mold.i.d) (cue u.uw)) +:: ?~ dec-res ~| "Failed to decode {(trip key.i.d)}" ~ +:: =/ nr [res u.dec-res] +:: $(res nr, d t.d) + +:: =df |* wer=(list [key=@t =mold]) +:: |= in=(map @t @t) +:: ?~ wer ~ +:: :_ ((df t.wer) in) +:: =/ val (~(get by in) key.i.wer) +:: ?~ val ~| "key {(trip key.i.wer)} not found in map" ~ +:: =/ uw (slaw %uw u.val) ?~ uw +:: ~& uw=uw +:: =/ is-t ((sane %t) u.val) +:: ~& is-t=is-t +:: ?. is-t ~| "%kaji.- passed value {u.val} of wrong format" ~ +:: u.val +:: =/ dec-res ((soft mold.i.wer) (cue u.uw)) +:: ?~ dec-res ~| "Failed to decode {(trip key.i.wer)}" ~ +:: u.dec-res + +:: =df |* [in=(map @t @t) d=(list [key=@t =mold])] +:: =| res=(unit) +:: |- +:: ~& res=res +:: ?~ d res +:: ~& key=key.i.d +:: =/ val (~(get by in) key.i.d) +:: ~& val=val +:: ?~ val ~ +:: =/ uw (slaw %uw u.val) ?~ uw +:: ~& uw=uw +:: =/ is-t ((sane %t) u.val) +:: ~& is-t=is-t +:: ?. is-t ~| "%kaji.- passed value {u.val} of wrong format" ~ +:: =/ nr ?~ res (some u.val) (some [(need res) u.val]) +:: $(res nr, d t.d) +:: =/ dec-res ((soft mold.i.d) (cue u.uw)) +:: ~& dec-res=dec-res +:: ?~ dec-res ~| "Failed to decode {(trip key.i.d)}" ~ +:: =/ nr ?~ res (some u.dec-res) (some [(need res) u.dec-res]) +:: $(res nr, d t.d) + +:: =m (malt `(list [@t @t])`~[['a' 'alpha'] ['b' (scot %uw (jam [our now]))]]) +:: =d `(list [@t mold])`~[['a' @] ['b' ,[@p @da]]] + + + + ++$ kaji-res +$% [%res eyre-res] + [%sse sse-res] +== ++$ sse-res + $: wire=kaji-wire + e=(list effect) + == ++$ kaji-wire + $% [%tab ~] + [%custom p=(list wire)] + [%all ~] + == ++$ eyre-res + $% [%full p=simple-payload:http] + [%page p=manx] + [%html p=manx] :: fragment + [%mime type=path p=@t] + [%glob p=mime] + == ++$ where + $% [%top ~] + [%bottom ~] + [%before sibling=@t] + == ++$ effect +$% [%redi url=@t] :: redirects; will replace the whole html of the site and update the tab history + [%swap =manx sel=@t inner=?] :: swaps a selector + [%add =manx container=@t =where] :: adds marl to a div + [%focus sel=@t] :: focuses on some selector + [%scroll sel=@t] :: scrolls to some selector + [%url url=@t] :: updates the url bar + [%modal =manx] :: opens a modal + [%alert =manx dur=@ud] :: opens an alert for given duration in ms + [%refresh ~] + [%custom =manx data=json] :: custom, you can set a handle for the 'kaji-fact' event in JS +== ++$ sse-card [%give %fact (list path) [%kaji vase]] + +++ ui-fact +|= [tab=@t res=(list effect)] ^- sse-card +=/ wire /sse/[tab] +[%give %fact ~[wire] [%kaji !>(res)]] + +++ live-fact +|= res=(list effect) ^- sse-card +[%give %fact ~[/ui] [%kaji !>(res)]] + +++ give-fact +|= [wires=(list path) res=(list effect)] ^- sse-card +[%give %fact wires [%kaji !>(res)]] + + +:: sse templates +++ ui + |_ tab-id=@t + ++ fact + |= res=(list effect) (ui-fact tab-id res) + ++ alert + =/ dur 2.000 + |= a=tape + =/ manx ;span:"{a}" + %+ ui-fact tab-id [%alert manx dur]^~ + ++ refresh-card :: wipe browser cache + %+ ui-fact tab-id [%refresh ~]^~ + -- +:: +:: response builders +:: eyre responses +++ error-response +|= code=@ud ^- eyre-res + :- %html (error-page code) +:: inline sse commands + +:: some helpers +:: manx builders +++ wrap-marl +|= m=marl ^- manx +;div + ;* m +== +++ error-page +|= code=@ud + ;html + ;body + ;p:"Error {<code>}" + == + == +++ fetch +|= pat=path +;div(kaji "fetch", src "{(trip (spat pat))}"); + + +++ add-error +|= m=manx ^- manx +=. a.g.m (snoc a.g.m [%kaji-error "true"]) +m +++ hide-manx +|= m=manx ^- manx +=. a.g.m :_ a.g.m [n=%hidden v=""] +m +++ modal +|= children=marl ^- manx +;div#kaji-modal-bg + ;div#kaji-modal-fg + ;* children + == +== +:: + +++ parse-formdata + |= body=(unit octs) ^- (unit (list [key=@t val=@t])) + ?~ body ~ + (rush q.u.body yquy:de-purl:html) + +++ get-redirect + |= redirect=cord + ^- simple-payload:http + [[303 ['location' redirect]~] ~] + +++ doctype "<!DOCTYPE html>" + +++ is-mobile + |= req=inbound-request:eyre ^- ? + =/ headers (malt header-list.request.req) + =/ ua (~(get by headers) 'user-agent') + =/ swidth (~(get by headers) 'x-kaji-vw') + ?~ ua ?~ swidth .n + =/ width (rush u.swidth dem) ?~ width .n + (lte u.width 800) + + ?| (cfind:sr 'android' u.ua .n) + (cfind:sr 'iphone' u.ua .n) + :: (cfind:sr 'ipad' u.ua .n) + == + +:: core functionality ++$ request-line-s + $: [ext=(unit @ta) site=(list @t)] + args=(list [key=@t value=@t]) + == +++ parse-req +|= req=inbound-request:eyre ^- req-line + =/ rl=(unit request-line-s) (rush url.request.req ;~(plug apat:de-purl:html yque:de-purl:html)) + ?~ rl + ~& >>> url-parsing-failed=url.request.req + !! + =/ is-mob (is-mobile req) + [path=site.u.rl ext.u.rl (malt args.u.rl) is-mob] + +++ manx-to-cord + |= [is-fragment=? =manx] ^- @t + %- crip + ?. is-fragment + %- en-xml:html manx + :: + %+ weld doctype + %- en-xml:html manx + +++ send-eyre-res + |= [eyre-id=@ta =simple-payload:http] + ^- (list card:agent:gall) + =/ header-cage + [%http-response-header !>(response-header.simple-payload)] + =/ data-cage + [%http-response-data !>(data.simple-payload)] + :~ [%give %fact ~[/http-response/[eyre-id]] header-cage] + [%give %fact ~[/http-response/[eyre-id]] data-cage] + [%give %kick ~[/http-response/[eyre-id]] ~] + == + +++ glob-payload + =| cache=_| + |= =mime ^- simple-payload:http + =/ content-type (rsh 3 (crip <p.mime>)) + =/ cache-header ?: cache + ['cache-control' 'max-age=86400'] + ['cache-control' 'no-cache, no-store, must-revalidate'] + :: ~& >>> ends-in=`@t`(swp 3 (end [3 5] (swp 3 q.q.mime))) + :_ `q.mime + [200 [['content-type' content-type] cache-header ~]] + +++ http-payload + =| cache=_| + |= [mime-type=path t=@t] ^- simple-payload:http + =/ content-type (rsh 3 (crip <mime-type>)) + =/ octs (as-octs:mimes:html t) + =/ cache-header ?: cache + ['cache-control' 'max-age=86400'] + ['cache-control' 'no-cache, no-store, must-revalidate'] + :_ `octs + [200 [['content-type' content-type] cache-header ~]] +:: +++ js +|% + ++ collapsible ^~ %- trip + ''' + function createCollapsible(el){ + console.log("creating collapsible") + const targetID = el.getAttribute("target"); + const targetEl = document.getElementById(targetID); + targetEl.classList.toggle("hide"); + let show = false; + el.addEventListener('click', () => { + console.log(show, "clicked on toggle") + console.log(targetID) + console.log(targetEl) + show = !show; + // el.classList.toggle("") TODO would need to toggle the button itself + targetEl.classList.toggle("not-hide") + targetEl.classList.toggle("hide") + }) + } + document.querySelectorAll(".toggle").forEach(createCollapsible) + console.log(document.querySelectorAll(".toggle")) + ''' +-- +++ payload-bail ^- simple-payload:http +%+ http-payload /text/plain 'Error' + +++ init +|* [=bowl:gall app-state=mold kaji-req=mold] +|% + +$ request + $% [%eyre p=eyre-order] + [%kaji tab=@t req=kaji-req] + == + +$ router $-([request bowl:gall app-state] kaji-res) + ++ route + |= [=router r=request state=app-state] + |^ ^- (list card:agent:gall) + ?- -.r + %eyre + =/ =req-line (parse-req req.p.r) + %+ send-eyre-res id.p.r + ?+ [pat ext]:req-line + :: default case + =/ resp (router r bowl state) + ?. ?=(%res -.resp) payload-bail + ?- +<.resp + %full p.resp + %page (http-payload /text/html (manx-to-cord .n (inject-head p.resp))) + %html (http-payload /text/html (manx-to-cord .y p.resp)) + %mime (http-payload type.resp p.resp) + %glob (glob-payload p.resp) + == + [[%session ~] [~ %js]] (http-payload /text/javascript docket-session-js) + [[%kaji-session ~] [~ %js]] (http-payload /text/javascript session-js) + [[%kaji ~] [~ %js]] (http-payload /text/javascript kaji-js) + [[%kaji ~] [~ %css]] (http-payload /text/css kaji-css) + + == + %kaji + =/ resp (router r bowl state) + ?. ?=(%sse -.resp) ~ :_ ~ + ?- -.wire.resp + %all (live-fact e.resp) + %tab (ui-fact tab.r e.resp) + %custom (give-fact p.wire.resp e.resp) + == + == + ++ inject-head + |= m=manx ^- manx + =/ sip (scow %p src.bowl) + =/ dap (trip dap.bowl) + =/ tags=marl :~ + ;link/"/kaji.css"(rel "stylesheet"); + ;script@"/kaji.js"; + ;script@"/kaji-session.js?ship={sip}&dap={dap}"; + == + |- + ?~ c.m m + ?: .=(%head n.g.i.c.m) + =. c.i.c.m (weld c.i.c.m tags) m + $(c.m t.c.m) + ++ docket-session-js ^~ + (rap 3 'window.ship = "' (rsh 3 (scot %p our.bowl)) '";' ~) + + ++ session-js ^~ %- crip + =/ ship (scow %p our.bowl) + =/ app (trip dap.bowl) + =/ live-ui "/ui" + """ + window.ship = '{ship}' + window.app = '{app}' + window.liveUI = '{live-ui}'; + """ + -- +-- +-- diff --git a/desk/lib/kaji.js b/desk/lib/kaji.js new file mode 100644 index 0000000..a37dada --- /dev/null +++ b/desk/lib/kaji.js @@ -0,0 +1,723 @@ + const tabId = `${Date.now()}${Math.floor(Math.random() * 100)}`; + const channelId = `kaji-${tabId}`; + const channelPath = `/~/channel/${channelId}`; + let channelMessageId = 0; + const parser = new DOMParser(); + + addEventListener('DOMContentLoaded', async () => { + await openChannel(); + scanElements(document); + handleDefaultScroll(); + }); + + function handleDefaultScroll(){ + const params = new URLSearchParams(window.location.search); + const goto = params.get('goto'); + if (goto) { + const target = document.getElementById(goto); + if (target) target.scrollIntoView({block: "center"}); + else (console.log(goto, "target not found")) + } + } + function insertAndScan(parent, htmlString){ + parent.innerHTML = htmlString; + scanElements(parent); + } + function scanElements(el){ + const isEl = el instanceof HTMLElement; + if (!el) return + const elements = el.querySelectorAll('[kaji]'); + if (isEl && el.getAttribute("kaji")) setListener(el); + elements.forEach(el => setListener(el)); + } + function loadScripts(el){ + const scripts = el.querySelectorAll("script"); + for (let scr of scripts){ + const newScript = document.createElement('script'); + if (scr.src) newScript.src = scr.src + else if (scr.textContent) newScript.textContent = scr.textContent + document.body.appendChild(newScript); + } + } + function setLocaleTime(el){ + const els = el.querySelectorAll(".locale-dt"); + for (let de of els){ + const timestamp = Number(de.textContent); + // TODO error handle the parsing + const date = new Date(timestamp); + // TODO set the format at the server + let localDate = ""; + if (de.classList.includes("time")) + localDate = date.toLocaleDateString(); + if (de.classList.includes("date")) + localDate = date.toLocaleTimeString(); + else localDate = date.toLocaleString(); + de.textContent = localDate; + } + + } + async function openChannel(){ + console.log(window.ship, "opening channel") + const sub1 = makeSubscribeBody(window.ship, window.app, window.liveUI); + const ssePath = `/sse/${tabId}`; + const sub2 = makeSubscribeBody(window.ship, window.app, ssePath); + const pok = makePokeBody(window.ship, "hood", "helm-hi", "hai") + const body = JSON.stringify([sub1, sub2, pok]) + await fetch(channelPath, { + method: 'PUT', + body + }); + eventSource = new EventSource(channelPath); + eventSource.addEventListener('message', handleChannelStream); + } + async function put(bodies){ + console.log({channelPath, bodies}, "put body") + const res = await fetch(channelPath, { + method: "PUT", + body: JSON.stringify(bodies) + }) + return await res + } + function subscribe(path){ + document.addEventListener('DOMContentLoaded', () => { + const sub = makeSubscribeBody(window.ship, window.app, path); + put([sub]) + }); + } + function handleChannelStream(e){ + const streamResponse = JSON.parse(e.data); + if (streamResponse.response !== 'diff') return; + sendAck(streamResponse.id) + const res = streamResponse.json; + if (!res || res?.length === 0) return; + for (let effect of res){ + console.log(effect, "sse command") + if ("refresh" in effect) clearBrowserCache() + if ("redi" in effect) redirect(effect.redi) + if ("focus" in effect) handleFocus(effect.focus) + if ("scroll" in effect) handleScroll(effect.scroll) + if ("url" in effect) updateURL(effect.url) + if ("custom" in effect) dispatchFact(effect.custom) + else { + const key = Object.keys(effect)[0]; + const htmlData = effect[key].manx; + const nel = parser.parseFromString(htmlData, 'text/html').body.firstChild; + if ("swap" in effect) swapTarget(null, nel, effect.swap.sel, effect.swap.inner); + if ("add" in effect) addEls(null, nel, effect.add.container, effect.add.where) + if ("modal" in effect) showModal(nel) + if ("alert" in effect) showAlert(nel, effect.alert.duration) + } + } + } + + function clearBrowserCache(){ + window.location.reload(true); + } + function handleFocus(sel){ + const el = document.querySelector(sel); + if (el) el.focus(); + } + function handleScroll(sel){ + const el = document.querySelector(sel); + if (el) el.scrollIntoView(); + } + function updateURL(url){ + window.history.pushState(null, null, url) + } + function redirect(url){ + // document.body.innerHTML = html; + // scanElements(document.body); + // history.pushState({}, '', url) + console.log(url, "redirecting") + window.location.href = url; + } + function dispatchFact(detail){ + const myCustomEvent = new CustomEvent("kaji-fact", { detail }); + document.dispatchEvent(myCustomEvent); + } + + function partialManx(newElement, selector){ + const existing = document.getElementById(newElement.id); + if (newElement && existing) + existing.parentNode.replaceChild(newElement, existing); + else { + const toReplace = document.querySelector(selector); + toReplace.parentNode.replaceChild(newElement, toReplace); + } + } + function addManx(newElement, selector){ + const container = document.getElementById(selector); + container.appendChild(newElement); + } + function wrapInModal(el){ + const background = document.createElement("div"); + background.id = "kaji-modal-bg"; + const foreground = document.createElement("div"); + foreground.id = "kaji-modal-fg"; + // Append modal content to modal + foreground.appendChild(el); + background.appendChild(foreground); + document.body.appendChild(background); + // Click outside to close + window.onclick = function(event) { + if (event.target == background) background.remove(); + } + } + function showModal(html){ + const background = document.createElement("div"); + background.id = "kaji-modal-bg"; + const foreground = document.createElement("div"); + foreground.id = "kaji-modal-fg"; + insertAndScan(foreground, html) + // Append modal content to modal + background.appendChild(foreground); + document.body.appendChild(background); + // Click outside to close + window.onclick = function(event) { + if (event.target == background) background.remove(); + } + } + function showAlert(element, duration){ + const div = document.createElement("div"); + div.id = "kaji-alert"; + div.appendChild(element); + document.body.appendChild(div); + setTimeout(() => document.body.removeChild(div), duration) + } + function passAttributes(parent, child){ + for (let attr of parent.attributes){ + const n = attr.name; + const v = attr.value; + if (n === "class" || n === "id") continue; + const haveIt = child.getAttribute(n); + if (v && !haveIt) child.setAttribute(n, v) + } + } + + function findForm(el){ + const is = isFormChild(el); + if (!is) return + let form; + let parent = el.parentElement; + while (!form){ + if (!parent) break; + passAttributes(parent, el) + const tag = parent.tagName.toLowerCase(); + if (tag === "form") form = parent; + else parent = parent.parentElement; + } + if (form) el.params = getFormData(form) + } + + function isFormChild(el){ + const tag = el.tagName.toLowerCase(); + return (tag === "input" + || tag === "select" + || tag === "option" + || tag === "textarea" + || tag === "button") + } + + function setListener(el){ + const kaji = el.getAttribute('kaji'); + // immediate calls + // we're not gonna bother with settings params here. + if (kaji === "mobile") fetchMobile(el) + else if (kaji === "fetch") fetchSource(el) + else if (kaji === "iscroll") infiniteScroll(el) + else if (kaji === "search") handleLiveSearch(el) + else if (kaji === "clickaway") clickaway(el) + // event listeners + else { + const trigger = el.getAttribute("trigger") || defaultTrigger(el); + el.addEventListener(trigger, (e) => { + routeKaji(e, el, kaji) + }) + } + } + + function routeKaji(e, el, kaji){ + + if (kaji === "navi") navigate(e, el) + if (kaji === "modal") mmodal(e, el) + if (kaji === "toggle") toggle(e, el) + if (kaji === "destroy") destroy(e, el) + // urbit stuff + if (kaji === "scry") scry2(e) + if (kaji === "watch") watch(e, el) + if (kaji === "poke") poke(e, el) + if (kaji === "thread") thread(e, el) + } + + function clickaway(el){ + window.onclick = function(event) { + if (el.contains(event.target)) return + else el.hidden = true; + } + } + + function destroy(e, el){ + e.stopPropagation(); + const targ = e.target.getAttribute("targ"); + if (!targ) return + const targs = targ.split("/").map(m => lookabove(e.target, m)); + for (let t of targs){ + if (t) t.parentElement.removeChild(t); + } + } + function bail(string){ + console.log(string) + return + } + function handleLiveSearch(el){ + const bounceSetting = el.getAttribute("bounce"); + const num = Number(bounceSetting || 0); + if (Number.isNaN(num)) return bail("bounce setting NaN"); + // + const debounce = (fn, delay) => { + let timeout; + return (...args) => { + clearTimeout(timeout); + timeout = setTimeout(() => fn(...args), delay) + } + } + const handler = (e) => scry(e, el); + + const debounced = debounce(handler, num); + el.addEventListener("keyup", debounced); + } + + + function isNarrow(){ + return window.innerWidth < 768; // TODO + } + async function fetchMobile(el){ + const path = el.getAttribute('path'); + if (!isNarrow()) return + const res = await fetch(path); + const html = await res.text(); + const nel = parser.parseFromString(html, 'text/html').body.firstChild; + scanElements(nel); + el.replaceWith(nel); + } + async function fetchSource(el){ + const res = await fetch(el.getAttribute("src")); + const html = await res.text(); + const nel = parser.parseFromString(html, 'text/html').body.firstChild; + el.replaceWith(nel) + } + function infiniteScroll(el){ + let observer = new IntersectionObserver((entries, observer) => { + entries.forEach(entry => { + if (entry.isIntersecting) { + const spinner = replaceWithSpinner(entry.target); + const url = getURLwithParams(el); + routerScry(url).then(nel => { + if (!nel) return + const cont = entry.target.getAttribute("cont"); + // TODO + addEls(el, nel, cont, addWhere(el)) + dispatchScry({swapMode: "add", container: cont, element: nel}) + spinner.remove() + }); + observer.unobserve(entry.target); + } + }) + }); + observer.observe(el); + } + function replaceWithSpinner(el){ + const spinner = document.createElement("img"); + spinner.src = "spinner.svg"; + spinner.classList.add("iscroll-spinner") + el.replaceWith(spinner); + return spinner; + } + function handleError(res, el){ + if(!el) { + console.log(res, "No element found scrying") + return true + } + if (el.id === "kaji-alert") { + const dur = el.getAttribute("dur"); + const num = Number(dur); + showAlert(el, num); + return true + } + const err = el.getAttribute("kaji-error"); + if (!err) return false + showError(el); + return true + } + function showError(el){ + return + } + function lookabove(el, sel){ + console.log(el, "looking above") + console.log(sel, "sel") + if (!sel) { + console.log(sel, "selector not found") + return null + } + if (sel[0] === "#") return document.getElementById(sel.slice(1)); + if (!el) return null + const found = el.querySelector(sel); + if (!found) return lookabove(el.parentElement, sel) + else return found + } + function toggle(e, el){ + e.stopPropagation(); + const targ = e.target.getAttribute("targ"); + if (!targ) return + const targs = targ.split("/").map(m => lookabove(e.target, m)); + targs.forEach(t => { + if (e.target.getAttribute("modal")) wrapInModal(t); + if (t) t.hidden = !t.hidden + }) + + } + async function routerScry(path){ + console.log(path, "router scry") + const res = await fetch(path) + const html = await res.text() + const nel = parser.parseFromString(html, 'text/html').body.firstChild; + if (handleError(html, nel)) return null + scanElements(nel); + loadScripts(nel); + return nel + } + function dispatchScry(detail){ + const myCustomEvent = new CustomEvent("kaji-scry", { detail }); + document.dispatchEvent(myCustomEvent); + } + + function addWhere(el){ + const where = el.getAttribute("where") + if (!where) return { bottom: null } + if (where === "bottom") return { bottom: null } + if (where === "top") return { top: null } + if (where === "before") { + const sibling = el.getAttribute("sibling"); + if (!sibling) return null + else return { before: sibling } + } + else return null + } + function addEls(originEl, nel, selector, where){ + if (!where) bail("no where given to addEls") + const container = originEl + ? lookabove(originEl, selector) + : document.querySelector(selector); + if (!container) bail("no container given to addEls") + while (nel.firstChild){ + if ("top" in where) container.prepend(nel.firstChild) + else if ("bottom" in where) container.appendChild(nel.firstChild) + else if ("before" in where){ + const sibling = document.querySelector(where.before); + if (!sibling) bail ("sibling at addEls doesn't exist") + container.insertBefore(nel.firstChild, sibling); + } + } + } + + + function defaultTrigger(el){ + const tag = el.tagName.toLowerCase(); + if (tag === "form") return "submit" + if (tag === "input" || tag === "textarea" || tag === "select") return "change" + else return "click"; + } + function toggleIndicator(el, on){ + const indicator = el.getAttribute('indicator'); + const indEl = document.querySelector(indicator); + if (indEl) + indEl.style.display = on ? "block" : "none"; + } + + function getURLwithParams(el){ + findForm(el); + const spath = el.getAttribute("path"); + const path = spath || window.location.href; + // decide on priority when conflict + const current = new URLSearchParams(window.location.search); + const [pat, pars] = path.split("?"); + if (pars) { + const param = new URLSearchParams(pars); + for (let [k, v] of param.entries()){ + current.set(k, v) + } + } + const name = el.getAttribute("name"); + const params = el.params + ? el.params + : el.tagName === 'FORM' + ? getFormData(el) + : {}; + const second = new URLSearchParams(params); + const final = new URLSearchParams(); + for (let [k, v] of current.entries()){ + final.set(k, v) + } + if (name && el.value) final.set(name, el.value); + for (let [k, v] of second.entries()){ + final.set(k, v) + } + const url = `${pat}?${final.toString()}`; + return url + } + + function consolidateAttributes(el){ + let parent = el.parentElement; + while (parent){ + passAttributes(parent, el); + parent = parent.parentElement; + } + } + async function scry2(e){ + console.log(e, "scry event") + // this should go to kaji root + const el = e.target; + consolidateAttributes(el); + // + // this should go to url building function + const path = el.getAttribute("path") || window.location.href; + const params = new URLSearchParams(window.location.search); + const [pat, parString] = path.split("?"); + if (parString) { + const newParams = new URLSearchParams(parString); + for (let [k, v] of newParams.entries()){ + params.set(k, v) + } + } + const name = el.getAttribute("name"); + if (name) params.set(name, el.value); + const url = `${path}?${params.toString()}`; + // scry proper + e.preventDefault(); + const swapMode = el.getAttribute("swap") || "swap"; + toggleIndicator(el, true); + const nel = await routerScry(url); + console.log(nel, "nel") + if (!nel) return + const showParams = el.getAttribute("show-params"); + if (showParams) raiseParams(url); + let container; + if (swapMode === "swap"){ + toggleTab(el); + const target = el.getAttribute('targ') + const swhere = el.getAttribute('where'); + const where = !swhere ? true : (swhere === "inner") + container = swapTarget(el, nel, target, where) + } + else if (swapMode === "add"){ + const cont = el.getAttribute('cont') + container = await addEls(el, nel, cont, addWhere(el)); + } + toggleIndicator(el, false); + if (container) dispatchScry({swapMode, container}) + + + + } + async function scry(e, el){ + console.log(e, "scry event") + e.preventDefault(); + const url = getURLwithParams(el); + console.log(url, "url") + toggleIndicator(el, true); + const swapMode = el.getAttribute("swap"); + const nel = await routerScry(url); + if (!nel) return + const showParams = el.getAttribute("show-params"); + if (showParams) raiseParams(url); + let container; + if (swapMode === "swap"){ + toggleTab(el); + const target = el.getAttribute('targ') + const swhere = el.getAttribute('where'); + const where = !swhere ? true : (swhere === "inner") + container = swapTarget(el, nel, target, where) + } + else if (swapMode === "add"){ + const cont = el.getAttribute('cont') + container = await addEls(el, nel, cont, addWhere(el)); + } + toggleIndicator(el, false); + if (container) dispatchScry({swapMode, container}) + } + + function raiseParams(url){ + const params = url.split("?")[1] || ""; + const displayURL = `${window.location.pathname}?${params}`; + updateURL(displayURL) + } + + async function navigate(e, el){ + e.preventDefault(); + const path = el.getAttribute('path'); + const href = findAnchor(e.target); + const uri = path ? path : href; + if (!uri) throw new Error("no fetch path found") + const res = await fetch(uri); + const html = await res.text() + // If in a modal, replace the modal content with this + const modal = e.target.closest("#kaji-modal-fg"); + if (modal) insertAndScan(modal, html) + else insertAndScan(document.querySelector("body"), html); + } + function findAnchor(el){ + const a = el.closest("a"); + if (a) return a.href + else return null + } + async function mmodal(e, el){ + const path = el.getAttribute('path'); + const href = findAnchor(e.target); + const uri = path ? path : href; + if (!uri) throw new Error("no fetch path found") + const res = await fetch(uri); + const html = await res.text(); + showModal(html); + } + + function hasSetTarget(el){ + return !!el.attributes.targ + } + function toggleTab(el){ + if (!el.classList.contains("tab")) return; + const par = el.parentElement; + if (!el.classList.contains("active")){ + const curr = el.parentElement.querySelector(".active"); + curr.classList.remove("active"); + el.classList.add("active"); + } + } + function swapTarget(originEl, nel, targetSelector, inner){ + const domEL = originEl + ? lookabove(originEl, targetSelector) + : document.querySelector(targetSelector); + if (!domEL) { + console.log("no container", targetSelector) + return + } + if (inner){ + domEL.innerHTML = ''; + while (nel.firstChild){ + domEL.appendChild(nel.firstChild); + } + } else domEL.parentElement.replaceChild(nel, domEL) + return domEL + } + async function poke(e, el){ + e.preventDefault(); + const ship = el.getAttribute('ship'); + const app = el.getAttribute('app'); + const mark = el.getAttribute('mark') || 'kaji'; + const json = el.getAttribute('json'); + console.log(el.params, "poke params?") + + const tgt = e.currentTarget; + const button = tgt.tagName === 'FORM' + ? tgt.querySelector('input[type="submit"]') + : tgt; + // TODO add flag to configure this + button.disabled = true; + // wipe form + const action = tgt.getAttribute('action'); + const name = tgt.getAttribute("name"); + const payload = tgt.getAttribute('payload'); + // const value = payload ? payload : tgt.value; + const body = json ? json + : (tgt.tagName === 'FORM') + ? {action, ...getFormData(tgt)} + : action ? // if we set an action we send {action, name: value} + {action, [name]: payload} + : {action: name, [name]: payload}; + e.stopPropagation(); // this cancels currentTarget going up and up + if (tgt.tagName === 'FORM') wipeForm(tgt); + const b = {...body, origin: window.location.pathname, tab: tabId}; + console.log(b, "poke params") + const bodies = [makePokeBody(window.ship, window.app, mark, b)] + await put(bodies); + button.disabled = false + } + function wipeForm(form){ + const wipe = form.getAttribute("wipe"); + if (!wipe) return + const inputs = [ + ...form.getElementsByTagName("input"), + ...form.getElementsByTagName("textarea") + ]; + for (let input of inputs){ + if (input.type.toLowerCase() === 'text') input.value = ''; + if (input.tagName === "TEXTAREA") input.value = ''; + } + } + + function getFormData(form){ + const d = new FormData(form); + return Object.fromEntries(d) + } + + async function watch(e, el){ + const ship = el.getAttribute('ship'); + const app = el.getAttribute('app'); + const path = el.getAttribute('path'); + const body = makeSubscribeBody(ship, app, path); + return await fetch(channelPath, { + method: 'PUT', + body + }); + } + // threads don't support noun payloads yet + async function thread(e, el){ + console.log(el.params, "thread params?") + const desk = el.getAttribute('desk'); + const thread = el.getAttribute('thread'); + const inputMark = el.getAttribute('input-mark') || 'kaji'; + const outputMark = el.getAttribute('output-mark') || 'kaji'; + const noun = el.getAttribute('noun'); + + fetch(`/spider/${desk}/${inputMark}/${thread}/${outputMark}.kaji`, { + headers: { + 'Content-type': 'application/x-urb-jam' + }, + method: 'POST', + body: noun + }); + } + async function sendAck(id){ + return await fetch(channelPath, { + method: 'PUT', + body: makeAck(id) + }); + } + function makeSubscribeBody(ship, app, path) { + channelMessageId++; + return { + id: channelMessageId, + action: 'subscribe', + ship: ship.slice(1), // fucking tilde crap + app, + path + }; + }; + function makePokeBody(ship, app, mark, json) { + channelMessageId++; + return { + id: channelMessageId, + action: 'poke', + ship: ship.slice(1), // fucking tilde crap + app, + mark, + json + }; + }; + function makeAck(eventId) { + channelMessageId++; + return JSON.stringify([{ + id: channelMessageId, + action: 'ack', + "event-id": eventId + }]); + }; diff --git a/desk/lib/markdown.hoon b/desk/lib/markdown.hoon new file mode 100644 index 0000000..20e2fe5 --- /dev/null +++ b/desk/lib/markdown.hoon @@ -0,0 +1,699 @@ +/- tp=trill-post +|% +++ hi %hi +:: ++ parse +:: |= str=@t +:: ^- (unit (list block:tp)) +:: (rush str apex) +:: :: +:: +$ errata (each tape block:d) +:: +$ erratum +:: $% [%prose =tape] +:: [%line =tape] +:: [%br ~] +:: [%code =tape] +:: [%block =block:d] +:: == +:: +$ lang +:: $% [%p p=tape] :: prose +:: [%c p=tape] :: code +:: [%br ~] :: line break +:: == +:: ++ trace +:: |* [tag=@t sef=rule] +:: |= tub=nail +:: ?. dbug +:: (sef tub) +:: ~| [tag tub] +:: (sef tub) +:: ++ lyke +:: |$ [res] +:: [p=hair q=(unit [p=res q=nail])] +:: :: +:: ++ dbug & +:: ++ edict +:: |$ [prod] +:: $-(nail (like prod)) +:: :: +:: ++ rack +:: |* [los=tape sab=rule] +:: =+ vex=(sab [1 1] los) +:: ?~(q.vex ~ [~ u=p.u.q.vex]) +:: :: +:: ++ sing +:: |_ $: =nail +:: out=(list verse:d) +:: == +:: ++ sing . +:: ++ abet out +:: ++ bite +:: |= [txt=tape rul=(edict (list verse:d))] +:: ^- (unit (list verse:d)) +:: (rust txt rul) +:: ++ chew +:: |= rul=(edict (list verse:d)) +:: ^- [? _sing] +:: =/ tub (rul nail) +:: ?~ q.tub +:: ~? dbug failed-parsing/[tub nail] +:: [| sing] +:: =. nail q.u.q.tub +:: =. out (welp out p.u.q.tub) +:: [& sing] +:: ++ by-line +:: (more ret (star ;~(less ret next))) +:: ++ main +:: ^+ sing +:: %+ roll (scan q.nail by-line) +:: |= [txt=tape si=_sing] +:: ^+ si +:: =/ out out:si +:: ?: =(~ txt) +:: ?^ out +:: ?: ?=(%block -.i.out) si(out out) :: don't double space +:: => .(out `(list verse:d)`out) +:: si(out (snoc out inline/~[break/~])) +:: => .(out `(list verse:d)`out) +:: si(out (snoc out inline/~[break/~])) +:: ?^ bok=(rack txt hymn) +:: ~! bok +:: si(out (snoc out u.bok)) +:: =/ erratum=(list errata) +:: ~ +:: |- ^+ si +:: ?~ erratum si(out out) +:: ?: ?=(%| -.i.erratum) +:: $(erratum t.erratum, out (snoc out block/p.i.erratum)) +:: =^ inl si +:: abet:main:(abed:draw:si p.p.nail p.i.erratum) +:: $(out (snoc out inline/inl), erratum t.erratum) +:: :: +:: ++ hr (cold rule/~ (jest '---')) + +:: :: +:: ++ hymn +:: ^- (edict verse:d) +:: :: %+ cook (late ~) +:: %+ stag %block +:: ;~ pose +:: header-rul +:: hr +:: listing +:: == +:: :: +:: ++ listing +:: %+ cook +:: |= [mode=?(%ordered %unordered) ls=(list inline:d)] +:: ^- block:d +:: =/ item=listing:d [%item ls] +:: [%listing %list mode ~[item] ~] +:: =- ;~(pfix (star ace) -) +:: ;~ plug +:: ;~(pose (cold %ordered dem) (cold %unordered ;~(pose tar hep lus))) +:: :: +:: ^- (edict (list inline:d)) +:: |= n=^nail +:: =^ ine=(list inline:d) sing +:: abet:main:(abed:draw [p.p.nail q.n]) +:: ?: =(~ ine) +:: [p.nail ~] +:: [p.nail `[ine nail]] +:: == + +:: :: +:: ++ header-rul +:: %+ cook +:: |= [a=(list) b=(list inline:d)] +:: ^- block:d +:: =/ len (lent a) +:: =- [%header - b] +:: ?+ len !! :: forbidden by +stun +:: %1 %h1 +:: %2 %h2 +:: %3 %h3 +:: %4 %h4 +:: %5 %h5 +:: %6 %h6 +:: == +:: =- ;~(plug (stun [1 6] hax) -) +:: ^- (edict (list inline:d)) +:: |= n=_nail +:: =^ ine=(list inline:d) sing +:: abet:main:(abed:draw [p.p.nail q.n]) +:: ?: =(~ ine) +:: [p.nail ~] +:: [p.nail `[ine nail]] +:: ++ draw +:: |_ [mode=?(%normal %quote) inl=(list inline:d) nail=^nail] +:: ++ draw . +:: ++ abet +:: ?~ q.nail +:: [inl sing] +:: ~? dbug incomplete-parsing/nail +:: [inl sing] +:: ++ abed +:: |= [lin=@ud =tape] +:: draw(nail [[lin 1] tape]) +:: ++ peek +:: |= rul=(edict (list inline:d)) +:: ^- ? +:: =(~ q:(rul nail)) +:: ++ chew +:: |= rul=(edict (list inline:d)) +:: ^- [? _draw] +:: =/ tub (rul nail) +:: ?~ q.tub +:: ~? dbug failed-parsing/[tub nail] +:: [| draw] +:: =. nail q.u.q.tub +:: =. inl (welp inl p.u.q.tub) +:: [& draw] +:: ++ is-quote (peek (cold *(list inline:d) gar)) +:: ++ main +:: ^+ draw +:: =^ ok=? draw +:: (chew line) +:: ?: ok draw +:: =^ o=? draw +:: (chew raw-line) +:: ~| should-never-crash-fallback-parsing/nail +:: ?>(o draw) +:: ++ raw-line +:: (cook (cork crip (late ~)) (star next)) +:: :: +:: ++ line +:: %+ knee *(list inline:d) +:: |^ +:: |. ~+ +:: %- plus +:: ;~ pose +:: link +:: (stag %blockquote ;~(pfix gar line)) +:: :: (ifix [;~(plug tar tar) ;~(plug tar tar)] (stag %italics line)) +:: (parse-wrapped %italics ;~(plug tar tar)) +:: (parse-wrapped %bold tar) +:: code +:: ::(sear (ifix [tar tar] (stag %bold line))) +:: :: (parse-wrapped tar (stag %bold line)) +:: word +:: == +:: :: +:: ++ link +:: %+ cook +:: |= [con=tape src=tape] +:: ^- inline:d +:: [%link (crip src) (crip con)] +:: ;~ plug +:: (ifix [sel ser] (star ;~(less ser prn))) +:: (ifix [pal par] (star ;~(less par prn))) +:: == +:: ++ parse-wrapped +:: |* [tag=* delim=rule] +:: %+ stag tag +:: %+ sear fail-if-empty +:: (ifix [delim delim] line) +:: :: +:: ++ code +:: %+ stag %inline-code +:: %+ ifix [tic tic] +:: %+ cook crip +:: %- star +:: ;~(less tic prn) +:: -- +:: -- +:: -- +:: :: +:: ++ ran-hymn +:: |= str=tape +:: ^- verse:d +:: (scan str hymn:sing) +:: ++ ran +:: |= str=@t +:: ^- (list verse:d) +:: %- squeeze +:: abet:~(main sing [[1 1] (trip str)] ~) +:: ++ nixt +:: |= tub=nail +:: ^- (like char) +:: ?~ q.tub +:: (fail tub) +:: =+ zac=(lust i.q.tub p.tub) +:: ?: =('\\' i.q.tub) +:: ?~ t.q.tub +:: [zac [~ i.q.tub [zac t.q.tub]]] +:: =+ zec=(lust i.t.q.tub zac) +:: [zec [~ i.t.q.tub [zec t.t.q.tub]]] +:: [zac [~ i.q.tub [zac t.q.tub]]] +:: :: TODO: squeeze after parsing? +:: ++ migrate +:: |= [f=flag:d atom=@ud ls=(list content:post:gra:d)] +:: ^- (list verse:d) +:: =: flag f +:: time atom +:: == +:: %- squeeze +:: =< - +:: %+ roll ls +:: |= [con=content:post:gra:d out=(list verse:d) prev-break=_&] +:: ^- [(list verse:d) ?] +:: :_ ?=(?(%code %reference %url) -.con) +:: ?- -.con +:: %text (welp out (ring (trip text.con) prev-break)) +:: %mention (snoc out [%inline ~[ship/ship.con]]) :: TODO: i swear I PR'd ships +:: %code (snoc out [%inline ~[code/expression.con]]) +:: %reference (snoc out [%block (ref:nert:chat-graph reference.con)]) +:: :: +:: %url +:: =/ def=verse:d +:: [%inline ~[link/[url.con '']]] +:: %+ snoc out +:: ?~ ext=(rush url.con (cook rear (most dot (cook crip (plus ;~(less dot prn)))))) +:: def +:: ?. ?=(?(%png %jpeg %jpeg) u.ext) +:: def +:: [%block %image url.con 0 0 ''] +:: == +:: :: +:: ++ squeeze +:: |= ls=(list verse:d) +:: %- flop +:: %+ roll ls +:: |= [=verse:d out=(list verse:d)] +:: ^+ out +:: ?~ out [verse out] +:: ?- -.i.out +:: %inline +:: ?. ?=(%inline -.verse) [verse out] +:: :_(t.out [%inline (welp p.i.out p.verse)]) +:: :: +:: %block +:: ?. ?=(%block -.verse) [verse out] +:: (welp (flop (squeeze-lists verse i.out)) t.out) +:: == +:: :: +:: ++ squeeze-lists +:: |= [a=verse:d b=verse:d] +:: ^- (list verse:d) +:: ?. &(?=(%block -.a) ?=(%block -.b)) ~[a b] +:: ?. &(?=(%listing -.p.a) ?=(%listing -.p.b)) ~[a b] +:: ?. &(?=(%list -.p.p.a) ?=(%list -.p.p.b)) ~[a b] +:: ~! p.p.a +:: ?. =(p.p.p.a p.p.p.b) ~[a b] +:: =; =verse:d +:: ~[verse] +:: :- %block +:: :^ %listing %list +:: p.p.p.a +:: [(welp q.p.p.a q.p.p.a) (welp r.p.p.a r.p.p.b)] + +:: :: +:: ++ run-line +:: |= str=@t +:: ^- (list inline:d) +:: ~ +:: ++ apex (most (plus ret) block) +:: ++ ret +:: (jest '\0a\0a') +:: ++ para +:: ;~ pose +:: block +:: (stag %inline quote) +:: (stag %inline line) +:: == +:: ++ quote +:: (stag %blockquote (fzing (plus ;~(pfix gar line)))) +:: ++ block +:: %+ stag %block +:: ;~ pose +:: paragraph +:: blockquote +:: heading +:: media +:: codeblock +:: eval +:: tasklist +:: ref +:: == +:: :: +++ blockquote +;~ plug + (jest '> ') + +== +++ heading + %+ cook + |= [a=tape b=tape] + ^- block:tp + =/ len (lent a) + =/ h ?+ len %h6 + %1 %h1 + %2 %h2 + %3 %h3 + %4 %h4 + %5 %h5 + %6 %h6 + == + [%heading (crip b) h] + ;~(plug ;~(sfix (stun [1 6] hax) ace) (star next)) +++ lbr (just `@t`10) +++ word (star aln) +++ codeblock :: cf. +code + %+ cook |= [lang=tape code=tape] + ^- block:tp + [%codeblock (crip code) (crip lang)] + ;~ plug + ;~ sfix + ;~ pfix + (jest '```') + word + == + lbr + == + ;~ sfix + (star ;~(less (jest '\0a```') next)) + (jest '\0a```') + == + == +++ eval :: parse the hoon? +[%eval 'lol'] +:: ++ media :: would be cool to have syntax for image blocks +:: ;~ pfix +:: zap +:: link +:: == +++ link + %+ cook |= [alt=tape href=tape] ^- inline:tp + [%link (crip href) (crip alt)] + ;~ plug + (ifix [sel ser] (star ;~(less ser prn))) + (ifix [pal par] (plus ;~(less par prn))) + == + +:: :: +:: ++ hr +:: (jest '----') +:: :: +:: ++ word +:: (cook crip (plus ;~(less cab ret tar tic sel next))) +:: ++ fzing +:: |* rul=rule +:: (cook |*(a=(list) (zing a)) rul) +:: ++ listify +:: |* rul=rule +:: (cook |*(* ~[+<]) rul) +:: ++ fail-if-empty |=(a=(list inline:d) `(unit (list inline:d))`?:(=(~ a) ~ `a)) +:: :: +:: ++ line +:: %+ knee *(list inline:d) +:: |^ +:: |. ~+ +:: %- plus +:: ;~ pose +:: :: (ifix [;~(plug tar tar) ;~(plug tar tar)] (stag %italics line)) +:: (parse-wrapped %italics ;~(plug tar tar)) +:: (parse-wrapped %bold tar) +:: (parse-wrapped %italics cab) +:: code +:: ::(sear (ifix [tar tar] (stag %bold line))) +:: :: (parse-wrapped tar (stag %bold line)) +:: word +:: == +:: ++ parse-wrapped +:: |* [tag=* delim=rule] +:: %+ stag tag +:: %+ sear fail-if-empty +:: (ifix [delim delim] line) +:: :: +:: ++ code +:: %+ stag %inline-code +:: %+ ifix [tic tic] +:: %+ cook crip +:: %- star +:: ;~(less tic prn) +:: -- +:: ::: +:: ++ lin +:: |= txt=@t +:: ((plus ;~(less ret next)) [1 1] (trip txt)) +:: :: +:: ++ by-line +:: |= txt=tape +:: (split-rule txt ret) +:: :: +:: ++ log-fall +:: |* [tag=@ta str=tape a=(unit) b=*] +:: ?~ a +:: b +:: u.a +:: :: +:: ++ infix-lr +:: |* [left=rule right=rule inner=rule] +:: |= tub=nail +:: =+ vex=(left tub) +:: ?~ q.vex +:: (fail tub) +:: =/ but=nail tub +:: =+ outer=(;~(sfix (plus ;~(less right nixt)) (opt-sfix-end right)) q.u.q.vex) +:: ?~ q.outer +:: (fail tub) +:: =+ in=(inner [1 1] p.u.q.outer) +:: ?~ q.in +:: (fail tub) +:: outer(p.u.q p.u.q.in) +:: :: +:: ++ pose-further +:: |* [vex=edge sab=rule] +:: =+ roq=(sab) +:: ?: =(p.vex (last p.vex p.roq)) +:: vex +:: roq +:: :: +:: ++ infix +:: |* [delim=rule inner=rule] +:: |= tub=nail +:: =+ vex=(delim tub) +:: ?~ q.vex +:: (fail tub) +:: =/ but=nail tub +:: =+ outer=(;~(sfix (plus ;~(less delim nixt)) (opt-sfix-end delim)) q.u.q.vex) +:: ?~ q.outer +:: (fail tub) +:: =+ in=(inner [1 1] p.u.q.outer) +:: ?~ q.in +:: (fail tub) +:: outer(p.u.q p.u.q.in) :: +:: :: +:: ++ opt-sfix-end +:: |* sef=rule +:: |= tub=nail +:: ?: =(q.tub ~) +:: [p=p.tub q=[~ u=[p=~ q=tub]]] +:: =+ vex=(sef tub) +:: vex +:: :: +:: ++ infix-multi +:: |* inner=rule +:: |* [vex=edge delim=rule] +:: =/ roq +:: ?:(=(~ q.vex) (delim) vex) +:: ?~ q.roq :: did not find start delim, fail +:: [p=p.roq q=~] +:: =+ out=(;~(sfix (plus ;~(less delim next)) (opt-sfix-end delim)) q.u.q.roq) +:: ?~ q.out +:: [p=p.vex q=~] +:: =+ in=(inner [1 1] p.u.q.out) +:: ?~ q.in +:: [p=p.vex q=~] +:: [p=p.out q=[~ u=[p=p.u.q.in q=q.u.q.out]]] +:: :: +:: ++ infix-multi-bad +:: |* inner=rule +:: |= [vex=(lyke _(wonk (inner))) delim=$-(nail (lyke _(wonk (inner))))] +:: ^- (lyke _(wonk (inner))) +:: ?. ?=(~ q.vex) :: if success, ret +:: [p=p.vex q=~] +:: =+ roq=(delim) +:: ?~ q.roq :: did not find start delim, fail +:: [p=(last p.vex p.roq) q=q.roq] +:: ~! q.u.q.roq +:: =+ out=(;~(sfix (plus ;~(less delim next)) (opt-sfix-end delim)) q.u.q.roq) +:: ?~ q.out +:: [p=p.vex q=~] +:: =+ in=(inner [1 1] p.u.q.out) +:: ?~ q.in +:: [p=p.vex q=~] +:: [p=p.out q=[~ u=[p=p.u.q.in q=q.u.q.out]]] +:: :: +:: ++ split-rule +:: |* [txt=tape delim=rule] +:: ^- (list tape) +:: =- (log-fall %split-rule tape - [txt ~]) +:: (rust txt (more delim (star ;~(less delim next)))) +:: :: +:: ++ by-code +:: |^ +:: |= txt=tape +:: ^- (list lang) +:: (log-fall %by-code txt (rust txt (star apex)) ~[[%p txt]]) +:: :: (log-fall %by-code txt (rust txt (plus apex)) ~[[%& txt]]) +:: ++ apex +:: ;~ pose +:: code +:: prose-simple +:: (stag %p (listify next)) +:: == +:: ++ code +:: ;~ pose-further +:: (infix ;~(plug tic tic tic) code-inner) +:: (infix ;~(plug sig sig sig) code-inner) +:: == +:: ++ code-inner +:: (stag %c (star next)) +:: ++ prose-simple +:: (stag %p (plus ;~(less sig tic next))) +:: -- +:: :: +:: ++ elem +:: |% +:: ++ head +:: %+ cook +:: |= [a=(list) b=(list inline:d)] +:: ^- verse:d +:: =/ len (lent a) +:: =- [%block %header - b] +:: ?+ len !! :: forbidden by +stun +:: %1 %h1 +:: %2 %h2 +:: %3 %h3 +:: %4 %h4 +:: %5 %h5 +:: %6 %h6 +:: == +:: ;~(plug (stun [1 6] hax) inline) +:: ++ blockquote (stag %inline (listify (stag %blockquote ;~(pfix gar inline)))) +:: ++ hr (stag %block (cold `block:d`rule/~ (jest '---'))) +:: ++ str (tie (plus ;~(less cab tar tic sig sel nbsp nixt))) +:: ++ inline-verse (stag %inline inline) +:: ++ nbsp (jest ' ') +:: ++ inline +:: %+ knee *(list inline:d) +:: |. ~+ +:: %+ trace %inline +:: %- plus +:: ;~ pose +:: (stag %bold (infix ;~(plug cab cab) inline)) +:: (stag %bold (infix ;~(plug tar tar) inline)) +:: (stag %inline-code (infix tic code)) +:: (stag %italics (infix cab inline)) +:: (stag %italics (infix tar inline)) +:: (stag %ship ;~(pfix sig fed:ag)) +:: link +:: (cold ' ' (jest ' ')) +:: str +:: nixt +:: == +:: ++ link +:: %+ stag %link +:: %+ cook |=([a=@t b=@t] [b a]) +:: ;~ plug +:: (infix-lr sel ser (tie (star prn))) +:: (infix-lr pal par (tie (star prn))) +:: == +:: :: +:: ++ line-start +:: ^- (edict verse:d) +:: =- ;~(pfix (star whit) -) +:: ;~ pose +:: head +:: blockquote +:: hr +:: inline-verse +:: == +:: -- +:: :: +:: ++ code +:: (tie (star nixt)) +:: ++ tie +:: |* rul=rule +:: (cook crip rul) +:: :: +:: ++ whit ;~(pose (jest '\09') ace) +:: :: +:: ++ lift-blocks +:: |= [txt=tape prev-break=?] +:: ^- (list erratum) +:: =- (log-fall %lift-blocks txt - ~[prose/txt]) +:: %+ rust txt +:: %+ cook +:: |= ls=(list erratum) +:: ?~ ls ls +:: ?. prev-break ls +:: ?. ?=(%prose -.i.ls) +:: ls +:: [[%line tape.i.ls] t.ls] +:: %- plus +:: ;~ pose +:: %+ cook +:: |= [alt=tape src=tape] +:: ^- erratum +:: [%block [%image (crip src) 0 0 (crip alt)]] +:: =- ;~(pfix zap -) +:: ;~ plug +:: (ifix [sel ser] (star ;~(less ser prn))) +:: (ifix [pal par] (plus ;~(less par prn))) +:: == +:: :: +:: (stag %prose (plus ;~(less ;~(plug zap sel) prn))) +:: == +:: :: +:: ++ ring +:: |= [txt=tape last-break=?] +:: ^- (list verse:d) +:: =/ langs (by-code txt) +:: =/ lines=(list lang) +:: %- zing +:: %+ turn langs +:: |= =lang +:: ^- (list ^lang) +:: ?. ?=(%p -.lang) +:: ~[lang] +:: =/ ls=(list ^lang) (turn (by-line p.lang) (lead %p)) +:: =/ sep=^lang br/~ +:: (join sep ls) +:: =/ err=(list erratum) +:: =< - +:: %+ roll lines +:: |= [=lang out=(list erratum) prev-break=_last-break] +:: ^- [(list erratum) ?] +:: :_ =(%br -.lang) +:: ?: ?=(%c -.lang) +:: (snoc out [%code p.lang]) +:: ?: ?=(%br -.lang) +:: (snoc out br/~) +:: (welp out (lift-blocks p.lang prev-break)) +:: =/ blocks=(list verse:d) +:: %+ turn err +:: |= e=erratum +:: ^- verse:d +:: ?- -.e +:: %br [%inline ~[break/~]] +:: :: +:: %code [%inline ~[code/(crip tape.e)]] +:: %block [%block block.e] +:: :: +:: %prose +:: =/ def=verse:d [%inline ~[(crip tape.e)]] +:: =- (log-fall %prose-verse tape.e - def) +:: (rust tape.e inline-verse:elem) +:: :: +:: %line +:: =/ def=verse:d [%inline ~[(crip tape.e)]] +:: =; =verse:d +:: ?: ?=(%inline -.verse) +:: [%inline break/~ p.verse] +:: verse +:: =- (log-fall %line-verse tape.e - def) +:: (rust tape.e line-start:elem) +:: == +:: (squeeze blocks) +-- diff --git a/desk/lib/mast.hoon b/desk/lib/mast.hoon new file mode 100644 index 0000000..74636e8 --- /dev/null +++ b/desk/lib/mast.hoon @@ -0,0 +1,694 @@ +:: :: :: :: +:: +:: Mast - a Sail framework +:: +:: [v.1.0.1] +:: +:: +:: This library contains a system for building fully dynamic Sail front-ends +:: where all front-end app state and the current state of the display itself +:: live on your ship. +:: +:: A small script that is generic to any application is inserted into your Sail +:: and used to establish an Eyre channel, receive display updates from your ship, +:: and to sync the browser with them. +:: +:: Events on the browser are handled completely within your ship, +:: without the need to write a single line of JavaScript. +:: You may describe event listeners in your Sail components with attributes like this: +:: =event "/click/..." +:: The first segment of the path is the event listener name, +:: with further segments defining an arbitrary endpoint for an event handler on your agent. +:: Events are sent as pokes under a json mark, which can be parsed with the library. +:: You may also return data from the event like this: +:: =return "/target/value" +:: The first segment is the object to return data from, and the second is the property to return. +:: Data can be returned from the target element, event object, or any other element associated by id. +:: +:: When the display state changes as a result of events initiated on the browser, +:: or from any other kind of event in the agent, updates to the browser containing +:: only the necessary amount of html to achieve this state are sent and swapped in. +:: +:: +:: The server section contains all of the arms for usage in your app. +:: Rig, plank, and gust are the main arms. See the description of these arms below. +:: +:: For more details visit: https://github.com/R-JG/mast +:: +:: :: :: :: +|% ++$ view manx ++$ yard [url=path sail=gate] ++$ yards (list yard) ++$ parsed-req [tags=path data=(map @t @t)] +:: :: :: :: +:: +:: Server +:: +:: :: :: :: +:: +:: - The rig arm is used to produce a new instance of the display state. +:: - "yards" is the list of your app's routes, each corresponding to a root level Sail component +:: (i.e. a complete document with html, head, and body tags). +:: - "url" is either the request url from Eyre in the context of a direct http request, +:: or the current url (this should be saved in state). +:: - "app-state" represents the total sample for each of your root level Sail components +:: (currently, root level Sail components in yards each need to take the same sample). +:: - Rig uses the url to select the matching yard and renders its Sail component. +:: - The newly produced display state should then be used with either plank or gust, +:: and saved as the current display state in the agent. +:: +++ rig + |* [=yards url=path app-state=*] + ^- view + ?~ yards + (adky (manx sail-404)) + =/ yurl=path url.i.yards + ?: |- + ?~ url + %.n + ?~ yurl + %.n + ?. |(=(i.url i.yurl) =(%$ i.yurl)) + %.n + ?: &(=(~ t.url) =(~ t.yurl)) + %.y + $(url t.url, yurl t.yurl) + =/ rigd (adky (manx (sail.i.yards app-state))) + rigd(a.g (mart [[%url (path <url>)] a.g.rigd])) + $(yards t.yards) +:: +:: - The plank arm is used for serving whole pages in response to %handle-http-request pokes, +:: acting as the first point of contact for the app. +:: - Plank needs to take some basic information about the page that you are serving: +:: - "app" is the name of the app, +:: - "sub" is the subscription path that the client will subscribe to for receiving display updates, +:: - "ship" is your patp, +:: - "rid" is the Eyre id from the %handle-http-request poke, +:: - "new" is the newly rendered display state produced with rig. +:: - Plank produces a list of cards serving the http response. +:: +++ plank + |= [app=tape sub=path ship=@p rid=@ta new=view] + ^- (list card:agent:gall) + ?~ c.new !! + %^ make-direct-http-cards rid + [200 ['Content-Type' 'text/html'] ~] + :- ~ + ^- octs + %- as-octt:mimes:html + %- en-xml:html + ^- manx + %= new + a.g %- mart :^ + [%app app] + [%path <(path sub)>] + [%ship +:(scow %p ship)] + a.g.new + c.i.c (marl [script-node c.i.c.new]) + == +:: +:: - The gust arm is used for producing a set of display updates for the browser, +:: used typically after making changes to your app's state, and rendering new display data with rig. +:: - "sub" is the subscription path that was sent initially in plank, where gust will send the updates. +:: - "old" is the display state that is currently saved in your agent's state, +:: produced some time previously by rig. +:: - "new" is the new display data to be produced with rig just before gust gets used. +:: - Gust can be used anywhere you'd make a subscription update (in contrast to plank). +:: - Gust produces a single card. +:: +++ gust + |= [sub=path old=view new=view] + ^- card:agent:gall + ?~ c.old !! + ?~ c.new !! + ?~ t.c.old !! + ?~ t.c.new !! + ?~ a.g.new !! + :^ %give %fact ~[sub] + :- %json + !> %- tape:enjs:format + %- en-xml:html + ^- manx + ;g + =url v.i.a.g.new + ;* %+ algo + c.i.t.c.old + c.i.t.c.new + == +:: +++ parse-json + |= j=json + ^- parsed-req + %- (ot ~[tags+pa data+(om so)]):dejs:format j +:: +++ parse-url + |= url=@t + ^- path + %- paru (trip url) +:: +++ make-css-response + |= [rid=@ta css=@t] + ^- (list card:agent:gall) + %^ make-direct-http-cards rid + [200 ['Content-Type' 'text/css'] ~] + [~ (as-octs:mimes:html css)] +:: +++ make-auth-redirect + |= rid=@ta + ^- (list card:agent:gall) + %^ make-direct-http-cards rid + [307 ['Location' '/~/login?redirect='] ~] ~ +:: +++ make-400 + |= rid=@ta + ^- (list card:agent:gall) + %^ make-direct-http-cards + rid [400 ~] ~ +:: +++ make-404 + |= [rid=@ta data=(unit octs)] + ^- (list card:agent:gall) + %^ make-direct-http-cards + rid [404 ~] data +:: +++ make-direct-http-cards + |= [rid=@ta head=response-header.simple-payload:http data=(unit octs)] + ^- (list card:agent:gall) + :~ [%give %fact ~[/http-response/[rid]] [%http-response-header !>(head)]] + [%give %fact ~[/http-response/[rid]] [%http-response-data !>(data)]] + [%give %kick ~[/http-response/[rid]] ~] + == +:: :: :: :: +:: +:: Algorithms +:: +:: :: :: :: +++ algo + |= [old=marl new=marl] + ^- marl + =/ i=@ud 0 + =/ acc=marl ~ + |- + ?~ new + ?. =(~ old) + ?: =(%skip -.-.-.old) + $(old +.old) + :_ acc + :_ ~ + :- %d + =/ c=@ud 0 + |- ^- mart + ?~ old + ~ + :- :- (crip (weld "d" <c>)) + (getv a.g.i.old %key) + $(old t.old, c +(c)) + acc + ?: &(?=(^ old) =(%skip -.-.-.old)) + $(old t.old) + ?: =(%m n.g.i.new) + $(new t.new, i +(i), acc (snoc acc i.new)) + =/ j=@ud 0 + =/ jold=marl old + =/ nkey=[n=mane k=tape] [n.g.i.new (getv a.g.i.new %key)] + |- + ?~ new + !! + ?~ jold + %= ^$ + new t.new + i +(i) + acc %+ snoc acc + ;n(id <i>) + ;+ i.new + == + == + ?~ old + !! + ?: =(%skip n.g.i.jold) + $(jold t.jold, j +(j)) + ?: .=(nkey [n.g.i.jold (getv a.g.i.jold %key)]) + ?. =(0 j) + =/ n=@ud 0 + =/ nnew=marl new + =/ okey=[n=mane k=tape] [n.g.i.old (getv a.g.i.old %key)] + |- + ?~ nnew + ^^$(old (snoc t.old i.old)) + ?: =(%m n.g.i.nnew) + $(nnew t.nnew, n +(n)) + =/ nnky=[n=mane k=tape] [n.g.i.nnew (getv a.g.i.nnew %key)] + ?. .=(okey nnky) + $(nnew t.nnew, n +(n)) + ?: (gte n j) + =/ aupd=mart (upda a.g.i.old a.g.i.nnew) + ?~ aupd + %= ^^$ + old c.i.old + new c.i.nnew + i 0 + acc + %= ^^$ + old t.old + new %^ newm new n + ;m(id <(add n i)>, key k.nnky); + == + == + %= ^^$ + old c.i.old + new c.i.nnew + i 0 + acc + %= ^^$ + old t.old + new %^ newm new n + ;m(id <(add n i)>, key k.nnky); + acc :_ acc + [[%c [[%key k.nnky] aupd]] ~] + == + == + =/ aupd=mart (upda a.g.i.jold a.g.i.new) + ?~ aupd + %= ^^$ + old c.i.jold + new c.i.new + i 0 + acc + %= ^^$ + old (newm old j ;skip;) + new t.new + i +(i) + acc %+ snoc acc + ;m(id <i>, key k.nkey); + == + == + %= ^^$ + old c.i.jold + new c.i.new + i 0 + acc + %= ^^$ + old (newm old j ;skip;) + new t.new + i +(i) + acc :- [[%c [[%key k.nkey] aupd]] ~] + %+ snoc + acc + ;m(id <i>, key k.nkey); + == + == + ?: =("text" (getv a.g.i.new %mast)) + ?: =(+.-.+.-.-.+.-.old +.-.+.-.-.+.-.new) + ^$(old t.old, new t.new, i +(i)) + %= ^$ + old t.old + new t.new + i +(i) + acc [i.new acc] + == + =/ aupd=mart (upda a.g.i.old a.g.i.new) + ?~ aupd + %= ^$ + old c.i.old + new c.i.new + i 0 + acc ^$(old t.old, new t.new, i +(i)) + == + %= ^$ + old c.i.old + new c.i.new + i 0 + acc + %= ^$ + old t.old + new t.new + i +(i) + acc :_ acc + [[%c [[%key k.nkey] aupd]] ~] + == + == + $(jold t.jold, j +(j)) +:: +++ adky + |= root=manx + |^ ^- manx + (tanx root "0" "~") + ++ tanx + |= [m=manx key=tape pkey=tape] + =/ fkey=tape (getv a.g.m %key) + =/ nkey=tape ?~(fkey key fkey) + ?: =(%$ n.g.m) + ;span + =mast "text" + =key nkey + =pkey pkey + ;+ m + == + =: a.g.m %- mart + ?~ fkey + [[%key nkey] [[%pkey pkey] a.g.m]] + [[%pkey pkey] a.g.m] + c.m (tarl c.m nkey) + == + m + ++ tarl + |= [m=marl key=tape] + =/ i=@ud 0 + |- ^- marl + ?~ m + ~ + :- %^ tanx + (manx i.m) + (weld (scow %ud i) (weld "-" key)) + key + $(m t.m, i +(i)) + -- +:: +++ getv + |= [m=mart tag=@tas] + ^- tape + ?~ m + ~ + ?: =(n.i.m tag) + v.i.m + $(m t.m) +:: +++ upda + |= [om=mart nm=mart] + =/ acc=mart ~ + |- ^- mart + ?~ nm + ?~ om + acc + :_ acc + :- %rem + =/ omom=mart om + |- + ?~ omom + ~ + =/ nom=tape +:<n.i.omom> + |- + ?~ nom + [' ' ^$(omom t.omom)] + [i.nom $(nom t.nom)] + =/ i=@ud 0 + =/ com=mart om + |- + ?~ nm + !! + ?~ com + ^$(nm t.nm, acc [i.nm acc]) + ?~ om + !! + ?: =(n.i.com n.i.nm) + ?: =(v.i.com v.i.nm) + ^$(om (oust [i 1] (mart om)), nm t.nm) + %= ^$ + om (oust [i 1] (mart om)) + nm t.nm + acc [i.nm acc] + == + $(com t.com, i +(i)) +:: +++ newm + |= [ml=marl i=@ud mx=manx] + =/ j=@ud 0 + |- ^- marl + ?~ ml + ~ + :- ?: =(i j) + mx + i.ml + $(ml t.ml, j +(j)) +:: +++ paru + |= turl=tape + ^- path + =/ tacc=tape ~ + =/ pacc=path ~ + |- + ?~ turl + ?~ tacc + pacc + (snoc pacc (crip tacc)) + ?: =('/' i.turl) + ?~ tacc + $(turl t.turl) + %= $ + turl t.turl + tacc ~ + pacc (snoc pacc (crip tacc)) + == + $(turl t.turl, tacc (snoc tacc i.turl)) +:: :: :: :: +:: +:: Sail +:: +:: :: :: :: +++ script-node + ^- manx + ;script + ;+ ;/ script + == +++ sail-404 + ^- manx + ;html + ;head + ;meta(charset "utf-8"); + == + ;body + ;span: 404 + == + == +:: :: :: :: +:: +:: Script +:: +:: :: :: :: +++ script + ^~ + %- trip + ''' + let ship; + let app; + let displayUpdatePath; + let channelMessageId = 0; + let eventSource; + const channelId = `${Date.now()}${Math.floor(Math.random() * 100)}`; + const channelPath = `${window.location.origin}/~/channel/${channelId}`; + addEventListener('DOMContentLoaded', async () => { + ship = document.documentElement.getAttribute('ship'); + app = document.documentElement.getAttribute('app'); + displayUpdatePath = document.documentElement.getAttribute('path'); + await connectToShip(); + let eventElements = document.querySelectorAll('[event]'); + eventElements.forEach(el => setEventListeners(el)); + }); + function setEventListeners(el) { + const eventTags = el.getAttribute('event'); + const returnTags = el.getAttribute('return'); + eventTags.split(/\s+/).forEach(eventStr => { + const eventType = eventStr.split('/', 2)[1]; + el[`on${eventType}`] = (e) => pokeShip(e, eventStr, returnTags); + }); + }; + async function connectToShip() { + try { + const storageKey = `${ship}${app}${displayUpdatePath}`; + let storedId = localStorage.getItem(storageKey); + localStorage.setItem(storageKey, channelId); + if (storedId) { + const delPath = `${window.location.origin}/~/channel/${storedId}`; + await fetch(delPath, { + method: 'PUT', + body: JSON.stringify([{ + id: channelMessageId, + action: 'delete' + }]) + }); + }; + const body = JSON.stringify(makeSubscribeBody()); + await fetch(channelPath, { + method: 'PUT', + body + }); + eventSource = new EventSource(channelPath); + eventSource.addEventListener('message', handleChannelStream); + } catch (error) { + console.error(error); + }; + }; + function pokeShip(event, tagString, dataString) { + try { + let data = {}; + if (dataString) { + const dataToReturn = dataString.split(/\s+/); + dataToReturn.forEach(dataTag => { + let splitDataTag = dataTag.split('/'); + if (splitDataTag[0] === '') splitDataTag.shift(); + const kind = splitDataTag[0]; + const key = splitDataTag.pop(); + if (kind === 'event') { + if (!(key in event)) { + console.error(`Property: ${key} does not exist on the event object`); + return; + }; + data[dataTag] = String(event[key]); + } else if (kind === 'target') { + if (!(key in event.currentTarget)) { + console.error(`Property: ${key} does not exist on the target object`); + return; + }; + data[dataTag] = String(event.currentTarget[key]); + } else { + const elementId = splitDataTag.join('/'); + const linkedEl = document.getElementById(elementId); + if (!linkedEl) { + console.error(`No element found for id: ${kind}`); + return; + }; + if (!(key in linkedEl)) { + console.error(`Property: ${key} does not exist on the object with id: ${elementId}`); + return; + }; + data[dataTag] = String(linkedEl[key]); + }; + }); + }; + fetch(channelPath, { + method: 'PUT', + body: JSON.stringify(makePokeBody({ + tags: tagString, + data + })) + }); + } catch (error) { + console.error(error); + }; + }; + function handleChannelStream(event) { + try { + const streamResponse = JSON.parse(event.data); + if (streamResponse.response !== 'diff') return; + fetch(channelPath, { + method: 'PUT', + body: JSON.stringify(makeAck(streamResponse.id)) + }); + const htmlData = streamResponse.json; + if (!htmlData) return; + let container = document.createElement('template'); + container.innerHTML = htmlData; + if (container.content.firstElementChild.childNodes.length === 0) return; + const navUrl = container.content.firstElementChild.getAttribute('url'); + if (navUrl && (navUrl !== window.location.pathname)) { + history.pushState({}, '', navUrl); + }; + while (container.content.firstElementChild.children.length > 0) { + let gustChild = container.content.firstElementChild.firstElementChild; + if (gustChild.tagName === 'D') { + for (const att of gustChild.attributes) { + const dkey = att.value; + document.querySelector(`[key="${dkey}"]`).remove(); + }; + gustChild.remove(); + } else if (gustChild.tagName === 'N') { + const nodeKey = gustChild.firstElementChild.getAttribute('key'); + const parentKey = gustChild.firstElementChild.getAttribute('pkey'); + const appendIndex = gustChild.id; + let domParent = document.querySelector(`[key="${parentKey}"]`); + domParent.insertBefore(gustChild.firstElementChild, domParent.children[appendIndex]); + let appendedChild = domParent.querySelector(`[key="${nodeKey}"]`); + if (appendedChild.getAttribute('event')) { + setEventListeners(appendedChild); + }; + if (appendedChild.childElementCount > 0) { + let needingListeners = appendedChild.querySelectorAll('[event]'); + needingListeners.forEach(child => setEventListeners(child)); + }; + appendedChild = appendedChild.nextElementSibling; + gustChild.remove(); + } else if (gustChild.tagName === 'M') { + const nodeKey = gustChild.getAttribute('key'); + const nodeIndex = gustChild.id; + let existentNode = document.querySelector(`[key="${nodeKey}"]`); + let childAtIndex = existentNode.parentElement.children[nodeIndex]; + if (existentNode.nextElementSibling + && (existentNode.nextElementSibling.getAttribute('key') + === childAtIndex.getAttribute('key'))) { + existentNode.parentElement.insertBefore(existentNode, childAtIndex.nextElementSibling); + } else { + existentNode.parentElement.insertBefore(existentNode, childAtIndex); + }; + gustChild.remove(); + } else if (gustChild.tagName === 'C') { + const nodeKey = gustChild.getAttribute('key'); + const attToRem = gustChild.getAttribute('rem')?.slice(0, -1).split(' ') ?? []; + let existentNode = document.querySelector(`[key="${nodeKey}"]`); + attToRem.forEach(att => { + if (att === 'event') { + const eventType = existentNode.getAttribute('event').split('/', 2)[1]; + existentNode[`on${eventType}`] = null; + }; + existentNode.removeAttribute(att); + }); + gustChild.removeAttribute('key'); + gustChild.removeAttribute('rem'); + for (const att of gustChild.attributes) { + existentNode.setAttribute(att.name, att.value); + if (att.name === 'event') { + const eventType = existentNode.getAttribute('event').split('/', 2)[1]; + existentNode[`on${eventType}`] = null; + setEventListeners(existentNode); + }; + }; + gustChild.remove(); + } else { + const nodeKey = gustChild.getAttribute('key'); + let existentNode = document.querySelector(`[key="${nodeKey}"]`); + existentNode.replaceWith(gustChild); + let replacedNode = document.querySelector(`[key="${nodeKey}"]`); + if (replacedNode.getAttribute('event')) { + setEventListeners(replacedNode); + }; + if (replacedNode.childElementCount > 0) { + let needingListeners = replacedNode.querySelectorAll('[event]'); + needingListeners.forEach(child => setEventListeners(child)); + }; + }; + }; + } catch (error) { + console.error(error); + }; + }; + function makeSubscribeBody() { + channelMessageId++; + return [{ + id: channelMessageId, + action: 'subscribe', + ship: ship, + app: app, + path: displayUpdatePath + }]; + }; + function makePokeBody(jsonData) { + channelMessageId++; + return [{ + id: channelMessageId, + action: 'poke', + ship: ship, + app: app, + mark: 'json', + json: jsonData + }]; + }; + function makeAck(eventId) { + channelMessageId++; + return [{ + id: channelMessageId, + action: 'ack', + "event-id": eventId + }]; + }; + ''' +--
\ No newline at end of file diff --git a/desk/lib/mmast.hoon b/desk/lib/mmast.hoon new file mode 100644 index 0000000..319c201 --- /dev/null +++ b/desk/lib/mmast.hoon @@ -0,0 +1,693 @@ + +:: :: :: :: +:: +:: Mast - a Sail framework +:: +:: [v.1.0.1] +:: +:: +:: This library contains a system for building fully dynamic Sail front-ends +:: where all front-end app state and the current state of the display itself +:: live on your ship. +:: +:: A small script that is generic to any application is inserted into your Sail +:: and used to establish an Eyre channel, receive display updates from your ship, +:: and to sync the browser with them. +:: +:: Events on the browser are handled completely within your ship, +:: without the need to write a single line of JavaScript. +:: You may describe event listeners in your Sail components with attributes like this: +:: =event "/click/..." +:: The first segment of the path is the event listener name, +:: with further segments defining an arbitrary endpoint for an event handler on your agent. +:: Events are sent as pokes under a json mark, which can be parsed with the library. +:: You may also return data from the event like this: +:: =return "/target/value" +:: The first segment is the object to return data from, and the second is the property to return. +:: Data can be returned from the target element, event object, or any other element associated by id. +:: +:: When the display state changes as a result of events initiated on the browser, +:: or from any other kind of event in the agent, updates to the browser containing +:: only the necessary amount of html to achieve this state are sent and swapped in. +:: +:: +:: The server section contains all of the arms for usage in your app. +:: Rig, plank, and gust are the main arms. See the description of these arms below. +:: +:: For more details visit: https://github.com/R-JG/mast +:: +:: :: :: :: +|% ++$ sail-gate $-([app-state=* =bowl:gall] manx) ++$ router $-(path sail-gate) ++$ parsed-req [tags=path data=(map @t @t)] +:: :: :: :: +:: +:: Server +:: +:: :: :: :: +:: +:: - The rig arm is used to produce a new instance of the display state. +:: - "yards" is the list of your app's routes, each corresponding to a root level Sail component +:: (i.e. a complete document with html, head, and body tags). +:: - "url" is either the request url from Eyre in the context of a direct http request, +:: or the current url (this should be saved in state). +:: - "app-state" represents the total sample for each of your root level Sail components +:: (currently, root level Sail components in yards each need to take the same sample). +:: - Rig uses the url to select the matching yard and renders its Sail component. +:: - The newly produced display state should then be used with either plank or gust, +:: and saved as the current display state in the agent. +:: +++ rig + |* [=router url=path app-state=* =bowl:gall] + ^- manx + =/ sail (router url) + (sail app-state bowl) +:: +:: - The plank arm is used for serving whole pages in response to %handle-http-request pokes, +:: acting as the first point of contact for the app. +:: - Plank needs to take some basic information about the page that you are serving: +:: - "app" is the name of the app, +:: - "sub" is the subscription path that the client will subscribe to for receiving display updates, +:: - "ship" is your patp, +:: - "rid" is the Eyre id from the %handle-http-request poke, +:: - "new" is the newly rendered display state produced with rig. +:: - Plank produces a list of cards serving the http response. +:: +:: ++ plank +:: |= [eyre-id=@ta m=manx =bowl:gall] +:: ^- (list card:agent:gall) +:: %^ make-direct-http-cards eyre-id +:: [200 ['Content-Type' 'text/html'] ~] +:: :- ~ +:: ^- octs +:: %- as-octt:mimes:html +:: %- en-xml:html +:: ^- manx +:: %= m +:: a.g %- mart :^ +:: [%app (trip dap.bowl)] +:: [%path "/ui"] +:: [%ship (scow %p our.bowl)] +:: a.g.m +:: c.i.c (marl [script-node c.i.c.m]) +:: == +:: +:: - The gust arm is used for producing a set of display updates for the browser, +:: used typically after making changes to your app's state, and rendering new display data with rig. +:: - "sub" is the subscription path that was sent initially in plank, where gust will send the updates. +:: - "old" is the display state that is currently saved in your agent's state, +:: produced some time previously by rig. +:: - "new" is the new display data to be produced with rig just before gust gets used. +:: - Gust can be used anywhere you'd make a subscription update (in contrast to plank). +:: - Gust produces a single card. +:: +++ gast + |= [old=manx new=manx] + ?~ c.old !! + ?~ c.new !! + ?~ t.c.old !! + ?~ t.c.new !! + ?~ a.g.new !! + ^- manx + ;g + =url v.i.a.g.new + ;* %+ algo + c.i.t.c.old + c.i.t.c.new + == +:: ++ gust +:: |= [old=manx new=manx] +:: ^- card:agent:gall +:: ?~ c.old !! +:: ?~ c.new !! +:: ?~ t.c.old !! +:: ?~ t.c.new !! +:: ?~ a.g.new !! +:: :^ %give %fact /ui +:: :- %json +:: !> %- tape:enjs:format +:: %- en-xml:html +:: ^- manx +:: ;g +:: =url v.i.a.g.new +:: ;* %+ algo +:: c.i.t.c.old +:: c.i.t.c.new +:: == +:: +++ parse-json + |= j=json + ^- parsed-req + %- (ot ~[tags+pa data+(om so)]):dejs:format j +:: +++ parse-url + |= url=@t + ^- path + %- paru (trip url) +:: +++ make-css-response + |= [rid=@ta css=@t] + ^- (list card:agent:gall) + %^ make-direct-http-cards rid + [200 ['Content-Type' 'text/css'] ~] + [~ (as-octs:mimes:html css)] +:: +++ make-auth-redirect + |= rid=@ta + ^- (list card:agent:gall) + %^ make-direct-http-cards rid + [307 ['Location' '/~/login?redirect='] ~] ~ +:: +++ make-400 + |= rid=@ta + ^- (list card:agent:gall) + %^ make-direct-http-cards + rid [400 ~] ~ +:: +++ make-404 + |= [rid=@ta data=(unit octs)] + ^- (list card:agent:gall) + %^ make-direct-http-cards + rid [404 ~] data +:: +++ make-direct-http-cards + |= [rid=@ta head=response-header.simple-payload:http data=(unit octs)] + ^- (list card:agent:gall) + :~ [%give %fact ~[/http-response/[rid]] [%http-response-header !>(head)]] + [%give %fact ~[/http-response/[rid]] [%http-response-data !>(data)]] + [%give %kick ~[/http-response/[rid]] ~] + == +:: :: :: :: +:: +:: Algorithms +:: +:: :: :: :: +++ algo + |= [old=marl new=marl] + ^- marl + =/ i=@ud 0 + =/ acc=marl ~ + |- + ?~ new + ?. =(~ old) + ?: =(%skip -.-.-.old) + $(old +.old) + :_ acc + :_ ~ + :- %d + =/ c=@ud 0 + |- ^- mart + ?~ old + ~ + :- :- (crip (weld "d" <c>)) + (getv a.g.i.old %key) + $(old t.old, c +(c)) + acc + ?: &(?=(^ old) =(%skip -.-.-.old)) + $(old t.old) + ?: =(%m n.g.i.new) + $(new t.new, i +(i), acc (snoc acc i.new)) + =/ j=@ud 0 + =/ jold=marl old + =/ nkey=[n=mane k=tape] [n.g.i.new (getv a.g.i.new %key)] + |- + ?~ new + !! + ?~ jold + %= ^$ + new t.new + i +(i) + acc %+ snoc acc + ;n(id <i>) + ;+ i.new + == + == + ?~ old + !! + ?: =(%skip n.g.i.jold) + $(jold t.jold, j +(j)) + ?: .=(nkey [n.g.i.jold (getv a.g.i.jold %key)]) + ?. =(0 j) + =/ n=@ud 0 + =/ nnew=marl new + =/ okey=[n=mane k=tape] [n.g.i.old (getv a.g.i.old %key)] + |- + ?~ nnew + ^^$(old (snoc t.old i.old)) + ?: =(%m n.g.i.nnew) + $(nnew t.nnew, n +(n)) + =/ nnky=[n=mane k=tape] [n.g.i.nnew (getv a.g.i.nnew %key)] + ?. .=(okey nnky) + $(nnew t.nnew, n +(n)) + ?: (gte n j) + =/ aupd=mart (upda a.g.i.old a.g.i.nnew) + ?~ aupd + %= ^^$ + old c.i.old + new c.i.nnew + i 0 + acc + %= ^^$ + old t.old + new %^ newm new n + ;m(id <(add n i)>, key k.nnky); + == + == + %= ^^$ + old c.i.old + new c.i.nnew + i 0 + acc + %= ^^$ + old t.old + new %^ newm new n + ;m(id <(add n i)>, key k.nnky); + acc :_ acc + [[%c [[%key k.nnky] aupd]] ~] + == + == + =/ aupd=mart (upda a.g.i.jold a.g.i.new) + ?~ aupd + %= ^^$ + old c.i.jold + new c.i.new + i 0 + acc + %= ^^$ + old (newm old j ;skip;) + new t.new + i +(i) + acc %+ snoc acc + ;m(id <i>, key k.nkey); + == + == + %= ^^$ + old c.i.jold + new c.i.new + i 0 + acc + %= ^^$ + old (newm old j ;skip;) + new t.new + i +(i) + acc :- [[%c [[%key k.nkey] aupd]] ~] + %+ snoc + acc + ;m(id <i>, key k.nkey); + == + == + ?: =("text" (getv a.g.i.new %mast)) + ?: =(+.-.+.-.-.+.-.old +.-.+.-.-.+.-.new) + ^$(old t.old, new t.new, i +(i)) + %= ^$ + old t.old + new t.new + i +(i) + acc [i.new acc] + == + =/ aupd=mart (upda a.g.i.old a.g.i.new) + ?~ aupd + %= ^$ + old c.i.old + new c.i.new + i 0 + acc ^$(old t.old, new t.new, i +(i)) + == + %= ^$ + old c.i.old + new c.i.new + i 0 + acc + %= ^$ + old t.old + new t.new + i +(i) + acc :_ acc + [[%c [[%key k.nkey] aupd]] ~] + == + == + $(jold t.jold, j +(j)) +:: +++ adky + |= root=manx + |^ ^- manx + (tanx root "0" "~") + ++ tanx + |= [m=manx key=tape pkey=tape] + =/ fkey=tape (getv a.g.m %key) + =/ nkey=tape ?~(fkey key fkey) + ?: =(%$ n.g.m) + ;span + =mast "text" + =key nkey + =pkey pkey + ;+ m + == + =: a.g.m %- mart + ?~ fkey + [[%key nkey] [[%pkey pkey] a.g.m]] + [[%pkey pkey] a.g.m] + c.m (tarl c.m nkey) + == + m + ++ tarl + |= [m=marl key=tape] + =/ i=@ud 0 + |- ^- marl + ?~ m + ~ + :- %^ tanx + (manx i.m) + (weld (scow %ud i) (weld "-" key)) + key + $(m t.m, i +(i)) + -- +:: +++ getv + |= [m=mart tag=@tas] + ^- tape + ?~ m + ~ + ?: =(n.i.m tag) + v.i.m + $(m t.m) +:: +++ upda + |= [om=mart nm=mart] + =/ acc=mart ~ + |- ^- mart + ?~ nm + ?~ om + acc + :_ acc + :- %rem + =/ omom=mart om + |- + ?~ omom + ~ + =/ nom=tape +:<n.i.omom> + |- + ?~ nom + [' ' ^$(omom t.omom)] + [i.nom $(nom t.nom)] + =/ i=@ud 0 + =/ com=mart om + |- + ?~ nm + !! + ?~ com + ^$(nm t.nm, acc [i.nm acc]) + ?~ om + !! + ?: =(n.i.com n.i.nm) + ?: =(v.i.com v.i.nm) + ^$(om (oust [i 1] (mart om)), nm t.nm) + %= ^$ + om (oust [i 1] (mart om)) + nm t.nm + acc [i.nm acc] + == + $(com t.com, i +(i)) +:: +++ newm + |= [ml=marl i=@ud mx=manx] + =/ j=@ud 0 + |- ^- marl + ?~ ml + ~ + :- ?: =(i j) + mx + i.ml + $(ml t.ml, j +(j)) +:: +++ paru + |= turl=tape + ^- path + =/ tacc=tape ~ + =/ pacc=path ~ + |- + ?~ turl + ?~ tacc + pacc + (snoc pacc (crip tacc)) + ?: =('/' i.turl) + ?~ tacc + $(turl t.turl) + %= $ + turl t.turl + tacc ~ + pacc (snoc pacc (crip tacc)) + == + $(turl t.turl, tacc (snoc tacc i.turl)) +:: :: :: :: +:: +:: Sail +:: +:: :: :: :: +++ script-node + ^- manx + ;script + ;+ ;/ script + == +++ sail-404 + ^- manx + ;html + ;head + ;meta(charset "utf-8"); + == + ;body + ;span: 404 + == + == +:: :: :: :: +:: +:: Script +:: +:: :: :: :: +++ script + ^~ + %- trip + ''' + let ship; + let app; + let displayUpdatePath; + let channelMessageId = 0; + let eventSource; + const channelId = `${Date.now()}${Math.floor(Math.random() * 100)}`; + const channelPath = `${window.location.origin}/~/channel/${channelId}`; + addEventListener('DOMContentLoaded', async () => { + ship = document.documentElement.getAttribute('ship'); + app = document.documentElement.getAttribute('app'); + displayUpdatePath = document.documentElement.getAttribute('path'); + await connectToShip(); + let eventElements = document.querySelectorAll('[event]'); + eventElements.forEach(el => setEventListeners(el)); + }); + function setEventListeners(el) { + const eventTags = el.getAttribute('event'); + const returnTags = el.getAttribute('return'); + eventTags.split(/\s+/).forEach(eventStr => { + const eventType = eventStr.split('/', 2)[1]; + el[`on${eventType}`] = (e) => pokeShip(e, eventStr, returnTags); + }); + }; + async function connectToShip() { + try { + const storageKey = `${ship}${app}${displayUpdatePath}`; + let storedId = localStorage.getItem(storageKey); + localStorage.setItem(storageKey, channelId); + if (storedId) { + const delPath = `${window.location.origin}/~/channel/${storedId}`; + await fetch(delPath, { + method: 'PUT', + body: JSON.stringify([{ + id: channelMessageId, + action: 'delete' + }]) + }); + }; + const body = JSON.stringify(makeSubscribeBody()); + await fetch(channelPath, { + method: 'PUT', + body + }); + eventSource = new EventSource(channelPath); + eventSource.addEventListener('message', handleChannelStream); + } catch (error) { + console.error(error); + }; + }; + function pokeShip(event, tagString, dataString) { + try { + let data = {}; + if (dataString) { + const dataToReturn = dataString.split(/\s+/); + dataToReturn.forEach(dataTag => { + let splitDataTag = dataTag.split('/'); + if (splitDataTag[0] === '') splitDataTag.shift(); + const kind = splitDataTag[0]; + const key = splitDataTag.pop(); + if (kind === 'event') { + if (!(key in event)) { + console.error(`Property: ${key} does not exist on the event object`); + return; + }; + data[dataTag] = String(event[key]); + } else if (kind === 'target') { + if (!(key in event.currentTarget)) { + console.error(`Property: ${key} does not exist on the target object`); + return; + }; + data[dataTag] = String(event.currentTarget[key]); + } else { + const elementId = splitDataTag.join('/'); + const linkedEl = document.getElementById(elementId); + if (!linkedEl) { + console.error(`No element found for id: ${kind}`); + return; + }; + if (!(key in linkedEl)) { + console.error(`Property: ${key} does not exist on the object with id: ${elementId}`); + return; + }; + data[dataTag] = String(linkedEl[key]); + }; + }); + }; + fetch(channelPath, { + method: 'PUT', + body: JSON.stringify(makePokeBody({ + tags: tagString, + data + })) + }); + } catch (error) { + console.error(error); + }; + }; + function handleChannelStream(event) { + try { + const streamResponse = JSON.parse(event.data); + if (streamResponse.response !== 'diff') return; + fetch(channelPath, { + method: 'PUT', + body: JSON.stringify(makeAck(streamResponse.id)) + }); + const htmlData = streamResponse.json; + if (!htmlData) return; + let container = document.createElement('template'); + container.innerHTML = htmlData; + if (container.content.firstElementChild.childNodes.length === 0) return; + const navUrl = container.content.firstElementChild.getAttribute('url'); + if (navUrl && (navUrl !== window.location.pathname)) { + history.pushState({}, '', navUrl); + }; + while (container.content.firstElementChild.children.length > 0) { + let gustChild = container.content.firstElementChild.firstElementChild; + if (gustChild.tagName === 'D') { + for (const att of gustChild.attributes) { + const dkey = att.value; + document.querySelector(`[key="${dkey}"]`).remove(); + }; + gustChild.remove(); + } else if (gustChild.tagName === 'N') { + const nodeKey = gustChild.firstElementChild.getAttribute('key'); + const parentKey = gustChild.firstElementChild.getAttribute('pkey'); + const appendIndex = gustChild.id; + let domParent = document.querySelector(`[key="${parentKey}"]`); + domParent.insertBefore(gustChild.firstElementChild, domParent.children[appendIndex]); + let appendedChild = domParent.querySelector(`[key="${nodeKey}"]`); + if (appendedChild.getAttribute('event')) { + setEventListeners(appendedChild); + }; + if (appendedChild.childElementCount > 0) { + let needingListeners = appendedChild.querySelectorAll('[event]'); + needingListeners.forEach(child => setEventListeners(child)); + }; + appendedChild = appendedChild.nextElementSibling; + gustChild.remove(); + } else if (gustChild.tagName === 'M') { + const nodeKey = gustChild.getAttribute('key'); + const nodeIndex = gustChild.id; + let existentNode = document.querySelector(`[key="${nodeKey}"]`); + let childAtIndex = existentNode.parentElement.children[nodeIndex]; + if (existentNode.nextElementSibling + && (existentNode.nextElementSibling.getAttribute('key') + === childAtIndex.getAttribute('key'))) { + existentNode.parentElement.insertBefore(existentNode, childAtIndex.nextElementSibling); + } else { + existentNode.parentElement.insertBefore(existentNode, childAtIndex); + }; + gustChild.remove(); + } else if (gustChild.tagName === 'C') { + const nodeKey = gustChild.getAttribute('key'); + const attToRem = gustChild.getAttribute('rem')?.slice(0, -1).split(' ') ?? []; + let existentNode = document.querySelector(`[key="${nodeKey}"]`); + attToRem.forEach(att => { + if (att === 'event') { + const eventType = existentNode.getAttribute('event').split('/', 2)[1]; + existentNode[`on${eventType}`] = null; + }; + existentNode.removeAttribute(att); + }); + gustChild.removeAttribute('key'); + gustChild.removeAttribute('rem'); + for (const att of gustChild.attributes) { + existentNode.setAttribute(att.name, att.value); + if (att.name === 'event') { + const eventType = existentNode.getAttribute('event').split('/', 2)[1]; + existentNode[`on${eventType}`] = null; + setEventListeners(existentNode); + }; + }; + gustChild.remove(); + } else { + const nodeKey = gustChild.getAttribute('key'); + let existentNode = document.querySelector(`[key="${nodeKey}"]`); + existentNode.replaceWith(gustChild); + let replacedNode = document.querySelector(`[key="${nodeKey}"]`); + if (replacedNode.getAttribute('event')) { + setEventListeners(replacedNode); + }; + if (replacedNode.childElementCount > 0) { + let needingListeners = replacedNode.querySelectorAll('[event]'); + needingListeners.forEach(child => setEventListeners(child)); + }; + }; + }; + } catch (error) { + console.error(error); + }; + }; + function makeSubscribeBody() { + channelMessageId++; + return [{ + id: channelMessageId, + action: 'subscribe', + ship: ship, + app: app, + path: displayUpdatePath + }]; + }; + function makePokeBody(jsonData) { + channelMessageId++; + return [{ + id: channelMessageId, + action: 'poke', + ship: ship, + app: app, + mark: 'json', + json: jsonData + }]; + }; + function makeAck(eventId) { + channelMessageId++; + return [{ + id: channelMessageId, + action: 'ack', + "event-id": eventId + }]; + }; + ''' +--
\ No newline at end of file diff --git a/desk/lib/mop-extensions.hoon b/desk/lib/mop-extensions.hoon new file mode 100644 index 0000000..e82e286 --- /dev/null +++ b/desk/lib/mop-extensions.hoon @@ -0,0 +1,158 @@ +|* [key=mold val=mold] +=> |% + +$ item [key=key val=val] + -- +~% %mope-comp ..zuse ~ +|= compare=$-([key key] ?) +~% %mope-core ..zuse ~ +|% +:: +uno: merge with conflict resolution function +:: +++ uno + ~/ %uno + |= [a=(tree item) b=(tree item)] + |= [meg=$-([key val val] val)] + ^- (tree item) + ?~ b a + ?~ a b + ?: =(key.n.a key.n.b) + :- n=[key.n.a (meg key.n.a val.n.a val.n.b)] + [l=$(a l.a, b l.b) r=$(a r.a, b r.b)] + ?: (mor key.n.a key.n.b) + ?: (compare key.n.b key.n.a) + $(l.a $(a l.a, r.b ~), b r.b) + $(r.a $(a r.a, l.b ~), b l.b) + ?: (compare key.n.a key.n.b) + $(l.b $(b l.b, r.a ~), a r.a) + $(r.b $(b r.b, l.a ~), a l.a) +:: +bat: tabulate a subset excluding start element with a max count (backwards) +:: +++ bat + |= [a=(tree item) b=(unit key) c=@] + ^- (list item) + |^ + e:(tabulate (del-span a b) b c) + :: + ++ tabulate + |= [a=(tree item) b=(unit key) c=@] + ^- [d=@ e=(list item)] + ?: ?&(?=(~ b) =(c 0)) + [0 ~] + =| f=[d=@ e=(list item)] + |- ^+ f + ?: ?|(?=(~ a) =(d.f c)) f + =. f $(a r.a) + ?: =(d.f c) f + =. f [+(d.f) [n.a e.f]] + ?:(=(d.f c) f $(a l.a)) + :: + ++ del-span + |= [a=(tree item) b=(unit key)] + ^- (tree item) + ?~ a a + ?~ b a + ?: =(key.n.a u.b) + l.a + ?. (compare key.n.a u.b) + $(a l.a) + a(r $(a r.a)) + -- +:: +dop: dip:on but in reverse order (right to left) +:: +++ dop + |* state=mold + |= $: a=(tree item) + =state + f=$-([state item] [(unit val) ? state]) + == + ^+ [state a] + :: acc: accumulator + :: + :: .stop: set to %.y by .f when done traversing + :: .state: threaded through each run of .f and produced by +abet + :: + =/ acc [stop=`?`%.n state=state] + =< abet =< main + |% + ++ this . + ++ abet [state.acc a] + :: +main: main recursive loop; performs a partial inorder traversal + :: + ++ main + ^+ this + :: stop if empty or we've been told to stop + :: + ?: =(~ a) this + ?: stop.acc this + :: reverse in-order traversal: right -> node -> left, until .f sets .stop + :: + =. this right + ?: stop.acc this + =^ del this node + =? this !stop.acc left + :: XX: remove for now; bring back when upstreaming + :: =? a del (nip a) + this + :: +node: run .f on .n.a, updating .a, .state, and .stop + :: + ++ node + ^+ [del=*? this] + :: run .f on node, updating .stop.acc and .state.acc + :: + ?> ?=(^ a) + =^ res acc (f state.acc n.a) + ?~ res + [del=& this] + [del=| this(val.n.a u.res)] + :: +left: recurse on left subtree, copying mutant back into .l.a + :: + ++ left + ^+ this + ?~ a this + =/ lef main(a l.a) + lef(a a(l a.lef)) + :: +right: recurse on right subtree, copying mutant back into .r.a + :: + ++ right + ^+ this + ?~ a this + =/ rig main(a r.a) + rig(a a(r a.rig)) + -- +:: +bot: produce the N leftmost elements +:: +++ bot + |= [a=(tree item) b=@] + ^- (list item) + |^ p:(items-with-remainder a b) + ++ items-with-remainder + |= [a=(tree item) b=@] + ^- (pair (list item) @) + ?~ a [~ b] + ?: =(b 0) [~ 0] + =/ left-result (items-with-remainder l.a b) + ?: =(q.left-result 0) left-result + ?: =(q.left-result 1) [(zing ~[p.left-result ~[n.a]]) (dec q.left-result)] + =/ right-result + (items-with-remainder r.a (dec q.left-result)) + [(zing ~[p.left-result ~[n.a] p.right-result]) q.right-result] + -- +:: +top: produce the N rightmost elements +:: +++ top + |= [a=(tree item) b=@] + ^- (list item) + |^ p:(items-with-remainder a b) + ++ items-with-remainder + |= [a=(tree item) b=@] + ^- (pair (list item) @) + ?~ a [~ b] + ?: =(b 0) [~ 0] + =/ right-result (items-with-remainder r.a b) + ?: =(q.right-result 0) right-result + ?: =(q.right-result 1) [[n.a p.right-result] (dec q.right-result)] + =/ left-result + (items-with-remainder l.a (dec q.right-result)) + [(zing ~[p.left-result ~[n.a] p.right-result]) q.left-result] + -- +-- diff --git a/desk/lib/new-sigil/core.hoon b/desk/lib/new-sigil/core.hoon new file mode 100644 index 0000000..342689b --- /dev/null +++ b/desk/lib/new-sigil/core.hoon @@ -0,0 +1,9 @@ +/+ symbols=sigil-symbols +|% +=| p=@p +++ $ +=/ background "#000" +=/ foreground "#FFF" +=/ size 128 +=/ phonemes (chunk p) +--
\ No newline at end of file diff --git a/desk/lib/new-sigil/symbols.hoon b/desk/lib/new-sigil/symbols.hoon new file mode 100644 index 0000000..4069f1d --- /dev/null +++ b/desk/lib/new-sigil/symbols.hoon @@ -0,0 +1,1026 @@ +|% + ++ bac +"<g transform='@TR'><path d='M0 0C0 70.6925 57.3075 128 128 128V0H0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><line x1='-0.0029152' x2='127.983' y2='127.986' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/><circle cx='64' cy='64' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='64' cy='64' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/><circle cx='16' cy='112' r='11.5' fill='@BG' stroke='@BG' stroke-width='@SW'/><circle cx='16' cy='112' r='9' fill='@FG' stroke='@FG' stroke-width='@SW'/></g>", + ++ bal +"<g transform='@TR'><path d='M0.0541 0C70.7217 0.0292317 128 57.3256 128 128C57.3177 128 0.0164917 70.7089 7.62806e-06 0.0305091C7.62851e-06 0.0203397 -4.44317e-10 0.01017 0 0H0.0541Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><circle cx='32' cy='32' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='32' cy='32' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/><line x1='0.5' y1='-0.5' x2='181.5' y2='-0.5' transform='matrix(-0.707107 0.707107 0.707107 0.707107 128.71 0)' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/><line x1='128' y1='32.0072' x2='32.7071' y2='127.3' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/><line x1='128' y1='64.0072' x2='64.7071' y2='127.3' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/><line x1='128' y1='96.0072' x2='96.7071' y2='127.3' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/></g>", + ++ ban +"<g transform='@TR'><path d='M0 0C0 70.6925 57.3075 128 128 128V0H0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M128 0C128 70.6924 70.6924 128 -1.52588e-05 128' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ bar +"<g transform='@TR'><circle cx='64' cy='64' r='64' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M-0.00292969 0L127.997 128' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/><circle cx='64' cy='64' r='16' stroke='@BG' fill='none' stroke-width='@SW'/><circle cx='32' cy='32' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='32' cy='32' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ bat +"<g transform='@TR'><path d='M0 0C0 70.6925 57.3075 128 128 128V0H0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M128 0C128 35.3462 99.3462 64 64 64C28.6538 64 0 35.3462 0 0' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ bec +"<g transform='@TR'><path d='M128 128C128 57.3076 70.6925 6.18013e-06 1.11901e-05 0L0 128L128 128Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M-0.00280762 0L127.997 128' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/><path fill-rule='evenodd' clip-rule='evenodd' d='M80 64C80 72.8366 72.8366 80 64 80C55.1634 80 48 72.8366 48 64C48 55.1634 55.1634 48 64 48C72.8366 48 80 55.1634 80 64ZM64 72C68.4183 72 72 68.4183 72 64C72 59.5817 68.4183 56 64 56C59.5817 56 56 59.5817 56 64C56 68.4183 59.5817 72 64 72Z' fill='@BG'/></g>", + ++ bel +"<g transform='@TR'><path d='M0 127.946C0.0292286 57.2783 57.3256 3.08928e-06 128 0C128 70.6823 70.7089 127.984 0.0305092 128C0.0203397 128 0.01017 128 2.36469e-09 128L0 127.946Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><circle cx='64' cy='64' r='32' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ ben +"<g transform='@TR'><rect width='128' height='128' fill='@FG' stroke='@BG' stroke-width='@SW'/><circle cx='64' cy='64' r='8' stroke='@BG' fill='none' stroke-width='@SW'/><circle cx='32' cy='64' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='32' cy='64' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ bep +"<g transform='@TR'><path d='M128 0C57.3075 8.42999e-07 -8.42999e-07 57.3075 0 128H128V0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M128 64C92.6538 64 64 92.6538 64 128' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ ber +"<g transform='@TR'><path d='M64 128H0L5.59506e-06 0L64 5.59506e-06C99.3462 8.68512e-06 128 28.6538 128 64C128 99.3462 99.3462 128 64 128Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M96 0L96 128' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ bes +"<g transform='@TR'><path d='M128 128C128 57.3076 70.6925 6.18013e-06 1.11901e-05 0L0 128L128 128Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M64 128C64 92.6538 35.3462 64 0 64' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M-0.00280762 0L127.997 128' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/></g>", + ++ bet +"<g transform='@TR'><circle cx='64' cy='64' r='64' fill='@FG' stroke='@BG' stroke-width='@SW'/><line x1='16.0036' y1='15.9965' x2='48.0036' y2='47.9965' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ bex +"<g transform='@TR'><path d='M64 128H0L5.59506e-06 0L64 5.59506e-06C99.3462 8.68512e-06 128 28.6538 128 64C128 99.3462 99.3462 128 64 128Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><line x1='16.0036' y1='15.9965' x2='48.0036' y2='47.9965' stroke='@BG' fill='none' stroke-width='@SW'/><path fill-rule='evenodd' clip-rule='evenodd' d='M80 64C80 72.8366 72.8366 80 64 80C55.1634 80 48 72.8366 48 64C48 55.1634 55.1634 48 64 48C72.8366 48 80 55.1634 80 64ZM64 72C68.4183 72 72 68.4183 72 64C72 59.5817 68.4183 56 64 56C59.5817 56 56 59.5817 56 64C56 68.4183 59.5817 72 64 72Z' fill='@BG'/></g>", + ++ bic +"<g transform='@TR'><path d='M0 0C0 70.6925 57.3075 128 128 128V0H0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M128 96C74.9807 96 32 53.0193 32 -4.19629e-06' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ bid +"<g transform='@TR'><path d='M0 0C0 70.6925 57.3075 128 128 128V0H0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M32 0C32 70.6925 74.9807 128 128 128' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M128 64L0 64' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ bil +"<g transform='@TR'><path d='M64 0H128V128H64C28.6538 128 0 99.3462 0 64C0 28.6538 28.6538 0 64 0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><line x1='80.0035' y1='79.9965' x2='112.004' y2='111.997' stroke='@BG' fill='none' stroke-width='@SW'/><path fill-rule='evenodd' clip-rule='evenodd' d='M80 64C80 72.8366 72.8366 80 64 80C55.1634 80 48 72.8366 48 64C48 55.1634 55.1634 48 64 48C72.8366 48 80 55.1634 80 64ZM64 72C68.4183 72 72 68.4183 72 64C72 59.5817 68.4183 56 64 56C59.5817 56 56 59.5817 56 64C56 68.4183 59.5817 72 64 72Z' fill='@BG'/></g>", + ++ bin +"<g transform='@TR'><rect width='128' height='128' fill='@FG' stroke='@BG' stroke-width='@SW'/></g>", + ++ bis +"<g transform='@TR'><path d='M0 0C0 70.6925 57.3075 128 128 128V0H0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><line x1='128' y1='64' x2='-8.87604e-09' y2='64' stroke='@BG' fill='none' stroke-width='@SW'/><line x1='128' y1='96' x2='-8.87604e-09' y2='96' stroke='@BG' fill='none' stroke-width='@SW'/><line x1='128' y1='32' x2='-8.87604e-09' y2='32' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ bit +"<g transform='@TR'><path d='M0.0541 0C70.7217 0.0292317 128 57.3256 128 128C57.3177 128 0.0164917 70.7089 7.62806e-06 0.0305091C7.62851e-06 0.0203397 -4.44317e-10 0.01017 0 0H0.0541Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M128 0L0 128' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/><circle cx='64' cy='64' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='64' cy='64' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ bol +"<g transform='@TR'><circle cx='64' cy='64' r='64' fill='@FG' stroke='@BG' stroke-width='@SW'/><circle cx='64' cy='64' r='48' stroke='@BG' fill='none' stroke-width='@SW'/><line x1='128' y1='64' x2='-4.37114e-08' y2='64' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ bon +"<g transform='@TR'><path d='M128 0C57.3075 8.42999e-07 -8.42999e-07 57.3075 0 128H128V0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M128 128C92.6538 128 64 99.3462 64 64C64 28.6538 92.6538 4.215e-07 128 0' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ bor +"<g transform='@TR'><path d='M64 0H128V128H64C28.6538 128 0 99.3462 0 64C0 28.6538 28.6538 0 64 0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><line x1='-0.0029152' x2='127.983' y2='127.986' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/><path d='M0 128C4.63574e-06 92.6489 14.3309 60.6449 37.5 37.4807' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M32 128C32 101.492 42.7436 77.4939 60.1138 60.1217' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M64 128C64 110.328 71.1626 94.3287 82.7432 82.7471' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M95.6284 128C95.6284 119.164 99.2097 111.164 105 105.374' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ bos +"<g transform='@TR'><path d='M0 0C0 70.6925 57.3075 128 128 128V0H0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><line x1='-0.0029152' x2='127.983' y2='127.986' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/><circle cx='32' cy='32' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='32' cy='32' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ bot +"<g transform='@TR'><path d='M64 0H128V128H64C28.6538 128 0 99.3462 0 64C0 28.6538 28.6538 0 64 0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><line x1='32' y1='2.18557e-08' x2='32' y2='128' stroke='@BG' fill='none' stroke-width='@SW'/><circle cx='32' cy='96' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='32' cy='96' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/><circle cx='32' cy='32' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='32' cy='32' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ bud +"<g transform='@TR'><path d='M128 128C128 57.3076 70.6925 6.18013e-06 1.11901e-05 0L0 128L128 128Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M16 64C16 90.5097 37.4903 112 64 112' stroke='@BG' fill='none' stroke-width='@SW'/><circle cx='16' cy='64' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='16' cy='64' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ bur +"<g transform='@TR'><path d='M5.59506e-06 128C70.6925 128 128 70.6925 128 0L0 5.59506e-06L5.59506e-06 128Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M7.37542e-06 -3.56072e-06C1.19529e-06 70.6924 57.3075 128 128 128' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M128 0L0 128' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/></g>", + ++ bus +"<g transform='@TR'><path d='M128 128C128 57.3076 70.6925 6.18013e-06 1.11901e-05 0L0 128L128 128Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M32 128C32 110.327 17.6731 96 0 96' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M-0.00292969 0L127.997 128' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/></g>", + ++ byl +"<g transform='@TR'><path d='M5.59506e-06 128C70.6925 128 128 70.6925 128 0L0 5.59506e-06L5.59506e-06 128Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><circle cx='16' cy='112' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='16' cy='112' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/><path d='M-0.00280762 0L127.997 128' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/><path d='M22.1288 22.6299C16.0075 28.7511 8.0234 31.874 0.00134547 31.9986M44.7562 45.2573C32.3866 57.6269 16.2133 63.8747 0.00134277 64.0005M67.3836 67.8847C48.7656 86.5027 24.403 95.8749 0.00134412 96.0012' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ byn +"<g transform='@TR'><path d='M5.59506e-06 128C70.6925 128 128 70.6925 128 0L0 5.59506e-06L5.59506e-06 128Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M128 0C128 35.3511 113.669 67.3551 90.5 90.5193' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M96 0C96 26.5077 85.2564 50.5061 67.8862 67.8783' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M64 0C64 17.6721 56.8374 33.6713 45.2568 45.2529' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M32.3716 0C32.3716 8.83603 28.7903 16.8356 23 22.6264' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ byr +"<g transform='@TR'><path d='M0 127.946C0.0292286 57.2783 57.3256 3.08928e-06 128 0C128 70.6823 70.7089 127.984 0.0305092 128C0.0203397 128 0.01017 128 2.36469e-09 128L0 127.946Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M-0.00280762 0L127.997 128' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/><circle cx='48' cy='80' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='48' cy='80' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ byt +"<g transform='@TR'><path d='M64 128H0L5.59506e-06 0L64 5.59506e-06C99.3462 8.68512e-06 128 28.6538 128 64C128 99.3462 99.3462 128 64 128Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><circle cx='64' cy='64' r='48' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M128 64L0 64' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M32 0L32 128' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ dab +"<g transform='@TR'><path d='M0 0C0 70.6925 57.3075 128 128 128V0H0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><line y1='-0.5' x2='45.2548' y2='-0.5' transform='matrix(0.707107 -0.707107 -0.707107 -0.707107 79.65 47.6499)' stroke='@BG' fill='none' stroke-width='@SW'/><circle cx='16' cy='112' r='11.5' fill='@BG' stroke='@BG' stroke-width='@SW'/><circle cx='16' cy='112' r='9' fill='@FG' stroke='@FG' stroke-width='@SW'/></g>", + ++ dac +"<g transform='@TR'><path d='M0 0C0 70.6925 57.3075 128 128 128V0H0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M128 0L0 128' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/><path d='M64 0L64 128' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M128 64L-5.96046e-08 64' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ dal +"<g transform='@TR'><path d='M0.0541 0C70.7217 0.0292317 128 57.3256 128 128C57.3177 128 0.0164917 70.7089 7.62806e-06 0.0305091C7.62851e-06 0.0203397 -4.44317e-10 0.01017 0 0H0.0541Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><line x1='-0.0029152' x2='63.29' y2='63.2929' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/><line x1='0.5' y1='-0.5' x2='181.5' y2='-0.5' transform='matrix(-0.707107 0.707107 0.707107 0.707107 128.71 0)' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/><line x1='128' y1='32.0072' x2='32.7071' y2='127.3' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/><line x1='128' y1='64.0072' x2='64.7071' y2='127.3' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/><line x1='128' y1='96.0072' x2='96.7071' y2='127.3' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/></g>", + ++ dan +"<g transform='@TR'><path d='M64 0H128V128H64C28.6538 128 0 99.3462 0 64C0 28.6538 28.6538 0 64 0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><line x1='64' y1='2.18557e-08' x2='64' y2='128' stroke='@BG' fill='none' stroke-width='@SW'/><line x1='96' y1='2.18557e-08' x2='96' y2='128' stroke='@BG' fill='none' stroke-width='@SW'/><circle cx='64' cy='64' r='16' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ dap +"<g transform='@TR'><path d='M0 0C0 70.6925 57.3075 128 128 128V0H0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><line x1='80.0035' y1='79.9964' x2='112.004' y2='111.996' stroke='@BG' fill='none' stroke-width='@SW'/><circle cx='64' cy='64' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='64' cy='64' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ dar +"<g transform='@TR'><circle cx='64' cy='64' r='64' fill='@FG' stroke='@BG' stroke-width='@SW'/><circle cx='32' cy='96' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='32' cy='96' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/><path d='M86.6274 86.6274C99.1242 74.1307 99.1242 53.8694 86.6274 41.3726C74.1306 28.8758 53.8694 28.8758 41.3726 41.3726' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M75.3137 75.3137C81.5621 69.0653 81.5621 58.9347 75.3137 52.6863C69.0653 46.4379 58.9347 46.4379 52.6863 52.6863' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M97.9411 97.9411C116.686 79.1959 116.686 48.804 97.9411 30.0589C79.196 11.3137 48.804 11.3137 30.0589 30.0589' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M-0.00292969 0L127.997 128' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/></g>", + ++ das +"<g transform='@TR'><rect width='128' height='128' fill='@FG' stroke='@BG' stroke-width='@SW'/><line x1='64' y1='2.18557e-08' x2='64' y2='128' stroke='@BG' fill='none' stroke-width='@SW'/><path fill-rule='evenodd' clip-rule='evenodd' d='M80 64C80 72.8366 72.8366 80 64 80C55.1634 80 48 72.8366 48 64C48 55.1634 55.1634 48 64 48C72.8366 48 80 55.1634 80 64ZM64 72C68.4183 72 72 68.4183 72 64C72 59.5817 68.4183 56 64 56C59.5817 56 56 59.5817 56 64C56 68.4183 59.5817 72 64 72Z' fill='@BG'/></g>", + ++ dat +"<g transform='@TR'><path d='M0 0C0 70.6925 57.3075 128 128 128V0H0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M128 128C92.6538 128 64 99.3462 64 64C64 28.6538 92.6538 -1.54503e-06 128 0' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ dav +"<g transform='@TR'><path d='M64 0H128V128H64C28.6538 128 0 99.3462 0 64C0 28.6538 28.6538 0 64 0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M128 64L0 64' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M96 64C96 46.3269 81.6731 32 64 32' stroke='@BG' fill='none' stroke-width='@SW'/><circle cx='96' cy='64' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='96' cy='64' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ deb +"<g transform='@TR'><rect width='128' height='128' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M64 -6.35781e-07C64 35.3462 35.3462 64 0 64' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ dec +"<g transform='@TR'><path d='M128 128C128 57.3076 70.6925 6.18013e-06 1.11901e-05 0L0 128L128 128Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><circle cx='64' cy='64' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='64' cy='64' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/><circle cx='112' cy='16' r='11.5' fill='@BG' stroke='@BG' stroke-width='@SW'/><circle cx='112' cy='16' r='9' fill='@FG' stroke='@FG' stroke-width='@SW'/></g>", + ++ def +"<g transform='@TR'><path d='M0.0541 0C70.7217 0.0292317 128 57.3256 128 128C57.3177 128 0.0164917 70.7089 7.62806e-06 0.0305091C7.62851e-06 0.0203397 -4.44317e-10 0.01017 0 0H0.0541Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M0 128L128 0' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/><path d='M0 94L94 0' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/><path d='M0 64L64 0' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/><path d='M0 32L32 0' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/><circle cx='16' cy='112' r='11.5' fill='@BG' stroke='@BG' stroke-width='@SW'/><circle cx='16' cy='112' r='9' fill='@FG' stroke='@FG' stroke-width='@SW'/></g>", + ++ deg +"<g transform='@TR'><rect width='128' height='128' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M64 128C64 92.6538 35.3462 64 0 64' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ del +"<g transform='@TR'><path d='M0 127.946C0.0292286 57.2783 57.3256 3.08928e-06 128 0C128 70.6823 70.7089 127.984 0.0305092 128C0.0203397 128 0.01017 128 2.36469e-09 128L0 127.946Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><circle cx='32' cy='96' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='32' cy='96' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ dem +"<g transform='@TR'><circle cx='64' cy='64' r='64' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M-0.00292969 0L127.997 128' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/><path d='M64 -6.35781e-07C64 35.3462 35.3462 64 0 64' stroke='@BG' fill='none' stroke-width='@SW'/><circle cx='32' cy='32' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='32' cy='32' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ den +"<g transform='@TR'><rect width='128' height='128' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M1.52575e-06 96C53.0193 96 96 53.0193 96 0' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M-0.00280762 0L127.997 128' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/></g>", + ++ dep +"<g transform='@TR'><path d='M128 0C57.3075 8.42999e-07 -8.42999e-07 57.3075 0 128H128V0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M32 128C32 101.492 42.7436 77.4939 60.1138 60.1216' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M64 128C64 110.328 71.1626 94.3287 82.7432 82.7471' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M95.6284 128C95.6284 119.164 99.2097 111.164 105 105.374' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ der +"<g transform='@TR'><path d='M0 64L5.59506e-06 0L128 1.11901e-05V64C128 99.3462 99.3462 128 64 128C28.6538 128 -4.6351e-06 99.3462 0 64Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M96 128L96 0' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ des +"<g transform='@TR'><path d='M128 0C57.3075 8.42999e-07 -8.42999e-07 57.3075 0 128H128V0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M96 0L96 128' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ det +"<g transform='@TR'><circle cx='64' cy='64' r='64' fill='@FG' stroke='@BG' stroke-width='@SW'/><line x1='15.9964' y1='111.996' x2='47.9964' y2='79.9964' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ dev +"<g transform='@TR'><path d='M64 128H0L5.59506e-06 0L64 5.59506e-06C99.3462 8.68512e-06 128 28.6538 128 64C128 99.3462 99.3462 128 64 128Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><line x1='96.5' y1='3.07317e-08' x2='96.5' y2='128' stroke='@BG' fill='none' stroke-width='@SW'/><line x1='32.5' y1='3.07317e-08' x2='32.5' y2='128' stroke='@BG' fill='none' stroke-width='@SW'/><circle cx='64' cy='64' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='64' cy='64' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ dex +"<g transform='@TR'><path d='M64 128H0L5.59506e-06 0L64 5.59506e-06C99.3462 8.68512e-06 128 28.6538 128 64C128 99.3462 99.3462 128 64 128Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><line x1='64' y1='2.18557e-08' x2='64' y2='128' stroke='@BG' fill='none' stroke-width='@SW'/><path fill-rule='evenodd' clip-rule='evenodd' d='M80 64C80 72.8366 72.8366 80 64 80C55.1634 80 48 72.8366 48 64C48 55.1634 55.1634 48 64 48C72.8366 48 80 55.1634 80 64ZM64 72C68.4183 72 72 68.4183 72 64C72 59.5817 68.4183 56 64 56C59.5817 56 56 59.5817 56 64C56 68.4183 59.5817 72 64 72Z' fill='@BG'/></g>", + ++ dib +"<g transform='@TR'><circle cx='64' cy='64' r='64' fill='@FG' stroke='@BG' stroke-width='@SW'/><line x1='8.74228e-08' y1='64' x2='128' y2='64' stroke='@BG' fill='none' stroke-width='@SW'/><line x1='5.25874e-08' y1='32' x2='128' y2='32' stroke='@BG' fill='none' stroke-width='@SW'/><circle cx='64' cy='32' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='64' cy='32' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ dif +"<g transform='@TR'><path d='M0 0C0 70.6925 57.3075 128 128 128V0H0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M60.1244 67.3837C41.5063 48.7657 32.1342 24.4031 32.0079 0.00145601M82.7518 44.7563C70.3822 32.3867 64.1344 16.2134 64.0086 0.00145196M105.379 22.1289C99.258 16.0077 96.1351 8.02351 96.0105 0.00145196' stroke='@BG' fill='none' stroke-width='@SW'/><line x1='0.5' y1='-0.5' x2='181.5' y2='-0.5' transform='matrix(-0.707107 0.707107 0.707107 0.707107 128.71 0)' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/><circle cx='16' cy='16' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='16' cy='16' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/><circle cx='16' cy='112' r='11.5' fill='@BG' stroke='@BG' stroke-width='@SW'/><circle cx='16' cy='112' r='9' fill='@FG' stroke='@FG' stroke-width='@SW'/></g>", + ++ dig +"<g transform='@TR'><path d='M64 0H128V128H64C28.6538 128 0 99.3462 0 64C0 28.6538 28.6538 0 64 0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><line x1='64.5' y1='-0.5' x2='64.5' y2='127.5' stroke='@BG' fill='none' stroke-width='@SW'/><line x1='16.0035' y1='15.9965' x2='48.0035' y2='47.9965' stroke='@BG' fill='none' stroke-width='@SW'/><circle cx='64' cy='64' r='16' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ dil +"<g transform='@TR'><path d='M64 0H128V128H64C28.6538 128 0 99.3462 0 64C0 28.6538 28.6538 0 64 0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><line x1='80.0036' y1='79.9964' x2='112.004' y2='111.996' stroke='@BG' fill='none' stroke-width='@SW'/><line x1='0.5' y1='-0.5' x2='181.5' y2='-0.5' transform='matrix(-0.707107 0.707107 0.707107 0.707107 128.71 0)' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/></g>", + ++ din +"<g transform='@TR'><rect width='128' height='128' fill='@FG' stroke='@BG' stroke-width='@SW'/><line x1='96' y1='2.18557e-08' x2='96' y2='128' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ dir +"<g transform='@TR'><path d='M0 0C0 70.6925 57.3075 128 128 128V0H0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M96 64C96 81.6731 81.6731 96 64 96' stroke='@BG' fill='none' stroke-width='@SW'/><line x1='16.0035' y1='15.9965' x2='48.0035' y2='47.9965' stroke='@BG' fill='none' stroke-width='@SW'/><circle cx='64' cy='64' r='16' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ dis +"<g transform='@TR'><path d='M128 0C57.3075 8.42999e-07 -8.42999e-07 57.3075 0 128H128V0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M-0.0029152 0L127.997 128' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/><circle cx='96' cy='32' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='96' cy='32' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/><circle cx='32' cy='96' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='32' cy='96' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ div +"<g transform='@TR'><rect width='128' height='128' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M64 0L64 128' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M-4.19629e-06 96C70.6924 96 128 53.0193 128 5.59506e-06' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M-2.79753e-06 64C70.6924 64 128 35.3462 128 5.59506e-06' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ doc +"<g transform='@TR'><path d='M0 127.946C0.0292286 57.2783 57.3256 3.08928e-06 128 0C128 70.6823 70.7089 127.984 0.0305092 128C0.0203397 128 0.01017 128 2.36469e-09 128L0 127.946Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M127.997 0L-0.00291443 128' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/><circle cx='64' cy='64' r='16' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M86.6274 41.3726C74.1306 28.8758 53.8694 28.8758 41.3726 41.3726C28.8758 53.8694 28.8758 74.1306 41.3726 86.6274' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ dol +"<g transform='@TR'><circle cx='64' cy='64' r='64' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M128 64L0 64' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M-4.19629e-06 16C26.5097 16 48 37.4903 48 64C48 90.5097 26.5097 112 0 112' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ don +"<g transform='@TR'><path d='M128 0C57.3075 8.42999e-07 -8.42999e-07 57.3075 0 128H128V0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M-3.8147e-06 128C-7.24632e-07 92.6538 28.6538 64 64 64C99.3462 64 128 92.6538 128 128' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ dop +"<g transform='@TR'><circle cx='64' cy='64' r='64' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M64 112C90.5097 112 112 90.5097 112 64C112 37.4903 90.5097 16 64 16' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M128 64L0 64' stroke='@BG' fill='none' stroke-width='@SW'/><circle cx='64' cy='64' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='64' cy='64' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ dor +"<g transform='@TR'><path d='M64 0H128V128H64C28.6538 128 0 99.3462 0 64C0 28.6538 28.6538 0 64 0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><line y1='63.5' x2='128' y2='63.5' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ dos +"<g transform='@TR'><path d='M0 0C0 70.6925 57.3075 128 128 128V0H0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><line x1='-0.0029152' x2='127.983' y2='127.986' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/><path d='M86.6274 86.6274C99.1242 74.1306 99.1242 53.8693 86.6274 41.3725C74.1306 28.8758 53.8694 28.8758 41.3726 41.3725' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ dot +"<g transform='@TR'><path d='M64 0H128V128H64C28.6538 128 0 99.3462 0 64C0 28.6538 28.6538 0 64 0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><circle cx='64' cy='64' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='64' cy='64' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ dov +"<g transform='@TR'><rect width='128' height='128' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M128 0L0 128' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/><path d='M-0.701724 31.9914C25.6281 31.9914 49.4822 42.5913 66.8261 59.7565M-0.701723 63.9914C16.7916 63.9914 32.6456 71.0098 44.1982 82.3844M-0.701722 95.9914C7.955 95.9914 15.8089 99.4288 21.5694 105.013' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M0 0C35.3511 0 67.3551 14.3309 90.5193 37.5' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ doz +"<g transform='@TR'><circle cx='64' cy='64' r='64' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M128 128L0 0' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/><path d='M30.0589 30.0589C48.804 11.3137 79.196 11.3137 97.9411 30.0589C116.686 48.804 116.686 79.196 97.9411 97.9411' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M52.6863 52.6863C58.9347 46.4379 69.0653 46.4379 75.3137 52.6863C81.5621 58.9347 81.5621 69.0653 75.3137 75.3137' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M41.3726 41.3726C53.8694 28.8758 74.1306 28.8758 86.6274 41.3726C99.1242 53.8694 99.1242 74.1306 86.6274 86.6274' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ duc +"<g transform='@TR'><path d='M128 128C128 57.3076 70.6925 6.18013e-06 1.11901e-05 0L0 128L128 128Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M128 64L0 64' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M128 32L0 32' stroke='@BG' fill='none' stroke-width='@SW'/><circle cx='32' cy='32' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='32' cy='32' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ dul +"<g transform='@TR'><circle cx='64' cy='64' r='64' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M64 16C90.5097 16 112 37.4903 112 64' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M64 64L64 128' stroke='@BG' fill='none' stroke-width='@SW'/><circle cx='64' cy='64' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='64' cy='64' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ dun +"<g transform='@TR'><path d='M64 128H0L5.59506e-06 0L64 5.59506e-06C99.3462 8.68512e-06 128 28.6538 128 64C128 99.3462 99.3462 128 64 128Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M112 64C112 37.4903 90.5097 16 64 16' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ dur +"<g transform='@TR'><path d='M0 64L5.59506e-06 0L128 1.11901e-05V64C128 99.3462 99.3462 128 64 128C28.6538 128 -4.6351e-06 99.3462 0 64Z' fill='@FG' stroke='@BG' stroke-width='@SW'/></g>", + ++ dus +"<g transform='@TR'><path d='M128 128C128 57.3076 70.6925 6.18013e-06 1.11901e-05 0L0 128L128 128Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M32 -3.05151e-06C32 53.0193 74.9807 96 128 96' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M128 0L0 128' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/></g>", + ++ dut +"<g transform='@TR'><rect width='128' height='128' fill='@FG' stroke='@BG' stroke-width='@SW'/><circle cx='96' cy='96' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='96' cy='96' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ dux +"<g transform='@TR'><path d='M5.59506e-06 128C70.6925 128 128 70.6925 128 0L0 5.59506e-06L5.59506e-06 128Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M-2.79795e-06 -3.55988e-06C70.6924 -4.40288e-06 128 57.3075 128 128' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ dyl +"<g transform='@TR'><path d='M128 128C128 57.3076 70.6925 6.18013e-06 1.11901e-05 0L0 128L128 128Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M2.03434e-06 128C70.6924 128 128 70.6925 128 0' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ dyn +"<g transform='@TR'><path d='M5.59506e-06 128C70.6925 128 128 70.6925 128 0L0 5.59506e-06L5.59506e-06 128Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M128 32L0 32' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ dyr +"<g transform='@TR'><path d='M0 127.946C0.0292286 57.2783 57.3256 3.08928e-06 128 0C128 70.6823 70.7089 127.984 0.0305092 128C0.0203397 128 0.01017 128 2.36469e-09 128L0 127.946Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M-0.00292969 0L127.997 128' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/><circle cx='96' cy='32' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='96' cy='32' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/><circle cx='32' cy='96' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='32' cy='96' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ dys +"<g transform='@TR'><path d='M128 128C128 57.3076 70.6925 6.18013e-06 1.11901e-05 0L0 128L128 128Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M-3.8147e-06 1.11901e-05C-7.24633e-07 35.3462 28.6538 64 64 64C99.3462 64 128 35.3462 128 0' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ dyt +"<g transform='@TR'><path d='M64 128H0L5.59506e-06 0L64 5.59506e-06C99.3462 8.68512e-06 128 28.6538 128 64C128 99.3462 99.3462 128 64 128Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><circle cx='64' cy='64' r='32' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M128 64L0 64' stroke='@BG' fill='none' stroke-width='@SW'/><circle cx='32' cy='64' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='32' cy='64' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ fab +"<g transform='@TR'><path d='M0 0C0 70.6925 57.3075 128 128 128V0H0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M128 0L0 128' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/><circle cx='64' cy='64' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='64' cy='64' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/><circle cx='16' cy='112' r='11.5' fill='@BG' stroke='@BG' stroke-width='@SW'/><circle cx='16' cy='112' r='9' fill='@FG' stroke='@FG' stroke-width='@SW'/></g>", + ++ fad +"<g transform='@TR'><path d='M5.59506e-06 128C70.6925 128 128 70.6925 128 0L0 5.59506e-06L5.59506e-06 128Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><circle cx='96' cy='32' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='96' cy='32' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/><circle cx='32' cy='96' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='32' cy='96' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ fal +"<g transform='@TR'><path d='M0 127.946C0.0292286 57.2783 57.3256 3.08928e-06 128 0C128 70.6823 70.7089 127.984 0.0305092 128C0.0203397 128 0.01017 128 2.36469e-09 128L0 127.946Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M0 128L128 0' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/><path d='M0 0C35.3511 0 67.3551 14.3309 90.5193 37.5' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M0 32C26.5077 32 50.5061 42.7436 67.8783 60.1138' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M0 64C17.6721 64 33.6713 71.1626 45.2529 82.7432' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M0 95.6284C8.83603 95.6284 16.8356 99.2097 22.6264 105' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ fam +"<g transform='@TR'><path d='M64 0H128V128H64C28.6538 128 0 99.3462 0 64C0 28.6538 28.6538 0 64 0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><line x1='128' y1='64' x2='-4.37114e-08' y2='64' stroke='@BG' fill='none' stroke-width='@SW'/><line x1='64' y1='2.18557e-08' x2='64' y2='128' stroke='@BG' fill='none' stroke-width='@SW'/><circle cx='64' cy='64' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='64' cy='64' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ fan +"<g transform='@TR'><path d='M64 0H128V128H64C28.6538 128 0 99.3462 0 64C0 28.6538 28.6538 0 64 0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M128 0L0 128' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/><path d='M64 0L64 128' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M-0.00292969 0L127.997 128' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/></g>", + ++ fas +"<g transform='@TR'><rect width='128' height='128' fill='@FG' stroke='@BG' stroke-width='@SW'/><circle cx='64' cy='64' r='32' stroke='@BG' fill='none' stroke-width='@SW'/><circle cx='96' cy='64' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='96' cy='64' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ feb +"<g transform='@TR'><rect width='128' height='128' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M7.37542e-06 -3.56072e-06C1.19529e-06 70.6924 57.3075 128 128 128' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ fed +"<g transform='@TR'><circle cx='64' cy='64' r='64' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M128 32L0 32' stroke='@BG' fill='none' stroke-width='@SW'/><circle cx='64' cy='64' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='64' cy='64' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ fel +"<g transform='@TR'><path d='M0 127.946C0.0292286 57.2783 57.3256 3.08928e-06 128 0C128 70.6823 70.7089 127.984 0.0305092 128C0.0203397 128 0.01017 128 2.36469e-09 128L0 127.946Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><line y1='-0.5' x2='45.2548' y2='-0.5' transform='matrix(0.707107 -0.707107 -0.707107 -0.707107 79.65 47.6499)' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ fen +"<g transform='@TR'><rect width='128' height='128' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M-0.00280762 0L127.997 128' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/><path d='M0 128C4.63574e-06 92.6489 14.3309 60.6449 37.5 37.4807' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M32 128C32 101.492 42.7436 77.4939 60.1138 60.1217' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M64 128C64 110.328 71.1626 94.3287 82.7432 82.7471' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M95.6284 128C95.6284 119.164 99.2097 111.164 105 105.374' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ fep +"<g transform='@TR'><path d='M128 128C128 57.3076 70.6925 6.18013e-06 1.11901e-05 0L0 128L128 128Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M128 0L0 128' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/></g>", + ++ fer +"<g transform='@TR'><path d='M64 128H0L5.59506e-06 0L64 5.59506e-06C99.3462 8.68512e-06 128 28.6538 128 64C128 99.3462 99.3462 128 64 128Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M64 0L64 128' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ fes +"<g transform='@TR'><path d='M128 0C57.3075 8.42999e-07 -8.42999e-07 57.3075 0 128H128V0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M32 0L32 128' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ fet +"<g transform='@TR'><circle cx='64' cy='64' r='64' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M128 0L0 128' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/></g>", + ++ fex +"<g transform='@TR'><path d='M64 128H0L5.59506e-06 0L64 5.59506e-06C99.3462 8.68512e-06 128 28.6538 128 64C128 99.3462 99.3462 128 64 128Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><line y1='-0.5' x2='45.2548' y2='-0.5' transform='matrix(0.707107 -0.707107 -0.707107 -0.707107 79.6499 47.6499)' stroke='@BG' fill='none' stroke-width='@SW'/><path fill-rule='evenodd' clip-rule='evenodd' d='M80 64C80 72.8366 72.8366 80 64 80C55.1634 80 48 72.8366 48 64C48 55.1634 55.1634 48 64 48C72.8366 48 80 55.1634 80 64ZM64 72C68.4183 72 72 68.4183 72 64C72 59.5817 68.4183 56 64 56C59.5817 56 56 59.5817 56 64C56 68.4183 59.5817 72 64 72Z' fill='@BG'/></g>", + ++ fid +"<g transform='@TR'><path d='M0 0C0 70.6925 57.3075 128 128 128V0H0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M-0.00291443 0L127.997 128' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/><circle cx='96' cy='96' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='96' cy='96' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/><circle cx='32' cy='32' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='32' cy='32' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ fig +"<g transform='@TR'><path d='M64 0H128V128H64C28.6538 128 0 99.3462 0 64C0 28.6538 28.6538 0 64 0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M64 0L64 128' stroke='@BG' fill='none' stroke-width='@SW'/><circle cx='64' cy='64' r='32' stroke='@BG' fill='none' stroke-width='@SW'/><circle cx='64' cy='64' r='16' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ fil +"<g transform='@TR'><path d='M64 0H128V128H64C28.6538 128 0 99.3462 0 64C0 28.6538 28.6538 0 64 0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><line x1='128' y1='64' x2='-4.37114e-08' y2='64' stroke='@BG' fill='none' stroke-width='@SW'/><line x1='64' y1='2.18557e-08' x2='64' y2='128' stroke='@BG' fill='none' stroke-width='@SW'/><line x1='32' y1='2.18557e-08' x2='32' y2='128' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ fin +"<g transform='@TR'><rect width='128' height='128' fill='@FG' stroke='@BG' stroke-width='@SW'/><line x1='98' y1='2.18557e-08' x2='98' y2='128' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ fip +"<g transform='@TR'><path d='M64 0H128V128H64C28.6538 128 0 99.3462 0 64C0 28.6538 28.6538 0 64 0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><circle cx='64' cy='64' r='32' stroke='@BG' fill='none' stroke-width='@SW'/><line x1='-0.0029152' x2='127.983' y2='127.986' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/><circle cx='64' cy='96' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='64' cy='96' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ fir +"<g transform='@TR'><path d='M0 0C0 70.6925 57.3075 128 128 128V0H0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><line y1='-0.5' x2='45.2548' y2='-0.5' transform='matrix(0.707107 -0.707107 -0.707107 -0.707107 79.65 47.6499)' stroke='@BG' fill='none' stroke-width='@SW'/><line x1='80.0036' y1='79.9965' x2='112.004' y2='111.997' stroke='@BG' fill='none' stroke-width='@SW'/><line x1='16.0035' y1='15.9965' x2='48.0035' y2='47.9965' stroke='@BG' fill='none' stroke-width='@SW'/><circle cx='64' cy='64' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='64' cy='64' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ fit +"<g transform='@TR'><path d='M0.0541 0C70.7217 0.0292317 128 57.3256 128 128C57.3177 128 0.0164917 70.7089 7.62806e-06 0.0305091C7.62851e-06 0.0203397 -4.44317e-10 0.01017 0 0H0.0541Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><line x1='0.5' y1='-0.5' x2='181.5' y2='-0.5' transform='matrix(-0.707107 0.707107 0.707107 0.707107 128.71 0)' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/></g>", + ++ fod +"<g transform='@TR'><path d='M64 0H128V128H64C28.6538 128 0 99.3462 0 64C0 28.6538 28.6538 0 64 0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path fill-rule='evenodd' clip-rule='evenodd' d='M80 64C80 72.8366 72.8366 80 64 80C55.1634 80 48 72.8366 48 64C48 55.1634 55.1634 48 64 48C72.8366 48 80 55.1634 80 64ZM64 72C68.4183 72 72 68.4183 72 64C72 59.5817 68.4183 56 64 56C59.5817 56 56 59.5817 56 64C56 68.4183 59.5817 72 64 72Z' fill='@BG'/></g>", + ++ fog +"<g transform='@TR'><path d='M128 0C57.3075 8.42999e-07 -8.42999e-07 57.3075 0 128H128V0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M-0.00292969 0L127.997 128' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/><path d='M86.6274 86.6274C99.1242 74.1306 99.1242 53.8694 86.6274 41.3726C74.1306 28.8758 53.8694 28.8758 41.3726 41.3726' stroke='@BG' fill='none' stroke-width='@SW'/><circle cx='64' cy='64' r='16' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ fol +"<g transform='@TR'><circle cx='64' cy='64' r='64' fill='@FG' stroke='@BG' stroke-width='@SW'/><circle cx='64' cy='64' r='16' stroke='@BG' fill='none' stroke-width='@SW'/><line x1='128' y1='64' x2='-4.37114e-08' y2='64' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ fon +"<g transform='@TR'><path d='M128 0C57.3075 8.42999e-07 -8.42999e-07 57.3075 0 128H128V0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><line x1='-0.0029152' x2='127.983' y2='127.986' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/></g>", + ++ fop +"<g transform='@TR'><circle cx='64' cy='64' r='64' fill='@FG' stroke='@BG' stroke-width='@SW'/><line x1='-0.0029152' x2='127.983' y2='127.986' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/><path d='M16 64C16 90.5097 37.4903 112 64 112' stroke='@BG' fill='none' stroke-width='@SW'/><circle cx='16' cy='64' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='16' cy='64' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ for +"<g transform='@TR'><path d='M64 0H128V128H64C28.6538 128 0 99.3462 0 64C0 28.6538 28.6538 0 64 0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><line x1='96' y1='2.18557e-08' x2='96' y2='128' stroke='@BG' fill='none' stroke-width='@SW'/><circle cx='64' cy='64' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='64' cy='64' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ fos +"<g transform='@TR'><path d='M5.59506e-06 128C70.6925 128 128 70.6925 128 0L0 5.59506e-06L5.59506e-06 128Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><line x1='-0.0029152' x2='127.983' y2='127.986' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/><path d='M96 0C96 53.0193 53.0193 96 0 96' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M64 0C64 35.3462 35.3462 64 0 64' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M32 0C32 17.6731 17.6731 32 0 32' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ fot +"<g transform='@TR'><path d='M64 0H128V128H64C28.6538 128 0 99.3462 0 64C0 28.6538 28.6538 0 64 0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><line x1='15.9964' y1='111.997' x2='47.9964' y2='79.9965' stroke='@BG' fill='none' stroke-width='@SW'/><circle cx='64' cy='64' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='64' cy='64' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ ful +"<g transform='@TR'><circle cx='64' cy='64' r='64' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M64 96C81.6731 96 96 81.6731 96 64C96 46.3269 81.6731 32 64 32' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ fun +"<g transform='@TR'><path d='M128 64V128H0L2.79753e-06 64C4.34256e-06 28.6538 28.6538 -1.54503e-06 64 0C99.3462 1.54503e-06 128 28.6538 128 64Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><line x1='15.9964' y1='111.997' x2='47.9964' y2='79.9965' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M-0.00280762 0L127.997 128' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/><circle cx='16' cy='112' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='16' cy='112' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ fur +"<g transform='@TR'><path d='M5.59506e-06 128C70.6925 128 128 70.6925 128 0L0 5.59506e-06L5.59506e-06 128Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M128 0L0 128' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/><path d='M86.8823 41.6275C74.3855 29.1307 54.1242 29.1307 41.6274 41.6275C29.1307 54.1243 29.1307 74.3855 41.6274 86.8823' stroke='@BG' fill='none' stroke-width='@SW'/><circle cx='64' cy='64' r='16' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ fus +"<g transform='@TR'><path d='M128 128C128 57.3076 70.6925 6.18013e-06 1.11901e-05 0L0 128L128 128Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M128 0L0 128' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/><path d='M32 128C32 110.327 17.6731 96 0 96' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ fyl +"<g transform='@TR'><path d='M5.59506e-06 128C70.6925 128 128 70.6925 128 0L0 5.59506e-06L5.59506e-06 128Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M22.1288 22.6299C16.0075 28.7511 8.0234 31.874 0.00134547 31.9986M44.7562 45.2573C32.3866 57.6269 16.2133 63.8747 0.00134277 64.0005M67.3836 67.8847C48.7656 86.5027 24.403 95.8749 0.00134412 96.0012' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M-0.00280762 0L127.997 128' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/></g>", + ++ fyn +"<g transform='@TR'><path d='M5.59506e-06 128C70.6925 128 128 70.6925 128 0L0 5.59506e-06L5.59506e-06 128Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M128 0L0 128' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/></g>", + ++ fyr +"<g transform='@TR'><path d='M0 127.946C0.0292286 57.2783 57.3256 3.08928e-06 128 0C128 70.6823 70.7089 127.984 0.0305092 128C0.0203397 128 0.01017 128 2.36469e-09 128L0 127.946Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M-0.00268555 0L127.997 128' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/><line y1='-0.5' x2='45.2548' y2='-0.5' transform='matrix(0.707107 -0.707107 -0.707107 -0.707107 79.6499 47.6499)' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ hab +"<g transform='@TR'><path d='M0 0C0 70.6925 57.3075 128 128 128V0H0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><line x1='0.5' y1='-0.5' x2='181.5' y2='-0.5' transform='matrix(-0.707107 0.707107 0.707107 0.707107 128.71 0)' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/><path d='M60.1244 67.3837C41.5063 48.7657 32.1342 24.4031 32.0079 0.00145601M82.7518 44.7563C70.3822 32.3867 64.1344 16.2134 64.0086 0.00145196M105.379 22.1289C99.258 16.0077 96.1351 8.02351 96.0105 0.00145196' stroke='@BG' fill='none' stroke-width='@SW'/><circle cx='16' cy='112' r='11.5' fill='@BG' stroke='@BG' stroke-width='@SW'/><circle cx='16' cy='112' r='9' fill='@FG' stroke='@FG' stroke-width='@SW'/></g>", + ++ hac +"<g transform='@TR'><path d='M0 0C0 70.6925 57.3075 128 128 128V0H0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><line x1='0.5' y1='-0.5' x2='181.5' y2='-0.5' transform='matrix(-0.707107 0.707107 0.707107 0.707107 128.71 0)' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/><circle cx='64' cy='64' r='32' stroke='@BG' fill='none' stroke-width='@SW'/><circle cx='64' cy='64' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='64' cy='64' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ had +"<g transform='@TR'><path d='M5.59506e-06 128C70.6925 128 128 70.6925 128 0L0 5.59506e-06L5.59506e-06 128Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><circle cx='32' cy='32' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='32' cy='32' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ hal +"<g transform='@TR'><path d='M0 127.946C0.0292286 57.2783 57.3256 3.08928e-06 128 0C128 70.6823 70.7089 127.984 0.0305092 128C0.0203397 128 0.01017 128 2.36469e-09 128L0 127.946Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><line x1='64.5' y1='-0.5' x2='64.5' y2='127.5' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M16 64C16 90.5097 37.4903 112 64 112' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M112 64C112 37.4903 90.5097 16 64 16' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ han +"<g transform='@TR'><path d='M5.59506e-06 128C70.6925 128 128 70.6925 128 0L0 5.59506e-06L5.59506e-06 128Z' fill='@FG' stroke='@BG' stroke-width='@SW'/></g>", + ++ hap +"<g transform='@TR'><circle cx='64' cy='64' r='64' fill='@FG' stroke='@BG' stroke-width='@SW'/><circle cx='64' cy='64' r='32' stroke='@BG' fill='none' stroke-width='@SW'/><circle cx='64' cy='64' r='48' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M-0.00292969 0L127.997 128' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/><circle cx='64' cy='64' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='64' cy='64' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ har +"<g transform='@TR'><circle cx='64' cy='64' r='64' fill='@FG' stroke='@BG' stroke-width='@SW'/><line x1='64' y1='2.18557e-08' x2='64' y2='128' stroke='@BG' fill='none' stroke-width='@SW'/><circle cx='64' cy='64' r='16' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ has +"<g transform='@TR'><rect width='128' height='128' fill='@FG' stroke='@BG' stroke-width='@SW'/><circle cx='64' cy='64' r='32' stroke='@BG' fill='none' stroke-width='@SW'/><circle cx='64' cy='32' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='64' cy='32' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/><circle cx='32' cy='64' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='32' cy='64' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ hat +"<g transform='@TR'><path d='M0 0C0 70.6925 57.3075 128 128 128V0H0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><circle cx='16' cy='16' r='8' fill='@FG' stroke='@FG' stroke-width='@SW'/><line x1='0.5' y1='-0.5' x2='181.5' y2='-0.5' transform='matrix(-0.707107 0.707107 0.707107 0.707107 128.71 0)' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/><path fill-rule='evenodd' clip-rule='evenodd' d='M48 32C48 40.8366 40.8366 48 32 48C23.1634 48 16 40.8366 16 32C16 23.1634 23.1634 16 32 16C40.8366 16 48 23.1634 48 32ZM32 40C36.4183 40 40 36.4183 40 32C40 27.5817 36.4183 24 32 24C27.5817 24 24 27.5817 24 32C24 36.4183 27.5817 40 32 40Z' fill='@BG'/></g>", + ++ hav +"<g transform='@TR'><path d='M0 0C0 70.6925 57.3075 128 128 128V0H0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><line x1='96' y1='2.18557e-08' x2='96' y2='128' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ heb +"<g transform='@TR'><rect width='128' height='128' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M2.03434e-06 128C70.6924 128 128 70.6925 128 0' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ hec +"<g transform='@TR'><path d='M128 128C128 57.3076 70.6925 6.18013e-06 1.11901e-05 0L0 128L128 128Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><circle cx='32' cy='32' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='32' cy='32' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/><circle cx='32' cy='96' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='32' cy='96' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/><circle cx='96' cy='96' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='96' cy='96' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ hep +"<g transform='@TR'><path d='M128 128C128 57.3076 70.6925 6.18013e-06 1.11901e-05 0L0 128L128 128Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><line x1='-0.00285417' x2='127.983' y2='127.986' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/><path d='M-0.00292969 0L127.997 128' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/></g>", + ++ hes +"<g transform='@TR'><path d='M128 0C57.3075 8.42999e-07 -8.42999e-07 57.3075 0 128H128V0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M32 0L32 128' stroke='@BG' fill='none' stroke-width='@SW'/><path fill-rule='evenodd' clip-rule='evenodd' d='M48 96C48 104.837 40.8366 112 32 112C23.1634 112 16 104.837 16 96C16 87.1634 23.1634 80 32 80C40.8366 80 48 87.1634 48 96ZM32 104C36.4183 104 40 100.418 40 96C40 91.5817 36.4183 88 32 88C27.5817 88 24 91.5817 24 96C24 100.418 27.5817 104 32 104Z' fill='@BG'/></g>", + ++ het +"<g transform='@TR'><circle cx='64' cy='64' r='64' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M96 128L96 0' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ hex +"<g transform='@TR'><path d='M64 128H0L5.59506e-06 0L64 5.59506e-06C99.3462 8.68512e-06 128 28.6538 128 64C128 99.3462 99.3462 128 64 128Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M128 0L0 128' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/><path fill-rule='evenodd' clip-rule='evenodd' d='M80 64C80 72.8366 72.8366 80 64 80C55.1634 80 48 72.8366 48 64C48 55.1634 55.1634 48 64 48C72.8366 48 80 55.1634 80 64ZM64 72C68.4183 72 72 68.4183 72 64C72 59.5817 68.4183 56 64 56C59.5817 56 56 59.5817 56 64C56 68.4183 59.5817 72 64 72Z' fill='@BG'/></g>", + ++ hid +"<g transform='@TR'><path d='M0 0C0 70.6925 57.3075 128 128 128V0H0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M-0.00292969 0L127.997 128' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/><path d='M2.03434e-06 128C70.6924 128 128 70.6925 128 0' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M1.52575e-06 96C53.0193 96 96 53.0193 96 0' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M1.01717e-06 64C35.3462 64 64 35.3462 64 0' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M5.08584e-07 32C17.6731 32 32 17.6731 32 0' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ hil +"<g transform='@TR'><path d='M64 0H128V128H64C28.6538 128 0 99.3462 0 64C0 28.6538 28.6538 0 64 0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><line x1='8.74228e-08' y1='64' x2='128' y2='64' stroke='@BG' fill='none' stroke-width='@SW'/><line x1='64' y1='2.18557e-08' x2='64' y2='128' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ hin +"<g transform='@TR'><rect width='128' height='128' fill='@FG' stroke='@BG' stroke-width='@SW'/><line x1='32' y1='2.18557e-08' x2='32' y2='128' stroke='@BG' fill='none' stroke-width='@SW'/><path fill-rule='evenodd' clip-rule='evenodd' d='M48 64C48 72.8366 40.8366 80 32 80C23.1634 80 16 72.8366 16 64C16 55.1634 23.1634 48 32 48C40.8366 48 48 55.1634 48 64ZM32 72C36.4183 72 40 68.4183 40 64C40 59.5817 36.4183 56 32 56C27.5817 56 24 59.5817 24 64C24 68.4183 27.5817 72 32 72Z' fill='@BG'/></g>", + ++ hob +"<g transform='@TR'><path d='M128 64V128H0L2.79753e-06 64C4.34256e-06 28.6538 28.6538 -1.54503e-06 64 0C99.3462 1.54503e-06 128 28.6538 128 64Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><line x1='128' y1='64' x2='-4.37114e-08' y2='64' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ hoc +"<g transform='@TR'><path d='M64 0H128V128H64C28.6538 128 0 99.3462 0 64C0 28.6538 28.6538 0 64 0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><line y1='-0.5' x2='45.2548' y2='-0.5' transform='matrix(0.707107 -0.707107 -0.707107 -0.707107 79.65 47.6499)' stroke='@BG' fill='none' stroke-width='@SW'/><circle cx='64' cy='64' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='64' cy='64' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ hod +"<g transform='@TR'><path d='M64 0H128V128H64C28.6538 128 0 99.3462 0 64C0 28.6538 28.6538 0 64 0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M32 0L32 128' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ hol +"<g transform='@TR'><circle cx='64' cy='64' r='64' fill='@FG' stroke='@BG' stroke-width='@SW'/><line x1='128' y1='64' x2='-4.37114e-08' y2='64' stroke='@BG' fill='none' stroke-width='@SW'/><circle cx='64' cy='64' r='16' stroke='@BG' fill='none' stroke-width='@SW'/><circle cx='64' cy='96' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='64' cy='96' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ hop +"<g transform='@TR'><circle cx='64' cy='64' r='64' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M128 64L0 64' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M64 96C81.6731 96 96 81.6731 96 64C96 46.3269 81.6731 32 64 32' stroke='@BG' fill='none' stroke-width='@SW'/><circle cx='64' cy='64' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='64' cy='64' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ hos +"<g transform='@TR'><path d='M0 0C0 70.6925 57.3075 128 128 128V0H0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><line x1='80.0036' y1='79.9965' x2='112.004' y2='111.997' stroke='@BG' fill='none' stroke-width='@SW'/><line x1='16.0036' y1='15.9965' x2='48.0036' y2='47.9965' stroke='@BG' fill='none' stroke-width='@SW'/><circle cx='48' cy='48' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='48' cy='48' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/><circle cx='80' cy='47' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='80' cy='47' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/><circle cx='80' cy='81' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='80' cy='81' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/><circle cx='48' cy='80' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='48' cy='80' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ hul +"<g transform='@TR'><circle cx='64' cy='64' r='64' fill='@FG' stroke='@BG' stroke-width='@SW'/><circle cx='64' cy='64' r='32' stroke='@BG' fill='none' stroke-width='@SW'/><circle cx='48' cy='64' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='48' cy='64' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ hus +"<g transform='@TR'><path d='M128 128C128 57.3076 70.6925 6.18013e-06 1.11901e-05 0L0 128L128 128Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M-0.00292969 0L127.997 128' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/><path d='M64 96C46.3269 96 32 81.6731 32 64' stroke='@BG' fill='none' stroke-width='@SW'/><circle cx='64' cy='64' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='64' cy='64' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ hut +"<g transform='@TR'><rect width='128' height='128' fill='@FG' stroke='@BG' stroke-width='@SW'/><circle cx='64' cy='64' r='48' stroke='@BG' fill='none' stroke-width='@SW'/><circle cx='32' cy='32' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='32' cy='32' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/><circle cx='96' cy='96' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='96' cy='96' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ lab +"<g transform='@TR'><path d='M128 0C57.3075 8.42999e-07 -8.42999e-07 57.3075 0 128H128V0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><line x1='-0.0029152' x2='127.983' y2='127.986' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/><line y1='-0.5' x2='45.2548' y2='-0.5' transform='matrix(0.707107 -0.707107 -0.707107 -0.707107 79.65 47.6499)' stroke='@BG' fill='none' stroke-width='@SW'/><line x1='15.9964' y1='111.997' x2='47.9964' y2='79.9965' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ lac +"<g transform='@TR'><path d='M0 0C0 70.6925 57.3075 128 128 128V0H0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M64 -9.40976e-06C64 70.6924 92.6538 128 128 128' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M32 -7.63193e-07C32 70.6924 74.9807 128 128 128' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M128 64L0 64' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ lad +"<g transform='@TR'><path d='M128 0C57.3075 8.42999e-07 -8.42999e-07 57.3075 0 128H128V0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><line x1='95.35' y1='32.7071' x2='32.0571' y2='96' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/><circle cx='96' cy='32' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='96' cy='32' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/><circle cx='32' cy='96' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='32' cy='96' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ lag +"<g transform='@TR'><path d='M64 0H128V128H64C28.6538 128 0 99.3462 0 64C0 28.6538 28.6538 0 64 0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M64 112C90.5097 112 112 90.5097 112 64' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ lan +"<g transform='@TR'><path d='M64 0H128V128H64C28.6538 128 0 99.3462 0 64C0 28.6538 28.6538 0 64 0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><line x1='64' y1='2.18557e-08' x2='64' y2='128' stroke='@BG' fill='none' stroke-width='@SW'/><line x1='32' y1='2.18557e-08' x2='32' y2='128' stroke='@BG' fill='none' stroke-width='@SW'/><circle cx='64' cy='64' r='16' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ lap +"<g transform='@TR'><path d='M0 0C0 70.6925 57.3075 128 128 128V0H0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M112 64C112 37.4903 90.5097 16 64 16' stroke='@BG' fill='none' stroke-width='@SW'/><circle cx='112' cy='64' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='112' cy='64' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ lar +"<g transform='@TR'><circle cx='64' cy='64' r='64' fill='@FG' stroke='@BG' stroke-width='@SW'/><line x1='2.78181e-08' y1='64' x2='128' y2='64' stroke='@BG' fill='none' stroke-width='@SW'/><circle cx='64' cy='64' r='16' stroke='@BG' fill='none' stroke-width='@SW'/><circle cx='64' cy='96' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='64' cy='96' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/><circle cx='64' cy='32' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='64' cy='32' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ las +"<g transform='@TR'><rect width='128' height='128' fill='@FG' stroke='@BG' stroke-width='@SW'/><circle cx='64' cy='64' r='48' stroke='@BG' fill='none' stroke-width='@SW'/><circle cx='16' cy='64' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='16' cy='64' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ lat +"<g transform='@TR'><path d='M0 0C0 70.6925 57.3075 128 128 128V0H0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M2.03434e-06 128C70.6924 128 128 70.6925 128 0' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M1.52575e-06 96C53.0193 96 96 53.0193 96 0' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M1.01717e-06 64C35.3462 64 64 35.3462 64 0' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M5.08584e-07 32C17.6731 32 32 17.6731 32 0' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ lav +"<g transform='@TR'><path d='M128 0C57.3075 8.42999e-07 -8.42999e-07 57.3075 0 128H128V0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M128 128C92.6489 128 60.6449 113.669 37.4807 90.5' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M128 96C101.492 96 77.4939 85.2564 60.1217 67.8862' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M128 64C110.328 64 94.3287 56.8374 82.7471 45.2568' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M128 32.3716C119.164 32.3716 111.164 28.7903 105.374 23' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ leb +"<g transform='@TR'><rect width='128' height='128' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M-1.64036e-05 32C53.0193 32 96 74.9807 96 128' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ lec +"<g transform='@TR'><path d='M128 128C128 57.3076 70.6925 6.18013e-06 1.11901e-05 0L0 128L128 128Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M-0.00292969 0L127.997 128' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/><circle cx='64' cy='64' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='64' cy='64' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ led +"<g transform='@TR'><circle cx='64' cy='64' r='64' fill='@FG' stroke='@BG' stroke-width='@SW'/><circle cx='64' cy='32' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='64' cy='32' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ leg +"<g transform='@TR'><rect width='128' height='128' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M7.63192e-07 32C17.6731 32 32 46.3269 32 64C32 81.6731 17.6731 96 0 96' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ len +"<g transform='@TR'><rect width='128' height='128' fill='@FG' stroke='@BG' stroke-width='@SW'/><circle cx='64' cy='64' r='48' stroke='@BG' fill='none' stroke-width='@SW'/><circle cx='64' cy='96' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='64' cy='96' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ lep +"<g transform='@TR'><path d='M128 0C57.3075 8.42999e-07 -8.42999e-07 57.3075 0 128H128V0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M128 96C110.327 96 96 110.327 96 128' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ ler +"<g transform='@TR'><path d='M64 128H0L5.59506e-06 0L64 5.59506e-06C99.3462 8.68512e-06 128 28.6538 128 64C128 99.3462 99.3462 128 64 128Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M32 0L32 128' stroke='@BG' fill='none' stroke-width='@SW'/><circle cx='32' cy='32' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='32' cy='32' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ let +"<g transform='@TR'><circle cx='64' cy='64' r='64' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M64 0L64 128' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ lev +"<g transform='@TR'><path d='M64 128H0L5.59506e-06 0L64 5.59506e-06C99.3462 8.68512e-06 128 28.6538 128 64C128 99.3462 99.3462 128 64 128Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><circle cx='32' cy='32' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='32' cy='32' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ lex +"<g transform='@TR'><path d='M64 128H0L5.59506e-06 0L64 5.59506e-06C99.3462 8.68512e-06 128 28.6538 128 64C128 99.3462 99.3462 128 64 128Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M-0.00292969 0L127.997 128' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/><line x1='15.9965' y1='111.997' x2='47.9965' y2='79.9965' stroke='@BG' fill='none' stroke-width='@SW'/><path fill-rule='evenodd' clip-rule='evenodd' d='M80 64C80 72.8366 72.8366 80 64 80C55.1634 80 48 72.8366 48 64C48 55.1634 55.1634 48 64 48C72.8366 48 80 55.1634 80 64ZM64 72C68.4183 72 72 68.4183 72 64C72 59.5817 68.4183 56 64 56C59.5817 56 56 59.5817 56 64C56 68.4183 59.5817 72 64 72Z' fill='@BG'/></g>", + ++ lib +"<g transform='@TR'><circle cx='64' cy='64' r='64' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M128 64C92.6538 64 64 92.6538 64 128' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M128 64L0 64' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ lid +"<g transform='@TR'><path d='M0 0C0 70.6925 57.3075 128 128 128V0H0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><line x1='16.0036' y1='15.9965' x2='48.0036' y2='47.9965' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M128 0L0 128' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/></g>", + ++ lig +"<g transform='@TR'><circle cx='64' cy='64' r='64' fill='@FG' stroke='@BG' stroke-width='@SW'/><circle cx='64' cy='64' r='48' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ lin +"<g transform='@TR'><rect width='128' height='128' fill='@FG' stroke='@BG' stroke-width='@SW'/><line x1='64' y1='128' x2='64' y2='-6.55671e-08' stroke='@BG' fill='none' stroke-width='@SW'/><circle cx='80' cy='64' r='8' fill='@BG'/></g>", + ++ lis +"<g transform='@TR'><path d='M128 128C128 57.3076 70.6925 6.18013e-06 1.11901e-05 0L0 128L128 128Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M128 64L0 64' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M-4.70488e-06 64C35.3462 64 64 35.3462 64 0' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ lit +"<g transform='@TR'><path d='M0.0541 0C70.7217 0.0292317 128 57.3256 128 128C57.3177 128 0.0164917 70.7089 7.62806e-06 0.0305091C7.62851e-06 0.0203397 -4.44317e-10 0.01017 0 0H0.0541Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M-0.00286865 0L127.997 128' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/><path d='M128 0C128 35.3511 113.669 67.3551 90.5 90.5193' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M96 0C96 26.5077 85.2564 50.5061 67.8862 67.8783' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M64 0C64 17.6721 56.8374 33.6713 45.2568 45.2529' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M32.3716 0C32.3716 8.83603 28.7903 16.8356 23 22.6264' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ liv +"<g transform='@TR'><rect width='128' height='128' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M-5.21346e-06 32C70.6924 32 128 17.6731 128 0' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M3.4331e-06 96C70.6924 96 128 53.0193 128 0' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M64 0L64 128' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ loc +"<g transform='@TR'><path d='M0.0541 0C70.7217 0.0292317 128 57.3256 128 128C57.3177 128 0.0164917 70.7089 7.62806e-06 0.0305091C7.62851e-06 0.0203397 -4.44317e-10 0.01017 0 0H0.0541Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M128 96C74.9807 96 32 53.0193 32 -4.19629e-06' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ lod +"<g transform='@TR'><path d='M64 0H128V128H64C28.6538 128 0 99.3462 0 64C0 28.6538 28.6538 0 64 0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M16 64C16 90.5097 37.4903 112 64 112' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ lom +"<g transform='@TR'><rect width='128' height='128' fill='@FG' stroke='@BG' stroke-width='@SW'/><circle cx='32' cy='32' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='32' cy='32' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/><circle cx='96' cy='32' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='96' cy='32' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/><circle cx='96' cy='96' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='96' cy='96' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ lon +"<g transform='@TR'><path d='M128 0C57.3075 8.42999e-07 -8.42999e-07 57.3075 0 128H128V0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M2.03434e-06 128C70.6924 128 128 70.6925 128 0' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M1.52575e-06 96C53.0193 96 96 53.0193 96 0' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M1.01717e-06 64C35.3462 64 64 35.3462 64 0' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M5.08584e-07 32C17.6731 32 32 17.6731 32 0' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ lop +"<g transform='@TR'><circle cx='64' cy='64' r='64' fill='@FG' stroke='@BG' stroke-width='@SW'/><line x1='128' y1='64' x2='-8.87604e-09' y2='64' stroke='@BG' fill='none' stroke-width='@SW'/><line x1='128' y1='32' x2='-8.87604e-09' y2='32' stroke='@BG' fill='none' stroke-width='@SW'/><circle cx='64' cy='64' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='64' cy='64' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ lor +"<g transform='@TR'><path d='M64 0H128V128H64C28.6538 128 0 99.3462 0 64C0 28.6538 28.6538 0 64 0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><line x1='64' y1='2.18557e-08' x2='64' y2='128' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ los +"<g transform='@TR'><path d='M0 0C0 70.6925 57.3075 128 128 128V0H0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><line x1='-0.0029152' x2='127.983' y2='127.986' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/><circle cx='96' cy='96' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='96' cy='96' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ luc +"<g transform='@TR'><path d='M128 128C128 57.3076 70.6925 6.18013e-06 1.11901e-05 0L0 128L128 128Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><line x1='128' y1='64' x2='-8.87604e-09' y2='64' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M128 64L0 64' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M128 96L0 96' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ lud +"<g transform='@TR'><path d='M128 128C128 57.3076 70.6925 6.18013e-06 1.11901e-05 0L0 128L128 128Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M128 64L0 64' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M32 0L32 128' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M64 0L64 128' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M96 0L96 128' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ lug +"<g transform='@TR'><path d='M64 128H0L5.59506e-06 -7.62939e-06L64 -2.03434e-06C99.3462 1.05573e-06 128 28.6538 128 64C128 99.3462 99.3462 128 64 128Z' fill='@FG' stroke='@BG' stroke-width='@SW'/></g>", + ++ lun +"<g transform='@TR'><circle cx='64' cy='64' r='64' fill='@FG' stroke='@BG' stroke-width='@SW'/><circle cx='64' cy='64' r='32' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ lup +"<g transform='@TR'><path d='M64 128H0L5.59506e-06 -7.62939e-06L64 -2.03434e-06C99.3462 1.05573e-06 128 28.6538 128 64C128 99.3462 99.3462 128 64 128Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M64 16C90.5097 16 112 37.4903 112 64C112 90.5097 90.5097 112 64 112' stroke='@BG' fill='none' stroke-width='@SW'/><line x1='128' y1='64' x2='-8.87604e-09' y2='64' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ lur +"<g transform='@TR'><path d='M128 128C128 57.3076 70.6925 6.18013e-06 1.11901e-05 0L0 128L128 128Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M64 0L64 128' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M96 0L96 128' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M32 0L32 128' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ lus +"<g transform='@TR'><path d='M128 128C128 57.3076 70.6925 6.18013e-06 1.11901e-05 0L0 128L128 128Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M128 0L0 128' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/><circle cx='96' cy='96' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='96' cy='96' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ lut +"<g transform='@TR'><rect width='128' height='128' fill='@FG' stroke='@BG' stroke-width='@SW'/><circle cx='32' cy='64' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='32' cy='64' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ lux +"<g transform='@TR'><path d='M5.59506e-06 128C70.6925 128 128 70.6925 128 0L0 5.59506e-06L5.59506e-06 128Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path fill-rule='evenodd' clip-rule='evenodd' d='M80 64C80 72.8366 72.8366 80 64 80C55.1634 80 48 72.8366 48 64C48 55.1634 55.1634 48 64 48C72.8366 48 80 55.1634 80 64ZM64 72C68.4183 72 72 68.4183 72 64C72 59.5817 68.4183 56 64 56C59.5817 56 56 59.5817 56 64C56 68.4183 59.5817 72 64 72Z' fill='@BG'/></g>", + ++ lyd +"<g transform='@TR'><path d='M0.0541 0C70.7217 0.0292317 128 57.3256 128 128C57.3177 128 0.0164917 70.7089 7.62806e-06 0.0305091C7.62851e-06 0.0203397 -4.44317e-10 0.01017 0 0H0.0541Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M-0.00280762 0L127.997 128' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/><circle cx='64' cy='64' r='32' stroke='@BG' fill='none' stroke-width='@SW'/><circle cx='64' cy='32' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='64' cy='32' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ lyn +"<g transform='@TR'><path d='M5.59506e-06 128C70.6925 128 128 70.6925 128 0L0 5.59506e-06L5.59506e-06 128Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M32 0L32 128' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ lyr +"<g transform='@TR'><path d='M0 127.946C0.0292286 57.2783 57.3256 3.08928e-06 128 0C128 70.6823 70.7089 127.984 0.0305092 128C0.0203397 128 0.01017 128 2.36469e-09 128L0 127.946Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M-0.00268555 0L127.997 128' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/><circle cx='80' cy='48' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='80' cy='48' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ lys +"<g transform='@TR'><path d='M128 128C128 57.3076 70.6925 6.18013e-06 1.11901e-05 0L0 128L128 128Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><circle cx='64' cy='64' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='64' cy='64' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/><circle cx='16' cy='112' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='16' cy='112' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ lyt +"<g transform='@TR'><path d='M64 128H0L5.59506e-06 0L64 5.59506e-06C99.3462 8.68512e-06 128 28.6538 128 64C128 99.3462 99.3462 128 64 128Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M128 0L0 128' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/><line x1='80.0035' y1='79.9965' x2='112.003' y2='111.997' stroke='@BG' fill='none' stroke-width='@SW'/><circle cx='64' cy='64' r='16' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ lyx +"<g transform='@TR'><path d='M5.59506e-06 128C70.6925 128 128 70.6925 128 0L0 5.59506e-06L5.59506e-06 128Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M-0.00292969 0L127.997 128' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/><circle cx='32' cy='32' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='32' cy='32' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ mac +"<g transform='@TR'><path d='M0 0C0 70.6925 57.3075 128 128 128V0H0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><circle cx='16' cy='112' r='11.5' fill='@BG' stroke='@BG' stroke-width='@SW'/><circle cx='16' cy='112' r='9' fill='@FG' stroke='@FG' stroke-width='@SW'/></g>", + ++ mag +"<g transform='@TR'><path d='M64 0H128V128H64C28.6538 128 0 99.3462 0 64C0 28.6538 28.6538 0 64 0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><circle cx='64' cy='64' r='32' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M128 64L0 64' stroke='@BG' fill='none' stroke-width='@SW'/><circle cx='64' cy='96' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='64' cy='96' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ mal +"<g transform='@TR'><path d='M0.0541 0C70.7217 0.0292317 128 57.3256 128 128C57.3177 128 0.0164917 70.7089 7.62806e-06 0.0305091C7.62851e-06 0.0203397 -4.44317e-10 0.01017 0 0H0.0541Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><line x1='80.0035' y1='79.9964' x2='112.004' y2='111.996' stroke='@BG' fill='none' stroke-width='@SW'/><circle cx='16' cy='112' r='11.5' fill='@BG' stroke='@BG' stroke-width='@SW'/><circle cx='16' cy='112' r='9' fill='@FG' stroke='@FG' stroke-width='@SW'/></g>", + ++ map +"<g transform='@TR'><path d='M128 0C57.3075 8.42999e-07 -8.42999e-07 57.3075 0 128H128V0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><line x1='80.0036' y1='79.9965' x2='112.004' y2='111.997' stroke='@BG' fill='none' stroke-width='@SW'/><circle cx='64' cy='64' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='64' cy='64' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ mar +"<g transform='@TR'><circle cx='64' cy='64' r='64' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M-0.0029152 0L127.997 128' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/><path d='M64 64L64 128' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M86.6274 86.6274C99.1242 74.1307 99.1242 53.8694 86.6274 41.3726C74.1306 28.8758 53.8694 28.8758 41.3726 41.3726' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M75.3137 75.3137C81.5621 69.0653 81.5621 58.9347 75.3137 52.6863C69.0653 46.4379 58.9347 46.4379 52.6863 52.6863' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M97.9411 97.9411C116.686 79.1959 116.686 48.804 97.9411 30.0589C79.196 11.3137 48.804 11.3137 30.0589 30.0589' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ mas +"<g transform='@TR'><rect width='128' height='128' fill='@FG' stroke='@BG' stroke-width='@SW'/><circle cx='64' cy='64' r='32' stroke='@BG' fill='none' stroke-width='@SW'/><path fill-rule='evenodd' clip-rule='evenodd' d='M80 64C80 72.8366 72.8366 80 64 80C55.1634 80 48 72.8366 48 64C48 55.1634 55.1634 48 64 48C72.8366 48 80 55.1634 80 64ZM64 72C68.4183 72 72 68.4183 72 64C72 59.5817 68.4183 56 64 56C59.5817 56 56 59.5817 56 64C56 68.4183 59.5817 72 64 72Z' fill='@BG'/></g>", + ++ mat +"<g transform='@TR'><path d='M0 0C0 70.6925 57.3075 128 128 128V0H0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M128 32C110.327 32 96 17.6731 96 0' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ meb +"<g transform='@TR'><rect width='128' height='128' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M32 -3.05151e-06C32 53.0193 74.9807 96 128 96' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ mec +"<g transform='@TR'><path d='M128 128C128 57.3076 70.6925 6.18013e-06 1.11901e-05 0L0 128L128 128Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><line x1='80.0035' y1='79.9965' x2='112.003' y2='111.997' stroke='@BG' fill='none' stroke-width='@SW'/><circle cx='64' cy='64' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='64' cy='64' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ med +"<g transform='@TR'><circle cx='64' cy='64' r='64' fill='@FG' stroke='@BG' stroke-width='@SW'/><circle cx='96' cy='64' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='96' cy='64' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ meg +"<g transform='@TR'><rect width='128' height='128' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M128 64C92.6538 64 64 92.6538 64 128' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ mel +"<g transform='@TR'><path d='M0 127.946C0.0292286 57.2783 57.3256 3.08928e-06 128 0C128 70.6823 70.7089 127.984 0.0305092 128C0.0203397 128 0.01017 128 2.36469e-09 128L0 127.946Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><line x1='15.9964' y1='111.997' x2='47.9964' y2='79.9965' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ mep +"<g transform='@TR'><path d='M128 0C57.3075 8.42999e-07 -8.42999e-07 57.3075 0 128H128V0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M128 64L0 64' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M128 96L0 96' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M128 32L0 32' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ mer +"<g transform='@TR'><path d='M64 128H0L5.59506e-06 0L64 5.59506e-06C99.3462 8.68512e-06 128 28.6538 128 64C128 99.3462 99.3462 128 64 128Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M32 0L32 128' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ mes +"<g transform='@TR'><path d='M128 128C128 57.3076 70.6925 6.18013e-06 1.11901e-05 0L0 128L128 128Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M-0.00280762 0L127.997 128' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/><line x1='15.9964' y1='111.996' x2='47.9964' y2='79.9964' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ met +"<g transform='@TR'><circle cx='64' cy='64' r='64' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M32 128L32 0' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ mev +"<g transform='@TR'><path d='M64 128H0L5.59506e-06 0L64 5.59506e-06C99.3462 8.68512e-06 128 28.6538 128 64C128 99.3462 99.3462 128 64 128Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><circle cx='64' cy='64' r='16' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ mex +"<g transform='@TR'><path d='M64 128H0L5.59506e-06 0L64 5.59506e-06C99.3462 8.68512e-06 128 28.6538 128 64C128 99.3462 99.3462 128 64 128Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M-0.00292969 0L127.997 128' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/><path fill-rule='evenodd' clip-rule='evenodd' d='M80 64C80 72.8366 72.8366 80 64 80C55.1634 80 48 72.8366 48 64C48 55.1634 55.1634 48 64 48C72.8366 48 80 55.1634 80 64ZM64 72C68.4183 72 72 68.4183 72 64C72 59.5817 68.4183 56 64 56C59.5817 56 56 59.5817 56 64C56 68.4183 59.5817 72 64 72Z' fill='@BG'/></g>", + ++ mic +"<g transform='@TR'><path d='M128 128C128 57.3076 70.6925 6.18013e-06 1.11901e-05 0L0 128L128 128Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M-2.09815e-06 80C26.5097 80 48 101.49 48 128' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ mid +"<g transform='@TR'><path d='M0 0C0 70.6925 57.3075 128 128 128V0H0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><line x1='128' y1='64' x2='-4.37114e-08' y2='64' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M128 64C92.6538 64 64 92.6538 64 128' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ mig +"<g transform='@TR'><path d='M64 0H128V128H64C28.6538 128 0 99.3462 0 64C0 28.6538 28.6538 0 64 0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><line x1='64' y1='2.18557e-08' x2='64' y2='128' stroke='@BG' fill='none' stroke-width='@SW'/><line x1='80.0036' y1='79.9965' x2='112.004' y2='111.997' stroke='@BG' fill='none' stroke-width='@SW'/><circle cx='64' cy='64' r='16' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ mil +"<g transform='@TR'><path d='M64 0H128V128H64C28.6538 128 0 99.3462 0 64C0 28.6538 28.6538 0 64 0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><line x1='128' y1='64' x2='-4.37114e-08' y2='64' stroke='@BG' fill='none' stroke-width='@SW'/><line x1='128' y1='32' x2='-4.37114e-08' y2='32' stroke='@BG' fill='none' stroke-width='@SW'/><line x1='128' y1='96' x2='-4.37114e-08' y2='96' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ min +"<g transform='@TR'><rect width='128' height='128' fill='@FG' stroke='@BG' stroke-width='@SW'/><line x1='-0.0029152' x2='127.983' y2='127.986' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/></g>", + ++ mip +"<g transform='@TR'><path d='M128 0C57.3075 8.42999e-07 -8.42999e-07 57.3075 0 128H128V0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><line x1='64' y1='2.18557e-08' x2='64' y2='128' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M128 128C92.6538 128 64 99.3462 64 64C64 28.6538 92.6538 4.215e-07 128 0' stroke='@BG' fill='none' stroke-width='@SW'/><circle cx='64' cy='64' r='16' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ mir +"<g transform='@TR'><path d='M0 0C0 70.6925 57.3075 128 128 128V0H0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><line x1='16.0036' y1='15.9964' x2='48.0036' y2='47.9964' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M96 64C96 46.3269 81.6731 32 64 32' stroke='@BG' fill='none' stroke-width='@SW'/><circle cx='64' cy='64' r='16' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ mis +"<g transform='@TR'><path d='M128 0C57.3075 8.42999e-07 -8.42999e-07 57.3075 0 128H128V0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M128 64C92.6538 64 64 92.6538 64 128' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M-0.00286865 0L127.997 128' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/></g>", + ++ mit +"<g transform='@TR'><path d='M0.0541 0C70.7217 0.0292317 128 57.3256 128 128C57.3177 128 0.0164917 70.7089 7.62806e-06 0.0305091C7.62851e-06 0.0203397 -4.44317e-10 0.01017 0 0H0.0541Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><line x1='0.5' y1='-0.5' x2='181.5' y2='-0.5' transform='matrix(-0.707107 0.707107 0.707107 0.707107 128.71 0)' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/><circle cx='32' cy='32' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='32' cy='32' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ moc +"<g transform='@TR'><path d='M0.0541 0C70.7217 0.0292317 128 57.3256 128 128C57.3177 128 0.0164917 70.7089 7.62806e-06 0.0305091C7.62851e-06 0.0203397 -4.44317e-10 0.01017 0 0H0.0541Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M128 64L0 64' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M128 96L0 96' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M128 32L0 32' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ mod +"<g transform='@TR'><path d='M64 0H128V128H64C28.6538 128 0 99.3462 0 64C0 28.6538 28.6538 0 64 0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M0 96L128 96' stroke='@BG' fill='none' stroke-width='@SW'/><line x1='16.0035' y1='15.9965' x2='48.0035' y2='47.9965' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ mog +"<g transform='@TR'><path d='M128 0C57.3075 8.42999e-07 -8.42999e-07 57.3075 0 128H128V0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><line x1='-0.0029152' x2='127.983' y2='127.986' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/><circle cx='64' cy='64' r='32' stroke='@BG' fill='none' stroke-width='@SW'/><circle cx='64' cy='64' r='16' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ mol +"<g transform='@TR'><circle cx='64' cy='64' r='64' fill='@FG' stroke='@BG' stroke-width='@SW'/><line x1='128' y1='64' x2='-4.37114e-08' y2='64' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M112 64C112 90.5097 90.5097 112 64 112C37.4903 112 16 90.5097 16 64' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M112 0C112 26.5097 90.5097 48 64 48C37.4903 48 16 26.5097 16 0' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ mon +"<g transform='@TR'><path d='M128 0C57.3075 8.42999e-07 -8.42999e-07 57.3075 0 128H128V0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path fill-rule='evenodd' clip-rule='evenodd' d='M80 64C80 72.8366 72.8366 80 64 80C55.1634 80 48 72.8366 48 64C48 55.1634 55.1634 48 64 48C72.8366 48 80 55.1634 80 64ZM64 72C68.4183 72 72 68.4183 72 64C72 59.5817 68.4183 56 64 56C59.5817 56 56 59.5817 56 64C56 68.4183 59.5817 72 64 72Z' fill='@BG'/></g>", + ++ mop +"<g transform='@TR'><circle cx='64' cy='64' r='64' fill='@FG' stroke='@BG' stroke-width='@SW'/><line x1='-0.0029152' x2='127.983' y2='127.986' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/><circle cx='64' cy='64' r='32' stroke='@BG' fill='none' stroke-width='@SW'/><circle cx='32' cy='64' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='32' cy='64' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ mor +"<g transform='@TR'><path d='M64 0H128V128H64C28.6538 128 0 99.3462 0 64C0 28.6538 28.6538 0 64 0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><line x1='16.0035' y1='15.9964' x2='48.0035' y2='47.9964' stroke='@BG' fill='none' stroke-width='@SW'/><line x1='15.9964' y1='111.996' x2='47.9964' y2='79.9964' stroke='@BG' fill='none' stroke-width='@SW'/><circle cx='64' cy='64' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='64' cy='64' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ mos +"<g transform='@TR'><path d='M0 0C0 70.6925 57.3075 128 128 128V0H0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><line x1='0.5' y1='-0.5' x2='181.5' y2='-0.5' transform='matrix(-0.707107 0.707107 0.707107 0.707107 128.71 0)' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/><circle cx='96' cy='32' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='96' cy='32' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ mot +"<g transform='@TR'><path d='M64 0H128V128H64C28.6538 128 0 99.3462 0 64C0 28.6538 28.6538 0 64 0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M128 96C110.327 96 96 81.6731 96 64C96 46.3269 110.327 32 128 32' stroke='@BG' fill='none' stroke-width='@SW'/><circle cx='64' cy='64' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='64' cy='64' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ mud +"<g transform='@TR'><path d='M128 128C128 57.3076 70.6925 6.18013e-06 1.11901e-05 0L0 128L128 128Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M-0.00292969 0L127.997 128' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/><circle cx='80' cy='80' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='80' cy='80' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ mug +"<g transform='@TR'><path d='M64 128H0L5.59506e-06 0L64 5.59506e-06C99.3462 8.68512e-06 128 28.6538 128 64C128 99.3462 99.3462 128 64 128Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M64 96C81.6731 96 96 81.6731 96 64C96 46.3269 81.6731 32 64 32' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ mul +"<g transform='@TR'><circle cx='64' cy='64' r='64' fill='@FG' stroke='@BG' stroke-width='@SW'/><line x1='80.0035' y1='79.9964' x2='112.003' y2='111.996' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M112 64C112 37.4903 90.5097 16 64 16' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ mun +"<g transform='@TR'><circle cx='64' cy='64' r='64' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M128 64C92.6538 64 64 35.3462 64 0' stroke='@BG' fill='none' stroke-width='@SW'/><circle cx='64' cy='64' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='64' cy='64' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ mur +"<g transform='@TR'><path d='M128 128C128 57.3076 70.6925 6.18013e-06 1.11901e-05 0L0 128L128 128Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M128 64L0 64' stroke='@BG' fill='none' stroke-width='@SW'/><circle cx='64' cy='64' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='64' cy='64' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/><circle cx='32' cy='64' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='32' cy='64' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ mus +"<g transform='@TR'><path d='M128 128C128 57.3076 70.6925 6.18013e-06 1.11901e-05 0L0 128L128 128Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><line x1='0.5' y1='-0.5' x2='181.5' y2='-0.5' transform='matrix(-0.707107 0.707107 0.707107 0.707107 128.71 0)' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/><path d='M96 128C96 74.9807 53.0193 32 0 32' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ mut +"<g transform='@TR'><rect width='128' height='128' fill='@FG' stroke='@BG' stroke-width='@SW'/><circle cx='96' cy='32' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='96' cy='32' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ myl +"<g transform='@TR'><path d='M5.59506e-06 128C70.6925 128 128 70.6925 128 0L0 5.59506e-06L5.59506e-06 128Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><line x1='16.0035' y1='15.9965' x2='48.0035' y2='47.9965' stroke='@BG' fill='none' stroke-width='@SW'/><circle cx='16' cy='16' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='16' cy='16' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ myn +"<g transform='@TR'><path d='M5.59506e-06 128C70.6925 128 128 70.6925 128 0L0 5.59506e-06L5.59506e-06 128Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M128 1.52638e-06C57.3076 -7.74381e-06 9.2702e-06 57.3075 0 128' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M128 32C74.9807 32 32 74.9807 32 128' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M128 64C92.6538 64 64 92.6538 64 128' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M128 96C110.327 96 96 110.327 96 128' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ myr +"<g transform='@TR'><path d='M0 127.946C0.0292286 57.2783 57.3256 3.08928e-06 128 0C128 70.6823 70.7089 127.984 0.0305092 128C0.0203397 128 0.01017 128 2.36469e-09 128L0 127.946Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M-0.00292969 0L127.997 128' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/><circle cx='32' cy='96' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='32' cy='96' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ nac +"<g transform='@TR'><path d='M0 0C0 70.6925 57.3075 128 128 128V0H0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><circle cx='64' cy='64' r='16' stroke='@BG' fill='none' stroke-width='@SW'/><circle cx='16' cy='112' r='11.5' fill='@BG' stroke='@BG' stroke-width='@SW'/><circle cx='16' cy='112' r='9' fill='@FG' stroke='@FG' stroke-width='@SW'/></g>", + ++ nal +"<g transform='@TR'><path d='M0.0541 0C70.7217 0.0292317 128 57.3256 128 128C57.3177 128 0.0164917 70.7089 7.62806e-06 0.0305091C7.62851e-06 0.0203397 -4.44317e-10 0.01017 0 0H0.0541Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><line x1='-0.0029152' x2='127.983' y2='127.986' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/><path d='M2.82114e-06 110C60.7513 110 110 60.7513 110 0' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M-5.09828e-06 73C40.3168 73 73 40.3168 73 0' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M-6.63647e-07 37C20.4345 37 37 20.4345 37 0' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ nam +"<g transform='@TR'><path d='M64 0H128V128H64C28.6538 128 0 99.3462 0 64C0 28.6538 28.6538 0 64 0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><line x1='8.74228e-08' y1='64' x2='128' y2='64' stroke='@BG' fill='none' stroke-width='@SW'/><circle cx='64' cy='64' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='64' cy='64' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/><circle cx='112' cy='64' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='112' cy='64' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ nap +"<g transform='@TR'><path d='M128 0C57.3075 8.42999e-07 -8.42999e-07 57.3075 0 128H128V0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><line x1='64' y1='2.18557e-08' x2='64' y2='128' stroke='@BG' fill='none' stroke-width='@SW'/><circle cx='96' cy='32' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='96' cy='32' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/><circle cx='96' cy='96' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='96' cy='96' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ nar +"<g transform='@TR'><circle cx='64' cy='64' r='64' fill='@FG' stroke='@BG' stroke-width='@SW'/><circle cx='64' cy='64' r='32' stroke='@BG' fill='none' stroke-width='@SW'/><circle cx='64' cy='64' r='8' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ nat +"<g transform='@TR'><path d='M0 0C0 70.6925 57.3075 128 128 128V0H0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M-1.52588e-05 128C-9.07866e-06 57.3075 57.3076 1.44926e-06 128 7.62939e-06' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ nav +"<g transform='@TR'><path d='M0 0C0 70.6925 57.3075 128 128 128V0H0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M128 96C101.492 96 77.4939 85.2564 60.1217 67.8862' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M128 64C110.328 64 94.3287 56.8374 82.7471 45.2568' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M128 32.3716C119.164 32.3716 111.164 28.7903 105.374 23' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ neb +"<g transform='@TR'><rect width='128' height='128' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M128 32C74.9807 32 32 74.9807 32 128' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ nec +"<g transform='@TR'><path d='M128 128C128 57.3076 70.6925 6.18013e-06 1.11901e-05 0L0 128L128 128Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><circle cx='32' cy='32' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='32' cy='32' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/><circle cx='96' cy='96' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='96' cy='96' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/><path d='M64 0L64 128' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ ned +"<g transform='@TR'><circle cx='64' cy='64' r='64' fill='@FG' stroke='@BG' stroke-width='@SW'/><circle cx='64' cy='64' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='64' cy='64' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ nel +"<g transform='@TR'><path d='M0 127.946C0.0292286 57.2783 57.3256 3.08928e-06 128 0C128 70.6823 70.7089 127.984 0.0305092 128C0.0203397 128 0.01017 128 2.36469e-09 128L0 127.946Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M-0.00268555 0L127.997 128' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/><path d='M96 1.90735e-06C96 53.0193 53.0193 96 0 96' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ nem +"<g transform='@TR'><circle cx='64' cy='64' r='64' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M-0.00292969 0L127.997 128' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/><path d='M128 64C92.6538 64 64 92.6538 64 128' stroke='@BG' fill='none' stroke-width='@SW'/><circle cx='32' cy='32' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='32' cy='32' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ nep +"<g transform='@TR'><path d='M128 128C128 57.3076 70.6925 6.18013e-06 1.11901e-05 0L0 128L128 128Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M128 128C57.3076 128 3.09007e-06 70.6925 0 0' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M128 96C74.9807 96 32 53.0193 32 0' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M128 64C92.6538 64 64 35.3462 64 0' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M128 32C110.327 32 96 17.6731 96 0' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ ner +"<g transform='@TR'><path d='M64 128H0L5.59506e-06 0L64 5.59506e-06C99.3462 8.68512e-06 128 28.6538 128 64C128 99.3462 99.3462 128 64 128Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M64 0L64 128' stroke='@BG' fill='none' stroke-width='@SW'/><line x1='15.9965' y1='111.997' x2='47.9965' y2='79.9965' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ nes +"<g transform='@TR'><path d='M128 0C57.3075 8.42999e-07 -8.42999e-07 57.3075 0 128H128V0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M64 0L64 128' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ net +"<g transform='@TR'><circle cx='64' cy='64' r='64' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M64 64L64 128' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ nev +"<g transform='@TR'><path d='M64 128H0L5.59506e-06 0L64 5.59506e-06C99.3462 8.68512e-06 128 28.6538 128 64C128 99.3462 99.3462 128 64 128Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><circle cx='64' cy='64' r='16' stroke='@BG' fill='none' stroke-width='@SW'/><circle cx='32' cy='32' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='32' cy='32' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ nex +"<g transform='@TR'><path d='M64 128H0L5.59506e-06 -7.62939e-06L64 -2.03434e-06C99.3462 1.05573e-06 128 28.6538 128 64C128 99.3462 99.3462 128 64 128Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><line x1='80.0035' y1='79.9964' x2='112.003' y2='111.996' stroke='@BG' fill='none' stroke-width='@SW'/><path fill-rule='evenodd' clip-rule='evenodd' d='M80 64C80 72.8366 72.8366 80 64 80C55.1634 80 48 72.8366 48 64C48 55.1634 55.1634 48 64 48C72.8366 48 80 55.1634 80 64ZM64 72C68.4183 72 72 68.4183 72 64C72 59.5817 68.4183 56 64 56C59.5817 56 56 59.5817 56 64C56 68.4183 59.5817 72 64 72Z' fill='@BG'/></g>", + ++ nib +"<g transform='@TR'><circle cx='64' cy='64' r='64' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M128 64L0 64' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M128 96L0 96' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ nid +"<g transform='@TR'><path d='M0 0C0 70.6925 57.3075 128 128 128V0H0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M128 64L0 64' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M128 128C92.6538 128 64 70.6925 64 7.63192e-07' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ nil +"<g transform='@TR'><path d='M64 0H128V128H64C28.6538 128 0 99.3462 0 64C0 28.6538 28.6538 0 64 0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><line x1='128' y1='64' x2='-8.87604e-09' y2='64' stroke='@BG' fill='none' stroke-width='@SW'/><line x1='128' y1='32' x2='-8.87604e-09' y2='32' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ nim +"<g transform='@TR'><path d='M128 64V128H0L2.79753e-06 64C4.34256e-06 28.6538 28.6538 -1.54503e-06 64 0C99.3462 1.54503e-06 128 28.6538 128 64Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><line x1='64' y1='2.18557e-08' x2='64' y2='128' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ nis +"<g transform='@TR'><path d='M128 0C57.3075 8.42999e-07 -8.42999e-07 57.3075 0 128H128V0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M128 32C74.9807 32 32 74.9807 32 128' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M-0.00285435 0L127.997 128' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/></g>", + ++ noc +"<g transform='@TR'><path d='M64 0H128V128H64C28.6538 128 0 99.3462 0 64C0 28.6538 28.6538 0 64 0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><line x1='64' y1='2.18557e-08' x2='64' y2='128' stroke='@BG' fill='none' stroke-width='@SW'/><circle cx='64' cy='64' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='64' cy='64' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ nod +"<g transform='@TR'><path d='M64 0H128V128H64C28.6538 128 0 99.3462 0 64C0 28.6538 28.6538 0 64 0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><circle cx='32' cy='64' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='32' cy='64' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/><circle cx='96' cy='64' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='96' cy='64' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ nol +"<g transform='@TR'><circle cx='64' cy='64' r='64' fill='@FG' stroke='@BG' stroke-width='@SW'/><line x1='128' y1='64' x2='1.51277e-05' y2='64' stroke='@BG' fill='none' stroke-width='@SW'/><circle cx='64' cy='96' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='64' cy='96' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ nom +"<g transform='@TR'><rect width='128' height='128' fill='@FG' stroke='@BG' stroke-width='@SW'/><circle cx='32' cy='96' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='32' cy='96' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/><circle cx='96' cy='96' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='96' cy='96' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/><circle cx='96' cy='32' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='96' cy='32' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ nop +"<g transform='@TR'><circle cx='64' cy='64' r='64' fill='@FG' stroke='@BG' stroke-width='@SW'/><line x1='-0.0029152' x2='127.983' y2='127.986' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/><line y1='-0.5' x2='45.2548' y2='-0.5' transform='matrix(0.707107 -0.707107 -0.707107 -0.707107 79.65 47.65)' stroke='@BG' fill='none' stroke-width='@SW'/><circle cx='64' cy='64' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='64' cy='64' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ nor +"<g transform='@TR'><path d='M64 0H128V128H64C28.6538 128 0 99.3462 0 64C0 28.6538 28.6538 0 64 0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M64 96C46.3269 96 32 81.6731 32 64' stroke='@BG' fill='none' stroke-width='@SW'/><circle cx='64' cy='64' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='64' cy='64' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ nos +"<g transform='@TR'><path d='M0 0C0 70.6925 57.3075 128 128 128V0H0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><line x1='0.5' y1='-0.5' x2='181.5' y2='-0.5' transform='matrix(-0.707107 0.707107 0.707107 0.707107 128.71 0)' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/><circle cx='32' cy='32' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='32' cy='32' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ nov +"<g transform='@TR'><rect width='128' height='128' fill='@FG' stroke='@BG' stroke-width='@SW'/><line x1='-0.0029152' x2='127.983' y2='127.986' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/><path d='M2.03434e-06 128C70.6924 128 128 70.6925 128 0' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M1.52575e-06 96C53.0193 96 96 53.0193 96 0' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M1.01717e-06 64C35.3462 64 64 35.3462 64 0' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M5.08584e-07 32C17.6731 32 32 17.6731 32 0' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ nub +"<g transform='@TR'><path d='M128 128C128 57.3076 70.6925 6.18013e-06 1.11901e-05 0L0 128L128 128Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M128 64L0 64' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ nul +"<g transform='@TR'><circle cx='64' cy='64' r='64' fill='@FG' stroke='@BG' stroke-width='@SW'/><circle cx='64' cy='64' r='32' stroke='@BG' fill='none' stroke-width='@SW'/><circle cx='32' cy='64' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='32' cy='64' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ num +"<g transform='@TR'><path d='M128 128C128 57.3076 70.6925 6.18013e-06 1.11901e-05 0L0 128L128 128Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M128 0L0 128' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/><circle cx='32' cy='32' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='32' cy='32' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/><circle cx='96' cy='96' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='96' cy='96' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ nup +"<g transform='@TR'><path d='M64 128H0L5.59506e-06 -7.62939e-06L64 -2.03434e-06C99.3462 1.05573e-06 128 28.6538 128 64C128 99.3462 99.3462 128 64 128Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M64 16C90.5097 16 112 37.4903 112 64C112 90.5097 90.5097 112 64 112' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ nus +"<g transform='@TR'><path d='M128 128C128 57.3076 70.6925 6.18013e-06 1.11901e-05 0L0 128L128 128Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M-0.00280762 0L127.997 128' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/><path d='M0.000105172 128C35.3582 128 67.3679 113.664 90.5332 90.4863' stroke='@BG' fill='none' stroke-width='@SW'/><circle cx='31' cy='32' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='31' cy='32' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ nut +"<g transform='@TR'><rect width='128' height='128' fill='@FG' stroke='@BG' stroke-width='@SW'/><line x1='80.0035' y1='79.9964' x2='112.003' y2='111.996' stroke='@BG' fill='none' stroke-width='@SW'/><line y1='-0.5' x2='45.2548' y2='-0.5' transform='matrix(0.707107 -0.707107 -0.707107 -0.707107 79.6499 47.6499)' stroke='@BG' fill='none' stroke-width='@SW'/><circle cx='96' cy='96' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='96' cy='96' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ nux +"<g transform='@TR'><path d='M128 128C128 57.3076 70.6925 6.18013e-06 1.11901e-05 0L0 128L128 128Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M128 64L0 64' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M128 96L0 96' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M128 32L0 32' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ nyd +"<g transform='@TR'><path d='M0.0541 0C70.7217 0.0292317 128 57.3256 128 128C57.3177 128 0.0164917 70.7089 7.62806e-06 0.0305091C7.62851e-06 0.0203397 -4.44317e-10 0.01017 0 0H0.0541Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M-0.00292969 0L127.997 128' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/><circle cx='64' cy='64' r='32' stroke='@BG' fill='none' stroke-width='@SW'/><circle cx='64' cy='64' r='16' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ nyl +"<g transform='@TR'><path d='M128 128C128 57.3076 70.6925 6.18013e-06 1.11901e-05 0L0 128L128 128Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M-0.00292969 0L127.997 128' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/><path d='M0 128C4.63574e-06 92.6489 14.3309 60.6449 37.5 37.4807' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M32 128C32 101.492 42.7436 77.4939 60.1138 60.1217' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M64 128C64 110.328 71.1626 94.3287 82.7432 82.7471' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M95.6284 128C95.6284 119.164 99.2097 111.164 105 105.374' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ nym +"<g transform='@TR'><path d='M5.59506e-06 128C70.6925 128 128 70.6925 128 0L0 5.59506e-06L5.59506e-06 128Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M64 0L64 128' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M96 0L96 128' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M32 0L32 128' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ nyr +"<g transform='@TR'><path d='M0 127.946C0.0292286 57.2783 57.3256 3.08928e-06 128 0C128 70.6823 70.7089 127.984 0.0305092 128C0.0203397 128 0.01017 128 2.36469e-09 128L0 127.946Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M-0.00268555 0L127.997 128' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/><path d='M95.9984 0C95.9984 26.3298 85.3985 50.1839 68.2332 67.5278M63.9983 0C63.9983 17.4933 56.9799 33.3473 45.6054 44.8999M31.9983 0C31.9983 8.65672 28.5609 16.5106 22.9766 22.2711' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ nys +"<g transform='@TR'><path d='M128 128C128 57.3076 70.6925 6.18013e-06 1.11901e-05 0L0 128L128 128Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><circle cx='16' cy='112' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='16' cy='112' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ nyt +"<g transform='@TR'><path d='M64 128H0L5.59506e-06 0L64 5.59506e-06C99.3462 8.68512e-06 128 28.6538 128 64C128 99.3462 99.3462 128 64 128Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M128 64L0 64' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M64 32C81.6731 32 96 46.3269 96 64' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M64 16C90.5097 16 112 37.4903 112 64' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ nyx +"<g transform='@TR'><path d='M5.59506e-06 128C70.6925 128 128 70.6925 128 0L0 5.59506e-06L5.59506e-06 128Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M-0.00292969 0L127.997 128' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/><path fill-rule='evenodd' clip-rule='evenodd' d='M80 64C80 72.8366 72.8366 80 64 80C55.1634 80 48 72.8366 48 64C48 55.1634 55.1634 48 64 48C72.8366 48 80 55.1634 80 64ZM64 72C68.4183 72 72 68.4183 72 64C72 59.5817 68.4183 56 64 56C59.5817 56 56 59.5817 56 64C56 68.4183 59.5817 72 64 72Z' fill='@BG'/></g>", + ++ pac +"<g transform='@TR'><path d='M0 0C0 70.6925 57.3075 128 128 128V0H0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M128 0L0 128' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/><circle cx='64' cy='64' r='16' stroke='@BG' fill='none' stroke-width='@SW'/><circle cx='64' cy='32' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='64' cy='32' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ pad +"<g transform='@TR'><path d='M0 0C0 70.6925 57.3075 128 128 128V0H0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><circle cx='96' cy='32' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='96' cy='32' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ pag +"<g transform='@TR'><path d='M64 0H128V128H64C28.6538 128 0 99.3462 0 64C0 28.6538 28.6538 0 64 0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><line x1='15.9964' y1='111.997' x2='47.9964' y2='79.9965' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ pal +"<g transform='@TR'><path d='M0.0541 0C70.7217 0.0292317 128 57.3256 128 128C57.3177 128 0.0164917 70.7089 7.62806e-06 0.0305091C7.62851e-06 0.0203397 -4.44317e-10 0.01017 0 0H0.0541Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M128 0L0 128' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/><path d='M128 96C101.492 96 77.4939 85.2564 60.1217 67.8862' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M128 64C110.328 64 94.3287 56.8374 82.7471 45.2568' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M128 32.3716C119.164 32.3716 111.164 28.7903 105.374 23' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ pan +"<g transform='@TR'><path d='M0 0C0 70.6925 57.3075 128 128 128V0H0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><line x1='0.5' y1='-0.5' x2='181.5' y2='-0.5' transform='matrix(-0.707107 0.707107 0.707107 0.707107 128.71 0)' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/><path d='M41.3726 86.6274C28.8758 74.1306 28.8758 53.8693 41.3726 41.3725C53.8694 28.8758 74.1306 28.8758 86.6274 41.3725' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ par +"<g transform='@TR'><circle cx='64' cy='64' r='64' fill='@FG' stroke='@BG' stroke-width='@SW'/><line x1='0.5' y1='-0.5' x2='181.5' y2='-0.5' transform='matrix(-0.707107 0.707107 0.707107 0.707107 128.693 0)' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/><circle cx='64' cy='64' r='16' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ pas +"<g transform='@TR'><rect width='128' height='128' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M32 0L32 128' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M64 0L64 128' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M96 0L96 128' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ pat +"<g transform='@TR'><path d='M0 0C0 70.6925 57.3075 128 128 128V0H0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M32 -2.67054e-06C32 53.0193 74.9807 96 128 96' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M64 -1.78036e-06C64 35.3462 92.6538 64 128 64' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M96 -8.9018e-07C96 17.6731 110.327 32 128 32' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ pec +"<g transform='@TR'><path d='M128 128C128 57.3076 70.6925 6.18013e-06 1.11901e-05 0L0 128L128 128Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M128 0L0 128' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/><circle cx='64' cy='64' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='64' cy='64' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ ped +"<g transform='@TR'><circle cx='64' cy='64' r='64' fill='@FG' stroke='@BG' stroke-width='@SW'/><circle cx='32' cy='64' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='32' cy='64' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ peg +"<g transform='@TR'><rect width='128' height='128' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M96 0C96 17.6731 81.6731 32 64 32C46.3269 32 32 17.6731 32 0' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ pel +"<g transform='@TR'><path d='M0 127.946C0.0292286 57.2783 57.3256 3.08928e-06 128 0C128 70.6823 70.7089 127.984 0.0305092 128C0.0203397 128 0.01017 128 2.36469e-09 128L0 127.946Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><circle cx='64' cy='64' r='32' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M112 64C112 37.4903 90.5097 16 64 16' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ pem +"<g transform='@TR'><circle cx='64' cy='64' r='64' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M-0.00280762 0L127.997 128' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/><path d='M64 128C64 92.6538 35.3462 64 0 64' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ pen +"<g transform='@TR'><rect width='128' height='128' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M96 0C96 17.6731 81.6731 32 64 32C46.3269 32 32 17.6731 32 0' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M-0.00292969 0L127.997 128' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/></g>", + ++ per +"<g transform='@TR'><path d='M0 64L5.59506e-06 0L128 1.11901e-05V64C128 99.3462 99.3462 128 64 128C28.6538 128 -4.6351e-06 99.3462 0 64Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M64 0L64 128' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ pes +"<g transform='@TR'><path d='M128 0C57.3075 8.42999e-07 -8.42999e-07 57.3075 0 128H128V0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M64 112C90.5097 112 112 90.5097 112 64' stroke='@BG' fill='none' stroke-width='@SW'/><line x1='-0.00285417' x2='127.983' y2='127.986' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/></g>", + ++ pet +"<g transform='@TR'><circle cx='64' cy='64' r='64' fill='@FG' stroke='@BG' stroke-width='@SW'/><line x1='80.0035' y1='79.9964' x2='112.003' y2='111.996' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ pex +"<g transform='@TR'><path d='M64 128H0L5.59506e-06 0L64 5.59506e-06C99.3462 8.68512e-06 128 28.6538 128 64C128 99.3462 99.3462 128 64 128Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><circle cx='64' cy='64' r='32' stroke='@BG' fill='none' stroke-width='@SW'/><path fill-rule='evenodd' clip-rule='evenodd' d='M80 64C80 72.8366 72.8366 80 64 80C55.1634 80 48 72.8366 48 64C48 55.1634 55.1634 48 64 48C72.8366 48 80 55.1634 80 64ZM64 72C68.4183 72 72 68.4183 72 64C72 59.5817 68.4183 56 64 56C59.5817 56 56 59.5817 56 64C56 68.4183 59.5817 72 64 72Z' fill='@BG'/></g>", + ++ pic +"<g transform='@TR'><path d='M128 128C128 57.3076 70.6925 6.18013e-06 1.11901e-05 0L0 128L128 128Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M96 128C96 74.9807 53.0193 32 0 32' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M64 128C64 92.6538 35.3462 64 0 64' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M32 128C32 110.327 17.6731 96 0 96' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ pid +"<g transform='@TR'><path d='M0 0C0 70.6925 57.3075 128 128 128V0H0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><line x1='-0.0029152' x2='127.983' y2='127.986' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/><circle cx='16' cy='112' r='11.5' fill='@BG' stroke='@BG' stroke-width='@SW'/><circle cx='16' cy='112' r='9' fill='@FG' stroke='@FG' stroke-width='@SW'/></g>", + ++ pil +"<g transform='@TR'><path d='M64 0H128V128H64C28.6538 128 0 99.3462 0 64C0 28.6538 28.6538 0 64 0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><line x1='0.5' y1='-0.5' x2='181.5' y2='-0.5' transform='matrix(-0.707107 0.707107 0.707107 0.707107 128.71 0)' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/><circle cx='96' cy='96' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='96' cy='96' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ pin +"<g transform='@TR'><rect width='128' height='128' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M32 0L32 128' stroke='@BG' fill='none' stroke-width='@SW'/><circle cx='32' cy='32' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='32' cy='32' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ pit +"<g transform='@TR'><path d='M0.0541 0C70.7217 0.0292317 128 57.3256 128 128C57.3177 128 0.0164917 70.7089 7.62806e-06 0.0305091C7.62851e-06 0.0203397 -4.44317e-10 0.01017 0 0H0.0541Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><line x1='0.5' y1='-0.5' x2='181.5' y2='-0.5' transform='matrix(-0.707107 0.707107 0.707107 0.707107 128.71 0)' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/><circle cx='16' cy='112' r='11.5' fill='@BG' stroke='@BG' stroke-width='@SW'/><circle cx='16' cy='112' r='9' fill='@FG' stroke='@FG' stroke-width='@SW'/></g>", + ++ poc +"<g transform='@TR'><path d='M0.0541 0C70.7217 0.0292317 128 57.3256 128 128C57.3177 128 0.0164917 70.7089 7.62806e-06 0.0305091C7.62851e-06 0.0203397 -4.44317e-10 0.01017 0 0H0.0541Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><line x1='64.5' y1='-0.5' x2='64.5' y2='127.5' stroke='@BG' fill='none' stroke-width='@SW'/><line x1='96.5' y1='-0.5' x2='96.5' y2='127.5' stroke='@BG' fill='none' stroke-width='@SW'/><line x1='32.5' y1='-0.5' x2='32.5' y2='127.5' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ pod +"<g transform='@TR'><path d='M64 0H128V128H64C28.6538 128 0 99.3462 0 64C0 28.6538 28.6538 0 64 0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><line x1='128' y1='96' x2='-8.87604e-09' y2='96' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ pol +"<g transform='@TR'><circle cx='64' cy='64' r='64' fill='@FG' stroke='@BG' stroke-width='@SW'/><circle cx='64' cy='64' r='48' stroke='@BG' fill='none' stroke-width='@SW'/><line x1='128' y1='32' x2='-8.87604e-09' y2='32' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ pon +"<g transform='@TR'><path d='M128 0C57.3075 8.42999e-07 -8.42999e-07 57.3075 0 128H128V0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/></g>", + ++ pos +"<g transform='@TR'><path d='M0 0C0 70.6925 57.3075 128 128 128V0H0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><line x1='-0.0029152' x2='127.983' y2='127.986' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/><circle cx='96' cy='32' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='96' cy='32' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ pub +"<g transform='@TR'><path d='M128 128C128 57.3076 70.6925 6.18013e-06 1.11901e-05 0L0 128L128 128Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M32 0L32 128' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ pun +"<g transform='@TR'><circle cx='64' cy='64' r='64' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M112 64C112 37.4903 90.5097 16 64 16' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M96 64C96 46.3269 81.6731 32 64 32' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M80 64C80 55.1634 72.8366 48 64 48' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ pur +"<g transform='@TR'><path d='M5.59506e-06 128C70.6925 128 128 70.6925 128 0L0 5.59506e-06L5.59506e-06 128Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M-0.00292969 0L127.997 128' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/><path d='M3.73284e-05 64C17.6633 64 33.6554 56.8445 45.2356 45.2741' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ put +"<g transform='@TR'><rect width='128' height='128' fill='@FG' stroke='@BG' stroke-width='@SW'/><circle cx='32' cy='96' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='32' cy='96' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ pyl +"<g transform='@TR'><path d='M128 128C128 57.3076 70.6925 6.18013e-06 1.11901e-05 0L0 128L128 128Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M-5.59506e-06 128C35.3462 128 64 99.3462 64 64C64 28.6538 35.3462 1.54503e-06 0 0' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ pyx +"<g transform='@TR'><path d='M5.59506e-06 128C70.6925 128 128 70.6925 128 0L0 5.59506e-06L5.59506e-06 128Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M-0.00292969 0L127.997 128' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/><circle cx='96' cy='32' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='96' cy='32' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ rab +"<g transform='@TR'><path d='M128 0C57.3075 8.42999e-07 -8.42999e-07 57.3075 0 128H128V0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M-0.00292969 0L127.997 128' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/><line x1='15.9965' y1='111.997' x2='47.9964' y2='79.9965' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ rac +"<g transform='@TR'><path d='M0.0541 0C70.7217 0.0292317 128 57.3256 128 128C57.3177 128 0.0164917 70.7089 7.62806e-06 0.0305091C7.62851e-06 0.0203397 -4.44317e-10 0.01017 0 0H0.0541Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><circle cx='16' cy='112' r='11.5' fill='@BG' stroke='@BG' stroke-width='@SW'/><circle cx='16' cy='112' r='9' fill='@FG' stroke='@FG' stroke-width='@SW'/></g>", + ++ rad +"<g transform='@TR'><path d='M128 128C128 57.3076 70.6925 6.18013e-06 1.11901e-05 0L0 128L128 128Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><circle cx='32' cy='96' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='32' cy='96' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ rag +"<g transform='@TR'><path d='M64 0H128V128H64C28.6538 128 0 99.3462 0 64C0 28.6538 28.6538 0 64 0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><line x1='16.0036' y1='15.9965' x2='48.0036' y2='47.9965' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ ral +"<g transform='@TR'><path d='M0.0541 0C70.7217 0.0292317 128 57.3256 128 128C57.3177 128 0.0164917 70.7089 7.62806e-06 0.0305091C7.62851e-06 0.0203397 -4.44317e-10 0.01017 0 0H0.0541Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><circle cx='64' cy='64' r='32' stroke='@BG' fill='none' stroke-width='@SW'/><circle cx='64' cy='64' r='16' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ ram +"<g transform='@TR'><path d='M64 0H128V128H64C28.6538 128 0 99.3462 0 64C0 28.6538 28.6538 0 64 0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><line x1='64' y1='2.18557e-08' x2='64' y2='128' stroke='@BG' fill='none' stroke-width='@SW'/><path fill-rule='evenodd' clip-rule='evenodd' d='M80 64C80 72.8366 72.8366 80 64 80C55.1634 80 48 72.8366 48 64C48 55.1634 55.1634 48 64 48C72.8366 48 80 55.1634 80 64ZM64 72C68.4183 72 72 68.4183 72 64C72 59.5817 68.4183 56 64 56C59.5817 56 56 59.5817 56 64C56 68.4183 59.5817 72 64 72Z' fill='@BG'/></g>", + ++ ran +"<g transform='@TR'><path d='M64 0H128V128H64C28.6538 128 0 99.3462 0 64C0 28.6538 28.6538 0 64 0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M64 0L64 128' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M-0.00291443 0L127.997 128' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/><circle cx='64' cy='64' r='16' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ rap +"<g transform='@TR'><path d='M0 0C0 70.6925 57.3075 128 128 128V0H0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><line x1='64' y1='-1.29797e-08' x2='64' y2='128' stroke='@BG' fill='none' stroke-width='@SW'/><circle cx='96' cy='64' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='96' cy='64' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ rav +"<g transform='@TR'><path d='M0 0C0 70.6925 57.3075 128 128 128V0H0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M128 32L0 32' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ reb +"<g transform='@TR'><rect width='128' height='128' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M128 -9.40976e-06C57.3075 -6.31969e-06 -3.09007e-06 57.3075 0 128' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ rec +"<g transform='@TR'><path d='M128 128C128 57.3076 70.6925 6.18013e-06 1.11901e-05 0L0 128L128 128Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><circle cx='32' cy='96' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='32' cy='96' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/><circle cx='96' cy='96' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='96' cy='96' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ red +"<g transform='@TR'><circle cx='64' cy='64' r='64' fill='@FG' stroke='@BG' stroke-width='@SW'/><circle cx='64' cy='96' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='64' cy='96' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ ref +"<g transform='@TR'><path d='M0.0541 0C70.7217 0.0292317 128 57.3256 128 128C57.3177 128 0.0164917 70.7089 7.62806e-06 0.0305091C7.62851e-06 0.0203397 -4.44317e-10 0.01017 0 0H0.0541Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M-0.00292969 0L127.997 128' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/><circle cx='16' cy='112' r='11.5' fill='@BG' stroke='@BG' stroke-width='@SW'/><circle cx='16' cy='112' r='9' fill='@FG' stroke='@FG' stroke-width='@SW'/></g>", + ++ reg +"<g transform='@TR'><rect width='128' height='128' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M128 96C110.327 96 96 81.6731 96 64C96 46.3269 110.327 32 128 32' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ rel +"<g transform='@TR'><path d='M0 127.946C0.0292286 57.2783 57.3256 3.08928e-06 128 0C128 70.6823 70.7089 127.984 0.0305092 128C0.0203397 128 0.01017 128 2.36469e-09 128L0 127.946Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M128 64L0 64' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M128 96L0 96' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M128 32L0 32' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ rem +"<g transform='@TR'><circle cx='64' cy='64' r='64' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M-0.00292969 0L127.997 128' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/><path d='M128 64C92.6538 64 64 35.3462 64 0' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ ren +"<g transform='@TR'><rect width='128' height='128' fill='@FG' stroke='@BG' stroke-width='@SW'/><line x1='80.0035' y1='79.9965' x2='112.003' y2='111.997' stroke='@BG' fill='none' stroke-width='@SW'/><circle cx='64' cy='64' r='16' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ rep +"<g transform='@TR'><path d='M128 0C57.3075 8.42999e-07 -8.42999e-07 57.3075 0 128H128V0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M32 128C32 74.9807 74.9807 32 128 32' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ res +"<g transform='@TR'><path d='M128 0C57.3075 8.42999e-07 -8.42999e-07 57.3075 0 128H128V0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><line x1='80.0035' y1='79.9965' x2='112.003' y2='111.997' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ ret +"<g transform='@TR'><circle cx='64' cy='64' r='64' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M128 64L0 64' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ rev +"<g transform='@TR'><path d='M64 128H0L5.59506e-06 0L64 5.59506e-06C99.3462 8.68512e-06 128 28.6538 128 64C128 99.3462 99.3462 128 64 128Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><line x1='15.9965' y1='111.997' x2='53.9965' y2='73.9965' stroke='@BG' fill='none' stroke-width='@SW'/><circle cx='16' cy='112' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='16' cy='112' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/><path fill-rule='evenodd' clip-rule='evenodd' d='M80 64C80 72.8366 72.8366 80 64 80C55.1634 80 48 72.8366 48 64C48 55.1634 55.1634 48 64 48C72.8366 48 80 55.1634 80 64ZM64 72C68.4183 72 72 68.4183 72 64C72 59.5817 68.4183 56 64 56C59.5817 56 56 59.5817 56 64C56 68.4183 59.5817 72 64 72Z' fill='@BG'/></g>", + ++ rex +"<g transform='@TR'><path d='M64 128H0L5.59506e-06 0L64 5.59506e-06C99.3462 8.68512e-06 128 28.6538 128 64C128 99.3462 99.3462 128 64 128Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M128 64L0 64' stroke='@BG' fill='none' stroke-width='@SW'/><path fill-rule='evenodd' clip-rule='evenodd' d='M80 64C80 72.8366 72.8366 80 64 80C55.1634 80 48 72.8366 48 64C48 55.1634 55.1634 48 64 48C72.8366 48 80 55.1634 80 64ZM64 72C68.4183 72 72 68.4183 72 64C72 59.5817 68.4183 56 64 56C59.5817 56 56 59.5817 56 64C56 68.4183 59.5817 72 64 72Z' fill='@BG'/></g>", + ++ rib +"<g transform='@TR'><circle cx='64' cy='64' r='64' fill='@FG' stroke='@BG' stroke-width='@SW'/><line x1='8.74228e-08' y1='64' x2='128' y2='64' stroke='@BG' fill='none' stroke-width='@SW'/><line x1='64' y1='2.18557e-08' x2='64' y2='128' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ ric +"<g transform='@TR'><path d='M128 128C128 57.3076 70.6925 6.18013e-06 1.11901e-05 0L0 128L128 128Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M96 128C96 74.9807 53.0193 32 0 32' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ rid +"<g transform='@TR'><path d='M0 0C0 70.6925 57.3075 128 128 128V0H0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M64 0L64 128' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M96 0L96 128' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ rig +"<g transform='@TR'><circle cx='64' cy='64' r='64' fill='@FG' stroke='@BG' stroke-width='@SW'/><circle cx='64' cy='32' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='64' cy='32' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/><circle cx='64' cy='96' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='64' cy='96' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ ril +"<g transform='@TR'><path d='M64 0H128V128H64C28.6538 128 0 99.3462 0 64C0 28.6538 28.6538 0 64 0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><line x1='0.5' y1='-0.5' x2='181.5' y2='-0.5' transform='matrix(-0.707107 0.707107 0.707107 0.707107 128.693 0)' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/><circle cx='96' cy='32' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='96' cy='32' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ rin +"<g transform='@TR'><rect width='128' height='128' fill='@FG' stroke='@BG' stroke-width='@SW'/><line x1='64' y1='2.18557e-08' x2='64' y2='128' stroke='@BG' fill='none' stroke-width='@SW'/><line x1='32' y1='2.18557e-08' x2='32' y2='128' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ rip +"<g transform='@TR'><path d='M64 0H128V128H64C28.6538 128 0 99.3462 0 64C0 28.6538 28.6538 0 64 0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M-0.00292969 0L127.997 128' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/><path d='M96 64C96 46.3269 81.6731 32 64 32' stroke='@BG' fill='none' stroke-width='@SW'/><circle cx='96' cy='64' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='96' cy='64' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ ris +"<g transform='@TR'><path d='M128 0C57.3075 8.42999e-07 -8.42999e-07 57.3075 0 128H128V0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><line x1='-0.0029152' x2='127.983' y2='127.986' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/><path d='M128 0C128 35.3511 113.669 67.3551 90.5 90.5193' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M96 0C96 26.5077 85.2564 50.5061 67.8862 67.8783' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M64 0C64 17.6721 56.8374 33.6713 45.2568 45.2529' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M32.3716 0C32.3716 8.83603 28.7903 16.8356 23 22.6264' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ rit +"<g transform='@TR'><path d='M0.0541 0C70.7217 0.0292317 128 57.3256 128 128C57.3177 128 0.0164917 70.7089 7.62806e-06 0.0305091C7.62851e-06 0.0203397 -4.44317e-10 0.01017 0 0H0.0541Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><line x1='0.5' y1='-0.5' x2='181.5' y2='-0.5' transform='matrix(-0.707107 0.707107 0.707107 0.707107 128.71 0)' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/><path fill-rule='evenodd' clip-rule='evenodd' d='M80 64C80 72.8366 72.8366 80 64 80C55.1634 80 48 72.8366 48 64C48 55.1634 55.1634 48 64 48C72.8366 48 80 55.1634 80 64ZM64 72C68.4183 72 72 68.4183 72 64C72 59.5817 68.4183 56 64 56C59.5817 56 56 59.5817 56 64C56 68.4183 59.5817 72 64 72Z' fill='@BG'/></g>", + ++ riv +"<g transform='@TR'><rect width='128' height='128' fill='@FG' stroke='@BG' stroke-width='@SW'/><circle cx='64' cy='64' r='32' stroke='@BG' fill='none' stroke-width='@SW'/><line x1='64' y1='2.18557e-08' x2='64' y2='128' stroke='@BG' fill='none' stroke-width='@SW'/><circle cx='64' cy='64' r='48' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ roc +"<g transform='@TR'><path d='M0.0541 0C70.7217 0.0292317 128 57.3256 128 128C57.3177 128 0.0164917 70.7089 7.62806e-06 0.0305091C7.62851e-06 0.0203397 -4.44317e-10 0.01017 0 0H0.0541Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><circle cx='64' cy='64' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='64' cy='64' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/><circle cx='16' cy='112' r='11.5' fill='@BG' stroke='@BG' stroke-width='@SW'/><circle cx='16' cy='112' r='9' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='112' cy='16' r='11.5' fill='@BG' stroke='@BG' stroke-width='@SW'/><circle cx='112' cy='16' r='9' fill='@FG' stroke='@FG' stroke-width='@SW'/></g>", + ++ rol +"<g transform='@TR'><circle cx='64' cy='64' r='64' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M128 64L0 64' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M64 16C90.5097 16 112 37.4903 112 64C112 90.5097 90.5097 112 64 112' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ ron +"<g transform='@TR'><path d='M128 0C57.3075 8.42999e-07 -8.42999e-07 57.3075 0 128H128V0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M128 0C128 70.6924 70.6925 128 0 128' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ rop +"<g transform='@TR'><circle cx='64' cy='64' r='64' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M-0.00292969 0L127.997 128' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/><path d='M112 64C112 37.4903 90.5097 16 64 16' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ ros +"<g transform='@TR'><path d='M0 0C0 70.6925 57.3075 128 128 128V0H0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><line x1='0.5' y1='-0.5' x2='181.5' y2='-0.5' transform='matrix(-0.707107 0.707107 0.707107 0.707107 128.71 0)' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/><circle cx='96' cy='96' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='96' cy='96' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ rov +"<g transform='@TR'><rect width='128' height='128' fill='@FG' stroke='@BG' stroke-width='@SW'/><line x1='-0.0029152' x2='127.983' y2='127.986' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/><path d='M128 0C128 35.3511 113.669 67.3551 90.5 90.5193' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M96 0C96 26.5077 85.2564 50.5061 67.8862 67.8783' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M64 0C64 17.6721 56.8374 33.6713 45.2568 45.2529' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M32.3716 0C32.3716 8.83603 28.7903 16.8356 23 22.6264' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ ruc +"<g transform='@TR'><path d='M128 128C128 57.3076 70.6925 6.18013e-06 1.11901e-05 0L0 128L128 128Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M128 64L0 64' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M128 32L0 32' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ rud +"<g transform='@TR'><path d='M128 128C128 57.3076 70.6925 6.18013e-06 1.11901e-05 0L0 128L128 128Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M128 64L0 64' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M32 0L32 128' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M64 0L64 128' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ rul +"<g transform='@TR'><circle cx='64' cy='64' r='64' fill='@FG' stroke='@BG' stroke-width='@SW'/><line x1='80.0035' y1='79.9964' x2='112.003' y2='111.996' stroke='@BG' fill='none' stroke-width='@SW'/><path fill-rule='evenodd' clip-rule='evenodd' d='M80 64C80 72.8366 72.8366 80 64 80C55.1634 80 48 72.8366 48 64C48 55.1634 55.1634 48 64 48C72.8366 48 80 55.1634 80 64ZM64 72C68.4183 72 72 68.4183 72 64C72 59.5817 68.4183 56 64 56C59.5817 56 56 59.5817 56 64C56 68.4183 59.5817 72 64 72Z' fill='@BG'/></g>", + ++ rum +"<g transform='@TR'><path d='M5.59506e-06 128C70.6925 128 128 70.6925 128 0L0 5.59506e-06L5.59506e-06 128Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M5.08584e-07 32C17.6731 32 32 17.6731 32 0' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ run +"<g transform='@TR'><path d='M64 128H0L5.59506e-06 0L64 5.59506e-06C99.3462 8.68512e-06 128 28.6538 128 64C128 99.3462 99.3462 128 64 128Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M64 0L64 128' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M96 0L96 128' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M32 0L32 128' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ rup +"<g transform='@TR'><path d='M64 128H0L5.59506e-06 0L64 5.59506e-06C99.3462 8.68512e-06 128 28.6538 128 64C128 99.3462 99.3462 128 64 128Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M64 0L64 128' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M64 112C90.5097 112 112 90.5097 112 64C112 37.4903 90.5097 16 64 16' stroke='@BG' fill='none' stroke-width='@SW'/><circle cx='64' cy='64' r='32' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ rus +"<g transform='@TR'><path d='M128 128C128 57.3076 70.6925 6.18013e-06 1.11901e-05 0L0 128L128 128Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M128 0L0 128' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/><path d='M64 128C64 92.6538 35.3462 64 0 64' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ rut +"<g transform='@TR'><rect width='128' height='128' fill='@FG' stroke='@BG' stroke-width='@SW'/><circle cx='32' cy='32' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='32' cy='32' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ rux +"<g transform='@TR'><path d='M128 128C128 57.3076 70.6925 6.18013e-06 1.11901e-05 0L0 128L128 128Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M128 64L0 64' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M32 64C32 81.6731 46.3269 96 64 96' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ ryc +"<g transform='@TR'><path d='M128 128C128 57.3076 70.6925 6.18013e-06 1.11901e-05 0L0 128L128 128Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M128 96L0 96' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ ryd +"<g transform='@TR'><path d='M0.0541 0C70.7217 0.0292317 128 57.3256 128 128C57.3177 128 0.0164917 70.7089 7.62806e-06 0.0305091C7.62851e-06 0.0203397 -4.44317e-10 0.01017 0 0H0.0541Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M-0.00280762 0L127.997 128' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/><path d='M96 64C96 81.6731 81.6731 96 64 96' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ ryg +"<g transform='@TR'><path d='M5.59506e-06 128C70.6925 128 128 70.6925 128 0L0 5.59506e-06L5.59506e-06 128Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M-2.79795e-06 -3.55988e-06C70.6924 -4.40288e-06 128 57.3075 128 128' stroke='@BG' fill='none' stroke-width='@SW'/><line x1='16.0035' y1='15.9965' x2='48.0035' y2='47.9965' stroke='@BG' fill='none' stroke-width='@SW'/><circle cx='64' cy='64' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='64' cy='64' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ ryl +"<g transform='@TR'><path d='M0 0C0 70.6925 57.3075 128 128 128V0H0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M128 0L0 128' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/><path d='M128 128C92.6489 128 60.6449 113.669 37.4807 90.5' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M128 96C101.492 96 77.4939 85.2564 60.1217 67.8862' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M128 64C110.328 64 94.3287 56.8374 82.7471 45.2568' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M128 32.3716C119.164 32.3716 111.164 28.7903 105.374 23' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ rym +"<g transform='@TR'><path d='M5.59506e-06 128C70.6925 128 128 70.6925 128 0L0 5.59506e-06L5.59506e-06 128Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M128 96L0 96' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ ryn +"<g transform='@TR'><path d='M5.59506e-06 128C70.6925 128 128 70.6925 128 0L0 5.59506e-06L5.59506e-06 128Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M128 128C57.3075 128 -3.09007e-06 70.6925 0 0' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ ryp +"<g transform='@TR'><path d='M5.59506e-06 128C70.6925 128 128 70.6925 128 0L0 5.59506e-06L5.59506e-06 128Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M-0.00292969 0L127.997 128' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/></g>", + ++ rys +"<g transform='@TR'><path d='M128 128C128 57.3076 70.6925 6.18013e-06 1.11901e-05 0L0 128L128 128Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M1.52575e-06 96C53.0193 96 96 53.0193 96 0' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ ryt +"<g transform='@TR'><path d='M64 128H0L5.59506e-06 -7.62939e-06L64 -2.03434e-06C99.3462 1.05573e-06 128 28.6538 128 64C128 99.3462 99.3462 128 64 128Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><circle cx='64' cy='64' r='16' stroke='@BG' fill='none' stroke-width='@SW'/><circle cx='64' cy='64' r='48' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M128 0L0 128' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/></g>", + ++ ryx +"<g transform='@TR'><path d='M5.59506e-06 128C70.6925 128 128 70.6925 128 0L0 5.59506e-06L5.59506e-06 128Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><line x1='0.5' y1='-0.5' x2='181.5' y2='-0.5' transform='matrix(-0.707107 0.707107 0.707107 0.707107 128.71 0)' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/><path d='M128 0L0 128' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/><circle cx='64' cy='64' r='16' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ sab +"<g transform='@TR'><path d='M0 0C0 70.6925 57.3075 128 128 128V0H0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M-0.00292969 0L127.997 128' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/><line y1='-0.5' x2='45.2548' y2='-0.5' transform='matrix(0.707107 -0.707107 -0.707107 -0.707107 79.65 47.65)' stroke='@BG' fill='none' stroke-width='@SW'/><circle cx='16' cy='112' r='11.5' fill='@BG' stroke='@BG' stroke-width='@SW'/><circle cx='16' cy='112' r='9' fill='@FG' stroke='@FG' stroke-width='@SW'/></g>", + ++ sal +"<g transform='@TR'><path d='M0.0541 0C70.7217 0.0292317 128 57.3256 128 128C57.3177 128 0.0164917 70.7089 7.62806e-06 0.0305091C7.62851e-06 0.0203397 -4.44317e-10 0.01017 0 0H0.0541Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M0 128L128 0' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/><path d='M-0.701724 31.9914C25.6281 31.9914 49.4822 42.5913 66.8261 59.7565M-0.701723 63.9914C16.7916 63.9914 32.6456 71.0098 44.1982 82.3844M-0.701722 95.9914C7.955 95.9914 15.8089 99.4288 21.5694 105.013' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ sam +"<g transform='@TR'><path d='M64 0H128V128H64C28.6538 128 0 99.3462 0 64C0 28.6538 28.6538 0 64 0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><circle cx='64' cy='64' r='48' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M64 0L64 128' stroke='@BG' fill='none' stroke-width='@SW'/><path fill-rule='evenodd' clip-rule='evenodd' d='M80 64C80 72.8366 72.8366 80 64 80C55.1634 80 48 72.8366 48 64C48 55.1634 55.1634 48 64 48C72.8366 48 80 55.1634 80 64ZM64 72C68.4183 72 72 68.4183 72 64C72 59.5817 68.4183 56 64 56C59.5817 56 56 59.5817 56 64C56 68.4183 59.5817 72 64 72Z' fill='@BG'/></g>", + ++ san +"<g transform='@TR'><path d='M0 0C0 70.6925 57.3075 128 128 128V0H0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><line x1='-0.0029152' x2='127.983' y2='127.986' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/></g>", + ++ sap +"<g transform='@TR'><path d='M0 0C0 70.6925 57.3075 128 128 128V0H0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><line x1='128' y1='64' x2='-4.37114e-08' y2='64' stroke='@BG' fill='none' stroke-width='@SW'/><circle cx='96' cy='64' r='8' fill='@BG'/></g>", + ++ sar +"<g transform='@TR'><circle cx='64' cy='64' r='64' fill='@FG' stroke='@BG' stroke-width='@SW'/><circle cx='64' cy='64' r='48' stroke='@BG' fill='none' stroke-width='@SW'/><circle cx='64' cy='64' r='48' stroke='@BG' fill='none' stroke-width='@SW'/><line x1='64' y1='2.18557e-08' x2='64' y2='128' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ sat +"<g transform='@TR'><path d='M0 0C0 70.6925 57.3075 128 128 128V0H0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M128 128C128 57.3076 70.6925 0 0 0' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ sav +"<g transform='@TR'><path d='M64 0H128V128H64C28.6538 128 0 99.3462 0 64C0 28.6538 28.6538 0 64 0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><line x1='0.5' y1='-0.5' x2='181.5' y2='-0.5' transform='matrix(-0.707107 0.707107 0.707107 0.707107 128.71 0)' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/><path d='M96 64C96 46.3269 81.6731 32 64 32' stroke='@BG' fill='none' stroke-width='@SW'/><circle cx='64' cy='32' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='64' cy='32' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ seb +"<g transform='@TR'><rect width='128' height='128' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M128 64C92.6538 64 64 35.3462 64 0' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ sec +"<g transform='@TR'><path d='M128 128C128 57.3076 70.6925 6.18013e-06 1.11901e-05 0L0 128L128 128Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><circle cx='32' cy='32' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='32' cy='32' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ sed +"<g transform='@TR'><circle cx='64' cy='64' r='64' fill='@FG' stroke='@BG' stroke-width='@SW'/><circle cx='64' cy='64' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='64' cy='64' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/><circle cx='96' cy='64' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='96' cy='64' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ sef +"<g transform='@TR'><path d='M0.0541 0C70.7217 0.0292317 128 57.3256 128 128C57.3177 128 0.0164917 70.7089 7.62806e-06 0.0305091C7.62851e-06 0.0203397 -4.44317e-10 0.01017 0 0H0.0541Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><circle cx='64' cy='64' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='64' cy='64' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/><circle cx='16' cy='112' r='11.5' fill='@BG' stroke='@BG' stroke-width='@SW'/><circle cx='16' cy='112' r='9' fill='@FG' stroke='@FG' stroke-width='@SW'/></g>", + ++ seg +"<g transform='@TR'><rect width='128' height='128' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M32 128C32 110.327 46.3269 96 64 96C81.6731 96 96 110.327 96 128' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ sel +"<g transform='@TR'><path d='M0 127.946C0.0292286 57.2783 57.3256 3.08928e-06 128 0C128 70.6823 70.7089 127.984 0.0305092 128C0.0203397 128 0.01017 128 2.36469e-09 128L0 127.946Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><circle cx='64' cy='64' r='8' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ sem +"<g transform='@TR'><circle cx='64' cy='64' r='64' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M1.01717e-06 64C35.3462 64 64 35.3462 64 0' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M-0.00292969 0L127.997 128' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/></g>", + ++ sen +"<g transform='@TR'><rect width='128' height='128' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M64 0L64 128' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M96 128C96 110.327 81.6731 96 64 96C46.3269 96 32 110.327 32 128' stroke='@BG' fill='none' stroke-width='@SW'/><circle cx='64' cy='64' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='64' cy='64' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ sep +"<g transform='@TR'><path d='M128 0C57.3075 8.42999e-07 -8.42999e-07 57.3075 0 128H128V0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M64 128L64 0' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M32 128L32 0' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M96 128L96 0' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ ser +"<g transform='@TR'><path d='M0 64L5.59506e-06 0L128 1.11901e-05V64C128 99.3462 99.3462 128 64 128C28.6538 128 -4.6351e-06 99.3462 0 64Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M32 0L32 128' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ set +"<g transform='@TR'><circle cx='64' cy='64' r='64' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M64 64L128 64' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ sev +"<g transform='@TR'><path d='M64 128H0L5.59506e-06 0L64 5.59506e-06C99.3462 8.68512e-06 128 28.6538 128 64C128 99.3462 99.3462 128 64 128Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><circle cx='64' cy='64' r='48' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ sib +"<g transform='@TR'><circle cx='64' cy='64' r='64' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M128 0L0 128' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/><path d='M64 9.40976e-06C64 35.3462 92.6538 64 128 64' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ sic +"<g transform='@TR'><path d='M0 0C0 70.6925 57.3075 128 128 128V0H0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M128 0L0 128' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/></g>", + ++ sid +"<g transform='@TR'><path d='M0 0C0 70.6925 57.3075 128 128 128V0H0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M128 64L0 64' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M128 128C110.327 128 96 113.673 96 96C96 78.3269 110.327 64 128 64' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ sig +"<g transform='@TR'><circle cx='64' cy='64' r='64' fill='@FG' stroke='@BG' stroke-width='@SW'/><circle cx='32' cy='64' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='32' cy='64' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/><circle cx='96' cy='64' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='96' cy='64' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ sil +"<g transform='@TR'><path d='M64 0H128V128H64C28.6538 128 0 99.3462 0 64C0 28.6538 28.6538 0 64 0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><line x1='16.0036' y1='15.9965' x2='48.0036' y2='47.9965' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M128 0L0 128' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/></g>", + ++ sim +"<g transform='@TR'><path d='M128 64V128H0L2.79753e-06 64C4.34256e-06 28.6538 28.6538 -1.54503e-06 64 0C99.3462 1.54503e-06 128 28.6538 128 64Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M64 0L64 128' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M32 0L32 128' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ sip +"<g transform='@TR'><rect width='128' height='128' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M64 0L64 128' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M16 64C16 37.4903 37.4903 16 64 16' stroke='@BG' fill='none' stroke-width='@SW'/><circle cx='16' cy='64' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='16' cy='64' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ sit +"<g transform='@TR'><path d='M0.0541 0C70.7217 0.0292317 128 57.3256 128 128C57.3177 128 0.0164917 70.7089 7.62806e-06 0.0305091C7.62851e-06 0.0203397 -4.44317e-10 0.01017 0 0H0.0541Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path fill-rule='evenodd' clip-rule='evenodd' d='M80 64C80 72.8366 72.8366 80 64 80C55.1634 80 48 72.8366 48 64C48 55.1634 55.1634 48 64 48C72.8366 48 80 55.1634 80 64ZM64 72C68.4183 72 72 68.4183 72 64C72 59.5817 68.4183 56 64 56C59.5817 56 56 59.5817 56 64C56 68.4183 59.5817 72 64 72Z' fill='@BG'/></g>", + ++ siv +"<g transform='@TR'><rect width='128' height='128' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M64 0L64 128' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M128 96L0 96' stroke='@BG' fill='none' stroke-width='@SW'/><circle cx='64' cy='64' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='64' cy='64' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ soc +"<g transform='@TR'><path d='M0 127.946C0.0292286 57.2783 57.3256 3.08928e-06 128 0C128 70.6823 70.7089 127.984 0.0305092 128C0.0203397 128 0.01017 128 2.36469e-09 128L0 127.946Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><line x1='64' y1='2.18557e-08' x2='64' y2='128' stroke='@BG' fill='none' stroke-width='@SW'/><circle cx='64' cy='64' r='16' stroke='@BG' fill='none' stroke-width='@SW'/><circle cx='16' cy='16' r='11.5' fill='@BG' stroke='@BG' stroke-width='@SW'/><circle cx='16' cy='16' r='9' fill='@FG' stroke='@FG' stroke-width='@SW'/></g>", + ++ sog +"<g transform='@TR'><path d='M128 0C57.3075 8.42999e-07 -8.42999e-07 57.3075 0 128H128V0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M128 0L0 128' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/><path d='M64 96C81.6731 96 96 81.6731 96 64C96 46.3269 81.6731 32 64 32' stroke='@BG' fill='none' stroke-width='@SW'/><circle cx='64' cy='64' r='16' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ sol +"<g transform='@TR'><circle cx='64' cy='64' r='64' fill='@FG' stroke='@BG' stroke-width='@SW'/><circle cx='64' cy='64' r='32' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M128 64L-5.96046e-08 64' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ som +"<g transform='@TR'><rect width='128' height='128' fill='@FG' stroke='@BG' stroke-width='@SW'/><circle cx='96' cy='96' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='96' cy='96' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/><circle cx='32' cy='96' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='32' cy='96' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/><circle cx='32' cy='32' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='32' cy='32' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ son +"<g transform='@TR'><path d='M128 0C57.3075 8.42999e-07 -8.42999e-07 57.3075 0 128H128V0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><line x1='127.553' y1='128.224' x2='63.5528' y2='0.223598' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ sop +"<g transform='@TR'><circle cx='64' cy='64' r='64' fill='@FG' stroke='@BG' stroke-width='@SW'/><circle cx='64' cy='64' r='32' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M-0.00292969 0L127.997 128' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/><circle cx='64' cy='32' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='64' cy='32' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ sor +"<g transform='@TR'><path d='M64 0H128V128H64C28.6538 128 0 99.3462 0 64C0 28.6538 28.6538 0 64 0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M-0.00292969 0L127.997 128' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/><path d='M128 0C128 35.3511 113.669 67.3551 90.5 90.5193' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M96 0C96 26.5077 85.2564 50.5061 67.8862 67.8783' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M64 0C64 17.6721 56.8374 33.6713 45.2568 45.2529' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M32.3716 0C32.3716 8.83603 28.7903 16.8356 23 22.6264' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ sov +"<g transform='@TR'><rect width='128' height='128' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M0 128L128 0' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/><path d='M128 128C92.6489 128 60.6449 113.669 37.4807 90.5' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M128 96C101.492 96 77.4939 85.2564 60.1217 67.8862' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M128 64C110.328 64 94.3287 56.8374 82.7471 45.2568' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M128 32.3716C119.164 32.3716 111.164 28.7903 105.374 23' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ sub +"<g transform='@TR'><path d='M128 128C128 57.3076 70.6925 6.18013e-06 1.11901e-05 0L0 128L128 128Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M64 0L64 128' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ sud +"<g transform='@TR'><path d='M128 128C128 57.3076 70.6925 6.18013e-06 1.11901e-05 0L0 128L128 128Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><line x1='128' y1='64' x2='-8.87604e-09' y2='64' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M128 64L0 64' stroke='@BG' fill='none' stroke-width='@SW'/><path fill-rule='evenodd' clip-rule='evenodd' d='M80 64C80 72.8366 72.8366 80 64 80C55.1634 80 48 72.8366 48 64C48 55.1634 55.1634 48 64 48C72.8366 48 80 55.1634 80 64ZM64 72C68.4183 72 72 68.4183 72 64C72 59.5817 68.4183 56 64 56C59.5817 56 56 59.5817 56 64C56 68.4183 59.5817 72 64 72Z' fill='@BG'/></g>", + ++ sug +"<g transform='@TR'><path d='M64 128H0L5.59506e-06 0L64 5.59506e-06C99.3462 8.68512e-06 128 28.6538 128 64C128 99.3462 99.3462 128 64 128Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><circle cx='16' cy='64' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='16' cy='64' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/><circle cx='80' cy='64' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='80' cy='64' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ sul +"<g transform='@TR'><circle cx='64' cy='64' r='64' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M64 96C46.3269 96 32 81.6731 32 64C32 46.3269 46.3269 32 64 32' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ sum +"<g transform='@TR'><path d='M5.59506e-06 128C70.6925 128 128 70.6925 128 0L0 5.59506e-06L5.59506e-06 128Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M1.01717e-06 64C35.3462 64 64 35.3462 64 0' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ sun +"<g transform='@TR'><circle cx='64' cy='64' r='64' stroke='@BG' stroke-width='@SW' fill='@FG'/><circle cx='80' cy='80' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='80' cy='80' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/><circle cx='80' cy='48' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='80' cy='48' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/><circle cx='48' cy='48' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='48' cy='48' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/><circle cx='48' cy='80' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='48' cy='80' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ sup +"<g transform='@TR'><path d='M64 128H0L5.59506e-06 0L64 5.59506e-06C99.3462 8.68512e-06 128 28.6538 128 64C128 99.3462 99.3462 128 64 128Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M64 112C90.5097 112 112 90.5097 112 64C112 37.4903 90.5097 16 64 16' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M128 64L0 64' stroke='@BG' fill='none' stroke-width='@SW'/><circle cx='64' cy='64' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='64' cy='64' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ sur +"<g transform='@TR'><path d='M128 128C128 57.3076 70.6925 6.18013e-06 1.11901e-05 0L0 128L128 128Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M-0.00292969 0L127.997 128' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/><path d='M3.73284e-05 64.0001C17.6633 64.0001 33.6554 56.8446 45.2356 45.2742' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M0.000105172 128C35.3582 128 67.3679 113.664 90.5332 90.4863' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ sut +"<g transform='@TR'><rect width='128' height='128' fill='@FG' stroke='@BG' stroke-width='@SW'/><circle cx='32' cy='32' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='32' cy='32' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/><circle cx='96' cy='96' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='96' cy='96' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ syd +"<g transform='@TR'><path d='M0.0541 0C70.7217 0.0292317 128 57.3256 128 128C57.3177 128 0.0164917 70.7089 7.62806e-06 0.0305091C7.62851e-06 0.0203397 -4.44317e-10 0.01017 0 0H0.0541Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M64 16C37.4903 16 16 37.4903 16 64' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M-0.00292969 0L127.997 128' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/></g>", + ++ syl +"<g transform='@TR'><path d='M5.59506e-06 128C70.6925 128 128 70.6925 128 0L0 5.59506e-06L5.59506e-06 128Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M-0.00292969 0L127.997 128' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/><circle cx='32' cy='96' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='32' cy='96' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/><circle cx='96' cy='32' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='96' cy='32' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ sym +"<g transform='@TR'><path d='M5.59506e-06 128C70.6925 128 128 70.6925 128 0L0 5.59506e-06L5.59506e-06 128Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><line x1='96.5' y1='3.07317e-08' x2='96.5' y2='128' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ syn +"<g transform='@TR'><path d='M5.59506e-06 128C70.6925 128 128 70.6925 128 0L0 5.59506e-06L5.59506e-06 128Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M0 0C35.3511 0 67.3551 14.3309 90.5193 37.5' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M0 32C26.5077 32 50.5061 42.7436 67.8783 60.1138' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M0 64C17.6721 64 33.6713 71.1626 45.2529 82.7432' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M0 95.6284C8.83603 95.6284 16.8356 99.2097 22.6264 105' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ syp +"<g transform='@TR'><path d='M5.59506e-06 128C70.6925 128 128 70.6925 128 0L0 5.59506e-06L5.59506e-06 128Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M-0.00280762 0L127.997 128' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/><path d='M1.01717e-06 64C35.3462 64 64 35.3462 64 0' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ syr +"<g transform='@TR'><path d='M0 127.946C0.0292286 57.2783 57.3256 3.08928e-06 128 0C128 70.6823 70.7089 127.984 0.0305092 128C0.0203397 128 0.01017 128 2.36469e-09 128L0 127.946Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M-0.00292969 0L127.997 128' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/><circle cx='96' cy='32' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='96' cy='32' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ syt +"<g transform='@TR'><path d='M64 128H0L5.59506e-06 0L64 5.59506e-06C99.3462 8.68512e-06 128 28.6538 128 64C128 99.3462 99.3462 128 64 128Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><circle cx='64' cy='64' r='32' stroke='@BG' fill='none' stroke-width='@SW'/><circle cx='64' cy='64' r='48' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M128 0L0 128' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/></g>", + ++ syx +"<g transform='@TR'><path d='M5.59506e-06 128C70.6925 128 128 70.6925 128 0L0 5.59506e-06L5.59506e-06 128Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M0 128C4.63574e-06 92.6488 14.3309 60.6449 37.5 37.4807' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M32 128C32 101.492 42.7436 77.4939 60.1138 60.1216' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M64 128C64 110.328 71.1626 94.3287 82.7432 82.7471' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M95.6284 128C95.6284 119.164 99.2097 111.164 105 105.374' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M-0.00280762 0L127.997 128' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/></g>", + ++ tab +"<g transform='@TR'><path d='M0 0C0 70.6925 57.3075 128 128 128V0H0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><circle cx='64' cy='64' r='8' stroke='@BG' fill='none' stroke-width='@SW'/><line x1='-0.0029152' x2='127.983' y2='127.986' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/><circle cx='16' cy='112' r='11.5' fill='@BG' stroke='@BG' stroke-width='@SW'/><circle cx='16' cy='112' r='9' fill='@FG' stroke='@FG' stroke-width='@SW'/></g>", + ++ tac +"<g transform='@TR'><path d='M0 0C0 70.6925 57.3075 128 128 128V0H0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M128 0L0 128' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/><circle cx='64' cy='32' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='64' cy='32' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/><circle cx='96' cy='64' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='96' cy='64' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ tad +"<g transform='@TR'><path d='M0 0C0 70.6925 57.3075 128 128 128V0H0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><circle cx='32' cy='32' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='32' cy='32' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/><circle cx='96' cy='96' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='96' cy='96' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ tag +"<g transform='@TR'><path d='M64 0H128V128H64C28.6538 128 0 99.3462 0 64C0 28.6538 28.6538 0 64 0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><line x1='80.0036' y1='79.9964' x2='112.004' y2='111.996' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ tal +"<g transform='@TR'><path d='M0.0541 0C70.7217 0.0292317 128 57.3256 128 128C57.3177 128 0.0164917 70.7089 7.62806e-06 0.0305091C7.62851e-06 0.0203397 -4.44317e-10 0.01017 0 0H0.0541Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><line x1='0.5' y1='-0.5' x2='181.5' y2='-0.5' transform='matrix(-0.707107 0.707107 0.707107 0.707107 128.71 0)' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/><path d='M96 128C96 74.9807 53.0193 32 0 32' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ tam +"<g transform='@TR'><path d='M64 0H128V128H64C28.6538 128 0 99.3462 0 64C0 28.6538 28.6538 0 64 0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><line x1='128' y1='96' x2='-8.87604e-09' y2='96' stroke='@BG' fill='none' stroke-width='@SW'/><line x1='128' y1='32' x2='-8.87604e-09' y2='32' stroke='@BG' fill='none' stroke-width='@SW'/><circle cx='64' cy='64' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='64' cy='64' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ tan +"<g transform='@TR'><path d='M0 0C0 70.6925 57.3075 128 128 128V0H0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M96 128C96 74.9807 53.0193 32 0 32' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M64 128C64 92.6538 35.3462 64 0 64' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M48 128C48 101.49 26.5097 80 0 80' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M32 128C32 110.327 17.6731 96 0 96' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M16 128C16 119.163 8.83656 112 0 112' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M128 128C128 57.3075 70.6925 0 0 0' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ tap +"<g transform='@TR'><circle cx='64' cy='64' r='64' fill='@FG' stroke='@BG' stroke-width='@SW'/><circle cx='64' cy='64' r='48' stroke='@BG' fill='none' stroke-width='@SW'/><line x1='128' y1='64' x2='-8.87604e-09' y2='64' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M64 32C81.6731 32 96 46.3269 96 64C96 81.6731 81.6731 96 64 96' stroke='@BG' fill='none' stroke-width='@SW'/><circle cx='64' cy='64' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='64' cy='64' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ tar +"<g transform='@TR'><circle cx='64' cy='64' r='64' fill='@FG' stroke='@BG' stroke-width='@SW'/><circle cx='64' cy='64' r='48' stroke='@BG' fill='none' stroke-width='@SW'/><circle cx='16' cy='64' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='16' cy='64' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ tas +"<g transform='@TR'><rect width='128' height='128' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M64 0L64 128' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M64 32C81.6731 32 96 46.3269 96 64C96 81.6731 81.6731 96 64 96' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ teb +"<g transform='@TR'><rect width='128' height='128' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M1.52575e-06 96C53.0193 96 96 53.0193 96 0' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ tec +"<g transform='@TR'><path d='M128 128C128 57.3076 70.6925 6.18013e-06 1.11901e-05 0L0 128L128 128Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><line x1='80.0035' y1='79.9965' x2='112.003' y2='111.997' stroke='@BG' fill='none' stroke-width='@SW'/><path fill-rule='evenodd' clip-rule='evenodd' d='M80 64C80 72.8366 72.8366 80 64 80C55.1634 80 48 72.8366 48 64C48 55.1634 55.1634 48 64 48C72.8366 48 80 55.1634 80 64ZM64 72C68.4183 72 72 68.4183 72 64C72 59.5817 68.4183 56 64 56C59.5817 56 56 59.5817 56 64C56 68.4183 59.5817 72 64 72Z' fill='@BG'/></g>", + ++ ted +"<g transform='@TR'><circle cx='64' cy='64' r='64' fill='@FG' stroke='@BG' stroke-width='@SW'/><circle cx='32' cy='96' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='32' cy='96' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ teg +"<g transform='@TR'><rect width='128' height='128' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M128 80C119.163 80 112 72.8366 112 64C112 55.1634 119.163 48 128 48' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ tel +"<g transform='@TR'><path d='M0 127.946C0.0292286 57.2783 57.3256 3.08928e-06 128 0C128 70.6823 70.7089 127.984 0.0305092 128C0.0203397 128 0.01017 128 2.36469e-09 128L0 127.946Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><circle cx='15' cy='112' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='15' cy='112' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/><path d='M0 0L127.986 127.986' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/><path d='M32 0L128 96' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/><path d='M64 0L128 64' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/><path d='M96 0L128 32' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/></g>", + ++ tem +"<g transform='@TR'><circle cx='64' cy='64' r='64' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M128 64C92.6538 64 64 92.6538 64 128' stroke='@BG' fill='none' stroke-width='@SW'/><line x1='-0.00285417' x2='127.983' y2='127.986' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/></g>", + ++ ten +"<g transform='@TR'><rect width='128' height='128' fill='@FG' stroke='@BG' stroke-width='@SW'/><circle cx='48' cy='48' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='48' cy='48' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/><circle cx='80' cy='48' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='80' cy='48' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/><circle cx='80' cy='80' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='80' cy='80' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/><circle cx='48' cy='80' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='48' cy='80' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ tep +"<g transform='@TR'><path d='M128 0C57.3075 8.42999e-07 -8.42999e-07 57.3075 0 128H128V0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M1.14479e-06 96C53.0193 96 96 53.0193 96 0' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ ter +"<g transform='@TR'><path d='M0 64L5.59506e-06 0L128 1.11901e-05V64C128 99.3462 99.3462 128 64 128C28.6538 128 -4.6351e-06 99.3462 0 64Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><line x1='96.5' y1='3.07317e-08' x2='96.5' y2='128' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M1.01717e-06 64C35.3462 64 64 35.3462 64 0' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ tes +"<g transform='@TR'><path d='M128 0C57.3075 8.42999e-07 -8.42999e-07 57.3075 0 128H128V0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M64 0L64 128' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M128 64L0 64' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ tev +"<g transform='@TR'><path d='M64 128H0L5.59506e-06 0L64 5.59506e-06C99.3462 8.68512e-06 128 28.6538 128 64C128 99.3462 99.3462 128 64 128Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><circle cx='64' cy='64' r='32' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ tex +"<g transform='@TR'><path d='M64 128H0L5.59506e-06 0L64 5.59506e-06C99.3462 8.68512e-06 128 28.6538 128 64C128 99.3462 99.3462 128 64 128Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><line x1='15.9965' y1='111.997' x2='47.9965' y2='79.9965' stroke='@BG' fill='none' stroke-width='@SW'/><path fill-rule='evenodd' clip-rule='evenodd' d='M80 64C80 72.8366 72.8366 80 64 80C55.1634 80 48 72.8366 48 64C48 55.1634 55.1634 48 64 48C72.8366 48 80 55.1634 80 64ZM64 72C68.4183 72 72 68.4183 72 64C72 59.5817 68.4183 56 64 56C59.5817 56 56 59.5817 56 64C56 68.4183 59.5817 72 64 72Z' fill='@BG'/></g>", + ++ tic +"<g transform='@TR'><path d='M0 0C0 70.6925 57.3075 128 128 128V0H0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M128 32C110.327 32 96 17.6731 96 -1.39876e-06' stroke='@BG' fill='none' stroke-width='@SW'/><circle cx='64' cy='64' r='32' stroke='@BG' fill='none' stroke-width='@SW'/><circle cx='64' cy='64' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='64' cy='64' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ tid +"<g transform='@TR'><path d='M0 0C0 70.6925 57.3075 128 128 128V0H0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><line x1='64' y1='2.18557e-08' x2='64' y2='128' stroke='@BG' fill='none' stroke-width='@SW'/><line x1='96' y1='2.18557e-08' x2='96' y2='128' stroke='@BG' fill='none' stroke-width='@SW'/><path fill-rule='evenodd' clip-rule='evenodd' d='M112 32C112 40.8366 104.837 48 96 48C87.1634 48 80 40.8366 80 32C80 23.1634 87.1634 16 96 16C104.837 16 112 23.1634 112 32ZM96 40C100.418 40 104 36.4183 104 32C104 27.5817 100.418 24 96 24C91.5817 24 88 27.5817 88 32C88 36.4183 91.5817 40 96 40Z' fill='@BG'/></g>", + ++ til +"<g transform='@TR'><path d='M64 0H128V128H64C28.6538 128 0 99.3462 0 64C0 28.6538 28.6538 0 64 0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><line x1='80.0036' y1='79.9965' x2='112.004' y2='111.997' stroke='@BG' fill='none' stroke-width='@SW'/><circle cx='64' cy='64' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='64' cy='64' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ tim +"<g transform='@TR'><path d='M128 64V128H0L2.79753e-06 64C4.34256e-06 28.6538 28.6538 -1.54503e-06 64 0C99.3462 1.54503e-06 128 28.6538 128 64Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M-0.00291443 0L127.997 128' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/></g>", + ++ tin +"<g transform='@TR'><rect width='128' height='128' fill='@FG' stroke='@BG' stroke-width='@SW'/><line x1='32' y1='2.18557e-08' x2='32' y2='128' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ tip +"<g transform='@TR'><path d='M128 0C57.3075 8.42999e-07 -8.42999e-07 57.3075 0 128H128V0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M64 0L64 128' stroke='@BG' fill='none' stroke-width='@SW'/><path fill-rule='evenodd' clip-rule='evenodd' d='M80 64C80 72.8366 72.8366 80 64 80C55.1634 80 48 72.8366 48 64C48 55.1634 55.1634 48 64 48C72.8366 48 80 55.1634 80 64ZM64 72C68.4183 72 72 68.4183 72 64C72 59.5817 68.4183 56 64 56C59.5817 56 56 59.5817 56 64C56 68.4183 59.5817 72 64 72Z' fill='@BG'/></g>", + ++ tir +"<g transform='@TR'><path d='M0 0C0 70.6925 57.3075 128 128 128V0H0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><line x1='-0.0029152' x2='127.983' y2='127.986' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/><circle cx='64' cy='64' r='16' stroke='@BG' fill='none' stroke-width='@SW'/><circle cx='64' cy='64' r='32' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ tob +"<g transform='@TR'><path d='M128 64V128H0L2.79753e-06 64C4.34256e-06 28.6538 28.6538 -1.54503e-06 64 0C99.3462 1.54503e-06 128 28.6538 128 64Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M128 96L0 96' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ toc +"<g transform='@TR'><path d='M0.0541 0C70.7217 0.0292317 128 57.3256 128 128C57.3177 128 0.0164917 70.7089 7.62806e-06 0.0305091C7.62851e-06 0.0203397 -4.44317e-10 0.01017 0 0H0.0541Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><line x1='128' y1='96' x2='-8.87604e-09' y2='96' stroke='@BG' fill='none' stroke-width='@SW'/><circle cx='64' cy='64' r='16' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ tod +"<g transform='@TR'><path d='M64 0H128V128H64C28.6538 128 0 99.3462 0 64C0 28.6538 28.6538 0 64 0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><circle cx='64' cy='96' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='64' cy='96' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/><circle cx='64' cy='32' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='64' cy='32' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ tog +"<g transform='@TR'><path d='M128 0C57.3075 8.42999e-07 -8.42999e-07 57.3075 0 128H128V0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M64 96C46.3269 96 32 81.6731 32 64' stroke='@BG' fill='none' stroke-width='@SW'/><circle cx='64' cy='64' r='16' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M128 0L0 128' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/></g>", + ++ tol +"<g transform='@TR'><circle cx='64' cy='64' r='64' fill='@FG' stroke='@BG' stroke-width='@SW'/><line x1='128' y1='64' x2='-4.37114e-08' y2='64' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M16 128C16 101.49 37.4903 80 64 80C90.5097 80 112 101.49 112 128' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ tom +"<g transform='@TR'><rect width='128' height='128' fill='@FG' stroke='@BG' stroke-width='@SW'/><circle cx='32' cy='32' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='32' cy='32' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/><circle cx='96' cy='32' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='96' cy='32' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/><circle cx='32' cy='96' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='32' cy='96' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ ton +"<g transform='@TR'><path d='M128 0C57.3075 8.42999e-07 -8.42999e-07 57.3075 0 128H128V0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M128 32C74.9807 32 32 74.9807 32 128' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M128 64C92.6538 64 64 92.6538 64 128' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M128 96C110.327 96 96 110.327 96 128' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ top +"<g transform='@TR'><circle cx='64' cy='64' r='64' fill='@FG' stroke='@BG' stroke-width='@SW'/><line x1='-0.0029152' x2='127.983' y2='127.986' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/><circle cx='64' cy='64' r='32' stroke='@BG' fill='none' stroke-width='@SW'/><circle cx='64' cy='64' r='16' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ tor +"<g transform='@TR'><path d='M64 0H128V128H64C28.6538 128 0 99.3462 0 64C0 28.6538 28.6538 0 64 0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><circle cx='64' cy='64' r='32' stroke='@BG' fill='none' stroke-width='@SW'/><circle cx='64' cy='64' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='64' cy='64' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ tuc +"<g transform='@TR'><path d='M128 128C128 57.3076 70.6925 6.18013e-06 1.11901e-05 0L0 128L128 128Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M128 64L0 64' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M128 96L0 96' stroke='@BG' fill='none' stroke-width='@SW'/><circle cx='96' cy='96' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='96' cy='96' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/><circle cx='32' cy='64' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='32' cy='64' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ tud +"<g transform='@TR'><path d='M128 128C128 57.3076 70.6925 6.18013e-06 1.11901e-05 0L0 128L128 128Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M128 64L0 64' stroke='@BG' fill='none' stroke-width='@SW'/><circle cx='32' cy='64' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='32' cy='64' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ tug +"<g transform='@TR'><path d='M64 128H0L5.59506e-06 0L64 5.59506e-06C99.3462 8.68512e-06 128 28.6538 128 64C128 99.3462 99.3462 128 64 128Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M128 64L0 64' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M128 32L0 32' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ tul +"<g transform='@TR'><circle cx='64' cy='64' r='64' fill='@FG' stroke='@BG' stroke-width='@SW'/><path fill-rule='evenodd' clip-rule='evenodd' d='M80 64C80 72.8366 72.8366 80 64 80C55.1634 80 48 72.8366 48 64C48 55.1634 55.1634 48 64 48C72.8366 48 80 55.1634 80 64ZM64 72C68.4183 72 72 68.4183 72 64C72 59.5817 68.4183 56 64 56C59.5817 56 56 59.5817 56 64C56 68.4183 59.5817 72 64 72Z' fill='@BG'/></g>", + ++ tun +"<g transform='@TR'><path d='M128 64V128H0L2.79753e-06 64C4.34256e-06 28.6538 28.6538 -1.54503e-06 64 0C99.3462 1.54503e-06 128 28.6538 128 64Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M-0.00292969 0L127.997 128' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/><circle cx='64' cy='64' r='48' stroke='@BG' fill='none' stroke-width='@SW'/><circle cx='64' cy='64' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='64' cy='64' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ tus +"<g transform='@TR'><path d='M128 128C128 57.3076 70.6925 6.18013e-06 1.11901e-05 0L0 128L128 128Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M128 0L0 128' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/><circle cx='32' cy='32' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='32' cy='32' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ tux +"<g transform='@TR'><path d='M128 128C128 57.3076 70.6925 6.18013e-06 1.11901e-05 0L0 128L128 128Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M128 64L0 64' stroke='@BG' fill='none' stroke-width='@SW'/><circle cx='64' cy='96' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='64' cy='96' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ tyc +"<g transform='@TR'><path d='M128 128C128 57.3076 70.6925 6.18013e-06 1.11901e-05 0L0 128L128 128Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path fill-rule='evenodd' clip-rule='evenodd' d='M80 64C80 72.8366 72.8366 80 64 80C55.1634 80 48 72.8366 48 64C48 55.1634 55.1634 48 64 48C72.8366 48 80 55.1634 80 64ZM64 72C68.4183 72 72 68.4183 72 64C72 59.5817 68.4183 56 64 56C59.5817 56 56 59.5817 56 64C56 68.4183 59.5817 72 64 72Z' fill='@BG'/></g>", + ++ tyd +"<g transform='@TR'><path d='M0.0541 0C70.7217 0.0292317 128 57.3256 128 128C57.3177 128 0.0164917 70.7089 7.62806e-06 0.0305091C7.62851e-06 0.0203397 -4.44317e-10 0.01017 0 0H0.0541Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M-0.00280762 0L127.997 128' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/><line y1='-0.5' x2='45.2548' y2='-0.5' transform='matrix(0.707107 -0.707107 -0.707107 -0.707107 79.65 47.6499)' stroke='@BG' fill='none' stroke-width='@SW'/><line x1='15.9964' y1='111.997' x2='47.9964' y2='79.9965' stroke='@BG' fill='none' stroke-width='@SW'/><circle cx='64' cy='64' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='64' cy='64' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ tyl +"<g transform='@TR'><path d='M128 128C128 57.3076 70.6925 6.18013e-06 1.11901e-05 0L0 128L128 128Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M7.37542e-06 -3.56072e-06C1.19529e-06 70.6924 57.3075 128 128 128' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ tyn +"<g transform='@TR'><path d='M5.59506e-06 128C70.6925 128 128 70.6925 128 0L0 5.59506e-06L5.59506e-06 128Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M128 -2.28831e-06C57.3076 -3.13131e-06 8.42999e-07 57.3075 0 128' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ typ +"<g transform='@TR'><path d='M5.59506e-06 128C70.6925 128 128 70.6925 128 0L0 5.59506e-06L5.59506e-06 128Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M-0.00292969 0L127.997 128' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/><path d='M96 1.90735e-06C96 53.0193 53.0193 96 0 96' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ tyr +"<g transform='@TR'><path d='M0 127.946C0.0292286 57.2783 57.3256 3.08928e-06 128 0C128 70.6823 70.7089 127.984 0.0305092 128C0.0203397 128 0.01017 128 2.36469e-09 128L0 127.946Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M0 0L128 128' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/><path d='M128 64C92.6538 64 64 35.3462 64 0' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M0 64C35.3462 64 64 92.6538 64 128' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ tyv +"<g transform='@TR'><path d='M0 127.946C0.0292286 57.2783 57.3256 3.08928e-06 128 0C128 70.6823 70.7089 127.984 0.0305092 128C0.0203397 128 0.01017 128 2.36469e-09 128L0 127.946Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M256 0L128 128' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/><circle cx='64' cy='64' r='32' stroke='@BG' fill='none' stroke-width='@SW'/><circle cx='96' cy='32' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='96' cy='32' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/><circle cx='32' cy='96' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='32' cy='96' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ wac +"<g transform='@TR'><path d='M0 0C0 70.6925 57.3075 128 128 128V0H0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M128 64L0 64' stroke='@BG' fill='none' stroke-width='@SW'/><circle cx='64' cy='64' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='64' cy='64' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/><circle cx='16' cy='112' r='11.5' fill='@BG' stroke='@BG' stroke-width='@SW'/><circle cx='16' cy='112' r='9' fill='@FG' stroke='@FG' stroke-width='@SW'/></g>", + ++ wal +"<g transform='@TR'><path d='M0 127.946C0.0292286 57.2783 57.3256 3.08928e-06 128 0C128 70.6823 70.7089 127.984 0.0305092 128C0.0203397 128 0.01017 128 2.36469e-09 128L0 127.946Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><line x1='64.5' y1='-0.5' x2='64.5' y2='127.5' stroke='@BG' fill='none' stroke-width='@SW'/><line x1='32' y1='2.18557e-08' x2='32' y2='128' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ wan +"<g transform='@TR'><path d='M0 0C0 70.6925 57.3075 128 128 128V0H0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M0 0C0 70.6925 57.3075 128 128 128V0H0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/></g>", + ++ wat +"<g transform='@TR'><path d='M0 0C0 70.6925 57.3075 128 128 128V0H0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path fill-rule='evenodd' clip-rule='evenodd' d='M80 64C80 72.8366 72.8366 80 64 80C55.1634 80 48 72.8366 48 64C48 55.1634 55.1634 48 64 48C72.8366 48 80 55.1634 80 64ZM64 72C68.4183 72 72 68.4183 72 64C72 59.5817 68.4183 56 64 56C59.5817 56 56 59.5817 56 64C56 68.4183 59.5817 72 64 72Z' fill='@BG'/></g>", + ++ web +"<g transform='@TR'><rect width='128' height='128' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M128 128C128 57.3075 70.6925 0 0 0' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ wed +"<g transform='@TR'><circle cx='64' cy='64' r='64' fill='@FG' stroke='@BG' stroke-width='@SW'/><circle cx='32' cy='32' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='32' cy='32' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ weg +"<g transform='@TR'><rect width='128' height='128' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M79.5254 0C79.5254 8.83656 72.3619 16 63.5254 16C54.6888 16 47.5254 8.83656 47.5254 0' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ wel +"<g transform='@TR'><path d='M0 127.946C0.0292286 57.2783 57.3256 3.08928e-06 128 0C128 70.6823 70.7089 127.984 0.0305092 128C0.0203397 128 0.01017 128 2.36469e-09 128L0 127.946Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M128 32C74.9807 32 32 74.9807 32 128' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M128 64C92.6538 64 64 92.6538 64 128' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M128 96C110.327 96 96 110.327 96 128' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ wen +"<g transform='@TR'><rect width='128' height='128' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M1.01717e-06 64C35.3462 64 64 35.3462 64 0' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M-0.00292969 0L127.997 128' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/></g>", + ++ wep +"<g transform='@TR'><path d='M128 0C57.3075 8.42999e-07 -8.42999e-07 57.3075 0 128H128V0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><circle cx='96' cy='96' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='96' cy='96' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ wer +"<g transform='@TR'><path d='M0 64L5.59506e-06 0L128 1.11901e-05V64C128 99.3462 99.3462 128 64 128C28.6538 128 -4.6351e-06 99.3462 0 64Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M32 0L32 128' stroke='@BG' fill='none' stroke-width='@SW'/><circle cx='32' cy='32' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='32' cy='32' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ wes +"<g transform='@TR'><path d='M128 0C57.3075 8.42999e-07 -8.42999e-07 57.3075 0 128H128V0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><line x1='80.0035' y1='79.9965' x2='112.003' y2='111.997' stroke='@BG' fill='none' stroke-width='@SW'/><circle cx='112' cy='112' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='112' cy='112' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ wet +"<g transform='@TR'><circle cx='64' cy='64' r='64' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M64 64H0' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ wex +"<g transform='@TR'><path d='M64 128H0L5.59506e-06 0L64 5.59506e-06C99.3462 8.68512e-06 128 28.6538 128 64C128 99.3462 99.3462 128 64 128Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path fill-rule='evenodd' clip-rule='evenodd' d='M80 64C80 72.8366 72.8366 80 64 80C55.1634 80 48 72.8366 48 64C48 55.1634 55.1634 48 64 48C72.8366 48 80 55.1634 80 64ZM64 72C68.4183 72 72 68.4183 72 64C72 59.5817 68.4183 56 64 56C59.5817 56 56 59.5817 56 64C56 68.4183 59.5817 72 64 72Z' fill='@BG'/></g>", + ++ wic +"<g transform='@TR'><path d='M128 0C57.3075 8.42999e-07 -8.42999e-07 57.3075 0 128H128V0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><circle cx='96' cy='32' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='96' cy='32' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/><circle cx='32' cy='96' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='32' cy='96' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ wid +"<g transform='@TR'><path d='M0 0C0 70.6925 57.3075 128 128 128V0H0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><line x1='48.0035' y1='80.0036' x2='16.0035' y2='112.004' stroke='@BG' fill='none' stroke-width='@SW'/><path fill-rule='evenodd' clip-rule='evenodd' d='M80 64C80 72.8366 72.8366 80 64 80C55.1634 80 48 72.8366 48 64C48 55.1634 55.1634 48 64 48C72.8366 48 80 55.1634 80 64ZM64 72C68.4183 72 72 68.4183 72 64C72 59.5817 68.4183 56 64 56C59.5817 56 56 59.5817 56 64C56 68.4183 59.5817 72 64 72Z' fill='@BG'/></g>", + ++ win +"<g transform='@TR'><rect width='128' height='128' fill='@FG' stroke='@BG' stroke-width='@SW'/><line x1='64' y1='2.18557e-08' x2='64' y2='128' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ wis +"<g transform='@TR'><path d='M0 0C0 70.6925 57.3075 128 128 128V0H0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M128 64L0 64' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M128 32L0 32' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ wit +"<g transform='@TR'><path d='M0 127.946C0.0292286 57.2783 57.3256 3.08928e-06 128 0C128 70.6823 70.7089 127.984 0.0305092 128C0.0203397 128 0.01017 128 2.36469e-09 128L0 127.946Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><line x1='64' y1='2.18557e-08' x2='64' y2='128' stroke='@BG' fill='none' stroke-width='@SW'/><line x1='32' y1='2.18557e-08' x2='32' y2='128' stroke='@BG' fill='none' stroke-width='@SW'/><line x1='96' y1='2.18557e-08' x2='96' y2='128' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ wol +"<g transform='@TR'><circle cx='64' cy='64' r='64' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M0 64L128 64' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M128 96C110.327 96 96 81.6731 96 64C96 46.3269 110.327 32 128 32' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ wor +"<g transform='@TR'><path d='M64 0H128V128H64C28.6538 128 0 99.3462 0 64C0 28.6538 28.6538 0 64 0Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><line y1='-0.5' x2='45.2548' y2='-0.5' transform='matrix(0.707107 -0.707107 -0.707107 -0.707107 79.65 47.65)' stroke='@BG' fill='none' stroke-width='@SW'/><line x1='-0.0029152' x2='127.983' y2='127.986' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/><path d='M64 96C46.3269 96 32 81.6731 32 64' stroke='@BG' fill='none' stroke-width='@SW'/><circle cx='64' cy='64' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='64' cy='64' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ wyc +"<g transform='@TR'><path d='M128 128C128 57.3076 70.6925 6.18013e-06 1.11901e-05 0L0 128L128 128Z' fill='@FG' stroke='@BG' stroke-width='@SW'/></g>", + ++ wyd +"<g transform='@TR'><path d='M0.0541 0C70.7217 0.0292317 128 57.3256 128 128C57.3177 128 0.0164917 70.7089 7.62806e-06 0.0305091C7.62851e-06 0.0203397 -4.44317e-10 0.01017 0 0H0.0541Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M-0.00292969 0L127.997 128' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/><path d='M32 64C32 46.3269 46.3269 32 64 32' stroke='@BG' fill='none' stroke-width='@SW'/><circle cx='32' cy='64' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='32' cy='64' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ wyl +"<g transform='@TR'><path d='M128 128C128 57.3076 70.6925 6.18013e-06 1.11901e-05 0L0 128L128 128Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M-3.8147e-06 128C-7.24633e-07 92.6538 28.6538 64 64 64C99.3462 64 128 92.6538 128 128' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ wyn +"<g transform='@TR'><path d='M5.59506e-06 128C70.6925 128 128 70.6925 128 0L0 5.59506e-06L5.59506e-06 128Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M1.52575e-06 96C53.0193 96 96 53.0193 96 0' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M1.01717e-06 64C35.3462 64 64 35.3462 64 0' stroke='@BG' fill='none' stroke-width='@SW'/><path d='M5.08584e-07 32C17.6731 32 32 17.6731 32 0' stroke='@BG' fill='none' stroke-width='@SW'/></g>", + ++ wyt +"<g transform='@TR'><path d='M64 128H0L5.59506e-06 0L64 5.59506e-06C99.3462 8.68512e-06 128 28.6538 128 64C128 99.3462 99.3462 128 64 128Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M128 0L0 128' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/><circle cx='64' cy='64' r='48' stroke='@BG' fill='none' stroke-width='@SW'/><circle cx='16' cy='64' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='16' cy='64' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ wyx +"<g transform='@TR'><path d='M5.59506e-06 128C70.6925 128 128 70.6925 128 0L0 5.59506e-06L5.59506e-06 128Z' fill='@FG' stroke='@BG' stroke-width='@SW'/><path d='M-0.00292969 0L127.997 128' stroke='@BG' stroke-linecap='square' fill='none' stroke-width='@SW'/><circle cx='32' cy='96' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='32' cy='96' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/><circle cx='32' cy='32' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='32' cy='32' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/><circle cx='96' cy='32' r='11.5' fill='@FG' stroke='@FG' stroke-width='@SW'/><circle cx='96' cy='32' r='9' fill='@BG' stroke='@BG' stroke-width='@SW'/></g>", + ++ zod +"<g transform='@TR'><circle cx='64' cy='64' r='64' fill='@FG' stroke='@BG' stroke-width='@SW'/></g>", +-- diff --git a/desk/lib/openai.hoon b/desk/lib/openai.hoon new file mode 100644 index 0000000..4d42bd8 --- /dev/null +++ b/desk/lib/openai.hoon @@ -0,0 +1,763 @@ +/- cookies +/+ server, sr=sortug +:: |_ key=@t +|% +++ key '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' +.^(scry:cookies ()) +:: follows open AI reference docs as of 07-OCT-2023 +++ api-key (crip "Bearer {(trip key)}") +++ base-url "https://api.openai.com/v1" +:: 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 ++$ ljson $%([%s @t] [%n @t]) +:: Passes each member of list a to gate b, which must produce a unit. Produces a new list with all the results that do not produce ~. +++ clean +|* [key=@tas j=?(%s %n) d=(unit)] +?~ d ~ +`[key j u.d] + +:: ++ audio +:: |% +:: ++ endpoint "/audio" +:: +$ response-format $?(%json %text %srt %verbose-json %vtt) +:: ++ transcription +:: |% +:: ++ endpoint "/transcriptions" +:: +$ req +:: $: file=file +:: model=@t :: 'whisper-1' +:: language=(unit @t) +:: prompt=(unit @t) +:: response-format=(unit response-format) +:: temperature=(unit @rd) :: 0-1 + +:: == +:: ++ ret %todo +:: -- +:: ++ translation +:: |% +:: ++ endpoint "/audio/translation" +:: +$ req +:: $: file=file +:: model=@t :: 'whisper-1' +:: prompt=(unit @t) +:: response-format=(unit response-format) +:: temperature=(unit @rd) :: 0-1 +:: == +:: -- +:: -- +++ test +|= text=@t +(chat [~[[%system text 'Pepe']] 'gpt-3.5-turbo']) +++ chat +|^ request:completions + ++ endpoint "/chat" + ++ completions + |% + ++ t + |% + +$ role $?(%system %user %assistant %function) + +$ function-call + $: name=@t + arguments=@t + == + +$ function + $: description=(unit @t) + name=@t + parameters=object:json-schema:sortug + == + +$ logit-bias (map @t @ud) + +$ stop $@(@t (list @t)) :: up to 4 sequences + +$ message + $: =role + content=$?(@t ~) :: not optional, but can be null + name=@t + == + +$ request + $: messages=(list message) + model=@tas + :: frequency-penalty=(unit @ud) :: -2.0 to 2.0 + :: function-call=(unit function-call) + :: functions=(list function) + :: logit-bias=(unit logit-bias) + :: max-tokens=(unit @ud) + :: n=(unit @ud) + :: presence-penalty=(unit @ud) + :: stop=(unit stop) + :: stream=(unit ?) :: SSE, nice + :: temperature=(unit @ud) + :: top-p=(unit @ud) + :: user=(unit @t) + == + +$ full-response + $: id=@t + choices=(list choice) + created=@da + model=@t + object=@t :: 'chat.completion.chunk' + =usage + == + +$ usage + $: completion-tokens=@ud + prompt-tokens=@ud + total-tokens=@ud + == + +$ chunk-response + $: id=@t + choices=(list choice) + created=@da + model=@t + object=@t :: 'chat.completion.chunk' + == + +$ choice + $: index=@ud + =delta + =finish-reason + == + +$ finish-reason $?(%stop %length %content-filter %function-call ~) + +$ chunk-choice + $: index=@ud + =delta + =finish-reason + == + +$ delta + $: content=$?(@t ~) + =role + function-call=(unit function-call) + == + ++ dejs + =, dejs:format + =/ de de:json-helpers:sortug + |% + ++ full + |= jon=@t ^- full-response + %. (need (de:json:html jon)) + %- ot + :~ id+so + choices+(ar de-choice) + created+du + model+so + object+so + usage+de-usage + == + ++ de-choice + %- ot + :~ index+ni + message+de-delta + ['finish_reason' de-finish-reason] + == + ++ de-usage + %- ot + :~ ['completion_tokens' ni] + ['prompt_tokens' ni] + ['total_tokens' ni] + == + + ++ chunk + |= jon=@t ^- chunk-response + %. (need (de:json:html jon)) + %- ot + :~ id+so + choices+(ar de-chunk-choice) + created+du + model+so + object+so + == + ++ de-chunk-choice + %- ot + :~ index+ni + delta+de-delta + ['finish-reason' de-finish-reason] + == + ++ de-role %- su %- perk + :~(%system %user %assistant %function) + ++ de-finish-reason %- maybe:de %- su %- perk + :~(%stop %length %content-filter %function-call) + ++ de-delta + %- ou + :~ + content+(un (maybe:de so)) + role+(un de-role) + ['function-call' (ur:de de-function-call)] + == + ++ de-function-call + %- ot + :~ name+so + arguments+so + == + -- + ++ enjs + =, enjs:format + |_ req=request + ++ $ + %- pairs + :~ messages+a+(turn messages.req en-msg) + model+s+model.req + == + ++ en-msg + |= msg=message + %- pairs + :~ role+s+role.msg + :- %content ?~ content.msg ~ s+content.msg + == + -- + -- + ++ endpoint "/completions" + ++ request + |= req=request:t + ^- request:http + =/ method %'POST' + =/ url %- crip "{base-url}{^endpoint}{endpoint}" + =/ headers + :~ + ['Authorization' api-key] + ['Content-type' 'application/json'] + == + =/ json (enjs:t req) + ~& > req=req + ~& >> sending=(en:json:html json) + =/ body (json-to-octs:server (enjs:t req)) + [method url headers `body] + + -- +-- +:: ++ embeddings +:: |% +:: ++ endpoint "/embeddings" +:: ++ req %'POST' +:: +$ input +:: $@ @t (list @t) +:: +$ req-type +:: $: =input +:: model=@tas +:: user=(unit @t) +:: == +:: +$ res +:: $: object=@t +:: data=(list embed) +:: model=@tas +:: usage=[prompt-tokens=@ud total-tokens=@ud] +:: == +:: +$ embed +:: $: index=@ud +:: embedding=(list @rd) :: TODO make this strings? +:: object=@t :: 'embedding' +:: == +:: ++ res-dejson +:: =, dejs:format +:: %- ot +:: :~ object+so +:: model+so +:: usage+usage-dejson +:: data+(ar embed-dejson) +:: == +:: ++ usage-dejson +:: =, dejs:format +:: %- ot +:: :~ ['prompt_tokens' ni] +:: ['total_tokens' ni] +:: == +:: ++ embed-dejson +:: %- ot +:: :~ object+so +:: index+ni +:: embedding+(ar ne) :: TODO make this strings?? +:: == +:: -- +:: ++ fine-tuning +:: |% +:: ++ endpoint "/fine_tuning/jobs +:: +$ job +:: $: id=@t +:: created-at=@ud +:: error=(unit error) +:: fine-tuned-model=(unit @t) +:: finished-at=(unit @ud) +:: =hyperparameters +:: model=@tas +:: organization-id=@t +:: result-files=(list @t) +:: =status +:: trained-tokens=(unit @ud) +:: training-file=@t +:: validation-file=(unit @t) +:: == +:: +$ job-event +:: $: id=@t +:: created-at=@ +:: level=@t :: 'warn', 'info', ... +:: message=@t +:: data=(unit job) :: I think +:: type=@t :: 'message' +:: == +:: ++ job-dejson +:: =, dejs:format +:: %- ot +:: :~ id+so +:: fine-tuned-model+uso +:: finished-at+uso +:: hyperparameters+hdj +:: model=(se %tas) +:: 'organization_id'+so +:: 'result_files'+(ar so) +:: status+(se %tas) +:: 'trained_tokens'+uso +:: 'training_file'+so +:: 'validation_file'+uso +:: == +:: ++ job-event-dejson +:: %- ot +:: :~ id+so +:: level+so +:: message+so +:: data+job-dejson +:: == +:: ++ uso +:: |= j=json +:: ?~ j ~ +:: ?: ?=(-.j %s) (so j) +:: ?: ?=(-.j %n) (ni j) ~ +:: ++ hdj +:: %- ot +:: :~ :- 'n_epochs' +:: |= j=json +:: ?: ?=(-.j %s) %auto +:: ?: ?=(-.j %n) (ni j) +:: == +:: +$ events-res +:: $: data=(list job-event) +:: has-more=? +:: == +:: ++ events-res-dejson +:: =, dejs:format +:: %- ot +:: :~ data+(ar job-event-djson) +:: has-more+bo +:: == +:: +$ status $?(%validating-files %queued %running %succeeded %failed %cancelled) +:: +$ hyperparameters [%n-epochs $?(%auto @ud)] +:: ++ create +:: |% +:: ++ endpoint "" +:: ++ req %POST +:: +$ req-type +:: $: model=@tas +:: training-file=@t +:: hyperparameters=(unit hyperparameters) +:: validation-file=(unit @t) +:: suffix=(unit @t) +:: == +:: -- +:: ++ get-all +:: |_ [after=(unit @t) limit=(unit @ud)] +:: ++ endpoint +:: ?~ after +:: ?~ limit +:: :: none +:: "" +:: :: limit but not after +:: "?limit={<u.limit>}" +:: ?~ limit +:: :: after but not limit +:: "?after={(trip u.after)}" +:: :: both +:: "?limit={<u.limit>}&after={(trip u.after)}" +:: ++ req %GET +:: ++ res events-res +:: ++ dejs events-res-dejson + +:: -- +:: ++ get +:: |_ id=@t +:: ++ endpoint "/{(trip id)}" +:: ++ req %GET +:: ++ res job +:: ++ res-dejson job-dejson +:: -- +:: ++ cancel +:: |_ id=@t +:: ++ endpoint "/{(trip id)}/cancel" +:: ++ req %POST +:: ++ res job +:: ++ res-dejson job-dejson +:: -- +:: ++ get-events +:: |_ [id=@t after=(unit @t) limit=(unit @ud)] +:: :: TODO There must be a better way to handle optional query params +:: ++ endpoint "/{(trip id)}/events" +:: ++ req %GET +:: ++ res events-res +:: ++ dejs events-res-dejson +:: -- +:: -- +:: ++ files +:: |% +:: ++ endpoint "/files" +:: +$ file-type +:: $: id=@t +:: bytes=@ud +:: created-at=@ud +:: filename=@t +:: purpose=@t :: 'currently only fine-tune' +:: =status +:: status-details=(unit @t) +:: == +:: ++ dejs +:: =, dejs:format +:: %- ot +:: :~ id+so +:: bytes+ni +:: ['created_at' ni] +:: filename+so +:: purpose+so +:: == +:: +$ status $?(%uploaded %processed %pending %error %deleting %deleted) +:: ++ get-all +:: |% +:: ++ endpoint "" +:: ++ req %GET +:: +$ res (list file-type) +:: ++ dejs +:: %- ot +:: :~ data+(ar ^dejs) +:: == +:: -- +:: ++ upload +:: |_ [file=@t purpose=@t] :: file is the actual file, not the name +:: ++ endpoint "" +:: ++ req %POST :: mulipart wtf +:: +$ res file-type +:: ++ dejs ^dejs +:: -- +:: ++ delete +:: |_ file-id=@t +:: ++ endpoint "/{file-id}" +:: ++ req %DELETE +:: +$ res +:: $: id=@t +:: deleted=? +:: == +:: ++ dejs +:: =, dejs:format +:: %- ot +:: :~ it+so +:: deleted+bo +:: == +:: -- +:: ++ get +:: |_ file-id=@t +:: ++ endpoint "/{file-id}" +:: ++ req %GET +:: +$ res file-type +:: ++ dejs ^dejs +:: -- +:: ++ content +:: |_ file-id=@t +:: ++ endpoint "/{file-id}/content" +:: ++ req %GET +:: +$ res "" :: the file content +:: -- +:: -- +++ images +|% + ++ endpoint "/images" + ++ t + |% + +$ image + $% [%'b64_json' @t] + [%url @t] + == + +$ response-format $?(%url %b64-json) + +$ size $?(%'256x256' %'512x512' %'1024x1024') + +$ res + $: created=@ud + data=(list image) + == + ++ dejs + =, dejs:format + |_ jon=@t + ++ $ ^- res + %. (need (de:json:html jon)) + %- ot + :~ created+ni + data+(ar de-data) + == + ++ de-data + %- of + :~ [%'b64_json' so] + [%url so] + == + -- + -- + ++ create + |^ request + ++ t + |% + +$ req + $: prompt=@t + n=(unit @ud) + response-format=(unit response-format:^t) + size=(unit size:^t) + user=(unit @t) + == + ++ enjs + =, enjs:format + |_ =req + ++ $ + %- pairs + :- prompt+s+prompt.req + :: %- murn :_ clean + :: :~ n+n+n.req + :: ['response_format' %s response-format.req] + :: size+s+size.req + :: user+s+user.req + :: == + ~ + -- + -- + ++ endpoint "/generations" + ++ request |= =req:t + ^- request:http + =/ method %'POST' + =/ url %- crip "{base-url}{^endpoint}{endpoint}" + =/ headers + :~ + ['Authorization' api-key] + ['Content-type' 'application/json'] + == + =/ body (json-to-octs:server (enjs:t req)) + [method url headers `body] + -- + :: ++ edit + :: :: TODO guess image is alread octs once it gets here so we just send tha + :: :: images must be png, <4mb, square + :: |^ request + :: ++ t + :: |% + :: ++ req + :: $: image=@t + :: prompt=@t + :: mask=(unit @t) + :: n=(unit @ud) + :: size=(unit size) + :: response-format=(unit response-format:t) + :: user=(unit @t) + :: == + :: -- + :: ++ endpoint "/edits" + :: ++ request :: multipart + :: ^- request:http + :: =/ method %'POST' + :: =/ url %- crip "{base-url}{^endpoint}{endpoint}" + :: =/ headers + :: :~ + :: ['Authorization' api-key] + :: == + :: =/ body ~ :: can we even do multipart + :: [method url headers ~] + :: -- + :: ++ variation + :: |_ [image=@t n=(unit @ud) size=(unit size) response-format=(unit response-format) user=(unit @t)] + :: ++ endpoint "/variations" + :: ++ request :: multipart + :: ^- request:http + :: =/ method %'POST' + :: =/ url %- crip "{base-url}{^endpoint}{endpoint}" + :: =/ headers + :: :~ + :: ['Authorization' api-key] + :: == + :: =/ body ~ :: can we even do multipart + :: [method url headers ~] + :: -- +-- +:: ++ models +:: |% +:: ++ endpoint "/models" +:: ++ request +:: ^- request:http +:: =/ method %'GET' +:: =/ url %- crip "{base-url}{endpoint}" +:: =/ headers +:: :~ +:: ['Authorization' api-key] +:: == +:: [method url headers ~] +:: +$ res (list model-res) +:: +$ model-res +:: $: id=@t +:: created=@ :: unix ts +:: object=@t :: always 'model' +:: owned-by=@t :: 'openai etc.' +:: == +:: ++ res-dejson +:: =, dejs:format +:: %- ot +:: :~ object+so +:: data+(ar model-res-dejson) +:: == +:: ++ model-res-dejson +:: =, dejs:format +:: %- ot +:: :~ id+so +:: created+ni +:: object+so +:: owned-by+so +:: == +:: ++ model +:: |_ name=@t +:: ++ endpoint "/{name}" +:: ++ request +:: ^- request:http +:: =/ method %'GET' +:: =/ url %- crip "{base-url}{^endpoint}{endpoint}" +:: =/ headers +:: :~ +:: ['Authorization' api-key] +:: == +:: [method url headers ~] +:: -- +:: ++ delete-model +:: |_ name=@t +:: ++ endpoint "{name}" +:: ++ request +:: ^- request:http +:: =/ method %'DELETE' +:: =/ url %- crip "{base-url}{^endpoint}{endpoint}" +:: =/ headers +:: :~ +:: ['Authorization' api-key] +:: == +:: [method url headers ~] +:: +$ res +:: $: id=@t +:: object=@t :: 'model' +:: deleted=? +:: == +:: ++ res-dejson +:: =, dejs:format +:: %- ot +:: :~ id+so +:: object+so +:: deleted+bo +:: == +:: -- +:: -- +:: ++ moderation +:: |% +:: ++ endpoints "/moderations" +:: +$ moderation-t +:: $: id=@t +:: model=@t +:: results=(list result) +:: == +:: +$ result +:: $: flagged=? +:: =categories +:: =category-scores +:: == +:: +$ categories +:: $: sexual=? +:: hate=? +:: harassment=? +:: self-harm=? +:: sexual-minors=? +:: hate-threatening=? +:: violence-graphic=? +:: self-harm-intent=? +:: self-harm-instructions=? +:: harassment-threatening=? +:: violence=? +:: == +:: +$ category-scores +:: $: sexual=@rd +:: hate=@rd +:: harassment=@rd +:: self-harm=@rd +:: sexual-minors=@rd +:: hate-threatening=@rd +:: violence-graphic=@rd +:: self-harm-intent=@rd +:: self-harm-instructions=@rd +:: harassment-threatening=@rd +:: violence=@rd +:: == +:: ++ dejs +:: =, dejs:format +:: %- ot +:: :~ id+so +:: model+(se %tas) +:: results+(ar de-result) +:: == +:: ++ de-result +:: =, dejs:format +:: %- ot +:: :~ flagged+bo +:: categories+de-categories +:: ['category_scores' de-category-scores] +:: == +:: ++ de-categories +:: =, dejs:format +:: %- ot +:: :~ sexual+bo +:: hate+bo +:: harassment+bo +:: self-harm+bo +:: 'sexual/minors'+bo +:: 'hate/threatening'+bo +:: 'violence/graphic'+bo +:: 'self-harm/intent'+bo +:: 'self-harm/instructions'+bo +:: 'harassment/threatening'+bo +:: violence+bo +:: == +:: ++ de-category-scores +:: =, dejs:format +:: %- ot +:: :~ sexual+ne +:: hate+ne +:: harassment+ne +:: self-harm+ne +:: 'sexual/minors'+ne +:: 'hate/threatening'+ne +:: 'violence/graphic'+ne +:: 'self-harm/intent'+ne +:: 'self-harm/instructions'+ne +:: 'harassment/threatening'+ne +:: violence+ne +:: == +:: ++ create +:: |_ =req +:: ++ endpoint "" +:: ++ request +:: ^- request:http +:: =/ method %'POST' +:: =/ url %- crip "{base-url}{^endpoint}{endpoint}" +:: =/ headers +:: :~ +:: ['content-type' 'application/json'] +:: ['Authorization' api-key] +:: == +:: =/ body (json-to-octs:server (enjs req)) +:: [method url headers `body] +:: +$ input $@ @t (list @t) +:: +$ model $?(%text-moderation-stable %text-moderation-latest) +:: +$ req +:: $: =input +:: model=(unit model) +:: == +:: ++ enjs +:: =, enjs:format +:: %- pairs +:: :~ input+s+(en-input input.req) +:: == +:: ++ en-input +:: =, enjs:format +:: ?^ input.req a+(turn input |=(s=@t s+s)) +:: s+input +:: +$ res moderation-t +:: ++ dejs ^dejs +:: -- +:: -- + +-- + diff --git a/desk/lib/p.hoon b/desk/lib/p.hoon new file mode 100644 index 0000000..8806410 --- /dev/null +++ b/desk/lib/p.hoon @@ -0,0 +1,65 @@ +|% +++ dinfix |* [pf=rule sf=rule] +=/ neither (star ;~(less ;~(pose pf sf) next)) +;~(pfix pf ;~(sfix neither sf)) +++ infix +|* =rule +(ifix [rule rule] (star ;~(less rule next))) ++$ block +$% [%p p=paragraph] + [%blockquote p=paragraph] + [%list p=(list paragraph) ordered=?] + [%tasklist p=(list task)] + [%heading p=paragraph h=?(%h1 %h2 %h3 %h4 %h5 %h6)] + [%table rows=(list (list paragraph))] + [%codeblock code=@t lang=@t] +== ++$ paragraph (list inline) ++$ task [text=paragraph done=?] ++$ inline +$% [%b p=paragraph] + [%i p=paragraph] + [%del p=paragraph] :: strikethrough + [%a href=@t text=@t] + [%img src=@t alt=@t] + [%codespan p=@t] + [%footnote id=@t text=paragraph] + [%br ~] + [%text p=@t] +== +++ brk (just '\0a') +:: ++ words (cook (crip zing (star word))) :: indefinite tarp +++ tics ;~(plug tic tic tic brk) +++ white (plus ace) :: whitespace +++ bq ;~(pfix ;~(plug gar ace) (plus inli)) +++ blok + ;~ pose + (stag %blockquote bq) + (stag %p (plus inli)) + == +++ inli + ;~ pose + :: *bold* + (stag %b (infix tar)) + (cold [%br ~] brk) + (stag %text (star next)) + :: _italic_ + :: (stag %i (ifix cab)) + :: :: `code` + :: (stag %codespan (ifix tic)) + :: :: [li](nk) + :: %+ stag %link + :: ;~ plug + :: (dinfix [sel ser]) + :: (dinfix [pal par]) + :: == + :: ::  + :: %+ stag %mage + :: ;~ pfix zap + :: ;~ plug + :: (dinfix [sel ser]) + :: (dinfix [pal par]) + :: == + :: == + == +--
\ No newline at end of file diff --git a/desk/lib/post.hoon b/desk/lib/post.hoon new file mode 100644 index 0000000..a0816da --- /dev/null +++ b/desk/lib/post.hoon @@ -0,0 +1,236 @@ +/- post=trill-post +|% +++ node-to-full +|= [p=post:post f=feed:post] ^- full-node:post +p(children (convert-children children.p f)) +++ convert-children +|= [children=(set id:post) f=feed:post] +^- full-graph:post +%- ~(rep in children) + |= [=id:post acc=full-graph:post] + =/ n (get:orm:post f id) + ?~ n acc + =/ full-node (node-to-full u.n f) + (put:form:post acc id full-node) +++ sanitize +|= c=contents:contents-1:post ^- ? +%+ roll c |= [i=block:contents-1:post acc=_&] +?. ?=(%paragraph -.i) acc +%+ roll p.i |= [ii=inline:contents-1:post iacc=_acc] +?. ?=(%link -.ii) iacc +?~ (de-purl:html href.ii) .n .y +++ block-size +|= =block:contents-1:post +?- -.block +%tasklist 0 :: TODO +%paragraph (inline-size p.block) +%blockquote (inline-size p.block) +%heading (lent (trip p.block)) +%list (inline-size p.block) +%media (media-size media.block) +%codeblock +?: (gth (lent (trip lang.block)) 400) 10.000 +(lent (trip code.block)) +%eval (lent (trip hoon.block)) +%ref +?: (gth (lent (trip app.block)) 400) 10.000 +(roll path.block |=([i=@t a=@] (add a (lent (trip i))))) +%json +?: (gth (lent (trip content.block)) 5.000) 10.000 +?: (gth (lent (trip origin.block)) 1.000) 10.000 +0 +%table +%+ roll rows.block |= [i=(list contents:contents-1:post) a=@] +=/ inner-count=@ +%+ roll i |= [ii=contents:contents-1:post ia=@] +(add ia (post-size ii)) +(add inner-count a) +== +++ post-size +|= c=contents:contents-1:post +=| count=@ +|- +?~ c count +=/ lc=@ (block-size i.c) +$(c t.c, count (add count lc)) +++ inline-token-size +|= i=inline:contents-1:post ^- @ud +?+ -.i (lent (trip p.i)) +%break 1 +%date 1 +%note (add (met 3 id.i) 10):: TODO) +%ship (lent (trip (scot %p p.i))) +%ruby (lent (trip p.i)) +%link +?: (gth (lent (trip href.i)) 400) 10.000 :: to prevent hacking through a huge href string +(lent (trip show.i)) +== +++ reduce-inline +|= [i=inline:contents-1:post chars=@ud] ^+ i +?- -.i +%break i +%date i +%note i :: TODO +%ship [%text (crip (weld (scag chars (trip (scot %ud p.i))) "..."))] +%ruby i(p (crip (scag chars (trip p.i)))) +%link i(show (crip (scag chars (trip show.i)))) +%bold + [-.i (crip (scag chars (trip +.i)))] +%codespan + [-.i (crip (scag chars (trip +.i)))] +%italic + [-.i (crip (scag chars (trip +.i)))] +%strike + [-.i (crip (scag chars (trip +.i)))] +%sub + [-.i (crip (scag chars (trip +.i)))] +%sup + [-.i (crip (scag chars (trip +.i)))] +%text + [-.i (crip (weld (scag chars (trip +.i)) "..."))] +%underline + [-.i (crip (scag chars (trip +.i)))] +== +++ inline-size +|= l=(list inline:contents-1:post) ^- @ +=| count=@ud +|- + ?~ l count + =/ lc=@ud (inline-token-size i.l) + $(l t.l, count (add count lc)) + + +++ media-size +|= =media:contents-1:post ^- @ +?- -.media +%video (lent (trip p.media)) +%audio (lent (trip p.media)) +%images %+ roll p.media +|= [[url=@t caption=@t] a=@] +%+ add a (add (met 3 url) (met 3 caption)) +== + +++ search +|= [q=@t p=post:post] ^- ? +=/ latest=content-list:post val:head:(pop:corm:post contents.p) +=/ in-tags %+ roll ~(tap in tags.p) |= [i=cord a=_|] +?: (contains i q) %& a +=/ in-blocks %+ roll latest |= [i=block:contents-1:post a=_|] +?: ?- -.i + %paragraph (in-inline p.i q) + %blockquote (in-inline p.i q) + %list (in-inline p.i q) + %heading (contains p.i q) + %codeblock (contains code.i q) + %eval (contains hoon.i q) + %json (contains content.i q) + %media (in-media media.i q) + %ref %| :: TODO + %table %| :: TODO + %tasklist .n :: TODO +== %& a +?| in-tags in-blocks == +++ contains +|= [container=cord query=cord] ^- ? +?~ (find (trip query) (trip container)) %| %& +++ in-media +|= [=media:contents-1:post q=@t] ^- ? +?. ?=(%images -.media) (contains p.media q) +%+ roll p.media |= [[url=cord caption=cord] a=_|] +?: ?| (contains url q) (contains caption q) == .y a +++ in-inline +|= [l=(list inline:contents-1:post) q=@t] ^- ? +%+ roll l |= [i=inline:contents-1:post a=_|] +?: ?+ -.i (contains p.i q) +%break %| +%ship (contains (scot %p p.i) q) +%date .n :: TODO +%note ?|((contains id.i q) (in-inline text.i q)) +%link ?|((contains href.i q) (contains show.i q)) +%ruby ?|((contains p.i q) (contains q.i q)) +== %& a +++ is-my-reply +|= [p=post:post r=post:post our=@p] ^- ? +?~ parent.r .n +?& .=(author.r our) !.=(author.p our) == +++ is-thread-child +|= [p=post:post r=post:post our=@p] ^- ? +?~ parent.r .n +?& .=(author.r our) .=(author.p our) == +++ houyi +|= fn=full-node:post ^- @ud +?~ children.fn 0 +=/ lst (tap:form:post children.fn) +%+ add (lent lst) +%+ roll lst +|= [[=id:post n=full-node:post] acc=@ud] +(add acc (houyi n)) + +:: +++ abbreviate-post +|= [cm=content-map:post max-chars=@ud] ^- content-list:post + =/ c (latest-contents cm) + :: we reduce the list of blocks. We count how many characters are there in each block. + :: If the block fits in our count, we insert the block in the filtered list. + :: If not, we cut the content of the box until it does. + =/ ret=content-list:post + =< +< + %^ spin c [bl=*content-list:post available=max-chars] + |= [b=block:contents-1:post [bl=_c available=@ud]] + :: We must return the same data type as the input + :: We don't want to map on the individual block so return as is + :- b + :: The state tho is what we're playing with. + :: We pass the current block and the available char count to another function + =/ cut=[(unit block:contents-1:post) @ud] (cut-block b available) + :: That function checks whether the block fits within the available count. + :: It returns a maybe block and the remaining count + :: If null, we return the list as is + ?~ -.cut [bl available] + :: If we get a block back, we add that to our block list, and update the available count + [[u.-.cut bl] +.cut] + (flop ret) +++ cut-block +:: now let's go inside the block +|= [b=block:contents-1:post available=@ud] +^- [(unit block:contents-1:post) @ud] +?+ -.b [~ 0] +:: :: This we can cut +%paragraph =/ inlines (cut-inlines p.b available) +?~ -.inlines [~ available] :- `[-.b -.inlines] +.inlines +:: :: these must go whole or nothing +:: :: %blockquote +:: :: %heading +:: :: %list +:: :: %media +:: :: %eval +:: :: %poll +:: :: %ref +:: :: %json +:: :: %table +== +++ cut-inlines +|= [li=(list inline:contents-1:post) available=@ud] ^+ [li available] +?: .=(0 available) [~ 0] +:: We spin again +=/ ret=[_li @ud] +=/ initial-state [*(list inline:contents-1:post) available] +=< + +%^ spin li initial-state +|= [l=inline:contents-1:post [nl=_li available=@ud]] +:: Again we're not mapping over the tokens, just mutating an internal state +:- l +:: If no more chars available we return of course +?: .=(0 available) [nl available] +:: We look at the size of the current token +=/ size (inline-token-size l) +:: If the size is smaller than available, we add to new list, and substract from available +?: (lte size available) +[[l nl] (sub available size)] +:: If size is bigger than available we reduce the token, insert to list, set avaibable as 0 +=/ reduced (reduce-inline l available) +[[reduced nl] 0] + +[(flop -.ret) +.ret] + +-- diff --git a/desk/lib/rails.hoon b/desk/lib/rails.hoon new file mode 100644 index 0000000..8db842e --- /dev/null +++ b/desk/lib/rails.hoon @@ -0,0 +1,7 @@ +|% ++$ response +$% [%page hed=header-list:http bod=manx] :: html page with headers + [%full p=simple-payload:http] + [%error code=@ud msg=@t] :: codes 400-500+ + [%redirect loc=@t] +--
\ No newline at end of file diff --git a/desk/lib/rout.hoon b/desk/lib/rout.hoon new file mode 100644 index 0000000..a818ec6 --- /dev/null +++ b/desk/lib/rout.hoon @@ -0,0 +1,53 @@ +/+ *sortug +|% ++$ card card:agent:gall ++$ eyre-poke [id=@da req=inbound-request:eyre] +:: our paths are particular ++$ paeth (list @t) ++$ req-path [=method:http paeth] ++$ route-map (map req-path simple-payload:http) ++$ data [=order state=mold] +:: I'd rather it can be a non-simple payload but whatever ++$ route $-(inbound-request route-end) +++ de-path +:: modified from apat:de-purl:html +=/ delim ;~(pose fas dot) +%+ cook :: get rid of the last dot and make the extension a part of the path +|= l=paeth ^+ l +=/ acc [nl=*_l i=1] +%^ spin l acc +|= [e=@t a=acc] +:- e :_ +(i) +:: only change the last one +?. .=(i (lent l)) a.a +(rash last (csplit dot)) +;~(pfix fas (more fas smeg:de-purl:html)) + +++ parse-url-path + |= url=@t + ^- request-line + (fall (rush url ;~(plug de-path yque:de-purl:html)) [[~ ~] ~]) +++ $ =state + |* state-type=mold + +=/ met method.request.req.order +=/ req-line (parse-request-line url.request.req.order) +=/ pth=path :- met site.req-line +?+ pth :_ state (serve-404 req-line) + [%'GET' ~ ~] :_ state (serve-index req-line) :: "/" + [%'GET' @ @ @ @ *] :_ state (serve-post site.req-line) + [%'POST' *] (handle-post req-line body.request.req.order state) + :: [%get %blog *] serve-blog + :: [%get 'chat' *] serve-chat + :: [%get 'forum' *] serve-forum + :: [%get 'about' *] serve-about +== + +:: The api we want is +(route eyre-poke route-map state bowl) +:: route-map is ++ +:: and from that we get +[(list card) simple-payload:http _state] +which the router itself resolves to (quip card _state) +--
\ No newline at end of file diff --git a/desk/lib/rudder.hoon b/desk/lib/rudder.hoon new file mode 100644 index 0000000..45eaf30 --- /dev/null +++ b/desk/lib/rudder.hoon @@ -0,0 +1,285 @@ +:: rudder: framework for routing & serving simple web frontends +:: +:: v1.0.2: newborn helmsman +:: +:: the primary usage pattern involves your app calling steer:rudder +:: with a configuration, then calling the resulting gate with an +:: incoming request and relevant context. +:: +:: %. [bowl [eyre-id inbound-request] dat] +:: %- (steer:rudder _dat cmd) +:: [pages route adlib solve] +:: +:: dat is app state passed into and transformed by the frontend code. +:: cmd is the type of app actions that the frontend may produce. +:: pages is a (map term (page _dat cmd)), contains per-view frontend logic. +:: route is a routing function, turning a url query into a $place. +:: adlib gets called with the full request when no route is found. +:: solve is a function that applies a cmd resulting from a POST request. +:: +:: the library provides some default implementations for route and adlib, +:: which you can construct using +point and +fours respectively. +:: +:: for examples and a more detailed description of handling http requests, +:: see /lib/rudder/poke-example.hoon +:: +:: pages implement a bundle of view logic, each implementing a door +:: with three arms. +:: +:: +build gets called for GET requests, producing a $reply to render. +:: +argue gets called for POST requests, turning it into a cmd. +:: +final gets called after POST requests, producing a $reply to render. +:: +:: for examples and a more detailed description of implementing a page, +:: see /lib/rudder/page-example.hoon +:: +::TODO +:: - should rudder really be falling back to generic error messages when +:: calling +final after failure? what if apps/pages want to provide +:: their own generic error message? +:: - in the full-default setup, the behavior of +alert is a little bit +:: awkward. because +point forces routes to omit trailing slashes, +:: you cannot refer to "the current page" in a consistent way. +:: you have to either hardcode the page name, or pass the full url +:: from the inbound-request. +:: a router that forces inclusion of trailing slashes would let you +:: use '.', but has unconventional url semantics, and doesn't mesh +:: nicely with single-level routing. +:: - some inconsistency between the expected output of +adlib and +solve. +:: "briefless" +solve results may be common, so it's nice that they're +:: easy to write. for +adlib that probably isn't as relevant, and +:: the current factoring makes for a nice =^ in the lib code, but... +:: on the other hand, they're still different output types semantically, +:: so inconsistency isn't the end of the world. would have to see how +:: this ends up looking in practice. +:: - +argue is awkward because its function signature doesn't really work +:: if the cmd type is an atom. +:: - maybe unsupported methods should go to the fallback too? +:: - currently ambiguous: do you catch would-fail actions during +argue, +:: or in +solve? might be best to catch earlier, but this splits +:: or duplicates business logic between app and pages... +:: +|% ++| %types :: outputs, inputs, function signatures +:: ++$ reply + $% [%page bod=manx] :: html page + [%xtra hed=header-list:http bod=manx] :: html page w/ heads + [%next loc=@t msg=brief] :: 303, succeeded + [%move loc=@t] :: 308, use other + [%auth loc=@t] :: 307, please log in + [%code cod=@ud msg=brief] :: error code page + [%full ful=simple-payload:http] :: full payload + == +:: ++$ place + $% [%page ath=? nom=term] :: serve from pages + [%away loc=(list @t)] :: 308, redirect + == +:: ++$ query + $: trail + args=(list [key=@t value=@t]) + == +:: ++$ trail + [ext=(unit @ta) site=(list @t)] +:: ++$ order [id=@ta inbound-request:eyre] ++$ route $-(trail (unit place)) ++$ brief ?(~ @t) +:: +++ page + |* [dat=mold cmd=mold] + $_ ^| + |_ [bowl:gall order dat] + ++ build |~([(list [k=@t v=@t]) (unit [? @t])] *reply) + ++ argue |~([header-list:http (unit octs)] *$@(brief cmd)) + ++ final |~([success=? msg=brief] *reply) + -- +:: ++$ card card:agent:gall +:: pilot: core server logic +:: ++| %pilot +:: +++ steer :: main helper constructor + |* [dat=mold cmd=mold] + |^ serve + +$ page (^page dat cmd) + +$ adlib $-(order [[(unit reply) (list card)] dat]) + +$ solve $-(cmd $@(brief [brief (list card) dat])) + :: + ++ serve :: main helper + |= [pages=(map @ta page) =route =adlib =solve] + |= [=bowl:gall =order =dat] + ^- (quip card _dat) + =* id id.order + =+ (purse url.request.order) + =/ target=(unit place) + (route -<) + :: if there is no route, fall back to adlib + :: + ?~ target + =^ [res=(unit reply) caz=(list card)] dat + (adlib order) + :_ dat + ?~ res caz + (weld (spout id (paint u.res)) caz) + :: route might be a redirect + :: + ?: ?=(%away -.u.target) + =+ (rap 3 '/' (join '/' loc.u.target)) + [(spout id (paint %move -)) dat] + :: route might require authentication + :: + ?: &(ath.u.target !authenticated.order) + [(spout id (paint %auth url.request.order)) dat] + :: route might have messed up and pointed to nonexistent page + :: + ?. (~(has by pages) nom.u.target) + [(spout id (issue 404 (cat 3 'no such page: ' nom.u.target))) dat] + :: + %. [bowl order dat] + (apply (~(got by pages) nom.u.target) solve) + :: + ++ apply :: page usage helper + |= [=page =solve] + |= [=bowl:gall =order =dat] + ^- (quip card _dat) + =. page ~(. page bowl order dat) + =* id id.order + ?+ method.request.order + [(spout id (issue 405 ~)) dat] + :: + %'GET' + :_ dat + =+ (purse url.request.order) + =^ msg args + ::NOTE as set by %next replies + ?~ msg=(get-header:http 'rmsg' args) [~ args] + [`[& u.msg] (delete-header:http 'rmsg' args)] + %+ spout id + (paint (build:page args msg)) + :: + %'POST' + ?@ act=(argue:page [header-list body]:request.order) + :_ dat + =? act ?=(~ act) 'failed to parse request' + (spout id (paint (final:page | act))) + ?@ res=(solve act) + :_ dat + =? act ?=(~ act) 'failed to process request' + (spout id (paint (final:page | res))) + :_ +>.res + =. +<+>.page +>.res + (weld (spout id (paint (final:page & -.res))) +<.res) + == + -- +:: easy: hands-off steering behavior +:: ++| %easy +:: +++ point :: simple single-level routing, +route + |= [base=(lest @t) auth=? have=(set term)] + ^- route + |= trail + ^- (unit place) + ?~ site=(decap base site) ~ + ?- u.site + ~ `[%page auth %index] + [~ ~] `[%away (snip ^site)] + [%index ~] `[%away (snip ^site)] + [@ ~] ?:((~(has in have) i.u.site) `[%page auth i.u.site] ~) + [@ ~ ~] `[%away (snip ^site)] + * ~ + == +:: +++ fours :: simple 404 responses, +adlib + |* dat=* + :: ^- adlib:(rest * _dat) + |= * + [[`[%code 404 'no route found'] ~] dat] +:: +++ alert :: simple redirecting +final handler + |= [next=@t build=$-([(list [@t @t]) (unit [? @t])] reply)] + |= [done=? =brief] + ^- reply + ?: done [%next next brief] + (build ~ `[| `@t`brief]) +:: cargo: payload generation +:: ++| %cargo +:: +++ paint :: render response + |= =reply + ^- simple-payload:http + ?- -.reply + %page [[200 ['content-type' 'text/html']~] `(press bod.reply)] + %xtra =? hed.reply ?=(~ (get-header:http 'content-type' hed.reply)) + ['content-type'^'text/html' hed.reply] + [[200 hed.reply] `(press bod.reply)] + %next =; loc [[303 ['location' loc]~] ~] + ?~ msg.reply loc.reply + %+ rap 3 + :~ loc.reply + ?:(?=(^ (find "?" (trip loc.reply))) '&' '?') + 'rmsg=' + (crip (en-urlt:html (trip msg.reply))) + == + %move [[308 ['location' loc.reply]~] ~] + %auth =/ loc (crip (en-urlt:html (trip loc.reply))) + [[307 ['location' (cat 3 '/~/login?redirect=' loc)]~] ~] + %code (issue +.reply) + %full ful.reply + == +:: +++ issue :: render status code page + |= [cod=@ud msg=brief] + ^- simple-payload:http + :- [cod ~] + =; nom=@t + `(as-octs:mimes:html (rap 3 ~[(scot %ud cod) ': ' nom '\0a' msg])) + ?+ cod '' + %400 'bad request' + %404 'not found' + %405 'method not allowed' + %500 'internal server error' + == +:: utils: fidgeting +:: ++| %utils +:: +++ decap :: strip leading base from full site path + |= [base=(list @t) site=(list @t)] + ^- (unit (list @t)) + ?~ base `site + ?~ site ~ + ?. =(i.base i.site) ~ + $(base t.base, site t.site) +:: +++ frisk :: parse url-encoded form args + |= body=@t + %- ~(gas by *(map @t @t)) + (fall (rush body yquy:de-purl:html) ~) +:: +::NOTE the below (and $query) are also available in /lib/server.hoon, +:: but we reimplement them here for independence's sake. +:: +++ purse :: url cord to query + |= url=@t + ^- query + (fall (rush url ;~(plug apat:de-purl:html yque:de-purl:html)) [[~ ~] ~]) +:: +++ press :: manx to octs + (cork en-xml:html as-octt:mimes:html) +:: +++ spout :: build full response cards + |= [eyre-id=@ta simple-payload:http] + ^- (list card) + =/ =path /http-response/[eyre-id] + :~ [%give %fact ~[path] [%http-response-header !>(response-header)]] + [%give %fact ~[path] [%http-response-data !>(data)]] + [%give %kick ~[path] ~] + == +--
\ No newline at end of file diff --git a/desk/lib/seq.hoon b/desk/lib/seq.hoon new file mode 100644 index 0000000..12f8d26 --- /dev/null +++ b/desk/lib/seq.hoon @@ -0,0 +1,1809 @@ +:: /lib/seq/hoon +:: |seq +:: operations for working with values of type list +:: +|% +:: +all-pairs: [(list T1) (list T2)] -> (list [T1 T2]) +:: +:: Returns a new list that contains all pairings of elements from two non-empty +:: lists. +:: Examples +:: > (all-pairs ~['a' 'b' 'c'] ~[1 2 3]) +:: ~[['c' 3] ['c' 2] ['c' 1] +:: ['b' 3] ['b' 2] ['b' 1] +:: ['a' 3] ['a' 2] ['a' 1]] +:: Source +++ all-pairs + |* [p=(list) q=(list)] + =/ a=(list _?>(?=(^ p) i.p)) p + =/ res=(list [_?>(?=(^ p) i.p) _?>(?=(^ q) i.q)]) ~ + =/ scnd=(list _?>(?=(^ q) i.q)) q + |- ^- (list [_?>(?=(^ p) i.p) _?>(?=(^ q) i.q)]) + ?~ a res + ?~ scnd $(a t.a, scnd q) + $(res [[i.a i.scnd] res], scnd +.scnd) +:: +append: [(list) (list)] -> (list) +:: +:: Returns a new list that contains the elements of the first list followed by +:: elements of the second list. +:: Examples +:: > (append "urb" "it") +:: "urbit" +:: > (append (limo [1 2 ~]) (limo [3 4 ~])) +:: ~[1 2 3 4] +:: Source +++ append weld +:: +average: (list @) -> @ud +:: +:: Returns the average of the values in a non-empty list. +:: Examples +:: > (average `(list @ud)`~[1 2 3 4]) +:: 2 +:: Source +++ average + |* a=(list @) + (div (roll a add) (lent a)) +:: +average-by: [(list T) projection:$-(T @ud)] -> @ud +:: +:: Returns the average of values in a list generated by applying a function to +:: each element of the list. +:: Examples +:: > (average-by (limo ~[[1 1] [2 2] [3 3] [4 4]]) |=([a=@ b=@] (add a b))) +:: 5 +:: Source +++ average-by + |* [a=(list) b=$-(* @ud)] + (div (roll (turn a b) add) (lent a)) +:: +choose: [(list T1) $-(T1 (unit T2))] -> (list T2) +:: +:: Applies a function to each element in a list and then returns a list of +:: values v where the applied function returns (unit v). +:: Returns an empty list when the input list is empty or when the applied +:: chooser function returns ~ for all elements. +:: Examples +:: > =a |=(a=@ ?.((gte a 2) ~ (some (add a 10)))) +:: > (choose `(list @)`[0 1 2 3 ~] a) +:: [i=12 t=[i=13 t=~]] +:: Source +++ choose murn +:: +chunk-by-size: [(list T) chunkSize:@] -> (list (list T)) +:: +:: Divides the input list into lists (chunks) with a positive number of at +:: most chunkSize elements. Returns a new list containing the generated lists +:: (chunks) as its elements. Returns an empty list when the input list is empty +:: Examples +:: > (chunk-by-size (limo ~[1 2 3 4 5 6 7]) 2) +:: [i=~[1 2] t=[i=~[3 4] t=~[~[5 6] ~[7]]]] +:: Crash +:: 'chunk size is 0' +:: Source +++ chunk-by-size + |* [p=(list) q=@ud] + ?: =(0 q) ~|('chunk size is 0' !!) + =/ res=(list (list _?>(?=(^ p) i.p))) ~ + =/ i=@ud 0 + =/ next=(list _?>(?=(^ p) i.p)) ~ + |- ^- (list (list _?>(?=(^ p) i.p))) + ?~ p (flop [(flop next) res]) + ?: =(i q) $(i 0, res [(flop next) res], next ~) + $(i +(i), next [i.p next], p t.p) +:: +collect: [(list T1) mapping:$-(T1 (list T2))] -> (list T2) +:: +:: For each element of the list, applies the given function. Concatenates all +:: the results and return the combined list. +:: Examples +:: > (collect (limo ~[1 2 3]) |=(a=* (limo ~[a a]))) +:: ~[1 1 2 2 3 3] +:: Source +++ collect + |* [p=(list) q=$-(* (list))] + =/ res=(list) ~ + |- + ?~ p (flop res) + =/ c=(list) (q i.p) + |- + ?~ c ^$(p t.p) + $(c t.c, res [i.c res]) +:: +compare: [(list T) (list T) comparer:$-([T T] ?)] -> (list ?) +:: +:: Compares two lists element by element using the given comparison function. +:: When an entry exists for both lists, returns the result of the comparer +:: function. When the second list is longer than the first returns %.y for +:: entries of second where first does not exist. When first list is longer +:: returns %.n for entries of first where second does not exist. +:: Examples +:: > (compare "when" "than" aor) +:: ~[%.n %.y %.n %.y] +:: Source +++ compare + |* [b=(list) c=(list) a=$-([* *] ?)] + =/ res=(list ?) ~ + =/ bb b + =/ cc c + |- ^- (list ?) + ?~ bb ?~ cc (flop res) $(cc t.cc, res [%.y res]) + ?~ cc $(bb t.bb, res [%.n res]) + $(bb t.bb, cc t.cc, res [(a i.bb i.cc) res]) +:: +concat: (list (list)) -> (list) +:: +:: Returns a new list that contains the elements of each of the lists in order. +:: Examples +:: > (concat (limo [(limo ['a' 'b' 'c' ~]) (limo ['e' 'f' 'g' ~]) +:: (limo ['h' 'i' 'j' ~]) ~])) +:: ~['a' 'b' 'c' 'e' 'f' 'g' 'h' 'i' 'j'] +:: > (concat (limo [(limo [1 'a' 2 'b' ~]) (limo [3 'c' 4 'd' ~]) ~])) +:: ~[1 97 2 98 3 99 4 100] +:: Source +++ concat zing +:: +contains: [(list) value:*] -> ? +:: +:: Tests if the list contains the specified element. +:: Examples +:: > (contains "yep" `(list tape)`~["nope" "yep"]) +:: %.y +:: Source +++ contains + |* [p=(list) q=*] + |- ^- ? + ?~ p %.n + ?: =(q i.p) %.y + $(p t.p) +:: +count-by: [(list T1) projection:$-(T1 T2)] -> (list [T2 @ud]) +:: +:: Applies a key-generating function to each element of a list and returns a +:: list yielding unique keys and their number of occurrences in the original +:: list. +:: Examples +:: > %: count-by +:: (limo ~["where" "when" "there" "then"]) +:: |=(a=tape (scag 2 a)) +:: == +:: ~[[[i=t' t="h"] 2] [[i='w' t="h"] 2]] +:: Source +++ count-by + |* [p=(list) q=$-(* *)] + =/ res=(map _?>(?=(^ p) (q i.p)) @ud) ~ + |- ^- (list [_?>(?=(^ p) (q i.p)) @ud]) + ?~ p ~(tap by res) + =/ key=_?>(?=(^ p) (q i.p)) (q i.p) + =/ val (~(get by res) key) + ?~ val $(res `(map _?>(?=(^ p) (q i.p)) @ud)`(~(put by res) key 1), p t.p) + %= $ + res `(map _?>(?=(^ p) (q i.p)) @ud)`(~(put by res) key +(`@ud`(need val))) + p t.p + == +:: +distinct: (list) -> (list) +:: +:: Returns a list that contains no duplicate entries according to generic hash +:: and equality comparisons on the entries. If an element occurs multiple times +:: in the list then the later occurrences are discarded. +:: Examples +:: > (distinct `(list tape)`~["tape1" "tape0" "tape1" "tape0"]) +:: ~["tape1" "tape0"] +:: Source +++ distinct + |* a=(list) + =/ b=(list _?>(?=(^ a) i.a)) ~ + =/ c=(set) ~ + |- ^+ a + ?~ a (flop b) + ?: (~(has in c) i.a) $(a t.a) + $(a t.a, b [i.a b], c (~(put in c) i.a)) +:: +distinct-by: [(list T1) projection:$-(T1 T2)] -> (list T1) +:: +:: Returns a list that contains no duplicate entries according to the generic +:: hash and equality comparisons on the keys returned by the given +:: key-generating function. If an element occurs multiple times in the list +:: then the later occurrences are discarded. +:: Examples +:: > =foo `(list [@ @])`~[[1 1] [1 2] [1 3] [2 1]] +:: > (distinct-by foo |=([a=@ b=@] (add a b))) +:: ~[[1 1] [1 2] [1 3]] +:: Source +++ distinct-by + |* [p=(list) q=$-(* *)] + =/ b=(list _?>(?=(^ p) i.p)) ~ + =/ c=(set) ~ + |- ^+ p + ?~ p (flop b) + ?: (~(has in c) (q i.p)) $(p t.p) + $(p t.p, b [i.p b], c (~(put in c) (q i.p))) +:: +empty: $ -> *(list $) +:: +:: Returns an empty list typed by the mold. (The bunt of the typed list.) +:: Examples +:: > (empty @t) +:: ~ +:: Source +++ empty + |* a=mold + *(list a) +:: +exactly-one: (list T) -> T +:: +:: Returns the only element of the list. Crashes if list has different length. +:: Examples +:: > (exactly-one (limo ~["tape"])) +:: "tape" +:: Crash +:: 'list length is not 1' +:: Source +++ exactly-one + |* a=(list) + ?: =(1 (lent a)) -.a + ~|('list length is not 1' !!) +:: +except: [(list T) items-to-exclude:(list T)] -> (list T) +:: +:: Returns a new list with the distinct elements of the input list which do not +:: appear in the items-to-exclude list, using generic hash and equality +:: comparisons to compare values. +:: Examples +:: > %: except +:: (limo ~["able" "baker" "charlie" "dog"]) +:: (limo ~["baker" "dog"]) +:: == +:: ~[[i='a' t="ble"] [i='c' t="harlie"]] +:: Source +++ except + |* [p=(list) q=(list)] + =/ qq (silt q) + =/ b=(list _?>(?=(^ p) i.p)) ~ + |- ^+ p + ?~ p (flop b) + ?: (~(has in qq) i.p) $(p t.p) + $(p t.p, b [i.p b], qq (~(put in qq) i.p)) +:: +exists: [(list T) predicate:$-(T ?)] -> ? +:: +:: Tests if any element of the list satisfies the given predicate. +:: Examples +:: > =foo |= a=tape +:: ?: ?&(=(4 (lent a)) =('a' -.a)) %.y %.n +:: > (exists (limo ~["aaa" "able" "baker" "charlie" "dog"]) foo) +:: %.y +:: Source +++ exists + |* [a=(list) b=$-(* ?)] + |- ^- ? + ?~ a %.n + ?: (b i.a) %.y + $(a t.a) +:: +exists2: [(list T1) (list T2) predicate:$-([T1 T2] ?)] -> ? +:: +:: Tests if any pair of corresponding elements of the lists satisfies the given +:: predicate. +:: Examples +:: > =foo |= [a=tape b=tape] +:: ?: =(-.a -.b) %.y %.n +:: > (exists2 (limo ~["cat" "betty"]) (limo ~["able" "butter"]) foo) +:: %.y +:: Source +++ exists2 + |* [a=(list) b=(list) c=$-([* *] ?)] + |- ^- ? + ?~ a %.n + ?~ b %.n + ?: (c [i.a i.b]) %.y + $(a t.a, b t.b) +:: +filter: [(list T) predicate:$-(T ?)] -> (list T) +:: +:: Returns a new list containing only the elements of the list for +:: which the given predicate returns "true" +:: Examples +:: > =a |=(a=@ (gth a 1)) +:: > (filter `(list @)`[0 1 2 3 ~] a) +:: [i=2 t=~[3]] +:: Source +++ filter skim +:: +:: +findx: [(list T) predicate:$-(T ?)] -> T +:: +:: Returns the first element for which the given function returns True. +:: Crashes if no such element exists. +:: Examples +:: > (findx (gulf [1 30]) |=(a=@ud ?&(=(0 (mod a 3)) =(0 (mod a 5))))) +:: 15 +:: Crash +:: 'not found' +:: Source +++ findx + |* [a=(list) b=$-(* ?)] + |- ^- _?>(?=(^ a) i.a) + ?~ a ~|('not found' !!) + ?: (b i.a) i.a $(a t.a) +:: +find-all: [(list T) predicate:$-(T ?)] -> (list T)) +:: +:: Returns all elements for which the given function returns True. +:: Crashes if no such element exists. +:: Examples +:: > (find-all (gulf [1 30]) |=(a=@ud ?&(=(0 (mod a 3)) =(0 (mod a 5))))) +:: ~[15 30] +:: Crash +:: 'not found' +:: Source +++ find-all + |* [a=(list) b=$-(* ?)] + =/ c=(list _?>(?=(^ a) i.a)) ~ + |- + ?~ a ?~ c ~|('not found' !!) (flop c) + ?: (b i.a) $(a t.a, c [i.a c]) $(a t.a) +:: +find-all-by-list: [(list T) arg:(list T) -> (list @)] +:: +:: Produces list of indices of all occurrences of the argument list sequence in +:: the sequence of the source list. +:: Examples +:: > (find-all-by-list "cbabab" "ba") +:: ~[1 3] +:: Source +++ find-all-by-list + |* [hstk=(list) nedl=(list)] + ^- (list @) + (fand nedl hstk) +:: +find-all-by-unit: [(list T1) chooser:$-(T1 (unit T2))] -> (list T2) +:: +:: Applies the given function to successive elements, returning the list of +:: elements where the function returns Some(x). +:: Crashes when no such element exists. +:: Examples +:: > %: find-all-by-unit +:: (limo ~[1 2 3 4]) +:: |=(a=@ ?:(=((mod a 2) 0) `a ~)) +:: == +:: ~[2 4] +:: Crash +:: 'not found' +:: Source +++ find-all-by-unit + |* [hstk=(list) nedl=$-(* (unit *))] + =/ b=(list _?>(?=(^ hstk) i.hstk)) ~ + |- ^- (list _?>(?=(^ hstk) i.hstk)) + ?~ hstk ?~ b ~|('not found' !!) + (flop b) + =/ x (nedl i.hstk) + ?~ x $(hstk t.hstk) + $(hstk t.hstk, b [(need x) b]) +:: +find-back: [(list T) predicate:$-(T ?)] -> T +:: +:: Returns the last element for which the given function returns True. +:: Crashes if no such element exists. +:: Examples +:: > %: find-back +:: (gulf [1 30]) +:: |=(a=@ud ?&(=(0 (mod a 3)) =(0 (mod a 5)))) +:: == +:: 30 +:: Crash +:: 'not found' +:: Source +++ find-back + |* [a=(list) b=$-(* ?)] + ?~ a ~|('not found' !!) + (findx (flop a) b) +:: +find-back-by-list: [(list T) arg:(list T)] -> @ +:: +:: Produces the index of the last occurrence of the argument list sequence in +:: the sequence of the source list. +:: Examples +:: > (find-back-by-list "cbabab" "ba") +:: 3 +:: Source +++ find-back-by-list + |* [hstk=(list) nedl=(list)] + (tail-end (find-all-by-list hstk nedl)) +:: +find-back-by-unit: [(list T1) chooser:$-(T1 (unit T2))] -> T2 +:: +:: Applies the given function to successive elements from the end back, +:: returning the first result where function returns Some(x) for some x. +:: Crashes when no such element exists. +:: Examples +:: > %: find-back-by-unit +:: (limo ~[1 2 3 4]) +:: |=(a=@ ?:(=((mod a 2) 0) `a ~)) +:: == +:: 4 +:: Crash +:: 'not found' +:: Source +++ find-back-by-unit + |* [hstk=(list) nedl=$-(* (unit *))] + ^- _?>(?=(^ hstk) i.hstk) + (find-by-unit (flop hstk) nedl) +:: +find-by-list: [(list T) arg:(list T)] -> @ +:: +:: Produces the index of the first occurrence of the argument list sequence in +:: the sequence of the source list. +:: Examples +:: > (find-by-list "cbabab" "ab") +:: 2 +:: Crash +:: 'not found' +:: Source +++ find-by-list + |* [hstk=(list) nedl=(list)] + ^- @ + =/ x (find nedl hstk) + ?~ x ~|('not found' !!) (need x) +:: +find-by-unit: [(list T1) chooser:$-(T1 (unit T2))] -> T2 +:: +:: Applies the given function to successive elements, returning the first +:: result where function returns Some(x) for some x. Crashes when no such +:: element exists. +:: Examples +:: > (find-by-unit (limo ~[1 2 3 4]) |=(a=@ ?:(=((mod a 2) 0) `a ~))) +:: 2 +:: Crash +:: 'not found' +:: Source +++ find-by-unit + |* [hstk=(list) nedl=$-(* (unit *))] + |- ^- _?>(?=(^ hstk) i.hstk) + ?~ hstk ~|('not found' !!) + =/ x (nedl i.hstk) + ?~ x $(hstk t.hstk) + (need x) +:: +find-index: [(list T) predicate:$-(T ?)] -> @ +:: +:: Returns the index of the first element in the list that satisfies the given +:: predicate. Crashes if no such element exists. +:: Examples +:: > %: find-index +:: (gulf [1 30]) +:: |=(a=@ud ?&(=(0 (mod a 3)) =(0 (mod a 5)))) +:: == +:: 14 +:: Crash +:: 'not found' +:: Source +++ find-index + |* [a=(list) b=$-(* ?)] + =/ i 0 + |- ^- @ + ?~ a ~|('not found' !!) + ?: (b i.a) i $(a t.a, i +(i)) +:: +find-index-all: [(list T) predicate:$-(T ?)] -> (list @) +:: +:: Returns the list of indices in the list that satisfies the given predicate. +:: Examples +:: > %: find-index-all +:: (gulf [1 30]) +:: |=(a=@ud ?&(=(0 (mod a 3)) =(0 (mod a 5)))) +:: == +:: ~[14 29] +:: Source +++ find-index-all + |* [a=(list) b=$-(* ?)] + =/ c=(list @) ~ + =/ i 0 + |- ^- (list @) + ?~ a (flop c) + ?: (b i.a) $(a t.a, c [i c], i +(i)) $(a t.a, i +(i)) +:: +find-index-back: [(list T) predicate:$-(T ?)] -> @ +:: +:: Returns the index of the last element in the list that satisfies the given +:: predicate. Crashes if no such element exists. +:: Examples +:: > %: find-index-back +:: (gulf [1 30]) +:: |=(a=@ud ?&(=(0 (mod a 3)) =(0 (mod a 5)))) +:: == +:: 29 +:: Crash +:: 'not found' +:: Source +++ find-index-back + |* [a=(list) c=$-(* ?)] + ?~ a ~|('not found' !!) + =/ b (flop a) + =/ i (dec (lent a)) + |- ^- @ud + ?~ b ~|('not found' !!) + ?: (c i.b) i + ?: =(0 i) ~|('not found' !!) + $(b t.b, i (dec i)) +:: +first-n: [(list T) count:@ud] -> (list T) +:: +:: Returns the first N elements of the list. +:: Examples +:: > (first-n `(list @)`[1 2 3 4 ~] 2) +:: [i=1 t=~[2]] +:: > (first-n `(list @)`[1 2 3 4 ~] 10) +:: [i=1 t=~[2 3 4]] +:: Source +++ first-n + |* [p=(list) q=@] + (scag q p) +:: +fold: [(list T1) state:T2 folder:$-([T1 T2] T2)] -> T2 +:: +:: Applies a function to each element of the list, threading an +:: accumulator argument through the computation. Take the second argument, and +:: apply the function to it and the first element of the list. Then feed this +:: result into the function along with the second element and so on. Return the +:: final result. If the input function is f and the elements are i0...iN then +:: computes f (... (f s i0) i1 ...) iN. +:: Examples +:: > (fold (gulf 1 5) 0 |=([n=@ state=@] (add state (mul n n)))) +:: 55 +:: Source +++ fold + |* [a=(list) b=* c=_|=(^ [** +<+])] + |- ^- _b + ?~ a b + $(a t.a, b (c i.a b)) +:: +fold2: [(list T1) (list T2) state:T3 folder:$-([T1 T2 T3] T3)] -> T3 +:: +:: Applies a function to corresponding elements of two lists, threading +:: an accumulator argument through the computation. The lists must have +:: identical sizes. If the input function is f and the elements are i0...iN and +:: j0...jN then computes f (... (f s i0 j0)...) iN jN. +:: Examples +:: > %: fold2 +:: (limo ~["Tails" "Head" "Tails"]) +:: (limo ~["Tails" "Head" "Head"]) +:: 0 +:: |=([n1=tape n2=tape state=@] ?:(=(n1 n2) +(state) state)) +:: == +:: 2 +:: Crash +:: 'lists of unequal length' +:: Source +++ fold2 + |* [a=(list) b=(list) c=* d=_|=(^ [** ** +<+])] + |- ^- _c + ?~ a ?~ b c ~|('lists of unequal length' !!) + ?~ b ~|('lists of unequal length' !!) + $(a t.a, b t.b, c (d i.a i.b c)) +:: +fold-back: [(list T1) state:T2 folder:$-([T1 T2] T2)] -> T2 +:: +:: Applies a function to each element of the list, starting from the end, +:: threading an accumulator argument through the computation. If the input +:: function is f and the elements are i0...iN then computes f i0 (...(f iN s)). +:: Examples +:: > =less-hungry |= [n=tape state=(list [tape @])] +:: ^+ state +:: ?~ state (limo ~[[n 1]]) +:: [[n +(+.i.state)] state] +:: > %: fold-back +:: (limo ~["Apple" "Pear" "Orange"]) +:: `(list [tape @])`~ +:: less-hungry +:: == +:: [i=["Apple" 3] t=~[["Pear" 2] ["Orange" 1]]] +:: Source +++ fold-back + |* [a=(list) b=* c=$-([* *] *)] + (fold (flop a) b c) +:: +fold-back2: [(list T1) (list T2) state:T3 folder:$-([T1 T2 T3] T3)] -> T3 +:: +:: Applies a function to corresponding elements of two lists, threading +:: an accumulator argument through the computation. The lists must have +:: identical sizes. If the input function is f and the elements are i0...iN and +:: j0...jN then computes f i0 j0 (...(f iN jN s)). +:: Examples +:: > %: fold-back2 +:: (limo ~["Tails" "Head" "Tails"]) +:: (limo ~["Tails" "Head" "Head"]) +:: `(list tape)`~ +:: |=([n1=tape n2=tape state=(list tape)] [(weld n1 n2) state]) +:: == +:: ~["TailsTails" "HeadHead" "TailsHead"] +:: Source +++ fold-back2 + |* [a=(list) b=(list) c=* d=$-([* * *] *)] + (fold2 (flop a) (flop b) c d) +:: +forall: [(list T) predicate:$-(T ?)] -> ? +:: +:: Tests if all elements of the list satisfy the given predicate. +:: Examples +:: > (forall (limo ~[2 4 8]) |=(a=@ ?:(=(0 (mod a 2)) %.y %.n))) +:: %.y +:: > (forall (limo ~[2 1 8]) |=(a=@ ?:(=(0 (mod a 2)) %.y %.n))) +:: %.n +:: Source +++ forall + |* [a=(list) predicate=$-(* ?)] + |- ^- ? + ?~ a %.y + ?. (predicate i.a) %.n + $(a t.a) +:: +forall2: [(list T1) (list T2) predicate:$-([T1 T2] ?)] -> ? +:: +:: Tests if all corresponding elements of the list satisfy the given +:: predicate pairwise. Crashes on lists of unequal length +:: Examples +:: > %: forall2 +:: (limo ~[1 4 8]) +:: (limo ~[3 4 8]) +:: |=([a=@ b=@] ?:(=(0 (mod (add a b) 2)) %.y %.n)) +:: == +:: %.y +:: > %: forall2 +:: (limo ~[1 5 8]) +:: (limo ~[3 4 8]) +:: |=([a=@ b=@] ?:(=(0 (mod (add a b) 2)) %.y %.n)) +:: == +:: %.n +:: Crash +:: 'lists of unequal length' +:: Source +++ forall2 + |* [a=(list) b=(list) predicate=$-(* ?)] + ?. =((lent a) (lent b)) ~|('lists of unequal length' !!) + |- ^- ? + ?~ a %.y + ?~ b ~|('cant get here' !!) + ?. (predicate i.a i.b) %.n + $(a t.a, b t.b) +:: +from-map: (map) -> (list [* *]) +:: +:: Produces the list of all key element pairs in map. +:: Examples +:: > =map-00 (to-map (limo ~[['aa' 1] ['bb' 2] ['cc' 3] ['dd' 4]])) +:: > (from-map map-00) +:: ~[[p='bb' q=2] [p='dd' q=4] [p='cc' q=3] [p='aa' q=1]] +:: Source +++ from-map + |* a=(map) + ~(tap by a) +:: +from-set: -> (list) +:: +:: Produces the list of element in set +:: Examples +:: > (from-set `(set tap)`[[n="tlon"] l=["urbit" ~ ~] r=["uqbar" ~ ~]]) +:: Source +++ from-set + |* a=(set) + ~(tap in a) +:: +get-head: (list T) -> T +:: +:: Returns the first element of the list. Crashes on empty list. +:: Examples +:: > (get-head ~[1 2]) +:: 1 +:: Crash +:: 'empty list' +:: Source +++ get-head + |* a=(list) + ?~ a ~|('empty list' !!) + i.a +:: +get-tail: (list T) -> (list T) +:: +:: Returns the list after removing the first element. +:: Examples +:: > (get-tail ~[1 2]) +:: ~[2] +:: Crash +:: 'empty list' +:: Source +++ get-tail + |* a=(list) + ?~ a ~|('empty list' !!) + t.a +:: +group-by: [(list T1) projection:$-(T1 T2)] -> (list [T2 (list T1)]) +:: +:: Applies a key-generating function to each element of a list and yields a +:: list of unique keys. Each unique key contains a list of all elements that +:: match to this key. +:: Examples +:: > (group-by (gulf 1 5) |=(a=@ (mod a 2))) +:: ~[[p=0 q=[i=4 t=~[[2 0]]]] [p=1 q=[i=5 t=~[[3 [1 0] 0]]]]] +:: Source +++ group-by + |* [a=(list) b=$-(* *)] + =/ d=(map * (list *)) ~ + |- + ?~ a ~(tap by d) + =/ e (b i.a) + =/ f (~(get by d) e) + ?~ f $(a t.a, d (~(put by d) e ~[i.a])) + $(a t.a, d (~(put by d) e ~[i.a (need f)])) +:: +indexed: (list T) -> (list [@ T]) +:: +:: Returns a new list whose elements are the corresponding elements of the +:: input list paired with the index (from 0) of each element. +:: Examples +:: > (indexed (gulf 1 3)) +:: ~[[0 1] [1 2] [2 3]] +:: Source +++ indexed + |* a=(list) + =/ b=(list [@ _?>(?=(^ a) i.a)]) ~ + =/ i 0 + |- ^- (list [@ _?>(?=(^ a) i.a)]) + ?~ a (flop b) + $(a t.a, b [[i i.a] b], i +(i)) +:: +init: [length:@ud initializer:$-(@ud T)] -> (list T) +:: +:: Creates a list by calling the given generator on each index. +:: Crashes on length = 0. +:: Examples +:: > (init 3 |=(a=@ (add a 5))) +:: ~[6 7 8] +:: Crash +:: 'empty list' +:: Source +++ init + |* [len=@ ini=$-(@ *)] + =/ a=(list *) ~ + ?: =(0 len) ~|('empty list' !!) + |- + ?: =(0 len) a + $(len (dec len), a [(ini len) a]) +:: +insert-at: [(list T) index:@ value:T] -> (list T) +:: +:: Return a new list with a new item inserted before the given index. +:: Examples +:: > (insert-at (limo ~[2 3 4]) 1 11) +:: ~[2 11 3 4] +:: Source +++ insert-at into +:: +insertManyAt: [(list T) values=(list T) index=@] -> (list T) +:: +:: Return a new list with new items inserted before the given index. +:: Examples +:: > (insert-many-at (limo ~[1 2 5 6 7]) (limo ~[3 4]) 2) +:: ~[1 2 3 4 5 6 7] +:: Crash +:: 'out of range' +:: Source +++ insert-many-at + |* [a=(list) values=(list) i=@] + ?: =(0 (lent values)) a + =/ len-a (lent a) + ?: (gth i len-a) ~|('out of range' !!) + ?~ values a + ?: =(0 i) (weld values a) + ?: =(len-a i) (weld a values) + =/ start (scag i a) + =/ end (slag i a) + (weld (weld start values) end) +:: +is-empty: (list) -> ? +:: +:: Returns true if the list contains no elements, false otherwise. +:: Examples +:: > (is-empty `(list @)`~[2]) +:: %.n +:: > (is-empty `(list @)`~) +:: %.y +:: Source +++ is-empty + |* a=(list) + ?~ a %.y %.n +:: +item: [(list T) index:@] -> T +:: +:: Indexes into the list. The first element has index 0. +:: Examples +:: > (item `(list @)`~["aa" "bb" "cc" "dd"] 2) +:: "cc" +:: Source +++ item + |* [a=(list) i=@] + (snag i a) +:: +iter: [(list T) fun:$-(T *)] -> ~ +:: +:: Applies the given function to each element of the list, dropping the +:: results. +:: Examples +:: > (iter (limo ~["tape1" "tape2"]) |=(a=tape (lent a))) +:: ~ +:: Source +++ iter + |* [a=(list) fun=$-(* *)] + =/ b (turn a fun) + ~ +:: +iter2: [(list T1) (list T2) fun:$-(T1 T2 *)] -> ~ +:: +:: Applies the given function to two lists simultaneously, dropping the +:: results. The lists must have identical size. +:: Examples +:: > %: iter2 +:: (limo ~["tape1" "tape2"]) +:: (limo ~["tape3" "tape4"]) +:: |=([a=tape b=tape] (add (lent a) (lent b))) +:: == +:: ~ +:: Crash +:: 'lists of unequal length' +:: Source +++ iter2 + |* [a=(list) b=(list) fun=$-(* *)] + =/ b (map2 a b fun) + ~ +:: +iteri: [(list T) fun:$-([@ T] *)] -> ~ +:: +:: Applies the given function to each element of the list and the index +:: of element, dropping the results. +:: Examples +:: > (iteri (limo ~[1 2 3]) |=([a=@ b=@] (add a b))) +:: ~ +:: Source +++ iteri +|* [a=(list) fun=$-(* *)] + =/ b (mapi a fun) + ~ +:: +iteri2: [(list T1) (list T2) fun:$-(@ T1 T2 *)] -> ~ +:: +:: Applies the given function to two lists and the current index, +:: dropping the results. The lists must have identical size. +:: Examples +:: > %: iteri2 +:: (limo ~[1 2 3]) +:: (limo ~[4 5 6]) +:: |=([a=@ b=@ c=@] (add (add a b) c)) +:: == +:: ~ +:: Crash +:: 'lists of unequal length' +:: Source +++ iteri2 + |* [a=(list) b=(list) fun=$-(* *)] + =/ b (mapi2 a b fun) + ~ +:: +last-n: [(list T) count:@] -> (list T) +:: +:: Returns the last N elements of the list. +:: Examples +:: > (last-n `(list @)`[1 2 3 4 ~] 2) +:: [i=3 t=~[4]] +:: > (last-n `(list @)`[1 2 3 4 ~] 10) +:: [i=1 t=~[2 3 4]] +:: Source +++ last-n + |* [p=(list) q=@] + (flop (scag q (flop p))) +:: +length: (list T) -> @u +:: +:: Returns the length of the list. +:: Examples +:: > (length [1 2 3 4 ~]) +:: 4 +:: > (length [1 'a' 2 'b' (some 10) ~]) +:: 5 +:: Source +++ length lent +:: +map-seq: [(list T1) mapping:$-(T1 T2)] -> (list T2) +:: +:: Builds a new list whose elements are the results of applying the given +:: gate to each of the elements of the list. +:: Examples +:: > (map (limo [104 111 111 110 ~]) @t) +:: <|h o o n|> +:: > =a |=(a=@ (add a 4)) +:: > (map (limo [1 2 3 4 ~]) a) +:: ~[5 6 7 8] +:: Source +++ map-seq turn +:: +map2: [(list T1) (list T2) mapping:$-([T1 T2] T3)] -> (list T3) +:: +:: Builds a new list whose elements are the results of applying the given +:: function to the corresponding elements of the two lists pairwise. +:: Crashes if lists are of unequal length +:: Examples +:: > (map2 (limo ~[1 2 3 4]) (limo ~[5 6 7 8]) |=(a=[@ @] (add -.a +.a))) +:: ~[6 8 10 12] +:: Crash +:: 'lists of unequal length' +:: Source +++ map2 + |* [a=(list) b=(list) c=gate] + =/ d=(list) ~ + |- + ?~ a ?~ b (flop d) ~|('lists of unequal length' !!) + ?~ b ~|('lists of unequal length' !!) + $(a t.a, b t.b, d [(c i.a i.b) d]) +:: +map3: [(list T1) (list T2) (list T3) $-([T1 T2 T3] T4)] -> (list T4) +:: +:: Builds a new list whose elements are the results of applying the given +:: function to the corresponding elements of the three lists +:: simultaneously. +:: Examples +:: > %: map3 +:: (limo ~[1 2 3 4]) +:: (limo ~[5 6 7 8]) +:: (limo ~[9 10 11 12]) +:: |=(a=[@ @ @] (add (add -.a +<.a) +>.a)) +:: == +:: ~[15 18 21 24] +:: Crash +:: 'lists of unequal length' +:: Source +++ map3 + |* [a=(list) b=(list) c=(list) d=gate] + =/ e=(list) ~ + |- + ?~ a ?~ b ?~ c (flop e) + ~|('lists of unequal length' !!) + ~|('lists of unequal length' !!) + ?~ b ~|('lists of unequal length' !!) + ?~ c ~|('lists of unequal length' !!) + $(a t.a, b t.b, c t.c, e [(d i.a i.b i.c) e]) +:: +map-fold: [(list T1) state:T2 $-([T1 T2] [T3 T2])] -> [(list T3) T2] +:: +:: Combines map and fold. Builds a new list whose elements are the results of +:: applying the given function to each of the elements of the input list. The +:: function is also used to accumulate a final value. +:: Examples +:: > =input `(list [@t @])`~[['in' 1] ['out' 2] ['in' 3]] +:: > =foo |* [p=[@t @] state=@] +:: ^- [[@t @] @] +:: ?: =(-.p 'in') [['in' (mul +.p 2)] (add state +.p)] +:: [['out' (mul +.p 2)] (mul state +.p)] +:: > (map-fold input 0 foo) +:: [~[['in' 2] ['out' 4] ['in' 6]] 5] +:: Source +++ map-fold spin +:: +map-fold-back: [(list T1) state:T2 $-([T1 T2] [T3 T2])] -> [(list T3) T2] +:: +:: Combines map and foldBack. Builds a new list whose elements are the results +:: of applying the given function to each of the elements of the input list, +:: starting from the end. +:: The function is also used to accumulate a final value. +:: Examples +:: > =input `(list [@t @])`~[['in' 1] ['out' 2] ['in' 3]] +:: > =foo |* [p=[@t @] state=@] +:: ^- [[@t @] @] +:: ?: =(-.p 'in') [['in' (mul +.p 2)] (add state +.p)] +:: [['out' (mul +.p 2)] (mul state +.p)] +:: > (map-fold-back input 0 foo) +:: [~[['in' 6] ['out' 4] ['in' 2]] 7] +:: Source +++ map-fold-back + |* [a=(list) state=* c=$-([* *] [* *])] + (spin (flop a) state c) +:: +mapi: [(list T1) mapping:$-([@ T1] T2)] -> (list T2) +:: +:: Builds a new list whose elements are the results of applying the given +:: function to each of the elements of the list. The integer index passed +:: to the function indicates the index (from 0) of element being transformed. +:: Examples +:: > (mapi (limo ~[1 2 3]) |=([a=@ b=@] (add a b))) +:: ~[1 3 5] +:: Source +++ mai + |* [a=(list) b=gate] + =| i=@ud + => .(a (homo a)) + ^- (list _?>(?=(^ a) (b i i.a))) + |- + ?~ a ~ + :- i=(b i i.a) + t=$(a t.a, i +(i)) +++ mapi + |* [a=(list) fun=$-([@ *] *)] + =/ i 0 + =/ b=(list) ~ + |- + ?~ a (flop b) + $(a t.a, b [(fun i i.a) b], i +(i)) +:: +mapi2: [(list T1) (list T2) mapping:$-([@ T1 T2] T3)] -> (list T3) +:: +:: Like mapi, but mapping corresponding elements from two lists of equal length. +:: Examples +:: > %: mapi2 +:: (limo ~[1 2 3]) +:: (limo ~[4 5 6]) +:: |=([a=@ b=@ c=@] (add (add a b) c)) +:: == +:: ~[5 8 11] +:: Crash +:: 'lists of unequal length' +:: Source +++ mapi2 + |* [a=(list) b=(list) fun=$-([@ * *] *)] + =/ i 0 + =/ c=(list) ~ + |- + ?~ a ?~ b (flop c) ~|('lists of unequal length' !!) + ?~ b ~|('lists of unequal length' !!) + $(a t.a, b t.b, c [(fun i i.a i.b) c], i +(i)) +:: +maxi: (list T) -> T +:: +:: Return the greatest of all elements of the list, compared via Operators.max. +:: Examples +:: > (maxi (limo ~[10 12 11])) +:: 12 +:: > (maxi (limo ~["max" "add" "busy"])) +:: Crash +:: 'empty list' +:: Source +++ maxi + |* a=(list) + ~| 'empty list' + =/ m -.a + |- + ?~ a m + ?: (aor m i.a) $(m i.a, a t.a) + $(a t.a) +:: +maxBy: [(list T) projection:$-(* *)] -> T +:: +:: Returns the greatest of all elements of the list, compared via Operators.max +:: on the function result. +:: Examples +:: > (max-by (limo ~["aa" "mmmm" "zzz"]) |=(a=tape (lent a))) +:: "mmmm" +:: Crash +:: 'empty list' +:: Source +++ max-by + |* [a=(list) q=$-(* *)] + ~| 'empty list' + =/ m -.a + |- + ?~ a m + ?: (aor (q m) (q i.a)) $(m i.a, a t.a) + $(a t.a) +:: +mini: (list T) +:: +:: Returns the lowest of all elements of the list, compared via Operators.min. +:: Examples +:: > (mini (limo ~[11 12 10])) +:: 10 +:: > (mini (limo ~["min" "add" "busy"])) +:: "add" +:: Crash +:: 'empty list' +:: Source +++ mini + |* a=(list) + ~| 'empty list' + =/ m -.a + |- + ?~ a m + ?. (aor m i.a) $(m i.a, a t.a) + $(a t.a) +:: +minBy: (list T) projection +:: +:: Returns the lowest of all elements of the list, compared via Operators.min +:: on the function result +:: Examples +:: > (min-by (limo ~["aa" "mmmm" "zzz"]) |=(a=tape (lent a))) +:: "aa" +:: Crash +:: 'empty list' +:: Source +++ min-by + |* [a=(list) q=$-(* *)] + ~| 'empty list' + =/ m -.a + |- + ?~ a m + ?. (aor (q m) (q i.a)) $(m i.a, a t.a) + $(a t.a) +:: +pairwise: (list T) -> (list [T T]) +:: +:: Returns a list of each element in the input list and its predecessor, with +:: the exception of the first element which is only returned as the predecessor +:: of the second element. +:: Examples +:: > (pairwise (limo ~[1 2 3 4])) +:: ~[[1 2] [2 3] [3 4]] +:: Source +++ pairwise + |* a=(list) + =/ b=(list [_?>(?=(^ a) i.a) _?>(?=(^ a) i.a)]) ~ + |- + ?: (lth (lent a) 2) (flop b) + ?~ a ~|('cant get here' !!) + ?~ t.a ~|('cant get here' !!) + $(a t.a, b [[i.a i.t.a] b]) +:: +partition: [(list T) predicate:$-( T ?)] -> [(list T) (list T)] +:: +:: Splits the list into two lists, containing the elements for +:: which the given predicate returns True and False respectively. Element order +:: is preserved in both of the created lists. +:: Examples +:: > =a |=(a=@ (gth a 1)) +:: > (partition `(list @)`[0 1 2 3 ~] a) +:: [p=[i=2 t=~[3]] q=[i=0 t=~[1]]] +:: Source +++ partition skid +:: +permute: [(list T) projection:$-(@ @)] -> (list T) +:: +:: Returns a list with all elements permuted according to the permutation +:: specified by operating on the element indices. +:: Examples +:: > (permute (limo ~[1 2 3 4]) |=(i=@ (mod +(i) 4))) +:: ~[4 1 2 3] +:: Source +++ permute + |* [a=(list) q=$-(@ @)] + =/ b=(list [@ _?>(?=(^ a) i.a)]) ~ + =/ i 0 + |- + ?~ a +:(unzip (sort b aor)) + $(a t.a, b [[(q i) i.a] b], i +(i)) +:: +reduce: [(list T) reduction:$-([T T] T)] -> T +:: +:: Apply a function to each element of the list, threading an accumulator +:: argument through the computation. Apply the function to the first two +:: elements of the list. Then feed this result into the function along with the +:: third element and so on. Return the final result. If the input function is f +:: and the elements are i0...iN then computes f (... (f i0 i1) i2 ...) iN. +:: Examples +:: > %+ reduce +:: `(list tape)`~["urbit" "is" "fun"] +:: |=([a=tape b=tape] (welp (snoc a ' ') b)) +:: "urbit is fun" +:: Crash +:: 'empty list' +:: Source +++ reduce + |* [a=(list) q=$-([* *] *)] + ?~ a ~|('empty list' !!) + =/ b `_?>(?=(^ a) i.a)`i.a + =/ c t.a + |- + ?~ c b + $(b (q b i.c), c t.c) +:: +reduceBack: [(list T) reduction:$-([T T] T)] -> T +:: +:: Applies a function to each element of the list, starting from the end, +:: threading an accumulator argument through the computation. If the input +:: function is f and the elements are i0...iN then computes +:: f i0 (...(f iN-1 iN)). +:: Examples +:: > %+ reduce-back +:: `(list tape)`~["urbit" "is" "fun"] +:: |=([a=tape b=tape] (welp (snoc a ' ') b)) +:: "fun is urbit" +:: Crash +:: 'empty list' +:: Source +++ reduce-back + |* [a=(list) q=$-([* *] *)] + (reduce (flop a) q) +:: +remove-at: [(list T) index:@] -> (list T) +:: +:: Return a new list with the item at a given index removed. +:: Examples +:: > (remove-at "good day, urbit!" 8) +:: "good day urbit!" +:: > (remove-at `(list @)`[1 2 3 4 ~] 2) +:: ~[1 2 4] +:: Crash +:: 'out of range' +:: Source +++ remove-at + |* [a=(list) i=@] + ?: (gte i (lent a)) ~|('out of range' !!) + (oust [i 1] a) +:: +remove-many-at: [(list T) index=@ count=@] -> (list T) +:: +:: Return a new list with the number of items starting at a given index removed +:: Examples +:: > (remove-many-at "good day, urbit!" [4 5]) +:: "good urbit!" +:: > (remove-many-at `(list @)`[1 2 3 4 ~] [2 2]) +:: ~[1 2] +:: Crash +:: 'out of range' +:: Source +++ remove-many-at + |* [a=(list) i=@ c=@] + ?: (gth (add i c) (lent a)) ~|('out of range' !!) + (oust [i c] a) +:: +replicate: [count=@ initial=T] -> (list T) +:: +:: Creates a list by replicating the given initial value. +:: Examples +:: > (replicate 20 %a) +:: ~[%a %a %a %a %a %a %a %a %a %a %a %a %a %a %a %a %a %a %a %a] +:: > (replicate 5 ~s1) +:: ~[~s1 ~s1 ~s1 ~s1 ~s1] +:: > `@dr`(roll (replicate 5 ~s1) add) +:: ~s5 +:: Source +++ replicate reap +:: +reverse: (list T) -> (list T) +:: +:: Returns a new list with the elements in reverse order. +:: Examples +:: > =a [1 2 3 ~] +:: > (flop a) +:: ~[3 2 1] +:: > (flop (flop a)) +:: ~[1 2 3] +:: Source +++ reverse flop +:: +scanx: [(list T1) state:T2 folder:$-([T1 T2] T2)] -> (list T2) +:: +:: Applies a function to each element of the list and an accumulator, threading +:: the accumulator argument through the computation. Returns the list of +:: intermediate results and the final result. +:: Examples +:: > %: scanx +:: `(list tape)`~["urbit" "is" "fun"] +:: "" +:: |=([a=tape b=tape] (welp (snoc b ' ') a)) +:: == +:: ~["" " urbit" "urbit is" " urbit is fun"] +:: Source +++ scanx + |* [a=(list) state=* fun=$-([* *] *)] + =/ b=(list _state) ~ + |- ^- (list _?>(?=(^ a) i.a)) + ?~ a (flop [state b]) + $(a t.a, b [state b], state (fun i.a state)) +:: +scan-back: [(list T) state:T2 folder:$-(T1 T2)] -> (list T2) +:: +:: Like fold-back, but returns both the intermediary and final results +:: Examples +:: Source +++ scan-back + |* [a=(list) state=* fun=$-([* *] *)] + =/ c=(list _?>(?=(^ a) i.a)) (flop a) + =/ b=(list _state) ~ + |- ^- (list _?>(?=(^ a) i.a)) + ?~ c (flop [state b]) + $(c t.c, b [state b], state (fun i.c state)) +:: +singleton: value: T -> (list T) +:: +:: Returns a list that contains one item only. +:: Examples +:: > (singleton "tape") +:: ~["tape"] +:: Source +++ singleton + |* a=* + (limo ~[a]) +:: +skip-n: [(list T) count:@] -> (list T) +:: +:: Returns the list after removing the first N elements. +:: Examples +:: > (skip-n `(list @)`[1 2 3 4 ~] 2) +:: ~[3 4] +:: Crash +:: 'out of range' +:: Source +++ skip-n + |* [p=(list) q=@] + ?~ p ?~ q p ~|('out of range' !!) + ?~ q p + $(p t.p, q (dec q)) +:: +skip-while: [(list T) predicate:$-(T ?)] -> (list T) +:: +:: Bypasses elements in a list while the given predicate returns True, and then +:: returns the remaining elements of the list. +:: Examples +:: > %: skip-while +:: (limo ~["a" "bbb" "cc" "d"]) +:: |=(a=tape (lth (lent a) 3)) +:: == +:: ~["bbb" "cc" "d"] +:: Source +++ skip-while + |* [a=(list) b=$-(* ?)] + =/ c=(list _?>(?=(^ a) i.a)) ~ + |- ^+ a + ?~ a (flop c) + ?~ c ?: (b i.a) $(a t.a) $(a t.a, c [i.a c]) + $(a t.a, c [i.a c]) +:: +sort-by: [(list T) projection:$-(T *)] -> (list T) +:: +:: Sorts the given list using keys given by the given projection. Keys are +:: compared using Operators.compare. +:: Examples +:: > (sort-by (limo ~["bb" "a" "dddd" "ccc"]) |=(a=tape (lent a))) +:: ~["a" "bb" "ccc" "dddd"] +:: Source +++ sort-by + |* [a=(list) proj=$-(* *)] + =/ b (turn a proj) + =/ c (zip b a) + +:(unzip (sort c aor)) +:: +sort-by-descending: [(list T) projection:$-(T *)] -> (list T) +:: +:: Sorts the given list in descending order using keys given by the given +:: projection. Keys are compared using Operators.compare. +:: Examples +:: > %: sort-by-descending +:: (limo ~["bb" "a" "dddd" "ccc"]) |=(a=tape (lent a)) +:: == +:: ~["dddd" "ccc" "bb" "a"] +:: Source +++ sort-by-descending + |* [a=(list) proj=$-(* *)] + =/ b (turn a proj) + =/ c (zip b a) + +:(unzip (sort c |=([a=* b=*] (aor b a)))) +:: +sort-descending: (list T) -> (list T) +:: +:: Sorts the given list in descending order using Operators.compare. +:: Examples +:: > (sort-descending (limo ~[4 2 1 3])) +:: ~[4 3 2 1] +:: Source +++ sort-descending + |* a=(list) + (sort a |=([a=* b=*] (aor b a))) +:: +sort-qik: (list T) -> (list T) +:: +:: Sorts the given list in ascending order using Operators.compare. +:: Examples +:: > (sort-qik (limo ~[4 2 1 3])) +:: ~[1 2 3 4] +:: Source +++ sort-qik + |* a=(list) + (sort a aor) +:: +split-at: [(list T) index:@] -> [(list T) (list T)] +:: +:: Splits a list into two lists, at the given index. +:: Examples +:: > (split-at (limo ~[1 2 3 4 5]) 2) +:: [~[1 2] ~[3 4 5]] +:: Source +++ split-at + |* [p=(list) i=@] + [(scag i p) (slag i p)] +:: +split-into: [(list T) count:@] -> (list (list T)) +:: +:: Splits the input list into at most count chunks. +:: Examples +:: > (split-into (gulf 1 10) 4) +:: Crash +:: 'count is 0' +:: Source +++ split-into + |* [a=(list) i=@] + ?~ i ~|('count is 0' !!) + =/ b=(list (list _?>(?=(^ a) i.a))) ~ + |- + ?: =(0 (lent a)) (flop b) + =/ q (div (lent a) i) + =/ r (mod (lent a) i) + =/ l ?: =(0 r) q +(q) + =/ c=(list _?>(?=(^ a) i.a)) ~ + |- + ?~ l ^$(b [(flop c) b], i (dec i)) + ?~ a ?~ c (flop b) (flop [(flop c) b]) + $(c [i.a c], l (dec l), a t.a) +:: +sum: (list @) -> @ +:: +:: Returns the sum of the elements in the list. +:: Examples +:: > (sum (limo ~[1 2 3])) +:: 6 +:: Source +++ sum + |* a=(list @) + =/ b=@ 0 + |- + ?~ a b + $(a t.a, b (add b i.a)) +:: +sum-by: [(list T) projection:$-(T @)] -> @ +:: +:: Returns the sum of the results generated by applying the function to each +:: element of the list. +:: Examples +:: > (sum-by (limo ~["a" "bb" "ccc"]) |=(a=tape (lent a))) +:: 6 +:: Source +++ sum-by + |* [a=(list) proj=$-(* @)] + =/ b=@ 0 + |- + ?~ a b + $(a t.a, b (add b (proj i.a))) +:: +tail-end: (list T) -> T +:: +:: Returns the last element of the list. +:: Crash when the input does not have any elements. +:: Examples +:: > (last ~[1 2 3]) +:: 3 +:: Crash +:: 'empty list' +:: Source +++ tail-end + |* a=(list) + ?~ a ~|('empty list' !!) + (rear a) +:: +take-while: [(list T) predicate:$-(T ?)] -> (list T) +:: +:: Returns a list that contains all elements of the original list while the +:: given predicate returns True, and then returns no further elements. +:: Examples +:: > %: take-while +:: (limo ~["a" "bb" "ccc" "d"]) +:: |=(a=tape (lth (lent a) 3)) +:: == +:: ~["a" "bb"] +:: Source +++ take-while + |* [a=(list) b=$-(* ?)] + =/ c=(list _?>(?=(^ a) i.a)) ~ + |- ^+ a + ?~ a (flop c) + ?: (b i.a) $(a t.a, c [i.a c]) + (flop c) +:: +to-map: (list [* *]) -> +:: +:: Produces a map from a list. +:: Examples +:: > (to-map (limo ~[['aa' 1] ['bb' 2] ['cc' 3] ['dd' 4]])) +:: [n=[p='dd' q=4] l=[n=[p='cc' q=3] l=[n=[p='aa' q=1] l=~ r=~] r=~] +:: r=[n=[p='bb' q=2] l=~ r=~]] +:: Source +++ to-map + |* a=(list) + (malt a) +:: +to-set: (list) -> +:: +:: Produces a set from a list. +:: Examples +:: > (to-map (limo ~[['aa' 1] ['bb' 2] ['cc' 3] ['dd' 4]])) +:: [n=['dd' 4] l=[n=['cc' 3] l=[n=['aa' 1] ~ ~] ~] r=[n=['bb' 2] ~ ~]] +:: Source +++ to-set + |* a=(list) + (silt a) +:: +transpose: (list (list T)) -> ?([~ ~] (list (list T))) +:: +:: Returns the transpose of the given sequence of lists. +:: Returns [~ ~] when all lists of list are ~. +:: Examples +:: > %- transpose +:: %: limo +:: (limo ~["a" "b" "c"]) +:: (limo ~["aa" "bb" "cc"]) +:: (limo ~["aaa" "bbb" "ccc"]) +:: ~ +:: == +:: ~[~["a" "aa" "aaa"] ~["b" "bb" "bbb"] ~["c" "cc" "ccc"]] +:: Crash +:: 'lists of unequal length' +:: Source +++ transpose + |* a=(list (list)) + =/ aa a + =/ equal=? %.y + ~| 'lists of unequal length' + |- ^- (list (list _?>(?=(^ ^ a) -.-.a))) + ?: =(%.n equal) !! + ?~ aa (transpose-jgd a) + ?~ t.aa (transpose-jgd a) + ?: =((lent i.aa) (lent i.t.aa)) $(aa t.aa) $(equal %.n) +:: +transpose-jgd: (list (list T)) -> ?([~ ~] (list (list T))) +:: +:: Returns the jagged transpose of the given sequence of lists. +:: Returns [~ ~] when all lists of list are ~. +:: Examples +:: > %- transpose-jgd +:: %: limo +:: (limo ~["a" "b" "c"]) +:: (limo ~["aa" "cc"]) +:: (limo ~["aaa" "bbb" "ccc"]) +:: ~ +:: == +:: ~[~["a" "aa" "aaa"] ~["b" "cc" "bbb"] ~["c" "ccc"]] +:: Source +++ transpose-jgd + |* a=(list (list)) + =/ aa=(list (list _?>(?=(^ ^ a) -.-.a))) a + =/ b=(list (list _?>(?=(^ ^ a) -.-.a))) ~ + =/ bb=(list _?>(?=(^ ^ a) -.-.a)) ~ + |- ^- (list (list _?>(?=(^ ^ a) -.-.a))) + ?~ a (flop b) + =/ c=(list (list _?>(?=(^ ^ a) -.-.a))) ~ + |- + ?~ aa + %= ^$ + a (flop c) + aa (flop c) + b [(flop bb) b] + bb ~ + == + ?~ -.aa $(aa t.aa) + ?~ ->.aa $(aa t.aa, bb [-<.aa bb]) + $(aa t.aa, bb [-<.aa bb], c [->.aa c]) +:: +try-exactly-one: (list T) -> (unit T) +:: +:: Returns the only element of the list or None if it is empty or contains more +:: than one element. +:: Examples +:: > (try-exactly-one (limo ~["tape"])) +:: [~ i=[i=t' t="ape"]] +:: Source +++ try-exactly-one + |* a=(list) + ?: =(1 (lent a)) `-.a + ~ +:: +try-find: [(list T) predicate:$-(T ?)] -> (unit T) +:: +:: Returns the first element for which the given function returns True. +:: Return None if no such element exists. +:: Examples +:: > (try-find (gulf [1 30]) |=(a=@ud ?&(=(0 (mod a 3)) =(0 (mod a 5))))) +:: `15 +:: Source +++ try-find + |* [a=(list) b=$-(* ?)] + |- ^- (unit _?>(?=(^ a) i.a)) + ?~ a ~ + ?: (b i.a) `i.a $(a t.a) +:: +try-find-back: [(list T) predicate:$-(T ?)] -> (unit T) +:: +:: Returns the last element for which the given function returns True. +:: Return None if no such element exists. +:: Examples +:: > %: try-find-back +:: (gulf [1 30]) +:: |=(a=@ud ?&(=(0 (mod a 3)) =(0 (mod a 5)))) +:: == +:: `30 +:: Source +++ try-find-back + |* [a=(list) b=$-(* ?)] + ?~ a ~ + (try-find (flop a) b) +:: +try-find-by-unit: [(list T) chooser:$-(T (unit T))] -> (unit T) +:: +:: Applies the given function to successive elements, returning Some(x) for the +:: first result where function returns Some(x). +:: If no such element exists then return None. +:: Examples +:: > (search-by-unit (limo ~[1 2 3 4]) |=(a=@ ?:(=((mod a 2) 0) `a ~))) +:: `2 +:: Crash +:: 'not found' +:: Source +++ try-find-by-unit + |* [hstk=(list) nedl=$-(* (unit *))] + |- ^- (unit _?>(?=(^ hstk) i.hstk)) + ?~ hstk ~ + =/ x (nedl i.hstk) + ?~ x $(hstk t.hstk) x +:: +try-find-index: [(list T) predicate:$-(T ?)] -> (unit @) +:: +:: Returns the index of the first element in the list that satisfies the given +:: predicate. Return None if no such element exists. +:: Examples +:: > %: try-find-index +:: (gulf [1 30]) +:: |=(a=@ud ?&(=(0 (mod a 3)) =(0 (mod a 5)))) +:: == +:: `14 +:: Source +++ try-find-index + |* [a=(list) b=$-(* ?)] + =/ i 0 + |- ^- (unit @) + ?~ a ~ + ?: (b i.a) `i $(a t.a, i +(i)) +:: +try-find-index-back: [(list T) predicate:$-(T ?)] -> (unit @) +:: +:: Returns the index of the last element in the list that satisfies the given +:: predicate. Return None if no such element exists. +:: Examples +:: > %: try-find-index-back +:: (gulf [1 30]) +:: |=(a=@ud ?&(=(0 (mod a 3)) =(0 (mod a 5)))) +:: == +:: `29 +:: Source +++ try-find-index-back + |* [a=(list) c=$-(* ?)] + ?~ a ~ + =/ b (flop a) + =/ i (dec (lent a)) + |- ^- (unit @ud) + ?~ b ~ + ?: (c i.b) `i + ?: =(0 i) ~ + $(b t.b, i (dec i)) +:: +try-head: (list T) -> (unit T) +:: +:: Returns the first element of the list, or None if the list is empty. +:: Examples +:: > (try-head ~[1 2]) +:: `1 +:: Source +++ try-head + |* a=(list) + ?~ a ~ + `i.a +:: +try-item: [(list T) index:@] -> (unit T) +:: +:: Tries to find the nth element in the list. Returns None if index is negative +:: or the list does not contain enough elements. +:: Examples +:: > (try-item `(list @)`~["aa" "bb" "cc" "dd"] 2) +:: [~ "cc"] +:: > (try-item `(list tape)`~["aa" "bb"] 2) +:: ~ +:: Source +++ try-item + |* [a=(list) i=@] + ?: (gte i (lent a)) ~ + `(snag i a) +:: +try-remove-at: [(list T) index:@] -> (unit (list T)) +:: +:: Attempt a new list with the item at a given index removed returning +:: Some((list T)) upon success. +:: Examples +:: > (try-remove-at "good day, urbit!" 8) +:: [~ "good day urbit!"] +:: > (try-remove-at `(list @)`[1 2 3 4 ~] 2) +:: [~ ~[1 2 4]] +:: Source +++ try-remove-at + |* [a=(list) i=@] + ?: (gte i (lent a)) ~ + `(oust [i 1] a) +:: +try-remove-many-at: [(list T) index=@ count=@] -> (list T) +:: +:: Return a new list with the number of items starting at a given index removed +:: returning Some((list T)) upon success. +:: Examples +:: > (try-remove-many-at "good day, urbit!" [4 5]) +:: [~ "good urbit!"] +:: > (try-remove-many-at `(list @)`[1 2 3 4 ~] [2 2]) +:: [~ ~[1 2]] +:: Source +++ try-remove-many-at + |* [a=(list) i=@ c=@] + ?: (gth (add i c) (lent a)) ~ + `(oust [i c] a) +:: +try-tail: (list T) -> (unit (list T)) +:: +:: Returns the elements of the list after the first. +:: Examples +:: > (try-tail ~[1 2]) +:: `~[2] +:: Source +++ try-tail + |* a=(list) + ?~ a ~ + `t.a +:: +try-tail-end: (list T) -> (unit T) +:: +:: Returns the last element of the list. Return None if no such element exists. +:: Examples +:: > (try-tail-end ~[1 2 3]) +:: `3 +:: Source +++ try-tail-end + |* a=(list) + ?~ a ~ + `(rear a) +:: +try-update-at: [(list T) index:@ value:T] -> (list T) +:: +:: Return a new list with the item at a given index set to the new value. +:: Examples +:: > (try-update-at (limo ~[2 3 4]) 1 11) +:: [~ ~[2 11 4]] +:: > (try-update-at (limo ~[2 3 4]) 3 11) +:: ~ +:: Crash +:: 'not found' +:: Source +++ try-update-at + |* [a=(list) b=@ c=*] + ?: (gte b (lent a)) ~ + `(snap a b c) +:: +unfold: [state:T1 generator:$-(T1 -> (unit [T1 T2]))] -> (list T2) +:: +:: Returns a list that contains the elements generated by the given computation +:: The generator is repeatedly called to build the list until it returns None. +:: The given initial state argument is passed to the element generator. +:: Examples +:: > (unfold 1 |=(a=@ ?:((gth a 100) ~ `[(mul a 2) a]))) +:: ~[1 2 4 8 16 32 64] +:: Source +++ unfold + |* [state=* gen=$-(* (unit [* *]))] + =/ res=(list) ~ + |- + =/ x (gen state) + ?~ x (flop res) + =/ y (need x) + $(state -.y, res [+.y res]) +:: +unzip: (list [T1 T2]) - [(list T1) (list T2)] +:: +:: Splits a list of pairs into two lists. +:: Examples +:: > (unzip (limo ~[[1 "aa"] [2 "bb"]])) +:: [~[1 2] ~["aa" "bb"]] +:: Source +++ unzip + |* a=(list [* *]) + =/ b=(list *) ~ + =/ c=(list *) ~ + |- + ?~ a [(flop b) (flop c)] + $(a t.a, b [-.i.a b], c [+.i.a c]) +:: +unzip3: (list [T1 T2 T3]) - [(list T1) (list T2) (list T3)] +:: +:: Splits a list of triples into three lists. +:: Examples +:: > (unzip3 (limo ~[[1 "aa" 'a'] [2 "bb" 'b']])) +:: [~[1 2] ~["aa" "bb"] ~['a' 'b']] +:: Source +++ unzip3 + |* a=(list [* *]) + =/ b=(list *) ~ + =/ c=(list *) ~ + =/ d=(list *) ~ + |- + ?~ a [(flop b) (flop c) (flop d)] + $(a t.a, b [-.i.a b], c [+<.i.a c], d [+>.i.a d]) +:: +update-at: [(list T) index:@ value:T] -> (list T) +:: +:: Return a new list with the item at a given index set to the new value. +:: Examples +:: > (update-at (limo ~[2 3 4]) 1 11) +:: ~[2 11 4] +:: Crash +:: 'not found' +:: Source +++ update-at + |* [a=(list) b=@ c=*] + ?: (gte b (lent a)) ~|('not found' !!) + (snap a b c) +:: +windowed: [(list T) window-size:@] -> (list (list T)) +:: +:: Returns a list of sliding windows containing elements drawn from the input +:: list. Each window is returned as a fresh list. +:: Examples +:: > (windowed (limo ~[1 2 3 4 5]) 3) +:: ~[~[1 2 3] ~[2 3 4] ~[3 4 5]] +:: Crash +:: 'empty list' +:: 'window length is 0' +:: 'list shorter than window' +:: Source +++ windowed + |* [p=(list *) q=@] + ?~ q ~|('window length is 0' !!) + =/ b=(list (list _?>(?=(^ p) i.p))) ~ + =/ sub-tree=(list _?>(?=(^ p) i.p)) ~ + =/ pp=(list _?>(?=(^ p) i.p)) p + |- ^- (list (list _?>(?=(^ p) i.p))) + ?~ p ~|('empty list' !!) + ?~ pp ?: (lth (lent sub-tree) q) + ?~ b ~|('list shorter than window' !!) (flop b) + $(pp t.p, b [(flop sub-tree) b], sub-tree ~) + ?: =((lent sub-tree) q) + $(p t.p, pp t.p, b [(flop sub-tree) b], sub-tree ~) + $(pp t.pp, sub-tree [i.pp sub-tree]) +:: +zip: [(list T1) (list T2)] -> (list [T1 T2]) +:: +:: Combines the two lists into a list of pairs. The two lists must have equal +:: lengths. +:: Examples +:: > (zip `(list @)`~[1 2] `(list @)`~["aa" "bb"]) +:: ~[[1 "aa"] [2 "bb"]] +:: Crash +:: 'lists of unequal length' +:: Source +++ zip + |* [a=(list) b=(list)] + =/ c=(list [_?>(?=(^ a) i.a) _?>(?=(^ b) i.b)]) ~ + |- ^- (list [_?>(?=(^ a) i.a) _?>(?=(^ b) i.b)]) + ?~ a ?~ b (flop c) ~|('lists of unequal length' !!) + ?~ b ~|('lists of unequal length' !!) + $(a t.a, b t.b, c [[i.a i.b] c]) +:: +zip3: [(list T1) (list T2) (list T3)] -> (list [T1 T2 T3]) +:: +:: Combines the three lists into a list of triples. The lists must have equal +:: lengths. +:: Examples +:: > %: zip3 +:: `(list @)`~[1 2] +:: `(list tape)`~["aa" "bb"] +:: `(list @t)`~['a' 'b'] +:: == +:: ~[[1 "aa" 'a'] [2 "bb" 'b']] +:: Crash +:: 'lists of unequal length' +:: Source +++ zip3 + |* [a=(list) b=(list) c=(list)] + =/ d=(list [_?>(?=(^ a) i.a) _?>(?=(^ b) i.b) _?>(?=(^ c) i.c)]) ~ + |- ^- (list [_?>(?=(^ a) i.a) _?>(?=(^ b) i.b) _?>(?=(^ c) i.c)]) + ?~ a ?~ b ?~ c (flop d) + ~|('lists of unequal length' !!) + ~|('lists of unequal length' !!) + ?~ b ~|('lists of unequal length' !!) + ?~ c ~|('lists of unequal length' !!) + $(a t.a, b t.b, c t.c, d [[i.a i.b i.c] d]) +--
\ No newline at end of file diff --git a/desk/lib/server.hoon b/desk/lib/server.hoon new file mode 100644 index 0000000..3ae3a0f --- /dev/null +++ b/desk/lib/server.hoon @@ -0,0 +1,174 @@ +=, eyre +|% ++$ request-line + $: [ext=(unit @ta) site=(list @t)] + args=(list [key=@t value=@t]) + == +:: +parse-request-line: take a cord and parse out a url +:: +++ parse-request-line + |= url=@t + ^- request-line + (fall (rush url ;~(plug apat:de-purl:html yque:de-purl:html)) [[~ ~] ~]) +:: +++ manx-to-octs + |= man=manx + ^- octs + (as-octt:mimes:html (en-xml:html man)) +:: +++ json-to-octs + |= jon=json + ^- octs + (as-octs:mimes:html (en:json:html jon)) +:: +++ app + |% + :: + :: +require-authorization: + :: redirect to the login page when unauthenticated + :: otherwise call handler on inbound request + :: + ++ require-authorization + |= $: =inbound-request:eyre + handler=$-(inbound-request:eyre simple-payload:http) + == + ^- simple-payload:http + :: + ?: authenticated.inbound-request + ~! this + ~! +:*handler + (handler inbound-request) + :: + =- [[307 ['location' -]~] ~] + %^ cat 3 + '/~/login?redirect=' + url.request.inbound-request + :: + :: +require-authorization-simple: + :: redirect to the login page when unauthenticated + :: otherwise pass through simple-paylod + :: + ++ require-authorization-simple + |= [=inbound-request:eyre =simple-payload:http] + ^- simple-payload:http + :: + ?: authenticated.inbound-request + ~! this + simple-payload + :: + =- [[307 ['location' -]~] ~] + %^ cat 3 + '/~/login?redirect=' + url.request.inbound-request + :: + ++ give-simple-payload + |= [eyre-id=@ta =simple-payload:http] + ^- (list card:agent:gall) + =/ header-cage + [%http-response-header !>(response-header.simple-payload)] + =/ data-cage + [%http-response-data !>(data.simple-payload)] + :~ [%give %fact ~[/http-response/[eyre-id]] header-cage] + [%give %fact ~[/http-response/[eyre-id]] data-cage] + [%give %kick ~[/http-response/[eyre-id]] ~] + == + -- +++ core + |% + ++ gate + =| opt=@ + |= a=@ opt + :: ++ try gate(opt 5) + ++ try2 + =/ g gate + g(opt 5) + -- +++ gen + |% + :: + ++ max-1-da ['cache-control' 'max-age=86400'] + :: ++ max-1-wk ['cache-control' 'max-age=604800'] + ++ max-1-wk ['cache-control' 'no-cache, no-store, must-revalidate'] + ++ no-cache ['cache-control' 'no-cache, no-store, must-revalidate'] + :: + ++ lol + =| lmao=? + |= a=* %lol + ++ html-response + =| cache=? + |= =octs + ^- simple-payload:http + :_ `octs + [200 [['content-type' 'text/html'] ?:(cache [max-1-wk ~] ~)]] + :: + ++ css-response + =| cache=? + |= =octs + ^- simple-payload:http + :_ `octs + [200 [['content-type' 'text/css'] ?:(cache [max-1-wk ~] ~)]] + :: + ++ js-response + =| cache=? + |= =octs + ^- simple-payload:http + :_ `octs + [200 [['content-type' 'text/javascript'] ?:(cache [max-1-wk ~] ~)]] + :: + ++ png-response + =| cache=? + |= =octs + ^- simple-payload:http + :_ `octs + [200 [['content-type' 'image/png'] ?:(cache [max-1-wk ~] ~)]] + :: + ++ svg-response + =| cache=? + |= =octs + ^- simple-payload:http + :_ `octs + [200 [['content-type' 'image/svg+xml'] ?:(cache [max-1-wk ~] ~)]] + :: + ++ ico-response + |= =octs + ^- simple-payload:http + [[200 [['content-type' 'image/x-icon'] max-1-wk ~]] `octs] + :: + ++ woff2-response + =| cache=? + |= =octs + ^- simple-payload:http + [[200 [['content-type' 'font/woff2'] max-1-wk ~]] `octs] + :: + ++ json-response + =| cache=_| + |= =json + ^- simple-payload:http + :_ `(json-to-octs json) + [200 [['content-type' 'application/json'] ?:(cache [max-1-da ~] ~)]] + :: + ++ manx-response + =| cache=_| + |= man=manx + ^- simple-payload:http + :_ `(manx-to-octs man) + [200 [['content-type' 'text/html'] ?:(cache [max-1-da ~] ~)]] + :: + ++ not-found + ^- simple-payload:http + [[404 ~] ~] + :: + ++ login-redirect + |= =request:http + ^- simple-payload:http + =- [[307 ['location' -]~] ~] + %^ cat 3 + '/~/login?redirect=' + url.request + :: + ++ redirect + |= redirect=cord + ^- simple-payload:http + [[307 ['location' redirect]~] ~] + -- +-- diff --git a/desk/lib/sigil/sigil.hoon b/desk/lib/sigil/sigil.hoon new file mode 100644 index 0000000..bde3889 --- /dev/null +++ b/desk/lib/sigil/sigil.hoon @@ -0,0 +1,227 @@ +:: sigil: @p svg generation +:: +:: usage: do a named import, then invoke as a function: +:: (sigil ~zod) +:: +:: optionally modify configuration parameters: +:: %. ~paldev +:: %_ sigil +:: size 25 +:: fg "black" +:: bg "#2aa779" +:: margin | +:: icon & +:: == +:: +::NOTE svg construction logic is coupled to the symbols definitions. +:: the symbols' elements assume they live in a space of 128x128. +:: what we do here is assume an svg _canvas_ of 128x128, draw the +:: symbols at their original sizes, and then scale them down to fit. +:: +/+ sigil-symbols +:: +:: config +:: +=/ fg=tape "white" +=/ bg=tape "black" +=/ size=@ud 128 +=/ margin=? & +=/ icon=? | +:: +:: +~% %sigil ..part ~ +=/ who=ship ~zod +=/ syc=@ud 1 +|^ |= =ship + ^- manx + :: + =. who ship + =/ syz (simp who) + =. syc (lent syz) + :: shift the sigil to account for the margin + :: scale the sigil to account for the amount of symbols + :: + =/ sire=@rd (sun:rd size) + =/ tr=tape + ::TODO render transform inside +sigil:svg? + %+ transform:svg + ?. margin ~ + =+ grid:pos + `[(gird:pos x) (gird:pos y)] + `span:pos + :: + =/ sw=@rd ::TODO + ?: icon .~0.8 ::TODO scale with size? + (add:rd .~0.33 (div:rd sire .~128)) + :: + %- outer:svg + %+ sigil:svg + [tr sw] + (symbols:svg syz) +:: +++ pos + |% + ++ span :: symbol scale (relative to full canvas) + ^- @rd + ::TODO accounting for margin here feels a bit ugly? + ?+ (max grid) !! + %1 ?:(margin .~0.4 .~1) + %2 ?:(margin .~0.4 .~0.5) + %4 ?:(margin .~0.2 .~0.25) + == + :: + ++ grid :: size in symbols + ^- [x=@ud y=@ud] + ?+ syc !! + %16 [4 4] + %8 [4 4] + %4 [2 2] + %2 [2 1] + %1 [1 1] + == + :: + ++ gird :: calculate margin + |= n=@ud + ^- @rd + =- (div:rd - .~2) :: / both sides + %+ sub:rd .~128 :: canvas size - + %+ mul:rd (sun:rd n) :: symbols * + %+ mul:rd span:pos :: symbol scale * + .~128 :: symbol size + :: + ++ plan :: as position on symbol grid + |= i=@ud + ^- [x=@ud y=@ud] + ?+ [syc i] !! + [%16 *] [(mod i 4) (div i 4)] + :: + [%8 %0] [0 0] + [%8 %1] [3 0] + [%8 %2] [0 3] + [%8 %3] [3 3] + [%8 %4] [1 1] + [%8 %5] [2 1] + [%8 %6] [1 2] + [%8 %7] [2 2] + :: + [%4 *] [(mod i 2) (div i 2)] + [%2 *] [i 0] + [%1 *] [0 0] + == + -- +:: +++ svg + |% + ++ outer + |= inner=manx + ^- manx + =/ s=tape ((d-co:co 1) size) + ;svg + =style "display: block; width: {s}px; height: {s}px;" :: prevent bottom margin on svg tag + =width s + =height s + =viewBox "0 0 128 128" + =version "1.1" + =xmlns "http://www.w3.org/2000/svg" + ::TODO additional attributes from config arg? + ;rect + =fill bg + =width "128" + =height "128"; + ;+ inner + == + :: + ::TODO should it be possible to get these svg elements out of this lib? + ++ sigil + |= [[tr=tape sw=@rd] symbols=(list manx)] + ^- manx + ;g + =transform tr + =stroke-width (say-rd sw) + =stroke-linecap "square" + =fill fg + =stroke bg + ::NOTE unfortunately, vector-effect cannot be inherited, + :: so it gets inlined in the symbol elements instead + :: =vector-effect "non-scaling-stroke" + ;* symbols + == + :: + ++ symbols + |= noms=(list @t) + ^- (list manx) + =| i=@ud + =/ l=@ud (lent noms) + |- + ?~ noms ~ + :_ $(noms t.noms, i +(i)) + ::TODO exclude if both 0 + =+ (plan:pos i) + ;g(transform (transform `[(sun:rd (mul x 128)) (sun:rd (mul y 128))] ~)) + ;* =+ ((symbol i.noms) fg bg) + ?.(icon - (scag 1 -)) + == + :: + ++ symbol ~(got by sigil-symbols) + :: + ++ transform ::TODO take manx instead so we can omit attr entirely? + |= [translate=(unit [x=@rd y=@rd]) scale=(unit @rd)] + ^- tape + %- zing + ^- (list tape) + ::TODO make cleaner + =- ?: ?=(?(~ [* ~]) -) - + (join " " `(list tape)`-) + ^- (list tape) + :~ ?~ translate ~ + ?: =([0 0] u.translate) ~ + "translate({(say-rd x.u.translate)} {(say-rd y.u.translate)})" + :: + ?~ scale ~ + "scale({(say-rd u.scale)})" + == + -- +:: +++ simp + |= =ship + ^- (list @t) + :: split into phonemes + :: + =/ noms=(list @t) + =/ nom=@t + (rsh 3 (scot %p ship)) + |- ?~ nom ~ + |- ?: =('-' (end 3 nom)) + $(nom (rsh 3 nom)) + :- (end 3^3 nom) + ^$(nom (rsh 3^3 nom)) + :: fill leading empties with 'zod' + :: + =/ left=@ud + =- (sub - (lent noms)) + %- bex + ?- (clan:title ship) + %czar 0 + %king 1 + %duke 2 + %earl 3 + %pawn 4 + == + |- + ?: =(0 left) noms + $(noms ['zod' noms], left (dec left)) +:: +++ rd ~(. ^rd %n) +++ say-rd + |= n=@rd + ^- tape + =/ =dn (drg:rd n) + ?> ?=(%d -.dn) + =/ [s=? m=@ud] (old:si e.dn) + =/ x=@ud (pow 10 m) + %+ weld + %- (d-co:co 1) + ?:(s (mul a.dn x) (div a.dn x)) + ?: s ~ + ['.' ((d-co:co m) (mod a.dn x))] +-- diff --git a/desk/lib/sigil/symbols.hoon b/desk/lib/sigil/symbols.hoon new file mode 100644 index 0000000..1131612 --- /dev/null +++ b/desk/lib/sigil/symbols.hoon @@ -0,0 +1,14332 @@ +:: sigil-symbols: svg symbols for phonemes, for use in /lib/sigil +:: +:: the map is keyed by phoneme cords and contains functions for +:: generating lists of manxes based on fore- and background colors, +:: intended to be wrapped up in an svg <g> for further processing. +:: +:: shapes and default attributes sourced from: +:: https://github.com/urbit/sigil-js/blob/fdea06f/src/index.json +:: +::NOTE to reduce svg size, we exclude certain common/shared attributes. +:: we expect the /lib/sigil to wrap these elements in a <g> which sets +:: those attributes, letting them be inherited. they are as follows: +:: =fill fg +:: =stroke bg +:: =stroke-linecap "square" +:: =stroke-width +:: we assume the defaults specified above, and only include those +:: attributes below if they deviate from those. (this includes adding +:: stroke="none" for elements whose original specification did not +:: include a stroke.) +:: unfortunately, the vector-effect attribute cannot be inherted by <g> +:: children, so we have to inline it for every element here. +:: for ease of change, we leave excluded attributes as comments here. +:: +^~ +%- ~(gas by *(map cord $-([fg=tape bg=tape] (list manx)))) +:~ + :- 'bac' + |= [fg=tape bg=tape] + :~ ;path + =d "M0 0C0 70.6925 57.3075 128 128 128V0H0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;line + =x1 "-0.0029152" + =x2 "127.983" + =y2 "127.986" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + ;circle + =cx "64" + =cy "64" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "64" + =cy "64" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + ;circle + =cx "16" + =cy "112" + =r "11.5" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + ;circle + =cx "16" + =cy "112" + =r "9" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + :: =stroke-width "2" + == +:: + :- 'bal' + |= [fg=tape bg=tape] + :~ ;path + =d "M0.0541 0C70.7217 0.0292317 128 57.3256 128 128C57.3177 128 0.0164917 70.7089 7.62806e-06 0.0305091C7.62851e-06 0.0203397 -4.44317e-10 0.01017 0 0H0.0541Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;circle + =cx "32" + =cy "32" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "32" + =cy "32" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + ;line + =x1 "0.5" + =y1 "-0.5" + =x2 "181.5" + =y2 "-0.5" + =transform "matrix(-0.707107 0.707107 0.707107 0.707107 128.71 0)" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + ;line + =x1 "128" + =y1 "32.0072" + =x2 "32.7071" + =y2 "127.3" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + ;line + =x1 "128" + =y1 "64.0072" + =x2 "64.7071" + =y2 "127.3" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + ;line + =x1 "128" + =y1 "96.0072" + =x2 "96.7071" + =y2 "127.3" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + == +:: + :- 'ban' + |= [fg=tape bg=tape] + :~ ;path + =d "M0 0C0 70.6925 57.3075 128 128 128V0H0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M128 0C128 70.6924 70.6924 128 -1.52588e-05 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'bar' + |= [fg=tape bg=tape] + :~ ;circle + =cx "64" + =cy "64" + =r "64" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M-0.00292969 0L127.997 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + ;circle + =cx "64" + =cy "64" + =r "16" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;circle + =cx "32" + =cy "32" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "32" + =cy "32" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'bat' + |= [fg=tape bg=tape] + :~ ;path + =d "M0 0C0 70.6925 57.3075 128 128 128V0H0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M128 0C128 35.3462 99.3462 64 64 64C28.6538 64 0 35.3462 0 0" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'bec' + |= [fg=tape bg=tape] + :~ ;path + =d "M128 128C128 57.3076 70.6925 6.18013e-06 1.11901e-05 0L0 128L128 128Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M-0.00280762 0L127.997 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + ;path + =fill-rule "evenodd" + =clip-rule "evenodd" + =stroke "none" + =d "M80 64C80 72.8366 72.8366 80 64 80C55.1634 80 48 72.8366 48 64C48 55.1634 55.1634 48 64 48C72.8366 48 80 55.1634 80 64ZM64 72C68.4183 72 72 68.4183 72 64C72 59.5817 68.4183 56 64 56C59.5817 56 56 59.5817 56 64C56 68.4183 59.5817 72 64 72Z" + =fill bg; + == +:: + :- 'bel' + |= [fg=tape bg=tape] + :~ ;path + =d "M0 127.946C0.0292286 57.2783 57.3256 3.08928e-06 128 0C128 70.6823 70.7089 127.984 0.0305092 128C0.0203397 128 0.01017 128 2.36469e-09 128L0 127.946Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;circle + =cx "64" + =cy "64" + =r "32" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'ben' + |= [fg=tape bg=tape] + :~ ;rect + =width "128" + =height "128" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;circle + =cx "64" + =cy "64" + =r "8" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;circle + =cx "32" + =cy "64" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "32" + =cy "64" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'bep' + |= [fg=tape bg=tape] + :~ ;path + =d "M128 0C57.3075 8.42999e-07 -8.42999e-07 57.3075 0 128H128V0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M128 64C92.6538 64 64 92.6538 64 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'ber' + |= [fg=tape bg=tape] + :~ ;path + =d "M64 128H0L5.59506e-06 0L64 5.59506e-06C99.3462 8.68512e-06 128 28.6538 128 64C128 99.3462 99.3462 128 64 128Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M96 0L96 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'bes' + |= [fg=tape bg=tape] + :~ ;path + =d "M128 128C128 57.3076 70.6925 6.18013e-06 1.11901e-05 0L0 128L128 128Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M64 128C64 92.6538 35.3462 64 0 64" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M-0.00280762 0L127.997 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + == +:: + :- 'bet' + |= [fg=tape bg=tape] + :~ ;circle + =cx "64" + =cy "64" + =r "64" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;line + =x1 "16.0036" + =y1 "15.9965" + =x2 "48.0036" + =y2 "47.9965" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'bex' + |= [fg=tape bg=tape] + :~ ;path + =d "M64 128H0L5.59506e-06 0L64 5.59506e-06C99.3462 8.68512e-06 128 28.6538 128 64C128 99.3462 99.3462 128 64 128Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;line + =x1 "16.0036" + =y1 "15.9965" + =x2 "48.0036" + =y2 "47.9965" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =fill-rule "evenodd" + =clip-rule "evenodd" + =stroke "none" + =d "M80 64C80 72.8366 72.8366 80 64 80C55.1634 80 48 72.8366 48 64C48 55.1634 55.1634 48 64 48C72.8366 48 80 55.1634 80 64ZM64 72C68.4183 72 72 68.4183 72 64C72 59.5817 68.4183 56 64 56C59.5817 56 56 59.5817 56 64C56 68.4183 59.5817 72 64 72Z" + =fill bg; + == +:: + :- 'bic' + |= [fg=tape bg=tape] + :~ ;path + =d "M0 0C0 70.6925 57.3075 128 128 128V0H0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M128 96C74.9807 96 32 53.0193 32 -4.19629e-06" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'bid' + |= [fg=tape bg=tape] + :~ ;path + =d "M0 0C0 70.6925 57.3075 128 128 128V0H0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M32 0C32 70.6925 74.9807 128 128 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M128 64L0 64" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'bil' + |= [fg=tape bg=tape] + :~ ;path + =d "M64 0H128V128H64C28.6538 128 0 99.3462 0 64C0 28.6538 28.6538 0 64 0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;line + =x1 "80.0035" + =y1 "79.9965" + =x2 "112.004" + =y2 "111.997" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =fill-rule "evenodd" + =clip-rule "evenodd" + =stroke "none" + =d "M80 64C80 72.8366 72.8366 80 64 80C55.1634 80 48 72.8366 48 64C48 55.1634 55.1634 48 64 48C72.8366 48 80 55.1634 80 64ZM64 72C68.4183 72 72 68.4183 72 64C72 59.5817 68.4183 56 64 56C59.5817 56 56 59.5817 56 64C56 68.4183 59.5817 72 64 72Z" + =fill bg; + == +:: + :- 'bin' + |= [fg=tape bg=tape] + :~ ;rect + =width "128" + =height "128" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + == +:: + :- 'bis' + |= [fg=tape bg=tape] + :~ ;path + =d "M0 0C0 70.6925 57.3075 128 128 128V0H0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;line + =x1 "128" + =y1 "64" + =x2 "-8.87604e-09" + =y2 "64" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;line + =x1 "128" + =y1 "96" + =x2 "-8.87604e-09" + =y2 "96" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;line + =x1 "128" + =y1 "32" + =x2 "-8.87604e-09" + =y2 "32" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'bit' + |= [fg=tape bg=tape] + :~ ;path + =d "M0.0541 0C70.7217 0.0292317 128 57.3256 128 128C57.3177 128 0.0164917 70.7089 7.62806e-06 0.0305091C7.62851e-06 0.0203397 -4.44317e-10 0.01017 0 0H0.0541Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M128 0L0 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + ;circle + =cx "64" + =cy "64" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "64" + =cy "64" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'bol' + |= [fg=tape bg=tape] + :~ ;circle + =cx "64" + =cy "64" + =r "64" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;circle + =cx "64" + =cy "64" + =r "48" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;line + =x1 "128" + =y1 "64" + =x2 "-4.37114e-08" + =y2 "64" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'bon' + |= [fg=tape bg=tape] + :~ ;path + =d "M128 0C57.3075 8.42999e-07 -8.42999e-07 57.3075 0 128H128V0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M128 128C92.6538 128 64 99.3462 64 64C64 28.6538 92.6538 4.215e-07 128 0" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'bor' + |= [fg=tape bg=tape] + :~ ;path + =d "M64 0H128V128H64C28.6538 128 0 99.3462 0 64C0 28.6538 28.6538 0 64 0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;line + =x1 "-0.0029152" + =x2 "127.983" + =y2 "127.986" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + ;path + =d "M0 128C4.63574e-06 92.6489 14.3309 60.6449 37.5 37.4807" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M32 128C32 101.492 42.7436 77.4939 60.1138 60.1217" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M64 128C64 110.328 71.1626 94.3287 82.7432 82.7471" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M95.6284 128C95.6284 119.164 99.2097 111.164 105 105.374" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'bos' + |= [fg=tape bg=tape] + :~ ;path + =d "M0 0C0 70.6925 57.3075 128 128 128V0H0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;line + =x1 "-0.0029152" + =x2 "127.983" + =y2 "127.986" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + ;circle + =cx "32" + =cy "32" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "32" + =cy "32" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'bot' + |= [fg=tape bg=tape] + :~ ;path + =d "M64 0H128V128H64C28.6538 128 0 99.3462 0 64C0 28.6538 28.6538 0 64 0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;line + =x1 "32" + =y1 "2.18557e-08" + =x2 "32" + =y2 "128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;circle + =cx "32" + =cy "96" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "32" + =cy "96" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + ;circle + =cx "32" + =cy "32" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "32" + =cy "32" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'bud' + |= [fg=tape bg=tape] + :~ ;path + =d "M128 128C128 57.3076 70.6925 6.18013e-06 1.11901e-05 0L0 128L128 128Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M16 64C16 90.5097 37.4903 112 64 112" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;circle + =cx "16" + =cy "64" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "16" + =cy "64" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'bur' + |= [fg=tape bg=tape] + :~ ;path + =d "M5.59506e-06 128C70.6925 128 128 70.6925 128 0L0 5.59506e-06L5.59506e-06 128Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M7.37542e-06 -3.56072e-06C1.19529e-06 70.6924 57.3075 128 128 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M128 0L0 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + == +:: + :- 'bus' + |= [fg=tape bg=tape] + :~ ;path + =d "M128 128C128 57.3076 70.6925 6.18013e-06 1.11901e-05 0L0 128L128 128Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M32 128C32 110.327 17.6731 96 0 96" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M-0.00292969 0L127.997 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + == +:: + :- 'byl' + |= [fg=tape bg=tape] + :~ ;path + =d "M5.59506e-06 128C70.6925 128 128 70.6925 128 0L0 5.59506e-06L5.59506e-06 128Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;circle + =cx "16" + =cy "112" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "16" + =cy "112" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + ;path + =d "M-0.00280762 0L127.997 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + ;path + =d "M22.1288 22.6299C16.0075 28.7511 8.0234 31.874 0.00134547 31.9986M44.7562 45.2573C32.3866 57.6269 16.2133 63.8747 0.00134277 64.0005M67.3836 67.8847C48.7656 86.5027 24.403 95.8749 0.00134412 96.0012" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'byn' + |= [fg=tape bg=tape] + :~ ;path + =d "M5.59506e-06 128C70.6925 128 128 70.6925 128 0L0 5.59506e-06L5.59506e-06 128Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M128 0C128 35.3511 113.669 67.3551 90.5 90.5193" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M96 0C96 26.5077 85.2564 50.5061 67.8862 67.8783" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M64 0C64 17.6721 56.8374 33.6713 45.2568 45.2529" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M32.3716 0C32.3716 8.83603 28.7903 16.8356 23 22.6264" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'byr' + |= [fg=tape bg=tape] + :~ ;path + =d "M0 127.946C0.0292286 57.2783 57.3256 3.08928e-06 128 0C128 70.6823 70.7089 127.984 0.0305092 128C0.0203397 128 0.01017 128 2.36469e-09 128L0 127.946Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M-0.00280762 0L127.997 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + ;circle + =cx "48" + =cy "80" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "48" + =cy "80" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'byt' + |= [fg=tape bg=tape] + :~ ;path + =d "M64 128H0L5.59506e-06 0L64 5.59506e-06C99.3462 8.68512e-06 128 28.6538 128 64C128 99.3462 99.3462 128 64 128Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;circle + =cx "64" + =cy "64" + =r "48" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M128 64L0 64" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M32 0L32 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'dab' + |= [fg=tape bg=tape] + :~ ;path + =d "M0 0C0 70.6925 57.3075 128 128 128V0H0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;line + =y1 "-0.5" + =x2 "45.2548" + =y2 "-0.5" + =transform "matrix(0.707107 -0.707107 -0.707107 -0.707107 79.65 47.6499)" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;circle + =cx "16" + =cy "112" + =r "11.5" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + ;circle + =cx "16" + =cy "112" + =r "9" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + :: =stroke-width "2" + == +:: + :- 'dac' + |= [fg=tape bg=tape] + :~ ;path + =d "M0 0C0 70.6925 57.3075 128 128 128V0H0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M128 0L0 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + ;path + =d "M64 0L64 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M128 64L-5.96046e-08 64" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'dal' + |= [fg=tape bg=tape] + :~ ;path + =d "M0.0541 0C70.7217 0.0292317 128 57.3256 128 128C57.3177 128 0.0164917 70.7089 7.62806e-06 0.0305091C7.62851e-06 0.0203397 -4.44317e-10 0.01017 0 0H0.0541Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;line + =x1 "-0.0029152" + =x2 "63.29" + =y2 "63.2929" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + ;line + =x1 "0.5" + =y1 "-0.5" + =x2 "181.5" + =y2 "-0.5" + =transform "matrix(-0.707107 0.707107 0.707107 0.707107 128.71 0)" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + ;line + =x1 "128" + =y1 "32.0072" + =x2 "32.7071" + =y2 "127.3" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + ;line + =x1 "128" + =y1 "64.0072" + =x2 "64.7071" + =y2 "127.3" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + ;line + =x1 "128" + =y1 "96.0072" + =x2 "96.7071" + =y2 "127.3" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + == +:: + :- 'dan' + |= [fg=tape bg=tape] + :~ ;path + =d "M64 0H128V128H64C28.6538 128 0 99.3462 0 64C0 28.6538 28.6538 0 64 0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;line + =x1 "64" + =y1 "2.18557e-08" + =x2 "64" + =y2 "128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;line + =x1 "96" + =y1 "2.18557e-08" + =x2 "96" + =y2 "128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;circle + =cx "64" + =cy "64" + =r "16" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'dap' + |= [fg=tape bg=tape] + :~ ;path + =d "M0 0C0 70.6925 57.3075 128 128 128V0H0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;line + =x1 "80.0035" + =y1 "79.9964" + =x2 "112.004" + =y2 "111.996" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;circle + =cx "64" + =cy "64" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "64" + =cy "64" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'dar' + |= [fg=tape bg=tape] + :~ ;circle + =cx "64" + =cy "64" + =r "64" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;circle + =cx "32" + =cy "96" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "32" + =cy "96" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + ;path + =d "M86.6274 86.6274C99.1242 74.1307 99.1242 53.8694 86.6274 41.3726C74.1306 28.8758 53.8694 28.8758 41.3726 41.3726" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M75.3137 75.3137C81.5621 69.0653 81.5621 58.9347 75.3137 52.6863C69.0653 46.4379 58.9347 46.4379 52.6863 52.6863" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M97.9411 97.9411C116.686 79.1959 116.686 48.804 97.9411 30.0589C79.196 11.3137 48.804 11.3137 30.0589 30.0589" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M-0.00292969 0L127.997 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + == +:: + :- 'das' + |= [fg=tape bg=tape] + :~ ;rect + =width "128" + =height "128" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;line + =x1 "64" + =y1 "2.18557e-08" + =x2 "64" + =y2 "128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =fill-rule "evenodd" + =clip-rule "evenodd" + =stroke "none" + =d "M80 64C80 72.8366 72.8366 80 64 80C55.1634 80 48 72.8366 48 64C48 55.1634 55.1634 48 64 48C72.8366 48 80 55.1634 80 64ZM64 72C68.4183 72 72 68.4183 72 64C72 59.5817 68.4183 56 64 56C59.5817 56 56 59.5817 56 64C56 68.4183 59.5817 72 64 72Z" + =fill bg; + == +:: + :- 'dat' + |= [fg=tape bg=tape] + :~ ;path + =d "M0 0C0 70.6925 57.3075 128 128 128V0H0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M128 128C92.6538 128 64 99.3462 64 64C64 28.6538 92.6538 -1.54503e-06 128 0" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'dav' + |= [fg=tape bg=tape] + :~ ;path + =d "M64 0H128V128H64C28.6538 128 0 99.3462 0 64C0 28.6538 28.6538 0 64 0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M128 64L0 64" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M96 64C96 46.3269 81.6731 32 64 32" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;circle + =cx "96" + =cy "64" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "96" + =cy "64" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'deb' + |= [fg=tape bg=tape] + :~ ;rect + =width "128" + =height "128" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M64 -6.35781e-07C64 35.3462 35.3462 64 0 64" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'dec' + |= [fg=tape bg=tape] + :~ ;path + =d "M128 128C128 57.3076 70.6925 6.18013e-06 1.11901e-05 0L0 128L128 128Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;circle + =cx "64" + =cy "64" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "64" + =cy "64" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + ;circle + =cx "112" + =cy "16" + =r "11.5" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + ;circle + =cx "112" + =cy "16" + =r "9" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + :: =stroke-width "2" + == +:: + :- 'def' + |= [fg=tape bg=tape] + :~ ;path + =d "M0.0541 0C70.7217 0.0292317 128 57.3256 128 128C57.3177 128 0.0164917 70.7089 7.62806e-06 0.0305091C7.62851e-06 0.0203397 -4.44317e-10 0.01017 0 0H0.0541Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M0 128L128 0" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + ;path + =d "M0 94L94 0" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + ;path + =d "M0 64L64 0" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + ;path + =d "M0 32L32 0" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + ;circle + =cx "16" + =cy "112" + =r "11.5" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + ;circle + =cx "16" + =cy "112" + =r "9" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + :: =stroke-width "2" + == +:: + :- 'deg' + |= [fg=tape bg=tape] + :~ ;rect + =width "128" + =height "128" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M64 128C64 92.6538 35.3462 64 0 64" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'del' + |= [fg=tape bg=tape] + :~ ;path + =d "M0 127.946C0.0292286 57.2783 57.3256 3.08928e-06 128 0C128 70.6823 70.7089 127.984 0.0305092 128C0.0203397 128 0.01017 128 2.36469e-09 128L0 127.946Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;circle + =cx "32" + =cy "96" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "32" + =cy "96" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'dem' + |= [fg=tape bg=tape] + :~ ;circle + =cx "64" + =cy "64" + =r "64" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M-0.00292969 0L127.997 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + ;path + =d "M64 -6.35781e-07C64 35.3462 35.3462 64 0 64" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;circle + =cx "32" + =cy "32" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "32" + =cy "32" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'den' + |= [fg=tape bg=tape] + :~ ;rect + =width "128" + =height "128" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M1.52575e-06 96C53.0193 96 96 53.0193 96 0" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M-0.00280762 0L127.997 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + == +:: + :- 'dep' + |= [fg=tape bg=tape] + :~ ;path + =d "M128 0C57.3075 8.42999e-07 -8.42999e-07 57.3075 0 128H128V0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M32 128C32 101.492 42.7436 77.4939 60.1138 60.1216" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M64 128C64 110.328 71.1626 94.3287 82.7432 82.7471" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M95.6284 128C95.6284 119.164 99.2097 111.164 105 105.374" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'der' + |= [fg=tape bg=tape] + :~ ;path + =d "M0 64L5.59506e-06 0L128 1.11901e-05V64C128 99.3462 99.3462 128 64 128C28.6538 128 -4.6351e-06 99.3462 0 64Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M96 128L96 0" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'des' + |= [fg=tape bg=tape] + :~ ;path + =d "M128 0C57.3075 8.42999e-07 -8.42999e-07 57.3075 0 128H128V0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M96 0L96 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'det' + |= [fg=tape bg=tape] + :~ ;circle + =cx "64" + =cy "64" + =r "64" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;line + =x1 "15.9964" + =y1 "111.996" + =x2 "47.9964" + =y2 "79.9964" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'dev' + |= [fg=tape bg=tape] + :~ ;path + =d "M64 128H0L5.59506e-06 0L64 5.59506e-06C99.3462 8.68512e-06 128 28.6538 128 64C128 99.3462 99.3462 128 64 128Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;line + =x1 "96.5" + =y1 "3.07317e-08" + =x2 "96.5" + =y2 "128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;line + =x1 "32.5" + =y1 "3.07317e-08" + =x2 "32.5" + =y2 "128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;circle + =cx "64" + =cy "64" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "64" + =cy "64" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'dex' + |= [fg=tape bg=tape] + :~ ;path + =d "M64 128H0L5.59506e-06 0L64 5.59506e-06C99.3462 8.68512e-06 128 28.6538 128 64C128 99.3462 99.3462 128 64 128Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;line + =x1 "64" + =y1 "2.18557e-08" + =x2 "64" + =y2 "128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =fill-rule "evenodd" + =clip-rule "evenodd" + =stroke "none" + =d "M80 64C80 72.8366 72.8366 80 64 80C55.1634 80 48 72.8366 48 64C48 55.1634 55.1634 48 64 48C72.8366 48 80 55.1634 80 64ZM64 72C68.4183 72 72 68.4183 72 64C72 59.5817 68.4183 56 64 56C59.5817 56 56 59.5817 56 64C56 68.4183 59.5817 72 64 72Z" + =fill bg; + == +:: + :- 'dib' + |= [fg=tape bg=tape] + :~ ;circle + =cx "64" + =cy "64" + =r "64" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;line + =x1 "8.74228e-08" + =y1 "64" + =x2 "128" + =y2 "64" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;line + =x1 "5.25874e-08" + =y1 "32" + =x2 "128" + =y2 "32" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;circle + =cx "64" + =cy "32" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "64" + =cy "32" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'dif' + |= [fg=tape bg=tape] + :~ ;path + =d "M0 0C0 70.6925 57.3075 128 128 128V0H0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M60.1244 67.3837C41.5063 48.7657 32.1342 24.4031 32.0079 0.00145601M82.7518 44.7563C70.3822 32.3867 64.1344 16.2134 64.0086 0.00145196M105.379 22.1289C99.258 16.0077 96.1351 8.02351 96.0105 0.00145196" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;line + =x1 "0.5" + =y1 "-0.5" + =x2 "181.5" + =y2 "-0.5" + =transform "matrix(-0.707107 0.707107 0.707107 0.707107 128.71 0)" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + ;circle + =cx "16" + =cy "16" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "16" + =cy "16" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + ;circle + =cx "16" + =cy "112" + =r "11.5" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + ;circle + =cx "16" + =cy "112" + =r "9" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + :: =stroke-width "2" + == +:: + :- 'dig' + |= [fg=tape bg=tape] + :~ ;path + =d "M64 0H128V128H64C28.6538 128 0 99.3462 0 64C0 28.6538 28.6538 0 64 0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;line + =x1 "64.5" + =y1 "-0.5" + =x2 "64.5" + =y2 "127.5" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;line + =x1 "16.0035" + =y1 "15.9965" + =x2 "48.0035" + =y2 "47.9965" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;circle + =cx "64" + =cy "64" + =r "16" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'dil' + |= [fg=tape bg=tape] + :~ ;path + =d "M64 0H128V128H64C28.6538 128 0 99.3462 0 64C0 28.6538 28.6538 0 64 0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;line + =x1 "80.0036" + =y1 "79.9964" + =x2 "112.004" + =y2 "111.996" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;line + =x1 "0.5" + =y1 "-0.5" + =x2 "181.5" + =y2 "-0.5" + =transform "matrix(-0.707107 0.707107 0.707107 0.707107 128.71 0)" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + == +:: + :- 'din' + |= [fg=tape bg=tape] + :~ ;rect + =width "128" + =height "128" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;line + =x1 "96" + =y1 "2.18557e-08" + =x2 "96" + =y2 "128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'dir' + |= [fg=tape bg=tape] + :~ ;path + =d "M0 0C0 70.6925 57.3075 128 128 128V0H0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M96 64C96 81.6731 81.6731 96 64 96" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;line + =x1 "16.0035" + =y1 "15.9965" + =x2 "48.0035" + =y2 "47.9965" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;circle + =cx "64" + =cy "64" + =r "16" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'dis' + |= [fg=tape bg=tape] + :~ ;path + =d "M128 0C57.3075 8.42999e-07 -8.42999e-07 57.3075 0 128H128V0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M-0.0029152 0L127.997 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + ;circle + =cx "96" + =cy "32" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "96" + =cy "32" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + ;circle + =cx "32" + =cy "96" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "32" + =cy "96" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'div' + |= [fg=tape bg=tape] + :~ ;rect + =width "128" + =height "128" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M64 0L64 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M-4.19629e-06 96C70.6924 96 128 53.0193 128 5.59506e-06" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M-2.79753e-06 64C70.6924 64 128 35.3462 128 5.59506e-06" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'doc' + |= [fg=tape bg=tape] + :~ ;path + =d "M0 127.946C0.0292286 57.2783 57.3256 3.08928e-06 128 0C128 70.6823 70.7089 127.984 0.0305092 128C0.0203397 128 0.01017 128 2.36469e-09 128L0 127.946Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M127.997 0L-0.00291443 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + ;circle + =cx "64" + =cy "64" + =r "16" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M86.6274 41.3726C74.1306 28.8758 53.8694 28.8758 41.3726 41.3726C28.8758 53.8694 28.8758 74.1306 41.3726 86.6274" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'dol' + |= [fg=tape bg=tape] + :~ ;circle + =cx "64" + =cy "64" + =r "64" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M128 64L0 64" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M-4.19629e-06 16C26.5097 16 48 37.4903 48 64C48 90.5097 26.5097 112 0 112" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'don' + |= [fg=tape bg=tape] + :~ ;path + =d "M128 0C57.3075 8.42999e-07 -8.42999e-07 57.3075 0 128H128V0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M-3.8147e-06 128C-7.24632e-07 92.6538 28.6538 64 64 64C99.3462 64 128 92.6538 128 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'dop' + |= [fg=tape bg=tape] + :~ ;circle + =cx "64" + =cy "64" + =r "64" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M64 112C90.5097 112 112 90.5097 112 64C112 37.4903 90.5097 16 64 16" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M128 64L0 64" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;circle + =cx "64" + =cy "64" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "64" + =cy "64" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'dor' + |= [fg=tape bg=tape] + :~ ;path + =d "M64 0H128V128H64C28.6538 128 0 99.3462 0 64C0 28.6538 28.6538 0 64 0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;line + =y1 "63.5" + =x2 "128" + =y2 "63.5" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'dos' + |= [fg=tape bg=tape] + :~ ;path + =d "M0 0C0 70.6925 57.3075 128 128 128V0H0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;line + =x1 "-0.0029152" + =x2 "127.983" + =y2 "127.986" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + ;path + =d "M86.6274 86.6274C99.1242 74.1306 99.1242 53.8693 86.6274 41.3725C74.1306 28.8758 53.8694 28.8758 41.3726 41.3725" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'dot' + |= [fg=tape bg=tape] + :~ ;path + =d "M64 0H128V128H64C28.6538 128 0 99.3462 0 64C0 28.6538 28.6538 0 64 0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;circle + =cx "64" + =cy "64" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "64" + =cy "64" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'dov' + |= [fg=tape bg=tape] + :~ ;rect + =width "128" + =height "128" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M128 0L0 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + ;path + =d "M-0.701724 31.9914C25.6281 31.9914 49.4822 42.5913 66.8261 59.7565M-0.701723 63.9914C16.7916 63.9914 32.6456 71.0098 44.1982 82.3844M-0.701722 95.9914C7.955 95.9914 15.8089 99.4288 21.5694 105.013" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M0 0C35.3511 0 67.3551 14.3309 90.5193 37.5" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'doz' + |= [fg=tape bg=tape] + :~ ;circle + =cx "64" + =cy "64" + =r "64" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M128 128L0 0" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + ;path + =d "M30.0589 30.0589C48.804 11.3137 79.196 11.3137 97.9411 30.0589C116.686 48.804 116.686 79.196 97.9411 97.9411" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M52.6863 52.6863C58.9347 46.4379 69.0653 46.4379 75.3137 52.6863C81.5621 58.9347 81.5621 69.0653 75.3137 75.3137" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M41.3726 41.3726C53.8694 28.8758 74.1306 28.8758 86.6274 41.3726C99.1242 53.8694 99.1242 74.1306 86.6274 86.6274" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'duc' + |= [fg=tape bg=tape] + :~ ;path + =d "M128 128C128 57.3076 70.6925 6.18013e-06 1.11901e-05 0L0 128L128 128Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M128 64L0 64" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M128 32L0 32" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;circle + =cx "32" + =cy "32" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "32" + =cy "32" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'dul' + |= [fg=tape bg=tape] + :~ ;circle + =cx "64" + =cy "64" + =r "64" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M64 16C90.5097 16 112 37.4903 112 64" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M64 64L64 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;circle + =cx "64" + =cy "64" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "64" + =cy "64" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'dun' + |= [fg=tape bg=tape] + :~ ;path + =d "M64 128H0L5.59506e-06 0L64 5.59506e-06C99.3462 8.68512e-06 128 28.6538 128 64C128 99.3462 99.3462 128 64 128Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M112 64C112 37.4903 90.5097 16 64 16" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'dur' + |= [fg=tape bg=tape] + :~ ;path + =d "M0 64L5.59506e-06 0L128 1.11901e-05V64C128 99.3462 99.3462 128 64 128C28.6538 128 -4.6351e-06 99.3462 0 64Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + == +:: + :- 'dus' + |= [fg=tape bg=tape] + :~ ;path + =d "M128 128C128 57.3076 70.6925 6.18013e-06 1.11901e-05 0L0 128L128 128Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M32 -3.05151e-06C32 53.0193 74.9807 96 128 96" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M128 0L0 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + == +:: + :- 'dut' + |= [fg=tape bg=tape] + :~ ;rect + =width "128" + =height "128" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;circle + =cx "96" + =cy "96" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "96" + =cy "96" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'dux' + |= [fg=tape bg=tape] + :~ ;path + =d "M5.59506e-06 128C70.6925 128 128 70.6925 128 0L0 5.59506e-06L5.59506e-06 128Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M-2.79795e-06 -3.55988e-06C70.6924 -4.40288e-06 128 57.3075 128 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'dyl' + |= [fg=tape bg=tape] + :~ ;path + =d "M128 128C128 57.3076 70.6925 6.18013e-06 1.11901e-05 0L0 128L128 128Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M2.03434e-06 128C70.6924 128 128 70.6925 128 0" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'dyn' + |= [fg=tape bg=tape] + :~ ;path + =d "M5.59506e-06 128C70.6925 128 128 70.6925 128 0L0 5.59506e-06L5.59506e-06 128Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M128 32L0 32" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'dyr' + |= [fg=tape bg=tape] + :~ ;path + =d "M0 127.946C0.0292286 57.2783 57.3256 3.08928e-06 128 0C128 70.6823 70.7089 127.984 0.0305092 128C0.0203397 128 0.01017 128 2.36469e-09 128L0 127.946Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M-0.00292969 0L127.997 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + ;circle + =cx "96" + =cy "32" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "96" + =cy "32" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + ;circle + =cx "32" + =cy "96" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "32" + =cy "96" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'dys' + |= [fg=tape bg=tape] + :~ ;path + =d "M128 128C128 57.3076 70.6925 6.18013e-06 1.11901e-05 0L0 128L128 128Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M-3.8147e-06 1.11901e-05C-7.24633e-07 35.3462 28.6538 64 64 64C99.3462 64 128 35.3462 128 0" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'dyt' + |= [fg=tape bg=tape] + :~ ;path + =d "M64 128H0L5.59506e-06 0L64 5.59506e-06C99.3462 8.68512e-06 128 28.6538 128 64C128 99.3462 99.3462 128 64 128Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;circle + =cx "64" + =cy "64" + =r "32" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M128 64L0 64" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;circle + =cx "32" + =cy "64" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "32" + =cy "64" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'fab' + |= [fg=tape bg=tape] + :~ ;path + =d "M0 0C0 70.6925 57.3075 128 128 128V0H0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M128 0L0 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + ;circle + =cx "64" + =cy "64" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "64" + =cy "64" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + ;circle + =cx "16" + =cy "112" + =r "11.5" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + ;circle + =cx "16" + =cy "112" + =r "9" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + :: =stroke-width "2" + == +:: + :- 'fad' + |= [fg=tape bg=tape] + :~ ;path + =d "M5.59506e-06 128C70.6925 128 128 70.6925 128 0L0 5.59506e-06L5.59506e-06 128Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;circle + =cx "96" + =cy "32" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "96" + =cy "32" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + ;circle + =cx "32" + =cy "96" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "32" + =cy "96" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'fal' + |= [fg=tape bg=tape] + :~ ;path + =d "M0 127.946C0.0292286 57.2783 57.3256 3.08928e-06 128 0C128 70.6823 70.7089 127.984 0.0305092 128C0.0203397 128 0.01017 128 2.36469e-09 128L0 127.946Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M0 128L128 0" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + ;path + =d "M0 0C35.3511 0 67.3551 14.3309 90.5193 37.5" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M0 32C26.5077 32 50.5061 42.7436 67.8783 60.1138" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M0 64C17.6721 64 33.6713 71.1626 45.2529 82.7432" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M0 95.6284C8.83603 95.6284 16.8356 99.2097 22.6264 105" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'fam' + |= [fg=tape bg=tape] + :~ ;path + =d "M64 0H128V128H64C28.6538 128 0 99.3462 0 64C0 28.6538 28.6538 0 64 0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;line + =x1 "128" + =y1 "64" + =x2 "-4.37114e-08" + =y2 "64" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;line + =x1 "64" + =y1 "2.18557e-08" + =x2 "64" + =y2 "128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;circle + =cx "64" + =cy "64" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "64" + =cy "64" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'fan' + |= [fg=tape bg=tape] + :~ ;path + =d "M64 0H128V128H64C28.6538 128 0 99.3462 0 64C0 28.6538 28.6538 0 64 0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M128 0L0 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + ;path + =d "M64 0L64 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M-0.00292969 0L127.997 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + == +:: + :- 'fas' + |= [fg=tape bg=tape] + :~ ;rect + =width "128" + =height "128" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;circle + =cx "64" + =cy "64" + =r "32" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;circle + =cx "96" + =cy "64" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "96" + =cy "64" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'feb' + |= [fg=tape bg=tape] + :~ ;rect + =width "128" + =height "128" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M7.37542e-06 -3.56072e-06C1.19529e-06 70.6924 57.3075 128 128 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'fed' + |= [fg=tape bg=tape] + :~ ;circle + =cx "64" + =cy "64" + =r "64" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M128 32L0 32" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;circle + =cx "64" + =cy "64" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "64" + =cy "64" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'fel' + |= [fg=tape bg=tape] + :~ ;path + =d "M0 127.946C0.0292286 57.2783 57.3256 3.08928e-06 128 0C128 70.6823 70.7089 127.984 0.0305092 128C0.0203397 128 0.01017 128 2.36469e-09 128L0 127.946Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;line + =y1 "-0.5" + =x2 "45.2548" + =y2 "-0.5" + =transform "matrix(0.707107 -0.707107 -0.707107 -0.707107 79.65 47.6499)" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'fen' + |= [fg=tape bg=tape] + :~ ;rect + =width "128" + =height "128" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M-0.00280762 0L127.997 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + ;path + =d "M0 128C4.63574e-06 92.6489 14.3309 60.6449 37.5 37.4807" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M32 128C32 101.492 42.7436 77.4939 60.1138 60.1217" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M64 128C64 110.328 71.1626 94.3287 82.7432 82.7471" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M95.6284 128C95.6284 119.164 99.2097 111.164 105 105.374" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'fep' + |= [fg=tape bg=tape] + :~ ;path + =d "M128 128C128 57.3076 70.6925 6.18013e-06 1.11901e-05 0L0 128L128 128Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M128 0L0 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + == +:: + :- 'fer' + |= [fg=tape bg=tape] + :~ ;path + =d "M64 128H0L5.59506e-06 0L64 5.59506e-06C99.3462 8.68512e-06 128 28.6538 128 64C128 99.3462 99.3462 128 64 128Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M64 0L64 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'fes' + |= [fg=tape bg=tape] + :~ ;path + =d "M128 0C57.3075 8.42999e-07 -8.42999e-07 57.3075 0 128H128V0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M32 0L32 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'fet' + |= [fg=tape bg=tape] + :~ ;circle + =cx "64" + =cy "64" + =r "64" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M128 0L0 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + == +:: + :- 'fex' + |= [fg=tape bg=tape] + :~ ;path + =d "M64 128H0L5.59506e-06 0L64 5.59506e-06C99.3462 8.68512e-06 128 28.6538 128 64C128 99.3462 99.3462 128 64 128Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;line + =y1 "-0.5" + =x2 "45.2548" + =y2 "-0.5" + =transform "matrix(0.707107 -0.707107 -0.707107 -0.707107 79.6499 47.6499)" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =fill-rule "evenodd" + =clip-rule "evenodd" + =stroke "none" + =d "M80 64C80 72.8366 72.8366 80 64 80C55.1634 80 48 72.8366 48 64C48 55.1634 55.1634 48 64 48C72.8366 48 80 55.1634 80 64ZM64 72C68.4183 72 72 68.4183 72 64C72 59.5817 68.4183 56 64 56C59.5817 56 56 59.5817 56 64C56 68.4183 59.5817 72 64 72Z" + =fill bg; + == +:: + :- 'fid' + |= [fg=tape bg=tape] + :~ ;path + =d "M0 0C0 70.6925 57.3075 128 128 128V0H0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M-0.00291443 0L127.997 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + ;circle + =cx "96" + =cy "96" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "96" + =cy "96" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + ;circle + =cx "32" + =cy "32" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "32" + =cy "32" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'fig' + |= [fg=tape bg=tape] + :~ ;path + =d "M64 0H128V128H64C28.6538 128 0 99.3462 0 64C0 28.6538 28.6538 0 64 0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M64 0L64 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;circle + =cx "64" + =cy "64" + =r "32" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;circle + =cx "64" + =cy "64" + =r "16" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'fil' + |= [fg=tape bg=tape] + :~ ;path + =d "M64 0H128V128H64C28.6538 128 0 99.3462 0 64C0 28.6538 28.6538 0 64 0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;line + =x1 "128" + =y1 "64" + =x2 "-4.37114e-08" + =y2 "64" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;line + =x1 "64" + =y1 "2.18557e-08" + =x2 "64" + =y2 "128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;line + =x1 "32" + =y1 "2.18557e-08" + =x2 "32" + =y2 "128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'fin' + |= [fg=tape bg=tape] + :~ ;rect + =width "128" + =height "128" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;line + =x1 "98" + =y1 "2.18557e-08" + =x2 "98" + =y2 "128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'fip' + |= [fg=tape bg=tape] + :~ ;path + =d "M64 0H128V128H64C28.6538 128 0 99.3462 0 64C0 28.6538 28.6538 0 64 0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;circle + =cx "64" + =cy "64" + =r "32" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;line + =x1 "-0.0029152" + =x2 "127.983" + =y2 "127.986" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + ;circle + =cx "64" + =cy "96" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "64" + =cy "96" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'fir' + |= [fg=tape bg=tape] + :~ ;path + =d "M0 0C0 70.6925 57.3075 128 128 128V0H0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;line + =y1 "-0.5" + =x2 "45.2548" + =y2 "-0.5" + =transform "matrix(0.707107 -0.707107 -0.707107 -0.707107 79.65 47.6499)" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;line + =x1 "80.0036" + =y1 "79.9965" + =x2 "112.004" + =y2 "111.997" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;line + =x1 "16.0035" + =y1 "15.9965" + =x2 "48.0035" + =y2 "47.9965" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;circle + =cx "64" + =cy "64" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "64" + =cy "64" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'fit' + |= [fg=tape bg=tape] + :~ ;path + =d "M0.0541 0C70.7217 0.0292317 128 57.3256 128 128C57.3177 128 0.0164917 70.7089 7.62806e-06 0.0305091C7.62851e-06 0.0203397 -4.44317e-10 0.01017 0 0H0.0541Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;line + =x1 "0.5" + =y1 "-0.5" + =x2 "181.5" + =y2 "-0.5" + =transform "matrix(-0.707107 0.707107 0.707107 0.707107 128.71 0)" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + == +:: + :- 'fod' + |= [fg=tape bg=tape] + :~ ;path + =d "M64 0H128V128H64C28.6538 128 0 99.3462 0 64C0 28.6538 28.6538 0 64 0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =fill-rule "evenodd" + =clip-rule "evenodd" + =stroke "none" + =d "M80 64C80 72.8366 72.8366 80 64 80C55.1634 80 48 72.8366 48 64C48 55.1634 55.1634 48 64 48C72.8366 48 80 55.1634 80 64ZM64 72C68.4183 72 72 68.4183 72 64C72 59.5817 68.4183 56 64 56C59.5817 56 56 59.5817 56 64C56 68.4183 59.5817 72 64 72Z" + =fill bg; + == +:: + :- 'fog' + |= [fg=tape bg=tape] + :~ ;path + =d "M128 0C57.3075 8.42999e-07 -8.42999e-07 57.3075 0 128H128V0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M-0.00292969 0L127.997 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + ;path + =d "M86.6274 86.6274C99.1242 74.1306 99.1242 53.8694 86.6274 41.3726C74.1306 28.8758 53.8694 28.8758 41.3726 41.3726" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;circle + =cx "64" + =cy "64" + =r "16" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'fol' + |= [fg=tape bg=tape] + :~ ;circle + =cx "64" + =cy "64" + =r "64" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;circle + =cx "64" + =cy "64" + =r "16" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;line + =x1 "128" + =y1 "64" + =x2 "-4.37114e-08" + =y2 "64" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'fon' + |= [fg=tape bg=tape] + :~ ;path + =d "M128 0C57.3075 8.42999e-07 -8.42999e-07 57.3075 0 128H128V0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;line + =x1 "-0.0029152" + =x2 "127.983" + =y2 "127.986" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + == +:: + :- 'fop' + |= [fg=tape bg=tape] + :~ ;circle + =cx "64" + =cy "64" + =r "64" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;line + =x1 "-0.0029152" + =x2 "127.983" + =y2 "127.986" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + ;path + =d "M16 64C16 90.5097 37.4903 112 64 112" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;circle + =cx "16" + =cy "64" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "16" + =cy "64" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'for' + |= [fg=tape bg=tape] + :~ ;path + =d "M64 0H128V128H64C28.6538 128 0 99.3462 0 64C0 28.6538 28.6538 0 64 0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;line + =x1 "96" + =y1 "2.18557e-08" + =x2 "96" + =y2 "128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;circle + =cx "64" + =cy "64" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "64" + =cy "64" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'fos' + |= [fg=tape bg=tape] + :~ ;path + =d "M5.59506e-06 128C70.6925 128 128 70.6925 128 0L0 5.59506e-06L5.59506e-06 128Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;line + =x1 "-0.0029152" + =x2 "127.983" + =y2 "127.986" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + ;path + =d "M96 0C96 53.0193 53.0193 96 0 96" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M64 0C64 35.3462 35.3462 64 0 64" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M32 0C32 17.6731 17.6731 32 0 32" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'fot' + |= [fg=tape bg=tape] + :~ ;path + =d "M64 0H128V128H64C28.6538 128 0 99.3462 0 64C0 28.6538 28.6538 0 64 0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;line + =x1 "15.9964" + =y1 "111.997" + =x2 "47.9964" + =y2 "79.9965" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;circle + =cx "64" + =cy "64" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "64" + =cy "64" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'ful' + |= [fg=tape bg=tape] + :~ ;circle + =cx "64" + =cy "64" + =r "64" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M64 96C81.6731 96 96 81.6731 96 64C96 46.3269 81.6731 32 64 32" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'fun' + |= [fg=tape bg=tape] + :~ ;path + =d "M128 64V128H0L2.79753e-06 64C4.34256e-06 28.6538 28.6538 -1.54503e-06 64 0C99.3462 1.54503e-06 128 28.6538 128 64Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;line + =x1 "15.9964" + =y1 "111.997" + =x2 "47.9964" + =y2 "79.9965" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M-0.00280762 0L127.997 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + ;circle + =cx "16" + =cy "112" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "16" + =cy "112" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'fur' + |= [fg=tape bg=tape] + :~ ;path + =d "M5.59506e-06 128C70.6925 128 128 70.6925 128 0L0 5.59506e-06L5.59506e-06 128Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M128 0L0 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + ;path + =d "M86.8823 41.6275C74.3855 29.1307 54.1242 29.1307 41.6274 41.6275C29.1307 54.1243 29.1307 74.3855 41.6274 86.8823" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;circle + =cx "64" + =cy "64" + =r "16" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'fus' + |= [fg=tape bg=tape] + :~ ;path + =d "M128 128C128 57.3076 70.6925 6.18013e-06 1.11901e-05 0L0 128L128 128Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M128 0L0 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + ;path + =d "M32 128C32 110.327 17.6731 96 0 96" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'fyl' + |= [fg=tape bg=tape] + :~ ;path + =d "M5.59506e-06 128C70.6925 128 128 70.6925 128 0L0 5.59506e-06L5.59506e-06 128Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M22.1288 22.6299C16.0075 28.7511 8.0234 31.874 0.00134547 31.9986M44.7562 45.2573C32.3866 57.6269 16.2133 63.8747 0.00134277 64.0005M67.3836 67.8847C48.7656 86.5027 24.403 95.8749 0.00134412 96.0012" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M-0.00280762 0L127.997 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + == +:: + :- 'fyn' + |= [fg=tape bg=tape] + :~ ;path + =d "M5.59506e-06 128C70.6925 128 128 70.6925 128 0L0 5.59506e-06L5.59506e-06 128Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M128 0L0 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + == +:: + :- 'fyr' + |= [fg=tape bg=tape] + :~ ;path + =d "M0 127.946C0.0292286 57.2783 57.3256 3.08928e-06 128 0C128 70.6823 70.7089 127.984 0.0305092 128C0.0203397 128 0.01017 128 2.36469e-09 128L0 127.946Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M-0.00268555 0L127.997 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + ;line + =y1 "-0.5" + =x2 "45.2548" + =y2 "-0.5" + =transform "matrix(0.707107 -0.707107 -0.707107 -0.707107 79.6499 47.6499)" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'hab' + |= [fg=tape bg=tape] + :~ ;path + =d "M0 0C0 70.6925 57.3075 128 128 128V0H0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;line + =x1 "0.5" + =y1 "-0.5" + =x2 "181.5" + =y2 "-0.5" + =transform "matrix(-0.707107 0.707107 0.707107 0.707107 128.71 0)" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + ;path + =d "M60.1244 67.3837C41.5063 48.7657 32.1342 24.4031 32.0079 0.00145601M82.7518 44.7563C70.3822 32.3867 64.1344 16.2134 64.0086 0.00145196M105.379 22.1289C99.258 16.0077 96.1351 8.02351 96.0105 0.00145196" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;circle + =cx "16" + =cy "112" + =r "11.5" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + ;circle + =cx "16" + =cy "112" + =r "9" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + :: =stroke-width "2" + == +:: + :- 'hac' + |= [fg=tape bg=tape] + :~ ;path + =d "M0 0C0 70.6925 57.3075 128 128 128V0H0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;line + =x1 "0.5" + =y1 "-0.5" + =x2 "181.5" + =y2 "-0.5" + =transform "matrix(-0.707107 0.707107 0.707107 0.707107 128.71 0)" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + ;circle + =cx "64" + =cy "64" + =r "32" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;circle + =cx "64" + =cy "64" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "64" + =cy "64" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'had' + |= [fg=tape bg=tape] + :~ ;path + =d "M5.59506e-06 128C70.6925 128 128 70.6925 128 0L0 5.59506e-06L5.59506e-06 128Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;circle + =cx "32" + =cy "32" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "32" + =cy "32" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'hal' + |= [fg=tape bg=tape] + :~ ;path + =d "M0 127.946C0.0292286 57.2783 57.3256 3.08928e-06 128 0C128 70.6823 70.7089 127.984 0.0305092 128C0.0203397 128 0.01017 128 2.36469e-09 128L0 127.946Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;line + =x1 "64.5" + =y1 "-0.5" + =x2 "64.5" + =y2 "127.5" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M16 64C16 90.5097 37.4903 112 64 112" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M112 64C112 37.4903 90.5097 16 64 16" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'han' + |= [fg=tape bg=tape] + :~ ;path + =d "M5.59506e-06 128C70.6925 128 128 70.6925 128 0L0 5.59506e-06L5.59506e-06 128Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + == +:: + :- 'hap' + |= [fg=tape bg=tape] + :~ ;circle + =cx "64" + =cy "64" + =r "64" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;circle + =cx "64" + =cy "64" + =r "32" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;circle + =cx "64" + =cy "64" + =r "48" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M-0.00292969 0L127.997 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + ;circle + =cx "64" + =cy "64" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "64" + =cy "64" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'har' + |= [fg=tape bg=tape] + :~ ;circle + =cx "64" + =cy "64" + =r "64" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;line + =x1 "64" + =y1 "2.18557e-08" + =x2 "64" + =y2 "128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;circle + =cx "64" + =cy "64" + =r "16" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'has' + |= [fg=tape bg=tape] + :~ ;rect + =width "128" + =height "128" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;circle + =cx "64" + =cy "64" + =r "32" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;circle + =cx "64" + =cy "32" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "64" + =cy "32" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + ;circle + =cx "32" + =cy "64" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "32" + =cy "64" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'hat' + |= [fg=tape bg=tape] + :~ ;path + =d "M0 0C0 70.6925 57.3075 128 128 128V0H0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;circle + =cx "16" + =cy "16" + =r "8" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;line + =x1 "0.5" + =y1 "-0.5" + =x2 "181.5" + =y2 "-0.5" + =transform "matrix(-0.707107 0.707107 0.707107 0.707107 128.71 0)" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + ;path + =fill-rule "evenodd" + =clip-rule "evenodd" + =stroke "none" + =d "M48 32C48 40.8366 40.8366 48 32 48C23.1634 48 16 40.8366 16 32C16 23.1634 23.1634 16 32 16C40.8366 16 48 23.1634 48 32ZM32 40C36.4183 40 40 36.4183 40 32C40 27.5817 36.4183 24 32 24C27.5817 24 24 27.5817 24 32C24 36.4183 27.5817 40 32 40Z" + =fill bg; + == +:: + :- 'hav' + |= [fg=tape bg=tape] + :~ ;path + =d "M0 0C0 70.6925 57.3075 128 128 128V0H0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;line + =x1 "96" + =y1 "2.18557e-08" + =x2 "96" + =y2 "128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'heb' + |= [fg=tape bg=tape] + :~ ;rect + =width "128" + =height "128" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M2.03434e-06 128C70.6924 128 128 70.6925 128 0" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'hec' + |= [fg=tape bg=tape] + :~ ;path + =d "M128 128C128 57.3076 70.6925 6.18013e-06 1.11901e-05 0L0 128L128 128Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;circle + =cx "32" + =cy "32" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "32" + =cy "32" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + ;circle + =cx "32" + =cy "96" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "32" + =cy "96" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + ;circle + =cx "96" + =cy "96" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "96" + =cy "96" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'hep' + |= [fg=tape bg=tape] + :~ ;path + =d "M128 128C128 57.3076 70.6925 6.18013e-06 1.11901e-05 0L0 128L128 128Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;line + =x1 "-0.00285417" + =x2 "127.983" + =y2 "127.986" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + ;path + =d "M-0.00292969 0L127.997 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + == +:: + :- 'hes' + |= [fg=tape bg=tape] + :~ ;path + =d "M128 0C57.3075 8.42999e-07 -8.42999e-07 57.3075 0 128H128V0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M32 0L32 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =fill-rule "evenodd" + =clip-rule "evenodd" + =stroke "none" + =d "M48 96C48 104.837 40.8366 112 32 112C23.1634 112 16 104.837 16 96C16 87.1634 23.1634 80 32 80C40.8366 80 48 87.1634 48 96ZM32 104C36.4183 104 40 100.418 40 96C40 91.5817 36.4183 88 32 88C27.5817 88 24 91.5817 24 96C24 100.418 27.5817 104 32 104Z" + =fill bg; + == +:: + :- 'het' + |= [fg=tape bg=tape] + :~ ;circle + =cx "64" + =cy "64" + =r "64" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M96 128L96 0" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'hex' + |= [fg=tape bg=tape] + :~ ;path + =d "M64 128H0L5.59506e-06 0L64 5.59506e-06C99.3462 8.68512e-06 128 28.6538 128 64C128 99.3462 99.3462 128 64 128Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M128 0L0 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + ;path + =fill-rule "evenodd" + =clip-rule "evenodd" + =stroke "none" + =d "M80 64C80 72.8366 72.8366 80 64 80C55.1634 80 48 72.8366 48 64C48 55.1634 55.1634 48 64 48C72.8366 48 80 55.1634 80 64ZM64 72C68.4183 72 72 68.4183 72 64C72 59.5817 68.4183 56 64 56C59.5817 56 56 59.5817 56 64C56 68.4183 59.5817 72 64 72Z" + =fill bg; + == +:: + :- 'hid' + |= [fg=tape bg=tape] + :~ ;path + =d "M0 0C0 70.6925 57.3075 128 128 128V0H0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M-0.00292969 0L127.997 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + ;path + =d "M2.03434e-06 128C70.6924 128 128 70.6925 128 0" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M1.52575e-06 96C53.0193 96 96 53.0193 96 0" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M1.01717e-06 64C35.3462 64 64 35.3462 64 0" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M5.08584e-07 32C17.6731 32 32 17.6731 32 0" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'hil' + |= [fg=tape bg=tape] + :~ ;path + =d "M64 0H128V128H64C28.6538 128 0 99.3462 0 64C0 28.6538 28.6538 0 64 0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;line + =x1 "8.74228e-08" + =y1 "64" + =x2 "128" + =y2 "64" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;line + =x1 "64" + =y1 "2.18557e-08" + =x2 "64" + =y2 "128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'hin' + |= [fg=tape bg=tape] + :~ ;rect + =width "128" + =height "128" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;line + =x1 "32" + =y1 "2.18557e-08" + =x2 "32" + =y2 "128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =fill-rule "evenodd" + =clip-rule "evenodd" + =stroke "none" + =d "M48 64C48 72.8366 40.8366 80 32 80C23.1634 80 16 72.8366 16 64C16 55.1634 23.1634 48 32 48C40.8366 48 48 55.1634 48 64ZM32 72C36.4183 72 40 68.4183 40 64C40 59.5817 36.4183 56 32 56C27.5817 56 24 59.5817 24 64C24 68.4183 27.5817 72 32 72Z" + =fill bg; + == +:: + :- 'hob' + |= [fg=tape bg=tape] + :~ ;path + =d "M128 64V128H0L2.79753e-06 64C4.34256e-06 28.6538 28.6538 -1.54503e-06 64 0C99.3462 1.54503e-06 128 28.6538 128 64Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;line + =x1 "128" + =y1 "64" + =x2 "-4.37114e-08" + =y2 "64" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'hoc' + |= [fg=tape bg=tape] + :~ ;path + =d "M64 0H128V128H64C28.6538 128 0 99.3462 0 64C0 28.6538 28.6538 0 64 0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;line + =y1 "-0.5" + =x2 "45.2548" + =y2 "-0.5" + =transform "matrix(0.707107 -0.707107 -0.707107 -0.707107 79.65 47.6499)" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;circle + =cx "64" + =cy "64" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "64" + =cy "64" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'hod' + |= [fg=tape bg=tape] + :~ ;path + =d "M64 0H128V128H64C28.6538 128 0 99.3462 0 64C0 28.6538 28.6538 0 64 0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M32 0L32 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'hol' + |= [fg=tape bg=tape] + :~ ;circle + =cx "64" + =cy "64" + =r "64" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;line + =x1 "128" + =y1 "64" + =x2 "-4.37114e-08" + =y2 "64" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;circle + =cx "64" + =cy "64" + =r "16" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;circle + =cx "64" + =cy "96" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "64" + =cy "96" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'hop' + |= [fg=tape bg=tape] + :~ ;circle + =cx "64" + =cy "64" + =r "64" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M128 64L0 64" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M64 96C81.6731 96 96 81.6731 96 64C96 46.3269 81.6731 32 64 32" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;circle + =cx "64" + =cy "64" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "64" + =cy "64" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'hos' + |= [fg=tape bg=tape] + :~ ;path + =d "M0 0C0 70.6925 57.3075 128 128 128V0H0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;line + =x1 "80.0036" + =y1 "79.9965" + =x2 "112.004" + =y2 "111.997" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;line + =x1 "16.0036" + =y1 "15.9965" + =x2 "48.0036" + =y2 "47.9965" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;circle + =cx "48" + =cy "48" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "48" + =cy "48" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + ;circle + =cx "80" + =cy "47" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "80" + =cy "47" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + ;circle + =cx "80" + =cy "81" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "80" + =cy "81" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + ;circle + =cx "48" + =cy "80" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "48" + =cy "80" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'hul' + |= [fg=tape bg=tape] + :~ ;circle + =cx "64" + =cy "64" + =r "64" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;circle + =cx "64" + =cy "64" + =r "32" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;circle + =cx "48" + =cy "64" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "48" + =cy "64" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'hus' + |= [fg=tape bg=tape] + :~ ;path + =d "M128 128C128 57.3076 70.6925 6.18013e-06 1.11901e-05 0L0 128L128 128Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M-0.00292969 0L127.997 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + ;path + =d "M64 96C46.3269 96 32 81.6731 32 64" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;circle + =cx "64" + =cy "64" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "64" + =cy "64" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'hut' + |= [fg=tape bg=tape] + :~ ;rect + =width "128" + =height "128" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;circle + =cx "64" + =cy "64" + =r "48" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;circle + =cx "32" + =cy "32" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "32" + =cy "32" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + ;circle + =cx "96" + =cy "96" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "96" + =cy "96" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'lab' + |= [fg=tape bg=tape] + :~ ;path + =d "M128 0C57.3075 8.42999e-07 -8.42999e-07 57.3075 0 128H128V0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;line + =x1 "-0.0029152" + =x2 "127.983" + =y2 "127.986" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + ;line + =y1 "-0.5" + =x2 "45.2548" + =y2 "-0.5" + =transform "matrix(0.707107 -0.707107 -0.707107 -0.707107 79.65 47.6499)" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;line + =x1 "15.9964" + =y1 "111.997" + =x2 "47.9964" + =y2 "79.9965" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'lac' + |= [fg=tape bg=tape] + :~ ;path + =d "M0 0C0 70.6925 57.3075 128 128 128V0H0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M64 -9.40976e-06C64 70.6924 92.6538 128 128 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M32 -7.63193e-07C32 70.6924 74.9807 128 128 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M128 64L0 64" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'lad' + |= [fg=tape bg=tape] + :~ ;path + =d "M128 0C57.3075 8.42999e-07 -8.42999e-07 57.3075 0 128H128V0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;line + =x1 "95.35" + =y1 "32.7071" + =x2 "32.0571" + =y2 "96" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + ;circle + =cx "96" + =cy "32" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "96" + =cy "32" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + ;circle + =cx "32" + =cy "96" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "32" + =cy "96" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'lag' + |= [fg=tape bg=tape] + :~ ;path + =d "M64 0H128V128H64C28.6538 128 0 99.3462 0 64C0 28.6538 28.6538 0 64 0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M64 112C90.5097 112 112 90.5097 112 64" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'lan' + |= [fg=tape bg=tape] + :~ ;path + =d "M64 0H128V128H64C28.6538 128 0 99.3462 0 64C0 28.6538 28.6538 0 64 0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;line + =x1 "64" + =y1 "2.18557e-08" + =x2 "64" + =y2 "128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;line + =x1 "32" + =y1 "2.18557e-08" + =x2 "32" + =y2 "128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;circle + =cx "64" + =cy "64" + =r "16" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'lap' + |= [fg=tape bg=tape] + :~ ;path + =d "M0 0C0 70.6925 57.3075 128 128 128V0H0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M112 64C112 37.4903 90.5097 16 64 16" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;circle + =cx "112" + =cy "64" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "112" + =cy "64" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'lar' + |= [fg=tape bg=tape] + :~ ;circle + =cx "64" + =cy "64" + =r "64" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;line + =x1 "2.78181e-08" + =y1 "64" + =x2 "128" + =y2 "64" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;circle + =cx "64" + =cy "64" + =r "16" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;circle + =cx "64" + =cy "96" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "64" + =cy "96" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + ;circle + =cx "64" + =cy "32" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "64" + =cy "32" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'las' + |= [fg=tape bg=tape] + :~ ;rect + =width "128" + =height "128" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;circle + =cx "64" + =cy "64" + =r "48" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;circle + =cx "16" + =cy "64" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "16" + =cy "64" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'lat' + |= [fg=tape bg=tape] + :~ ;path + =d "M0 0C0 70.6925 57.3075 128 128 128V0H0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M2.03434e-06 128C70.6924 128 128 70.6925 128 0" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M1.52575e-06 96C53.0193 96 96 53.0193 96 0" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M1.01717e-06 64C35.3462 64 64 35.3462 64 0" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M5.08584e-07 32C17.6731 32 32 17.6731 32 0" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'lav' + |= [fg=tape bg=tape] + :~ ;path + =d "M128 0C57.3075 8.42999e-07 -8.42999e-07 57.3075 0 128H128V0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M128 128C92.6489 128 60.6449 113.669 37.4807 90.5" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M128 96C101.492 96 77.4939 85.2564 60.1217 67.8862" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M128 64C110.328 64 94.3287 56.8374 82.7471 45.2568" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M128 32.3716C119.164 32.3716 111.164 28.7903 105.374 23" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'leb' + |= [fg=tape bg=tape] + :~ ;rect + =width "128" + =height "128" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M-1.64036e-05 32C53.0193 32 96 74.9807 96 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'lec' + |= [fg=tape bg=tape] + :~ ;path + =d "M128 128C128 57.3076 70.6925 6.18013e-06 1.11901e-05 0L0 128L128 128Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M-0.00292969 0L127.997 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + ;circle + =cx "64" + =cy "64" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "64" + =cy "64" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'led' + |= [fg=tape bg=tape] + :~ ;circle + =cx "64" + =cy "64" + =r "64" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;circle + =cx "64" + =cy "32" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "64" + =cy "32" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'leg' + |= [fg=tape bg=tape] + :~ ;rect + =width "128" + =height "128" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M7.63192e-07 32C17.6731 32 32 46.3269 32 64C32 81.6731 17.6731 96 0 96" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'len' + |= [fg=tape bg=tape] + :~ ;rect + =width "128" + =height "128" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;circle + =cx "64" + =cy "64" + =r "48" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;circle + =cx "64" + =cy "96" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "64" + =cy "96" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'lep' + |= [fg=tape bg=tape] + :~ ;path + =d "M128 0C57.3075 8.42999e-07 -8.42999e-07 57.3075 0 128H128V0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M128 96C110.327 96 96 110.327 96 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'ler' + |= [fg=tape bg=tape] + :~ ;path + =d "M64 128H0L5.59506e-06 0L64 5.59506e-06C99.3462 8.68512e-06 128 28.6538 128 64C128 99.3462 99.3462 128 64 128Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M32 0L32 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;circle + =cx "32" + =cy "32" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "32" + =cy "32" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'let' + |= [fg=tape bg=tape] + :~ ;circle + =cx "64" + =cy "64" + =r "64" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M64 0L64 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'lev' + |= [fg=tape bg=tape] + :~ ;path + =d "M64 128H0L5.59506e-06 0L64 5.59506e-06C99.3462 8.68512e-06 128 28.6538 128 64C128 99.3462 99.3462 128 64 128Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;circle + =cx "32" + =cy "32" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "32" + =cy "32" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'lex' + |= [fg=tape bg=tape] + :~ ;path + =d "M64 128H0L5.59506e-06 0L64 5.59506e-06C99.3462 8.68512e-06 128 28.6538 128 64C128 99.3462 99.3462 128 64 128Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M-0.00292969 0L127.997 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + ;line + =x1 "15.9965" + =y1 "111.997" + =x2 "47.9965" + =y2 "79.9965" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =fill-rule "evenodd" + =clip-rule "evenodd" + =stroke "none" + =d "M80 64C80 72.8366 72.8366 80 64 80C55.1634 80 48 72.8366 48 64C48 55.1634 55.1634 48 64 48C72.8366 48 80 55.1634 80 64ZM64 72C68.4183 72 72 68.4183 72 64C72 59.5817 68.4183 56 64 56C59.5817 56 56 59.5817 56 64C56 68.4183 59.5817 72 64 72Z" + =fill bg; + == +:: + :- 'lib' + |= [fg=tape bg=tape] + :~ ;circle + =cx "64" + =cy "64" + =r "64" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M128 64C92.6538 64 64 92.6538 64 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M128 64L0 64" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'lid' + |= [fg=tape bg=tape] + :~ ;path + =d "M0 0C0 70.6925 57.3075 128 128 128V0H0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;line + =x1 "16.0036" + =y1 "15.9965" + =x2 "48.0036" + =y2 "47.9965" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M128 0L0 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + == +:: + :- 'lig' + |= [fg=tape bg=tape] + :~ ;circle + =cx "64" + =cy "64" + =r "64" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;circle + =cx "64" + =cy "64" + =r "48" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'lin' + |= [fg=tape bg=tape] + :~ ;rect + =width "128" + =height "128" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;line + =x1 "64" + =y1 "128" + =x2 "64" + =y2 "-6.55671e-08" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;circle + =cx "80" + =cy "64" + =r "8" + =fill bg + =stroke "none"; + == +:: + :- 'lis' + |= [fg=tape bg=tape] + :~ ;path + =d "M128 128C128 57.3076 70.6925 6.18013e-06 1.11901e-05 0L0 128L128 128Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M128 64L0 64" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M-4.70488e-06 64C35.3462 64 64 35.3462 64 0" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'lit' + |= [fg=tape bg=tape] + :~ ;path + =d "M0.0541 0C70.7217 0.0292317 128 57.3256 128 128C57.3177 128 0.0164917 70.7089 7.62806e-06 0.0305091C7.62851e-06 0.0203397 -4.44317e-10 0.01017 0 0H0.0541Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M-0.00286865 0L127.997 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + ;path + =d "M128 0C128 35.3511 113.669 67.3551 90.5 90.5193" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M96 0C96 26.5077 85.2564 50.5061 67.8862 67.8783" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M64 0C64 17.6721 56.8374 33.6713 45.2568 45.2529" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M32.3716 0C32.3716 8.83603 28.7903 16.8356 23 22.6264" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'liv' + |= [fg=tape bg=tape] + :~ ;rect + =width "128" + =height "128" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M-5.21346e-06 32C70.6924 32 128 17.6731 128 0" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M3.4331e-06 96C70.6924 96 128 53.0193 128 0" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M64 0L64 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'loc' + |= [fg=tape bg=tape] + :~ ;path + =d "M0.0541 0C70.7217 0.0292317 128 57.3256 128 128C57.3177 128 0.0164917 70.7089 7.62806e-06 0.0305091C7.62851e-06 0.0203397 -4.44317e-10 0.01017 0 0H0.0541Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M128 96C74.9807 96 32 53.0193 32 -4.19629e-06" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'lod' + |= [fg=tape bg=tape] + :~ ;path + =d "M64 0H128V128H64C28.6538 128 0 99.3462 0 64C0 28.6538 28.6538 0 64 0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M16 64C16 90.5097 37.4903 112 64 112" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'lom' + |= [fg=tape bg=tape] + :~ ;rect + =width "128" + =height "128" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;circle + =cx "32" + =cy "32" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "32" + =cy "32" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + ;circle + =cx "96" + =cy "32" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "96" + =cy "32" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + ;circle + =cx "96" + =cy "96" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "96" + =cy "96" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'lon' + |= [fg=tape bg=tape] + :~ ;path + =d "M128 0C57.3075 8.42999e-07 -8.42999e-07 57.3075 0 128H128V0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M2.03434e-06 128C70.6924 128 128 70.6925 128 0" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M1.52575e-06 96C53.0193 96 96 53.0193 96 0" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M1.01717e-06 64C35.3462 64 64 35.3462 64 0" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M5.08584e-07 32C17.6731 32 32 17.6731 32 0" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'lop' + |= [fg=tape bg=tape] + :~ ;circle + =cx "64" + =cy "64" + =r "64" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;line + =x1 "128" + =y1 "64" + =x2 "-8.87604e-09" + =y2 "64" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;line + =x1 "128" + =y1 "32" + =x2 "-8.87604e-09" + =y2 "32" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;circle + =cx "64" + =cy "64" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "64" + =cy "64" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'lor' + |= [fg=tape bg=tape] + :~ ;path + =d "M64 0H128V128H64C28.6538 128 0 99.3462 0 64C0 28.6538 28.6538 0 64 0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;line + =x1 "64" + =y1 "2.18557e-08" + =x2 "64" + =y2 "128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'los' + |= [fg=tape bg=tape] + :~ ;path + =d "M0 0C0 70.6925 57.3075 128 128 128V0H0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;line + =x1 "-0.0029152" + =x2 "127.983" + =y2 "127.986" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + ;circle + =cx "96" + =cy "96" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "96" + =cy "96" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'luc' + |= [fg=tape bg=tape] + :~ ;path + =d "M128 128C128 57.3076 70.6925 6.18013e-06 1.11901e-05 0L0 128L128 128Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;line + =x1 "128" + =y1 "64" + =x2 "-8.87604e-09" + =y2 "64" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M128 64L0 64" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M128 96L0 96" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'lud' + |= [fg=tape bg=tape] + :~ ;path + =d "M128 128C128 57.3076 70.6925 6.18013e-06 1.11901e-05 0L0 128L128 128Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M128 64L0 64" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M32 0L32 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M64 0L64 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M96 0L96 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'lug' + |= [fg=tape bg=tape] + :~ ;path + =d "M64 128H0L5.59506e-06 -7.62939e-06L64 -2.03434e-06C99.3462 1.05573e-06 128 28.6538 128 64C128 99.3462 99.3462 128 64 128Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + == +:: + :- 'lun' + |= [fg=tape bg=tape] + :~ ;circle + =cx "64" + =cy "64" + =r "64" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;circle + =cx "64" + =cy "64" + =r "32" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'lup' + |= [fg=tape bg=tape] + :~ ;path + =d "M64 128H0L5.59506e-06 -7.62939e-06L64 -2.03434e-06C99.3462 1.05573e-06 128 28.6538 128 64C128 99.3462 99.3462 128 64 128Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M64 16C90.5097 16 112 37.4903 112 64C112 90.5097 90.5097 112 64 112" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;line + =x1 "128" + =y1 "64" + =x2 "-8.87604e-09" + =y2 "64" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'lur' + |= [fg=tape bg=tape] + :~ ;path + =d "M128 128C128 57.3076 70.6925 6.18013e-06 1.11901e-05 0L0 128L128 128Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M64 0L64 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M96 0L96 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M32 0L32 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'lus' + |= [fg=tape bg=tape] + :~ ;path + =d "M128 128C128 57.3076 70.6925 6.18013e-06 1.11901e-05 0L0 128L128 128Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M128 0L0 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + ;circle + =cx "96" + =cy "96" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "96" + =cy "96" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'lut' + |= [fg=tape bg=tape] + :~ ;rect + =width "128" + =height "128" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;circle + =cx "32" + =cy "64" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "32" + =cy "64" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'lux' + |= [fg=tape bg=tape] + :~ ;path + =d "M5.59506e-06 128C70.6925 128 128 70.6925 128 0L0 5.59506e-06L5.59506e-06 128Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =fill-rule "evenodd" + =clip-rule "evenodd" + =stroke "none" + =d "M80 64C80 72.8366 72.8366 80 64 80C55.1634 80 48 72.8366 48 64C48 55.1634 55.1634 48 64 48C72.8366 48 80 55.1634 80 64ZM64 72C68.4183 72 72 68.4183 72 64C72 59.5817 68.4183 56 64 56C59.5817 56 56 59.5817 56 64C56 68.4183 59.5817 72 64 72Z" + =fill bg; + == +:: + :- 'lyd' + |= [fg=tape bg=tape] + :~ ;path + =d "M0.0541 0C70.7217 0.0292317 128 57.3256 128 128C57.3177 128 0.0164917 70.7089 7.62806e-06 0.0305091C7.62851e-06 0.0203397 -4.44317e-10 0.01017 0 0H0.0541Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M-0.00280762 0L127.997 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + ;circle + =cx "64" + =cy "64" + =r "32" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;circle + =cx "64" + =cy "32" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "64" + =cy "32" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'lyn' + |= [fg=tape bg=tape] + :~ ;path + =d "M5.59506e-06 128C70.6925 128 128 70.6925 128 0L0 5.59506e-06L5.59506e-06 128Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M32 0L32 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'lyr' + |= [fg=tape bg=tape] + :~ ;path + =d "M0 127.946C0.0292286 57.2783 57.3256 3.08928e-06 128 0C128 70.6823 70.7089 127.984 0.0305092 128C0.0203397 128 0.01017 128 2.36469e-09 128L0 127.946Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M-0.00268555 0L127.997 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + ;circle + =cx "80" + =cy "48" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "80" + =cy "48" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'lys' + |= [fg=tape bg=tape] + :~ ;path + =d "M128 128C128 57.3076 70.6925 6.18013e-06 1.11901e-05 0L0 128L128 128Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;circle + =cx "64" + =cy "64" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "64" + =cy "64" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + ;circle + =cx "16" + =cy "112" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "16" + =cy "112" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'lyt' + |= [fg=tape bg=tape] + :~ ;path + =d "M64 128H0L5.59506e-06 0L64 5.59506e-06C99.3462 8.68512e-06 128 28.6538 128 64C128 99.3462 99.3462 128 64 128Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M128 0L0 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + ;line + =x1 "80.0035" + =y1 "79.9965" + =x2 "112.003" + =y2 "111.997" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;circle + =cx "64" + =cy "64" + =r "16" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'lyx' + |= [fg=tape bg=tape] + :~ ;path + =d "M5.59506e-06 128C70.6925 128 128 70.6925 128 0L0 5.59506e-06L5.59506e-06 128Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M-0.00292969 0L127.997 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + ;circle + =cx "32" + =cy "32" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "32" + =cy "32" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'mac' + |= [fg=tape bg=tape] + :~ ;path + =d "M0 0C0 70.6925 57.3075 128 128 128V0H0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;circle + =cx "16" + =cy "112" + =r "11.5" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + ;circle + =cx "16" + =cy "112" + =r "9" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + :: =stroke-width "2" + == +:: + :- 'mag' + |= [fg=tape bg=tape] + :~ ;path + =d "M64 0H128V128H64C28.6538 128 0 99.3462 0 64C0 28.6538 28.6538 0 64 0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;circle + =cx "64" + =cy "64" + =r "32" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M128 64L0 64" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;circle + =cx "64" + =cy "96" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "64" + =cy "96" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'mal' + |= [fg=tape bg=tape] + :~ ;path + =d "M0.0541 0C70.7217 0.0292317 128 57.3256 128 128C57.3177 128 0.0164917 70.7089 7.62806e-06 0.0305091C7.62851e-06 0.0203397 -4.44317e-10 0.01017 0 0H0.0541Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;line + =x1 "80.0035" + =y1 "79.9964" + =x2 "112.004" + =y2 "111.996" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;circle + =cx "16" + =cy "112" + =r "11.5" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + ;circle + =cx "16" + =cy "112" + =r "9" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + :: =stroke-width "2" + == +:: + :- 'map' + |= [fg=tape bg=tape] + :~ ;path + =d "M128 0C57.3075 8.42999e-07 -8.42999e-07 57.3075 0 128H128V0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;line + =x1 "80.0036" + =y1 "79.9965" + =x2 "112.004" + =y2 "111.997" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;circle + =cx "64" + =cy "64" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "64" + =cy "64" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'mar' + |= [fg=tape bg=tape] + :~ ;circle + =cx "64" + =cy "64" + =r "64" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M-0.0029152 0L127.997 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + ;path + =d "M64 64L64 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M86.6274 86.6274C99.1242 74.1307 99.1242 53.8694 86.6274 41.3726C74.1306 28.8758 53.8694 28.8758 41.3726 41.3726" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M75.3137 75.3137C81.5621 69.0653 81.5621 58.9347 75.3137 52.6863C69.0653 46.4379 58.9347 46.4379 52.6863 52.6863" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M97.9411 97.9411C116.686 79.1959 116.686 48.804 97.9411 30.0589C79.196 11.3137 48.804 11.3137 30.0589 30.0589" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'mas' + |= [fg=tape bg=tape] + :~ ;rect + =width "128" + =height "128" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;circle + =cx "64" + =cy "64" + =r "32" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =fill-rule "evenodd" + =clip-rule "evenodd" + =stroke "none" + =d "M80 64C80 72.8366 72.8366 80 64 80C55.1634 80 48 72.8366 48 64C48 55.1634 55.1634 48 64 48C72.8366 48 80 55.1634 80 64ZM64 72C68.4183 72 72 68.4183 72 64C72 59.5817 68.4183 56 64 56C59.5817 56 56 59.5817 56 64C56 68.4183 59.5817 72 64 72Z" + =fill bg; + == +:: + :- 'mat' + |= [fg=tape bg=tape] + :~ ;path + =d "M0 0C0 70.6925 57.3075 128 128 128V0H0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M128 32C110.327 32 96 17.6731 96 0" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'meb' + |= [fg=tape bg=tape] + :~ ;rect + =width "128" + =height "128" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M32 -3.05151e-06C32 53.0193 74.9807 96 128 96" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'mec' + |= [fg=tape bg=tape] + :~ ;path + =d "M128 128C128 57.3076 70.6925 6.18013e-06 1.11901e-05 0L0 128L128 128Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;line + =x1 "80.0035" + =y1 "79.9965" + =x2 "112.003" + =y2 "111.997" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;circle + =cx "64" + =cy "64" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "64" + =cy "64" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'med' + |= [fg=tape bg=tape] + :~ ;circle + =cx "64" + =cy "64" + =r "64" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;circle + =cx "96" + =cy "64" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "96" + =cy "64" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'meg' + |= [fg=tape bg=tape] + :~ ;rect + =width "128" + =height "128" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M128 64C92.6538 64 64 92.6538 64 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'mel' + |= [fg=tape bg=tape] + :~ ;path + =d "M0 127.946C0.0292286 57.2783 57.3256 3.08928e-06 128 0C128 70.6823 70.7089 127.984 0.0305092 128C0.0203397 128 0.01017 128 2.36469e-09 128L0 127.946Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;line + =x1 "15.9964" + =y1 "111.997" + =x2 "47.9964" + =y2 "79.9965" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'mep' + |= [fg=tape bg=tape] + :~ ;path + =d "M128 0C57.3075 8.42999e-07 -8.42999e-07 57.3075 0 128H128V0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M128 64L0 64" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M128 96L0 96" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M128 32L0 32" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'mer' + |= [fg=tape bg=tape] + :~ ;path + =d "M64 128H0L5.59506e-06 0L64 5.59506e-06C99.3462 8.68512e-06 128 28.6538 128 64C128 99.3462 99.3462 128 64 128Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M32 0L32 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'mes' + |= [fg=tape bg=tape] + :~ ;path + =d "M128 128C128 57.3076 70.6925 6.18013e-06 1.11901e-05 0L0 128L128 128Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M-0.00280762 0L127.997 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + ;line + =x1 "15.9964" + =y1 "111.996" + =x2 "47.9964" + =y2 "79.9964" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'met' + |= [fg=tape bg=tape] + :~ ;circle + =cx "64" + =cy "64" + =r "64" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M32 128L32 0" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'mev' + |= [fg=tape bg=tape] + :~ ;path + =d "M64 128H0L5.59506e-06 0L64 5.59506e-06C99.3462 8.68512e-06 128 28.6538 128 64C128 99.3462 99.3462 128 64 128Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;circle + =cx "64" + =cy "64" + =r "16" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'mex' + |= [fg=tape bg=tape] + :~ ;path + =d "M64 128H0L5.59506e-06 0L64 5.59506e-06C99.3462 8.68512e-06 128 28.6538 128 64C128 99.3462 99.3462 128 64 128Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M-0.00292969 0L127.997 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + ;path + =fill-rule "evenodd" + =clip-rule "evenodd" + =stroke "none" + =d "M80 64C80 72.8366 72.8366 80 64 80C55.1634 80 48 72.8366 48 64C48 55.1634 55.1634 48 64 48C72.8366 48 80 55.1634 80 64ZM64 72C68.4183 72 72 68.4183 72 64C72 59.5817 68.4183 56 64 56C59.5817 56 56 59.5817 56 64C56 68.4183 59.5817 72 64 72Z" + =fill bg; + == +:: + :- 'mic' + |= [fg=tape bg=tape] + :~ ;path + =d "M128 128C128 57.3076 70.6925 6.18013e-06 1.11901e-05 0L0 128L128 128Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M-2.09815e-06 80C26.5097 80 48 101.49 48 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'mid' + |= [fg=tape bg=tape] + :~ ;path + =d "M0 0C0 70.6925 57.3075 128 128 128V0H0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;line + =x1 "128" + =y1 "64" + =x2 "-4.37114e-08" + =y2 "64" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M128 64C92.6538 64 64 92.6538 64 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'mig' + |= [fg=tape bg=tape] + :~ ;path + =d "M64 0H128V128H64C28.6538 128 0 99.3462 0 64C0 28.6538 28.6538 0 64 0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;line + =x1 "64" + =y1 "2.18557e-08" + =x2 "64" + =y2 "128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;line + =x1 "80.0036" + =y1 "79.9965" + =x2 "112.004" + =y2 "111.997" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;circle + =cx "64" + =cy "64" + =r "16" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'mil' + |= [fg=tape bg=tape] + :~ ;path + =d "M64 0H128V128H64C28.6538 128 0 99.3462 0 64C0 28.6538 28.6538 0 64 0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;line + =x1 "128" + =y1 "64" + =x2 "-4.37114e-08" + =y2 "64" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;line + =x1 "128" + =y1 "32" + =x2 "-4.37114e-08" + =y2 "32" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;line + =x1 "128" + =y1 "96" + =x2 "-4.37114e-08" + =y2 "96" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'min' + |= [fg=tape bg=tape] + :~ ;rect + =width "128" + =height "128" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;line + =x1 "-0.0029152" + =x2 "127.983" + =y2 "127.986" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + == +:: + :- 'mip' + |= [fg=tape bg=tape] + :~ ;path + =d "M128 0C57.3075 8.42999e-07 -8.42999e-07 57.3075 0 128H128V0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;line + =x1 "64" + =y1 "2.18557e-08" + =x2 "64" + =y2 "128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M128 128C92.6538 128 64 99.3462 64 64C64 28.6538 92.6538 4.215e-07 128 0" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;circle + =cx "64" + =cy "64" + =r "16" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'mir' + |= [fg=tape bg=tape] + :~ ;path + =d "M0 0C0 70.6925 57.3075 128 128 128V0H0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;line + =x1 "16.0036" + =y1 "15.9964" + =x2 "48.0036" + =y2 "47.9964" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M96 64C96 46.3269 81.6731 32 64 32" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;circle + =cx "64" + =cy "64" + =r "16" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'mis' + |= [fg=tape bg=tape] + :~ ;path + =d "M128 0C57.3075 8.42999e-07 -8.42999e-07 57.3075 0 128H128V0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M128 64C92.6538 64 64 92.6538 64 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M-0.00286865 0L127.997 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + == +:: + :- 'mit' + |= [fg=tape bg=tape] + :~ ;path + =d "M0.0541 0C70.7217 0.0292317 128 57.3256 128 128C57.3177 128 0.0164917 70.7089 7.62806e-06 0.0305091C7.62851e-06 0.0203397 -4.44317e-10 0.01017 0 0H0.0541Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;line + =x1 "0.5" + =y1 "-0.5" + =x2 "181.5" + =y2 "-0.5" + =transform "matrix(-0.707107 0.707107 0.707107 0.707107 128.71 0)" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + ;circle + =cx "32" + =cy "32" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "32" + =cy "32" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'moc' + |= [fg=tape bg=tape] + :~ ;path + =d "M0.0541 0C70.7217 0.0292317 128 57.3256 128 128C57.3177 128 0.0164917 70.7089 7.62806e-06 0.0305091C7.62851e-06 0.0203397 -4.44317e-10 0.01017 0 0H0.0541Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M128 64L0 64" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M128 96L0 96" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M128 32L0 32" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'mod' + |= [fg=tape bg=tape] + :~ ;path + =d "M64 0H128V128H64C28.6538 128 0 99.3462 0 64C0 28.6538 28.6538 0 64 0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M0 96L128 96" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;line + =x1 "16.0035" + =y1 "15.9965" + =x2 "48.0035" + =y2 "47.9965" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'mog' + |= [fg=tape bg=tape] + :~ ;path + =d "M128 0C57.3075 8.42999e-07 -8.42999e-07 57.3075 0 128H128V0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;line + =x1 "-0.0029152" + =x2 "127.983" + =y2 "127.986" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + ;circle + =cx "64" + =cy "64" + =r "32" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;circle + =cx "64" + =cy "64" + =r "16" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'mol' + |= [fg=tape bg=tape] + :~ ;circle + =cx "64" + =cy "64" + =r "64" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;line + =x1 "128" + =y1 "64" + =x2 "-4.37114e-08" + =y2 "64" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M112 64C112 90.5097 90.5097 112 64 112C37.4903 112 16 90.5097 16 64" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M112 0C112 26.5097 90.5097 48 64 48C37.4903 48 16 26.5097 16 0" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'mon' + |= [fg=tape bg=tape] + :~ ;path + =d "M128 0C57.3075 8.42999e-07 -8.42999e-07 57.3075 0 128H128V0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =fill-rule "evenodd" + =clip-rule "evenodd" + =stroke "none" + =d "M80 64C80 72.8366 72.8366 80 64 80C55.1634 80 48 72.8366 48 64C48 55.1634 55.1634 48 64 48C72.8366 48 80 55.1634 80 64ZM64 72C68.4183 72 72 68.4183 72 64C72 59.5817 68.4183 56 64 56C59.5817 56 56 59.5817 56 64C56 68.4183 59.5817 72 64 72Z" + =fill bg; + == +:: + :- 'mop' + |= [fg=tape bg=tape] + :~ ;circle + =cx "64" + =cy "64" + =r "64" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;line + =x1 "-0.0029152" + =x2 "127.983" + =y2 "127.986" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + ;circle + =cx "64" + =cy "64" + =r "32" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;circle + =cx "32" + =cy "64" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "32" + =cy "64" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'mor' + |= [fg=tape bg=tape] + :~ ;path + =d "M64 0H128V128H64C28.6538 128 0 99.3462 0 64C0 28.6538 28.6538 0 64 0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;line + =x1 "16.0035" + =y1 "15.9964" + =x2 "48.0035" + =y2 "47.9964" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;line + =x1 "15.9964" + =y1 "111.996" + =x2 "47.9964" + =y2 "79.9964" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;circle + =cx "64" + =cy "64" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "64" + =cy "64" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'mos' + |= [fg=tape bg=tape] + :~ ;path + =d "M0 0C0 70.6925 57.3075 128 128 128V0H0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;line + =x1 "0.5" + =y1 "-0.5" + =x2 "181.5" + =y2 "-0.5" + =transform "matrix(-0.707107 0.707107 0.707107 0.707107 128.71 0)" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + ;circle + =cx "96" + =cy "32" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "96" + =cy "32" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'mot' + |= [fg=tape bg=tape] + :~ ;path + =d "M64 0H128V128H64C28.6538 128 0 99.3462 0 64C0 28.6538 28.6538 0 64 0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M128 96C110.327 96 96 81.6731 96 64C96 46.3269 110.327 32 128 32" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;circle + =cx "64" + =cy "64" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "64" + =cy "64" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'mud' + |= [fg=tape bg=tape] + :~ ;path + =d "M128 128C128 57.3076 70.6925 6.18013e-06 1.11901e-05 0L0 128L128 128Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M-0.00292969 0L127.997 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + ;circle + =cx "80" + =cy "80" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "80" + =cy "80" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'mug' + |= [fg=tape bg=tape] + :~ ;path + =d "M64 128H0L5.59506e-06 0L64 5.59506e-06C99.3462 8.68512e-06 128 28.6538 128 64C128 99.3462 99.3462 128 64 128Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M64 96C81.6731 96 96 81.6731 96 64C96 46.3269 81.6731 32 64 32" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'mul' + |= [fg=tape bg=tape] + :~ ;circle + =cx "64" + =cy "64" + =r "64" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;line + =x1 "80.0035" + =y1 "79.9964" + =x2 "112.003" + =y2 "111.996" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M112 64C112 37.4903 90.5097 16 64 16" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'mun' + |= [fg=tape bg=tape] + :~ ;circle + =cx "64" + =cy "64" + =r "64" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M128 64C92.6538 64 64 35.3462 64 0" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;circle + =cx "64" + =cy "64" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "64" + =cy "64" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'mur' + |= [fg=tape bg=tape] + :~ ;path + =d "M128 128C128 57.3076 70.6925 6.18013e-06 1.11901e-05 0L0 128L128 128Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M128 64L0 64" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;circle + =cx "64" + =cy "64" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "64" + =cy "64" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + ;circle + =cx "32" + =cy "64" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "32" + =cy "64" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'mus' + |= [fg=tape bg=tape] + :~ ;path + =d "M128 128C128 57.3076 70.6925 6.18013e-06 1.11901e-05 0L0 128L128 128Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;line + =x1 "0.5" + =y1 "-0.5" + =x2 "181.5" + =y2 "-0.5" + =transform "matrix(-0.707107 0.707107 0.707107 0.707107 128.71 0)" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + ;path + =d "M96 128C96 74.9807 53.0193 32 0 32" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'mut' + |= [fg=tape bg=tape] + :~ ;rect + =width "128" + =height "128" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;circle + =cx "96" + =cy "32" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "96" + =cy "32" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'myl' + |= [fg=tape bg=tape] + :~ ;path + =d "M5.59506e-06 128C70.6925 128 128 70.6925 128 0L0 5.59506e-06L5.59506e-06 128Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;line + =x1 "16.0035" + =y1 "15.9965" + =x2 "48.0035" + =y2 "47.9965" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;circle + =cx "16" + =cy "16" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "16" + =cy "16" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'myn' + |= [fg=tape bg=tape] + :~ ;path + =d "M5.59506e-06 128C70.6925 128 128 70.6925 128 0L0 5.59506e-06L5.59506e-06 128Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M128 1.52638e-06C57.3076 -7.74381e-06 9.2702e-06 57.3075 0 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M128 32C74.9807 32 32 74.9807 32 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M128 64C92.6538 64 64 92.6538 64 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M128 96C110.327 96 96 110.327 96 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'myr' + |= [fg=tape bg=tape] + :~ ;path + =d "M0 127.946C0.0292286 57.2783 57.3256 3.08928e-06 128 0C128 70.6823 70.7089 127.984 0.0305092 128C0.0203397 128 0.01017 128 2.36469e-09 128L0 127.946Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M-0.00292969 0L127.997 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + ;circle + =cx "32" + =cy "96" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "32" + =cy "96" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'nac' + |= [fg=tape bg=tape] + :~ ;path + =d "M0 0C0 70.6925 57.3075 128 128 128V0H0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;circle + =cx "64" + =cy "64" + =r "16" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;circle + =cx "16" + =cy "112" + =r "11.5" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + ;circle + =cx "16" + =cy "112" + =r "9" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + :: =stroke-width "2" + == +:: + :- 'nal' + |= [fg=tape bg=tape] + :~ ;path + =d "M0.0541 0C70.7217 0.0292317 128 57.3256 128 128C57.3177 128 0.0164917 70.7089 7.62806e-06 0.0305091C7.62851e-06 0.0203397 -4.44317e-10 0.01017 0 0H0.0541Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;line + =x1 "-0.0029152" + =x2 "127.983" + =y2 "127.986" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + ;path + =d "M2.82114e-06 110C60.7513 110 110 60.7513 110 0" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M-5.09828e-06 73C40.3168 73 73 40.3168 73 0" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M-6.63647e-07 37C20.4345 37 37 20.4345 37 0" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'nam' + |= [fg=tape bg=tape] + :~ ;path + =d "M64 0H128V128H64C28.6538 128 0 99.3462 0 64C0 28.6538 28.6538 0 64 0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;line + =x1 "8.74228e-08" + =y1 "64" + =x2 "128" + =y2 "64" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;circle + =cx "64" + =cy "64" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "64" + =cy "64" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + ;circle + =cx "112" + =cy "64" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "112" + =cy "64" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'nap' + |= [fg=tape bg=tape] + :~ ;path + =d "M128 0C57.3075 8.42999e-07 -8.42999e-07 57.3075 0 128H128V0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;line + =x1 "64" + =y1 "2.18557e-08" + =x2 "64" + =y2 "128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;circle + =cx "96" + =cy "32" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "96" + =cy "32" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + ;circle + =cx "96" + =cy "96" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "96" + =cy "96" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'nar' + |= [fg=tape bg=tape] + :~ ;circle + =cx "64" + =cy "64" + =r "64" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;circle + =cx "64" + =cy "64" + =r "32" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;circle + =cx "64" + =cy "64" + =r "8" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'nat' + |= [fg=tape bg=tape] + :~ ;path + =d "M0 0C0 70.6925 57.3075 128 128 128V0H0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M-1.52588e-05 128C-9.07866e-06 57.3075 57.3076 1.44926e-06 128 7.62939e-06" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'nav' + |= [fg=tape bg=tape] + :~ ;path + =d "M0 0C0 70.6925 57.3075 128 128 128V0H0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M128 96C101.492 96 77.4939 85.2564 60.1217 67.8862" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M128 64C110.328 64 94.3287 56.8374 82.7471 45.2568" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M128 32.3716C119.164 32.3716 111.164 28.7903 105.374 23" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'neb' + |= [fg=tape bg=tape] + :~ ;rect + =width "128" + =height "128" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M128 32C74.9807 32 32 74.9807 32 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'nec' + |= [fg=tape bg=tape] + :~ ;path + =d "M128 128C128 57.3076 70.6925 6.18013e-06 1.11901e-05 0L0 128L128 128Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;circle + =cx "32" + =cy "32" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "32" + =cy "32" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + ;circle + =cx "96" + =cy "96" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "96" + =cy "96" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + ;path + =d "M64 0L64 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'ned' + |= [fg=tape bg=tape] + :~ ;circle + =cx "64" + =cy "64" + =r "64" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;circle + =cx "64" + =cy "64" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "64" + =cy "64" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'nel' + |= [fg=tape bg=tape] + :~ ;path + =d "M0 127.946C0.0292286 57.2783 57.3256 3.08928e-06 128 0C128 70.6823 70.7089 127.984 0.0305092 128C0.0203397 128 0.01017 128 2.36469e-09 128L0 127.946Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M-0.00268555 0L127.997 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + ;path + =d "M96 1.90735e-06C96 53.0193 53.0193 96 0 96" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'nem' + |= [fg=tape bg=tape] + :~ ;circle + =cx "64" + =cy "64" + =r "64" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M-0.00292969 0L127.997 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + ;path + =d "M128 64C92.6538 64 64 92.6538 64 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;circle + =cx "32" + =cy "32" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "32" + =cy "32" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'nep' + |= [fg=tape bg=tape] + :~ ;path + =d "M128 128C128 57.3076 70.6925 6.18013e-06 1.11901e-05 0L0 128L128 128Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M128 128C57.3076 128 3.09007e-06 70.6925 0 0" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M128 96C74.9807 96 32 53.0193 32 0" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M128 64C92.6538 64 64 35.3462 64 0" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M128 32C110.327 32 96 17.6731 96 0" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'ner' + |= [fg=tape bg=tape] + :~ ;path + =d "M64 128H0L5.59506e-06 0L64 5.59506e-06C99.3462 8.68512e-06 128 28.6538 128 64C128 99.3462 99.3462 128 64 128Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M64 0L64 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;line + =x1 "15.9965" + =y1 "111.997" + =x2 "47.9965" + =y2 "79.9965" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'nes' + |= [fg=tape bg=tape] + :~ ;path + =d "M128 0C57.3075 8.42999e-07 -8.42999e-07 57.3075 0 128H128V0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M64 0L64 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'net' + |= [fg=tape bg=tape] + :~ ;circle + =cx "64" + =cy "64" + =r "64" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M64 64L64 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'nev' + |= [fg=tape bg=tape] + :~ ;path + =d "M64 128H0L5.59506e-06 0L64 5.59506e-06C99.3462 8.68512e-06 128 28.6538 128 64C128 99.3462 99.3462 128 64 128Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;circle + =cx "64" + =cy "64" + =r "16" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;circle + =cx "32" + =cy "32" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "32" + =cy "32" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'nex' + |= [fg=tape bg=tape] + :~ ;path + =d "M64 128H0L5.59506e-06 -7.62939e-06L64 -2.03434e-06C99.3462 1.05573e-06 128 28.6538 128 64C128 99.3462 99.3462 128 64 128Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;line + =x1 "80.0035" + =y1 "79.9964" + =x2 "112.003" + =y2 "111.996" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =fill-rule "evenodd" + =clip-rule "evenodd" + =stroke "none" + =d "M80 64C80 72.8366 72.8366 80 64 80C55.1634 80 48 72.8366 48 64C48 55.1634 55.1634 48 64 48C72.8366 48 80 55.1634 80 64ZM64 72C68.4183 72 72 68.4183 72 64C72 59.5817 68.4183 56 64 56C59.5817 56 56 59.5817 56 64C56 68.4183 59.5817 72 64 72Z" + =fill bg; + == +:: + :- 'nib' + |= [fg=tape bg=tape] + :~ ;circle + =cx "64" + =cy "64" + =r "64" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M128 64L0 64" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M128 96L0 96" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'nid' + |= [fg=tape bg=tape] + :~ ;path + =d "M0 0C0 70.6925 57.3075 128 128 128V0H0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M128 64L0 64" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M128 128C92.6538 128 64 70.6925 64 7.63192e-07" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'nil' + |= [fg=tape bg=tape] + :~ ;path + =d "M64 0H128V128H64C28.6538 128 0 99.3462 0 64C0 28.6538 28.6538 0 64 0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;line + =x1 "128" + =y1 "64" + =x2 "-8.87604e-09" + =y2 "64" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;line + =x1 "128" + =y1 "32" + =x2 "-8.87604e-09" + =y2 "32" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'nim' + |= [fg=tape bg=tape] + :~ ;path + =d "M128 64V128H0L2.79753e-06 64C4.34256e-06 28.6538 28.6538 -1.54503e-06 64 0C99.3462 1.54503e-06 128 28.6538 128 64Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;line + =x1 "64" + =y1 "2.18557e-08" + =x2 "64" + =y2 "128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'nis' + |= [fg=tape bg=tape] + :~ ;path + =d "M128 0C57.3075 8.42999e-07 -8.42999e-07 57.3075 0 128H128V0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M128 32C74.9807 32 32 74.9807 32 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M-0.00285435 0L127.997 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + == +:: + :- 'noc' + |= [fg=tape bg=tape] + :~ ;path + =d "M64 0H128V128H64C28.6538 128 0 99.3462 0 64C0 28.6538 28.6538 0 64 0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;line + =x1 "64" + =y1 "2.18557e-08" + =x2 "64" + =y2 "128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;circle + =cx "64" + =cy "64" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "64" + =cy "64" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'nod' + |= [fg=tape bg=tape] + :~ ;path + =d "M64 0H128V128H64C28.6538 128 0 99.3462 0 64C0 28.6538 28.6538 0 64 0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;circle + =cx "32" + =cy "64" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "32" + =cy "64" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + ;circle + =cx "96" + =cy "64" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "96" + =cy "64" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'nol' + |= [fg=tape bg=tape] + :~ ;circle + =cx "64" + =cy "64" + =r "64" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;line + =x1 "128" + =y1 "64" + =x2 "1.51277e-05" + =y2 "64" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;circle + =cx "64" + =cy "96" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "64" + =cy "96" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'nom' + |= [fg=tape bg=tape] + :~ ;rect + =width "128" + =height "128" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;circle + =cx "32" + =cy "96" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "32" + =cy "96" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + ;circle + =cx "96" + =cy "96" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "96" + =cy "96" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + ;circle + =cx "96" + =cy "32" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "96" + =cy "32" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'nop' + |= [fg=tape bg=tape] + :~ ;circle + =cx "64" + =cy "64" + =r "64" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;line + =x1 "-0.0029152" + =x2 "127.983" + =y2 "127.986" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + ;line + =y1 "-0.5" + =x2 "45.2548" + =y2 "-0.5" + =transform "matrix(0.707107 -0.707107 -0.707107 -0.707107 79.65 47.65)" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;circle + =cx "64" + =cy "64" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "64" + =cy "64" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'nor' + |= [fg=tape bg=tape] + :~ ;path + =d "M64 0H128V128H64C28.6538 128 0 99.3462 0 64C0 28.6538 28.6538 0 64 0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M64 96C46.3269 96 32 81.6731 32 64" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;circle + =cx "64" + =cy "64" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "64" + =cy "64" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'nos' + |= [fg=tape bg=tape] + :~ ;path + =d "M0 0C0 70.6925 57.3075 128 128 128V0H0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;line + =x1 "0.5" + =y1 "-0.5" + =x2 "181.5" + =y2 "-0.5" + =transform "matrix(-0.707107 0.707107 0.707107 0.707107 128.71 0)" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + ;circle + =cx "32" + =cy "32" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "32" + =cy "32" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'nov' + |= [fg=tape bg=tape] + :~ ;rect + =width "128" + =height "128" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;line + =x1 "-0.0029152" + =x2 "127.983" + =y2 "127.986" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + ;path + =d "M2.03434e-06 128C70.6924 128 128 70.6925 128 0" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M1.52575e-06 96C53.0193 96 96 53.0193 96 0" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M1.01717e-06 64C35.3462 64 64 35.3462 64 0" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M5.08584e-07 32C17.6731 32 32 17.6731 32 0" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'nub' + |= [fg=tape bg=tape] + :~ ;path + =d "M128 128C128 57.3076 70.6925 6.18013e-06 1.11901e-05 0L0 128L128 128Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M128 64L0 64" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'nul' + |= [fg=tape bg=tape] + :~ ;circle + =cx "64" + =cy "64" + =r "64" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;circle + =cx "64" + =cy "64" + =r "32" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;circle + =cx "32" + =cy "64" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "32" + =cy "64" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'num' + |= [fg=tape bg=tape] + :~ ;path + =d "M128 128C128 57.3076 70.6925 6.18013e-06 1.11901e-05 0L0 128L128 128Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M128 0L0 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + ;circle + =cx "32" + =cy "32" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "32" + =cy "32" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + ;circle + =cx "96" + =cy "96" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "96" + =cy "96" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'nup' + |= [fg=tape bg=tape] + :~ ;path + =d "M64 128H0L5.59506e-06 -7.62939e-06L64 -2.03434e-06C99.3462 1.05573e-06 128 28.6538 128 64C128 99.3462 99.3462 128 64 128Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M64 16C90.5097 16 112 37.4903 112 64C112 90.5097 90.5097 112 64 112" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'nus' + |= [fg=tape bg=tape] + :~ ;path + =d "M128 128C128 57.3076 70.6925 6.18013e-06 1.11901e-05 0L0 128L128 128Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M-0.00280762 0L127.997 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + ;path + =d "M0.000105172 128C35.3582 128 67.3679 113.664 90.5332 90.4863" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;circle + =cx "31" + =cy "32" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "31" + =cy "32" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'nut' + |= [fg=tape bg=tape] + :~ ;rect + =width "128" + =height "128" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;line + =x1 "80.0035" + =y1 "79.9964" + =x2 "112.003" + =y2 "111.996" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;line + =y1 "-0.5" + =x2 "45.2548" + =y2 "-0.5" + =transform "matrix(0.707107 -0.707107 -0.707107 -0.707107 79.6499 47.6499)" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;circle + =cx "96" + =cy "96" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "96" + =cy "96" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'nux' + |= [fg=tape bg=tape] + :~ ;path + =d "M128 128C128 57.3076 70.6925 6.18013e-06 1.11901e-05 0L0 128L128 128Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M128 64L0 64" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M128 96L0 96" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M128 32L0 32" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'nyd' + |= [fg=tape bg=tape] + :~ ;path + =d "M0.0541 0C70.7217 0.0292317 128 57.3256 128 128C57.3177 128 0.0164917 70.7089 7.62806e-06 0.0305091C7.62851e-06 0.0203397 -4.44317e-10 0.01017 0 0H0.0541Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M-0.00292969 0L127.997 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + ;circle + =cx "64" + =cy "64" + =r "32" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;circle + =cx "64" + =cy "64" + =r "16" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'nyl' + |= [fg=tape bg=tape] + :~ ;path + =d "M128 128C128 57.3076 70.6925 6.18013e-06 1.11901e-05 0L0 128L128 128Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M-0.00292969 0L127.997 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + ;path + =d "M0 128C4.63574e-06 92.6489 14.3309 60.6449 37.5 37.4807" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M32 128C32 101.492 42.7436 77.4939 60.1138 60.1217" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M64 128C64 110.328 71.1626 94.3287 82.7432 82.7471" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M95.6284 128C95.6284 119.164 99.2097 111.164 105 105.374" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'nym' + |= [fg=tape bg=tape] + :~ ;path + =d "M5.59506e-06 128C70.6925 128 128 70.6925 128 0L0 5.59506e-06L5.59506e-06 128Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M64 0L64 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M96 0L96 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M32 0L32 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'nyr' + |= [fg=tape bg=tape] + :~ ;path + =d "M0 127.946C0.0292286 57.2783 57.3256 3.08928e-06 128 0C128 70.6823 70.7089 127.984 0.0305092 128C0.0203397 128 0.01017 128 2.36469e-09 128L0 127.946Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M-0.00268555 0L127.997 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + ;path + =d "M95.9984 0C95.9984 26.3298 85.3985 50.1839 68.2332 67.5278M63.9983 0C63.9983 17.4933 56.9799 33.3473 45.6054 44.8999M31.9983 0C31.9983 8.65672 28.5609 16.5106 22.9766 22.2711" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'nys' + |= [fg=tape bg=tape] + :~ ;path + =d "M128 128C128 57.3076 70.6925 6.18013e-06 1.11901e-05 0L0 128L128 128Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;circle + =cx "16" + =cy "112" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "16" + =cy "112" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'nyt' + |= [fg=tape bg=tape] + :~ ;path + =d "M64 128H0L5.59506e-06 0L64 5.59506e-06C99.3462 8.68512e-06 128 28.6538 128 64C128 99.3462 99.3462 128 64 128Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M128 64L0 64" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M64 32C81.6731 32 96 46.3269 96 64" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M64 16C90.5097 16 112 37.4903 112 64" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'nyx' + |= [fg=tape bg=tape] + :~ ;path + =d "M5.59506e-06 128C70.6925 128 128 70.6925 128 0L0 5.59506e-06L5.59506e-06 128Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M-0.00292969 0L127.997 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + ;path + =fill-rule "evenodd" + =clip-rule "evenodd" + =stroke "none" + =d "M80 64C80 72.8366 72.8366 80 64 80C55.1634 80 48 72.8366 48 64C48 55.1634 55.1634 48 64 48C72.8366 48 80 55.1634 80 64ZM64 72C68.4183 72 72 68.4183 72 64C72 59.5817 68.4183 56 64 56C59.5817 56 56 59.5817 56 64C56 68.4183 59.5817 72 64 72Z" + =fill bg; + == +:: + :- 'pac' + |= [fg=tape bg=tape] + :~ ;path + =d "M0 0C0 70.6925 57.3075 128 128 128V0H0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M128 0L0 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + ;circle + =cx "64" + =cy "64" + =r "16" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;circle + =cx "64" + =cy "32" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "64" + =cy "32" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'pad' + |= [fg=tape bg=tape] + :~ ;path + =d "M0 0C0 70.6925 57.3075 128 128 128V0H0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;circle + =cx "96" + =cy "32" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "96" + =cy "32" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'pag' + |= [fg=tape bg=tape] + :~ ;path + =d "M64 0H128V128H64C28.6538 128 0 99.3462 0 64C0 28.6538 28.6538 0 64 0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;line + =x1 "15.9964" + =y1 "111.997" + =x2 "47.9964" + =y2 "79.9965" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'pal' + |= [fg=tape bg=tape] + :~ ;path + =d "M0.0541 0C70.7217 0.0292317 128 57.3256 128 128C57.3177 128 0.0164917 70.7089 7.62806e-06 0.0305091C7.62851e-06 0.0203397 -4.44317e-10 0.01017 0 0H0.0541Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M128 0L0 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + ;path + =d "M128 96C101.492 96 77.4939 85.2564 60.1217 67.8862" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M128 64C110.328 64 94.3287 56.8374 82.7471 45.2568" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M128 32.3716C119.164 32.3716 111.164 28.7903 105.374 23" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'pan' + |= [fg=tape bg=tape] + :~ ;path + =d "M0 0C0 70.6925 57.3075 128 128 128V0H0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;line + =x1 "0.5" + =y1 "-0.5" + =x2 "181.5" + =y2 "-0.5" + =transform "matrix(-0.707107 0.707107 0.707107 0.707107 128.71 0)" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + ;path + =d "M41.3726 86.6274C28.8758 74.1306 28.8758 53.8693 41.3726 41.3725C53.8694 28.8758 74.1306 28.8758 86.6274 41.3725" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'par' + |= [fg=tape bg=tape] + :~ ;circle + =cx "64" + =cy "64" + =r "64" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;line + =x1 "0.5" + =y1 "-0.5" + =x2 "181.5" + =y2 "-0.5" + =transform "matrix(-0.707107 0.707107 0.707107 0.707107 128.693 0)" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + ;circle + =cx "64" + =cy "64" + =r "16" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'pas' + |= [fg=tape bg=tape] + :~ ;rect + =width "128" + =height "128" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M32 0L32 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M64 0L64 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M96 0L96 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'pat' + |= [fg=tape bg=tape] + :~ ;path + =d "M0 0C0 70.6925 57.3075 128 128 128V0H0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M32 -2.67054e-06C32 53.0193 74.9807 96 128 96" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M64 -1.78036e-06C64 35.3462 92.6538 64 128 64" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M96 -8.9018e-07C96 17.6731 110.327 32 128 32" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'pec' + |= [fg=tape bg=tape] + :~ ;path + =d "M128 128C128 57.3076 70.6925 6.18013e-06 1.11901e-05 0L0 128L128 128Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M128 0L0 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + ;circle + =cx "64" + =cy "64" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "64" + =cy "64" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'ped' + |= [fg=tape bg=tape] + :~ ;circle + =cx "64" + =cy "64" + =r "64" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;circle + =cx "32" + =cy "64" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "32" + =cy "64" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'peg' + |= [fg=tape bg=tape] + :~ ;rect + =width "128" + =height "128" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M96 0C96 17.6731 81.6731 32 64 32C46.3269 32 32 17.6731 32 0" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'pel' + |= [fg=tape bg=tape] + :~ ;path + =d "M0 127.946C0.0292286 57.2783 57.3256 3.08928e-06 128 0C128 70.6823 70.7089 127.984 0.0305092 128C0.0203397 128 0.01017 128 2.36469e-09 128L0 127.946Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;circle + =cx "64" + =cy "64" + =r "32" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M112 64C112 37.4903 90.5097 16 64 16" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'pem' + |= [fg=tape bg=tape] + :~ ;circle + =cx "64" + =cy "64" + =r "64" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M-0.00280762 0L127.997 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + ;path + =d "M64 128C64 92.6538 35.3462 64 0 64" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'pen' + |= [fg=tape bg=tape] + :~ ;rect + =width "128" + =height "128" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M96 0C96 17.6731 81.6731 32 64 32C46.3269 32 32 17.6731 32 0" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M-0.00292969 0L127.997 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + == +:: + :- 'per' + |= [fg=tape bg=tape] + :~ ;path + =d "M0 64L5.59506e-06 0L128 1.11901e-05V64C128 99.3462 99.3462 128 64 128C28.6538 128 -4.6351e-06 99.3462 0 64Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M64 0L64 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'pes' + |= [fg=tape bg=tape] + :~ ;path + =d "M128 0C57.3075 8.42999e-07 -8.42999e-07 57.3075 0 128H128V0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M64 112C90.5097 112 112 90.5097 112 64" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;line + =x1 "-0.00285417" + =x2 "127.983" + =y2 "127.986" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + == +:: + :- 'pet' + |= [fg=tape bg=tape] + :~ ;circle + =cx "64" + =cy "64" + =r "64" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;line + =x1 "80.0035" + =y1 "79.9964" + =x2 "112.003" + =y2 "111.996" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'pex' + |= [fg=tape bg=tape] + :~ ;path + =d "M64 128H0L5.59506e-06 0L64 5.59506e-06C99.3462 8.68512e-06 128 28.6538 128 64C128 99.3462 99.3462 128 64 128Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;circle + =cx "64" + =cy "64" + =r "32" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =fill-rule "evenodd" + =clip-rule "evenodd" + =stroke "none" + =d "M80 64C80 72.8366 72.8366 80 64 80C55.1634 80 48 72.8366 48 64C48 55.1634 55.1634 48 64 48C72.8366 48 80 55.1634 80 64ZM64 72C68.4183 72 72 68.4183 72 64C72 59.5817 68.4183 56 64 56C59.5817 56 56 59.5817 56 64C56 68.4183 59.5817 72 64 72Z" + =fill bg; + == +:: + :- 'pic' + |= [fg=tape bg=tape] + :~ ;path + =d "M128 128C128 57.3076 70.6925 6.18013e-06 1.11901e-05 0L0 128L128 128Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M96 128C96 74.9807 53.0193 32 0 32" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M64 128C64 92.6538 35.3462 64 0 64" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M32 128C32 110.327 17.6731 96 0 96" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'pid' + |= [fg=tape bg=tape] + :~ ;path + =d "M0 0C0 70.6925 57.3075 128 128 128V0H0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;line + =x1 "-0.0029152" + =x2 "127.983" + =y2 "127.986" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + ;circle + =cx "16" + =cy "112" + =r "11.5" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + ;circle + =cx "16" + =cy "112" + =r "9" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + :: =stroke-width "2" + == +:: + :- 'pil' + |= [fg=tape bg=tape] + :~ ;path + =d "M64 0H128V128H64C28.6538 128 0 99.3462 0 64C0 28.6538 28.6538 0 64 0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;line + =x1 "0.5" + =y1 "-0.5" + =x2 "181.5" + =y2 "-0.5" + =transform "matrix(-0.707107 0.707107 0.707107 0.707107 128.71 0)" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + ;circle + =cx "96" + =cy "96" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "96" + =cy "96" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'pin' + |= [fg=tape bg=tape] + :~ ;rect + =width "128" + =height "128" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M32 0L32 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;circle + =cx "32" + =cy "32" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "32" + =cy "32" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'pit' + |= [fg=tape bg=tape] + :~ ;path + =d "M0.0541 0C70.7217 0.0292317 128 57.3256 128 128C57.3177 128 0.0164917 70.7089 7.62806e-06 0.0305091C7.62851e-06 0.0203397 -4.44317e-10 0.01017 0 0H0.0541Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;line + =x1 "0.5" + =y1 "-0.5" + =x2 "181.5" + =y2 "-0.5" + =transform "matrix(-0.707107 0.707107 0.707107 0.707107 128.71 0)" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + ;circle + =cx "16" + =cy "112" + =r "11.5" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + ;circle + =cx "16" + =cy "112" + =r "9" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + :: =stroke-width "2" + == +:: + :- 'poc' + |= [fg=tape bg=tape] + :~ ;path + =d "M0.0541 0C70.7217 0.0292317 128 57.3256 128 128C57.3177 128 0.0164917 70.7089 7.62806e-06 0.0305091C7.62851e-06 0.0203397 -4.44317e-10 0.01017 0 0H0.0541Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;line + =x1 "64.5" + =y1 "-0.5" + =x2 "64.5" + =y2 "127.5" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;line + =x1 "96.5" + =y1 "-0.5" + =x2 "96.5" + =y2 "127.5" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;line + =x1 "32.5" + =y1 "-0.5" + =x2 "32.5" + =y2 "127.5" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'pod' + |= [fg=tape bg=tape] + :~ ;path + =d "M64 0H128V128H64C28.6538 128 0 99.3462 0 64C0 28.6538 28.6538 0 64 0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;line + =x1 "128" + =y1 "96" + =x2 "-8.87604e-09" + =y2 "96" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'pol' + |= [fg=tape bg=tape] + :~ ;circle + =cx "64" + =cy "64" + =r "64" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;circle + =cx "64" + =cy "64" + =r "48" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;line + =x1 "128" + =y1 "32" + =x2 "-8.87604e-09" + =y2 "32" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'pon' + |= [fg=tape bg=tape] + :~ ;path + =d "M128 0C57.3075 8.42999e-07 -8.42999e-07 57.3075 0 128H128V0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + == +:: + :- 'pos' + |= [fg=tape bg=tape] + :~ ;path + =d "M0 0C0 70.6925 57.3075 128 128 128V0H0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;line + =x1 "-0.0029152" + =x2 "127.983" + =y2 "127.986" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + ;circle + =cx "96" + =cy "32" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "96" + =cy "32" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'pub' + |= [fg=tape bg=tape] + :~ ;path + =d "M128 128C128 57.3076 70.6925 6.18013e-06 1.11901e-05 0L0 128L128 128Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M32 0L32 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'pun' + |= [fg=tape bg=tape] + :~ ;circle + =cx "64" + =cy "64" + =r "64" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M112 64C112 37.4903 90.5097 16 64 16" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M96 64C96 46.3269 81.6731 32 64 32" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M80 64C80 55.1634 72.8366 48 64 48" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'pur' + |= [fg=tape bg=tape] + :~ ;path + =d "M5.59506e-06 128C70.6925 128 128 70.6925 128 0L0 5.59506e-06L5.59506e-06 128Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M-0.00292969 0L127.997 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + ;path + =d "M3.73284e-05 64C17.6633 64 33.6554 56.8445 45.2356 45.2741" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'put' + |= [fg=tape bg=tape] + :~ ;rect + =width "128" + =height "128" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;circle + =cx "32" + =cy "96" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "32" + =cy "96" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'pyl' + |= [fg=tape bg=tape] + :~ ;path + =d "M128 128C128 57.3076 70.6925 6.18013e-06 1.11901e-05 0L0 128L128 128Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M-5.59506e-06 128C35.3462 128 64 99.3462 64 64C64 28.6538 35.3462 1.54503e-06 0 0" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'pyx' + |= [fg=tape bg=tape] + :~ ;path + =d "M5.59506e-06 128C70.6925 128 128 70.6925 128 0L0 5.59506e-06L5.59506e-06 128Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M-0.00292969 0L127.997 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + ;circle + =cx "96" + =cy "32" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "96" + =cy "32" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'rab' + |= [fg=tape bg=tape] + :~ ;path + =d "M128 0C57.3075 8.42999e-07 -8.42999e-07 57.3075 0 128H128V0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M-0.00292969 0L127.997 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + ;line + =x1 "15.9965" + =y1 "111.997" + =x2 "47.9964" + =y2 "79.9965" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'rac' + |= [fg=tape bg=tape] + :~ ;path + =d "M0.0541 0C70.7217 0.0292317 128 57.3256 128 128C57.3177 128 0.0164917 70.7089 7.62806e-06 0.0305091C7.62851e-06 0.0203397 -4.44317e-10 0.01017 0 0H0.0541Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;circle + =cx "16" + =cy "112" + =r "11.5" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + ;circle + =cx "16" + =cy "112" + =r "9" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + :: =stroke-width "2" + == +:: + :- 'rad' + |= [fg=tape bg=tape] + :~ ;path + =d "M128 128C128 57.3076 70.6925 6.18013e-06 1.11901e-05 0L0 128L128 128Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;circle + =cx "32" + =cy "96" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "32" + =cy "96" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'rag' + |= [fg=tape bg=tape] + :~ ;path + =d "M64 0H128V128H64C28.6538 128 0 99.3462 0 64C0 28.6538 28.6538 0 64 0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;line + =x1 "16.0036" + =y1 "15.9965" + =x2 "48.0036" + =y2 "47.9965" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'ral' + |= [fg=tape bg=tape] + :~ ;path + =d "M0.0541 0C70.7217 0.0292317 128 57.3256 128 128C57.3177 128 0.0164917 70.7089 7.62806e-06 0.0305091C7.62851e-06 0.0203397 -4.44317e-10 0.01017 0 0H0.0541Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;circle + =cx "64" + =cy "64" + =r "32" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;circle + =cx "64" + =cy "64" + =r "16" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'ram' + |= [fg=tape bg=tape] + :~ ;path + =d "M64 0H128V128H64C28.6538 128 0 99.3462 0 64C0 28.6538 28.6538 0 64 0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;line + =x1 "64" + =y1 "2.18557e-08" + =x2 "64" + =y2 "128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =fill-rule "evenodd" + =clip-rule "evenodd" + =stroke "none" + =d "M80 64C80 72.8366 72.8366 80 64 80C55.1634 80 48 72.8366 48 64C48 55.1634 55.1634 48 64 48C72.8366 48 80 55.1634 80 64ZM64 72C68.4183 72 72 68.4183 72 64C72 59.5817 68.4183 56 64 56C59.5817 56 56 59.5817 56 64C56 68.4183 59.5817 72 64 72Z" + =fill bg; + == +:: + :- 'ran' + |= [fg=tape bg=tape] + :~ ;path + =d "M64 0H128V128H64C28.6538 128 0 99.3462 0 64C0 28.6538 28.6538 0 64 0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M64 0L64 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M-0.00291443 0L127.997 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + ;circle + =cx "64" + =cy "64" + =r "16" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'rap' + |= [fg=tape bg=tape] + :~ ;path + =d "M0 0C0 70.6925 57.3075 128 128 128V0H0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;line + =x1 "64" + =y1 "-1.29797e-08" + =x2 "64" + =y2 "128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;circle + =cx "96" + =cy "64" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "96" + =cy "64" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'rav' + |= [fg=tape bg=tape] + :~ ;path + =d "M0 0C0 70.6925 57.3075 128 128 128V0H0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M128 32L0 32" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'reb' + |= [fg=tape bg=tape] + :~ ;rect + =width "128" + =height "128" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M128 -9.40976e-06C57.3075 -6.31969e-06 -3.09007e-06 57.3075 0 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'rec' + |= [fg=tape bg=tape] + :~ ;path + =d "M128 128C128 57.3076 70.6925 6.18013e-06 1.11901e-05 0L0 128L128 128Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;circle + =cx "32" + =cy "96" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "32" + =cy "96" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + ;circle + =cx "96" + =cy "96" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "96" + =cy "96" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'red' + |= [fg=tape bg=tape] + :~ ;circle + =cx "64" + =cy "64" + =r "64" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;circle + =cx "64" + =cy "96" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "64" + =cy "96" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'ref' + |= [fg=tape bg=tape] + :~ ;path + =d "M0.0541 0C70.7217 0.0292317 128 57.3256 128 128C57.3177 128 0.0164917 70.7089 7.62806e-06 0.0305091C7.62851e-06 0.0203397 -4.44317e-10 0.01017 0 0H0.0541Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M-0.00292969 0L127.997 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + ;circle + =cx "16" + =cy "112" + =r "11.5" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + ;circle + =cx "16" + =cy "112" + =r "9" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + :: =stroke-width "2" + == +:: + :- 'reg' + |= [fg=tape bg=tape] + :~ ;rect + =width "128" + =height "128" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M128 96C110.327 96 96 81.6731 96 64C96 46.3269 110.327 32 128 32" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'rel' + |= [fg=tape bg=tape] + :~ ;path + =d "M0 127.946C0.0292286 57.2783 57.3256 3.08928e-06 128 0C128 70.6823 70.7089 127.984 0.0305092 128C0.0203397 128 0.01017 128 2.36469e-09 128L0 127.946Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M128 64L0 64" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M128 96L0 96" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M128 32L0 32" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'rem' + |= [fg=tape bg=tape] + :~ ;circle + =cx "64" + =cy "64" + =r "64" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M-0.00292969 0L127.997 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + ;path + =d "M128 64C92.6538 64 64 35.3462 64 0" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'ren' + |= [fg=tape bg=tape] + :~ ;rect + =width "128" + =height "128" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;line + =x1 "80.0035" + =y1 "79.9965" + =x2 "112.003" + =y2 "111.997" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;circle + =cx "64" + =cy "64" + =r "16" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'rep' + |= [fg=tape bg=tape] + :~ ;path + =d "M128 0C57.3075 8.42999e-07 -8.42999e-07 57.3075 0 128H128V0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M32 128C32 74.9807 74.9807 32 128 32" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'res' + |= [fg=tape bg=tape] + :~ ;path + =d "M128 0C57.3075 8.42999e-07 -8.42999e-07 57.3075 0 128H128V0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;line + =x1 "80.0035" + =y1 "79.9965" + =x2 "112.003" + =y2 "111.997" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'ret' + |= [fg=tape bg=tape] + :~ ;circle + =cx "64" + =cy "64" + =r "64" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M128 64L0 64" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'rev' + |= [fg=tape bg=tape] + :~ ;path + =d "M64 128H0L5.59506e-06 0L64 5.59506e-06C99.3462 8.68512e-06 128 28.6538 128 64C128 99.3462 99.3462 128 64 128Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;line + =x1 "15.9965" + =y1 "111.997" + =x2 "53.9965" + =y2 "73.9965" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;circle + =cx "16" + =cy "112" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "16" + =cy "112" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + ;path + =fill-rule "evenodd" + =clip-rule "evenodd" + =stroke "none" + =d "M80 64C80 72.8366 72.8366 80 64 80C55.1634 80 48 72.8366 48 64C48 55.1634 55.1634 48 64 48C72.8366 48 80 55.1634 80 64ZM64 72C68.4183 72 72 68.4183 72 64C72 59.5817 68.4183 56 64 56C59.5817 56 56 59.5817 56 64C56 68.4183 59.5817 72 64 72Z" + =fill bg; + == +:: + :- 'rex' + |= [fg=tape bg=tape] + :~ ;path + =d "M64 128H0L5.59506e-06 0L64 5.59506e-06C99.3462 8.68512e-06 128 28.6538 128 64C128 99.3462 99.3462 128 64 128Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M128 64L0 64" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =fill-rule "evenodd" + =clip-rule "evenodd" + =stroke "none" + =d "M80 64C80 72.8366 72.8366 80 64 80C55.1634 80 48 72.8366 48 64C48 55.1634 55.1634 48 64 48C72.8366 48 80 55.1634 80 64ZM64 72C68.4183 72 72 68.4183 72 64C72 59.5817 68.4183 56 64 56C59.5817 56 56 59.5817 56 64C56 68.4183 59.5817 72 64 72Z" + =fill bg; + == +:: + :- 'rib' + |= [fg=tape bg=tape] + :~ ;circle + =cx "64" + =cy "64" + =r "64" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;line + =x1 "8.74228e-08" + =y1 "64" + =x2 "128" + =y2 "64" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;line + =x1 "64" + =y1 "2.18557e-08" + =x2 "64" + =y2 "128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'ric' + |= [fg=tape bg=tape] + :~ ;path + =d "M128 128C128 57.3076 70.6925 6.18013e-06 1.11901e-05 0L0 128L128 128Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M96 128C96 74.9807 53.0193 32 0 32" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'rid' + |= [fg=tape bg=tape] + :~ ;path + =d "M0 0C0 70.6925 57.3075 128 128 128V0H0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M64 0L64 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M96 0L96 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'rig' + |= [fg=tape bg=tape] + :~ ;circle + =cx "64" + =cy "64" + =r "64" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;circle + =cx "64" + =cy "32" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "64" + =cy "32" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + ;circle + =cx "64" + =cy "96" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "64" + =cy "96" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'ril' + |= [fg=tape bg=tape] + :~ ;path + =d "M64 0H128V128H64C28.6538 128 0 99.3462 0 64C0 28.6538 28.6538 0 64 0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;line + =x1 "0.5" + =y1 "-0.5" + =x2 "181.5" + =y2 "-0.5" + =transform "matrix(-0.707107 0.707107 0.707107 0.707107 128.693 0)" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + ;circle + =cx "96" + =cy "32" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "96" + =cy "32" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'rin' + |= [fg=tape bg=tape] + :~ ;rect + =width "128" + =height "128" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;line + =x1 "64" + =y1 "2.18557e-08" + =x2 "64" + =y2 "128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;line + =x1 "32" + =y1 "2.18557e-08" + =x2 "32" + =y2 "128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'rip' + |= [fg=tape bg=tape] + :~ ;path + =d "M64 0H128V128H64C28.6538 128 0 99.3462 0 64C0 28.6538 28.6538 0 64 0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M-0.00292969 0L127.997 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + ;path + =d "M96 64C96 46.3269 81.6731 32 64 32" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;circle + =cx "96" + =cy "64" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "96" + =cy "64" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'ris' + |= [fg=tape bg=tape] + :~ ;path + =d "M128 0C57.3075 8.42999e-07 -8.42999e-07 57.3075 0 128H128V0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;line + =x1 "-0.0029152" + =x2 "127.983" + =y2 "127.986" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + ;path + =d "M128 0C128 35.3511 113.669 67.3551 90.5 90.5193" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M96 0C96 26.5077 85.2564 50.5061 67.8862 67.8783" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M64 0C64 17.6721 56.8374 33.6713 45.2568 45.2529" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M32.3716 0C32.3716 8.83603 28.7903 16.8356 23 22.6264" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'rit' + |= [fg=tape bg=tape] + :~ ;path + =d "M0.0541 0C70.7217 0.0292317 128 57.3256 128 128C57.3177 128 0.0164917 70.7089 7.62806e-06 0.0305091C7.62851e-06 0.0203397 -4.44317e-10 0.01017 0 0H0.0541Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;line + =x1 "0.5" + =y1 "-0.5" + =x2 "181.5" + =y2 "-0.5" + =transform "matrix(-0.707107 0.707107 0.707107 0.707107 128.71 0)" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + ;path + =fill-rule "evenodd" + =clip-rule "evenodd" + =stroke "none" + =d "M80 64C80 72.8366 72.8366 80 64 80C55.1634 80 48 72.8366 48 64C48 55.1634 55.1634 48 64 48C72.8366 48 80 55.1634 80 64ZM64 72C68.4183 72 72 68.4183 72 64C72 59.5817 68.4183 56 64 56C59.5817 56 56 59.5817 56 64C56 68.4183 59.5817 72 64 72Z" + =fill bg; + == +:: + :- 'riv' + |= [fg=tape bg=tape] + :~ ;rect + =width "128" + =height "128" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;circle + =cx "64" + =cy "64" + =r "32" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;line + =x1 "64" + =y1 "2.18557e-08" + =x2 "64" + =y2 "128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;circle + =cx "64" + =cy "64" + =r "48" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'roc' + |= [fg=tape bg=tape] + :~ ;path + =d "M0.0541 0C70.7217 0.0292317 128 57.3256 128 128C57.3177 128 0.0164917 70.7089 7.62806e-06 0.0305091C7.62851e-06 0.0203397 -4.44317e-10 0.01017 0 0H0.0541Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;circle + =cx "64" + =cy "64" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "64" + =cy "64" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + ;circle + =cx "16" + =cy "112" + =r "11.5" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + ;circle + =cx "16" + =cy "112" + =r "9" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + :: =stroke-width "2" + ;circle + =cx "112" + =cy "16" + =r "11.5" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + ;circle + =cx "112" + =cy "16" + =r "9" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + :: =stroke-width "2" + == +:: + :- 'rol' + |= [fg=tape bg=tape] + :~ ;circle + =cx "64" + =cy "64" + =r "64" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M128 64L0 64" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M64 16C90.5097 16 112 37.4903 112 64C112 90.5097 90.5097 112 64 112" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'ron' + |= [fg=tape bg=tape] + :~ ;path + =d "M128 0C57.3075 8.42999e-07 -8.42999e-07 57.3075 0 128H128V0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M128 0C128 70.6924 70.6925 128 0 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'rop' + |= [fg=tape bg=tape] + :~ ;circle + =cx "64" + =cy "64" + =r "64" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M-0.00292969 0L127.997 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + ;path + =d "M112 64C112 37.4903 90.5097 16 64 16" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'ros' + |= [fg=tape bg=tape] + :~ ;path + =d "M0 0C0 70.6925 57.3075 128 128 128V0H0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;line + =x1 "0.5" + =y1 "-0.5" + =x2 "181.5" + =y2 "-0.5" + =transform "matrix(-0.707107 0.707107 0.707107 0.707107 128.71 0)" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + ;circle + =cx "96" + =cy "96" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "96" + =cy "96" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'rov' + |= [fg=tape bg=tape] + :~ ;rect + =width "128" + =height "128" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;line + =x1 "-0.0029152" + =x2 "127.983" + =y2 "127.986" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + ;path + =d "M128 0C128 35.3511 113.669 67.3551 90.5 90.5193" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M96 0C96 26.5077 85.2564 50.5061 67.8862 67.8783" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M64 0C64 17.6721 56.8374 33.6713 45.2568 45.2529" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M32.3716 0C32.3716 8.83603 28.7903 16.8356 23 22.6264" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'ruc' + |= [fg=tape bg=tape] + :~ ;path + =d "M128 128C128 57.3076 70.6925 6.18013e-06 1.11901e-05 0L0 128L128 128Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M128 64L0 64" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M128 32L0 32" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'rud' + |= [fg=tape bg=tape] + :~ ;path + =d "M128 128C128 57.3076 70.6925 6.18013e-06 1.11901e-05 0L0 128L128 128Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M128 64L0 64" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M32 0L32 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M64 0L64 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'rul' + |= [fg=tape bg=tape] + :~ ;circle + =cx "64" + =cy "64" + =r "64" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;line + =x1 "80.0035" + =y1 "79.9964" + =x2 "112.003" + =y2 "111.996" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =fill-rule "evenodd" + =clip-rule "evenodd" + =stroke "none" + =d "M80 64C80 72.8366 72.8366 80 64 80C55.1634 80 48 72.8366 48 64C48 55.1634 55.1634 48 64 48C72.8366 48 80 55.1634 80 64ZM64 72C68.4183 72 72 68.4183 72 64C72 59.5817 68.4183 56 64 56C59.5817 56 56 59.5817 56 64C56 68.4183 59.5817 72 64 72Z" + =fill bg; + == +:: + :- 'rum' + |= [fg=tape bg=tape] + :~ ;path + =d "M5.59506e-06 128C70.6925 128 128 70.6925 128 0L0 5.59506e-06L5.59506e-06 128Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M5.08584e-07 32C17.6731 32 32 17.6731 32 0" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'run' + |= [fg=tape bg=tape] + :~ ;path + =d "M64 128H0L5.59506e-06 0L64 5.59506e-06C99.3462 8.68512e-06 128 28.6538 128 64C128 99.3462 99.3462 128 64 128Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M64 0L64 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M96 0L96 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M32 0L32 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'rup' + |= [fg=tape bg=tape] + :~ ;path + =d "M64 128H0L5.59506e-06 0L64 5.59506e-06C99.3462 8.68512e-06 128 28.6538 128 64C128 99.3462 99.3462 128 64 128Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M64 0L64 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M64 112C90.5097 112 112 90.5097 112 64C112 37.4903 90.5097 16 64 16" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;circle + =cx "64" + =cy "64" + =r "32" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'rus' + |= [fg=tape bg=tape] + :~ ;path + =d "M128 128C128 57.3076 70.6925 6.18013e-06 1.11901e-05 0L0 128L128 128Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M128 0L0 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + ;path + =d "M64 128C64 92.6538 35.3462 64 0 64" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'rut' + |= [fg=tape bg=tape] + :~ ;rect + =width "128" + =height "128" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;circle + =cx "32" + =cy "32" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "32" + =cy "32" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'rux' + |= [fg=tape bg=tape] + :~ ;path + =d "M128 128C128 57.3076 70.6925 6.18013e-06 1.11901e-05 0L0 128L128 128Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M128 64L0 64" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M32 64C32 81.6731 46.3269 96 64 96" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'ryc' + |= [fg=tape bg=tape] + :~ ;path + =d "M128 128C128 57.3076 70.6925 6.18013e-06 1.11901e-05 0L0 128L128 128Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M128 96L0 96" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'ryd' + |= [fg=tape bg=tape] + :~ ;path + =d "M0.0541 0C70.7217 0.0292317 128 57.3256 128 128C57.3177 128 0.0164917 70.7089 7.62806e-06 0.0305091C7.62851e-06 0.0203397 -4.44317e-10 0.01017 0 0H0.0541Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M-0.00280762 0L127.997 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + ;path + =d "M96 64C96 81.6731 81.6731 96 64 96" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'ryg' + |= [fg=tape bg=tape] + :~ ;path + =d "M5.59506e-06 128C70.6925 128 128 70.6925 128 0L0 5.59506e-06L5.59506e-06 128Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M-2.79795e-06 -3.55988e-06C70.6924 -4.40288e-06 128 57.3075 128 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;line + =x1 "16.0035" + =y1 "15.9965" + =x2 "48.0035" + =y2 "47.9965" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;circle + =cx "64" + =cy "64" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "64" + =cy "64" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'ryl' + |= [fg=tape bg=tape] + :~ ;path + =d "M0 0C0 70.6925 57.3075 128 128 128V0H0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M128 0L0 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + ;path + =d "M128 128C92.6489 128 60.6449 113.669 37.4807 90.5" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M128 96C101.492 96 77.4939 85.2564 60.1217 67.8862" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M128 64C110.328 64 94.3287 56.8374 82.7471 45.2568" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M128 32.3716C119.164 32.3716 111.164 28.7903 105.374 23" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'rym' + |= [fg=tape bg=tape] + :~ ;path + =d "M5.59506e-06 128C70.6925 128 128 70.6925 128 0L0 5.59506e-06L5.59506e-06 128Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M128 96L0 96" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'ryn' + |= [fg=tape bg=tape] + :~ ;path + =d "M5.59506e-06 128C70.6925 128 128 70.6925 128 0L0 5.59506e-06L5.59506e-06 128Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M128 128C57.3075 128 -3.09007e-06 70.6925 0 0" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'ryp' + |= [fg=tape bg=tape] + :~ ;path + =d "M5.59506e-06 128C70.6925 128 128 70.6925 128 0L0 5.59506e-06L5.59506e-06 128Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M-0.00292969 0L127.997 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + == +:: + :- 'rys' + |= [fg=tape bg=tape] + :~ ;path + =d "M128 128C128 57.3076 70.6925 6.18013e-06 1.11901e-05 0L0 128L128 128Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M1.52575e-06 96C53.0193 96 96 53.0193 96 0" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'ryt' + |= [fg=tape bg=tape] + :~ ;path + =d "M64 128H0L5.59506e-06 -7.62939e-06L64 -2.03434e-06C99.3462 1.05573e-06 128 28.6538 128 64C128 99.3462 99.3462 128 64 128Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;circle + =cx "64" + =cy "64" + =r "16" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;circle + =cx "64" + =cy "64" + =r "48" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M128 0L0 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + == +:: + :- 'ryx' + |= [fg=tape bg=tape] + :~ ;path + =d "M5.59506e-06 128C70.6925 128 128 70.6925 128 0L0 5.59506e-06L5.59506e-06 128Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;line + =x1 "0.5" + =y1 "-0.5" + =x2 "181.5" + =y2 "-0.5" + =transform "matrix(-0.707107 0.707107 0.707107 0.707107 128.71 0)" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + ;path + =d "M128 0L0 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + ;circle + =cx "64" + =cy "64" + =r "16" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'sab' + |= [fg=tape bg=tape] + :~ ;path + =d "M0 0C0 70.6925 57.3075 128 128 128V0H0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M-0.00292969 0L127.997 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + ;line + =y1 "-0.5" + =x2 "45.2548" + =y2 "-0.5" + =transform "matrix(0.707107 -0.707107 -0.707107 -0.707107 79.65 47.65)" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;circle + =cx "16" + =cy "112" + =r "11.5" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + ;circle + =cx "16" + =cy "112" + =r "9" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + :: =stroke-width "2" + == +:: + :- 'sal' + |= [fg=tape bg=tape] + :~ ;path + =d "M0.0541 0C70.7217 0.0292317 128 57.3256 128 128C57.3177 128 0.0164917 70.7089 7.62806e-06 0.0305091C7.62851e-06 0.0203397 -4.44317e-10 0.01017 0 0H0.0541Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M0 128L128 0" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + ;path + =d "M-0.701724 31.9914C25.6281 31.9914 49.4822 42.5913 66.8261 59.7565M-0.701723 63.9914C16.7916 63.9914 32.6456 71.0098 44.1982 82.3844M-0.701722 95.9914C7.955 95.9914 15.8089 99.4288 21.5694 105.013" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'sam' + |= [fg=tape bg=tape] + :~ ;path + =d "M64 0H128V128H64C28.6538 128 0 99.3462 0 64C0 28.6538 28.6538 0 64 0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;circle + =cx "64" + =cy "64" + =r "48" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M64 0L64 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =fill-rule "evenodd" + =clip-rule "evenodd" + =stroke "none" + =d "M80 64C80 72.8366 72.8366 80 64 80C55.1634 80 48 72.8366 48 64C48 55.1634 55.1634 48 64 48C72.8366 48 80 55.1634 80 64ZM64 72C68.4183 72 72 68.4183 72 64C72 59.5817 68.4183 56 64 56C59.5817 56 56 59.5817 56 64C56 68.4183 59.5817 72 64 72Z" + =fill bg; + == +:: + :- 'san' + |= [fg=tape bg=tape] + :~ ;path + =d "M0 0C0 70.6925 57.3075 128 128 128V0H0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;line + =x1 "-0.0029152" + =x2 "127.983" + =y2 "127.986" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + == +:: + :- 'sap' + |= [fg=tape bg=tape] + :~ ;path + =d "M0 0C0 70.6925 57.3075 128 128 128V0H0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;line + =x1 "128" + =y1 "64" + =x2 "-4.37114e-08" + =y2 "64" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;circle + =cx "96" + =cy "64" + =r "8" + =fill bg + =stroke "none"; + == +:: + :- 'sar' + |= [fg=tape bg=tape] + :~ ;circle + =cx "64" + =cy "64" + =r "64" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;circle + =cx "64" + =cy "64" + =r "48" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;circle + =cx "64" + =cy "64" + =r "48" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;line + =x1 "64" + =y1 "2.18557e-08" + =x2 "64" + =y2 "128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'sat' + |= [fg=tape bg=tape] + :~ ;path + =d "M0 0C0 70.6925 57.3075 128 128 128V0H0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M128 128C128 57.3076 70.6925 0 0 0" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'sav' + |= [fg=tape bg=tape] + :~ ;path + =d "M64 0H128V128H64C28.6538 128 0 99.3462 0 64C0 28.6538 28.6538 0 64 0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;line + =x1 "0.5" + =y1 "-0.5" + =x2 "181.5" + =y2 "-0.5" + =transform "matrix(-0.707107 0.707107 0.707107 0.707107 128.71 0)" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + ;path + =d "M96 64C96 46.3269 81.6731 32 64 32" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;circle + =cx "64" + =cy "32" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "64" + =cy "32" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'seb' + |= [fg=tape bg=tape] + :~ ;rect + =width "128" + =height "128" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M128 64C92.6538 64 64 35.3462 64 0" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'sec' + |= [fg=tape bg=tape] + :~ ;path + =d "M128 128C128 57.3076 70.6925 6.18013e-06 1.11901e-05 0L0 128L128 128Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;circle + =cx "32" + =cy "32" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "32" + =cy "32" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'sed' + |= [fg=tape bg=tape] + :~ ;circle + =cx "64" + =cy "64" + =r "64" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;circle + =cx "64" + =cy "64" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "64" + =cy "64" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + ;circle + =cx "96" + =cy "64" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "96" + =cy "64" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'sef' + |= [fg=tape bg=tape] + :~ ;path + =d "M0.0541 0C70.7217 0.0292317 128 57.3256 128 128C57.3177 128 0.0164917 70.7089 7.62806e-06 0.0305091C7.62851e-06 0.0203397 -4.44317e-10 0.01017 0 0H0.0541Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;circle + =cx "64" + =cy "64" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "64" + =cy "64" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + ;circle + =cx "16" + =cy "112" + =r "11.5" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + ;circle + =cx "16" + =cy "112" + =r "9" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + :: =stroke-width "2" + == +:: + :- 'seg' + |= [fg=tape bg=tape] + :~ ;rect + =width "128" + =height "128" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M32 128C32 110.327 46.3269 96 64 96C81.6731 96 96 110.327 96 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'sel' + |= [fg=tape bg=tape] + :~ ;path + =d "M0 127.946C0.0292286 57.2783 57.3256 3.08928e-06 128 0C128 70.6823 70.7089 127.984 0.0305092 128C0.0203397 128 0.01017 128 2.36469e-09 128L0 127.946Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;circle + =cx "64" + =cy "64" + =r "8" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'sem' + |= [fg=tape bg=tape] + :~ ;circle + =cx "64" + =cy "64" + =r "64" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M1.01717e-06 64C35.3462 64 64 35.3462 64 0" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M-0.00292969 0L127.997 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + == +:: + :- 'sen' + |= [fg=tape bg=tape] + :~ ;rect + =width "128" + =height "128" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M64 0L64 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M96 128C96 110.327 81.6731 96 64 96C46.3269 96 32 110.327 32 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;circle + =cx "64" + =cy "64" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "64" + =cy "64" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'sep' + |= [fg=tape bg=tape] + :~ ;path + =d "M128 0C57.3075 8.42999e-07 -8.42999e-07 57.3075 0 128H128V0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M64 128L64 0" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M32 128L32 0" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M96 128L96 0" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'ser' + |= [fg=tape bg=tape] + :~ ;path + =d "M0 64L5.59506e-06 0L128 1.11901e-05V64C128 99.3462 99.3462 128 64 128C28.6538 128 -4.6351e-06 99.3462 0 64Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M32 0L32 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'set' + |= [fg=tape bg=tape] + :~ ;circle + =cx "64" + =cy "64" + =r "64" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M64 64L128 64" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'sev' + |= [fg=tape bg=tape] + :~ ;path + =d "M64 128H0L5.59506e-06 0L64 5.59506e-06C99.3462 8.68512e-06 128 28.6538 128 64C128 99.3462 99.3462 128 64 128Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;circle + =cx "64" + =cy "64" + =r "48" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'sib' + |= [fg=tape bg=tape] + :~ ;circle + =cx "64" + =cy "64" + =r "64" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M128 0L0 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + ;path + =d "M64 9.40976e-06C64 35.3462 92.6538 64 128 64" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'sic' + |= [fg=tape bg=tape] + :~ ;path + =d "M0 0C0 70.6925 57.3075 128 128 128V0H0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M128 0L0 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + == +:: + :- 'sid' + |= [fg=tape bg=tape] + :~ ;path + =d "M0 0C0 70.6925 57.3075 128 128 128V0H0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M128 64L0 64" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M128 128C110.327 128 96 113.673 96 96C96 78.3269 110.327 64 128 64" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'sig' + |= [fg=tape bg=tape] + :~ ;circle + =cx "64" + =cy "64" + =r "64" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;circle + =cx "32" + =cy "64" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "32" + =cy "64" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + ;circle + =cx "96" + =cy "64" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "96" + =cy "64" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'sil' + |= [fg=tape bg=tape] + :~ ;path + =d "M64 0H128V128H64C28.6538 128 0 99.3462 0 64C0 28.6538 28.6538 0 64 0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;line + =x1 "16.0036" + =y1 "15.9965" + =x2 "48.0036" + =y2 "47.9965" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M128 0L0 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + == +:: + :- 'sim' + |= [fg=tape bg=tape] + :~ ;path + =d "M128 64V128H0L2.79753e-06 64C4.34256e-06 28.6538 28.6538 -1.54503e-06 64 0C99.3462 1.54503e-06 128 28.6538 128 64Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M64 0L64 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M32 0L32 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'sip' + |= [fg=tape bg=tape] + :~ ;rect + =width "128" + =height "128" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M64 0L64 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M16 64C16 37.4903 37.4903 16 64 16" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;circle + =cx "16" + =cy "64" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "16" + =cy "64" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'sit' + |= [fg=tape bg=tape] + :~ ;path + =d "M0.0541 0C70.7217 0.0292317 128 57.3256 128 128C57.3177 128 0.0164917 70.7089 7.62806e-06 0.0305091C7.62851e-06 0.0203397 -4.44317e-10 0.01017 0 0H0.0541Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =fill-rule "evenodd" + =clip-rule "evenodd" + =stroke "none" + =d "M80 64C80 72.8366 72.8366 80 64 80C55.1634 80 48 72.8366 48 64C48 55.1634 55.1634 48 64 48C72.8366 48 80 55.1634 80 64ZM64 72C68.4183 72 72 68.4183 72 64C72 59.5817 68.4183 56 64 56C59.5817 56 56 59.5817 56 64C56 68.4183 59.5817 72 64 72Z" + =fill bg; + == +:: + :- 'siv' + |= [fg=tape bg=tape] + :~ ;rect + =width "128" + =height "128" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M64 0L64 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M128 96L0 96" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;circle + =cx "64" + =cy "64" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "64" + =cy "64" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'soc' + |= [fg=tape bg=tape] + :~ ;path + =d "M0 127.946C0.0292286 57.2783 57.3256 3.08928e-06 128 0C128 70.6823 70.7089 127.984 0.0305092 128C0.0203397 128 0.01017 128 2.36469e-09 128L0 127.946Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;line + =x1 "64" + =y1 "2.18557e-08" + =x2 "64" + =y2 "128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;circle + =cx "64" + =cy "64" + =r "16" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;circle + =cx "16" + =cy "16" + =r "11.5" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + ;circle + =cx "16" + =cy "16" + =r "9" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + :: =stroke-width "2" + == +:: + :- 'sog' + |= [fg=tape bg=tape] + :~ ;path + =d "M128 0C57.3075 8.42999e-07 -8.42999e-07 57.3075 0 128H128V0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M128 0L0 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + ;path + =d "M64 96C81.6731 96 96 81.6731 96 64C96 46.3269 81.6731 32 64 32" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;circle + =cx "64" + =cy "64" + =r "16" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'sol' + |= [fg=tape bg=tape] + :~ ;circle + =cx "64" + =cy "64" + =r "64" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;circle + =cx "64" + =cy "64" + =r "32" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M128 64L-5.96046e-08 64" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'som' + |= [fg=tape bg=tape] + :~ ;rect + =width "128" + =height "128" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;circle + =cx "96" + =cy "96" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "96" + =cy "96" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + ;circle + =cx "32" + =cy "96" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "32" + =cy "96" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + ;circle + =cx "32" + =cy "32" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "32" + =cy "32" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'son' + |= [fg=tape bg=tape] + :~ ;path + =d "M128 0C57.3075 8.42999e-07 -8.42999e-07 57.3075 0 128H128V0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;line + =x1 "127.553" + =y1 "128.224" + =x2 "63.5528" + =y2 "0.223598" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'sop' + |= [fg=tape bg=tape] + :~ ;circle + =cx "64" + =cy "64" + =r "64" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;circle + =cx "64" + =cy "64" + =r "32" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M-0.00292969 0L127.997 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + ;circle + =cx "64" + =cy "32" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "64" + =cy "32" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'sor' + |= [fg=tape bg=tape] + :~ ;path + =d "M64 0H128V128H64C28.6538 128 0 99.3462 0 64C0 28.6538 28.6538 0 64 0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M-0.00292969 0L127.997 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + ;path + =d "M128 0C128 35.3511 113.669 67.3551 90.5 90.5193" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M96 0C96 26.5077 85.2564 50.5061 67.8862 67.8783" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M64 0C64 17.6721 56.8374 33.6713 45.2568 45.2529" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M32.3716 0C32.3716 8.83603 28.7903 16.8356 23 22.6264" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'sov' + |= [fg=tape bg=tape] + :~ ;rect + =width "128" + =height "128" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M0 128L128 0" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + ;path + =d "M128 128C92.6489 128 60.6449 113.669 37.4807 90.5" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M128 96C101.492 96 77.4939 85.2564 60.1217 67.8862" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M128 64C110.328 64 94.3287 56.8374 82.7471 45.2568" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M128 32.3716C119.164 32.3716 111.164 28.7903 105.374 23" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'sub' + |= [fg=tape bg=tape] + :~ ;path + =d "M128 128C128 57.3076 70.6925 6.18013e-06 1.11901e-05 0L0 128L128 128Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M64 0L64 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'sud' + |= [fg=tape bg=tape] + :~ ;path + =d "M128 128C128 57.3076 70.6925 6.18013e-06 1.11901e-05 0L0 128L128 128Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;line + =x1 "128" + =y1 "64" + =x2 "-8.87604e-09" + =y2 "64" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M128 64L0 64" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =fill-rule "evenodd" + =clip-rule "evenodd" + =stroke "none" + =d "M80 64C80 72.8366 72.8366 80 64 80C55.1634 80 48 72.8366 48 64C48 55.1634 55.1634 48 64 48C72.8366 48 80 55.1634 80 64ZM64 72C68.4183 72 72 68.4183 72 64C72 59.5817 68.4183 56 64 56C59.5817 56 56 59.5817 56 64C56 68.4183 59.5817 72 64 72Z" + =fill bg; + == +:: + :- 'sug' + |= [fg=tape bg=tape] + :~ ;path + =d "M64 128H0L5.59506e-06 0L64 5.59506e-06C99.3462 8.68512e-06 128 28.6538 128 64C128 99.3462 99.3462 128 64 128Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;circle + =cx "16" + =cy "64" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "16" + =cy "64" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + ;circle + =cx "80" + =cy "64" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "80" + =cy "64" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'sul' + |= [fg=tape bg=tape] + :~ ;circle + =cx "64" + =cy "64" + =r "64" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M64 96C46.3269 96 32 81.6731 32 64C32 46.3269 46.3269 32 64 32" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'sum' + |= [fg=tape bg=tape] + :~ ;path + =d "M5.59506e-06 128C70.6925 128 128 70.6925 128 0L0 5.59506e-06L5.59506e-06 128Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M1.01717e-06 64C35.3462 64 64 35.3462 64 0" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'sun' + |= [fg=tape bg=tape] + :~ ;circle + =cx "64" + =cy "64" + =r "64" + :: =fill fg + =stroke "none"; + ;circle + =cx "80" + =cy "80" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "80" + =cy "80" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + ;circle + =cx "80" + =cy "48" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "80" + =cy "48" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + ;circle + =cx "48" + =cy "48" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "48" + =cy "48" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + ;circle + =cx "48" + =cy "80" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "48" + =cy "80" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'sup' + |= [fg=tape bg=tape] + :~ ;path + =d "M64 128H0L5.59506e-06 0L64 5.59506e-06C99.3462 8.68512e-06 128 28.6538 128 64C128 99.3462 99.3462 128 64 128Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M64 112C90.5097 112 112 90.5097 112 64C112 37.4903 90.5097 16 64 16" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M128 64L0 64" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;circle + =cx "64" + =cy "64" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "64" + =cy "64" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'sur' + |= [fg=tape bg=tape] + :~ ;path + =d "M128 128C128 57.3076 70.6925 6.18013e-06 1.11901e-05 0L0 128L128 128Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M-0.00292969 0L127.997 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + ;path + =d "M3.73284e-05 64.0001C17.6633 64.0001 33.6554 56.8446 45.2356 45.2742" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M0.000105172 128C35.3582 128 67.3679 113.664 90.5332 90.4863" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'sut' + |= [fg=tape bg=tape] + :~ ;rect + =width "128" + =height "128" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;circle + =cx "32" + =cy "32" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "32" + =cy "32" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + ;circle + =cx "96" + =cy "96" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "96" + =cy "96" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'syd' + |= [fg=tape bg=tape] + :~ ;path + =d "M0.0541 0C70.7217 0.0292317 128 57.3256 128 128C57.3177 128 0.0164917 70.7089 7.62806e-06 0.0305091C7.62851e-06 0.0203397 -4.44317e-10 0.01017 0 0H0.0541Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M64 16C37.4903 16 16 37.4903 16 64" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M-0.00292969 0L127.997 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + == +:: + :- 'syl' + |= [fg=tape bg=tape] + :~ ;path + =d "M5.59506e-06 128C70.6925 128 128 70.6925 128 0L0 5.59506e-06L5.59506e-06 128Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M-0.00292969 0L127.997 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + ;circle + =cx "32" + =cy "96" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "32" + =cy "96" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + ;circle + =cx "96" + =cy "32" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "96" + =cy "32" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'sym' + |= [fg=tape bg=tape] + :~ ;path + =d "M5.59506e-06 128C70.6925 128 128 70.6925 128 0L0 5.59506e-06L5.59506e-06 128Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;line + =x1 "96.5" + =y1 "3.07317e-08" + =x2 "96.5" + =y2 "128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'syn' + |= [fg=tape bg=tape] + :~ ;path + =d "M5.59506e-06 128C70.6925 128 128 70.6925 128 0L0 5.59506e-06L5.59506e-06 128Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M0 0C35.3511 0 67.3551 14.3309 90.5193 37.5" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M0 32C26.5077 32 50.5061 42.7436 67.8783 60.1138" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M0 64C17.6721 64 33.6713 71.1626 45.2529 82.7432" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M0 95.6284C8.83603 95.6284 16.8356 99.2097 22.6264 105" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'syp' + |= [fg=tape bg=tape] + :~ ;path + =d "M5.59506e-06 128C70.6925 128 128 70.6925 128 0L0 5.59506e-06L5.59506e-06 128Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M-0.00280762 0L127.997 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + ;path + =d "M1.01717e-06 64C35.3462 64 64 35.3462 64 0" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'syr' + |= [fg=tape bg=tape] + :~ ;path + =d "M0 127.946C0.0292286 57.2783 57.3256 3.08928e-06 128 0C128 70.6823 70.7089 127.984 0.0305092 128C0.0203397 128 0.01017 128 2.36469e-09 128L0 127.946Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M-0.00292969 0L127.997 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + ;circle + =cx "96" + =cy "32" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "96" + =cy "32" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'syt' + |= [fg=tape bg=tape] + :~ ;path + =d "M64 128H0L5.59506e-06 0L64 5.59506e-06C99.3462 8.68512e-06 128 28.6538 128 64C128 99.3462 99.3462 128 64 128Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;circle + =cx "64" + =cy "64" + =r "32" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;circle + =cx "64" + =cy "64" + =r "48" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M128 0L0 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + == +:: + :- 'syx' + |= [fg=tape bg=tape] + :~ ;path + =d "M5.59506e-06 128C70.6925 128 128 70.6925 128 0L0 5.59506e-06L5.59506e-06 128Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M0 128C4.63574e-06 92.6488 14.3309 60.6449 37.5 37.4807" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M32 128C32 101.492 42.7436 77.4939 60.1138 60.1216" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M64 128C64 110.328 71.1626 94.3287 82.7432 82.7471" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M95.6284 128C95.6284 119.164 99.2097 111.164 105 105.374" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M-0.00280762 0L127.997 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + == +:: + :- 'tab' + |= [fg=tape bg=tape] + :~ ;path + =d "M0 0C0 70.6925 57.3075 128 128 128V0H0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;circle + =cx "64" + =cy "64" + =r "8" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;line + =x1 "-0.0029152" + =x2 "127.983" + =y2 "127.986" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + ;circle + =cx "16" + =cy "112" + =r "11.5" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + ;circle + =cx "16" + =cy "112" + =r "9" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + :: =stroke-width "2" + == +:: + :- 'tac' + |= [fg=tape bg=tape] + :~ ;path + =d "M0 0C0 70.6925 57.3075 128 128 128V0H0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M128 0L0 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + ;circle + =cx "64" + =cy "32" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "64" + =cy "32" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + ;circle + =cx "96" + =cy "64" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "96" + =cy "64" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'tad' + |= [fg=tape bg=tape] + :~ ;path + =d "M0 0C0 70.6925 57.3075 128 128 128V0H0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;circle + =cx "32" + =cy "32" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "32" + =cy "32" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + ;circle + =cx "96" + =cy "96" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "96" + =cy "96" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'tag' + |= [fg=tape bg=tape] + :~ ;path + =d "M64 0H128V128H64C28.6538 128 0 99.3462 0 64C0 28.6538 28.6538 0 64 0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;line + =x1 "80.0036" + =y1 "79.9964" + =x2 "112.004" + =y2 "111.996" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'tal' + |= [fg=tape bg=tape] + :~ ;path + =d "M0.0541 0C70.7217 0.0292317 128 57.3256 128 128C57.3177 128 0.0164917 70.7089 7.62806e-06 0.0305091C7.62851e-06 0.0203397 -4.44317e-10 0.01017 0 0H0.0541Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;line + =x1 "0.5" + =y1 "-0.5" + =x2 "181.5" + =y2 "-0.5" + =transform "matrix(-0.707107 0.707107 0.707107 0.707107 128.71 0)" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + ;path + =d "M96 128C96 74.9807 53.0193 32 0 32" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'tam' + |= [fg=tape bg=tape] + :~ ;path + =d "M64 0H128V128H64C28.6538 128 0 99.3462 0 64C0 28.6538 28.6538 0 64 0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;line + =x1 "128" + =y1 "96" + =x2 "-8.87604e-09" + =y2 "96" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;line + =x1 "128" + =y1 "32" + =x2 "-8.87604e-09" + =y2 "32" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;circle + =cx "64" + =cy "64" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "64" + =cy "64" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'tan' + |= [fg=tape bg=tape] + :~ ;path + =d "M0 0C0 70.6925 57.3075 128 128 128V0H0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M96 128C96 74.9807 53.0193 32 0 32" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M64 128C64 92.6538 35.3462 64 0 64" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M48 128C48 101.49 26.5097 80 0 80" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M32 128C32 110.327 17.6731 96 0 96" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M16 128C16 119.163 8.83656 112 0 112" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M128 128C128 57.3075 70.6925 0 0 0" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'tap' + |= [fg=tape bg=tape] + :~ ;circle + =cx "64" + =cy "64" + =r "64" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;circle + =cx "64" + =cy "64" + =r "48" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;line + =x1 "128" + =y1 "64" + =x2 "-8.87604e-09" + =y2 "64" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M64 32C81.6731 32 96 46.3269 96 64C96 81.6731 81.6731 96 64 96" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;circle + =cx "64" + =cy "64" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "64" + =cy "64" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'tar' + |= [fg=tape bg=tape] + :~ ;circle + =cx "64" + =cy "64" + =r "64" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;circle + =cx "64" + =cy "64" + =r "48" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;circle + =cx "16" + =cy "64" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "16" + =cy "64" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'tas' + |= [fg=tape bg=tape] + :~ ;rect + =width "128" + =height "128" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M64 0L64 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M64 32C81.6731 32 96 46.3269 96 64C96 81.6731 81.6731 96 64 96" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'teb' + |= [fg=tape bg=tape] + :~ ;rect + =width "128" + =height "128" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M1.52575e-06 96C53.0193 96 96 53.0193 96 0" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'tec' + |= [fg=tape bg=tape] + :~ ;path + =d "M128 128C128 57.3076 70.6925 6.18013e-06 1.11901e-05 0L0 128L128 128Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;line + =x1 "80.0035" + =y1 "79.9965" + =x2 "112.003" + =y2 "111.997" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =fill-rule "evenodd" + =clip-rule "evenodd" + =stroke "none" + =d "M80 64C80 72.8366 72.8366 80 64 80C55.1634 80 48 72.8366 48 64C48 55.1634 55.1634 48 64 48C72.8366 48 80 55.1634 80 64ZM64 72C68.4183 72 72 68.4183 72 64C72 59.5817 68.4183 56 64 56C59.5817 56 56 59.5817 56 64C56 68.4183 59.5817 72 64 72Z" + =fill bg; + == +:: + :- 'ted' + |= [fg=tape bg=tape] + :~ ;circle + =cx "64" + =cy "64" + =r "64" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;circle + =cx "32" + =cy "96" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "32" + =cy "96" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'teg' + |= [fg=tape bg=tape] + :~ ;rect + =width "128" + =height "128" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M128 80C119.163 80 112 72.8366 112 64C112 55.1634 119.163 48 128 48" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'tel' + |= [fg=tape bg=tape] + :~ ;path + =d "M0 127.946C0.0292286 57.2783 57.3256 3.08928e-06 128 0C128 70.6823 70.7089 127.984 0.0305092 128C0.0203397 128 0.01017 128 2.36469e-09 128L0 127.946Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;circle + =cx "15" + =cy "112" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "15" + =cy "112" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + ;path + =d "M0 0L127.986 127.986" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + ;path + =d "M32 0L128 96" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + ;path + =d "M64 0L128 64" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + ;path + =d "M96 0L128 32" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + == +:: + :- 'tem' + |= [fg=tape bg=tape] + :~ ;circle + =cx "64" + =cy "64" + =r "64" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M128 64C92.6538 64 64 92.6538 64 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;line + =x1 "-0.00285417" + =x2 "127.983" + =y2 "127.986" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + == +:: + :- 'ten' + |= [fg=tape bg=tape] + :~ ;rect + =width "128" + =height "128" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;circle + =cx "48" + =cy "48" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "48" + =cy "48" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + ;circle + =cx "80" + =cy "48" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "80" + =cy "48" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + ;circle + =cx "80" + =cy "80" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "80" + =cy "80" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + ;circle + =cx "48" + =cy "80" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "48" + =cy "80" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'tep' + |= [fg=tape bg=tape] + :~ ;path + =d "M128 0C57.3075 8.42999e-07 -8.42999e-07 57.3075 0 128H128V0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M1.14479e-06 96C53.0193 96 96 53.0193 96 0" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'ter' + |= [fg=tape bg=tape] + :~ ;path + =d "M0 64L5.59506e-06 0L128 1.11901e-05V64C128 99.3462 99.3462 128 64 128C28.6538 128 -4.6351e-06 99.3462 0 64Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;line + =x1 "96.5" + =y1 "3.07317e-08" + =x2 "96.5" + =y2 "128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M1.01717e-06 64C35.3462 64 64 35.3462 64 0" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'tes' + |= [fg=tape bg=tape] + :~ ;path + =d "M128 0C57.3075 8.42999e-07 -8.42999e-07 57.3075 0 128H128V0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M64 0L64 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M128 64L0 64" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'tev' + |= [fg=tape bg=tape] + :~ ;path + =d "M64 128H0L5.59506e-06 0L64 5.59506e-06C99.3462 8.68512e-06 128 28.6538 128 64C128 99.3462 99.3462 128 64 128Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;circle + =cx "64" + =cy "64" + =r "32" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'tex' + |= [fg=tape bg=tape] + :~ ;path + =d "M64 128H0L5.59506e-06 0L64 5.59506e-06C99.3462 8.68512e-06 128 28.6538 128 64C128 99.3462 99.3462 128 64 128Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;line + =x1 "15.9965" + =y1 "111.997" + =x2 "47.9965" + =y2 "79.9965" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =fill-rule "evenodd" + =clip-rule "evenodd" + =stroke "none" + =d "M80 64C80 72.8366 72.8366 80 64 80C55.1634 80 48 72.8366 48 64C48 55.1634 55.1634 48 64 48C72.8366 48 80 55.1634 80 64ZM64 72C68.4183 72 72 68.4183 72 64C72 59.5817 68.4183 56 64 56C59.5817 56 56 59.5817 56 64C56 68.4183 59.5817 72 64 72Z" + =fill bg; + == +:: + :- 'tic' + |= [fg=tape bg=tape] + :~ ;path + =d "M0 0C0 70.6925 57.3075 128 128 128V0H0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M128 32C110.327 32 96 17.6731 96 -1.39876e-06" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;circle + =cx "64" + =cy "64" + =r "32" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;circle + =cx "64" + =cy "64" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "64" + =cy "64" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'tid' + |= [fg=tape bg=tape] + :~ ;path + =d "M0 0C0 70.6925 57.3075 128 128 128V0H0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;line + =x1 "64" + =y1 "2.18557e-08" + =x2 "64" + =y2 "128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;line + =x1 "96" + =y1 "2.18557e-08" + =x2 "96" + =y2 "128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =fill-rule "evenodd" + =clip-rule "evenodd" + =stroke "none" + =d "M112 32C112 40.8366 104.837 48 96 48C87.1634 48 80 40.8366 80 32C80 23.1634 87.1634 16 96 16C104.837 16 112 23.1634 112 32ZM96 40C100.418 40 104 36.4183 104 32C104 27.5817 100.418 24 96 24C91.5817 24 88 27.5817 88 32C88 36.4183 91.5817 40 96 40Z" + =fill bg; + == +:: + :- 'til' + |= [fg=tape bg=tape] + :~ ;path + =d "M64 0H128V128H64C28.6538 128 0 99.3462 0 64C0 28.6538 28.6538 0 64 0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;line + =x1 "80.0036" + =y1 "79.9965" + =x2 "112.004" + =y2 "111.997" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;circle + =cx "64" + =cy "64" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "64" + =cy "64" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'tim' + |= [fg=tape bg=tape] + :~ ;path + =d "M128 64V128H0L2.79753e-06 64C4.34256e-06 28.6538 28.6538 -1.54503e-06 64 0C99.3462 1.54503e-06 128 28.6538 128 64Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M-0.00291443 0L127.997 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + == +:: + :- 'tin' + |= [fg=tape bg=tape] + :~ ;rect + =width "128" + =height "128" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;line + =x1 "32" + =y1 "2.18557e-08" + =x2 "32" + =y2 "128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'tip' + |= [fg=tape bg=tape] + :~ ;path + =d "M128 0C57.3075 8.42999e-07 -8.42999e-07 57.3075 0 128H128V0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M64 0L64 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =fill-rule "evenodd" + =clip-rule "evenodd" + =stroke "none" + =d "M80 64C80 72.8366 72.8366 80 64 80C55.1634 80 48 72.8366 48 64C48 55.1634 55.1634 48 64 48C72.8366 48 80 55.1634 80 64ZM64 72C68.4183 72 72 68.4183 72 64C72 59.5817 68.4183 56 64 56C59.5817 56 56 59.5817 56 64C56 68.4183 59.5817 72 64 72Z" + =fill bg; + == +:: + :- 'tir' + |= [fg=tape bg=tape] + :~ ;path + =d "M0 0C0 70.6925 57.3075 128 128 128V0H0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;line + =x1 "-0.0029152" + =x2 "127.983" + =y2 "127.986" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + ;circle + =cx "64" + =cy "64" + =r "16" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;circle + =cx "64" + =cy "64" + =r "32" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'tob' + |= [fg=tape bg=tape] + :~ ;path + =d "M128 64V128H0L2.79753e-06 64C4.34256e-06 28.6538 28.6538 -1.54503e-06 64 0C99.3462 1.54503e-06 128 28.6538 128 64Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M128 96L0 96" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'toc' + |= [fg=tape bg=tape] + :~ ;path + =d "M0.0541 0C70.7217 0.0292317 128 57.3256 128 128C57.3177 128 0.0164917 70.7089 7.62806e-06 0.0305091C7.62851e-06 0.0203397 -4.44317e-10 0.01017 0 0H0.0541Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;line + =x1 "128" + =y1 "96" + =x2 "-8.87604e-09" + =y2 "96" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;circle + =cx "64" + =cy "64" + =r "16" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'tod' + |= [fg=tape bg=tape] + :~ ;path + =d "M64 0H128V128H64C28.6538 128 0 99.3462 0 64C0 28.6538 28.6538 0 64 0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;circle + =cx "64" + =cy "96" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "64" + =cy "96" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + ;circle + =cx "64" + =cy "32" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "64" + =cy "32" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'tog' + |= [fg=tape bg=tape] + :~ ;path + =d "M128 0C57.3075 8.42999e-07 -8.42999e-07 57.3075 0 128H128V0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M64 96C46.3269 96 32 81.6731 32 64" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;circle + =cx "64" + =cy "64" + =r "16" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M128 0L0 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + == +:: + :- 'tol' + |= [fg=tape bg=tape] + :~ ;circle + =cx "64" + =cy "64" + =r "64" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;line + =x1 "128" + =y1 "64" + =x2 "-4.37114e-08" + =y2 "64" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M16 128C16 101.49 37.4903 80 64 80C90.5097 80 112 101.49 112 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'tom' + |= [fg=tape bg=tape] + :~ ;rect + =width "128" + =height "128" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;circle + =cx "32" + =cy "32" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "32" + =cy "32" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + ;circle + =cx "96" + =cy "32" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "96" + =cy "32" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + ;circle + =cx "32" + =cy "96" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "32" + =cy "96" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'ton' + |= [fg=tape bg=tape] + :~ ;path + =d "M128 0C57.3075 8.42999e-07 -8.42999e-07 57.3075 0 128H128V0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M128 32C74.9807 32 32 74.9807 32 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M128 64C92.6538 64 64 92.6538 64 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M128 96C110.327 96 96 110.327 96 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'top' + |= [fg=tape bg=tape] + :~ ;circle + =cx "64" + =cy "64" + =r "64" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;line + =x1 "-0.0029152" + =x2 "127.983" + =y2 "127.986" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + ;circle + =cx "64" + =cy "64" + =r "32" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;circle + =cx "64" + =cy "64" + =r "16" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'tor' + |= [fg=tape bg=tape] + :~ ;path + =d "M64 0H128V128H64C28.6538 128 0 99.3462 0 64C0 28.6538 28.6538 0 64 0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;circle + =cx "64" + =cy "64" + =r "32" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;circle + =cx "64" + =cy "64" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "64" + =cy "64" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'tuc' + |= [fg=tape bg=tape] + :~ ;path + =d "M128 128C128 57.3076 70.6925 6.18013e-06 1.11901e-05 0L0 128L128 128Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M128 64L0 64" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M128 96L0 96" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;circle + =cx "96" + =cy "96" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "96" + =cy "96" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + ;circle + =cx "32" + =cy "64" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "32" + =cy "64" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'tud' + |= [fg=tape bg=tape] + :~ ;path + =d "M128 128C128 57.3076 70.6925 6.18013e-06 1.11901e-05 0L0 128L128 128Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M128 64L0 64" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;circle + =cx "32" + =cy "64" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "32" + =cy "64" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'tug' + |= [fg=tape bg=tape] + :~ ;path + =d "M64 128H0L5.59506e-06 0L64 5.59506e-06C99.3462 8.68512e-06 128 28.6538 128 64C128 99.3462 99.3462 128 64 128Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M128 64L0 64" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M128 32L0 32" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'tul' + |= [fg=tape bg=tape] + :~ ;circle + =cx "64" + =cy "64" + =r "64" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =fill-rule "evenodd" + =clip-rule "evenodd" + =stroke "none" + =d "M80 64C80 72.8366 72.8366 80 64 80C55.1634 80 48 72.8366 48 64C48 55.1634 55.1634 48 64 48C72.8366 48 80 55.1634 80 64ZM64 72C68.4183 72 72 68.4183 72 64C72 59.5817 68.4183 56 64 56C59.5817 56 56 59.5817 56 64C56 68.4183 59.5817 72 64 72Z" + =fill bg; + == +:: + :- 'tun' + |= [fg=tape bg=tape] + :~ ;path + =d "M128 64V128H0L2.79753e-06 64C4.34256e-06 28.6538 28.6538 -1.54503e-06 64 0C99.3462 1.54503e-06 128 28.6538 128 64Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M-0.00292969 0L127.997 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + ;circle + =cx "64" + =cy "64" + =r "48" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;circle + =cx "64" + =cy "64" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "64" + =cy "64" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'tus' + |= [fg=tape bg=tape] + :~ ;path + =d "M128 128C128 57.3076 70.6925 6.18013e-06 1.11901e-05 0L0 128L128 128Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M128 0L0 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + ;circle + =cx "32" + =cy "32" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "32" + =cy "32" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'tux' + |= [fg=tape bg=tape] + :~ ;path + =d "M128 128C128 57.3076 70.6925 6.18013e-06 1.11901e-05 0L0 128L128 128Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M128 64L0 64" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;circle + =cx "64" + =cy "96" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "64" + =cy "96" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'tyc' + |= [fg=tape bg=tape] + :~ ;path + =d "M128 128C128 57.3076 70.6925 6.18013e-06 1.11901e-05 0L0 128L128 128Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =fill-rule "evenodd" + =clip-rule "evenodd" + =stroke "none" + =d "M80 64C80 72.8366 72.8366 80 64 80C55.1634 80 48 72.8366 48 64C48 55.1634 55.1634 48 64 48C72.8366 48 80 55.1634 80 64ZM64 72C68.4183 72 72 68.4183 72 64C72 59.5817 68.4183 56 64 56C59.5817 56 56 59.5817 56 64C56 68.4183 59.5817 72 64 72Z" + =fill bg; + == +:: + :- 'tyd' + |= [fg=tape bg=tape] + :~ ;path + =d "M0.0541 0C70.7217 0.0292317 128 57.3256 128 128C57.3177 128 0.0164917 70.7089 7.62806e-06 0.0305091C7.62851e-06 0.0203397 -4.44317e-10 0.01017 0 0H0.0541Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M-0.00280762 0L127.997 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + ;line + =y1 "-0.5" + =x2 "45.2548" + =y2 "-0.5" + =transform "matrix(0.707107 -0.707107 -0.707107 -0.707107 79.65 47.6499)" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;line + =x1 "15.9964" + =y1 "111.997" + =x2 "47.9964" + =y2 "79.9965" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;circle + =cx "64" + =cy "64" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "64" + =cy "64" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'tyl' + |= [fg=tape bg=tape] + :~ ;path + =d "M128 128C128 57.3076 70.6925 6.18013e-06 1.11901e-05 0L0 128L128 128Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M7.37542e-06 -3.56072e-06C1.19529e-06 70.6924 57.3075 128 128 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'tyn' + |= [fg=tape bg=tape] + :~ ;path + =d "M5.59506e-06 128C70.6925 128 128 70.6925 128 0L0 5.59506e-06L5.59506e-06 128Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M128 -2.28831e-06C57.3076 -3.13131e-06 8.42999e-07 57.3075 0 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'typ' + |= [fg=tape bg=tape] + :~ ;path + =d "M5.59506e-06 128C70.6925 128 128 70.6925 128 0L0 5.59506e-06L5.59506e-06 128Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M-0.00292969 0L127.997 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + ;path + =d "M96 1.90735e-06C96 53.0193 53.0193 96 0 96" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'tyr' + |= [fg=tape bg=tape] + :~ ;path + =d "M0 127.946C0.0292286 57.2783 57.3256 3.08928e-06 128 0C128 70.6823 70.7089 127.984 0.0305092 128C0.0203397 128 0.01017 128 2.36469e-09 128L0 127.946Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M0 0L128 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + ;path + =d "M128 64C92.6538 64 64 35.3462 64 0" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M0 64C35.3462 64 64 92.6538 64 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'tyv' + |= [fg=tape bg=tape] + :~ ;path + =d "M0 127.946C0.0292286 57.2783 57.3256 3.08928e-06 128 0C128 70.6823 70.7089 127.984 0.0305092 128C0.0203397 128 0.01017 128 2.36469e-09 128L0 127.946Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M256 0L128 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + ;circle + =cx "64" + =cy "64" + =r "32" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;circle + =cx "96" + =cy "32" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "96" + =cy "32" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + ;circle + =cx "32" + =cy "96" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "32" + =cy "96" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'wac' + |= [fg=tape bg=tape] + :~ ;path + =d "M0 0C0 70.6925 57.3075 128 128 128V0H0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M128 64L0 64" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;circle + =cx "64" + =cy "64" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "64" + =cy "64" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + ;circle + =cx "16" + =cy "112" + =r "11.5" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + ;circle + =cx "16" + =cy "112" + =r "9" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + :: =stroke-width "2" + == +:: + :- 'wal' + |= [fg=tape bg=tape] + :~ ;path + =d "M0 127.946C0.0292286 57.2783 57.3256 3.08928e-06 128 0C128 70.6823 70.7089 127.984 0.0305092 128C0.0203397 128 0.01017 128 2.36469e-09 128L0 127.946Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;line + =x1 "64.5" + =y1 "-0.5" + =x2 "64.5" + =y2 "127.5" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;line + =x1 "32" + =y1 "2.18557e-08" + =x2 "32" + =y2 "128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'wan' + |= [fg=tape bg=tape] + :~ ;path + =d "M0 0C0 70.6925 57.3075 128 128 128V0H0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M0 0C0 70.6925 57.3075 128 128 128V0H0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + == +:: + :- 'wat' + |= [fg=tape bg=tape] + :~ ;path + =d "M0 0C0 70.6925 57.3075 128 128 128V0H0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =fill-rule "evenodd" + =clip-rule "evenodd" + =stroke "none" + =d "M80 64C80 72.8366 72.8366 80 64 80C55.1634 80 48 72.8366 48 64C48 55.1634 55.1634 48 64 48C72.8366 48 80 55.1634 80 64ZM64 72C68.4183 72 72 68.4183 72 64C72 59.5817 68.4183 56 64 56C59.5817 56 56 59.5817 56 64C56 68.4183 59.5817 72 64 72Z" + =fill bg; + == +:: + :- 'web' + |= [fg=tape bg=tape] + :~ ;rect + =width "128" + =height "128" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M128 128C128 57.3075 70.6925 0 0 0" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'wed' + |= [fg=tape bg=tape] + :~ ;circle + =cx "64" + =cy "64" + =r "64" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;circle + =cx "32" + =cy "32" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "32" + =cy "32" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'weg' + |= [fg=tape bg=tape] + :~ ;rect + =width "128" + =height "128" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M79.5254 0C79.5254 8.83656 72.3619 16 63.5254 16C54.6888 16 47.5254 8.83656 47.5254 0" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'wel' + |= [fg=tape bg=tape] + :~ ;path + =d "M0 127.946C0.0292286 57.2783 57.3256 3.08928e-06 128 0C128 70.6823 70.7089 127.984 0.0305092 128C0.0203397 128 0.01017 128 2.36469e-09 128L0 127.946Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M128 32C74.9807 32 32 74.9807 32 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M128 64C92.6538 64 64 92.6538 64 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M128 96C110.327 96 96 110.327 96 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'wen' + |= [fg=tape bg=tape] + :~ ;rect + =width "128" + =height "128" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M1.01717e-06 64C35.3462 64 64 35.3462 64 0" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M-0.00292969 0L127.997 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + == +:: + :- 'wep' + |= [fg=tape bg=tape] + :~ ;path + =d "M128 0C57.3075 8.42999e-07 -8.42999e-07 57.3075 0 128H128V0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;circle + =cx "96" + =cy "96" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "96" + =cy "96" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'wer' + |= [fg=tape bg=tape] + :~ ;path + =d "M0 64L5.59506e-06 0L128 1.11901e-05V64C128 99.3462 99.3462 128 64 128C28.6538 128 -4.6351e-06 99.3462 0 64Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M32 0L32 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;circle + =cx "32" + =cy "32" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "32" + =cy "32" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'wes' + |= [fg=tape bg=tape] + :~ ;path + =d "M128 0C57.3075 8.42999e-07 -8.42999e-07 57.3075 0 128H128V0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;line + =x1 "80.0035" + =y1 "79.9965" + =x2 "112.003" + =y2 "111.997" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;circle + =cx "112" + =cy "112" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "112" + =cy "112" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'wet' + |= [fg=tape bg=tape] + :~ ;circle + =cx "64" + =cy "64" + =r "64" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M64 64H0" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'wex' + |= [fg=tape bg=tape] + :~ ;path + =d "M64 128H0L5.59506e-06 0L64 5.59506e-06C99.3462 8.68512e-06 128 28.6538 128 64C128 99.3462 99.3462 128 64 128Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =fill-rule "evenodd" + =clip-rule "evenodd" + =stroke "none" + =d "M80 64C80 72.8366 72.8366 80 64 80C55.1634 80 48 72.8366 48 64C48 55.1634 55.1634 48 64 48C72.8366 48 80 55.1634 80 64ZM64 72C68.4183 72 72 68.4183 72 64C72 59.5817 68.4183 56 64 56C59.5817 56 56 59.5817 56 64C56 68.4183 59.5817 72 64 72Z" + =fill bg; + == +:: + :- 'wic' + |= [fg=tape bg=tape] + :~ ;path + =d "M128 0C57.3075 8.42999e-07 -8.42999e-07 57.3075 0 128H128V0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;circle + =cx "96" + =cy "32" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "96" + =cy "32" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + ;circle + =cx "32" + =cy "96" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "32" + =cy "96" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'wid' + |= [fg=tape bg=tape] + :~ ;path + =d "M0 0C0 70.6925 57.3075 128 128 128V0H0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;line + =x1 "48.0035" + =y1 "80.0036" + =x2 "16.0035" + =y2 "112.004" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =fill-rule "evenodd" + =clip-rule "evenodd" + =stroke "none" + =d "M80 64C80 72.8366 72.8366 80 64 80C55.1634 80 48 72.8366 48 64C48 55.1634 55.1634 48 64 48C72.8366 48 80 55.1634 80 64ZM64 72C68.4183 72 72 68.4183 72 64C72 59.5817 68.4183 56 64 56C59.5817 56 56 59.5817 56 64C56 68.4183 59.5817 72 64 72Z" + =fill bg; + == +:: + :- 'win' + |= [fg=tape bg=tape] + :~ ;rect + =width "128" + =height "128" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;line + =x1 "64" + =y1 "2.18557e-08" + =x2 "64" + =y2 "128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'wis' + |= [fg=tape bg=tape] + :~ ;path + =d "M0 0C0 70.6925 57.3075 128 128 128V0H0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M128 64L0 64" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M128 32L0 32" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'wit' + |= [fg=tape bg=tape] + :~ ;path + =d "M0 127.946C0.0292286 57.2783 57.3256 3.08928e-06 128 0C128 70.6823 70.7089 127.984 0.0305092 128C0.0203397 128 0.01017 128 2.36469e-09 128L0 127.946Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;line + =x1 "64" + =y1 "2.18557e-08" + =x2 "64" + =y2 "128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;line + =x1 "32" + =y1 "2.18557e-08" + =x2 "32" + =y2 "128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;line + =x1 "96" + =y1 "2.18557e-08" + =x2 "96" + =y2 "128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'wol' + |= [fg=tape bg=tape] + :~ ;circle + =cx "64" + =cy "64" + =r "64" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M0 64L128 64" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M128 96C110.327 96 96 81.6731 96 64C96 46.3269 110.327 32 128 32" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'wor' + |= [fg=tape bg=tape] + :~ ;path + =d "M64 0H128V128H64C28.6538 128 0 99.3462 0 64C0 28.6538 28.6538 0 64 0Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;line + =y1 "-0.5" + =x2 "45.2548" + =y2 "-0.5" + =transform "matrix(0.707107 -0.707107 -0.707107 -0.707107 79.65 47.65)" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;line + =x1 "-0.0029152" + =x2 "127.983" + =y2 "127.986" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + ;path + =d "M64 96C46.3269 96 32 81.6731 32 64" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;circle + =cx "64" + =cy "64" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "64" + =cy "64" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'wyc' + |= [fg=tape bg=tape] + :~ ;path + =d "M128 128C128 57.3076 70.6925 6.18013e-06 1.11901e-05 0L0 128L128 128Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + == +:: + :- 'wyd' + |= [fg=tape bg=tape] + :~ ;path + =d "M0.0541 0C70.7217 0.0292317 128 57.3256 128 128C57.3177 128 0.0164917 70.7089 7.62806e-06 0.0305091C7.62851e-06 0.0203397 -4.44317e-10 0.01017 0 0H0.0541Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M-0.00292969 0L127.997 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + ;path + =d "M32 64C32 46.3269 46.3269 32 64 32" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;circle + =cx "32" + =cy "64" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "32" + =cy "64" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'wyl' + |= [fg=tape bg=tape] + :~ ;path + =d "M128 128C128 57.3076 70.6925 6.18013e-06 1.11901e-05 0L0 128L128 128Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M-3.8147e-06 128C-7.24633e-07 92.6538 28.6538 64 64 64C99.3462 64 128 92.6538 128 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'wyn' + |= [fg=tape bg=tape] + :~ ;path + =d "M5.59506e-06 128C70.6925 128 128 70.6925 128 0L0 5.59506e-06L5.59506e-06 128Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M1.52575e-06 96C53.0193 96 96 53.0193 96 0" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M1.01717e-06 64C35.3462 64 64 35.3462 64 0" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;path + =d "M5.08584e-07 32C17.6731 32 32 17.6731 32 0" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + == +:: + :- 'wyt' + |= [fg=tape bg=tape] + :~ ;path + =d "M64 128H0L5.59506e-06 0L64 5.59506e-06C99.3462 8.68512e-06 128 28.6538 128 64C128 99.3462 99.3462 128 64 128Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M128 0L0 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + ;circle + =cx "64" + =cy "64" + =r "48" + =vector-effect "non-scaling-stroke" + :: =stroke bg + =fill "none"; + ;circle + =cx "16" + =cy "64" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "16" + =cy "64" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'wyx' + |= [fg=tape bg=tape] + :~ ;path + =d "M5.59506e-06 128C70.6925 128 128 70.6925 128 0L0 5.59506e-06L5.59506e-06 128Z" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + ;path + =d "M-0.00292969 0L127.997 128" + =vector-effect "non-scaling-stroke" + :: =stroke bg + :: =stroke-linecap "square" + =fill "none"; + ;circle + =cx "32" + =cy "96" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "32" + =cy "96" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + ;circle + =cx "32" + =cy "32" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "32" + =cy "32" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + ;circle + =cx "96" + =cy "32" + =r "11.5" + :: =fill fg + =vector-effect "non-scaling-stroke" + =stroke fg; + ;circle + =cx "96" + =cy "32" + =r "9" + =fill bg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "2" + == +:: + :- 'zod' + |= [fg=tape bg=tape] + :~ ;circle + =cx "64" + =cy "64" + =r "64" + :: =fill fg + =vector-effect "non-scaling-stroke"; + :: =stroke bg + :: =stroke-width "0.5" + == +==
\ No newline at end of file diff --git a/desk/lib/sortug.hoon b/desk/lib/sortug.hoon new file mode 100644 index 0000000..bf988da --- /dev/null +++ b/desk/lib/sortug.hoon @@ -0,0 +1,729 @@ +|% +++ maybe + |* =mold + $% [%ok mold] + [%err p=@t] + == +++ uri-encode + |= t=tape ^- tape + =+ (en-urlt:html t) :: double-encoding because iris decodes shit at some point for some reason +(en-urlt:html -) +++ web + |% + ++ images + %- silt :~('png' 'jpg' 'jpeg' 'svg' 'webp') + ++ is-image + |= url=@t ^- ? + =/ u=(unit purl:eyre) (de-purl:html url) + ?~ u .n + =/ ext p.q.u.u + ?~ ext .n + (~(has in images) u.ext) + -- +++ slice + |* [a=(list) count=@ud index=@ud] + =| i=@ud + |- ^+ a + ?~ a ~ + ?: .=(count 0) ~ + ?: (lth i index) $(a t.a, i +(i)) + :- i.a + $(a t.a, i +(i), count (dec count)) + +++ pick + |* [a=(list) b=@] + =/ top (dec (lent a)) + =/ ind (mod b top) + (snag ind a) +++ flop :: reverse + |* a=(list) + => .(a (homo a)) + ^+ a + =+ b=`_a`~ + |- + ?~ a b + $(a t.a, b [i.a b]) +++ seq +|% + :: TODO study these two well + ++ reel + ~/ %reel + |* [a=(list) b=_=>(~ |=([* *] +<+))] + |- ^+ ,.+<+.b + ?~ a + +<+.b + (b i.a $(a t.a)) + ++ roll + ~/ %roll + |* [a=(list) b=_=>(~ |=([* *] +<+))] + |- ^+ ,.+<+.b + ?~ a + +<+.b + $(a t.a, b b(+<+ (b i.a +<+.b))) + ++ snip + |* a=(list) + =/ rev (flop a) + ?~ rev a + (flop t.rev) +-- +++ fold +|* [a=(list) b=* c=_|=(^ +<+)] +|- ^+ b +?~ a b +=/ nb (c [i.a b]) +$(a t.a, b nb) +++ foldi +|* [a=(list) b=* c=_|=(^ +<+)] +=| i=@ud +|- ^+ b +?~ a b +=/ nb (c i i.a b) +$(a t.a, b nb, i +(i)) +++ mapi +|* [a=(list) b=gate] +=| i=@ud +=> .(a (homo a)) +^- (list _?>(?=(^ a) (b i i.a))) +|- +?~ a ~ +:- i=(b i i.a) +t=$(a t.a, i +(i)) +++ cord-size +|= c=@t +(met 3 c) +++ concat-cord-list +|= c=(list @t) +(rap 3 c) +++ cut-cord +|= [c=@t s=@ud e=@ud] +(cut 3 [s e] c) +++ cfind-index + |= [nedl=@t hay=@t length=@ud case=?] ^- (unit [snip=@t left-amari=@ud right-amari=@ud]) + =/ nlen (met 3 nedl) + =/ hlen (met 3 hay) + ?: (lth hlen nlen) ~ + =? nedl !case + (crass nedl) + :: iterate from index 0 + =/ pos 0 + =/ lim (sub hlen nlen) + |- + :: If our position is further than the length of query + :: it's obviously not gonna happen anymore so return + ?: (gth pos lim) ~ + :: If needle is equal to the [position needle-length] slice of hay then we're good + =/ substring ?: case (cut 3 [pos nlen] hay) (crass (cut 3 [pos nlen] hay)) + ?. .=(nedl substring) $(pos +(pos)) + :: we grab a bigger piece of the cord, starting where + =/ [start-index=@ud end-index=@ud] [pos (add pos nlen)] + :: say it's [150 160] + =/ halfway=@ud (div (sub length nlen) 2) :: that's 45 + =/ start=@ud ?: (gth pos halfway) (sub pos halfway) 0 :: that's 105 + =/ end=@ud ?: (gte (add halfway end-index) hlen) hlen (add halfway end-index) :: 200 + + =/ right-amari (sub halfway (sub end end-index)) :: 5 + =/ left-amari (sub halfway (sub start-index start)) :: 0 + =/ snip=@t (cut 3 [start end] hay) + %- some :+ snip left-amari right-amari + +++ cfindi + |= [nedl=@t hay=@t case=?] ^- @t + =/ nlen (met 3 nedl) + =/ hlen (met 3 hay) + =| res=@t + ?: (lth hlen nlen) res + =? nedl !case + (crass nedl) + :: iterate from index 0 + =/ pos 0 + =/ lim (sub hlen nlen) + |- + :: If our position is further than the length of query + :: it's obviously not gonna happen anymore so return + ?: (gth pos lim) res + :: If needle is equal to the [position needle-length] slice of hay then we're good + ?: .= nedl + ?: case + (cut 3 [pos nlen] hay) + (crass (cut 3 [pos nlen] hay)) + :: we grab a bigger piece of the cord, starting where + =/ s ?: (lte pos 50) 0 (sub pos 50) + (cut 3 [s 100] hay) + $(pos +(pos)) +++ cfind + |= [nedl=@t hay=@t case=?] + ^- ? + =/ nlen (met 3 nedl) + =/ hlen (met 3 hay) + ?: (lth hlen nlen) + | + =? nedl !case + (crass nedl) + =/ pos 0 + =/ lim (sub hlen nlen) + |- + ?: (gth pos lim) + | + ?: .= nedl + ?: case + (cut 3 [pos nlen] hay) + (crass (cut 3 [pos nlen] hay)) + & + $(pos +(pos)) + ++ crass + |= text=@t + ^- @t + %^ run + 3 + text + |= dat=@ + ^- @ + ?. &((gth dat 64) (lth dat 91)) + dat + (add dat 32) +++ js + |% + ++ de + |% + ++ maybe + |* fst=$-(json *) + |= jon=json + ?~ jon ~ (fst jon) + ++ st + |= mol=mold + |= jon=json + ?> ?=([%s *] jon) + %- mol p.jon + ++ ur + |* wit=$-(json *) + |= jon=(unit json) + ?~(jon ~ `(wit u.jon)) + ++ gen + |= jon=json + ?- -.jon + %s p.jon + %n p.jon + %b p.jon + %a (turn p.jon gen) + %o ((om:dejs:format gen) jon) + == + -- + ++ en + |% + ++ bitch %bitch + -- + -- +++ string + |% +++ replace + |= [bit=tape bot=tape =tape] + ^- ^tape + |- + =/ off (find bit tape) + ?~ off tape + =/ clr (oust [(need off) (lent bit)] tape) + $(tape :(weld (scag (need off) clr) bot (slag (need off) clr))) + :: +++ split + |= [str=tape delim=tape] + ^- (list tape) + (split-rule str (jest (crip delim))) +:: +:: Split string by parsing rule delimiter. +++ split-rule + |* [str=tape delim=rule] + ^- (list tape) + %+ fall + (rust str (more delim (star ;~(less delim next)))) + [str ~] +++ contains + |= [str=tape nedl=tape] + ^- ? + ?~ (find nedl str) | & + ++ trim + |= a=tape + |- ^- tape + ?: ?=([%' ' *] a) + $(a t.a) + (flop a) + ++ number + |= a=@ud ^- tape + ?: =(0 a) "0" + %- flop + |- ^- tape + ?:(=(0 a) ~ [(add '0' (mod a 10)) $(a (div a 10))]) + ++ capitalize + |= a=@t ^- tape + =/ t=(list @t) (trip a) + ?~ t (trip a) + t(i (sub i.t 32)) + ++ enpath + |= str=cord ^- path + =/ allow ;~(pose low nud) + =/ lcase %+ cook + |= a=@t (add 32 a) hig + =/ rul ;~(pose allow lcase) + =/ del ;~(less rul next) + =/ frul (more del (cook crip (star rul))) + (rash str frul) + ++ enkebab2 + |= str=cord ^- tape + =/ allow ;~(pose low nud hep) + =/ kebab (cold '-' next) + =/ lcase %+ cook + |= a=@t (add 32 a) hig + =/ rul ;~(pose allow lcase kebab) + (rash str (star rul)) + ++ enkebab3 + |= str=cord ^- tape + =/ allow ;~(pose low nud hep) + =/ kebab (cold '-' next) + =/ lcase %+ cook + |= a=@t (add 32 a) hig + =/ rul ;~(pose allow lcase unic kebab) + (rash str (star rul)) + ++ unic + %- cook :_ unicode + |= a=@ %- crip (scow:parsing %uw a) + ++ unicode (shim 128 100.000.000) + ++ enkebab + |= str=cord + ^- cord + ~| str + =- (fall - str) + %+ rush str + =/ name + %+ cook + |= part=tape + ^- tape + ?~ part part + :- (add i.part 32) + t.part + ;~(plug hig (star low)) + %+ cook + |=(a=(list tape) (crip (zing (join "-" a)))) + ;~(plug (star low) (star name)) + ++ cut-cord + |= [=cord chars=@ud] + %+ end 3^chars cord + ++ pad + |= [t=tape length=@ud] ^- tape + ?: .=(length (lent t)) t + $(t "0{t}") + ++ date-to-path + |= d=@da ^- path + =+ [[a y] m [d h mm s f]]=(yore d) + =/ yr (numb:enjs:format y) + ?> ?=(%n -.yr) + /[p.yr]/(scot %ud m)/(scot %ud d) + ++ date-to-tape + |= [d=@da delim=tape] ^- tape + =+ [[a y] m [d h mm s f]]=(yore d) + =/ ys (ud-to-cord y) + =/ month (pad "{<m.m>}" 2) + =/ day (pad "{<d.d>}" 2) + "{(trip ys)}{delim}{month}{delim}{day}" + ++ datetime-to-tape + |= [d=@da delim=tape] ^- tape + =+ [[a y] m [d h mm s f]]=(yore d) + =/ ys (ud-to-cord y) + =/ month (pad "{<m.m>}" 2) + =/ day (pad "{<d.d>}" 2) + =/ hours (pad "{<h.h>}" 2) + =/ minutes (pad "{<m.mm>}" 2) + =/ seconds (pad "{<s.s>}" 2) + "{(trip ys)}{delim}{month}{delim}{day} {hours}:{minutes}:{seconds}" + ++ time-to-tape + |= d=@da ^- tape + =+ [[a y] m [d h mm s f]]=(yore d) + =/ hours (pad "{<h.h>}" 2) + =/ minutes (pad "{<m.mm>}" 2) + "{hours}:{minutes}" + ++ ud-to-cord + |= n=@ud ^- @t + %- crip + %- zing (rush (scot %ud n) (more dot (star nud))) + ++ remove + |= [s=@t r=@t] ^- @t + %- crip + %- zing + %+ rush s + %+ more (jest r) + %- star + ;~(less (jest r) next) + -- +++ io + |_ =bowl:gall + ++ retrieve + |= =path + =/ bp /gx/(scot %p our.bowl)/[dap.bowl]/(scot %da now.bowl) + .^(* (weld bp (weld path /noun))) + ++ scry + |* [app=@tas =path =mold] + =/ bp /gx/(scot %p our.bowl)/[app]/(scot %da now.bowl) + =/ pat (weld bp (weld path /noun)) + .^(mold pat) + ++ scry2 + |* [app=@tas =path =mold] + =/ bp /gx/(scot %p our.bowl)/[app]/(scot %da now.bowl) + =/ pat (weld bp (weld path /noun)) + %- mole |. .^(mold pat) + ++ scry-pad + |= t=@tas ^- path /(scot %p our.bowl)/[t]/(scot %da now.bowl) + -- +++ sail + |% + ++ coki-to-string + |= m=(map @t @t) ^- cord + %- crip %- ~(rep by m) + |= [pair=[key=@t value=@t] acc=tape] + "{acc}{(trip key.pair)}={(trip value.pair)}; " + ++ handle-html-form + |= body=(unit octs) ^- (map @t @t) + ?~ body ~ + =/ text q.u.body + =/ clean (remove:string text '%0D') + :: TODO html forms use \0d\0a + :: for carriage return + :: this breaks the markdown parser + =/ parser (more tis (star next)) + =/ res (rush clean yquy:de-purl:html) + ?~ res ~ (malt u.res) + -- ++$ michi (list @t) :: proper path with upper case +++ parsing + |% + ++ to-htmldate |= d=@da ^- tape + =+ [[* y=@] m=@ [d=@ h=@ mm=@ s=@ f=*]]=(yore d) + =/ ys (scow %ud y) + =/ ms (pad:string (scow %ud m) 2) + =/ ds (pad:string (scow %ud d) 2) + =/ hs (pad:string (scow %ud h) 2) + =/ mins (pad:string (scow %ud mm) 2) + "{ys}-{ms}-{ds}T{hs}:{mins}" + ++ y (bass 10 (stun 3^4 dit)) + :: ++ m (sear (snug mon:yu) (plus alf)) + ++ d (bass 10 (stun 1^2 dit)) + :: :: ++t:stud:chrono: + ++ t :: hours:minutes:secs + :: %+ cook |=([h=@u @ m=@u @ s=@u] ~[h m s]) + :: ;~(plug d col d col d) + ;~(plug d col d) + ++ weekday-3 + ;~ pose + %+ cold 0 (jest 'Sun') + %+ cold 1 (jest 'Mon') + %+ cold 2 (jest 'Tue') + %+ cold 3 (jest 'Wed') + %+ cold 4 (jest 'Thu') + %+ cold 5 (jest 'Fri') + %+ cold 6 (jest 'Sat') + == + ++ monthname-3 + ;~ pose + %+ cold 1 (jest 'Jan') + %+ cold 2 (jest 'Feb') + %+ cold 3 (jest 'Mar') + %+ cold 4 (jest 'Apr') + %+ cold 5 (jest 'May') + %+ cold 6 (jest 'Jun') + %+ cold 7 (jest 'Jul') + %+ cold 8 (jest 'Aug') + %+ cold 9 (jest 'Sep') + %+ cold 10 (jest 'Oct') + %+ cold 11 (jest 'Nov') + %+ cold 12 (jest 'Dec') + == + ++ three-section-time :: hours:minutes:secs + %+ cook |=([h=@u @ m=@u @ s=@u] [h m s]) + ;~(plug d col d col d) + ++ html-datetime + %+ cook |= [y=@ud * m=@ud * d=@ud * h=@ud * min=@ud] + =/ dt *date =. dt dt(y y, m m, d.t d, h.t h, m.t min) + (year dt) + ;~ plug y hep d hep d (just 'T') + t + == + ++ twatter-date + %+ cook |= [w=@ * m=@ * d=@ * [h=@ mn=@ s=@] * y=@] + =| dat=date %- year + dat(y y, m m, t [d h mn s ~]) + ;~ plug + weekday-3 + ace + monthname-3 + ace + d + ace + three-section-time + ;~ plug + ace + lus + y + ace + == + y + == + ++ white (star gah) + ++ para + |% + ++ eof ;~(less next (easy ~)) + ++ white (mask "\09 ") + ++ blank ;~(plug (star white) (just '\0a')) + ++ hard-wrap (cold ' ' ;~(plug blank (star white))) + ++ one-space (cold ' ' (plus white)) + ++ empty + ;~ pose + ;~(plug blank (plus blank)) + ;~(plug (star white) eof) + ;~(plug blank (star white) eof) + == + ++ para + %+ ifix + [(star white) empty] + %- plus + ;~ less + empty + next + == + -- + ++ trim para:para :: from whom/lib/docu + ++ link auri:de-purl:html + ++ youtube + ;~ pfix + ;~ plug + (jest 'https://') + ;~ pose + (jest 'www.youtube.com/watch?v=') + (jest 'youtube.com/watch?v=') + (jest 'youtu.be/') + == + == + ;~ sfix + (star aln) + (star next) + == + == + ++ twatter + ;~ pfix + ;~ plug + (jest 'https://') + ;~ pose + (jest 'x.com/') + (jest 'twitter.com/') + == + (star ;~(less fas next)) + (jest '/status/') + == + ;~ sfix + (star nud) + (star next) + == + == + + :: WIP + ++ scow + |= [mod=@tas a=@] ^- tape + ?+ mod "" + %ud (a-co:co a) + %ux ((x-co:co 0) a) + %uv ((v-co:co 0) a) + %uw ((w-co:co 0) a) + == + ++ b64 (bass 64 (plus siw:ab)) + ++ b16 (bass 16 (plus six:ab)) + ++ slaw + |= [mod=@tas txt=@t] ^- (unit @) + ?+ mod ~ + %ud (rush txt dem) + %ux (rush txt b16) + %uv (rush txt vum:ag) + %uw (rush txt b64) + == + :: ++ b64 + :: %+ cook + :: |=(a=tape (rap 3 ^-((list @) a))) + :: (star ;~(pose nud low cen hig hep dot sig cab)) + ++ stam + %+ sear + |= m=michi + ^- (unit michi) + ?: ?=([~ ~] m) ~ + ?. =(~ (rear m)) `m + ~ + ;~(pfix fas (most fas b64)) + ++ smat + |= m=michi ^- tape + =/ t "/" + |- + ?~ m t + =/ nt "{t}/{(trip i.m)}" + $(m t.m, t nt) + ++ de-comma + %+ sear + |= p=path + ^- (unit path) + ?: ?=([~ ~] p) `~ + ?. =(~ (rear p)) `p + ~ + (most com urs:ab) + ++ de-path + :: modified from apat:de-purl:html + =/ delim ;~(pose fas dot) + %+ cook :: get rid of the last dot and make the extension a part of the path + |= p=path ?~ p p + =/ flopped=path (flop p) + =/ sr=path (rash -.flopped (csplit dot)) + =/ rest=path +.flopped + %- flop %+ welp (flop sr) rest + ;~(pfix fas (more fas smeg:de-purl:html)) + ++ atom-dots + |= s=@t ^- @ud + =/ no-dots (rush s dem) + ?~ no-dots (rash s dem:ag) u.no-dots + ++ csplit |* =rule + (more rule (cook crip (star ;~(less rule next)))) + ++ split |* =rule + (more rule (star ;~(less rule next))) + ++ dinfix |* [pf=rule sf=rule] + =/ neither (star ;~(less ;~(pose pf sf) next)) + ;~(pfix pf ;~(sfix neither sf)) + ++ infix + |* =rule + (ifix [rule rule] (star ;~(less rule next))) + + ++ infix2 + |* [delim=rule inner=rule] + |= tub=nail + =+ vex=(delim tub) + ?~ q.vex + (fail tub) + =/ but=nail tub + =+ outer=(;~(sfix (plus ;~(less delim next)) delim) q.u.q.vex) + ?~ q.outer + (fail tub) + =+ in=(inner [1 1] p.u.q.outer) + ?~ q.in + (fail tub) + outer(p.u.q p.u.q.in) + + ++ qux (bass 16 (stun [4 4] hit)) + ++ better-dejson :: parse JSON + =< |=(a=cord `(unit json)`(rush a apex)) + |% + :: :: ++abox:de-json:html + ++ abox :: array + %+ stag %a + (ifix [sel (wish ser)] (more (wish com) apex)) + :: :: ++apex:de-json:html + ++ apex :: any value + %+ knee *json |. ~+ + %+ ifix [spac spac] + ;~ pose + (cold ~ (jest 'null')) + (stag %b bool) + (stag %s stri) + (cook |=(s=tape [%n p=(rap 3 s)]) numb) + abox + obox + == + :: :: ++bool:de-json:html + ++ bool :: boolean + ;~ pose + (cold & (jest 'true')) + (cold | (jest 'false')) + == + :: :: ++digs:de-json:html + ++ digs :: digits + (star (shim '0' '9')) + :: :: ++esca:de-json:html + ++ esca :: escaped character + ;~ pfix bas + =* loo + =* lip + ^- (list (pair @t @)) + [b+8 t+9 n+10 f+12 r+13 ~] + =* wow `(map @t @)`(malt lip) + (sear ~(get by wow) low) + =* tuf ;~(pfix (just 'u') (cook tuft qux)) + ;~(pose doq fas soq bas loo tuf) + == + :: :: ++expo:de-json:html + ++ expo :: exponent + ;~ (comp twel) + (piec (mask "eE")) + (mayb (piec (mask "+-"))) + digs + == + :: :: ++frac:de-json:html + ++ frac :: fraction + ;~(plug dot digs) + :: :: ++jcha:de-json:html + ++ jcha :: string character + ;~(pose ;~(less doq bas prn) esca) + :: :: ++mayb:de-json:html + ++ mayb :: optional + |*(bus=rule ;~(pose bus (easy ~))) + :: :: ++numb:de-json:html + ++ numb :: number + ;~ (comp twel) + (mayb (piec hep)) + ;~ pose + (piec (just '0')) + ;~(plug (shim '1' '9') digs) + == + (mayb frac) + (mayb expo) + == + :: :: ++obje:de-json:html + ++ obje :: object list + %+ ifix [(wish kel) (wish ker)] + (more (wish com) pear) + :: :: ++obox:de-json:html + ++ obox :: object + (stag %o (cook malt obje)) + :: :: ++pear:de-json:html + ++ pear :: key-value + ;~(plug ;~(sfix (wish stri) (wish col)) apex) + :: :: ++piec:de-json:html + ++ piec :: listify + |* bus=rule + (cook |=(a=@ [a ~]) bus) + :: :: ++stri:de-json:html + ++ stri :: string + (cook crip (ifix [doq doq] (star jcha))) + :: :: ++tops:de-json:html + ++ tops :: strict value + ;~(pose abox obox) + :: :: ++spac:de-json:html + ++ spac :: whitespace + (star (mask [`@`9 `@`10 `@`13 ' ' ~])) + :: :: ++twel:de-json:html + ++ twel :: tape weld + |=([a=tape b=tape] (weld a b)) + :: :: ++wish:de-json:html + ++ wish :: with whitespace + |*(sef=rule ;~(pfix spac sef)) + -- ::de-json + -- :: parsing +++ search + |% + ++ parse-query + |= query=@t ^- (map @t [query=@t neg=?]) + :: =s \'"machine learning" OR "data science" lmao -filter:links -from:elonmusk since:2023-01-01 until:2023-10-12 lang:en filter:verified\' + ~ + ++ apex + %+ knee ** + |. ~+ + %- star + ;~ pose + (stag %quot quotes) + (stag %white (split:parsing ace)) + (stag %lol rest) + :: next + == +++ rest (plus ;~(less doq next)) +++ quotes (infix:parsing doq) +++ else (star next) + -- +-- diff --git a/desk/lib/strand.hoon b/desk/lib/strand.hoon new file mode 100644 index 0000000..b0db35b --- /dev/null +++ b/desk/lib/strand.hoon @@ -0,0 +1 @@ +rand diff --git a/desk/lib/strandio.hoon b/desk/lib/strandio.hoon new file mode 100644 index 0000000..c2f2137 --- /dev/null +++ b/desk/lib/strandio.hoon @@ -0,0 +1,812 @@ +/- spider +/+ libstrand=strand +=, strand=strand:libstrand +=, strand-fail=strand-fail:libstrand +|% +++ send-raw-cards + |= cards=(list =card:agent:gall) + =/ m (strand ,~) + ^- form:m + |= strand-input:strand + [cards %done ~] +:: +++ send-raw-card + |= =card:agent:gall + =/ m (strand ,~) + ^- form:m + (send-raw-cards card ~) +:: +++ ignore + |= tin=strand-input:strand + `[%fail %ignore ~] +:: +++ get-bowl + =/ m (strand ,bowl:strand) + ^- form:m + |= tin=strand-input:strand + `[%done bowl.tin] +:: +++ get-beak + =/ m (strand ,beak) + ^- form:m + |= tin=strand-input:strand + `[%done [our q.byk da+now]:bowl.tin] +:: +++ get-time + =/ m (strand ,@da) + ^- form:m + |= tin=strand-input:strand + `[%done now.bowl.tin] +:: +++ get-our + =/ m (strand ,ship) + ^- form:m + |= tin=strand-input:strand + `[%done our.bowl.tin] +:: +++ get-entropy + =/ m (strand ,@uvJ) + ^- form:m + |= tin=strand-input:strand + `[%done eny.bowl.tin] +:: +:: Convert skips to %ignore failures. +:: +:: This tells the main loop to try the next handler. +:: +++ handle + |* a=mold + =/ m (strand ,a) + |= =form:m + ^- form:m + |= tin=strand-input:strand + =/ res (form tin) + =? next.res ?=(%skip -.next.res) + [%fail %ignore ~] + res +:: +:: Wait for a poke with a particular mark +:: +++ take-poke + |= =mark + =/ m (strand ,vase) + ^- form:m + |= tin=strand-input:strand + ?+ in.tin `[%skip ~] + ~ + `[%wait ~] + :: + [~ %poke @ *] + ?. =(mark p.cage.u.in.tin) + `[%skip ~] + `[%done q.cage.u.in.tin] + == +:: +++ take-sign-arvo + =/ m (strand ,[wire sign-arvo]) + ^- form:m + |= tin=strand-input:strand + ?+ in.tin `[%skip ~] + ~ + `[%wait ~] + :: + [~ %sign *] + `[%done [wire sign-arvo]:u.in.tin] + == +:: +:: Wait for a subscription update on a wire +:: +++ take-fact-prefix + |= =wire + =/ m (strand ,[path cage]) + ^- form:m + |= tin=strand-input:strand + ?+ in.tin `[%skip ~] + ~ `[%wait ~] + [~ %agent * %fact *] + ?. =(watch+wire (scag +((lent wire)) wire.u.in.tin)) + `[%skip ~] + `[%done (slag (lent wire) wire.u.in.tin) cage.sign.u.in.tin] + == +:: +:: Wait for a subscription update on a wire +:: +++ take-fact + |= =wire + =/ m (strand ,cage) + ^- form:m + |= tin=strand-input:strand + ?+ in.tin `[%skip ~] + ~ `[%wait ~] + [~ %agent * %fact *] + ?. =(watch+wire wire.u.in.tin) + `[%skip ~] + `[%done cage.sign.u.in.tin] + == +:: +:: Wait for a subscription close +:: +++ take-kick + |= =wire + =/ m (strand ,~) + ^- form:m + |= tin=strand-input:strand + ?+ in.tin `[%skip ~] + ~ `[%wait ~] + [~ %agent * %kick *] + ?. =(watch+wire wire.u.in.tin) + `[%skip ~] + `[%done ~] + == +:: +++ echo + =/ m (strand ,~) + ^- form:m + %- (main-loop ,~) + :~ |= ~ + ^- form:m + ;< =vase bind:m ((handle ,vase) (take-poke %echo)) + =/ message=tape !<(tape vase) + %- (slog leaf+"{message}..." ~) + ;< ~ bind:m (sleep ~s2) + %- (slog leaf+"{message}.." ~) + (pure:m ~) + :: + |= ~ + ^- form:m + ;< =vase bind:m ((handle ,vase) (take-poke %over)) + %- (slog leaf+"over..." ~) + (pure:m ~) + == +:: +++ take-watch + =/ m (strand ,path) + |= tin=strand-input:strand + ?+ in.tin `[%skip ~] + ~ `[%wait ~] + [~ %watch *] + `[%done path.u.in.tin] + == +:: +++ take-wake + |= until=(unit @da) + =/ m (strand ,~) + ^- form:m + |= tin=strand-input:strand + ?+ in.tin `[%skip ~] + ~ `[%wait ~] + [~ %sign [%wait @ ~] %behn %wake *] + ?. |(?=(~ until) =(`u.until (slaw %da i.t.wire.u.in.tin))) + `[%skip ~] + ?~ error.sign-arvo.u.in.tin + `[%done ~] + `[%fail %timer-error u.error.sign-arvo.u.in.tin] + == +:: +++ take-tune + |= =wire + =/ m (strand ,[spar:ames (unit roar:ames)]) + ^- form:m + |= tin=strand-input:strand + ?+ in.tin `[%skip ~] + ~ `[%wait ~] + :: + [~ %sign * %ames %tune ^ *] + ?. =(wire wire.u.in.tin) + `[%skip ~] + `[%done +>.sign-arvo.u.in.tin] + == +:: +++ take-poke-ack + |= =wire + =/ m (strand ,~) + ^- form:m + |= tin=strand-input:strand + ?+ in.tin `[%skip ~] + ~ `[%wait ~] + [~ %agent * %poke-ack *] + ?. =(wire wire.u.in.tin) + `[%skip ~] + ?~ p.sign.u.in.tin + `[%done ~] + `[%fail %poke-fail u.p.sign.u.in.tin] + == +:: +++ take-watch-ack + |= =wire + =/ m (strand ,~) + ^- form:m + |= tin=strand-input:strand + ?+ in.tin `[%skip ~] + ~ `[%wait ~] + [~ %agent * %watch-ack *] + ?. =(watch+wire wire.u.in.tin) + `[%skip ~] + ?~ p.sign.u.in.tin + `[%done ~] + `[%fail %watch-ack-fail u.p.sign.u.in.tin] + == +:: +++ poke + |= [=dock =cage] + =/ m (strand ,~) + ^- form:m + =/ =card:agent:gall [%pass /poke %agent dock %poke cage] + ;< ~ bind:m (send-raw-card card) + (take-poke-ack /poke) +:: +++ raw-poke + |= [=dock =cage] + =/ m (strand ,~) + ^- form:m + =/ =card:agent:gall [%pass /poke %agent dock %poke cage] + ;< ~ bind:m (send-raw-card card) + =/ m (strand ,~) + ^- form:m + |= tin=strand-input:strand + ?+ in.tin `[%skip ~] + ~ + `[%wait ~] + :: + [~ %agent * %poke-ack *] + ?. =(/poke wire.u.in.tin) + `[%skip ~] + `[%done ~] + == +:: +++ raw-poke-our + |= [app=term =cage] + =/ m (strand ,~) + ^- form:m + ;< =bowl:spider bind:m get-bowl + (raw-poke [our.bowl app] cage) +:: +++ poke-our + |= [=term =cage] + =/ m (strand ,~) + ^- form:m + ;< our=@p bind:m get-our + (poke [our term] cage) +:: +++ watch + |= [=wire =dock =path] + =/ m (strand ,~) + ^- form:m + =/ =card:agent:gall [%pass watch+wire %agent dock %watch path] + ;< ~ bind:m (send-raw-card card) + (take-watch-ack wire) +:: +++ watch-one + |= [=wire =dock =path] + =/ m (strand ,cage) + ^- form:m + ;< ~ bind:m (watch wire dock path) + ;< =cage bind:m (take-fact wire) + ;< ~ bind:m (take-kick wire) + (pure:m cage) +:: +++ watch-our + |= [=wire =term =path] + =/ m (strand ,~) + ^- form:m + ;< our=@p bind:m get-our + (watch wire [our term] path) +:: +++ scry + |* [=mold =path] + =/ m (strand ,mold) + ^- form:m + ?> ?=(^ path) + ?> ?=(^ t.path) + ;< =bowl:spider bind:m get-bowl + %- pure:m + .^(mold i.path (scot %p our.bowl) i.t.path (scot %da now.bowl) t.t.path) +:: +++ leave + |= [=wire =dock] + =/ m (strand ,~) + ^- form:m + =/ =card:agent:gall [%pass watch+wire %agent dock %leave ~] + (send-raw-card card) +:: +++ leave-our + |= [=wire =term] + =/ m (strand ,~) + ^- form:m + ;< our=@p bind:m get-our + (leave wire [our term]) +:: +++ rewatch + |= [=wire =dock =path] + =/ m (strand ,~) + ;< ~ bind:m ((handle ,~) (take-kick wire)) + ;< ~ bind:m (flog-text "rewatching {<dock>} {<path>}") + ;< ~ bind:m (watch wire dock path) + (pure:m ~) +:: +++ wait + |= until=@da + =/ m (strand ,~) + ^- form:m + ;< ~ bind:m (send-wait until) + (take-wake `until) +:: +++ keen + |= [=wire =spar:ames] + =/ m (strand ,~) + ^- form:m + (send-raw-card %pass wire %arvo %a %keen spar) +:: +++ sleep + |= for=@dr + =/ m (strand ,~) + ^- form:m + ;< now=@da bind:m get-time + (wait (add now for)) +:: +++ send-wait + |= until=@da + =/ m (strand ,~) + ^- form:m + =/ =card:agent:gall + [%pass /wait/(scot %da until) %arvo %b %wait until] + (send-raw-card card) +:: +++ map-err + |* computation-result=mold + =/ m (strand ,computation-result) + |= [f=$-([term tang] [term tang]) computation=form:m] + ^- form:m + |= tin=strand-input:strand + =* loop $ + =/ c-res (computation tin) + ?: ?=(%cont -.next.c-res) + c-res(self.next ..loop(computation self.next.c-res)) + ?. ?=(%fail -.next.c-res) + c-res + c-res(err.next (f err.next.c-res)) +:: +++ set-timeout + |* computation-result=mold + =/ m (strand ,computation-result) + |= [time=@dr computation=form:m] + ^- form:m + ;< now=@da bind:m get-time + =/ when (add now time) + =/ =card:agent:gall + [%pass /timeout/(scot %da when) %arvo %b %wait when] + ;< ~ bind:m (send-raw-card card) + |= tin=strand-input:strand + =* loop $ + ?: ?& ?=([~ %sign [%timeout @ ~] %behn %wake *] in.tin) + =((scot %da when) i.t.wire.u.in.tin) + == + `[%fail %timeout ~] + =/ c-res (computation tin) + ?: ?=(%cont -.next.c-res) + c-res(self.next ..loop(computation self.next.c-res)) + ?: ?=(%done -.next.c-res) + =/ =card:agent:gall + [%pass /timeout/(scot %da when) %arvo %b %rest when] + c-res(cards [card cards.c-res]) + c-res +:: +++ send-request + |= =request:http + =/ m (strand ,~) + ^- form:m + (send-raw-card %pass /request %arvo %i %request request *outbound-config:iris) +:: +++ send-cancel-request + =/ m (strand ,~) + ^- form:m + (send-raw-card %pass /request %arvo %i %cancel-request ~) +:: +++ take-client-response + =/ m (strand ,client-response:iris) + ^- form:m + |= tin=strand-input:strand + ?+ in.tin `[%skip ~] + ~ `[%wait ~] + :: + [~ %sign [%request ~] %iris %http-response %cancel *] + ::NOTE iris does not (yet?) retry after cancel, so it means failure + :- ~ + :+ %fail + %http-request-cancelled + ['http request was cancelled by the runtime']~ + :: + [~ %sign [%request ~] %iris %http-response %finished *] + `[%done client-response.sign-arvo.u.in.tin] + == +:: +:: Wait until we get an HTTP response or cancelation and unset contract +:: +++ take-maybe-sigh + =/ m (strand ,(unit httr:eyre)) + ^- form:m + ;< rep=(unit client-response:iris) bind:m + take-maybe-response + ?~ rep + (pure:m ~) + :: XX s/b impossible + :: + ?. ?=(%finished -.u.rep) + (pure:m ~) + (pure:m (some (to-httr:iris +.u.rep))) +:: +++ take-maybe-response + =/ m (strand ,(unit client-response:iris)) + ^- form:m + |= tin=strand-input:strand + ?+ in.tin `[%skip ~] + ~ `[%wait ~] + [~ %sign [%request ~] %iris %http-response %cancel *] + `[%done ~] + [~ %sign [%request ~] %iris %http-response %finished *] + `[%done `client-response.sign-arvo.u.in.tin] + == +:: +++ extract-body + |= =client-response:iris + =/ m (strand ,cord) + ^- form:m + ?> ?=(%finished -.client-response) + %- pure:m + ?~ full-file.client-response '' + q.data.u.full-file.client-response +:: +++ fetch-cord + |= url=tape + =/ m (strand ,cord) + ^- form:m + =/ =request:http [%'GET' (crip url) ~ ~] + ;< ~ bind:m (send-request request) + ;< =client-response:iris bind:m take-client-response + (extract-body client-response) +:: +++ fetch-json + |= url=tape + =/ m (strand ,json) + ^- form:m + ;< =cord bind:m (fetch-cord url) + =/ json=(unit json) (de:json:html cord) + ?~ json + (strand-fail %json-parse-error ~) + (pure:m u.json) +:: +++ hiss-request + |= =hiss:eyre + =/ m (strand ,(unit httr:eyre)) + ^- form:m + ;< ~ bind:m (send-request (hiss-to-request:html hiss)) + take-maybe-sigh +:: +:: +build-file: build the source file at the specified $beam +:: +++ build-file + |= [[=ship =desk =case] =spur] + =* arg +< + =/ m (strand ,(unit vase)) + ^- form:m + ;< =riot:clay bind:m + (warp ship desk ~ %sing %a case spur) + ?~ riot + (pure:m ~) + ?> =(%vase p.r.u.riot) + (pure:m (some !<(vase q.r.u.riot))) +:: +++ build-file-hard + |= [[=ship =desk =case] =spur] + =* arg +< + =/ m (strand ,vase) + ^- form:m + ;< =riot:clay + bind:m + (warp ship desk ~ %sing %a case spur) + ?> ?=(^ riot) + ?> ?=(%vase p.r.u.riot) + (pure:m !<(vase q.r.u.riot)) +:: +build-mark: build a mark definition to a $dais +:: +++ build-mark + |= [[=ship =desk =case] mak=mark] + =* arg +< + =/ m (strand ,dais:clay) + ^- form:m + ;< =riot:clay bind:m + (warp ship desk ~ %sing %b case /[mak]) + ?~ riot + (strand-fail %build-mark >arg< ~) + ?> =(%dais p.r.u.riot) + (pure:m !<(dais:clay q.r.u.riot)) +:: +build-tube: build a mark conversion gate ($tube) +:: +++ build-tube + |= [[=ship =desk =case] =mars:clay] + =* arg +< + =/ m (strand ,tube:clay) + ^- form:m + ;< =riot:clay bind:m + (warp ship desk ~ %sing %c case /[a.mars]/[b.mars]) + ?~ riot + (strand-fail %build-tube >arg< ~) + ?> =(%tube p.r.u.riot) + (pure:m !<(tube:clay q.r.u.riot)) +:: +:: +build-nave: build a mark definition to a $nave +:: +++ build-nave + |= [[=ship =desk =case] mak=mark] + =* arg +< + =/ m (strand ,vase) + ^- form:m + ;< =riot:clay bind:m + (warp ship desk ~ %sing %e case /[mak]) + ?~ riot + (strand-fail %build-nave >arg< ~) + ?> =(%nave p.r.u.riot) + (pure:m q.r.u.riot) +:: +build-cast: build a mark conversion gate (static) +:: +++ build-cast + |= [[=ship =desk =case] =mars:clay] + =* arg +< + =/ m (strand ,vase) + ^- form:m + ;< =riot:clay bind:m + (warp ship desk ~ %sing %f case /[a.mars]/[b.mars]) + ?~ riot + (strand-fail %build-cast >arg< ~) + ?> =(%cast p.r.u.riot) + (pure:m q.r.u.riot) +:: +:: Read from Clay +:: +++ warp + |= [=ship =riff:clay] + =/ m (strand ,riot:clay) + ;< ~ bind:m (send-raw-card %pass /warp %arvo %c %warp ship riff) + (take-writ /warp) +:: +++ read-file + |= [[=ship =desk =case] =spur] + =* arg +< + =/ m (strand ,cage) + ;< =riot:clay bind:m (warp ship desk ~ %sing %x case spur) + ?~ riot + (strand-fail %read-file >arg< ~) + (pure:m r.u.riot) +:: +++ check-for-file + |= [[=ship =desk =case] =spur] + =/ m (strand ,?) + ;< =riot:clay bind:m (warp ship desk ~ %sing %u case spur) + ?> ?=(^ riot) + (pure:m !<(? q.r.u.riot)) +:: +++ list-tree + |= [[=ship =desk =case] =spur] + =* arg +< + =/ m (strand ,(list path)) + ;< =riot:clay bind:m (warp ship desk ~ %sing %t case spur) + ?~ riot + (strand-fail %list-tree >arg< ~) + (pure:m !<((list path) q.r.u.riot)) +:: +:: Take Clay read result +:: +++ take-writ + |= =wire + =/ m (strand ,riot:clay) + ^- form:m + |= tin=strand-input:strand + ?+ in.tin `[%skip ~] + ~ `[%wait ~] + [~ %sign * ?(%behn %clay) %writ *] + ?. =(wire wire.u.in.tin) + `[%skip ~] + `[%done +>.sign-arvo.u.in.tin] + == +:: +check-online: require that peer respond before timeout +:: +++ check-online + |= [who=ship lag=@dr] + =/ m (strand ,~) + ^- form:m + %+ (map-err ,~) |=(* [%offline *tang]) + %+ (set-timeout ,~) lag + ;< ~ bind:m + (poke [who %hood] %helm-hi !>(~)) + (pure:m ~) +:: +++ eval-hoon + |= [gen=hoon bez=(list beam)] + =/ m (strand ,vase) + ^- form:m + =/ sut=vase !>(..zuse) + |- + ?~ bez + (pure:m (slap sut gen)) + ;< vax=vase bind:m (build-file-hard i.bez) + $(bez t.bez, sut (slop vax sut)) +:: +++ send-thread + |= [=bear:khan =shed:khan =wire] + =/ m (strand ,~) + ^- form:m + (send-raw-card %pass wire %arvo %k %lard bear shed) +:: +:: Queue on skip, try next on fail %ignore +:: +++ main-loop + |* a=mold + =/ m (strand ,~) + =/ m-a (strand ,a) + =| queue=(qeu (unit input:strand)) + =| active=(unit [in=(unit input:strand) =form:m-a forms=(list $-(a form:m-a))]) + =| state=a + |= forms=(lest $-(a form:m-a)) + ^- form:m + |= tin=strand-input:strand + =* top `form:m`..$ + =. queue (~(put to queue) in.tin) + |^ (continue bowl.tin) + :: + ++ continue + |= =bowl:strand + ^- output:m + ?> =(~ active) + ?: =(~ queue) + `[%cont top] + =^ in=(unit input:strand) queue ~(get to queue) + ^- output:m + =. active `[in (i.forms state) t.forms] + ^- output:m + (run bowl in) + :: + ++ run + ^- form:m + |= tin=strand-input:strand + ^- output:m + ?> ?=(^ active) + =/ res (form.u.active tin) + =/ =output:m + ?- -.next.res + %wait `[%wait ~] + %skip `[%cont ..$(queue (~(put to queue) in.tin))] + %cont `[%cont ..$(active `[in.u.active self.next.res forms.u.active])] + %done (continue(active ~, state value.next.res) bowl.tin) + %fail + ?: &(?=(^ forms.u.active) ?=(%ignore p.err.next.res)) + %= $ + active `[in.u.active (i.forms.u.active state) t.forms.u.active] + in.tin in.u.active + == + `[%fail err.next.res] + == + [(weld cards.res cards.output) next.output] + -- +:: +++ retry + |* result=mold + |= [crash-after=(unit @ud) computation=_*form:(strand (unit result))] + =/ m (strand ,result) + =| try=@ud + |- ^- form:m + =* loop $ + ?: =(crash-after `try) + (strand-fail %retry-too-many ~) + ;< ~ bind:m (backoff try ~m1) + ;< res=(unit result) bind:m computation + ?^ res + (pure:m u.res) + loop(try +(try)) +:: +++ backoff + |= [try=@ud limit=@dr] + =/ m (strand ,~) + ^- form:m + ;< eny=@uvJ bind:m get-entropy + %- sleep + %+ min limit + ?: =(0 try) ~s0 + %+ add + (mul ~s1 (bex (dec try))) + (mul ~s0..0001 (~(rad og eny) 1.000)) +:: +:: ---- +:: +:: Output +:: +++ flog + |= =flog:dill + =/ m (strand ,~) + ^- form:m + (send-raw-card %pass / %arvo %d %flog flog) +:: +++ flog-text + |= =tape + =/ m (strand ,~) + ^- form:m + (flog %text tape) +:: +++ flog-tang + |= =tang + =/ m (strand ,~) + ^- form:m + =/ =wall + (zing (turn (flop tang) (cury wash [0 80]))) + |- ^- form:m + =* loop $ + ?~ wall + (pure:m ~) + ;< ~ bind:m (flog-text i.wall) + loop(wall t.wall) +:: +++ trace + |= =tang + =/ m (strand ,~) + ^- form:m + (pure:m ((slog tang) ~)) +:: +++ app-message + |= [app=term =cord =tang] + =/ m (strand ,~) + ^- form:m + =/ msg=tape :(weld (trip app) ": " (trip cord)) + ;< ~ bind:m (flog-text msg) + (flog-tang tang) +:: +:: ---- +:: +:: Handle domains +:: +++ install-domain + |= =turf + =/ m (strand ,~) + ^- form:m + (send-raw-card %pass / %arvo %e %rule %turf %put turf) +:: +:: ---- +:: +:: Threads +:: +++ start-thread + |= file=term + =/ m (strand ,tid:spider) + ;< =bowl:spider bind:m get-bowl + (start-thread-with-args byk.bowl file *vase) +:: +++ start-thread-with-args + |= [=beak file=term args=vase] + =/ m (strand ,tid:spider) + ^- form:m + ;< =bowl:spider bind:m get-bowl + =/ tid + (scot %ta (cat 3 (cat 3 'strand_' file) (scot %uv (sham file eny.bowl)))) + =/ poke-vase !>(`start-args:spider`[`tid.bowl `tid beak file args]) + ;< ~ bind:m (poke-our %spider %spider-start poke-vase) + ;< ~ bind:m (sleep ~s0) :: wait for thread to start + (pure:m tid) +:: ++$ thread-result + (each vase [term tang]) +:: +++ await-thread + |= [file=term args=vase] + =/ m (strand ,thread-result) + ^- form:m + ;< =bowl:spider bind:m get-bowl + =/ tid (scot %ta (cat 3 'strand_' (scot %uv (sham file eny.bowl)))) + =/ poke-vase !>(`start-args:spider`[`tid.bowl `tid byk.bowl file args]) + ;< ~ bind:m (watch-our /awaiting/[tid] %spider /thread-result/[tid]) + ;< ~ bind:m (poke-our %spider %spider-start poke-vase) + ;< ~ bind:m (sleep ~s0) :: wait for thread to start + ;< =cage bind:m (take-fact /awaiting/[tid]) + ;< ~ bind:m (take-kick /awaiting/[tid]) + ?+ p.cage ~|([%strange-thread-result p.cage file tid] !!) + %thread-done (pure:m %& q.cage) + %thread-fail (pure:m %| ;;([term tang] q.q.cage)) + == +-- diff --git a/desk/lib/terse.sh b/desk/lib/terse.sh new file mode 100644 index 0000000..23ec32a --- /dev/null +++ b/desk/lib/terse.sh @@ -0,0 +1 @@ +terser kaji.js -m reserved=['subscribe'] -m toplevel -c top_retain=['subscribe'] -c toplevel -o kaji-min.js diff --git a/desk/lib/trill.hoon b/desk/lib/trill.hoon new file mode 100644 index 0000000..7b912dd --- /dev/null +++ b/desk/lib/trill.hoon @@ -0,0 +1,249 @@ +/- post=trill-post +/+ lib=boke, sr=sortug, plib=post +|% +++ node-to-full-fake +|= p=post:post ^- full-node:post +=/ fake-children=full-graph:post %- ~(rep in children.p) +|= [=id:post acc=full-graph:post] +(put:form:post acc id *full-node:post) +p(children fake-children) +++ node-to-full +|= [p=post:post f=feed:post] ^- full-node:post +p(children (convert-children children.p f)) +++ convert-children +|= [children=(set id:post) f=feed:post] +^- full-graph:post +%- ~(rep in children) + |= [=id:post acc=full-graph:post] + =/ n (get:orm:post f id) + ?~ n acc + =/ full-node (node-to-full u.n f) + (put:form:post acc id full-node) +++ find-mention-2 +|= [our=@p l=(list inline:contents-1:post)] ^- ? +%+ roll l |= [i=inline:contents-1:post a=_|] +?. ?=(%ship -.i) a +.=(our p.i) +++ sanitize +|= c=contents:contents-1:post ^- ? +%+ roll c |= [i=block:contents-1:post acc=_&] +?. ?=(%paragraph -.i) acc +%+ roll p.i |= [ii=inline:contents-1:post iacc=_acc] +?. ?=(%link -.ii) iacc +?~ (de-purl:html href.ii) .n .y +++ post-size +|= c=contents:contents-1:post +=| count=@ +|- +?~ c count +=/ lc=@ +?- -.i.c +%tasklist 0 :: TODO +%paragraph (inline-size p.i.c) +%blockquote (inline-size p.i.c) +%heading (lent (trip p.i.c)) +%list (inline-size p.i.c) +%media (media-size media.i.c) +%codeblock +?: (gth (lent (trip lang.i.c)) 400) 10.000 +(lent (trip code.i.c)) +%eval (lent (trip hoon.i.c)) +%ref +?: (gth (lent (trip app.i.c)) 400) 10.000 +(roll path.i.c |=([i=@t a=@] (add a (lent (trip i))))) +%json +?: (gth (lent (trip content.i.c)) 5.000) 10.000 +?: (gth (lent (trip origin.i.c)) 1.000) 10.000 +0 +%table +%+ roll rows.i.c |= [i=(list contents:contents-1:post) a=@] +=/ inner-count=@ +%+ roll i |= [ii=contents:contents-1:post ia=@] +(add ia (post-size ii)) +(add inner-count a) +== +$(c t.c, count (add count lc)) +++ inline-size +|= l=(list inline:contents-1:post) ^- @ +=| count=@ +|- +?~ l count +=/ lc=@ +?+ -.i.l (lent (trip p.i.l)) +%date 0 :: TODO +%note 0 :: TODO +%break 0 +%ruby (lent (trip p.i.l)) +%link +?: (gth (lent (trip href.i.l)) 400) 10.000 +(lent (trip show.i.l)) +== +$(l t.l, count (add count lc)) +++ media-size +|= =media:contents-1:post ^- @ +?- -.media +%video (lent (trip p.media)) +%audio (lent (trip p.media)) +%images %+ roll p.media +|= [[url=@t caption=@t] a=@] +%+ add a (lent (trip caption)) +== +:: search +++ text-search +|= [q=@t p=post:post case=?] ^- tape +=/ t (content-to-md:lib contents.p) +=? t !case (cass t) +=/ qt ?: case (trip q) (cass (trip q)) +=/ i (find qt t) +?~ i "" +=/ start ?: (lte u.i 50) 0 (sub u.i 50) +?: .=(start 0) +"{(swag [start 100] t)}..." +"...{(swag [start 100] t)}..." + +++ search +|= [q=@t p=post:post] ^- ? +?~ contents.p .n +=/ latest=content-list:post val:head:(pop:corm:post contents.p) +=/ in-tags %+ roll ~(tap in tags.p) |= [i=cord a=_|] +?: (contains i q) %& a +=/ in-blocks %+ roll latest |= [i=block:contents-1:post a=_|] +?: ?- -.i + %paragraph (in-inline p.i q) + %blockquote (in-inline p.i q) + %list (in-inline p.i q) + %heading (contains p.i q) + %codeblock (contains code.i q) + %eval (contains hoon.i q) + %json (contains content.i q) + %media (in-media media.i q) + %ref %| :: TODO + %table %| :: TODO + %tasklist .n :: TODO +== %& a +?| in-tags in-blocks == +++ contains +|= [container=cord query=cord] ^- ? +?~ (find (trip query) (trip container)) %| %& +++ in-media +|= [=media:contents-1:post q=@t] ^- ? +?. ?=(%images -.media) (contains p.media q) +%+ roll p.media |= [[url=cord caption=cord] a=_|] +?: (contains caption q) %& a +:: +++ text-search2 +|= [q=@t p=post:post case=?] ^- @t +?~ contents.p '' +=/ bl=(list block:contents-1:post) val:head:(pop:corm:post contents.p) +=| snippet=@t +|- +?~ bl snippet +:: TODO proper counts +?: (gth (met 3 snippet) 50) snippet +=/ ns +?+ -.i.bl snippet + %paragraph (from-inline p.i.bl q case) + %blockquote (from-inline p.i.bl q case) + %list (from-inline p.i.bl q case) + :: %heading (cfind:sr q p.i .n) + :: %codeblock (cfind:sr q code.i .n) + :: %eval (cfind:sr q hoon.i .n) + :: %json (cfind:sr q content.i .n) + :: %media (in-media2 media.i q) + %ref snippet :: TODO + %table snippet :: TODO + %tasklist snippet +== +$(bl t.bl, snippet (cat 3 snippet ns)) +++ from-inline +|= [l=(list inline:contents-1:post) q=@t case=?] ^- @t +=| snippet=@t +|- +?~ l snippet +?: (gth (met 3 snippet) 50) snippet +=/ r +?+ -.i.l (cfindi:sr q p.i.l .n) +%break .n +%date .n :: TODO +%note .n ::TODO +%ship (cfindi:sr q (scot %p p.i.l) .n) +%link (cat 3 (cfindi:sr q href.i.l .n) (cfindi:sr q show.i.l .n)) +%ruby (cat 3 (cfindi:sr q p.i.l .n) (cfindi:sr q q.i.l .n)) +== +$(l t.l, snippet (cat 3 snippet r)) + +++ search2 +|= [q=@t p=post:post] ^- ? +?~ contents.p .n +=/ latest=content-list:post val:head:(pop:corm:post contents.p) +=/ in-tags %+ roll ~(tap in tags.p) |= [i=cord a=_|] +?: (cfind:sr q i .n) %& a +=/ in-blocks %+ roll latest |= [i=block:contents-1:post a=_|] +?: ?- -.i + %paragraph (in-inline2 p.i q) + %blockquote (in-inline2 p.i q) + %list (in-inline2 p.i q) + %heading (cfind:sr q p.i .n) + %codeblock (cfind:sr q code.i .n) + %eval (cfind:sr q hoon.i .n) + %json (cfind:sr q content.i .n) + %media (in-media2 media.i q) + %ref %| :: TODO + %table %| :: TODO + %tasklist .n +== %& a +?| in-tags in-blocks == +++ in-media2 +|= [=media:contents-1:post q=@t] ^- ? +?. ?=(%images -.media) (cfind:sr q p.media .n) +%+ roll p.media |= [[url=cord caption=cord] a=_|] +?: (cfind:sr q url .n) %& a +++ in-inline2 +|= [l=(list inline:contents-1:post) q=@t] ^- ? +|- +?~ l .n +=/ i i.l +=/ r=? +?+ -.i (cfind:sr q p.i .n) +%break .n +%date .n +%note .n +%ship (cfind:sr q (scot %p p.i) .n) +%link ?|((cfind:sr q href.i .n) (cfind:sr q show.i .n)) +%ruby ?|((cfind:sr q p.i .n) (cfind:sr q q.i .n)) +== +?| r $(l t.l) == +:: +++ in-inline +|= [l=(list inline:contents-1:post) q=@t] ^- ? +%+ roll l |= [i=inline:contents-1:post a=_|] +?: ?+ -.i (contains p.i q) +%break %| +%date .n +%note ?|((contains id.i q) (in-inline text.i q)) +%ship (contains (scot %p p.i) q) +%link ?|((contains href.i q) (contains show.i q)) +%ruby ?|((contains p.i q) (contains q.i q)) +== %& a +++ is-my-reply +|= [p=post:post r=post:post our=@p] ^- ? +?~ parent.r .n +?& .=(author.r our) !.=(author.p our) == +++ is-thread-child +|= [p=post:post r=post:post our=@p] ^- ? +?~ parent.r .n +?& .=(author.r our) .=(author.p our) == +++ tag-search +|= [l=(list @t) =feed:post] ^- (list full-node:post) +%+ roll (tap:orm:post feed) |= [[* =post:post] acc=(list full-node:post)] +=/ found +=/ has .y +|- +?~ l has +?& has +=/ ns (~(has in tags.post) (crip (cass (trip i.l)))) +$(l t.l, has ns) +== +?. found acc :_ acc +(node-to-full:plib post feed) +-- diff --git a/desk/lib/trill/ui.hoon b/desk/lib/trill/ui.hoon new file mode 100644 index 0000000..8f05936 --- /dev/null +++ b/desk/lib/trill/ui.hoon @@ -0,0 +1,249 @@ +/- tp=trill-post +/+ sr=sortug +:: /+ md=markdown +|% +++ abbr +|= [t=@t c=@ud] ^- @t + =/ size (met 3 t) + ?: (lte size c) t + %^ cat 3 + (cut 3 [0 c] t) + '...' +++ abbr-t +|= [t=tape c=@ud] ^- tape + =/ size (lent t) + ?: (lte size c) t + %+ weld (scag c t) + "..." +:: tape -> post:trill, parsing user input from Sail +++ parse :: Markdown parser. Actually udon parser but it'll do +|= s=tape ^- (unit marl:hoot) :: finally +:: TODO check out parse:chat-graph.hoon +:: Annoying it requires a line break but then parses it as a space wtf +=, vast +(rust s cram:(sail .y)) ++$ heading $?(%h1 %h2 %h3 %h4 %h5 %h6) +++ tokenize +|= s=@t ^- content-list:tp + =/ t (weld (trip s) "\0a") + =/ parsed (parse t) + :: =/ parsed2 (parse:md t) + :: ~& > diary-parser=parsed2 + :: \0a can't be followed by a space. ever. those are the rules + ?~ parsed ~& error-parsing-markdown=t ~ + (marl-to-cl u.parsed) +++ marl-to-cl +|= =marl:hoot ^- content-list:tp + %- flop + %+ roll marl + |= [=tuna:hoot acc=content-list:tp] + :: man this is an annoying type if I ever saw one + ?@ -.tuna acc + =/ blk (manx-to-block tuna) + ?~ blk acc :_ acc u.blk +++ manx-to-block + |= =manx:hoot ^- (unit block:tp) + ?+ n.g.manx ~ + heading %- some [%heading (phead n.g.manx c.manx)] + %p %- some [%paragraph (inline-list c.manx)] + %blockquote %- some [%blockquote (inline-list c.manx)] + %pre %- some [%codeblock (pre c.manx)] + %hr %- some [%paragraph ~[[%break ~]]] + %ul %- some [%list (list-items c.manx) .n] + %ol %- some [%list (list-items c.manx) .y] + :: %table %- some (table-rows c.manx) + == +:: ++ table-row +:: |= =manx:hoot ^- (list cell:table:tp) +:: ?. ?=(%td n.g.manx) ~ + +:: ++ table-rows +:: |= =marl:hoot ^- table:tp +:: =/ a +:: %+ roll marl |= [=manx:hoot acc=table:tp] +:: :- %table +:: ?: ?=(%th n.g.manx) :_ rows.acc [(marl-to-cl c.manx) headers.acc] +:: ?. ?=(%tr n.g.manx) :- headers.acc +:: :- headers.acc rows.acc + +++ list-items +|= =marl:hoot ^- (list li:clist:tp) +%- flop +%+ roll marl |= [=tuna:hoot acc=(list li:clist:tp)] +?@ -.tuna acc +?. ?=(%li n.g.tuna) acc :_ acc (marl-to-cl c.tuna) +++ phead +|= [h=heading c=marl:hoot] ^- [p=cord q=heading] +:- (get-tag-text c) h +++ inline-list + |= c=marl:hoot ^- (list inline:tp) + %- flop + %+ roll c + |= [=tuna:hoot acc=(list inline:tp)] + ?@ -.tuna acc :_ acc (inline tuna) + ++ inline + |= =manx:hoot ^- inline:tp + ?: ?=(%$ n.g.manx) [%text (get-attrs-text a.g.manx)] + =/ text=@t (get-tag-text c.manx) + ?+ n.g.manx [%text text] + %i [%italic text] + %b [%bold text] + %code [%codespan text] + %br [%break ~] + %a :+ %link (get-attrs-text a.g.manx) (get-tag-text c.manx) + %img :+ %link (get-attr-text a.g.manx %src) (get-attr-text a.g.manx %alt) + == +:: +++ reduce-block +|= c=marl:hoot ^- @t +%+ roll c +|= [=tuna:hoot acc=@t] +?@ -.tuna acc +?+ n.g.tuna acc +%p (get-tag-text c.tuna) +== +++ get-attr-text +|= [a=mart:hoot attr=@tas] ^- @t +%- crip %- flop +%+ roll a +|= [[n=mane v=(list beer:hoot)] acc=tape] +?. .=(attr n) acc +%+ roll v +|= [b=beer:hoot acc=tape] +?^ b acc [b acc] +++ get-attrs-text :: this assumes we don't care about which attr, which we usually don't +|= a=mart:hoot ^- @t +:: ?: (gte (lent a) 1) +%- crip %- flop +%+ roll a +|= [[n=mane v=(list beer:hoot)] acc=tape] +%+ roll v +|= [b=beer:hoot acc=tape] +?^ b acc [b acc] +++ get-tag-text +|= c=marl:hoot ^- @t +:: there's only really one child in these things +%+ roll c +|= [=tuna:hoot acc=@t] +?@ -.tuna acc +%- crip +%- flop +%+ roll a.g.tuna +|= [[n=mane v=(list beer:hoot)] acc=tape] +%+ roll v +|= [b=beer:hoot acc=tape] +?^ b acc [b acc] + +++ pre +|= c=marl:hoot ^- [cord cord] +:_ '' :: lang not supported, duh +%+ roll c +|= [=tuna:hoot acc=@t] +?@ -.tuna acc +(get-attrs-text a.g.tuna) + + +++ parse-tags +|= t=@t ^- (unit (set @t)) + =/ lst (rush t (csplit:parsing:sr com)) + ?~ lst ~ (some (sy u.lst)) +++ tape-to-cm +|= =tape ^- content-map:tp +(gas:corm:tp *content-map:tp [*@da (tokenize (crip tape))]~) +:: post:trill -> manx + +:: post:trill -> (markdown) tape for display on sail +++ block-to-md +|= b=block:tp ^- tape + ?+ -.b "" +%paragraph + %^ foldi:sr p.b "" |= [in=@ud i=inline:tp acc=tape] + =/ il (inline-to-tape i) + ?: .=(+(in) (lent p.b)) + "{acc}{il}" + "{acc}{il} " +%blockquote + %+ weld "> " + %^ foldi:sr p.b "" |= [in=@ud i=inline:tp acc=tape] + =/ il (inline-to-tape i) + ?: .=(+(in) (lent p.b)) + "{acc}{il}" + "{acc}{il} " +%list + %^ foldi:sr p.b "" |= [in=@ud =li:tp acc=tape] + =/ li-tape (content-list-to-md li) + =/ line ?: ordered.b + "{<+(in)>}. {li-tape}" + "- {li-tape}" + ?: .=(+(in) (lent p.b)) + "{acc}{line}" + "{acc}{line}\0a" +%media + ?+ -.media.b "})" +%images %^ foldi:sr p.media.b "" |= [i=@ud [url=@t caption=@t] acc=tape] + =/ line "})" + ?: .=(+(i) (lent p.media.b)) + "{acc}{line}" + "{acc}{line}\0a" + == +%codeblock + """ + ``` + {(trip code.b)} + ``` + """ +%heading =/ dashes=tape ?- q.b + %h1 "# " + %h2 "## " + %h3 "### " + %h4 "#### " + %h5 "##### " + %h6 "###### " + == "{dashes}{(trip p.b)}" +%tasklist "" ::TODO + :: + :: %table acc + :: %eval acc + :: %ref acc + :: %json acc + == +++ content-list-to-md +|= =content-list:tp ^- tape + %^ foldi:sr content-list "" |= [i=@ud b=block:tp acc=tape] + =/ block-tape (block-to-md b) + ?: .=(+(i) (lent content-list)) + "{acc}{block-tape}" + "{acc}{block-tape}\0a\0a" +++ content-to-md +|= c=content-map:tp ^- tape + ?~ c "" + =/ latest=(list block:tp) val:head:(pop:corm:tp c) + (content-list-to-md latest) +++ inline-to-tape +|= i=inline:tp ^- tape + ?- -.i + %text (trip p.i) + %italic "_{(trip p.i)}_" + %bold "*{(trip p.i)}*" + %strike "~~{(trip p.i)}~~" + %ship (scow %p p.i) + %codespan "`{(trip p.i)}`" + %link "[{(trip show.i)}]({(trip href.i)})" + %break "\0a" + :: TODO custom syntax + %date + =/ t (time:enjs:format p.i) + ?. ?=(%n -.t) "" (trip p.t) + %note "" :: TODO + %underline (trip p.i) + %sup (trip p.i) + %sub (trip p.i) + %ruby (trip p.i) + == +++ tags-to-tape +|= t=(set @t) ^- tape + %^ foldi:sr ~(tap in t) "" |= [i=@ud c=@t acc=tape] + ?: .=(+(i) ~(wyt in t)) + "{acc}{(trip c)}" + "{acc}{(trip c)}," +-- diff --git a/desk/lib/trill/utils.hoon b/desk/lib/trill/utils.hoon new file mode 100644 index 0000000..ffff8b8 --- /dev/null +++ b/desk/lib/trill/utils.hoon @@ -0,0 +1,1054 @@ +/- tp=trill-post, tlonc=tlon-channels, *boke, contact +/+ sr=sortug, ui=trill-ui, const=constants +|% +++ user-profile +|= [u=@p =bowl:gall] ^- res:contact +=/ io ~(. io:sr bowl) +=/ has-contacts .^(? %gu (weld (scry-pad:io %contacts) /$)) +=/ has-whom .^(? %gu (weld (scry-pad:io %whom) /$)) +=/ tact ?. has-contacts ~ +=/ rolo (scry:io %contacts /all rolodex:contact) +=/ utact (~(get by rolo) u) +=/ prof ?~ utact ~ for.u.utact +?~ prof ~ ?~ con.prof ~ (some con.prof) + +=/ whom ?. has-whom ~ +=/ whoms (scry:io %whom /1/contacts/mars whoms:contact) +(~(get by whoms) [%.y u]) +=/ res +[u tact whom] +res +++ flatten-fn +|= fn=full-node:tp ^- (list post:tp) + :: ~> %bout.[0 %flattening] + =/ child-list (tap:form:tp children.fn) + :- p.fn + :: =/ l %+ turn child-list |= [* f=full-node:tp] p.f + =/ flist=(list post:tp) + =| l=(list post:tp) + |- + ?~ child-list l + =/ child=full-node:tp +.i.child-list + =/ nl (weld l (flatten-fn child)) + $(child-list t.child-list, l nl) + %+ sort flist |= [a=post:tp b=post:tp] (gth id.b id.a) + +++ get-children-page +|= [fn=full-node:tp r=page-req:tp] ^- spage:tp + =/ l (tap:form:tp children.fn) + =| p=spage:tp + |- + ?~ l + %= p + p %+ sort p.p |= [a=post:tp b=post:tp] (gth id.b id.a) + == + =/ node=full-node:tp val.i.l + =/ id id.p.node + ?. (page-cond id count.p r) $(l t.l) :: TODO mmm can i exit here + =/ subpage (get-children-page node r) + =/ new-posts=(list post:tp) p.subpage + =/ oldest ?~ older.p older.subpage + ?: (lth id u.older.p) older.subpage older.p + =/ newest ?~ newer.p newer.subpage + ?: (gth id u.newer.p) newer.subpage newer.p + %= $ + p.p (weld p.p [p.node new-posts]) + older.p oldest + newer.p newest + count.p +(count.p) + l t.l + == +++ get-siblings-page +|= fn=full-node:tp ^- spage:tp + =/ pg (get-children-page fn [~ ~ thread-page-size:const]) + =/ ind (find ~[p.fn] p.pg) + ?~ ind *spage:tp + =/ start=@ ?: (lth u.ind thread-page-size:const) 0 (sub u.ind thread-page-size:const) + %= pg + p (swag [start thread-page-size:const] p.pg) + == +:: ++ get-siblings-page-2 +:: |= l=(list post:tp) ^- spage:tp +:: =/ pg (get-children-page fn [~ ~ thread-page-size:const]) +:: =/ ind (find ~[p] p.pg) +:: ?~ ind *spage:tp +:: =/ start=@ ?: (lth u.ind thread-page-size:const) 0 (sub u.ind thread-page-size:const) +:: %= pg +:: p (swag [start thread-page-size:const] p.pg) +:: == + + +++ flatten-fn-2 +|= fn=full-node:tp ^- (list post:tp) + :: ~> %bout.[0 %flattening-2] + =/ child-list (tap:form:tp children.fn) + :- p.fn + %- sort :_ |= [a=post:tp b=post:tp] (gth id.b id.a) + |- ^- (list post:tp) + ?~ child-list ~ + %+ weld (flatten-fn-2 +.i.child-list) + $(child-list t.child-list) + +++ common-thread + |= [p=post:tp f=gfeed:tp] ^- @ud + =/ pid thread.p + =/ l (tap:gorm:tp f) + %- lent + %+ skim l |= [k=pid:tp v=post:tp] + .= thread.v pid +:: ++ flatten-4 +:: |= p=post:tp ^- (list pid:tp) +:: ~> %bout.[0 %flattening-4] +:: =/ child-list ~(tap in children.fn) +:: =/ =pid:tp [author.p id.p] +:: :- pid +:: |- ^- (list post:tp) +:: ?~ child-list ~ +:: =/ child-post (~(get by feed) pid) +:: %+ weld (flatten-fn-p child-post) +:: $(child-list t.child-list) +:: +$ ll (list pid:tp) +:: ++ flatten-raw +:: |= [l=ll acc=ll] ^- ll +:: ?~ l acc +:: $(l t.l, acc [i.l acc]) + + +++ node-to-full-fake +|= p=post:tp ^- full-node:tp + =/ fake-children=full-graph:tp %- ~(rep in children.p) + |= [=pid:tp acc=full-graph:tp] + (put:form:tp acc pid *full-node:tp) + :- p fake-children +++ node-to-full +|= [p=post:tp f=gfeed:tp] ^- full-node:tp + =/ children (~(del in children.p) [author.p id.p]) :: else infinite loop. not that it should happen at all + :- p (convert-children children f) + ++ convert-children + |= [children=(set pid:tp) f=gfeed:tp] + ^- full-graph:tp + %- ~(rep in children) + |= [=pid:tp acc=full-graph:tp] + =/ n (get:gorm:tp f pid) + ?~ n ~& child-not-found=pid acc + =/ full-node (node-to-full u.n f) + (put:form:tp acc pid full-node) +++ sanitize +|= c=content-list:tp ^- ? +%+ roll c |= [i=block:tp acc=_&] +?. ?=(%paragraph -.i) acc +%+ roll p.i |= [ii=inline:tp iacc=_acc] +?. ?=(%link -.ii) iacc +?~ (de-purl:html href.ii) .n .y +++ block-size +|= =block:tp ^- @ud +?- -.block +%tasklist 0 :: TODO +%paragraph (inline-size p.block) +%blockquote (inline-size p.block) +%heading (lent (trip p.block)) +%media (media-size media.block) +%codeblock +?: (gth (lent (trip lang.block)) 400) 10.000 +(lent (trip code.block)) +%eval (lent (trip hoon.block)) +%ref +?: (gth (lent (trip app.block)) 400) 10.000 +(roll path.block |=([i=@t a=@] (add a (lent (trip i))))) +%json +?: (gth (lent (trip content.block)) 5.000) 10.000 +?: (gth (lent (trip origin.block)) 1.000) 10.000 +0 +%list %+ roll p.block |= [c=content-list:tp a=@ud] %+ add a +%+ roll c |= [b=block:tp aa=@ud] (add aa (block-size b)) +:: %table +:: %+ roll rows.block |= [i=(list contents:tp) a=@] +:: =/ inner-count=@ +:: %+ roll i |= [ii=contents:tp ia=@] +:: (add ia (post-size ii)) +:: (add inner-count a) +== +++ post-size +|= c=content-list:tp +=| count=@ +|- +?~ c count +=/ lc=@ (block-size i.c) +$(c t.c, count (add count lc)) +++ inline-token-size +|= i=inline:tp ^- @ud +?+ -.i (lent (trip p.i)) +%break 1 +%date 1 +%note (add (met 3 id.i) 10):: TODO) +%ship (lent (trip (scot %p p.i))) +%ruby (lent (trip p.i)) +%link +?: (gth (lent (trip href.i)) 400) 10.000 :: to prevent hacking through a huge href string +(lent (trip show.i)) +== +++ reduce-inline +|= [i=inline:tp chars=@ud] ^+ i +?- -.i +%break i +%date i +%note i :: TODO +%ship [%text (crip (weld (scag chars (trip (scot %ud p.i))) "..."))] +%ruby i(p (crip (scag chars (trip p.i)))) +%link i(show (crip (scag chars (trip show.i)))) +%bold + [-.i (crip (scag chars (trip +.i)))] +%codespan + [-.i (crip (scag chars (trip +.i)))] +%italic + [-.i (crip (scag chars (trip +.i)))] +%strike + [-.i (crip (scag chars (trip +.i)))] +%sub + [-.i (crip (scag chars (trip +.i)))] +%sup + [-.i (crip (scag chars (trip +.i)))] +%text + [-.i (crip (weld (scag chars (trip +.i)) "..."))] +%underline + [-.i (crip (scag chars (trip +.i)))] +== +++ inline-size +|= l=(list inline:tp) ^- @ +=| count=@ud +|- + ?~ l count + =/ lc=@ud (inline-token-size i.l) + $(l t.l, count (add count lc)) + + +++ media-size +|= =media:tp ^- @ +?- -.media +%video (lent (trip p.media)) +%audio (lent (trip p.media)) +%images %+ roll p.media +|= [[url=@t caption=@t] a=@] +%+ add a (add (met 3 url) (met 3 caption)) +== + +++ search +|= [q=@t p=post:tp] ^- ? +=/ latest=content-list:tp val:head:(pop:corm:tp contents.p) +?| (in-tags ~(tap in tags.p) q) (in-blocks latest q) == +++ in-tags +|= [tl=(list @t) q=@t] ^- ? +|- +?~ tl .n +?: (contains i.tl q) .y $(tl t.tl) +++ in-blocks +|= [bl=content-list:tp q=@t] ^- ? +|- +?~ bl .n +?: (in-block i.bl q) .y $(bl t.bl) +++ in-block +|= [i=block:tp q=@t] ^- ? +?- -.i + %paragraph (in-inline p.i q) + %blockquote (in-inline p.i q) + %heading (contains p.i q) + %codeblock (contains code.i q) + %eval (contains hoon.i q) + %json (contains content.i q) + %media (in-media media.i q) + %ref %| :: TODO + :: %table %| :: TODO + %tasklist .n :: TODO + %list + |- + ?~ p.i .n + ?: (in-blocks i.p.i q) .y $(p.i t.p.i) +== +++ in-media +|= [=media:tp q=@t] ^- ? +?. ?=(%images -.media) (contains p.media q) +=/ l p.media +|- +?~ l .n +?: ?| (contains url.i.l q) (contains caption.i.l q) == .y $(l t.l) +++ in-inline +|= [l=(list inline:tp) q=@t] ^- ? +|- +?~ l .n +=/ i i.l +=/ has ?+ -.i (contains p.i q) +%break %| +%ship (contains (scot %p p.i) q) +%date .n :: TODO +%note ?|((contains id.i q) (in-inline text.i q)) +%link ?|((contains href.i q) (contains show.i q)) +%ruby ?|((contains p.i q) (contains q.i q)) +== +?: has .y $(l t.l) +++ is-my-reply +|= [p=post:tp r=post:tp our=@p] ^- ? +?~ parent.r .n +?& .=(author.r our) !.=(author.p our) == +++ is-thread-child +|= [p=post:tp r=post:tp our=@p] ^- ? +?~ parent.r .n +?& .=(author.r our) .=(author.p our) == +++ houyi +|= children=full-graph:tp ^- @ud + ?~ children 0 + =/ lst (tap:form:tp children) + %+ add (lent lst) + %+ roll lst + |= [[=pid:tp n=full-node:tp] acc=@ud] + (add acc (houyi children.n)) + +++ latest-contents +|= cm=content-map:tp ^- content-list:tp + =/ latest (pry:corm:tp cm) + ?~ latest ~ +.u.latest +:: + +++ abbreviate-post +|= [cm=content-map:tp max-chars=@ud] ^- content-list:tp + =/ c (latest-contents cm) + :: we reduce the list of blocks. We count how many characters are there in each block. + :: If the block fits in our count, we insert the block in the filtered list. + :: If not, we cut the content of the box until it does. + =/ ret=content-list:tp + =< +< + %^ spin c [bl=*content-list:tp available=max-chars] + |= [b=block:tp [bl=_c available=@ud]] + :: We must return the same data type as the input + :: We don't want to map on the individual block so return as is + :- b + :: The state tho is what we're playing with. + :: We pass the current block and the available char count to another function + =/ cut=[(unit block:tp) @ud] (cut-block b available) + :: That function checks whether the block fits within the available count. + :: It returns a maybe block and the remaining count + :: If null, we return the list as is + ?~ -.cut [bl available] + :: If we get a block back, we add that to our block list, and update the available count + [[u.-.cut bl] +.cut] + (flop ret) +++ cut-block +:: now let's go inside the block +|= [b=block:tp available=@ud] +^- [(unit block:tp) @ud] +?+ -.b [~ 0] +:: :: This we can cut +%paragraph =/ inlines (cut-inlines p.b available) +?~ -.inlines [~ available] :- `[-.b -.inlines] +.inlines +:: :: these must go whole or nothing +:: :: %blockquote +:: :: %heading +:: :: %list +:: :: %media +:: :: %eval +:: :: %poll +:: :: %ref +:: :: %json +:: :: %table +== +++ cut-inlines +|= [li=(list inline:tp) available=@ud] ^+ [li available] +?: .=(0 available) [~ 0] +:: We spin again +=/ ret=[_li @ud] +=/ initial-state [*(list inline:tp) available] +=< + +%^ spin li initial-state +|= [l=inline:tp [nl=_li available=@ud]] +:: Again we're not mapping over the tokens, just mutating an internal state +:- l +:: If no more chars available we return of course +?: .=(0 available) [nl available] +:: We look at the size of the current token +=/ size (inline-token-size l) +:: If the size is smaller than available, we add to new list, and substract from available +?: (lte size available) +[[l nl] (sub available size)] +:: If size is bigger than available we reduce the token, insert to list, set avaibable as 0 +=/ reduced (reduce-inline l available) +[[reduced nl] 0] + +[(flop -.ret) +.ret] + +:: +:: +:: search +++ text-search +|= [q=@t length=@ud p=post:tp case=?] ^- tape + :: ~> %bout.[0 %text-search] + =/ t (content-to-md:ui contents.p) + :: ~2020.7.31..23.51.21 + +:: =/ hstk ?: case t (cass t) +:: =/ nedl ?: case (trip q) (cass (trip q)) +:: =/ i (find nedl hstk) +:: ?~ i "" +:: =/ start ?: (lte u.i length) 0 (sub u.i length) +:: ?: .=(start 0) +:: "{(swag [start (mul 2 length)] t)}..." +:: "...{(swag [start (mul 2 length)] t)}..." + "" + +++ contains +|= [container=cord query=cord] ^- ? +?~ (find (trip query) (trip container)) %| %& +:: +++ text-search-ind +|= [q=@t length=@ud p=post:tp case=?] ^- @t + :: ~> %bout.[0 %text-search-ind] + ?~ contents.p '' + =/ bl=(list block:tp) val:head:(pop:corm:tp contents.p) + =| ob=(list block:tp) + |- + ?~ bl '' + :: TODO proper counts + =/ i i.bl + =/ r=(unit completion) + ?+ -.i ~ + %paragraph (inline-ind p.i q length case) + %blockquote (inline-ind p.i q length case) + :: :: %list (from-inline p.i.bl q case) + %heading (cfind-index:sr q p.i length .n) + %codeblock (cfind-index:sr q code.i length .n) + %eval (cfind-index:sr q hoon.i length .n) + %json (cfind-index:sr q content.i length .n) + :: %media (in-media2 media.i q) + :: %ref snippet :: TODO + :: %table snippet :: TODO + :: %tasklist snippet + == + ?~ r $(bl t.bl, ob [i.bl ob]) + ?: (gte (met 3 snip.u.r) length) snip.u.r :: victory + =. u.r + ?. (gth left-amari.u.r 0) u.r :: go fetch stuff on the left + =/ left-fill=@t (fill-up-block left-amari.u.r ob .y) + =/ added (cat 3 left-fill snip.u.r) + u.r(snip added, left-amari (sub left-amari.u.r (met 3 left-fill))) + =. u.r + ?. (gth right-amari.u.r 0) u.r :: go fetch stuff on the right + =/ right-fill=@t (fill-up-block right-amari.u.r t.bl .n) + =/ added (cat 3 snip.u.r right-fill) + u.r(snip added, right-amari (sub right-amari.u.r (met 3 right-fill))) + + snip.u.r + + ++$ completion [snip=@t left-amari=@ud right-amari=@ud] +++ inline-ind +|= [l=(list inline:tp) q=@t length=@ud case=?] ^- (unit completion) + =| ob=(list inline:tp) + |- + ?~ l ~ + =/ r=(unit completion) + ?+ -.i.l (cfind-index:sr q p.i.l length .n) +%break ~ +%date ~ :: TODO +%note ~ ::TODO +%ship (cfind-index:sr q (scot %p p.i.l) length .n) +%link (cfind-index:sr q (cat 3 href.i.l show.i.l) length .n) +%ruby (cfind-index:sr q (cat 3 p.i.l q.i.l) length .n) + == + ?~ r $(l t.l, ob [i.l ob]) + ?: (gte (met 3 snip.u.r) length) r :: exit condition + =. u.r + ?. (gth left-amari.u.r 0) u.r :: go fetch stuff on the left + =/ left-fill=@t (fill-up left-amari.u.r ob .y) + =/ added (cat 3 left-fill snip.u.r) + u.r(snip added, left-amari (sub left-amari.u.r (met 3 left-fill))) + =. u.r + ?. (gth right-amari.u.r 0) u.r :: go fetch stuff on the right + =/ right-fill=@t (fill-up right-amari.u.r t.l .n) + =/ added (cat 3 snip.u.r right-fill) + u.r(snip added, right-amari (sub right-amari.u.r (met 3 right-fill))) + + r + +:: +++ fill-up-block +|= [length=@ud l=(list block:tp) backwards=?] ^- @t + =| acc=@t + |- + ?~ l acc + ?: ?=(%paragraph -.i.l) (fill-up length p.i.l backwards) + ?: ?=(%blockquote -.i.l) (fill-up length p.i.l backwards) + =/ string=@t + ?+ -.i.l '' + %heading p.i.l + %codeblock code.i.l + %eval hoon.i.l + %json content.i.l + :: %media (in-media2 media.i q) + :: %ref snippet :: TODO + :: %table snippet :: TODO + :: %tasklist snippet + :: :: %list (from-inline p.i.bl q case) + == + =. acc ?: backwards + =/ end (met 3 string) + =/ start ?: (lth end length) 0 (sub end length) + =/ piece=@t (cut 3 [start end] string) + (cat 3 piece acc) + :: forwards + =/ piece=@t (cut 3 [0 length] string) + (cat 3 acc piece) + + =/ size (met 3 acc) + ?: .=(size length) acc :: exit condition + ?: (gte size length) '' :: bug + $(l t.l, length (sub length size)) + +++ fill-up +|= [length=@ud l=(list inline:tp) backwards=?] ^- @t + =| acc=@t + |- + ?~ l acc + =/ string=@t + ?+ -.i.l p.i.l +%break '' +%date '' :: TODO +%note '' ::TODO +%ship (scot %p p.i.l) +%link (cat 3 href.i.l show.i.l) +%ruby (cat 3 p.i.l q.i.l) + == + =. acc ?: backwards + =/ end (met 3 string) + =/ start ?: (lth end length) 0 (sub end length) + =/ piece=@t (cut 3 [start end] string) + (cat 3 piece acc) + :: forwards + =/ piece=@t (cut 3 [0 length] string) + (cat 3 acc piece) + + + =/ size (met 3 acc) + ?: .=(size length) acc :: exit condition + ?: (gth size length) '' :: this should never happen + $(l t.l, length (sub length size)) + +:: +++ text-search2 +|= [q=@t length=@ud p=post:tp case=?] ^- @t + ~> %bout.[0 %text-search] + ?~ contents.p '' + =/ bl=(list block:tp) val:head:(pop:corm:tp contents.p) + =| snippet=@t + |- + ?~ bl snippet + :: TODO proper counts + ?: (gth (met 3 snippet) length) snippet + =/ i i.bl + =/ ns + ?+ -.i snippet + %paragraph (from-inline p.i q length case) + :: %blockquote (from-inline p.i q length case) + :: :: %list (from-inline p.i.bl q case) + :: %heading (cfind:sr q p.i .n) + :: %codeblock (cfind:sr q code.i .n) + :: %eval (cfind:sr q hoon.i .n) + :: %json (cfind:sr q content.i .n) + :: %media (in-media2 media.i q) + :: %ref snippet :: TODO + :: %table snippet :: TODO + :: %tasklist snippet + == + $(bl t.bl, snippet (cat 3 snippet ns)) +++ from-inline +|= [l=(list inline:tp) q=@t length=@ud case=?] ^- @t + =| snippet=@t + |- + ?~ l snippet + ?: (gth (met 3 snippet) length) snippet + =/ r + ?+ -.i.l (cfindi:sr q p.i.l .n) + %break '\0a' + %date .n :: TODO + %note .n ::TODO + %ship (cfindi:sr q (scot %p p.i.l) .n) + %link (cat 3 (cfindi:sr q href.i.l .n) (cfindi:sr q show.i.l .n)) + %ruby (cat 3 (cfindi:sr q p.i.l .n) (cfindi:sr q q.i.l .n)) + == + $(l t.l, snippet (cat 3 snippet r)) + +:: ++ search2 +:: |= [q=@t p=post:tp] ^- ? +:: ?~ contents.p .n +:: =/ latest=content-list:tp val:head:(pop:corm:tp contents.p) +:: =/ in-tags %+ roll ~(tap in tags.p) |= [i=cord a=_|] +:: ?: (cfind:sr q i .n) %& a +:: =/ in-blocks %+ roll latest |= [i=block:tp a=_|] +:: ?: ?- -.i +:: %paragraph (in-inline2 p.i q) +:: %blockquote (in-block p.i q) +:: %list (in-inline2 p.i q) +:: %heading (cfind:sr q p.i .n) +:: %codeblock (cfind:sr q code.i .n) +:: %eval (cfind:sr q hoon.i .n) +:: %json (cfind:sr q content.i .n) +:: %media (in-media2 media.i q) +:: %ref %| :: TODO +:: %table %| :: TODO +:: %tasklist .n +:: == %& a +:: ?| in-tags in-blocks == +++ in-media2 +|= [=media:tp q=@t] ^- ? +?. ?=(%images -.media) (cfind:sr q p.media .n) +%+ roll p.media |= [[url=cord caption=cord] a=_|] +?: (cfind:sr q url .n) %& a +:: ++ in-inline2 +:: |= [l=(list inline:tp) q=@t] ^- ? +:: |- +:: ?~ l .n +:: =/ i i.l +:: =/ r=? +:: ?+ -.i (cfind:sr q p.i .n) +:: %break .n +:: %date .n +:: %note .n +:: %ship (cfind:sr q (scot %p p.i) .n) +:: %link ?|((cfind:sr q href.i .n) (cfind:sr q show.i .n)) +:: %ruby ?|((cfind:sr q p.i .n) (cfind:sr q q.i .n)) +:: == +:: ?| r $(l t.l) == +:: +++ page-cond +|= [id=@da current=@ud r=page-req:tp] ^- ? +=/ need-more (lth current count.r) +?~ newer.r + :: newest not bound + ?~ older.r + :: neither oldest or newest is bound + need-more + :: oldest is bound, newest isn't + ?& need-more (lth id u.older.r) == + :: newest bound + ?~ older.r + :: newest is bound, oldest isn't + ?& need-more (gth id u.newer.r) == + :: both are bound + ?&(need-more (lth id u.older.r) (gth id u.newer.r)) +++ get-post-page +|= [feed=gfeed:tp req=page-req:tp] ^- page:tp +=/ from-bottom=? ?& ?=(%~ older.req) ?!(?=(%~ newer.req)) == +=/ l ?. from-bottom (tap:gorm:tp feed) (flop (tap:gorm:tp feed)) +=/ res +%+ roll l +|= [[=pid:tp =post:tp] a=[p=page:tp max=@da min=@da]] +=/ id id.pid +?^ parent.post a +=/ max ?: (gth id max.a) id max.a +=/ min ?: ?|((lth id min.a) .=(min.a *@da)) id min.a +:_ [max min] +=/ condition=? (page-cond id count.p.a req) +?. condition p.a +=/ posts [(node-to-full post feed) p.p.a] +:: +=/ oldest ?~ older.p.a `id + ?: (lth id u.older.p.a) `id older.p.a +=/ newest ?~ newer.p.a `id + ?: (gth id u.newer.p.a) `id newer.p.a +[posts newest oldest +(count.p.a)] +:: TODO arg gotta figure this out +=/ o + ?: .=(older.p.res `min.res) ~ older.p.res + :: ?: (lth count.res count.req) ~ +=/ n ?: .=(newer.p.res `max.res) ~ newer.p.res +=/ poasts ?. from-bottom (flop p.p.res) p.p.res +[poasts n o count.p.res] +:: ++ basic-filter +:: |= [=feed:tp req=page-req:tp filter=$-(post:tp ?)] +:: |= [[=id:tp =post:tp] a=spage:tp] +:: ?. (filter post) a +:: =/ posts [post p.a] +:: =/ oldest ?~ older.a `id +:: ?: (lth id u.older.a) `id older.a +:: [posts newer.r oldest +(count.a)] +:: TODO spage or page... +++ get-filtered-post-page-full +|= [feed=gfeed:tp req=page-req:tp filter=$-(post:tp ?)] ^- page:tp +=/ from-bottom=? ?& ?=(%~ older.req) ?!(?=(%~ newer.req)) == +=/ l ?. from-bottom (tap:gorm:tp feed) (flop (tap:gorm:tp feed)) +=/ res +%+ roll l +|= [[=pid:tp =post:tp] a=[p=page:tp max=@da min=@da]] +=/ id id.pid +?. (filter post) a +=/ condition=? (page-cond id count.p.a req) +=/ max ?: (gth id max.a) id max.a +=/ min ?: ?|((lth id min.a) .=(min.a *@da)) id min.a +:_ [max min] +?. condition p.a +=/ posts [(node-to-full post feed) p.p.a] +:: +=/ oldest ?~ older.p.a `id + ?: (lth id u.older.p.a) `id older.p.a +=/ newest ?~ newer.p.a `id + ?: (gth id u.newer.p.a) `id newer.p.a +[posts newest oldest +(count.p.a)] +:: TODO arg gottaa figure this out +=/ o + ?: .=(older.p.res `min.res) ~ older.p.res + :: ?: (lth count.res count.req) ~ +=/ n ?: .=(newer.p.res `max.res) ~ newer.p.res +=/ poasts ?. from-bottom (flop p.p.res) p.p.res +[poasts n o count.p.res] +++ get-filtered-post-page +|= [feed=gfeed:tp req=page-req:tp filter=$-(post:tp ?)] ^- spage:tp + =/ from-bottom=? ?& ?=(%~ older.req) ?!(?=(%~ newer.req)) == + =/ l ?. from-bottom (tap:gorm:tp feed) (flop (tap:gorm:tp feed)) + =/ res + %+ roll l + |= [[=pid:tp =post:tp] a=[p=spage:tp max=@da min=@da]] + =/ id id.pid + ?. (filter post) a + =/ condition=? (page-cond id count.p.a req) + =/ max ?: (gth id max.a) id max.a + =/ min ?: ?|((lth id min.a) .=(min.a *@da)) id min.a + :_ [max min] + ?. condition p.a + =/ posts [post p.p.a] + :: + =/ oldest ?~ older.p.a `id + ?: (lth id u.older.p.a) `id older.p.a + =/ newest ?~ newer.p.a `id + ?: (gth id u.newer.p.a) `id newer.p.a + [posts newest oldest +(count.p.a)] + :: TODO arg gottaa figure this out + =/ o + ?: .=(older.p.res `min.res) ~ older.p.res + :: ?: (lth count.res count.req) ~ + =/ n ?: .=(newer.p.res `max.res) ~ newer.p.res + =/ poasts ?. from-bottom (flop p.p.res) p.p.res + [poasts n o count.p.res] + +:: ++ get-tag-page +:: |= [feed=gfeed:tp tt=tags-table l=(list @t) r=page-req:tp] ^- page:tp +:: ~> %bout +:: =/ pids %+ roll l |= [i=@t a=(list pid:tp)] =/ ps (~(get by tt) i) +:: ?~ ps a (weld u.ps a) +:: =/ filter |= =post:tp (~(has in (sy pids)) [author.post id.post]) +:: (get-filtered-post-page-full feed r filter) + +:: ++ pcond +:: |= [id=@da r=page-req:tp] ^- ? +:: ?~ older.r +:: ?~ newer.r .y +:: (gth id u.newer.r) +:: ?~ newer.r +:: (lth id u.older.r) +:: ?& (lth id u.older.r) (gth id u.newer.r) == + +:: ++ get-tag-page-2 +:: |= [feed=gfeed:tp tt=tags-table l=(list @t) r=page-req:tp] ^- page:tp +:: =/ =pid-graph:tp +:: ~> %bout +:: %+ roll l |= [i=@t a=pid-graph:tp] +:: =/ pids-by-tag (~(get by tt) i) +:: ?~ pids-by-tag a =/ pl (flop u.pids-by-tag) +:: |- +:: ?~ pl a +:: ?. (pcond id.i.pl r) $(pl t.pl) +:: %= $ +:: a (put:porm:tp a id.i.pl ship.i.pl) +:: pl t.pl +:: == +:: =/ top (pry:porm:tp pid-graph) +:: =/ tom (ram:porm:tp pid-graph) +:: =/ max ?~ top ~ `-.u.top +:: =/ min ?~ tom ~ `-.u.tom +:: =/ res=page:tp +:: =| =page:tp +:: =/ pids (tap:porm:tp pid-graph) +:: |- +:: ?~ pids page +:: =/ id -.i.pids +:: ?: .=(count.page count.r) page +:: ?. (pcond id r) $(pids t.pids) +:: =/ post (get:gorm:tp feed [+.i.pids id]) +:: ?~ post $(pids t.pids) +:: =/ np=page:tp +:: =/ posts [(node-to-full u.post feed) p.page] +:: =/ oldest ?~ older.page `id +:: ?: (lth id u.older.page) `id older.page +:: =/ newest ?~ newer.page `id +:: ?: (gth id u.newer.page) `id newer.page +:: [posts newest oldest +(count.page)] +:: %= $ +:: page np +:: pids t.pids +:: == +:: =/ n ?: .=(max newer.res) ~ newer.res +:: =/ o ?: .=(min older.res) ~ older.res +:: res(newer n, older o, p (flop p.res)) + +:: ++ get-tag-page-3 +:: |= [feed=gfeed:tp tt=tags-table l=(list @t) r=page-req:tp] ^- page:tp +:: ~> %bout +:: =/ empty *page:tp +:: =| count=@ud +:: =/ posts=(list full-node:tp) +:: |- ^- (list full-node:tp) +:: ?~ l ~ +:: =/ pids (~(get by tt) i.l) +:: ?~ pids ~ +:: =/ pl (flop u.pids) +:: %+ welp ^- (list full-node:tp) +:: |- +:: ?~ pl ~ +:: ?: (gte count count.r) ~ +:: ?. (pcond +.i.pl r) $(pl t.pl) +:: =/ poast (get:gorm:tp feed i.pl) +:: ?~ poast $(pl t.pl) +:: =/ fn (node-to-full u.poast feed) +:: :- fn +:: $(pl t.pl, count +(count)) +:: $(l t.l) +:: :: +:: =/ newer ~ +:: =/ older ?~ posts ~ (some id:p:(rear posts)) +:: [posts newer older (lent posts)] + +++ tag-search + |= l=(list @t) + |= =post:tp ^- ? + |- + ?~ l .n + =/ ok=? ?& (~(has in tags.post) (crip (cass (trip i.l)))) ?=(%~ parent.post) == + ?: ok .y + $(l t.l) + +++ tag-search-old +|= [l=(list @t) feed=gfeed:tp r=page-req:tp] ^- page:tp + %+ roll (tap:gorm:tp feed) |= [[=pid:tp =post:tp] a=page:tp] + =/ id id.pid + =/ condition (page-cond id count.a r) + ?. condition a + =/ found + =/ has .y + |- + ?~ l has + ?& has + =/ ns (~(has in tags.post) (crip (cass (trip i.l)))) + $(l t.l, has ns) + == + =/ posts ?. found p.a :_ p.a + (node-to-full post feed) + =/ oldest ?~ older.a `id + ?: (lth id u.older.a) `id older.a + =/ count ?: .=(count.a count.r) count.r +(count.a) + [posts newer.r oldest count] +:: +++ search-filter-full +|= [feed=gfeed:tp req=page-req:tp filter=$-(post:tp ?)] ^- page:tp +=/ from-bottom=? ?& ?=(%~ older.req) ?!(?=(%~ newer.req)) == +=/ l ?. from-bottom (tap:gorm:tp feed) (flop (tap:gorm:tp feed)) +=/ res +%+ roll l +|= [[=pid:tp =post:tp] a=[p=page:tp max=@da min=@da]] +=/ id id.pid +?. (filter post) a +=/ condition=? (page-cond id count.p.a req) +=/ max ?: (gth id max.a) id max.a +=/ min ?: ?|((lth id min.a) .=(min.a *@da)) id min.a +:_ [max min] +?. condition p.a +=/ posts [(node-to-full post feed) p.p.a] +:: +=/ oldest ?~ older.p.a `id + ?: (lth id u.older.p.a) `id older.p.a +=/ newest ?~ newer.p.a `id + ?: (gth id u.newer.p.a) `id newer.p.a +[posts newest oldest +(count.p.a)] +=/ o + ?: .=(older.p.res `min.res) ~ older.p.res + :: ?: (lth count.res count.req) ~ +=/ n ?: .=(newer.p.res `max.res) ~ newer.p.res +=/ poasts ?. from-bottom (flop p.p.res) p.p.res +[poasts n o count.p.res] + +++ search-filter +|= [feed=gfeed:tp req=page-req:tp filter=$-(post:tp ?)] ^- spage:tp +=/ from-bottom=? ?& ?=(%~ older.req) ?!(?=(%~ newer.req)) == +=/ l ?. from-bottom (tap:gorm:tp feed) (flop (tap:gorm:tp feed)) +=/ res +%+ roll l +|= [[=pid:tp =post:tp] a=[p=spage:tp max=@da min=@da]] +=/ id id.pid +?. (filter post) a +=/ condition=? (page-cond id count.p.a req) +=/ max ?: (gth id max.a) id max.a +=/ min ?: ?|((lth id min.a) .=(min.a *@da)) id min.a +:_ [max min] +?. condition p.a +=/ posts [post p.p.a] +:: +=/ oldest ?~ older.p.a `id + ?: (lth id u.older.p.a) `id older.p.a +=/ newest ?~ newer.p.a `id + ?: (gth id u.newer.p.a) `id newer.p.a +[posts newest oldest +(count.p.a)] +=/ o + ?: .=(older.p.res `min.res) ~ older.p.res + :: ?: (lth count.res count.req) ~ +=/ n ?: .=(newer.p.res `max.res) ~ newer.p.res +=/ poasts ?. from-bottom (flop p.p.res) p.p.res +[poasts n o count.p.res] + +:: +++ tlon-scan-to-post + |= s=reference:tlonc ^- post:tp + =/ np *post:tp + ?: ?=(%post -.s) + =/ =memo:tlonc +>-.s + =/ children %- sy %+ turn (tap:on-replies:tlonc replies.+<.s) + |= [id=@da reply:tlonc] [author id] + %= np + id sent.memo + author author.memo + thread [~zod sent.memo] :: TODO mmm + parent ~ + contents (tlon-trill-contents content.memo sent.memo) + children children + == + :: + =/ =memo:tlonc +.reply.s + =/ par parent-id.-.reply.s + %= np + id sent.memo + author author.memo + thread [~zod par] :: TODO really? + parent (some [~zod par]) :: TODO mmm + contents (tlon-trill-contents content.memo sent.memo) + == +++ tlon-trill-contents + |= [l=(list verse:tlonc) =time] ^- content-map:tp + =/ cl=content-list:tp %+ roll l + |= [i=verse:tlonc a=content-list:tp] + ?: ?=(%block -.i) :_ a (tlon-block p.i) + =/ l p.i + =/ nb=content-list:tp *content-list:tp + =/ cl=content-list:tp + |- + ?~ l nb + =/ nnb=content-list:tp + ?: ?=(%task -.i.l) =/ task [(turn q.i.l tlon-inline) p.i.l] + =/ lb (last-block nb %tasklist) + =/ tl=(list task:tp) ?~ lb ~ ?. ?=(%tasklist -.u.lb) ~ p.u.lb + (snoc nb [%tasklist (snoc tl task)]) + ?: ?=(%blockquote -.i.l) + (snoc nb [%blockquote (turn p.i.l tlon-inline)]) + ?: ?=(%code -.i.l) + (snoc nb [%codeblock p.i.l '']) + ?: ?=(%block -.i.l) + (snoc nb [%ref %channels ~zod /]) :: TODO lol + :: + =/ bun=(list inline:tp) ~ + =/ f (flop nb) + =/ inlines ?~ f bun + =/ first=block:tp -.f + ?. ?=(%paragraph -.first) bun p.first + %+ snoc nb :- %paragraph + %+ snoc inlines + ?- -.i.l + %italics [%italic (crip (flatten-tlon-inline p.i.l))] + %bold [%bold (crip (flatten-tlon-inline p.i.l))] + %strike [%strike (crip (flatten-tlon-inline p.i.l))] + %inline-code [%codespan p.i.l] + %ship [%ship p.i.l] + %tag [%text p.i.l] + %link [%link p.i.l q.i.l] + %break [%break ~] + == + $(l t.l, nb nnb) + (weld cl a) + + =/ g=(list [@da content-list:tp]) :~([time (flop cl)]) + %+ gas:corm:tp *content-map:tp g + +:: +++ last-block +|= [l=content-list:tp tag=$?(%paragraph %tasklist)] ^- (unit block:tp) +=/ f (flop l) +|- +?~ f ~ +?: .=(tag -.i.f) (some i.f) $(f t.f) +++ tlon-block +|= b=block:tlonc ^- block:tp +?- -.b +%image [%media %images ~[[src.b alt.b]]] +%cite (tlon-cite +.b) +%header [%heading (crip (flatten-tlon-inline q.b)) p.b] +%listing (tlon-listing p.b) +%rule [%paragraph ~] +%code [%codeblock code.b lang.b] +== +++ tlon-listing +|= l=listing:tlonc ^- block:tp +?. ?=(%list -.l) [%paragraph (turn p.l tlon-inline)] +:: + ?: ?=(%tasklist p.l) :- %tasklist ~ :: TODO wtf is this%+ roll q.l :: TODO idgi what r does in this type + :- %list :_ ?=(%ordered p.l) ~ :: TODO i'm tired + :: :_ ~ :_ ~ %+ roll q.l tlon-listing + +++ tlon-inline +|= i=inline:tlonc ^- inline:tp +?@ i [%text i] +?- -.i +%italics [%italic (crip (flatten-tlon-inline p.i))] +%bold [%bold (crip (flatten-tlon-inline p.i))] +%strike [%strike (crip (flatten-tlon-inline p.i))] +%blockquote [%text (crip (weld "> " (flatten-tlon-inline p.i)))] +%inline-code [%codespan p.i] +%code [%codespan p.i] +%ship [%ship p.i] +%block [%break ~]:: [%ref %channels ~zod /] +%tag [%text p.i] +%link [%link p.i q.i] +%task [%text ''] +%break [%break ~] +== +++ flatten-tlon-inline +|= l=(list inline:tlonc) ^- tape +%+ roll l |= [i=inline:tlonc a=tape] +=/ res +?@ i (trip i) +?- -.i +%italics (flatten-tlon-inline p.i) +%bold (flatten-tlon-inline p.i) +%strike (flatten-tlon-inline p.i) +%blockquote (flatten-tlon-inline p.i) +%inline-code (trip p.i) +%code (trip p.i) +%ship (scow %p p.i) +%block (trip q.i) +%tag (trip p.i) +%link (trip p.i) +%task (flatten-tlon-inline q.i) +%break "" +== +" {a} {res}" +++ tlon-cite +|= c=cite:tlonc +:- %ref +?- -.c +%chan [%channels p.q.nest.c wer.c] :: TODO is this path ok? nah needs type of channel and whatever +%group [%groups p.flag.c /[q.flag.c]] +%desk [%app p.flag.c wer.c] :: TODO same +%bait [%groups p.grp.c wer.c] :: TODO same +== +:: ++ add-tag-lookup +:: |= [lt=(list @t) =pid:tp table=tags-table] ^- tags-table +:: %^ fold:sr lt table |= [tag=@t a=tags-table] +:: =/ cur (~(get by a) tag) +:: =/ nl ?~ cur +:: =/ bnt *threads +:: (put:torm:tp bnt pid ) +:: ~[pid] [pid u.cur] +:: (~(put by a) tag nl) + +-- diff --git a/desk/lib/twatter.hoon b/desk/lib/twatter.hoon new file mode 100644 index 0000000..3410c0d --- /dev/null +++ b/desk/lib/twatter.hoon @@ -0,0 +1,511 @@ +/- spider +/+ strandio,sr=sortug, server +=, strand=strand:spider +=, strand-fail=strand-fail:libstrand:spider +|% ++$ kv [k=@t v=@t] ++$ param [k=@t v=json] +:: check nitter/src/consts.nim +++ auth-key :: nitters +'Bearer AAAAAAAAAAAAAAAAAAAAAFQODgEAAAAAVHTp76lzh3rFzcHbmHVvQxYYpTw%3DckAlMINMjmCwxUcaXbAN4XqJVdgMJaHqNOFgPMK0zN1qLqLQCF' +++ api-key +'Bearer AAAAAAAAAAAAAAAAAAAAANRILgAAAAAAnNwIzUejRCOuH5E6I8xnZz4puTs%3D1Zv7ttfk8LF81IUq16cHjhLTvJu4FA33AGWWjCpTnA' +++ api-key2 +'Bearer AAAAAAAAAAAAAAAAAAAAAIWCCAAAAAAA2C25AxqI%2BYCS7pdfJKRH8Xh19zA%3D8vpDZzPHaEJhd20MKVWp3UR38YoPpuTX7UD2cVYo3YNikubuxd' +:: iphone +++ api-key-3 +'Bearer AAAAAAAAAAAAAAAAAAAAAAj4AQAAAAAAPraK64zCZ9CSzdLesbE7LB%2Bw4uE%3DVJQREvQNCZJNiz3rHO7lOXlkVOQkzzdsgu6wWgcazdMUaGoUGm' +:: ipad -- TimelineSearch returns data in a different format, making nitter return empty results. on the other hand, it has high rate limits. build separate token pools per endpoint? +++ api-key-4 +'Bearer AAAAAAAAAAAAAAAAAAAAAGHtAgAAAAAA%2Bx7ILXNILCqkSGIzy6faIHZ9s3Q%3DQy97w6SIrzE7lQwPJEYQBsArEE2fC25caFwRBvAGi456G09vGR' +++ base-url +"https://api.twitter.com/" +++ graphql +(weld base-url "graphql/") +++ burl +|= [query-id=tape path=tape] ^- tape +"{graphql}{query-id}/{path}" +++ urls + |% + ++ tweet-lurk + [query-id="mbnjGF4gOwo5gyp9pe5s4A" path="TweetResultByRestId"] + :: logged gets + ++ user-by-id + [query-id="oPppcargziU1uDQHAUmH-A" path="UserResultByIdQuery"] + ++ user-tweets + [query-id="VgitpdpNZ-RUIp5D1Z_D-A" path="UserTweets"] + ++ user-by-name + [query-id="G3KGOASz96M-Qu0nwmGXNg" path="UserByScreenName"] + ++ user-replies + [query-id="8IS8MaO-2EN6GZZZb8jF0g" path="UserWithProfileTweetsAndRepliesQueryV2"] + ++ user-media + [query-id="PDfFf8hGeJvUCiTyWtw4wQ" path="MediaTimelineV2"] + ++ conversation + [query-id="83h5UyHZ9wEKBVzALX8R_g" path="ConversationTimelineV2"] + ++ tweet-result + [query-id="sITyJdhRPpvpEjg4waUmTA" path="TweetResultByIdQuery"] + ++ list-by-id + [query-id="iTpgCtbdxrsJfyx0cFjHqg" path="ListByRestId"] + ++ list-by-slug + [query-id="-kmqNvm5Y-cVrfvBy6docg" path="ListBySlug"] + ++ list-members + [query-id="P4NpVZDqUD_7MEM84L-8nw" path="ListMembers"] + ++ list-timeline + [query-id="BbGLL1ZfMibdFNWlk7a0Pw" path="ListTimeline"] + ++ tweet-detail + [query-id="BbmLpxKh8rX8LNe2LhVujA" path="TweetDetail"] + ++ search-timeline + [query-id="lZ0GCEojmtQfiUQa5oJSEw" path="SearchTimeline"] + :: POST URLs + ++ create-tweet + [query-id="5V_dkq1jfalfiFOEZ4g47A" path="CreateTweet"] + ++ create-retweet + [query-id="ojPdsZsimiJrUGLR1sjUtA" path="CreateRetweet"] + ++ favorite-tweet + [query-id="lI07N6Otwv1PhnEgXILM7A" path="FavoriteTweet"] + ++ delete-tweet + [query-id="VaenaVgh5q5ih7kvyVjgtg" path="DeleteTweet"] + -- +:: shit this is legacy +++ notifications-url "https://twitter.com/i/api/2/notifications/all.json" +++ base-variables +^- (list param) +:~ +['includePromotedContent' b+%|] +['withHighlightedLabel' b+%|] +['withCommunity' b+%|] +['with_rux_injections' b+%|] +['referrer' s+'tweet'] +['withTweetQuoteCount' b+%&] +['withBirdwatchNotes' b+%|] +['withBirdwatchPivots' b+%|] +['withTweetResult' b+%&] +['withReactions' b+%&] +['withReactionsMetadata' b+%|] +['withReactionsPerspective' b+%|] +['withSuperFollowsTweetFields' b+%|] +['withSuperFollowsUserFields' b+%|] +['withUserResults' b+%|] +['withVoice' b+%&] +['withV2Timeline' b+%&] +:: +['withQuickPromoteEligibilityTweetFields' b+%|] +== +++ build-variables +|= l=(list param) ^- tape +%- uri-encode:sr +%- trip +%- en:json:html %- pairs:enjs:format +(weld base-variables l) +++ features-2 +^- tape +%- uri-encode:sr +%- trip +%- en:json:html %- pairs:enjs:format +:~ +['android_graphql_skip_api_media_color_palette' b+.n] +['blue_business_profile_image_shape_enabled' b+.n] +['creator_subscriptions_subscription_count_enabled' b+.n] +['creator_subscriptions_tweet_preview_api_enabled' b+.y] +['freedom_of_speech_not_reach_fetch_enabled' b+.n] +['graphql_is_translatable_rweb_tweet_is_translatable_enabled' b+.n] +['hidden_profile_likes_enabled' b+.n] +['highlights_tweets_tab_ui_enabled' b+.n] +['interactive_text_enabled' b+.n] +['longform_notetweets_consumption_enabled' b+.y] +['longform_notetweets_inline_media_enabled' b+.n] +['longform_notetweets_richtext_consumption_enabled' b+.y] +['longform_notetweets_rich_text_read_enabled' b+.n] +['responsive_web_edit_tweet_api_enabled' b+.n] +['responsive_web_home_pinned_timelines_enabled' b+.n] +['responsive_web_enhance_cards_enabled' b+.n] +['responsive_web_graphql_exclude_directive_enabled' b+.y] +['responsive_web_graphql_skip_user_profile_image_extensions_enabled' b+.n] +['responsive_web_graphql_timeline_navigation_enabled' b+.n] +['responsive_web_media_download_video_enabled' b+.n] +['responsive_web_text_conversations_enabled' b+.n] +['responsive_web_twitter_article_tweet_consumption_enabled' b+.n] +['responsive_web_twitter_blue_verified_badge_is_enabled' b+.y] +['rweb_lists_timeline_redesign_enabled' b+.y] +['spaces_2022_h2_clipping' b+.y] +['spaces_2022_h2_spaces_communities' b+.y] +['standardized_nudges_misinfo' b+.n] +['subscriptions_verification_info_enabled' b+.y] +['subscriptions_verification_info_reason_enabled' b+.y] +['subscriptions_verification_info_verified_since_enabled' b+.y] +['super_follow_badge_privacy_enabled' b+.n] +['super_follow_exclusive_tweet_notifications_enabled' b+.n] +['super_follow_tweet_api_enabled' b+.n] +['super_follow_user_api_enabled' b+.n] +['tweet_awards_web_tipping_enabled' b+.n] +['tweet_with_visibility_results_prefer_gql_limited_actions_policy_enabled' b+.n] +['tweetypie_unmention_optimization_enabled' b+.n] +['unified_cards_ad_metadata_container_dynamic_card_content_query_enabled' b+.n] +['verified_phone_label_enabled' b+.n] +['vibe_api_enabled' b+.n] +['view_counts_everywhere_api_enabled' b+.n] +== +++ post-features ^- (list [@t json]) +:~ ['c9s_tweet_anatomy_moderator_badge_enabled' b+.y] + ['freedom_of_speech_not_reach_fetch_enabled' b+.y] + ['graphql_is_translatable_rweb_tweet_is_translatable_enabled' b+.y] + ['longform_notetweets_consumption_enabled' b+.y] + ['longform_notetweets_inline_media_enabled' b+.y] + ['longform_notetweets_rich_text_read_enabled' b+.y] + ['responsive_web_edit_tweet_api_enabled' b+.y] + ['responsive_web_enhance_cards_enabled' b+.n] + ['responsive_web_graphql_exclude_directive_enabled' b+.y] + ['responsive_web_graphql_skip_user_profile_image_extensions_enabled' b+.n] + ['responsive_web_graphql_timeline_navigation_enabled' b+.y] + ['responsive_web_home_pinned_timelines_enabled' b+.y] + ['responsive_web_media_download_video_enabled' b+.n] + ['responsive_web_twitter_article_tweet_consumption_enabled' b+.n] + ['standardized_nudges_misinfo' b+.y] + ['tweet_awards_web_tipping_enabled' b+.n] + ['tweet_with_visibility_results_prefer_gql_limited_actions_policy_enabled' b+.y] + ['tweetypie_unmention_optimization_enabled' b+.y] + ['verified_phone_label_enabled' b+.n] + ['view_counts_everywhere_api_enabled' b+.y] +== +++ features +^- tape +%- uri-encode:sr +%- trip +%- en:json:html %- pairs:enjs:format +:~ +['creator_subscriptions_tweet_preview_api_enabled' b+%&] +['freedom_of_speech_not_reach_fetch_enabled' b+%|] +['graphql_is_translatable_rweb_tweet_is_translatable_enabled' b+%&] +['interactive_text_enabled' b+%&] +['longform_notetweets_consumption_enabled' b+%&] +['longform_notetweets_inline_media_enabled' b+%&] +['longform_notetweets_rich_text_read_enabled' b+%|] +['longform_notetweets_richtext_consumption_enabled' b+%|] +['responsive_web_edit_tweet_api_enabled' b+%&] +['responsive_web_enhance_cards_enabled' b+%|] +['responsive_web_home_pinned_timelines_enabled' b+.n] +['responsive_web_graphql_exclude_directive_enabled' b+%&] +['responsive_web_graphql_timeline_navigation_enabled' b+%&] +['responsive_web_graphql_skip_user_profile_image_extensions_enabled' b+%|] +['responsive_web_media_download_video_enabled' b+%&] +['responsive_web_text_conversations_enabled' b+%|] +['responsive_web_twitter_blue_verified_badge_is_enabled' b+%&] +['responsive_web_twitter_article_tweet_consumption_enabled' b+%&] +['rweb_lists_timeline_redesign_enabled' b+%&] +['standardized_nudges_misinfo' b+%&] +['tweet_awards_web_tipping_enabled' b+%|] +['tweet_with_visibility_results_prefer_gql_limited_actions_policy_enabled' b+%|] +['tweetypie_unmention_optimization_enabled' b+%&] +['verified_phone_label_enabled' b+%|] +['vibe_api_enabled' b+%&] +['view_counts_everywhere_api_enabled' b+%&] +:: +['android_graphql_skip_api_media_color_palette' b+.y] +['super_follow_badge_privacy_enabled' b+.y] +['super_follow_tweet_api_enabled' b+.y] +['subscriptions_verification_info_enabled' b+.y] +['blue_business_profile_image_shape_enabled' b+.n] +['super_follow_user_api_enabled' b+.y] +['creator_subscriptions_subscription_count_enabled' b+.y] +['super_follow_exclusive_tweet_notifications_enabled' b+.y] +['unified_cards_ad_metadata_container_dynamic_card_content_query_enabled' b+.y] +:: logged +['c9s_tweet_anatomy_moderator_badge_enabled' b+.n] +:: logged profile +['hidden_profile_likes_enabled' b+.n] +['subscriptions_verification_info_verified_since_enabled' b+.n] +['highlights_tweets_tab_ui_enabled' b+.n] +['subscriptions_verification_info_is_identity_verified_enabled' b+.n] +['hidden_profile_subscriptions_enabled' b+.n] +== +++ userid-params +|= id=@t ^- tape +=/ vrs (build-variables ~[['userId' %s id] ['count' %n '20']]) +"?variables={vrs}&features={features}" +++ post-params +|= id=@t ^- tape +=/ vrs (build-variables ~[['tweetId' %s id]]) +"?variables={vrs}&features={features}" +++ user-params +|= id=@t ^- tape +=/ vrs (build-variables ~[['screen_name' %s id]]) +"?variables={vrs}&features={features-2}" +++ user-tweets-params +|= id=@t ^- tape +=/ vrs (build-variables ~[['rest_id' %s id] ['count' %n '100']]) +"?variables={vrs}&features={features-2}" +++ legacy-params ^- (list kv) +:~ ['include_profile_interstitial_type' '1'] + ['include_blocking' '1'] + ['include_blocked_by' '1'] + ['include_followed_by' '1'] + ['include_want_retweets' '1'] + ['include_mute_edge' '1'] + ['include_can_dm' '1'] + ['include_can_media_tag' '1'] + ['include_ext_has_nft_avatar' '1'] + ['include_ext_is_blue_verified' '1'] + ['include_ext_verified_type' '1'] + ['skip_status' '1'] + ['cards_platform' 'Web-12'] + ['include_cards' '1'] + ['include_ext_alt_text' 'true'] + ['include_ext_limited_action_results' 'false'] + ['include_quote_count' 'true'] + ['include_reply_count' '1'] + ['tweet_mode' 'extended'] + ['include_ext_collab_control' 'true'] + ['include_ext_views' 'true'] + ['include_entities' 'true'] + ['include_ext_media_color' 'true'] + ['include_ext_media_availability' 'true'] + ['include_ext_sensitive_media_warning' 'true'] + ['include_ext_trusted_friends_metadata' 'true'] + ['send_error_codes' 'true'] + ['simple_quoted_tweet' 'true'] + ['include_ext_edit_control' 'true'] + ['ext' 'mediaStats,highlightedLabel,hasNftAvatar,voiceInfo,enrichments,superFollowMetadata,unmentionInfo,editControl,collab_control,vibe'] +== +++ params-to-tape +|= l=(list kv) ^- tape +%+ roll l +|= [i=[k=@t v=@t] a=tape] +=/ key (trip k.i) +=/ val (trip v.i) +?~ a "{a}key={val}" +"{a}&{key}={val}" +++ notes-params +%- params-to-tape +%+ weld legacy-params +:~ ['count' '20'] + ['requestContext' 'launch'] +== +++ search-params +|= [query=@t cursor=@t count=@ type=?(%user %post)] ^- tape +=/ base=(list kv) %+ weld legacy-params +:~ ['q' query] + ['count' (crip "{<count>}")] + ['query_source' 'typeahead_click'] :: 'typed_query + ['cursor' cursor] + ['pc' '1'] + ['spelling_corrections' '1'] + ['include_ext_edit_control' 'true'] + ['ext' 'mediaStats,highlightedLabel,hasNftAvatar,voiceInfo,enrichments,superFollowMetadata,unmentionInfo,editControl,collab_control,vibe'] +== +=/ full=(list [@t @t]) ?- type + %user (snoc base ['result_filter' 'user']) + %post (snoc base ['tweet_search_mode' 'live']) +== +(params-to-tape full) +:: requests +:: guest-token +++ gt-request +^- request:http +=/ method %'POST' +=/ url 'https://api.twitter.com/1.1/guest/activate.json' +=/ headers +:~ +['connection' 'keep-alive'] +['authorization' auth-key] +['content-type' 'application/x-www-form-urlffencoded'] +['x-twitter-active-user' 'yes'] +['x-twitter-client-language' 'en-us'] +['Accept-language' 'en-US,en;q=0.9'] +['Accept' '*/*'] +['origin' 'https://twitter.com'] +['referer' 'https://twitter.com/'] +['DNT' '1'] +['User-agent' 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.93 Safari/537.36'] +== +[method url headers ~] +++ parse-gt +|= res=client-response:iris +=/ m (strand ,cord) +^- form:m +?. ?=(%finished -.res) (strand-fail:strand %no-body ~) +?~ full-file.res (strand-fail:strand %no-body ~) +=/ body=@t q.data.u.full-file.res +=/ jon=(unit json) (de:json:html body) +?~ jon (strand-fail:strand %no-body ~) +(pure:m (parse-gt-json u.jon)) +++ parse-gt-json + |= =json + ^- @t + =/ mapi ((om so):dejs:format json) + (~(got by mapi) 'guest_token') +::: csrf +++ csrf-token-request +^- request:http +=/ method %'GET' +=/ url 'https://developer.twitter.com/en' +=/ headers +:~ +['connection' 'keep-alive'] +['content-type' 'application/x-www-form-urlffencoded'] +['x-twitter-active-user' 'yes'] +['x-twitter-client-language' 'en-us'] +['Accept-language' 'en-US,en;q=0.9'] +['Accept' '*/*'] +['origin' 'https://twitter.com'] +['referer' 'https://twitter.com/'] +['DNT' '1'] +['User-agent' 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.93 Safari/537.36'] +== +[method url headers ~] +++ parse-csrf +|= res=client-response:iris +=/ m (strand ,cord) +^- form:m +?. ?=(%finished -.res) (strand-fail:strand %no-body ~) +=+ %+ skim headers.response-header.res +|= pair=[key=@t value=@t] .=(key.pair 'set-cookie') +=/ cookies=(list @t) %+ turn - +|= pair=[key=@t value=@t] value.pair :: parse this a bit +=/ csrf (extract-csrf cookies) +(pure:m csrf) +++ extract-csrf +|= cookies=(list @t) ^- @t +%+ roll cookies +|= [item=@t acc=@t] +?. (contains:string:sr (trip item) "ct0=") acc +=+ (split:string:sr (trip item) ";") +=+ (split:string:sr (snag 0 -) "=") +(crip (snag 1 -)) +:: ++ embed-request +:: |= id=@t +:: =/ endpoint %- crip "{embed-url:endpoints}{(trip id)}" +:: =/ method %'GET' +:: =/ headers +:: :~ +:: ['connection' 'keep-alive'] +:: ['Accept-language' 'en-US,en;q=0.9'] +:: ['Accept' '*/*'] +:: ['origin' 'https://platform.twitter.com'] +:: ['referer' 'https://platform.twitter.com/'] +:: ['DNT' '1'] +:: ['User-agent' 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.93 Safari/537.36'] +:: == +:: [method endpoint headers ~] +++ twatter-request +|= [endpoint=@t gt=@t csrf=@t] +^- request:http +=/ method %'GET' +=/ headers +:~ + ['connection' 'keep-alive'] + ['authorization' auth-key] + ['content-type' 'application/json'] + ['x-csrf-token' csrf] + ['x-guest-token' gt] + ['x-twitter-active-user' 'yes'] + ['x-twitter-client-language' 'en-us'] + ['Accept-language' 'en-US,en;q=0.9'] + ['Accept' '*/*'] + ['origin' 'https://twitter.com'] + ['referer' 'https://twitter.com/'] + ['DNT' '1'] + ['User-agent' 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.93 Safari/537.36'] + :: ['authority' 'api.twitter.com'] +== +[method endpoint headers ~] +:: ++ build-request-url +:: |= [endpoint=tape l=(list kv)] ^- @t +:: =/ vars (uri-encode:u (build-variables l)) +:: =+ (weld base-url:endpoints endpoint) +:: =+ (weld - vars) +:: (crip -) +:: ++ build-request-v2-url +:: |= [key=@t query=@t cursor=@t endpoint=tape] ^- @t +:: =/ vars (uri-encode:u (build-variables key query cursor)) +:: =/ feat (uri-encode:u features) +:: =+ (weld base-url:endpoiunts endpoint) +:: =+ (weld - vars) +:: =+ (weld - "&features={feat}") +:: (crip -) +:: ++ build-search-url +:: |= [query=@t cursor=@t] :: TODO count and replies +:: :: " include:nativeretweets", " include:replies" +:: =/ q "{<query>} include:nativeretweets exclude:replies" +:: :: =/ q "{<query>} include:nativeretweets include:replies" +:: =/ qq %- en-urlt:html (en-urlt:html q) +:: =/ c %- en-urlt:html (en-urlt:html (trip cursor)) +:: :: =/ c (en-urlt:html (trip cursor)) +:: :: =/ c (trip cursor) +:: =+ +:: "include_profile_interstitial_type=1&cursor={c}&include_blocking=1&include_blocked_by=1&include_followed_by=1&include_want_retweets=1&include_mute_edge=1&include_can_dm=1&include_can_media_tag=1&include_ext_has_nft_avatar=1&skip_status=1&cards_platform=Web-12&include_cards=1&include_ext_alt_text=true&include_quote_count=true&include_reply_count=1&tweet_mode=extended&include_entities=true&include_user_entities=true&include_ext_media_color=true&include_ext_media_availability=true&include_ext_sensitive_media_warning=true&send_error_codes=true&simple_quoted_tweet=true&tweet_search_mode=live&q={qq}&count=20&query_source=typed_query&pc=1&spelling_corrections=1&ext=mediaStats%2ChighlightedLabel%2ChasNftAvatar%2CvoiceInfo%2CsuperFollowMetadata" +:: =+ (weld search:endpoints (search-params query cursor 20 %post)) +:: =+ (weld base-url:endpoints -) +:: (crip -) :: =/ url %- crip (weld tweet-lurk (post-params id.u.command)) + :: =/ req (twatter-request url gt csrf) +++ lurk-headers +:~ + ['Connection' 'keep-alive'] + ['Content-type' 'application/json'] + ['X-twitter-active-user' 'yes'] + ['X-twitter-client-language' 'en-us'] + ::['x-guest-token' gt] + ['Accept-language' 'en-US,en;q=0.9'] + ['Accept' '*/*'] + ['origin' 'https://twitter.com'] + ['referer' 'https://twitter.com/'] + ['DNT' '1'] + ['User-agent' 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.93 Safari/537.36'] +== +++ logged-headers +|= [cookie-string=@t csrf=@t] +:: =/ cookie-string +:: 'guest_id=v1%3A169380915299959910; guest_id_ads=v1%3A169380915299959910; guest_id_marketing=v1%3A169380915299959910; kdt=VZeo5b3hVg9VsnQjJYiUsFLNvQIa1lqnxry4dcXK; auth_token=88ab0ccf40bb6be863354720d504895c7308e647; ct0=9469495056e099284acb28c9889422b02285c3883e8c9e681c287c2b1287e2e4a8d0ed3dff9a1db4ef05152d2d3f9a891031804a5fc80ef0d8b0ab251067558eec751d8241f617517a47f12a5c0b1ba8; twid=u%3D1633158398555353096; lang=en; external_referer=8e8t2xd8A2w%3D|0|F8C7rVpldvGNltGxuH%2ByoRY%2FzjrflHIZH061f%2B5OiIwP17ZTz34ZGg%3D%3D; personalization_id="v1_kxI2MM4RPdOgambYqR1tUA=="' +:: =/ csrf '9469495056e099284acb28c9889422b02285c3883e8c9e681c287c2b1287e2e4a8d0ed3dff9a1db4ef05152d2d3f9a891031804a5fc80ef0d8b0ab251067558eec751d8241f617517a47f12a5c0b1ba8' +:~ ['Cookie' cookie-string] + ['Connection' 'keep-alive'] + ['Authorization' api-key] + ['Content-type' 'application/json'] + ['X-csrf-token' csrf] + ['X-twitter-active-user' 'yes'] + ['X-twitter-auth-type' 'OAuth2Session'] + ['X-twitter-client-language' 'en-us'] + ['Accept-language' 'en-US,en;q=0.9'] + ['Accept' '*/*'] + ['origin' 'https://twitter.com'] + ['referer' 'https://twitter.com/'] + ['DNT' '1'] + ['User-agent' 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.93 Safari/537.36'] + :: ['authority' 'api.twitter.com'] +== +:: ++ build-post-body +:: |= p=post-req:tw ^- octs +:: =, enjs:format +:: %- json-to-octs:server +:: %- pairs %- limo +:: :~ [%features (pairs post-features)] +:: ['queryId' s+(crip query-id:create-tweet:urls)] +:: ['variables' (pairs (build-post-vars p))] +:: == +:: ++ build-post-vars +:: |= p=post-req:tw +:: =, enjs:format +:: =/ text=@t ?. mask.p text.p +:: :: TODO automated masking +:: 'This tweet is too spicy for Elon Musk\'s friends. To read it click on the link at my bio' +:: =/ base-vars +:: :~ ['dark_request' b+.n] +:: ['semantic_annotation_ids' a+~] +:: ['tweet_text' s+text] +:: :- 'media' %- pairs +:: :~ ['possibly_sensitive' b+.n] +:: ['media_entities' a+~] +:: == +:: == +:: ?^ quoting.p :_ base-vars :- 'attachment_url' s+u.quoting.p +:: ?^ replying.p :_ base-vars :- 'reply' %- pairs +:: :~ ['exclude_reply_user_ids' a+~] +:: ['in_reply_to_twitter_id' s+u.replying.p] +:: == +:: base-vars +:: ++ logged-req ^- request:http +:: =/ url %- crip (weld user-tweets (userid-params '1633158398555353096')) +:: [%'GET' url logged-headers ~] +:: :: {"userId":"1633158398555353096","count":20,"includePromotedContent":true,"withQuickPromoteEligibilityTweetFields":true,"withVoice":true,"withV2Timeline":true} +:: {"responsive_web_graphql_exclude_directive_enabled":true,"verified_phone_label_enabled":false,"responsive_web_home_pinned_timelines_enabled":true,"creator_subscriptions_tweet_preview_api_enabled":true,"responsive_web_graphql_timeline_navigation_enabled":true,"responsive_web_graphql_skip_user_profile_image_extensions_enabled":false,"c9s_tweet_anatomy_moderator_badge_enabled":true,"tweetypie_unmention_optimization_enabled":true,"responsive_web_edit_tweet_api_enabled":true,"graphql_is_translatable_rweb_tweet_is_translatable_enabled":true,"view_counts_everywhere_api_enabled":true,"longform_notetweets_consumption_enabled":true,"responsive_web_twitter_article_tweet_consumption_enabled":false,"tweet_awards_web_tipping_enabled":false,"freedom_of_speech_not_reach_fetch_enabled":true,"standardized_nudges_misinfo":true,"tweet_with_visibility_results_prefer_gql_limited_actions_policy_enabled":true,"longform_notetweets_rich_text_read_enabled":true,"longform_notetweets_inline_media_enabled":true,"responsive_web_media_download_video_enabled":false,"responsive_web_enhance_cards_enabled":false} + +-- diff --git a/desk/lib/wall.hoon b/desk/lib/wall.hoon new file mode 100644 index 0000000..1ecb879 --- /dev/null +++ b/desk/lib/wall.hoon @@ -0,0 +1,156 @@ +/- b=boke +/+ const=constants +|_ him=@p + +++ tags +|= in=(list @t) ^- (list @t) + %+ skim in tag-filter +++ tag-map +|= tt=tags-table:b ^- tags-table:b + =/ tag-list ~(tap by tt) + %- malt + %+ skim tag-list |= [t=@t *] (tag-filter t) + +++ post-filter +|= tags=(set @t) ^- ? + ?^ (~(int in public-tags) tags) .y + =/ l ~(tap in tags) + |- + ?~ l .y + ?. (tag-filter i.l) .n + $(l t.l) + +++ display-filter +|= t=@t ^- ? +?: .=('blog' t) .n +(tag-filter t) + +++ tag-filter +|= t=@t ^- ? + ?: .=('blog' t) .n + ?: is-admin .y + ?: is-comet (~(has in public-tags) t) + =/ group (~(get by groups) t) + ?~ group .y + (~(has in u.group) him) + + ::?: .=('vip' t) (~(has in subscribers) him) + +:: Where are tags shown +:: 1. Blog postlists +:: 2. Blog post headers +:: 3. Board index +:: 4. Thread index :: actually not yet +:: 5. Thread show, below the main post +:: 6. People can jump in +:: need a list of routes that expose tags +++ public-tags ^- (set @t) +%- silt +:~ 'wyb' + 'public' + 'ngmi' + 'blog' +== +++ boards ^- (set @t) +?: is-comet public-tags +~(key by categories:const) + +++ is-comet ?=(%pawn (clan:title him)) +++ is-admin ^- ? +?| .=(him ~docteg-mothep) + .=((^sein:title him) ~docteg-mothep) +== +++ groups ^- (map @t (set @p)) +|^ + %- malt + :~ :- 'oldtianming' tianming + :- 'ogs' ogs + == + :: + ++ tianming ^- (set @p) + %- silt + :~ ~locpyl-tidnyd + ~torwes-minput + == + ++ ogs ^- (set @p) + %- silt + :~ ~sorwet + ~finnem + ~tiller-tolbus + ~torwes-minput + ~wispem-wantex + ~sogsyt-rammer + ~sivner-figbus + ~simtex-poster + ~libhut-samwes + ~sarlev-sarsen + ~samtyd-lodhet + ~wolrex-sabdun + ~ritpub-sipsyl + ~rignet-bicteg + ~ribben-donnyl + ~ribfel-lodfep + ~radbus-tactyl + ~pathus-hiddyn + ~mopfel-winrux + ~molsur-winnel + ~moddus-sorted + ~midlyx-hatrys + ~millyt-dorsen + ~midsum-salrux + ~micdeg-rinryl + ~master-morzod + ~locpyl-tidnyd + ~hansel-ribbur + ~fonner-batmul + ~fiprys + ~finned-palmer + ~datder-sonnet + ~bidhec-lopwyc + ~mirtyl-wacdec + ~polwex + ~mogtus-sanlux + == +-- +++ subscribers ^- (set @p) +%- silt +:~ ~polwex + ~wolrex-sabdun + ~mogtus-sanlux + ~sollyd-ritnux + ~bidhec-lopwyc +== ++$ substype $?(%base %urbit %full) ++$ subscription + $: started=@da + type=substype + period=$?(%monthly %yearly) + paid=payment + == ++$ payment + $% [%btc amount=@ud address=@t] + [%eth amount=@ud address=@ux] + [%other curr=@tas amount=@ud address=@t] + == ++$ subscription-map (map @p subscription) +++ subs ^- subscription-map + %- malt + :~ :- ~mogtus-sanlux `subscription`[~2024.3.1 %base %yearly %btc 0 ''] + :- ~wolrex-sabdun `subscription`[~2024.3.4 %base %yearly %eth 14 0x0] :: TODO get the currency unit right + :- ~sollyd-ritnux `subscription`[~2024.3.13 %base %yearly %other %sol 0 ''] :: TODO get the currency unit right + :- ~bidhec-lopwyc `subscription`[~2024.3.18 %base %yearly %other %btc 74 ''] :: TODO get the currency unit right + :- ~fiprys `subscription`[~2024.3.24 %full %yearly %other %eth 6 ''] :: TODO get the currency unit right + :- ~molsur-winnel `subscription`[~2024.8.1 %full %yearly %other %eth 6 ''] :: TODO get the currency unit right + :- ~sigmes-modfyn `subscription`[~2024.1.6 %base %yearly %other %usdt 50 ''] :: TODO get the currency unit right +== +++ subscription-type + |= now=@da ^- (unit substype) + ?: is-admin `%full + =/ sub (~(get by subs) him) + ?~ sub ~ + =/ expired %+ gte now + ?: ?=(%yearly period.u.sub) + (add ~d365 started.u.sub) + (add ~d30 started.u.sub) :: TODO use yore for this + ?: expired ~ %- some type.u.sub +-- diff --git a/desk/lib/web2.hoon b/desk/lib/web2.hoon new file mode 100644 index 0000000..6200ebe --- /dev/null +++ b/desk/lib/web2.hoon @@ -0,0 +1,64 @@ +|% ++$ app-creds +$% [%twatter twatter-creds] + [%insta insta-creds] + [%openai p=api-key] + [%neets p=api-key] + [%chatgpt chatgpt-creds] +== ++$ app $?(%twatter %openai %insta %chatgpt %neets) ++$ api-key @t ++$ twatter-creds +$: auth-token=@t + ct0=@t + kdt=@t + twid=@t +== ++$ insta-creds +$: sessionid=@t + ds-user-id=@t + csrftoken=@t +== ++$ chatgpt-creds +$: cookie=@t +== ++$ poke +$% [%add name=@t =app-creds] + [%del name=@t] +== ++$ ui +$% [%scry scry] + [%fact fact] +== ++$ scry +$% [%ng ~] + [%ok p=app-creds] + [%active (set app)] +== ++$ fact +$% [%nothing ~] +== ++$ coki +$: key=@t + value=@t + max-age=@ + expiry=@da + path=@t + domain=@t + secure=_.y + http-only=_.y + samesite=$?(%strict %lax %none) + partitioned=_| +== +++ muh ^- twatter-creds +:* '245a891674d0130f09782cdc0eb3a0e995928305' + 'f2e216c7e1a7fd1e6fab09f6d25b0348c0c70c988ad715bca2307bb0995d3fa8dad5e5b6abbe4a56c13ee168135435e64baeab150e3cab2507a3ddeb28f17aacbc8222a7fed9526952629e4209ddeda2' + 'KDwilxYdu5TZHJbmXLrW1nC4k4CzeqxuKvU9Lcbb' + 'u%3D1710606417324015616' +== +++ twatter-action + $% [%timeline ~] + [%user p=@t] + == + +-- diff --git a/desk/mar/bill.hoon b/desk/mar/bill.hoon new file mode 100644 index 0000000..76cef34 --- /dev/null +++ b/desk/mar/bill.hoon @@ -0,0 +1,34 @@ +|_ bil=(list dude:gall) +++ grow + |% + ++ mime `^mime`[/text/x-bill (as-octs:mimes:html hoon)] + ++ noun bil + ++ hoon + ^- @t + |^ (crip (of-wall:format (wrap-lines (spit-duz bil)))) + :: + ++ wrap-lines + |= taz=wall + ^- wall + ?~ taz ["~"]~ + :- (weld ":~ " i.taz) + %- snoc :_ "==" + (turn t.taz |=(t=tape (weld " " t))) + :: + ++ spit-duz + |= duz=(list dude:gall) + ^- wall + (turn duz |=(=dude:gall ['%' (trip dude)])) + -- + ++ txt (to-wain:format hoon) + -- +++ grab + |% + ++ noun (list dude:gall) + ++ mime + |= [=mite len=@ud tex=@] + ~_ tex + !<((list dude:gall) (slap !>(~) (ream tex))) + -- +++ grad %noun +-- diff --git a/desk/mar/css.hoon b/desk/mar/css.hoon new file mode 100644 index 0000000..1a87081 --- /dev/null +++ b/desk/mar/css.hoon @@ -0,0 +1,25 @@ +:: +:::: /hoon/css/mar + :: +/? 310 +=, eyre +=, mimes:html +|_ mud=@t +++ grow :: convert to + |% + ++ mime [/text/css (as-octs mud)] :: convert to %mime + ++ hymn :: convert to %hymn + |^ html + ++ style ;style + ;- (trip mud) + == + ++ html ;html:(head:"{style}" body) + -- + -- +++ grab + |% :: convert from + ++ mime |=([p=mite q=octs] (@t q.q)) + ++ noun @t :: clam from %noun + -- +++ grad %mime +-- diff --git a/desk/mar/greg-event.hoon b/desk/mar/greg-event.hoon new file mode 100644 index 0000000..47b9d9d --- /dev/null +++ b/desk/mar/greg-event.hoon @@ -0,0 +1,14 @@ +/- b=boke +:: +|_ e=radio-event:b +++ grad %noun +++ grow + |% + ++ noun e + -- +:: +++ grab + |% + ++ noun radio-event:b + -- +-- diff --git a/desk/mar/hoon.hoon b/desk/mar/hoon.hoon new file mode 100644 index 0000000..428e105 --- /dev/null +++ b/desk/mar/hoon.hoon @@ -0,0 +1,36 @@ +:::: /hoon/hoon/mar + :: +/? 310 +:: +=, eyre +|_ own=@t +:: +++ grow :: convert to + |% + ++ mime `^mime`[/text/x-hoon (as-octs:mimes:html own)] :: convert to %mime + ++ hymn + ;html + ;head + ;title:"Source" + ;script@"//cdnjs.cloudflare.com/ajax/libs/codemirror/4.3.0/codemirror.js"; + ;script@"/lib/syntax/hoon.js"; + ;link(rel "stylesheet", href "//cdnjs.cloudflare.com/ajax/libs/". + "codemirror/4.3.0/codemirror.min.css"); + ;link/"/lib/syntax/codemirror.css"(rel "stylesheet"); + == + ;body + ;textarea#src:"{(trip own)}" + ;script:'CodeMirror.fromTextArea(src, {lineNumbers:true, readOnly:true})' + == + == + ++ txt + (to-wain:format own) + -- +++ grab + |% :: convert from + ++ mime |=([p=mite q=octs] q.q) + ++ noun @t :: clam from %noun + ++ txt of-wain:format + -- +++ grad %txt +-- diff --git a/desk/mar/ico.hoon b/desk/mar/ico.hoon new file mode 100644 index 0000000..e862b9b --- /dev/null +++ b/desk/mar/ico.hoon @@ -0,0 +1,12 @@ +|_ dat=@ +++ grow + |% + ++ mime [/image/x-icon (as-octs:mimes:html dat)] + -- +++ grab + |% + ++ mime |=([p=mite q=octs] q.q) + ++ noun @ + -- +++ grad %mime +-- diff --git a/desk/mar/jam.hoon b/desk/mar/jam.hoon new file mode 100644 index 0000000..cbbd524 --- /dev/null +++ b/desk/mar/jam.hoon @@ -0,0 +1,17 @@ +:: +:::: /hoon/jam/mar + :: +/? 310 +:: +=, mimes:html +|_ mud=@ +++ grow + |% + ++ mime [/application/x-urb-jam (as-octs mud)] + -- +++ grab + |% :: convert from + ++ noun @ :: clam from %noun + -- +++ grad %mime +-- diff --git a/desk/mar/js.hoon b/desk/mar/js.hoon new file mode 100644 index 0000000..fe010d9 --- /dev/null +++ b/desk/mar/js.hoon @@ -0,0 +1,25 @@ +:: +:::: /hoon/js/mar + :: +/? 310 +:: +=, eyre +|_ mud=@ +++ grow + |% + ++ mime [/application/javascript (as-octs:mimes:html (@t mud))] + ++ hymn :: convert to %hymn + |^ html + ++ script ;script + ;- (trip (@t mud)) + == + ++ html ;html:(head:"{script}" body) + -- + -- +++ grab + |% :: convert from + ++ mime |=([p=mite q=octs] (@t q.q)) + ++ noun cord :: clam from %noun + -- +++ grad %mime +-- diff --git a/desk/mar/json.hoon b/desk/mar/json.hoon new file mode 100644 index 0000000..7d6fcbf --- /dev/null +++ b/desk/mar/json.hoon @@ -0,0 +1,26 @@ +:: +:::: /hoon/json/mar + :: +/? 310 + :: +:::: compute + :: +=, eyre +=, format +=, html +|_ jon=^json +:: +++ grow :: convert to + |% + ++ mime [/application/json (as-octs:mimes -:txt)] :: convert to %mime + ++ txt [(en:json jon)]~ + -- +++ grab + |% :: convert from + ++ mime |=([p=mite q=octs] (fall (de:json (@t q.q)) *^json)) + ++ noun ^json :: clam from %noun + ++ numb numb:enjs + ++ time time:enjs + -- +++ grad %mime +-- diff --git a/desk/mar/kaji.hoon b/desk/mar/kaji.hoon new file mode 100644 index 0000000..4061b49 --- /dev/null +++ b/desk/mar/kaji.hoon @@ -0,0 +1,56 @@ +:: +:::: /hoon/kaji/mar + :: +/? 310 +/+ kaji +:::: A kaji html string mark +|_ efs=(list effect:kaji) :: this only affects +grow +++ grab |% + ++ noun @ + ++ json |= jon=^json + =/ mp ((om:dejs:format so:dejs:format) jon) + =/ action ~| 'action not set by web input' (~(got by mp) 'action') + :- action (~(del by mp) 'action') + -- +++ grow |% + ++ noun efs + :: for scries + :: ++ mime [/application/x-urb-jam (as-octs:mimes:html (crip (en-xml:html *manx)))] + :: for facts + ++ json =, enjs:format + |^ :- %a %+ turn efs |= e=effect:kaji %+ frond -.e + ?- -.e + %refresh ~ + %redi [%s url.e] + %focus [%s sel.e] + %scroll [%s sel.e] + %url [%s url.e] + %custom %- pairs + :~ [%manx %s (crip (en-xml:html manx.e))] + [%event data.e] + == + %modal %+ frond %manx [%s (crip (en-xml:html manx.e))] + %alert %- pairs + :~ [%manx %s (crip (en-xml:html manx.e))] + [%duration (numb dur.e)] + == + %swap %- pairs + :~ [%manx %s (crip (en-xml:html manx.e))] + [%sel %s sel.e] + [%inner %b inner.e] + == + %add %- pairs + :~ [%manx %s (crip (en-xml:html manx.e))] + [%container %s container.e] + [%where (en-where where.e)] + == + == + ++ en-where |= w=where.kaji %+ frond -.w + ?- -.w + %top ~ + %bottom ~ + %before [%s sibling.w] + == + -- + -- +-- diff --git a/desk/mar/kelvin.hoon b/desk/mar/kelvin.hoon new file mode 100644 index 0000000..7f1b409 --- /dev/null +++ b/desk/mar/kelvin.hoon @@ -0,0 +1,28 @@ +|_ kal=waft:clay +++ grow + |% + ++ mime `^mime`[/text/x-kelvin (as-octs:mimes:html hoon)] + ++ noun kal + ++ hoon + %+ rap 3 + %+ turn + %+ sort + ~(tap in (waft-to-wefts:clay kal)) + |= [a=weft b=weft] + ?: =(lal.a lal.b) + (gte num.a num.b) + (gte lal.a lal.b) + |= =weft + (rap 3 '[%' (scot %tas lal.weft) ' ' (scot %ud num.weft) ']\0a' ~) + :: + ++ txt (to-wain:format hoon) + -- +++ grab + |% + ++ noun waft:clay + ++ mime + |= [=mite len=@ud tex=@] + (cord-to-waft:clay tex) + -- +++ grad %noun +-- diff --git a/desk/mar/mime.hoon b/desk/mar/mime.hoon new file mode 100644 index 0000000..83b4dae --- /dev/null +++ b/desk/mar/mime.hoon @@ -0,0 +1,32 @@ +:: +:::: /hoon/mime/mar + :: +/? 310 +:: +|_ own=mime +++ grow + ^? + |% + ++ jam `@`q.q.own + -- +:: +++ grab :: convert from + ^? + |% + ++ noun mime :: clam from %noun + ++ tape + |=(a=_"" [/application/x-urb-unknown (as-octt:mimes:html a)]) + -- +++ grad + ^? + |% + ++ form %mime + ++ diff |=(mime +<) + ++ pact |=(mime +<) + ++ join |=([mime mime] `(unit mime)`~) + ++ mash + |= [[ship desk mime] [ship desk mime]] + ^- mime + ~|(%mime-mash !!) + -- +-- diff --git a/desk/mar/noun.hoon b/desk/mar/noun.hoon new file mode 100644 index 0000000..ff5443e --- /dev/null +++ b/desk/mar/noun.hoon @@ -0,0 +1,22 @@ +:: +:::: /hoon/noun/mar + :: +/? 310 +!: +:::: A minimal noun mark +|_ non=* +++ grab |% + ++ noun * + -- +++ grow |% + ++ mime [/application/x-urb-jam (as-octs:mimes:html (jam non))] + -- +++ grad + |% + ++ form %noun + ++ diff |=(* +<) + ++ pact |=(* +<) + ++ join |=([* *] *(unit *)) + ++ mash |=([[ship desk *] [ship desk *]] `*`~|(%noun-mash !!)) + -- +-- diff --git a/desk/mar/sh.hoon b/desk/mar/sh.hoon new file mode 100644 index 0000000..fe010d9 --- /dev/null +++ b/desk/mar/sh.hoon @@ -0,0 +1,25 @@ +:: +:::: /hoon/js/mar + :: +/? 310 +:: +=, eyre +|_ mud=@ +++ grow + |% + ++ mime [/application/javascript (as-octs:mimes:html (@t mud))] + ++ hymn :: convert to %hymn + |^ html + ++ script ;script + ;- (trip (@t mud)) + == + ++ html ;html:(head:"{script}" body) + -- + -- +++ grab + |% :: convert from + ++ mime |=([p=mite q=octs] (@t q.q)) + ++ noun cord :: clam from %noun + -- +++ grad %mime +-- diff --git a/desk/mar/ship.hoon b/desk/mar/ship.hoon new file mode 100644 index 0000000..176bcad --- /dev/null +++ b/desk/mar/ship.hoon @@ -0,0 +1,20 @@ +|_ s=ship +++ grad %noun +++ grow + |% + ++ noun s + ++ json s+(scot %p s) + ++ mime + ^- ^mime + [/text/x-ship (as-octt:mimes:html (scow %p s))] + + -- +++ grab + |% + ++ noun ship + ++ json (su:dejs:format ;~(pfix sig fed:ag)) + ++ mime + |= [=mite len=@ tex=@] + (slav %p (snag 0 (to-wain:format tex))) + -- +-- diff --git a/desk/mar/svg.hoon b/desk/mar/svg.hoon new file mode 100644 index 0000000..2911e49 --- /dev/null +++ b/desk/mar/svg.hoon @@ -0,0 +1,12 @@ +|_ dat=@ +++ grow + |% + ++ mime [/image/'svg+xml' (as-octs:mimes:html dat)] + -- +++ grab + |% + ++ mime |=([p=mite q=octs] q.q) + ++ noun @ + -- +++ grad %mime +-- diff --git a/desk/mar/ttf.hoon b/desk/mar/ttf.hoon new file mode 100644 index 0000000..fe010d9 --- /dev/null +++ b/desk/mar/ttf.hoon @@ -0,0 +1,25 @@ +:: +:::: /hoon/js/mar + :: +/? 310 +:: +=, eyre +|_ mud=@ +++ grow + |% + ++ mime [/application/javascript (as-octs:mimes:html (@t mud))] + ++ hymn :: convert to %hymn + |^ html + ++ script ;script + ;- (trip (@t mud)) + == + ++ html ;html:(head:"{script}" body) + -- + -- +++ grab + |% :: convert from + ++ mime |=([p=mite q=octs] (@t q.q)) + ++ noun cord :: clam from %noun + -- +++ grad %mime +-- diff --git a/desk/mar/txt.hoon b/desk/mar/txt.hoon new file mode 100644 index 0000000..982dce9 --- /dev/null +++ b/desk/mar/txt.hoon @@ -0,0 +1,274 @@ +:: +:::: /hoon/txt/mar + :: +/? 310 +:: +=, clay +=, differ +=, format +=, mimes:html +|_ txt=wain +:: +++ grab :: convert from + |% + ++ mime |=((pair mite octs) (to-wain q.q)) + ++ noun wain :: clam from %noun + -- +++ grow + => v=. + |% + ++ mime => v [/text/plain (as-octs (of-wain txt))] + -- +++ grad + |% + ++ form %txt-diff + ++ diff + |= tyt=wain + ^- (urge cord) + (lusk txt tyt (loss txt tyt)) + :: + ++ pact + |= dif=(urge cord) + ~| [%pacting dif] + ^- wain + (lurk txt dif) + :: + ++ join + |= [ali=(urge cord) bob=(urge cord)] + ^- (unit (urge cord)) + |^ + =. ali (clean ali) + =. bob (clean bob) + |- ^- (unit (urge cord)) + ?~ ali `bob + ?~ bob `ali + ?- -.i.ali + %& + ?- -.i.bob + %& + ?: =(p.i.ali p.i.bob) + %+ bind $(ali t.ali, bob t.bob) + |=(cud=(urge cord) [i.ali cud]) + ?: (gth p.i.ali p.i.bob) + %+ bind $(p.i.ali (sub p.i.ali p.i.bob), bob t.bob) + |=(cud=(urge cord) [i.bob cud]) + %+ bind $(ali t.ali, p.i.bob (sub p.i.bob p.i.ali)) + |=(cud=(urge cord) [i.ali cud]) + :: + %| + ?: =(p.i.ali (lent p.i.bob)) + %+ bind $(ali t.ali, bob t.bob) + |=(cud=(urge cord) [i.bob cud]) + ?: (gth p.i.ali (lent p.i.bob)) + %+ bind $(p.i.ali (sub p.i.ali (lent p.i.bob)), bob t.bob) + |=(cud=(urge cord) [i.bob cud]) + ~ + == + :: + %| + ?- -.i.bob + %| + ?. =(i.ali i.bob) + ~ + %+ bind $(ali t.ali, bob t.bob) + |=(cud=(urge cord) [i.ali cud]) + :: + %& + ?: =(p.i.bob (lent p.i.ali)) + %+ bind $(ali t.ali, bob t.bob) + |=(cud=(urge cord) [i.ali cud]) + ?: (gth p.i.bob (lent p.i.ali)) + %+ bind $(ali t.ali, p.i.bob (sub p.i.bob (lent p.i.ali))) + |=(cud=(urge cord) [i.ali cud]) + ~ + == + == + ++ clean :: clean + |= wig=(urge cord) + ^- (urge cord) + ?~ wig ~ + ?~ t.wig wig + ?: ?=(%& -.i.wig) + ?: ?=(%& -.i.t.wig) + $(wig [[%& (add p.i.wig p.i.t.wig)] t.t.wig]) + [i.wig $(wig t.wig)] + ?: ?=(%| -.i.t.wig) + $(wig [[%| (welp p.i.wig p.i.t.wig) (welp q.i.wig q.i.t.wig)] t.t.wig]) + [i.wig $(wig t.wig)] + -- + :: + ++ mash + |= $: [als=ship ald=desk ali=(urge cord)] + [bos=ship bod=desk bob=(urge cord)] + == + ^- (urge cord) + |^ + =. ali (clean ali) + =. bob (clean bob) + |- ^- (urge cord) + ?~ ali bob + ?~ bob ali + ?- -.i.ali + %& + ?- -.i.bob + %& + ?: =(p.i.ali p.i.bob) + [i.ali $(ali t.ali, bob t.bob)] + ?: (gth p.i.ali p.i.bob) + [i.bob $(p.i.ali (sub p.i.ali p.i.bob), bob t.bob)] + [i.ali $(ali t.ali, p.i.bob (sub p.i.bob p.i.ali))] + :: + %| + ?: =(p.i.ali (lent p.i.bob)) + [i.bob $(ali t.ali, bob t.bob)] + ?: (gth p.i.ali (lent p.i.bob)) + [i.bob $(p.i.ali (sub p.i.ali (lent p.i.bob)), bob t.bob)] + =/ [fic=(unce cord) ali=(urge cord) bob=(urge cord)] + (resolve ali bob) + [fic $(ali ali, bob bob)] + :: ~ :: here, alice is good for a while, but not for the whole + == :: length of bob's changes + :: + %| + ?- -.i.bob + %| + =/ [fic=(unce cord) ali=(urge cord) bob=(urge cord)] + (resolve ali bob) + [fic $(ali ali, bob bob)] + :: + %& + ?: =(p.i.bob (lent p.i.ali)) + [i.ali $(ali t.ali, bob t.bob)] + ?: (gth p.i.bob (lent p.i.ali)) + [i.ali $(ali t.ali, p.i.bob (sub p.i.bob (lent p.i.ali)))] + =/ [fic=(unce cord) ali=(urge cord) bob=(urge cord)] + (resolve ali bob) + [fic $(ali ali, bob bob)] + == + == + :: + ++ annotate :: annotate conflict + |= $: ali=(list @t) + bob=(list @t) + bas=(list @t) + == + ^- (list @t) + %- zing + ^- (list (list @t)) + %- flop + ^- (list (list @t)) + :- :_ ~ + %^ cat 3 '<<<<<<<<<<<<' + %^ cat 3 ' ' + %^ cat 3 `@t`(scot %p bos) + %^ cat 3 '/' + bod + + :- bob + :- ~['------------'] + :- bas + :- ~['++++++++++++'] + :- ali + :- :_ ~ + %^ cat 3 '>>>>>>>>>>>>' + %^ cat 3 ' ' + %^ cat 3 `@t`(scot %p als) + %^ cat 3 '/' + ald + ~ + :: + ++ clean :: clean + |= wig=(urge cord) + ^- (urge cord) + ?~ wig ~ + ?~ t.wig wig + ?: ?=(%& -.i.wig) + ?: ?=(%& -.i.t.wig) + $(wig [[%& (add p.i.wig p.i.t.wig)] t.t.wig]) + [i.wig $(wig t.wig)] + ?: ?=(%| -.i.t.wig) + $(wig [[%| (welp p.i.wig p.i.t.wig) (welp q.i.wig q.i.t.wig)] t.t.wig]) + [i.wig $(wig t.wig)] + :: + ++ resolve + |= [ali=(urge cord) bob=(urge cord)] + ^- [fic=[%| p=(list cord) q=(list cord)] ali=(urge cord) bob=(urge cord)] + =- [[%| bac (annotate alc boc bac)] ali bob] + |- ^- $: $: bac=(list cord) + alc=(list cord) + boc=(list cord) + == + ali=(urge cord) + bob=(urge cord) + == + ?~ ali [[~ ~ ~] ali bob] + ?~ bob [[~ ~ ~] ali bob] + ?- -.i.ali + %& + ?- -.i.bob + %& [[~ ~ ~] ali bob] :: no conflict + %| + =+ lob=(lent p.i.bob) + ?: =(lob p.i.ali) + [[p.i.bob p.i.bob q.i.bob] t.ali t.bob] + ?: (lth lob p.i.ali) + [[p.i.bob p.i.bob q.i.bob] [[%& (sub p.i.ali lob)] t.ali] t.bob] + =+ wat=(scag (sub lob p.i.ali) p.i.bob) + =+ ^= res + %= $ + ali t.ali + bob [[%| (scag (sub lob p.i.ali) p.i.bob) ~] t.bob] + == + :* :* (welp bac.res wat) + (welp alc.res wat) + (welp boc.res q.i.bob) + == + ali.res + bob.res + == + == + :: + %| + ?- -.i.bob + %& + =+ loa=(lent p.i.ali) + ?: =(loa p.i.bob) + [[p.i.ali q.i.ali p.i.ali] t.ali t.bob] + ?: (lth loa p.i.bob) + [[p.i.ali q.i.ali p.i.ali] t.ali [[%& (sub p.i.bob loa)] t.bob]] + =+ wat=(slag (sub loa p.i.bob) p.i.ali) + =+ ^= res + %= $ + ali [[%| (scag (sub loa p.i.bob) p.i.ali) ~] t.ali] + bob t.bob + == + :* :* (welp bac.res wat) + (welp alc.res q.i.ali) + (welp boc.res wat) + == + ali.res + bob.res + == + :: + %| + =+ loa=(lent p.i.ali) + =+ lob=(lent p.i.bob) + ?: =(loa lob) + [[p.i.ali q.i.ali q.i.bob] t.ali t.bob] + =+ ^= res + ?: (gth loa lob) + $(ali [[%| (scag (sub loa lob) p.i.ali) ~] t.ali], bob t.bob) + ~& [%scagging loa=loa pibob=p.i.bob slag=(scag loa p.i.bob)] + $(ali t.ali, bob [[%| (scag (sub lob loa) p.i.bob) ~] t.bob]) + :* :* (welp bac.res ?:((gth loa lob) p.i.bob p.i.ali)) + (welp alc.res q.i.ali) + (welp boc.res q.i.bob) + == + ali.res + bob.res + == + == + == + -- + -- +-- diff --git a/desk/mar/udon.hoon b/desk/mar/udon.hoon new file mode 100644 index 0000000..61782c4 --- /dev/null +++ b/desk/mar/udon.hoon @@ -0,0 +1,29 @@ +:: +:::: /hoon/udon/mar + :: +/+ cram +:: +|_ mud=@t +++ grow + |% + ++ mime [/text/x-unmark (as-octs:mimes:html mud)] + ++ txt + (to-wain:format mud) + ++ front :: XX performance, types + ^- (map term knot) + =/ reamed (ream mud) + ~& >> reamed=reamed + %- ~(run by inf:(static:cram reamed)) + |= a=dime ^- cord + ?+ (end 3 p.a) (scot a) + %t q.a + == + -- +++ grab + |% + ++ mime |=((pair mite octs) q.q) + ++ noun @t + ++ txt of-wain:format + -- +++ grad %txt +-- diff --git a/desk/sur/boke.hoon b/desk/sur/boke.hoon new file mode 100644 index 0000000..6af312d --- /dev/null +++ b/desk/sur/boke.hoon @@ -0,0 +1,113 @@ +/- tp=trill-post, tlonc=tlon-channels, polls +|% ++$ action +$% [%add p=post:tp] + [%del p=id:tp] + :: approve comments? + [%add-board name=@t] + [%del-board name=@t] +== ++$ kaji-req +$% [%board-redi =post:tp] + [%blog-redi =post:tp] + [%redi url=@t] + [%tv-chat p=@t q=post:tp] + [%radio-chat p=@p q=*] + [%chat-msg p=flag:tlonc q=memo:tlonc] +== ++$ state state-0 ++$ tags-table (map @t pidmap) ++$ pathmap (map path pid:tp) ++$ threadsf ((mop pid:tp thread:tp) ggth:tp) ++$ pidmap ((mop pid:tp pid:tp) ggth:tp) ++$ external ((mop esrc epost) extc) +++ erm ((on id:tp post:tp) gth) ++$ esrc +$: time=@da + id=@t :: whatever +== ++$ epost + $: =pid:tp + url=@t + service=@t + json=@t +== +++ extc |= [a=esrc b=esrc] (gth time.a time.b) +:: in active threads the pid is the pid of the last reply ++$ state-0 +$: %0 + :: all data here. flat structure. fk'it + feed=gfeed:tp + threads=threadsf + active-threads=pidmap :: same as above but ordered by last reply + paths=pathmap + tags=tags-table + tv=tv-table + polls=polls-table + notifications=hark-table + external=(map @t external) :: twitter etc, tagged or named +== ++$ tv-table + $: urbit=(map @p urbit-radio) + here=(map @t bstv) + == ++$ hark-table (map @p t-hark) ++$ t-hark + $: last-online=@da + tracking=(map pid:tp post:tp) + == ++$ polls-table (map pid:tp poll:polls) ++$ bstv + $: name=@t + owner=@p + current=[playing=@t started=@da] :: should point to the schedule + schedule=(map @da tv-station) + == ++$ tv-station + $: description=cord + src=cord :: source file + started=@da + ended=(unit @da) + viewers=(map @p (list presence)) + chat=(list post:tp) + perms=* + == ++$ presence [came=@da left=@da] ++$ twr $%([%our name=@t owner=@p tv=tv-station] [%urb name=@t owner=@p p=urbit-radio]) ++$ urbit-radio + $: + description=cord + location=ship + time=@da + viewers=@ud + == ++$ radio-event + $% [%put p=urbit-radio] + [%remove =ship] + [%request ~] + [%response minitowers=(map ship urbit-radio)] + == + ++$ admin +$: banned=(set address:eyre) + settings=(map @p setting) +== ++$ setting +$: thing=* +== + +:: fetching stuff, shouldn't be here really but whatever ++$ section $?(%blog %comments %chat %threads %replies) ++$ chat-page [p=scan:tlonc older=(unit @da) newer=(unit @da) count=@ud] ++$ search-res $%([%chat chat-page] [%trill search-page]) ++$ search-page + $: res=(list post-snip) + newer=cursor:tp + older=cursor:tp + == ++$ post-snip + $: fn=full-node:tp + snip=@t + == + +-- diff --git a/desk/sur/contact.hoon b/desk/sur/contact.hoon new file mode 100644 index 0000000..973f954 --- /dev/null +++ b/desk/sur/contact.hoon @@ -0,0 +1,51 @@ +/+ sr=sortug +|% +++ get-contacts +|= =bowl:gall +=/ io ~(. io:sr bowl) +(scry:io %whom /1/contacts/mars whoms) +:: fuck it ++$ res +$: p=@p + contact=(unit contact) + whom=(unit whom) +== +:: %contacts ++$ foreign [for=$@(~ prof) sag=*] ++$ prof [wen=@da con=$@(~ contact)] ++$ rolodex (map ship foreign) ++$ contact +$: nickname=@t + bio=@t + status=@t + color=@ux + avatar=(unit @t) + cover=(unit @t) + groups=(set (pair ship term)) +== +:: %whom ++$ whoms (map (each @p @t) whom) ++$ whom +$: info=(map @tas info-field) + profile=(unit profile) +== ++$ access-level ?(%public %mutual) +:: ++$ profile + $: info=(map @tas [value=info-field access=access-level]) + fields=(map @tas field-def) + == ++$ field-def [name=@t type=field-type-tag] +:: ++$ field-type-tag ?(%text %date %look %tint %coll) +:: ++$ info-field + $% [%text @t] + [%date @da] + [%look @t] :: link to image + [%tint @ux] :: color (0-255) + [%coll coll] :: collection of items on Urbit (groups, apps, wikis, etc) + == +:: ++$ coll (set [=ship slug=@ta]) +-- diff --git a/desk/sur/polls.hoon b/desk/sur/polls.hoon new file mode 100644 index 0000000..93085c2 --- /dev/null +++ b/desk/sur/polls.hoon @@ -0,0 +1,57 @@ +/- gate=trill-gate +|% ++$ pid [ship=@p id=@da] ++$ id @da ++$ expiry @da ++$ text @t ++$ poll +$: author=ship + =time + =expiry + =text + options=(list @t) + =votes + read=lock:gate + write=lock:gate +== ++$ votes +$% excl + incl +== ++$ excl [%exc p=(map ship @ud)] ++$ incl [%inc p=(map @ud (map @p (set @ud)))] +:: some helpers + +++ new-poll +|= [=pid =text =expiry options=(list @t) inc=?] +=/ votes ?. inc *excl *incl +^- poll +:* author=-.pid + time=+.pid + expiry + text + options + votes + read=*lock:gate + write=*lock:gate +== +:: comms ++$ ui-action +$% [%propose text=@t =expiry options=(list @t) exc=?] + [%cancel =id] + [%change-expiry =id =expiry] + [%vote =pid option=@ comment=@t] + [%cancel-vote =pid] +== ++$ update +$% [%new-poll =poll] + [%ded-poll p=pid] + [%old-poll p=poll q=upd] +== ++$ upd +$? [%new-vote p=@ud] + [%expiry-changed q=expiry] + [%vote-changed p=@p old=@ new=@] + [%vote-canceled p=@p q=@] +== +-- diff --git a/desk/sur/spider.hoon b/desk/sur/spider.hoon new file mode 100644 index 0000000..7c21268 --- /dev/null +++ b/desk/sur/spider.hoon @@ -0,0 +1,27 @@ +/+ libstrand=strand +=, strand=strand:libstrand +|% ++$ thread $-(vase shed:khan) ++$ input [=tid =cage] ++$ tid tid:strand ++$ bowl bowl:strand ++$ http-error + $? %bad-request :: 400 + %forbidden :: 403 + %nonexistent :: 404 + %offline :: 504 + == ++$ start-args + $: parent=(unit tid) + use=(unit tid) + =beak + file=term + =vase + == ++$ inline-args + $: parent=(unit tid) + use=(unit tid) + =beak + =shed:khan + == +-- diff --git a/desk/sur/tlon-chat.hoon b/desk/sur/tlon-chat.hoon new file mode 100644 index 0000000..dd82833 --- /dev/null +++ b/desk/sur/tlon-chat.hoon @@ -0,0 +1,1268 @@ +|% +++ meta +|% ++$ data + $: title=cord + description=cord + image=cord + cover=cord + == ++$ diff + $% [%title =cord] + [%description =cord] + [%image =cord] + [%cover =cord] + == +-- +++ d +|% +:: $flag: identifier for a diary channel ++$ flag (pair ship term) +:: $feel: either an emoji identifier like :diff or a URL for custom ++$ feel @ta +:: $view: the persisted display format for a diary ++$ view ?(%grid %list) +:: $sort: the persisted sort type for a diary ++$ sort ?(%alpha %time) +:: $shelf: my ship's diaries ++$ shelf (map flag diary) +:: $said: used for references ++$ said (pair flag outline) +:: $plan: index into diary state +:: p: Note being referred to +:: q: Quip being referred to, if any +:: ++$ plan + (pair time (unit time)) +:: +:: $diary: written longform communication +:: +:: net: an indicator of whether I'm a host or subscriber +:: log: the history of all modifications +:: perm: holds the diary's permissions +:: view: what format to display +:: sort: how to order posts +:: notes: the actual contents of the diary +:: remark: what is the last thing we've read +:: banter: comments organized by post +:: ++$ diary + $: =net + =log + =perm + =view + =sort + =notes + =remark + == +:: +:: $notes: a set of time ordered diary posts +:: +++ notes + =< rock + |% + +$ rock + ((mop time note) lte) + ++ on + ((^on time note) lte) + +$ diff + (pair time delta) + +$ delta + $% [%add p=essay] + [%edit p=essay] + [%del ~] + [%quips p=diff:quips] + [%add-feel p=ship q=feel] + [%del-feel p=ship] + == + -- +:: +:: $quips: a set of time ordered note comments +:: +++ quips + =< rock + |% + +$ rock + ((mop time quip) lte) + ++ on + ((^on time quip) lte) + +$ diff + (pair time delta) + +$ delta + $% [%add p=memo] + [%del ~] + [%add-feel p=ship q=feel] + [%del-feel p=ship] + == + -- +:: +:: $outline: abridged $note +:: .quips: number of comments +:: ++$ outline + [quips=@ud quippers=(set ship) essay] +:: +++ outlines + =< outlines + |% + +$ outlines ((mop time outline) lte) + ++ on ((^on time outline) lte) + -- +:: +:: $note: a diary post +:: ++$ note [seal essay] +:: $quip: a post comment +:: ++$ quip [cork memo] +:: +:: $seal: host-side data for a note +:: ++$ seal + $: =time + =quips + feels=(map ship feel) + == +:: +:: $cork: host-side data for a quip +:: ++$ cork + $: =time + feels=(map ship feel) + == +:: $essay: the post data itself +:: +:: title: the name of the post +:: image: a visual displayed as a header +:: content: the body of the post +:: author: the ship that wrote the post +:: sent: the client-side time the post was made +:: ++$ essay + $: title=@t + image=@t + content=(list verse) + author=ship + sent=time + == ++$ story (pair (list block) (list inline)) +:: $memo: the comment data itself +:: +:: content: the body of the comment +:: author: the ship that wrote the comment +:: sent: the client-side time the comment was made +:: ++$ memo + $: content=story + author=ship + sent=time + == +:: $verse: a chunk of post content +:: +:: blocks stand on their own. inlines come in groups and get wrapped +:: into a paragraph +:: ++$ verse + $% [%block p=block] + [%inline p=(list inline)] + == +:: $listing: recursive type for infinitely nested <ul> or <ol> ++$ listing + $% [%list p=?(%ordered %unordered) q=(list listing) r=(list inline)] + [%item p=(list inline)] + == +:: $block: post content that sits outside of the normal text +:: +:: %image: a visual, we record dimensions for better rendering +:: %cite: an Urbit reference +:: %header: a traditional HTML heading, h1-h6 +:: %listing: a traditional HTML list, ul and ol +:: ++$ block + $% [%image src=cord height=@ud width=@ud alt=cord] + [%cite =cite:c] + [%header p=?(%h1 %h2 %h3 %h4 %h5 %h6) q=(list inline)] + [%listing p=listing] + [%rule ~] + == +:: $inline: post content that flows within a paragraph +:: +:: @t: plain text +:: %italics: italic text +:: %bold: bold text +:: %strike: strikethrough text +:: %inline-code: code formatting for small snippets +:: %blockquote: blockquote surrounded content +:: %block: link/reference to blocks +:: %code: code formatting for large snippets +:: %tag: tag gets special signifier +:: %link: link to a URL with a face +:: %break: line break +:: ++$ inline + $@ @t + $% [%italics p=(list inline)] + [%bold p=(list inline)] + [%strike p=(list inline)] + [%blockquote p=(list inline)] + [%inline-code p=cord] + [%ship p=ship] + [%block p=@ud q=cord] + [%code p=cord] + [%tag p=cord] + [%link p=cord q=cord] + [%break ~] + == +:: $log: a time ordered history of modifications to a diary +:: ++$ log + ((mop time diff) lte) +++ log-on + ((on time diff) lte) +:: +:: $action: the complete set of data required to modify a diary +:: ++$ action + (pair flag:g update) +:: +:: $update: a representation in time of a modification to a diary +:: ++$ update + (pair time diff) +:: +:: $diff: the full suite of modifications that can be made to a diary +:: ++$ diff + $% [%notes p=diff:notes] + :: + [%add-sects p=(set sect:g)] + [%del-sects p=(set sect:g)] + :: + [%create p=perm q=notes] + [%view p=view] + [%sort p=sort] + :: + == +:: +:: $net: an indicator of whether I'm a host or subscriber +:: +:: %pub: am publisher/host with fresh log +:: %sub: subscribed to the ship at saga +:: ++$ net + $% [%sub p=ship load=_| =saga:e] + [%pub ~] :: TODO: permissions? + == +:: +:: $briefs: a map of diary unread information +:: +:: brief: the last time a diary was read, how many posts since, +:: and the id of the last read note +:: +++ briefs + =< briefs + |% + +$ briefs + (map flag brief) + +$ brief + [last=time count=@ud read-id=(unit time)] + +$ update + (pair flag brief) + -- +:: $remark: a marker representing the last note I've read +:: ++$ remark + [last-read=time watching=_| ~] +:: ++$ remark-action + (pair flag remark-diff) +:: ++$ remark-diff + $% [%read ~] + [%read-at p=time] + [?(%watch %unwatch) ~] + == +:: +:: $perm: represents the permissions for a diary channel and gives a +:: pointer back to the group it belongs to. +:: ++$ perm + $: writers=(set sect:g) + group=flag:g + == +:: $leave: a flag to pass for a channel leave +:: ++$ leave flag:g +:: +:: $create: represents a request to create a channel +:: +:: The name will be used as part of the flag which represents the +:: channel. $create is consumed by the diary agent first and then +:: passed to the groups agent to register the channel with the group. +:: +:: Write permission is stored with the specific agent in the channel, +:: read permission is stored with the group's data. +:: ++$ create + $: group=flag:g + name=term + title=cord + description=cord + readers=(set sect:g) + writers=(set sect:g) + == +-- +++ c +|% ++$ writ [seal memo] +:: $id: an identifier for chat messages ++$ id (pair ship time) +:: $feel: either an emoji identifier like :wave: or a URL for custom ++$ feel @ta ++$ said (pair flag writ) +:: +:: $seal: the id of a chat and its meta-responses +:: +:: id: the id of the message +:: feels: reactions to a message +:: replied: set of replies to a message +:: ++$ seal + $: =id + feels=(map ship feel) + replied=(set id) + == +:: +:: $whom: a polymorphic identifier for chats +:: ++$ whom + $% [%flag p=flag] + [%ship p=ship] + [%club p=id:club] + == +:: +:: $briefs: a map of chat/club/dm unread information +:: +:: brief: the last time a message was read, how many messages since, +:: and the id of the last read message +:: +++ briefs + =< briefs + |% + +$ briefs + (map whom brief) + +$ brief + [last=time count=@ud read-id=(unit id)] + +$ update + (pair whom brief) + -- +:: ++$ remark-action + (pair whom remark-diff) +:: ++$ remark-diff + $% [%read ~] + [%read-at p=time] + [?(%watch %unwatch) ~] + == +:: +:: $flag: an identifier for a $chat channel +:: ++$ flag (pair ship term) +:: +:: $diff: represents an update to state +:: +:: %writs: a chat message update +:: %add-sects: add sects to writer permissions +:: %del-sects: delete sects from writers +:: %create: create a new chat +:: ++$ diff + $% [%writs p=diff:writs] + :: + [%add-sects p=(set sect:g)] + [%del-sects p=(set sect:g)] + :: + [%create p=perm q=pact] + == +:: $index: a map of chat message id to server received message time +:: ++$ index (map id time) +:: +:: $pact: a double indexed map of chat messages, id -> time -> message +:: ++$ pact + $: wit=writs + dex=index + == +:: +:: $club: a direct line of communication between multiple parties +:: +:: uses gossip to ensure all parties keep in sync +:: +++ club + =< club + |% + :: $id: an identification signifier for a $club + :: + +$ id @uvH + :: $net: status of club + :: + +$ net ?(%archive %invited %done) + +$ club [=pact crew] + :: + :: $crew: a container for the metadata for the club + :: + :: team: members that have accepted an invite + :: hive: pending members that have been invited + :: met: metadata representing club + :: net: status + :: pin: should the $club be pinned to the top + :: + +$ crew + $: team=(set ship) + hive=(set ship) + met=data:meta + =net + pin=_| + == + :: $rsvp: a $club invitation response + :: + +$ rsvp [=id =ship ok=?] + :: $create: a request to create a $club with a starting set of ships + :: + +$ create + [=id hive=(set ship)] + :: $invite: the contents to send in an invitation to someone + :: + +$ invite [=id team=(set ship) hive=(set ship) met=data:meta] + :: $echo: number of times diff has been echoed + :: + +$ echo @ud + +$ diff (pair echo delta) + :: + +$ delta + $% [%writ =diff:writs] + [%meta meta=data:meta] + [%team =ship ok=?] + [%hive by=ship for=ship add=?] + [%init team=(set ship) hive=(set ship) met=data:meta] + == + :: + +$ action (pair id diff) + -- +:: +:: $writs: a set of time ordered chat messages +:: +++ writs + =< writs + |% + +$ writs + ((mop time writ) lte) + ++ on + ((^on time writ) lte) + +$ diff + (pair id delta) + +$ delta + $% [%add p=memo] + [%del ~] + [%add-feel p=ship q=feel] + [%del-feel p=ship] + == + -- +:: +:: $dm: a direct line of communication between two ships +:: +:: net: status of dm +:: id: a message identifier +:: action: an update to the dm +:: rsvp: a response to a dm invitation +:: +++ dm + =< dm + |% + +$ dm + $: =pact + =remark + =net + pin=_| + == + +$ net ?(%inviting %invited %archive %done) + +$ id (pair ship time) + +$ diff diff:writs + +$ action (pair ship diff) + +$ rsvp [=ship ok=?] + -- +:: +:: $log: a time ordered map of all modifications to groups +:: ++$ log + ((mop time diff) lte) +++ log-on + ((on time diff) lte) ++$ remark + [last-read=time watching=_| ~] +:: +:: $chat: a group based channel for communicating +:: ++$ chat + [=net =remark =log =perm =pact] +:: +:: $notice: the contents of an automated message +:: +:: pfix: text preceding ship name +:: sfix: text following ship name +:: ++$ notice [pfix=@t sfix=@t] +:: +:: $content: the contents of a message whether handwritten or automated +:: ++$ content + $% [%story p=story] + [%notice p=notice] + == +:: +:: $draft: the contents of an unsent message at a particular $whom +:: ++$ draft + (pair whom story) +:: +:: $story: handwritten contents of a message +:: +:: blocks precede inline content +:: ++$ story + (pair (list block) (list inline)) +:: +:: $block: content which stands on it's own outside of inline content +:: ++$ block + $% [%image src=cord height=@ud width=@ud alt=cord] + [%cite =cite] + == +:: +:: $inline: a representation of text with or without formatting +:: +:: @t: plain text +:: %italics: italic text +:: %bold: bold text +:: %strike: strikethrough text +:: %blockquote: blockquote surrounded content +:: %inline-code: code formatting for small snippets +:: %ship: a mention of a ship +:: %block: link/reference to blocks +:: %code: code formatting for large snippets +:: %tag: tag gets special signifier +:: %link: link to a URL with a face +:: %break: line break +:: ++$ inline + $@ @t + $% [%italics p=(list inline)] + [%bold p=(list inline)] + [%strike p=(list inline)] + [%blockquote p=(list inline)] + [%inline-code p=cord] + [%ship p=ship] + [%block p=@ud q=cord] + [%code p=cord] + [%tag p=cord] + [%link p=cord q=cord] + [%break ~] + == +:: +:: $memo: a chat message with metadata +:: +:: replying: what message we're replying to +:: author: writer of the message +:: sent: time (from sender) when the message was sent +:: content: body of the message +:: ++$ memo + $: replying=(unit id) + author=ship + sent=time + =content + == +:: +:: $net: an indicator of whether I'm a host or subscriber +:: +:: %load: iniating chat join +:: %pub: am publisher/host with fresh log +:: %sub: subscribed to the ship +:: ++$ net + $% [%sub host=ship load=_| =saga:e] + [%pub ~] + == +:: +:: $action: the complete set of data required to edit a chat +:: ++$ action + (pair flag update) +:: +:: $update: a representation in time of a modification of a chat +:: ++$ update + (pair time diff) +:: +:: $logs: a time ordered map of all modifications to groups +:: ++$ logs + ((mop time diff) lte) +:: +:: $perm: represents the permissions for a channel and gives a pointer +:: back to the group it belongs to. +:: ++$ perm + $: writers=(set sect:g) + group=flag:g + == +:: +:: $leave: a flag to pass for a channel leave +:: ++$ leave flag:g +:: +:: $create: represents a request to create a channel +:: +:: The name will be used as part of the flag which represents the +:: channel. $create is consumed by the chat agent first +:: and then passed to the groups agent to register the channel with +:: the group. +:: +:: Write permission is stored with the specific agent in the channel, +:: read permission is stored with the group's data. +:: ++$ create + $: group=flag:g + name=term + title=cord + description=cord + readers=(set sect:g) + writers=(set sect:g) + == +-- +++ cite +=< cite +|% +++ purse + |= =(pole knot) + ^- (unit cite) + ?. =(~.1 -.pole) ~ + =. pole +.pole + ?+ pole ~ + [%chan agent=@ ship=@ name=@ rest=*] + =/ ship (slaw %p ship.pole) + ?~ ship ~ + `[%chan [agent.pole u.ship name.pole] rest.pole] + :: + [%desk ship=@ name=@ rest=*] + =/ ship (slaw %p ship.pole) + ?~ ship ~ + `[%desk [u.ship name.pole] rest.pole] + :: + [%group ship=@ name=@ ~] + =/ ship (slaw %p ship.pole) + ?~ ship ~ + `[%group u.ship name.pole] + == +++ parse + |= =path + ^- cite + (need (purse path)) +:: +++ print + |= c=cite + |^ ^- path + :- (scot %ud 1) + ?- -.c + %chan chan/(welp (nest nest.c) wer.c) + %desk desk/(welp (flag flag.c) wer.c) + %group group/(flag flag.c) + %bait bait/:(welp (flag grp.c) (flag gra.c) wer.c) + == + ++ flag + |= f=flag:g + ~[(scot %p p.f) q.f] + ++ nest + |= n=nest:g + [p.n (flag q.n)] + -- +:: ++$ cite + $% [%chan =nest:g wer=path] + [%group =flag:g] + [%desk =flag:g wer=path] + [%bait grp=flag:g gra=flag:g wer=path] + :: scry into groups when you receive a bait for a chat that doesn't exist yet + :: work out what app + == +-- +++ e +|% +:: $saga: version synchronisation state +:: %dex: publisher is ahead +:: %lev: we are ahead +:: %chi: full sync +:: ++$ saga + $% [%dex ver=@ud] + [%lev ~] + [%chi ~] + == + ++$ epic @ud +:: +-- +++ h +|% +:: $flag: identifier for a heap channel ++$ flag (pair ship term) +:: $feel: either an emoji identifier like :wave or a URL for custom ++$ feel @ta +:: $view: the persisted display format for a heap ++$ view ?(%grid %list) +:: $stash: heaps I've joined ++$ stash (map flag heap) +:: $said: used for curio references ++$ said (pair flag curio) +:: +:: $heap: a collection of curiosities +:: +:: net: an indicator of whether I'm a host or subscriber +:: log: the history of all modifications +:: perm: holds the heap's permissions +:: view: what format to display +:: curios: the actual contents of the heap +:: remark: what is the last thing we've seen/read +:: ++$ heap + $: =net + =log + =perm + =view + =curios + =remark + == +:: $curios: a set of time ordered heap items +:: +++ curios + =< curios + |% + +$ curios + ((mop time curio) lte) + ++ on + ((^on time curio) lte) + +$ diff + (pair time delta) + +$ delta + $% [%add p=heart] + [%edit p=heart] + [%del ~] + [%add-feel p=ship q=feel] + [%del-feel p=ship] + == + -- +:: $curio: an item in the collection or a comment about an item +:: ++$ curio [seal heart] +:: +:: $seal: the id of a curio and its meta-responses +:: +:: time: the id of the curio +:: feels: reactions to a curio +:: replied: set of replies to a curio +:: ++$ seal + $: =time + feels=(map ship feel) + replied=(set time) + == +:: $heart: the curio data itself +:: +:: title: name of the curio +:: content: body of the curio +:: author: writer of the curio +:: sent: the client-side time the curio was made +:: replying: what curio we're commenting on +:: ++$ heart + $: title=(unit @t) + =content + author=ship + sent=time + replying=(unit time) + == +:: $content: curio content +:: ++$ content + (pair (list block) (list inline)) +:: $block: block-level curio content ++$ block + $% [%image src=cord height=@ud width=@ud alt=cord] + [%cite =cite] + == +:: $inline: curio content that flows within a paragraph +:: +:: @t: plain text +:: %italics: italic text +:: %bold: bold text +:: %strike: strikethrough text +:: %inline-code: code formatting for small snippets +:: %blockquote: blockquote surrounded content +:: %code: code formatting for large snippets +:: %tag: tag gets special signifier +:: %link: link to a URL with a face +:: %break: line break +:: ++$ inline + $@ @t + $% [%italics p=(list inline)] + [%bold p=(list inline)] + [%strike p=(list inline)] + [%blockquote p=(list inline)] + [%inline-code p=cord] + [%ship p=ship] + [%code p=cord] + [%block p=@ud q=cord] + [%tag p=cord] + [%link p=cord q=cord] + [%break ~] + == +:: $log: a time ordered history of modifications to a heap +:: ++$ log + ((mop time diff) lte) +++ log-on + ((on time diff) lte) +:: +:: $action: the complete set of data required to modify a heap +:: ++$ action + (pair flag:g update) +:: +:: $update: a representation in time of a modification to a heap +:: ++$ update + (pair time diff) +:: +:: $diff: the full suite of modifications that can be made to a heap +:: ++$ diff + $% [%curios p=diff:curios] + :: + [%add-sects p=(set sect:g)] + [%del-sects p=(set sect:g)] + :: + [%create p=perm q=curios] + [%view p=view] + == +:: $net: an indicator of whether I'm a host or subscriber +:: +:: %pub: am publisher/host with fresh log +:: %sub: subscribed to the ship +:: ++$ net + $% [%sub p=ship load=_| =saga:e] + [%pub ~] + == +:: +:: $briefs: a map of heap unread information +:: +:: brief: the last time a heap was read, how many items since, +:: and the id of the last seen curio +:: +++ briefs + =< briefs + |% + +$ briefs + (map flag brief) + +$ brief + [last=time count=@ud read-id=(unit time)] + +$ update + (pair flag brief) + -- +:: $remark: a marker representing the last note I've read +:: ++$ remark + [last-read=time watching=_| ~] +:: ++$ remark-action + (pair flag remark-diff) +:: ++$ remark-diff + $% [%read ~] + [%read-at p=time] + [?(%watch %unwatch) ~] + == +:: $perm: represents the permissions for a heap channel and gives a +:: pointer back to the group it belongs to. +:: ++$ perm + $: writers=(set sect:g) + group=flag:g + == +:: $leave: a flag to pass for a channel leave +:: ++$ leave flag:g +:: +:: $create: represents a request to create a channel +:: +:: The name will be used as part of the flag which represents the +:: channel. $create is consumed by the heap agent first and then +:: passed to the groups agent to register the channel with the group. +:: +:: Write permission is stored with the specific agent in the channel, +:: read permission is stored with the group's data. +:: ++$ create + $: group=flag:g :: TODO: unmanaged-style group chats + name=term + title=cord + description=cord + readers=(set sect:g) + writers=(set sect:g) + == +-- +++ g +|% +:: $flag: ID for a group +:: ++$ flag (pair ship term) +:: +:: $nest: ID for a channel, {app}/{ship}/{name} +:: ++$ nest (pair dude:gall flag) +:: +:: $sect: ID for cabal, similar to a role +:: ++$ sect term +:: +:: $zone: channel grouping +:: +:: includes its own metadata for display and keeps the order of +:: channels within. +:: +:: zone: the term that represents the ID of a zone +:: realm: the metadata representing the zone and the order of channels +:: delta: the set of actions that can be taken on a zone +:: %add: create a zone +:: %del: delete the zone +:: %edit: modify the zone metadata +:: %mov: reorders the zone in the group +:: %mov-nest: reorders a channel within the zone +:: +++ zone + =< zone + |% + +$ zone @tas + +$ realm + $: met=data:meta + ord=(list nest) + == + +$ diff (pair zone delta) + +$ delta + $% [%add meta=data:meta] + [%del ~] + [%edit meta=data:meta] + [%mov idx=@ud] + [%mov-nest =nest idx=@ud] + == + -- +:: +:: $fleet: group members and their associated metadata +:: +:: vessel: a user's set of sects or roles and the time that they joined +:: @da default represents an admin added member that has yet to join +:: +++ fleet + =< fleet + |% + +$ fleet (map ship vessel) + +$ vessel + $: sects=(set sect) + joined=time + == + +$ diff + $% [%add ~] + [%del ~] + [%add-sects sects=(set sect)] + [%del-sects sects=(set sect)] + == + -- +:: +:: $channel: a medium for interaction +:: +++ channel + =< channel + |% + +$ preview + $: =nest + meta=data:meta + group=^preview + == + :: + +$ channels (map nest channel) + :: + :: $channel: a collection of metadata about a specific agent integration + :: + :: meta: title, description, image, cover + :: added: when the channel was created + :: zone: what zone or section to bucket in + :: join: should the channel be joined by new members + :: readers: what sects can see the channel, empty means anyone + :: + +$ channel + $: meta=data:meta + added=time + =zone + join=? + readers=(set sect) + == + :: + :: $diff: represents the set of actions you can take on a channel + :: + :: add: create a channel, should be called from agent + :: del: delete a channel + :: add-sects: add sects to readers + :: del-sects: delete sects from readers + :: zone: change the zone of the channel + :: join: toggle default join + :: + +$ diff + $% [%add =channel] + [%del ~] + :: + [%add-sects sects=(set sect)] + [%del-sects sects=(set sect)] + :: + [%zone =zone] + :: + [%join join=_|] + == + -- +:: +:: $group: collection of people and the pathways in which they interact +:: +:: group holds all data around members, permissions, channel +:: organization, and its own metadata to represent the group +:: ++$ group + $: =fleet + cabals=(map sect cabal) + zones=(map zone realm:zone) + zone-ord=(list zone) + =bloc + =channels:channel + imported=(set nest) + =cordon + secret=? + meta=data:meta + == +:: +:: $cabal: metadata representing a $sect or role +:: +++ cabal + =< cabal + |% + :: + +$ cabal + [meta=data:meta ~] + :: + +$ diff + $% [%add meta=data:meta] + [%del ~] + == + -- +:: +:: $cordon: group entry and visibility permissions +:: +++ cordon + =< cordon + |% + :: + :: $open: a group with open entry, only bans are barred entry + :: + ++ open + |% + :: $ban: set of ships and ranks/classes that are not allowed entry + :: + :: bans can either be done at the individual ship level or by the + :: rank level (comet/moon/etc.) + :: + +$ ban [ships=(set ship) ranks=(set rank:title)] + +$ diff + $% [%add-ships p=(set ship)] + [%del-ships p=(set ship)] + :: + [%add-ranks p=(set rank:title)] + [%del-ranks p=(set rank:title)] + == + -- + :: + :: $shut: a group with closed entry, everyone barred entry + :: + :: a shut cordon means that the group is closed, but still visible. + :: people may request entry and either be accepted or denied or + :: they may be invited directly + :: + :: ask: represents those requesting entry + :: pending: represents those who've been invited + :: + ++ shut + |% + +$ state [pend=(set ship) ask=(set ship)] + +$ kind ?(%ask %pending) + +$ diff + $% [%add-ships p=kind q=(set ship)] + [%del-ships p=kind q=(set ship)] + == + -- + :: + :: $cordon: a set of metadata to represent the entry policy for a group + :: + :: open: a group with open entry, only bans barred entry + :: shut: a group with closed entry, everyone barred entry + :: afar: a custom entry policy defined by another agent + :: + +$ cordon + $% [%shut state:shut] + [%afar =flag =path desc=@t] + [%open =ban:open] + == + :: + :: $diff: the actions you can take on a cordon + :: + +$ diff + $% [%shut p=diff:shut] + [%open p=diff:open] + [%swap p=cordon] + == + -- +:: +:: $bloc: superuser sects +:: +:: sects in the bloc set are allowed to make modifications to the group +:: and its various metadata and permissions +:: +++ bloc + =< bloc + |% + +$ bloc (set sect) + +$ diff + $% [%add p=(set sect)] + [%del p=(set sect)] + == + -- +:: +:: $diff: the general set of changes that can be made to a group +:: ++$ diff + $% [%fleet p=(set ship) q=diff:fleet] + [%cabal p=sect q=diff:cabal] + [%channel p=nest q=diff:channel] + [%bloc p=diff:bloc] + [%cordon p=diff:cordon] + [%zone p=diff:zone] + [%meta p=data:meta] + [%secret p=?] + [%create p=group] + [%del ~] + == +:: +:: $action: the complete set of data required to edit a group +:: ++$ action + (pair flag update) +:: +:: $update: a representation in time of a modification of a group +:: ++$ update + (pair time diff) +:: +:: $create: a request to make a group +:: ++$ create + $: name=term + title=cord + description=cord + image=cord + cover=cord + =cordon + members=(jug ship sect) + secret=? + == +:: ++$ init [=time =group] +:: ++$ groups + (map flag group) ++$ net-groups + (map flag [net group]) +:: +:: $log: a time ordered map of all modifications to groups +:: ++$ log + ((mop time diff) lte) +:: +++ log-on + ((on time diff) lte) +:: +:: $net: an indicator of whether I'm a host or subscriber +:: ++$ net + $~ [%pub ~] + $% [%pub p=log] + [%sub p=time load=_| =saga:e] + == +:: +:: $join: a join request, can elect to join all channels +:: ++$ join + $: =flag + join-all=? + == +:: +:: $knock: a request to enter a closed group +:: ++$ knock flag +:: +:: $progress: the state of a group join +:: ++$ progress + ?(%knocking %adding %watching %done %error) +:: +:: $claim: a mark for gangs to represent a join in progress +:: ++$ claim + $: join-all=? + =progress + == +:: +:: $preview: the metadata and entry policy for a group +:: ++$ preview + $: =flag + meta=data:meta + =cordon + =time + secret=? + == +:: ++$ previews (map flag preview) +:: +:: $invite: a marker to show you've been invited to a group +:: ++$ invite (pair flag ship) +:: +:: $gang: view of foreign group +:: ++$ gang + $: cam=(unit claim) + pev=(unit preview) + vit=(unit invite) + == +:: ++$ gangs (map flag gang) +-- +--
\ No newline at end of file diff --git a/desk/sur/tlon/channels.hoon b/desk/sur/tlon/channels.hoon new file mode 100644 index 0000000..c222d4c --- /dev/null +++ b/desk/sur/tlon/channels.hoon @@ -0,0 +1,464 @@ +:: channels: message stream structures +:: +:: four shapes that cross client-subscriber-publisher boundaries: +:: - actions client-to-subscriber change requests (user actions) +:: - commands subscriber-to-publisher change requests +:: - updates publisher-to-subscriber change notifications +:: - responses subscriber-to-client change notifications +:: +:: --action--> --command--> +:: client subscriber publisher +:: <--response-- <--update-- +:: +:: local actions _may_ become responses, +:: remote actions become commands, +:: commands _may_ become updates, +:: updates _may_ become responses. +:: +/- g=tlon-groups, c=tlon-cite +/+ mp=mop-extensions +|% ++| %ancients +:: +++ mar + |% + ++ act `mark`%channel-action + ++ cmd `mark`%channel-command + ++ upd `mark`%channel-update + ++ log `mark`%channel-logs + ++ not `mark`%channel-posts + -- +:: ++| %primitives +:: ++$ flag (pair ship term) ++$ v-channels (map nest v-channel) +++ v-channel + |^ ,[global local] + :: $global: should be identical between ships + :: + +$ global + $: posts=v-posts + order=(rev order=arranged-posts) + view=(rev =view) + sort=(rev =sort) + perm=(rev =perm) + == + :: $window: sparse set of time ranges + :: + ::TODO populate this + +$ window (list [from=time to=time]) + :: .window: time range for requested posts that we haven't received + :: .diffs: diffs for posts in the window, to apply on receipt + :: + +$ future + [=window diffs=(jug id-post u-post)] + :: $local: local-only information + :: + +$ local + $: =net + =log + =remark + =window + =future + == + -- +:: $v-post: a channel post +:: ++$ v-post [v-seal (rev essay)] ++$ id-post time ++$ v-posts ((mop id-post (unit v-post)) lte) +++ on-v-posts ((on id-post (unit v-post)) lte) +++ mo-v-posts ((mp id-post (unit v-post)) lte) +:: $v-reply: a post comment +:: ++$ v-reply [v-reply-seal (rev memo)] ++$ id-reply time ++$ v-replies ((mop id-reply (unit v-reply)) lte) +++ on-v-replies ((on id-reply (unit v-reply)) lte) +++ mo-v-replies ((mp time (unit v-reply)) lte) +:: $v-seal: host-side data for a post +:: ++$ v-seal $+ channel-seal + $: id=id-post + replies=v-replies + reacts=v-reacts + == +:: $v-reply-seal: host-side data for a reply +:: ++$ v-reply-seal + $: id=id-reply + reacts=v-reacts + == +:: $essay: top-level post, with metadata +:: ++$ essay [memo =kind-data] +:: $reply-meta: metadata for all replies ++$ reply-meta + $: reply-count=@ud + last-repliers=(set ship) + last-reply=(unit time) + == +:: $kind-data: metadata for a channel type's "post" +:: ++$ kind-data + $% [%diary title=@t image=@t] + [%heap title=(unit @t)] + [%chat kind=$@(~ [%notice ~])] + == +:: $memo: post data proper +:: +:: content: the body of the comment +:: author: the ship that wrote the comment +:: sent: the client-side time the comment was made +:: ++$ memo + $: content=story + author=ship + sent=time + == +:: $story: post body content +:: ++$ story (list verse) +:: $verse: a chunk of post content +:: +:: blocks stand on their own. inlines come in groups and get wrapped +:: into a paragraph +:: ++$ verse + $% [%block p=block] + [%inline p=(list inline)] + == +:: $listing: recursive type for infinitely nested <ul> or <ol> ++$ listing + $% [%list p=?(%ordered %unordered %tasklist) q=(list listing) r=(list inline)] + [%item p=(list inline)] + == +:: $block: post content that sits outside of the normal text +:: +:: %image: a visual, we record dimensions for better rendering +:: %cite: an Urbit reference +:: %header: a traditional HTML heading, h1-h6 +:: %listing: a traditional HTML list, ul and ol +:: %code: a block of code +:: ++$ block $+ channel-block + $% [%image src=cord height=@ud width=@ud alt=cord] + [%cite =cite:c] + [%header p=?(%h1 %h2 %h3 %h4 %h5 %h6) q=(list inline)] + [%listing p=listing] + [%rule ~] + [%code code=cord lang=cord] + == +:: $inline: post content that flows within a paragraph +:: +:: @t: plain text +:: %italics: italic text +:: %bold: bold text +:: %strike: strikethrough text +:: %inline-code: code formatting for small snippets +:: %blockquote: blockquote surrounded content +:: %block: link/reference to blocks +:: %code: code formatting for large snippets +:: %tag: tag gets special signifier +:: %link: link to a URL with a face +:: %break: line break +:: ++$ inline $+ channel-inline + $@ @t + $% [%italics p=(list inline)] + [%bold p=(list inline)] + [%strike p=(list inline)] + [%blockquote p=(list inline)] + [%inline-code p=cord] + [%code p=cord] + [%ship p=ship] + [%block p=@ud q=cord] + [%tag p=cord] + [%link p=cord q=cord] + [%task p=?(%.y %.n) q=(list inline)] + [%break ~] + == +:: ++$ kind ?(%diary %heap %chat) +:: $nest: identifier for a channel ++$ nest [=kind =ship name=term] +:: $view: the persisted display format for a channel ++$ view $~(%list ?(%grid %list)) +:: $sort: the persisted sort type for a channel ++$ sort $~(%time ?(%alpha %time %arranged)) +:: $arranged-posts: an array of postIds ++$ arranged-posts (unit (list time)) +:: $hidden-posts: a set of ids for posts that are hidden ++$ hidden-posts (set id-post) +:: $post-toggle: hide or show a particular post by id ++$ post-toggle + $% [%hide =id-post] + [%show =id-post] + == +:: $react: either an emoji identifier like :diff or a URL for custom ++$ react @ta ++$ v-reacts (map ship (rev (unit react))) +:: $scan: search results ++$ scan (list reference) ++$ reference + $% [%post =post] + [%reply =id-post =reply] + == +:: $said: used for references ++$ said (pair nest reference) +:: $plan: index into channel state +:: p: Post being referred to +:: q: Reply being referred to, if any +:: ++$ plan + (pair time (unit time)) +:: +:: $net: subscriber-only state +:: ++$ net [p=ship load=_|] +:: +:: $unreads: a map of channel unread information, for clients +:: $unread: unread data for a specific channel, for clients +:: recency: time of most recent message +:: count: how many posts are unread +:: unread-id: the id of the first unread top-level post +:: threads: for each unread thread, the id of the first unread reply +:: ++$ unreads (map nest unread) ++$ unread + $: recency=time + count=@ud + unread-id=(unit id-post) + threads=(map id-post id-reply) + == +:: $remark: markers representing unread state +:: last-read: time at which the user last read this channel +:: watching: unused, intended for disabling unread accumulation +:: unread-threads: threads that contain unread messages +:: ++$ remark [recency=time last-read=time watching=_| unread-threads=(set id-post)] +:: +:: $perm: represents the permissions for a channel and gives a +:: pointer back to the group it belongs to. +:: ++$ perm + $: writers=(set sect:g) + group=flag:g + == +:: +:: $log: a time ordered history of modifications to a channel +:: ++$ log ((mop time u-channel) lte) +++ log-on ((on time u-channel) lte) +:: +:: $create-channel: represents a request to create a channel +:: +:: $create-channel is consumed by the channel agent first and then +:: passed to the groups agent to register the channel with the group. +:: +:: Write permission is stored with the specific agent in the channel, +:: read permission is stored with the group's data. +:: ++$ create-channel + $: =kind + name=term + group=flag:g + title=cord + description=cord + readers=(set sect:g) + writers=(set sect:g) + == +:: $outline: abridged $post +:: .replies: number of comments +:: ++$ outline + [replies=@ud replyers=(set ship) essay] +:: +++ outlines + =< outlines + |% + +$ outlines ((mop time outline) lte) + ++ on ((^on time outline) lte) + -- +++ rev + |$ [data] + [rev=@ud data] +:: +++ apply-rev + |* [old=(rev) new=(rev)] + ^+ [changed=& old] + ?: (lth rev.old rev.new) + &+new + |+old +:: +++ next-rev + |* [old=(rev) new=*] + ^+ [changed=& old] + ?: =(+.old new) + |+old + &+old(rev +(rev.old), + new) +:: ++| %actions +:: +:: some actions happen to be the same as commands, but this can freely +:: change +:: +::NOTE we might want to add a action-id=uuid to this eventually, threading +:: that through all the way, so that an $r-channels may indicate what +:: originally caused it ++$ a-channels + $% [%create =create-channel] + [%pin pins=(list nest)] + [%channel =nest =a-channel] + [%toggle-post toggle=post-toggle] + == ++$ a-channel + $% [%join group=flag:g] + [%leave ~] + a-remark + c-channel + == +:: ++$ a-remark + $~ [%read ~] + $% [%read ~] + [%read-at =time] + [%watch ~] + [%unwatch ~] + == +:: ++$ a-post c-post ++$ a-reply c-reply +:: ++| %commands +:: ++$ c-channels + $% [%create =create-channel] + [%channel =nest =c-channel] + == ++$ c-channel + $% [%post =c-post] + [%view =view] + [%sort =sort] + [%order order=arranged-posts] + [%add-writers sects=(set sect:g)] + [%del-writers sects=(set sect:g)] + == +:: ++$ c-post + $% [%add =essay] + [%edit id=id-post =essay] + [%del id=id-post] + [%reply id=id-post =c-reply] + c-react + == +:: ++$ c-reply + $% [%add =memo] + [%edit id=id-reply =memo] + [%del id=id-reply] + c-react + == +:: ++$ c-react + $% [%add-react id=@da p=ship q=react] + [%del-react id=@da p=ship] + == +:: ++| %updates +:: ++$ update [=time =u-channel] ++$ u-channels [=nest =u-channel] ++$ u-channel + $% [%create =perm] + [%order (rev order=arranged-posts)] + [%view (rev =view)] + [%sort (rev =sort)] + [%perm (rev =perm)] + [%post id=id-post =u-post] + == +:: ++$ u-post + $% [%set post=(unit v-post)] + [%reacts reacts=v-reacts] + [%essay (rev =essay)] + [%reply id=id-reply =u-reply] + == +:: ++$ u-reply + $% [%set reply=(unit v-reply)] + [%reacts reacts=v-reacts] + == +:: ++$ u-checkpoint global:v-channel +:: ++| %responses +:: ++$ r-channels [=nest =r-channel] ++$ r-channel + $% [%posts =posts] + [%post id=id-post =r-post] + [%order order=arranged-posts] + [%view =view] + [%sort =sort] + [%perm =perm] + :: + [%create =perm] + [%join group=flag:g] + [%leave ~] + a-remark + == +:: ++$ r-post + $% [%set post=(unit post)] + [%reply id=id-reply =reply-meta =r-reply] + [%reacts =reacts] + [%essay =essay] + == +:: ++$ r-reply + $% [%set reply=(unit reply)] + [%reacts =reacts] + == +:: versions of backend types with their revision numbers stripped, +:: because the frontend shouldn't care to learn those. +:: ++$ channels (map nest channel) +++ channel + |^ ,[global local] + +$ global + $: =posts + order=arranged-posts + =view + =sort + =perm + == + :: + +$ local + $: =net + =remark + == + -- ++$ paged-posts + $: =posts + newer=(unit time) + older=(unit time) + total=@ud + == ++$ posts ((mop id-post (unit post)) lte) ++$ post [seal essay] ++$ seal + $: id=id-post + =reacts + =replies + =reply-meta + == ++$ reacts (map ship react) ++$ reply [reply-seal memo] ++$ replies ((mop id-reply reply) lte) ++$ reply-seal [id=id-reply parent-id=id-post =reacts] +++ on-posts ((on id-post (unit post)) lte) +++ on-replies ((on id-reply reply) lte) ++$ cite cite:c +-- diff --git a/desk/sur/tlon/cite.hoon b/desk/sur/tlon/cite.hoon new file mode 100644 index 0000000..1d92a46 --- /dev/null +++ b/desk/sur/tlon/cite.hoon @@ -0,0 +1,57 @@ +/- g=tlon-groups +=< cite +|% +++ purse + |= =(pole knot) + ^- (unit cite) + ?. =(~.1 -.pole) ~ + =. pole +.pole + ?+ pole ~ + [%chan agent=@ ship=@ name=@ rest=*] + =/ ship (slaw %p ship.pole) + ?~ ship ~ + `[%chan [agent.pole u.ship name.pole] rest.pole] + :: + [%desk ship=@ name=@ rest=*] + =/ ship (slaw %p ship.pole) + ?~ ship ~ + `[%desk [u.ship name.pole] rest.pole] + :: + [%group ship=@ name=@ ~] + =/ ship (slaw %p ship.pole) + ?~ ship ~ + `[%group u.ship name.pole] + == +:: +++ parse + |= =path + ^- cite + (need (purse path)) +:: +++ print + |= c=cite + |^ ^- path + :- (scot %ud 1) + ?- -.c + %chan chan/(welp (nest nest.c) wer.c) + %desk desk/(welp (flag flag.c) wer.c) + %group group/(flag flag.c) + %bait bait/:(welp (flag grp.c) (flag gra.c) wer.c) + == + ++ flag + |= f=flag:g + ~[(scot %p p.f) q.f] + ++ nest + |= n=nest:g + [p.n (flag q.n)] + -- +:: ++$ cite + $% [%chan =nest:g wer=path] + [%group =flag:g] + [%desk =flag:g wer=path] + [%bait grp=flag:g gra=flag:g wer=path] + :: scry into groups when you receive a bait for a chat that doesn't exist yet + :: work out what app + == +-- diff --git a/desk/sur/tlon/groups.hoon b/desk/sur/tlon/groups.hoon new file mode 100644 index 0000000..cf03233 --- /dev/null +++ b/desk/sur/tlon/groups.hoon @@ -0,0 +1,383 @@ +|% +++ epic +|% ++$ saga + $~ [%lev ~] + $% [%dex ver=@ud] + [%lev ~] + [%chi ~] + == + ++$ epic @ud +-- +++ meta +|% ++$ data + $: title=cord + description=cord + image=cord + cover=cord + == ++$ diff + $% [%title =cord] + [%description =cord] + [%image =cord] + [%cover =cord] + == +-- +++ e epic +++ okay `epic:e`2 +++ mar + |% + ++ act `mark`(rap 3 %group-action '-' (scot %ud okay) ~) + ++ upd `mark`(rap 3 %group-update '-' (scot %ud okay) ~) + ++ log `mark`(rap 3 %group-log '-' (scot %ud okay) ~) + ++ int `mark`(rap 3 %group-init '-' (scot %ud okay) ~) + -- +:: $flag: ID for a group +:: ++$ flag (pair ship term) +:: +:: $nest: ID for a channel, {app}/{ship}/{name} +:: ++$ nest (pair term flag) +:: +:: $sect: ID for cabal, similar to a role +:: ++$ sect term +:: +:: $zone: channel grouping +:: +:: includes its own metadata for display and keeps the order of +:: channels within. +:: +:: zone: the term that represents the ID of a zone +:: realm: the metadata representing the zone and the order of channels +:: delta: the set of actions that can be taken on a zone +:: %add: create a zone +:: %del: delete the zone +:: %edit: modify the zone metadata +:: %mov: reorders the zone in the group +:: %mov-nest: reorders a channel within the zone +:: +++ zone + =< zone + |% + +$ zone @tas + +$ realm + $: met=data:meta + ord=(list nest) + == + +$ diff (pair zone delta) + +$ delta + $% [%add meta=data:meta] + [%del ~] + [%edit meta=data:meta] + [%mov idx=@ud] + [%mov-nest =nest idx=@ud] + == + -- +:: +:: $fleet: group members and their associated metadata +:: +:: vessel: a user's set of sects or roles and the time that they joined +:: @da default represents an admin added member that has yet to join +:: +++ fleet + =< fleet + |% + +$ fleet (map ship vessel) + +$ vessel + $: sects=(set sect) + joined=time + == + +$ diff + $% [%add ~] + [%del ~] + [%add-sects sects=(set sect)] + [%del-sects sects=(set sect)] + == + -- +:: +:: $channel: a medium for interaction +:: +++ channel + =< channel + |% + +$ preview + $: =nest + meta=data:meta + group=^preview + == + :: + +$ channels (map nest channel) + :: + :: $channel: a collection of metadata about a specific agent integration + :: + :: meta: title, description, image, cover + :: added: when the channel was created + :: zone: what zone or section to bucket in + :: join: should the channel be joined by new members + :: readers: what sects can see the channel, empty means anyone + :: + +$ channel + $: meta=data:meta + added=time + =zone + join=? + readers=(set sect) + == + :: + :: $diff: represents the set of actions you can take on a channel + :: + :: add: create a channel + :: edit: edit a channel + :: del: delete a channel + :: add-sects: add sects to readers + :: del-sects: delete sects from readers + :: zone: change the zone of the channel + :: join: toggle default join + :: + +$ diff + $% [%add =channel] + [%edit =channel] + [%del ~] + :: + [%add-sects sects=(set sect)] + [%del-sects sects=(set sect)] + :: + [%zone =zone] + :: + [%join join=_|] + == + -- +:: +:: $group: collection of people and the pathways in which they interact +:: +:: group holds all data around members, permissions, channel +:: organization, and its own metadata to represent the group +:: ++$ group + $: =fleet + cabals=(map sect cabal) + zones=(map zone realm:zone) + zone-ord=(list zone) + =bloc + =channels:channel + imported=(set nest) + =cordon + secret=? + meta=data:meta + == +:: ++$ group-ui [group saga=(unit saga:e)] +:: $cabal: metadata representing a $sect or role +:: +++ cabal + =< cabal + |% + :: + +$ cabal + [meta=data:meta ~] + :: + +$ diff + $% [%add meta=data:meta] + [%edit meta=data:meta] + [%del ~] + == + -- +:: +:: $cordon: group entry and visibility permissions +:: +++ cordon + =< cordon + |% + :: + :: $open: a group with open entry, only bans are barred entry + :: + ++ open + |% + :: $ban: set of ships and ranks/classes that are not allowed entry + :: + :: bans can either be done at the individual ship level or by the + :: rank level (comet/moon/etc.) + :: + +$ ban [ships=(set ship) ranks=(set rank:title)] + +$ diff + $% [%add-ships p=(set ship)] + [%del-ships p=(set ship)] + :: + [%add-ranks p=(set rank:title)] + [%del-ranks p=(set rank:title)] + == + -- + :: + :: $shut: a group with closed entry, everyone barred entry + :: + :: a shut cordon means that the group is closed, but still visible. + :: people may request entry and either be accepted or denied or + :: they may be invited directly + :: + :: ask: represents those requesting entry + :: pending: represents those who've been invited + :: + ++ shut + |% + +$ state [pend=(set ship) ask=(set ship)] + +$ kind ?(%ask %pending) + +$ diff + $% [%add-ships p=kind q=(set ship)] + [%del-ships p=kind q=(set ship)] + == + -- + :: + :: $cordon: a set of metadata to represent the entry policy for a group + :: + :: open: a group with open entry, only bans barred entry + :: shut: a group with closed entry, everyone barred entry + :: afar: a custom entry policy defined by another agent + :: + +$ cordon + $% [%shut state:shut] + [%afar =flag =path desc=@t] + [%open =ban:open] + == + :: + :: $diff: the actions you can take on a cordon + :: + +$ diff + $% [%shut p=diff:shut] + [%open p=diff:open] + [%swap p=cordon] + == + -- +:: +:: $bloc: superuser sects +:: +:: sects in the bloc set are allowed to make modifications to the group +:: and its various metadata and permissions +:: +++ bloc + =< bloc + |% + +$ bloc (set sect) + +$ diff + $% [%add p=(set sect)] + [%del p=(set sect)] + == + -- +:: +:: $diff: the general set of changes that can be made to a group +:: ++$ diff + $% [%fleet p=(set ship) q=diff:fleet] + [%cabal p=sect q=diff:cabal] + [%channel p=nest q=diff:channel] + [%bloc p=diff:bloc] + [%cordon p=diff:cordon] + [%zone p=diff:zone] + [%meta p=data:meta] + [%secret p=?] + [%create p=group] + [%del ~] + == +:: +:: $action: the complete set of data required to edit a group +:: ++$ action + (pair flag update) +:: +:: $update: a representation in time of a modification of a group +:: ++$ update + (pair time diff) +:: +:: $create: a request to make a group +:: ++$ create + $: name=term + title=cord + description=cord + image=cord + cover=cord + =cordon + members=(jug ship sect) + secret=? + == +:: ++$ init [=time =group] +:: +:: $groups-ui: map for frontend to display groups ++$ groups-ui + (map flag group-ui) ++$ groups + (map flag group) ++$ net-groups + (map flag [net group]) +:: +:: $log: a time ordered map of all modifications to groups +:: ++$ log + ((mop time diff) lte) +:: +++ log-on + ((on time diff) lte) +:: +:: $net: an indicator of whether I'm a host or subscriber +:: ++$ net + $~ [%pub ~] + $% [%pub p=log] + [%sub p=time load=_| =saga:e] + == +:: +:: $join: a join request, can elect to join all channels +:: ++$ join + $: =flag + join-all=? + == +:: +:: $knock: a request to enter a closed group +:: ++$ knock flag +:: +:: $progress: the state of a group join +:: ++$ progress + ?(%knocking %adding %watching %done %error) +:: +:: $claim: a mark for gangs to represent a join in progress +:: ++$ claim + $: join-all=? + =progress + == +:: +:: $preview: the metadata and entry policy for a group +:: ++$ preview + $: =flag + meta=data:meta + =cordon + =time + secret=? + == +:: ++$ previews (map flag preview) +:: +:: $invite: a marker to show you've been invited to a group +:: ++$ invite (pair flag ship) +:: +:: $gang: view of foreign group +:: ++$ gang + $: cam=(unit claim) + pev=(unit preview) + vit=(unit invite) + == +:: ++$ gangs (map flag gang) +:: +-- diff --git a/desk/sur/trill/gate.hoon b/desk/sur/trill/gate.hoon new file mode 100644 index 0000000..ddc0adb --- /dev/null +++ b/desk/sur/trill/gate.hoon @@ -0,0 +1,26 @@ +|% ++$ gate +$: =lock + begs=(set @p) :: follow requests + post-begs=(set post-beg) :: read requests for specific posts + :: TODO include whole thread? + mute=lock :: mute list to prevent request spamming + backlog=$~(50 @) :: size of backlog sent to followers by default +== ++$ post-beg [=ship id=@da] + ++$ lock +$: rank=[caveats=(set rank:title) locked=_| public=?] + luk=[caveats=(set ship) locked=_| public=?] + ship=[caveats=(set ship) locked=_| public=?] + tags=[caveats=(set @t) locked=_| public=?] + custom=[fn=(unit $-(@p ?)) public=?] +== ++$ change +$% [%set-rank set=(set rank:title) locked=? public=?] + [%set-luk set=(set ship) locked=? public=?] + [%set-ship set=(set ship) locked=? public=?] + [%set-tags set=(set @t) locked=? public=?] + [%set-custom term] :: Handle this and set in hoon +== +-- diff --git a/desk/sur/trill/post.hoon b/desk/sur/trill/post.hoon new file mode 100644 index 0000000..78c5e1a --- /dev/null +++ b/desk/sur/trill/post.hoon @@ -0,0 +1,115 @@ +/- gate=trill-gate +/+ mp=mop-extensions +|% ++$ id @da ++$ pid [=ship =id] +:: anon post type? ++$ tag @t ++$ gfeed ((mop pid post) ggth) +++ ggth |=([[shipa=@p a=time] [shipb=@p b=time]] (gth a b)) +++ gorm ((on pid post) ggth) +++ torm ((on pid thread) ggth) +++ porm ((on pid pid) ggth) +++ gorrm ((mp pid post) ggth) ++$ feed ((mop id post) gth) +++ orm ((on id post) gth) ++$ full-graph ((mop pid full-node) ggth) +++ form ((on pid full-node) ggth) +:: instead of using this I'm just gonna jam old names ++$ perms [read=lock:gate write=lock:gate] ++$ cursor (unit id) ++$ page-req [newer=cursor older=cursor count=@ud] ++$ full-node [p=post children=$~(~ full-graph)] ++$ cpage [p=(list post) top=@ud bot=@ud] ++$ spage [p=(list post) page-req] ++$ page [p=(list full-node) page-req] ++$ pfilter $-(=post ?) ++$ tfilter $-(=thread ?) ++$ bfilter $-([=thread =post] ?) :: search filter ++$ tpage [p=(list thread) page-req] ++$ thread + $: =pid + replies=(list pid) :: key should be the head of this list + title=@t + =path + tags=(set tag) + snip=content-list + == ++$ post + $: =id + title=@t + author=ship + thread=pid :: this is the key of the threads table! + parent=(unit pid) + children=(set pid) + contents=content-map + =perms + =engagement + =signature + tags=(set tag) ::TODO make sure it's not infinite + == +:: ++$ signature [p=@uvH q=ship r=life] ++$ engagement + $: + =reacts quoted=(set signed-pid) + shared=(set signed-pid) + == ++$ signed-pid [=signature =pid] ++$ react @t ++$ reacts (map ship signed-react) ++$ signed-react [p=react q=signature] + + ++$ content-map ((mop time content-list) gth) +++ corm ((on time content-list) gth) ++$ heading $?(%h1 %h2 %h3 %h4 %h5 %h6) ++$ content-list (list block) ++$ paragraph (list inline) +:: man tables are a rabbit hole. we'll get to it +++ table +|^ [%table headers=(list cell) rows=(list row)] ++$ row (list cell) ++$ cell content-list +-- ++$ clist [%list p=(list li) ordered=?] ++$ li content-list ++$ block + $% [%paragraph p=paragraph] + [%blockquote p=paragraph] + :: table + clist + [%heading p=cord q=heading] + [%media =media] + [%codeblock code=cord lang=cord] + [%eval hoon=cord] + [%tasklist p=(list task)] + :: + [%ref app=term =ship =path] + [%json origin=term content=@t] + == ++$ task [p=paragraph q=?] ++$ poll-opt [option=cord votes=@] ++$ media + $% [%images p=(list [url=@t caption=@t])] + [%video p=cord] + [%audio p=cord] + == ++$ inline + $% [%text p=cord] + [%italic p=cord] + [%bold p=cord] + [%strike p=cord] + [%codespan p=cord] + [%link href=cord show=cord] + [%break ~] + :: not strictly markdown + [%ship p=ship] + [%date p=@da] + [%note id=cord text=(list inline)] :: footnotes and so on + [%underline p=cord] + [%sup p=cord] + [%sub p=cord] + [%ruby p=cord q=cord] + == +-- diff --git a/desk/sur/twatter/json.hoon b/desk/sur/twatter/json.hoon new file mode 100644 index 0000000..476508b --- /dev/null +++ b/desk/sur/twatter/json.hoon @@ -0,0 +1,105 @@ +=, dejs-soft:format +|% +++ username +%- ot :_ ~ :- 'data' +%- ot :_ ~ :- 'user' +%- ot :_ ~ :- 'result' +%- ot + :~ :: :- '__typename' so + :: :- 'id' so + :- 'rest_id' so + :: :- 'profile_image_shape' so + :: :- 'is_profile-translatable' bo + :: :- 'is_blue_verified' bo + :: :- 'has_graduated_access' bo + :: :- 'is_profile-translatable' bo + :: :- 'creator_subscriptions_count' ni + :: :- 'legacy_extended_profile' so :: empty objects + :: :- 'verification_info' so + :: :- 'business_account' so + :: :- 'affiliates_highlighted_label' so + :: :- 'legacy' %- ot + :: :~ :- 'can-dm' bo + :: :- 'can-media-tag' bo + :: :- 'can-media-tag' bo + :: :- 'default_profile' bo + :: :- 'default_profile_image' bo + :: :- 'has_custom_timelines' bo + :: :- 'is_translator' bo + :: :- 'possibly_sensitive' bo + :: :- 'verified' bo + :: :- 'want_retweets' bo + :: :- 'fast_followers_count' ni + :: :- 'favourites_count' ni + :: :- 'followers_count' ni + :: :- 'friends_count' ni + :: :- 'listed_count' ni + :: :- 'media_count' ni + :: :- 'normal_followers_count' ni + :: :- 'statuses_count' ni + :: :- 'description' so + :: :- 'location' so + :: :- 'name' so + :: :- 'profile_banner_url' so + :: :- 'profile_image_url_https' so + :: :- 'screen_name' so + :: :- 'profile_interstitial_type' so :: mmm + :: :- 'translator_type' so + :: :- 'pinned_tweets_ids_str' (ar so) + :: :- 'withheld_in_countries' (ar so) + :: :- 'entities' %- ot + :: :~ :- 'description' %- ot + :: :~ :- 'urls' (ar so) + :: == + :: == + :: == + == +++ user-tweets +=, dejs-soft:format +%- ot :_ ~ :- 'data' +%- ot :_ ~ :- 'user' +%- ot :_ ~ :- 'result' +%- ot + :~ :- '__typename' so + :- 'timeline_v2' %- ot :_ ~ + :- 'timeline' %- ot + :~ :- 'metadata' %- ot ~ + :- 'instructions' (ar instruction) + == + == +++ instruction +|= jon=json + :: ?>(%o -.jon) + =/ type (~(got by p.jon) 'type') + ?: .=([%s 'TimelineClearCache'] type) ((ot ~) jon) + ?: .=([%s 'TimelinePinEntry'] type) ((ot timeline-pin-entry) jon) + ?: .=([%s 'TimelineAddEntries'] type) ((ot timeline-add-entries) jon) + !! + +:~ :- 'TimelinePinEntry' timeline-pin-entry + :- 'TimelineAddEntries' timeline-add-entries +== + +++ timeline-pin-entry +%- ot +:~ :- 'type' so + :- 'entry' %- ot + :~ :- 'entryId' so + :- 'sortIndex' so + :- 'content' content + == +== +++ timeline-add-entries +so +++ content +%- ot +:~ :- 'entryType' so + :- '__typename' so + :- 'itemContent' item-content + :- 'clientEventInfo' client-event-info +== +++ item-content +so +++ client-event-info +so +-- diff --git a/desk/sur/twatter/test.json b/desk/sur/twatter/test.json new file mode 100644 index 0000000..ec747fa --- /dev/null +++ b/desk/sur/twatter/test.json @@ -0,0 +1 @@ +null
\ No newline at end of file diff --git a/desk/sys.kelvin b/desk/sys.kelvin new file mode 100644 index 0000000..af17e6b --- /dev/null +++ b/desk/sys.kelvin @@ -0,0 +1,4 @@ +[%zuse 412] +[%zuse 411] +[%zuse 410] +[%zuse 409] diff --git a/desk/ted/tw.hoon b/desk/ted/tw.hoon new file mode 100644 index 0000000..1fffee5 --- /dev/null +++ b/desk/ted/tw.hoon @@ -0,0 +1,61 @@ +/- spider, jon=twatter-json +/+ strandio, sr=sortug, w2=web2, lib=twatter +=, strand=strand:spider +=, dejs-soft:format +=, strand-fail=strand-fail:libstrand:spider +=< run +|% +++ get-body +|= res=client-response:iris ^- @t + ?. ?=(%finished -.res) '' + ?~ full-file.res '' + q.data.u.full-file.res +++ coki-to-string +|= t=twatter-creds:w2 ^- cord + =/ at (trip auth-token.t) + =/ ct0 (trip ct0.t) + =/ kdt (trip kdt.t) + =/ twid (trip twid.t) + %- crip + "auth_token={at};ct0={ct0};kdt={kdt};twid={twid};" +:: +++ run + ^- thread:spider + |= arg=vase + ~& > arg=arg + =/ m (strand vase) + ^- form:m + =/ coki muh:w2 + =/ csrf ct0.coki + =/ coki-string (coki-to-string coki) + =/ headers (logged-headers:lib coki-string csrf) + |^ + :: =/ req !<(twatter-action:w2 arg) + =/ req=twatter-action:w2 [%user 'spandrell4'] + ?+ -.req (pure:m !>(%bad)) + %user (fetch-tw-user +.req) + == + ++ fetch-tw-user + |= username=@t + =/ vars (build-variables:lib ~[['screen_name' %s username]]) + =/ url %- crip (weld (burl:lib user-by-name:urls:lib) "?variables={vars}&features={features:lib}") + =/ req1 [%'GET' url headers ~] + ;< ~ bind:m (send-request:strandio req1) + ;< res1=client-response:iris bind:m take-client-response:strandio + =/ body1=@t (get-body res1) + :: ~& >> body1 + =/ j (de:json:html body1) + ?~ j (pure:m !>(%bad-js)) + =/ dejs (username:jon u.j) + ?~ dejs (pure:m !>(%bad-js)) + =/ user-id=@t u.dejs + =/ url2 %- crip (weld (burl:lib user-tweets:urls:lib) (userid-params:lib user-id)) + =/ req2 [%'GET' url2 headers ~] + ;< ~ bind:m (send-request:strandio req2) + ;< res2=client-response:iris bind:m take-client-response:strandio + =/ body2 (get-body res2) + =/ jon (de:json:html body2) + ?~ jon (pure:m !>(%bad-json)) + (pure:m !>(u.jon)) + -- +-- diff --git a/desk/ted/twatter.hoon b/desk/ted/twatter.hoon new file mode 100644 index 0000000..018fa27 --- /dev/null +++ b/desk/ted/twatter.hoon @@ -0,0 +1,158 @@ +/- spider, w=web2-main, tw=web2-twatter, cokis=web2-cookies +/+ strandio, string, sr=sortug, *web2-twatter +=, strand=strand:spider +=, dejs-soft:format +=, strand-fail=strand-fail:libstrand:spider +=< run +|% +++ cookie-check + |= body=@t ^- (unit ?) + =/ jon=(unit json) (better-dejson:parsing:sr body) + ?~ jon ~ + =/ error=(unit error-res:tw) (errors:dejs:tw u.jon) + ?~ error `.y + ?~ u.error ~ + =/ main (head u.error) + `.n + :: :- ~ !.=(code.main 32) + :: + :: :- ~ %+ roll +.u.error + :: |= [[msg=@t code=@ud] acc=@t] code + +++ parse-user-id + |= body=@t ^- (unit @t) + =/ jon=(unit json) (better-dejson:parsing:sr body) + ?~ jon ~ + `(profile:dejs:tw u.jon) +:: ++ get-body +:: |= res=client-response:iris +:: =/ m (strand cord) +:: ^- form:m +:: ?. ?=(%finished -.res) (strand-fail %no-body ~) +:: ?~ full-file.res (strand-fail %no-body ~) +:: =/ body=@t q.data.u.full-file.res +:: (pure:m body) +++ get-body +|= res=client-response:iris ^- @t +?. ?=(%finished -.res) '' +?~ full-file.res '' +q.data.u.full-file.res +++ coki-to-string +|= t=twatter-creds:cokis ^- cord +=/ at (trip auth-token.t) +=/ ct0 (trip ct0.t) +=/ kdt (trip kdt.t) +=/ twid (trip twid.t) +%- crip +"auth_token={at};ct0={ct0};kdt={kdt};twid={twid};" +++ run + ^- thread:spider + |= arg=vase + =/ m (strand vase) + ^- form:m + |^ + =/ req !<((unit request:w) arg) :: dojo only? + ?~ req (pure:m !>([%fail 'wrong request'])) + ?. ?=(%twatter -.u.req) (pure:m !>([%fail 'wrong request'])) + =/ =action:tw +.u.req + ?: ?=(%lurk -.action) (lurk thread.action) + :: Else is logged in, need cookies + ;< =bowl:spider bind:m get-bowl:strandio + =/ coki (scry:io:sr %trill-cookies /app/twatter scry:cokis our.bowl now.bowl) + ?: ?=(%ng -.coki) (pure:m !>([%twatter %no-coki ~])) + ?: ?=(%active -.coki) (pure:m !>([%twatter %no-coki ~])) + ?. ?=(%twatter -.p.coki) (pure:m !>([%twatter %no-coki ~])) + =/ csrf ct0.p.coki + =/ tw=twatter-creds:cokis +.p.coki + =/ coki-string (coki-to-string tw) + =/ headers (logged-headers coki-string csrf) + ?+ -.action (pure:m !>([%fail 'wrong request'])) + %user + =/ vars (build-variables ~[['screen_name' %s username.action]]) + =/ url %- crip (weld (burl user-by-name:urls) "?variables={vars}&features={features}") + =/ req1 [%'GET' url headers ~] + ;< ~ bind:m (send-request:strandio req1) + ;< res1=client-response:iris bind:m take-client-response:strandio + =/ body1=@t (get-body res1) + =/ coki-ok (cookie-check body1) + ?~ coki-ok (pure:m !>([%fail 'parsing error'])) + ?. u.coki-ok + (pure:m !>([%twatter %no-coki ~])) + =/ user-id (parse-user-id body1) + ?~ user-id (pure:m !>([%fail 'parsing error'])) + =/ url2 %- crip (weld (burl user-tweets:urls) (userid-params u.user-id)) + =/ req2 [%'GET' url2 headers ~] + ;< ~ bind:m (send-request:strandio req2) + ;< res2=client-response:iris bind:m take-client-response:strandio + =/ body2 (get-body res2) + (pure:m !>([%twatter %user body1 body2])) + :: ?~ user-id (pure:m !>(`response:tw`[%user profile=`user-profile feed=~])) + :: =/ tw-data-req ?- replies.u.command + :: %| (twatter-request (build-request-url 'userId' u.user-id cursor.u.command user-tweets:endpoints) gt csrf) + :: %& (twatter-request (build-request-url 'userId' u.user-id cursor.u.command user-tweets-replies:endpoints) gt csrf) == + %thread + =/ vars (build-variables ~[['focalTweetId' %s id.action]]) + =/ url %- crip (weld (burl tweet-detail:urls) "?variables={vars}&features={features}") + :: =/ tw-data-req (embed-request id.u.command) + :: =/ req (twatter-request url gt csrf) + =/ req [%'GET' url headers ~] + :: =/ tw-data-req (twatter-request (build-request-v2-url 'tweetId' id.u.command cursor.u.command tweet-lurk:endpoints) gt csrf) + ;< ~ bind:m (send-request:strandio req) + ;< res=client-response:iris bind:m take-client-response:strandio + =/ body (get-body res) + =/ coki-ok (cookie-check body) + ?~ coki-ok (pure:m !>([%fail 'parsing error'])) + ?. u.coki-ok + :: (lurk id.action) + (pure:m !>([%twatter %no-coki ~])) + (pure:m !>([%twatter %thread body])) + %search + =/ vars (build-variables ~[['rawQuery' %s query.action] ['querySource' %s 'typed_query'] ['product' %s 'Latest']]) + =/ url %- crip (weld (burl search-timeline:urls) "?variables={vars}&features={features}") + :: =/ tw-data-req (twatter-request (build-search-url query.u.command cursor.u.command) gt csrf) + =/ req [%'GET' url headers ~] + ;< ~ bind:m (send-request:strandio req) + ;< res=client-response:iris bind:m take-client-response:strandio + =/ body (get-body res) + (pure:m !>([%twatter %search query.action body])) + %hark + =/ vars "?{notes-params}" + =/ url %- crip (weld notifications-url vars) + =/ req [%'GET' url headers ~] + ;< ~ bind:m (send-request:strandio req) + ;< res=client-response:iris bind:m take-client-response:strandio + =/ body (get-body res) + (pure:m !>([%twatter %hark body])) + :: posts + %post + =/ url (crip (burl create-tweet:urls)) + =/ body=octs (build-post-body +.action) + =/ req [%'POST' url headers `body] + ;< ~ bind:m (send-request:strandio req) + ;< res=client-response:iris bind:m take-client-response:strandio + =/ res-body (get-body res) + :: TODO error handle. If successful the body returns a {data: {create_tweet: tweet_results...}} object + (pure:m !>([%twatter %post-ack ~])) + == + ++ lurk + |= tweet-id=@t + =/ csrf-req csrf-token-request :: TODO could cache gt and crsf for a while, instead of fetching on every request + ;< ~ bind:m (send-request:strandio csrf-req) + ;< csrf-res=client-response:iris bind:m take-client-response:strandio + ;< csrf=@t bind:m (parse-csrf csrf-res) + =/ guest-token-req gt-request + ;< ~ bind:m (send-request:strandio guest-token-req) + ;< gt-res=client-response:iris bind:m take-client-response:strandio + ;< gt=@t bind:m (parse-gt gt-res) + :: turns out we do need this + =/ vars (build-variables ~[['tweetId' %s tweet-id]]) + =/ url %- crip (weld (burl tweet-lurk:urls) "?variables={vars}&features={features}") + =/ req1 (twatter-request url gt csrf) + :: =/ req1 [%'GET' url lurk-headers ~] + ;< ~ bind:m (send-request:strandio req1) + ;< res1=client-response:iris bind:m take-client-response:strandio + =/ body1 (get-body res1) + (pure:m !>([%twatter %thread-lurk body1])) + + -- +-- diff --git a/desk/web/about.hoon b/desk/web/about.hoon new file mode 100644 index 0000000..71783bd --- /dev/null +++ b/desk/web/about.hoon @@ -0,0 +1,65 @@ +=< about +|% +++ about +;div.blog + ;p: Welcome to Bloody Shovel 4. The latest iteration of Spandrell's blog. Now revived as a larger community app. In addition to the old blog (which will be continued), this website now provides a discussion forum (the Board), live group chats and more functionality to come. + + ;p: The blog is open to read by everyone, and there is one public chat and one public board. Everything else is login only. To login you will need an Urbit ID. They're easy to get these days. Click on the Login page for details. + + ;p: Logging in allows you to leave comments on the blog, and post on the main chat and most forum boards. Also you can watch Spandrell TV. + ;p + ; All other functionality is exclusive to Subscribers. For more details please visit + ;a/"/subscribe":"the subscribe page" + ; . + == + + ;p: The basic building blog of this website is tags. Every blogpost and board thread is tagged. You can search for tags easily in the search page and board selection page. + + ;p: If you're new here, what follows is the old text explaining what the blog is about. I'm happy to say I still stand by all my old opinions, even though of course I have new ones which I will develop further in new posts on the blog. Stay tuned. + + + ;p: I am a European man living in Asia who blogs about the past and future of civilization. + ;p: I started this blog in 2011, and since then I developed a few theories which have been influential. The background of my thought is that modern Civilization, more precisely modern Western Civilization, is on a death spiral. I try to use the insights taken from world history, the theory of evolution and pragmatic philosophy to understand why. + ;p + ;span: My self-selected bests posts can be found seen at this link: + ;a/"/blog?t=Top%20Post":"Top Posts" + == + ;p: Here are some of my core theses: + ;a/"/blog?t=WNANR" + ;h2: We Need a New Religion + == + ;p: Humans are social animals, and religions are the way that humans build social capital so that a culture can last and prosper. The present religions aren’t doing a very good job, so we should think about developing a new one. + ;a/"/2015/10/9/the-social-module" + ;h2: Status Points theory + == + ;p: Human minds do not have rational and irrational halves. Humans have evolved to care about social status, and all our behavior is designed to maximize it. Behavior which is often regarded as “irrational” should be understood as status-seeking behavior which happens to sacrifice other more immediate concerns. All people really care is about their position among their group of peers, their Dunbar circle. + ;a/"/blog?t=signaling" + ;h2: Signaling spirals + == + ;p: All religions and ideologies contain silly, even absurd ideas. These ideas impose some costs into society, but they are necessary in order to ensure the loyalty of all members of society. In good, stable times, there is a set amount of ideas one must believe, but in times of political instability, when loyalty and cohesion in the power structure is broken, new absurd ideas and practices start to appear at an increasingly fast pace, creating societal chaos and cultural destruction. + ;a/"/blog?t=men" + ;h2: Sex Wars are real and universal + == + ;p: Biology is quite simply a long history of conflict. Conflict is everywhere within and without species; entities grow different to compete better, or become more similar to prevail in conflict. Sexual species require some degree of cooperation to survive, but not a lot. The optimal mating strategy of the sexes is antagonistic, and there's no way around that. The smarter and wealtheir we get the worse the conflict will become. + ;a/"/blog?t=islam" + ;h2: Islam is Toxic Masculinity + == + ;p: Islam in its radical will continue to grow because it is good for men. Feminism lowers the incentive for men to raise families, hence the low birth rates all across the world. Islam allows men to dominate their women, which makes it easier for the average man to raise a family, hence the higher birth rates in Muslim countries. The shock that Muslim men feel on encountering Feminism in Europe is the biggest factor in driving Muslim men to Islamic terrorism. + ;a/"/2015/6/3/the-purpose-of-absurdity" + ;h2: Point deer, make horse + == + ;p: Any group, any political body requires the loyalty of its members in order to survive. It is not easy, though, to check people for their loyalty. Besides surveillance, a common method is to force people to make costly signals, i.e. make them do things that are hard for them, which lower their status. A common way of doing this is to force people to believe absurd things, which has been recorded in Chinese history more than 2,000 years ago. + ;a/"/2013/3/26/lee-kuan-yew-drains-your-brains-for-short-term-gain" + ;h2: IQ Shredders + == + ;p: High IQ people are driven to big cities, lured good education and employment opportunities. However once they get there, they are drawn to a rat-race of competition for jobs and for sexual opportunities. This, added to the complete emancipation of women, leads to the best human capital in the world delaying marriage and childbirth, which results in extremely low birth rates, in some places (e.g. Singapore) with TFR’s below 1. This results in the systematic destruction of the genetic material which produces high productivity in our modern economies. + ;a/"/blog?t=bioleninism" + ;h2: Biological Leninism (Bioleninism) + == + ;p: In order to sell a product, you make give something people want. In order to build a political movement, you must give people higher status than they presently have. The key innovation of industrial-era politics was Leninism, which built a movement with those who were socially deprived in traditional society due to their class; peasants, workers and foreigners, which were loyal to the Communist project in exchange for erasing the class and tribe distinctions of traditional society. In the post-industrial world, the mainstream political force, Progressivism, has build an effectively one-party regime by recruiting those who were lower status in both traditional and industrial society, ie. pre-1960 society due to their biological characteristics: unmarried women, homosexuals, people of different races. + ;p: Most of the theories above were developed not by myself alone, but are the result of many years through many years of debate and discussions with like-minded friends, discussions held in this blog and on other online and real venues. Some people call us reactionaries, others neoreactionaries, others #fullreactionaries. If you are more interested in these ideas you can reach me by email, interact with the community of commenters at this blog, or read other friendly sites, such as Social Matter, Thermidor, Outside in, Jim’s, or Mencius Moldbug’s. + ;p: My writing tends to have a focus on language, on using proper and accurate terms to name things, and how unclear language tends to have political intentions behind them. I also write often about international politics, which a focus on East Asia. China is growing to be a power which can rival the global hegemony of the United States. I believe that to be a good thing, but in opinion, informed by my knowledge of the people and my readings of its history, China is very different from Western powers, and has neither the interest nor the capability to run a global empire where it exports its culture and institutions. + ;p: I personally moderate the comments on the blog. I will delete Any uncivil comment, and ban reincident or hostile people. + ;p: I can be reached at site -at-spandrell●ch or on urbit as ~docteg-mothep + == +-- diff --git a/desk/web/assets/favicon.ico b/desk/web/assets/favicon.ico Binary files differnew file mode 100644 index 0000000..7bb609b --- /dev/null +++ b/desk/web/assets/favicon.ico diff --git a/desk/web/assets/fonts/arvo-bold-italic.ttf b/desk/web/assets/fonts/arvo-bold-italic.ttf Binary files differnew file mode 100644 index 0000000..b87118b --- /dev/null +++ b/desk/web/assets/fonts/arvo-bold-italic.ttf diff --git a/desk/web/assets/fonts/arvo-bold.ttf b/desk/web/assets/fonts/arvo-bold.ttf Binary files differnew file mode 100644 index 0000000..38341b1 --- /dev/null +++ b/desk/web/assets/fonts/arvo-bold.ttf diff --git a/desk/web/assets/fonts/arvo-italic.ttf b/desk/web/assets/fonts/arvo-italic.ttf Binary files differnew file mode 100644 index 0000000..1a19337 --- /dev/null +++ b/desk/web/assets/fonts/arvo-italic.ttf diff --git a/desk/web/assets/fonts/arvo-regular.ttf b/desk/web/assets/fonts/arvo-regular.ttf Binary files differnew file mode 100644 index 0000000..d8d0ec8 --- /dev/null +++ b/desk/web/assets/fonts/arvo-regular.ttf diff --git a/desk/web/assets/fonts/crimsontext-bold-italic.ttf b/desk/web/assets/fonts/crimsontext-bold-italic.ttf Binary files differnew file mode 100644 index 0000000..233e387 --- /dev/null +++ b/desk/web/assets/fonts/crimsontext-bold-italic.ttf diff --git a/desk/web/assets/fonts/crimsontext-bold.ttf b/desk/web/assets/fonts/crimsontext-bold.ttf Binary files differnew file mode 100644 index 0000000..327757c --- /dev/null +++ b/desk/web/assets/fonts/crimsontext-bold.ttf diff --git a/desk/web/assets/fonts/crimsontext-italic.ttf b/desk/web/assets/fonts/crimsontext-italic.ttf Binary files differnew file mode 100644 index 0000000..e8fe8b8 --- /dev/null +++ b/desk/web/assets/fonts/crimsontext-italic.ttf diff --git a/desk/web/assets/fonts/crimsontext-regular.ttf b/desk/web/assets/fonts/crimsontext-regular.ttf Binary files differnew file mode 100644 index 0000000..82dfeab --- /dev/null +++ b/desk/web/assets/fonts/crimsontext-regular.ttf diff --git a/desk/web/assets/fonts/crimsontext-semibold-italic.ttf b/desk/web/assets/fonts/crimsontext-semibold-italic.ttf Binary files differnew file mode 100644 index 0000000..66b129b --- /dev/null +++ b/desk/web/assets/fonts/crimsontext-semibold-italic.ttf diff --git a/desk/web/assets/fonts/crimsontext-semibold.ttf b/desk/web/assets/fonts/crimsontext-semibold.ttf Binary files differnew file mode 100644 index 0000000..19c4c4c --- /dev/null +++ b/desk/web/assets/fonts/crimsontext-semibold.ttf diff --git a/desk/web/assets/fonts/lol.ico b/desk/web/assets/fonts/lol.ico new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/desk/web/assets/fonts/lol.ico diff --git a/desk/web/assets/search.svg b/desk/web/assets/search.svg new file mode 100644 index 0000000..5d48d1b --- /dev/null +++ b/desk/web/assets/search.svg @@ -0,0 +1,13 @@ +<svg version="1.1" id="_x32_" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 512 512" style="width: 256px; height: 256px; opacity: 1;" xml:space="preserve"> +<style type="text/css"> + .st0{fill:#4B4B4B;} +</style> +<g> + <path class="st0" d="M495.272,423.558c0,0-68.542-59.952-84.937-76.328c-24.063-23.938-33.69-35.466-25.195-54.931 + c37.155-75.78,24.303-169.854-38.72-232.858c-79.235-79.254-207.739-79.254-286.984,0c-79.245,79.264-79.245,207.729,0,287.003 + c62.985,62.985,157.088,75.837,232.839,38.691c19.466-8.485,31.022,1.142,54.951,25.215c16.384,16.385,76.308,84.937,76.308,84.937 + c31.089,31.071,55.009,11.95,69.368-2.39C507.232,478.547,526.362,454.638,495.272,423.558z M286.017,286.012 + c-45.9,45.871-120.288,45.871-166.169,0c-45.88-45.871-45.88-120.278,0-166.149c45.881-45.871,120.269-45.871,166.169,0 + C331.898,165.734,331.898,240.141,286.017,286.012z" style="fill: rgb(75, 75, 75);"></path> +</g> +</svg>
\ No newline at end of file diff --git a/desk/web/assets/spinner.svg b/desk/web/assets/spinner.svg new file mode 100644 index 0000000..a6763ca --- /dev/null +++ b/desk/web/assets/spinner.svg @@ -0,0 +1 @@ +<svg width="24" height="24" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><style>.spinner_0XTQ{transform-origin:center;animation:spinner_y6GP .75s linear infinite}@keyframes spinner_y6GP{100%{transform:rotate(360deg)}}</style><path class="spinner_0XTQ" d="M12,23a9.63,9.63,0,0,1-8-9.5,9.51,9.51,0,0,1,6.79-9.1A1.66,1.66,0,0,0,12,2.81h0a1.67,1.67,0,0,0-1.94-1.64A11,11,0,0,0,12,23Z"/></svg>
\ No newline at end of file diff --git a/desk/web/blog/post-header.hoon b/desk/web/blog/post-header.hoon new file mode 100644 index 0000000..3bee975 --- /dev/null +++ b/desk/web/blog/post-header.hoon @@ -0,0 +1,118 @@ +/- tp=trill-post +/+ sr=sortug, lib=boke, wall +=< html +|% +++ css ^~ %- trip +''' + #post-header{ + -webkit-locale: "en"; + text-size-adjust: 100%; + color: rgb(0, 0, 0); + font-size: 16px; + font-weight: 400; + text-rendering: optimizelegibility; + -webkit-font-smoothing: antialiased; + line-height: 1.618; + text-shadow: rgb(0, 0, 0) 0px 0px 0px; + align-items: center; + border-bottom-color: rgb(223, 223, 223); + border-bottom-style: dotted; + border-bottom-width: 1px; + box-sizing: border-box; + margin-left: 0px; + margin-right: 0px; + padding-bottom: 30px; + padding-left: 32px; + padding-right: 32px; + padding-top: 30px; + text-align: center; + + & h2{ + font-size: 2.1rem; + text-transform: uppercase; + } + + & #post-meta, .comment-meta, .entry-footer { + font-size: 90%; + font-style: italic; + color: #969696; + } + @media (min-width: 768px){ + & .col-md-4 { + -ms-flex: 0 0 33.333333%; + flex: 0 0 33.333333%; + max-width: 33.333333%; + } + } + & .breadcrumbs { + list-style: none; + display: inline-block; + margin: 0; + padding: 0; + border: none; + background: transparent; + text-indent: 0; + + } + & .breadcrumbs li { + display: inline-block; + margin: 0 0.3rem; + padding: 0; + border: none; + background: transparent; + text-indent: 0; + } + & .tags{ + display: block; + text-transform: capitalize; + } + + } +''' +++ html +|= [t=thread:tp who=@p] ^- manx +=/ url (trip (spat path.t)) :: TODO check for relative/absolute path +=/ date (date-to-tape:string:sr id.pid.t "-") + +=+ [[a y] m [d h mm s f]]=(yore id.pid.t) +=/ ys %- trip (ud-to-cord:string:sr y) +=/ ming (get-name:lib ship.pid.t) +=/ nam + ?. .=(ship.pid.t ~docteg-mothep) ming + "Spandrell" :: TODO should use the user component here + +=/ ttags (tags:wall ~(tap in tags.t)) +:: +;div#post-header + ;style:"{css}" + ;h2:"{(trip title.t)}" + ;div#post-meta + ;span + ; Posted by {nam} on + ;ul.breadcrumbs + ;li + ;a/"/{ys}":"{ys}" + == + ; / + ;li + ;a/"/{ys}/{<m.m>}":"{<m.m>}" + == + ; / + ;li + ;a/"/{ys}/{<m.m>}/{<d.d>}":"{<d.d>}" + == + == + == + ;+ ?: .=(0 (lent ttags)) ;span:"" + ;div.tags + ;* %+ mapi:sr ttags + |= [i=@ t=@t] ^- manx + =/ tt (trip t) + =/ path "/blog?t={tt}" + =/ show + ?. .=(i (dec (lent ttags))) "{tt}, " tt + ;a/"{path}":"{show}" + == + == +== +-- diff --git a/desk/web/blog/post-list.hoon b/desk/web/blog/post-list.hoon new file mode 100644 index 0000000..35a3590 --- /dev/null +++ b/desk/web/blog/post-list.hoon @@ -0,0 +1,159 @@ +/- tp=trill-post +/+ sr=sortug, plib=trill-utils, lib=boke, kaji +/= content /web/components/post-text +|% +++ abbreviated-post +|= [cm=content-map:tp button=manx] ^- (list manx) + =/ abbreviated (abbreviate-post:plib cm 1.000) + =/ blocks (latest-contents:plib cm) + ?: .=(blocks abbreviated) %+ turn blocks block:content + %+ snoc (turn abbreviated block:content) button + +++ post-snippet +|= t=thread:tp ^- manx + =/ url (trip (spat path.t)) :: TODO check for relative/absolute path + =+ [[a y] m [d h mm s f]]=(yore id.pid.t) + =/ ys %- trip (ud-to-cord:string:sr y) + :: =/ author (scot %p p.author.p) + =/ count (lent replies.t) + =/ comment-count ?: .=(count 0) "No" "{<count>}" + :: + =/ continue-button + ;div.continue-button-wrapper + ;a.continue-button/"{url}":"Continue" + == + =/ comment-div + ;span + ;a/"{url}#comments":"{comment-count} comments" + == + =/ tag-links + %+ mapi:sr ~(tap in tags.t) + |= [i=@ tg=@t] ^- manx + =/ tt (trip tg) + =/ path "/blog?t={tt}" + =/ show ?: .=(i (dec ~(wyt in tags.t))) tt "{tt}, " + ;a/"{path}":"{show}" + +:: +;article + ;header + ;h2 + ;a/"{url}":"{(trip title.t)}" + == + == + ;main + ;* %+ turn snip.t block:content + ;+ continue-button + == + ;div.post-metadata + ;span + ; Posted on + ;a/"{ys}":"{ys}" + ;a/"{ys}/{<m.m>}":"/{<m.m>}" + ;a/"{ys}/{<m.m>}/{<d.d>}":"/{<d.d>}" + == + :: ;span + :: ; by + :: ;a/"by/{author}":"{author}" + :: == + == + ;+ ?: .=(0 ~(wyt in tags.t)) ;footer ;+ comment-div == + ;footer + ; Tagged as + ;span.tags-links + ;* tag-links + == + ;+ comment-div + == +== +++ css ^~ %- trip +''' +#post-list{ + :: top: 0; + margin: auto; + + & article{ + margin: 0 0 1.5em; + margin-top: 40px; + border-bottom: 1px dotted #dfdfdf; + padding: 0 2rem; + padding-bottom: 40px; + + & header h2{ + font-size: 1.8rem; + text-align: center; + letter-spacing: 1px; + text-transform: uppercase; + line-height: 1.4em; + font-weight: 500; + } + & .post-metadata, article footer{ + font-size: 90%; + font-style: italic; + color: #969696; + } + + & main{ + margin: 1.5em 0 0; + } + } + & .tags-links{ + text-transform: capitalize; + margin-right: 1ch; + } + + & .continue-button-wrapper{ + margin-top: 1.5rem; + margin-bottom: 1.5rem; + } + & .continue-button{ + font-family: 'Montserrat', sans-serif; + text-transform: uppercase; + letter-spacing: 1px; + font-size: 13px; + -webkit-transition: all .4s ease; + -o-transition: all .4s ease; + transition: all .4s ease; + padding: 0.5rem, 0rem, 0.5rem, 1.25rem; + line-height: 1.5; + border-radius: 0.2rem; + } + & .cursor{ + text-align: center; + margin: 1rem; + } +} +@media (max-width: 800px){ + #post-list{ + & article{ + padding: 0; + line-height: 1.7rem; + } + } +} + + +''' +++ test +|= [p=post:tp children=full-graph:tp] ^- manx +=/ pid [author.p id.p] +=/ pat /blog/snip/(scot %uw (jam pid)) +(fetch:kaji pat) +++ cursor +|= [cursor=(unit @da) label=tape] +?~ cursor ;div; +=/ path "/blog/f?cursor={(scow:parsing:sr %uw u.cursor)}" +;div.cursor(kaji "iscroll", path path, cont "#post-list", where "bottom") + ;button:"{label} posts" +== +++ html +|= [p=tpage:tp =marl] +^- manx +;div#post-list.blog + ;style:"{css}" + ;* marl + :: ;+ (cursor newer.p "Newer") + ;* (turn p.p post-snippet) + ;+ (cursor older.p "Older") +== +-- diff --git a/desk/web/blog/post.hoon b/desk/web/blog/post.hoon new file mode 100644 index 0000000..0366fc9 --- /dev/null +++ b/desk/web/blog/post.hoon @@ -0,0 +1,344 @@ +/- tp=trill-post +/+ plib=trill-utils, sr=sortug, kaji, lib=boke, const=constants +/= post-text /web/components/post-text +/= post-header /web/blog/post-header +|_ [[t=thread:tp =post:tp children=full-graph:tp] =bowl:gall is-mobile=?] +++ css ^~ %- trip +''' +#post-text{ + -webkit-locale: "en"; + text-size-adjust: 100%; + color: rgb(0, 0, 0); + line-height: 1.618; + text-shadow: rgb(0, 0, 0) 0px 0px 0px; + border-bottom-color: rgb(223, 223, 223); + border-bottom-style: dotted; + border-bottom-width: 1px; + box-sizing: border-box; + display: block; + margin-bottom: 24px; + margin-left: 0px; + margin-right: 0px; + margin-top: 0px; + padding-bottom: 40px; + padding-left: 32px; + padding-right: 32px; + padding-top: 4px; +} +@media (max-width: 800px){ + #post-text{ + padding: 0; + line-height: 1.2; + } +} +#comments{ + -webkit-locale: "en"; + text-size-adjust: 100%; + color: rgb(0, 0, 0); + line-height: 1.618; + text-align: left; + text-shadow: rgb(0, 0, 0) 0px 0px 0px; + box-sizing: border-box; + display: block; + margin-bottom: 32px; + padding-bottom: 0px; + padding-left: 16px; + padding-right: 16px; + padding-top: 0px; +} +#comments h3{ + -webkit-locale: "en"; + text-size-adjust: 100%; + color: rgb(0, 0, 0); + text-align: left; + text-shadow: rgb(0, 0, 0) 0px 0px 0px; + font-size: 18.72px; + font-weight: 400; + box-sizing: border-box; + display: block; + line-height: 1.2; + margin-block-end: 9.36px; + margin-block-start: 9.36px; + margin-bottom: 9.36px; + margin-inline-end: 0px; + margin-inline-start: 0px; + margin-left: 0px; + margin-right: 0px; + margin-top: 9.36px; +} +.comment-list{ + -webkit-locale: "en"; + text-size-adjust: 100%; + color: rgb(0, 0, 0); + line-height: 1.618; + text-align: left; + text-shadow: rgb(0, 0, 0) 0px 0px 0px; + box-sizing: border-box; + display: block; + list-style-image: none; + list-style-position: outside; + list-style-type: none; + margin-block-end: 24px; + margin-block-start: 0px; + margin-bottom: 24px; + margin-inline-end: 0px; + margin-inline-start: 0px; + margin-left: 0px; + margin-right: 0px; + margin-top: 0px; + padding-inline-start: 0px; + padding-left: 0px; +} +.comment-list li{ + position: relative; + -webkit-locale: "en"; + text-size-adjust: 100%; + color: rgb(0, 0, 0); + line-height: 1.618; + text-shadow: rgb(0, 0, 0) 0px 0px 0px; + list-style-image: none; + list-style-position: outside; + list-style-type: none; + border-left-color: rgb(223, 223, 223); + border-left-style: solid; + border-left-width: 1px; + box-sizing: border-box; + display: list-item; + padding-bottom: 16px; + padding-left: 10px; + padding-right: 0px; + padding-top: 16px; + text-align: left; +} +.comment-author{ + font-weight: 700; + color: var(--text); + font-style: normal; + font-size: 1rem; + margin-right: 1rem; +} +.comment-content{ + font-size: 90%; +} +#reply-title{ + display: inline; +} +.reply-prompt{ + color: var(--hong); + font-size: 0.9rem; +} +.nested{ + padding-left: 1rem; +} +#reply-box{ + & textarea{ + width: 100%; + } + .author-data{ + display: flex; + justify-content: space-between; + + & .name{ + margin-left: 1rem; + } + } +} +/* desktop */ +@media (min-width: 800px){ + #reply-box{ + width: 40%; + } +} +/* mobile */ +@media (max-width: 800px){ + #reply-box{ + width: 100%; + } +} +.collapse-button, .uncollapse-button{ + width: 15px; + position: absolute; + left: -10px; + top: 21px; +} +''' +++ script ^~ %- trip +''' +function scanTweets(){ + const nodes = document.querySelectorAll(".parsed-twatter"); + for (let n of nodes){ + const status = n.getAttribute("status"); + twttr.widgets.createTweet(status, n.parentElement, { + conversation: true + }) + } +} +window.addEventListener('load', () => { + scanTweets(); +}) +''' +++ post-content +^- manx +;div#post-text + ;style:"{css}" + ;* (content:post-text contents.post) +== +++ comments +=/ =pid:tp [author.post id.post] +=/ board-path (trip (spat (board-path:lib t))) +=/ l (lent replies.t) +=/ length ?: .=(0 l) "No" "{<l>}" +=/ js "$store.replying_to.show('main')" +^- manx +;div#comments + ;a/"{board-path}":"Switch to Board View" + ;h3:"{length} comments" + ;div#big-reply + ;span.fl + =kaji "scry" + =path "/blog/f/reply/{(enc:kaji [pid pid])}" + =swap "add" + =cont "#big-reply" + ; Leave a reply + == + == + ;+ comment-list +== +++ comment-list ^- manx +=/ cs (tap:form:tp children) +;div#comments-wrapper + ;ul#comments-top.comment-list + =id "children{(scow %ud id.post)}" + ;* (turn (flop cs) comment) + == +== + +++ comment +=| nested=@ud +|= [=pid:tp [p=post:tp c=full-graph:tp]] +^- manx +=/ author (get-name:lib -.pid) +=/ full-time (datetime-to-tape:string:sr id.pid "/") +=/ time ?. is-mobile full-time + (post-date-ago:lib id.pid now.bowl %tam) + +=/ id=tape (enc:kaji pid) +=/ js=tape "$store.replying_to.show('{id}')" +=/ post-meta (enc:kaji [[author.post id.post] pid]) +=/ permalink "" +;li + =id "comment-{id}" + ;img.collapse-button + =src "https://s3.spandrell.ch/assets/board/ui/collapse.svg" + =kaji "toggle" + =targ ".comment-proper/.uncollapse-button/.collapse-button" + ; + == + ;img.uncollapse-button + =src "https://s3.spandrell.ch/assets/board/ui/uncollapse.svg" + =kaji "toggle" + =targ ".comment-proper/.uncollapse-button/.collapse-button" + =hidden "" + ; + == + ;div.comment + ;div.comment-meta + ;div.row + ;a.comment-author/"/u/{author}":"{author}" + ; | + ;a.comment-time + =title "{time}" + =href permalink + ; {time} + == + ;* ?. (is-admin:lib src.bowl) ~ + ;= ;span:"|" + ;a + =kaji "poke" + =action "del-comment" + =name "pid" + =payload id + ; Nuke + == + == + == + == + ;div.comment-proper + ;div.comment-content + ;* (content:post-text contents.p) + == + ;span.fl.reply-prompt + =id id + =kaji "scry" + =path "/blog/f/reply/{post-meta}" + =swap "swap" + =targ ".reply-box" + ; reply + == + ;div.reply-box; + ;+ (grandchildren [p c] +(nested)) + == + == +== +++ shit +=| nested=@ud +|= a=@ud %lol + +++ grandchildren +|= [p=full-node:tp nested=@ud] ^- manx +=/ cs (tap:form:tp children.p) +=/ c (houyi:plib children.p) +=/ count (scow:parsing:sr %ud c) + +?: ?& (gth (lent cs) 0) (gth nested 5) is-mobile == + =/ pids [[author.post id.post] [author.p.p id.p.p]] + =/ path "/blog/f/subthread/{(enc:kaji pids)}" + ;a + =kaji "scry" + =path path + =swap "swap" + =targ "#comments-wrapper" + ; Show {count} more comments + == +=/ id=tape (enc:kaji [author.p.p id.p.p]) +=/ newcomms comment :: need to tisfas it to be able to manipulate the optional variable + :: I don't get it +;ul.comment-list.nested + =id "children-{id}" + ;* (turn (flop cs) newcomms(nested nested)) +== +++ comment-subthread +|= fn=full-node:tp +=/ cs (tap:form:tp children.fn) +=/ ocs (tap:form:tp children) +=/ c (houyi:plib children.fn) +=/ oc (houyi:plib children) +=/ count (scow:parsing:sr %ud c) +=/ total (scow:parsing:sr %ud oc) +=/ =pid:tp [author.post id.post] +;div#subthread + ;div + ;p:"Showing {count} comments of {total}" + ;a + =kaji "scry" + =path "/blog/f/comments/{(enc:kaji pid)}" + =swap "swap" + =targ "#comments-wrapper" + ; Go back to top + == + == + ;div#comments-top.comment-list + =id "children{(scow %ud id.post)}" + ;* (turn (flop cs) comment) + == +== + + +++ html ^- manx + ;div.blog + ;+ (post-header t src.bowl) + ;+ post-content + ;+ comments + ;script:"{script}" + == +-- diff --git a/desk/web/blog/router.hoon b/desk/web/blog/router.hoon new file mode 100644 index 0000000..32a96c9 --- /dev/null +++ b/desk/web/blog/router.hoon @@ -0,0 +1,198 @@ +/- boke, cnt=contact, tp=trill-post +/+ kaji, fetch-lib=fetch, plib=trill-utils, const=constants, sr=sortug, lib=boke, ui=trill-ui +/= index /web/index +/= post-list /web/blog/post-list +/= post-show /web/blog/post +/= title /web/blog/title +/= user /web/components/user + +|_ [rl=req-line:kaji s=state:boke =bowl:gall] ++* fetch ~(. fetch-lib [s bowl]) + +++ eyre-bail (error-response:kaji 404) +++ manx-bail (error-page:kaji 404) +:: +++ $ ^- eyre-res:kaji + =/ p pat.rl ::?. mob.rl pat.rl [%m pat.rl] + ?+ p ~& >>> path-not-found=`path`p eyre-bail + ~ (serve-page par.rl) + [%snip pid=@ ~] (post-snippet pid.p) + :: + [%f rest=*] (fragment rest.p) + [%b rest=*] (threads rest.p) + == +++ serve-index + :- %page +:: =/ paginated (get-tag-page:plib feed.s tags.s ~['blog'] [~ ~ page-size]) + =/ paginated (thread-page-by-tags:fetch ~['blog'] [~ ~ blog-page-size:const] ~) + :: =/ paginated ~> %bout (get-tag-page:plib feed.s tags.s ~['blog'] [~ ~ page-size]) + =/ main=manx (html:post-list paginated ~) + (index ~[title main] bowl) + +++ serve-page +|= params=(map @t @t) + :- %page ^- manx + =/ tags + =/ ptags (~(get by params) 't') + ?~ ptags ~['blog'] + =/ parsed (parse-tags:ui u.ptags) + ?~ parsed ~['blog'] :: TODO some error here + ~(tap in u.parsed) + =/ older + =/ pcursor (~(get by params) 'cursor') ?~ pcursor ~ + (slaw:parsing:sr %uw u.pcursor) + =/ req [~ older blog-page-size:const] + =/ paginated (thread-page-by-tags:fetch tags req ~) + =/ tag-title + =/ ptags (~(get by params) 't') + ?~ ptags ~ + ;+ ;h3.tag-title:"Posts tagged as {(trip u.ptags)}" + =/ main=manx (html:post-list paginated tag-title) + (index ~[title main] bowl) + + + + + +++ show + :- %page + =/ dat (op-by-path:fetch pat.rl) + ?~ dat manx-bail + =/ main=manx + ~(html post-show [u.dat bowl mob.rl]) + (index ~[main] bowl) + +++ threads +|= p=(pole knot) + :- %page + =/ dat (op-by-path:fetch p) + ?~ dat manx-bail + =/ main=manx + ~(html post-show [u.dat bowl mob.rl]) + (index ~[main] bowl) +:: don't think we're using this now +++ post-snippet + |= [ss=@] + :- %html + =/ pid (dec:kaji ss pid:tp) + ?~ pid manx-bail + :: =/ post (get:gorm:tp feed.s u.pid) + =/ thread (get:torm:tp threads.s u.pid) + ?~ thread manx-bail + :: =/ fn (node-to-full:plib u.post feed.s) + (post-snippet:post-list u.thread) + + + + + + :: ?+ pat bail + :: [type=@t name=@t cursor=@t ~] + :: :: TODO %feed type at some point? + :: =/ older (slaw:parsing:sr %uw cursor.pat) ?~ older inline-error + :: ?. ?=(?(%b %t) type.pat) inline-error + :: ?: ?=(%b type.pat) + :: =/ page (board-to-page:lib name.pat tags.s feed.s [~ older board-page-size:cns]) + :: ?~ page inline-error + :: (serve-post-page name.pat u.page .n) + :: :: single tag + :: =/ page (tag-to-page:lib name.pat tags.s feed.s [~ older board-page-size:cns]) ?~ page inline-error + :: (serve-post-page name.pat u.page .y) + :: == + :: ++ serve-post-page + :: |= [name=@t =page:tp is-tag=?] + :: ~& >> serving-page=+.page + :: =/ previews ?: ?=(%blog name) + :: (turn p.page post-snippet:post-list) + :: :: + :: =/ contacts (get-contacts:cnt bowl) + :: %+ turn p.page |= fn=full-node:tp (thread-preview fn contacts bowl) + :: ;div + :: ;* %+ snoc previews + :: (cursor:cm older.page "Older" name is-tag) + :: == + ++ fragment + |= p=(pole knot) + :- %html + ?+ p manx-bail + ~ blog-page + [%comments uid=@t ~] (blog-comments uid.p) + [%subthread uid=@t ~] (subthread uid.p) + [%reply uid=@t ~] (reply-box uid.p) + == + ++ blog-page + =/ params=(map @t @t) par.rl + =/ tags + =/ ptags (~(get by params) 't') + ?~ ptags ~['blog'] + =/ parsed (parse-tags:ui u.ptags) + ?~ parsed ~['blog'] ~(tap in u.parsed) + =/ older + =/ pcursor (~(get by params) 'cursor') ?~ pcursor ~ + (slaw:parsing:sr %uw u.pcursor) + =/ req=page-req:tp [~ older blog-page-size:const] + :: =/ paginated (get-tag-page-2:plib feed.s tags.s tags req) + =/ paginated (thread-page-by-tags:fetch tags req ~) + (html:post-list paginated ~) +++ blog-comments +|= hash=@t + =/ op (op-by-hash:fetch hash) + ?~ op manx-bail + ~(comment-list post-show [u.op bowl mob.rl]) + +++ subthread +|= hash=@t + =/ both (dec:kaji hash ,[op=pid:tp sub=pid:tp]) + ?~ both manx-bail + =/ op (op-by-pid:fetch op.u.both) + ?~ op manx-bail + =/ sub-op (fn-by-pid:fetch sub.u.both) + ?~ sub-op manx-bail + =/ core ~(. post-show [u.op bowl mob.rl]) + + (comment-subthread:core u.sub-op) + +++ reply-box +|= hash=@t +?: .=(%pawn (clan:^title src.bowl)) +;div#reply-box + ;p:"You must login with an Urbit ID to comment" +== +=/ usr (user src.bowl *whoms:cnt 30) :: TODO + ;div + ;div#reply-box + ;span + =id "cancel-reply" + =class "fl" + =kaji "destroy" + =targ "#reply-box" + ; Cancel reply + == + ;form#reply-form + =kaji "poke" + =action "add-reply" + ;textarea#comment + =name "text" + =cols "45" + =rows "8" + =maxlength "6552" + =autocomplete "off" + ; + == + ;div.author-data + ;div.as.flex + ;span:"Posting as " + ;div.flex.ml1 + ;+ avatar.usr + ;+ name.usr + == + == + ;input#submit-comment(type "submit", value "Poast"); + == + ;input(type "hidden", name "parents", value (trip hash)); + ;input(type "hidden", name "is-blog", value ".y"); + ;span#error-div; + == + == + == +-- diff --git a/desk/web/blog/title.hoon b/desk/web/blog/title.hoon new file mode 100644 index 0000000..7675165 --- /dev/null +++ b/desk/web/blog/title.hoon @@ -0,0 +1,11 @@ +=< html +|% +++ html ^- manx + ;header + ;h1 + ;a/"/":"Bloody Shovel 4" + == + ;h4:"Nemo nos Salvabit" + :: ;h4:"不當而當亂也" + == +--
\ No newline at end of file diff --git a/desk/web/board/index.hoon b/desk/web/board/index.hoon new file mode 100644 index 0000000..f70eb03 --- /dev/null +++ b/desk/web/board/index.hoon @@ -0,0 +1,456 @@ +/- boke, tp=trill-post, cnt=contact +/+ sr=sortug, plib=trill-utils, sigil=sigil-sigil, lib=boke, kaji, const=constants, fetch-lib=fetch +/= thread-preview /web/components/thread-preview +|_ [s=state:boke =bowl:gall is-mobile=?] ++* fetch ~(. fetch-lib [s bowl]) +++ show-css ^~ %- trip +''' +.thread-preview{ + display: flex; + gap: 0.5rem; + align-items: center; + border-bottom: 1px solid var(--text-color); + margin: auto; + padding: 0.4rem; + color: var(--text-color); + + & .thread-author{ + width: 10%; + & img, & svg { + width: 40px; + } + } + + & .thread-name{ + width: 60%; + + & h2{ + margin: 0; + color: var(--text-color); + } + + & .thread-tags{ + display: flex; + gap: 0.3rem; + & .tag{ + padding: 0.2rem; + background-color: var(--huang); + opacity: 0.9; + font-size: 0.7rem; + cursor: pointer; + border-radius: 0.7rem; + } + } + } + + & .reply-count{ + width: 10%; + } + & .dates{ + width: 20%; + text-align: right; + padding-right: 0.5rem; + & .last-reply-author{ + display: flex; + gap: 1ch; + margin-left: auto; + width: fit-content; + } + } + + &. reply-count{ + font-size: 0.9rem; + } +} +@media (max-width: 768px){ + .thread-preview{ + & .meta{ + justify-content: space-between; + } + & img, & svg{ + display: none!important; + } + } +} +''' +++ css ^~ %- trip +''' +body > main{ + width: unset!important; +} +.tab:hover{ + font-weight: 700; +} +.tab.active{ + font-weight: 700; +} +#board-index{ + width: 16%; + padding: 0 0.5rem; + border-right: 1px solid grey; + + & header{ + display: flex; + height: 60px; + + & #select{ + color: var(--hong); + } + & img{ + width: 30px; + } + } +} +#board-list{ + padding: 0.5rem; + height: calc(100% - 4rem); + & .entry.active{ + border: 1px solid black; /* TODO */ + } + & .entry{ + cursor: pointer; + display: flex; + align-items: center; + margin-bottom: 0.5rem; + & img{ + width: 30px; + margin-right: 10px; + } + & h3{ + font-size: 30px; + margin: 0 10px 0 0; + } + & h4{ + margin: 0; + } + } + & .entry:hover{ + background-color: rgb(100, 100, 100, 0.3); + } +} +.tabs{ + align-items: center; + justify-content: space-evenly; + width: 100%; +} +#board-proper{ + width: 84%; /* TODO third column?*/ + + & .title{ + padding: 1rem 2rem; + height: 60px; + border-bottom: 1px solid var(--text-color); + display: flex; + justify-content: space-between; + + & h2{ + text-transform: uppercase; + width: 30%; + margin: 0; + } + } + & #thread-list{ + height: calc(100% - 60px); + overflow-y: scroll; + } + #sorting{ + display: flex; + justify-content: space-evenly; + gap: 1rem; + align-items: center; + border-bottom: 1px solid var(--text-color); + + & .sort-cat{ + display: flex; + align-items: center; + cursor: pointer; + } + } +} + +@media (max-width: 768px){ + #board-main{ + display: block; + & #board-index{ + width: 100%; + } + & #board-proper{ + display: none; + } + } +} +''' +++ mobile-css ^~ %- trip +''' +@media (max-width: 800px){ + #board-proper{ + & .title{ + padding: 0.5rem; + border-bottom: 1px solid var(--text-color); + & input{ + width: 30%; + line-height: 2rem; + } + } + & #thread-list{ + padding: 1rem; + + & .thread-preview{ + color: var(--text-color); + & h2{ + margin-bottom: 0.2rem; + } + & .thread-inner{ + border-bottom: 1px solid black; + margin-bottom: 0.5rem; + } + & .meta{ + opacity: 0.7; + display: flex; + align-items: center; + justify-content: space-between; + } + } + } + } +} +.by-author{ + display: flex; + gap: 1ch; +} + +#tag-search{ + margin-bottom: 1rem; +} +''' +++ big-button-css ^~ %- trip +''' +.big-button{ + display: flex; + background-color: var(--hong); + margin: auto; + position: fixed; + bottom: 50px; + left: 50%; + transform: translateX(-50%); + & svg{ + width: 20px; + } +} +''' +++ big-button +;a.button.big-button/"/board/n" + ;style:"{big-button-css}" + ;svg + =viewBox "0 0 20 20" + =enable-background "new 0 0 20 20" + ;path + =fill "#FFFFFF" + =d "M17.561,2.439c-1.442-1.443-2.525-1.227-2.525-1.227L8.984,7.264L2.21,14.037L1.2,18.799l4.763-1.01l6.774-6.771l6.052-6.052C18.788,4.966,19.005,3.883,17.561,2.439z M5.68,17.217l-1.624,0.35c-0.156-0.293-0.345-0.586-0.69-0.932c-0.346-0.346-0.639-0.533-0.932-0.691l0.35-1.623l0.47-0.469c0,0,0.883,0.018,1.881,1.016c0.997,0.996,1.016,1.881,1.016,1.881L5.68,17.217z" + ; + == + ; + == + ;span:"New Thread" +== + +++ recent-post +|= [* =post:tp] +:: =/ snippet (abbreviate-post:plib contents.post 100) +=/ tags=marl %^ foldi:sr ~(tap in tags.post) `marl`~ |= [i=@ud tag=@t acc=marl] +?: (gth i 3) acc +:_ acc +=/ tt (trip tag) +;a@"/boards/tag/{tt}":"{tt}" + +;div.recent-post + ;div.author:"{(scow %p author.post)}" + ;div.tags + ;* tags + == +== +++ main +|= post-list=manx +^- manx +;div#board-main.flex.fh +;style: {css} +;style:"{show-css}" + ;div#board-index.fh + ;header + ;div.tabs :: Boards/tags/latest + ;div.tab.active + =kaji "scry" + =path "/board/f/boards" + =swap "swap" + =targ "#board-list" + ; Boards + == + ;div.tab + =kaji "scry" + =path "/board/f/tags" + =swap "swap" + =targ "#board-list" + ; Tags + == + == + == + ;div#board-list.fsy + ;* category-list + == + == + ;+ post-list +== +++ category-list ^- marl + :- ;div.entry + =kaji "scry" + =swap "swap" + =path "/board/f/page/l/l/0" + =targ "#board-proper" + :: ;img@"https://s3.spandrell.ch/assets/board/boards/{name}.svg"; + ;h3: 全 + ;h4: All + == + ;* %+ turn ~(tap by categories:const) |= [p=@tas *] + =/ name (trip p) + ;div.entry + =kaji "scry" + =swap "swap" + =path "/board/f/page/b/{name}/0" + =targ "#board-proper" + ;img@"https://s3.spandrell.ch/assets/board/boards/{name}.svg"; + ;h4: {name} + == +++ make-tag-list + |= l=(list [@t @ud]) ^- marl + ;= ;+ tag-search-input + ;+ ?~ l + ;span:"No tags found" + ;div#board-list-inner.tags + ;* %+ turn l tag-preview + == + == +++ tag-search-input +;div#tag-search + ;input(type "text", name "query", placeholder "Search tag") + =kaji "search" + =bounce "1000" + =path "/board/f/tag-search" + =swap "swap" + =targ "#board-list-inner" + ; + == +== +++ tag-preview + |= [t=@t c=@ud] ^- manx + =/ name (trip t) + =/ count (scow:parsing:sr %ud c) + ?. is-mobile + ;div.entry + =kaji "scry" + =swap "swap" + =path "/board/f/page/t/{name}/0" + =targ "#board-proper" + ;h4:"{name} ({count})" + == + ;a.entry/"/board/t/{name}" + ;h4:"{name} ({count})" + == + +++ cursor +|= [cursor=(unit @da) label=tape =rq search=(unit @t)] ^- manx +?~ cursor ;div; +=/ type + ?- -.rq + %latest "l/l" + %board "b/{(trip name.rq)}" + %tag "t/{(trip name.rq)}" + == +=/ path ?~ search +"/board/f/page/{type}/{(scow:parsing:sr %uw u.cursor)}" +"/board/f/search/{type}/{(scow:parsing:sr %uw u.cursor)}?query={(trip u.search)}" + +;div.cursor(kaji "iscroll", path path, cont "#thread-list", where "bottom") + ;button:"{label} posts" +== ++$ rq $%([%latest ~] [%board name=@t] [%tag name=@t]) +++ post-index +|= [=tpage:tp =rq contacts=whoms:cnt search=(unit @t) is-mobile=?] ^- manx +~& > cursors=[newer.tpage older.tpage] +=/ title ?- -.rq + %latest "Latest posts" + %board (trip +.rq) + %tag "Tag: {(trip +.rq)}" == +:: =/ cursor-string ?~ older.page "0" (scow:parsing:sr %uw u.older.page) +=/ cursor-string "" +~& page-req=+.page +:: =/ order "Post date" :: || "Reply date" +=/ flop-path "/board/f/flop/" +=/ search-path ?- -.rq + %latest "/board/f/search/l/l/{cursor-string}" + %board "/board/f/search/b/{(trip +.rq)}/{cursor-string}" + %tag "/board/f/search/t/{(trip +.rq)}/{cursor-string}" == +=/ sort-path ?- -.rq + %latest "/board/f/page/h/l/l/0" + %board "/board/f/page/b/{(trip +.rq)}/0" + %tag "/board/f/page/t/{(trip +.rq)}/0" == + +;div#board-proper.fh + ;style: {mobile-css} + ;div.title.f1 + :: ;button + :: =kaji "scry" + :: path flop-path + :: ; Flop + :: == + ;h2:"{title}" + ;input(type "text") + =placeholder "Search threads" + =kaji "search" + =name "query" + =bounce "1000" + =path search-path + =swap "swap" + =targ "#thread-list" + ; + == + == + :: ;div#sorting + :: =kaji "scry" + :: =swap "swap" + :: =targ "thread-list" + + :: ;div.sort-cat + :: ;span:"Title" + :: ;span(path "{sort-path}?sort=title&dir=asc"):"⇑" + :: ;span(path "{sort-path}?sort=title&dir=desc"):"⇓" + :: == + :: ;div.sort-cat + :: ;span:"Author" + :: == + :: ;div.sort-cat + :: ;span:"Posted" + :: == + :: ;div.sort-cat + :: ;span:"Last Reply" + :: == + :: ;div.sort-cat + :: ;span:"Reply Count" + :: == + :: == + ;div#thread-list + ;* %+ turn p.tpage |= t=thread:tp + =/ preview ~(. thread-preview [t contacts bowl]) + ?: is-mobile mobile:preview wide:preview + ;+ (cursor older.tpage "Older" rq search) + == + ;+ big-button +== +++ previews +|= [=tpage:tp =rq contacts=whoms:cnt search=(unit @t) is-mobile=?] ^- manx +;div + ;* %+ turn p.tpage |= t=thread:tp + =/ preview ~(. thread-preview [t contacts bowl]) + ?: is-mobile mobile:preview wide:preview + ;+ (cursor older.tpage "Older" rq search) +== +-- diff --git a/desk/web/board/mobile-index.hoon b/desk/web/board/mobile-index.hoon new file mode 100644 index 0000000..3c57173 --- /dev/null +++ b/desk/web/board/mobile-index.hoon @@ -0,0 +1,128 @@ +/- boke, tp=trill-post, cnt=contact +/+ sr=sortug, plib=trill-utils, sigil=sigil-sigil, lib=boke, kaji, const=constants +/= board /web/board/index +|_ [s=state:boke =bowl:gall] +++ css ^~ %- trip +''' +#board-index{ + margin-top: 1rem; + .tabs{ + width: 50%; + margin: auto; + + & .tab.active{ + font-weight: 700; + } + } + & #board-list{ + input{ + display: block; + margin: auto; + } + } + & #board-list-inner { + display: flex; + flex-wrap: wrap; + justify-content: center; + + & .board{ + display: block; + cursor: pointer; + padding: 1rem 0; + border: 1px solid var(--text-color); + margin: 0.3rem; + width: 20%; + text-align: center; + & .hanzi{ + font-size: 50px; + margin: 0; + color: var(--text-color); + } + & h4{ + word-break: keep-all; + text-align: center; + } + + & img{ + width: 50px; + display: block; + margin: 0 auto 0.5rem auto; + } + } + & .entry{ + display: flex; + flex: 0 0 33%; + align-items: center; + padding: 0.5rem 1rem; + + & h4{ + margin-right: 0.2rem; + } + } + } + +} +#board{ + display: block; +} + #board-index{ + .board{ + width: unset; + } + & h4{ + font-size: 1rem; + } + } + #tag-search{ + margin-bottom: 1rem; + } +''' +++ $ +:: =/ latest (bot:gorrm:tp feed.s 10) +;div#board-index + ;style: {css} + ;h2.tc:"Forum" + ;div.tabs + :: ;div.tab + :: =path "/board/latest" + :: ; Latest + :: == + ;div.tab.active + =kaji "scry" + =swap "swap" + =targ "#board-list-inner" + =path "/board/ff/boards" + ; Categories + == + ;div.tab + =kaji "scry" + =swap "swap" + =targ "#board-list" + =path "/board/ff/tags" + ; Tags + == + == + ;div#board-list + ;div#board-list-inner + ;* category-list + == + == + ;+ big-button:board +== +++ category-list ^- marl + :- + ;a.board/"/board/all" + ;div + ;h3.hanzi: 全 + ;h4: All + == + == + ;* %+ turn ~(tap by categories:const) |= [p=@tas *] + =/ name (trip p) + ;a.board/"/board/b/{name}" + ;div + ;img@"https://s3.spandrell.ch/assets/board/boards/{name}.svg"; + ;h4: {name} + == + == +-- diff --git a/desk/web/board/new.hoon b/desk/web/board/new.hoon new file mode 100644 index 0000000..ed71a91 --- /dev/null +++ b/desk/web/board/new.hoon @@ -0,0 +1,299 @@ +/- *boke, cnt=contact, tp=trill-post +/+ ui=trill-ui, kaji, const=constants, wall +/= user /web/components/user +|_ [tt=tags-table =bowl:gall edit=(unit [thread:tp post:tp])] +++ css ^~ %- trip +''' +#error-div{ + color: red; +} +#new-thread{ + padding: 10px; + margin: auto; + border: 1px solid var(--background-color); + border-radius: 1%; + + & fieldset{ + border: none; + padding: 0; + margin-top: 1rem; + + & label{ + display: block; + } + & input{ + width: 100%; + line-height: 1.5rem; + } + } + + & .board-choice{ + display: flex; + align-items: center; + + & .left{ + width: 20%; + & select{ + background-color: var(--background-color); + height: 2rem; + } + } + & .right{ + margin-left: 2rem; + flex-grow: 1; + } + } + & .author{ + img{ + width:30px; + height:30px; + } + & .name{ + margin-left: 1rem; + } + } + & #bordered{ + border: 1px solid black; + width: 100%; + height: 50vh; + overflow-y: scroll; + & textarea{ + resize: none; + width: 100%; + height: 90%; + border: none; + outline: none; + } + } + & #chips{ + position: relative; + width: 100%; + border: 1px solid rgb(107, 114, 128); + padding: 0 0.5rem; + + & .chip{ + display: inline-block; + font-size: 13px; + font-weight: 500; + color: rgba(0, 0, 0, 0.6); + line-height: 26px; + padding: 0 12px; + border-radius: 16px; + background-color: #e4e4e4; + cursor: pointer; + margin: 0 2px; + } + & .selected-chip{ + background-color: rgb(100, 100, 100); + } + & .chip:hover{ + background-color: rgb(100, 100, 100); + } + + & input{ + border: 0; + display: inline-block; + font-size: 16px; + height: 2rem; + line-height: 32px; + outline: 0; + margin: 0; + padding: 0 !important; + } + } +} +@media (min-width: 800px){ + #new-thread{ + width: 70%; + } + +} +@media (max-width: 800px){ + +} +.buttons{ + display: flex; + gap: 0.5rem; + justify-content: end; + align-items: center; + +} +#poll-button{ + border: none; + background: url('https://s3.spandrell.ch/assets/board/ui/poll.svg'); + background-size: cover; + width: 30px; + height: 30px; +} +''' +++ script +=/ json-tags=json %- pairs:enjs:format + %+ turn ~(tap by tt) |= [tag=@t p=(list *)] + :+ tag %n (scot %ud (lent p)) +=/ json-string %- trip %- en:json:html json-tags +^~ %+ weld +""" +const jsonString = '{json-string}'; +const allTags = JSON.parse(jsonString); + +""" +%- trip +''' +console.log(allTags, "tags") +const tagInput = document.getElementById("tag-input"); +const tagStore = document.getElementById("tag-store"); +const chipContainer = document.getElementById("chips"); +tagInput.addEventListener("keypress", handleKey); +tagInput.addEventListener("keyup", handleBackspace); + +const chipList = new Set(); + +function init(){ + setTimeout(() => { + console.log(tagStore.value, "tagstore") + const initTags = tagStore.value.split(","); + for (let tag of initTags){ + if (tag){ + chipList.add(tag); + loadChip(tag); + } + } + }, 500) +} +init(); + +function chipString(){ + const string = [...chipList].reduce((acc, i) => `${acc},${i}`); + // const string = JSON.stringify(Array.from(chipList)); + tagStore.value = string; +} +function addChip(itag){ + const tag = itag.toLowerCase(); + if (!chipList.has(tag) && tag.length > 0 && tag.length < 32) { + chipList.add(tag); + this.loadChip(tag) + tagInput.value = ""; + chipString(); + } +} +function removeChip(e){ + chipList.delete(e.target.innerText); + chipContainer.removeChild(e.target); + chipString(); +} +function loadChip(tag) { + const c = document.createElement('div'); + c.classList.add("chip"); + c.id = tag; + c.innerText = tag; + c.addEventListener("click", removeChip) + chipContainer.insertBefore(c, tagInput); +} +function handleBackspace(e){ + console.log(e.keyCode, "keyup") + console.log(e.target.selectionStart, "keyup") + if (!(e.keyCode === 8 && e.target.selectionStart == 0)) return + const chips = chipContainer.querySelectorAll('.chip'); + if (chips.length === 0) return + const to_delete = chipContainer.querySelector('.selected-chip'); + + if (to_delete) removeChip({target: to_delete}); + else { + const last_chip = chips[chips.length - 1]; + last_chip.classList.add("selected-chip"); + } +} +function handleKey(e) { + // autocomplete? + console.log(e.keyCode, "keycode") + console.log(e) + if (e.keyIdentifier == 'U+000A' || e.keyIdentifier == 'Enter' || e.keyCode == 13) e.preventDefault(); + if (e.keyCode === 13) addChip(e.target.value); +} + + +''' +++ $ ^- manx +=/ [stitle=tape stags=tape stext=tape] ?~ edit ["" "" ""] +:+ (trip title.-.u.edit) + (tags-to-tape:ui tags.-.u.edit) + (content-to-md:ui contents.+.u.edit) +=/ wal ~(. wall src.bowl) +=/ cats boards:wal +=/ whoms (get-contacts:cnt bowl) +=/ usr (user src.bowl whoms 30) +=/ subscription (subscription-type:wal now.bowl) +;div#new-thread.fsy + ;style:"{css}" + ;+ ?~ edit + ;h1.tc:"New Thread" + ;h1.tc:"Edit Thread" + ;form + =kaji "poke" + =action "add-thread" + ;fieldset + ;label:"Title" + ;input(type "text", name "title", value stitle); + == + ;fieldset.board-choice + ;label.left + ;div:"Board" + ;select + =name "board" + ;* %+ turn %- sort :_ aor ~(tap in cats) |= nam=@t + =/ name (trip nam) + ?: .=(nam 'public') + ;option(value name, selected ""):"{name}" + ;option(value name):"{name}" + == + == + ;label.right + ;div:"Tags" + ;div#chips + ;input(type "text", placeholder "press enter to input individual tags, click on a tag to delete", enterkeyhint "enter", id "tag-input"); + ;input(type "hidden", id "tag-store", name "tags", value stags); + == + == + == + ;fieldset + ;label:"Text" + ;div#bordered + ;textarea(name "text") + ; {stext} + == + == + == + ;div.f1 + ;div.author.flex + ;div:"Posting as" + ;div.flex.ml1 + ;+ avatar.usr + ;+ name.usr + == + == + ;input(type "hidden", name "error-div", value "#error-div"); + ;span#error-div; + ;div.buttons + ;* ?~ subscription ~ + ;= ;button#poll-button(type "button") + =kaji "scry" + =swap "add" + =cont "#bordered" + =path "/board/f/poll/new" + ; + == + ;input#upload-img@"https://s3.spandrell.ch/assets/board/octicons/image-24.svg"(type "image"); + == + ;* ?~ edit ;+ ;input(type "submit", value "Submit"); + ;= ;input(type "submit", value "Edit"); + ;input(type "hidden", name "editing") + =value (enc:kaji pid.-.u.edit) + ; + == + == + == + == + == + ;script:"{script}" +== +-- diff --git a/desk/web/board/router.hoon b/desk/web/board/router.hoon new file mode 100644 index 0000000..48c72a9 --- /dev/null +++ b/desk/web/board/router.hoon @@ -0,0 +1,281 @@ +/- boke, cnt=contact, tp=trill-post +/+ kaji, fetch-lib=fetch, plib=trill-utils, const=constants, sr=sortug, lib=boke, ui=trill-ui +/= index /web/index +/= board /web/board/index +/= mobile /web/board/mobile-index +/= thread-page /web/board/thread +/= new-thread /web/board/new +/= nag /web/nag +/= poll /web/components/poll + +|_ [rl=req-line:kaji s=state:boke =bowl:gall] + +* fetch ~(. fetch-lib [s bowl]) + b ~(. board [s bowl mob.rl]) + :: + ++ eyre-bail (error-response:kaji 404) + ++ manx-bail (error-page:kaji 404) +:: +++ $ ^- eyre-res:kaji + =/ p ?. mob.rl pat.rl [%m pat.rl] + + ?: ?=([%m ~] p) [%page (index ~[(mobile s bowl)] bowl)] + ?: ?=([%m %ff rest=*] p) [%html (mobile-fragment rest.p)] + =. p ?: ?=([%m rest=*] p) ((pole knot) rest.p) p + ?: ?=([%f rest=*] p) [%html (fragment rest.p)] + :- %page + %- index :_ bowl :_ ~ + ?+ p manx-bail + :: boards + ~ (main par.rl) + :: these two mostly for mobile + [%t tag=@t ~] (tag-index tag.p) + [%b cat=@t ~] (board-index cat.p) + [%all ~] all-posts + :: threads + [%n ~] (new-thread tags.s bowl ~) + [%edit uid=@t ~] (edit-thread uid.p) + [%blog rest=*] (blog-as-thread rest.p) + [%p %esc uid=@t ~] (board-thread-no-path uid.p) + [tag=@t title=@t rest=*] (board-thread tag.p title.p rest.p) + :: [%p rest=*] (board-thread rest.p) + == +++ fragment + |= p=(pole knot) + ?+ p ~& no-fragment=p manx-bail + :: fetching categories + [%boards ~] (w category-list:b) + [%tags ~] (w (make-tag-list:b (scag 21 (tags-by-size:lib tags.s src.bowl)))) + [%tag-search ~] (w tag-search) + :: fetching posts + [%page type=@t name=@t cursor=@t ~] (post-page type.p name.p cursor.p *_par.rl) + [%search type=@t name=@t cursor=@t ~] (post-page type.p name.p cursor.p par.rl) + :: + :: fetching replies of thread + [%replies thread=@t cursor=@t ~] (thread-replies thread.p cursor.p) + [%snip uid=@t ~] (post-snippet uid.p) + [%edit uid=@t ~] (edit-box uid.p) + [%poll %new ~] new-poll + == +++ mobile-fragment + |= p=(pole knot) + ?+ p manx-bail + [%boards ~] (w category-list:mobile) + [%tags ~] (w (make-tag-list:b (scag 33 (tags-by-size:lib tags.s src.bowl)))) + [%tag-search ~] + =/ uq (~(get by par.rl) 'query') + %- w + ;* ?~ uq :~(;span:"No query") + %+ turn (tag-search:fetch u.uq) tag-preview:b + [%snip uid=@t ~] (post-snippet uid.p) + [%edit uid=@t ~] (edit-box uid.p) + == + + + +++ w wrap-marl:kaji +:: Boards +++ main +|= params=(map @t @t) + =/ post-list + =/ tag (~(get by params) 't') + ?^ tag (post-page 't' u.tag '0' ~) + =/ brd (~(get by params) 'b') + ?^ brd (post-page 'b' u.brd '0' ~) + (post-page '' '' '0' ~) + + (main.b post-list) + +++ tag-search ^- marl + =/ uq (~(get by par.rl) 'query') + ;* ?~ uq :~(;span:"No query") + %+ turn (tag-search:fetch u.uq) tag-preview:b + + ++$ rq $%([%latest ~] [%board name=@t] [%tag name=@t]) + +++ tag-index +|= tag=@t + %- post-page + :^ 't' tag '0' ~ +++ board-index +|= cat=@t + %- post-page + :^ 'b' cat '0' ~ +++ all-posts + %- post-page + :^ 'l' '' '0' ~ + +++ post-page + |= [stype=@t name=@t scursor=@t params=(map @t @t)] + =/ contacts (get-contacts:cnt bowl) + =/ older=(unit @) ?: .=('0' scursor) ~ (slaw:parsing:sr %uw scursor) + =/ =rq + ?: .=(stype 't') [%tag name] + ?: .=(stype 'b') [%board name] + [%latest ~] + + =/ query (~(get by params) 'query') + =/ sort-by (~(get by params) 'sort') + =/ page-req [~ older board-page-size:const] + =/ filter ?~ query + %- some |= =thread:tp + !(~(has in tags.thread) 'blog') + %- some |= =thread:tp + ?: (~(has in tags.thread) 'blog') .n + (cfind:sr u.query title.thread .n) + =/ =tpage:tp + ?- -.rq + %latest (active-thread-page-all:fetch page-req filter) + %tag (active-thread-page-by-tags:fetch ~[name] page-req filter) + %board (active-thread-page-by-board:fetch name page-req filter) + == + ?: .=('0' scursor) + (post-index:b tpage rq contacts query mob.rl) + (previews:b tpage rq contacts query mob.rl) +:: Threads + +++ edit-thread |= uid=@t + =/ op (thread-by-hash:fetch uid) + ?~ op manx-bail + (new-thread tags.s bowl op) +++ board-thread-no-path + |= uid=@t + =/ post (post:fetch uid) + ?~ post manx-bail + (serve-thread u.post) + +++ blog-as-thread + |= p=path + =/ op (by-path:fetch p) + ?~ op ~& board-blog-path-not-found=p manx-bail + =/ is-op .=(thread.u.op [author.u.op id.u.op]) + ?. is-op manx-bail (serve-thread u.op) + +++ serve-thread +|= =post:tp + =/ ted (get:torm:tp threads.s thread.post) + ?~ ted ~& board-ted-not-found=rl manx-bail + :: =/ fn (node-to-full:plib post feed.s) + =/ contacts (get-contacts:cnt bowl) + :: =/ post-pid=pid:tp [author.u.post id.u.post] + :: ?~ parent.post + =/ =cpage:tp (thread-children:fetch u.ted) + =. p.cpage [post p.cpage] + ~& >> cpage=+.cpage + (thread-page u.ted cpage ~ ~ contacts s bowl mob.rl) +++ thread-replies +|= [ts=@t cs=@t] + =/ contacts (get-contacts:cnt bowl) + =/ thread (dec:kaji ts pid:tp) + ?~ thread manx-bail + =/ cursor (dec:kaji cs @ud) + ?~ cursor manx-bail + =/ ted (get:torm:tp threads.s u.thread) + ?~ ted manx-bail + ?~ replies.u.ted manx-bail + =/ =cpage:tp (older-children:fetch u.ted +(u.cursor)) + =< inline + %= thread-page + thread u.ted + children cpage + focus (some i.replies.u.ted) + search ~ + contacts contacts + state s + bowl bowl + is-mobile mob.rl + == + +++ board-thread + |= [tag=@t title=@t rest=(pole knot)] + =/ post (by-path:fetch [tag title ~]) + ?~ post ~& board-path-not-found=rl cant-show + (serve-thread u.post) + + ++ cant-show html:nag + + :: =/ children (flatten-fn-2:plib fn) + :: =/ req [~ ~ thread-page-size:const] + :: =/ children (get-children-page:plib fn req) + :: ~& children=+.children + + :: =/ par (get:gorm:tp feed.s u.parent.post) + :: ?~ par ~& par-not-found=rl + :: =/ children (bulk-post-by-pid:fetch replies.u.ted) + :: =/ =spage:tp [children ~ ~ (lent children)] + :: (thread-page title.u.ted contents.u.post spage ~ ~ contacts bowl mob.rl) + :: =/ siblings (get-siblings-page-2:plib u.par) + :: (thread-page title.u.ted contents.u.post siblings `post-pid ~ contacts bowl mob.rl) + +++ edit-box + |= uid=@t + =/ up (post:fetch uid) + ?~ up not-found + =/ tag-string (tags-to-tape:ui tags.u.up) + =/ post-text (content-to-md:ui contents.u.up) + =/ action ?~ parent.u.up "add-post" "add-reply" + ;form.content.edit-box + =kaji "poke" + =action action + ;input(type "hidden", name "editing", value (trip uid)); + ;input(type "hidden", name "error-div", value ".error-div"); + ;input(type "hidden", name "title", value (trip title.u.up)); + ;* ?~ parent.u.up ~ =/ p-string (enc:kaji [thread.u.up u.parent.u.up]) + ;+ ;input(type "hidden", name "parents", value p-string); + ;textarea + =name "text" + ; {post-text} + == + :: ;label + :: ; Tags + :: ;input(type "text", name "tags", value tag-string); + :: == + ;div.buttons + ;input + =type "submit" + =value "Save" + ; + == + ;button + =kaji "poke" + =action "del-reply" + =name "pid" + =payload (trip uid) + ; Delete + == + ;div.error-div; + == + == +++ post-snippet + |= uid=@t + =/ up (post:fetch uid) + ?~ up not-found + =/ contacts (get-contacts:cnt bowl) + =/ t thread-page(bowl bowl, state s, contacts contacts) + (snippet:t u.up) + + +++ not-found +;div + ; Post not found +== + +++ new-poll (form:poll bowl) + + +:: ++ serve-tags +:: |= tags=path +:: =/ postl (search-filter-full:plib feed.s [~ ~ board-page-size:const] (tag-search:plib tags)) +:: =/ tag-string %^ foldi:sr tags "" |= [i=@ud t=@t acc=tape] +:: ?: .=(i (dec (lent tags))) +:: "{acc}{(trip t)}" +:: "{acc}{(trip t)}, " +:: =/ page +:: ;div#tag-search +:: ;header +:: ;h2.tc: Tag Search: {tag-string} +:: == +:: ;+ (html:post-list postl) +:: == +:: (index ~[title page] bowl) +-- diff --git a/desk/web/board/thread.hoon b/desk/web/board/thread.hoon new file mode 100644 index 0000000..98811f8 --- /dev/null +++ b/desk/web/board/thread.hoon @@ -0,0 +1,807 @@ +/- boke, tp=trill-post, cons=contact +/+ sr=sortug, plib=trill-utils, ui=trill-ui, sigil=sigil-sigil, lib=boke, kaji, constants, wall +/= post-text /web/components/post-text +/= user /web/components/user +|_ [=thread:tp children=cpage:tp focus=(unit pid:tp) search=(unit @t) contacts=whoms:cons =state:boke =bowl:gall is-mobile=?] ++* wal ~(. wall src.bowl) + pt ~(. post-text [state bowl]) +++ css ^~ %- trip +''' +body>main{ + width: 100%!important; +} +@media (max-width: 800px){ + body>main{ + padding: 0!important; + } +} +#board-thread{ + max-width: 1280px; + margin: auto; + +/* base styles */ + & header{ + margin-top: 1rem; + & img{ + width: 20px; + margin-left: 1rem; + } + } + + & p{ + font-size: 1.1rem; + } + +} + +.reply{ + display: grid; + border: 1px solid silver; + + & .author{ + + & .avatar{ + max-height: 100px; + max-width: 64px; + display: block; + margin: auto; + } + & .name{ + font-weight: 500; + color: var(--hong); + text-align: center; + word-break: break-word; + } + } + + & .metadata { + & p{ + margin: -10px 0 0 0; + font-size: 14px; + } + & .timestamps span{ + margin-right: 0.3rem; + } + & .buttons{ + display: flex; + & img{ + height: 20px; + width: 20px; + margin: 5px 5px; + cursor: pointer; + } + } + + } + + & .content{ + text-align: left: + word-wrap: break-word; + + & img{ + max-width: 100%; + } + + & p{ + padding: 0.5rem; + font-weight: 400; + overflow: hidden; + word-break: break-word; + white-space: normal; + margin: 1rem 0; + } + & blockquote{ + margin: 1rem 2rem 1rem 1rem; + padding: 0.4rem; + border: 1px solid grey; + border-radius: 2%; + } + & .youtube-frame{ + display: block; + margin: auto; + width: 70%; + min-height: 30vw; + } + } + & footer{ + width: 100%; + padding: 0 0.5rem; + .tags{ + padding: 0; + font-size: 0.9rem; + flex-wrap: wrap; + + a{ + margin-left: 0.1rem; + } + } + } + +} + + + + /* desktop */ + + @media (min-width: 1000px){ + #posts{ + display: flex; + } + #replies{ + width: 83.33%; + } + } + @media(min-width: 800px){ + + #sidebar{ + position: sticky; + top: 4rem; + right: 0; + align-self: flex-start; + + & button, & .button{ + display: block; + margin: 1rem auto; + width: 100%; + } + } + + .reply{ + padding: 1rem; + padding-left: 0.4rem; + margin: 1rem; + grid-template-columns: 10% 90%; + grid-template-rows: 40px auto; + + & .author{ + grid-column-start: 1; + grid-column-end: 2; + grid-row-start: 1; + grid-row-end: 3; + } + + & .metadata{ + display: flex; + justify-content: space-between; + border-bottom: 1px solid grey; /* TODO darkmode */ + grid-column-start: 2; + grid-column-end: 3; + grid-row-start: 1; + grid-row-end: 2; + } + + & .content{ + grid-column-start: 2; + grid-column-end: 3; + grid-row-start: 2; + grid-row-end: 3; + + & img{ + margin: 0 auto; + max-height: 300px; + } + } + } + } + /* mobile */ + @media(max-width: 800px){ + & header{ + padding: 0 1rem; + & h1{ + font-size: 1.8rem; + } + } + #replies{ + margin-bottom: 3rem; + } + + #posts{ + display: block; + width: 100%; + + & > footer{ + background-color: black; + display:flex; + justify-content: space-evenly; + width: 100vw; + position: fixed; + bottom: 0; + height: 3rem; + + & button{ + height: 3rem; + } + } + & .replies{ + margin-bottom: 3rem; + } + } + + .reply{ + padding-top: 10px; + grid-template-columns: 100px auto; + grid-template-rows: 80px auto; + + & .author{ + grid-column-start; 1; + grid-column-end: 2; + grid-row-start: 1; + grid-row-end: 2; + + & .avatar{ + height: 60px; + width: 60px; + display: block; + margin: 0 auto; + } + & .name{ + font-size: 0.9rem; + } + } + & .metadata{ + grid-column-start: 2; + grid-column-end: 3; + grid-row-start: 1; + grid-row-end: 2; + padding: 0 0.2rem; + border-bottom: 1px solid grey; + + /* & .date{ + display: flex; + justify-content: space-between; + align-items: center; + }*/ + .updated-date{ + display: none; + } + + & .buttons{ + width: 100%; + justify-content: space-between; + margin-top: 0.5rem; + } + } + & .content{ + grid-column-start: 1; + grid-column-end: 3; + grid-row-start: 2; + grid-row-end: 3; + + & img{ + max-height: 300px; + } + + } + } + } + + +} + +#page-nav{ + .button{ + width: 30px; + height: 30px; + } +} +.icon-button{ + padding: 0.2rem; + & img{ + width: 20px; + } +} +.replying{ + margin: 1rem; + padding: 0.5rem; + width: fit-content; + cursor: pointer; + background-color: rgb(100, 100, 100, 0.3); + border-radius: 0.5rem; + & span{ + margin: 0 0.4rem; + } +} +.edit-box{ + display: block; + & textarea{ + display: block; + width: 100%; + height: 200px; + outline: none; + resize: none; + } + & label{ + margin-right: 1rem; + } +} +.reply-box{ + & .bordered{ + border: 1px solid black; + & blockquote{ + margin:0; + padding: 0.3rem; + border-bottom: 1px solid grey; + & .content{ + color: green; + white-space: pre-wrap; + } + & .content::before{ + content: "> "; + } + } + & .quoting-author{ + display: flex; + gap: 1ch; + } + & textarea{ + resize: none; + display: block; + border: none; + outline: none; + width: 100%; + } + } + & .reply-buttons{ + margin-top: 0.8rem; + display: flex; + gap: 0.5rem; + justify-content: end; + align-items: center; + + & input[type=image]{ + width: 30px; + } + + } +} +/* poll */ +/* base */ + +.poll{ + border: 1px solid black; + margin: 1rem auto; + & .bottom-row{ + height: 1rem; + } + & .top-row{ + position: relative; + height: 2rem; + & h6{ + position: absolute; + left: 1%; + font-size: 1.1rem; + } + & h3{ + position: absolute; + left: 50%; + transform: translateX(-50%); + font-size: 1.4rem; + max-width: 65%; + } + } + & .poll-type{ + font-size: 0.7rem; + float: left; + } + & .expiry{ + font-size: 0.8rem; + float: right; + } + & .poll-option{ + position: relative; + border: 2px solid grey; + width: 80%; + height: 2rem; + margin: 0.3rem auto 0.3rem auto; + & .inner{ + padding: 0 0.5rem; + z-index: 20; + } + & .poll-option-color{ + z-index: 19; + position: absolute; + top: 0; + left: 0; + background-color: var(--huang); + opacity: 0.6; + height: 100%; + } + } + & .poll-option-name{ + max-width: 75%; + } + + & .poll-option.open:hover{ + border:2px solid green; + cursor: pointer; + } + & .poll-option.not-voted{ + cursor: pointer; + } + & .poll-option.voted{ + border: 2px solid blue; + } +} +@media (min-width: 800px){ + .poll{ + width: 50%; + padding: 1rem; + } + +} +@media (max-width: 800px){ + .poll{ + width: 80%; + padding: 0.3rem; + } + +} +#poll-button{ + border: none; + background: url('https://s3.spandrell.ch/assets/board/ui/poll.svg'); + background-size: cover; + width: 40px; + height: 40px; +} +.copied{ + border: 2px solid green; + border-radius: 50%; +} +''' +++ thread-js ^~ %- trip +''' +function threadJS(){ + const buttons = document.querySelectorAll(".buttons"); + buttons.forEach(el => { + const parent = el.closest(".reply"); + if (!parent) return + const cb = el.querySelector(".copy-button") + + cb.addEventListener("click", () => { + const bp = `https://spandrell.ch/board` + const path = document.getElementById("board-thread").getAttribute("path"); + navigator.clipboard.writeText(bp + path).then(res => { + console.log(res, "write to clipboard") + cb.classList.add("copied"); + setTimeout(() => cb.classList.remove("copied"), 1000) + }).catch(er => { + console.log(er, "couldn't write to clipboard") + }) + }) + + const db = el.querySelector(".down-button") + db.addEventListener("click", () => { + parent.querySelector("footer").scrollIntoView(); + }) + }); + const up = document.querySelector("#go-up") + up.addEventListener("click", () => { + document.querySelector("#top").scrollIntoView(); + }) + const down = document.querySelector("#go-down") + down.addEventListener("click", () => { + document.querySelector("#bottom").scrollIntoView(); + }) +} + +function scanTweets(){ + const nodes = document.querySelectorAll(".parsed-twatter"); + for (let n of nodes){ + const status = n.getAttribute("status"); + twttr.widgets.createTweet(status, n.parentElement, { + conversation: true + }) + } +} +window.addEventListener('load', () => { + scanTweets(); + threadJS(); +}) +function composerJS(){ + const upl = document.getElementById("upload-img"); + upl.addEventListener("click", (e) => { + e.preventDefault(); + e.stopPropagation(); + }) + +} +''' +++ $ ^- manx +:: =/ index (mul (dec page) board-page-size:constants) +:: =/ is-op .=(thread.p.fn [author.p.fn id.p.fn]) +=/ is-op .y +=/ author=@p ship.pid.thread +=/ path-string (trip (spat path.thread)) +;div#board-thread.fsy + =path path-string + ;div#top; + ;style:"{css}" + ;header.fxc + :: ;+ ?: is-op + ;h1.tc:"{(trip title.thread)}" + :: ;h3.tc:"From {(trip title.p.fn)}" + ;* ?. ?|((is-admin:lib src.bowl) .=(author src.bowl)) ~ + :~(edit-button delete-button) + == + ;div#posts + ;+ inline + ;+ ?. is-mobile sidebar mobile-footer + == + ;script:"{thread-js}" +== +++ inline + ;div#replies + :: ;* (cursor newer.children "Newer" search) + ;* %+ mapi:sr p.children thread-child + ;* (cursor bot.children "Older" search) + == +++ cursor +|= [cursor=@ud label=tape search=(unit @t)] ^- marl + =/ len (lent replies.thread) + ?: (gte +(cursor) len) ~ + =/ thread-path (enc:kaji pid.thread) + =/ cursor-path (enc:kaji cursor) + =/ path ?~ search + "/board/f/replies/{thread-path}/{cursor-path}" + "/board/f/replies/{thread-path}/{cursor-path}?query={(trip u.search)}" + + ;+ ;div.cursor(kaji "iscroll", path path, cont "#replies", where "bottom") + ;button:"{label} posts" + == + +++ edit-button +=/ pid-string (enc:kaji pid.thread) +;a/"/board/edit/{pid-string}" + ;img@"https://s3.spandrell.ch/assets/board/ui/edit.svg"; +== +++ delete-button +=/ pid-string (enc:kaji pid.thread) +;a + =kaji "poke" + =action "del-thread" + =name "pid" + =payload pid-string + ;img@"https://s3.spandrell.ch/assets/board/ui/delete.svg"; +== + +++ thread-child +|= [post-index=@ud =post:tp] ^- manx +:: =/ base-index (mul (dec page) board-page-size:constants) +:: =/ pind (add base-index +(post-index)) +=/ post-index (add post-index top.children) +=/ usr ?: is-mobile + (user author.post contacts 60) + (user author.post contacts 64) +=/ pid-string (enc:kaji [author.post id.post]) +=/ jammed-parents %- enc:kaji [op=pid.thread parent=[author.post id.post]] +;div.reply(id pid-string) + ;div.author + ;+ avatar.usr + ;+ name.usr + == + ;div.metadata + ;+ (date post post-index) + ;* ?: .=(post-index (dec (lent p.children))) ;+ ;div#bottom; ~ + ;+ (buttons post pid-string) + == + ;div.content + ;* (quote post) + ;* (content:pt contents.post) + ;* ?: .=(post-index 0) ;+ (footer post) ~ + == + ;+ (reply-box post name.usr jammed-parents) +== +++ quote +|= p=post:tp ^- marl +?~ parent.p ~ +?: .=(u.parent.p thread.p) ~ +=/ usr (user ship.u.parent.p contacts 0) +;+ ;div.replying.flex + =kaji "modal" + =path "/board/f/snip/{(enc:kaji u.parent.p)}" + ;span:"Replying to:" + ;+ name.usr + == + + +++ date +|= [=post:tp post-index=@ud] +=/ date-string (datetime-to-tape:string:sr id.post "-") +=/ posted ;span.posted-date:"Posted: {date-string}" +=/ last-edit=time key:head:(pop:corm:tp contents.post) +=/ =marl ?: .=(last-edit id.post) posted^~ +;= ;+ posted + ;span.updated-date:"Edited: {(datetime-to-tape:string:sr last-edit "-")}" +== +;div.date + ;p.timestamps + ;* marl + == + ;p.meta + ;span:"Post #{(scow:parsing:sr %ud +(post-index))}/{<+((lent replies.thread))>}" + ;span.engagement:"" + == +== +++ buttons +|= [=post:tp id=tape] +:: =/ votes %+ roll ~(tap by reacts.engagement.post) |= [[s=@p [r=@t *]] acc=@] +:: ?: ?|(=(r "thumbsup") =(r "👍")) +;div.buttons + ;* ?. ?|((is-admin:lib src.bowl) .=(author.post src.bowl)) ~ + ;+ ;img@"https://s3.spandrell.ch/assets/board/ui/edit.svg" + =kaji "scry" + =path "/board/f/edit/{id}" + =swap "swap" + =where "outer" + =targ "[id=\"{id}\"] .content" + ; + == + ;img.copy-button@"https://s3.spandrell.ch/assets/board/ui/copy.svg"; + ;img + =src "https://s3.spandrell.ch/assets/board/ui/upvote.svg" + ; + == + ;img@"https://s3.spandrell.ch/assets/board/ui/downvote.svg" + ; + == + ;img.down-button@"https://s3.spandrell.ch/assets/board/ui/down.svg"; + ;img@"https://s3.spandrell.ch/assets/board/ui/reply.svg" + =kaji "toggle" + =targ ".reply-box" + =modal "1" + ; + == + ;img.collapse-button + =src "https://s3.spandrell.ch/assets/board/ui/collapse.svg" + =kaji "toggle" + =targ ".content/.avatar/.uncollapse-button/.collapse-button" + ; + == + ;img.uncollapse-button + =src "https://s3.spandrell.ch/assets/board/ui/uncollapse.svg" + =kaji "toggle" + =targ ".content/.avatar/.uncollapse-button/.collapse-button" + =hidden "" + ; + == +== +++ reply-box +|= [parent=post:tp author=manx jammed-parents=tape] ^- manx +=/ parent-text=tape (content-to-md:ui contents.parent) +=/ snip ?: (gth (lent parent-text) 150) + "{(scag 150 parent-text)}..." + parent-text +=/ error-div "err{jammed-parents}" +=/ subscription (subscription-type:wal now.bowl) +:: %- serve-modal:kaji :_ ~ +;div.reply-box + =hidden "" + ;form + =kaji "poke" + =action "add-reply" + ;div.bordered + ;blockquote + ;div.quoting-author + ;span:"Replying to" + ;+ author + == + ;div.content:"{snip}" + == + ;textarea + =name "text" + =rows "10" + =placeholder "Your reply" + ; + == + == + ;input(type "hidden", name "parents", value jammed-parents); + ;input(type "hidden", name "title", value ""); + ;input(type "hidden", name "error-div", value "#{error-div}"); + ;span.error-div(id error-div); + ;div.reply-buttons + ;* ?~ subscription ~ + ;= ;button#poll-button(type "button") + =kaji "scry" + =swap "add" + =cont ".bordered" + =path "/board/f/poll/new" + ; + == + ;input#upload-img@"https://s3.spandrell.ch/assets/board/octicons/image-24.svg"(type "image"); + == + ;input(type "submit", value "Send"); + == + :: == + == +== +++ footer +|= =post:tp +=/ count ~(wyt in tags.post) +=/ tags ?. (gth count 0) ;span; +=/ tag-links +%+ mapi:sr ~(tap in tags.post) + |= [i=@ t=@t] ^- manx =/ tt (trip t) =/ path "/board?t={tt}" + =/ show ?: .=(i (dec count)) tt "{tt}, " + ;a/"{path}":"{show}" +;div.tags.flex + ; Tags: + ;* tag-links +== +;footer + ;+ tags +== + + ++ mobile-footer + =/ blog-path (trip (spat (blog-path:lib thread))) + ;footer + ;a/"{blog-path}" + ;button:"Blog view" + == + ;button#go-up:"Up" + ;button#go-down:"Down" + ;button + =kaji "toggle" + =targ ".reply-box" + =modal "1" + ; Reply + == + == + + ++ sidebar + :: =/ from +((mul (dec page) board-page-size:constants)) + :: =/ to + :: =/ added (add from board-page-size:constants) + :: ?: (gth added (lent children)) (lent children) added + :: =/ froms (number:string:sr from) + :: =/ tos (number:string:sr to) + =/ post-count (number:string:sr (lent p.children)) + =/ blog-path (trip (spat (blog-path:lib thread))) +:: =/ max-page +((div (lent children) board-page-size:constants)) + :: =/ page-count %- number:string:sr max-page + :: =/ prev-page %- number:string:sr ?: .=(page 1) 1 (dec page) + :: =/ curr-page (number:string:sr page) + :: =/ next-page %- number:string:sr ?: .=(page max-page) page +(page) + ;div#sidebar + :: ;div#search-box + :: ;form.flex + :: ;input(name "thread-search", placeholder "Search on Thread"); + :: ;button.icon-button + :: ;img@"https://s3.spandrell.ch/assets/board/ui/search.svg"(type "image"); + :: == + :: == + :: == + ;a/"{blog-path}" + ;button:"Blog view" + == + ;button#go-up:"Go To Top" + ;button#go-down:"Go To Bottom" + ;button + =kaji "toggle" + =targ ".reply-box" + =modal "1" + ; Reply + == + == +++ snippet +|= =post:tp ^- manx +=/ date-string (datetime-to-tape:string:sr id.post "-") +=/ usr (user author.post contacts 64) +;div.snippet.reply + ;div.author + ;+ avatar.usr + ;+ name.usr + == + ;div.metadata + ;div.date + ;p.timestamps + ;span.posted-date:"Posted: {date-string}" + == + == + == + ;div.content + ;* (quote post) + ;* (content:pt contents.post) + :: ;+ (footer post) + == +== +-- diff --git a/desk/web/calendar/cal/day.hoon b/desk/web/calendar/cal/day.hoon new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/desk/web/calendar/cal/day.hoon diff --git a/desk/web/calendar/cal/event.hoon b/desk/web/calendar/cal/event.hoon new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/desk/web/calendar/cal/event.hoon diff --git a/desk/web/calendar/cal/month.hoon b/desk/web/calendar/cal/month.hoon new file mode 100644 index 0000000..1a6ec3f --- /dev/null +++ b/desk/web/calendar/cal/month.hoon @@ -0,0 +1,321 @@ +/+ sr=sortug +|_ =bowl:gall +++ css ^~ %- trip +''' +body { + font-family: system-ui, -apple-system, BlinkMacSystemFont, avenir next, avenir, + segoe ui, helvetica neue, helvetica, Cantarell, Ubuntu, roboto, noto, arial, + sans-serif; + margin: 10vh auto; + max-width: 120ch; + background: #fffff4; + color: #140; +} + +h1 { + font-size: 1.2rem; + font-weight: bold; +} + +input, +button { + border: none; + color: inherit; + font: inherit; +} +input { + background: none; +} +input:focus-visible { + outline: solid 1px #140; +} +button { + background: #261; + color: white; + font-weight: bold; + border-radius: 0.25rem; +} +button:hover, +button:focus-visible { + background: #483; +} + +.month-control { + display: flex; +} +.month-control h2 { + font-size: 1rem; + font-weight: bold; + margin: 0; + margin-inline-end: auto; +} +.month-control a { + flex: 0 1 6ch; + text-align: end; + font-weight: bold; + color: inherit; +} + +table { + padding: 0; + width: 100%; + height: 100%; + & th{ + opacity: 0.6; + text-align: center; + padding: 0.5rem 0; + } + & td{ + border-top: solid 1px currentColor; + min-width: 0; + min-height: 8rem; + height: 4rem; + + } +} + + +.day-weekend { + color: #c88; +} +.day-past { + color: #2423; +} + +.date { + height: 100%; + display: flex; + flex-direction: column; +} +.date ul { + padding: 0; + list-style: none; +} + +.date-num { + aspect-ratio: 1; + border-radius: 100rem; + background: #fffff4; + position: absolute; + z-index: 1; +} +.day-today .date-num { + padding: 0 0.125em; + background: #220; + color: white; +} + +.create-event-form { + flex: 1 1 auto; + margin: 0; +} +.create-event { + background: none; + color: transparent; + width: 100%; + height: 100%; + cursor: crosshair; +} +.create-event:hover, +.create-event:focus-visible { + background: #efe4; +} +.create-event:focus-visible { + color: #140; +} + +.event { + margin: 0.25rem 0.5rem; +} +.event:first-child { + margin-top: 0.5rem; +} + +.event > form { + display: flex; + margin: 0; +} + +.event-button { + position: relative; + flex: 1 1 auto; + padding: 0.25rem; + background: white; + color: #000b; + border-radius: 0.25rem; + text-wrap: nowrap; + text-overflow: ellipsis; + overflow: hidden; + text-align: start; + font-size: 0.8rem; + font-weight: bold; + text-decoration: none; +} +.event-button::after { + content: ""; + position: absolute; + inset: 0; +} +.event-button:hover::after, +.event-button:focus-visible::after { + background: #fff4; +} +.day-past .event:not(:focus-within):not(:has(dialog[open])) .event-button { + opacity: 0.4; +} + +.event dialog { + inset: unset; + margin-top: 0.3rem; + padding: 0.75rem; + background: white; + border: solid 1px #ceb; + box-shadow: 0 0.25rem 0.5rem #0301, 0 0rem 2rem #0301; + z-index: 9999; +} +.event dialog::after { + content: ''; + position: absolute; + left: 0.4rem; + top: calc(-0.3rem - 2px); + width: 0.6rem; + height: 0.6rem; + transform: rotate(45deg); + background: inherit; + border: inherit; + border-right: none; + border-bottom: none; +} + +.event dialog form { + margin: 0; + display: flex; + flex-direction: column; + gap: 0.5rem; +} +.event-dialog-row { + display: flex; + gap: 0.5rem; +} + +.event input[type="text"] { + border-bottom: solid 1px currentColor; + max-width: 15ch; +} + +.delete-button { + background: #820; +} +.delete-button:hover, +.delete-button:focus-visible { + background: #a42; +} +''' +++ html +|= time=@da ^- manx +=, chrono:userlib +=/ dat (yore time) +=+ [[a y] m [d h mm s f]]=dat +=/ mon %+ snag (dec m) mon:yu +=/ nmon %+ snag m mon:yu +=/ pmon =/ ind ?: .=(1 m) 11 (sub m 2) + %+ snag ind mon:yu +=/ year (scow:parsing:sr %ud y) +=/ nyear (scow:parsing:sr %ud +(y)) +=/ pyear (scow:parsing:sr %ud (dec y)) +=/ weekday %+ snag (daws dat) wik:yu +:: =/ weeknames (snoc +.wik:yu -.wik:yu) +=/ weeknames wik:yu +=/ first-of-month dat(d.t 1) +=/ month-starts-at (daws first-of-month) +;div#month.month + ;style: {css} + ;div.month-control + ;h2.current-month:"{mon} {year}" + ;a/"":"<- {pmon}" + ;a/"":"{nmon} ->" + == + ;table + ;tr + ;* %+ turn weeknames |= t=tape ;th.wday-name:"{t}" + == + ;* %+ turn (get-nums time) |= l=(list date) + ;tr + ;* %+ turn l cell + == + == +== ++$ row (list date) +++ get-nums +|= =time ^- (list row) +=, chrono:userlib + =/ =date (yore time) + =+ [[a y] m [d h mm s f]]=date + =/ first-of-month date(d.t 1) + =/ first-day (year first-of-month) + =/ month-start (daws first-of-month) + ~& month-start=month-start + =| l=(list row) + =| i=@ud + |- + =/ dat + ?: (gth month-start i) + =/ diff (sub month-start i) + =/ back (sub first-day (mul ~d1 diff)) + (yore back) + + =/ curr (sub i month-start) + (yore (add first-day (mul ~d1 curr))) + :: =/ nm m.added + :: =/ to-next-month (gth nm m) + :: ?: to-next-month added curr + + ?~ l $(l [~[dat] l], i +(i)) + + ?. .=(0 (mod i 7)) + =. i.l [dat i.l] + $(i +(i)) + + =. i.l (flop i.l) + =/ curr (sub i month-start) + =/ added (yore (add first-day (mul ~d1 curr))) + =/ nm m.added + =/ to-next-month (gth nm m) + ?: to-next-month (flop l) + =/ nrow ~[added] + + $(l [nrow l], i +(i)) + :: exit-condition + +++ cell +|= =date ^- manx + =/ [faded=? today=?] [.n .n] + =/ nums (scow %ud d.t.date) + ?: faded + :: + ;td.faded + ;div:"{nums}" + == + ?: today + ;td.today + ;div:"{nums}" + == + :: + ;td + ;div:"{nums}" + == + :: +++ get-num +|= [feira=@ud =time] ^- @ud +=, chrono:userlib + =/ date (yore time) + =/ first-of-month date(d.t 1) + =/ month-starts-at (daws first-of-month) + ?: (lth feira month-starts-at) + =/ diff (sub month-starts-at feira) + =/ back (sub time (mul ~d1 diff)) + d.t:(yore back) + :: e.g. month starts in day 3 (thu) and we're in day 4 (fri) + =/ diff (sub feira month-starts-at) + +(diff) +-- diff --git a/desk/web/calendar/cal/new.hoon b/desk/web/calendar/cal/new.hoon new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/desk/web/calendar/cal/new.hoon diff --git a/desk/web/calendar/cal/week.hoon b/desk/web/calendar/cal/week.hoon new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/desk/web/calendar/cal/week.hoon diff --git a/desk/web/calendar/cal/year.hoon b/desk/web/calendar/cal/year.hoon new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/desk/web/calendar/cal/year.hoon diff --git a/desk/web/calendar/day.hoon b/desk/web/calendar/day.hoon new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/desk/web/calendar/day.hoon diff --git a/desk/web/calendar/event.hoon b/desk/web/calendar/event.hoon new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/desk/web/calendar/event.hoon diff --git a/desk/web/calendar/main.hoon b/desk/web/calendar/main.hoon new file mode 100644 index 0000000..bc8e5c2 --- /dev/null +++ b/desk/web/calendar/main.hoon @@ -0,0 +1,77 @@ +/- boke +|_ [s=state:boke =bowl:gall] +++ css ^~ %- trip +''' +html, body, main{ + height: 100%; + overflow-y: hidden; +} +main{ + display: flex; + & #icons{ + width: 5%; + border-right: 1px solid black; + & img{ + display:block; + margin: auto; + cursor: pointer; + width: 30px; + } + } +} +.scroll{ + height: 100%; + overflow-y: auto; +} +#main{ + display: flex; + width: 95%; +} +''' +++ $ ^- manx +;html +=data-theme "light" + ;head + ;meta(charset "utf-8"); + ;meta(name "viewport", content "width=device-width, initial-scale=1, shrink-to-fit=no"); + ;title:"Sorcal" + ;style:"{css}" + == + ;body + ;main + ;div#icons + =kaji "scry" + =swap "swap" + =targ "#main" + ;img@"https://s3.sortug.com/img/icons/notes.svg" + =path "/cal/f/notes" + ; + == + ;img@"https://s3.sortug.com/img/icons/todo.svg" + =path "/cal/f/todo" + ; + == + ;img@"https://s3.sortug.com/img/icons/calendar.svg" + =path "/cal/f/cal" + ; + == + ;select + =kaji "scry" + =path "/search/f" + =name "interval" + ;option + =value "all" + ; All time + == + ;option + =value "day" + :: =selected "" + ; Past 24h + == + == + == + ;div#main; + == + == +== +-- diff --git a/desk/web/calendar/month.hoon b/desk/web/calendar/month.hoon new file mode 100644 index 0000000..6a7d4a1 --- /dev/null +++ b/desk/web/calendar/month.hoon @@ -0,0 +1,326 @@ +/+ sr=sortug +|_ =bowl:gall +++ css ^~ %- trip +''' +body { + font-family: system-ui, -apple-system, BlinkMacSystemFont, avenir next, avenir, + segoe ui, helvetica neue, helvetica, Cantarell, Ubuntu, roboto, noto, arial, + sans-serif; + margin: 10vh auto; + max-width: 120ch; + background: #fffff4; + color: #140; +} + +h1 { + font-size: 1.2rem; + font-weight: bold; +} + +input, +button { + border: none; + color: inherit; + font: inherit; +} +input { + background: none; +} +input:focus-visible { + outline: solid 1px #140; +} +button { + background: #261; + color: white; + font-weight: bold; + border-radius: 0.25rem; +} +button:hover, +button:focus-visible { + background: #483; +} + +.month-control { + display: flex; +} +.month-control h2 { + font-size: 1rem; + font-weight: bold; + margin: 0; + margin-inline-end: auto; +} +.month-control a { + flex: 0 1 6ch; + text-align: end; + font-weight: bold; + color: inherit; +} + +table { + padding: 0; + width: 100%; + height: 100%; + & th{ + opacity: 0.6; + text-align: center; + padding: 0.5rem 0; + } + & td{ + border-top: solid 1px currentColor; + min-width: 0; + min-height: 8rem; + height: 4rem; + + } +} + + +.day-weekend { + color: #c88; +} +.day-past { + color: #2423; +} + +.date { + height: 100%; + display: flex; + flex-direction: column; +} +.date ul { + padding: 0; + list-style: none; +} + +.date-num { + aspect-ratio: 1; + border-radius: 100rem; + background: #fffff4; + position: absolute; + z-index: 1; +} +.day-today .date-num { + padding: 0 0.125em; + background: #220; + color: white; +} + +.create-event-form { + flex: 1 1 auto; + margin: 0; +} +.create-event { + background: none; + color: transparent; + width: 100%; + height: 100%; + cursor: crosshair; +} +.create-event:hover, +.create-event:focus-visible { + background: #efe4; +} +.create-event:focus-visible { + color: #140; +} + +.event { + margin: 0.25rem 0.5rem; +} +.event:first-child { + margin-top: 0.5rem; +} + +.event > form { + display: flex; + margin: 0; +} + +.event-button { + position: relative; + flex: 1 1 auto; + padding: 0.25rem; + background: white; + color: #000b; + border-radius: 0.25rem; + text-wrap: nowrap; + text-overflow: ellipsis; + overflow: hidden; + text-align: start; + font-size: 0.8rem; + font-weight: bold; + text-decoration: none; +} +.event-button::after { + content: ""; + position: absolute; + inset: 0; +} +.event-button:hover::after, +.event-button:focus-visible::after { + background: #fff4; +} +.day-past .event:not(:focus-within):not(:has(dialog[open])) .event-button { + opacity: 0.4; +} + +.event dialog { + inset: unset; + margin-top: 0.3rem; + padding: 0.75rem; + background: white; + border: solid 1px #ceb; + box-shadow: 0 0.25rem 0.5rem #0301, 0 0rem 2rem #0301; + z-index: 9999; +} +.event dialog::after { + content: ''; + position: absolute; + left: 0.4rem; + top: calc(-0.3rem - 2px); + width: 0.6rem; + height: 0.6rem; + transform: rotate(45deg); + background: inherit; + border: inherit; + border-right: none; + border-bottom: none; +} + +.event dialog form { + margin: 0; + display: flex; + flex-direction: column; + gap: 0.5rem; +} +.event-dialog-row { + display: flex; + gap: 0.5rem; +} + +.event input[type="text"] { + border-bottom: solid 1px currentColor; + max-width: 15ch; +} + +.delete-button { + background: #820; +} +.delete-button:hover, +.delete-button:focus-visible { + background: #a42; +} +''' +++ html +|= time=@da ^- manx +=, chrono:userlib +=/ dat (yore time) +=+ [[a y] m [d h mm s f]]=dat +=/ mon %+ snag (dec m) mon:yu +=/ nmon %+ snag m mon:yu +=/ pmon =/ ind ?: .=(1 m) 11 (sub m 2) + %+ snag ind mon:yu +=/ year (scow:parsing:sr %ud y) +=/ nyear (scow:parsing:sr %ud +(y)) +=/ pyear (scow:parsing:sr %ud (dec y)) +=/ weekday %+ snag (daws dat) wik:yu +:: =/ weeknames (snoc +.wik:yu -.wik:yu) +=/ weeknames wik:yu +=/ first-of-month dat(d.t 1) +=/ month-starts-at (daws first-of-month) +;html +;head; +;body +;style: {css} + ;div#month.month + ;div.month-control + ;h2.current-month:"{mon} {year}" + ;a/"":"<- {pmon}" + ;a/"":"{nmon} ->" + == + ;table + ;tr + ;* %+ turn weeknames |= t=tape ;th.wday-name:"{t}" + == + ;* %+ turn (get-nums time) |= l=(list date) + ;tr + ;* %+ turn l cell + == + == + == +== +== ++$ row (list date) +++ get-nums +|= =time ^- (list row) +=, chrono:userlib + =/ =date (yore time) + =+ [[a y] m [d h mm s f]]=date + =/ first-of-month date(d.t 1) + =/ first-day (year first-of-month) + =/ month-start (daws first-of-month) + ~& month-start=month-start + =| l=(list row) + =| i=@ud + |- + =/ dat + ?: (gth month-start i) + =/ diff (sub month-start i) + =/ back (sub first-day (mul ~d1 diff)) + (yore back) + + =/ curr (sub i month-start) + (yore (add first-day (mul ~d1 curr))) + :: =/ nm m.added + :: =/ to-next-month (gth nm m) + :: ?: to-next-month added curr + + ?~ l $(l [~[dat] l], i +(i)) + + ?. .=(0 (mod i 7)) + =. i.l [dat i.l] + $(i +(i)) + + =. i.l (flop i.l) + =/ curr (sub i month-start) + =/ added (yore (add first-day (mul ~d1 curr))) + =/ nm m.added + =/ to-next-month (gth nm m) + ?: to-next-month (flop l) + =/ nrow ~[added] + + $(l [nrow l], i +(i)) + :: exit-condition + +++ cell +|= =date ^- manx + =/ [faded=? today=?] [.n .n] + =/ nums (scow %ud d.t.date) + ?: faded + :: + ;td.faded + ;div:"{nums}" + == + ?: today + ;td.today + ;div:"{nums}" + == + :: + ;td + ;div:"{nums}" + == + :: +++ get-num +|= [feira=@ud =time] ^- @ud +=, chrono:userlib + =/ date (yore time) + =/ first-of-month date(d.t 1) + =/ month-starts-at (daws first-of-month) + ?: (lth feira month-starts-at) + =/ diff (sub month-starts-at feira) + =/ back (sub time (mul ~d1 diff)) + d.t:(yore back) + :: e.g. month starts in day 3 (thu) and we're in day 4 (fri) + =/ diff (sub feira month-starts-at) + +(diff) +-- diff --git a/desk/web/calendar/new.hoon b/desk/web/calendar/new.hoon new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/desk/web/calendar/new.hoon diff --git a/desk/web/calendar/notes.hoon b/desk/web/calendar/notes.hoon new file mode 100644 index 0000000..6190e84 --- /dev/null +++ b/desk/web/calendar/notes.hoon @@ -0,0 +1,100 @@ +/- tp=trill-post +/+ ui=trill-ui +/+ kaji +|_ [notes=(list post:tp) =bowl:gall] + +++ css ^~ %- trip +''' +*{ + box-sizing: border-box; +} +#list{ + width: 20%; + border-right: 1px solid black; + & .entry{ + padding: 1rem; + cursor: pointer; + } +} +#composer{ + width: 80%; + & form{ + height: 100%; + padding: 2rem; + #inputs{ + height: 100%; + & input,textarea{ + display: block; + width: 100%; + outline: none; + } + #top{ + display: flex; + input[type=text]{ + font-size: 2rem; + font-weight: 700; + height: 2rem; + border: none; + margin-bottom: 1rem; + flex-grow: 1; + } + input[type=submit]{ + height: 2rem; + width: fit-content; + } + } + & textarea{ + height: 90%; + resize: none; + border: none; + } + } + } +} +''' +++ $ +;div + ;style: {css} + ;div#list.scroll + =kaji "scry" + =targ "#inputs" + ;* %+ turn notes note-preview + == + ;div#composer + ;form + =kaji "poke" + =action "save-note" + ;div#inputs + ;div#top + ;input(type "text", value "Title"); + ;input(type "submit", value "Save"); + == + ;textarea(name "text") + ; This is a Markdown note + == + == + == + == +== +++ note-preview +|= n=post:tp +=/ id (enc:kaji [author.n id.n]) +;div.entry + =path "/cal/f/note/{id}" + ; {(trip title.n)} +== +++ note +|= n=post:tp ^- manx +=/ pid-string (enc:kaji [author.n id.n]) +=/ post-text (content-to-md:ui contents.n) +;div + ;div#top + ;input(type "hidden", name "pid", value pid-string); + ;input(type "text", value (trip title.n)); + ;input(type "submit", value "Save"); + == + ;textarea(name "text") + ; {post-text} + == +== +-- diff --git a/desk/web/calendar/router.hoon b/desk/web/calendar/router.hoon new file mode 100644 index 0000000..793f946 --- /dev/null +++ b/desk/web/calendar/router.hoon @@ -0,0 +1,66 @@ +/- boke, tp=trill-post, cnt=contact +/+ kaji, fetch-lib=fetch, plib=trill-utils, const=constants, sr=sortug, lib=boke, ui=trill-ui +/= index /web/index +/= main /web/calendar/main +/= notes /web/calendar/notes +/= todo /web/calendar/todo +/= cal /web/calendar/cal/month + +|_ [rl=req-line:kaji s=state:boke =bowl:gall] ++* fetch ~(. fetch-lib [s bowl]) +++ eyre-bail (error-response:kaji 404) +++ manx-bail (error-page:kaji 404) +:: +++ $ ^- eyre-res:kaji + ~& >> routing-cal=rl + =/ p pat.rl ::?. mob.rl pat.rl [%m pat.rl] + ?+ p eyre-bail + ~ root + [%f rest=*] :- %html (fragment rest.p) + == +++ root + :- %page (main s bowl) + +++ fragment +|= p=(pole knot) +=/ st s + ?+ p manx-bail + [%notes ~] (notes note-list bowl) + [%todo ~] (todo st bowl) + [%cal ~] (~(html cal bowl) now.bowl) + :: + [%note uid=@t ~] (note uid.p) + [%todo uid=@t ~] manx-bail + [%cal %day uid=@t ~] manx-bail + [%cal %week uid=@t ~] manx-bail + [%cal %month uid=@t ~] manx-bail + [%cal %event uid=@t ~] manx-bail + == +++ note |= uid=@t ^- manx + =/ upid (dec:kaji uid pid:tp) + ?~ upid manx-bail + =/ =post:tp (make-note 'rofl') + (note:notes post) + +++ note-list ^- (list post:tp) + %+ turn ~['Note 1' 'Lol' 'Hoon' 'Blog ideas' 'lmao'] + make-note +++ make-note + |= t=@t ^- post:tp + =/ tokens (tokenize:ui t) + =/ tags (silt ~[t 'note']) + =/ p (build-post:lib tokens tags [our.bowl now.bowl]) + p(title t) ++$ task + $: title=@t + desc=paragraph:tp + priority=@ud + status=$?(%todo %wip %done) + created=@da + due=((mop @da @da) gth) + creator=@p + subtasks=$~(~ (list task)) + workers=(map @p @t) :: who's doing what + tags=(set @t) + == +-- diff --git a/desk/web/calendar/todo.hoon b/desk/web/calendar/todo.hoon new file mode 100644 index 0000000..311c59e --- /dev/null +++ b/desk/web/calendar/todo.hoon @@ -0,0 +1,6 @@ +|_ [s=* =bowl:gall] +++ $ +;div#todo + ;p: hi +== +-- diff --git a/desk/web/calendar/week.hoon b/desk/web/calendar/week.hoon new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/desk/web/calendar/week.hoon diff --git a/desk/web/calendar/year.hoon b/desk/web/calendar/year.hoon new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/desk/web/calendar/year.hoon diff --git a/desk/web/chat/chat.hoon b/desk/web/chat/chat.hoon new file mode 100644 index 0000000..92c451a --- /dev/null +++ b/desk/web/chat/chat.hoon @@ -0,0 +1,317 @@ +/- c=tlon-channels, contact +/+ sr=sortug, kaji, sigil=sigil-sigil, lib=boke +/= user /web/components/user +|_ [=whoms:contact =bowl:gall] +:: ++$ mane $@(@tas [@tas @tas]) :: XML name+space ++$ manx $~([[%$ ~] ~] [g=marx c=marl]) :: dynamic XML node ++$ marl (list manx) :: XML node list ++$ mars [t=[n=%$ a=[i=[n=%$ v=tape] t=~]] c=~] :: XML cdata ++$ mart (list [n=mane v=tape]) :: XML attributes ++$ marx $~([%$ ~] [n=mane a=mart]) :: dynamic XML tag +++ md +''' +# H1 + +## H2 + +### H3 + +#### H4 + +##### H5 + +###### H6 + +This is a paragraph with _italics_, *bold* and +`inline code`. Sentences can be hard wrapped. + + +- unordered +- list + ++ ordered ++ list + +[link](https://urbit.org) + + + +``` +fenced codeblock +(note language spec not supported) +``` + +horizontal rule: +--- + +> block quotes + may be hard-wrapped if indented + +Backslash at end\ +of line adds linebreak + +Udon syntax may be prefixed with \*backslashes\* to escape. + +Hoon atom literals like ~sampel-palnet and ~.foo will +be rendered as inline code. + +''' +++ css ^~ %- trip +''' +#chat-box{ + height: 100%; + width: 100%; + border: 1px solid var(--text-color); + display: flex; + flex-direction: column; + + input[type=text]{ + outline: none; + } + + header{ + border-bottom: 1px solid var(--text-color); + display: flex; + padding: 0.5rem; + + h3{ + margin: 0; + } + } +} +#chat-container{ + flex-grow: 1; + overflow-y: scroll; + word-break: break-all; + padding: 0.5rem; + + + .chat-msg { + display: flex; + min-height: 4rem; + + .left { + margin-right: 1rem; + + & .avatar{ + width: 32px; + height: 32px; + } + } + .right { + width: 100%; + .metadata { + display: flex; + color: rgb(100, 100, 100); + font-size: 0.8rem; + + .name{ + font-family: "Anonymous Pro"; + margin-right: 0.5rem; + } + } + .chat-content{ + font-family: Inter; + } + } + } +} +#chat-container .chat-content img{ + max-width: 80%; + display: block; + margin: 0 auto; +} +#chat-composer{ + display: flex; +} +#text-input{ + flex-grow: 1; +} +.row{ + display: flex; +} +.f1{ + display: flex; + justify-content: space-between; +} + +@media (min-width: 800px){ + header{ + padding: 0.5rem 2rem; + + } + +} +@media (max-width: 800px){ + + header{ + & .chat-name{ + text-align: end; + } + } + +} + +''' +++ script +|= sub-path=tape +^~ %+ weld %- trip +''' +document.addEventListener('DOMContentLoaded', (event) => { + const room = document.getElementById("chat-container"); + if (room) room.scrollTop = room.scrollHeight +}) + +document.addEventListener('kaji-fact', (event) => { + const room = document.getElementById("chat-container"); + if (room) setTimeout(() => room.scrollTop = room.scrollHeight, 50) +}) + +''' +""" +subscribe('{sub-path}'); +""" +++ main +|= page=paged-posts:c +=/ sip our.bowl +=/ name 'chat' +=/ sub-path "/chat/{(scow %p sip)}/{(trip name)}" +^- manx + =/ chat-list (tap:on-posts:c posts.page) + ;div#chat-box + ;style:"{css}" + ;script:"{(script sub-path)}" + ;header.f1 + ;h3: Bloody Shovel Public Chat + ;div.chat-name:"~tasdev-docteg-mothep/bloody-shovel-public/chat" + == + ;div#chat-container + ;* %+ turn chat-list |= [=time up=(unit post:c)] + ?~ up ;span; + (post-div +<.u.up) + == + ;form + =id "chat-composer" + =kaji "poke" + =action "add-chat" + =wipe "yes" + ;input#text-input(type "text", name "input", autocomplete "off"); + ;input(type "submit", value "Submit"); + == + == +++ post-div +|= =memo:c ^- manx +:: =/ =memo:c +<.post +:: seal is engagement, essay is the post +=/ usr (user author.memo whoms 32) +;div.chat-msg + ;div.left + ;+ avatar.usr + == + ;div.right + ;div.metadata + ;+ name.usr + ;div.time:"{(time-to-tape:string:sr sent.memo)}" + == + ;div.chat-content + ;* %+ turn content.memo |= =verse:c + ?: ?=(%block -.verse) (block +.verse) + ;div.inline + ;* %+ turn p.verse tinline + == + == + == +== +:: chat:tlon -> manx +++ block |= b=block:c + ?- -.b + %image + ;img + =src "{(trip src.b)}" + :: =width "{(scow %ud width.b)}" + :: =height "{(scow %ud height.b)}" + =alt "{(trip alt.b)}" + ; + == + %cite ;p:"oops" + %header (heading-to-manx +.b) + %listing (listing-to-manx +.b) + %code ;code + =lang "{(trip code.b)}" + ; (trip lang.b) + == + %rule ;p:"" + == +:: :: +++ listing-to-manx + |= l=listing:c ^- manx + ?: ?=(%item -.l) + ;li + ;* %+ turn p.l tinline + == + :: + :: =/ inl (tinline r.l) :: ??? + ?: ?=(%ordered p.l) + ;ol + ;* %+ turn q.l listing-to-manx + == + ?: ?=(%unordered p.l) + ;ul + ;* %+ turn q.l listing-to-manx + == + :: %tasklist + ;div.task-list + ;* %+ turn q.l listing-to-manx + == +++ heading-to-manx +|= [p=?(%h1 %h2 %h3 %h4 %h5 %h6) q=(list inline:c)] ^- manx + =/ tp (turn q tinline) + ?- p + %h1 ;h1 + ;* tp + == + %h2 ;h2 + ;* tp + == + %h3 ;h3 + ;* tp + == + %h4 ;h4 + ;* tp + == + %h5 ;h5 + ;* tp + == + %h6 ;h6 + ;* tp + == + == +:: :: +++ tinline |= i=inline:c + ?@ i ;span:"{(trip i)}" + ?- -.i + %italics ;i + ;* (turn p.i tinline) + == + %bold ;em:"" + %strike ;span.strike:"" + %blockquote ;blockquote + ;* (turn p.i tinline) + == + :: + %inline-code ;code:"{(trip p.i)}" + %code ;code:"{(trip p.i)}" + %ship ;span.ship:"{(trip (scot %p p.i))}" + %block ;span.ref:"Reference to {(scow %ud p.i)} {(trip q.i)}" + %tag ;span.tag:"{(trip p.i)}" + %link ;a/"{(trip p.i)}"(target "_blank"):"{(trip q.i)}" + %task ;span.task + ; Done: {(bool-string p.i)} + ;* (turn q.i tinline) + == + %break ;br; + == +++ bool-string + |= a=? ^- tape ?:(a "yes" "no") +-- diff --git a/desk/web/components/chat.hoon b/desk/web/components/chat.hoon new file mode 100644 index 0000000..f616a16 --- /dev/null +++ b/desk/web/components/chat.hoon @@ -0,0 +1,127 @@ +/- c=tlon-channels +/+ sr=sortug, kaji, sigil=sigil-sigil, lib=boke +=< html +|% +++ css ^~ %- trip +''' +#chat-box{ + height: 100%; + width: 100%; + border: 1px solid var(--text-color); + display: flex; + flex-direction: column; + + input[type=text]{ + outline: none; + } + + header{ + border-bottom: 1px solid var(--text-color); + display: flex; + padding: 0.5rem 2rem; + + h3{ + margin: 0; + } + } +} +#chat-container{ + flex-grow: 1; + overflow-y: scroll; + word-break: break-all; + padding: 0.5rem; + + + .chat-msg { + display: flex; + min-height: 4rem; + + .left { + margin-right: 1rem; + + & .anon-avatar{ + width: 32px; + height: 32px; + } + } + .right { + width: 100%; + .metadata { + display: flex; + color: rgb(100, 100, 100); + font-size: 0.8rem; + + .author{ + font-family: "Anonymous Pro"; + margin-right: 0.5rem; + } + } + .chat-content{ + font-family: Inter; + } + } + } +} +#chat-container .chat-content img{ + max-width: 80%; + display: block; + margin: 0 auto; +} +#chat-composer{ + display: flex; +} +#text-input{ + flex-grow: 1; +} +.row{ + display: flex; +} +.f1{ + display: flex; + justify-content: space-between; +} +''' +++ script ^~ %- trip +''' +document.addEventListener('DOMContentLoaded', (event) => { + const room = document.getElementById("chat-container"); + if (room) room.scrollTop = room.scrollHeight +}) + +document.addEventListener('kaji-fact', (event) => { + const room = document.getElementById("chat-container"); + if (room) setTimeout(() => room.scrollTop = room.scrollHeight, 50) +}) +''' +++ post-to-manx +|= post=@t +;div.chat-msg + ;p:"(trip post)" +== +++ html + |= =bowl:gall ^- manx + =/ pat /chat/(scot %p our.bowl)/chat/posts/newest/200/post + =/ io ~(. io:sr bowl) + =/ scrying (scry:io %channels pat paged-posts:c) + =/ chat-list (tap:on-posts:c posts.scrying) + ;div#chat-box + ;style:"{css}" + ;script:"{script}" + ;header.f1 + ;h3: Bloody Shovel Public Chat + ;div: ~hostyr-docteg-mothep/spandrell + == + ;div#chat-container + ;* %+ turn chat-list |= [=time up=(unit post:c)] + ?~ up ;p:"Deleted post" + (tlon-chat-post-to-manx:lib u.up) + == + ;form + =id "chat-composer" + =kaji "poke" + =action "add-chat" + ;input#text-input(type "text", name "input", autocomplete "off"); + ;input(type "submit", value "Submit"); + == + == +-- diff --git a/desk/web/components/common.hoon b/desk/web/components/common.hoon new file mode 100644 index 0000000..553103a --- /dev/null +++ b/desk/web/components/common.hoon @@ -0,0 +1,11 @@ +/+ sr=sortug +|% +++ cursor +|= [cursor=(unit @da) label=tape name=@t tag=?] ^- manx +?~ cursor ;div; +=/ type ?: tag "t" "b" +=/ path "/page/{type}/{(trip name)}/{(scow:parsing:sr %uw u.cursor)}" +;div.cursor(kaji "iscroll", path path, cont "#post-list", where "bottom") + ;button:"{label} posts" +== +-- diff --git a/desk/web/components/date.hoon b/desk/web/components/date.hoon new file mode 100644 index 0000000..1526af0 --- /dev/null +++ b/desk/web/components/date.hoon @@ -0,0 +1,18 @@ +/+ sr=sortug +|_ [date=@da link=?] +++ $ +^- marl +=+ [[a y] m [d h mm s f]]=(yore date) +=/ ys %- trip (ud-to-cord:string:sr y) +?: link +;= + ;a/"{ys}":"{ys}" + ;a/"{ys}/{<m.m>}":"/{<m.m>}" + ;a/"{ys}/{<m.m>}/{<d.d>}":"/{<d.d>}" +== +;= + ;span:"{ys}" + ;span:"/{<m.m>}" + ;span:"/{<d.d>}" +== +--
\ No newline at end of file diff --git a/desk/web/components/modals.hoon b/desk/web/components/modals.hoon new file mode 100644 index 0000000..7068a97 --- /dev/null +++ b/desk/web/components/modals.hoon @@ -0,0 +1,20 @@ +/- boke +/+ kaji +|_ [s=state:boke =bowl:gall pat=path] +++ $ +?+ pat (error-page:kaji 404) +[%login ~] login +== +++ login +;div#modal-body + ;h3: Login with an Urbit ship + ;form + =kaji "navi" + ;fieldset + ;label: Urbit ID + ;input(type "text", name "ship"); + == + ;input(type "submit", value "Login"); + == +== +--
\ No newline at end of file diff --git a/desk/web/components/poll.hoon b/desk/web/components/poll.hoon new file mode 100644 index 0000000..3184ec0 --- /dev/null +++ b/desk/web/components/poll.hoon @@ -0,0 +1,208 @@ +/- *polls +/+ sr=sortug, kaji, lib=boke +|% +++ css ^~ %- trip +''' +.new-poll{ + border: 1px solid black; + width: 80%; + margin: auto; + margin-bottom: 1rem; + padding: 1rem; + #poll-title{ + font-size: 1.5rem; + padding: 0.3rem; + margin-bottom: 0.5rem; + text-align: center; + } + & input[type=text]{ + display: block; + line-height: 1.5rem; + width: 80%; + margin: 0.3rem auto; + } + #final-row{ + border-top: 1px solid black; + } + #bet-input{ + width: 30%; + display: inline-block; + margin-left: 1ch; + } +} +@media (max-width: 800px){ + #final-row{ + display: block; + } +} + +''' +++ script ^~ %- trip +''' +function newOpts(){ + const button = document.getElementById("add-opt-button"); + const container = document.getElementById("options"); + + button.addEventListener("click", (e) => { + console.log(e, "clck") + e.preventDefault(); + e.stopPropagation(); + + const currentOpts = container.querySelectorAll(".opt"); + const index = currentOpts.length; + + const input = document.createElement("input"); + input.classList.add("opt"); + input.type = "text"; + input.name = `poll-opt-${index}`; + input.placeholder = "New Option"; + input.autocomplete = "off"; + container.appendChild(input); + }) +} +setTimeout(newOpts, 500); +''' +++ form +|= =bowl:gall ^- manx +;form +;div.new-poll + ;style:"{css}" + ;input#poll-title(type "text", name "poll-title", placeholder "Poll Question"); + ;div#options + ;input.opt(type "text", name "poll-opt-0", placeholder "First Option", autocomplete "off"); + ;input.opt(type "text", name "poll-opt-1", placeholder "Second Option", autocomplete "off"); + == + ;div.f1 + ;div + ;label: Multiple Choice + ;input(type "checkbox", name "poll-multiple"); + == + ;button#add-opt-button(type "button"):"Add" + == + ;div#final-row.f1 + ;div + ;label: Require betting + ;input#bet-input(type "text", name "poll-min-bet"); + == + ;div + ;label: Expires + ;input(type "datetime-local", name "poll-expiry"); + == + == + ;script:"{script}" +== +== ++$ opt + $: text=@t + votes=(set @p) + == +++ show +|= [=poll =bowl:gall] ^- manx + =/ poll-type=tape ?: ?=(%exc -.votes.poll) "Single choice poll" "Multiple choice poll" + =/ pid-string (enc:kaji [author.poll time.poll]) + =/ total=@ud + ?: ?=(%exc -.votes.poll) + ~(wyt by p.votes.poll) + %- ~(rep by p.votes.poll) |= [it=[@ud m=(map @p (set @ud))] acc=@ud] + (add acc ~(wyt by m.it)) + + |^ + ?: (gth now.bowl expiry.poll) expired-poll fresh-poll + ++ fresh-poll ^- manx + =/ expiry-string (post-date-ago:lib now.bowl expiry.poll %yau) + ;div.poll + ;div.top-row + ;h6:"Open Poll" + ;h3.hs:"{(trip text.poll)}" + == + ;div.options + ;* %+ mapi:sr options.poll fresh-opt + == + ;div.bottom-row.f1 + ;div.poll-type:"{poll-type}" + ;div.expiry:"Expires in {expiry-string}" + == + == + ++ fresh-opt + |= [i=@ud text=@t] + =/ payload (enc:kaji [author.poll time.poll i]) + =/ stats (opt-stats i) + =/ pct (scow %ud pct.stats) + =/ style "width: {pct}%;" + =/ classes + ?: ?=(%exc -.votes.poll) + =/ have-voted (~(get by p.votes.poll) src.bowl) + ?~ have-voted + "poll-option open" + ?: .=(u.have-voted i) + "poll-option voted" + "poll-option not-voted" + :: inc + =/ opt-votes (~(get by p.votes.poll) i) + ?~ opt-votes "poll-option open" + =/ my-votes (~(get by u.opt-votes) src.bowl) + ?~ my-votes "poll-option open" + ?: (~(has in u.my-votes) i) + "poll-option voted" + "poll-option open" + + + ;div + =class classes + =kaji "poke" + =action "vote-poll" + =name "option" + =payload payload + + ;div.poll-option-color(style style); + ;div.f1.inner + =name "option-{(scow %ud i)}" + =payload "vote" + ;div.poll-option-name.hs:"{(trip text)}" + ;div:"{pct}%" + == + == + ++ expired-poll ^- manx + =/ expiry-string (post-date-ago:lib expiry.poll now.bowl %yau) + ;div.poll + ;div.top-row + ;h6:"Closed Poll" + ;h3.hs:"{(trip text.poll)}" + == + ;div.options + ;* %+ mapi:sr options.poll dead-opt + == + ;div.bottom-row + ;div.poll-type:"{poll-type}" + ;div.expiry:"Expired {expiry-string} ago" + == + == + ++ dead-opt + |= [i=@ud text=@t] ^- manx + =/ stats (opt-stats i) + =/ pct (scow %ud pct.stats) + =/ style "width: {pct}%;" + ;div.poll-option + ;div.poll-option-color(style style); + ;div.inner.f1 + ;div.poll-option-name.hs:"{(trip text)}" + ;div:"{pct}%" + == + == + ++ opt-stats + |= i=@ud ^- [count=@ud pct=@ud voters=(set @p)] + =/ voters + ?: ?=(%exc -.votes.poll) + =/ all-votes ~(tap by p.votes.poll) + %+ roll all-votes |= [[sip=@p vote=@ud] acc=(set @p)] + ?. .=(vote i) acc %- ~(put in acc) sip + :: + =/ all-votes (~(get by p.votes.poll) i) + ?~ all-votes ~ + ~(key by u.all-votes) + =/ voter-count ~(wyt in voters) + =/ pct ?: .=(total 0) 0 (div (mul voter-count 100) total) + [voter-count pct voters] + + -- +-- diff --git a/desk/web/components/post-header.hoon b/desk/web/components/post-header.hoon new file mode 100644 index 0000000..a9cb1e2 --- /dev/null +++ b/desk/web/components/post-header.hoon @@ -0,0 +1,111 @@ +/- tp=trill-post +/+ sr=sortug, lib=boke +=< html +|% +++ css ^~ %- trip +''' + #post-header{ + -webkit-locale: "en"; + text-size-adjust: 100%; + color: rgb(0, 0, 0); + font-size: 16px; + font-weight: 400; + text-rendering: optimizelegibility; + -webkit-font-smoothing: antialiased; + line-height: 1.618; + text-shadow: rgb(0, 0, 0) 0px 0px 0px; + align-items: center; + border-bottom-color: rgb(223, 223, 223); + border-bottom-style: dotted; + border-bottom-width: 1px; + box-sizing: border-box; + margin-left: 0px; + margin-right: 0px; + padding-bottom: 30px; + padding-left: 32px; + padding-right: 32px; + padding-top: 30px; + text-align: center; + + & h2{ + font-size: 2.1rem; + text-transform: uppercase; + } + + & #post-meta, .comment-meta, .entry-footer { + font-size: 90%; + font-style: italic; + color: #969696; + } + @media (min-width: 768px){ + & .col-md-4 { + -ms-flex: 0 0 33.333333%; + flex: 0 0 33.333333%; + max-width: 33.333333%; + } + } + & .breadcrumbs { + list-style: none; + display: inline-block; + margin: 0; + padding: 0; + border: none; + background: transparent; + text-indent: 0; + + } + & .breadcrumbs li { + display: inline-block; + margin: 0 0.3rem; + padding: 0; + border: none; + background: transparent; + text-indent: 0; + } + & .tags{ + display: block; + text-transform: capitalize; + } + + } +''' +++ html +|= p=post:tp ^- manx +=/ url (trip (spat (title-to-path:lib title.p id.p))) :: TODO check for relative/absolute path +=/ date (date-to-tape:string:sr id.p "-") + +=+ [[a y] m [d h mm s f]]=(yore id.p) +=/ ys %- trip (ud-to-cord:string:sr y) + +:: +;div#post-header + ;style:"{css}" + ;h2:"{(trip title.p)}" + ;div#post-meta + ;span + ; Posted by Spandrell on + ;ul.breadcrumbs + ;li + ;a/"{ys}":"{ys}" + == + ; / + ;li + ;a/"{ys}/{<m.m>}":"{<m.m>}" + == + ; / + ;li + ;a/"{ys}/{<m.m>}/{<d.d>}":"{<d.d>}" + == + == + == + ;+ ?: .=(0 ~(wyt in tags.p)) ;span:"" + ;div.tags + ;* %+ mapi:sr ~(tap in tags.p) + |= [i=@ t=@t] ^- manx + ?. .=(i (dec ~(wyt in tags.p))) + ;a/"/tags/{(trip t)}":"{(trip t)}, " + ;a/"/tags/{(trip t)}":"{(trip t)}" + == + == +== +--
\ No newline at end of file diff --git a/desk/web/components/post-list.hoon b/desk/web/components/post-list.hoon new file mode 100644 index 0000000..427aa72 --- /dev/null +++ b/desk/web/components/post-list.hoon @@ -0,0 +1,148 @@ +/- tp=trill-post +/+ sr=sortug, plib=trill-utils, lib=boke, kaji +/= content /web/components/post-text +|% +++ abbreviated-post +|= [cm=content-map:tp button=manx] ^- (list manx) +=/ abbreviated (abbreviate-post:plib cm 1.000) +=/ blocks (latest-contents:plib cm) +?: .=(blocks abbreviated) %+ turn blocks block:content +%+ snoc (turn abbreviated block:content) button + +++ post-snippet +|= [p=post:tp children=full-graph:tp] ^- manx +=/ url (trip (spat (title-to-path:lib title.p id.p))) :: TODO check for relative/absolute path +=+ [[a y] m [d h mm s f]]=(yore id.p) +=/ ys %- trip (ud-to-cord:string:sr y) +:: =/ author (scot %p p.author.p) +=/ count (houyi:plib children) +=/ comment-count ?: .=(count 0) "No" "{<count>}" +:: +=/ continue-button +;div.continue-button-wrapper + ;a.continue-button/"{url}":"Continue" +== +=/ comment-div + ;span + ;a/"{url}#comments":"{comment-count} comments" + == +=/ tag-links +%+ mapi:sr ~(tap in tags.p) + |= [i=@ t=@t] ^- manx + ?. .=(i (dec ~(wyt in tags.p))) + ;a/"/tags/{(trip t)}":"{(trip t)}, " + ;a/"/tags/{(trip t)}":"{(trip t)} " + +:: +;article + ;header + ;h2 + ;a/"{url}":"{(trip title.p)}" + == + == + ;main + ;* (abbreviated-post contents.p continue-button) + == + ;div.post-metadata + ;span + ; Posted on + ;a/"{ys}":"{ys}" + ;a/"{ys}/{<m.m>}":"/{<m.m>}" + ;a/"{ys}/{<m.m>}/{<d.d>}":"/{<d.d>}" + == + :: ;span + :: ; by + :: ;a/"by/{author}":"{author}" + :: == + == + ;+ ?: .=(0 ~(wyt in tags.p)) ;footer ;+ comment-div == + ;footer + ; Tagged as + ;span.tags-links + ;* tag-links + == + ;+ comment-div + == +== +++ css ^~ %- trip +''' +#post-list{ + :: top: 0; + margin: auto; + + & article{ + margin: 0 0 1.5em; + margin-top: 40px; + border-bottom: 1px dotted #dfdfdf; + padding: 0 2rem; + padding-bottom: 40px; + + & header h2{ + font-size: 1.8rem; + text-align: center; + letter-spacing: 1px; + text-transform: uppercase; + line-height: 1.4em; + font-weight: 500; + } + & .post-metadata, article footer{ + font-size: 90%; + font-style: italic; + color: #969696; + } + + & main{ + margin: 1.5em 0 0; + } + } + & .tags-links{ + text-transform: capitalize; + margin-right: 1ch; + } + + & .continue-button-wrapper{ + margin-top: 1.5rem; + margin-bottom: 1.5rem; + } + & .continue-button{ + font-family: 'Montserrat', sans-serif; + text-transform: uppercase; + letter-spacing: 1px; + font-size: 13px; + -webkit-transition: all .4s ease; + -o-transition: all .4s ease; + transition: all .4s ease; + padding: 0.5rem, 0rem, 0.5rem, 1.25rem; + line-height: 1.5; + border-radius: 0.2rem; + } + & .cursor{ + text-align: center; + margin: 1rem; + } +} + + +''' +++ test +|= [p=post:tp children=full-graph:tp] ^- manx +=/ pid [author.p id.p] +=/ pat /blog/snip/(scot %uw (jam pid)) +(fetch:kaji pat) +++ cursor +|= [cursor=(unit @da) label=tape] +?~ cursor ;div; +=/ path "/page/t/blog/{(scow:parsing:sr %uw `@uw`u.cursor)}" +;div.cursor(kaji "iscroll", path path, cont "#post-list", where "bottom") + ;button:"{label} posts" +== +++ html +|= p=page:tp +^- manx +;div#post-list + ;style:"{css}" + ;+ (cursor newer.p "Newer") + ;* (turn p.p post-snippet) + ;+ (cursor older.p "Older") +== +-- diff --git a/desk/web/components/post-text.hoon b/desk/web/components/post-text.hoon new file mode 100644 index 0000000..0335e4e --- /dev/null +++ b/desk/web/components/post-text.hoon @@ -0,0 +1,182 @@ +/- b=boke, tp=trill-post +/+ sr=sortug, plib=trill-utils +/= poll-div /web/components/poll +|_ [s=state:b =bowl:gall] +++ content +|= c=content-map:tp ^- (list manx) +=/ latest (pry:corm:tp c) +?~ latest ~ +(content-list +.u.latest) +++ content-list +|= c=content-list:tp ^- (list manx) +(turn c block) +++ block +|= b=block:tp ^- manx +?+ -.b ;p; +%paragraph (pg +.b) +%blockquote (bq +.b) +%heading (heading +.b) +:: %table (table +.b) +%list (htmlist +.b) +%media (media +.b) +%codeblock (codeblock +.b) +%eval (eval +.b) +%ref (refblock +.b) +== +++ eval +|= txt=@t ^- manx +:: Ream can crash if the cord is wrong +:: soften instead +=/ uhoon (rush txt vest) +?~ uhoon ;p:"The hoon you tried to run ({(trip txt)}) is invalid." +=/ run %- mule |. +%+ slap !>(..zuse) u.uhoon +?: ?=(%.n -.run) :: if virtualization fails get a (list tank) +;p + ;span:"Evaluation of {(trip txt)} failed:" + ;br; + ;* %+ turn p.run |= t=tank ;span:"{~(ram re t)}" +== +;p:"{(text p.run)}" +++ pg +|= l=(list inline:tp) ^- manx +;p +;* %+ turn l inline +== +++ bq +|= l=(list inline:tp) ^- manx +;blockquote +;* %+ turn l inline +== +:: ++ table +:: |= rows=(list (list content-list:tp)) +:: ;table +:: ;* %+ turn rows +:: |= l=(list content-list:tp) +:: ;tr +:: ;* %+ turn l +:: |= cl=content-list:tp +:: ;td +:: ;* (turn cl block) +:: == +:: == +:: == +++ refblock +|= [app=term src=@p pat=path] + ?+ app ;span; + %polls (poll-loader pat) + == +++ poll-loader +|= scry-path=(pole knot) ^- manx +?. ?=([ship=@t id=@t ~] scry-path) ;span; +=/ usip (slaw %p ship.scry-path) +?~ usip ;span; +=/ uid (slaw %da id.scry-path) +?~ uid ;span; +=/ upoll (~(get by polls.s) [u.usip u.uid]) +?~ upoll ;span:"Poll not found" +(show:poll-div u.upoll bowl) + + +++ htmlist +|= [l=(list content-list:tp) ordered=?] +?: ordered +;ol + ;* %+ turn l li +== +;ul + ;* %+ turn l li +== +++ li +|= l=content-list:tp ^- manx +;li + ;* (turn l block) +== +++ media +|= m=media:tp ^- manx +?- -.m +%video ;video@"{(trip p.m)}"; +%audio ;audio@"{(trip p.m)}"; +%images ;div.images + ;* %+ turn p.m + |= [url=@t caption=@t] ;img@"{(trip url)}"(alt (trip caption)); + == +== +++ codeblock +|= [code=@t lang=@t] :: TODO lang suff +;pre +;code:"{(trip code)}" +== +++ heading +|= [pp=@t q=@] ^- manx +=/ p (trip pp) +?: .=(1 q) ;h1:"{p}" +?: .=(2 q) ;h2:"{p}" +?: .=(3 q) ;h3:"{p}" +?: .=(4 q) ;h4:"{p}" +?: .=(5 q) ;h5:"{p}" +?: .=(6 q) ;h6:"{p}" +;p:"" +++ inline +|= l=inline:tp ^- manx +?- -.l + %text (parse-text p.l) + %italic ;i:"{(trip p.l)}" + %bold ;strong:"{(trip p.l)}" + %strike ;del:"{(trip p.l)}" + %ship ;span.ship:"{(trip (scot %p p.l))}" + %codespan ;code:"{(trip p.l)}" + %link ?. (is-image:web:sr href.l) + ;a/"{(trip href.l)}"(target "_blank"):"{(trip show.l)}" + ;a/"{(trip href.l)}" + =target "_blank" + ;img@"{(trip href.l)}"(alt (trip show.l)); + == + %date + =/ s (time:enjs:format p.l) + ?. ?=(%n -.s) ;span; + ;span.timestamp(timestamp (trip p.s)):"" + %note ;span; + %break ;br; + %underline ;span.underline:"{(trip p.l)}" + %sup ;sup:"{(trip p.l)}" + %sub ;sub:"{(trip p.l)}" + %ruby ;ruby + "{(trip p.l)}" + ;rt:"{(trip q.l)}" + == +== +++ parse-text +|= txt=@t ^- manx +=/ tpe (trip txt) +=/ youtube (rush txt youtube:parsing:sr) +?^ youtube +:: ;a/"{tpe}" +:: ;img@"https://i.ytimg.com/vi/{u.youtube}/hqdefault.jpg"; +:: == +;iframe.youtube-frame@"https://www.youtube.com/embed/{u.youtube}"; +=/ twatter-status (rush txt twatter:parsing:sr) +?^ twatter-status +;div :: goddamn twatter embeds insert themselves as last child + ;a.parsed-twatter(status u.twatter-status):"{tpe}" +== +=/ trimmed (rush txt trim:parsing:sr) +?~ trimmed ~& parsing-error=txt ;span.parsing-error; +=/ link=(unit purl:eyre) (rust u.trimmed link:parsing:sr) +?^ link + ?^ p.q.u.link + ?: (is-img u.p.q.u.link) ;img@"{u.trimmed}"; + ;a.parsed-link/"{tpe}"(target "_blank"):"{tpe}" :: normal link + ;a.parsed-link/"{tpe}"(target "_blank"):"{tpe}" :: normal link +;span:"{tpe}" + +++ is-img +|= t=@ta +=/ img-set %- silt +:~ ~.webp + ~.png + ~.jpeg + ~.jpg +== +(~(has in img-set) t) +-- diff --git a/desk/web/components/post.hoon b/desk/web/components/post.hoon new file mode 100644 index 0000000..488c308 --- /dev/null +++ b/desk/web/components/post.hoon @@ -0,0 +1,274 @@ +/- tp=trill-post +/+ plib=trill-utils, sr=sortug, kaji, lib=boke +/= content /web/components/post-text +/= post-header /web/components/post-header +|_ [[=post:tp children=full-graph:tp] who=@p] +++ css ^~ %- trip +''' +#post-text{ + -webkit-locale: "en"; + text-size-adjust: 100%; + color: rgb(0, 0, 0); + line-height: 1.618; + text-align: left; + text-shadow: rgb(0, 0, 0) 0px 0px 0px; + border-bottom-color: rgb(223, 223, 223); + border-bottom-style: dotted; + border-bottom-width: 1px; + box-sizing: border-box; + display: block; + margin-bottom: 24px; + margin-left: 0px; + margin-right: 0px; + margin-top: 0px; + padding-bottom: 40px; + padding-left: 32px; + padding-right: 32px; + padding-top: 4px; +} +#comments{ + -webkit-locale: "en"; + text-size-adjust: 100%; + color: rgb(0, 0, 0); + line-height: 1.618; + text-align: left; + text-shadow: rgb(0, 0, 0) 0px 0px 0px; + box-sizing: border-box; + display: block; + margin-bottom: 32px; + padding-bottom: 0px; + padding-left: 16px; + padding-right: 16px; + padding-top: 0px; +} +#comments h3{ + -webkit-locale: "en"; + text-size-adjust: 100%; + color: rgb(0, 0, 0); + text-align: left; + text-shadow: rgb(0, 0, 0) 0px 0px 0px; + font-size: 18.72px; + font-weight: 400; + box-sizing: border-box; + display: block; + line-height: 1.2; + margin-block-end: 9.36px; + margin-block-start: 9.36px; + margin-bottom: 9.36px; + margin-inline-end: 0px; + margin-inline-start: 0px; + margin-left: 0px; + margin-right: 0px; + margin-top: 9.36px; +} +#comment-list{ + -webkit-locale: "en"; + text-size-adjust: 100%; + color: rgb(0, 0, 0); + line-height: 1.618; + text-align: left; + text-shadow: rgb(0, 0, 0) 0px 0px 0px; + box-sizing: border-box; + display: block; + list-style-image: none; + list-style-position: outside; + list-style-type: none; + margin-block-end: 24px; + margin-block-start: 0px; + margin-bottom: 24px; + margin-inline-end: 0px; + margin-inline-start: 0px; + margin-left: 0px; + margin-right: 0px; + margin-top: 0px; + padding-inline-start: 0px; + padding-left: 0px; +} +.comment-list li{ + -webkit-locale: "en"; + text-size-adjust: 100%; + color: rgb(0, 0, 0); + line-height: 1.618; + text-shadow: rgb(0, 0, 0) 0px 0px 0px; + list-style-image: none; + list-style-position: outside; + list-style-type: none; + border-left-color: rgb(223, 223, 223); + border-left-style: solid; + border-left-width: 1px; + box-sizing: border-box; + display: list-item; + padding-bottom: 16px; + padding-left: 10px; + padding-right: 0px; + padding-top: 16px; + text-align: left; +} +.comment-author{ + font-weight: 700; + color: var(--text); + font-style: normal; + font-size: 1rem; + margin-right: 1rem; +} +.comment-content{ + font-size: 90%; +} +#reply-title{ + display: inline; +} +.reply-prompt{ + color: var(--hong); + font-size: 0.9rem; +} +''' +++ script %- trip +''' +document.addEventListener('alpine:init', () => { + console.log(Alpine, Date.now()) + Alpine.store("comment", { + text: "", + set(s){ + this.text = s + } + }); + Alpine.store("replying_to", { + show(s){ + return this.to === s + }, + to: "", + open(s){ + this.to = s + } + }); + Alpine.bind('bigReplyButton', () => ({ + type: 'button', + 'x-on:click'(){ + Alpine.store('replying_to').open('main'); + } + })); + Alpine.bind('ReplyButton', () => ({ + type: 'button', + 'x-on:click'() { + Alpine.store("replying_to").open(this.$el.id) + } + })); + Alpine.bind("cancelButton", () => ({ + 'x-on:click'() { + Alpine.store("replying_to").open("") + } + })) + Alpine.bind("collapseButton", () => ({ + 'x-on:click'() { + Alpine.store("replying_to").open("") + } + })) +}) +''' +++ post-content +^- manx +;div#post-text + ;style:"{css}" + ;* (content contents.post) +== +++ comments +=/ cs (tap:form:tp children) +=/ l (houyi:plib children) +=/ length ?: .=(0 l) "No" "{<l>}" +=/ js "$store.replying_to.show('main')" +^- manx +;div#comments + ;a/"/board/p/{(board-path:lib post)}":"Switch to Board View" + ;h3:"{length} comments" + ;span.fl(x-bind "bigReplyButton"):"Leave a reply" + ;div(x-show js) + ;+ (reply-box-f [author.post id.post]) + == + ;ul.comment-list + =id "children{(scow %ud id.post)}" + ;* (turn cs comment) + == +== +++ grandchildren +|= p=full-node:tp ^- manx +=/ cs (tap:form:tp children.p) +;ul.comment-list + =id "children{(scow %ud id.p.p)}" + ;* (turn cs comment) +== +++ comment +|= [=pid:tp [p=post:tp c=full-graph:tp]] +^- manx +=/ author (get-name:lib -.pid) +=/ time (datetime-to-tape:string:sr id.pid "/") +=/ id=tape "{<`@ud`id.pid>}" +=/ js=tape "$store.replying_to.show('{id}')" +:: =/ uncollapse=manx ;span.cp(x-bind "collapseButton"):"[+] ({<(houyi p)>})" +:: =/ collapse ;span.cp(x-bind "collapseButton"):"[-]" +;li + =id "comment{id}" + ;div.comment-meta + ;div.row + ;a.comment-author/"/u/{author}":"{author}" + ; | + ;a.comment-time/"{time}":"{time}" + ; | + == + == + ;div.comment-content + ;* (content contents.p) + == + ;div(x-show js) + ;+ (reply-box-f pid) + == + ;span.fl.reply-prompt(id id, x-bind "ReplyButton"):"reply" + ;+ (grandchildren [p c]) +== +++ reply-box-f +|= =pid:tp +?: .=(%pawn (clan:title who)) +;p#respond:"You must login with an Urbit ID to comment" +(reply-box pid) +++ reply-box +|= =pid:tp +^- manx +=/ post-meta (enc:kaji [[author.post id.post] pid]) +=/ parent-id=tape "{<`@ud`id.pid>}" +=/ author %- trip (scot %p who) +;div#respond + ;span + =id "cancel-reply" + =class "fl" + =x-bind "cancelButton" + ; Cancel reply + == + ;form#reply-form + =kaji "poke" + =action "add-post" + ;label(for "comment"); + ;textarea#comment + =name "comment" + =cols "45" + =rows "8" + =maxlength "6552" + =autocomplete "off" + ; + == + ;div#author-data + ;span:"Posting as " + ;span:"{author}" + == + ;input(type "hidden", name "post-meta", value post-meta); + ;input#submit-comment(type "submit", value "Poast"); + == +== +++ html ^- manx +~& post +~& >> children + ;div + ;+ (post-header post) + ;+ post-content + ;+ comments + ;script:"{script}" + == +-- diff --git a/desk/web/components/sidebar.hoon b/desk/web/components/sidebar.hoon new file mode 100644 index 0000000..f0fa536 --- /dev/null +++ b/desk/web/components/sidebar.hoon @@ -0,0 +1,38 @@ +/- tp=trill-post +/+ *sortug +=< html +|% +++ css ^~ %- trip +''' +#sidebar{ + width: 25%; +} +''' +++ recent-comments +:: =/ comments ;; (list [c=post:tp p=post:tp]) (retrieve /recent-comments bowl) +;section#recent-comments + ;h6.widget-title:"Recent Comments" + :: ;ul + :: ;* %+ turn comments |= [c=post:tp p=post:tp] ^- manx + :: =/ author "" + :: =/ excerpt "" + :: ;li + :: ;span.comment-author-link:"{author}" + :: ;span:"on" + :: ;a/"{path.p}":"{(trip title.p)}" + :: ;span.excerpt:"{excerpt}" + :: == + :: == +== +++ html + ;div#sidebar + ;style:"{css}" + ;div#searchbox + ;input(type "text"); + :: bestposts + :: recentposts + ;+ recent-comments + :: archivedropdown + == + == +--
\ No newline at end of file diff --git a/desk/web/components/thread-preview.hoon b/desk/web/components/thread-preview.hoon new file mode 100644 index 0000000..758f6d3 --- /dev/null +++ b/desk/web/components/thread-preview.hoon @@ -0,0 +1,70 @@ +/- tp=trill-post, cnt=contact +/+ lib=boke, sigil=sigil-sigil, sr=sortug, plib=trill-utils, ui=trill-ui, wall +/= user /web/components/user + +|_ [t=thread:tp contacts=whoms:cnt =bowl:gall] ++* wal ~(. wall src.bowl) +++ is-blog (~(has in tags.t) 'blog') +++ pat %- trip %- spat ?: is-blog (blog-path:lib t) (weld /board path.t) +++ wide +:: =/ blocks (abbreviate-post:plib content.p.fn 500) +=/ u (user ship.pid.t contacts 40) +=/ reply-count (scow:parsing:sr %ud (lent replies.t)) +=/ ttags (tags:wal ~(tap in tags.t)) +;div.thread-preview + ;div.thread-author + ;+ -.u + ;+ +.u + == + ;div.thread-name + ;div + ;a/"{pat}" + ;h2:"{(trip title.t)}" + == + ;div.thread-tags + ;* %+ turn ttags |= tg=@t ;a.tag/"/board?t={(trip tg)}": {(trip tg)} + == + == + == + ;div.reply-count + ;div:"Posted {(post-date-ago:lib id.pid.t now.bowl %tam)} ago" + ;div:"{reply-count} replies" + == + ;div.dates + ;* last-reply + == +== +++ last-reply ^- marl + ?~ replies.t ~ + =/ usr (user ship.i.replies.t contacts 40) + ;+ ;div.last-reply + ;span: Last reply {(post-date-ago:lib id.i.replies.t now.bowl %tam)} ago + ;div.last-reply-author + ;span: by + ;+ name.usr + == + == +++ mobile + =/ usr (user ship.pid.t contacts 40) + =/ reply-count (scow:parsing:sr %ud (lent replies.t)) + +;a.thread-preview/"{pat}" +;div.thread-inner + ;h2:"{(trip title.t)}" + ;div.meta + ;div.author + ;div.by-author + ;span:"by" + ;+ +.usr + == + ;div:"{(post-date-ago:lib id.pid.t now.bowl %yau)} ago" + == + ;* ?~ replies.t ~ + ;+ ;div.reply + ;div:"{reply-count} replies" + ;div: Last {(post-date-ago:lib id.i.replies.t now.bowl %tam)} ago + == + == +== +== +-- diff --git a/desk/web/components/user.hoon b/desk/web/components/user.hoon new file mode 100644 index 0000000..871c029 --- /dev/null +++ b/desk/web/components/user.hoon @@ -0,0 +1,28 @@ +/- cnt=contact +/+ sigil=sigil-sigil, lib=boke +/+ lib=boke +|_ [u=@p =whoms:cnt avatar-size=@ud] +++ $ ^- [avatar=manx name=manx] +=/ ming (get-name:lib u) +=/ sig sigil(size avatar-size) + =/ sigl ?: (lth u (bex 64)) + ;div.avatar ;+ (sig u) == + =/ random (random-avatar:lib (jam u)) + ;img.avatar@"{random}"; +=/ nam ;div.name:"{ming}" + +=/ prof (~(get by whoms) [%.y u]) +?~ prof [sigl nam] +=/ avatar + =/ avatar-data (~(get by info.u.prof) %avatar) + ?~ avatar-data sigl + ?. ?=(%look -.u.avatar-data) sigl + ;img.avatar@"{(trip +.u.avatar-data)}"; +=/ name-div + =/ name-data (~(get by info.u.prof) %nickname) + ?~ name-data nam + ?. ?=(%text -.u.name-data) nam + ;div.name:"{(trip +.u.name-data)}" + +[avatar name-div] +-- diff --git a/desk/web/components/welcome.hoon b/desk/web/components/welcome.hoon new file mode 100644 index 0000000..c3c07f5 --- /dev/null +++ b/desk/web/components/welcome.hoon @@ -0,0 +1,20 @@ +=< html +|% +++ css ^~ %- trip +''' +#welcome{ +height: 114px; +text-align: center; +border-bottom-color: rgb(223, 223, 223); +border-bottom-style: dotted; +border-bottom-width: 1px; +} +''' +++ html + |= who=@p + ;div#welcome + ;style:"{css}" + ;h4:"Welcome to the all-new Spandrell site." + ;h4:"{(trip (scot %p who))}" + == +--
\ No newline at end of file diff --git a/desk/web/editor.hoon b/desk/web/editor.hoon new file mode 100644 index 0000000..f07d351 --- /dev/null +++ b/desk/web/editor.hoon @@ -0,0 +1,262 @@ +/- sur=boke, tp=trill-post +/+ ui=trill-ui, sr=sortug, plib=trill-utils, kaji, lib=boke +|_ [[=thread:tp =post:tp children=full-graph:tp] s=state:sur =bowl:gall] +++ css ^~ %- trip +''' +#admin{ + display:flex; + #editor{ + fieldset{ + border: none; + } + input[type=text]{ + width: 100%; + line-height: 1.5rem; + } + + textarea{ + width: 100%; + height: 50vh; + resize: none; + } + } + #sidebar{ + width: 30%; + height: 100vh; + overflow-y: scroll; + } + #right{ + width: 70%; + } + .admin-post{ + } + #comments{ + textarea{ + width: 100%; + height: 10rem; + } + } +} +''' +++ script +=/ json-tags=json %- pairs:enjs:format + %+ turn ~(tap by tags.s) |= [tag=@t p=(list *)] + :+ tag %n (scot %ud (lent p)) +=/ json-string %- trip %- en:json:html json-tags +^~ %+ weld +""" +const jsonString = '{json-string}'; +const allTags = JSON.parse(jsonString); + +""" +%- trip +''' +console.log(allTags, "tags") +const tagInput = document.getElementById("tag-input"); +const tagStore = document.getElementById("tag-store"); +const chipContainer = document.getElementById("chips"); +tagInput.addEventListener("keypress", handleKey); +tagInput.addEventListener("keyup", handleBackspace); + +const chipList = new Set(); + +function init(){ + setTimeout(() => { + console.log(tagStore.value, "tagstore") + const initTags = tagStore.value.split(","); + for (let tag of initTags){ + if (tag){ + chipList.add(tag); + loadChip(tag); + } + } + }, 500) +} +init(); + +function chipString(){ + const string = [...chipList].reduce((acc, i) => `${acc},${i}`); + // const string = JSON.stringify(Array.from(chipList)); + tagStore.value = string; +} +function addChip(itag){ + const tag = itag.toLowerCase(); + if (!chipList.has(tag) && tag.length > 0 && tag.length < 32) { + chipList.add(tag); + this.loadChip(tag) + tagInput.value = ""; + chipString(); + } +} +function removeChip(e){ + chipList.delete(e.target.innerText); + chipContainer.removeChild(e.target); + chipString(); +} +function loadChip(tag) { + const c = document.createElement('div'); + c.classList.add("chip"); + c.id = tag; + c.innerText = tag; + c.addEventListener("click", removeChip) + chipContainer.insertBefore(c, tagInput); +} +function handleBackspace(e){ + console.log(e.keyCode, "keyup") + console.log(e.target.selectionStart, "keyup") + if (!(e.keyCode === 8 && e.target.selectionStart == 0)) return + const chips = chipContainer.querySelectorAll('.chip'); + if (chips.length === 0) return + const to_delete = chipContainer.querySelector('.selected-chip'); + + if (to_delete) removeChip({target: to_delete}); + else { + const last_chip = chips[chips.length - 1]; + last_chip.classList.add("selected-chip"); + } +} +function handleKey(e) { + // autocomplete? + console.log(e.keyCode, "keycode") + console.log(e) + if (e.keyIdentifier == 'U+000A' || e.keyIdentifier == 'Enter' || e.keyCode == 13) e.preventDefault(); + if (e.keyCode === 13) addChip(e.target.value); +} + + +''' +++ form ^- manx +=/ is-edit !.=(*@da id.post) +=/ tag-string (tags-to-tape:ui tags.post) +=/ post-text (content-to-md:ui contents.post) +;div#editor + ;style:"{css}" + ;a/"/bianji" + ;h3:"编辑器" + == + ;form + =kaji "poke" + =action "add-thread" + ;* ?. is-edit ~ + ;+ ;input(type "hidden", name "editing", value (enc:kaji [~docteg-mothep id.post])); + ;fieldset + ;label:"title" + ;input(type "text", name "title", value (trip title.thread)); + == + ;fieldset + ;div:"Tags" + ;div#chips + ;input(type "text", placeholder "press enter to input individual tags, click on a tag to delete", enterkeyhint "enter", id "tag-input"); + ;input(type "hidden", id "tag-store", name "tags", value tag-string); + == + == + ;fieldset + ;textarea(name "text") + ; {post-text} + == + == + ;span#error-div; + ;input(type "hidden", name "error-div", value "#error-div"); + ;input(type "hidden", name "is-blog", value "is"); + ;+ ?. is-edit + ;fieldset + ;input(type "submit", value "Submit"); + == + ;fieldset.fl + ;input(type "submit", value "Edit"); + ;button + =kaji "poke" + =action "del-thread" + =name "pid" + =payload (enc:kaji pid.thread) + ; Delete + == + == + == + ;script:"{script}" +== +++ comments +;div#comments + ;+ ?~ children ;h3:"No comments" + ;div + ;h3:"{<(houyi:plib children)>} comments" + ;* %+ turn (tap:form:tp children) comment + == +== +++ comment +|= [=pid:tp p=full-node:tp] +^- manx +=+ [sip id]=pid +=/ author (get-name:lib sip) +=/ time (datetime-to-tape:string:sr id.p.p "/") +=/ id=tape (scow:parsing:sr %ud id) +=/ js=tape "$store.replying_to.show('{id}')" +:: =/ uncollapse=manx ;span.cp(x-bind "collapseButton"):"[+] ({<(houyi p)>})" +:: =/ collapse ;span.cp(x-bind "collapseButton"):"[-]" +;li + =id "comment{id}" + ;div.comment-meta + ;div.row + ;a.comment-author/"{author}":"{author}" + ; | + ;a.comment-time/"{time}":"{time}" + ; | + ;span.toggle + =target "comment-tree-{id}" + ; [-] + == + ;button + =kaji "poke" + =action "del-post" + =name "pid" + =payload (scow:parsing:sr %uw (jam pid)) + ; Delete + == + == + == + ;form.comment-content + =kaji "poke" + =action "edit-post" + ;textarea + =name "comment" + ; {(content-to-md:ui contents.p.p)} + == + ;input(type "hidden", name "id", value id); + ;input(type "hidden", name "error-div", value "#error-div"); + ;input(type "hidden", name "ship", value (scow %p sip)); + ;input(type "submit", value "Edit"); + == + :: ;span.fl(id id, x-bind "ReplyButton"):"reply" + ;+ (grandchildren p) +== +++ grandchildren +|= p=full-node:tp ^- manx +:: ?~ children.p ;ul.comment-list; +=/ cs=(list [pid:tp full-node:tp]) (tap:form:tp children.p) +;ul.comment-list + =id "comment-tree-{(scow:parsing:sr %ud id.p.p)}" + ;* (turn cs comment) +== +++ post-list ^- manx + =/ sorted %+ sort ~(tap by paths.s) + |= [[* p1=pid:tp] [* p2=pid:tp]] (gth id.p2 id.p1) + ;div#sidebar + ;* %+ roll sorted |= [[pat=path =pid:tp] acc=marl] + =/ ted (get:torm:tp threads.s pid) + ?~ ted acc + ?. (~(has in tags.u.ted) 'blog') acc + :_ acc + ;div.admin-post.fl + ;a/"/bianji{(trip (spat pat))}":"{(trip title.u.ted)}" + == + == +++ $ ^- manx +;div#admin + ;+ post-list + ;div#right + ;+ form + ;+ comments + == + ;script:"{collapsible:js:kaji}" +== +-- diff --git a/desk/web/feed/feed.hoon b/desk/web/feed/feed.hoon new file mode 100644 index 0000000..fafcb7e --- /dev/null +++ b/desk/web/feed/feed.hoon @@ -0,0 +1,47 @@ +/- boke, tp=trill-post, tlonc=tlon-channels, cnt=contact +/+ plib=trill-utils, ui=trill-ui, sr=sortug, lib=boke, const=constants, kaji +/= post-text /web/components/post-text +/= date-div /web/components/date +/= user /web/components/user +/= chat-manx /web/chat/chat +|_ [s=state:boke =bowl:gall] +++ css ^~ %- trip +''' +ddEventListener('kaji-scry', async () => highlight()); +''' ++$ section $?(%blog %comments %chat %threads %replies) +++ cursor +|= [d=(unit time) up=?] ^- marl + ?~ d ~ + =/ cursor-string (scow:parsing:sr %uw `@uw`u.d) + =/ name ?: up "before" "after" + =/ label ?: up "Newer Posts" "Older Posts" + =/ indicator ?: up "#spinner-up" "#spinner-down" + =/ button=manx + ;button + =kaji "iscroll" + =name name + =value cursor-string + =path "/search/f" + =cont "#search-results" + =indicator indicator + ; {label} + == + =/ upc + ;div + ;+ button + ;img#spinner-up.spinner@"spinner.svg"(style "display: none;"); + == + =/ downc + ;div + ;img#spinner-down.spinner@"spinner.svg"(style "display: none;"); + ;+ button + == + ;+ ?: up upc downc + +++ main ^- manx +;div#feed.fsy + ;style: {css} + ;h1.tc:"Feed" +== +-- diff --git a/desk/web/feed/router.hoon b/desk/web/feed/router.hoon new file mode 100644 index 0000000..9c61b4b --- /dev/null +++ b/desk/web/feed/router.hoon @@ -0,0 +1,39 @@ +/- boke, tp=trill-post, cnt=contact +/+ kaji, fetch-lib=fetch, plib=trill-utils, const=constants, sr=sortug, lib=boke +/= index /web/index +/= subscribe /web/subscribe +/= feedp /web/feed/feed + +|_ [rl=req-line:kaji s=state:boke =bowl:gall] ++* fetch ~(. fetch-lib [s bowl]) + feed ~(. feedp [s bowl]) +++ eyre-bail (error-response:kaji 404) +++ manx-bail (error-page:kaji 404) +:: +++ $ ^- eyre-res:kaji + =/ p pat.rl ::?. mob.rl pat.rl [%m pat.rl] + ?. (is-subscribed:lib src.bowl) nudge + ~& serving-search=rl(pat p) + ?+ p eyre-bail + ~ main + [%f rest=*] (fragment rest.p) + == +++ nudge + :- %page + ~& "pay me" + =/ sub ~(. subscribe src.bowl) + =/ nudgep (nudge:sub "Feed") + (index ~[nudgep] bowl) +++ main + :- %page + + (index ~[main:feed] bowl) +++ fragment +|= p=(pole knot) + :- %html manx-bail + :: =/ args (parse-params par.rl) + :: ~& args=args + :: ?~ args manx-bail + :: =/ res (search:fetch u.args) + :: (results:srch u.args res) +-- diff --git a/desk/web/index.css b/desk/web/index.css new file mode 100644 index 0000000..d41d32b --- /dev/null +++ b/desk/web/index.css @@ -0,0 +1,295 @@ + * { + box-sizing: border-box; + } + + /*@font-face { + font-family: 'Arvo'; + src: url('/fonts/arvo-regular.ttf') format('truetype'); + } + + @font-face { + font-family: 'Crimson Text'; + src: url('/fonts/crimsontext-regular.ttf') format('truetype'); + font-weight: normal; + font-style: normal; + }*/ + + :root { + --red05: rgba(255, 65, 54, 0.05); + --red100: rgba(255, 65, 54, 1); + --blue05: rgba(33, 157, 255, 0.05); + --blue30: rgba(33, 157, 255, 0.3); + --blue100: rgba(33, 157, 255, 1); + --black05: rgba(0, 0, 0, 0.05); + --black20: rgba(0, 0, 0, 0.2); + --black60: rgba(0, 0, 0, 0.6); + --white: rgba(255, 255, 255, 1); + --text: rgba(0, 0, 0, 1); + --hong: rgb(141, 15, 15); + --huang: rgb(230, 180, 60); + --lan: rgb(30, 60, 80); + } + + [data-theme=dark] { + --background-color: black; + --text-color: rgb(200, 200, 200); + } + + [data-theme=light] { + /* --background-color: #EFF1EC; */ + --background-color: white; + --text-color: black; + } + + html { + height: 100%; + color: var(--text-color); + -webkit-font-smoothing: antialiased; + } + + body { + margin: 0; + width: 100%; + height: 100%; + font-size: 16px; + font-weight: 400; + line-height: 1.5; + font-size: 1rem; + line-height: 1.618; + text-align: left; + color: black !important; + text-rendering: optimizeLegibility !important; + -webkit-font-smoothing: antialiased; + word-break: break-word; + } + + body>main>header { + border-bottom: 1px solid #eee; + text-align: center; + margin: 1rem auto; + padding: 1rem 0; + } + + h1 { + margin-bottom: 0px; + text-transform: uppercase; + letter-spacing: 1px; + font-size: 40px; + font-weight: 500; + line-height: 1.25; + color: #363636; + margin-top: 0; + } + + h4 { + font-size: 1.4rem; + } + + body>main>header a { + color: var(--text); + text-decoration: none; + background-color: transparent; + } + + h1, + h2, + h3, + h4, + h5, + h6 { + margin: 0 0 0.5em 0; + font-weight: 400; + line-height: 1.2; + font-family: 'Crimson Text'; + } + + p { + font-family: 'Crimson Text'; + font-size: 20px; + } + + a, + button, + input { + transition: all .4s ease; + } + + a, + .fl { + text-decoration: none; + color: #B70E0E; + cursor: pointer; + } + + body>main { + height: calc(100% - 4rem); + /* minus navbar */ + } + + .error-div, + #error-div { + color: red; + } + + .blog { + text-align: justify; + } + + /* desktop */ + @media (min-width: 935px) { + .blog { + width: 935px; + margin: auto; + } + } + + @media (max-width: 935px) { + body>main { + width: inherit; + } + + .blog { + padding: 0 0.5rem; + } + } + + #content { + flex: 0 0 70%; + max-width: 70%; + } + + input[type="submit"], + button, + .button { + border-color: #181818; + background-color: #181818; + padding: 0.5rem 1.25rem; + color: #fff; + font-size: 0.875rem; + line-height: 1.5; + border-radius: 0.2rem; + display: inline-block; + font-weight: 400; + text-align: center; + white-space: nowrap; + vertical-align: middle; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + cursor: pointer; + -webkit-transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, -webkit-box-shadow 0.15s ease-in-out; + transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, -webkit-box-shadow 0.15s ease-in-out; + -o-transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; + transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; + transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out, -webkit-box-shadow 0.15s ease-in-out; + font-family: 'Montserrat', sans-serif; + text-transform: uppercase; + letter-spacing: 1px; + font-size: 13px; + -webkit-transition: all .4s ease; + -o-transition: all .4s ease; + transition: all .4s ease; + } + + .hs { + white-space: nowrap; + overflow-x: auto; + } + + .cp { + cursor: pointer; + } + + .tabs { + display: flex; + justify-content: space-between; + + & .tab { + cursor: pointer; + padding: 0.2rem; + } + + & .tab.active { + border-bottom: 1px solid var(--red); + } + } + + /* mobile responsive */ + @media (max-width: 768px) { + body>main { + padding: 0.2rem; + } + } + + /* tailwindy stuff */ + .flex { + display: flex; + } + + .ml1 { + margin-left: 1rem; + } + + .ml2 { + margin-right: 1rem; + } + + .fhns { + height: 100%; + overflow: hidden; + } + + .fh { + height: 100%; + } + + .sy { + overflow-y: scroll; + } + + .fsy { + overflow-y: scroll; + height: 100%; + + } + + .fxc { + display: flex; + justify-content: center; + align-items: baseline; + } + + .f1 { + display: flex; + justify-content: space-between; + align-items: center; + } + + .gc { + position: fixed; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + z-index: 100; + } + + .axc { + position: absolute; + left: 50%; + transform: translateX(-50%); + } + + .xc { + display: block; + margin-left: auto; + margin-right: auto; + } + + .tc { + text-align: center !important; + } + + .bb { + border-bottom: 1px solid var(--text-color); + }
\ No newline at end of file diff --git a/desk/web/index.hoon b/desk/web/index.hoon new file mode 100644 index 0000000..7684289 --- /dev/null +++ b/desk/web/index.hoon @@ -0,0 +1,31 @@ +/- tp=trill-post +/+ *sortug +/= nav /web/layout/nav +/= footer /web/layout/footer +/= sidebar /web/components/sidebar +/* css %css /web/index/css +|_ [children=marl =bowl:gall] +++ $ + :: ;link(rel "icon", type "image/svg+xml", href (weld "data:image/svg+xml;utf8," favicon)); +^- manx + ;html + =data-theme "light" + ;head + ;meta(charset "utf-8"); + ;meta(name "viewport", content "width=device-width, initial-scale=1, shrink-to-fit=no"); + ;title:"Bloody Shovel 4" + ;style:"{(trip css)}" + ;script@"https://platform.twitter.com/widgets.js"(async "", charset "utf-8"); + ;link/"https://fonts.googleapis.com"(rel "preconnect"); + ;link/"https://fonts.gstatic.com"(rel "preconnect"); + ;link/"https://fonts.googleapis.com/css2?family=Arvo&family=Crimson+Text&family=Inter&display=swap"(rel "stylesheet"); + == + ;body + ;+ (nav bowl) + ;main + ;* children + == + :: ;+ footer + == + == +-- diff --git a/desk/web/invoice.hoon b/desk/web/invoice.hoon new file mode 100644 index 0000000..b3529c7 --- /dev/null +++ b/desk/web/invoice.hoon @@ -0,0 +1,87 @@ +|% +++ css ^~ %- trip +''' +body{ + width: 600; + margin: auto; + height: 100%; + overflow-y: hidden; +} +.row{ + display: flex; +} +.meta{ + justify-items: right; +} +''' +++ logo "https://s3.sortug.com/img/sortug-logo.png" +++ html +;html +;body +;style: {css} + ;div.row + ;div.logo + ;div:"Sortug Development" + ;img@"{logo}"; + == + ;h1: Invoice + == + ;div.row + ;div.dest + ;div:"Billed to:" + ;div:"Chorus One AG" + == + ;div.meta + ;div:"Invoice #20240205" + ;div:"Issued 2024/Feb/21" + ;div:"Due: On receipt" + == + == + ;table.items + ;tr + ;th:"Description" + ;th:"Quantity" + ;th:"Price" + ;th:"Amount" + == + ;tr.item + ;td.desc + ;div:"Urbit Development" + ;span:"Development of Tendermint implementation for %chain project" + == + ;td:"1" + ;td:"USD 2,500" + ;td:"USD 2,500" + == + == + ;div.row + ;div.payment + ;h2:"Payment Method" + ;div:"Bank name: HSBC Hong Kong" + ;div:"Bank address: 1 Queen's Road Central, Hong Kong" + ;div:"SWIFT code: HSBCHKHHHKH" + ;div:"Account number: 121-338933-833" + ;div:"Account name: Santiago Campos Losada" + == + ;table.total + ;tr + ;td:"Subtotal" + ;td:"USD 2,500" + == + ;tr + ;td:"Tax" + ;td:"-" + == + ;tr + ;td:"Discount" + ;td:"-" + == + ;tr.total + ;td:"Total due" + ;td:"USD 2,500" + == + == + == +== +== +-- diff --git a/desk/web/layout/footer.hoon b/desk/web/layout/footer.hoon new file mode 100644 index 0000000..dd12b8e --- /dev/null +++ b/desk/web/layout/footer.hoon @@ -0,0 +1,22 @@ +=< html +|% +++ css ^~ %- trip +''' +body>footer{ + text-align: center; + background: #181818; + color: rgba(255, 255, 255, 0.6); + padding: 0.5rem 0; + font-size: 90%; + letter-spacing: 0.5px; + border-top: 2px solid rgba(0, 0, 0, 0.15); + text-align: center; +} +''' +++ html + ;footer + ;style:"{css}" + ;div:"©︎ Spandrell 2011-2024 All rights reserved." + ;p:"Powered by %kaji" + == +-- diff --git a/desk/web/layout/nav.hoon b/desk/web/layout/nav.hoon new file mode 100644 index 0000000..871ab69 --- /dev/null +++ b/desk/web/layout/nav.hoon @@ -0,0 +1,310 @@ +/+ sigil=sigil-sigil +/* global-css %css /web/index/css +|_ =bowl:gall +++ css ^~ %- trip +''' +body > nav { + box-shadow: inset 0 2px 4px rgba(30, 30, 30, 0.15); + position: sticky; + top: 0; + z-index: 1020; + clear: both; + display: flex; + justify-content: space-between; + width: 100%; + height: 4rem; + text-align: center; + background: black; + color: rgb(220, 220, 220); + padding: 0 1rem; + z-index: 100; + box-sizing: border-box; + + & #top-left { + margin: 1rem 0; + color: inherit; + width: 60px; + } + & .menu{ + height: 55px; + } +& .option{ + display: block; + text-decoration: none; + color: #fff; + text-transform: uppercase; + font-family: 'Montserrat', sans-serif; + font-weight: 500; + font-size: 13px; + letter-spacing: 0.5px; + margin: 1.2rem 0.5rem; +} + + + & ul { + display: flex; + list-style: none; + margin: 0; + padding-left: 0; + position: absolute; + top: 50%; /* position the top edge of the element at the middle of the parent */ + left: 50%; /* position the left edge of the element at the middle of the parent */ + transform: translate(-50%, -50%); /* This is a shorthand of + translateX(-50%) and translateY(-50%) */ + + & li{ + margin: 0 0.5rem; + + & a, nav>form a { + display: block; + text-decoration: none; + color: #fff; + text-transform: uppercase; + font-family: 'Montserrat', sans-serif; + font-weight: 500; + font-size: 13px; + letter-spacing: 0.5px; + } + } + } + & a:hover { + color: rgba(255, 255, 255, 0.7); + } + + /* icon links style + & svg{ + fill: white; + } + & path{ + fill: white; + } + & circle{ + stroke: white; + } + & svg{ + float: left; + margin-top: 10px; + margin-left: 10px; + } + & .nav-right svg{ + height: 4rem; + border-left: 1px solid white; + border-right: 1px solid white; + margin-left: 0.5rem; + } */ + & .icon{ + width: 30px; + } + & form{ + background-color: var(--background-color); + margin: 0.7rem; + padding: 0 0.3rem; + } + & input[type=text]{ + background-color: var(--background-color); + outline: none; + padding: 0.3rem; + border: none; + } + + @media (max-width:935px) { + & input[type=text]{ + display: none; + } + & form{ + background-color: inherit; + width: 50px; + } + & .icon{ + filter: invert(); + } + } + & .sigil{ + padding: 6px 0; + } + +} + +''' +++ mobile-css ^~ %- trip +''' +body > nav{ + padding: 5px 1rem; + & #logo{ + position: absolute; + left: 50%; + transform: translateX(-50%); + width: 25%; + } + & #menu-button{ + width: 30px; + float: right; + } + #nav-menu{ + background-color: black; + position: fixed; + top: 25px; + right: 25px; + height: max-content; + width: 40%; + + & a{ + display: block; + padding: 5px; + color: white; + } + } +} +''' +++ smol +;nav + ;style:"{css}" + ;style:"{mobile-css}" + ;a/"/" + ;img#logo@"https://s3.spandrell.ch/assets/board/ui/tianming.svg"; + == + ;img#menu-button@"https://s3.spandrell.ch/assets/board/ui/menu.svg" + =kaji "toggle" + =targ "#nav-menu" + ; + == + ;div#nav-menu.cp + =role "link" + =kaji "clickaway" + =hidden "" + ;a/"/blog":"BLOG" + ;a/"/chat":"CHAT" + ;a/"/board":"BOARD" + ;a/"/feed":"FEED" + ;a/"/tv":"TV" + ;a/"/wiki":"WIKI" + :: ;a/"/apps/canvas":"CANVAS" + ;a/"/book":"BOOKS" + ;a/"/about":"ABOUT" + ;a/"/search":"SEARCH" + ;+ ?: .=(%pawn (clan:title src.bowl)) + ;a/"/login":"LOGIN" + ;a/"/user":"PROFILE" + == +== +:: TODO figure this out +++ ext ^- manx + =/ sip (scow %p src.bowl) + =/ dap (trip dap.bowl) + ;nav + =kaji "mobile" + =path "/f/mobile-nav" + =hide "clickaway" + ;style:"{css}" + ;style:"{(trip global-css)}" + ;a#top-left/"/" + ;img@"https://s3.spandrell.ch/assets/board/ui/tianming.svg"; + == + ;ul + ;li + ;a/"/blog":"BLOG" + == + ;li + ;a/"/chat":"CHAT" + == + ;li + ;a/"/board":"BOARD" + == + ;li + ;a/"/feed":"FEED" + == + ;li + ;a/"/tv":"TV" + == + ;li + ;a/"/wiki":"WIKI" + == + :: ;li + :: ;a/"/apps/canvas":"CANVAS" + :: == + ;li + ;a/"/book":"BOOKS" + == + ;li + ;a/"/about":"ABOUT" + == + == + ;div.flex.nav-right + :: ;form#global-search.f1 + :: =kaji "search" + :: =path "/search" + :: ;input(type "text", name "query"); + :: ;input.icon@"https://s3.sortug.com/img/icons/search-l.svg"(type "image"); + :: == + ;a.option/"/search":"search" + ;+ ?: .=(%pawn (clan:title src.bowl)) + ;a.option + =href "/login" + ; Login + == + ;a.sigil + =href "/user" + ;+ (sigil(size 48) src.bowl) + == + == + ;script@"/kaji.js"; + ;script@"/kaji-session.js?ship={sip}&dap={dap}"; + == +++ $ ^- manx + ;nav + =kaji "mobile" + =path "/f/mobile-nav" + =hide "clickaway" + ;style:"{css}" + ;a#top-left/"/" + ;img@"https://s3.spandrell.ch/assets/board/ui/tianming.svg"; + == + ;ul + ;li + ;a/"/blog":"BLOG" + == + ;li + ;a/"/chat":"CHAT" + == + ;li + ;a/"/board":"BOARD" + == + ;li + ;a/"/feed":"FEED" + == + ;li + ;a/"/tv":"TV" + == + ;li + ;a/"/wiki":"WIKI" + == + :: ;li + :: ;a/"/apps/canvas":"CANVAS" + :: == + ;li + ;a/"/book":"BOOKS" + == + ;li + ;a/"/about":"ABOUT" + == + == + ;div.flex.nav-right + :: ;form#global-search.f1 + :: =kaji "search" + :: =path "/search" + :: ;input(type "text", name "query"); + :: ;input.icon@"https://s3.sortug.com/img/icons/search-l.svg"(type "image"); + :: == + ;a.option/"/search":"search" + ;+ ?: .=(%pawn (clan:title src.bowl)) + ;a.option + =href "/login" + ; Login + == + ;a.sigil + =href "/user" + ;+ (sigil(size 48) src.bowl) + == + == + == +-- diff --git a/desk/web/layout/title.hoon b/desk/web/layout/title.hoon new file mode 100644 index 0000000..7675165 --- /dev/null +++ b/desk/web/layout/title.hoon @@ -0,0 +1,11 @@ +=< html +|% +++ html ^- manx + ;header + ;h1 + ;a/"/":"Bloody Shovel 4" + == + ;h4:"Nemo nos Salvabit" + :: ;h4:"不當而當亂也" + == +--
\ No newline at end of file diff --git a/desk/web/login.hoon b/desk/web/login.hoon new file mode 100644 index 0000000..017df8d --- /dev/null +++ b/desk/web/login.hoon @@ -0,0 +1,82 @@ +|_ who=@p +++ script ^~ %- trip +''' +console.log('oh hai') +''' +++ css ^~ %- trip +''' +#login{ + margin-top: 3rem; + & h1 { + text-align: center; + } + & form{ + margin: auto; + width: 50%; + text-align: center; + + & input[type=text]{ + outline: none; + padding: 0.5rem; + } + & button{ + display: block; + margin: 1rem auto; + } + + } +} +''' +++ $ ^- manx + :: =/ redirect=(unit @t) (get-header:http 'redirect' u.parsed) +:: =/ redirect-str ?~(redirect-url "" (trip u.redirect-url)) + =/ redirect-str "" +;div#login.blog + ;style: {css} + ;h1: Login + ;p: You can read the most of the blog or hang out at the public chat room without an account, but in order to leave comments or join the board you will need to login. + ;p: Bloody Shovel 4 does not keep any credentials from its visitors. There is no registration process. No passwords and emails or phone numbers here. + ;p: You can login with your Urbit ship. Input your Urbit ID below, you will be redirected to your own ship's interface to authorize the login. + ;form(action "/~/login", method "post") + ;p: Urbit ID + ;input.mono(type "text") + =name "name" + =id "name" + =placeholder "~sorreg-namtyv" + =required "true" + =minlength "4" + =maxlength "14" + =pattern "~((([a-z]\{6})\{1,2}-\{0,2})+|[a-z]\{3})"; + ;input(type "hidden", name "redirect", value redirect-str); + ;button(name "eauth", type "submit"):"Login" + == + ;p: If you don't have an Urbit ID please reach out to site@spandrell.ch and we'll help you get one. +== +:: ++ new-session-key +:: |- ^- @uv +:: =/ candidate=@uv (~(raw og (shas %session-key eny)) 128) +:: ?. (~(has by sessions.auth.state) candidate) +:: candidate +:: $(eny (shas %try-again candidate)) +:: :: are there cookies passed with this request? +:: =/ cookie-header=@t +:: %+ roll header-list.request +:: |= [[key=@t value=@t] c=@t] +:: ?. =(key 'cookie') +:: c +:: (cat 3 (cat 3 c ?~(c 0 '; ')) value) +:: :: is there an urbauth cookie? +:: :: +:: ?~ urbauth=(get-header:http (crip "urbauth-{(scow %p our)}") u.cookies) +:: ++ session-cookie-string +:: |= [session=@uv extend=?] +:: ^- @t +:: %- crip +:: =; max-age=tape +:: "urbauth-{(scow %p our)}={(scow %uv session)}; Path=/; Max-Age={max-age}" +:: %- format-ud-as-integer +:: ?. extend 0 +:: (div (msec:milly session-timeout) 1.000) +:: ++ cookie-stuff +:: ['set-cookie' (session-cookie-string session-id |)] +-- diff --git a/desk/web/manx.hoon b/desk/web/manx.hoon new file mode 100644 index 0000000..53e1d08 --- /dev/null +++ b/desk/web/manx.hoon @@ -0,0 +1,16 @@ +/- tp=trill-post +/+ plib=trill-utils +/= post-show /web/blog/post +/= index /web/index +|% +++ post-manx +|= [p=post:tp feed=gfeed:tp who=@p] ^- manx + =/ fn (node-to-full:plib p feed) +~(html post-show [fn who]) +++ layout +|= [body=manx =bowl:gall] ^- manx + (index ~[body] bowl) +++ post +|= [p=post:tp feed=gfeed:tp =bowl:gall] ^- manx +%+ index ~[(post-manx p feed src.bowl)] bowl +-- diff --git a/desk/web/merch.hoon b/desk/web/merch.hoon new file mode 100644 index 0000000..978cd3f --- /dev/null +++ b/desk/web/merch.hoon @@ -0,0 +1,67 @@ +=< merch +|% +++ css ^~ %- trip +''' +section{ + position: relative; + display: flex; + gap: 1rem; + align-items: center; + & img{ + width: 100px; + border: 1px solid black; + } + & .desc{ + .p{ + margin-top: 2.5rem; + } + & a{ + margin: 0 1ch; + } + } +} +''' +++ merch +;div.blog + ;style: {css} + ;h1.tc:"Books" + ;main + ;section + ;a/"https://westmartian.square.site/product/bs-1/1" + ;img@"https://s3.spandrell.ch/assets/book-vol1.jpg"; + == + ;div.desc + ;h2.axc: Bloody Shovel, Volumes 1-2 + ;div.p + ;p: If you would like a physical book with all the posts from this blog up to 2022, our friends at West Martian will sell it to you, in two volumes. Click on the image to go to their website. + ;p: I'm told it makes a wonderful gift, and a great prop at parties. + ;p: You can also find it on Amazon if you feel like paying extra to Jeff Bezos so he can buy a bigger yacht for his second wife. + ;p + ;span: We'll also send you an ebook (in any format you like) for + ;a/"/subscribe":"a yearly subscription." + == + == + == + == + ;section + ;img@"https://s3.spandrell.ch/assets/newbook.webp"; + ;div.desc + ;h2.axc: The History of Right Retreat + ;div.p + ;p + ;span: But there's more to come. An upcoming book, tentatively called "The History of Right Retreat", is in the works, in collaboration with our friends at + ;a/"https://passage.press":"Passage Publishing." + == + ;p: Think of it as a history book elaborating on Biological Leninism. + ;p + ;span: All + ;a/"/subscribe": Subscribers + ;span: to Bloody Shovel 4 will get an exclusive look as the book progresses. Once it done it will be sold at + ;a/"https://passage.press":"the Passage Press book store." + == + == + == + == + == +== +-- diff --git a/desk/web/nag.hoon b/desk/web/nag.hoon new file mode 100644 index 0000000..4c3e94d --- /dev/null +++ b/desk/web/nag.hoon @@ -0,0 +1,21 @@ +|% +++ css ^~ %- trip +''' +a{ + margin: 0 0.5ch; +} +''' +++ html +;div + ;style:"{css}" + ;p: It appears you don't have access to this content. + ;p + ;span: You might have to + ;a/"/login":"Login" + ;span: or + ;a/"/subscribe":"Subscribe" + ;span: to get access + == +== +++ something %hi +-- diff --git a/desk/web/oldrouter.hoon b/desk/web/oldrouter.hoon new file mode 100644 index 0000000..424b44e --- /dev/null +++ b/desk/web/oldrouter.hoon @@ -0,0 +1,130 @@ +/- tp=trill-post +/+ *server, sortug, lib=boke, ui=trill-ui +/= index /web/index +/= post-header /web/components/post-header +/= post-content /web/components/post-text +/= welcome /web/components/welcome +/= post-list /web/components/post-list +|_ =bowl:gall ++$ state +$: %0 + =feed:tp + paths=(map path post:tp) +== ++$ ret [(list card:agent:gall) state] ++$ order [eyre-id=@ta req=inbound-request:eyre] ++$ payloads [p=(list card:agent:gall) q=simple-payload:http] ++$ comment-req [text=@t thread=@da parent=@da author=@p] ++$ new-post [title=@t text=@t author=@p] +++ r +|= [=order =state] ^- ret +~& >> http-req=order +=/ met method.request.req.order +=/ req-line (parse-request-line url.request.req.order) +=/ pth=path :- met site.req-line +~& >>> path=`(list @tas)`pth +=/ pl=[payloads _state] +?+ pth :_ state (serve-404 req-line) + [%'GET' ~ ~] :_ state (serve-index req-line) :: "/" + [%'GET' @ @ @ @ *] :_ state (serve-post site.req-line) + [%'POST' *] (handle-post req-line body.request.req.order state) + :: [%get %blog *] serve-blog + :: [%get 'chat' *] serve-chat + :: [%get 'forum' *] serve-forum + :: [%get 'about' *] serve-about +== +:_ +.pl +%+ weld p.-.pl +%+ give-simple-payload:app eyre-id.order q.-.pl + + +:: TODO send the whole request instead of the req-line +++ serve-index +|= rl=request-line ^- payloads +=/ poasts ;; (list full-node:tp) (retrieve:sortug /index bowl) +:- ~ +%- html-response:gen +(index (welcome src.bowl) (post-list poasts) bowl) +++ serve-post +|= =path ^- payloads +=/ pst ;; full-node:tp (retrieve:sortug (weld /post path) bowl) +=/ post-show ~(. post-content pst src.bowl) +:- ~ +%- html-response:gen +(index (post-header pst) html:post-show bowl) +++ handle-post +|= [rl=request-line body=(unit octs) =state] ^- [payloads _state] +?+ site.rl :_ state (serve-error 404) + [%poast ~] :_ state (serve-error 404) + [%comment ~] (handle-comment body state) +== +++ handle-comment +|= [body=(unit octs) =state] ^- [payloads _state] +=/ cr=(unit comment-req) (parse-comment body) +?~ cr :_ state (serve-error 500) :: TODO not quite but anyway +~& > cr=cr +=/ blog-post (get:orm:tp feed.state thread.u.cr) +?~ blog-post :_ state (serve-error 404) +=/ parent (get:orm:tp feed.state parent.u.cr) +?~ parent :_ state (serve-error 404) +=/ new-post *post:tp +=/ comment-id now.bowl +=/ content-list (tokenize:ui text.u.cr) +?~ content-list [(serve-error 505) state] +=/ contents (gas:corm:tp *content-map:tp ~[[now.bowl content-list]]) +=/ p %= new-post +id comment-id +host our.bowl +author ship+author.u.cr +thread thread.u.cr +parent `parent.u.cr +contents contents +== +~& > p=p +=/ nc (~(put in children.u.parent) comment-id) +=/ npar u.parent(children nc) +=/ nf (put:orm:tp feed.state comment-id p) +=/ nff (put:orm:tp nf id.npar npar) +=/ ns state(feed nff) +=/ url %- crip "{(trip (spat path.u.blog-post))}#comment{<`@`comment-id>}" +~& >>> redirect-url=url :: redirect:gen doesn't change the method wtf +:_ ns `(redirect url) +++ redirect + |= redirect=cord + ^- simple-payload:http + [[303 ['location' redirect]~] ~] +++ parse-comment +|= body=(unit octs) +=/ kvm (handle-html-form:sortug body) +=/ comment (~(get by kvm) 'comment') +?~ comment ~ +=/ thread (~(get by kvm) 'thread') +?~ thread ~ +=/ parent (~(get by kvm) 'parent') +?~ parent ~ +=/ author (~(get by kvm) 'author') +?~ author ~ +=/ t (slaw %ud u.thread) +?~ t ~ +=/ p (slaw %ud u.parent) +?~ p ~ +=/ a (slaw %p u.author) +?~ a ~ +`:*(u.comment u.t u.p u.a) +++ serve-404 +|= =request-line +(serve-error 404) +++ serve-error +|= code=@ud +^- payloads +:- ~ +%- html-response:gen +%- as-octs:mimes:html +%- crip +%- en-xml:html +;html + ;body + ;p:"Error {<code>}" + == +== +-- diff --git a/desk/web/root.hoon b/desk/web/root.hoon new file mode 100644 index 0000000..ceb6e19 --- /dev/null +++ b/desk/web/root.hoon @@ -0,0 +1,91 @@ +/- b=boke, tp=trill-post, c=tlon-channels +/+ fetch-lib=fetch, sr=sortug +/= chat-page /web/chat/chat +|_ [s=state:b =bowl:gall] ++* fetch ~(. fetch-lib [s bowl]) +++ css ^~ %- trip +''' +section{ + display: flex; + width: 100%; + & .a{ + width: 50%; + } +} +h2{ + padding-bottom: 0.2rem; + border-bottom: 1px solid black; + text-align: center; +} +.chat-author{ + margin-right: 1ch; +} +.preview{ + padding: 0 0.8rem; + text-align: left; +} +''' +++ last-blog (thread-page-by-tags:fetch ~['blog'] [~ ~ 5] ~) +++ last-board (thread-page-no-wall:fetch [~ ~ 5] (some |=(t=thread:tp !(~(has in tags.t) 'blog')))) +++ last-chat + =/ pat /chat/(scot %p our.bowl)/chat/posts/newest/5/post + =/ scry ~(scry io:sr bowl) + =/ chat-posts (scry %channels pat paged-posts:c) + (tap:on-posts:c posts.chat-posts) +++ last-feed +:: TODO if gates show only spandrell4 posts +%ok +++ $ +=/ blog last-blog +=/ board last-board +=/ chat last-chat +=/ feed last-feed +;div.blog + ;style:"{css}" + ;div + ;h2: Now playing on Spandrell TV + ;a/"/tv":"Dune Week!" + ;p:"Dune (1984), Dune Part One (2021), Dune (2000 Mini Series), Children of dune (2003 Mini Series)" + == + ;section + ;div.a.blog-activity + ;h2: Last on Blog + ;ul.preview + ;* %+ turn p.blog |= t=thread:tp + ;li + ;a/"{(trip (spat path.t))}":"{(trip title.t)}" + == + == + == + ;div.a.board-activity + ;h2: Last on Board + ;ul.preview + ;* %+ turn p.board |= t=thread:tp + ;li + ;a/"{(trip (spat (weld /board path.t)))}":"{(trip title.t)}" + == + == + == + == + ;section + ;div.a.chat-activity + ;h2: Last on Chat + ;* %+ turn chat |= [time=@da up=(unit post:c)] + ?~ up ;span; =/ memo +<.u.up + =/ author ?: ?=(%pawn (clan:title author.memo)) "anon" (scow %p author.memo) + ;a/"/chat" + ;* %+ turn content.memo |= =verse:c + ?: ?=(%block -.verse) ;span; + ;div.preview.inline + ;span.chat-author:"{author}:" + ;* %+ turn p.verse tinline:chat-page + == + == + == + ;div.a.feed-activity + ;h2: Last on Feed + ;a/"/feed":"Coming soon!" + == + == +== +-- diff --git a/desk/web/router.hoon b/desk/web/router.hoon new file mode 100644 index 0000000..547a2f9 --- /dev/null +++ b/desk/web/router.hoon @@ -0,0 +1,270 @@ +/- *boke, tp=trill-post, cnt=contact, tlonc=tlon-channels +/+ kaji, plib=trill-utils, lib=boke, sr=sortug, const=constants +/= index /web/index +/= nav /web/layout/nav +:: +/= blog /web/blog/router +/= title /web/blog/title +:: +/= board /web/board/router +:: +/= feed /web/feed/router +:: +/= search /web/search/router +:: +/= chat-page /web/chat/chat +:: +/= tv /web/tv/router +/= tvp /web/tv/tv + +/= about /web/about +/= merch /web/merch +:: +:: common +/= modals /web/components/modals +/= cm /web/components/common +:: +/= root /web/root +/= login /web/login +/= subscribe /web/subscribe +/= user /web/user +/= editor /web/editor +:: + +/* spinner %noun /web/assets/spinner/svg +/* favicon %noun /web/assets/favicon/ico +|% +++ eyre-bail (error-response:kaji 404) +++ manx-bail (error-page:kaji 404) ++$ request +$% [%eyre p=eyre-order:kaji] + [%kaji tab=@t req=kaji-req] +== +++ route +|= [r=request =bowl:gall s=state] ^- kaji-res:kaji +|^ + ?- -.r + %eyre :- %res ^- eyre-res:kaji + =/ rl=req-line:kaji (parse-req:kaji req.p.r) + =/ met method.request.req.p.r + =/ fpath=(pole knot) [met pat.rl] + ?: ?=([%apps %canvas rest=*] pat.rl) (serve-canvas rest.pat.rl rl) + ?: ?=([~ @] ext.rl) (serve-assets rl) + :: ?: ?=([[%session ~] [~ %js]] [pat ext]:rl) :- %full (serve-other:kaji %js (crip "window.ship = {(trip (rsh 3 (scot %p our.bowl)))};")) + ?+ fpath eyre-bail + [%'GET' rest=*] (serve-get rl(pat rest.fpath)) + == + %kaji :- %sse ^- sse-res:kaji + ?- -.req.r + %blog-redi (redirect-post post.req.r .y .y) + %board-redi (redirect-post post.req.r .n .n) + %redi (ui-effect [%redi url.req.r]) + %tv-chat (give-tv-chat +.req.r) + %radio-chat (give-radio-chat +.req.r) + %chat-msg (give-chat-msg +.req.r) + == + == +++ kaji-bail :- [%tab ~] :~([%redi '/404']) +++ ui-effect |= e=effect:kaji ^- sse-res:kaji + :- [%tab ~] :~(e) +:: +:: Eyre handling +:: + ++ serve-assets + |= rl=req-line:kaji + ~& serving-assets=rl + ?+ [pat ext]:rl eyre-bail + [[%spinner ~] [~ %svg]] [%mime ['image' 'svg+xml' ~] spinner] + [[%favicon ~] [~ %ico]] [%mime ['image' 'x-icon' ~] favicon] + :: [[%fonts @t ~] [~ %ttf]] ~& pat.rl + :: ~& ~(key by fonts) + :: =/ font (~(got by fonts) 'name') + :: [%mime /application/octet-stream font] + == + + ++ serve-get + |= rl=req-line:kaji ^- eyre-res:kaji + =/ pat pat.rl + ?+ pat ~(show blog [rl s bowl]) + [~ ~] serve-root + [%blog rest=*] (blog [rl(pat rest.pat) s bowl]) + :: + [%board rest=*] (board rl(pat rest.pat) s bowl) + :: + [%feed rest=*] (feed rl(pat rest.pat) s bowl) + :: + [%search rest=*] (search rl(pat rest.pat) s bowl) + :: + [%tv rest=*] (tv rl(pat rest.pat) s bowl) + :: + :: users + [%login rest=*] serve-login + [%subscribe ~] serve-subscribe + [%logout ~] logout + [%user ~] serve-profile + [%user u=@t ~] (serve-user u.pat) + [%chat ~] serve-chat + [%about ~] serve-about + [%book ~] serve-merch + :: admin + [%bianji rest=*] (serve-editor rest.pat) + :: + [%f rest=*] (serve-fragment rest.pat) + == + + + ++ serve-root + :- %page + =/ page (root [s bowl]) + (index ~[title page] bowl) + ++ serve-login + :- %page + (index ~[(login src.bowl)] bowl) + ++ serve-profile :- %page + =/ page (user src.bowl s bowl) + (index ~[page] bowl) + + ++ serve-subscribe + :- %page + (index ~[(subscribe src.bowl)] bowl) + + ++ serve-user + |= suser=@t :- %page + =/ who (slaw %p suser) + ?~ who manx-bail + =/ page (user u.who s bowl) + (index ~[page] bowl) + :: + ++ serve-editor + |= p=path + :- %page + ?. (is-admin:lib src.bowl) manx-bail + =/ bunt [*thread:tp *full-node:tp] + =/ pid (~(get by paths.s) p) + =/ pp ?~ pid bunt + =/ poast (get:gorm:tp feed.s u.pid) + =/ ted (get:torm:tp threads.s u.pid) + ?~ ted bunt ?~ poast bunt + :- u.ted (node-to-full:plib u.poast feed.s) + =/ page=manx (editor pp s bowl) + (index ~[page] bowl) + + ++ serve-chat + :- %page + =/ contacts (get-contacts:cnt bowl) + =/ pat /chat/(scot %p our.bowl)/chat/posts/newest/200/post + =/ scry ~(scry io:sr bowl) + =/ chat-posts (scry %channels pat paged-posts:tlonc) + =/ chat-core ~(. chat-page [contacts bowl]) + =/ page (main:chat-core chat-posts) + (index ~[page] bowl) + + ++ serve-about + :- %page + (index ~[title about] bowl) + ++ serve-merch + :- %page + (index ~[merch] bowl) + + ++ serve-fragment + |= pat=(pole knot) :- %html + ?+ pat manx-bail + [%mobile-nav ~] ~(smol nav bowl) + == + + + ++ logout + :- %full + ^- simple-payload:http + [[303 ['location' '/~/logout'] ['redirect' '/']~] ~] + + :: + :: Kaji handling + :: + ++ redirect-post + |= [=post:tp blog-view=? is-blog=?] ^- sse-res:kaji + =/ ted (get:torm:tp threads.s thread.post) + ?~ ted kaji-bail + =/ pat-string=@t %- spat (get-path:lib path.u.ted blog-view is-blog) + =/ url ?~ parent.post pat-string + =/ hash (enc:kaji [author.post id.post]) + =/ id "comment-{hash}" + (crip "{(trip pat-string)}?goto={id}") + (ui-effect [%redi url]) + + + ++ give-tv-chat + |= [name=@t p=post:tp] + =/ m :: TODO FIX THIS CRAP. inner vs outer html is annoying af + ;div + ;+ (chat-msg:tvp p) + == + =/ effects :~ [%add m '#chat-container' %bottom ~] + [%custom *manx %s 'scroll'] == + :_ effects [%custom ~[/tv/our/[name]]] + ++ give-radio-chat + |= [s=@p p=*] + :: =/ m :: TODO FIX THIS CRAP. inner vs outer html is annoying af + :: ;div + :: ;+ (chat-msg:tvp p) + :: == + :: =/ effects :~ [%add m '#chat-container' %bottom ~] + :: [%custom *manx %s 'scroll'] == + :: :_ effects [%custom ~[/tv/our/(scot %p s)]] + :- [%tab ~] + ~ + + ++ give-chat-msg + |= [=flag:tlonc q=memo:tlonc] + =/ subpath /chat/(scot %p p.flag)/[q.flag] + =/ contacts (get-contacts:cnt bowl) + =/ tlonchat ~(. chat-page [contacts bowl]) + =/ m ;div ;+ (post-div:tlonchat q) == + :- [%custom ~[subpath]] + :~ [%add m '#chat-container' %bottom ~] + [%custom *manx %s 'scroll'] + == + + :: lets play with globs + +$ glob-reference + [hash=@uvH location=glob-location] + :: + +$ glob-location + $% [%http =cord] + [%ames =ship] + == + +$ version + [major=@ud minor=@ud patch=@ud] + +$ glob (map path mime) + +$ href + $% [%glob base=term =glob-reference] + [%site =path] + == + :: glob handling, TODO put in kaji.hoon + ++ serve-canvas + |= [p=(pole knot) rl=req-line:kaji] + =/ pat /charges/canvas + =/ scry ~(scry io:sr bowl) + =/ scry-res (scry %docket pat *) + =/ glob ((soft glob) scry-res) + ?~ glob eyre-bail + =/ glob u.glob + :: ~& glob=~(key by glob) + =/ suffix (weld p (drop ext.rl)) + ?: =(suffix /desk/js) + :+ %mime /text/js + 'window.desk = "canvas";' + =/ requested=path + ?: (~(has by glob) suffix) suffix + /index/html + =/ data=(unit mime) + (~(get by glob) requested) + ?~ data ~& >>> glob-not-found=suffix eyre-bail + :: =/ lmao ?: (cfind:sr 'start' (spat suffix) .n) ~& > `@t`q.q.u.data .n .n + :: =/ clean (replace:string:sr "/apps/canvas" "/canvas" (trip q.q.u.data)) + :: =. q.q.u.data (crip clean) + :: =/ lmao ?: (cfind:sr 'start' (spat suffix) .n) ~& >> `@t`q.q.u.data .n .n + + [%glob u.data] +-- +-- diff --git a/desk/web/search/router.hoon b/desk/web/search/router.hoon new file mode 100644 index 0000000..7e43327 --- /dev/null +++ b/desk/web/search/router.hoon @@ -0,0 +1,112 @@ +/- boke, tp=trill-post, cnt=contact +/+ kaji, fetch-lib=fetch, plib=trill-utils, const=constants, sr=sortug, lib=boke +/= index /web/index +/= search /web/search/search +/= subscribe /web/subscribe +|_ [rl=req-line:kaji s=state:boke =bowl:gall] ++* fetch ~(. fetch-lib [s bowl]) + srch ~(. search [s bowl]) +++ eyre-bail (error-response:kaji 404) +++ manx-bail (error-page:kaji 404) +:: +++ $ ^- eyre-res:kaji + =/ p pat.rl ::?. mob.rl pat.rl [%m pat.rl] + ?. (is-subscribed:lib src.bowl) nudge + ~& serving-search=rl(pat p) + ?+ p eyre-bail + ~ main + [%f ~] (search-fragment par.rl) + == +++ nudge + :- %page + =/ sub ~(. subscribe src.bowl) + =/ nudgep (nudge:sub "Search") + (index ~[nudgep] bowl) +++ main + :- %page + ~& >> params=~(tap by par.rl) + =/ args parse-params + ~& args=args + =/ page ?~ args init:srch + =/ res (search:fetch u.args) + (page:srch u.args res) + (index ~[page] bowl) +++ search-fragment +|= pmap=(map @t @t) + :- %html + =/ args parse-params + ~& args=args + ?~ args manx-bail + =/ res (search:fetch u.args) + (results:srch u.args res) +:: ++ inline-search +:: |= ssection=@t +:: =/ sec ((soft section) ssection) +:: ?~ sec bail +:: =/ args (parse-params par.rl) +:: ~& args=args +:: ?~ args bail +:: =/ res (search:fetch u.sec u.args) +:: (results:srch [u.sec u.args] res) +:: ++ dated-search +:: |= [ssection=@t date=@t] +:: =/ sec ((soft section) ssection) +:: ?~ sec bail +:: =/ interval=@dr +:: ?: .=('day' date) ~d1 +:: ?: .=('week' date) ~d7 +:: ?: .=('month' date) ~d30 +:: ?: .=('year' date) ~d365 ~s1 +:: ?: .=(~s1 interval) bail +:: =/ args (parse-params par.rl) +:: ~& args=args +:: ?~ args bail +:: =/ req=page-req:tp [(some (sub now.bowl interval)) ~ search-page-size:const] +:: =/ res (search:fetch u.sec query.u.args tags.u.args req) +:: (results:srch [u.sec u.args] res) + :: =/ sec (section:srch section) + :: =/ args (parse-params:srch par.rl) + :: ?~ args inline-search-error + :: =/ res (fetch-results:srch sec query.u.args req.u.args) + :: ?~ res inline-search-error + :: =/ =marl (res-to-marl:srch sec query.u.args u.res) + :: ;div + :: ;* marl + :: == + :: ++ inline-search-error + :: %- serve-html:kaji :_ .n %- add-error:kaji + :: %+ alert:kaji "An error ocurred" 3.000 + ++$ section $?(%blog %comments %chat %threads %replies) ++$ pars [=section query=@t tags=(list @t) req=page-req:tp] +++ parse-params ^- (unit pars) + =/ pmap par.rl + =/ query (~(get by pmap) 'query') ?~ query ~ + ?: .=(u.query '') ~ + :: =/ ts (~(get by pmap) 'tags') ?~ ts ~ + =/ =section + =/ ssec (~(get by pmap) 'section') ?~ ssec %blog + =/ tsec ((soft section) u.ssec) ?~ tsec %blog u.tsec + =/ sdr (~(get by pmap) 'interval') + =/ r=page-req:tp [~ ~ search-page-size:const] + =. r ?. ?=(^ sdr) r + =/ interval=@dr + ?: .=('day' u.sdr) ~d1 + ?: .=('week' u.sdr) ~d7 + ?: .=('month' u.sdr) ~d30 + ?: .=('year' u.sdr) ~d365 ~s0 + ?: .=(interval 0) r + r(newer (some (sub now.bowl interval))) + + =/ o (~(get by pmap) 'after') + =/ n (~(get by pmap) 'before') + =/ c (~(get by pmap) 'count') + =? older.r ?=(^ o) (slaw:parsing:sr %uw u.o) + =? newer.r ?=(^ n) (slaw:parsing:sr %uw u.n) + =. count.r ?~ c count.r + =/ cc (slaw %ud u.c) + ?~ cc count.r u.cc + + %- some + [section u.query ~ r] +-- diff --git a/desk/web/search/search.hoon b/desk/web/search/search.hoon new file mode 100644 index 0000000..1cf58d0 --- /dev/null +++ b/desk/web/search/search.hoon @@ -0,0 +1,441 @@ +/- boke, tp=trill-post, tlonc=tlon-channels, cnt=contact +/+ plib=trill-utils, ui=trill-ui, sr=sortug, lib=boke, const=constants, kaji, wall +/= post-text /web/components/post-text +/= date-div /web/components/date +/= user /web/components/user +/= chat-manx /web/chat/chat +|_ [s=state:boke =bowl:gall] ++* wal ~(. wall src.bowl) +++ css ^~ %- trip +''' +#query-string{ + font-weight: 700; + font-size: 1.3rem; +} +#search{ + + & .form{ + + & .row{ + padding: 0.5rem; + border-bottom: 1px solid var(--text-color); + align-items: center; + + & input{ + line-height: 2rem; + flex-grow:1; + } + & h2{ + margin: 0 1rem 0 0; + color: var(--text-color); + } +} + +#filters{ + display: flex; + justify-content: space-between; + padding-top: 0.5rem; + + & select{ + background-color: var(--background-color); + height: 2rem; + } +} + +} + & fieldset{ + display: block; +} + & section{ + margin: 2rem 0; + + & h3 { + font-size: 1.6rem; + } + } + & .res{ + border-bottom: 1px solid var(--text-color); + padding: 0.5rem; + & .name{ + font-weight: 600; + } + & .snip{ + padding: 0 1rem; + } + + /* comments */ + & .comment-meta{ + display: flex; + flex-wrap: wrap; + font-size: 0.9rem; + + & a{ + font-size: 0.9rem; + } + + & .sep{ + margin: 0 0.3rem; + } + } + + & a { + font-size: 1.3rem; + } + & .tag{ + margin: 0 0.3rem; + padding: 0.1rem; + background-color: var(--huang); + opacity: 0.9; + font-size: 0.7rem; + cursor: pointer; + } + } + & .not-found{ + margin-top: 4rem; + } +& .highlight{ + background-color: var(--huang); + } +& button{ + display: block; + margin: 1rem auto; + } +& .spinner{ + width: 50px; + height: 50px; + margin: 1rem auto; + } +& #spinner-zh{ + width: 100px; + height: 100px; +} +& .tabs { + box-shadow: 0 4px 8px 0 rgba(0,0,0,0.2); + border-radius: 5px; + overflow: hidden; + + & .tab { + background-color: #f1f1f1; + float: left; + border: none; + outline: none; + cursor: pointer; + padding: 14px 16px; + transition: 0.3s; + } + + & .tab:hover { + background-color: #ddd; + } + /* Style for active tab */ + & .tab.active { + background-color: #ccc; + } + } +} +@media (min-width: 800px){ + #search{ + width: 70%; + margin: auto; + } +} +''' +++ script ^~ %- trip +''' +function highlight(){ + const params = new URLSearchParams(new URL(window.location.href).search); + const query = params.get('query'); + const div = document.getElementById("search"); + const snips = div.querySelectorAll(".snip"); + const titles = div.querySelectorAll(".title"); + [...titles, ...snips].forEach(el => { + const h = el.innerHTML; + const r = new RegExp(`(${query.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')})`, 'gi'); + const h2 = h.replace(r, `<span class="highlight">$1</span>`) + el.innerHTML = h2 + }); +} +document.addEventListener("kaji-scry", (e) => highlight()); +addEventListener('DOMContentLoaded', async () => highlight()); +addEventListener('kaji-scry', async () => highlight()); +''' ++$ section $?(%blog %comments %chat %threads %replies) +++ cursor +|= [=pars d=(unit time) up=?] ^- marl + ?~ d ~ + =/ cursor-string (scow:parsing:sr %uw `@uw`u.d) + =/ name ?: up "before" "after" + =/ label ?: up "Newer Posts" "Older Posts" + =/ indicator ?: up "#spinner-up" "#spinner-down" + =/ button=manx + ;button + =kaji "iscroll" + =name name + =value cursor-string + =path "/search/f" + =cont "#search-results" + =indicator indicator + ; {label} + == + =/ upc + ;div + ;+ button + ;img#spinner-up.spinner@"spinner.svg"(style "display: none;"); + == + =/ downc + ;div + ;img#spinner-down.spinner@"spinner.svg"(style "display: none;"); + ;+ button + == + ;+ ?: up upc downc + +++ blog-result +|= [fn=full-node:tp snip=@t] ^- manx + =/ ttags (tags:wal ~(tap in tags.p.fn)) + ;div.res + ;header.f1 + ;div + ;a.title/"{(trip (spat (title-to-path:lib title.p.fn id.p.fn)))}":"{(trip title.p.fn)}" + ;div + ;* %+ turn ttags |= t=@t ;a.tag/"/blog?t={(trip t)}": {(trip t)} + == + == + ;div.post-date + ;* (date-div id.p.fn .y) + == + == + ;div.snip + ;p:"{(trip snip)}" + == + == +++ comment-result +|= [fn=full-node:tp snip=@t contacts=whoms:cnt] ^- manx + =/ thread (get:gorm:tp feed.s thread.p.fn) + ?~ thread ;span; + =/ thread-link=tape (trip (spat (title-to-path:lib title.u.thread id.u.thread))) :: TODO check for relative/absolute path + =/ thread-link=tape (find-board-path:lib paths.s u.thread) + =/ uid (enc:kaji [author.p.fn id.p.fn]) + =/ permalink=tape %+ weld thread-link "/{uid}" + =/ time-string=tape (post-date-ago:lib id.p.fn now.bowl %yau) + =/ usr (user author.p.fn contacts 32) +;div.res + =id "comment-{uid}" + ;div.comment-meta + ;a/"/u/{(scow %p author.p.fn)}" + ;+ name.usr + == + ;span.sep:"|" + ;a/"{permalink}":"{time-string} ago" + ;span.sep:"|" + ;a/"{thread-link}":"On: {(trip title.u.thread)}" + == + ;div.snip + ;p:"{(trip snip)}" + == +== +++ thread-result +|= [fn=full-node:tp snip=@t contacts=whoms:cnt] ^- manx + =/ thread-link=tape (find-board-path:lib paths.s p.fn) + =/ time-string=tape (post-date-ago:lib id.p.fn now.bowl %yau) + =/ usr (user author.p.fn contacts 32) + =/ ttags (tags:wal ~(tap in tags.p.fn)) +;div.res + ;header.f1 + ;div + ;a.title/"/board/p/{thread-link}":"{(trip title.p.fn)}" + ;div + ;* %+ turn ttags |= t=@t ;a.tag/"/board?t={(trip t)}": {(trip t)} + == + == + ;div.post-date:"{time-string} ago" + == + ;+ name.usr + ;div.snip + ;p:"{(trip snip)}" + == +== +++ reply-result +|= [fn=full-node:tp snip=@t contacts=whoms:cnt] ^- manx + =/ thread (get:gorm:tp feed.s thread.p.fn) + ?~ thread ;span; + =/ thread-link=tape (find-board-path:lib paths.s u.thread) + =/ uid (enc:kaji [author.p.fn id.p.fn]) + =/ permalink=tape %+ weld thread-link "/{uid}" + =/ time-string=tape (post-date-ago:lib id.p.fn now.bowl %yau) + =/ ttags (tags:wal ~(tap in tags.p.fn)) + =/ usr (user author.p.fn contacts 32) +;div.res + ;header.f1 + ;div + ;a/"/board/p/{permalink}":"{(trip title.p.fn)}" + ;div + ;* %+ turn ttags |= t=@t ;a.tag/"/board?t={(trip t)}": {(trip t)} + == + == + ;div.post-date:"{time-string} ago" + == + ;+ name.usr + ;div.snip + ;p:"{(trip snip)}" + == +== +:: +++ chat-result +|= [r=reference:tlonc =whoms:cnt] ^- manx +=/ chat-core ~(. chat-manx [whoms bowl]) +?- -.r +%post (post-div:chat-core +<.post.r) +%reply (post-div:chat-core +.reply.r) +== +++ make-params +|= [query=@t res=page-req:tp] +:: =/ newer ?~ newer.res "" "&before={(scow %uw `@uw`u.newer.res)}" +:: =/ older ?~ older.res "" "&after={(scow %uw `@uw`u.older.res)}" +:: =/ count ?: .=(count.res page-size:lib) "" "&count={(scow %ud count.res)}" +:: %- en-urlt:html +:: "?query={(trip query)}{newer}{older}{count}" +"?query={(trip query)}" +++ form +|= =pars +^- manx + ;form.form + =swap "swap" + =targ "#search-results" + =path "/search/f" + =show-params "show" + =indicator "#spinner-zh" + + ;div.flex.row + ;a/"/search" + ;h2:"Search" + == + ;input(type "text", name "query", value (trip query.pars)) + =placeholder "Search all Bloody Shovel Content" + =kaji "search" + =bounce "1000" + ; + == + :: ;fieldset + :: ;label + :: ; Tags + :: ;input(type "text", name "tags"); + :: == + :: == + == + ;div#filters.row + ;label + ; Section + ;select + =name "section" + =kaji "scry" + =path "/search/f" + ;* %+ turn ~["blog" "comments" "threads" "replies" "chat"] |= t=tape + ?: .=(section.pars (crip t)) + ;option + =value t + =selected "" + ; {t} + == + ;option + =value t + ; {t} + == + == + == + ;label + ; Date + ;select + =name "interval" + =kaji "scry" + =path "/search/f" + ;option + =value "all" + ; All time + == + ;option + =value "day" + :: =selected "" + ; Past 24h + == + ;option + =value "week" + ; Last week + == + ;option + =value "month" + ; Last month + == + ;option + =value "year" + ; Last year + == + == + == + == + == ++$ pars [=section query=@t tags=(list @t) req=page-req:tp] +++ chat-cursor +|= [query=@t p=chat-page:boke] ^- marl +~ +++ chatp +|= [query=@t r=page-req:tp p=chat-page:boke] ^- marl +?~ p.p + ;+ ;p.xc:"No results for {(trip query)} on Bloody Shovel Chats" +=/ contacts (get-contacts:cnt bowl) + %+ welp + ;* %+ turn p.p |= ref=reference:tlonc + (chat-result ref contacts) + ;* (chat-cursor query p) + +++ tp-page +|= [=pars p=search-page:boke] ^- marl +?~ res.p ~ + :: ;+ ;p:"No results for {(trip query.pars)} under section {(trip section.pars)}" +=/ contacts (get-contacts:cnt bowl) +?- section.pars + %blog %+ welp + ;* %+ turn res.p |= [fn=full-node:tp snip=@t] + (blog-result fn snip) + ;* (cursor pars older.p .n) + %comments %+ welp + ;* %+ turn res.p |= [fn=full-node:tp snip=@t] + (comment-result fn snip contacts) + ;* (cursor pars older.p .n) + %threads %+ welp + ;* %+ turn res.p |= [fn=full-node:tp snip=@t] + (thread-result fn snip contacts) + ;* (cursor pars older.p .n) + + %replies %+ welp + ;* %+ turn res.p |= [fn=full-node:tp snip=@t] + (reply-result fn snip contacts) + ;* (cursor pars older.p .n) + %chat ~ +== + +++ init ^- manx +;div#search.fsy + ;style: {css} + ;+ (form [%blog '' ~ [~ ~ search-page-size:const]]) + ;img#spinner-zh.gc@"spinner.svg"(style "display: none;"); + ;div#search-results; + ;script: {script} +== +++ page +|= [=pars res=search-res:boke] ^- manx +;div#search.fsy + ;style: {css} + ;img#spinner-zh.gc@"spinner.svg"(style "display: none;"); + ;+ (form pars) + ;* ?: .=(query.pars '') ;+ ;p:"Not found" ~ + ;+ (results pars res) + ;script: {script} +== +++ results +|= [=pars res=search-res:boke] ^- manx + ;div#search-results + ;* ?: ?=(%chat -.res) + (chatp query.pars req.pars +.res) + (tp-page pars +.res) + == +-- diff --git a/desk/web/subscribe.hoon b/desk/web/subscribe.hoon new file mode 100644 index 0000000..b8dac3d --- /dev/null +++ b/desk/web/subscribe.hoon @@ -0,0 +1,131 @@ +|_ who=@p +++ script ^~ %- trip +''' +console.log('oh hai') +''' +++ css ^~ %- trip +''' +#login{ + margin-top: 3rem; + padding-bottom: 3rem; + & h1 { + text-align: center; + } + & form{ + margin: auto; + width: 50%; + text-align: center; + + & input[type=text]{ + outline: none; + padding: 0.5rem; + } + & button{ + display: block; + margin: 1rem auto; + } + + } +} +''' +++ $ ^- manx + :: =/ redirect=(unit @t) (get-header:http 'redirect' u.parsed) +:: =/ redirect-str ?~(redirect-url "" (trip u.redirect-url)) + =/ redirect-str "" +;div#login.blog + ;style: {css} + ;h1: Subscribe + ;p: Some content in this website is only accessible to subscribers. As for why, keep reading on. + ;p + ;span: To subscribe just send me an Urbit DM to ~docteg-mothep, or an email to + ;a/"mailto:sub@spandrell.ch":"sub@spandrell.ch" + == + ;p: There's three kinds of subscriptions: + ;ol + ;li + ;p: Base Subscription: $5/month or $50/year. + == + ;li + ;p: Urbit Subscription: $10/month or $100/year. I'll give you a free Urbit planet and manage it for you. + == + ;li + ;p: Full Subscription: $20/month or $200/year. All the above, early access to my upcoming books and an encrypted @spandrell.ch mailbox. + == + == + ;p: I'll take any mainstream crypto, but can't take cards. + ;p:"Be reminded that I don't keep user data in this website; all logins work through Urbit, so you will need to run an Urbit instance to subscribe anyway" + ;p: Urbit IDs are permanent identities and some people might not want to use their regular planet to post here, in that case I recommend acquiring an Urbit subscription, that way you can have a second Urbit planet for shitposting purposes. + ;h2.tc: Subscriber privileges + ;p: Subscribing will give you the following privileges: + ;ul + ;li + ;p: Ability to comment on all blog posts, past and present. + == + ;li + ;p: Access to all boards in the Forum, including VIP. + == + ;li + ;p: Urbit or Email notifications for threads, blog posts or blog comment threads that you follow. + == + ;li + ;p: Ability to post anonymously or generate new identities. + == + ;li + ;p: Access to the VIP chat rooms. + == + ;li + ;p: Ability to Edit pages in the Wiki. + == + ;li + ;p: Access to the Feed page, where the community puts feeds together with Twitter and RSS content from across the web. + == + ;li + ;p: Access to the Search page, where all blog posts, comments, forum posts and chat messages are searchable. + == + == + ;h2.tc: Grift Rationale + ;p: Many friends have asked me since years ago why I don't start a Substack, or get a bluecheck on Twitter and start grifting there. + ;p:"There's many reasons for that; one being that I just dislike depending on web platforms that can kick me out any day without recourse. It's the current year, we can and should try to handle publishing and payments without needing to ask permission to boomers who if not hate us don't give a shit about us." + ;p: Most importantly, all web2 platforms require KYC. I'd have to doxx myself to Substack, Twitter or whatever. Which isn't that big of a deal these days; it seems the worst of Left-led cancel culture are over. And for all I know the people at Substack like my blog. Still, I'm not Curtis Yarvin, I don't know these people personally and have no reason to trust them. + ;p: I do have bills to pay though, and would like to be have more time to write here and provide a good service for my audience, both with writing and good community software. I firmly believe the internet needs a place where you can say nigger and I want to help. The website is still under construction, it's not fully featured yet, but we'll get there. + +== +++ nudge + |= wat=tape + =/ css %- trip 'a{margin-right: 1ch;}' + ;div.blog.tc + ;style: {css} + ;p:"{wat} page is only available to subscribers" + ;p + ;a/"/subscribe":"Click here" + ;span:"to subscribe to Bloody Shovel 4 and enjoy full access to all content and communities" + == + == +:: ++ new-session-key +:: |- ^- @uv +:: =/ candidate=@uv (~(raw og (shas %session-key eny)) 128) +:: ?. (~(has by sessions.auth.state) candidate) +:: candidate +:: $(eny (shas %try-again candidate)) +:: :: are there cookies passed with this request? +:: =/ cookie-header=@t +:: %+ roll header-list.request +:: |= [[key=@t value=@t] c=@t] +:: ?. =(key 'cookie') +:: c +:: (cat 3 (cat 3 c ?~(c 0 '; ')) value) +:: :: is there an urbauth cookie? +:: :: +:: ?~ urbauth=(get-header:http (crip "urbauth-{(scow %p our)}") u.cookies) +:: ++ session-cookie-string +:: |= [session=@uv extend=?] +:: ^- @t +:: %- crip +:: =; max-age=tape +:: "urbauth-{(scow %p our)}={(scow %uv session)}; Path=/; Max-Age={max-age}" +:: %- format-ud-as-integer +:: ?. extend 0 +:: (div (msec:milly session-timeout) 1.000) +:: ++ cookie-stuff +:: ['set-cookie' (session-cookie-string session-id |)] +-- diff --git a/desk/web/test.udon b/desk/web/test.udon new file mode 100644 index 0000000..0770e90 --- /dev/null +++ b/desk/web/test.udon @@ -0,0 +1,57 @@ +;> + +# H1 + +## H2 + +### H3 + +#### H4 + +##### H5 + +###### H6 + +This is a paragraph with _italics_, *bold* and +`inline code`. Sentences can be hard wrapped. + + +- unordered +- list + ++ ordered ++ list + +[link](https://urbit.org) + + + +``` +fenced codeblock +(note language spec not supported) +``` + +horizontal rule: +--- + +> block quotes + may be hard-wrapped if indented + +Backslash at end\ +of line adds linebreak + +Udon syntax may be prefixed with \*backslashes\* to escape. + +Hoon atom literals like ~sampel-palnet and ~.foo will +be rendered as inline code. + +;table + ;tr + ;td: Arbitrary + ;td: Sail + == + ;tr + ;td: is + ;td: allowed + == +== diff --git a/desk/web/thread.hoon b/desk/web/thread.hoon new file mode 100644 index 0000000..e88185d --- /dev/null +++ b/desk/web/thread.hoon @@ -0,0 +1,478 @@ +/- boke, tp=trill-post, cons=contact +/+ sr=sortug, plib=trill-utils, sigil=sigil-sigil, lib=boke, kaji, constants +/= post-content /web/components/post-text +|_ [fn=full-node:tp children=(list post:tp) page=@ud contacts=whoms:cons =bowl:gall] +++ thread-css ^~ %- trip +''' +body>main{ + width: 100%!important; +} +@media (max-width: 800px){ + body>main{ + padding: 0!important; + } +} +#board-thread{ + max-width: 1280px; + margin: auto; + +/* base styles */ + & header{ + & img{ + width: 20px; + margin-left: 1rem; + } + } + + & p{ + font-size: 1.1rem; + } + & .reply{ + display: grid; + border: 1px solid silver; + + & .author{ + margin-right: 1rem; + + & .avatar{ + max-height: 100px; + max-width: 88px; + } + & .name{ + font-weight: 500; + color: var(--hong); + text-align: center; + word-break: break-word; + } + } + + & .metadata { + & p{ + margin: -5px 0 0 0; + font-size: 14px; + } + & .buttons{ + display: flex; + img{ + height: 20px; + width: 20px; + margin: 5px 5px; + cursor: pointer; + } + } + + } + + & .content{ + text-align: left: + word-wrap: break-word; + + & p{ + padding: 0.5rem; + font-weight: 400; + overflow: hidden; + word-break: break-word; + white-space: normal; + margin: 1rem 0; + } + & blockquote{ + margin: 1rem 2rem 1rem 1rem; + padding: 0.4rem; + border: 1px solid grey; + border-radius: 2%; + } + } + } + & footer{ + width: 100%; + .tags{ + padding: 0; + font-size: 0.9rem; + flex-wrap: wrap; + + a{ + margin-left: 0.1rem; + } + } + } + + + /* desktop */ + + @media (min-width: 1000px){ + #posts{ + display: flex; + } + #replies{ + width: 83.33%; + } + } + @media(min-width: 800px){ + + & #sidebar{ + position: sticky; + top: 4rem; + right: 0; + align-self: flex-start; + } + + & #posts{ + + & .reply{ + padding: 1rem; + margin: 1rem; + grid-template-columns: 10% 90%; + grid-template-rows: 40px auto; + + & .author{ + grid-column-start: 1; + grid-column-end: 2; + grid-row-start: 1; + grid-row-end: 3; + } + + & .metadata{ + display: flex; + justify-content: space-between; + border-bottom: 1px solid grey; /* TODO darkmode */ + grid-column-start: 2; + grid-column-end: 3; + grid-row-start: 1; + grid-row-end: 2; + } + + & .content{ + grid-column-start: 2; + grid-column-end: 3; + grid-row-start: 2; + grid-row-end: 3; + + & img{ + margin: 0 auto; + } + } + } + } + } + /* mobile */ + @media(max-width: 800px){ + + + & #posts{ + display: block; + width: 100%; + + & .reply{ + padding-top: 10px; + grid-template-columns: 100px auto; + grid-template-rows: 80px auto; + + & .author{ + grid-column-start; 1; + grid-column-end: 2; + grid-row-start: 1; + grid-row-end: 2; + + & .avatar{ + height: 60px; + width: 60px; + display: block; + margin: 0 auto; + } + } + & .metadata{ + grid-column-start: 2; + grid-column-end: 3; + grid-row-start: 1; + grid-row-end: 2; + padding: 0; + border-bottom: 1px solid grey; + + & .buttons{ + width: 100%; + justify-content: space-between; + margin-top: 0.5rem; + } + } + & .content{ + grid-column-start: 1; + grid-column-end: 3; + grid-row-start: 2; + grid-row-end: 3; + + } + } + } + } + + + + + & #sidebar{ + padding-top: 2rem 0.5rem 0.5rem 0.5rem; + + & div{ + margin: 1rem 0; + } + + & #search-box{ + margin-top: 0.25rem; + + & input{ + width: 100%!important; + border: 1px solid var(--text-color); + } + } + } +} + +.reply-box{ + & .replying-to{ + display: flex; + + & .name{ + margin-left: 1rem; + } + } + & textarea{ + resize: none; + display: block; + outline: none; + width: 100%; + } + & input[type=submit]{ + margin-top: 0.5rem; + float:right; + } +} +''' +++ thread-js ^~ %- trip +''' +const buttons = document.querySelectorAll(".buttons"); +console.log(buttons, "buttons") +buttons.forEach(el => { + const parent = el.closest(".reply"); + const cb = el.querySelector(".copy-button") + cb.addEventListener("click", () => { + const path = `https://spandrell.ch/board/p/${parent.id}` + navigator.clipboard.writeText(path).then(res => { + console.log(res, "write to clipboard") + }).catch(er => { + console.log(er, "couldn't write to clipboard") + }) + }) + const db = el.querySelector(".down-button") + db.addEventListener("click", () => { + parent.querySelector("footer").scrollIntoView(); + }) +}); + +''' +++ $ ^- manx +=/ index (mul (dec page) board-page-size:constants) +=/ childlist (slice:sr children board-page-size:constants index) +;div#board-thread + ;style:"{thread-css}" + ;header.fxc + ;h1:"{(trip title.p.fn)}" + ;+ %+ hide-if:kaji ?|((is-admin:lib src.bowl) .=(author.p.fn src.bowl)) + edit-button + == + ;div#posts + ;div#replies + ;* %+ mapi:sr childlist thread-child + == + ;+ sidebar + == + ;script:"{thread-js}" +== +++ edit-button +=/ pid-string (enc:kaji [author.p.fn id.p.fn]) +;a/"/board/edit/{pid-string}" + ;img@"https://s3.spandrell.ch/assets/board/ui/edit.svg"; +== + +++ thread-child +|= [post-index=@ud =post:tp] ^- manx +=/ base-index (mul (dec page) board-page-size:constants) +=/ pind (add base-index +(post-index)) +=/ usr (user author.post) +=/ pid-string (enc:kaji [author.post id.post]) +=/ jammed-parents %- enc:kaji [op=[author.p.fn id.p.fn] parent=[author.post id.post]] +;div.reply(id pid-string) + ;div.author + ;+ avatar.usr + ;+ name.usr + == + ;div.metadata + ;+ (date post pind) + ;+ (buttons post) + == + ;div.content + ;* (post-content contents.post) + ;+ (footer post) + == + ;+ (reply-box name.usr jammed-parents) +== +++ user +|= u=@p ^- [avatar=manx name=manx] +=/ ming (get-name:lib u) +=/ sig sigil(size 80) +=/ sigl ?: ?=(%ship -.ming) (sig u) +=/ random (random-avatar:lib (jam u)) +;img.avatar@"{random}"; +=/ nam ;div.name:"{ming}" +=/ prof (~(get by contacts) [%.y u]) +?~ prof [sigl nam] +=/ avatar + =/ avatar-data (~(get by info.u.prof) %avatar) + ?~ avatar-data sigl + ?. ?=(%look -.u.avatar-data) sigl + ;img.avatar@"{(trip +.u.avatar-data)}"; +=/ name + =/ name-data (~(get by info.u.prof) %nickname) + ?~ name-data nam + ?. ?=(%text -.u.name-data) nam + ;div.name:"{(trip +.u.name-data)}" + +[avatar name] +++ date +|= [=post:tp post-index=@ud] +=/ date-string (datetime-to-tape:string:sr id.post "-") +=/ posted ;span.posted-date:"{date-string}" +=/ last-edit=time key:head:(pop:corm:tp contents.post) +=/ =marl ?: .=(last-edit id.post) posted^~ +:~ posted + ;span.updated-date:"{(datetime-to-tape:string:sr last-edit "-")}" +== +;div.date + ;p + ;* marl + == + ;p + ;span:"Post #{(scow:parsing:sr %ud post-index)}" + ;span.engagement:"" + == +== +++ buttons +|= =post:tp +:: =/ votes %+ roll ~(tap by reacts.engagement.post) |= [[s=@p [r=@t *]] acc=@] +:: ?: ?|(=(r "thumbsup") =(r "👍")) +;div.buttons + ;+ %+ hide-if:kaji ?|((is-admin:lib src.bowl) .=(author.post src.bowl)) + ;img@"https://s3.spandrell.ch/assets/board/ui/edit.svg"; + ;img.copy-button@"https://s3.spandrell.ch/assets/board/ui/copy.svg"; + ;img + =src "https://s3.spandrell.ch/assets/board/ui/upvote.svg" + ; + == + ;img@"https://s3.spandrell.ch/assets/board/ui/downvote.svg" + ; + == + ;img.down-button@"https://s3.spandrell.ch/assets/board/ui/down.svg"; + ;img@"https://s3.spandrell.ch/assets/board/ui/reply.svg" + =kaji "toggle" + =targ ".reply-box" + =modal "1" + ; + == + ;img.collapse-button + =src "https://s3.spandrell.ch/assets/board/ui/collapse.svg" + =kaji "toggle" + =targ ".content/.avatar/.uncollapse-button/.collapse-button" + ; + == + ;img.uncollapse-button + =src "https://s3.spandrell.ch/assets/board/ui/uncollapse.svg" + =kaji "toggle" + =targ ".content/.avatar/.uncollapse-button/.collapse-button" + =hidden "" + ; + == +== +++ reply-box +|= [author=manx jammed-parents=tape] ^- manx +:: %- serve-modal:kaji :_ ~ +;div.reply-box + =hidden "" + ;div.replying-to + ;div:"Replying to" + ;+ author + == + ;form + =kaji "poke" + =action "add-post" + ;textarea + =name "text" + =rows "10" + ; + == + ;input(type "hidden", name "parents", value jammed-parents); + ;input(type "submit", value "Send"); + :: == + == +== +++ footer +|= =post:tp +=/ count ~(wyt in tags.post) +=/ tags ?. (gth count 0) ;span:"" +=/ tag-links +%+ mapi:sr ~(tap in tags.post) + |= [i=@ t=@t] ^- manx + ?. .=(i (dec count)) + ;a/"/tags/{(trip t)}":"{(trip t)}, " + ;a/"/tags/{(trip t)}":"{(trip t)} " +;div.tags.flex + ; Tags: + ;* tag-links +== +;footer + ;+ tags +== +:: +++ sidebar +=/ from +((mul (dec page) board-page-size:constants)) +=/ to + =/ added (add from board-page-size:constants) + ?: (gth added (lent children)) (lent children) added +=/ froms (number:string:sr from) +=/ tos (number:string:sr to) +=/ post-count (number:string:sr (lent children)) +=/ max-page +((div (lent children) board-page-size:constants)) +=/ page-count %- number:string:sr max-page +=/ prev-page %- number:string:sr ?: .=(page 1) 1 (dec page) +=/ curr-page (number:string:sr page) +=/ next-page %- number:string:sr ?: .=(page max-page) page +(page) +;div#sidebar + ;button:"Back to Board" + ;div#search-box + ;form.flex + ;input(name "thread-search", placeholder "Search on Thread"); + ;button + ;img@"https://s3.spandrell.ch/assets/board/ui/search.svg"; + == + == + == + ;div#stats + ;p:"{post-count} Posts - {page-count} Pages" + ;p:"Showing posts {froms} to {tos}" + == + ;div#page-nav + ;a.button/"1":"1" + ;a.button/"{prev-page}" + ;img@"https://s3.spandrell.ch/assets/board/ui/left.svg"; + == + ;a.button:"{curr-page}" + ;a.button/"{next-page}" + ;img@"https://s3.spandrell.ch/assets/board/ui/right.svg"; + == + ;a.button/"{page-count}":"{page-count}" + == + ;button + =kaji "toggle" + =targ ".reply-box" + =modal "1" + ; Reply + == +== +-- diff --git a/desk/web/tv/router.hoon b/desk/web/tv/router.hoon new file mode 100644 index 0000000..6f4df21 --- /dev/null +++ b/desk/web/tv/router.hoon @@ -0,0 +1,39 @@ +/- boke, tp=trill-post, cnt=contact +/+ kaji, fetch-lib=fetch, plib=trill-utils, const=constants, sr=sortug, lib=boke +/= index /web/index +/= tvp /web/tv/tv +/= subscribe /web/subscribe +|_ [rl=req-line:kaji s=state:boke =bowl:gall] ++* fetch ~(. fetch-lib [s bowl]) + tv ~(. tvp [s bowl]) +++ eyre-bail (error-response:kaji 404) +++ manx-bail (error-page:kaji 404) +:: +++ $ ^- eyre-res:kaji + =/ p pat.rl ::?. mob.rl pat.rl [%m pat.rl] + :: ?. (is-subscribed:lib src.bowl) nudge + ?+ p eyre-bail + ~ main + [%f *] fragment + == +++ main + :- %page + =/ ut (~(get by here.tv.s) 'spandrell-tv') + ?~ ut manx-bail + =/ sta (~(get by schedule.u.ut) started.current.u.ut) + ?~ sta manx-bail :: TODO old station sorry + =/ page (main:tv ['spandrell-tv' %our 'Spandrell TV' ~docteg-mothep u.sta]) + (index ~[page] bowl) + +++ nudge + :- %page + =/ sub ~(. subscribe src.bowl) + =/ nudgep (nudge:sub "TV") + (index ~[nudgep] bowl) +++ fragment + :- %html + ?+ pat.rl manx-bail + [%f %s ~] ;div ;* tv-list:tv == + [%f %u ~] ;div ;* radio-list:tv == + == +-- diff --git a/desk/web/tv/tv.hoon b/desk/web/tv/tv.hoon new file mode 100644 index 0000000..5a3360a --- /dev/null +++ b/desk/web/tv/tv.hoon @@ -0,0 +1,285 @@ +/- *boke +/+ kaji, sr=sortug, lib=boke +/= post-text /web/components/post-text +|_ [s=state =bowl:gall] +++ css ^~ %- trip +''' +#tv{ + padding: 1rem; + + & main{ + margin-top: 0.5rem; + height: 50vw; + & #screen{ + } + & #chat{ + border: 1px solid var(--text-color); + h3{ + height: 1.5rem; + margin: 0; + } + + & #chat-container{ + overflow-y: scroll; + max-height: calc(100% - 3.5rem); + height: calc(100% - 3.5rem); + .chat-msg{ + padding: 0.5rem; + & .author{ + opacity: 0.8; + font-family: Inter; + } + & .chat-content{ + padding: 0.3rem 1rem; + & p{ + margin: 0; + } + } + } + } + & form{ + display: flex; + margin-bottom: 0; + border-top: 1px solid black; + + & input{ + border: none; + border-radius: 0; + } + + & input[type=text]{ + width: 100%; + height: 2rem; + } + & input[type=submit]{ + padding: 0.2rem; + } + } + } + } + & #radio-list{ + overflow-y: scroll; + max-height: 70vh; + & .entry{ + cursor: pointer; + } + } +} +#video{ + width: 100%; + background-color: black; +} +.tabs{ + display: flex; + gap: 1rem; + & .tab{ + cursor: pointer; + } +} +@media (min-width: 1200px){ +#tv main{ + display: flex; + align-items: stretch; + gap: 1rem; + +} +#screen{ + width: 75%; +} +#chat{ + width: 25%; +} +@media (max-width: 1200px){ +#screen{ + width: 100%; +} +#chat{ + width: 25%; +} + +} +.movie-name{ + font-size: 1.2rem; + font-weight: 500; +} +''' +++ script +|= sub-path=tape +^~ %+ weld %- trip +''' +function initVideo(videoSrc){ + const video = document.getElementById('video'); + video.autoplay = true; + console.log(videoSrc, "starting video") + + if (Hls.isSupported()) { + var hls = new Hls(); + hls.loadSource(videoSrc); + hls.attachMedia(video); + hls.on(Hls.Events.MANIFEST_LOADED, function (event, data) { + console.log("manifest loaded", [event, data]) + }); + hls.on(Hls.Events.MANIFEST_LOADED, function (event, data) { + console.log("manifest loaded", [event, data]) + }); + hls.on(Hls.Events.FRAG_LOADED, function (event, data) { + console.log("frag loaded", [event, data]) + }); + hls.on(Hls.Events.LEVEL_LOADED, function (event, data) { + console.log("level loaded", [event, data]) + }); + hls.on(Hls.Events.SUBTITLE_TRACK_SWITCH, function (event, data) { + console.log("sub switch", [event, data]) + }); + hls.on(Hls.Events.SUBTITLE_TRACK_LOADED, function (event, data) { + console.log("sub loaded", [event, data]) + }); + hls.on(Hls.Events.MANIFEST_PARSED, function (event, data) { + console.log("manifest parsed", [event, data]) + video.play(); + }); + } + // HLS.js is not supported on platforms that natively support HLS + else if (video.canPlayType('application/vnd.apple.mpegurl')) { + video.src = videoSrc; + video.addEventListener('loadedmetadata', function () { + video.play(); + }); + } + +} +document.addEventListener('DOMContentLoaded', () => { + const src = 'https://hydrogen.finnem.net/hls/live.m3u8'; + //const src = 'https://hls.urbit.cam/output.m3u8'; + initVideo(src); + const room = document.getElementById("chat-container"); + if (room) room.scrollTop = room.scrollHeight +}); + +document.addEventListener('kaji-fact', (event) => { + console.log(event.detail, "kaji fact") + if (event.detail.event === "scroll"){ + const room = document.getElementById("chat-container"); + if (room) setTimeout(() => room.scrollTop = room.scrollHeight, 50) + } + else if ("change-radio" in event.detail) + initVideo(event.detail["change-radio"]); +}); + +''' +""" +subscribe('{sub-path}'); + +""" +++ main +|= [symbol=@tas =twr] ^- manx + =/ author (scow %p owner.twr) + =/ name (trip symbol) + =/ sub-path "/tv/{(trip -.twr)}/{name}" + ~& sub-path=sub-path +;div#tv + ;style: {css} + ;main + ;div#screen + ;video#video + =controls "" + ; + == + ;+ (broadcast-metadata twr) + == + ;+ (chat-box symbol twr) + == + :: ;+ rl + ;script: {(script sub-path)} + ;script@"https://cdn.jsdelivr.net/npm/hls.js@latest"; +== +++ broadcast-metadata +|= =twr ^- manx + =/ author (scow %p owner.twr) + =/ stat-name (trip name.twr) + ?: ?=(%our -.twr) + =/ desc (trip description.tv.twr) + ;div.meta + ;div.movie-name:"{desc}" + ;div.movie-from:"from {stat-name} by {author}" + == + :: + =/ desc (trip description.p.twr) + ;div.meta + ;div:"{desc}" + ;div:"by {author}" + == + +++ rl ^- manx + ;div#radio-list + ;div.tabs + =kaji "scry" + =swap "swap" + =targ "#rlist" + ;div.tab + =path "/tv/f/s" + ; Spandrell TV + == + ;div.tab + =path "/tv/f/u" + ; Urbit Radio + == + == + ;div#rlist + ;* tv-list + == + == +++ radio-list ^- marl + %+ turn ~(tap by urbit.tv.s) |= [p=@p q=urbit-radio] + ;div.entry + =kaji "poke" + =action "change-radio" + =payload (enc:kaji p) + ;p:"{(trip description.q)}" + ;p:"by {(scow %p p)}" + == +++ tv-list ^- marl + %+ turn ~(tap by here.tv.s) |= [p=@t q=bstv] + ;div.entry + =kaji "poke" + =action "change-nradio" + =payload (trip p) + ;p:"{(trip playing.current.q)}" + ;p:"by {(scow %p owner.q)}" + == + +++ chat-box +|= [symbol=@tas =twr] +?: ?=(%urb -.twr) ;div; +;div#chat + ;h3.tc.bb:"Chat" + ;div#chat-container + ;* %+ turn (flop chat.tv.twr) chat-msg + == + ;form + =id "chat-composer" + =kaji "poke" + =action "add-radio-chat" + =wipe "yes" + ;input#text-input(type "text", name "input", placeholder "Nice", autocomplete "off"); + ;input(type "hidden", name "type", value (trip -.twr)); + ;input(type "hidden", name "owner", value (scow %p owner.twr)); + ;input(type "hidden", name "name", value (trip symbol)); + ;input(type "submit", value "⇛"); + == + +== +++ chat-msg +|= p=post:tp +:: =/ usr (user author.p whoms 32) + =/ author ?: (is-anon:lib author.p) "anon" (scow %p author.p) +;div.chat-msg + ;div.f1 + ;div.author:"{author}:" + ;div.time:"{(time-to-tape:string:sr id.p)}" + == + ;div.chat-content + ;* (content:post-text contents.p) + == +== +-- diff --git a/desk/web/user.hoon b/desk/web/user.hoon new file mode 100644 index 0000000..5076f0b --- /dev/null +++ b/desk/web/user.hoon @@ -0,0 +1,71 @@ +/- *boke, tp=trill-post, cnt=contact +/+ sigil=sigil-sigil, sr=sortug, wall +/= user /web/components/user +|_ [who=@p s=state =bowl:gall] +++ css ^~ %- trip +''' +#user{ + margin-top: 1rem; + + & .avatar svg{ + margin: auto; + } + .button{ + display: block; + width: max-content; + margin: auto; + } +} +''' +++ script ^~ %- trip +''' + const el = document.getElementById("logout"); + el.addEventListener("click", run); + async function run(){ + // const res = await fetch("/~/logout?redirect=/"); + const res = await fetch("/~/logout"); + if (res) window.location.href = "/"; + console.log(res, "res") + } +''' ++$ stats [count=@ud first=@da last=@da] +++ get-stats ^- stats + %+ roll (tap:gorm:tp feed.s) |= [[=pid:tp *] a=stats] + ?. .=(ship.pid who) a + =. count.a +(count.a) + =. first.a + ?: .=(first.a *@da) id.pid + ?: (lth id.pid first.a) id.pid first.a + =. last.a ?: (gth id.pid last.a) id.pid last.a + a + +++ $ + =/ wal ~(. wall src.bowl) + =/ contacts (get-contacts:cnt bowl) + =/ usr (user src.bowl contacts 100) + =/ is-self .=(src.bowl who) + =/ stats get-stats + =/ subscription (subscription-type:wal now.bowl) + + +;div#user.blog + ;style: {css} + ;h1.tc: User Profile + ;+ -.usr + ;h2.tc + ;+ +.usr + == + ;+ ?: .=(0 count.stats) ;p:"No posts" + ;div.stats + ;p: Post Count: {(number:string:sr count.stats)} + ;p: First post: {(date-to-tape:string:sr first.stats "/")} + ;p: Latest post: {(date-to-tape:string:sr last.stats "/")} + == + ;* ?. is-self ~ + ;* ?~ subscription + ;+ ;a.button/"/subscribe":"Subscribe" ~ + ;+ ;button#logout.button:"Logout" + ;script:"{script}" + +== +-- diff --git a/sqlite.hoon b/sqlite.hoon new file mode 100644 index 0000000..9d38dbe --- /dev/null +++ b/sqlite.hoon @@ -0,0 +1,163 @@ +|% +++ on-poke-noun |= a=* + ?: ?=(%sqlite a) dump-to-sqlite + ?: ?=(%licki a) init-lick + ?: ?=(%slick a) stop-lick + ?: ?=([%lick *] a) (send-lick +.a) + `this + +++ init-lick + ~& "init lick" + :_ this :_ ~ + =/ note=note-arvo [%l %spin /'licker.sock'] + [%pass /lick/init %arvo note] +++ stop-lick + :_ this :_ ~ + =/ note=note-arvo [%l %shut /'licker.sock'] + [%pass /lick/init %arvo note] +++ send-lick +|= a=* + :_ this :_ ~ + =/ note=note-arvo [%l %spit /'licker.sock' %noun a] + [%pass /lick/init %arvo note] + +++ dump-to-sqlite + =/ l (tap:gorm:tp f) + =/ l (scag 5 l) + =/ res + |- + ?~ l ~ + =/ poast i.l + ~& >> poast=poast + $(l t.l) + :: TODO prov + :: =/ tv-chat + :: =/ tvs (~(got by here.tv) 'spandrell-tv') + :: =/ sta (~(got by schedule.tvs) started.current.tvs) + :: chat.sta + :: =/ data=dump-type [(tap:gorm:tp feed) (tap:torm:tp threads) active-threads paths tags tv-chat] + :: =/ vase !>((jam data)) + :: =/ =soba:clay :_ ~ [/data/site-dump/(scot %da now.bowl)/jam %ins %noun vase] + :: =/ =nori:clay [%& soba] + :: =/ =task:clay [%info %blog nori] + :: =/ note=note-arvo [%c task] + :: [%pass /dump/[dap.bowl] %arvo note] + `this + + + + ++ user-sql |= [author=@p joined=@da avatar=@t display=(unit @t)] ^- (list card) + =/ tsn (scow:parsing:sr %ud (unm:chrono:userlib joined)) + =/ id (scow:parsing:sr %ud author) + =/ ava (trip avatar) + :: if planet + ?: (lth author (pow 2 32)) + =/ dis ?~ display (scow %p author) (trip u.display) + =/ sql + """ + INSERT OR IGNORE INTO users(id, joined,avatar, display) + VALUES({id}, {tsn}, '{ava}', '{dis}'); + """ + =/ sql2 + """ + INSERT INTO claims(user_id, protocol, value, notes) + VALUES({id}, 'urbit', '{(scow %p author)}', 'Set automatically on migration to BS5'); + """ + [(send-lick [%sql (crip sql)]) (send-lick [%sql sql2]) ~] + :: fooking comets + + =/ dis ?~ display "NULL" "{'(trip u.display)'}" + =/ sql + """ + INSERT OR IGNORE INTO users(id, joined, avatar, display) + VALUES({id}, {tsn}, '{ava}', '{dis}'); + """ + [(send-lick [%sql (crip sql)])]~ + + :: + ++ tag-sql |= tags=(set @t) ^- (list card) + %- ~(run in tags) |= tag=@t + =/ sql + """ + INSERT OR IGNORE INTO tags(tag) VALUES('{(trip tag)}') + """ + (send-lick [%sql (crip sql)]) + + ++ tagpost-sql |= [tag=@t post-id=tape] + + =/ sql + """ + INSERT OR IGNORE INTO tags_posts(tag, post_id) VALUES('{(trip tag)}', {post-id}) + """ + (send-lick [%sql (crip sql)]) + + ++ tagcomment-sql |= [tag=@t post-id=tape] + + =/ sql + """ + INSERT OR IGNORE INTO tags_comments(tag, comment_id) VALUES('{(trip tag)}', {post-id}) + """ + (send-lick [%sql (crip sql)]) + + ++ post-sql |= [ted=thread:tp =post:tp] ^- (list card) + =/ tsn (scow:parsing:sr %ud (unm:chrono:userlib id.post)) + =/ author-idn (scow %p author.post) + =/ title (trip title.ted) + =/ snippet (content-list-to-md:ui snip.ted) + =/ content (content-to-md:ui contents.post) + =/ url (trip (spat path.ted)) + =/ sql + """ + INSERT INTO posts(ts,author_id, title, content, snippet, url) + VALUES({tsn}, {author-idn}, '{title}', '{content}', '{snippet}', '{url}'); + """ + :- (send-lick [%sql (crip sql)]) + (~(run in tags.ted) |=(tag=@t (tagpost-sql tag tsn))) + + ++ comment-sql |= =post:tp ^- (list card) + + =/ tsn (scow:parsing:sr %ud (unm:chrono:userlib id.post)) + =/ user-id (scow %p author.post) + =/ content (content-to-md:ui contents.post) + =/ post-id (scow:parsing:sr %ud (unm:chrono:userlib +.pid.post)) + =/ parent-id ?~ parent.post "NULL" (scow:parsing:sr %ud (unm:chrono:userlib post-id)) + =/ sql + """ + INSERT INTO comments(ts,user_id, content, approved, comment_type, post_id, parent_id) + VALUES({tsn}, {user-id}, {content}, {approved}, {type}, {post-id}, {parent-id}); + """ + :- (send-lick [%sql (crip sql)]) + (~(run in tags.ted) |=(tag=@t (tagcomment-sql tag tsn))) + ++ insert-sql3 + """ + INSERT INTO tags(tag) + VALUES({tsn}, {user-idn}, {content}, {approved-n}, {type}, {post-idn}, {parent-idn}); + """ + ++ ted-cards |= ted=thread:tp ^- (list card) + + =/ post (get:gorm:tp feed pid.ted) + ?~ post ~& >>> nooooo-post=ted !! + =/ user-cards (user-sql author.u.post id.u.post '' ~) + =/ tags-cards (tag-sql tags.ted) + =/ post-cards (post-sql ted u.post) + %+ weld user-cards %+ weld tags-cards post-cards + + ++ post-cards |= =post:tp ^- (list card) + + =/ user-cards (user-sql author.post id.post '' ~) + =/ tags-cards (tag-sql tags.post) + =/ post-cards (comment-sql post) + %+ weld user-cards %+ weld tags-cards post-cards + +++ on-arvo + |= [=(pole knot) =sign-arvo] + ?: ?=([%lick %soak *] sign-arvo) + ?+ [mark noun]:sign-arvo `this + [%connect ~] ((slog 'socket connected' ~) `this) + [%disconnected ~] ((slog 'socket disconnected' ~) `this) + [%error *] ((slog leaf+"socket error {(trip ;;(@t noun.sign-arvo))}" ~) `this) + [%noun *] ((slog leaf+"socket noun {(trip ;;(@t noun.sign-arvo))}" ~) `this) + == + `this + +-- |