on master help sign in
98 files changed+11583
since splitsnapshots
unifiedsplit
.gitignore+2 README.md+125 RELEASING.md+166 desk/app/sphinx.hoon+431 desk/desk.bill+2 desk/desk.docket-0+11 desk/gen/get.hoon+9 desk/gen/metaphone.hoon+6 desk/gen/publish-all.hoon+29 desk/gen/publish.hoon+9 desk/gen/ranks.hoon+37 desk/gen/state.hoon+8 desk/gen/validate.hoon+6 desk/lib/gossip.hoon+826 desk/lib/metaphone.hoon+192 desk/lib/pals.hoon+24 desk/lib/sift.hoon+250 desk/lib/sphinx-json.hoon+72 desk/lib/sphinx.hoon+255 desk/lib/validate-url.hoon+20 desk/mar/declarations.hoon+14 desk/mar/declare.hoon+14 desk/mar/directory-listing.hoon+13 desk/mar/directory.hoon+14 desk/mar/gossip/rumor.hoon+11 desk/mar/pals/command.hoon+22 desk/mar/remove.hoon+14 desk/mar/search.hoon+14 desk/mar/state.hoon+12 desk/mar/tags.hoon+14 desk/sur/pals.hoon+41 desk/sur/sphinx.hoon+139 desk/sys.kelvin+1 desk/ted/publish-all.hoon+40 flake.lock+63 flake.nix+98 ui/.gitignore+8 ui/.nvmrc+1 ui/index.html+17 ui/package-lock.json+5678 ui/package.json+48 ui/postcss.config.js+8 ui/public/android-chrome-512x512.png ui/public/manifest.json+14 ui/src/api.ts+12 ui/src/app.tsx+55 ui/src/assets/apple-touch-icon.png ui/src/assets/favicon.ico ui/src/assets/favicon.svg+12 ui/src/assets/safari-pinned-tab.svg+54 ui/src/components/CenterColumn.tsx+6 ui/src/components/ErrorMessage.tsx+26 ui/src/components/Filter.tsx+55 ui/src/components/Layout.tsx+75 ui/src/components/Listing.tsx+74 ui/src/components/ListingImage.tsx+26 ui/src/components/Listings.tsx+41 ui/src/components/Logo.tsx+13 ui/src/components/Meta.tsx+41 ui/src/components/Paginator.tsx+129 ui/src/components/PostOptions.tsx+56 ui/src/components/SearchInput.tsx+32 ui/src/components/Spinner.tsx+11 ui/src/components/TagCloud.tsx+18 ui/src/components/TagField.tsx+157 ui/src/env.d.ts+15 ui/src/keys.ts+14 ui/src/logic/useMedia.ts+25 ui/src/logic/utils.ts+11 ui/src/main.tsx+11 ui/src/manage-listings/AllListings.tsx+65 ui/src/manage-listings/Apps.tsx+92 ui/src/manage-listings/Groups.tsx+99 ui/src/manage-listings/MyListings.tsx+34 ui/src/manage-listings/Notebooks.tsx+70 ui/src/manage-listings/Post.tsx+142 ui/src/manage-listings/Posts.tsx+122 ui/src/pages/Search.tsx+113 ui/src/pages/Tag.tsx+82 ui/src/routes.ts+16 ui/src/state/apps.ts+39 ui/src/state/groups.ts+76 ui/src/state/pals.ts+62 ui/src/state/posts.ts+108 ui/src/state/search.ts+49 ui/src/state/tags.ts+21 ui/src/styles/base.css ui/src/styles/components.css+16 ui/src/styles/index.css+8 ui/src/styles/utilities.css+3 ui/src/types/index.ts+304 ui/src/types/sphinx.ts+52 ui/src/utils.ts+196 ui/src/vite-env.d.ts+1 ui/src/window.ts+8 ui/tailwind.config.js+19 ui/tsconfig.json+19 ui/vite.config.ts+20
.gitignorenew file+2
@@ -0,0 +1,2 @@
1+/result
2+/result-*
README.mdnew file+125
@@ -0,0 +1,125 @@
1+# sphinx
2+
3+A search engine powered by you and your pals for finding answers to your
4+riddles.
5+
6+sphinx keeps a directory of listings: apps, groups, notebook posts and links.
7+The listings you publish go to your mutual pals and on to their mutual pals,
8+theirs come to you, and you search everything you've received.
9+
10+## Install
11+
12+sphinx runs on the kernels listed in `desk/sys.kelvin`, currently
13+`[%zuse 408]`. Check your ship first: in the dojo, `+vats %base` must show
14+`/sys/kelvin: [%zuse 408]`. If it shows an older kernel, let your ship finish
15+its update first. If the update is blocked, Landscape lists the apps that
16+block it, and `|bump` suspends them.
17+
18+Then, in your ship's dojo:
19+
20+```
21+|install ~donmec-sallud %sphinx
22+```
23+
24+For a new install, you can also search for ~donmec-sallud in Landscape and
25+install sphinx from there.
26+
27+sphinx shares listings through %pals. Install it with
28+`|install ~paldev %pals` and add your friends as pals. Without %pals you only
29+see your own listings.
30+
31+### Moving from ~nocsyx-lassul
32+
33+sphinx used to be distributed from ~nocsyx-lassul. Its last release there
34+only supports `[%zuse 412]`, so it can't run on a current ship. On a
35+`[%zuse 412]` ship it blocks the kernel update until you `|bump`. After the
36+kernel check above, switch it to ~donmec-sallud in the dojo:
37+
38+```
39+|install ~donmec-sallud %sphinx
40+```
41+
42+Your listings are kept. Use the dojo for this: Landscape's Get App can't
43+switch an existing install. It asks ~nocsyx-lassul again, and docket refuses
44+because sphinx is already installed.
45+
46+If you ran `|install` before your ship reached `[%zuse 408]`, sphinx stays
47+suspended after the update, and another `|install` only prints
48+`already syncing`. Run `|uninstall %sphinx`, then
49+`|install ~donmec-sallud %sphinx` again. Your listings are kept.
50+
51+## Development
52+
53+The repo has two parts:
54+
55+- `desk/`: the Hoon agent, its marks and libraries, and the docket file.
56+- `ui/`: the web interface, built with [React], [TypeScript],
57+ [Tailwind CSS] and [Vite].
58+
59+### Build
60+
61+With Nix:
62+
63+```sh
64+nix build .#desk -o result-desk # the desk; Nix makes its files read-only
65+nix build .#glob -o result-glob # the UI, built for /apps/sphinx/
66+```
67+
68+To put the desk on a test ship, copy it writable and with `--delete`, as in
69+RELEASING.md step 2. vere aborts at `|unmount` if the mount is read-only.
70+
71+```sh
72+chmod -R u+w result-desk-rw 2>/dev/null; rm -rf result-desk-rw &&
73+cp -RL result-desk result-desk-rw && chmod -R u+w result-desk-rw &&
74+rsync -rpc --delete result-desk-rw/ <pier>/sphinx/
75+```
76+
77+The desk output adds what `desk/` needs from urbit's `base-dev` and
78+landscape's `desk-dev`. Both are pinned in `flake.nix` for the kelvin in
79+`desk/sys.kelvin`. When you port sphinx to a new kernel, update those two
80+inputs together with `desk/sys.kelvin`.
81+
82+Without Nix, run `npm install` and `npm run build` in `ui/` to build the UI
83+into `ui/dist/`. Use the Node version in `ui/.nvmrc`.
84+
85+To publish a release from ~donmec-sallud, follow [RELEASING.md](RELEASING.md).
86+
87+### Working on the UI
88+
89+You need a running ship with sphinx installed. In `ui/`:
90+
91+1. Run `npm install`.
92+2. Create `ui/.env.local` with `VITE_SHIP_URL=<URL>`, where `<URL>` is your
93+ ship's web address, for example `http://localhost:8080`. Git ignores this
94+ file.
95+3. Run `npm run dev` and open the address it prints.
96+
97+The dev server sends every request except those for the interface itself to
98+the ship, so you see live data. Vite reloads the page as you change the code.
99+
100+### The tile image
101+
102+The tile is inlined in `desk/desk.docket-0` as a `data:` URI, so Landscape
103+doesn't load it from another server.
104+
105+To get the SVG out:
106+
107+```sh
108+sed -n "s|^ image+'data:image/svg+xml;base64,\(.*\)'\$|\1|p" desk/desk.docket-0 | base64 -d > tile.svg
109+```
110+
111+To put a new one in, print a new `image+` line and replace the old line in
112+`desk/desk.docket-0` with it:
113+
114+```sh
115+printf " image+'data:image/svg+xml;base64,%s'\n" "$(base64 < tile.svg | tr -d '\n')"
116+```
117+
118+Keep the rest of the file as it is. Docket rewrites the file when a glob is
119+uploaded, and the hash copy-back in RELEASING.md should only change the hash.
120+A new tile doesn't need a new glob.
121+
122+[react]: https://react.dev/
123+[typescript]: https://www.typescriptlang.org/
124+[tailwind css]: https://tailwindcss.com/
125+[vite]: https://vitejs.dev/
RELEASING.mdnew file+166
@@ -0,0 +1,166 @@
1+# Releasing sphinx
2+
3+sphinx is published from ~donmec-sallud. Ships install it with
4+`|install ~donmec-sallud %sphinx` and then follow it: the desk syncs from
5+~donmec-sallud's `%sphinx` desk, and docket fetches the UI (the glob) over ames
6+from ~donmec-sallud.
7+
8+A release has three parts:
9+
10+1. **Desk**: copy `nix build .#desk` into ~donmec-sallud's mounted `%sphinx`
11+ desk and commit it.
12+2. **Glob**: if the UI changed, upload `nix build .#glob` at `/docket/upload`.
13+ Docket hashes it and writes the hash into the desk's `desk.docket-0`.
14+3. **Hash copy-back**: copy that `desk.docket-0` back into the repo and commit
15+ it.
16+
17+Never skip the copy-back. On every commit of the desk, docket compares the hash
18+in `desk.docket-0` with the glob it serves, and when they differ it drops the
19+glob and waits for a new upload. So a stale hash in the repo takes the UI down
20+at the next release, on ~donmec-sallud and on every ship that installed
21+sphinx, until the glob is uploaded again.
22+
23+## Before you start
24+
25+- [ ] ~donmec-sallud runs a kernel listed in `desk/sys.kelvin`. In its dojo,
26+ `+vats %base` prints it on the `/sys/kelvin:` line. If it isn't listed,
27+ port the desk to that kernel first.
28+- [ ] Optional: bump `version` in `desk/desk.docket-0`. Landscape and the
29+ sphinx footer show it.
30+- [ ] Everything is committed and pushed. The release is whatever the repo
31+ builds.
32+
33+The commands below use these shell variables:
34+
35+```sh
36+server=user@host # ssh login of the user that runs ~donmec-sallud's vere and owns the pier
37+pier=/path/to/donmec-sallud # the pier directory on that machine
38+```
39+
40+## 1. Build
41+
42+From the repo root:
43+
44+```sh
45+nix build .#desk -o result-desk
46+nix build .#glob -o result-glob
47+```
48+
49+## 2. Desk
50+
51+First release only, in ~donmec-sallud's dojo:
52+
53+```
54+|new-desk %sphinx
55+|mount %sphinx
56+```
57+
58+Leave the desk mounted. The copy-back in step 4 reads the mounted file.
59+
60+Every release, copy the desk into the mount from a writable copy of the
61+build:
62+
63+```sh
64+chmod -R u+w result-desk-rw 2>/dev/null; rm -rf result-desk-rw &&
65+cp -RL result-desk result-desk-rw && chmod -R u+w result-desk-rw &&
66+rsync -rpc --delete result-desk-rw/ "$server:$pier/sphinx/"
67+ssh "$server" find "$pier/sphinx" '!' -perm -u+w # must print nothing
68+```
69+
70+- The `&&`s stop the copy when an earlier step fails, so a leftover
71+ `result-desk-rw` from an interrupted run is never sent.
72+- Send a writable copy. Nix store files and directories are read-only, and
73+ `-p` copies their modes into the mount. Don't rely on `rsync --chmod=u+w`:
74+ macOS's `rsync` (openrsync) accepts it and ignores it. In a read-only
75+ mount, vere aborts when it has to delete a file, for example at
76+ `|unmount %sphinx` in step 3, and clay's writes to read-only files fail.
77+- `-c` compares contents. Don't use `rsync -a`: Nix store files all have
78+ mtime 1, so with `-a` rsync can skip an edited file of the same size.
79+
80+Then in the dojo:
81+
82+```
83+|commit %sphinx
84+```
85+
86+The dojo lists the changed files, for example
87+`: /~donmec-sallud/sphinx/4/desk/docket-0`. A commit that changes nothing
88+prints nothing. A mark or build error rejects the whole commit, so fix the
89+desk and repeat this step.
90+
91+First release only:
92+
93+```
94+|install our %sphinx
95+|public %sphinx
96+:treaty|publish %sphinx
97+```
98+
99+- `|install our %sphinx` starts the app on ~donmec-sallud. Docket then prints
100+ `docket: awaiting manual glob for %sphinx desk` until step 3.
101+- `|public %sphinx` lets other ships read the desk. Without it, clay doesn't
102+ answer their requests, so `|install ~donmec-sallud %sphinx` waits without
103+ an error. A waiting install continues by itself once the desk is public.
104+- `:treaty|publish %sphinx` lists sphinx under ~donmec-sallud in Landscape's
105+ app search. It also makes the desk public.
106+
107+## 3. Glob
108+
109+Upload on the first release and whenever `ui/` changed since the last one. If
110+you're unsure, upload anyway: the same files give the same hash.
111+
112+1. Log in to ~donmec-sallud's web interface in Chrome or Firefox. Safari can't
113+ upload folders. `+code` in the dojo prints the password.
114+2. Open `/docket/upload` on that host, pick the desk `sphinx`, choose the
115+ `result-glob` folder and press **glob!**. If the folder picker won't follow
116+ the `result-glob` symlink, press ⇧⌘G and paste the path that
117+ `readlink result-glob` prints.
118+3. The page answers `successfully globbed`.
119+4. Refresh the mount in the dojo:
120+
121+ ```
122+ |unmount %sphinx
123+ |mount %sphinx
124+ ```
125+
126+ Docket wrote the new hash into clay. vere rewrites a mounted file only
127+ while it still holds exactly what clay last wrote there. If the
128+ `desk.docket-0` you committed differs in any byte from what docket prints
129+ (another layout, or a final newline an editor added), the mounted file
130+ keeps the old hash, and any later `|commit %sphinx`, even one with no
131+ edits, puts the old hash back and takes the UI down. The remount rewrites
132+ the mount from clay. It's harmless when the file is already current, so
133+ always do it.
134+
135+## 4. Hash copy-back
136+
137+After every upload and remount:
138+
139+```sh
140+scp "$server:$pier/sphinx/desk.docket-0" desk/desk.docket-0
141+```
142+
143+Only the hash on the `glob-ames` line should change. Commit
144+`desk/desk.docket-0` and push it.
145+
146+## 5. Check
147+
148+- [ ] `/apps/sphinx/` on ~donmec-sallud loads.
149+- [ ] The dojo has not printed `docket: awaiting manual glob for %sphinx desk`
150+ since the last commit or upload.
151+- [ ] `+vats %sphinx` shows `app status: running`.
152+- [ ] First release only: another ship can `|install ~donmec-sallud %sphinx`.
153+ Its log shows `kiln: merge into %sphinx succeeded` and
154+ `docket: fetching %ames glob for %sphinx desk`.
155+- [ ] A ship that installed sphinx shows the release at `/apps/sphinx/`.
156+ After a glob upload, it answers 404 until it has downloaded the new
157+ glob from ~donmec-sallud.
158+
159+## If the UI is down
160+
161+`docket: awaiting manual glob for %sphinx desk` after a commit means the hash
162+in the desk's `desk.docket-0` doesn't match the glob docket serves, usually
163+because a copy-back or a remount was skipped. Build the glob from the released
164+commit, upload it and remount (step 3), then do the copy-back (step 4). Other
165+ships pick up the corrected `desk.docket-0` and fetch the glob again on their
166+own.
desk/app/sphinx.hoonnew file+431
@@ -0,0 +1,431 @@
1+/- s=sphinx
2+/+ gossip, default-agent, verb, dbug
3+/+ *sphinx
4+/+ sift
5+/+ m=metaphone
6+/$ grab-listing %noun %directory-listing
7+/$ grab-directory %noun %directory
8+=, de-purl:html
9+^- agent:gall
10+=>
11+ |%
12+ +$ card card:agent:gall
13+ +$ edition
14+ $% state-0:s
15+ state-1:s
16+ state:s
17+ ==
18+ :: +guard-verb: refuse /verb watches from other ships
19+ ::
20+ :: lib/verb (here and inside lib/gossip) answers /verb/events and
21+ :: /verb/events-plus for anyone, and those carry every poke, card
22+ :: and wire of the agent, the mutuals in gossip's wires included
23+ ::
24+ ++ guard-verb
25+ |= inner=agent:gall
26+ ^- agent:gall
27+ |_ =bowl:gall
28+ +* this .
29+ ag ~(. inner bowl)
30+ ++ on-init
31+ ^- (quip card _this)
32+ =^ cards inner on-init:ag
33+ [cards this]
34+ ::
35+ ++ on-save on-save:ag
36+ ++ on-load
37+ |= old=vase
38+ ^- (quip card _this)
39+ =^ cards inner (on-load:ag old)
40+ :: and end the /verb watches other ships made before this guard
41+ ::
42+ :_ this
43+ %+ weld cards
44+ %+ murn ~(val by sup.bowl)
45+ |= [=ship =path]
46+ ^- (unit card)
47+ ?. &(?=([%verb *] path) !=(our.bowl ship)) ~
48+ `[%give %kick ~[path] `ship]
49+ ::
50+ ++ on-poke
51+ |= [=mark =vase]
52+ ^- (quip card _this)
53+ =^ cards inner (on-poke:ag mark vase)
54+ [cards this]
55+ ::
56+ ++ on-watch
57+ |= =path
58+ ^- (quip card _this)
59+ ?< &(?=([%verb *] path) !=(our.bowl src.bowl))
60+ =^ cards inner (on-watch:ag path)
61+ [cards this]
62+ ::
63+ ++ on-leave
64+ |= =path
65+ ^- (quip card _this)
66+ =^ cards inner (on-leave:ag path)
67+ [cards this]
68+ ::
69+ ++ on-peek on-peek:ag
70+ ++ on-agent
71+ |= [=wire =sign:agent:gall]
72+ ^- (quip card _this)
73+ =^ cards inner (on-agent:ag wire sign)
74+ [cards this]
75+ ::
76+ ++ on-arvo
77+ |= [=wire =sign-arvo]
78+ ^- (quip card _this)
79+ =^ cards inner (on-arvo:ag wire sign-arvo)
80+ [cards this]
81+ ::
82+ ++ on-fail
83+ |= [=term =tang]
84+ ^- (quip card _this)
85+ =^ cards inner (on-fail:ag term tang)
86+ [cards this]
87+ --
88+ --
89+=| state:s
90+=* state -
91+=<
92+ %- guard-verb
93+ %+ verb |
94+ %- %+ agent:gossip
95+ [2 %mutuals %mutuals |]
96+ %- malt
97+ ^- (list [mark $-(* vase)])
98+ :~ [%directory-listing |=(n=* !>((grab-listing n)))]
99+ [%directory |=(n=* !>((grab-directory n)))]
100+ ==
101+ %- agent:dbug
102+ |_ =bowl:gall
103+ +* this .
104+ def ~(. (default-agent this %.n) bowl)
105+ cor ~(. +> [bowl ~])
106+ ++ on-init
107+ ^- (quip card _this)
108+ =^ cards state
109+ abet:init:cor
110+ [cards this]
111+ ::
112+ ++ on-save !>(state)
113+ ++ on-load
114+ |= =vase
115+ =/ old !<(edition vase)
116+ |^
117+ ?- -.old
118+ %2 `this(state (get-state-2 directory.old))
119+ %1 `this(state (get-state-2 directory.old))
120+ %0 `this(state (get-state-2 (directory-0-to-1 directory.old)))
121+ ==
122+ ++ directory-0-to-1
123+ |= =directory:directory-state-zero:s
124+ ^- directory:s
125+ %- ~(run by directory)
126+ |= =listing:directory-state-zero:s
127+ ^- listing:s
128+ =/ post post.listing(+63 [+63.post.listing ''])
129+ listing(+2 post)
130+ ::
131+ ++ get-state-2
132+ |= =directory:s
133+ =/ purged (purge-invalid directory)
134+ :* %2
135+ (reindex purged)
136+ purged
137+ (purge-foreign purged)
138+ ==
139+ ++ reindex
140+ |= =directory:s
141+ %+ roll
142+ ~(tap by directory)
143+ |= [[=hash:s l=listing:s] i=index:s]
144+ (~(catalog delver i) hash l)
145+ ++ purge-invalid
146+ |= =directory:s
147+ ^- directory:s
148+ %- malt
149+ %+ skim
150+ ~(tap by directory)
151+ |= [=hash:s =listing:s]
152+ :: the old %directory handler kept peers' entries under any key
153+ ::
154+ ?& =(hash hash.listing)
155+ =(hash (digest post.listing))
156+ (listing-valid listing)
157+ ==
158+ ++ purge-foreign
159+ |= =directory:s
160+ ^- directory:s
161+ %- malt
162+ %+ skim
163+ ~(tap by directory)
164+ |= [=hash:s =listing:s]
165+ =(our.bowl source.listing)
166+ --
167+ ::
168+ ++ on-poke
169+ |= [=mark =vase]
170+ ^- (quip card _this)
171+ =^ cards state
172+ abet:(poke:cor mark vase)
173+ [cards this]
174+ ++ on-watch
175+ |= =path
176+ ^- (quip card _this)
177+ =^ cards state
178+ abet:(watch:cor path)
179+ [cards this]
180+ ::
181+ ++ on-peek peek:cor
182+ ::
183+ ++ on-leave on-leave:def
184+ ++ on-fail on-fail:def
185+ ::
186+ ++ on-agent
187+ |= [=wire =sign:agent:gall]
188+ ^- (quip card _this)
189+ =^ cards state
190+ abet:(agent:cor wire sign)
191+ [cards this]
192+ ++ on-arvo
193+ |= [=wire sign=sign-arvo]
194+ ^- (quip card _this)
195+ =^ cards state
196+ abet:(arvo:cor wire sign)
197+ [cards this]
198+ --
199+|_ [=bowl:gall cards=(list card)]
200+++ abet [(flop cards) state]
201+++ cor .
202+++ emit |=(=card cor(cards [card cards]))
203+++ give |=(=gift:agent:gall (emit %give gift))
204+++ init
205+ ^+ cor
206+ cor
207+++ poke
208+ |= [=mark =vase]
209+ |^ ^+ cor
210+ ?+ mark ~|(bad-poke/mark !!)
211+ %declare
212+ =+ !<(=declare:s vase)
213+ (publish declare cor)
214+ ::
215+ %declarations
216+ =+ !<(decs=(list declare:s) vase)
217+ =. cor (roll decs publish)
218+ cor
219+ ::
220+ %remove
221+ ?> from-self
222+ =+ !<(=hash:s vase)
223+ di-abet:di-remove:(di-abed:di-core hash)
224+ ==
225+ ++ publish
226+ |= [=declare:s core=_cor]
227+ ^+ cor
228+ :: .core accumulates a %declarations batch: a skipped listing must
229+ :: return it, not the pre-batch .cor, or the batch so far is lost
230+ ::
231+ ?> from-self
232+ =/ listing
233+ :* post=q.declare
234+ hash=(digest q.declare)
235+ reach=p.declare
236+ source=our.bowl
237+ time=now.bowl
238+ ==
239+ ?: (~(has by directory.core) hash.listing)
240+ ~& 'Listing already exists.'
241+ core
242+ ?. (listing-valid listing) core
243+ di-abet:(di-publish:(di-abed:di-core:core hash.listing) listing)
244+ --
245+::
246+++ watch
247+ |= =path
248+ ^+ cor
249+ ?+ path ~|(bad-watch-path/path !!)
250+ [%~.~ %gossip %source ~]
251+ (give %fact ~ directory+!>(directory))
252+ ==
253+++ agent
254+ |= [=wire =sign:agent:gall]
255+ ^+ cor
256+ ?+ wire ~|(bad-agent-wire/wire !!)
257+ [%~.~ %gossip %gossip ~]
258+ ?+ -.sign ~|([%unexpected-gossip-sign -.sign] !!)
259+ %fact
260+ =* mark p.cage.sign
261+ =* vase q.cage.sign
262+ ?+ mark
263+ ~& [dap.bowl %unexpected-mark-fact mark wire=wire]
264+ cor
265+ %directory-listing
266+ =+ !<(=listing:s vase)
267+ ?> =(hash.listing (digest post.listing))
268+ ?: (~(has by directory) hash.listing)
269+ ~& 'Listing already exists.'
270+ cor
271+ ?. (listing-valid listing) cor
272+ di-abet:(di-receive:(di-abed:di-core hash.listing) listing)
273+ ::
274+ %directory
275+ =+ !<(d=directory:s vase)
276+ :: take only listings we don't have yet that pass the checks a
277+ :: %directory-listing gets: a peer's map must not replace our
278+ :: listings, and each listing may be indexed only once
279+ ::
280+ =/ new=(list [=hash:s =listing:s])
281+ %+ skim ~(tap by d)
282+ |= [=hash:s l=listing:s]
283+ ?& =(hash hash.l)
284+ =(hash (digest post.l))
285+ !(~(has by directory) hash)
286+ (listing-valid l)
287+ ==
288+ =. directory (~(gas by directory) new)
289+ =. index
290+ %+ roll new
291+ |= [[=hash:s l=listing:s] i=_index]
292+ (~(catalog delver i) hash l)
293+ cor
294+ ==
295+ ==
296+ ==
297+++ arvo
298+ |= [=wire sign=sign-arvo]
299+ ^+ cor
300+ ~& arvo/wire
301+ cor
302+++ peek
303+ |= =path
304+ ^- (unit (unit cage))
305+ ?+ path [~ ~]
306+ [%x %published ~]
307+ ``directory+!>(published)
308+ ::
309+ [%x %state ~]
310+ ``noun+!>(state)
311+ [%x %tags ~]
312+ =- ``tags+!>(-)
313+ %+ roll
314+ ~(tap by directory)
315+ |= [[=hash:s =listing:s] tags=(map @t @ud)]
316+ %-
317+ %- ~(uno by tags)
318+ %- malt
319+ %+ turn
320+ tags.post.listing
321+ |=(tag=@t [tag 1])
322+ |= [key=@t a=@ud b=@ud]
323+ (add a b)
324+ ::
325+ [%x %lookup %tag @ @ @ ~]
326+ =- ``search+!>(-)
327+ ^- search:s
328+ =/ start (slav %ud i.t.t.t.path)
329+ =/ limit (slav %ud i.t.t.t.t.path)
330+ =/ tag (slav %t i.t.t.t.t.t.path)
331+ %^ page start limit
332+ %+ sort
333+ %+ skim
334+ ~(val by directory)
335+ |= =listing:s
336+ !=(~ (find ~[tag] tags.post.listing))
337+ |= [a=listing:s b=listing:s]
338+ (lth time.b time.a)
339+ ::
340+ [%x %lookup @ @ @ $@(~ [@ ~])]
341+ =- ``search+!>(-)
342+ ^- search:s
343+ =/ filter
344+ %+ rash i.t.t.path
345+ (perk [%app %group %content %other %all ~])
346+ =/ start (slav %ud i.t.t.t.path)
347+ =/ limit (slav %ud i.t.t.t.t.path)
348+ =/ term
349+ ?^ t.t.t.t.t.path
350+ `@t`(slav %t i.t.t.t.t.t.path)
351+ ~
352+ :: expects encoded @t values)
353+ %^ page start limit
354+ ?~ term
355+ %+ skim
356+ ~(val by directory)
357+ |= =listing:s
358+ |(=(filter %all) =(filter type.post.listing))
359+ =/ entries (~(get-entries delver index) term)
360+ :: ~& %+ turn
361+ :: entries
362+ :: |= [=hash:s =rank:s]
363+ :: [(~(got by directory) hash) rank]
364+ %+ skim
365+ %- get-listings
366+ %- get-hashes
367+ %- sort-entries
368+ entries
369+ |= =listing:s
370+ |(=(filter %all) =(filter type.post.listing))
371+ ==
372+++ page
373+ |= [start=@ud limit=@ud all=(list listing:s)]
374+ =/ listings (swag [start limit] all)
375+ :* listings
376+ start
377+ limit
378+ (lent listings)
379+ (lent all)
380+ ==
381+++ get-listings
382+ |= l=(list hash)
383+ %+ murn l
384+ |=(=hash:s (~(get by directory) hash))
385+++ from-self =(our src):bowl
386+++ di-core
387+ |_ [=listing:s =hash:s gone=_|]
388+ ++ di-core .
389+ ++ di-abet
390+ =. directory
391+ ?: gone (~(del by directory) hash)
392+ (~(put by directory) hash listing)
393+ cor
394+ ++ di-abed
395+ |= h=hash:s
396+ di-core(hash h, listing (~(gut by directory) h *listing:s))
397+ ++ di-remove
398+ =. gone &
399+ =/ keys (~(gut by trail.index) hash ~)
400+ =. trail.index (~(del by trail.index) hash)
401+ =. lookup.index
402+ ^- lookup:s
403+ %- ~(uni by lookup.index)
404+ %- malt
405+ %+ turn
406+ keys
407+ |= =key:s
408+ :- key
409+ ^- (list entry:s)
410+ %+ skip
411+ (~(got by lookup.index) key)
412+ |=([h=hash:s =rank:s] =(h hash))
413+ =? published (~(has by published) hash)
414+ (~(del by published) hash)
415+ di-core
416+ ++ di-publish
417+ |= l=listing:s
418+ =. listing l
419+ =. index (~(catalog delver index) hash l)
420+ =. published
421+ ?. =(source.listing our:bowl) published
422+ (~(put by published) hash.listing listing)
423+ =. cor (emit (invent:gossip %directory-listing !>(listing)))
424+ di-core
425+ ++ di-receive
426+ |= l=listing:s
427+ =. listing l
428+ =. index (~(catalog delver index) hash l)
429+ di-core
430+ --
431+--
desk/desk.billnew file+2
@@ -0,0 +1,2 @@
1+:~ %sphinx
2+==
desk/desk.docket-0new file+11
@@ -0,0 +1,11 @@
1+:~
2+ title+'sphinx'
3+ info+'A search engine powered by you and your pals for finding answers to your riddles'
4+ color+0xb2.5068
5+ version+[0 7 0]
6+ website+'https://github.com/iko-soy/sphinx'
7+ license+'MIT'
8+ image+'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9Ii0zMCAxNSA2MDAgNjAwIiBmaWxsPSJub25lIj48c3R5bGU+LnN0MXtmaWxsOiNlN2FiNzl9PC9zdHlsZT48cGF0aCBjbGFzcz0ic3QxIiBkPSJNMjk0LjY5IDU2Mi45NmMtMy4zNCAwLTYuNjgtLjA5LTEwLjAyLjAyLTcuNTkuMjUtMTUuMS0uMi0yMi41NS0xLjg1LTkuNTQtMi4xMi0xNy44NS02LjU3LTI0LjYyLTEzLjUzLTQuMTUtNC4yNy03Ljk3LTguOTQtMTEuNC0xMy44MS0xMC40Mi0xNC44Mi0yMC40OS0yOS44OS0zMC44Ni00NC43NS0xMS44OC0xNy4wMi0yNC4wNC0zMy44NS0zNS44OC01MC45LTguNDMtMTIuMTQtMTYuNTYtMjQuNDgtMjQuNzItMzYuOC0yLjAxLTMuMDQtNC41Ny01LjE2LTcuNzYtNi44OC0yMS4zMy0xMS41MS0zOC44NC0yNy4xOC01MS40Ni00OC4wMy0zLjY0LTYuMDItNy4yNy0xMi4wNi0xMC41LTE4LjMtNC41Ni04LjgxLTYuOTgtMTguMzktOS4wNC0yOC4wNC00LjY3LTIxLjg2LTIuNDktNDMuMTIgNi42OC02My40NSA1Ljc4LTEyLjgyIDExLjkzLTI1LjUgMTguNjYtMzcuODQgMTQuNjctMjYuOTIgMzEuMTktNTIuNjcgNTAuMzctNzYuNjUgOC40OC0xMC42IDE3LjUzLTIwLjY1IDI4LjA5LTI5LjI2IDIwLjItMTYuNDcgNDIuOTctMjcuOTQgNjcuOTktMzUuMDUgOC40Ny0yLjQxIDE3LjA1LTQuMTggMjUuODEtNS4yNiA2Ljk3LS44NiAxMy44Mi0yLjYxIDIwLjc4LTMuNiA4LjE4LTEuMTUgMTYuNC0yLjA0IDI0LjYzLTIuNzggOS40NS0uODUgMTguOTMtMS41OCAyOC40MS0yLjA0IDE0Ljk5LS43MyAyOS44NS43MiA0NC42NCAzLjI1IDIzLjYgNC4wMyA0Ni44NSA5LjU2IDY5Ljk4IDE1LjY4IDMuMDUuODEgNi4wMSAxLjk4IDkuMDUgMi44NSAzLjE5LjkxIDQuNDYgMy4wNCA0LjU3IDYuMjMuMjggOC43OS43NCAxNy41Ny45OSAyNi4zNi4xNSA1LjQ1LjA4IDEwLjkxLjAzIDE2LjM2LS4wNCAzLjU3LjY1IDYuOTcgMS43OCAxMC4zNCAzLjQ3IDEwLjM0IDYuOTMgMjAuNjggMTAuMyAzMS4wNCAzLjEgOS41MyA2LjA1IDE5LjExIDkuMTcgMjguNjMgMS4yIDMuNjcgMi40OCA3LjM1IDQuMTQgMTAuODIgOC4zMiAxNy40NyAxNi43MiAzNC45IDI1LjE5IDUyLjI5IDUuNzggMTEuODYgMTEuNzIgMjMuNjMgMTcuNiAzNS40NS42MyAxLjI2IDEuMTkgMi41NSAxLjg5IDMuNzcgNC43IDguMjggMy44NCAxNi41OS0uMDkgMjQuNzctMi41OSA1LjM5LTUuNTIgMTAuNjEtOC4zOSAxNS44Ni01LjQgOS44OC0xMC43NiAxOS43OC0xNi4zMiAyOS41Ny0zLjMgNS44MS00LjY2IDEyLjAxLTUuMTMgMTguNjEtMS4zIDE4LjQxLTMuMDcgMzYuNzgtNS45MSA1NS4wNC0xLjc5IDExLjQ2LTIuOTEgMjMuMDItNC40NyAzNC41Mi0xLjU0IDExLjMyLTMuMiAyMi42My00LjkxIDMzLjkyLTIgMTMuMjEtNC4xNyAyNi40LTYuMTEgMzkuNjItLjM4IDIuNi0xLjEzIDQuNzQtMy4zIDYuMjgtLjQzLjMtLjguNjgtMS4yMSAxLjAyLTcuOTcgNi43Ny03Ljk3IDYuODEtMTguNSA3LjAxLTYuNjguMTItMTMuMzcuMTItMjAuMDUuMTQtMS4yMyAwLTIuNDYtLjEtMy42OS0uMTktMi4zMS0uMTYtMy44Ni0xLjE3LTQuNzEtMy41LTIuMjctNi4yOC00LjczLTEyLjQ4LTcuMDgtMTguNzMtMS4xMS0yLjk2LTIuMi01LjkzLTMuMjEtOC45Mi0uNTMtMS41OS0xLjY3LTIuMzUtMy4xNy0yLjI3LTMuNS4xOS03LjAzLjM4LTEwLjQ2IDEuMDEtMS4xLjItMi4yNCAxLjY0LTIuODMgMi43OS0xLjMxIDIuNTMtMy4yNiAzLjM4LTUuOTkgMy40Mi0xNS42NS4yNC0zMS4zLjU2LTQ2Ljk1LjkxLTIuMzMuMDUtNC4xMy0uNTctNS4yNC0yLjcyLS42My0xLjIxLTEuNjYtMS42Ny0zLjA1LTEuNjMtNS40NS4xNC0xMC45MS4xNy0xNi4zNi4zMy0yLjU5LjA4LTMuMjYuOTktMi4yMyAzLjMzIDMuMzQgNy41NiA2LjgzIDE1LjA1IDEwLjI4IDIyLjU2Ljk1IDIuMDggMi4wNiA0LjA5IDIuOSA2LjIxIDEuMTUgMi45My41MSA0LjQxLTIuNjIgNC45Mi01LjIuODUtMTAuNDUgMS41NC0xNS43IDEuODEtNS43OS4zMS0xMS42LjA3LTE3LjQxLjA3LS4wMy4wMS0uMDMtLjAxLS4wMy0uMDN6bTc3Ljk0LTQwMS40N2MtNC45NS4xNC0xMC45My4xOC0xNi45LjUtNy45LjQyLTE1Ljc5IDEuMDgtMjMuNTEgMy0xNS40NSAzLjg1LTMwLjA4IDkuNzktNDQuMDIgMTcuNDUtMi40NSAxLjM1LTQuODIgMi45Ni02LjkgNC44Mi0xLjc5IDEuNi0zLjU5IDMuNTItNC41NyA1LjY2LTMuMDYgNi43MS02LjA4IDEzLjQ4LTguNDkgMjAuNDQtMy41MiAxMC4xOC00LjIgMjAuNzMtMS41NyAzMS4yMSA0LjUxIDE4LjAxIDEyLjUxIDM0LjMzIDI0Ljg5IDQ4LjMyIDguMzMgOS40MiAxOC4wMyAxNy4yOSAyOC41NCAyNC4xMSAzLjUxIDIuMjggNy4zNiA0LjE3IDExLjI4IDUuNjggNS40MSAyLjA4IDExLjAzIDMuNiAxNi41MyA1LjQ0IDIuMjQuNzUgNC4zNS43NSA2LjY4LjE4IDExLjQ0LTIuODIgMjIuOS01LjU0IDM0LjM5LTguMTQgNy4yLTEuNjMgMTQuNS0yLjgzIDIxLjY4LTQuNTMgNS42NS0xLjM0IDkuNi41MyAxMi40NCA1LjM3LjYyIDEuMDYgMS4yOCAyLjExIDIgMy4xMSAxLjEzIDEuNTcgMi4yNCAxLjYgMy4yMS0uMTUgNC44Ny04Ljc2IDkuODEtMTcuNDkgMTMuMDktMjcuMDMgNC45My0xNC4zMSA0LjgtMjkuMDYgMy42Ny00My44NS0uNzgtMTAuMTYtMS45Ny0yMC4yOS0yLjk0LTMwLjQ0LS4zMi0zLjM2LTEuMDMtNC4wOC00LjM0LTMuNDQtNS43OSAxLjExLTExLjU0Ljg3LTE3LjMyLS4wMS0yLjYxLS40LTUuMjEtLjc5LTcuODMtMS4xMi0xLjYyLS4yLTIuNDcuNzktMS43NiAyLjIgMS4yNiAyLjUgMi42NCA0Ljk3IDQuMTUgNy4zMyAzLjEzIDQuODkgNi4zNCA5LjczIDkuNjEgMTQuNTIgMi4zOSAzLjUxIDIuODkgNy4yMSAxLjA3IDExLTIuNDEgNS4wMi00LjI2IDEwLjUyLTkuNzIgMTMuMzYtMS40NC43NS0xLjk4IDIuMTItMS42IDMuNTcuMzkgMS40OCAxLjEgMi45IDEuODUgNC4yNSAxLjExIDEuOTggMi40OSAzLjgxIDMuNTUgNS44MS45MyAxLjc2IDEuMTggMy44LjMxIDUuNjItMS4xNyAyLjQ3LTEuNDYgNC45Mi0xLjI2IDcuNjQuMjUgMy40Ni0xLjUyIDUuNzktNC45MSA2LjUtMi43Mi41Ny01LjU4Ljc1LTguMzcuNjUtMTAuMDItLjM1LTIwLjAzLS42NC0zMC4wNC4zMi0xLjc0LjE3LTMuNTIuMTktNS4yNy4xLTEuOTktLjExLTMuMTctMS4wMi0zLjAyLTIuMjMuMjMtMS44OCAxLjc5LTEuOTQgMy4xOS0yLjAzIDUuMjYtLjM1IDEwLjUzLS44NSAxNS44LS44OSA2LjUtLjA1IDEyLjk5LjM2IDE5LjQ5LjQzIDIuMjUuMDIgNC41NC0uMjMgNi43Ni0uNjMgMS4yOC0uMjMgMi4xMy0xLjMgMi4wNC0yLjcxLS4xLTEuNTMtLjg0LTIuNzQtMi40NS0zLjAxLTEuMi0uMjEtMi40NS0uMjEtMy42OC0uMjQtNC40LS4wOS04LjgtLjAzLTEzLjE5LS4yNS02LjQ0LS4zMS0xMi41OS44NS0xOC41OCAzLjEzLTIuNDYuOTMtNC45NiAxLjg4LTcuNTMgMi4zNi0xLjgzLjM0LTMuOTEuMjctNS42Ny0uMjgtMy4wOC0uOTYtMy45MS00LjQxLTEuNzMtNi44IDEuMDMtMS4xMyAyLjQ2LTEuOTggMy44NS0yLjY5IDQuMjMtMi4xNSA4LjU2LTQuMTIgMTIuOC02LjI1IDcuOTgtNC4wMSAxNi40Mi02LjE5IDI1LjM0LTYuNTMgMS40LS4wNSAyLjgyLS4xNCA0LjE4LS40Ni41Mi0uMTIgMS4zMS0xLjA0IDEuMjItMS40LS4xOS0uNzEtLjc4LTEuNTItMS40My0xLjg0LS43NC0uMzYtMS43Mi0uMzItMi41OS0uMjktNC4zOS4xOS04Ljc3LjUtMTMuMTcuNjMtMy4xNS4wOS02LjMxLjEzLTkuNDUtLjExLTIuMDItLjE2LTMuMDMtMS4yOS0yLjgxLTIuNDguMzItMS43NCAxLjczLTIuMDMgMy4xNy0yLjIzLjM1LS4wNS43LS4wNCAxLjA1LS4wNiA1LjgtLjE3IDExLjYxLS4yMyAxNy40LS41NiAzLjY3LS4yMSA3LjM0LS43MiAxMC45Ny0xLjMyIDIuMDgtLjM1IDQuMTItMS4xMyA1LjI0LTMuMTcuMjEtLjM5LjItLjk4LjEtMS40My0uMDQtLjE4LS42LS4zNi0uOTEtLjM1LTEwLjcxLjUyLTIxLjQyIDEuMDgtMzIuMTMgMS42LTIuNTguMTMtNC44MiAxLjA5LTYuNjcgMi44MS0xLjc5IDEuNjctMy40MSAzLjUzLTUuMDggNS4zNC0uNzEuNzctMS4yMyAxLjc1LTIuMDMgMi4zOS0uNDMuMzUtMS4zOS40My0xLjkxLjE5cy0xLS45OS0xLjExLTEuNTljLS4xMS0uNjMuMDYtMS40Ni40MS0yIDQuMTMtNi40MSA4Ljk0LTExLjc0IDE3LjQxLTExLjk2IDguMDktLjIxIDE2LjE3LS42NSAyNC4yNC0xLjA4IDIuODEtLjE1IDUuNjEtLjUxIDguMzktLjkgMy41Ni0uNSA0Ljc4LTIuNzUgMy4yMy02LS42OC0xLjQyLTEuNjQtMi43LTIuNTEtNC4wMi0zLjU5LTUuNDMtNy4zMS0xMC43Ny0xMC43Ni0xNi4yOS0yLjkxLTQuNjUtNS40LTkuNjMtNS40LTE1LjI0IDAtNi44NS41MS0xMy42OS44MS0yMC41NC4wMi0uMzUuMTYtLjY4LjIyLTEuMDMgMS4wNC02LjM0IDQuNzMtMTAuNDMgMTAuNzItMTIuNTUgOC40NC0yLjk4IDE2LjgzLTMuNTMgMjUuMTEuNTcuNjMuMzEgMS4yNy42MiAxLjkyLjg4IDIuMTYuODUgMi43OC41OCAzLjMzLTEuNzQgMS41NS02LjUxLjktNi4xNi00LjM1LTcuOC05Ljc4LTMuMDYtMTkuODItNC42NC0yOS45OS01LjcxLTEyLjI1LTEuMjYtMjQuNDktMi4zMy0zNy44Ni0xLjA5em0tMTU3LjA4IDYuMjljLTEuMzQtMTAuMS0yLjUtMjAuMjMtNC4wNi0zMC4zLTIuNDctMTUuOTctNS4yMS0zMS45MS03Ljg0LTQ3Ljg1LS4wOS0uNTItLjE0LTEuMDUtLjI3LTEuNTUtLjI3LTEuMDEtMS4yMi0xLjIzLTItLjQ1LS40OS41LS45NCAxLjA0LTEuMzggMS41OS0xNy4wMyAyMS4yOC0zMy45MSA0Mi42Ny00OS45OSA2NC42OC04LjcyIDExLjkzLTE3LjAyIDI0LjE0LTI0LjUyIDM2Ljg4LTYuODkgMTEuNy0xMi42OCAyMy45MS0xNi43NiAzNi44OS0yLjcxIDguNjMtNC4wMSAxNy40MS0zLjExIDI2LjUgMS4wNSAxMC42NiAxLjc2IDIxLjM2IDIuNjggMzIuMDQuNzEgOC4yMyAxLjM5IDE2LjQ2IDIuMzIgMjQuNjYuNzYgNi43MyAxLjI0IDYuOTYgNy45MyA2LjQ2IDE0LjAyLTEuMDUgMjguMDQtMi4wMyA0Mi4wNS0zLjEzIDUuMjUtLjQxIDEwLjQ4LTEuMTYgMTUuNzMtMS42MyA5LjI3LS44MyAxOC40Mi0yLjg1IDI3Ljc5LTIuNjMgMS4yMi4wMyAyLjQ2LS4xNyAzLjY3LS4zOSAyLjE3LS40IDIuNTQtMS4xMyAxLjgyLTMuMzUtLjE2LS41LS4zOC0uOTgtLjU5LTEuNDctMy45Ny05LjYtNy4xOC0xOS40NC05Ljg5LTI5LjQ3LS41My0xLjk1LTEuNzctMy43OC0yLjk1LTUuNDctMi43Mi0zLjg4LTUuODktNy40Ny04LjM5LTExLjQ5LTguODktMTQuMy0xMy43NS0yOS41NC0xMC41NS00Ni42NiAxLjkyLTEwLjI5IDYuMTgtMTkuMzUgMTIuOTYtMjcuMjggNC40LTUuMTUgOS44Ny04LjM3IDE2LjU3LTkuNDYgMS4yMS0uMiAyLjQxLS40OCAzLjYzLS42NyA1LjQ3LS44NSA1LjQ3LS44NCA1LjE1LTYuNDV6bTQ1LjAxIDY0LjFjLS40MS03LjQxIDEuMDYtMTQuNjQgMy42MS0yMS42MiAxLjkzLTUuMjcgNC40Mi0xMC4zNCA2LjU1LTE1LjU1IDMuMzEtOC4wOCA5LjMtMTMuNTggMTYuOTItMTcuMzcgNy40LTMuNjggMTQuODMtNy4zMyAyMi40OC0xMC40NCAxMC4xMi00LjExIDIwLjU1LTcuNTIgMzEuNDctOC41NiAxMS4zNy0xLjA5IDIyLjgtMS42IDM0LjIxLTIuMSAxMy4zOC0uNTkgMjYuNzIuMTkgNDAgMS45OCA3LjY3IDEuMDMgMTUuMzMgMi4wOSAyMi43NSA0LjQzIDIuMTguNjkgNC4zOSAxLjI5IDYuNjEgMS43OSAxLjU5LjM2IDIuMy0uMTggMi41NC0xLjgxLjE4LTEuMjEuMjEtMi40NS4yNS0zLjY4LjI4LTcuNTYuNS0xNS4xMi44My0yMi42OC4xMy0yLjk4LjU5LTUuOTYuNjctOC45NC4wOS0zLjE1LS43LTQuMDItMy44OS00LjUtMTEuNjUtMS43My0yMy4zMS0zLjQ1LTM0Ljk4LTUuMDctMi40Mi0uMzQtNC45MS0uMjktNy4zNy0uMjYtMS42Mi4wMi0yLjU5IDEuMDItMi43OCAyLjYzLS4xMiAxLjA0LS4xMSAyLjEtLjE1IDMuMTYtLjIzIDUuOC0uNCAxMS42LS42OSAxNy4zOS0uMjEgNC4wMS0xLjQ3IDUuMTctNS42NyA1LjE1LTIuNjMtLjAxLTUuMjYtLjQyLTcuOS0uNDUtNC4yMS0uMDUtOC40OS0uMzgtMTIuNjEuMjYtMy43NS41OC02LjEtLjYzLTcuOTktMy41My0xLjI1LTEuOTEtMi41NS0zLjgtMy42OC01Ljc5LTMuMDMtNS4zNi02LjE1LTEwLjY4LTguODktMTYuMTgtMS4zOS0yLjgtMy4xMi0zLjktNi4xOS0zLjU5LTguNC44NS0xNi44NSAxLjItMjUuMiAyLjM1LTI1LjExIDMuNDMtNDkuODYgOC44MS03NC40OSAxNC43LTguNzEgMi4wOC0xNy4yOCA0Ljc5LTI1Ljg3IDcuMzctMy40MiAxLjAzLTMuNzMgMS41My0zLjM2IDQuODkuODYgNy44NiAxLjkxIDE1LjcxIDIuODEgMjMuNTYuMzUgMy4wMiAxLjU0IDUuMDIgNC42NCA2LjI1IDYuODkgMi43MyAxMS40OSA4LjAyIDE0LjI3IDE0Ljc4IDEuNDcgMy41NiAyLjYzIDcuMjggMy41OSAxMS4wMiAyLjY4IDEwLjM4IDQuOTggMjAuODYgNy44IDMxLjIgMy44OCAxNC4yNSA3LjkgMjguNDYgMTIuMjIgNDIuNTggNC44MiAxNS43NCAxNC4xMiAyOC42NyAyNi41OSAzOS4yMyA3LjI0IDYuMTMgMTQuOTggMTEuNjcgMjIuNDcgMTcuNTEgNy41NCA1Ljg4IDE1LjcyIDEwLjcgMjQuNTkgMTQuMjIgNC41NCAxLjggNy42MyA0Ljg1IDkuOCA5LjA3IDIuNDkgNC44NSA1LjIxIDkuNTkgNy40OSAxNC41NCAxMS4zOSAyNC43NyAyMi42OCA0OS41OSAzNCA3NC4zOS41OCAxLjI4IDEuMTIgMi41OSAxLjc0IDMuODQgMS4wMSAyLjAyIDEuODEgMi4xIDMuNTIuNDMgNC41My00LjQzIDQuODEtNS43MSAyLjEtMTEuNTQtNi42LTE0LjE5LTEzLjIyLTI4LjM4LTE5LjktNDIuNTQtMy4zLTYuOTktNy4xNS0xMy43NS0xMC0yMC45Mi01LjAyLTEyLjYtMTAuNjYtMjQuODktMTYuNjMtMzcuMDYtMS4yLTIuNDUtMi44NC0zLjgyLTUuMzYtNC41NS0zLjM4LS45OC02LjY4LTIuMjEtMTAuMDQtMy4yMy02LjgtMi4wNy0xMy4wOC01LjE4LTE4LjgxLTkuMzUtNC4yNi0zLjExLTguNDctNi4yOS0xMi41OS05LjU5LTE5Ljc2LTE1Ljg0LTMyLjI5LTM2LjQtMzkuMzEtNjAuNTMtMS42MS01LjYxLTIuNDktMTEuMzMtMi4xNy0xNy4yOXptNzYuMjQgMTIwLjA0Yy0xLjgyLS45Mi0yLjg2LTEuNDQtMy44OS0xLjk3LTQuMzgtMi4yNC04Ljk5LTQuMTMtMTMuMDktNi44LTEyLjA4LTcuODktMjMuNzYtMTYuMzYtMzQuNTUtMjUuOTYtMTIuMzItMTAuOTUtMjEuNTYtMjQuMDUtMjYuNzEtMzkuODQtMS4wNC0zLjE3LTIuMTgtNi4zMi0zLjEyLTkuNTItNi40MS0yMS43Ni0xMS44Mi00My43OC0xNi45Ny02NS44Ni0xLjIxLTUuMi0zLjA1LTEwLjEtNi4xNi0xNC40NS0zLjA4LTQuMy03LjA2LTcuNzItMTIuMzQtOC4zNi0xMC4yMi0xLjI1LTE5LjczLjUtMjYuNjMgOS4xNC0xMS44MSAxNC44Mi0xNS4zMSAzMS40Ni05LjY5IDQ5LjU4IDUuMzggMTcuMzQgMTYuMjggMzAuOTggMzAuMjMgNDIuMyA0LjE3IDMuMzggOSA1LjUxIDE0LjM0IDYuMjQgMS41Mi4yMSAzLjE4LjE4IDQuNjctLjE4IDguMjItMS45OSAxMi40Mi0xMC4zMyA5LjA3LTE4LjEyLTEuMTgtMi43My0yLjg2LTUuMjQtNC4yMy03LjktLjU1LTEuMDctMS4wMi0yLjIzLTEuMjItMy40MS0uMDktLjUyLjQzLTEuNDEuOTMtMS43LjQ5LS4yOSAxLjQyLS4yNiAxLjk0LjAyLjc0LjQgMS40NiAxLjA1IDEuODcgMS43OCAyLjA3IDMuNjcgNC4yMyA3LjMxIDUuOTggMTEuMTMgMS4zNSAyLjkzIDEuMzEgNi4xMS40NSA5LjMtMS4yIDQuNDEtMy4zNSA4LjE3LTcuMTMgMTAuNzUtMi41MiAxLjcyLTIuOTIgMy43My0xLjc1IDYuMzQuMzYuOC41OSAxLjY1LjkgMi40OCA1LjggMTUuNTkgMTUuMjQgMjguODYgMjYuNDQgNDAuOTQgNC45NiA1LjM0IDExLjAxIDkuMjcgMTcuNjcgMTIuMjMgMy4zNyAxLjUgNi43OSAyLjkxIDEwLjA3IDQuNiA2LjMxIDMuMjQgMTMuMDYgNC4wNyAxOS45NyAzLjgxIDIuNTktLjEgNS4zMi0uNjEgNy42Ny0xLjY0IDQuNjctMi4wNCA5LjM4LTMuODEgMTUuMjgtNC45M3ptMTE4LjQzLTIxOS45NmMtLjMuMDctLjYuMTQtLjkxLjIxLS4xOSAxLjItLjUgMi40LS41NSAzLjYxLS4yNCA1LjI3LS4zOCAxMC41NC0uNiAxNS44MS0uMzUgOC4yNS0uMzYgMTYuNTMtMi40NSAyNC42LTIuMjIgOC41My0zLjQzIDE3LjIyLTMuNjkgMjYuMDEtLjQ3IDE2LjU0LjU3IDMyLjk5IDIuNzMgNDkuNDIgMS42MSAxMi4yMyAxLjU1IDI0LjU1LS45OSAzNi43My0uMTguODYtLjQ0IDEuNzEtLjUzIDIuNTgtLjIgMi4wNi40MSAzLjAzIDIuNDEgMy4zNiAyLjYuNDMgNS4yMi43OSA3Ljg0Ljk0IDguNzcuNTEgMTcuNTUuODQgMjYuMzIgMS4zOSA2LjY2LjQyIDEzLjMxIDEuMDUgMTkuOTYgMS42MiA1LjI1LjQ1IDEwLjUgMS4wMiAxNS43NSAxLjM5IDQuNTUuMzIgNS4zOS0uNzMgMy45My01LjE1LS44OC0yLjY1LTIuMTYtNS4xOS0zLjQyLTcuNjktNS4xMy0xMC4yMS0xMC40NC0yMC4zMy0xNS40NS0zMC42LTkuNDktMTkuNDMtMTguODUtMzguOTEtMjguMTctNTguNDItMS41OC0zLjMyLTIuODQtNi44MS0zLjk5LTEwLjMxLTUuNDUtMTYuNy0xMC44LTMzLjQ0LTE2LjIxLTUwLjE2LS41Ny0xLjgxLTEuMzEtMy41Ny0xLjk4LTUuMzR6bS0xNDUuMzkgMjY0LjRjLjIzLjgxLjQyIDIuMDMuOTIgMy4xMS45NiAyLjA3IDIuMSA0LjA2IDMuMTcgNi4wOCA1LjkxIDExLjIgMTIuMDEgMjIuMyAxNy42NyAzMy42MyA1Ljk3IDExLjk2IDExLjUgMjQuMTQgMTcuMjMgMzYuMjEgMS41MSAzLjE4IDMuMDIgNi4zNiA0LjY1IDkuNDcgMS4xMSAyLjExIDEuODcgMi4xMSAzLjU1LjM3IDQuOTktNS4xOSA5Ljk2LTEwLjQyIDE1LjAyLTE1LjU0IDMuMDktMy4xMyA2LjQzLTYgOS41LTkuMTUgNi4zNi02LjUzIDYuNC00LjMxIDIuNC0xMy4zNi03LjM5LTE2LjczLTE1LjA3LTMzLjM0LTIyLjY1LTQ5Ljk5LTQuNzQtMTAuNC05LjQ5LTIwLjgtMTQuMzEtMzEuMTctMS4xOC0yLjU1LTIuNjMtNC45OC0zLjk1LTcuNDYtLjc1LTEuNDEtMS44OS0xLjg2LTMuNS0xLjczLTQuNDMuMzQtOC42NyAxLjI5LTEyLjc1IDMuMDgtNC4yNiAxLjg3LTcuMzQgNC43My04LjcyIDkuMjgtMi41IDguMjQtNS4wNSAxNi40Ny03LjU3IDI0LjcxLS4yLjY2LS4zNiAxLjM1LS42NiAyLjQ2em0tMzEuNjIgMjYuNjdjMy4zNy4wMyA0LjEzLS42MSA0LjYyLTIuOTkuMTEtLjUyLjExLTEuMDUuMjEtMS41NyAyLjczLTE0Ljg3IDUuNDUtMjkuNzMgOC4xOS00NC42LjYxLTMuMjggMS4zNS02LjU0IDEuOTEtOS44NC41NC0zLjIyLjE5LTMuOS0yLjc1LTUuNDktMS43LS45Mi0zLjQ2LTEuNzQtNS4yNS0yLjQ2LTExLjktNC43Ni0yMS41LTEyLjQ1LTI5LjM4LTIyLjUxLTkuMDYtMTEuNTctMTYuODQtMjMuODUtMjEuNC0zNy45My0uODYtMi42Ny0yLjIzLTQuMDEtNS4xOS00LjIxLTcuMjQtLjUtMTMuNTMtMy41My0xOS4xOC04LS45Ni0uNzYtMS45My0xLjUyLTIuOTctMi4xNy0uMTQtLjA5LS45OS40OC0uOTYuNjMuMjkgMS4zNy42NiAyLjczIDEuMDggNC4wNiAzLjI5IDEwLjQyIDcuNzkgMjAuMzUgMTIuMTkgMzAuMzMgNS42NyAxMi44NyAxMS4yOCAyNS43NyAxNi43NyAzOC43MSA2LjA0IDE0LjI0IDExLjk0IDI4LjU1IDE3Ljg0IDQyLjg1IDIuMSA1LjA4IDUuMDMgOS42NyA4LjExIDE0LjE2IDIuNzMgMy45NyA2LjM4IDcuMDUgMTAuNzQgOS4xMyAyLjAzLjk4IDQuMjcgMS41MSA1LjQyIDEuOXptMTIyLjIxIDY0LjQ4YzUuNjIgMCAxMS4yNS0uMTMgMTYuODYuMDUgMy4wNy4xIDUuMy0uOTYgNy40MS0zLjE0IDUuNjEtNS44MSAxMS40LTExLjQ1IDE3LjEyLTE3LjE2IDYuMS02LjA4IDEyLjI4LTEyLjA3IDE4LjI2LTE4LjI3IDIuNDItMi41MSA0LjU0LTUuMzUgNi40OC04LjI1IDEuNC0yLjA5LjUtMy44NC0yLjAzLTQuMDYtMi43OC0uMjUtNS42Mi0uMjEtOC40MS4wMy01LjYuNDgtMTEuMiAxLTE2Ljc1IDEuODItMTAuOTQgMS42Mi0yMS44NSAzLjQ4LTMyLjc3IDUuMi0yLjM2LjM3LTQuMyAxLjMtNS44NiAzLjE3LTguOSAxMC42OS0xOSAyMC4yMi0yOSAyOS44NS0yLjc4IDIuNjgtNS41MSA1LjQzLTguMTEgOC4yOC0uOTggMS4wNy0yLjg5IDIuMjMtMS44MiAzLjg2LjQ1LjY4IDIuNTguNDUgMy45Mi4zMyAxMS41NC0xLjAzIDIzLjA4LTIuMSAzNC43LTEuNzF6bS0xMzEuMzEtNjIuMDRjLjMyIDEuMTguNCAxLjg2LjY4IDIuNDUgNS4yOCAxMS4zIDEwLjMyIDIyLjczIDE1Ljk0IDMzLjg2IDguOTYgMTcuNzMgMTguNDEgMzUuMiAyNi4yMSA1My40OS4yOC42NS42MSAxLjI2LjkzIDEuODkuNjkgMS4zOCAxLjgyIDIuMjEgMy4zNCAyLjIxIDUuNjIgMCAxMS4yNC0uMDUgMTYuODYtLjE4IDEuMjctLjAzIDEuNzYtMS4wMiAxLjI4LTIuMjktLjQzLTEuMTUtMS0yLjI1LTEuNTMtMy4zNS0zLjU4LTcuNDQtNy4xNC0xNC45LTEwLjc3LTIyLjMyLTcuNzQtMTUuNzktMTUuMTItMzEuNzMtMjEuNjItNDguMDctLjg0LTIuMTItMS42Mi00LjMyLTIuODEtNi4yNC0zLjQ5LTUuNjctOC05LjgtMTUuMzUtOS4wMy0zLjIxLjM0LTYuMy0uMTgtOS4zMy0xLjI1LTEuMTEtLjM5LTIuMjQtLjY5LTMuODMtMS4xN3ptLTE0MC4wNS04OC44NGM0Ljk3LS4zNyA4LjY1LS43OCAxMi4zMy0uOSAxOC44LS42MSAzNy41Ny0xLjcxIDU2LjMtMy40OSA2LjMtLjYgMTIuNTctMS40MiAxOC44NS0yLjE5IDIuNDYtLjMgMy0xLjIzIDIuMDItMy41OC0xLjIzLTIuOTEtMi42NS01Ljc1LTMuOTEtOC42NS0uODctMi4wMS0yLjMtMy00LjUtMi45NC01LjI3LjE1LTEwLjYxLS4yNC0xNS43OS40OC0yMy4xOCAzLjE5LTQ2LjQ5IDQuNzktNjkuODMgNi4wNS0xLjc1LjA5LTMuNTEuMjUtNS4yNS41MS0zLjM1LjUxLTMuNzYgMS4yOS0yLjEgNC4wMyAxLjE4IDEuOTUgMi42OSAzLjcyIDMuNzYgNS43MyAyLjA0IDMuODggNC44NyA1LjkzIDguMTIgNC45NXpNMzg0LjYzIDE0MC4zYzAgLjA4LjAxLjE2LjAxLjI0IDIuMS4xOCA0LjIuNDYgNi4zMS41IDIuOTkuMDUgMy43Ny0uNjYgMy45MS0zLjY4LjE4LTMuNjkuMy03LjM5LjItMTEuMDctLjE5LTcuMDItLjA3LTE0LjAyLTEuMDEtMjEuMDQtLjg2LTYuNDUtMy45NC0xMS4xOS04Ljg0LTE0Ljk2LTIuMjEtMS43LTQuNzItMy4wMi03LjE4LTQuMzctMy4yLTEuNzUtMy40Ni0yLjE0LTIuODItNS44My4xMi0uNjkuNDMtMS4zNy40My0yLjA2LS4wMi0zLjUuMzktNy4xLS4yOS0xMC40OC0xLjMzLTYuNTItNS45My0xMC42OC0xMS43Ny0xMy4yOC0zLjM0LTEuNDktNy4wMi0yLjIyLTEwLjU1LTMuMjctNy4yLTIuMTUtMTMuOTItLjUxLTIwLjM2IDIuNzktNi4wOSAzLjExLTcuNjQgNS45LTYuOTMgMTIuNy40NiA0LjQ0IDEuNjYgOC44IDUuMTQgMTEuODEgNC42OCA0LjA0IDkuOCA3LjM0IDE2LjIyIDguMjMgNC43OS42NiA1Ljk3IDIuMzYgNS4zOSA3LjIzLS43NCA2LjI3LjE5IDEyLjMxIDIuMjYgMTguMTUgMy4zNiA5LjUxIDguNzggMTcuOTggMTQuMDcgMjYuNDkgMS4zOSAyLjI0IDMuMjcgMi43OCA1Ljg0IDIuNDcgMy4yOS0uNDIgNi42NC0uNDEgOS45Ny0uNTd6bS0yMTguNSAyMzYuNTF2LS4xYzEwLjM1LS40MyAyMC43LS44NiAzMS4wNC0xLjI5LjUzLS4wMiAxLjA1LS4xMSAxLjU3LS4xNCAxMS4zOS0uNjQgMjIuNzgtMS4yNyAzNC4xNi0xLjkuODgtLjA1IDEuNzYuMDEgMi42My0uMDYgMS42Ny0uMTMgMi4xNy0uODMgMS41NS0yLjQ2LTEuMjMtMy4yOS0yLjU2LTYuNTQtMy44OS05Ljc5LTEuNzktNC40LTIuODUtNS4wNS03LjUyLTQuNzItOC4wNS41Ni0xNi4xIDEuMjgtMjQuMTYgMS42Mi0xNC4yMS42LTI4LjQzLjkyLTQyLjY0IDEuNDQtNC43My4xOC05LjQ2LjU4LTE0LjE4Ljk3LTEuOTIuMTYtMi40IDEuMjMtMS4zIDIuODggMi41MiAzLjggNS4xNyA3LjUzIDcuNzEgMTEuMzIgMS4wOSAxLjYzIDIuNTggMi4yNSA0LjQ3IDIuMjQgMy41NC0uMDMgNy4wNS0uMDEgMTAuNTYtLjAxem01Ni40IDY0LjZjMCAuMDQgMCAuMDkuMDEuMTMgMTMuMzItLjQ5IDI2LjY1LS45OCAzOS45Ny0xLjQ4IDEuNC0uMDUgMi44Mi0uMDggNC4yLS4yOCAxLjc5LS4yNiAyLjQ4LTEuMzMgMS43Ni0yLjk4LTEuNzYtNC4wMi0zLjY2LTcuOTctNS41My0xMS45My0uNzUtMS42LTIuMDktMi4yOC0zLjgyLTIuMzItMS4wNS0uMDItMi4xLS4xMS0zLjE2LS4xLTExLjkzLjA5LTIzLjg3LjA4LTM1LjguMzQtOC4wNi4xNy0xNi4xMi43Mi0yNC4xOCAxLjEtNC4wMy4xOS04LjA2LjM0LTEyLjA5LjYyLTEuOTUuMTQtMi42MSAxLjItMS43MSAyLjgzIDIuMzkgNC4yOSA0LjkgOC41MiA3LjM5IDEyLjc0Ljc2IDEuMyAxLjk0IDEuOTggMy40OSAxLjk2IDEuNC0uMDEgMi44MS4wNSA0LjIxLjAxIDguNDMtLjIgMTYuODUtLjQzIDI1LjI2LS42NHptLTQuMjktMTA2LjU3Yy0yLjM3LjItMy45Ni4yNS01LjUyLjQ3LTIyLjg0IDMuMTktNDUuODMgNC40Mi02OC44NiA1LjA5LTQuMzkuMTMtOC43Ny41LTEzLjE1Ljg3LTEuNjQuMTQtMi4yMyAxLjI2LTEuMzMgMi41NiAyLjYxIDMuNzUgNS4zMyA3LjQyIDguMDQgMTEuMS45NiAxLjMgMi4zIDEuMjQgMy44IDEuMTYgMTQuNzQtLjg2IDI5LjQ4LTEuNjggNDQuMjItMi40NCAxMC41My0uNTQgMjEuMDctLjk1IDMxLjYxLTEuNDcgMi44MS0uMTQgNS42MS0uNDUgOC40MS0uNzMgMy4xMy0uMzEgMy41Ni0uOTkgMi4zNS00LjEzLTEuMDctMi43OS0yLjQ1LTUuNDYtMy40Ny04LjI3LTEuMjEtMy4zNi0zLjM3LTQuODEtNi4xLTQuMjF6bS0xMi40NCA2Ni43MWgtMzEuODdjLTEuNCAwLTIuODEtLjA0LTQuMjEuMDYtMS4yNy4wOS0xLjgyIDEuMDktMS4xNyAyLjI1IDEuNTUgMi43NSAzLjIzIDUuNDMgNC44MiA4LjE2IDQuODEgOC4yNCA0LjgxIDguMjMgMTQuMzkgNy42OCA5LjgxLS41NyAxOS42Mi0xLjM1IDI5LjQ0LTEuNjMgMTIuMjctLjM2IDI0LjU1LTEuNDcgMzYuODQtLjQ2Ljg3LjA3IDEuNzYuMDQgMi42My0uMDEgMS43Ny0uMTEgMi4xOS0uODcgMS4zLTIuMzgtMi4xMy0zLjYzLTQuMzctNy4yLTYuMzgtMTAuODktMS4wMy0xLjktMi4zOS0yLjkzLTQuNTMtMy4wMy00LjU1LS4yMS05LjEtLjY4LTEzLjY0LS42Mi04Ljk0LjEyLTE3Ljg4LjU0LTI3LjYyLjg3em0tLjQ3LTQuNzd2LS40N2MxMi40Ny0uMTcgMjQuOTQtLjMzIDM3LjQxLS41LjE4IDAgLjM1IDAgLjUzLS4wMSAzLjI0LS4yIDMuODYtLjk5IDIuNzEtMy44OS0xLjI5LTMuMjYtMi44OS02LjQxLTQuMTUtOS42OS0xLjExLTIuOS0zLjE1LTQuMDctNi4xLTQtNS42Mi4xMy0xMS4yNS4xMS0xNi44Ni40LTE1LjYxLjgxLTMxLjIxIDEuNzgtNDYuODIgMi42LTQuNTYuMjQtOS4xNC4xNi0xMy43LjMyLTEuNjIuMDYtMi4yNSAxLjEtMS41IDIuNSAxLjU4IDIuOTQgMy40NiA1LjcyIDQuOTIgOC43MSAxLjUzIDMuMSAzLjc5IDQuMTIgNy4xOSA0LjA3IDEyLjEyLS4xNCAyNC4yNS0uMDQgMzYuMzctLjA0em02MC43NCAxMDguMzJjMCAuMDguMDEuMTYuMDEuMjMgNS45Ny0uMjUgMTEuOTMtLjU0IDE3LjktLjcyIDQuNzQtLjE0IDkuNDktLjEyIDE0LjIzLS4yMyAyLjY3LS4wNiAzLjA5LS43MiAxLjktMy4yNS0xLjc4LTMuODItMy44My03LjUyLTUuNTItMTEuMzgtMS4zMi0yLjk5LTMuMzktNC4zLTYuNi0zLjk5LTEuMDUuMS0yLjExLjAxLTMuMTYuMDYtNy45LjMzLTE1Ljc5Ljg3LTIzLjY5Ljk3LTEyLjk5LjE1LTI1Ljk4IDEuNDEtMzguOTguMzctLjM1LS4wMy0uNy0uMDItMS4wNSAwLTIuMjkuMTEtMi44NCAxLjAyLTEuNTcgMy4wMyAyLjUzIDQuMDEgNS4zNyA3LjgzIDcuNzYgMTEuOTMgMi4wNiAzLjUzIDQuODIgNC41MSA4Ljc2IDQuMjYgOS45OS0uNjEgMjAtLjg3IDMwLjAxLTEuMjh6bS00OC45Mi00MS43NWM3LjkyLS4zNSAxNS4yOS0uNyAyMi42NS0xIDExLjIyLS40NiAyMi40NS0uODkgMzMuNjctMS4zNSAxLjA0LS4wNCAyLjEtLjE1IDMuMTEtLjQxIDEuNC0uMzYgMS45OC0xLjQzIDEuMzctMi44NC0xLjYtMy43LTMuMzItNy4zNi01LjA0LTExLS42Ni0xLjQtMS44OS0yLjAzLTMuNDItMi4wMy0xLjIzIDAtMi40Ni4wMS0zLjY4LjA3LTUuMjYuMjgtMTAuNTEuNzItMTUuNzcuODUtMTcuMDIuNDItMzQuMDQuNzItNTEuMDYgMS4wNy0uNy4wMS0xLjQxIDAtMi4xLjA2LTIuMjUuMjEtMi42OCAxLjA0LTEuNDcgMy4xNCAyLjAyIDMuNDkgNC4yMiA2Ljg5IDYuMTcgMTAuNDEgMS4yNyAyLjI5IDMuMDggMy4xMiA1LjYxIDMuMDUgMy40OS0uMSA3LS4wMiA5Ljk2LS4wMnptMjIuMjcgMTkuMDV2LjE4YzE0Ljc0LS41MSAyOS40OS0xLjAyIDQ0LjIzLTEuNTMuODgtLjAzIDEuNzYtLjAzIDIuNjItLjE4IDIuMTItLjM2IDIuNzctMS40IDEuOTYtMy4zLS43Ni0xLjc3LTEuNjgtMy40OC0yLjU5LTUuMTgtMy44NS03LjI3LTMuMDgtNi44NS0xMS4yOC02LjUzLTE4LjQzLjctMzYuODUgMS40LTU1LjI4IDIuMDctMy4zMy4xMi02LjY4LjA2LTEwLjAxLjE4LTEuNjMuMDYtMi4yMSAxLjA1LTEuNCAyLjQ5IDEuNjMgMi45MSAzLjQ0IDUuNzIgNS4wOSA4LjYyIDEuMjUgMi4yIDMuMDQgMy4yMyA1LjU4IDMuMjEgNy4wMy0uMDYgMTQuMDYtLjAzIDIxLjA4LS4wM3ptMjUuNjMgMjcuOTZjLTMuNjkgMC0xMC41Ni0uMDctMTcuNDEuMDMtMy42OS4wNi03LjM4LjM2LTExLjA2LjY2LTEuNjkuMTQtMi4xNyAxLjEzLTEuMTYgMi41NCAyLjk4IDQuMTQgNi4wNiA4LjIgOS4xMyAxMi4yOCAxLjMyIDEuNzUgMy4yMiAxLjk3IDUuMjIgMS44NSA0LjkxLS4zIDkuODItLjcgMTQuNzQtLjg5IDEzLjE4LS41MiAyNi4zNi0uOTUgMzkuNTQtMS40MyAxLjIzLS4wNCAyLjQ3LS4wNiAzLjY3LS4yOSAxLjc2LS4zMyAyLjMtMS4yOSAxLjY0LTMuMS0uNzctMi4xNS0xLjk4LTQuMTYtMi41Ni02LjM1LTEuMzQtNS4wNy01LTYuMzYtOS41OS02LjM4LTEuMDYtLjAxLTIuMTEtLjAyLTMuMTcuMDItOC41OS4zLTE3LjIuNjItMjguOTkgMS4wNnptMjQwLjY2LTE5My41OGMuMDEtLjA1LjAxLS4xLjAyLS4xNCAzLjE3IDAgNi4zMy4wNCA5LjUtLjAzIDEuMDMtLjAyIDIuMzYuMDEgMy4wMi0uNTkgMi42Ny0yLjQyIDMuOTktNS43IDQuOTUtOS4wOS4xMi0uNDItLjU1LTEuMjktMS4wNy0xLjYtLjcyLS40NC0xLjYyLS42OC0yLjQ4LS43OS0zLjE0LS40LTYuMjgtLjgyLTkuNDQtMS4wNS0xOS42My0xLjQ2LTM5LjI3LTIuODgtNTguOS00LjMtLjg4LS4wNi0xLjc2LS4wNy0yLjY0LS4wOS0xLjU2LS4wMy0yLjc2LjYyLTMuNDIgMi4wMi0xLjUgMy4xOC0yLjk5IDYuMzctNC4zOCA5LjYtLjYzIDEuNDYtLjAzIDIuMzQgMS42NCAyLjQ0IDMuNTEuMjIgNy4wMy4yOCAxMC41NC40OCAxNy41NiAxLjAzIDM1LjExIDIuMDkgNTIuNjYgMy4xNHptLTkuNiAxNy43M2MwLS4wNC4wMS0uMDguMDEtLjEyIDEuNCAwIDIuODEuMDEgNC4yMSAwIDkuOTEtLjA2IDcuODEgMS4xNCAxMi44LTcuNjYgMi42LTQuNTggMi4xNi01LjE3LTMuMTctNS4zNS0xMi4xLS40Mi0yNC4xOS0uNzktMzYuMjgtMS4zOC02LjY1LS4zMi0xMy4yOC0xLjE0LTE5LjkyLTEuNTctNC41NS0uMy05LjExLS4zNC0xMy42Ny0uNDUtMS40My0uMDMtMi45MS4xNi0zLjcxIDEuNTMtMS44NiAzLjE3LTMuNjcgNi4zOC01LjM4IDkuNjMtLjQ3Ljg5LjAyIDEuNzcgMS4wNSAxLjk5IDEuMDIuMjIgMi4wOC4yNyAzLjEzLjMzIDcuNy40MiAxNS40MS44NCAyMy4xMiAxLjIzIDEyLjU5LjYxIDI1LjIgMS4yMSAzNy44MSAxLjgyem0tNjAuMDggMS43OGMwLS4wNiAwLS4xMi4wMS0uMTctLjcgMC0xLjQtLjAxLTIuMTEgMC0yLjcuMDUtMy4zNC43NS0yLjQ2IDMuMDggMS4zIDMuNDUgMi43OSA2LjgyIDQuMiAxMC4yMi44NCAyLjAyIDIuMzYgMi45MSA0LjU2IDIuODQgMi40Ni0uMDggNC45MS0uMDQgNy4zNy0uMDggMTQuNzQtLjI4IDI5LjQ4LS42IDQ0LjIxLS44NiA4Ljg2LS4xNiA3LjI2IDEuMzYgMTEuODgtNy4zMiAyLjE4LTQuMSAxLjgxLTQuNTktMy00Ljc2LTExLjA1LS4zOC0yMi4xLS42NC0zMy4xNC0xLjE0LTEwLjUxLS40Ny0yMS4wMS0xLjE5LTMxLjUyLTEuODF6TTIyOS42MyA3OS43MmMuMSAxLjI2LjEyIDEuNzkuMTkgMi4zMSAxLjM5IDEwLjQyIDIuNzIgMjAuODUgNC4yMSAzMS4yNS43IDQuODUgMS42MiA5LjY4IDIuNjIgMTQuNDguNTMgMi41NCAxLjQgMy4wOCAzLjY1IDIuNTUgNC4wOS0uOTcgOC4xNy0yLjAyIDEyLjIxLTMuMTcgMi4yOC0uNjUgMi41OC0xLjM3IDIuMTEtMy45Ni0uMTYtLjg2LS4zOS0xLjcxLS41Ni0yLjU3LTEuNzItOC43Ni0zLjUyLTE3LjUxLTUuMTEtMjYuMy0uOS01LTEuNDMtMTAuMDYtMi4xMy0xNS4wOS0uNjUtNC42OC0xLjc4LTUuNjUtNi4xNC00LjcyLTIuOTEuNjItNS43NCAxLjU3LTguNiAyLjQtMS43NS41Mi0yLjU4IDEuNzEtMi40NSAyLjgyem0tNi43OS0uOTVjLTQuNjggMS4xOS05LjEgMi4yNi0xMy40OSAzLjQ2LTEuMzUuMzctMS44NCAxLjU1LTEuNzEgMi45Mi4wOC44Ny4yNyAxLjczLjQxIDIuNiAxLjYyIDkuNTEgMy4yMyAxOS4wMiA0Ljg2IDI4LjUzIDEuMDEgNS44OCAxLjk5IDExLjc2IDMuMDYgMTcuNjMuNDkgMi42NyAxLjQyIDMuMjMgNC4wNSAyLjQ5IDMuMDQtLjg2IDYuMDYtMS43OCA5LjA0LTIuODIgMi43LS45NCAzLjA2LTEuNjMgMi43NC00LjI3LS4wNi0uNTItLjIyLTEuMDMtLjMxLTEuNTUtMi40OS0xNC4xNy00LjUyLTI4LjQxLTUuODYtNDIuNzQtLjEzLTEuMzktLjMyLTIuODMtLjgxLTQuMTItLjI5LS43OS0xLjIyLTEuMzUtMS45OC0yLjEzem0yMjYuNTggNDE4LjI2YzguNzkgMCAxNS40OC4wMSAyMi4xNy0uMDEgMS4wNSAwIDIuMi4xNiAzLjEzLS4yLjg3LS4zMyAyLjAyLTEuMTUgMi4xOC0xLjkzLjkxLTQuNDcgMS42My04Ljk4IDIuMjUtMTMuNTEuMjItMS42MS0uNzgtMi42NC0yLjQ1LTIuODMtLjctLjA4LTEuNC0uMTUtMi4xLS4xNC0xMS43OC4yOC0yMy41Ni41OC0zNS4zNC44Ni0xLjgyLjA0LTMuNDcuNDktNC43OSAxLjgzLTIuNTkgMi42My01LjMyIDUuMTUtNy43MyA3Ljk0LTEuMTggMS4zNy0yLjk0IDIuODUtMi4yIDUuMDUuODggMi42MiAzLjM2IDIuMjQgNS4zOCAyLjMzIDcuMTkuMzIgMTQuNC40NyAxOS41LjYxek0zMDAuMTcgMzYyLjNjLTEuNDYtLjA2LTEuNy4xLTIuMzkgMi4zNy0uMi42Ny0uMzYgMS4zNi0uNDkgMi4wNS0yLjQzIDEyLjk0LTQuODggMjUuODgtNy4yNSAzOC44My0uODIgNC40OS0xLjQxIDkuMDItMi4xNSAxMy41Mi0uMzggMi4zMi4xIDQuMDMgMi40NiA1LjE2IDIuMDQuOTggMy44NiAyLjQxIDUuOCAzLjYyIDEuNTYuOTcgMi4yOS43MiAyLjU4LTEuMDIuNTgtMy40Ni45NS02Ljk2IDEuNi0xMC40MSAyLjk3LTE1LjcyIDYuOTctMzEuMTggMTIuMTctNDYuMzEuNDYtMS4zMy45NC0yLjY1IDEuMjgtNC4wMS40LTEuNi0uMTEtMi40NC0xLjY1LTIuNjItMy42NS0uNDItNy4zMi0uNzMtMTEuOTYtMS4xOHpNMjYxLjE5IDY5Ljg3Yy0xLjU1LjQyLTQuNDYgMS4wNi03LjI2IDIuMDMtMi45OSAxLjAzLTMuMzcgMS42Ni0yLjg5IDQuNjUgMS44MyAxMS4yNiAzLjY4IDIyLjUxIDUuNjggMzMuNzQuNzQgNC4xNCAxLjgzIDguMjIgMi45MyAxMi4yOS41OCAyLjEzIDEuMjggMi41MSAzLjQ5IDIuMTMgMy4xMS0uNTMgNi4yMi0xLjE0IDkuMjgtMS44OSAyLjIyLS41NCAyLjU3LTEuMiAyLjIyLTMuMzktLjE5LTEuMjEtLjU1LTIuMzktLjgxLTMuNTktLjkxLTQuMjktMi04LjU1LTIuNjctMTIuODgtMS41LTkuNzEtMi43Ny0xOS40Ni00LjE1LTI5LjE5LS40NS0zLjIxLTEuMjYtMy45MS01LjgyLTMuOXptMTguNDgtMy4xOGMtLjQxLjA1LTIuMDEuMDgtMy41NC40My0zLjY3Ljg1LTQuNTEgMi4wNS00LjQxIDUuOTUuMDMgMS4wNS4wNiAyLjEyLjIyIDMuMTUgMS40NSA5LjU1IDIuODEgMTkuMTIgNC40NCAyOC42My43NyA0LjQ5IDIgOC45MSAzLjE3IDEzLjMyLjU5IDIuMjEgMS4zMiAyLjY2IDMuNDEgMi4zMyAyLjk1LS40NyA1Ljg5LTEuMDMgOC43OC0xLjc0IDIuMjMtLjU1IDIuOC0xLjY0IDIuNDItMy45MS0uMTItLjY5LS4zNy0xLjM2LS41NC0yLjA0LTIuNS0xMC4wNy00LjU1LTIwLjIyLTUuODUtMzAuNTEtLjUzLTQuMTgtMS4xMi04LjM2LTEuNzQtMTIuNTItLjQ4LTMuMTctLjc0LTMuMzMtNC4xNC0zLjIyLS4zNS4wMS0uNy4wNC0yLjIyLjEzem02LjQzIDQ2NC4xMWMwIC4yMi4wMS40NC4wMS42Ni01Ljk4IDAtMTEuOTYtLjExLTE3Ljk0LjAzLTUuMDkuMTItMTAuMTguNTEtMTUuMjcuODUtLjYxLjA0LTEuMTkuNTItMS43OC43OS4yOS42MS40NSAxLjMzLjg5IDEuOCAyLjAyIDIuMjEgNC4xOSA0LjI4IDYuMTUgNi41MiAyLjg5IDMuMzEgNi4zNiA0LjUyIDEwLjc4IDQuMTMgMTQuNzEtMS4yOCAyOS40NC0yLjI4IDQ0LjE2LTMuNDcgNC4wMy0uMzIgNC40LTEuMTIgMi44My01LjA4LS4zMi0uODItLjc4LTEuNTktMS4wMS0yLjQzLTEuMDQtMy43Mi0zLjU2LTQuNzItNy4yLTQuNTMtNy4yLjQtMTQuNDEuNTEtMjEuNjIuNzN6bTE4Mi4zLTE1OS40M2MwLS4wNi4wMS0uMTMuMDEtLjE5IDYuNDguMjkgMTIuOTcuNTkgMTkuNDUuODggMy4yNi4xNCAzLjU2LS4wOCA0LjMzLTMuMTcuNjctMi43MSAxLjA5LTUuNDIgMi41Ny03Ljk1IDIuNTUtNC4zNCAyLjA1LTUuMDUtMi45NC00Ljk3LTE1LjQ0LjI1LTMwLjg3LjU2LTQ2LjMxLjg1LS44OC4wMi0xLjc2LjA2LTIuNjMuMTctMi42Mi4zMy0zLjE1IDEuMDUtMi4zIDMuNC43OCAyLjE0IDEuNzkgNC4xOSAyLjYgNi4zMy45MyAyLjQ3IDIuNjggMy40MyA1LjI2IDMuNTUgNi42Ni4yOSAxMy4zMS43MiAxOS45NiAxLjF6TTI5Ni43OCA2NC42N2MtNS4yMS0uMi02LjMyLjkyLTUuOTIgNS45Ny4wMy4zNS4wNS43LjEgMS4wNSAxLjg0IDEzLjQgNC4wMyAyNi43MyA3LjM4IDM5Ljg1LjMgMS4xOS41MiAyLjQ3IDEuMTUgMy40OC40OS43OCAxLjYxIDEuNzggMi4zNSAxLjcgMy42NC0uMzkgNy4yNy0xLjAzIDEwLjg3LTEuNzYgMS40Mi0uMjkgMS44Mi0xLjU1IDEuNTctMi45MS0uMTYtLjg2LS40MS0xLjctLjY1LTIuNTUtMy43OS0xMy41Mi03LjU3LTI3LjA1LTExLjM4LTQwLjU2LTEuMTEtMy44Ny0xLjUtNC4xMS01LjQ3LTQuMjd6TTQ1MS40IDUwMS45MXYtLjIzYy0xLjA1IDAtMi4xMS4wMy0zLjE2IDAtNi4xNC0uMTgtMTIuMjctLjQtMTguNDEtLjU1LTItLjA1LTIuNjMuNjktMi4wNiAyLjU3Ljk2IDMuMTkgMi4xNyA2LjMgMy4xIDkuNS44IDIuNzUgMi40IDMuOTYgNS4zMyAzLjk5IDExLjU4LjExIDIzLjE2LjM2IDM0LjczLjU3IDEuNjIuMDMgMi43My0uNjEgMy0yLjI4LjU4LTMuNjQgMS4xNy03LjI3IDEuNjUtMTAuOTIuMTktMS40NC0uNjUtMi4zNi0yLjA4LTIuNTItMS4yMi0uMTQtMi40NS0uMTItMy42OC0uMTMtNi4xNC0uMDEtMTIuMjggMC0xOC40MiAwek0zMTQuOTcgNjMuOTdjLTEuNTMgMC0yLjQxLjAxLTMuMjkgMC00Ljg4LS4wNy01LjU3Ljc5LTQuNDQgNS41My4yNCAxLjAyLjQ5IDIuMDUuNzggMy4wNiAzLjIzIDExLjEyIDYuNDYgMjIuMjMgOS42OSAzMy4zNC41NCAxLjg1IDEuMDggMy43IDEuNjQgNS41NS40NyAxLjU2IDEuNTcgMi4zMyAzLjE1IDIuMjIgMS45Mi0uMTMgMy44My0uNDEgNS43NC0uNjEgMy4xOS0uMzMgMy43Ni0uNzEgMi45OC00LjUzLS40Mi0yLjA2LTEuMDUtNC4wNy0xLjU2LTYuMTItMi43Mi0xMC44OS01LjU0LTIxLjc1LTguMS0zMi42Ny0xLjM4LTUuOTYtMS4xOC02LjAxLTYuNTktNS43N3ptMTU4LjYgMzI3LjMzYzQuMzkgMCA4Ljc4LjA4IDEzLjE3LS4wMyAzLjAyLS4wOCAzLjcxLS43OSA0LjA3LTMuNjcuMjktMi4yNi41Mi00LjU0LjY5LTYuODEuMTktMi42My0uNTItMy40OS0zLjE5LTMuNjktNC43My0uMzQtOS40Ni0uNTgtMTQuMTktLjg1LTUuNDMtLjMxLTEwLjg3LS42Mi0xNi4zLS44OS0yLjYzLS4xMy01LjI2LS4yNi03LjktLjI1LTEuNzEgMC0yLjQ3Ljg4LTEuOTEgMi4yOCAxLjUgMy43NSAzLjA0IDcuNDggNC44NCAxMS4wOS40Ni45MiAxLjgxIDEuNjUgMi45IDEuOTUgMS44NC41MSAzLjguNzggNS43MS44MyA0LjAyLjEzIDguMDcuMDUgMTIuMTEuMDR6bS0yMC4yOSAxMzAuODV2LS4yNGMtNS4yNyAwLTEwLjU0LS4wNy0xNS44MS4wMy0yLjQ5LjA0LTMuMTQuOTgtMi40IDMuMzggMS4wMyAzLjM2IDIuMjggNi42NSAzLjM0IDkuOTkuNjggMi4xNSAyLjEyIDMuMDkgNC4zIDMuMTcgNC4zOS4xNiA4Ljc4LjUyIDEzLjE2LjUxIDMuODYtLjAyIDcuNzEtLjQ1IDExLjU3LS42NyAyLjA4LS4xMiAzLjItMS4xOCAzLjUtMy4yMi40Mi0yLjc4Ljk1LTUuNTQgMS4zMS04LjMyLjQxLTMuMTMtLjExLTMuODMtMy4xOS0zLjk5LTUuMjUtLjI5LTEwLjUxLS40NC0xNS43OC0uNjR6bS04My40OCAxLjEydi0uOTJjNS45NiAwIDExLjkyLjA0IDE3Ljg4LS4wMyAxLjM3LS4wMSAzLjI3LjEyIDQuMDItLjY3IDIuNjEtMi43NyA0Ljg1LTUuOSA3LjEzLTguOTcuMTMtLjE3LS41MS0xLjI2LS45OC0xLjQ0LS43OC0uMy0xLjcxLS4yNy0yLjU5LS4zLTcuMDEtLjIxLTE0LjAyLS4zOS0yMS4wMi0uNTgtMy41MS0uMS03LjAxLS4xNi0xMC41Mi0uMjktMi0uMDgtMy44Ni4yMS01LjM0IDEuNy0yLjk3IDIuOTgtNS45NCA1Ljk2LTguODQgOS0uMzkuNDItLjY5IDEuNDEtLjQ2IDEuODEuMjUuNDMgMS4xNy42NiAxLjc5LjY3IDYuMzEuMDQgMTIuNjIuMDIgMTguOTMuMDJ6bTY0Ljc0IDE3LjI4Yy0uNTQtMS45Mi0uODctMy4yOS0xLjMxLTQuNjMtNC4xMS0xMi41My04LjIzLTI1LjA2LTEyLjM3LTM3LjU4LS4zMy0xLS43NC0xLjk4LTEuMTktMi45My0uNTYtMS4xOC0xLjQzLTIuMDItMi44Mi0yLjA2LTEuNC0uMDQtMi44Mi0uMTMtNC4yMSAwLTEuOTYuMTktMi42NiAxLjI5LTIuMTggMy4zNC4zMiAxLjM3Ljc5IDIuNyAxLjI1IDQuMDMgNC43IDEzLjgyIDkuNDkgMjcuNjEgMTQuMDggNDEuNDcgMi4wOSA2LjMxIDIuOTggNC45OSA2LjcgMS4zOC45My0uOTEgMS41MS0yLjIgMi4wNS0zLjAyem0yNi43Ny02Ni44OWM0LjIyIDAgOS40OS4wNiAxNC43NS0uMDIgMy43Ny0uMDYgNC41Ni0uOCA1LjA2LTQuNTQuMzItMi40My41LTQuODkuNjUtNy4zNC4xNS0yLjUzLS40LTMuMzMtMi44Ni0zLjMzLTYuMTQgMC0xMi4yOC4xNy0xOC40Mi4zNS0yLjM3LjA3LTQuMzYgMS4wNi02LjA1IDIuNzktMy40NCAzLjUxLTcgNi45LTEwLjQ0IDEwLjQxLS41Mi41My0uNjUgMS40NC0uOTcgMi4xOC42Ni4xNCAxLjMzLjQzIDEuOTkuNCA1LjA4LS4yNSAxMC4xNi0uNTYgMTYuMjktLjl6bS00MS4zNS0zNzcuOGguMTVjMC0zLjUxLS4wNC03LjAzLjAxLTEwLjU0LjEyLTguMzQuODctNy42OC03Ljk4LTkuODctNS4wMi0xLjI0LTUuNjUtLjc1LTUuNDYgNC4zLjM0IDguOTUuODUgMTcuODkgMS4zIDI2LjgzLjMxIDYuMTMuOSA2LjcxIDcuMTMgNy4xMS4zNS4wMi43LjA1IDEuMDUuMDUgMy4wMS4wMyAzLjc2LS42NSAzLjc5LTMuNjUuMDMtNC43Ni4wMS05LjUuMDEtMTQuMjN6bS0zOS4yMSA0MDkuNTh2LjRjNC4zOCAwIDguNzYuMDMgMTMuMTQtLjAyIDEuMzktLjAxIDIuODEtLjEyIDQuMTctLjM5IDEuMTktLjI0IDEuODEtMS4xNyAxLjM2LTIuMzctLjg3LTIuMjktMS44Ny00LjUzLTIuODQtNi43OC0uOTQtMi4xNy0yLjU2LTMuMS00Ljk3LTMuMTEtOS4yOC0uMDEtMTguNTQtLjU4LTI3LjgxLjgyLTQuODMuNzMtNS40MS42NC0zLjkzIDUuODUuMTQuNTEuMzYuOTkuNDYgMS41MS41NyAyLjgzIDIuMjUgNC4xNSA1LjE4IDQuMTEgNS4wOS0uMDcgMTAuMTctLjAyIDE1LjI0LS4wMnptNDQuMTgtNDA5LjEyaC0uMjVjMCAzLjM0LS4wMSA2LjY4IDAgMTAuMDIuMDEgMS41OC0uMDMgMy4xNy4wOSA0Ljc0LjIyIDMgLjcxIDMuNjUgMy42MSA0LjMzIDEuNy40IDMuNDcuNTcgNS4yMS42OSAyLjYyLjE4IDMuMDktLjI2IDMuMjMtMi44Ni4wOS0xLjc1IDAtMy41Mi4wNy01LjI3LjI5LTcuMDIuNTctMTQuMDUuOTItMjEuMDYuMjMtNC42OS0uMTQtNS4yNS00LjktNi40MS0xLjUzLS4zNy0zLjA3LS43OC00LjYzLTEuMDEtMi42NC0uNC0zLjI4LjA1LTMuMzMgMi42MS0uMDkgNC43My0uMDIgOS40Ny0uMDIgMTQuMjJ6bTUwLjMzIDMxMy4zM3YuNjRjMy4zNCAwIDYuNjguMDkgMTAuMDItLjAzIDIuNDUtLjA5IDMuMS0uNjkgMy41Mi0zLjA2LjQzLTIuNDIuNzctNC44Ny44Ny03LjMyLjExLTIuNzEtLjY0LTMuNTItMy4zNC0zLjYtOS40OC0uMjktMTguOTctLjQ4LTI4LjQ2LS42OC0xLjE2LS4wMi0xLjU4Ljg0LTEuMTggMS43NyAxLjMxIDMuMDcgMi43OCA2LjA3IDQuMTIgOS4xMi45NyAyLjIxIDIuNjQgMy4xNyA0Ljk4IDMuMTYgMy4xNS0uMDEgNi4zMSAwIDkuNDcgMHptLTcyLjQ0LTMwMi4zN2MtLjMtOS4yNy0uNTgtMTguNTQtLjktMjcuODEtLjA0LTEuMjItLjI2LTIuNDQtLjQxLTMuNjUtLjIzLTEuOTQtMS4yMy0zLjItMy4xOS0zLjY4LTIuODktLjcxLTUuNzUtMS41Mi04LjY1LTIuMjEtMS43Ni0uNDItMi4yOS4wMy0yLjExIDEuODMuNDggNC44OC45NSA5Ljc2IDEuNjYgMTQuNjEuMTkgMS4yOC45OCAyLjY2IDEuODkgMy42MiA0Ljc1IDUuMDUgNy4xMyAxMS4xMyA4LjI4IDE3Ljg0LjI3IDEuNTgtLjM3IDMuNzkgMi4wNyA0LjI2IDEuMzEuMjQgMS43Ni0xLjEyIDEuMzYtNC44MXptMjQuMzYgODEuODN2LjI4Yy0xLjkyIDAtMy44NS0uMDktNS43Ny4wMi0zLjM4LjItNi40MSAxLjQ0LTkuMzQgMy4xNy0zLjcyIDIuMi00LjY3IDUuNDEtNC4xNSA5LjM3LjE4IDEuMzYgMSAxLjc0IDIuMjQgMS4zMy41LS4xNi45Ny0uNCAxLjQ2LS41OSA1LjgtMi4yNyAxMS43OS0zLjE4IDE4LjAxLTIuNSAzLjEzLjM0IDYuMjcuNjkgOS40MS44Ljg4LjAzIDIuMTUtLjUgMi42My0xLjIgMS4zMy0xLjk0LjY1LTUuNjctMS4xMS03LjIxLTIuMDMtMS43OC00LjQyLTIuODUtNy4xLTMuMTItMi4wOC0uMjEtNC4xOC0uMjQtNi4yOC0uMzV6bTQ4LjMgMjI2LjAxdi0uMjVjLTIuNjEtLjE3LTUuMjItLjQtNy44NC0uNDctMS42LS4wNS0yLjEzLjk0LTEuNDYgMi40My4wNy4xNi4xMy4zMy4yMy40NyAzLjQ0IDQuNDYgNi4yOCA5LjE1IDYuOCAxNC45Ny4xNCAxLjYgMS41IDIuMzUgMy4wNyAyLjIgMi4yNi0uMjEgNC41LS41NSA2Ljc1LS44NyAxLjM1LS4xOSAyLjI5LS45OCAyLjUxLTIuMzEuNzItNC4zIDEuNS04LjYgMS45OC0xMi45Mi4yNS0yLjIzLS42OC0zLjA4LTMuMTQtMy4yMS0yLjk2LS4xNi01LjkzLS4wNC04LjktLjA0ek0zMzAuMjQgODUuM2MuMzkgMS42Ny43NCAzLjM1IDEuMTggNSAxLjMxIDQuOSAyLjY1IDkuNzkgMy45OCAxNC42OSAxLjgyIDYuNzEuNzUgNy4yNiA5LjY3IDYuNzguNTItLjAzIDEuMDUtLjA5IDEuNTctLjE0IDEuNTItLjE1IDIuMDktMS4wMiAxLjk2LTIuNS0uNDMtNC44Ny0uODYtOS43NC0xLjIzLTE0LjYxLS4xMy0xLjc4LS44My0zLjAxLTIuNjYtMy4zOS01LjAzLTEuMDUtOS41NS0zLjI1LTE0LjQ3LTUuODN6bTk4LjYxIDEzMC4yNmMzLjE5LS41NyA2Ljg1LS45NyAxMC4zNS0xLjkzIDIuNjEtLjcyIDMuNDQtMi45NCAyLjcyLTUuNDItLjYtMi4wNi0yLjMzLTIuNjMtNC4wOS0yLjctNS41OS0uMjQtMTEuMTktLjQ5LTE2Ljc4LS4zNi0zLjcyLjA5LTcuMTUgMS42Mi0xMC4zNyAzLjQ3LS42LjM0LTEuMTkuNzUtMS42NiAxLjI2LS43Mi43OS0uNjIgMS43My4yOSAyLjIxIDEuMDYuNTYgMi4yNCAxLjAyIDMuNDIgMS4yMSA1LjE5Ljc4IDEwLjM5IDEuNDYgMTYuMTIgMi4yNnptLTI5LjUzIDY5LjMzYzMuNDUgMCA3LjEyLjAyIDEwLjgtLjAxIDEuMDQtLjAxIDIuMTItLjA0IDMuMTItLjMgMS42Ny0uNDQgMi4zOC0yLjI0IDEuNTctMy43OC0xLjI0LTIuMzgtMy4yOS0zLjYxLTUuOTItMy43NC0yLjgtLjEzLTUuNi0uMTYtOC40LS4xLTYuMDQuMTMtMTEuNzcgMS42LTE3LjE5IDQuMjQtMy45MyAxLjkyLTcuODIgMy45My0xMS42OSA1Ljk2LTEuNjYuODctMy4yMiAxLjkxLTQuODMgMi44NyAyLjEzIDEuMzEgMy44Mi0uNCA1LjctLjgzLjM0LS4wOC42Ny0uMjEuOTktLjM0IDguMi0zLjU0IDE2LjY4LTUuMjQgMjUuODUtMy45N3ptNTAuNDUtMTgzLjc5aC4yMlY4Ny40NmMwLTMuNDItMi4zMi00LjI4LTUuMzEtNC4zMy0uNTQtLjAxLTEuMzIuNTgtMS41OSAxLjEtLjM4Ljc0LS41MSAxLjY4LS41NCAyLjU0LS4yOCA4LjkxLS42IDE3LjgzLS43MiAyNi43NC0uMDUgMy4zNCAxLjY0IDQuNTkgNS4wMSA0LjM4IDEuNDItLjA5IDIuMzUtLjc4IDIuNjEtMi4xMi4yNC0xLjE5LjMtMi40My4zMS0zLjY1LjAzLTMuNjcuMDEtNy4zNC4wMS0xMS4wMnpNMjczLjgyIDU1MC4xN2MtLjA0LjI5LS4wNy41OC0uMTEuODcuOTguMyAxLjkzLjcxIDIuOTMuODggMi40Mi40MSA0Ljg1Ljg4IDcuMjkgMS4wMyA2LjMxLjM5IDEyLjY0LjcyIDE4Ljk2Ljg3IDUuMjcuMTMgMTAuNTUuMDggMTUuODItLjA4IDIuNS0uMDggMy43My0xLjA2IDMuNjQtMi4yNS0uMTUtMS44LTEuNzctMy45MS0zLjQyLTQuMjQtMS4wMi0uMjEtMi4xLS4yNC0zLjE1LS4yMi0zLjE2LjA2LTYuMzMuMDktOS40OC4zMi05LjI5LjY2LTE4LjU3IDEuNC0yNy44NSAyLjE1LTEuNTUuMTItMy4wOS40NC00LjYzLjY3em0xOTguNjUtOTYuNTh2LS4wN2MyLjQ2IDAgNC45MS4wNSA3LjM3LS4wMiAxLjU4LS4wNCAyLjczLS45NCAzLjAxLTIuNDcuNTgtMy4yOCAxLjA4LTYuNTcgMS40MS05Ljg4LjE3LTEuNjktLjc4LTIuNTgtMi41OS0yLjUzLTEuOTIuMDUtMy44My40NC01Ljc1LjU2LTIuMTMuMTQtMy40NCAxLjE5LTQuNTUgMy4wMi0xLjcyIDIuODQtMy43OSA1LjQ2LTUuNzIgOC4xNy0uNDEuNTctMS4wNyAxLjA1LTEuMjMgMS42Ny0uMTEuNDMuNDIgMS40Ny43IDEuNDggMi40NC4xMiA0LjkuMDcgNy4zNS4wN3ptLTI5LjEzLTI2Ny43MmMtLjczLS44MS0xLjM3LTEuODYtMi4zLTIuNDgtOC43My01LjgtMTcuODQtNS43NS0yNy4wMy0xLjMxLTEuNjIuNzgtMi43OSAyLjU0LTQuMDcgMy45My0uMjguMy0uMTYuOTctLjIyIDEuNDcuNDkuMDQgMS4wNS4yNyAxLjQ1LjExIDkuOTktNC4yNyAyMC4wNi00LjUyIDMwLjI0LS43MS4zMS4xMi43My4xNiAxLjAyLjA0LjI2LS4xMi40My0uNDkuOTEtMS4wNXptMTAuNDYgMzU3Ljg5Yy00LjItLjI2LTcuMzctLjQtMTAuNTItLjY4LTMuNDQtLjMtNS41OCAxLjctNy40NiA0LjEyLS4xOS4yNS4yMSAxLjMzLjYgMS41Ny41NC4zMyAxLjM1LjMyIDIuMDUuMzEgNi42OC0uMTUgMTMuMzYtLjM1IDIwLjA0LS40OSAyLjUtLjA1IDQuMjgtMS40NCA1LjkyLTMuMDcuMjgtLjI4LjMzLS45LjMtMS4zNS0uMDEtLjE2LS41OS0uMzktLjkxLS4zOS0zLjY4LS4wMy03LjM3LS4wMi0xMC4wMi0uMDJ6bS00Ny4wNy0yNy44OXYtLjA0Yy4zNSAwIC43LjAyIDEuMDUgMCAyLjkzLS4xOCAzLjUtLjkgMi42Ny0zLjU3LTEuNjYtNS4zNS0zLjM3LTEwLjY5LTUuMS0xNi4wMi0uMjYtLjgxLS42LTEuNzctMS4yMi0yLjIzLS41OC0uNDMtMS42My0uNDYtMi4zOC0uMjgtLjMxLjA4LS42NSAxLjI0LS41IDEuNzguMzYgMS4zNCAxLjAyIDIuNiAxLjUyIDMuOTEuODEgMi4xMiAxLjU5IDQuMjYgMi4zNyA2LjQgMS4wMiAyLjc2IDEuMzYgNS4zNS0uOSA3Ljg1LTEuMDkgMS4yMS0uMzggMi4xMiAxLjQ1IDIuMi4zNC4wMS42OSAwIDEuMDQgMHpNMzgzLjY5IDgxLjQxYy0uMjgtMy4yNC0uMzYtNS41My0uNzItNy43Ny0uMjQtMS41LS44OS0yLjkzLTEuMzYtNC4zOS0yLjE4IDEuMTUtLjcyIDMuMDgtLjk0IDQuNjMtLjMyIDIuMjUtLjQ1IDQuNTItLjU5IDYuNzktLjA4IDEuMzYgMS4xNiAyLjYyIDIuMjUgMi4xNy42MS0uMjUuOTMtMS4yMiAxLjM1LTEuODkuMDctLjEyLjAxLS4zNC4wMS40NnoiLz48cGF0aCBjbGFzcz0ic3QxIiBkPSJNMzE3LjM4IDIwNy41OGMuODcuNCAxLjQ2LjgyIDIuMS45NiA2LjM3IDEuMyAxMi43MiAyLjY2IDE5LjEyIDMuNzkgOC43MiAxLjU0IDE3LjE1LjIyIDI1LjMyLTMuMDQgMS4zMS0uNTIgMi41Ny0xLjE2IDMuODgtMS42NiAxLjk0LS43NCAzLjI0LS41MSAzLjY1LjY4LjYxIDEuNzQtLjY4IDIuNTQtMS44NiAzLjMyLS41OC4zOC0xLjIyLjctMS44Ni45OS04LjgxIDQuMDQtMTguMDQgNS45NC0yNy43MSA0Ljc5LTUuNC0uNjQtMTAuNzUtMS43My0xNi4wOC0yLjgtNC4xMy0uODMtOC4yMS0xLjkzLTEyLjI5LTIuOTktMS4xNy0uMy0yLjM1LS43NS0zLjM3LTEuMzktMS4yNi0uNzktMS40Ni0yLjY1LS4zNi0zLjY3IDEtLjk0IDIuMjItMS43IDMuNDYtMi4zMSA5LjUzLTQuNzMgMTkuNTUtNy44NSAzMC4xNS05LjAzIDcuMTYtLjggMTQuMy0yIDIxLjUxLS41NCAxLjM4LjI4IDIuNDctLjA5IDIuOTYtMS40OS41OC0xLjY5IDAtMy40LTEuMzMtNC4xNC0uMzEtLjE3LS42My0uMzItLjk2LS40Mi0xMS41LTMuMzktMjIuOTMtNC45OC0zNC42LS4zMS05LjY0IDMuODYtMTkuMjkgNy42NS0yOC4yMiAxMy4wMS0yLjA4IDEuMjUtNC4xMyAyLjc3LTUuNzEgNC41OS0zLjA1IDMuNTEtMy4xMyA3LjAzLjA4IDEwLjQxIDMuMzcgMy41NSA3LjE1IDYuNzYgMTAuOTkgOS44MiAzLjI5IDIuNjIgNi44NyA0LjkgMTAuNCA3LjIgNC42NiAzLjAzIDcuNjQgNy4xOSA4Ljg4IDEyLjU5Ljc1IDMuMjUgMS41NSA2LjUgMi4xIDkuNzkgMS4zIDcuNjYgMy40NiAxNS4wNiA2LjA3IDIyLjM1IDEuODQgNS4xMiAzLjQ2IDEwLjMzIDUuMDUgMTUuNTQuNCAxLjMxLjUxIDIuNzguMzYgNC4xNC0uMDcuNjQtLjk4IDEuNDEtMS42OCAxLjY5LS40NS4xNy0xLjQ0LS4yOS0xLjc4LS43Ni0uNi0uODItLjk1LTEuODUtMS4yOC0yLjgzLTIuMTgtNi41LTQuNDctMTIuOTYtNi40My0xOS41Mi0xLjg1LTYuMjItMy4zNi0xMi41NS00Ljk2LTE4Ljg0LS40Ny0xLjg3LS44NC0zLjc4LTEuMDktNS43LS45NS03LjI3LTQuNDItMTIuNjItMTAuODctMTYuNDctNC45NS0yLjk1LTkuMzYtNi44Mi0xMy45MS0xMC40MS0xLjc5LTEuNDEtMy4zOC0zLjA4LTQuOTMtNC43NS02LjQ5LTctNC4yNi0xMy44MiAxLjExLTE5LjAzIDEuNzQtMS42OSAzLjkxLTMgNi4wMS00LjI1IDkuNzEtNS43NiAxOS45OS0xMC4zMyAzMC42Ny0xMy45NCA4Ljg2LTMgMTcuODctMy42IDI2Ljk4LS45NyAyLjE5LjYzIDQuNDUgMS4wMyA2LjY3IDEuNTYgNS4xMiAxLjIzIDEwLjMzIDIuMTUgMTUuMDYgNC42NyAxLjY0Ljg3IDIuNTIuMDkgMi42MS0xLjg0LjExLTIuMzctLjk2LTQuMDctMi44NS01LjI5LTYuMTItMy45Ni0xMi42Mi03LjAxLTIwLTcuNTktOC44Ni0uNjktMTcuNTQuMDYtMjUuOTMgMy4zMS02LjcyIDIuNi0xMy41NiA0Ljg5LTIwLjI1IDcuNTctMy40MSAxLjM3LTYuNiAzLjI4LTkuODggNC45Ny0xLjQuNzMtMi43NCAxLjYtNC4xNyAyLjI2LTEuODMuODQtMy4xOS41OS0zLjY4LS41OS0uNjktMS42NS4yMy0yLjc5IDEuNTEtMy41MSA0LjYtMi41NyA5LjA4LTUuNDQgMTMuOTItNy40NSA3Ljk1LTMuMyAxNi4xLTYuMTIgMjQuMjMtOC45NiA4LjgxLTMuMDggMTcuOTYtMy40MiAyNy4wOS0yLjE4IDcuNDMgMS4wMSAxNC4xMiA0LjI4IDIwLjIxIDguNTkgNC44NSAzLjQzIDYuMDcgMTAuNDQgMyAxNS41NS0xLjAzIDEuNzItMi41NiAyLjMzLTQuNTEgMS40OS0xLjkzLS44My0zLjctMi4wNC01LjYxLTIuOS0yLjI1LTEuMDEtMy4xNi0uMzgtMy41IDIuMTMtLjk4IDcuMzktLjk3IDcuMzUtOC40OCA1LjkyLTIuMDYtLjM5LTQuMTktLjgxLTYuMjYtLjcyLTExLjYyLjUzLTIzLjE0IDEuNzEtMzQuMDkgNi4wMi0xLjU2LjU4LTMuMzMuOS00LjY2IDIuNTl6TTIzMS43MyAyMDUuMTRjLS42OSA3LjE1LTMuMjUgMTQuOTItMTAuMTggMTkuOTQtNC43MyAzLjQzLTUuNTQgNi45NC0zLjk1IDEyLjA3IDEuMzUgNC4zNCAyLjE2IDguODYgMy4xNyAxMy4zLjM0IDEuNSAxLjAzIDMuMTctLjc4IDQuMjItMS4yNi43My0yLjUyLS4zOS0zLjUxLTMtLjMxLS44Mi0uNjEtMS42Ni0uNzktMi41MS0xLjI2LTYuMTktMi40NS0xMi4zOS0zLjc2LTE4LjU3LS41LTIuMzYuMDgtNC4xIDIuMTctNS4zOSAxLjE5LS43NCAyLjI1LTEuNjggMy4zOC0yLjUxIDUuMDgtMy43NCA3Ljc4LTguOTggOS4xNS0xNC45NSAyLjY0LTExLjUzLTguMDEtMTkuMDItMTcuNTktMTUuNDItNC4zNyAxLjY0LTguMTUgNC4xLTExLjIgNy42Mi0zLjAxIDMuNDgtNC4yNSA3LjU5LTQuMjYgMTIuMTUgMCAxLjQxLS4yMiAyLjg5LTEuOTUgMy4zMi0xLjI2LjMxLTIuMzctMS4xMi0yLjQxLTMuNDEtLjA5LTQuODcgMS4xOC05LjQyIDQuMDQtMTMuMzggNC4zOS02LjA5IDEwLjMzLTEwLjAxIDE3LjY4LTExLjUyIDEwLjYyLTIuMjIgMjAuNzggNi4xIDIwLjc5IDE4LjA0ek0yMTcuMzkgMjcwLjEzYy4wMS0zLjM4IDIuOTUtNi4wNCA2LjY4LTYuMDQgMy43MSAwIDYuNiAyLjczIDYuNTIgNi4xNi0uMDggMy40NC0yLjk2IDYuMzctNi4zOCA2LjUtMy41NC4xNC02LjgzLTMuMDUtNi44Mi02LjYyem04LjYyLjM4Yy0uNy0uNzYtMS4xNS0xLjYxLTEuNTMtMS41OS0uNy4wNS0xLjM3LjYzLTIuMDUuOTguNC42NC43MiAxLjcxIDEuMjIgMS44MS41OC4xMiAxLjMzLS42MyAyLjM2LTEuMnpNMzkyLjA4IDEyMS4yOWMtLjM3IDMuNjQtLjY0IDYuOTctMS4wNSAxMC4yOC0uMzQgMi43Mi0xLjg4IDQuNDctNC42MyA1LjA1LS42OS4xNC0xLjM2LjM2LTIuMDUuNTEtNi43NCAxLjQ4LTguMjMuODktMTEuMDUtNS40OC0zLjY5LTguMzUtNy4yLTE2Ljc5LTEwLjYxLTI1LjI2LTEuMDQtMi41OS0xLjYxLTUuMzgtMi4yMi04LjEyLS4zLTEuMzUtLjM2LTIuOC0uMjQtNC4xOS41Mi02LjAzIDQuOTktOS4xIDEwLjc0LTcuMjkgNS4xOCAxLjYzIDkuMzcgNC43NSAxMi41OCA5LjE0IDMuOTEgNS4zNSA2LjI2IDExLjM3IDcuNTIgMTcuODIuNDkgMi41OS43IDUuMjIgMS4wMSA3LjU0em0tNC43NiAxLjQyYy0uMjEtOC41Mi0yLjI5LTE1LjctNi4zMS0yMi4yOS0yLjE0LTMuNTEtNS4wMy02LjMyLTguOC04LjA5LS45NS0uNDQtMS45NC0uODctMi45Ni0xLjA3LTIuNDYtLjQ5LTQuMTMuNzUtNC4zNiAzLjI4LS4xMSAxLjItLjA2IDIuNDkuMjUgMy42NS44MSAzLjA1IDEuNjcgNi4xIDIuNzYgOS4wNiAxLjYzIDQuNDUgMy40MiA4Ljg1IDUuMjQgMTMuMjIgMS40MSAzLjQgMi45NyA2Ljc1IDQuNDggMTAuMTEuOTcgMi4xNyAyLjggMi40MiA0Ljg2IDIuMTIgMi41NS0uMzggMy41Mi0xLjEgMy45Ni0zLjQ3LjQ1LTIuNC42Ni00Ljg2Ljg4LTYuNTJ6TTM1Mi4wMiA4NC4zNGMtMS44Mi0uMzktNC45MS0uOTktNy45Ny0xLjczLTEuMDEtLjI0LTEuOTctLjc2LTIuODgtMS4yNy05LjMyLTUuMjgtOS43MS0xNi45NS0uNzctMjIuODYgMi41NS0xLjY5IDUuMzktMi41OSA4LjQzLTIuNjUgNi4xOS0uMTEgMTEuNzggMS41OCAxNi41IDUuNzQgNS4xNCA0LjUzIDUuOTIgMTAuMyAyLjExIDE2LjAyLTMuMzYgNS4wNS04LjM5IDYuNi0xNS40MiA2Ljc1em0tMS42NS0yNC4xNWMtMS43Mi4yOC0zLjUyLjMyLTUuMTQuOS0zLjczIDEuMzMtNi4yMSAzLjk3LTYuNzUgOC0uNDMgMy4yNCAyIDcuMDUgNS44NyA4LjUyIDIuOSAxLjExIDYuMDggMS45NSA5LjE2IDIuMDQgNC4xMy4xMiA3Ljk5LTEuMiAxMC4zMi01LjEzIDIuMDEtMy4zOSAxLjczLTYuMzItMS4xNC05LjAyLTMuNDMtMy4yMi03LjM5LTUuMzMtMTIuMzItNS4zMXoiLz48L3N2Zz4='
9+ base+'sphinx'
10+ glob-ames+[~donmec-sallud 0v0]
11+==
desk/gen/get.hoonnew file+9
@@ -0,0 +1,9 @@
1+/- s=sphinx
2+:- %say
3+|= $: [now=@da eny=@uv =beak]
4+ [[=hash:s ~] ~]
5+ ==
6+=/ our (scot %p p.beak)
7+=/ wen (scot %da now)
8+=/ state=state:s .^(state:s /gx/[our]/sphinx/[wen]/state/noun)
9+noun+(~(got by directory.state) hash)
desk/gen/metaphone.hoonnew file+6
@@ -0,0 +1,6 @@
1+/+ *metaphone
2+:- %say
3+|= $: [now=@da eny=@uv =beak]
4+ [[word=@t ~] ~]
5+ ==
6+noun+(utter word)
desk/gen/publish-all.hoonnew file+29
@@ -0,0 +1,29 @@
1+/- s=sphinx
2+/+ *sphinx
3+:- %say
4+|= $: [now=@da eny=@uv =beak]
5+ [~ ~]
6+ ==
7+:- %declarations
8+^- (list declare:s)
9+:~ :- %friends
10+ ['networked subject' %group 'web+urbitgraph://group/~matwet/networked-subject' 'https://subject.network | networked subject' ~['hosting' 'networking' 'urbit' 'ops'] 'https://urbits3.ams3.digitaloceanspaces.com/sitful-hatred/2022.7.07..17.15.52-ns.png' '']
11+ :- %friends
12+ ['Hooniverse' %group 'web+urbitgraph://group/~hiddev-dannut/new-hooniverse' 'Community based Hoon learning for all levels. For discussion of Hoon specific to Uqbar, join ~hiddev-dannut/uhoon' ~['hoon' 'dev' 'urbit' 'programming' 'education'] 'https://i.imgur.com/ghThlz7.png' '']
13+ :- %friends
14+ ['Hollow Mars Theory' %group 'web+urbitgraph://group/~rabsef-bicrym/hollow-mars-theory' 'Definitely NOT a Conspiracy Chat' ~['conspiracies' 'ufos' 'steel beams'] '' '']
15+ :- %friends
16+ ['celestial systems' %group 'web+urbitgraph://group/~nocsyx-lassul/celestial-systems' 'A place for pilots who are building hosting providers' ~['hosting' 'ops' 'urbit'] '' '']
17+ :- %friends
18+ ['Structure' %group 'web+urbitgraph://group/~fabled-faster/structure' 'Urbit Structural Design and Engineering Group. Always Thinking About Mechanics.' ~['design' 'ux' 'hci' 'urbit'] 'https://fabled-faster.nyc3.digitaloceanspaces.com/fabled-faster/2022.1.27..17.59.43-image.png' '']
19+ :- %friends
20+ ['The Marketplace' %group 'web+urbitgraph://group/~tirrel/the-marketplace' 'Welcome to The Marketplace, featuring The Pit, Urbit\'s first open-outcry market!' ~['urbit' 'market' 'sell' 'buy'] 'https://snipboard.io/U0IYyi.jpg' '']
21+ :- %friends
22+ ['The Forge' %group 'web+urbitgraph://group/~middev/the-forge' 'pale fire computing' ~['dev' 'programming' 'hoon' 'urbit'] 'https://nyc3.digitaloceanspaces.com/archiv/littel-wolfur/2021.5.06..21.01.58-the%20forge.png' '']
23+ :- %friends
24+ ['UFORIA' %group 'web+urbitgraph://group/~tiplec-lacnyx/ufora' 'UFO Research, Investigations, and Analysis' ~['UFO' 'conspiracies' 'research'] 'https://tiplec-lacnyx.nyc3.digitaloceanspaces.com/tiplec-lacnyx/2021.12.27..06.09.47-change1.jpg' '']
25+ :- %friends
26+ ['Urbit Community' %group 'web+urbitgraph://group/~bitbet-bolbel/urbit-community' 'World hub, help desk, meet and greet, etc.' ~['general' 'urbit' 'community' 'help'] 'https://fabled-faster.nyc3.digitaloceanspaces.com/fabled-faster/2021.4.02..21.52.41-UC.png' '']
27+ :- %friends
28+ ['Urbytes' %group 'web+urbitgraph://group/~nartes-fasrum/urbytes' 'We feed and water Mars.' ~['cooking' 'food' 'beverages' 'peanut butter eggs'] '' '']
29+==
desk/gen/publish.hoonnew file+9
@@ -0,0 +1,9 @@
1+/- s=sphinx
2+/+ *sphinx
3+:- %say
4+|= $: [now=@da eny=@uv =beak]
5+ [[=post:s ~] ~]
6+ ==
7+:- %declare
8+^- declare:s
9+[%friends post]
desk/gen/ranks.hoonnew file+37
@@ -0,0 +1,37 @@
1+/- s=sphinx
2+/+ *sphinx, *sift
3+:- %say
4+|= $: [now=@da eny=@uv =beak]
5+ [[word=@t algo=?(%all %exact %phonetic %ngram) ~] ~]
6+ ==
7+=/ our (scot %p p.beak)
8+=/ wen (scot %da now)
9+=/ state=state:s .^(state:s /gx/[our]/sphinx/[wen]/state/noun)
10+=/ title (norm:sift word) :: full query
11+=/ parts (sift:sift word) :: split query
12+=/ index ~(. delver index.state)
13+=/ lookup
14+ ?- algo
15+ %all get-entries.index
16+ %exact get-exact.index
17+ %ngram get-trigrams.index
18+ %phonetic get-phonetics.index
19+ ==
20+=/ title-entries=(list entry:s)
21+ %+ turn
22+ (lookup title)
23+ (uprank 10)
24+=/ entries=(list entry:s)
25+ %- sum-ranks.index
26+ %- zing
27+ %+ turn
28+ parts
29+ |= word=@t
30+ (lookup word)
31+:- %noun
32+%+ turn
33+ ?: =(algo %all) (lookup word)
34+ (welp entries title-entries)
35+|= [=hash:s =rank:s]
36+=/ listing (~(got by directory.state) hash)
37+[rank title.post.listing hash]
desk/gen/state.hoonnew file+8
@@ -0,0 +1,8 @@
1+/- s=sphinx
2+:- %say
3+|= $: [now=@da eny=@uv =beak]
4+ [~ ~]
5+ ==
6+=/ our (scot %p p.beak)
7+=/ wen (scot %da now)
8+noun+.^(state:s /gx/[our]/sphinx/[wen]/state/noun)
desk/gen/validate.hoonnew file+6
@@ -0,0 +1,6 @@
1+/+ *validate-url
2+:- %say
3+|= $: [now=@da eny=@uv =beak]
4+ [[url=@t ~] ~]
5+ ==
6+noun+(validate url)
desk/lib/gossip.hoonnew file+826
@@ -0,0 +1,826 @@
1+:: gossip: data sharing with pals (and pals of pals, etc)
2+::
3+:: v1.1.1: sneaky whisper
4+::
5+:: automates using /app/pals for peer & content discovery,
6+:: letting the underlying agent focus on handling the data.
7+::
8+:: usage
9+::
10+:: to use this library, call its +agent arm with an initial
11+:: configuration and a map of, per mark, noun->vase convertors,
12+:: then call the resulting gate with the agent's door.
13+::
14+:: data from peers will come in through +on-agent, as %facts with
15+:: a /~/gossip wire.
16+:: the mark convertors ensure that this library can reconstitute the
17+:: appropriate vases from the (cask *)s it sends around internally.
18+:: if a mark conversion for a received datum isn't available, then
19+:: the library will inject a %fact with a %gossip-unknown mark instead,
20+:: containing a (cask *). the agent may either store it for later use,
21+:: or handle it directly.
22+::
23+:: for new incoming subscriptions, the underlying agent's +on-watch is
24+:: called, with /~/gossip/source, so that it may give initial results.
25+::TODO but this is somewhat wrong for multi-hop subscriptions, right?
26+:: /source is only intended to give _locally originating_ data.
27+:: if hops are >1, should we do both /source and /gossip?
28+:: doesn't this result in a lot of traffic, for know-a-lot cases?
29+::
30+:: when data originates locally and needs to be given to our peers,
31+:: simply produce a normal %fact on the /~/gossip/source path.
32+:: the +invent helper can be used to do this.
33+:: refrain from re-emitting received %facts manually. the library will
34+:: handle this for you, based on the current configuration.
35+::
36+:: to change the configuration after the agent has been started, emit
37+:: a %fact with the %gossip-config mark on the /~/gossip/config path.
38+:: the +configure helper can be used to do this.
39+:: the +read-config helper scries out the current configuration.
40+:: setting hops to 1 distributes the data to direct pals only.
41+:: setting hops to 0 prevents emission of any gossip data at all,
42+:: even during initial subscription setup.
43+:: setting pass to true causes 50% of locally-originating data to be
44+:: proxied through a random "tell" peer. note that the proxy will have
45+:: a 50% chance of proxying in turn. for low amounts of hops, data could
46+:: escape the local social graph entirely.
47+::
48+:: (we introduce the /~/etc path prefix convention to indicate paths
49+:: that are for library-specific use only.
50+:: the advantage this has over the "mutated agent" pattern (for example,
51+:: /lib/shoe) is that the library consumes a normal $agent:gall, making
52+:: it theoretically easier to compose with other agent libraries.
53+:: the disavantage, of course, is that internal interaction with the
54+:: wrapper library isn't type-checked anymore. helper functions make
55+:: that less of a problem, but the developer must stay vigilant about
56+:: casting all the relevant outputs.)
57+::
58+:: when considering the types of data to be sent through gossip, keep
59+:: in mind that the library keeps track of (hashes of) all the individual
60+:: datums it has heard. as such, if your data is of the shape @t, and we
61+:: hear a 'hello' once, we will completely ignore any 'hello' that come
62+:: afterward, even if they originate from distinct events.
63+:: if this is a problem for your use case, consider including a timestamp
64+:: or other source of uniqueness with each distinct datum.
65+::
66+:: note that this library and its protocol are currently not in the
67+:: business of providing anonymized gossip. any slightly motivated actor
68+:: will have no problem modifying this library to detect and record
69+:: sources of data with good accuracy.
70+::
71+:: wip, libdev thoughts
72+::
73+:: we may want to include additional metadata alongside gossip facts,
74+:: such as a hop counter, set of informed peers, origin timestamp, etc.
75+:: we may want to use pokes exclusively, instead of watches/facts,
76+:: making it easier to exclude the src.bowl, include metadata, etc.
77+::
78+:: we currently only emit every rumor as a fact once at most. but we might
79+:: receive it again later, with a higher hop count. if we want to try for
80+:: maximum reach within the given hops, we should re-send if we receive a
81+:: known rumor with higher hop counter. but this may not be worth the added
82+:: complexity...
83+::
84+:: what if this was a userspace-infrastructure app instead of a wrapper?
85+:: how would ensuring installation of this app-dependency work?
86+:: it gains us... a higher chance of peers having this installed.
87+:: what if it was just part of pals?
88+:: would let us more-reliably poke mutuals and leeches, if we wanted to do
89+:: a proxy-broadcast thing.
90+::
91+:: when considering adding features like rumor signing, keep in mind that
92+:: this library is mostly in the business of ferrying casks. perhaps
93+:: features like signing should be left up to applications themselves.
94+::
95+:: internal logic
96+::
97+:: - on-init or during first on-load, watch pals for targets & leeches.
98+:: - if pals is not running, the watch will simply pend until it starts.
99+:: - if pals ever watch-nacks (it shouldn't), we try rewatching after ~m1.
100+::
101+:: - for facts produced on /~/gossip/source, we
102+:: - 50% chance to redirect into the "pass flow" (see below)
103+:: - wrap them as %gossip-rumor to send them out on /~/gossip/gossip
104+:: - for new pals matching the hear mode, we watch their /~/gossip/gossip
105+:: - for gone pals, we leave that watch
106+:: - for facts on those watches
107+:: - ensure they're %gossip-rumors, ignoring otherwise
108+:: - unwrap them and +on-agent /~/gossip/gossip into the inner agent, and
109+:: - re-emit them as facts on /~/gossip/gossip if there are hops left
110+:: - for nacks on those watches, we retry after ~m30
111+::
112+:: - other gossip instances may poke us with rumors directly
113+:: - the inner agent learns the rumor normally, as if it came from a fact
114+:: - based on randomness (50/50), we do one of two things:
115+:: - publish the rumor as a fact to our subscribers, like the above
116+:: - poke a randomly selected peer (in the "tell" set) with the rumor
117+:: - when poking, store the rumor until we receive a poke-ack
118+:: - upon receiving a positive poke-ack, delete the local datum
119+:: - upon receiving a negative poke-ack, do the 50/50 again
120+:: - if we do not receive a poke-ack within some time, do the 50/50 again
121+::
122+/- pals
123+/+ lp=pals, dbug, verb
124+::
125+|%
126++$ rumor
127+ $: [kind=@ meta=*]
128+ data=(cask *)
129+ ==
130++$ meta-0 hops=_0
131+::
132++$ hash @uv
133+::
134++$ whos
135+ $? %anybody :: any ship discoverable through pals
136+ %targets :: any ship we've added as a pal
137+ %mutuals :: any mutual pal
138+ ==
139+::
140++$ config
141+ $: hops=_1 :: how far away gossip may travel
142+ :: (1 hop is pals only, 0 stops exposing data at all)
143+ hear=whos :: who to subscribe to
144+ tell=whos :: who to allow subscriptions from
145+ pass=? :: whether to (50/50) emit data through proxy
146+ ==
147+::
148+++ pass-timeout ~s30
149+::
150+++ invent
151+ |= =cage
152+ ^- card:agent:gall
153+ [%give %fact [/~/gossip/source]~ cage]
154+::
155+++ configure
156+ |= =config
157+ ^- card:agent:gall
158+ [%give %fact [/~/gossip/config]~ %gossip-config !>(config)]
159+::
160+++ read-config
161+ |= bowl:gall
162+ ^- config
163+ .^(config %gx /(scot %p our)/[dap]/(scot %da now)/~/gossip/config/noun)
164+::
165+++ agent
166+ |= $: init=config
167+ grab=(map mark $-(* vase))
168+ ==
169+ ^- $-(agent:gall agent:gall)
170+ |^ agent
171+ ::
172+ +$ state-3
173+ $: %3
174+ manner=config :: latest config
175+ memory=(set hash) :: datums seen (by inner agent)
176+ shared=(set hash) :: datums shared (as fact)
177+ passed=(map hash [rumor @da]) :: pending relays & timeouts
178+ misses=(set ship) :: ships that won't relay
179+ future=(list rumor) :: rumors of unknown kinds
180+ ==
181+ ::
182+ +$ card card:agent:gall
183+ ::
184+ ++ helper
185+ |_ [=bowl:gall state-3]
186+ +* state +<+
187+ pals ~(. lp bowl)
188+ ++ en-cage
189+ |= =(cask *)
190+ ^- cage
191+ ?^ to=(~(get by grab) p.cask)
192+ ::TODO +soft or otherwise virtualize? don't want to risk crashes, right?
193+ [p.cask (u.to q.cask)]
194+ ~& [gossip+dap.bowl %no-mark p.cask]
195+ [%gossip-unknown !>(cask)]
196+ ::
197+ ++ de-cage
198+ |=(cage `(cask *)`[p q.q])
199+ ::
200+ ++ en-rumor ::NOTE assumes !=(0 hops.manner)
201+ |= =cage
202+ ^- rumor
203+ :_ (de-cage cage)
204+ ~| [%en-rumor initial-hops=hops.manner]
205+ [%0 `meta-0`(dec hops.manner)]
206+ ::
207+ ++ en-hash
208+ |= rumor
209+ (sham data)
210+ ::
211+ ++ play-card :: en-rumor relevant facts, handle config changes
212+ |= =card
213+ ^- (quip ^card _state)
214+ ?. ?=([%give %fact *] card) [[card]~ state]
215+ ?: =(~ paths.p.card) [[card]~ state]
216+ =/ [int=(list path) ext=(list path)]
217+ %+ skid paths.p.card
218+ |= =path
219+ ?=([%~.~ %gossip *] path)
220+ =/ caz=(list ^card)
221+ ?: =(~ ext) ~
222+ [card(paths.p ext)]~
223+ ?: ?=(~ int) [caz state]
224+ =* path i.int
225+ :: there may only be one gossip-internal path per card
226+ ::
227+ ?. =(~ t.int)
228+ ~& [gossip+dap.bowl %too-many-internal-targets int]
229+ ~|([%too-many-internal-targets int] !!)
230+ ?: =(/~/gossip/config path)
231+ ~| [%weird-fact-on-config p.cage.p.card]
232+ ?> =(%gossip-config p.cage.p.card)
233+ =/ old=config manner
234+ =. manner !<(config q.cage.p.card)
235+ :_ state
236+ ;: weld
237+ (hear-changed hear.old)
238+ (tell-changed tell.old)
239+ caz
240+ ==
241+ ~| [%strange-internal-target path]
242+ ?> =(/~/gossip/source path)
243+ :: if hops is configured at 0, we don't broadcast at all.
244+ ::
245+ =/ =rumor (en-rumor cage.p.card)
246+ =. memory (~(put in memory) (en-hash rumor))
247+ ?: =(0 hops.manner)
248+ [caz state]
249+ =^ cas state (emit-rumor rumor)
250+ [(weld cas caz) state]
251+ ::
252+ ++ emit-rumor :: gossip a rumor as-is
253+ |= =rumor
254+ ^- (quip card _state)
255+ =/ =hash (en-hash rumor)
256+ =* fact
257+ :- [%give %fact [/~/gossip/gossip]~ %gossip-rumor !>(rumor)]~
258+ %_ state
259+ passed (~(del by passed) hash)
260+ shared (~(put in shared) hash)
261+ ==
262+ :: if we don't want to proxy, always send as fact
263+ ::
264+ ?. pass.manner
265+ fact
266+ :: if we want to proxy, do so 50% of the time
267+ ::
268+ ?. =(0 (~(rad og eny.bowl) 2))
269+ fact
270+ :: if we're proxying, but there's no reasonable targets, send as fact
271+ ::
272+ =/ aides=(set ship)
273+ :: reasonable targets do not include ourselves, whoever
274+ :: caused us to want to (re)send this rumor, or ships that failed
275+ :: to proxy for us before.
276+ :: that last one is important because we need to avoid the mistake of
277+ :: occasionally sending them pokes that just linger in our outbound
278+ :: ames flows and keep retrying. (ideally we'd do those all pokes for
279+ :: a target on the same flow, but we really like storing information
280+ :: in the wire and don't want to do per-relay queues in state. we also
281+ :: don't particularly care about ordering guarantees for gossip.)
282+ :: we don't just get the set of ships with active incoming or outgoing
283+ :: subscriptions, because that constrains the set unnecessarily. for
284+ :: some configs, ships in .tell (that aren't in .hear) might be
285+ :: running the agent without actively listening to us.
286+ ::
287+ =- (~(dif in (~(del in (~(del in -) our.bowl)) src.bowl)) misses)
288+ ?- tell.manner
289+ %anybody (~(uni in (targets:pals ~.)) leeches:pals)
290+ %targets (targets:pals ~.)
291+ %mutuals (mutuals:pals ~.)
292+ ==
293+ =/ count=@ud ~(wyt in aides)
294+ ?: =(0 count)
295+ fact
296+ :: poke a randomly chosen proxy with the rumor
297+ ::
298+ =/ proxy=ship (snag (~(rad og +(eny.bowl)) count) ~(tap in aides))
299+ =/ =time (add now.bowl pass-timeout)
300+ =. passed (~(put by passed) hash [rumor time])
301+ :_ state
302+ =/ =wire /~/gossip/passed/(scot %p proxy)/(scot %uv hash)
303+ =/ =cage gossip-rumor+!>(rumor)
304+ :~ [%pass wire %agent [proxy dap.bowl] %poke cage]
305+ [%pass wire %arvo %b %wait time]
306+ ==
307+ ::
308+ ++ play-cards
309+ |= cards=(list card)
310+ ^- (quip card _state)
311+ =| out=(list card)
312+ |-
313+ ?~ cards [out state]
314+ =^ caz state (play-card i.cards)
315+ $(out (weld out caz), cards t.cards)
316+ ::
317+ ++ play-first-cards
318+ |= cards=(list card)
319+ ^- (quip card _state)
320+ =| out=(list card)
321+ |-
322+ ?~ cards [out state]
323+ ?. ?=([%give %fact ~ *] i.cards)
324+ =^ caz state (play-card i.cards)
325+ $(out (weld out caz), cards t.cards)
326+ :: if hops is set to 0, we block even the initial response
327+ ::
328+ ?: =(0 hops.manner) $(cards t.cards)
329+ =. cage.p.i.cards
330+ [%gossip-rumor !>((en-rumor cage.p.i.cards))]
331+ $(out (snoc out i.cards), cards t.cards)
332+ ::
333+ ++ jump-rumor :: relay a rumor if we haven't yet
334+ |= =rumor
335+ ^- (quip card _state)
336+ =/ =hash (en-hash rumor)
337+ ?: (~(has in shared) hash) [~ state]
338+ ?> =(%0 kind.rumor) ::NOTE should have been checked for already
339+ ?~ meta=((soft ,hops=@ud) meta.rumor) [~ state]
340+ =* hops hops.u.meta
341+ ?: =(0 hops) [~ state]
342+ =. meta.rumor (dec hops)
343+ :- [%give %fact [/~/gossip/gossip]~ %gossip-rumor !>(rumor)]~
344+ state(shared (~(put in shared) (en-hash rumor)))
345+ ::
346+ ++ may-watch
347+ |= who=ship
348+ ?- tell.manner
349+ %anybody &
350+ %targets (~(has in (targets:pals ~.)) who)
351+ %mutuals (~(has in (mutuals:pals ~.)) who)
352+ ==
353+ ::
354+ ::
355+ ++ watch-pals
356+ ^- (list card)
357+ =/ =gill:gall [our.bowl %pals]
358+ :~ [%pass /~/gossip/pals/targets %agent gill %watch /targets]
359+ [%pass /~/gossip/pals/leeches %agent gill %watch /leeches]
360+ ==
361+ ::
362+ ++ watching-target
363+ |= s=ship
364+ %- ~(has by wex.bowl)
365+ [/~/gossip/gossip/(scot %p s) s dap.bowl]
366+ ::
367+ ++ want-target
368+ %~ has in
369+ ?- hear.manner
370+ %anybody (~(uni in leeches:pals) (targets:pals ~.))
371+ %targets (targets:pals ~.)
372+ %mutuals (mutuals:pals ~.)
373+ ==
374+ ::
375+ ++ retry-timer
376+ |= [t=@dr p=path]
377+ ^- card
378+ :+ %pass [%~.~ %gossip %retry p]
379+ [%arvo %b %wait (add now.bowl t)]
380+ ::
381+ ++ watch-target
382+ |= s=ship
383+ ^- (list card)
384+ ?: (watching-target s) ~
385+ :_ ~
386+ :+ %pass /~/gossip/gossip/(scot %p s)
387+ [%agent [s dap.bowl] %watch /~/gossip/gossip]
388+ ::
389+ ++ leave-target
390+ |= s=ship
391+ ^- card
392+ :+ %pass /~/gossip/gossip/(scot %p s)
393+ [%agent [s dap.bowl] %leave ~]
394+ ::
395+ ++ kick-target
396+ |= s=ship
397+ ^- card
398+ [%give %kick [/~/gossip/gossip]~ `s]
399+ ::
400+ ++ hear-changed
401+ |= old=whos
402+ ^- (list card)
403+ =* new hear.manner
404+ ?: =(old new) ~
405+ =/ listen=(set ship)
406+ ?- new
407+ %anybody (~(uni in leeches:pals) (targets:pals ~.))
408+ %targets (targets:pals ~.)
409+ %mutuals (mutuals:pals ~.)
410+ ==
411+ =/ hearing=(set ship)
412+ %- ~(gas in *(set ship))
413+ %+ murn ~(tap by wex.bowl)
414+ |= [[=wire =ship =term] [acked=? =path]]
415+ ^- (unit ^ship)
416+ ?. ?=([%~.~ %gossip %gossip @ ~] wire) ~
417+ `ship
418+ %+ weld
419+ (turn ~(tap in (~(dif in hearing) listen)) leave-target)
420+ ^- (list card)
421+ (zing (turn ~(tap in (~(dif in listen) hearing)) watch-target))
422+ ::
423+ ++ tell-changed
424+ |= old=whos
425+ ^- (list card)
426+ =* new tell.manner
427+ ?: =(old new) ~
428+ ?- [old new]
429+ $? [* %anybody]
430+ [%mutuals *]
431+ ==
432+ :: perms got broader, we can just no-op
433+ ::
434+ ~
435+ ::
436+ [* ?(%targets %mutuals)]
437+ :: perms got tighter, we need to kick stragglers
438+ ::
439+ =/ allowed=(set ship)
440+ ?- new
441+ %anybody !!
442+ %targets (targets:pals ~.)
443+ %mutuals (mutuals:pals ~.)
444+ ==
445+ %+ murn ~(val by sup.bowl)
446+ |= [s=ship p=path]
447+ ^- (unit card)
448+ =; kick=?
449+ ?.(kick ~ `(kick-target s))
450+ ?& ?=([%~.~ %gossip %gossip ~] p)
451+ !(~(has in allowed) s)
452+ ==
453+ ==
454+ --
455+ ::
456+ ++ agent
457+ |= inner=agent:gall
458+ =| state-3
459+ =* state -
460+ %+ verb |
461+ %- agent:dbug
462+ ^- agent:gall
463+ |_ =bowl:gall
464+ +* this .
465+ pals ~(. lp bowl)
466+ def ~(. (default-agent this %|) bowl)
467+ og ~(. inner bowl)
468+ up ~(. helper bowl state)
469+ ++ on-init
470+ ^- (quip card _this)
471+ =. manner init
472+ =^ cards inner on-init:og
473+ =^ cards state (play-cards:up cards)
474+ [(weld watch-pals:up cards) this]
475+ ::
476+ ++ on-save (slop !>([%gossip state]) on-save:og)
477+ ++ on-load
478+ |= ole=vase
479+ ^- (quip card _this)
480+ ?. ?=([[%gossip *] *] q.ole)
481+ =. manner init
482+ =^ cards inner (on-load:og ole)
483+ =^ cards state (play-cards:up cards)
484+ [(weld watch-pals:up cards) this]
485+ ::
486+ |^ =+ !<([%gossip old=state-any] (slot 2 ole))
487+ =/ ile=vase (slot 3 ole)
488+ =? old ?=(%0 -.old) (state-0-to-1 old)
489+ =? old ?=(%1 -.old) (state-1-to-2 old)
490+ :: before version 3, we stored the inner +on-save vase inside
491+ :: our own +on-save vase. undoing this double-vasing coincided
492+ :: with the h135 type-of-type upgrade.
493+ ::
494+ =? ile ?=(%2 -.old) (next-vase:h136 !<(vase:h136 ile))
495+ =? old ?=(%2 -.old) (state-2-to-3 old)
496+ ?> ?=(%3 -.old)
497+ =. state old
498+ =^ cards inner (on-load:og ile)
499+ =^ cards state (play-cards:up cards)
500+ ::TODO for later versions, add :future retry logic as needed
501+ [cards this]
502+ ::
503+ +$ state-any $%(state-0 state-1 state-2 state-3)
504+ ::
505+ +$ state-2
506+ $: %2
507+ manner=config
508+ memory=(set hash)
509+ shared=(set hash)
510+ passed=(map hash [rumor @da])
511+ misses=(set ship)
512+ future=(list rumor)
513+ ==
514+ ++ state-2-to-3
515+ |=(s=state-2 s(- %3))
516+ ::
517+ +$ state-1
518+ $: %1
519+ manner=config
520+ memory=(set hash)
521+ shared=(set hash)
522+ passed=(map hash [rumor @da])
523+ future=(list rumor)
524+ ==
525+ ++ state-1-to-2
526+ |= state-1
527+ [%2 manner memory shared passed ~ future]
528+ ::
529+ +$ state-0 [%0 manner=config-0 memory=(set hash) future=(list rumor)]
530+ +$ config-0 [hops=_1 hear=whos tell=whos]
531+ ++ state-0-to-1
532+ |= state-0
533+ ^- state-1
534+ [%1 (config-0-to-1 manner) memory memory ~ future]
535+ ++ config-0-to-1
536+ |= config-0
537+ ^- config
538+ [hops hear tell pass.init]
539+ --
540+ ::
541+ ++ on-watch
542+ |= =path
543+ ^- (quip card _this)
544+ ?. ?=([%~.~ %gossip *] path)
545+ =^ cards inner (on-watch:og path)
546+ =^ cards state (play-cards:up cards)
547+ [cards this]
548+ :: /~/gossip/gossip
549+ ?> =(/gossip t.t.path)
550+ ?. (may-watch:up src.bowl)
551+ ~|(%gossip-forbidden !!)
552+ =^ cards inner (on-watch:og /~/gossip/source)
553+ =^ cards state (play-first-cards:up cards)
554+ [cards this]
555+ ::
556+ ++ on-poke
557+ |= [=mark =vase]
558+ ^- (quip card _this)
559+ ::TODO gossip config pokes
560+ ?. =(%gossip-rumor mark)
561+ =^ cards inner (on-poke:og +<)
562+ =^ cards state (play-cards:up cards)
563+ [cards this]
564+ ?. (want-target:up src.bowl)
565+ ~|(%gossip-rejected !!)
566+ :: we're getting pokes from them, so we should try relaying through
567+ :: them again if we stopped doing so
568+ ::NOTE this only ever cleans out .misses for ships producing content
569+ ::
570+ =. misses (~(del in misses) src.bowl)
571+ ::TODO dedupe with +on-agent %fact
572+ =+ !<(=rumor vase)
573+ =/ =hash (en-hash:up rumor)
574+ ?: (~(has in memory) hash)
575+ [~ this]
576+ ?. =(%0 kind.rumor)
577+ ~& [gossip+dap.bowl %delaying-unknown-rumor-kind kind.rumor]
578+ [~ this(future [rumor future])]
579+ =. memory (~(put in memory) hash)
580+ =/ mage=cage (en-cage:up data.rumor)
581+ =^ cards inner (on-agent:og /~/gossip/gossip %fact mage)
582+ =^ caz1 state (play-cards:up cards)
583+ =^ caz2 state (emit-rumor:up rumor)
584+ [(weld caz1 caz2) this]
585+ ::
586+ ++ on-agent
587+ |= [=wire =sign:agent:gall]
588+ ^- (quip card _this)
589+ ?. ?=([%~.~ %gossip *] wire)
590+ =^ cards inner (on-agent:og wire sign)
591+ =^ cards state (play-cards:up cards)
592+ [cards this]
593+ ::
594+ ?+ t.t.wire ~|([%gossip %unexpected-wire wire] !!)
595+ [%gossip @ ~]
596+ ~| t.t.wire
597+ ?> =(src.bowl (slav %p i.t.t.t.wire))
598+ ?- -.sign
599+ %fact
600+ =* mark p.cage.sign
601+ =* vase q.cage.sign
602+ ?. =(%gossip-rumor mark)
603+ ~& [gossip+dap.bowl %ignoring-unexpected-fact mark=mark]
604+ [~ this]
605+ :: we're getting facts from them, so we should try relaying through
606+ :: them again if we stopped doing so
607+ ::NOTE this only ever cleans out .misses for ships in .hear
608+ ::
609+ =. misses (~(del in misses) src.bowl)
610+ ::TODO de-dupe with +on-poke
611+ =+ !<(=rumor vase)
612+ =/ =hash (en-hash:up rumor)
613+ ?: (~(has in memory) hash)
614+ =^ cards state (jump-rumor:up rumor)
615+ [cards this]
616+ ?. =(%0 kind.rumor)
617+ ~& [gossip+dap.bowl %delaying-unknown-rumor-kind kind.rumor]
618+ [~ this(future [rumor future])]
619+ =. memory (~(put in memory) hash)
620+ =/ mage=cage (en-cage:up data.rumor)
621+ =^ cards inner (on-agent:og /~/gossip/gossip sign(cage mage))
622+ =^ caz1 state (play-cards:up cards)
623+ =^ caz2 state (jump-rumor:up rumor)
624+ [(weld caz1 caz2) this]
625+ ::
626+ %watch-ack
627+ :_ this
628+ ?~ p.sign ~
629+ :: 30 minutes might cost us some responsiveness when the other
630+ :: party changes their local config, but in return we save both
631+ :: ourselves and others from a lot of needless retries.
632+ :: (notably, "do we still care" check also lives in %wake logic.)
633+ ::
634+ [(retry-timer:up ~m30 /watch/(scot %p src.bowl))]~
635+ ::
636+ %kick
637+ :_ this
638+ :: to prevent pathological kicks from exploding, we always
639+ :: wait a couple seconds before resubscribing.
640+ :: perhaps this is overly careful, but we cannot tell the
641+ :: difference between "clog" kicks and "missing mark" kicks,
642+ :: so we cannot take more accurate/appropriate action here.
643+ :: (notably, "do we still care" check also lives in %wake logic.)
644+ ::
645+ [(retry-timer:up ~s15 /watch/(scot %p src.bowl))]~
646+ ::
647+ %poke-ack
648+ ~& [gossip+dap.bowl %unexpected-poke-ack wire]
649+ [~ this]
650+ ==
651+ ::
652+ [%passed ?([@ ~] [@ @ ~])]
653+ ?. ?=(%poke-ack -.sign)
654+ ~& [gossip+dap.bowl %unexpected-sign wire -.sign]
655+ [~ this]
656+ ~| t.t.wire
657+ :: regardless of anything else: if they acked the poke, they are
658+ :: accepting of relay requests, if they nacked they're unaccepting
659+ ::
660+ =. misses
661+ ?: ?=(~ p.sign)
662+ (~(del in misses) src.bowl)
663+ (~(put in misses) src.bowl)
664+ =/ =hash
665+ ?: ?=([@ ~] t.t.t.wire)
666+ (slav %uv i.t.t.t.wire)
667+ (slav %uv i.t.t.t.t.wire)
668+ ?~ rum=(~(get by passed) hash)
669+ [~ this]
670+ ::NOTE emitting rest is cute, but doesn't actually work reliably,
671+ :: due to userspace duct shenanigans. %wake logic will have to
672+ :: be defensive...
673+ =/ rest=card [%pass wire %arvo %b %rest +.u.rum]
674+ ?~ p.sign [[rest]~ this(passed (~(del by passed) hash))]
675+ =^ caz state (emit-rumor:up -.u.rum)
676+ [[rest caz] this]
677+ ::
678+ [%pals @ ~]
679+ ?- -.sign
680+ %poke-ack ~&([gossip+dap.bowl %unexpected-poke-ack wire] [~ this])
681+ %kick [watch-pals:up this]
682+ ::
683+ %watch-ack
684+ :_ this
685+ ?~ p.sign ~
686+ %- (slog 'gossip: failed to subscribe on %pals!!' u.p.sign)
687+ [(retry-timer:up ~m1 t.t.wire)]~
688+ ::
689+ %fact
690+ =* mark p.cage.sign
691+ =* vase q.cage.sign
692+ ?. =(%pals-effect mark)
693+ ~& [gossip+dap.bowl %unexpected-fact-mark mark wire]
694+ [~ this]
695+ =+ !<(=effect:^pals vase)
696+ :_ this
697+ =* ship ship.effect
698+ =* kick [(kick-target:up ship)]~
699+ =* view (watch-target:up ship)
700+ =* flee [(leave-target:up ship)]~
701+ ?- -.effect
702+ %meet
703+ ?- hear.manner
704+ %anybody view
705+ %targets view
706+ %mutuals ?:((mutual:pals ~. ship) view ~)
707+ ==
708+ ::
709+ %part
710+ %+ weld
711+ ?- tell.manner
712+ %anybody ~
713+ %targets kick
714+ %mutuals kick
715+ ==
716+ ?- hear.manner
717+ %anybody ?:((leeche:pals ship) ~ flee)
718+ %targets flee
719+ %mutuals flee
720+ ==
721+ ::
722+ %near
723+ ?- hear.manner
724+ %anybody view
725+ %targets ~
726+ %mutuals ?:((mutual:pals ~. ship) view ~)
727+ ==
728+ ::
729+ %away
730+ %+ weld
731+ ?- tell.manner
732+ %anybody ~
733+ %targets ~
734+ %mutuals kick
735+ ==
736+ ?- hear.manner
737+ %anybody ?:((target:pals ~. ship) ~ flee)
738+ %targets ~
739+ %mutuals flee
740+ ==
741+ ==
742+ ==
743+ ==
744+ ::
745+ ++ on-peek
746+ |= =path
747+ ^- (unit (unit cage))
748+ ?: =(/x/whey path)
749+ :+ ~ ~
750+ :- %mass
751+ !> ^- (list mass)
752+ :- %gossip^&+state
753+ =/ dat (on-peek:og path)
754+ ?: ?=(?(~ [~ ~]) dat) ~
755+ (fall ((soft (list mass)) q.q.u.u.dat) ~)
756+ ?: =(/x/dbug/state path)
757+ ``noun+(slop on-save:og !>(gossip=state))
758+ ?. ?=([@ %~.~ %gossip *] path)
759+ (on-peek:og path)
760+ ?. ?=(%x i.path) [~ ~]
761+ ?+ t.t.t.path [~ ~]
762+ [%config ~] ``noun+!>(manner)
763+ ==
764+ ::
765+ ++ on-leave
766+ |= =path
767+ ^- (quip card _this)
768+ ?: ?=([%~.~ %gossip *] path)
769+ [~ this]
770+ =^ cards inner (on-leave:og path)
771+ =^ cards state (play-cards:up cards)
772+ [cards this]
773+ ::
774+ ++ on-arvo
775+ |= [=wire sign=sign-arvo:agent:gall]
776+ ^- (quip card _this)
777+ ?. ?=([%~.~ %gossip *] wire)
778+ =^ cards inner (on-arvo:og wire sign)
779+ =^ cards state (play-cards:up cards)
780+ [cards this]
781+ ?+ t.t.wire ~|(wire !!)
782+ [%passed ?([@ ~] [@ @ ~])]
783+ =/ =hash
784+ ?: ?=([@ ~] t.t.t.wire)
785+ (slav %uv i.t.t.t.wire)
786+ (slav %uv i.t.t.t.t.wire)
787+ ?~ rum=(~(get by passed) hash) [~ this]
788+ :: since timer cancellation isn't fully reliable, this timer fire
789+ :: might be from a relay that nacked our poke. if the timer fired
790+ :: earlier than expected, assume that to be the case and no-op.
791+ ::
792+ ?: (gth +.u.rum now.bowl) [~ this]
793+ :: they failed to respond to our relay request in time, mark them as
794+ :: unaccepting (if we know who they are from a the new-style wire)
795+ :: and try sending the rumor again
796+ ::
797+ =? misses ?=([@ @ ~] t.t.t.wire)
798+ (~(put in misses) (slav %p i.t.t.t.wire))
799+ =^ cards state (emit-rumor:up -.u.rum)
800+ [cards this]
801+ ::
802+ [%retry *]
803+ ?> ?=(%wake +<.sign)
804+ ?+ t.t.t.wire ~|(wire !!)
805+ [%pals *]
806+ ::NOTE this might result in subscription wire re-use,
807+ :: but if we hit this path we should be loud anyway.
808+ [watch-pals:up this]
809+ ::
810+ [%watch @ ~]
811+ :_ this
812+ =/ target=ship (slav %p i.t.t.t.t.wire)
813+ ?. (want-target:up target) ~
814+ (watch-target:up target)
815+ ==
816+ ==
817+ ::
818+ ++ on-fail
819+ |= [term tang]
820+ ^- (quip card _this)
821+ =^ cards inner (on-fail:og +<)
822+ =^ cards state (play-cards:up cards)
823+ [cards this]
824+ --
825+ --
826+--
desk/lib/metaphone.hoonnew file+192
@@ -0,0 +1,192 @@
1+|%
2+++ utter
3+ |= corpus=@t
4+ ^- @t
5+ =/ norm (cuss (trip corpus))
6+ ?: =(norm '') ''
7+ ~(phone core [norm *tape 0])
8+++ core
9+ |_ [text=tape chars=tape index=@ud]
10+ ++ phone
11+ ?: =(current 'A')
12+ ?: =(next 'E') (jump2 'E')
13+ (jump 'A')
14+ ?:
15+ ?& =(next 'N')
16+ ?| =(current 'G')
17+ =(current 'K')
18+ =(current 'P')
19+ ==
20+ ==
21+ (jump2 'N')
22+ ?: =(current 'W')
23+ ?: =(next 'R') (jump2 'R')
24+ ?: =(next 'H') (jump2 current)
25+ ?: (vowel next) (jump2 'W')
26+ recite
27+ ?: =(current 'X') (jump 'S')
28+ ?:
29+ ?| =(current 'E')
30+ =(current 'I')
31+ =(current 'O')
32+ =(current 'U')
33+ ==
34+ (jump current)
35+ recite
36+ ++ recite
37+ ?: (gte index (lent text))
38+ (crip chars)
39+ :: B -> B unless in MB
40+ ?: &(=(current 'B') !=(prev 'M'))
41+ (jump 'B')
42+ :: 'sh' if -CIA- or -CH, but not SCH, except SCHW (SCHW is handled in S)
43+ :: S if -CI-, -CE- or -CY- dropped if -SCI-, SCE-, -SCY- (handed in S)
44+ :: else K
45+ ?: =(current 'C')
46+ ?: (soft next)
47+ :: C[IEY]
48+ ?: &(=(next 'I') =((at 2 &) 'A'))
49+ :: CIA
50+ (jump sh)
51+ ?: !=(prev 'S')
52+ (jump 'S')
53+ advance
54+ ?: =(next 'H')
55+ (jump2 sh)
56+ (jump 'K')
57+ :: J if in -DGE-, -DGI- or -DGY-, else T
58+ ?: =(current 'D')
59+ ?: &(=(next 'G') (soft (at 2 &)))
60+ (jump2 'J')
61+ (jump 'T')
62+ :: F if in -GH and not B--GH, D--GH, -H--GH, -H---GH
63+ :: else dropped if -GNED, -GN,
64+ :: else dropped if -DGE-, -DGI- or -DGY- (handled in D)
65+ :: else J if in -GE-, -GI, -GY and not GG
66+ :: else K
67+ ?: =(current 'G')
68+ ?: =(next 'H')
69+ ?: |(!(no-gh-to-f (at 3 |)) =((at 4 |) 'H'))
70+ (jump2 'F')
71+ advance
72+ ?: =(next 'N')
73+ ?: !&(=((at 2 &) 'E') =((at 3 &) 'D'))
74+ (jump 'K')
75+ advance
76+ ?: &((soft next) !=(prev 'G'))
77+ (jump 'J')
78+ (jump 'K')
79+ :: H if before a vowel and not after C,G,P,S,T
80+ ?: &(=(current 'H') (vowel next) !(dipthong-h prev))
81+ (jump 'H')
82+ :: Dropped if after C, else K
83+ ?: &(=(current 'K') !=(prev 'C'))
84+ (jump 'K')
85+ :: F if before H, else P
86+ ?: =(current 'P')
87+ ?: =(next 'H')
88+ (jump 'F')
89+ (jump 'P')
90+ :: K
91+ ?: =(current 'Q')
92+ (jump 'K')
93+ :: 'sh' in -SH-, -SIO- or -SIA- or -SCHW-, else S
94+ ?: =(current 'S')
95+ ?: &(=(next 'I') |(=((at 2 &) 'O') =((at 2 &) 'A')))
96+ (jump sh)
97+ ?: =(next 'H')
98+ (jump2 sh)
99+ (jump 'S')
100+ :: sh' in -TIA- or -TIO-, else 'th' before H, else T
101+ ?: =(current 'T')
102+ ?: &(=(next 'I') |(=((at 2 &) 'O') =((at 2 &) 'A')))
103+ (jump sh)
104+ ?: =(next 'H')
105+ (jump2 th)
106+ ?: !&(=(next 'C') =((at 2 &) 'H'))
107+ (jump 'T')
108+ advance
109+ :: F
110+ ?: =(current 'V')
111+ (jump 'F')
112+ ?: &(=(current 'W') (vowel next))
113+ (jump 'W')
114+ :: KS
115+ ?: =(current 'X')
116+ (jump 'KS')
117+ :: Y if followed by a vowel
118+ ?: &(=(current 'Y') (vowel next))
119+ (jump 'Y')
120+ :: S
121+ ?: =(current 'Z')
122+ (jump 'S')
123+ ?:
124+ ?| =(current 'F')
125+ =(current 'J')
126+ =(current 'L')
127+ =(current 'M')
128+ =(current 'N')
129+ =(current 'R')
130+ ==
131+ (jump current)
132+ advance
133+ ++ advance
134+ =. index +(index)
135+ recite
136+ ++ jump
137+ |= char=@t
138+ =. chars (snoc chars char)
139+ =. index +(index)
140+ recite
141+ ++ jump2
142+ |= char=@t
143+ =. chars (snoc chars char)
144+ =. index (add index 2)
145+ recite
146+ ++ current (snag index text)
147+ ++ next
148+ ?: (gte index (dec (lent text))) ''
149+ (snag +(index) text)
150+ ++ prev
151+ ?: (lte index 0) ''
152+ (snag (dec index) text)
153+ ++ at
154+ |= [offset=@ud forward=?]
155+ ?: forward
156+ ?: (gth (add index offset) (dec (lent text))) ''
157+ (snag (add index offset) text)
158+ ?: (lth index offset) ''
159+ ?: (lth (sub index offset) 0) ''
160+ (snag (sub index offset) text)
161+ --
162+++ soft
163+ |= char=@t
164+ ?| =(char 'E')
165+ =(char 'I')
166+ =(char 'Y')
167+ ==
168+++ vowel
169+ |= char=@t
170+ ?| =(char 'A')
171+ =(char 'E')
172+ =(char 'I')
173+ =(char 'O')
174+ =(char 'U')
175+ ==
176+++ dipthong-h
177+ |= char=@t
178+ ?| =(char 'C')
179+ =(char 'G')
180+ =(char 'P')
181+ =(char 'S')
182+ =(char 'T')
183+ ==
184+++ no-gh-to-f
185+ |= char=@t
186+ ?| =(char 'B')
187+ =(char 'D')
188+ =(char 'H')
189+ ==
190+++ sh 'X'
191+++ th '0'
192+--
desk/lib/pals.hoonnew file+24
@@ -0,0 +1,24 @@
1+:: pals: manual peer discovery
2+::
3+/- *pals
4+::
5+|_ bowl:gall
6+++ records (s ^records /)
7+++ leeches (s (set ship) /leeches)
8+++ targets |= list=@ta (s (set ship) %targets ?~(list / /[list]))
9+++ mutuals |= list=@ta (s (set ship) %mutuals ?~(list / /[list]))
10+++ leeche |= =ship (s _| /leeches/(scot %p ship))
11+++ target |= [list=@ta =ship] (s _| /mutuals/[list]/(scot %p ship))
12+++ mutual |= [list=@ta =ship] (s _| /mutuals/[list]/(scot %p ship))
13+::
14+++ labels ?. running `(set @ta)`~
15+ ~(key by dir:.^(arch %gy (snoc base %targets)))
16+::
17+++ base ~+ `path`/(scot %p our)/pals/(scot %da now)
18+++ running ~+ .^(? %gu (snoc base %$))
19+::
20+++ s
21+ |* [=mold =path] ~+
22+ ?. running *mold
23+ .^(mold %gx (weld base (snoc `^path`path %noun)))
24+--
desk/lib/sift.hoonnew file+250
@@ -0,0 +1,250 @@
1+|%
2+++ sift
3+ |= corpus=@t
4+ ^- (list @t)
5+ ?: =(corpus '') ~
6+ =/ parts (split corpus)
7+ ?~ parts ~
8+ %+ skip
9+ (need parts)
10+ |= word=@t
11+ (~(has in words) word)
12+++ norm
13+ |= corpus=@t
14+ ^- @t
15+ ?: =(corpus '') ''
16+ =/ cleaned (trimall (weave (expunge (weave (trimall `corpus)))))
17+ ?~ cleaned ''
18+ (crip (cass (need cleaned)))
19+++ weave
20+ |= corpus=(unit tape)
21+ ^- (unit @t)
22+ ?~ corpus ~
23+ (some (crip (need corpus)))
24+++ split
25+ |= corpus=@t
26+ ^- (unit (list @t))
27+ ?: =(corpus '') ~
28+ =/ test (norm corpus)
29+ %+ rush test
30+ (more (plus ws) (cook crip (plus ;~(pose aln hep))))
31+++ allowed ;~(pose aln hep ace)
32+++ banned ;~(less allowed next)
33+++ ws (mask " \0a\0d\09")
34+++ expunge
35+ |= corpus=(unit @t)
36+ ^- (unit tape)
37+ ?~ corpus ~
38+ =/ text (need corpus)
39+ ?: =(text '') ~
40+ =/ parsed
41+ %+ rush text
42+ %- plus
43+ ;~ pose
44+ ;~(pfix (plus banned) (star allowed))
45+ ;~(sfix (star allowed) (plus banned))
46+ (plus allowed)
47+ ==
48+ ?~ parsed ~
49+ `(zing (need parsed))
50+++ trimall
51+ |= corpus=(unit @t)
52+ ^- (unit tape)
53+ ?~ corpus ~
54+ =/ text (need corpus)
55+ ?: =(text '') ~
56+ %+ rush text
57+ %+ ifix [(star ws) (star ws)]
58+ %- star
59+ ;~ less
60+ ;~(plug (plus ws) ;~(less next (easy ~)))
61+ ;~(pose (cold ' ' (plus ws)) next)
62+ ==
63+++ words
64+ %- silt
65+ :~ 'a'
66+ 'about'
67+ 'above'
68+ 'actually'
69+ 'after'
70+ 'again'
71+ 'against'
72+ 'all'
73+ 'almost'
74+ 'also'
75+ 'although'
76+ 'always'
77+ 'am'
78+ 'an'
79+ 'and'
80+ 'any'
81+ 'are'
82+ 'as'
83+ 'at'
84+ 'be'
85+ 'became'
86+ 'become'
87+ 'because'
88+ 'been'
89+ 'before'
90+ 'being'
91+ 'below'
92+ 'between'
93+ 'both'
94+ 'but'
95+ 'by'
96+ 'can'
97+ 'could'
98+ 'did'
99+ 'do'
100+ 'does'
101+ 'doing'
102+ 'down'
103+ 'during'
104+ 'each'
105+ 'either'
106+ 'else'
107+ 'few'
108+ 'for'
109+ 'from'
110+ 'further'
111+ 'had'
112+ 'has'
113+ 'have'
114+ 'having'
115+ 'he'
116+ 'he\'d'
117+ 'he\'ll'
118+ 'hence'
119+ 'he\'s'
120+ 'her'
121+ 'here'
122+ 'here\'s'
123+ 'hers'
124+ 'herself'
125+ 'him'
126+ 'himself'
127+ 'his'
128+ 'how'
129+ 'how\'s'
130+ 'I'
131+ 'I\'d'
132+ 'I\'ll'
133+ 'I\'m'
134+ 'I\'ve'
135+ 'if'
136+ 'in'
137+ 'into'
138+ 'is'
139+ 'it'
140+ 'it\'s'
141+ 'its'
142+ 'itself'
143+ 'just'
144+ 'let\'s'
145+ 'may'
146+ 'maybe'
147+ 'me'
148+ 'might'
149+ 'mine'
150+ 'more'
151+ 'most'
152+ 'must'
153+ 'my'
154+ 'myself'
155+ 'neither'
156+ 'nor'
157+ 'not'
158+ 'of'
159+ 'oh'
160+ 'on'
161+ 'once'
162+ 'only'
163+ 'ok'
164+ 'or'
165+ 'other'
166+ 'ought'
167+ 'our'
168+ 'ours'
169+ 'ourselves'
170+ 'out'
171+ 'over'
172+ 'own'
173+ 'same'
174+ 'she'
175+ 'she\'d'
176+ 'she\'ll'
177+ 'she\'s'
178+ 'should'
179+ 'so'
180+ 'some'
181+ 'such'
182+ 'than'
183+ 'that'
184+ 'that\'s'
185+ 'the'
186+ 'their'
187+ 'theirs'
188+ 'them'
189+ 'themselves'
190+ 'then'
191+ 'there'
192+ 'there\'s'
193+ 'these'
194+ 'they'
195+ 'they\'d'
196+ 'they\'ll'
197+ 'they\'re'
198+ 'they\'ve'
199+ 'this'
200+ 'those'
201+ 'through'
202+ 'to'
203+ 'too'
204+ 'under'
205+ 'until'
206+ 'up'
207+ 'very'
208+ 'was'
209+ 'we'
210+ 'we\'d'
211+ 'we\'ll'
212+ 'we\'re'
213+ 'we\'ve'
214+ 'were'
215+ 'what'
216+ 'what\'s'
217+ 'when'
218+ 'whenever'
219+ 'when\'s'
220+ 'where'
221+ 'whereas'
222+ 'wherever'
223+ 'where\'s'
224+ 'whether'
225+ 'which'
226+ 'while'
227+ 'who'
228+ 'whoever'
229+ 'who\'s'
230+ 'whose'
231+ 'whom'
232+ 'why'
233+ 'why\'s'
234+ 'will'
235+ 'with'
236+ 'within'
237+ 'would'
238+ 'yes'
239+ 'yet'
240+ 'you'
241+ 'you\'d'
242+ 'you\'ll'
243+ 'you\'re'
244+ 'you\'ve'
245+ 'your'
246+ 'yours'
247+ 'yourself'
248+ 'yourselves'
249+ ==
250+--
desk/lib/sphinx-json.hoonnew file+72
@@ -0,0 +1,72 @@
1+/- s=sphinx
2+|%
3+++ enjs
4+ =, enjs:format
5+ |%
6+ ++ post
7+ |= p=post:s
8+ %- pairs
9+ :~ title/s/title.p
10+ type/s/type.p
11+ link/s/link.p
12+ description/s/description.p
13+ tags/a/(turn tags.p (lead %s))
14+ image/s/image.p
15+ color/s/color.p
16+ ==
17+ ++ listing
18+ |= l=listing:s
19+ %- pairs
20+ :~ post/(post post.l)
21+ hash/s/(scot %uv hash.l)
22+ source/s/(scot %p source.l)
23+ time/(time time.l)
24+ ==
25+ ++ search
26+ |= =search:s
27+ %- pairs
28+ :~ listings/a/(turn listings.search listing)
29+ :: numb, not (scot %ud): 1.234 would be read as a fraction
30+ ::
31+ start/(numb start.search)
32+ limit/(numb limit.search)
33+ size/(numb size.search)
34+ total/(numb total.search)
35+ ==
36+ ++ directory
37+ |= d=directory:s
38+ %- pairs
39+ %+ turn ~(tap by d)
40+ |= [=hash:s l=listing:s]
41+ [(scot %uv hash) (listing l)]
42+ ++ tags
43+ |= tags=(map @t @ud)
44+ %- pairs
45+ %+ turn ~(tap by tags)
46+ |= [tag=@t count=@ud]
47+ [tag (numb count)]
48+ --
49+++ dejs
50+ =, dejs:format
51+ |%
52+ ++ declarations (ar declare)
53+ ++ declare
54+ ^- $-(json declare:s)
55+ %- ot
56+ :~ reach/(su (perk [%friends %public %private ~]))
57+ post/post
58+ ==
59+ ++ post
60+ ^- $-(json post:s)
61+ %- ot
62+ :~ title/so
63+ type/type
64+ link/so
65+ description/so
66+ tags/(ar so)
67+ image/so
68+ color/so
69+ ==
70+ ++ type (su (perk [%app %group %content %other ~]))
71+ --
72+--
desk/lib/sphinx.hoonnew file+255
@@ -0,0 +1,255 @@
1+/- *sphinx
2+/+ sift
3+/+ *validate-url
4+/+ m=metaphone
5+|%
6+++ iching
7+ |= word=@t
8+ ^- (list @t)
9+ =/ w (trip word)
10+ =. w
11+ ?. (lth (lent w) 3) w
12+ (weld w (reap (sub 3 (lent w)) ' '))
13+ %+ turn
14+ (gulf 0 (sub (lent w) 3))
15+ |= index=@ud
16+ %- crip
17+ ^- tape
18+ ^- (list @)
19+ %+ sort
20+ `(list @ud)``(list @)`(swag [index 3] w)
21+ |= [p=@ud q=@ud]
22+ (gth q p)
23+++ digest
24+ |= =post
25+ ^- @uv
26+ %- shax
27+ %- crip
28+ :~ title.post
29+ `@t`type.post
30+ link.post
31+ image.post
32+ description.post
33+ (crip tags.post)
34+ ==
35+++ uprank
36+ |= offset=@ud
37+ |= =entry
38+ ^- ^entry
39+ [hash.entry (add rank.entry offset)]
40+++ sort-entries
41+ |= entries=(list entry)
42+ %+ sort entries
43+ |= [a=entry b=entry]
44+ (gth rank.a rank.b)
45+++ get-hashes
46+ |= entries=(list entry)
47+ %+ turn
48+ entries
49+ |=(=entry hash.entry)
50+:: +lengths-valid: bounds on what a peer can send, checked before
51+:: anything is indexed
52+::
53+:: source and time aren't in the digest, so a peer picks them too:
54+:: +time:enjs crashes before 1970, and rendering a huge atom is
55+:: quadratic
56+::
57+++ lengths-valid
58+ |= l=listing
59+ ?& (lte (met 3 title.post.l) 77)
60+ (lte (met 3 description.post.l) 256)
61+ (lte (lent tags.post.l) 8)
62+ (levy tags.post.l |=(tag=@t (lte (met 3 tag) 1.024)))
63+ (lte (met 3 link.post.l) 1.024)
64+ (lte (met 3 image.post.l) 1.024)
65+ (lte (met 3 color.post.l) 1.024)
66+ (lte (met 3 source.l) 16)
67+ (gte time.l ~1970.1.1)
68+ (lth time.l ~275000.1.1)
69+ ==
70+++ urls-valid
71+ |= l=listing
72+ =/ image
73+ ?: =(image.post.l '') 'X'
74+ (validate image.post.l)
75+ =/ link (validate link.post.l)
76+ &(!=(image ~) !=(link ~))
77+++ listing-valid
78+ |= l=listing
79+ :: lengths first: don't parse urls of oversized listings
80+ ::
81+ &((lengths-valid l) (urls-valid l))
82+++ delver
83+ |_ [=lookup =trigrams =phonetics =trail]
84+ ++ get
85+ ^- index
86+ [lookup trigrams phonetics trail]
87+ ++ catalog
88+ |= [=hash l=listing]
89+ ?. (listing-valid l) get
90+ =/ entries=^lookup
91+ %- malt
92+ ^- (list [@t (list entry)])
93+ %- zing
94+ :~ ~[[type.post.l ~[[hash rank=4]]]]
95+ %+ turn
96+ (sift:sift description.post.l)
97+ |= word=@t
98+ [word ~[[hash rank=8]]]
99+ :: +iching is quadratic in the length of a key, so long
100+ :: tags aren't indexed
101+ ::
102+ %+ turn
103+ (skim tags.post.l |=(tag=@t (lte (met 3 tag) 64)))
104+ |= tag=@t
105+ [(norm:sift tag) ~[[hash rank=12]]]
106+ %+ turn
107+ (sift:sift title.post.l)
108+ |= word=@t
109+ [word ~[[hash rank=16]]]
110+ ~[[(crip (cass (trip title.post.l))) ~[[hash rank=20]]]]
111+ ==
112+ =/ keys ~(tap in ~(key by entries))
113+ =. trail (~(put by trail) hash keys)
114+ :: only touch the new keys: rebuilding the whole map for every
115+ :: listing made cataloging a directory quadratic
116+ ::
117+ =. lookup
118+ %+ roll ~(tap by entries)
119+ |= [[=key value=(list entry)] lok=_lookup]
120+ (~(put by lok) key (weld value (~(gut by lok) key ~)))
121+ =. trigrams
122+ %+ roll
123+ %+ snoc
124+ %+ turn keys
125+ |= =key
126+ %- malt
127+ %+ turn (iching key)
128+ |= =trigram
129+ [trigram (silt ~[key])]
130+ trigrams
131+ |= [next=^trigrams t=^trigrams]
132+ %- (~(uno by t) next)
133+ |= [k=key v=(set key) w=(set key)]
134+ (~(uni in v) w)
135+ =. phonetics
136+ %-
137+ %- ~(uno by phonetics)
138+ %- malt
139+ %+ turn keys
140+ |= =key
141+ [(utter:m key) (silt ~[key])]
142+ |= [k=key v=(set key) w=(set key)]
143+ (~(uni in v) w)
144+ get
145+ ++ get-entries
146+ |= query=@t
147+ ^- (list entry)
148+ ?~ (find " " (trip query))
149+ =/ t (get-title-entries query)
150+ :: ~& t
151+ ~(tap by (malt t))
152+ %~ tap by
153+ %-
154+ %~ uni by :: union and prefer title entries (better rank)
155+ (malt (get-part-entries query))
156+ (malt (get-title-entries query))
157+ ++ get-part-entries
158+ |= query=@t
159+ ^- (list entry)
160+ =/ parts (sift:sift query) :: split query
161+ %- sum-ranks
162+ %- zing
163+ %+ turn
164+ parts
165+ |= word=@t
166+ ;: weld
167+ (get-phonetics word)
168+ (turn (get-trigrams word) (uprank 2))
169+ (turn (get-exact word) (uprank 6))
170+ ==
171+ ++ get-title-entries
172+ |= query=@t
173+ ^- (list entry)
174+ =/ title (norm:sift query) :: full query
175+ =/ exact (turn (get-exact title) (uprank 8))
176+ =/ trigrams (turn (get-trigrams title) (uprank 4))
177+ =/ phonetics (get-phonetics title)
178+ ;: weld
179+ phonetics
180+ trigrams
181+ exact
182+ ==
183+ ++ sum-ranks
184+ |= entries=(list entry)
185+ ^- (list entry)
186+ %+ turn
187+ %~ tap by
188+ %+ roll
189+ entries
190+ |= [=entry gourd=(jar hash rank)]
191+ (~(add ja gourd) entry)
192+ |= [=hash es=(list rank)]
193+ ^- entry
194+ [hash (roll es add)]
195+ ++ get-exact
196+ |= term=@t
197+ (~(gut by lookup) term *(list entry))
198+ ++ get-trigrams
199+ |= term=@t
200+ ^- (list entry)
201+ %- zing
202+ %+ turn
203+ (get-keys term)
204+ |= item=@t
205+ (~(gut by lookup) item *(list entry))
206+ ++ get-phonetics
207+ |= term=key
208+ ^- (list entry)
209+ =/ keys
210+ %+ skim
211+ %~ tap in
212+ (~(gut by phonetics) (utter:m term) *(set key))
213+ |= word=key
214+ !=(term word)
215+ %+ roll
216+ keys
217+ |= [word=key entries=(list entry)]
218+ %+ weld
219+ entries
220+ (~(gut by lookup) word *(list entry))
221+ ++ get-keys
222+ |= term=@t
223+ ^- (list @t)
224+ =/ tally (get-term-counts term)
225+ =/ tallys ~(tap by tally)
226+ =/ count (lent (iching term))
227+ %+ turn
228+ %+ sort
229+ %+ skim
230+ tallys
231+ |= [k=@t v=@ud]
232+ (gth:rs (div:rs (sun:rs v) (sun:rs count)) .0.6)
233+ |= [[k=@t v=@ud] [l=@t w=@ud]]
234+ (lth v w)
235+ |= [k=@t v=@ud]
236+ k
237+ ++ get-term-counts
238+ |= term=@t
239+ ^- (map @t @ud)
240+ %+ roll
241+ (iching term)
242+ |= [ngram=@t tally=(map @t @ud)]
243+ ^- (map @t @ud)
244+ =/ words=(set @t) (~(gut by trigrams) ngram *(set @t))
245+ %-
246+ %- ~(uno by tally)
247+ %- malt
248+ %+ turn
249+ ~(tap in words)
250+ |= word=@t
251+ [word 1]
252+ |= [k=@t v=@ud w=@ud]
253+ (add v w)
254+ --
255+--
desk/lib/validate-url.hoonnew file+20
@@ -0,0 +1,20 @@
1+|%
2+++ validate
3+ |= url=@t
4+ ^- (unit @t)
5+ %+ rush url
6+ %+ cold url
7+ ;~ plug
8+ ;~ pose
9+ ;~ plug
10+ ;~(plug alf (star ;~(pose aln lus dot hep)) col fas fas)
11+ ;~(pose thor:de-purl:html ;~(pfix sig fed:ag))
12+ ==
13+ (easy ~)
14+ ==
15+ ;~ plug
16+ ;~(pose apat:de-purl:html (easy *pork:eyre))
17+ yque:de-purl:html
18+ ==
19+ ==
20+--
desk/mar/declarations.hoonnew file+14
@@ -0,0 +1,14 @@
1+/- s=sphinx
2+/+ j=sphinx-json
3+|_ d=(list declare:s)
4+++ grad %noun
5+++ grow
6+ |%
7+ ++ noun d
8+ --
9+++ grab
10+ |%
11+ ++ noun (list declare:s)
12+ ++ json declarations:dejs:j
13+ --
14+--
desk/mar/declare.hoonnew file+14
@@ -0,0 +1,14 @@
1+/- s=sphinx
2+/+ j=sphinx-json
3+|_ =declare:s
4+++ grad %noun
5+++ grow
6+ |%
7+ ++ noun declare
8+ --
9+++ grab
10+ |%
11+ ++ noun declare:s
12+ ++ json declare:dejs:j
13+ --
14+--
desk/mar/directory-listing.hoonnew file+13
@@ -0,0 +1,13 @@
1+/- s=sphinx
2+/+ j=sphinx-json
3+|_ =listing:s
4+++ grad %noun
5+++ grow
6+ |%
7+ ++ noun listing
8+ --
9+++ grab
10+ |%
11+ ++ noun listing:s
12+ --
13+--
desk/mar/directory.hoonnew file+14
@@ -0,0 +1,14 @@
1+/- s=sphinx
2+/+ j=sphinx-json
3+|_ =directory:s
4+++ grad %noun
5+++ grow
6+ |%
7+ ++ noun directory
8+ ++ json (directory:enjs:j directory)
9+ --
10+++ grab
11+ |%
12+ ++ noun directory:s
13+ --
14+--
desk/mar/gossip/rumor.hoonnew file+11
@@ -0,0 +1,11 @@
1+|_ rum=[[@ *] (cask *)]
2+++ grad %noun
3+++ grow
4+ |%
5+ ++ noun rum
6+ --
7+++ grab
8+ |%
9+ ++ noun ,[[@ *] (cask *)]
10+ --
11+--
desk/mar/pals/command.hoonnew file+22
@@ -0,0 +1,22 @@
1+:: pals-command: friend management
2+::
3+/- *pals
4+::
5+|_ cmd=command
6+++ grad %noun
7+++ grow
8+ |%
9+ ++ noun cmd
10+ --
11+++ grab
12+ |%
13+ ++ noun command
14+ ++ json
15+ ^- $-(^json command)
16+ =, dejs:format
17+ |^ (of meet+arg part+arg ~)
18+ ++ arg
19+ (ot 'ship'^(su fed:ag) 'in'^(as so) ~)
20+ --
21+ --
22+--
desk/mar/remove.hoonnew file+14
@@ -0,0 +1,14 @@
1+/- s=sphinx
2+/+ j=sphinx-json
3+|_ =hash:s
4+++ grad %noun
5+++ grow
6+ |%
7+ ++ noun hash
8+ --
9+++ grab
10+ |%
11+ ++ noun hash:s
12+ ++ json (se:dejs:format %uv)
13+ --
14+--
desk/mar/search.hoonnew file+14
@@ -0,0 +1,14 @@
1+/- s=sphinx
2+/+ j=sphinx-json
3+|_ =search:s
4+++ grad %noun
5+++ grow
6+ |%
7+ ++ noun search
8+ ++ json (search:enjs:j search)
9+ --
10+++ grab
11+ |%
12+ ++ noun search:s
13+ --
14+--
desk/mar/state.hoonnew file+12
@@ -0,0 +1,12 @@
1+/- s=sphinx
2+|_ =state:s
3+++ grad %noun
4+++ grow
5+ |%
6+ ++ noun state
7+ --
8+++ grab
9+ |%
10+ ++ noun state:s
11+ --
12+--
desk/mar/tags.hoonnew file+14
@@ -0,0 +1,14 @@
1+/- s=sphinx
2+/+ j=sphinx-json
3+|_ tags=(map @t @ud)
4+++ grad %noun
5+++ grow
6+ |%
7+ ++ noun tags
8+ ++ json (tags:enjs:j tags)
9+ --
10+++ grab
11+ |%
12+ ++ noun (map @t @ud)
13+ --
14+--
desk/sur/pals.hoonnew file+41
@@ -0,0 +1,41 @@
1+:: pals: manual neighboring
2+::
3+|%
4++$ records :: local state
5+ $: outgoing=(jug ship @ta)
6+ incoming=(set ship)
7+ ::
8+ :: receipts: for all outgoing, status
9+ ::
10+ :: if ship not in receipts, poke awaiting ack
11+ :: if ship present as true, poke acked positively
12+ :: if ship present as false, poke acked negatively
13+ ::
14+ receipts=(map ship ?)
15+ ==
16+::
17++$ gesture :: to/from others
18+ $% [%hey ~]
19+ [%bye ~]
20+ ==
21+::
22++$ command :: from ourselves
23+ $% [%meet =ship in=(set @ta)] :: empty set allowed
24+ [%part =ship in=(set @ta)] :: empty set implies un-targeting
25+ ==
26+::
27++$ effect :: to ourselves
28+ $% target-effect
29+ leeche-effect
30+ ==
31+::
32++$ target-effect
33+ $% [%meet =ship] :: hey to target
34+ [%part =ship] :: bye to target
35+ ==
36+::
37++$ leeche-effect
38+ $% [%near =ship] :: hey from leeche
39+ [%away =ship] :: bye from leeche
40+ ==
41+--
desk/sur/sphinx.hoonnew file+139
@@ -0,0 +1,139 @@
1+|%
2++$ key @t :: keyword that points to listings
3++$ hash @uv :: @uv version of shax result
4++$ rank @ud :: @ud representing priority of listing
5++$ phonetic @t :: @t consisting of phonetic characters from metaphone
6++$ trigram @t :: @t consisting of three characters taken from a word
7+::
8+:: an entry points to a listing hash and provides
9+:: a semblance of priority for the listing
10+::
11++$ entry
12+ $: =hash :: hash of listing contents
13+ =rank :: based on which attribute keyword came from
14+ ==
15+::
16+:: a post represents a search result which points to some
17+:: external resource through a link. this is a rich result
18+:: which gives a summary of the resource as well as an image
19+:: and related topics.
20+::
21++$ post-type ?(%app %group %content %other)
22+::
23++$ post
24+ $: title=@t
25+ type=post-type
26+ link=@t
27+ description=@t
28+ tags=(list @t)
29+ image=@t
30+ color=@t
31+ ==
32+::
33++$ reach ?(%private %friends %public)
34+::
35++$ declare (pair reach post)
36+::
37+:: a listing includes the content of the post as well as information
38+:: that would affect the hash so are left out, namely time, source and
39+:: hash. each post has a source and time so that they can be updated
40+:: via the source requesting to replace the listing and hash.
41+::
42+::
43++$ listing
44+ $: =post
45+ =hash
46+ =reach
47+ source=@p
48+ time=@da
49+ ==
50+::
51+:: lookup acts as a search index for keywords, each key points to
52+:: an entry which points to a listing. listings are separate from
53+:: the lookup because they are repeated under different keys
54+::
55++$ lookup (map key (list entry))
56+::
57+:: phonetics act as a way to account for spelling errors. we keep a map
58+:: of phonetic to set of lookup keys. we take the query's phonetics and
59+:: use that to add other words to the results.
60++$ phonetics (map phonetic (set key))
61+::
62+:: trigrams act similarly to phonetics. we keep a map of trigram to set
63+:: of lookup keys. we take the query's trigrams and count how many
64+:: times a particular key comes up.
65++$ trigrams (map trigram (set key))
66+::
67+:: trail is a way for us to know all the keys required to update
68+:: a listing with the new hash of it's contents
69+::
70++$ trail (map hash (list key))
71+::
72+:: directory is a hash table of all current listings. each hash is
73+:: created by taking the hash of the entire listings contents.
74+::
75++$ directory (map hash listing)
76+::
77++$ search
78+ $: listings=(list listing)
79+ start=@ud
80+ limit=@ud
81+ size=@ud
82+ total=@ud
83+ ==
84+::
85++$ index
86+ $: =lookup
87+ =trigrams
88+ =phonetics
89+ =trail
90+ ==
91+::
92++$ state
93+ $: %2
94+ =index
95+ =directory
96+ published=directory
97+ ==
98+::
99++$ state-1
100+ $: %1
101+ =lookup
102+ =trigrams
103+ =phonetics
104+ =trail
105+ =directory
106+ published=directory
107+ ==
108+::
109++$ state-0
110+ $: %0
111+ =lookup
112+ =trigrams
113+ =phonetics
114+ =trail
115+ =directory:directory-state-zero
116+ published=directory:directory-state-zero
117+ ==
118+++ directory-state-zero
119+ |%
120+ +$ post
121+ $: title=@t
122+ type=post-type
123+ link=@t
124+ description=@t
125+ tags=(list @t)
126+ image=@t
127+ ==
128+ ::
129+ +$ listing
130+ $: =post
131+ =hash
132+ =reach
133+ source=@p
134+ time=@da
135+ ==
136+ ::
137+ +$ directory (map hash listing)
138+ --
139+--
desk/sys.kelvinnew file+1
@@ -0,0 +1 @@
1+[%zuse 408]
desk/ted/publish-all.hoonnew file+40
@@ -0,0 +1,40 @@
1+/- spider
2+/- s=sphinx
3+/+ *strandio
4+=, strand=strand:spider
5+=/ posts
6+ ^- (list declare:s)
7+ :~ :- %friends
8+ ['networked subject' %group 'web+urbitgraph://group/~matwet/networked-subject' 'https://subject.network | networked subject' ~['hosting' 'networking' 'urbit' 'ops'] 'https://urbits3.ams3.digitaloceanspaces.com/sitful-hatred/2022.7.07..17.15.52-ns.png' '']
9+ :- %friends
10+ ['Hooniverse' %group 'web+urbitgraph://group/~hiddev-dannut/new-hooniverse' 'Community based Hoon learning for all levels. For discussion of Hoon specific to Uqbar, join ~hiddev-dannut/uhoon' ~['hoon' 'dev' 'urbit' 'programming' 'education'] 'https://i.imgur.com/ghThlz7.png' '']
11+ :- %friends
12+ ['Hollow Mars Theory' %group 'web+urbitgraph://group/~rabsef-bicrym/hollow-mars-theory' 'Definitely NOT a Conspiracy Chat' ~['conspiracies' 'ufos' 'steel beams'] '' '']
13+ :- %friends
14+ ['celestial systems' %group 'web+urbitgraph://group/~nocsyx-lassul/celestial-systems' 'A place for pilots who are building hosting providers' ~['hosting' 'ops' 'urbit'] '' '']
15+ :- %friends
16+ ['Structure' %group 'web+urbitgraph://group/~fabled-faster/structure' 'Urbit Structural Design and Engineering Group. Always Thinking About Mechanics.' ~['design' 'ux' 'hci' 'urbit'] 'https://fabled-faster.nyc3.digitaloceanspaces.com/fabled-faster/2022.1.27..17.59.43-image.png' '']
17+ :- %friends
18+ ['The Marketplace' %group 'web+urbitgraph://group/~tirrel/the-marketplace' 'Welcome to The Marketplace, featuring The Pit, Urbit\'s first open-outcry market!' ~['urbit' 'market' 'sell' 'buy'] 'https://snipboard.io/U0IYyi.jpg' '']
19+ :- %friends
20+ ['The Forge' %group 'web+urbitgraph://group/~middev/the-forge' 'pale fire computing' ~['dev' 'programming' 'hoon' 'urbit'] 'https://nyc3.digitaloceanspaces.com/archiv/littel-wolfur/2021.5.06..21.01.58-the%20forge.png' '']
21+ :- %friends
22+ ['UFORIA' %group 'web+urbitgraph://group/~tiplec-lacnyx/ufora' 'UFO Research, Investigations, and Analysis' ~['UFO' 'conspiracies' 'research'] 'https://tiplec-lacnyx.nyc3.digitaloceanspaces.com/tiplec-lacnyx/2021.12.27..06.09.47-change1.jpg' '']
23+ :- %friends
24+ ['Urbit Community' %group 'web+urbitgraph://group/~bitbet-bolbel/urbit-community' 'World hub, help desk, meet and greet, etc.' ~['general' 'urbit' 'community' 'help'] 'https://fabled-faster.nyc3.digitaloceanspaces.com/fabled-faster/2021.4.02..21.52.41-UC.png' '']
25+ :- %friends
26+ ['Urbytes' %group 'web+urbitgraph://group/~nartes-fasrum/urbytes' 'We feed and water Mars.' ~['cooking' 'food' 'beverages' 'peanut butter eggs'] '' '']
27+ ==
28+^- thread:spider
29+|= arg=vase
30+=/ m (strand ,vase)
31+^- form:m
32+;< our=@p bind:m get-our
33+;< ~ bind:m
34+ %- send-raw-cards
35+ ^- (list card:agent:gall)
36+ %+ turn
37+ posts
38+ |= =declare:s
39+ [%pass /poke %agent [our %sphinx] %poke [%declare !>(declare)]]
40+(pure:m !>(~))
flake.locknew file+63
@@ -0,0 +1,63 @@
1+{
2+ "nodes": {
3+ "landscape": {
4+ "flake": false,
5+ "locked": {
6+ "lastModified": 1781809440,
7+ "narHash": "sha256-woNZKzK8xlBxnMMrQOzInA7+gGxs7BgjGbmTi7OGi6g=",
8+ "owner": "tloncorp",
9+ "repo": "landscape",
10+ "rev": "3ea2679f2003ed3ca1a6b322cd7857a774eac305",
11+ "type": "github"
12+ },
13+ "original": {
14+ "owner": "tloncorp",
15+ "repo": "landscape",
16+ "rev": "3ea2679f2003ed3ca1a6b322cd7857a774eac305",
17+ "type": "github"
18+ }
19+ },
20+ "nixpkgs": {
21+ "locked": {
22+ "lastModified": 1792210252,
23+ "narHash": "sha256-Mh0PUaIv4nFY+8wAGonaEh8iBzwsmdNlwjVHmFg1Biw=",
24+ "owner": "NixOS",
25+ "repo": "nixpkgs",
26+ "rev": "09063bd1f2b36fd9fd793c36dfade7bd40a93dfc",
27+ "type": "github"
28+ },
29+ "original": {
30+ "owner": "NixOS",
31+ "ref": "nixos-unstable",
32+ "repo": "nixpkgs",
33+ "type": "github"
34+ }
35+ },
36+ "root": {
37+ "inputs": {
38+ "landscape": "landscape",
39+ "nixpkgs": "nixpkgs",
40+ "urbit": "urbit"
41+ }
42+ },
43+ "urbit": {
44+ "flake": false,
45+ "locked": {
46+ "lastModified": 1785851358,
47+ "narHash": "sha256-eHoGwqirk7zMpOn/y8dKqozz5IiQ7nqek/ypxIOaRiU=",
48+ "owner": "urbit",
49+ "repo": "urbit",
50+ "rev": "5a187fededc4582a34fcd6055c67bb63e0917b94",
51+ "type": "github"
52+ },
53+ "original": {
54+ "owner": "urbit",
55+ "ref": "408k-2",
56+ "repo": "urbit",
57+ "type": "github"
58+ }
59+ }
60+ },
61+ "root": "root",
62+ "version": 7
63+}
flake.nixnew file+98
@@ -0,0 +1,98 @@
1+{
2+ description = "sphinx desk";
3+
4+ inputs = {
5+ nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
6+
7+ # Dependency desks. Keep them on releases for the kelvin in
8+ # desk/sys.kelvin ([%zuse 408]) and bump them together with it.
9+ urbit = {
10+ # release tag for [%zuse 408]
11+ url = "github:urbit/urbit/408k-2";
12+ flake = false;
13+ };
14+ landscape = {
15+ # No 408 tag: the staging head Tlon promoted on 2026-06-18, whose
16+ # desk/sys.kelvin lists [%zuse 410] [%zuse 409] [%zuse 408].
17+ url = "github:tloncorp/landscape/3ea2679f2003ed3ca1a6b322cd7857a774eac305";
18+ flake = false;
19+ };
20+ };
21+
22+ outputs =
23+ {
24+ self,
25+ nixpkgs,
26+ urbit,
27+ landscape,
28+ }:
29+ let
30+ forAllSystems = nixpkgs.lib.genAttrs nixpkgs.lib.systems.flakeExposed;
31+
32+ # Only what ./desk needs from the dependency desks: its imports,
33+ # transitively, and the marks for its file types plus json and mime.
34+ # 408 clay builds every mark on the desk at each commit and OTA, and one
35+ # that fails to build rejects the whole event, so extra marks are a
36+ # liability.
37+ basePicks = [
38+ "lib/dbug.hoon"
39+ "lib/default-agent.hoon"
40+ "lib/skeleton.hoon"
41+ "lib/strand.hoon"
42+ "lib/strandio.hoon"
43+ "lib/verb.hoon"
44+ "sur/spider.hoon"
45+ "sur/verb.hoon"
46+ "mar/bill.hoon"
47+ "mar/hoon.hoon"
48+ "mar/json.hoon"
49+ "mar/kelvin.hoon"
50+ "mar/mime.hoon"
51+ "mar/noun.hoon"
52+ "mar/txt.hoon"
53+ ];
54+ # desk.docket-0 needs mar/docket-0, which imports lib/docket and
55+ # sur/docket.
56+ docketPicks = [
57+ "lib/docket.hoon"
58+ "mar/docket-0.hoon"
59+ "sur/docket.hoon"
60+ ];
61+ in
62+ {
63+ packages = forAllSystems (
64+ system:
65+ let
66+ pkgs = nixpkgs.legacyPackages.${system};
67+ in
68+ {
69+ # The picks, then ./desk on top. -L copies symlink targets, so the
70+ # desk is plain files.
71+ desk = pkgs.runCommandLocal "sphinx-desk" { } ''
72+ mkdir $out
73+ for f in ${toString basePicks}; do
74+ install -Dm644 ${urbit}/pkg/base-dev/$f $out/$f
75+ done
76+ for f in ${toString docketPicks}; do
77+ install -Dm644 ${landscape}/desk-dev/$f $out/$f
78+ done
79+ cp -RL ${./desk}/. $out
80+ '';
81+ # The UI files, served under /apps/sphinx/. Upload this directory at
82+ # /docket/upload on the ship in desk/desk.docket-0's glob-ames.
83+ glob = pkgs.buildNpmPackage {
84+ name = "sphinx-glob";
85+ src = ./ui;
86+ nodejs = pkgs.nodejs_22;
87+ npmDepsHash = "sha256-uOUDkt0spCWdlOfto5Y3o5R9PP6oeYmGMcwUjEdzC/M=";
88+ installPhase = ''
89+ runHook preInstall
90+ cp -R dist $out
91+ runHook postInstall
92+ '';
93+ };
94+ default = self.packages.${system}.desk;
95+ }
96+ );
97+ };
98+}
ui/.gitignorenew file+8
@@ -0,0 +1,8 @@
1+node_modules
2+.DS_Store
3+dist
4+dist-ssr
5+*.local
6+stats.html
7+.eslintcache
8+.vercel
ui/.nvmrcnew file+1
@@ -0,0 +1 @@
1+22
ui/index.htmlnew file+17
@@ -0,0 +1,17 @@
1+<!DOCTYPE html>
2+<html lang="en">
3+ <head>
4+ <meta charset="UTF-8" />
5+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6+ <title>sphinx</title>
7+ <meta name="theme-color" content="#ffffff" />
8+ <link rel="icon" href="/src/assets/favicon.svg" sizes="any" type="image/svg+xml" />
9+ <link rel="mask-icon" href="/src/assets/safari-pinned-tab.svg" color="#000000" />
10+ <link rel="apple-touch-icon" sizes="180x180" href="/src/assets/apple-touch-icon.png" />
11+ <link rel="manifest" href="/manifest.json" />
12+ </head>
13+ <body class="font-sans text-mauve bg-linen antialiased">
14+ <div id="app"></div>
15+ <script type="module" src="/src/main.tsx"></script>
16+ </body>
17+</html>
ui/package-lock.jsonnew file+5678
@@ -0,0 +1,5678 @@
1+{
2+ "name": "sphinx",
3+ "version": "0.0.0",
4+ "lockfileVersion": 2,
5+ "requires": true,
6+ "packages": {
7+ "": {
8+ "name": "sphinx",
9+ "version": "0.0.0",
10+ "dependencies": {
11+ "@heroicons/react": "^1.0.6",
12+ "@radix-ui/react-dropdown-menu": "^0.1.6",
13+ "@radix-ui/react-select": "^0.1.1",
14+ "@radix-ui/react-toggle-group": "^0.1.5",
15+ "@tanstack/react-query": "^4.29.5",
16+ "@urbit/api": "2.2",
17+ "@urbit/http-api": "^2.0.0",
18+ "big-integer": "^1.6.51",
19+ "classnames": "^2.3.1",
20+ "color2k": "^2.0.2",
21+ "lodash.debounce": "^4.0.8",
22+ "query-string": "^7.1.1",
23+ "react": "^17.0.2",
24+ "react-dom": "^17.0.2",
25+ "react-hook-form": "^7.33.1",
26+ "react-router-dom": "^6.3.0",
27+ "react-select": "^5.4.0",
28+ "remove-markdown-and-html": "^0.1.0",
29+ "urbit-ob": "^5.0.1",
30+ "zustand": "^4.0.0-rc.1"
31+ },
32+ "devDependencies": {
33+ "@types/lodash.debounce": "^4.0.7",
34+ "@types/react": "^17.0.0",
35+ "@types/react-dom": "^17.0.0",
36+ "@urbit/vite-plugin-urbit": "^0.8.0",
37+ "@vitejs/plugin-react-refresh": "^1.3.1",
38+ "autoprefixer": "^10.4.7",
39+ "postcss": "^8.4.14",
40+ "postcss-import": "^14.1.0",
41+ "tailwindcss": "^3.1.4",
42+ "tailwindcss-labeled-groups": "^0.0.2",
43+ "typescript": "^4.3.2",
44+ "vite": "^2.9.13"
45+ }
46+ },
47+ "node_modules/@ampproject/remapping": {
48+ "version": "2.2.0",
49+ "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz",
50+ "integrity": "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==",
51+ "dependencies": {
52+ "@jridgewell/gen-mapping": "^0.1.0",
53+ "@jridgewell/trace-mapping": "^0.3.9"
54+ },
55+ "engines": {
56+ "node": ">=6.0.0"
57+ }
58+ },
59+ "node_modules/@babel/code-frame": {
60+ "version": "7.18.6",
61+ "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz",
62+ "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==",
63+ "dependencies": {
64+ "@babel/highlight": "^7.18.6"
65+ },
66+ "engines": {
67+ "node": ">=6.9.0"
68+ }
69+ },
70+ "node_modules/@babel/compat-data": {
71+ "version": "7.18.6",
72+ "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.18.6.tgz",
73+ "integrity": "sha512-tzulrgDT0QD6U7BJ4TKVk2SDDg7wlP39P9yAx1RfLy7vP/7rsDRlWVfbWxElslu56+r7QOhB2NSDsabYYruoZQ==",
74+ "engines": {
75+ "node": ">=6.9.0"
76+ }
77+ },
78+ "node_modules/@babel/core": {
79+ "version": "7.18.6",
80+ "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.18.6.tgz",
81+ "integrity": "sha512-cQbWBpxcbbs/IUredIPkHiAGULLV8iwgNRMFzvbhEXISp4f3rUUXE5+TIw6KwUWUR3DwyI6gmBRnmAtYaWehwQ==",
82+ "dependencies": {
83+ "@ampproject/remapping": "^2.1.0",
84+ "@babel/code-frame": "^7.18.6",
85+ "@babel/generator": "^7.18.6",
86+ "@babel/helper-compilation-targets": "^7.18.6",
87+ "@babel/helper-module-transforms": "^7.18.6",
88+ "@babel/helpers": "^7.18.6",
89+ "@babel/parser": "^7.18.6",
90+ "@babel/template": "^7.18.6",
91+ "@babel/traverse": "^7.18.6",
92+ "@babel/types": "^7.18.6",
93+ "convert-source-map": "^1.7.0",
94+ "debug": "^4.1.0",
95+ "gensync": "^1.0.0-beta.2",
96+ "json5": "^2.2.1",
97+ "semver": "^6.3.0"
98+ },
99+ "engines": {
100+ "node": ">=6.9.0"
101+ },
102+ "funding": {
103+ "type": "opencollective",
104+ "url": "https://opencollective.com/babel"
105+ }
106+ },
107+ "node_modules/@babel/generator": {
108+ "version": "7.18.7",
109+ "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.18.7.tgz",
110+ "integrity": "sha512-shck+7VLlY72a2w9c3zYWuE1pwOKEiQHV7GTUbSnhyl5eu3i04t30tBY82ZRWrDfo3gkakCFtevExnxbkf2a3A==",
111+ "dependencies": {
112+ "@babel/types": "^7.18.7",
113+ "@jridgewell/gen-mapping": "^0.3.2",
114+ "jsesc": "^2.5.1"
115+ },
116+ "engines": {
117+ "node": ">=6.9.0"
118+ }
119+ },
120+ "node_modules/@babel/generator/node_modules/@jridgewell/gen-mapping": {
121+ "version": "0.3.2",
122+ "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz",
123+ "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==",
124+ "dependencies": {
125+ "@jridgewell/set-array": "^1.0.1",
126+ "@jridgewell/sourcemap-codec": "^1.4.10",
127+ "@jridgewell/trace-mapping": "^0.3.9"
128+ },
129+ "engines": {
130+ "node": ">=6.0.0"
131+ }
132+ },
133+ "node_modules/@babel/helper-compilation-targets": {
134+ "version": "7.18.6",
135+ "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.18.6.tgz",
136+ "integrity": "sha512-vFjbfhNCzqdeAtZflUFrG5YIFqGTqsctrtkZ1D/NB0mDW9TwW3GmmUepYY4G9wCET5rY5ugz4OGTcLd614IzQg==",
137+ "dependencies": {
138+ "@babel/compat-data": "^7.18.6",
139+ "@babel/helper-validator-option": "^7.18.6",
140+ "browserslist": "^4.20.2",
141+ "semver": "^6.3.0"
142+ },
143+ "engines": {
144+ "node": ">=6.9.0"
145+ },
146+ "peerDependencies": {
147+ "@babel/core": "^7.0.0"
148+ }
149+ },
150+ "node_modules/@babel/helper-environment-visitor": {
151+ "version": "7.18.6",
152+ "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.6.tgz",
153+ "integrity": "sha512-8n6gSfn2baOY+qlp+VSzsosjCVGFqWKmDF0cCWOybh52Dw3SEyoWR1KrhMJASjLwIEkkAufZ0xvr+SxLHSpy2Q==",
154+ "engines": {
155+ "node": ">=6.9.0"
156+ }
157+ },
158+ "node_modules/@babel/helper-function-name": {
159+ "version": "7.18.6",
160+ "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.18.6.tgz",
161+ "integrity": "sha512-0mWMxV1aC97dhjCah5U5Ua7668r5ZmSC2DLfH2EZnf9c3/dHZKiFa5pRLMH5tjSl471tY6496ZWk/kjNONBxhw==",
162+ "dependencies": {
163+ "@babel/template": "^7.18.6",
164+ "@babel/types": "^7.18.6"
165+ },
166+ "engines": {
167+ "node": ">=6.9.0"
168+ }
169+ },
170+ "node_modules/@babel/helper-hoist-variables": {
171+ "version": "7.18.6",
172+ "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz",
173+ "integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==",
174+ "dependencies": {
175+ "@babel/types": "^7.18.6"
176+ },
177+ "engines": {
178+ "node": ">=6.9.0"
179+ }
180+ },
181+ "node_modules/@babel/helper-module-imports": {
182+ "version": "7.18.6",
183+ "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz",
184+ "integrity": "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==",
185+ "dependencies": {
186+ "@babel/types": "^7.18.6"
187+ },
188+ "engines": {
189+ "node": ">=6.9.0"
190+ }
191+ },
192+ "node_modules/@babel/helper-module-transforms": {
193+ "version": "7.18.6",
194+ "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.18.6.tgz",
195+ "integrity": "sha512-L//phhB4al5uucwzlimruukHB3jRd5JGClwRMD/ROrVjXfLqovYnvQrK/JK36WYyVwGGO7OD3kMyVTjx+WVPhw==",
196+ "dependencies": {
197+ "@babel/helper-environment-visitor": "^7.18.6",
198+ "@babel/helper-module-imports": "^7.18.6",
199+ "@babel/helper-simple-access": "^7.18.6",
200+ "@babel/helper-split-export-declaration": "^7.18.6",
201+ "@babel/helper-validator-identifier": "^7.18.6",
202+ "@babel/template": "^7.18.6",
203+ "@babel/traverse": "^7.18.6",
204+ "@babel/types": "^7.18.6"
205+ },
206+ "engines": {
207+ "node": ">=6.9.0"
208+ }
209+ },
210+ "node_modules/@babel/helper-plugin-utils": {
211+ "version": "7.18.6",
212+ "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.18.6.tgz",
213+ "integrity": "sha512-gvZnm1YAAxh13eJdkb9EWHBnF3eAub3XTLCZEehHT2kWxiKVRL64+ae5Y6Ivne0mVHmMYKT+xWgZO+gQhuLUBg==",
214+ "engines": {
215+ "node": ">=6.9.0"
216+ }
217+ },
218+ "node_modules/@babel/helper-simple-access": {
219+ "version": "7.18.6",
220+ "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.18.6.tgz",
221+ "integrity": "sha512-iNpIgTgyAvDQpDj76POqg+YEt8fPxx3yaNBg3S30dxNKm2SWfYhD0TGrK/Eu9wHpUW63VQU894TsTg+GLbUa1g==",
222+ "dependencies": {
223+ "@babel/types": "^7.18.6"
224+ },
225+ "engines": {
226+ "node": ">=6.9.0"
227+ }
228+ },
229+ "node_modules/@babel/helper-split-export-declaration": {
230+ "version": "7.18.6",
231+ "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz",
232+ "integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==",
233+ "dependencies": {
234+ "@babel/types": "^7.18.6"
235+ },
236+ "engines": {
237+ "node": ">=6.9.0"
238+ }
239+ },
240+ "node_modules/@babel/helper-validator-identifier": {
241+ "version": "7.18.6",
242+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.18.6.tgz",
243+ "integrity": "sha512-MmetCkz9ej86nJQV+sFCxoGGrUbU3q02kgLciwkrt9QqEB7cP39oKEY0PakknEO0Gu20SskMRi+AYZ3b1TpN9g==",
244+ "engines": {
245+ "node": ">=6.9.0"
246+ }
247+ },
248+ "node_modules/@babel/helper-validator-option": {
249+ "version": "7.18.6",
250+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz",
251+ "integrity": "sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw==",
252+ "engines": {
253+ "node": ">=6.9.0"
254+ }
255+ },
256+ "node_modules/@babel/helpers": {
257+ "version": "7.18.6",
258+ "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.18.6.tgz",
259+ "integrity": "sha512-vzSiiqbQOghPngUYt/zWGvK3LAsPhz55vc9XNN0xAl2gV4ieShI2OQli5duxWHD+72PZPTKAcfcZDE1Cwc5zsQ==",
260+ "dependencies": {
261+ "@babel/template": "^7.18.6",
262+ "@babel/traverse": "^7.18.6",
263+ "@babel/types": "^7.18.6"
264+ },
265+ "engines": {
266+ "node": ">=6.9.0"
267+ }
268+ },
269+ "node_modules/@babel/highlight": {
270+ "version": "7.18.6",
271+ "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz",
272+ "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==",
273+ "dependencies": {
274+ "@babel/helper-validator-identifier": "^7.18.6",
275+ "chalk": "^2.0.0",
276+ "js-tokens": "^4.0.0"
277+ },
278+ "engines": {
279+ "node": ">=6.9.0"
280+ }
281+ },
282+ "node_modules/@babel/parser": {
283+ "version": "7.18.6",
284+ "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.18.6.tgz",
285+ "integrity": "sha512-uQVSa9jJUe/G/304lXspfWVpKpK4euFLgGiMQFOCpM/bgcAdeoHwi/OQz23O9GK2osz26ZiXRRV9aV+Yl1O8tw==",
286+ "bin": {
287+ "parser": "bin/babel-parser.js"
288+ },
289+ "engines": {
290+ "node": ">=6.0.0"
291+ }
292+ },
293+ "node_modules/@babel/plugin-syntax-jsx": {
294+ "version": "7.18.6",
295+ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.18.6.tgz",
296+ "integrity": "sha512-6mmljtAedFGTWu2p/8WIORGwy+61PLgOMPOdazc7YoJ9ZCWUyFy3A6CpPkRKLKD1ToAesxX8KGEViAiLo9N+7Q==",
297+ "dependencies": {
298+ "@babel/helper-plugin-utils": "^7.18.6"
299+ },
300+ "engines": {
301+ "node": ">=6.9.0"
302+ },
303+ "peerDependencies": {
304+ "@babel/core": "^7.0.0-0"
305+ }
306+ },
307+ "node_modules/@babel/plugin-transform-react-jsx-self": {
308+ "version": "7.18.6",
309+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.18.6.tgz",
310+ "integrity": "sha512-A0LQGx4+4Jv7u/tWzoJF7alZwnBDQd6cGLh9P+Ttk4dpiL+J5p7NSNv/9tlEFFJDq3kjxOavWmbm6t0Gk+A3Ig==",
311+ "dev": true,
312+ "dependencies": {
313+ "@babel/helper-plugin-utils": "^7.18.6"
314+ },
315+ "engines": {
316+ "node": ">=6.9.0"
317+ },
318+ "peerDependencies": {
319+ "@babel/core": "^7.0.0-0"
320+ }
321+ },
322+ "node_modules/@babel/plugin-transform-react-jsx-source": {
323+ "version": "7.18.6",
324+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.18.6.tgz",
325+ "integrity": "sha512-utZmlASneDfdaMh0m/WausbjUjEdGrQJz0vFK93d7wD3xf5wBtX219+q6IlCNZeguIcxS2f/CvLZrlLSvSHQXw==",
326+ "dev": true,
327+ "dependencies": {
328+ "@babel/helper-plugin-utils": "^7.18.6"
329+ },
330+ "engines": {
331+ "node": ">=6.9.0"
332+ },
333+ "peerDependencies": {
334+ "@babel/core": "^7.0.0-0"
335+ }
336+ },
337+ "node_modules/@babel/runtime": {
338+ "version": "7.18.6",
339+ "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.18.6.tgz",
340+ "integrity": "sha512-t9wi7/AW6XtKahAe20Yw0/mMljKq0B1r2fPdvaAdV/KPDZewFXdaaa6K7lxmZBZ8FBNpCiAT6iHPmd6QO9bKfQ==",
341+ "dependencies": {
342+ "regenerator-runtime": "^0.13.4"
343+ },
344+ "engines": {
345+ "node": ">=6.9.0"
346+ }
347+ },
348+ "node_modules/@babel/template": {
349+ "version": "7.18.6",
350+ "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.18.6.tgz",
351+ "integrity": "sha512-JoDWzPe+wgBsTTgdnIma3iHNFC7YVJoPssVBDjiHfNlyt4YcunDtcDOUmfVDfCK5MfdsaIoX9PkijPhjH3nYUw==",
352+ "dependencies": {
353+ "@babel/code-frame": "^7.18.6",
354+ "@babel/parser": "^7.18.6",
355+ "@babel/types": "^7.18.6"
356+ },
357+ "engines": {
358+ "node": ">=6.9.0"
359+ }
360+ },
361+ "node_modules/@babel/traverse": {
362+ "version": "7.18.6",
363+ "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.18.6.tgz",
364+ "integrity": "sha512-zS/OKyqmD7lslOtFqbscH6gMLFYOfG1YPqCKfAW5KrTeolKqvB8UelR49Fpr6y93kYkW2Ik00mT1LOGiAGvizw==",
365+ "dependencies": {
366+ "@babel/code-frame": "^7.18.6",
367+ "@babel/generator": "^7.18.6",
368+ "@babel/helper-environment-visitor": "^7.18.6",
369+ "@babel/helper-function-name": "^7.18.6",
370+ "@babel/helper-hoist-variables": "^7.18.6",
371+ "@babel/helper-split-export-declaration": "^7.18.6",
372+ "@babel/parser": "^7.18.6",
373+ "@babel/types": "^7.18.6",
374+ "debug": "^4.1.0",
375+ "globals": "^11.1.0"
376+ },
377+ "engines": {
378+ "node": ">=6.9.0"
379+ }
380+ },
381+ "node_modules/@babel/types": {
382+ "version": "7.18.7",
383+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.18.7.tgz",
384+ "integrity": "sha512-QG3yxTcTIBoAcQmkCs+wAPYZhu7Dk9rXKacINfNbdJDNERTbLQbHGyVG8q/YGMPeCJRIhSY0+fTc5+xuh6WPSQ==",
385+ "dependencies": {
386+ "@babel/helper-validator-identifier": "^7.18.6",
387+ "to-fast-properties": "^2.0.0"
388+ },
389+ "engines": {
390+ "node": ">=6.9.0"
391+ }
392+ },
393+ "node_modules/@emotion/babel-plugin": {
394+ "version": "11.9.2",
395+ "resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.9.2.tgz",
396+ "integrity": "sha512-Pr/7HGH6H6yKgnVFNEj2MVlreu3ADqftqjqwUvDy/OJzKFgxKeTQ+eeUf20FOTuHVkDON2iNa25rAXVYtWJCjw==",
397+ "dependencies": {
398+ "@babel/helper-module-imports": "^7.12.13",
399+ "@babel/plugin-syntax-jsx": "^7.12.13",
400+ "@babel/runtime": "^7.13.10",
401+ "@emotion/hash": "^0.8.0",
402+ "@emotion/memoize": "^0.7.5",
403+ "@emotion/serialize": "^1.0.2",
404+ "babel-plugin-macros": "^2.6.1",
405+ "convert-source-map": "^1.5.0",
406+ "escape-string-regexp": "^4.0.0",
407+ "find-root": "^1.1.0",
408+ "source-map": "^0.5.7",
409+ "stylis": "4.0.13"
410+ },
411+ "peerDependencies": {
412+ "@babel/core": "^7.0.0"
413+ }
414+ },
415+ "node_modules/@emotion/babel-plugin/node_modules/escape-string-regexp": {
416+ "version": "4.0.0",
417+ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
418+ "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
419+ "engines": {
420+ "node": ">=10"
421+ },
422+ "funding": {
423+ "url": "https://github.com/sponsors/sindresorhus"
424+ }
425+ },
426+ "node_modules/@emotion/cache": {
427+ "version": "11.9.3",
428+ "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.9.3.tgz",
429+ "integrity": "sha512-0dgkI/JKlCXa+lEXviaMtGBL0ynpx4osh7rjOXE71q9bIF8G+XhJgvi+wDu0B0IdCVx37BffiwXlN9I3UuzFvg==",
430+ "dependencies": {
431+ "@emotion/memoize": "^0.7.4",
432+ "@emotion/sheet": "^1.1.1",
433+ "@emotion/utils": "^1.0.0",
434+ "@emotion/weak-memoize": "^0.2.5",
435+ "stylis": "4.0.13"
436+ }
437+ },
438+ "node_modules/@emotion/hash": {
439+ "version": "0.8.0",
440+ "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.8.0.tgz",
441+ "integrity": "sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow=="
442+ },
443+ "node_modules/@emotion/memoize": {
444+ "version": "0.7.5",
445+ "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.7.5.tgz",
446+ "integrity": "sha512-igX9a37DR2ZPGYtV6suZ6whr8pTFtyHL3K/oLUotxpSVO2ASaprmAe2Dkq7tBo7CRY7MMDrAa9nuQP9/YG8FxQ=="
447+ },
448+ "node_modules/@emotion/react": {
449+ "version": "11.9.3",
450+ "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.9.3.tgz",
451+ "integrity": "sha512-g9Q1GcTOlzOEjqwuLF/Zd9LC+4FljjPjDfxSM7KmEakm+hsHXk+bYZ2q+/hTJzr0OUNkujo72pXLQvXj6H+GJQ==",
452+ "dependencies": {
453+ "@babel/runtime": "^7.13.10",
454+ "@emotion/babel-plugin": "^11.7.1",
455+ "@emotion/cache": "^11.9.3",
456+ "@emotion/serialize": "^1.0.4",
457+ "@emotion/utils": "^1.1.0",
458+ "@emotion/weak-memoize": "^0.2.5",
459+ "hoist-non-react-statics": "^3.3.1"
460+ },
461+ "peerDependencies": {
462+ "@babel/core": "^7.0.0",
463+ "react": ">=16.8.0"
464+ },
465+ "peerDependenciesMeta": {
466+ "@babel/core": {
467+ "optional": true
468+ },
469+ "@types/react": {
470+ "optional": true
471+ }
472+ }
473+ },
474+ "node_modules/@emotion/serialize": {
475+ "version": "1.0.4",
476+ "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.0.4.tgz",
477+ "integrity": "sha512-1JHamSpH8PIfFwAMryO2bNka+y8+KA5yga5Ocf2d7ZEiJjb7xlLW7aknBGZqJLajuLOvJ+72vN+IBSwPlXD1Pg==",
478+ "dependencies": {
479+ "@emotion/hash": "^0.8.0",
480+ "@emotion/memoize": "^0.7.4",
481+ "@emotion/unitless": "^0.7.5",
482+ "@emotion/utils": "^1.0.0",
483+ "csstype": "^3.0.2"
484+ }
485+ },
486+ "node_modules/@emotion/sheet": {
487+ "version": "1.1.1",
488+ "resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.1.1.tgz",
489+ "integrity": "sha512-J3YPccVRMiTZxYAY0IOq3kd+hUP8idY8Kz6B/Cyo+JuXq52Ek+zbPbSQUrVQp95aJ+lsAW7DPL1P2Z+U1jGkKA=="
490+ },
491+ "node_modules/@emotion/unitless": {
492+ "version": "0.7.5",
493+ "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.7.5.tgz",
494+ "integrity": "sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg=="
495+ },
496+ "node_modules/@emotion/utils": {
497+ "version": "1.1.0",
498+ "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.1.0.tgz",
499+ "integrity": "sha512-iRLa/Y4Rs5H/f2nimczYmS5kFJEbpiVvgN3XVfZ022IYhuNA1IRSHEizcof88LtCTXtl9S2Cxt32KgaXEu72JQ=="
500+ },
501+ "node_modules/@emotion/weak-memoize": {
502+ "version": "0.2.5",
503+ "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.2.5.tgz",
504+ "integrity": "sha512-6U71C2Wp7r5XtFtQzYrW5iKFT67OixrSxjI4MptCHzdSVlgabczzqLe0ZSgnub/5Kp4hSbpDB1tMytZY9pwxxA=="
505+ },
506+ "node_modules/@heroicons/react": {
507+ "version": "1.0.6",
508+ "resolved": "https://registry.npmjs.org/@heroicons/react/-/react-1.0.6.tgz",
509+ "integrity": "sha512-JJCXydOFWMDpCP4q13iEplA503MQO3xLoZiKum+955ZCtHINWnx26CUxVxxFQu/uLb4LW3ge15ZpzIkXKkJ8oQ==",
510+ "peerDependencies": {
511+ "react": ">= 16"
512+ }
513+ },
514+ "node_modules/@jridgewell/gen-mapping": {
515+ "version": "0.1.1",
516+ "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz",
517+ "integrity": "sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==",
518+ "dependencies": {
519+ "@jridgewell/set-array": "^1.0.0",
520+ "@jridgewell/sourcemap-codec": "^1.4.10"
521+ },
522+ "engines": {
523+ "node": ">=6.0.0"
524+ }
525+ },
526+ "node_modules/@jridgewell/resolve-uri": {
527+ "version": "3.0.8",
528+ "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.0.8.tgz",
529+ "integrity": "sha512-YK5G9LaddzGbcucK4c8h5tWFmMPBvRZ/uyWmN1/SbBdIvqGUdWGkJ5BAaccgs6XbzVLsqbPJrBSFwKv3kT9i7w==",
530+ "engines": {
531+ "node": ">=6.0.0"
532+ }
533+ },
534+ "node_modules/@jridgewell/set-array": {
535+ "version": "1.1.2",
536+ "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz",
537+ "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==",
538+ "engines": {
539+ "node": ">=6.0.0"
540+ }
541+ },
542+ "node_modules/@jridgewell/sourcemap-codec": {
543+ "version": "1.4.14",
544+ "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz",
545+ "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw=="
546+ },
547+ "node_modules/@jridgewell/trace-mapping": {
548+ "version": "0.3.14",
549+ "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.14.tgz",
550+ "integrity": "sha512-bJWEfQ9lPTvm3SneWwRFVLzrh6nhjwqw7TUFFBEMzwvg7t7PCDenf2lDwqo4NQXzdpgBXyFgDWnQA+2vkruksQ==",
551+ "dependencies": {
552+ "@jridgewell/resolve-uri": "^3.0.3",
553+ "@jridgewell/sourcemap-codec": "^1.4.10"
554+ }
555+ },
556+ "node_modules/@microsoft/fetch-event-source": {
557+ "version": "2.0.1",
558+ "resolved": "https://registry.npmjs.org/@microsoft/fetch-event-source/-/fetch-event-source-2.0.1.tgz",
559+ "integrity": "sha512-W6CLUJ2eBMw3Rec70qrsEW0jOm/3twwJv21mrmj2yORiaVmVYGS4sSS5yUwvQc1ZlDLYGPnClVWmUUMagKNsfA=="
560+ },
561+ "node_modules/@nodelib/fs.scandir": {
562+ "version": "2.1.5",
563+ "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
564+ "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==",
565+ "dev": true,
566+ "dependencies": {
567+ "@nodelib/fs.stat": "2.0.5",
568+ "run-parallel": "^1.1.9"
569+ },
570+ "engines": {
571+ "node": ">= 8"
572+ }
573+ },
574+ "node_modules/@nodelib/fs.stat": {
575+ "version": "2.0.5",
576+ "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz",
577+ "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==",
578+ "dev": true,
579+ "engines": {
580+ "node": ">= 8"
581+ }
582+ },
583+ "node_modules/@nodelib/fs.walk": {
584+ "version": "1.2.8",
585+ "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz",
586+ "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==",
587+ "dev": true,
588+ "dependencies": {
589+ "@nodelib/fs.scandir": "2.1.5",
590+ "fastq": "^1.6.0"
591+ },
592+ "engines": {
593+ "node": ">= 8"
594+ }
595+ },
596+ "node_modules/@radix-ui/number": {
597+ "version": "0.1.0",
598+ "resolved": "https://registry.npmjs.org/@radix-ui/number/-/number-0.1.0.tgz",
599+ "integrity": "sha512-rpf6QiOWLHAkM4FEMYu9i+5Jr8cKT893+R4mPpcdsy4LD7omr9JfdOqj/h/xPA5+EcVrpMMlU6rrRYpUB5UI8g==",
600+ "dependencies": {
601+ "@babel/runtime": "^7.13.10"
602+ }
603+ },
604+ "node_modules/@radix-ui/popper": {
605+ "version": "0.1.0",
606+ "resolved": "https://registry.npmjs.org/@radix-ui/popper/-/popper-0.1.0.tgz",
607+ "integrity": "sha512-uzYeElL3w7SeNMuQpXiFlBhTT+JyaNMCwDfjKkrzugEcYrf5n52PHqncNdQPUtR42hJh8V9FsqyEDbDxkeNjJQ==",
608+ "dependencies": {
609+ "@babel/runtime": "^7.13.10",
610+ "csstype": "^3.0.4"
611+ }
612+ },
613+ "node_modules/@radix-ui/primitive": {
614+ "version": "0.1.0",
615+ "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-0.1.0.tgz",
616+ "integrity": "sha512-tqxZKybwN5Fa3VzZry4G6mXAAb9aAqKmPtnVbZpL0vsBwvOHTBwsjHVPXylocYLwEtBY9SCe665bYnNB515uoA==",
617+ "dependencies": {
618+ "@babel/runtime": "^7.13.10"
619+ }
620+ },
621+ "node_modules/@radix-ui/react-arrow": {
622+ "version": "0.1.4",
623+ "resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-0.1.4.tgz",
624+ "integrity": "sha512-BB6XzAb7Ml7+wwpFdYVtZpK1BlMgqyafSQNGzhIpSZ4uXvXOHPlR5GP8M449JkeQzgQjv9Mp1AsJxFC0KuOtuA==",
625+ "dependencies": {
626+ "@babel/runtime": "^7.13.10",
627+ "@radix-ui/react-primitive": "0.1.4"
628+ },
629+ "peerDependencies": {
630+ "react": "^16.8 || ^17.0"
631+ }
632+ },
633+ "node_modules/@radix-ui/react-collection": {
634+ "version": "0.1.4",
635+ "resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-0.1.4.tgz",
636+ "integrity": "sha512-3muGI15IdgaDFjOcO7xX8a35HQRBRF6LH9pS6UCeZeRmbslkVeHyJRQr2rzICBUoX7zgIA0kXyMDbpQnJGyJTA==",
637+ "dependencies": {
638+ "@babel/runtime": "^7.13.10",
639+ "@radix-ui/react-compose-refs": "0.1.0",
640+ "@radix-ui/react-context": "0.1.1",
641+ "@radix-ui/react-primitive": "0.1.4",
642+ "@radix-ui/react-slot": "0.1.2"
643+ },
644+ "peerDependencies": {
645+ "react": "^16.8 || ^17.0"
646+ }
647+ },
648+ "node_modules/@radix-ui/react-compose-refs": {
649+ "version": "0.1.0",
650+ "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-0.1.0.tgz",
651+ "integrity": "sha512-eyclbh+b77k+69Dk72q3694OHrn9B3QsoIRx7ywX341U9RK1ThgQjMFZoPtmZNQTksXHLNEiefR8hGVeFyInGg==",
652+ "dependencies": {
653+ "@babel/runtime": "^7.13.10"
654+ },
655+ "peerDependencies": {
656+ "react": "^16.8 || ^17.0"
657+ }
658+ },
659+ "node_modules/@radix-ui/react-context": {
660+ "version": "0.1.1",
661+ "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-0.1.1.tgz",
662+ "integrity": "sha512-PkyVX1JsLBioeu0jB9WvRpDBBLtLZohVDT3BB5CTSJqActma8S8030P57mWZb4baZifMvN7KKWPAA40UmWKkQg==",
663+ "dependencies": {
664+ "@babel/runtime": "^7.13.10"
665+ },
666+ "peerDependencies": {
667+ "react": "^16.8 || ^17.0"
668+ }
669+ },
670+ "node_modules/@radix-ui/react-dismissable-layer": {
671+ "version": "0.1.5",
672+ "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-0.1.5.tgz",
673+ "integrity": "sha512-J+fYWijkX4M4QKwf9dtu1oC0U6e6CEl8WhBp3Ad23yz2Hia0XCo6Pk/mp5CAFy4QBtQedTSkhW05AdtSOEoajQ==",
674+ "dependencies": {
675+ "@babel/runtime": "^7.13.10",
676+ "@radix-ui/primitive": "0.1.0",
677+ "@radix-ui/react-compose-refs": "0.1.0",
678+ "@radix-ui/react-primitive": "0.1.4",
679+ "@radix-ui/react-use-body-pointer-events": "0.1.1",
680+ "@radix-ui/react-use-callback-ref": "0.1.0",
681+ "@radix-ui/react-use-escape-keydown": "0.1.0"
682+ },
683+ "peerDependencies": {
684+ "react": "^16.8 || ^17.0"
685+ }
686+ },
687+ "node_modules/@radix-ui/react-dropdown-menu": {
688+ "version": "0.1.6",
689+ "resolved": "https://registry.npmjs.org/@radix-ui/react-dropdown-menu/-/react-dropdown-menu-0.1.6.tgz",
690+ "integrity": "sha512-RZhtzjWwJ4ZBN7D8ek4Zn+ilHzYuYta9yIxFnbC0pfqMnSi67IQNONo1tuuNqtFh9SRHacPKc65zo+kBBlxtdg==",
691+ "dependencies": {
692+ "@babel/runtime": "^7.13.10",
693+ "@radix-ui/primitive": "0.1.0",
694+ "@radix-ui/react-compose-refs": "0.1.0",
695+ "@radix-ui/react-context": "0.1.1",
696+ "@radix-ui/react-id": "0.1.5",
697+ "@radix-ui/react-menu": "0.1.6",
698+ "@radix-ui/react-primitive": "0.1.4",
699+ "@radix-ui/react-use-controllable-state": "0.1.0"
700+ },
701+ "peerDependencies": {
702+ "react": "^16.8 || ^17.0",
703+ "react-dom": "^16.8 || ^17.0"
704+ }
705+ },
706+ "node_modules/@radix-ui/react-focus-guards": {
707+ "version": "0.1.0",
708+ "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-guards/-/react-focus-guards-0.1.0.tgz",
709+ "integrity": "sha512-kRx/swAjEfBpQ3ns7J3H4uxpXuWCqN7MpALiSDOXiyo2vkWv0L9sxvbpZeTulINuE3CGMzicVMuNc/VWXjFKOg==",
710+ "dependencies": {
711+ "@babel/runtime": "^7.13.10"
712+ },
713+ "peerDependencies": {
714+ "react": "^16.8 || ^17.0"
715+ }
716+ },
717+ "node_modules/@radix-ui/react-focus-scope": {
718+ "version": "0.1.4",
719+ "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-0.1.4.tgz",
720+ "integrity": "sha512-fbA4ES3H4Wkxp+OeLhvN6SwL7mXNn/aBtUf7DRYxY9+Akrf7dRxl2ck4lgcpPsSg3zSDsEwLcY+h5cmj5yvlug==",
721+ "dependencies": {
722+ "@babel/runtime": "^7.13.10",
723+ "@radix-ui/react-compose-refs": "0.1.0",
724+ "@radix-ui/react-primitive": "0.1.4",
725+ "@radix-ui/react-use-callback-ref": "0.1.0"
726+ },
727+ "peerDependencies": {
728+ "react": "^16.8 || ^17.0"
729+ }
730+ },
731+ "node_modules/@radix-ui/react-id": {
732+ "version": "0.1.5",
733+ "resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-0.1.5.tgz",
734+ "integrity": "sha512-IPc4H/63bes0IZ1GJJozSEkSWcDyhNGtKFWUpJ+XtaLyQ1X3x7Mf6fWwWhDcpqlYEP+5WtAvfqcyEsyjP+ZhBQ==",
735+ "dependencies": {
736+ "@babel/runtime": "^7.13.10",
737+ "@radix-ui/react-use-layout-effect": "0.1.0"
738+ },
739+ "peerDependencies": {
740+ "react": "^16.8 || ^17.0"
741+ }
742+ },
743+ "node_modules/@radix-ui/react-label": {
744+ "version": "0.1.5",
745+ "resolved": "https://registry.npmjs.org/@radix-ui/react-label/-/react-label-0.1.5.tgz",
746+ "integrity": "sha512-Au9+n4/DhvjR0IHhvZ1LPdx/OW+3CGDie30ZyCkbSHIuLp4/CV4oPPGBwJ1vY99Jog3zyQhsGww9MXj8O9Aj/A==",
747+ "dependencies": {
748+ "@babel/runtime": "^7.13.10",
749+ "@radix-ui/react-compose-refs": "0.1.0",
750+ "@radix-ui/react-context": "0.1.1",
751+ "@radix-ui/react-id": "0.1.5",
752+ "@radix-ui/react-primitive": "0.1.4"
753+ },
754+ "peerDependencies": {
755+ "react": "^16.8 || ^17.0"
756+ }
757+ },
758+ "node_modules/@radix-ui/react-menu": {
759+ "version": "0.1.6",
760+ "resolved": "https://registry.npmjs.org/@radix-ui/react-menu/-/react-menu-0.1.6.tgz",
761+ "integrity": "sha512-ho3+bhpr3oAFkOBJ8VkUb1BcGoiZBB3OmcWPqa6i5RTUKrzNX/d6rauochu2xDlWjiRtpVuiAcsTVOeIC4FbYQ==",
762+ "dependencies": {
763+ "@babel/runtime": "^7.13.10",
764+ "@radix-ui/primitive": "0.1.0",
765+ "@radix-ui/react-collection": "0.1.4",
766+ "@radix-ui/react-compose-refs": "0.1.0",
767+ "@radix-ui/react-context": "0.1.1",
768+ "@radix-ui/react-dismissable-layer": "0.1.5",
769+ "@radix-ui/react-focus-guards": "0.1.0",
770+ "@radix-ui/react-focus-scope": "0.1.4",
771+ "@radix-ui/react-id": "0.1.5",
772+ "@radix-ui/react-popper": "0.1.4",
773+ "@radix-ui/react-portal": "0.1.4",
774+ "@radix-ui/react-presence": "0.1.2",
775+ "@radix-ui/react-primitive": "0.1.4",
776+ "@radix-ui/react-roving-focus": "0.1.5",
777+ "@radix-ui/react-use-callback-ref": "0.1.0",
778+ "@radix-ui/react-use-direction": "0.1.0",
779+ "aria-hidden": "^1.1.1",
780+ "react-remove-scroll": "^2.4.0"
781+ },
782+ "peerDependencies": {
783+ "react": "^16.8 || ^17.0",
784+ "react-dom": "^16.8 || ^17.0"
785+ }
786+ },
787+ "node_modules/@radix-ui/react-popper": {
788+ "version": "0.1.4",
789+ "resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-0.1.4.tgz",
790+ "integrity": "sha512-18gDYof97t8UQa7zwklG1Dr8jIdj3u+rVOQLzPi9f5i1YQak/pVGkaqw8aY+iDUknKKuZniTk/7jbAJUYlKyOw==",
791+ "dependencies": {
792+ "@babel/runtime": "^7.13.10",
793+ "@radix-ui/popper": "0.1.0",
794+ "@radix-ui/react-arrow": "0.1.4",
795+ "@radix-ui/react-compose-refs": "0.1.0",
796+ "@radix-ui/react-context": "0.1.1",
797+ "@radix-ui/react-primitive": "0.1.4",
798+ "@radix-ui/react-use-rect": "0.1.1",
799+ "@radix-ui/react-use-size": "0.1.1",
800+ "@radix-ui/rect": "0.1.1"
801+ },
802+ "peerDependencies": {
803+ "react": "^16.8 || ^17.0"
804+ }
805+ },
806+ "node_modules/@radix-ui/react-portal": {
807+ "version": "0.1.4",
808+ "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-0.1.4.tgz",
809+ "integrity": "sha512-MO0wRy2eYRTZ/CyOri9NANCAtAtq89DEtg90gicaTlkCfdqCLEBsLb+/q66BZQTr3xX/Vq01nnVfc/TkCqoqvw==",
810+ "dependencies": {
811+ "@babel/runtime": "^7.13.10",
812+ "@radix-ui/react-primitive": "0.1.4",
813+ "@radix-ui/react-use-layout-effect": "0.1.0"
814+ },
815+ "peerDependencies": {
816+ "react": "^16.8 || ^17.0",
817+ "react-dom": "^16.8 || ^17.0"
818+ }
819+ },
820+ "node_modules/@radix-ui/react-presence": {
821+ "version": "0.1.2",
822+ "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-0.1.2.tgz",
823+ "integrity": "sha512-3BRlFZraooIUfRlyN+b/Xs5hq1lanOOo/+3h6Pwu2GMFjkGKKa4Rd51fcqGqnVlbr3jYg+WLuGyAV4KlgqwrQw==",
824+ "dependencies": {
825+ "@babel/runtime": "^7.13.10",
826+ "@radix-ui/react-compose-refs": "0.1.0",
827+ "@radix-ui/react-use-layout-effect": "0.1.0"
828+ },
829+ "peerDependencies": {
830+ "react": ">=16.8"
831+ }
832+ },
833+ "node_modules/@radix-ui/react-primitive": {
834+ "version": "0.1.4",
835+ "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-0.1.4.tgz",
836+ "integrity": "sha512-6gSl2IidySupIMJFjYnDIkIWRyQdbu/AHK7rbICPani+LW4b0XdxBXc46og/iZvuwW8pjCS8I2SadIerv84xYA==",
837+ "dependencies": {
838+ "@babel/runtime": "^7.13.10",
839+ "@radix-ui/react-slot": "0.1.2"
840+ },
841+ "peerDependencies": {
842+ "react": "^16.8 || ^17.0"
843+ }
844+ },
845+ "node_modules/@radix-ui/react-roving-focus": {
846+ "version": "0.1.5",
847+ "resolved": "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-0.1.5.tgz",
848+ "integrity": "sha512-ClwKPS5JZE+PaHCoW7eu1onvE61pDv4kO8W4t5Ra3qMFQiTJLZMdpBQUhksN//DaVygoLirz4Samdr5Y1x1FSA==",
849+ "dependencies": {
850+ "@babel/runtime": "^7.13.10",
851+ "@radix-ui/primitive": "0.1.0",
852+ "@radix-ui/react-collection": "0.1.4",
853+ "@radix-ui/react-compose-refs": "0.1.0",
854+ "@radix-ui/react-context": "0.1.1",
855+ "@radix-ui/react-id": "0.1.5",
856+ "@radix-ui/react-primitive": "0.1.4",
857+ "@radix-ui/react-use-callback-ref": "0.1.0",
858+ "@radix-ui/react-use-controllable-state": "0.1.0"
859+ },
860+ "peerDependencies": {
861+ "react": "^16.8 || ^17.0"
862+ }
863+ },
864+ "node_modules/@radix-ui/react-select": {
865+ "version": "0.1.1",
866+ "resolved": "https://registry.npmjs.org/@radix-ui/react-select/-/react-select-0.1.1.tgz",
867+ "integrity": "sha512-xY3jLz2c6ZBHflldGsA79bE/swUfRMpiRPQf+JDihOufsd3z5uW22PFe0MS5bGZiIpK6aAZAvwqEd2Bu7hqp8w==",
868+ "dependencies": {
869+ "@babel/runtime": "^7.13.10",
870+ "@radix-ui/number": "0.1.0",
871+ "@radix-ui/primitive": "0.1.0",
872+ "@radix-ui/react-collection": "0.1.4",
873+ "@radix-ui/react-compose-refs": "0.1.0",
874+ "@radix-ui/react-context": "0.1.1",
875+ "@radix-ui/react-dismissable-layer": "0.1.5",
876+ "@radix-ui/react-focus-scope": "0.1.4",
877+ "@radix-ui/react-id": "0.1.5",
878+ "@radix-ui/react-label": "0.1.5",
879+ "@radix-ui/react-portal": "0.1.4",
880+ "@radix-ui/react-primitive": "0.1.4",
881+ "@radix-ui/react-use-callback-ref": "0.1.0",
882+ "@radix-ui/react-use-controllable-state": "0.1.0",
883+ "@radix-ui/react-use-layout-effect": "0.1.0",
884+ "@radix-ui/react-use-previous": "0.1.1",
885+ "@radix-ui/react-visually-hidden": "0.1.4",
886+ "aria-hidden": "^1.1.1",
887+ "react-remove-scroll": "^2.4.0"
888+ },
889+ "peerDependencies": {
890+ "react": "^16.8 || ^17.0",
891+ "react-dom": "^16.8 || ^17.0"
892+ }
893+ },
894+ "node_modules/@radix-ui/react-slot": {
895+ "version": "0.1.2",
896+ "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-0.1.2.tgz",
897+ "integrity": "sha512-ADkqfL+agEzEguU3yS26jfB50hRrwf7U4VTwAOZEmi/g+ITcBWe12yM46ueS/UCIMI9Py+gFUaAdxgxafFvY2Q==",
898+ "dependencies": {
899+ "@babel/runtime": "^7.13.10",
900+ "@radix-ui/react-compose-refs": "0.1.0"
901+ },
902+ "peerDependencies": {
903+ "react": "^16.8 || ^17.0"
904+ }
905+ },
906+ "node_modules/@radix-ui/react-toggle": {
907+ "version": "0.1.4",
908+ "resolved": "https://registry.npmjs.org/@radix-ui/react-toggle/-/react-toggle-0.1.4.tgz",
909+ "integrity": "sha512-gxUq6NgMc4ChV8VJnwdYqueeoblspwXHAexYo+jM9N2hFLbI1C587jLjdTHzIcUa9q68Xaw4jtiImWDOokEhRw==",
910+ "dependencies": {
911+ "@babel/runtime": "^7.13.10",
912+ "@radix-ui/primitive": "0.1.0",
913+ "@radix-ui/react-primitive": "0.1.4",
914+ "@radix-ui/react-use-controllable-state": "0.1.0"
915+ },
916+ "peerDependencies": {
917+ "react": "^16.8 || ^17.0"
918+ }
919+ },
920+ "node_modules/@radix-ui/react-toggle-group": {
921+ "version": "0.1.5",
922+ "resolved": "https://registry.npmjs.org/@radix-ui/react-toggle-group/-/react-toggle-group-0.1.5.tgz",
923+ "integrity": "sha512-Yp14wFiqe00azF+sG5CCJz4JGOP/f5Jj+CxLlZCmMpG5qhVTWeaeG4YH6pvX4KL41fS8x9FAaLb8wW9y01o67g==",
924+ "dependencies": {
925+ "@babel/runtime": "^7.13.10",
926+ "@radix-ui/primitive": "0.1.0",
927+ "@radix-ui/react-context": "0.1.1",
928+ "@radix-ui/react-primitive": "0.1.4",
929+ "@radix-ui/react-roving-focus": "0.1.5",
930+ "@radix-ui/react-toggle": "0.1.4",
931+ "@radix-ui/react-use-controllable-state": "0.1.0"
932+ },
933+ "peerDependencies": {
934+ "react": "^16.8 || ^17.0"
935+ }
936+ },
937+ "node_modules/@radix-ui/react-use-body-pointer-events": {
938+ "version": "0.1.1",
939+ "resolved": "https://registry.npmjs.org/@radix-ui/react-use-body-pointer-events/-/react-use-body-pointer-events-0.1.1.tgz",
940+ "integrity": "sha512-R8leV2AWmJokTmERM8cMXFHWSiv/fzOLhG/JLmRBhLTAzOj37EQizssq4oW0Z29VcZy2tODMi9Pk/htxwb+xpA==",
941+ "dependencies": {
942+ "@babel/runtime": "^7.13.10",
943+ "@radix-ui/react-use-layout-effect": "0.1.0"
944+ },
945+ "peerDependencies": {
946+ "react": "^16.8 || ^17.0"
947+ }
948+ },
949+ "node_modules/@radix-ui/react-use-callback-ref": {
950+ "version": "0.1.0",
951+ "resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-0.1.0.tgz",
952+ "integrity": "sha512-Va041McOFFl+aV+sejvl0BS2aeHx86ND9X/rVFmEFQKTXCp6xgUK0NGUAGcgBlIjnJSbMYPGEk1xKSSlVcN2Aw==",
953+ "dependencies": {
954+ "@babel/runtime": "^7.13.10"
955+ },
956+ "peerDependencies": {
957+ "react": "^16.8 || ^17.0"
958+ }
959+ },
960+ "node_modules/@radix-ui/react-use-controllable-state": {
961+ "version": "0.1.0",
962+ "resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-0.1.0.tgz",
963+ "integrity": "sha512-zv7CX/PgsRl46a52Tl45TwqwVJdmqnlQEQhaYMz/yBOD2sx2gCkCFSoF/z9mpnYWmS6DTLNTg5lIps3fV6EnXg==",
964+ "dependencies": {
965+ "@babel/runtime": "^7.13.10",
966+ "@radix-ui/react-use-callback-ref": "0.1.0"
967+ },
968+ "peerDependencies": {
969+ "react": "^16.8 || ^17.0"
970+ }
971+ },
972+ "node_modules/@radix-ui/react-use-direction": {
973+ "version": "0.1.0",
974+ "resolved": "https://registry.npmjs.org/@radix-ui/react-use-direction/-/react-use-direction-0.1.0.tgz",
975+ "integrity": "sha512-NajpY/An9TCPSfOVkgWIdXJV+VuWl67PxB6kOKYmtNAFHvObzIoh8o0n9sAuwSAyFCZVq211FEf9gvVDRhOyiA==",
976+ "dependencies": {
977+ "@babel/runtime": "^7.13.10"
978+ },
979+ "peerDependencies": {
980+ "react": "^16.8 || ^17.0"
981+ }
982+ },
983+ "node_modules/@radix-ui/react-use-escape-keydown": {
984+ "version": "0.1.0",
985+ "resolved": "https://registry.npmjs.org/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-0.1.0.tgz",
986+ "integrity": "sha512-tDLZbTGFmvXaazUXXv8kYbiCcbAE8yKgng9s95d8fCO+Eundv0Jngbn/hKPhDDs4jj9ChwRX5cDDnlaN+ugYYQ==",
987+ "dependencies": {
988+ "@babel/runtime": "^7.13.10",
989+ "@radix-ui/react-use-callback-ref": "0.1.0"
990+ },
991+ "peerDependencies": {
992+ "react": "^16.8 || ^17.0"
993+ }
994+ },
995+ "node_modules/@radix-ui/react-use-layout-effect": {
996+ "version": "0.1.0",
997+ "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-0.1.0.tgz",
998+ "integrity": "sha512-+wdeS51Y+E1q1Wmd+1xSSbesZkpVj4jsg0BojCbopWvgq5iBvixw5vgemscdh58ep98BwUbsFYnrywFhV9yrVg==",
999+ "dependencies": {
1000+ "@babel/runtime": "^7.13.10"
1001+ },
1002+ "peerDependencies": {
1003+ "react": "^16.8 || ^17.0"
1004+ }
1005+ },
1006+ "node_modules/@radix-ui/react-use-previous": {
1007+ "version": "0.1.1",
1008+ "resolved": "https://registry.npmjs.org/@radix-ui/react-use-previous/-/react-use-previous-0.1.1.tgz",
1009+ "integrity": "sha512-O/ZgrDBr11dR8rhO59ED8s5zIXBRFi8MiS+CmFGfi7MJYdLbfqVOmQU90Ghf87aifEgWe6380LA69KBneaShAg==",
1010+ "dependencies": {
1011+ "@babel/runtime": "^7.13.10"
1012+ },
1013+ "peerDependencies": {
1014+ "react": "^16.8 || ^17.0"
1015+ }
1016+ },
1017+ "node_modules/@radix-ui/react-use-rect": {
1018+ "version": "0.1.1",
1019+ "resolved": "https://registry.npmjs.org/@radix-ui/react-use-rect/-/react-use-rect-0.1.1.tgz",
1020+ "integrity": "sha512-kHNNXAsP3/PeszEmM/nxBBS9Jbo93sO+xuMTcRfwzXsmxT5gDXQzAiKbZQ0EecCPtJIzqvr7dlaQi/aP1PKYqQ==",
1021+ "dependencies": {
1022+ "@babel/runtime": "^7.13.10",
1023+ "@radix-ui/rect": "0.1.1"
1024+ },
1025+ "peerDependencies": {
1026+ "react": "^16.8 || ^17.0"
1027+ }
1028+ },
1029+ "node_modules/@radix-ui/react-use-size": {
1030+ "version": "0.1.1",
1031+ "resolved": "https://registry.npmjs.org/@radix-ui/react-use-size/-/react-use-size-0.1.1.tgz",
1032+ "integrity": "sha512-pTgWM5qKBu6C7kfKxrKPoBI2zZYZmp2cSXzpUiGM3qEBQlMLtYhaY2JXdXUCxz+XmD1YEjc8oRwvyfsD4AG4WA==",
1033+ "dependencies": {
1034+ "@babel/runtime": "^7.13.10"
1035+ },
1036+ "peerDependencies": {
1037+ "react": "^16.8 || ^17.0"
1038+ }
1039+ },
1040+ "node_modules/@radix-ui/react-visually-hidden": {
1041+ "version": "0.1.4",
1042+ "resolved": "https://registry.npmjs.org/@radix-ui/react-visually-hidden/-/react-visually-hidden-0.1.4.tgz",
1043+ "integrity": "sha512-K/q6AEEzqeeEq/T0NPChvBqnwlp8Tl4NnQdrI/y8IOY7BRR+Ug0PEsVk6g48HJ7cA1//COugdxXXVVK/m0X1mA==",
1044+ "dependencies": {
1045+ "@babel/runtime": "^7.13.10",
1046+ "@radix-ui/react-primitive": "0.1.4"
1047+ },
1048+ "peerDependencies": {
1049+ "react": "^16.8 || ^17.0"
1050+ }
1051+ },
1052+ "node_modules/@radix-ui/rect": {
1053+ "version": "0.1.1",
1054+ "resolved": "https://registry.npmjs.org/@radix-ui/rect/-/rect-0.1.1.tgz",
1055+ "integrity": "sha512-g3hnE/UcOg7REdewduRPAK88EPuLZtaq7sA9ouu8S+YEtnyFRI16jgv6GZYe3VMoQLL1T171ebmEPtDjyxWLzw==",
1056+ "dependencies": {
1057+ "@babel/runtime": "^7.13.10"
1058+ }
1059+ },
1060+ "node_modules/@rollup/pluginutils": {
1061+ "version": "4.2.1",
1062+ "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-4.2.1.tgz",
1063+ "integrity": "sha512-iKnFXr7NkdZAIHiIWE+BX5ULi/ucVFYWD6TbAV+rZctiRTY2PL6tsIKhoIOaoskiWAkgu+VsbXgUVDNLHf+InQ==",
1064+ "dev": true,
1065+ "dependencies": {
1066+ "estree-walker": "^2.0.1",
1067+ "picomatch": "^2.2.2"
1068+ },
1069+ "engines": {
1070+ "node": ">= 8.0.0"
1071+ }
1072+ },
1073+ "node_modules/@tanstack/query-core": {
1074+ "version": "4.29.5",
1075+ "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-4.29.5.tgz",
1076+ "integrity": "sha512-xXIiyQ/4r9KfaJ3k6kejqcaqFXXBTzN2aOJ5H1J6aTJE9hl/nbgAdfF6oiIu0CD5xowejJEJ6bBg8TO7BN4NuQ==",
1077+ "funding": {
1078+ "type": "github",
1079+ "url": "https://github.com/sponsors/tannerlinsley"
1080+ }
1081+ },
1082+ "node_modules/@tanstack/react-query": {
1083+ "version": "4.29.5",
1084+ "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-4.29.5.tgz",
1085+ "integrity": "sha512-F87cibC3s3eG0Q90g2O+hqntpCrudKFnR8P24qkH9uccEhXErnJxBC/AAI4cJRV2bfMO8IeGZQYf3WyYgmSg0w==",
1086+ "dependencies": {
1087+ "@tanstack/query-core": "4.29.5",
1088+ "use-sync-external-store": "^1.2.0"
1089+ },
1090+ "funding": {
1091+ "type": "github",
1092+ "url": "https://github.com/sponsors/tannerlinsley"
1093+ },
1094+ "peerDependencies": {
1095+ "react": "^16.8.0 || ^17.0.0 || ^18.0.0",
1096+ "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0",
1097+ "react-native": "*"
1098+ },
1099+ "peerDependenciesMeta": {
1100+ "react-dom": {
1101+ "optional": true
1102+ },
1103+ "react-native": {
1104+ "optional": true
1105+ }
1106+ }
1107+ },
1108+ "node_modules/@tanstack/react-query/node_modules/use-sync-external-store": {
1109+ "version": "1.2.0",
1110+ "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz",
1111+ "integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==",
1112+ "peerDependencies": {
1113+ "react": "^16.8.0 || ^17.0.0 || ^18.0.0"
1114+ }
1115+ },
1116+ "node_modules/@types/lodash": {
1117+ "version": "4.14.182",
1118+ "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.182.tgz",
1119+ "integrity": "sha512-/THyiqyQAP9AfARo4pF+aCGcyiQ94tX/Is2I7HofNRqoYLgN1PBoOWu2/zTA5zMxzP5EFutMtWtGAFRKUe961Q==",
1120+ "dev": true
1121+ },
1122+ "node_modules/@types/lodash.debounce": {
1123+ "version": "4.0.7",
1124+ "resolved": "https://registry.npmjs.org/@types/lodash.debounce/-/lodash.debounce-4.0.7.tgz",
1125+ "integrity": "sha512-X1T4wMZ+gT000M2/91SYj0d/7JfeNZ9PeeOldSNoE/lunLeQXKvkmIumI29IaKMotU/ln/McOIvgzZcQ/3TrSA==",
1126+ "dev": true,
1127+ "dependencies": {
1128+ "@types/lodash": "*"
1129+ }
1130+ },
1131+ "node_modules/@types/parse-json": {
1132+ "version": "4.0.0",
1133+ "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz",
1134+ "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA=="
1135+ },
1136+ "node_modules/@types/prop-types": {
1137+ "version": "15.7.5",
1138+ "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz",
1139+ "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w=="
1140+ },
1141+ "node_modules/@types/react": {
1142+ "version": "17.0.47",
1143+ "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.47.tgz",
1144+ "integrity": "sha512-mk0BL8zBinf2ozNr3qPnlu1oyVTYq+4V7WA76RgxUAtf0Em/Wbid38KN6n4abEkvO4xMTBWmnP1FtQzgkEiJoA==",
1145+ "dependencies": {
1146+ "@types/prop-types": "*",
1147+ "@types/scheduler": "*",
1148+ "csstype": "^3.0.2"
1149+ }
1150+ },
1151+ "node_modules/@types/react-dom": {
1152+ "version": "17.0.17",
1153+ "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-17.0.17.tgz",
1154+ "integrity": "sha512-VjnqEmqGnasQKV0CWLevqMTXBYG9GbwuE6x3VetERLh0cq2LTptFE73MrQi2S7GkKXCf2GgwItB/melLnxfnsg==",
1155+ "dev": true,
1156+ "dependencies": {
1157+ "@types/react": "^17"
1158+ }
1159+ },
1160+ "node_modules/@types/react-transition-group": {
1161+ "version": "4.4.5",
1162+ "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.5.tgz",
1163+ "integrity": "sha512-juKD/eiSM3/xZYzjuzH6ZwpP+/lejltmiS3QEzV/vmb/Q8+HfDmxu+Baga8UEMGBqV88Nbg4l2hY/K2DkyaLLA==",
1164+ "dependencies": {
1165+ "@types/react": "*"
1166+ }
1167+ },
1168+ "node_modules/@types/scheduler": {
1169+ "version": "0.16.2",
1170+ "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz",
1171+ "integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew=="
1172+ },
1173+ "node_modules/@urbit/api": {
1174+ "version": "2.2.0",
1175+ "resolved": "https://registry.npmjs.org/@urbit/api/-/api-2.2.0.tgz",
1176+ "integrity": "sha512-W8kP9OT6yOK62n+4yCPO3i9QqU5xriLvZQ9WYW4SAV7ktbSrGuf2kmYbnoqfA/NybIs9Q/MbFkPewrz4XJ96Ag==",
1177+ "dependencies": {
1178+ "@babel/runtime": "^7.16.0",
1179+ "big-integer": "^1.6.48",
1180+ "core-js": "^3.19.1",
1181+ "immer": "^9.0.1",
1182+ "urbit-ob": "^5.0.1"
1183+ }
1184+ },
1185+ "node_modules/@urbit/http-api": {
1186+ "version": "2.1.3",
1187+ "resolved": "https://registry.npmjs.org/@urbit/http-api/-/http-api-2.1.3.tgz",
1188+ "integrity": "sha512-/wL7kQ/b2m24+cJiQ/3bFoU4jq3Qbl9h+JCb3H/1yovhFSUI7RPUbV20ONhCPTryXch6CC5QbgCALStJYHvKJg==",
1189+ "dependencies": {
1190+ "@babel/runtime": "^7.12.5",
1191+ "@microsoft/fetch-event-source": "^2.0.0",
1192+ "browser-or-node": "^1.3.0",
1193+ "core-js": "^3.19.1"
1194+ }
1195+ },
1196+ "node_modules/@urbit/vite-plugin-urbit": {
1197+ "version": "0.8.0",
1198+ "resolved": "https://registry.npmjs.org/@urbit/vite-plugin-urbit/-/vite-plugin-urbit-0.8.0.tgz",
1199+ "integrity": "sha512-cx540xZBuHfzud/kOuYU4xPpsFcgE7mF0heac5uXVutDqjySvVXimEuZgBN23ULC7l60R/bAJ2jOWygBwWen4A==",
1200+ "dev": true,
1201+ "dependencies": {
1202+ "vite-plugin-html-config": "^1.0.6",
1203+ "vite-plugin-rewrite-all": "^0.1.2"
1204+ }
1205+ },
1206+ "node_modules/@vitejs/plugin-react-refresh": {
1207+ "version": "1.3.6",
1208+ "resolved": "https://registry.npmjs.org/@vitejs/plugin-react-refresh/-/plugin-react-refresh-1.3.6.tgz",
1209+ "integrity": "sha512-iNR/UqhUOmFFxiezt0em9CgmiJBdWR+5jGxB2FihaoJfqGt76kiwaKoVOJVU5NYcDWMdN06LbyN2VIGIoYdsEA==",
1210+ "deprecated": "This package has been deprecated in favor of @vitejs/plugin-react",
1211+ "dev": true,
1212+ "dependencies": {
1213+ "@babel/core": "^7.14.8",
1214+ "@babel/plugin-transform-react-jsx-self": "^7.14.5",
1215+ "@babel/plugin-transform-react-jsx-source": "^7.14.5",
1216+ "@rollup/pluginutils": "^4.1.1",
1217+ "react-refresh": "^0.10.0"
1218+ },
1219+ "engines": {
1220+ "node": ">=12.0.0"
1221+ }
1222+ },
1223+ "node_modules/acorn": {
1224+ "version": "7.4.1",
1225+ "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz",
1226+ "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==",
1227+ "dev": true,
1228+ "bin": {
1229+ "acorn": "bin/acorn"
1230+ },
1231+ "engines": {
1232+ "node": ">=0.4.0"
1233+ }
1234+ },
1235+ "node_modules/acorn-node": {
1236+ "version": "1.8.2",
1237+ "resolved": "https://registry.npmjs.org/acorn-node/-/acorn-node-1.8.2.tgz",
1238+ "integrity": "sha512-8mt+fslDufLYntIoPAaIMUe/lrbrehIiwmR3t2k9LljIzoigEPF27eLk2hy8zSGzmR/ogr7zbRKINMo1u0yh5A==",
1239+ "dev": true,
1240+ "dependencies": {
1241+ "acorn": "^7.0.0",
1242+ "acorn-walk": "^7.0.0",
1243+ "xtend": "^4.0.2"
1244+ }
1245+ },
1246+ "node_modules/acorn-walk": {
1247+ "version": "7.2.0",
1248+ "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz",
1249+ "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==",
1250+ "dev": true,
1251+ "engines": {
1252+ "node": ">=0.4.0"
1253+ }
1254+ },
1255+ "node_modules/ansi-styles": {
1256+ "version": "3.2.1",
1257+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
1258+ "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
1259+ "dependencies": {
1260+ "color-convert": "^1.9.0"
1261+ },
1262+ "engines": {
1263+ "node": ">=4"
1264+ }
1265+ },
1266+ "node_modules/anymatch": {
1267+ "version": "3.1.2",
1268+ "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz",
1269+ "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==",
1270+ "dev": true,
1271+ "dependencies": {
1272+ "normalize-path": "^3.0.0",
1273+ "picomatch": "^2.0.4"
1274+ },
1275+ "engines": {
1276+ "node": ">= 8"
1277+ }
1278+ },
1279+ "node_modules/arg": {
1280+ "version": "5.0.2",
1281+ "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz",
1282+ "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==",
1283+ "dev": true
1284+ },
1285+ "node_modules/aria-hidden": {
1286+ "version": "1.1.3",
1287+ "resolved": "https://registry.npmjs.org/aria-hidden/-/aria-hidden-1.1.3.tgz",
1288+ "integrity": "sha512-RhVWFtKH5BiGMycI72q2RAFMLQi8JP9bLuQXgR5a8Znp7P5KOIADSJeyfI8PCVxLEp067B2HbP5JIiI/PXIZeA==",
1289+ "dependencies": {
1290+ "tslib": "^1.0.0"
1291+ },
1292+ "engines": {
1293+ "node": ">=8.5.0"
1294+ }
1295+ },
1296+ "node_modules/autoprefixer": {
1297+ "version": "10.4.7",
1298+ "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.7.tgz",
1299+ "integrity": "sha512-ypHju4Y2Oav95SipEcCcI5J7CGPuvz8oat7sUtYj3ClK44bldfvtvcxK6IEK++7rqB7YchDGzweZIBG+SD0ZAA==",
1300+ "dev": true,
1301+ "funding": [
1302+ {
1303+ "type": "opencollective",
1304+ "url": "https://opencollective.com/postcss/"
1305+ },
1306+ {
1307+ "type": "tidelift",
1308+ "url": "https://tidelift.com/funding/github/npm/autoprefixer"
1309+ }
1310+ ],
1311+ "dependencies": {
1312+ "browserslist": "^4.20.3",
1313+ "caniuse-lite": "^1.0.30001335",
1314+ "fraction.js": "^4.2.0",
1315+ "normalize-range": "^0.1.2",
1316+ "picocolors": "^1.0.0",
1317+ "postcss-value-parser": "^4.2.0"
1318+ },
1319+ "bin": {
1320+ "autoprefixer": "bin/autoprefixer"
1321+ },
1322+ "engines": {
1323+ "node": "^10 || ^12 || >=14"
1324+ },
1325+ "peerDependencies": {
1326+ "postcss": "^8.1.0"
1327+ }
1328+ },
1329+ "node_modules/babel-plugin-macros": {
1330+ "version": "2.8.0",
1331+ "resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-2.8.0.tgz",
1332+ "integrity": "sha512-SEP5kJpfGYqYKpBrj5XU3ahw5p5GOHJ0U5ssOSQ/WBVdwkD2Dzlce95exQTs3jOVWPPKLBN2rlEWkCK7dSmLvg==",
1333+ "dependencies": {
1334+ "@babel/runtime": "^7.7.2",
1335+ "cosmiconfig": "^6.0.0",
1336+ "resolve": "^1.12.0"
1337+ }
1338+ },
1339+ "node_modules/big-integer": {
1340+ "version": "1.6.51",
1341+ "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.51.tgz",
1342+ "integrity": "sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg==",
1343+ "engines": {
1344+ "node": ">=0.6"
1345+ }
1346+ },
1347+ "node_modules/binary-extensions": {
1348+ "version": "2.2.0",
1349+ "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
1350+ "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==",
1351+ "dev": true,
1352+ "engines": {
1353+ "node": ">=8"
1354+ }
1355+ },
1356+ "node_modules/bn.js": {
1357+ "version": "4.12.0",
1358+ "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz",
1359+ "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA=="
1360+ },
1361+ "node_modules/braces": {
1362+ "version": "3.0.2",
1363+ "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
1364+ "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
1365+ "dev": true,
1366+ "dependencies": {
1367+ "fill-range": "^7.0.1"
1368+ },
1369+ "engines": {
1370+ "node": ">=8"
1371+ }
1372+ },
1373+ "node_modules/browser-or-node": {
1374+ "version": "1.3.0",
1375+ "resolved": "https://registry.npmjs.org/browser-or-node/-/browser-or-node-1.3.0.tgz",
1376+ "integrity": "sha512-0F2z/VSnLbmEeBcUrSuDH5l0HxTXdQQzLjkmBR4cYfvg1zJrKSlmIZFqyFR8oX0NrwPhy3c3HQ6i3OxMbew4Tg=="
1377+ },
1378+ "node_modules/browserslist": {
1379+ "version": "4.21.1",
1380+ "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.1.tgz",
1381+ "integrity": "sha512-Nq8MFCSrnJXSc88yliwlzQe3qNe3VntIjhsArW9IJOEPSHNx23FalwApUVbzAWABLhYJJ7y8AynWI/XM8OdfjQ==",
1382+ "funding": [
1383+ {
1384+ "type": "opencollective",
1385+ "url": "https://opencollective.com/browserslist"
1386+ },
1387+ {
1388+ "type": "tidelift",
1389+ "url": "https://tidelift.com/funding/github/npm/browserslist"
1390+ }
1391+ ],
1392+ "dependencies": {
1393+ "caniuse-lite": "^1.0.30001359",
1394+ "electron-to-chromium": "^1.4.172",
1395+ "node-releases": "^2.0.5",
1396+ "update-browserslist-db": "^1.0.4"
1397+ },
1398+ "bin": {
1399+ "browserslist": "cli.js"
1400+ },
1401+ "engines": {
1402+ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
1403+ }
1404+ },
1405+ "node_modules/callsites": {
1406+ "version": "3.1.0",
1407+ "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
1408+ "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
1409+ "engines": {
1410+ "node": ">=6"
1411+ }
1412+ },
1413+ "node_modules/camelcase-css": {
1414+ "version": "2.0.1",
1415+ "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz",
1416+ "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==",
1417+ "dev": true,
1418+ "engines": {
1419+ "node": ">= 6"
1420+ }
1421+ },
1422+ "node_modules/caniuse-lite": {
1423+ "version": "1.0.30001361",
1424+ "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001361.tgz",
1425+ "integrity": "sha512-ybhCrjNtkFji1/Wto6SSJKkWk6kZgVQsDq5QI83SafsF6FXv2JB4df9eEdH6g8sdGgqTXrFLjAxqBGgYoU3azQ==",
1426+ "funding": [
1427+ {
1428+ "type": "opencollective",
1429+ "url": "https://opencollective.com/browserslist"
1430+ },
1431+ {
1432+ "type": "tidelift",
1433+ "url": "https://tidelift.com/funding/github/npm/caniuse-lite"
1434+ }
1435+ ]
1436+ },
1437+ "node_modules/chalk": {
1438+ "version": "2.4.2",
1439+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
1440+ "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
1441+ "dependencies": {
1442+ "ansi-styles": "^3.2.1",
1443+ "escape-string-regexp": "^1.0.5",
1444+ "supports-color": "^5.3.0"
1445+ },
1446+ "engines": {
1447+ "node": ">=4"
1448+ }
1449+ },
1450+ "node_modules/chokidar": {
1451+ "version": "3.5.3",
1452+ "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz",
1453+ "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==",
1454+ "dev": true,
1455+ "funding": [
1456+ {
1457+ "type": "individual",
1458+ "url": "https://paulmillr.com/funding/"
1459+ }
1460+ ],
1461+ "dependencies": {
1462+ "anymatch": "~3.1.2",
1463+ "braces": "~3.0.2",
1464+ "glob-parent": "~5.1.2",
1465+ "is-binary-path": "~2.1.0",
1466+ "is-glob": "~4.0.1",
1467+ "normalize-path": "~3.0.0",
1468+ "readdirp": "~3.6.0"
1469+ },
1470+ "engines": {
1471+ "node": ">= 8.10.0"
1472+ },
1473+ "optionalDependencies": {
1474+ "fsevents": "~2.3.2"
1475+ }
1476+ },
1477+ "node_modules/chokidar/node_modules/glob-parent": {
1478+ "version": "5.1.2",
1479+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
1480+ "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
1481+ "dev": true,
1482+ "dependencies": {
1483+ "is-glob": "^4.0.1"
1484+ },
1485+ "engines": {
1486+ "node": ">= 6"
1487+ }
1488+ },
1489+ "node_modules/classnames": {
1490+ "version": "2.3.1",
1491+ "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.3.1.tgz",
1492+ "integrity": "sha512-OlQdbZ7gLfGarSqxesMesDa5uz7KFbID8Kpq/SxIoNGDqY8lSYs0D+hhtBXhcdB3rcbXArFr7vlHheLk1voeNA=="
1493+ },
1494+ "node_modules/color-convert": {
1495+ "version": "1.9.3",
1496+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
1497+ "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
1498+ "dependencies": {
1499+ "color-name": "1.1.3"
1500+ }
1501+ },
1502+ "node_modules/color-name": {
1503+ "version": "1.1.3",
1504+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
1505+ "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw=="
1506+ },
1507+ "node_modules/color2k": {
1508+ "version": "2.0.2",
1509+ "resolved": "https://registry.npmjs.org/color2k/-/color2k-2.0.2.tgz",
1510+ "integrity": "sha512-kJhwH5nAwb34tmyuqq/lgjEKzlFXn1U99NlnB6Ws4qVaERcRUYeYP1cBw6BJ4vxaWStAUEef4WMr7WjOCnBt8w=="
1511+ },
1512+ "node_modules/connect-history-api-fallback": {
1513+ "version": "1.6.0",
1514+ "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-1.6.0.tgz",
1515+ "integrity": "sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg==",
1516+ "dev": true,
1517+ "engines": {
1518+ "node": ">=0.8"
1519+ }
1520+ },
1521+ "node_modules/convert-source-map": {
1522+ "version": "1.8.0",
1523+ "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz",
1524+ "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==",
1525+ "dependencies": {
1526+ "safe-buffer": "~5.1.1"
1527+ }
1528+ },
1529+ "node_modules/core-js": {
1530+ "version": "3.23.3",
1531+ "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.23.3.tgz",
1532+ "integrity": "sha512-oAKwkj9xcWNBAvGbT//WiCdOMpb9XQG92/Fe3ABFM/R16BsHgePG00mFOgKf7IsCtfj8tA1kHtf/VwErhriz5Q==",
1533+ "hasInstallScript": true,
1534+ "funding": {
1535+ "type": "opencollective",
1536+ "url": "https://opencollective.com/core-js"
1537+ }
1538+ },
1539+ "node_modules/cosmiconfig": {
1540+ "version": "6.0.0",
1541+ "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-6.0.0.tgz",
1542+ "integrity": "sha512-xb3ZL6+L8b9JLLCx3ZdoZy4+2ECphCMo2PwqgP1tlfVq6M6YReyzBJtvWWtbDSpNr9hn96pkCiZqUcFEc+54Qg==",
1543+ "dependencies": {
1544+ "@types/parse-json": "^4.0.0",
1545+ "import-fresh": "^3.1.0",
1546+ "parse-json": "^5.0.0",
1547+ "path-type": "^4.0.0",
1548+ "yaml": "^1.7.2"
1549+ },
1550+ "engines": {
1551+ "node": ">=8"
1552+ }
1553+ },
1554+ "node_modules/cssesc": {
1555+ "version": "3.0.0",
1556+ "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz",
1557+ "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==",
1558+ "dev": true,
1559+ "bin": {
1560+ "cssesc": "bin/cssesc"
1561+ },
1562+ "engines": {
1563+ "node": ">=4"
1564+ }
1565+ },
1566+ "node_modules/csstype": {
1567+ "version": "3.1.0",
1568+ "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.0.tgz",
1569+ "integrity": "sha512-uX1KG+x9h5hIJsaKR9xHUeUraxf8IODOwq9JLNPq6BwB04a/xgpq3rcx47l5BZu5zBPlgD342tdke3Hom/nJRA=="
1570+ },
1571+ "node_modules/debug": {
1572+ "version": "4.3.4",
1573+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
1574+ "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
1575+ "dependencies": {
1576+ "ms": "2.1.2"
1577+ },
1578+ "engines": {
1579+ "node": ">=6.0"
1580+ },
1581+ "peerDependenciesMeta": {
1582+ "supports-color": {
1583+ "optional": true
1584+ }
1585+ }
1586+ },
1587+ "node_modules/decode-uri-component": {
1588+ "version": "0.2.0",
1589+ "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz",
1590+ "integrity": "sha512-hjf+xovcEn31w/EUYdTXQh/8smFL/dzYjohQGEIgjyNavaJfBY2p5F527Bo1VPATxv0VYTUC2bOcXvqFwk78Og==",
1591+ "engines": {
1592+ "node": ">=0.10"
1593+ }
1594+ },
1595+ "node_modules/defined": {
1596+ "version": "1.0.0",
1597+ "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.0.tgz",
1598+ "integrity": "sha512-Y2caI5+ZwS5c3RiNDJ6u53VhQHv+hHKwhkI1iHvceKUHw9Df6EK2zRLfjejRgMuCuxK7PfSWIMwWecceVvThjQ==",
1599+ "dev": true
1600+ },
1601+ "node_modules/detect-node-es": {
1602+ "version": "1.1.0",
1603+ "resolved": "https://registry.npmjs.org/detect-node-es/-/detect-node-es-1.1.0.tgz",
1604+ "integrity": "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ=="
1605+ },
1606+ "node_modules/detective": {
1607+ "version": "5.2.1",
1608+ "resolved": "https://registry.npmjs.org/detective/-/detective-5.2.1.tgz",
1609+ "integrity": "sha512-v9XE1zRnz1wRtgurGu0Bs8uHKFSTdteYZNbIPFVhUZ39L/S79ppMpdmVOZAnoz1jfEFodc48n6MX483Xo3t1yw==",
1610+ "dev": true,
1611+ "dependencies": {
1612+ "acorn-node": "^1.8.2",
1613+ "defined": "^1.0.0",
1614+ "minimist": "^1.2.6"
1615+ },
1616+ "bin": {
1617+ "detective": "bin/detective.js"
1618+ },
1619+ "engines": {
1620+ "node": ">=0.8.0"
1621+ }
1622+ },
1623+ "node_modules/didyoumean": {
1624+ "version": "1.2.2",
1625+ "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz",
1626+ "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==",
1627+ "dev": true
1628+ },
1629+ "node_modules/dlv": {
1630+ "version": "1.1.3",
1631+ "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz",
1632+ "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==",
1633+ "dev": true
1634+ },
1635+ "node_modules/dom-helpers": {
1636+ "version": "5.2.1",
1637+ "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz",
1638+ "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==",
1639+ "dependencies": {
1640+ "@babel/runtime": "^7.8.7",
1641+ "csstype": "^3.0.2"
1642+ }
1643+ },
1644+ "node_modules/electron-to-chromium": {
1645+ "version": "1.4.176",
1646+ "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.176.tgz",
1647+ "integrity": "sha512-92JdgyRlcNDwuy75MjuFSb3clt6DGJ2IXSpg0MCjKd3JV9eSmuUAIyWiGAp/EtT0z2D4rqbYqThQLV90maH3Zw=="
1648+ },
1649+ "node_modules/error-ex": {
1650+ "version": "1.3.2",
1651+ "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz",
1652+ "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==",
1653+ "dependencies": {
1654+ "is-arrayish": "^0.2.1"
1655+ }
1656+ },
1657+ "node_modules/esbuild": {
1658+ "version": "0.14.48",
1659+ "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.14.48.tgz",
1660+ "integrity": "sha512-w6N1Yn5MtqK2U1/WZTX9ZqUVb8IOLZkZ5AdHkT6x3cHDMVsYWC7WPdiLmx19w3i4Rwzy5LqsEMtVihG3e4rFzA==",
1661+ "dev": true,
1662+ "hasInstallScript": true,
1663+ "bin": {
1664+ "esbuild": "bin/esbuild"
1665+ },
1666+ "engines": {
1667+ "node": ">=12"
1668+ },
1669+ "optionalDependencies": {
1670+ "esbuild-android-64": "0.14.48",
1671+ "esbuild-android-arm64": "0.14.48",
1672+ "esbuild-darwin-64": "0.14.48",
1673+ "esbuild-darwin-arm64": "0.14.48",
1674+ "esbuild-freebsd-64": "0.14.48",
1675+ "esbuild-freebsd-arm64": "0.14.48",
1676+ "esbuild-linux-32": "0.14.48",
1677+ "esbuild-linux-64": "0.14.48",
1678+ "esbuild-linux-arm": "0.14.48",
1679+ "esbuild-linux-arm64": "0.14.48",
1680+ "esbuild-linux-mips64le": "0.14.48",
1681+ "esbuild-linux-ppc64le": "0.14.48",
1682+ "esbuild-linux-riscv64": "0.14.48",
1683+ "esbuild-linux-s390x": "0.14.48",
1684+ "esbuild-netbsd-64": "0.14.48",
1685+ "esbuild-openbsd-64": "0.14.48",
1686+ "esbuild-sunos-64": "0.14.48",
1687+ "esbuild-windows-32": "0.14.48",
1688+ "esbuild-windows-64": "0.14.48",
1689+ "esbuild-windows-arm64": "0.14.48"
1690+ }
1691+ },
1692+ "node_modules/esbuild-android-64": {
1693+ "version": "0.14.48",
1694+ "resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.14.48.tgz",
1695+ "integrity": "sha512-3aMjboap/kqwCUpGWIjsk20TtxVoKck8/4Tu19rubh7t5Ra0Yrpg30Mt1QXXlipOazrEceGeWurXKeFJgkPOUg==",
1696+ "cpu": [
1697+ "x64"
1698+ ],
1699+ "dev": true,
1700+ "optional": true,
1701+ "os": [
1702+ "android"
1703+ ],
1704+ "engines": {
1705+ "node": ">=12"
1706+ }
1707+ },
1708+ "node_modules/esbuild-android-arm64": {
1709+ "version": "0.14.48",
1710+ "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.14.48.tgz",
1711+ "integrity": "sha512-vptI3K0wGALiDq+EvRuZotZrJqkYkN5282iAfcffjI5lmGG9G1ta/CIVauhY42MBXwEgDJkweiDcDMRLzBZC4g==",
1712+ "cpu": [
1713+ "arm64"
1714+ ],
1715+ "dev": true,
1716+ "optional": true,
1717+ "os": [
1718+ "android"
1719+ ],
1720+ "engines": {
1721+ "node": ">=12"
1722+ }
1723+ },
1724+ "node_modules/esbuild-darwin-64": {
1725+ "version": "0.14.48",
1726+ "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.14.48.tgz",
1727+ "integrity": "sha512-gGQZa4+hab2Va/Zww94YbshLuWteyKGD3+EsVon8EWTWhnHFRm5N9NbALNbwi/7hQ/hM1Zm4FuHg+k6BLsl5UA==",
1728+ "cpu": [
1729+ "x64"
1730+ ],
1731+ "dev": true,
1732+ "optional": true,
1733+ "os": [
1734+ "darwin"
1735+ ],
1736+ "engines": {
1737+ "node": ">=12"
1738+ }
1739+ },
1740+ "node_modules/esbuild-darwin-arm64": {
1741+ "version": "0.14.48",
1742+ "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.48.tgz",
1743+ "integrity": "sha512-bFjnNEXjhZT+IZ8RvRGNJthLWNHV5JkCtuOFOnjvo5pC0sk2/QVk0Qc06g2PV3J0TcU6kaPC3RN9yy9w2PSLEA==",
1744+ "cpu": [
1745+ "arm64"
1746+ ],
1747+ "dev": true,
1748+ "optional": true,
1749+ "os": [
1750+ "darwin"
1751+ ],
1752+ "engines": {
1753+ "node": ">=12"
1754+ }
1755+ },
1756+ "node_modules/esbuild-freebsd-64": {
1757+ "version": "0.14.48",
1758+ "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.48.tgz",
1759+ "integrity": "sha512-1NOlwRxmOsnPcWOGTB10JKAkYSb2nue0oM1AfHWunW/mv3wERfJmnYlGzL3UAOIUXZqW8GeA2mv+QGwq7DToqA==",
1760+ "cpu": [
1761+ "x64"
1762+ ],
1763+ "dev": true,
1764+ "optional": true,
1765+ "os": [
1766+ "freebsd"
1767+ ],
1768+ "engines": {
1769+ "node": ">=12"
1770+ }
1771+ },
1772+ "node_modules/esbuild-freebsd-arm64": {
1773+ "version": "0.14.48",
1774+ "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.48.tgz",
1775+ "integrity": "sha512-gXqKdO8wabVcYtluAbikDH2jhXp+Klq5oCD5qbVyUG6tFiGhrC9oczKq3vIrrtwcxDQqK6+HDYK8Zrd4bCA9Gw==",
1776+ "cpu": [
1777+ "arm64"
1778+ ],
1779+ "dev": true,
1780+ "optional": true,
1781+ "os": [
1782+ "freebsd"
1783+ ],
1784+ "engines": {
1785+ "node": ">=12"
1786+ }
1787+ },
1788+ "node_modules/esbuild-linux-32": {
1789+ "version": "0.14.48",
1790+ "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.14.48.tgz",
1791+ "integrity": "sha512-ghGyDfS289z/LReZQUuuKq9KlTiTspxL8SITBFQFAFRA/IkIvDpnZnCAKTCjGXAmUqroMQfKJXMxyjJA69c/nQ==",
1792+ "cpu": [
1793+ "ia32"
1794+ ],
1795+ "dev": true,
1796+ "optional": true,
1797+ "os": [
1798+ "linux"
1799+ ],
1800+ "engines": {
1801+ "node": ">=12"
1802+ }
1803+ },
1804+ "node_modules/esbuild-linux-64": {
1805+ "version": "0.14.48",
1806+ "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.14.48.tgz",
1807+ "integrity": "sha512-vni3p/gppLMVZLghI7oMqbOZdGmLbbKR23XFARKnszCIBpEMEDxOMNIKPmMItQrmH/iJrL1z8Jt2nynY0bE1ug==",
1808+ "cpu": [
1809+ "x64"
1810+ ],
1811+ "dev": true,
1812+ "optional": true,
1813+ "os": [
1814+ "linux"
1815+ ],
1816+ "engines": {
1817+ "node": ">=12"
1818+ }
1819+ },
1820+ "node_modules/esbuild-linux-arm": {
1821+ "version": "0.14.48",
1822+ "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.14.48.tgz",
1823+ "integrity": "sha512-+VfSV7Akh1XUiDNXgqgY1cUP1i2vjI+BmlyXRfVz5AfV3jbpde8JTs5Q9sYgaoq5cWfuKfoZB/QkGOI+QcL1Tw==",
1824+ "cpu": [
1825+ "arm"
1826+ ],
1827+ "dev": true,
1828+ "optional": true,
1829+ "os": [
1830+ "linux"
1831+ ],
1832+ "engines": {
1833+ "node": ">=12"
1834+ }
1835+ },
1836+ "node_modules/esbuild-linux-arm64": {
1837+ "version": "0.14.48",
1838+ "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.48.tgz",
1839+ "integrity": "sha512-3CFsOlpoxlKPRevEHq8aAntgYGYkE1N9yRYAcPyng/p4Wyx0tPR5SBYsxLKcgPB9mR8chHEhtWYz6EZ+H199Zw==",
1840+ "cpu": [
1841+ "arm64"
1842+ ],
1843+ "dev": true,
1844+ "optional": true,
1845+ "os": [
1846+ "linux"
1847+ ],
1848+ "engines": {
1849+ "node": ">=12"
1850+ }
1851+ },
1852+ "node_modules/esbuild-linux-mips64le": {
1853+ "version": "0.14.48",
1854+ "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.48.tgz",
1855+ "integrity": "sha512-cs0uOiRlPp6ymknDnjajCgvDMSsLw5mST2UXh+ZIrXTj2Ifyf2aAP3Iw4DiqgnyYLV2O/v/yWBJx+WfmKEpNLA==",
1856+ "cpu": [
1857+ "mips64el"
1858+ ],
1859+ "dev": true,
1860+ "optional": true,
1861+ "os": [
1862+ "linux"
1863+ ],
1864+ "engines": {
1865+ "node": ">=12"
1866+ }
1867+ },
1868+ "node_modules/esbuild-linux-ppc64le": {
1869+ "version": "0.14.48",
1870+ "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.48.tgz",
1871+ "integrity": "sha512-+2F0vJMkuI0Wie/wcSPDCqXvSFEELH7Jubxb7mpWrA/4NpT+/byjxDz0gG6R1WJoeDefcrMfpBx4GFNN1JQorQ==",
1872+ "cpu": [
1873+ "ppc64"
1874+ ],
1875+ "dev": true,
1876+ "optional": true,
1877+ "os": [
1878+ "linux"
1879+ ],
1880+ "engines": {
1881+ "node": ">=12"
1882+ }
1883+ },
1884+ "node_modules/esbuild-linux-riscv64": {
1885+ "version": "0.14.48",
1886+ "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.48.tgz",
1887+ "integrity": "sha512-BmaK/GfEE+5F2/QDrIXteFGKnVHGxlnK9MjdVKMTfvtmudjY3k2t8NtlY4qemKSizc+QwyombGWTBDc76rxePA==",
1888+ "cpu": [
1889+ "riscv64"
1890+ ],
1891+ "dev": true,
1892+ "optional": true,
1893+ "os": [
1894+ "linux"
1895+ ],
1896+ "engines": {
1897+ "node": ">=12"
1898+ }
1899+ },
1900+ "node_modules/esbuild-linux-s390x": {
1901+ "version": "0.14.48",
1902+ "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.48.tgz",
1903+ "integrity": "sha512-tndw/0B9jiCL+KWKo0TSMaUm5UWBLsfCKVdbfMlb3d5LeV9WbijZ8Ordia8SAYv38VSJWOEt6eDCdOx8LqkC4g==",
1904+ "cpu": [
1905+ "s390x"
1906+ ],
1907+ "dev": true,
1908+ "optional": true,
1909+ "os": [
1910+ "linux"
1911+ ],
1912+ "engines": {
1913+ "node": ">=12"
1914+ }
1915+ },
1916+ "node_modules/esbuild-netbsd-64": {
1917+ "version": "0.14.48",
1918+ "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.48.tgz",
1919+ "integrity": "sha512-V9hgXfwf/T901Lr1wkOfoevtyNkrxmMcRHyticybBUHookznipMOHoF41Al68QBsqBxnITCEpjjd4yAos7z9Tw==",
1920+ "cpu": [
1921+ "x64"
1922+ ],
1923+ "dev": true,
1924+ "optional": true,
1925+ "os": [
1926+ "netbsd"
1927+ ],
1928+ "engines": {
1929+ "node": ">=12"
1930+ }
1931+ },
1932+ "node_modules/esbuild-openbsd-64": {
1933+ "version": "0.14.48",
1934+ "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.48.tgz",
1935+ "integrity": "sha512-+IHf4JcbnnBl4T52egorXMatil/za0awqzg2Vy6FBgPcBpisDWT2sVz/tNdrK9kAqj+GZG/jZdrOkj7wsrNTKA==",
1936+ "cpu": [
1937+ "x64"
1938+ ],
1939+ "dev": true,
1940+ "optional": true,
1941+ "os": [
1942+ "openbsd"
1943+ ],
1944+ "engines": {
1945+ "node": ">=12"
1946+ }
1947+ },
1948+ "node_modules/esbuild-sunos-64": {
1949+ "version": "0.14.48",
1950+ "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.14.48.tgz",
1951+ "integrity": "sha512-77m8bsr5wOpOWbGi9KSqDphcq6dFeJyun8TA+12JW/GAjyfTwVtOnN8DOt6DSPUfEV+ltVMNqtXUeTeMAxl5KA==",
1952+ "cpu": [
1953+ "x64"
1954+ ],
1955+ "dev": true,
1956+ "optional": true,
1957+ "os": [
1958+ "sunos"
1959+ ],
1960+ "engines": {
1961+ "node": ">=12"
1962+ }
1963+ },
1964+ "node_modules/esbuild-windows-32": {
1965+ "version": "0.14.48",
1966+ "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.14.48.tgz",
1967+ "integrity": "sha512-EPgRuTPP8vK9maxpTGDe5lSoIBHGKO/AuxDncg5O3NkrPeLNdvvK8oywB0zGaAZXxYWfNNSHskvvDgmfVTguhg==",
1968+ "cpu": [
1969+ "ia32"
1970+ ],
1971+ "dev": true,
1972+ "optional": true,
1973+ "os": [
1974+ "win32"
1975+ ],
1976+ "engines": {
1977+ "node": ">=12"
1978+ }
1979+ },
1980+ "node_modules/esbuild-windows-64": {
1981+ "version": "0.14.48",
1982+ "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.14.48.tgz",
1983+ "integrity": "sha512-YmpXjdT1q0b8ictSdGwH3M8VCoqPpK1/UArze3X199w6u8hUx3V8BhAi1WjbsfDYRBanVVtduAhh2sirImtAvA==",
1984+ "cpu": [
1985+ "x64"
1986+ ],
1987+ "dev": true,
1988+ "optional": true,
1989+ "os": [
1990+ "win32"
1991+ ],
1992+ "engines": {
1993+ "node": ">=12"
1994+ }
1995+ },
1996+ "node_modules/esbuild-windows-arm64": {
1997+ "version": "0.14.48",
1998+ "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.48.tgz",
1999+ "integrity": "sha512-HHaOMCsCXp0rz5BT2crTka6MPWVno121NKApsGs/OIW5QC0ggC69YMGs1aJct9/9FSUF4A1xNE/cLvgB5svR4g==",
2000+ "cpu": [
2001+ "arm64"
2002+ ],
2003+ "dev": true,
2004+ "optional": true,
2005+ "os": [
2006+ "win32"
2007+ ],
2008+ "engines": {
2009+ "node": ">=12"
2010+ }
2011+ },
2012+ "node_modules/escalade": {
2013+ "version": "3.1.1",
2014+ "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz",
2015+ "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==",
2016+ "engines": {
2017+ "node": ">=6"
2018+ }
2019+ },
2020+ "node_modules/escape-string-regexp": {
2021+ "version": "1.0.5",
2022+ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
2023+ "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==",
2024+ "engines": {
2025+ "node": ">=0.8.0"
2026+ }
2027+ },
2028+ "node_modules/estree-walker": {
2029+ "version": "2.0.2",
2030+ "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz",
2031+ "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==",
2032+ "dev": true
2033+ },
2034+ "node_modules/fast-glob": {
2035+ "version": "3.2.11",
2036+ "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz",
2037+ "integrity": "sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==",
2038+ "dev": true,
2039+ "dependencies": {
2040+ "@nodelib/fs.stat": "^2.0.2",
2041+ "@nodelib/fs.walk": "^1.2.3",
2042+ "glob-parent": "^5.1.2",
2043+ "merge2": "^1.3.0",
2044+ "micromatch": "^4.0.4"
2045+ },
2046+ "engines": {
2047+ "node": ">=8.6.0"
2048+ }
2049+ },
2050+ "node_modules/fast-glob/node_modules/glob-parent": {
2051+ "version": "5.1.2",
2052+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
2053+ "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
2054+ "dev": true,
2055+ "dependencies": {
2056+ "is-glob": "^4.0.1"
2057+ },
2058+ "engines": {
2059+ "node": ">= 6"
2060+ }
2061+ },
2062+ "node_modules/fastq": {
2063+ "version": "1.13.0",
2064+ "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz",
2065+ "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==",
2066+ "dev": true,
2067+ "dependencies": {
2068+ "reusify": "^1.0.4"
2069+ }
2070+ },
2071+ "node_modules/fill-range": {
2072+ "version": "7.0.1",
2073+ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
2074+ "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
2075+ "dev": true,
2076+ "dependencies": {
2077+ "to-regex-range": "^5.0.1"
2078+ },
2079+ "engines": {
2080+ "node": ">=8"
2081+ }
2082+ },
2083+ "node_modules/filter-obj": {
2084+ "version": "1.1.0",
2085+ "resolved": "https://registry.npmjs.org/filter-obj/-/filter-obj-1.1.0.tgz",
2086+ "integrity": "sha512-8rXg1ZnX7xzy2NGDVkBVaAy+lSlPNwad13BtgSlLuxfIslyt5Vg64U7tFcCt4WS1R0hvtnQybT/IyCkGZ3DpXQ==",
2087+ "engines": {
2088+ "node": ">=0.10.0"
2089+ }
2090+ },
2091+ "node_modules/find-root": {
2092+ "version": "1.1.0",
2093+ "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz",
2094+ "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng=="
2095+ },
2096+ "node_modules/fraction.js": {
2097+ "version": "4.2.0",
2098+ "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.2.0.tgz",
2099+ "integrity": "sha512-MhLuK+2gUcnZe8ZHlaaINnQLl0xRIGRfcGk2yl8xoQAfHrSsL3rYu6FCmBdkdbhc9EPlwyGHewaRsvwRMJtAlA==",
2100+ "dev": true,
2101+ "engines": {
2102+ "node": "*"
2103+ },
2104+ "funding": {
2105+ "type": "patreon",
2106+ "url": "https://www.patreon.com/infusion"
2107+ }
2108+ },
2109+ "node_modules/fsevents": {
2110+ "version": "2.3.2",
2111+ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
2112+ "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
2113+ "dev": true,
2114+ "hasInstallScript": true,
2115+ "optional": true,
2116+ "os": [
2117+ "darwin"
2118+ ],
2119+ "engines": {
2120+ "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
2121+ }
2122+ },
2123+ "node_modules/function-bind": {
2124+ "version": "1.1.1",
2125+ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
2126+ "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A=="
2127+ },
2128+ "node_modules/gensync": {
2129+ "version": "1.0.0-beta.2",
2130+ "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz",
2131+ "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==",
2132+ "engines": {
2133+ "node": ">=6.9.0"
2134+ }
2135+ },
2136+ "node_modules/get-nonce": {
2137+ "version": "1.0.1",
2138+ "resolved": "https://registry.npmjs.org/get-nonce/-/get-nonce-1.0.1.tgz",
2139+ "integrity": "sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==",
2140+ "engines": {
2141+ "node": ">=6"
2142+ }
2143+ },
2144+ "node_modules/glob-parent": {
2145+ "version": "6.0.2",
2146+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
2147+ "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==",
2148+ "dev": true,
2149+ "dependencies": {
2150+ "is-glob": "^4.0.3"
2151+ },
2152+ "engines": {
2153+ "node": ">=10.13.0"
2154+ }
2155+ },
2156+ "node_modules/globals": {
2157+ "version": "11.12.0",
2158+ "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz",
2159+ "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==",
2160+ "engines": {
2161+ "node": ">=4"
2162+ }
2163+ },
2164+ "node_modules/has": {
2165+ "version": "1.0.3",
2166+ "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
2167+ "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
2168+ "dependencies": {
2169+ "function-bind": "^1.1.1"
2170+ },
2171+ "engines": {
2172+ "node": ">= 0.4.0"
2173+ }
2174+ },
2175+ "node_modules/has-flag": {
2176+ "version": "3.0.0",
2177+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
2178+ "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
2179+ "engines": {
2180+ "node": ">=4"
2181+ }
2182+ },
2183+ "node_modules/history": {
2184+ "version": "5.3.0",
2185+ "resolved": "https://registry.npmjs.org/history/-/history-5.3.0.tgz",
2186+ "integrity": "sha512-ZqaKwjjrAYUYfLG+htGaIIZ4nioX2L70ZUMIFysS3xvBsSG4x/n1V6TXV3N8ZYNuFGlDirFg32T7B6WOUPDYcQ==",
2187+ "dependencies": {
2188+ "@babel/runtime": "^7.7.6"
2189+ }
2190+ },
2191+ "node_modules/hoist-non-react-statics": {
2192+ "version": "3.3.2",
2193+ "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz",
2194+ "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==",
2195+ "dependencies": {
2196+ "react-is": "^16.7.0"
2197+ }
2198+ },
2199+ "node_modules/immer": {
2200+ "version": "9.0.15",
2201+ "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.15.tgz",
2202+ "integrity": "sha512-2eB/sswms9AEUSkOm4SbV5Y7Vmt/bKRwByd52jfLkW4OLYeaTP3EEiJ9agqU0O/tq6Dk62Zfj+TJSqfm1rLVGQ==",
2203+ "funding": {
2204+ "type": "opencollective",
2205+ "url": "https://opencollective.com/immer"
2206+ }
2207+ },
2208+ "node_modules/import-fresh": {
2209+ "version": "3.3.0",
2210+ "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
2211+ "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==",
2212+ "dependencies": {
2213+ "parent-module": "^1.0.0",
2214+ "resolve-from": "^4.0.0"
2215+ },
2216+ "engines": {
2217+ "node": ">=6"
2218+ },
2219+ "funding": {
2220+ "url": "https://github.com/sponsors/sindresorhus"
2221+ }
2222+ },
2223+ "node_modules/invariant": {
2224+ "version": "2.2.4",
2225+ "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz",
2226+ "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==",
2227+ "dependencies": {
2228+ "loose-envify": "^1.0.0"
2229+ }
2230+ },
2231+ "node_modules/is-arrayish": {
2232+ "version": "0.2.1",
2233+ "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
2234+ "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg=="
2235+ },
2236+ "node_modules/is-binary-path": {
2237+ "version": "2.1.0",
2238+ "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
2239+ "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
2240+ "dev": true,
2241+ "dependencies": {
2242+ "binary-extensions": "^2.0.0"
2243+ },
2244+ "engines": {
2245+ "node": ">=8"
2246+ }
2247+ },
2248+ "node_modules/is-core-module": {
2249+ "version": "2.9.0",
2250+ "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.9.0.tgz",
2251+ "integrity": "sha512-+5FPy5PnwmO3lvfMb0AsoPaBG+5KHUI0wYFXOtYPnVVVspTFUuMZNfNaNVRt3FZadstu2c8x23vykRW/NBoU6A==",
2252+ "dependencies": {
2253+ "has": "^1.0.3"
2254+ },
2255+ "funding": {
2256+ "url": "https://github.com/sponsors/ljharb"
2257+ }
2258+ },
2259+ "node_modules/is-extglob": {
2260+ "version": "2.1.1",
2261+ "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
2262+ "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
2263+ "dev": true,
2264+ "engines": {
2265+ "node": ">=0.10.0"
2266+ }
2267+ },
2268+ "node_modules/is-glob": {
2269+ "version": "4.0.3",
2270+ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
2271+ "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
2272+ "dev": true,
2273+ "dependencies": {
2274+ "is-extglob": "^2.1.1"
2275+ },
2276+ "engines": {
2277+ "node": ">=0.10.0"
2278+ }
2279+ },
2280+ "node_modules/is-number": {
2281+ "version": "7.0.0",
2282+ "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
2283+ "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
2284+ "dev": true,
2285+ "engines": {
2286+ "node": ">=0.12.0"
2287+ }
2288+ },
2289+ "node_modules/js-tokens": {
2290+ "version": "4.0.0",
2291+ "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
2292+ "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="
2293+ },
2294+ "node_modules/jsesc": {
2295+ "version": "2.5.2",
2296+ "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz",
2297+ "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==",
2298+ "bin": {
2299+ "jsesc": "bin/jsesc"
2300+ },
2301+ "engines": {
2302+ "node": ">=4"
2303+ }
2304+ },
2305+ "node_modules/json-parse-even-better-errors": {
2306+ "version": "2.3.1",
2307+ "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz",
2308+ "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w=="
2309+ },
2310+ "node_modules/json5": {
2311+ "version": "2.2.1",
2312+ "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz",
2313+ "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==",
2314+ "bin": {
2315+ "json5": "lib/cli.js"
2316+ },
2317+ "engines": {
2318+ "node": ">=6"
2319+ }
2320+ },
2321+ "node_modules/lilconfig": {
2322+ "version": "2.0.5",
2323+ "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.0.5.tgz",
2324+ "integrity": "sha512-xaYmXZtTHPAw5m+xLN8ab9C+3a8YmV3asNSPOATITbtwrfbwaLJj8h66H1WMIpALCkqsIzK3h7oQ+PdX+LQ9Eg==",
2325+ "dev": true,
2326+ "engines": {
2327+ "node": ">=10"
2328+ }
2329+ },
2330+ "node_modules/lines-and-columns": {
2331+ "version": "1.2.4",
2332+ "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
2333+ "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg=="
2334+ },
2335+ "node_modules/lodash.chunk": {
2336+ "version": "4.2.0",
2337+ "resolved": "https://registry.npmjs.org/lodash.chunk/-/lodash.chunk-4.2.0.tgz",
2338+ "integrity": "sha512-ZzydJKfUHJwHa+hF5X66zLFCBrWn5GeF28OHEr4WVWtNDXlQ/IjWKPBiikqKo2ne0+v6JgCgJ0GzJp8k8bHC7w=="
2339+ },
2340+ "node_modules/lodash.debounce": {
2341+ "version": "4.0.8",
2342+ "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz",
2343+ "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow=="
2344+ },
2345+ "node_modules/lodash.isequal": {
2346+ "version": "4.5.0",
2347+ "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz",
2348+ "integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ=="
2349+ },
2350+ "node_modules/loose-envify": {
2351+ "version": "1.4.0",
2352+ "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
2353+ "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
2354+ "dependencies": {
2355+ "js-tokens": "^3.0.0 || ^4.0.0"
2356+ },
2357+ "bin": {
2358+ "loose-envify": "cli.js"
2359+ }
2360+ },
2361+ "node_modules/memoize-one": {
2362+ "version": "5.2.1",
2363+ "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-5.2.1.tgz",
2364+ "integrity": "sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q=="
2365+ },
2366+ "node_modules/merge2": {
2367+ "version": "1.4.1",
2368+ "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
2369+ "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==",
2370+ "dev": true,
2371+ "engines": {
2372+ "node": ">= 8"
2373+ }
2374+ },
2375+ "node_modules/micromatch": {
2376+ "version": "4.0.5",
2377+ "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz",
2378+ "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==",
2379+ "dev": true,
2380+ "dependencies": {
2381+ "braces": "^3.0.2",
2382+ "picomatch": "^2.3.1"
2383+ },
2384+ "engines": {
2385+ "node": ">=8.6"
2386+ }
2387+ },
2388+ "node_modules/minimist": {
2389+ "version": "1.2.6",
2390+ "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz",
2391+ "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==",
2392+ "dev": true
2393+ },
2394+ "node_modules/ms": {
2395+ "version": "2.1.2",
2396+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
2397+ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
2398+ },
2399+ "node_modules/nanoid": {
2400+ "version": "3.3.4",
2401+ "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz",
2402+ "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==",
2403+ "dev": true,
2404+ "bin": {
2405+ "nanoid": "bin/nanoid.cjs"
2406+ },
2407+ "engines": {
2408+ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
2409+ }
2410+ },
2411+ "node_modules/node-releases": {
2412+ "version": "2.0.5",
2413+ "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.5.tgz",
2414+ "integrity": "sha512-U9h1NLROZTq9uE1SNffn6WuPDg8icmi3ns4rEl/oTfIle4iLjTliCzgTsbaIFMq/Xn078/lfY/BL0GWZ+psK4Q=="
2415+ },
2416+ "node_modules/normalize-path": {
2417+ "version": "3.0.0",
2418+ "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
2419+ "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
2420+ "dev": true,
2421+ "engines": {
2422+ "node": ">=0.10.0"
2423+ }
2424+ },
2425+ "node_modules/normalize-range": {
2426+ "version": "0.1.2",
2427+ "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz",
2428+ "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==",
2429+ "dev": true,
2430+ "engines": {
2431+ "node": ">=0.10.0"
2432+ }
2433+ },
2434+ "node_modules/object-assign": {
2435+ "version": "4.1.1",
2436+ "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
2437+ "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
2438+ "engines": {
2439+ "node": ">=0.10.0"
2440+ }
2441+ },
2442+ "node_modules/object-hash": {
2443+ "version": "3.0.0",
2444+ "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz",
2445+ "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==",
2446+ "dev": true,
2447+ "engines": {
2448+ "node": ">= 6"
2449+ }
2450+ },
2451+ "node_modules/parent-module": {
2452+ "version": "1.0.1",
2453+ "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
2454+ "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==",
2455+ "dependencies": {
2456+ "callsites": "^3.0.0"
2457+ },
2458+ "engines": {
2459+ "node": ">=6"
2460+ }
2461+ },
2462+ "node_modules/parse-json": {
2463+ "version": "5.2.0",
2464+ "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz",
2465+ "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==",
2466+ "dependencies": {
2467+ "@babel/code-frame": "^7.0.0",
2468+ "error-ex": "^1.3.1",
2469+ "json-parse-even-better-errors": "^2.3.0",
2470+ "lines-and-columns": "^1.1.6"
2471+ },
2472+ "engines": {
2473+ "node": ">=8"
2474+ },
2475+ "funding": {
2476+ "url": "https://github.com/sponsors/sindresorhus"
2477+ }
2478+ },
2479+ "node_modules/path-parse": {
2480+ "version": "1.0.7",
2481+ "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
2482+ "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw=="
2483+ },
2484+ "node_modules/path-type": {
2485+ "version": "4.0.0",
2486+ "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
2487+ "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==",
2488+ "engines": {
2489+ "node": ">=8"
2490+ }
2491+ },
2492+ "node_modules/picocolors": {
2493+ "version": "1.0.0",
2494+ "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz",
2495+ "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ=="
2496+ },
2497+ "node_modules/picomatch": {
2498+ "version": "2.3.1",
2499+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
2500+ "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
2501+ "dev": true,
2502+ "engines": {
2503+ "node": ">=8.6"
2504+ },
2505+ "funding": {
2506+ "url": "https://github.com/sponsors/jonschlinkert"
2507+ }
2508+ },
2509+ "node_modules/pify": {
2510+ "version": "2.3.0",
2511+ "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
2512+ "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==",
2513+ "dev": true,
2514+ "engines": {
2515+ "node": ">=0.10.0"
2516+ }
2517+ },
2518+ "node_modules/postcss": {
2519+ "version": "8.4.14",
2520+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.14.tgz",
2521+ "integrity": "sha512-E398TUmfAYFPBSdzgeieK2Y1+1cpdxJx8yXbK/m57nRhKSmk1GB2tO4lbLBtlkfPQTDKfe4Xqv1ASWPpayPEig==",
2522+ "dev": true,
2523+ "funding": [
2524+ {
2525+ "type": "opencollective",
2526+ "url": "https://opencollective.com/postcss/"
2527+ },
2528+ {
2529+ "type": "tidelift",
2530+ "url": "https://tidelift.com/funding/github/npm/postcss"
2531+ }
2532+ ],
2533+ "dependencies": {
2534+ "nanoid": "^3.3.4",
2535+ "picocolors": "^1.0.0",
2536+ "source-map-js": "^1.0.2"
2537+ },
2538+ "engines": {
2539+ "node": "^10 || ^12 || >=14"
2540+ }
2541+ },
2542+ "node_modules/postcss-import": {
2543+ "version": "14.1.0",
2544+ "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-14.1.0.tgz",
2545+ "integrity": "sha512-flwI+Vgm4SElObFVPpTIT7SU7R3qk2L7PyduMcokiaVKuWv9d/U+Gm/QAd8NDLuykTWTkcrjOeD2Pp1rMeBTGw==",
2546+ "dev": true,
2547+ "dependencies": {
2548+ "postcss-value-parser": "^4.0.0",
2549+ "read-cache": "^1.0.0",
2550+ "resolve": "^1.1.7"
2551+ },
2552+ "engines": {
2553+ "node": ">=10.0.0"
2554+ },
2555+ "peerDependencies": {
2556+ "postcss": "^8.0.0"
2557+ }
2558+ },
2559+ "node_modules/postcss-js": {
2560+ "version": "4.0.0",
2561+ "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.0.0.tgz",
2562+ "integrity": "sha512-77QESFBwgX4irogGVPgQ5s07vLvFqWr228qZY+w6lW599cRlK/HmnlivnnVUxkjHnCu4J16PDMHcH+e+2HbvTQ==",
2563+ "dev": true,
2564+ "dependencies": {
2565+ "camelcase-css": "^2.0.1"
2566+ },
2567+ "engines": {
2568+ "node": "^12 || ^14 || >= 16"
2569+ },
2570+ "funding": {
2571+ "type": "opencollective",
2572+ "url": "https://opencollective.com/postcss/"
2573+ },
2574+ "peerDependencies": {
2575+ "postcss": "^8.3.3"
2576+ }
2577+ },
2578+ "node_modules/postcss-load-config": {
2579+ "version": "3.1.4",
2580+ "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-3.1.4.tgz",
2581+ "integrity": "sha512-6DiM4E7v4coTE4uzA8U//WhtPwyhiim3eyjEMFCnUpzbrkK9wJHgKDT2mR+HbtSrd/NubVaYTOpSpjUl8NQeRg==",
2582+ "dev": true,
2583+ "dependencies": {
2584+ "lilconfig": "^2.0.5",
2585+ "yaml": "^1.10.2"
2586+ },
2587+ "engines": {
2588+ "node": ">= 10"
2589+ },
2590+ "funding": {
2591+ "type": "opencollective",
2592+ "url": "https://opencollective.com/postcss/"
2593+ },
2594+ "peerDependencies": {
2595+ "postcss": ">=8.0.9",
2596+ "ts-node": ">=9.0.0"
2597+ },
2598+ "peerDependenciesMeta": {
2599+ "postcss": {
2600+ "optional": true
2601+ },
2602+ "ts-node": {
2603+ "optional": true
2604+ }
2605+ }
2606+ },
2607+ "node_modules/postcss-nested": {
2608+ "version": "5.0.6",
2609+ "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-5.0.6.tgz",
2610+ "integrity": "sha512-rKqm2Fk0KbA8Vt3AdGN0FB9OBOMDVajMG6ZCf/GoHgdxUJ4sBFp0A/uMIRm+MJUdo33YXEtjqIz8u7DAp8B7DA==",
2611+ "dev": true,
2612+ "dependencies": {
2613+ "postcss-selector-parser": "^6.0.6"
2614+ },
2615+ "engines": {
2616+ "node": ">=12.0"
2617+ },
2618+ "funding": {
2619+ "type": "opencollective",
2620+ "url": "https://opencollective.com/postcss/"
2621+ },
2622+ "peerDependencies": {
2623+ "postcss": "^8.2.14"
2624+ }
2625+ },
2626+ "node_modules/postcss-selector-parser": {
2627+ "version": "6.0.10",
2628+ "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.10.tgz",
2629+ "integrity": "sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==",
2630+ "dev": true,
2631+ "dependencies": {
2632+ "cssesc": "^3.0.0",
2633+ "util-deprecate": "^1.0.2"
2634+ },
2635+ "engines": {
2636+ "node": ">=4"
2637+ }
2638+ },
2639+ "node_modules/postcss-value-parser": {
2640+ "version": "4.2.0",
2641+ "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz",
2642+ "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==",
2643+ "dev": true
2644+ },
2645+ "node_modules/prop-types": {
2646+ "version": "15.8.1",
2647+ "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
2648+ "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==",
2649+ "dependencies": {
2650+ "loose-envify": "^1.4.0",
2651+ "object-assign": "^4.1.1",
2652+ "react-is": "^16.13.1"
2653+ }
2654+ },
2655+ "node_modules/query-string": {
2656+ "version": "7.1.1",
2657+ "resolved": "https://registry.npmjs.org/query-string/-/query-string-7.1.1.tgz",
2658+ "integrity": "sha512-MplouLRDHBZSG9z7fpuAAcI7aAYjDLhtsiVZsevsfaHWDS2IDdORKbSd1kWUA+V4zyva/HZoSfpwnYMMQDhb0w==",
2659+ "dependencies": {
2660+ "decode-uri-component": "^0.2.0",
2661+ "filter-obj": "^1.1.0",
2662+ "split-on-first": "^1.0.0",
2663+ "strict-uri-encode": "^2.0.0"
2664+ },
2665+ "engines": {
2666+ "node": ">=6"
2667+ },
2668+ "funding": {
2669+ "url": "https://github.com/sponsors/sindresorhus"
2670+ }
2671+ },
2672+ "node_modules/queue-microtask": {
2673+ "version": "1.2.3",
2674+ "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
2675+ "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==",
2676+ "dev": true,
2677+ "funding": [
2678+ {
2679+ "type": "github",
2680+ "url": "https://github.com/sponsors/feross"
2681+ },
2682+ {
2683+ "type": "patreon",
2684+ "url": "https://www.patreon.com/feross"
2685+ },
2686+ {
2687+ "type": "consulting",
2688+ "url": "https://feross.org/support"
2689+ }
2690+ ]
2691+ },
2692+ "node_modules/quick-lru": {
2693+ "version": "5.1.1",
2694+ "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz",
2695+ "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==",
2696+ "dev": true,
2697+ "engines": {
2698+ "node": ">=10"
2699+ },
2700+ "funding": {
2701+ "url": "https://github.com/sponsors/sindresorhus"
2702+ }
2703+ },
2704+ "node_modules/react": {
2705+ "version": "17.0.2",
2706+ "resolved": "https://registry.npmjs.org/react/-/react-17.0.2.tgz",
2707+ "integrity": "sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==",
2708+ "dependencies": {
2709+ "loose-envify": "^1.1.0",
2710+ "object-assign": "^4.1.1"
2711+ },
2712+ "engines": {
2713+ "node": ">=0.10.0"
2714+ }
2715+ },
2716+ "node_modules/react-dom": {
2717+ "version": "17.0.2",
2718+ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz",
2719+ "integrity": "sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA==",
2720+ "dependencies": {
2721+ "loose-envify": "^1.1.0",
2722+ "object-assign": "^4.1.1",
2723+ "scheduler": "^0.20.2"
2724+ },
2725+ "peerDependencies": {
2726+ "react": "17.0.2"
2727+ }
2728+ },
2729+ "node_modules/react-hook-form": {
2730+ "version": "7.33.1",
2731+ "resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.33.1.tgz",
2732+ "integrity": "sha512-ydTfTxEJdvgjCZBj5DDXRc58oTEfnFupEwwTAQ9FSKzykEJkX+3CiAkGtAMiZG7IPWHuzgT6AOBfogiKhUvKgg==",
2733+ "engines": {
2734+ "node": ">=12.22.0"
2735+ },
2736+ "funding": {
2737+ "type": "opencollective",
2738+ "url": "https://opencollective.com/react-hook-form"
2739+ },
2740+ "peerDependencies": {
2741+ "react": "^16.8.0 || ^17 || ^18"
2742+ }
2743+ },
2744+ "node_modules/react-is": {
2745+ "version": "16.13.1",
2746+ "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
2747+ "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
2748+ },
2749+ "node_modules/react-refresh": {
2750+ "version": "0.10.0",
2751+ "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.10.0.tgz",
2752+ "integrity": "sha512-PgidR3wST3dDYKr6b4pJoqQFpPGNKDSCDx4cZoshjXipw3LzO7mG1My2pwEzz2JVkF+inx3xRpDeQLFQGH/hsQ==",
2753+ "dev": true,
2754+ "engines": {
2755+ "node": ">=0.10.0"
2756+ }
2757+ },
2758+ "node_modules/react-remove-scroll": {
2759+ "version": "2.5.4",
2760+ "resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.5.4.tgz",
2761+ "integrity": "sha512-xGVKJJr0SJGQVirVFAUZ2k1QLyO6m+2fy0l8Qawbp5Jgrv3DeLalrfMNBFSlmz5kriGGzsVBtGVnf4pTKIhhWA==",
2762+ "dependencies": {
2763+ "react-remove-scroll-bar": "^2.3.3",
2764+ "react-style-singleton": "^2.2.1",
2765+ "tslib": "^2.1.0",
2766+ "use-callback-ref": "^1.3.0",
2767+ "use-sidecar": "^1.1.2"
2768+ },
2769+ "engines": {
2770+ "node": ">=10"
2771+ },
2772+ "peerDependencies": {
2773+ "@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0",
2774+ "react": "^16.8.0 || ^17.0.0 || ^18.0.0"
2775+ },
2776+ "peerDependenciesMeta": {
2777+ "@types/react": {
2778+ "optional": true
2779+ }
2780+ }
2781+ },
2782+ "node_modules/react-remove-scroll-bar": {
2783+ "version": "2.3.3",
2784+ "resolved": "https://registry.npmjs.org/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.3.tgz",
2785+ "integrity": "sha512-i9GMNWwpz8XpUpQ6QlevUtFjHGqnPG4Hxs+wlIJntu/xcsZVEpJcIV71K3ZkqNy2q3GfgvkD7y6t/Sv8ofYSbw==",
2786+ "dependencies": {
2787+ "react-style-singleton": "^2.2.1",
2788+ "tslib": "^2.0.0"
2789+ },
2790+ "engines": {
2791+ "node": ">=10"
2792+ },
2793+ "peerDependencies": {
2794+ "@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0",
2795+ "react": "^16.8.0 || ^17.0.0 || ^18.0.0"
2796+ },
2797+ "peerDependenciesMeta": {
2798+ "@types/react": {
2799+ "optional": true
2800+ }
2801+ }
2802+ },
2803+ "node_modules/react-remove-scroll-bar/node_modules/tslib": {
2804+ "version": "2.4.0",
2805+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz",
2806+ "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ=="
2807+ },
2808+ "node_modules/react-remove-scroll/node_modules/tslib": {
2809+ "version": "2.4.0",
2810+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz",
2811+ "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ=="
2812+ },
2813+ "node_modules/react-router": {
2814+ "version": "6.3.0",
2815+ "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.3.0.tgz",
2816+ "integrity": "sha512-7Wh1DzVQ+tlFjkeo+ujvjSqSJmkt1+8JO+T5xklPlgrh70y7ogx75ODRW0ThWhY7S+6yEDks8TYrtQe/aoboBQ==",
2817+ "dependencies": {
2818+ "history": "^5.2.0"
2819+ },
2820+ "peerDependencies": {
2821+ "react": ">=16.8"
2822+ }
2823+ },
2824+ "node_modules/react-router-dom": {
2825+ "version": "6.3.0",
2826+ "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.3.0.tgz",
2827+ "integrity": "sha512-uaJj7LKytRxZNQV8+RbzJWnJ8K2nPsOOEuX7aQstlMZKQT0164C+X2w6bnkqU3sjtLvpd5ojrezAyfZ1+0sStw==",
2828+ "dependencies": {
2829+ "history": "^5.2.0",
2830+ "react-router": "6.3.0"
2831+ },
2832+ "peerDependencies": {
2833+ "react": ">=16.8",
2834+ "react-dom": ">=16.8"
2835+ }
2836+ },
2837+ "node_modules/react-select": {
2838+ "version": "5.4.0",
2839+ "resolved": "https://registry.npmjs.org/react-select/-/react-select-5.4.0.tgz",
2840+ "integrity": "sha512-CjE9RFLUvChd5SdlfG4vqxZd55AZJRrLrHzkQyTYeHlpOztqcgnyftYAolJ0SGsBev6zAs6qFrjm6KU3eo2hzg==",
2841+ "dependencies": {
2842+ "@babel/runtime": "^7.12.0",
2843+ "@emotion/cache": "^11.4.0",
2844+ "@emotion/react": "^11.8.1",
2845+ "@types/react-transition-group": "^4.4.0",
2846+ "memoize-one": "^5.0.0",
2847+ "prop-types": "^15.6.0",
2848+ "react-transition-group": "^4.3.0"
2849+ },
2850+ "peerDependencies": {
2851+ "react": "^16.8.0 || ^17.0.0 || ^18.0.0",
2852+ "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0"
2853+ }
2854+ },
2855+ "node_modules/react-style-singleton": {
2856+ "version": "2.2.1",
2857+ "resolved": "https://registry.npmjs.org/react-style-singleton/-/react-style-singleton-2.2.1.tgz",
2858+ "integrity": "sha512-ZWj0fHEMyWkHzKYUr2Bs/4zU6XLmq9HsgBURm7g5pAVfyn49DgUiNgY2d4lXRlYSiCif9YBGpQleewkcqddc7g==",
2859+ "dependencies": {
2860+ "get-nonce": "^1.0.0",
2861+ "invariant": "^2.2.4",
2862+ "tslib": "^2.0.0"
2863+ },
2864+ "engines": {
2865+ "node": ">=10"
2866+ },
2867+ "peerDependencies": {
2868+ "@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0",
2869+ "react": "^16.8.0 || ^17.0.0 || ^18.0.0"
2870+ },
2871+ "peerDependenciesMeta": {
2872+ "@types/react": {
2873+ "optional": true
2874+ }
2875+ }
2876+ },
2877+ "node_modules/react-style-singleton/node_modules/tslib": {
2878+ "version": "2.4.0",
2879+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz",
2880+ "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ=="
2881+ },
2882+ "node_modules/react-transition-group": {
2883+ "version": "4.4.2",
2884+ "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.2.tgz",
2885+ "integrity": "sha512-/RNYfRAMlZwDSr6z4zNKV6xu53/e2BuaBbGhbyYIXTrmgu/bGHzmqOs7mJSJBHy9Ud+ApHx3QjrkKSp1pxvlFg==",
2886+ "dependencies": {
2887+ "@babel/runtime": "^7.5.5",
2888+ "dom-helpers": "^5.0.1",
2889+ "loose-envify": "^1.4.0",
2890+ "prop-types": "^15.6.2"
2891+ },
2892+ "peerDependencies": {
2893+ "react": ">=16.6.0",
2894+ "react-dom": ">=16.6.0"
2895+ }
2896+ },
2897+ "node_modules/read-cache": {
2898+ "version": "1.0.0",
2899+ "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz",
2900+ "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==",
2901+ "dev": true,
2902+ "dependencies": {
2903+ "pify": "^2.3.0"
2904+ }
2905+ },
2906+ "node_modules/readdirp": {
2907+ "version": "3.6.0",
2908+ "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
2909+ "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
2910+ "dev": true,
2911+ "dependencies": {
2912+ "picomatch": "^2.2.1"
2913+ },
2914+ "engines": {
2915+ "node": ">=8.10.0"
2916+ }
2917+ },
2918+ "node_modules/regenerator-runtime": {
2919+ "version": "0.13.9",
2920+ "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz",
2921+ "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA=="
2922+ },
2923+ "node_modules/remove-markdown-and-html": {
2924+ "version": "0.1.0",
2925+ "resolved": "https://registry.npmjs.org/remove-markdown-and-html/-/remove-markdown-and-html-0.1.0.tgz",
2926+ "integrity": "sha512-Sy03RJ/R/FBbK6wutBKKIyEVMQS+TzSpGc8pBxwrh0LiqyVIaD/LkitUABIJJ59iryhvrPTmS8dzd3DoLdopHg=="
2927+ },
2928+ "node_modules/resolve": {
2929+ "version": "1.22.1",
2930+ "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz",
2931+ "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==",
2932+ "dependencies": {
2933+ "is-core-module": "^2.9.0",
2934+ "path-parse": "^1.0.7",
2935+ "supports-preserve-symlinks-flag": "^1.0.0"
2936+ },
2937+ "bin": {
2938+ "resolve": "bin/resolve"
2939+ },
2940+ "funding": {
2941+ "url": "https://github.com/sponsors/ljharb"
2942+ }
2943+ },
2944+ "node_modules/resolve-from": {
2945+ "version": "4.0.0",
2946+ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
2947+ "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
2948+ "engines": {
2949+ "node": ">=4"
2950+ }
2951+ },
2952+ "node_modules/reusify": {
2953+ "version": "1.0.4",
2954+ "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
2955+ "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==",
2956+ "dev": true,
2957+ "engines": {
2958+ "iojs": ">=1.0.0",
2959+ "node": ">=0.10.0"
2960+ }
2961+ },
2962+ "node_modules/rollup": {
2963+ "version": "2.75.7",
2964+ "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.75.7.tgz",
2965+ "integrity": "sha512-VSE1iy0eaAYNCxEXaleThdFXqZJ42qDBatAwrfnPlENEZ8erQ+0LYX4JXOLPceWfZpV1VtZwZ3dFCuOZiSyFtQ==",
2966+ "dev": true,
2967+ "bin": {
2968+ "rollup": "dist/bin/rollup"
2969+ },
2970+ "engines": {
2971+ "node": ">=10.0.0"
2972+ },
2973+ "optionalDependencies": {
2974+ "fsevents": "~2.3.2"
2975+ }
2976+ },
2977+ "node_modules/run-parallel": {
2978+ "version": "1.2.0",
2979+ "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
2980+ "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==",
2981+ "dev": true,
2982+ "funding": [
2983+ {
2984+ "type": "github",
2985+ "url": "https://github.com/sponsors/feross"
2986+ },
2987+ {
2988+ "type": "patreon",
2989+ "url": "https://www.patreon.com/feross"
2990+ },
2991+ {
2992+ "type": "consulting",
2993+ "url": "https://feross.org/support"
2994+ }
2995+ ],
2996+ "dependencies": {
2997+ "queue-microtask": "^1.2.2"
2998+ }
2999+ },
3000+ "node_modules/safe-buffer": {
3001+ "version": "5.1.2",
3002+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
3003+ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
3004+ },
3005+ "node_modules/scheduler": {
3006+ "version": "0.20.2",
3007+ "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.20.2.tgz",
3008+ "integrity": "sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ==",
3009+ "dependencies": {
3010+ "loose-envify": "^1.1.0",
3011+ "object-assign": "^4.1.1"
3012+ }
3013+ },
3014+ "node_modules/semver": {
3015+ "version": "6.3.0",
3016+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
3017+ "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
3018+ "bin": {
3019+ "semver": "bin/semver.js"
3020+ }
3021+ },
3022+ "node_modules/source-map": {
3023+ "version": "0.5.7",
3024+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
3025+ "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==",
3026+ "engines": {
3027+ "node": ">=0.10.0"
3028+ }
3029+ },
3030+ "node_modules/source-map-js": {
3031+ "version": "1.0.2",
3032+ "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz",
3033+ "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==",
3034+ "dev": true,
3035+ "engines": {
3036+ "node": ">=0.10.0"
3037+ }
3038+ },
3039+ "node_modules/split-on-first": {
3040+ "version": "1.1.0",
3041+ "resolved": "https://registry.npmjs.org/split-on-first/-/split-on-first-1.1.0.tgz",
3042+ "integrity": "sha512-43ZssAJaMusuKWL8sKUBQXHWOpq8d6CfN/u1p4gUzfJkM05C8rxTmYrkIPTXapZpORA6LkkzcUulJ8FqA7Uudw==",
3043+ "engines": {
3044+ "node": ">=6"
3045+ }
3046+ },
3047+ "node_modules/strict-uri-encode": {
3048+ "version": "2.0.0",
3049+ "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz",
3050+ "integrity": "sha512-QwiXZgpRcKkhTj2Scnn++4PKtWsH0kpzZ62L2R6c/LUVYv7hVnZqcg2+sMuT6R7Jusu1vviK/MFsu6kNJfWlEQ==",
3051+ "engines": {
3052+ "node": ">=4"
3053+ }
3054+ },
3055+ "node_modules/stylis": {
3056+ "version": "4.0.13",
3057+ "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.0.13.tgz",
3058+ "integrity": "sha512-xGPXiFVl4YED9Jh7Euv2V220mriG9u4B2TA6Ybjc1catrstKD2PpIdU3U0RKpkVBC2EhmL/F0sPCr9vrFTNRag=="
3059+ },
3060+ "node_modules/supports-color": {
3061+ "version": "5.5.0",
3062+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
3063+ "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
3064+ "dependencies": {
3065+ "has-flag": "^3.0.0"
3066+ },
3067+ "engines": {
3068+ "node": ">=4"
3069+ }
3070+ },
3071+ "node_modules/supports-preserve-symlinks-flag": {
3072+ "version": "1.0.0",
3073+ "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
3074+ "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
3075+ "engines": {
3076+ "node": ">= 0.4"
3077+ },
3078+ "funding": {
3079+ "url": "https://github.com/sponsors/ljharb"
3080+ }
3081+ },
3082+ "node_modules/tailwindcss": {
3083+ "version": "3.1.4",
3084+ "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.1.4.tgz",
3085+ "integrity": "sha512-NrxbFV4tYsga/hpWbRyUfIaBrNMXDxx5BsHgBS4v5tlyjf+sDsgBg5m9OxjrXIqAS/uR9kicxLKP+bEHI7BSeQ==",
3086+ "dev": true,
3087+ "dependencies": {
3088+ "arg": "^5.0.2",
3089+ "chokidar": "^3.5.3",
3090+ "color-name": "^1.1.4",
3091+ "detective": "^5.2.1",
3092+ "didyoumean": "^1.2.2",
3093+ "dlv": "^1.1.3",
3094+ "fast-glob": "^3.2.11",
3095+ "glob-parent": "^6.0.2",
3096+ "is-glob": "^4.0.3",
3097+ "lilconfig": "^2.0.5",
3098+ "normalize-path": "^3.0.0",
3099+ "object-hash": "^3.0.0",
3100+ "picocolors": "^1.0.0",
3101+ "postcss": "^8.4.14",
3102+ "postcss-import": "^14.1.0",
3103+ "postcss-js": "^4.0.0",
3104+ "postcss-load-config": "^3.1.4",
3105+ "postcss-nested": "5.0.6",
3106+ "postcss-selector-parser": "^6.0.10",
3107+ "postcss-value-parser": "^4.2.0",
3108+ "quick-lru": "^5.1.1",
3109+ "resolve": "^1.22.0"
3110+ },
3111+ "bin": {
3112+ "tailwind": "lib/cli.js",
3113+ "tailwindcss": "lib/cli.js"
3114+ },
3115+ "engines": {
3116+ "node": ">=12.13.0"
3117+ },
3118+ "peerDependencies": {
3119+ "postcss": "^8.0.9"
3120+ }
3121+ },
3122+ "node_modules/tailwindcss-labeled-groups": {
3123+ "version": "0.0.2",
3124+ "resolved": "https://registry.npmjs.org/tailwindcss-labeled-groups/-/tailwindcss-labeled-groups-0.0.2.tgz",
3125+ "integrity": "sha512-leOVv9h2K9WDHoXPXVBOmTJgWECVkpVFc/hjrwuqGUEtNxvRvuOtCjenu9ppY+pJtky5INJUqDCNa8pS3AbYmw==",
3126+ "dev": true,
3127+ "peerDependencies": {
3128+ "tailwindcss": "^3.0.23"
3129+ }
3130+ },
3131+ "node_modules/tailwindcss/node_modules/color-name": {
3132+ "version": "1.1.4",
3133+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
3134+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
3135+ "dev": true
3136+ },
3137+ "node_modules/to-fast-properties": {
3138+ "version": "2.0.0",
3139+ "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz",
3140+ "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==",
3141+ "engines": {
3142+ "node": ">=4"
3143+ }
3144+ },
3145+ "node_modules/to-regex-range": {
3146+ "version": "5.0.1",
3147+ "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
3148+ "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
3149+ "dev": true,
3150+ "dependencies": {
3151+ "is-number": "^7.0.0"
3152+ },
3153+ "engines": {
3154+ "node": ">=8.0"
3155+ }
3156+ },
3157+ "node_modules/tslib": {
3158+ "version": "1.14.1",
3159+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
3160+ "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
3161+ },
3162+ "node_modules/typescript": {
3163+ "version": "4.7.4",
3164+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.4.tgz",
3165+ "integrity": "sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ==",
3166+ "dev": true,
3167+ "bin": {
3168+ "tsc": "bin/tsc",
3169+ "tsserver": "bin/tsserver"
3170+ },
3171+ "engines": {
3172+ "node": ">=4.2.0"
3173+ }
3174+ },
3175+ "node_modules/update-browserslist-db": {
3176+ "version": "1.0.4",
3177+ "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.4.tgz",
3178+ "integrity": "sha512-jnmO2BEGUjsMOe/Fg9u0oczOe/ppIDZPebzccl1yDWGLFP16Pa1/RM5wEoKYPG2zstNcDuAStejyxsOuKINdGA==",
3179+ "funding": [
3180+ {
3181+ "type": "opencollective",
3182+ "url": "https://opencollective.com/browserslist"
3183+ },
3184+ {
3185+ "type": "tidelift",
3186+ "url": "https://tidelift.com/funding/github/npm/browserslist"
3187+ }
3188+ ],
3189+ "dependencies": {
3190+ "escalade": "^3.1.1",
3191+ "picocolors": "^1.0.0"
3192+ },
3193+ "bin": {
3194+ "browserslist-lint": "cli.js"
3195+ },
3196+ "peerDependencies": {
3197+ "browserslist": ">= 4.21.0"
3198+ }
3199+ },
3200+ "node_modules/urbit-ob": {
3201+ "version": "5.0.1",
3202+ "resolved": "https://registry.npmjs.org/urbit-ob/-/urbit-ob-5.0.1.tgz",
3203+ "integrity": "sha512-qGNAwu87XNkW3g8ah4fUwmh2EKXtsdhEbyEiE5qX4Op17rhLH3HSkvu8g9z+MhqX51Uz9sf8ktvqJj/IRwETIQ==",
3204+ "dependencies": {
3205+ "bn.js": "^4.11.8",
3206+ "lodash.chunk": "^4.2.0",
3207+ "lodash.isequal": "^4.5.0"
3208+ }
3209+ },
3210+ "node_modules/use-callback-ref": {
3211+ "version": "1.3.0",
3212+ "resolved": "https://registry.npmjs.org/use-callback-ref/-/use-callback-ref-1.3.0.tgz",
3213+ "integrity": "sha512-3FT9PRuRdbB9HfXhEq35u4oZkvpJ5kuYbpqhCfmiZyReuRgpnhDlbr2ZEnnuS0RrJAPn6l23xjFg9kpDM+Ms7w==",
3214+ "dependencies": {
3215+ "tslib": "^2.0.0"
3216+ },
3217+ "engines": {
3218+ "node": ">=10"
3219+ },
3220+ "peerDependencies": {
3221+ "@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0",
3222+ "react": "^16.8.0 || ^17.0.0 || ^18.0.0"
3223+ },
3224+ "peerDependenciesMeta": {
3225+ "@types/react": {
3226+ "optional": true
3227+ }
3228+ }
3229+ },
3230+ "node_modules/use-callback-ref/node_modules/tslib": {
3231+ "version": "2.4.0",
3232+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz",
3233+ "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ=="
3234+ },
3235+ "node_modules/use-sidecar": {
3236+ "version": "1.1.2",
3237+ "resolved": "https://registry.npmjs.org/use-sidecar/-/use-sidecar-1.1.2.tgz",
3238+ "integrity": "sha512-epTbsLuzZ7lPClpz2TyryBfztm7m+28DlEv2ZCQ3MDr5ssiwyOwGH/e5F9CkfWjJ1t4clvI58yF822/GUkjjhw==",
3239+ "dependencies": {
3240+ "detect-node-es": "^1.1.0",
3241+ "tslib": "^2.0.0"
3242+ },
3243+ "engines": {
3244+ "node": ">=10"
3245+ },
3246+ "peerDependencies": {
3247+ "@types/react": "^16.9.0 || ^17.0.0 || ^18.0.0",
3248+ "react": "^16.8.0 || ^17.0.0 || ^18.0.0"
3249+ },
3250+ "peerDependenciesMeta": {
3251+ "@types/react": {
3252+ "optional": true
3253+ }
3254+ }
3255+ },
3256+ "node_modules/use-sidecar/node_modules/tslib": {
3257+ "version": "2.4.0",
3258+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz",
3259+ "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ=="
3260+ },
3261+ "node_modules/use-sync-external-store": {
3262+ "version": "1.1.0",
3263+ "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.1.0.tgz",
3264+ "integrity": "sha512-SEnieB2FPKEVne66NpXPd1Np4R1lTNKfjuy3XdIoPQKYBAFdzbzSZlSn1KJZUiihQLQC5Znot4SBz1EOTBwQAQ==",
3265+ "peerDependencies": {
3266+ "react": "^16.8.0 || ^17.0.0 || ^18.0.0"
3267+ }
3268+ },
3269+ "node_modules/util-deprecate": {
3270+ "version": "1.0.2",
3271+ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
3272+ "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
3273+ "dev": true
3274+ },
3275+ "node_modules/vite": {
3276+ "version": "2.9.13",
3277+ "resolved": "https://registry.npmjs.org/vite/-/vite-2.9.13.tgz",
3278+ "integrity": "sha512-AsOBAaT0AD7Mhe8DuK+/kE4aWYFMx/i0ZNi98hJclxb4e0OhQcZYUrvLjIaQ8e59Ui7txcvKMiJC1yftqpQoDw==",
3279+ "dev": true,
3280+ "dependencies": {
3281+ "esbuild": "^0.14.27",
3282+ "postcss": "^8.4.13",
3283+ "resolve": "^1.22.0",
3284+ "rollup": "^2.59.0"
3285+ },
3286+ "bin": {
3287+ "vite": "bin/vite.js"
3288+ },
3289+ "engines": {
3290+ "node": ">=12.2.0"
3291+ },
3292+ "optionalDependencies": {
3293+ "fsevents": "~2.3.2"
3294+ },
3295+ "peerDependencies": {
3296+ "less": "*",
3297+ "sass": "*",
3298+ "stylus": "*"
3299+ },
3300+ "peerDependenciesMeta": {
3301+ "less": {
3302+ "optional": true
3303+ },
3304+ "sass": {
3305+ "optional": true
3306+ },
3307+ "stylus": {
3308+ "optional": true
3309+ }
3310+ }
3311+ },
3312+ "node_modules/vite-plugin-html-config": {
3313+ "version": "1.0.8",
3314+ "resolved": "https://registry.npmjs.org/vite-plugin-html-config/-/vite-plugin-html-config-1.0.8.tgz",
3315+ "integrity": "sha512-3tTtBQO+6zpC8uzAAfj3FWygj+V6H6F9fEt5KtB3j5UHsRYP0yLpTHsMvubXtqCXbKDp1oOakYYSjprqYcbrpA==",
3316+ "dev": true,
3317+ "engines": {
3318+ "node": ">=12.0.0"
3319+ },
3320+ "peerDependencies": {
3321+ "vite": "^2.0.5"
3322+ }
3323+ },
3324+ "node_modules/vite-plugin-rewrite-all": {
3325+ "version": "0.1.2",
3326+ "resolved": "https://registry.npmjs.org/vite-plugin-rewrite-all/-/vite-plugin-rewrite-all-0.1.2.tgz",
3327+ "integrity": "sha512-hBFuG043kbixgZ/ke9SzKhkO6P8a5ryxD0CmZTe+/Cz17RIKi7uSeNUJy79V4FgavZ7pWVRg0tqVwJ7lP/A2/Q==",
3328+ "dev": true,
3329+ "dependencies": {
3330+ "connect-history-api-fallback": "^1.6.0"
3331+ },
3332+ "engines": {
3333+ "node": ">=12.0.0"
3334+ },
3335+ "peerDependencies": {
3336+ "vite": "^2.0.2"
3337+ }
3338+ },
3339+ "node_modules/xtend": {
3340+ "version": "4.0.2",
3341+ "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
3342+ "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==",
3343+ "dev": true,
3344+ "engines": {
3345+ "node": ">=0.4"
3346+ }
3347+ },
3348+ "node_modules/yaml": {
3349+ "version": "1.10.2",
3350+ "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz",
3351+ "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==",
3352+ "engines": {
3353+ "node": ">= 6"
3354+ }
3355+ },
3356+ "node_modules/zustand": {
3357+ "version": "4.0.0-rc.1",
3358+ "resolved": "https://registry.npmjs.org/zustand/-/zustand-4.0.0-rc.1.tgz",
3359+ "integrity": "sha512-qgcs7zLqBdHu0PuT3GW4WCIY5SgXdsv30GQMu9Qpp1BA2aS+sNS8l4x0hWuyEhjXkN+701aGWawhKDv6oWJAcw==",
3360+ "dependencies": {
3361+ "use-sync-external-store": "1.1.0"
3362+ },
3363+ "engines": {
3364+ "node": ">=12.7.0"
3365+ },
3366+ "peerDependencies": {
3367+ "immer": ">=9.0",
3368+ "react": ">=16.8"
3369+ },
3370+ "peerDependenciesMeta": {
3371+ "immer": {
3372+ "optional": true
3373+ },
3374+ "react": {
3375+ "optional": true
3376+ }
3377+ }
3378+ }
3379+ },
3380+ "dependencies": {
3381+ "@ampproject/remapping": {
3382+ "version": "2.2.0",
3383+ "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz",
3384+ "integrity": "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==",
3385+ "requires": {
3386+ "@jridgewell/gen-mapping": "^0.1.0",
3387+ "@jridgewell/trace-mapping": "^0.3.9"
3388+ }
3389+ },
3390+ "@babel/code-frame": {
3391+ "version": "7.18.6",
3392+ "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz",
3393+ "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==",
3394+ "requires": {
3395+ "@babel/highlight": "^7.18.6"
3396+ }
3397+ },
3398+ "@babel/compat-data": {
3399+ "version": "7.18.6",
3400+ "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.18.6.tgz",
3401+ "integrity": "sha512-tzulrgDT0QD6U7BJ4TKVk2SDDg7wlP39P9yAx1RfLy7vP/7rsDRlWVfbWxElslu56+r7QOhB2NSDsabYYruoZQ=="
3402+ },
3403+ "@babel/core": {
3404+ "version": "7.18.6",
3405+ "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.18.6.tgz",
3406+ "integrity": "sha512-cQbWBpxcbbs/IUredIPkHiAGULLV8iwgNRMFzvbhEXISp4f3rUUXE5+TIw6KwUWUR3DwyI6gmBRnmAtYaWehwQ==",
3407+ "requires": {
3408+ "@ampproject/remapping": "^2.1.0",
3409+ "@babel/code-frame": "^7.18.6",
3410+ "@babel/generator": "^7.18.6",
3411+ "@babel/helper-compilation-targets": "^7.18.6",
3412+ "@babel/helper-module-transforms": "^7.18.6",
3413+ "@babel/helpers": "^7.18.6",
3414+ "@babel/parser": "^7.18.6",
3415+ "@babel/template": "^7.18.6",
3416+ "@babel/traverse": "^7.18.6",
3417+ "@babel/types": "^7.18.6",
3418+ "convert-source-map": "^1.7.0",
3419+ "debug": "^4.1.0",
3420+ "gensync": "^1.0.0-beta.2",
3421+ "json5": "^2.2.1",
3422+ "semver": "^6.3.0"
3423+ }
3424+ },
3425+ "@babel/generator": {
3426+ "version": "7.18.7",
3427+ "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.18.7.tgz",
3428+ "integrity": "sha512-shck+7VLlY72a2w9c3zYWuE1pwOKEiQHV7GTUbSnhyl5eu3i04t30tBY82ZRWrDfo3gkakCFtevExnxbkf2a3A==",
3429+ "requires": {
3430+ "@babel/types": "^7.18.7",
3431+ "@jridgewell/gen-mapping": "^0.3.2",
3432+ "jsesc": "^2.5.1"
3433+ },
3434+ "dependencies": {
3435+ "@jridgewell/gen-mapping": {
3436+ "version": "0.3.2",
3437+ "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz",
3438+ "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==",
3439+ "requires": {
3440+ "@jridgewell/set-array": "^1.0.1",
3441+ "@jridgewell/sourcemap-codec": "^1.4.10",
3442+ "@jridgewell/trace-mapping": "^0.3.9"
3443+ }
3444+ }
3445+ }
3446+ },
3447+ "@babel/helper-compilation-targets": {
3448+ "version": "7.18.6",
3449+ "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.18.6.tgz",
3450+ "integrity": "sha512-vFjbfhNCzqdeAtZflUFrG5YIFqGTqsctrtkZ1D/NB0mDW9TwW3GmmUepYY4G9wCET5rY5ugz4OGTcLd614IzQg==",
3451+ "requires": {
3452+ "@babel/compat-data": "^7.18.6",
3453+ "@babel/helper-validator-option": "^7.18.6",
3454+ "browserslist": "^4.20.2",
3455+ "semver": "^6.3.0"
3456+ }
3457+ },
3458+ "@babel/helper-environment-visitor": {
3459+ "version": "7.18.6",
3460+ "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.6.tgz",
3461+ "integrity": "sha512-8n6gSfn2baOY+qlp+VSzsosjCVGFqWKmDF0cCWOybh52Dw3SEyoWR1KrhMJASjLwIEkkAufZ0xvr+SxLHSpy2Q=="
3462+ },
3463+ "@babel/helper-function-name": {
3464+ "version": "7.18.6",
3465+ "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.18.6.tgz",
3466+ "integrity": "sha512-0mWMxV1aC97dhjCah5U5Ua7668r5ZmSC2DLfH2EZnf9c3/dHZKiFa5pRLMH5tjSl471tY6496ZWk/kjNONBxhw==",
3467+ "requires": {
3468+ "@babel/template": "^7.18.6",
3469+ "@babel/types": "^7.18.6"
3470+ }
3471+ },
3472+ "@babel/helper-hoist-variables": {
3473+ "version": "7.18.6",
3474+ "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz",
3475+ "integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==",
3476+ "requires": {
3477+ "@babel/types": "^7.18.6"
3478+ }
3479+ },
3480+ "@babel/helper-module-imports": {
3481+ "version": "7.18.6",
3482+ "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz",
3483+ "integrity": "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==",
3484+ "requires": {
3485+ "@babel/types": "^7.18.6"
3486+ }
3487+ },
3488+ "@babel/helper-module-transforms": {
3489+ "version": "7.18.6",
3490+ "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.18.6.tgz",
3491+ "integrity": "sha512-L//phhB4al5uucwzlimruukHB3jRd5JGClwRMD/ROrVjXfLqovYnvQrK/JK36WYyVwGGO7OD3kMyVTjx+WVPhw==",
3492+ "requires": {
3493+ "@babel/helper-environment-visitor": "^7.18.6",
3494+ "@babel/helper-module-imports": "^7.18.6",
3495+ "@babel/helper-simple-access": "^7.18.6",
3496+ "@babel/helper-split-export-declaration": "^7.18.6",
3497+ "@babel/helper-validator-identifier": "^7.18.6",
3498+ "@babel/template": "^7.18.6",
3499+ "@babel/traverse": "^7.18.6",
3500+ "@babel/types": "^7.18.6"
3501+ }
3502+ },
3503+ "@babel/helper-plugin-utils": {
3504+ "version": "7.18.6",
3505+ "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.18.6.tgz",
3506+ "integrity": "sha512-gvZnm1YAAxh13eJdkb9EWHBnF3eAub3XTLCZEehHT2kWxiKVRL64+ae5Y6Ivne0mVHmMYKT+xWgZO+gQhuLUBg=="
3507+ },
3508+ "@babel/helper-simple-access": {
3509+ "version": "7.18.6",
3510+ "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.18.6.tgz",
3511+ "integrity": "sha512-iNpIgTgyAvDQpDj76POqg+YEt8fPxx3yaNBg3S30dxNKm2SWfYhD0TGrK/Eu9wHpUW63VQU894TsTg+GLbUa1g==",
3512+ "requires": {
3513+ "@babel/types": "^7.18.6"
3514+ }
3515+ },
3516+ "@babel/helper-split-export-declaration": {
3517+ "version": "7.18.6",
3518+ "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz",
3519+ "integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==",
3520+ "requires": {
3521+ "@babel/types": "^7.18.6"
3522+ }
3523+ },
3524+ "@babel/helper-validator-identifier": {
3525+ "version": "7.18.6",
3526+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.18.6.tgz",
3527+ "integrity": "sha512-MmetCkz9ej86nJQV+sFCxoGGrUbU3q02kgLciwkrt9QqEB7cP39oKEY0PakknEO0Gu20SskMRi+AYZ3b1TpN9g=="
3528+ },
3529+ "@babel/helper-validator-option": {
3530+ "version": "7.18.6",
3531+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz",
3532+ "integrity": "sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw=="
3533+ },
3534+ "@babel/helpers": {
3535+ "version": "7.18.6",
3536+ "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.18.6.tgz",
3537+ "integrity": "sha512-vzSiiqbQOghPngUYt/zWGvK3LAsPhz55vc9XNN0xAl2gV4ieShI2OQli5duxWHD+72PZPTKAcfcZDE1Cwc5zsQ==",
3538+ "requires": {
3539+ "@babel/template": "^7.18.6",
3540+ "@babel/traverse": "^7.18.6",
3541+ "@babel/types": "^7.18.6"
3542+ }
3543+ },
3544+ "@babel/highlight": {
3545+ "version": "7.18.6",
3546+ "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz",
3547+ "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==",
3548+ "requires": {
3549+ "@babel/helper-validator-identifier": "^7.18.6",
3550+ "chalk": "^2.0.0",
3551+ "js-tokens": "^4.0.0"
3552+ }
3553+ },
3554+ "@babel/parser": {
3555+ "version": "7.18.6",
3556+ "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.18.6.tgz",
3557+ "integrity": "sha512-uQVSa9jJUe/G/304lXspfWVpKpK4euFLgGiMQFOCpM/bgcAdeoHwi/OQz23O9GK2osz26ZiXRRV9aV+Yl1O8tw=="
3558+ },
3559+ "@babel/plugin-syntax-jsx": {
3560+ "version": "7.18.6",
3561+ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.18.6.tgz",
3562+ "integrity": "sha512-6mmljtAedFGTWu2p/8WIORGwy+61PLgOMPOdazc7YoJ9ZCWUyFy3A6CpPkRKLKD1ToAesxX8KGEViAiLo9N+7Q==",
3563+ "requires": {
3564+ "@babel/helper-plugin-utils": "^7.18.6"
3565+ }
3566+ },
3567+ "@babel/plugin-transform-react-jsx-self": {
3568+ "version": "7.18.6",
3569+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.18.6.tgz",
3570+ "integrity": "sha512-A0LQGx4+4Jv7u/tWzoJF7alZwnBDQd6cGLh9P+Ttk4dpiL+J5p7NSNv/9tlEFFJDq3kjxOavWmbm6t0Gk+A3Ig==",
3571+ "dev": true,
3572+ "requires": {
3573+ "@babel/helper-plugin-utils": "^7.18.6"
3574+ }
3575+ },
3576+ "@babel/plugin-transform-react-jsx-source": {
3577+ "version": "7.18.6",
3578+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.18.6.tgz",
3579+ "integrity": "sha512-utZmlASneDfdaMh0m/WausbjUjEdGrQJz0vFK93d7wD3xf5wBtX219+q6IlCNZeguIcxS2f/CvLZrlLSvSHQXw==",
3580+ "dev": true,
3581+ "requires": {
3582+ "@babel/helper-plugin-utils": "^7.18.6"
3583+ }
3584+ },
3585+ "@babel/runtime": {
3586+ "version": "7.18.6",
3587+ "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.18.6.tgz",
3588+ "integrity": "sha512-t9wi7/AW6XtKahAe20Yw0/mMljKq0B1r2fPdvaAdV/KPDZewFXdaaa6K7lxmZBZ8FBNpCiAT6iHPmd6QO9bKfQ==",
3589+ "requires": {
3590+ "regenerator-runtime": "^0.13.4"
3591+ }
3592+ },
3593+ "@babel/template": {
3594+ "version": "7.18.6",
3595+ "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.18.6.tgz",
3596+ "integrity": "sha512-JoDWzPe+wgBsTTgdnIma3iHNFC7YVJoPssVBDjiHfNlyt4YcunDtcDOUmfVDfCK5MfdsaIoX9PkijPhjH3nYUw==",
3597+ "requires": {
3598+ "@babel/code-frame": "^7.18.6",
3599+ "@babel/parser": "^7.18.6",
3600+ "@babel/types": "^7.18.6"
3601+ }
3602+ },
3603+ "@babel/traverse": {
3604+ "version": "7.18.6",
3605+ "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.18.6.tgz",
3606+ "integrity": "sha512-zS/OKyqmD7lslOtFqbscH6gMLFYOfG1YPqCKfAW5KrTeolKqvB8UelR49Fpr6y93kYkW2Ik00mT1LOGiAGvizw==",
3607+ "requires": {
3608+ "@babel/code-frame": "^7.18.6",
3609+ "@babel/generator": "^7.18.6",
3610+ "@babel/helper-environment-visitor": "^7.18.6",
3611+ "@babel/helper-function-name": "^7.18.6",
3612+ "@babel/helper-hoist-variables": "^7.18.6",
3613+ "@babel/helper-split-export-declaration": "^7.18.6",
3614+ "@babel/parser": "^7.18.6",
3615+ "@babel/types": "^7.18.6",
3616+ "debug": "^4.1.0",
3617+ "globals": "^11.1.0"
3618+ }
3619+ },
3620+ "@babel/types": {
3621+ "version": "7.18.7",
3622+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.18.7.tgz",
3623+ "integrity": "sha512-QG3yxTcTIBoAcQmkCs+wAPYZhu7Dk9rXKacINfNbdJDNERTbLQbHGyVG8q/YGMPeCJRIhSY0+fTc5+xuh6WPSQ==",
3624+ "requires": {
3625+ "@babel/helper-validator-identifier": "^7.18.6",
3626+ "to-fast-properties": "^2.0.0"
3627+ }
3628+ },
3629+ "@emotion/babel-plugin": {
3630+ "version": "11.9.2",
3631+ "resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.9.2.tgz",
3632+ "integrity": "sha512-Pr/7HGH6H6yKgnVFNEj2MVlreu3ADqftqjqwUvDy/OJzKFgxKeTQ+eeUf20FOTuHVkDON2iNa25rAXVYtWJCjw==",
3633+ "requires": {
3634+ "@babel/helper-module-imports": "^7.12.13",
3635+ "@babel/plugin-syntax-jsx": "^7.12.13",
3636+ "@babel/runtime": "^7.13.10",
3637+ "@emotion/hash": "^0.8.0",
3638+ "@emotion/memoize": "^0.7.5",
3639+ "@emotion/serialize": "^1.0.2",
3640+ "babel-plugin-macros": "^2.6.1",
3641+ "convert-source-map": "^1.5.0",
3642+ "escape-string-regexp": "^4.0.0",
3643+ "find-root": "^1.1.0",
3644+ "source-map": "^0.5.7",
3645+ "stylis": "4.0.13"
3646+ },
3647+ "dependencies": {
3648+ "escape-string-regexp": {
3649+ "version": "4.0.0",
3650+ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
3651+ "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA=="
3652+ }
3653+ }
3654+ },
3655+ "@emotion/cache": {
3656+ "version": "11.9.3",
3657+ "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.9.3.tgz",
3658+ "integrity": "sha512-0dgkI/JKlCXa+lEXviaMtGBL0ynpx4osh7rjOXE71q9bIF8G+XhJgvi+wDu0B0IdCVx37BffiwXlN9I3UuzFvg==",
3659+ "requires": {
3660+ "@emotion/memoize": "^0.7.4",
3661+ "@emotion/sheet": "^1.1.1",
3662+ "@emotion/utils": "^1.0.0",
3663+ "@emotion/weak-memoize": "^0.2.5",
3664+ "stylis": "4.0.13"
3665+ }
3666+ },
3667+ "@emotion/hash": {
3668+ "version": "0.8.0",
3669+ "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.8.0.tgz",
3670+ "integrity": "sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow=="
3671+ },
3672+ "@emotion/memoize": {
3673+ "version": "0.7.5",
3674+ "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.7.5.tgz",
3675+ "integrity": "sha512-igX9a37DR2ZPGYtV6suZ6whr8pTFtyHL3K/oLUotxpSVO2ASaprmAe2Dkq7tBo7CRY7MMDrAa9nuQP9/YG8FxQ=="
3676+ },
3677+ "@emotion/react": {
3678+ "version": "11.9.3",
3679+ "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.9.3.tgz",
3680+ "integrity": "sha512-g9Q1GcTOlzOEjqwuLF/Zd9LC+4FljjPjDfxSM7KmEakm+hsHXk+bYZ2q+/hTJzr0OUNkujo72pXLQvXj6H+GJQ==",
3681+ "requires": {
3682+ "@babel/runtime": "^7.13.10",
3683+ "@emotion/babel-plugin": "^11.7.1",
3684+ "@emotion/cache": "^11.9.3",
3685+ "@emotion/serialize": "^1.0.4",
3686+ "@emotion/utils": "^1.1.0",
3687+ "@emotion/weak-memoize": "^0.2.5",
3688+ "hoist-non-react-statics": "^3.3.1"
3689+ }
3690+ },
3691+ "@emotion/serialize": {
3692+ "version": "1.0.4",
3693+ "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.0.4.tgz",
3694+ "integrity": "sha512-1JHamSpH8PIfFwAMryO2bNka+y8+KA5yga5Ocf2d7ZEiJjb7xlLW7aknBGZqJLajuLOvJ+72vN+IBSwPlXD1Pg==",
3695+ "requires": {
3696+ "@emotion/hash": "^0.8.0",
3697+ "@emotion/memoize": "^0.7.4",
3698+ "@emotion/unitless": "^0.7.5",
3699+ "@emotion/utils": "^1.0.0",
3700+ "csstype": "^3.0.2"
3701+ }
3702+ },
3703+ "@emotion/sheet": {
3704+ "version": "1.1.1",
3705+ "resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.1.1.tgz",
3706+ "integrity": "sha512-J3YPccVRMiTZxYAY0IOq3kd+hUP8idY8Kz6B/Cyo+JuXq52Ek+zbPbSQUrVQp95aJ+lsAW7DPL1P2Z+U1jGkKA=="
3707+ },
3708+ "@emotion/unitless": {
3709+ "version": "0.7.5",
3710+ "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.7.5.tgz",
3711+ "integrity": "sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg=="
3712+ },
3713+ "@emotion/utils": {
3714+ "version": "1.1.0",
3715+ "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.1.0.tgz",
3716+ "integrity": "sha512-iRLa/Y4Rs5H/f2nimczYmS5kFJEbpiVvgN3XVfZ022IYhuNA1IRSHEizcof88LtCTXtl9S2Cxt32KgaXEu72JQ=="
3717+ },
3718+ "@emotion/weak-memoize": {
3719+ "version": "0.2.5",
3720+ "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.2.5.tgz",
3721+ "integrity": "sha512-6U71C2Wp7r5XtFtQzYrW5iKFT67OixrSxjI4MptCHzdSVlgabczzqLe0ZSgnub/5Kp4hSbpDB1tMytZY9pwxxA=="
3722+ },
3723+ "@heroicons/react": {
3724+ "version": "1.0.6",
3725+ "resolved": "https://registry.npmjs.org/@heroicons/react/-/react-1.0.6.tgz",
3726+ "integrity": "sha512-JJCXydOFWMDpCP4q13iEplA503MQO3xLoZiKum+955ZCtHINWnx26CUxVxxFQu/uLb4LW3ge15ZpzIkXKkJ8oQ==",
3727+ "requires": {}
3728+ },
3729+ "@jridgewell/gen-mapping": {
3730+ "version": "0.1.1",
3731+ "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz",
3732+ "integrity": "sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==",
3733+ "requires": {
3734+ "@jridgewell/set-array": "^1.0.0",
3735+ "@jridgewell/sourcemap-codec": "^1.4.10"
3736+ }
3737+ },
3738+ "@jridgewell/resolve-uri": {
3739+ "version": "3.0.8",
3740+ "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.0.8.tgz",
3741+ "integrity": "sha512-YK5G9LaddzGbcucK4c8h5tWFmMPBvRZ/uyWmN1/SbBdIvqGUdWGkJ5BAaccgs6XbzVLsqbPJrBSFwKv3kT9i7w=="
3742+ },
3743+ "@jridgewell/set-array": {
3744+ "version": "1.1.2",
3745+ "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz",
3746+ "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw=="
3747+ },
3748+ "@jridgewell/sourcemap-codec": {
3749+ "version": "1.4.14",
3750+ "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz",
3751+ "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw=="
3752+ },
3753+ "@jridgewell/trace-mapping": {
3754+ "version": "0.3.14",
3755+ "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.14.tgz",
3756+ "integrity": "sha512-bJWEfQ9lPTvm3SneWwRFVLzrh6nhjwqw7TUFFBEMzwvg7t7PCDenf2lDwqo4NQXzdpgBXyFgDWnQA+2vkruksQ==",
3757+ "requires": {
3758+ "@jridgewell/resolve-uri": "^3.0.3",
3759+ "@jridgewell/sourcemap-codec": "^1.4.10"
3760+ }
3761+ },
3762+ "@microsoft/fetch-event-source": {
3763+ "version": "2.0.1",
3764+ "resolved": "https://registry.npmjs.org/@microsoft/fetch-event-source/-/fetch-event-source-2.0.1.tgz",
3765+ "integrity": "sha512-W6CLUJ2eBMw3Rec70qrsEW0jOm/3twwJv21mrmj2yORiaVmVYGS4sSS5yUwvQc1ZlDLYGPnClVWmUUMagKNsfA=="
3766+ },
3767+ "@nodelib/fs.scandir": {
3768+ "version": "2.1.5",
3769+ "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
3770+ "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==",
3771+ "dev": true,
3772+ "requires": {
3773+ "@nodelib/fs.stat": "2.0.5",
3774+ "run-parallel": "^1.1.9"
3775+ }
3776+ },
3777+ "@nodelib/fs.stat": {
3778+ "version": "2.0.5",
3779+ "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz",
3780+ "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==",
3781+ "dev": true
3782+ },
3783+ "@nodelib/fs.walk": {
3784+ "version": "1.2.8",
3785+ "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz",
3786+ "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==",
3787+ "dev": true,
3788+ "requires": {
3789+ "@nodelib/fs.scandir": "2.1.5",
3790+ "fastq": "^1.6.0"
3791+ }
3792+ },
3793+ "@radix-ui/number": {
3794+ "version": "0.1.0",
3795+ "resolved": "https://registry.npmjs.org/@radix-ui/number/-/number-0.1.0.tgz",
3796+ "integrity": "sha512-rpf6QiOWLHAkM4FEMYu9i+5Jr8cKT893+R4mPpcdsy4LD7omr9JfdOqj/h/xPA5+EcVrpMMlU6rrRYpUB5UI8g==",
3797+ "requires": {
3798+ "@babel/runtime": "^7.13.10"
3799+ }
3800+ },
3801+ "@radix-ui/popper": {
3802+ "version": "0.1.0",
3803+ "resolved": "https://registry.npmjs.org/@radix-ui/popper/-/popper-0.1.0.tgz",
3804+ "integrity": "sha512-uzYeElL3w7SeNMuQpXiFlBhTT+JyaNMCwDfjKkrzugEcYrf5n52PHqncNdQPUtR42hJh8V9FsqyEDbDxkeNjJQ==",
3805+ "requires": {
3806+ "@babel/runtime": "^7.13.10",
3807+ "csstype": "^3.0.4"
3808+ }
3809+ },
3810+ "@radix-ui/primitive": {
3811+ "version": "0.1.0",
3812+ "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-0.1.0.tgz",
3813+ "integrity": "sha512-tqxZKybwN5Fa3VzZry4G6mXAAb9aAqKmPtnVbZpL0vsBwvOHTBwsjHVPXylocYLwEtBY9SCe665bYnNB515uoA==",
3814+ "requires": {
3815+ "@babel/runtime": "^7.13.10"
3816+ }
3817+ },
3818+ "@radix-ui/react-arrow": {
3819+ "version": "0.1.4",
3820+ "resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-0.1.4.tgz",
3821+ "integrity": "sha512-BB6XzAb7Ml7+wwpFdYVtZpK1BlMgqyafSQNGzhIpSZ4uXvXOHPlR5GP8M449JkeQzgQjv9Mp1AsJxFC0KuOtuA==",
3822+ "requires": {
3823+ "@babel/runtime": "^7.13.10",
3824+ "@radix-ui/react-primitive": "0.1.4"
3825+ }
3826+ },
3827+ "@radix-ui/react-collection": {
3828+ "version": "0.1.4",
3829+ "resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-0.1.4.tgz",
3830+ "integrity": "sha512-3muGI15IdgaDFjOcO7xX8a35HQRBRF6LH9pS6UCeZeRmbslkVeHyJRQr2rzICBUoX7zgIA0kXyMDbpQnJGyJTA==",
3831+ "requires": {
3832+ "@babel/runtime": "^7.13.10",
3833+ "@radix-ui/react-compose-refs": "0.1.0",
3834+ "@radix-ui/react-context": "0.1.1",
3835+ "@radix-ui/react-primitive": "0.1.4",
3836+ "@radix-ui/react-slot": "0.1.2"
3837+ }
3838+ },
3839+ "@radix-ui/react-compose-refs": {
3840+ "version": "0.1.0",
3841+ "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-0.1.0.tgz",
3842+ "integrity": "sha512-eyclbh+b77k+69Dk72q3694OHrn9B3QsoIRx7ywX341U9RK1ThgQjMFZoPtmZNQTksXHLNEiefR8hGVeFyInGg==",
3843+ "requires": {
3844+ "@babel/runtime": "^7.13.10"
3845+ }
3846+ },
3847+ "@radix-ui/react-context": {
3848+ "version": "0.1.1",
3849+ "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-0.1.1.tgz",
3850+ "integrity": "sha512-PkyVX1JsLBioeu0jB9WvRpDBBLtLZohVDT3BB5CTSJqActma8S8030P57mWZb4baZifMvN7KKWPAA40UmWKkQg==",
3851+ "requires": {
3852+ "@babel/runtime": "^7.13.10"
3853+ }
3854+ },
3855+ "@radix-ui/react-dismissable-layer": {
3856+ "version": "0.1.5",
3857+ "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-0.1.5.tgz",
3858+ "integrity": "sha512-J+fYWijkX4M4QKwf9dtu1oC0U6e6CEl8WhBp3Ad23yz2Hia0XCo6Pk/mp5CAFy4QBtQedTSkhW05AdtSOEoajQ==",
3859+ "requires": {
3860+ "@babel/runtime": "^7.13.10",
3861+ "@radix-ui/primitive": "0.1.0",
3862+ "@radix-ui/react-compose-refs": "0.1.0",
3863+ "@radix-ui/react-primitive": "0.1.4",
3864+ "@radix-ui/react-use-body-pointer-events": "0.1.1",
3865+ "@radix-ui/react-use-callback-ref": "0.1.0",
3866+ "@radix-ui/react-use-escape-keydown": "0.1.0"
3867+ }
3868+ },
3869+ "@radix-ui/react-dropdown-menu": {
3870+ "version": "0.1.6",
3871+ "resolved": "https://registry.npmjs.org/@radix-ui/react-dropdown-menu/-/react-dropdown-menu-0.1.6.tgz",
3872+ "integrity": "sha512-RZhtzjWwJ4ZBN7D8ek4Zn+ilHzYuYta9yIxFnbC0pfqMnSi67IQNONo1tuuNqtFh9SRHacPKc65zo+kBBlxtdg==",
3873+ "requires": {
3874+ "@babel/runtime": "^7.13.10",
3875+ "@radix-ui/primitive": "0.1.0",
3876+ "@radix-ui/react-compose-refs": "0.1.0",
3877+ "@radix-ui/react-context": "0.1.1",
3878+ "@radix-ui/react-id": "0.1.5",
3879+ "@radix-ui/react-menu": "0.1.6",
3880+ "@radix-ui/react-primitive": "0.1.4",
3881+ "@radix-ui/react-use-controllable-state": "0.1.0"
3882+ }
3883+ },
3884+ "@radix-ui/react-focus-guards": {
3885+ "version": "0.1.0",
3886+ "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-guards/-/react-focus-guards-0.1.0.tgz",
3887+ "integrity": "sha512-kRx/swAjEfBpQ3ns7J3H4uxpXuWCqN7MpALiSDOXiyo2vkWv0L9sxvbpZeTulINuE3CGMzicVMuNc/VWXjFKOg==",
3888+ "requires": {
3889+ "@babel/runtime": "^7.13.10"
3890+ }
3891+ },
3892+ "@radix-ui/react-focus-scope": {
3893+ "version": "0.1.4",
3894+ "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-0.1.4.tgz",
3895+ "integrity": "sha512-fbA4ES3H4Wkxp+OeLhvN6SwL7mXNn/aBtUf7DRYxY9+Akrf7dRxl2ck4lgcpPsSg3zSDsEwLcY+h5cmj5yvlug==",
3896+ "requires": {
3897+ "@babel/runtime": "^7.13.10",
3898+ "@radix-ui/react-compose-refs": "0.1.0",
3899+ "@radix-ui/react-primitive": "0.1.4",
3900+ "@radix-ui/react-use-callback-ref": "0.1.0"
3901+ }
3902+ },
3903+ "@radix-ui/react-id": {
3904+ "version": "0.1.5",
3905+ "resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-0.1.5.tgz",
3906+ "integrity": "sha512-IPc4H/63bes0IZ1GJJozSEkSWcDyhNGtKFWUpJ+XtaLyQ1X3x7Mf6fWwWhDcpqlYEP+5WtAvfqcyEsyjP+ZhBQ==",
3907+ "requires": {
3908+ "@babel/runtime": "^7.13.10",
3909+ "@radix-ui/react-use-layout-effect": "0.1.0"
3910+ }
3911+ },
3912+ "@radix-ui/react-label": {
3913+ "version": "0.1.5",
3914+ "resolved": "https://registry.npmjs.org/@radix-ui/react-label/-/react-label-0.1.5.tgz",
3915+ "integrity": "sha512-Au9+n4/DhvjR0IHhvZ1LPdx/OW+3CGDie30ZyCkbSHIuLp4/CV4oPPGBwJ1vY99Jog3zyQhsGww9MXj8O9Aj/A==",
3916+ "requires": {
3917+ "@babel/runtime": "^7.13.10",
3918+ "@radix-ui/react-compose-refs": "0.1.0",
3919+ "@radix-ui/react-context": "0.1.1",
3920+ "@radix-ui/react-id": "0.1.5",
3921+ "@radix-ui/react-primitive": "0.1.4"
3922+ }
3923+ },
3924+ "@radix-ui/react-menu": {
3925+ "version": "0.1.6",
3926+ "resolved": "https://registry.npmjs.org/@radix-ui/react-menu/-/react-menu-0.1.6.tgz",
3927+ "integrity": "sha512-ho3+bhpr3oAFkOBJ8VkUb1BcGoiZBB3OmcWPqa6i5RTUKrzNX/d6rauochu2xDlWjiRtpVuiAcsTVOeIC4FbYQ==",
3928+ "requires": {
3929+ "@babel/runtime": "^7.13.10",
3930+ "@radix-ui/primitive": "0.1.0",
3931+ "@radix-ui/react-collection": "0.1.4",
3932+ "@radix-ui/react-compose-refs": "0.1.0",
3933+ "@radix-ui/react-context": "0.1.1",
3934+ "@radix-ui/react-dismissable-layer": "0.1.5",
3935+ "@radix-ui/react-focus-guards": "0.1.0",
3936+ "@radix-ui/react-focus-scope": "0.1.4",
3937+ "@radix-ui/react-id": "0.1.5",
3938+ "@radix-ui/react-popper": "0.1.4",
3939+ "@radix-ui/react-portal": "0.1.4",
3940+ "@radix-ui/react-presence": "0.1.2",
3941+ "@radix-ui/react-primitive": "0.1.4",
3942+ "@radix-ui/react-roving-focus": "0.1.5",
3943+ "@radix-ui/react-use-callback-ref": "0.1.0",
3944+ "@radix-ui/react-use-direction": "0.1.0",
3945+ "aria-hidden": "^1.1.1",
3946+ "react-remove-scroll": "^2.4.0"
3947+ }
3948+ },
3949+ "@radix-ui/react-popper": {
3950+ "version": "0.1.4",
3951+ "resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-0.1.4.tgz",
3952+ "integrity": "sha512-18gDYof97t8UQa7zwklG1Dr8jIdj3u+rVOQLzPi9f5i1YQak/pVGkaqw8aY+iDUknKKuZniTk/7jbAJUYlKyOw==",
3953+ "requires": {
3954+ "@babel/runtime": "^7.13.10",
3955+ "@radix-ui/popper": "0.1.0",
3956+ "@radix-ui/react-arrow": "0.1.4",
3957+ "@radix-ui/react-compose-refs": "0.1.0",
3958+ "@radix-ui/react-context": "0.1.1",
3959+ "@radix-ui/react-primitive": "0.1.4",
3960+ "@radix-ui/react-use-rect": "0.1.1",
3961+ "@radix-ui/react-use-size": "0.1.1",
3962+ "@radix-ui/rect": "0.1.1"
3963+ }
3964+ },
3965+ "@radix-ui/react-portal": {
3966+ "version": "0.1.4",
3967+ "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-0.1.4.tgz",
3968+ "integrity": "sha512-MO0wRy2eYRTZ/CyOri9NANCAtAtq89DEtg90gicaTlkCfdqCLEBsLb+/q66BZQTr3xX/Vq01nnVfc/TkCqoqvw==",
3969+ "requires": {
3970+ "@babel/runtime": "^7.13.10",
3971+ "@radix-ui/react-primitive": "0.1.4",
3972+ "@radix-ui/react-use-layout-effect": "0.1.0"
3973+ }
3974+ },
3975+ "@radix-ui/react-presence": {
3976+ "version": "0.1.2",
3977+ "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-0.1.2.tgz",
3978+ "integrity": "sha512-3BRlFZraooIUfRlyN+b/Xs5hq1lanOOo/+3h6Pwu2GMFjkGKKa4Rd51fcqGqnVlbr3jYg+WLuGyAV4KlgqwrQw==",
3979+ "requires": {
3980+ "@babel/runtime": "^7.13.10",
3981+ "@radix-ui/react-compose-refs": "0.1.0",
3982+ "@radix-ui/react-use-layout-effect": "0.1.0"
3983+ }
3984+ },
3985+ "@radix-ui/react-primitive": {
3986+ "version": "0.1.4",
3987+ "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-0.1.4.tgz",
3988+ "integrity": "sha512-6gSl2IidySupIMJFjYnDIkIWRyQdbu/AHK7rbICPani+LW4b0XdxBXc46og/iZvuwW8pjCS8I2SadIerv84xYA==",
3989+ "requires": {
3990+ "@babel/runtime": "^7.13.10",
3991+ "@radix-ui/react-slot": "0.1.2"
3992+ }
3993+ },
3994+ "@radix-ui/react-roving-focus": {
3995+ "version": "0.1.5",
3996+ "resolved": "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-0.1.5.tgz",
3997+ "integrity": "sha512-ClwKPS5JZE+PaHCoW7eu1onvE61pDv4kO8W4t5Ra3qMFQiTJLZMdpBQUhksN//DaVygoLirz4Samdr5Y1x1FSA==",
3998+ "requires": {
3999+ "@babel/runtime": "^7.13.10",
4000+ "@radix-ui/primitive": "0.1.0",
4001+ "@radix-ui/react-collection": "0.1.4",
4002+ "@radix-ui/react-compose-refs": "0.1.0",
4003+ "@radix-ui/react-context": "0.1.1",
4004+ "@radix-ui/react-id": "0.1.5",
4005+ "@radix-ui/react-primitive": "0.1.4",
4006+ "@radix-ui/react-use-callback-ref": "0.1.0",
4007+ "@radix-ui/react-use-controllable-state": "0.1.0"
4008+ }
4009+ },
4010+ "@radix-ui/react-select": {
4011+ "version": "0.1.1",
4012+ "resolved": "https://registry.npmjs.org/@radix-ui/react-select/-/react-select-0.1.1.tgz",
4013+ "integrity": "sha512-xY3jLz2c6ZBHflldGsA79bE/swUfRMpiRPQf+JDihOufsd3z5uW22PFe0MS5bGZiIpK6aAZAvwqEd2Bu7hqp8w==",
4014+ "requires": {
4015+ "@babel/runtime": "^7.13.10",
4016+ "@radix-ui/number": "0.1.0",
4017+ "@radix-ui/primitive": "0.1.0",
4018+ "@radix-ui/react-collection": "0.1.4",
4019+ "@radix-ui/react-compose-refs": "0.1.0",
4020+ "@radix-ui/react-context": "0.1.1",
4021+ "@radix-ui/react-dismissable-layer": "0.1.5",
4022+ "@radix-ui/react-focus-scope": "0.1.4",
4023+ "@radix-ui/react-id": "0.1.5",
4024+ "@radix-ui/react-label": "0.1.5",
4025+ "@radix-ui/react-portal": "0.1.4",
4026+ "@radix-ui/react-primitive": "0.1.4",
4027+ "@radix-ui/react-use-callback-ref": "0.1.0",
4028+ "@radix-ui/react-use-controllable-state": "0.1.0",
4029+ "@radix-ui/react-use-layout-effect": "0.1.0",
4030+ "@radix-ui/react-use-previous": "0.1.1",
4031+ "@radix-ui/react-visually-hidden": "0.1.4",
4032+ "aria-hidden": "^1.1.1",
4033+ "react-remove-scroll": "^2.4.0"
4034+ }
4035+ },
4036+ "@radix-ui/react-slot": {
4037+ "version": "0.1.2",
4038+ "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-0.1.2.tgz",
4039+ "integrity": "sha512-ADkqfL+agEzEguU3yS26jfB50hRrwf7U4VTwAOZEmi/g+ITcBWe12yM46ueS/UCIMI9Py+gFUaAdxgxafFvY2Q==",
4040+ "requires": {
4041+ "@babel/runtime": "^7.13.10",
4042+ "@radix-ui/react-compose-refs": "0.1.0"
4043+ }
4044+ },
4045+ "@radix-ui/react-toggle": {
4046+ "version": "0.1.4",
4047+ "resolved": "https://registry.npmjs.org/@radix-ui/react-toggle/-/react-toggle-0.1.4.tgz",
4048+ "integrity": "sha512-gxUq6NgMc4ChV8VJnwdYqueeoblspwXHAexYo+jM9N2hFLbI1C587jLjdTHzIcUa9q68Xaw4jtiImWDOokEhRw==",
4049+ "requires": {
4050+ "@babel/runtime": "^7.13.10",
4051+ "@radix-ui/primitive": "0.1.0",
4052+ "@radix-ui/react-primitive": "0.1.4",
4053+ "@radix-ui/react-use-controllable-state": "0.1.0"
4054+ }
4055+ },
4056+ "@radix-ui/react-toggle-group": {
4057+ "version": "0.1.5",
4058+ "resolved": "https://registry.npmjs.org/@radix-ui/react-toggle-group/-/react-toggle-group-0.1.5.tgz",
4059+ "integrity": "sha512-Yp14wFiqe00azF+sG5CCJz4JGOP/f5Jj+CxLlZCmMpG5qhVTWeaeG4YH6pvX4KL41fS8x9FAaLb8wW9y01o67g==",
4060+ "requires": {
4061+ "@babel/runtime": "^7.13.10",
4062+ "@radix-ui/primitive": "0.1.0",
4063+ "@radix-ui/react-context": "0.1.1",
4064+ "@radix-ui/react-primitive": "0.1.4",
4065+ "@radix-ui/react-roving-focus": "0.1.5",
4066+ "@radix-ui/react-toggle": "0.1.4",
4067+ "@radix-ui/react-use-controllable-state": "0.1.0"
4068+ }
4069+ },
4070+ "@radix-ui/react-use-body-pointer-events": {
4071+ "version": "0.1.1",
4072+ "resolved": "https://registry.npmjs.org/@radix-ui/react-use-body-pointer-events/-/react-use-body-pointer-events-0.1.1.tgz",
4073+ "integrity": "sha512-R8leV2AWmJokTmERM8cMXFHWSiv/fzOLhG/JLmRBhLTAzOj37EQizssq4oW0Z29VcZy2tODMi9Pk/htxwb+xpA==",
4074+ "requires": {
4075+ "@babel/runtime": "^7.13.10",
4076+ "@radix-ui/react-use-layout-effect": "0.1.0"
4077+ }
4078+ },
4079+ "@radix-ui/react-use-callback-ref": {
4080+ "version": "0.1.0",
4081+ "resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-0.1.0.tgz",
4082+ "integrity": "sha512-Va041McOFFl+aV+sejvl0BS2aeHx86ND9X/rVFmEFQKTXCp6xgUK0NGUAGcgBlIjnJSbMYPGEk1xKSSlVcN2Aw==",
4083+ "requires": {
4084+ "@babel/runtime": "^7.13.10"
4085+ }
4086+ },
4087+ "@radix-ui/react-use-controllable-state": {
4088+ "version": "0.1.0",
4089+ "resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-0.1.0.tgz",
4090+ "integrity": "sha512-zv7CX/PgsRl46a52Tl45TwqwVJdmqnlQEQhaYMz/yBOD2sx2gCkCFSoF/z9mpnYWmS6DTLNTg5lIps3fV6EnXg==",
4091+ "requires": {
4092+ "@babel/runtime": "^7.13.10",
4093+ "@radix-ui/react-use-callback-ref": "0.1.0"
4094+ }
4095+ },
4096+ "@radix-ui/react-use-direction": {
4097+ "version": "0.1.0",
4098+ "resolved": "https://registry.npmjs.org/@radix-ui/react-use-direction/-/react-use-direction-0.1.0.tgz",
4099+ "integrity": "sha512-NajpY/An9TCPSfOVkgWIdXJV+VuWl67PxB6kOKYmtNAFHvObzIoh8o0n9sAuwSAyFCZVq211FEf9gvVDRhOyiA==",
4100+ "requires": {
4101+ "@babel/runtime": "^7.13.10"
4102+ }
4103+ },
4104+ "@radix-ui/react-use-escape-keydown": {
4105+ "version": "0.1.0",
4106+ "resolved": "https://registry.npmjs.org/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-0.1.0.tgz",
4107+ "integrity": "sha512-tDLZbTGFmvXaazUXXv8kYbiCcbAE8yKgng9s95d8fCO+Eundv0Jngbn/hKPhDDs4jj9ChwRX5cDDnlaN+ugYYQ==",
4108+ "requires": {
4109+ "@babel/runtime": "^7.13.10",
4110+ "@radix-ui/react-use-callback-ref": "0.1.0"
4111+ }
4112+ },
4113+ "@radix-ui/react-use-layout-effect": {
4114+ "version": "0.1.0",
4115+ "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-0.1.0.tgz",
4116+ "integrity": "sha512-+wdeS51Y+E1q1Wmd+1xSSbesZkpVj4jsg0BojCbopWvgq5iBvixw5vgemscdh58ep98BwUbsFYnrywFhV9yrVg==",
4117+ "requires": {
4118+ "@babel/runtime": "^7.13.10"
4119+ }
4120+ },
4121+ "@radix-ui/react-use-previous": {
4122+ "version": "0.1.1",
4123+ "resolved": "https://registry.npmjs.org/@radix-ui/react-use-previous/-/react-use-previous-0.1.1.tgz",
4124+ "integrity": "sha512-O/ZgrDBr11dR8rhO59ED8s5zIXBRFi8MiS+CmFGfi7MJYdLbfqVOmQU90Ghf87aifEgWe6380LA69KBneaShAg==",
4125+ "requires": {
4126+ "@babel/runtime": "^7.13.10"
4127+ }
4128+ },
4129+ "@radix-ui/react-use-rect": {
4130+ "version": "0.1.1",
4131+ "resolved": "https://registry.npmjs.org/@radix-ui/react-use-rect/-/react-use-rect-0.1.1.tgz",
4132+ "integrity": "sha512-kHNNXAsP3/PeszEmM/nxBBS9Jbo93sO+xuMTcRfwzXsmxT5gDXQzAiKbZQ0EecCPtJIzqvr7dlaQi/aP1PKYqQ==",
4133+ "requires": {
4134+ "@babel/runtime": "^7.13.10",
4135+ "@radix-ui/rect": "0.1.1"
4136+ }
4137+ },
4138+ "@radix-ui/react-use-size": {
4139+ "version": "0.1.1",
4140+ "resolved": "https://registry.npmjs.org/@radix-ui/react-use-size/-/react-use-size-0.1.1.tgz",
4141+ "integrity": "sha512-pTgWM5qKBu6C7kfKxrKPoBI2zZYZmp2cSXzpUiGM3qEBQlMLtYhaY2JXdXUCxz+XmD1YEjc8oRwvyfsD4AG4WA==",
4142+ "requires": {
4143+ "@babel/runtime": "^7.13.10"
4144+ }
4145+ },
4146+ "@radix-ui/react-visually-hidden": {
4147+ "version": "0.1.4",
4148+ "resolved": "https://registry.npmjs.org/@radix-ui/react-visually-hidden/-/react-visually-hidden-0.1.4.tgz",
4149+ "integrity": "sha512-K/q6AEEzqeeEq/T0NPChvBqnwlp8Tl4NnQdrI/y8IOY7BRR+Ug0PEsVk6g48HJ7cA1//COugdxXXVVK/m0X1mA==",
4150+ "requires": {
4151+ "@babel/runtime": "^7.13.10",
4152+ "@radix-ui/react-primitive": "0.1.4"
4153+ }
4154+ },
4155+ "@radix-ui/rect": {
4156+ "version": "0.1.1",
4157+ "resolved": "https://registry.npmjs.org/@radix-ui/rect/-/rect-0.1.1.tgz",
4158+ "integrity": "sha512-g3hnE/UcOg7REdewduRPAK88EPuLZtaq7sA9ouu8S+YEtnyFRI16jgv6GZYe3VMoQLL1T171ebmEPtDjyxWLzw==",
4159+ "requires": {
4160+ "@babel/runtime": "^7.13.10"
4161+ }
4162+ },
4163+ "@rollup/pluginutils": {
4164+ "version": "4.2.1",
4165+ "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-4.2.1.tgz",
4166+ "integrity": "sha512-iKnFXr7NkdZAIHiIWE+BX5ULi/ucVFYWD6TbAV+rZctiRTY2PL6tsIKhoIOaoskiWAkgu+VsbXgUVDNLHf+InQ==",
4167+ "dev": true,
4168+ "requires": {
4169+ "estree-walker": "^2.0.1",
4170+ "picomatch": "^2.2.2"
4171+ }
4172+ },
4173+ "@tanstack/query-core": {
4174+ "version": "4.29.5",
4175+ "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-4.29.5.tgz",
4176+ "integrity": "sha512-xXIiyQ/4r9KfaJ3k6kejqcaqFXXBTzN2aOJ5H1J6aTJE9hl/nbgAdfF6oiIu0CD5xowejJEJ6bBg8TO7BN4NuQ=="
4177+ },
4178+ "@tanstack/react-query": {
4179+ "version": "4.29.5",
4180+ "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-4.29.5.tgz",
4181+ "integrity": "sha512-F87cibC3s3eG0Q90g2O+hqntpCrudKFnR8P24qkH9uccEhXErnJxBC/AAI4cJRV2bfMO8IeGZQYf3WyYgmSg0w==",
4182+ "requires": {
4183+ "@tanstack/query-core": "4.29.5",
4184+ "use-sync-external-store": "^1.2.0"
4185+ },
4186+ "dependencies": {
4187+ "use-sync-external-store": {
4188+ "version": "1.2.0",
4189+ "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz",
4190+ "integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==",
4191+ "requires": {}
4192+ }
4193+ }
4194+ },
4195+ "@types/lodash": {
4196+ "version": "4.14.182",
4197+ "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.182.tgz",
4198+ "integrity": "sha512-/THyiqyQAP9AfARo4pF+aCGcyiQ94tX/Is2I7HofNRqoYLgN1PBoOWu2/zTA5zMxzP5EFutMtWtGAFRKUe961Q==",
4199+ "dev": true
4200+ },
4201+ "@types/lodash.debounce": {
4202+ "version": "4.0.7",
4203+ "resolved": "https://registry.npmjs.org/@types/lodash.debounce/-/lodash.debounce-4.0.7.tgz",
4204+ "integrity": "sha512-X1T4wMZ+gT000M2/91SYj0d/7JfeNZ9PeeOldSNoE/lunLeQXKvkmIumI29IaKMotU/ln/McOIvgzZcQ/3TrSA==",
4205+ "dev": true,
4206+ "requires": {
4207+ "@types/lodash": "*"
4208+ }
4209+ },
4210+ "@types/parse-json": {
4211+ "version": "4.0.0",
4212+ "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz",
4213+ "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA=="
4214+ },
4215+ "@types/prop-types": {
4216+ "version": "15.7.5",
4217+ "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz",
4218+ "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w=="
4219+ },
4220+ "@types/react": {
4221+ "version": "17.0.47",
4222+ "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.47.tgz",
4223+ "integrity": "sha512-mk0BL8zBinf2ozNr3qPnlu1oyVTYq+4V7WA76RgxUAtf0Em/Wbid38KN6n4abEkvO4xMTBWmnP1FtQzgkEiJoA==",
4224+ "requires": {
4225+ "@types/prop-types": "*",
4226+ "@types/scheduler": "*",
4227+ "csstype": "^3.0.2"
4228+ }
4229+ },
4230+ "@types/react-dom": {
4231+ "version": "17.0.17",
4232+ "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-17.0.17.tgz",
4233+ "integrity": "sha512-VjnqEmqGnasQKV0CWLevqMTXBYG9GbwuE6x3VetERLh0cq2LTptFE73MrQi2S7GkKXCf2GgwItB/melLnxfnsg==",
4234+ "dev": true,
4235+ "requires": {
4236+ "@types/react": "^17"
4237+ }
4238+ },
4239+ "@types/react-transition-group": {
4240+ "version": "4.4.5",
4241+ "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.5.tgz",
4242+ "integrity": "sha512-juKD/eiSM3/xZYzjuzH6ZwpP+/lejltmiS3QEzV/vmb/Q8+HfDmxu+Baga8UEMGBqV88Nbg4l2hY/K2DkyaLLA==",
4243+ "requires": {
4244+ "@types/react": "*"
4245+ }
4246+ },
4247+ "@types/scheduler": {
4248+ "version": "0.16.2",
4249+ "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz",
4250+ "integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew=="
4251+ },
4252+ "@urbit/api": {
4253+ "version": "2.2.0",
4254+ "resolved": "https://registry.npmjs.org/@urbit/api/-/api-2.2.0.tgz",
4255+ "integrity": "sha512-W8kP9OT6yOK62n+4yCPO3i9QqU5xriLvZQ9WYW4SAV7ktbSrGuf2kmYbnoqfA/NybIs9Q/MbFkPewrz4XJ96Ag==",
4256+ "requires": {
4257+ "@babel/runtime": "^7.16.0",
4258+ "big-integer": "^1.6.48",
4259+ "core-js": "^3.19.1",
4260+ "immer": "^9.0.1",
4261+ "urbit-ob": "^5.0.1"
4262+ }
4263+ },
4264+ "@urbit/http-api": {
4265+ "version": "2.1.3",
4266+ "resolved": "https://registry.npmjs.org/@urbit/http-api/-/http-api-2.1.3.tgz",
4267+ "integrity": "sha512-/wL7kQ/b2m24+cJiQ/3bFoU4jq3Qbl9h+JCb3H/1yovhFSUI7RPUbV20ONhCPTryXch6CC5QbgCALStJYHvKJg==",
4268+ "requires": {
4269+ "@babel/runtime": "^7.12.5",
4270+ "@microsoft/fetch-event-source": "^2.0.0",
4271+ "browser-or-node": "^1.3.0",
4272+ "core-js": "^3.19.1"
4273+ }
4274+ },
4275+ "@urbit/vite-plugin-urbit": {
4276+ "version": "0.8.0",
4277+ "resolved": "https://registry.npmjs.org/@urbit/vite-plugin-urbit/-/vite-plugin-urbit-0.8.0.tgz",
4278+ "integrity": "sha512-cx540xZBuHfzud/kOuYU4xPpsFcgE7mF0heac5uXVutDqjySvVXimEuZgBN23ULC7l60R/bAJ2jOWygBwWen4A==",
4279+ "dev": true,
4280+ "requires": {
4281+ "vite-plugin-html-config": "^1.0.6",
4282+ "vite-plugin-rewrite-all": "^0.1.2"
4283+ }
4284+ },
4285+ "@vitejs/plugin-react-refresh": {
4286+ "version": "1.3.6",
4287+ "resolved": "https://registry.npmjs.org/@vitejs/plugin-react-refresh/-/plugin-react-refresh-1.3.6.tgz",
4288+ "integrity": "sha512-iNR/UqhUOmFFxiezt0em9CgmiJBdWR+5jGxB2FihaoJfqGt76kiwaKoVOJVU5NYcDWMdN06LbyN2VIGIoYdsEA==",
4289+ "dev": true,
4290+ "requires": {
4291+ "@babel/core": "^7.14.8",
4292+ "@babel/plugin-transform-react-jsx-self": "^7.14.5",
4293+ "@babel/plugin-transform-react-jsx-source": "^7.14.5",
4294+ "@rollup/pluginutils": "^4.1.1",
4295+ "react-refresh": "^0.10.0"
4296+ }
4297+ },
4298+ "acorn": {
4299+ "version": "7.4.1",
4300+ "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz",
4301+ "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==",
4302+ "dev": true
4303+ },
4304+ "acorn-node": {
4305+ "version": "1.8.2",
4306+ "resolved": "https://registry.npmjs.org/acorn-node/-/acorn-node-1.8.2.tgz",
4307+ "integrity": "sha512-8mt+fslDufLYntIoPAaIMUe/lrbrehIiwmR3t2k9LljIzoigEPF27eLk2hy8zSGzmR/ogr7zbRKINMo1u0yh5A==",
4308+ "dev": true,
4309+ "requires": {
4310+ "acorn": "^7.0.0",
4311+ "acorn-walk": "^7.0.0",
4312+ "xtend": "^4.0.2"
4313+ }
4314+ },
4315+ "acorn-walk": {
4316+ "version": "7.2.0",
4317+ "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz",
4318+ "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==",
4319+ "dev": true
4320+ },
4321+ "ansi-styles": {
4322+ "version": "3.2.1",
4323+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
4324+ "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
4325+ "requires": {
4326+ "color-convert": "^1.9.0"
4327+ }
4328+ },
4329+ "anymatch": {
4330+ "version": "3.1.2",
4331+ "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz",
4332+ "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==",
4333+ "dev": true,
4334+ "requires": {
4335+ "normalize-path": "^3.0.0",
4336+ "picomatch": "^2.0.4"
4337+ }
4338+ },
4339+ "arg": {
4340+ "version": "5.0.2",
4341+ "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz",
4342+ "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==",
4343+ "dev": true
4344+ },
4345+ "aria-hidden": {
4346+ "version": "1.1.3",
4347+ "resolved": "https://registry.npmjs.org/aria-hidden/-/aria-hidden-1.1.3.tgz",
4348+ "integrity": "sha512-RhVWFtKH5BiGMycI72q2RAFMLQi8JP9bLuQXgR5a8Znp7P5KOIADSJeyfI8PCVxLEp067B2HbP5JIiI/PXIZeA==",
4349+ "requires": {
4350+ "tslib": "^1.0.0"
4351+ }
4352+ },
4353+ "autoprefixer": {
4354+ "version": "10.4.7",
4355+ "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.7.tgz",
4356+ "integrity": "sha512-ypHju4Y2Oav95SipEcCcI5J7CGPuvz8oat7sUtYj3ClK44bldfvtvcxK6IEK++7rqB7YchDGzweZIBG+SD0ZAA==",
4357+ "dev": true,
4358+ "requires": {
4359+ "browserslist": "^4.20.3",
4360+ "caniuse-lite": "^1.0.30001335",
4361+ "fraction.js": "^4.2.0",
4362+ "normalize-range": "^0.1.2",
4363+ "picocolors": "^1.0.0",
4364+ "postcss-value-parser": "^4.2.0"
4365+ }
4366+ },
4367+ "babel-plugin-macros": {
4368+ "version": "2.8.0",
4369+ "resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-2.8.0.tgz",
4370+ "integrity": "sha512-SEP5kJpfGYqYKpBrj5XU3ahw5p5GOHJ0U5ssOSQ/WBVdwkD2Dzlce95exQTs3jOVWPPKLBN2rlEWkCK7dSmLvg==",
4371+ "requires": {
4372+ "@babel/runtime": "^7.7.2",
4373+ "cosmiconfig": "^6.0.0",
4374+ "resolve": "^1.12.0"
4375+ }
4376+ },
4377+ "big-integer": {
4378+ "version": "1.6.51",
4379+ "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.51.tgz",
4380+ "integrity": "sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg=="
4381+ },
4382+ "binary-extensions": {
4383+ "version": "2.2.0",
4384+ "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
4385+ "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==",
4386+ "dev": true
4387+ },
4388+ "bn.js": {
4389+ "version": "4.12.0",
4390+ "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz",
4391+ "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA=="
4392+ },
4393+ "braces": {
4394+ "version": "3.0.2",
4395+ "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
4396+ "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
4397+ "dev": true,
4398+ "requires": {
4399+ "fill-range": "^7.0.1"
4400+ }
4401+ },
4402+ "browser-or-node": {
4403+ "version": "1.3.0",
4404+ "resolved": "https://registry.npmjs.org/browser-or-node/-/browser-or-node-1.3.0.tgz",
4405+ "integrity": "sha512-0F2z/VSnLbmEeBcUrSuDH5l0HxTXdQQzLjkmBR4cYfvg1zJrKSlmIZFqyFR8oX0NrwPhy3c3HQ6i3OxMbew4Tg=="
4406+ },
4407+ "browserslist": {
4408+ "version": "4.21.1",
4409+ "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.1.tgz",
4410+ "integrity": "sha512-Nq8MFCSrnJXSc88yliwlzQe3qNe3VntIjhsArW9IJOEPSHNx23FalwApUVbzAWABLhYJJ7y8AynWI/XM8OdfjQ==",
4411+ "requires": {
4412+ "caniuse-lite": "^1.0.30001359",
4413+ "electron-to-chromium": "^1.4.172",
4414+ "node-releases": "^2.0.5",
4415+ "update-browserslist-db": "^1.0.4"
4416+ }
4417+ },
4418+ "callsites": {
4419+ "version": "3.1.0",
4420+ "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
4421+ "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ=="
4422+ },
4423+ "camelcase-css": {
4424+ "version": "2.0.1",
4425+ "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz",
4426+ "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==",
4427+ "dev": true
4428+ },
4429+ "caniuse-lite": {
4430+ "version": "1.0.30001361",
4431+ "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001361.tgz",
4432+ "integrity": "sha512-ybhCrjNtkFji1/Wto6SSJKkWk6kZgVQsDq5QI83SafsF6FXv2JB4df9eEdH6g8sdGgqTXrFLjAxqBGgYoU3azQ=="
4433+ },
4434+ "chalk": {
4435+ "version": "2.4.2",
4436+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
4437+ "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
4438+ "requires": {
4439+ "ansi-styles": "^3.2.1",
4440+ "escape-string-regexp": "^1.0.5",
4441+ "supports-color": "^5.3.0"
4442+ }
4443+ },
4444+ "chokidar": {
4445+ "version": "3.5.3",
4446+ "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz",
4447+ "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==",
4448+ "dev": true,
4449+ "requires": {
4450+ "anymatch": "~3.1.2",
4451+ "braces": "~3.0.2",
4452+ "fsevents": "~2.3.2",
4453+ "glob-parent": "~5.1.2",
4454+ "is-binary-path": "~2.1.0",
4455+ "is-glob": "~4.0.1",
4456+ "normalize-path": "~3.0.0",
4457+ "readdirp": "~3.6.0"
4458+ },
4459+ "dependencies": {
4460+ "glob-parent": {
4461+ "version": "5.1.2",
4462+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
4463+ "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
4464+ "dev": true,
4465+ "requires": {
4466+ "is-glob": "^4.0.1"
4467+ }
4468+ }
4469+ }
4470+ },
4471+ "classnames": {
4472+ "version": "2.3.1",
4473+ "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.3.1.tgz",
4474+ "integrity": "sha512-OlQdbZ7gLfGarSqxesMesDa5uz7KFbID8Kpq/SxIoNGDqY8lSYs0D+hhtBXhcdB3rcbXArFr7vlHheLk1voeNA=="
4475+ },
4476+ "color-convert": {
4477+ "version": "1.9.3",
4478+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
4479+ "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
4480+ "requires": {
4481+ "color-name": "1.1.3"
4482+ }
4483+ },
4484+ "color-name": {
4485+ "version": "1.1.3",
4486+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
4487+ "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw=="
4488+ },
4489+ "color2k": {
4490+ "version": "2.0.2",
4491+ "resolved": "https://registry.npmjs.org/color2k/-/color2k-2.0.2.tgz",
4492+ "integrity": "sha512-kJhwH5nAwb34tmyuqq/lgjEKzlFXn1U99NlnB6Ws4qVaERcRUYeYP1cBw6BJ4vxaWStAUEef4WMr7WjOCnBt8w=="
4493+ },
4494+ "connect-history-api-fallback": {
4495+ "version": "1.6.0",
4496+ "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-1.6.0.tgz",
4497+ "integrity": "sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg==",
4498+ "dev": true
4499+ },
4500+ "convert-source-map": {
4501+ "version": "1.8.0",
4502+ "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz",
4503+ "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==",
4504+ "requires": {
4505+ "safe-buffer": "~5.1.1"
4506+ }
4507+ },
4508+ "core-js": {
4509+ "version": "3.23.3",
4510+ "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.23.3.tgz",
4511+ "integrity": "sha512-oAKwkj9xcWNBAvGbT//WiCdOMpb9XQG92/Fe3ABFM/R16BsHgePG00mFOgKf7IsCtfj8tA1kHtf/VwErhriz5Q=="
4512+ },
4513+ "cosmiconfig": {
4514+ "version": "6.0.0",
4515+ "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-6.0.0.tgz",
4516+ "integrity": "sha512-xb3ZL6+L8b9JLLCx3ZdoZy4+2ECphCMo2PwqgP1tlfVq6M6YReyzBJtvWWtbDSpNr9hn96pkCiZqUcFEc+54Qg==",
4517+ "requires": {
4518+ "@types/parse-json": "^4.0.0",
4519+ "import-fresh": "^3.1.0",
4520+ "parse-json": "^5.0.0",
4521+ "path-type": "^4.0.0",
4522+ "yaml": "^1.7.2"
4523+ }
4524+ },
4525+ "cssesc": {
4526+ "version": "3.0.0",
4527+ "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz",
4528+ "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==",
4529+ "dev": true
4530+ },
4531+ "csstype": {
4532+ "version": "3.1.0",
4533+ "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.0.tgz",
4534+ "integrity": "sha512-uX1KG+x9h5hIJsaKR9xHUeUraxf8IODOwq9JLNPq6BwB04a/xgpq3rcx47l5BZu5zBPlgD342tdke3Hom/nJRA=="
4535+ },
4536+ "debug": {
4537+ "version": "4.3.4",
4538+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
4539+ "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
4540+ "requires": {
4541+ "ms": "2.1.2"
4542+ }
4543+ },
4544+ "decode-uri-component": {
4545+ "version": "0.2.0",
4546+ "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz",
4547+ "integrity": "sha512-hjf+xovcEn31w/EUYdTXQh/8smFL/dzYjohQGEIgjyNavaJfBY2p5F527Bo1VPATxv0VYTUC2bOcXvqFwk78Og=="
4548+ },
4549+ "defined": {
4550+ "version": "1.0.0",
4551+ "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.0.tgz",
4552+ "integrity": "sha512-Y2caI5+ZwS5c3RiNDJ6u53VhQHv+hHKwhkI1iHvceKUHw9Df6EK2zRLfjejRgMuCuxK7PfSWIMwWecceVvThjQ==",
4553+ "dev": true
4554+ },
4555+ "detect-node-es": {
4556+ "version": "1.1.0",
4557+ "resolved": "https://registry.npmjs.org/detect-node-es/-/detect-node-es-1.1.0.tgz",
4558+ "integrity": "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ=="
4559+ },
4560+ "detective": {
4561+ "version": "5.2.1",
4562+ "resolved": "https://registry.npmjs.org/detective/-/detective-5.2.1.tgz",
4563+ "integrity": "sha512-v9XE1zRnz1wRtgurGu0Bs8uHKFSTdteYZNbIPFVhUZ39L/S79ppMpdmVOZAnoz1jfEFodc48n6MX483Xo3t1yw==",
4564+ "dev": true,
4565+ "requires": {
4566+ "acorn-node": "^1.8.2",
4567+ "defined": "^1.0.0",
4568+ "minimist": "^1.2.6"
4569+ }
4570+ },
4571+ "didyoumean": {
4572+ "version": "1.2.2",
4573+ "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz",
4574+ "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==",
4575+ "dev": true
4576+ },
4577+ "dlv": {
4578+ "version": "1.1.3",
4579+ "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz",
4580+ "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==",
4581+ "dev": true
4582+ },
4583+ "dom-helpers": {
4584+ "version": "5.2.1",
4585+ "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz",
4586+ "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==",
4587+ "requires": {
4588+ "@babel/runtime": "^7.8.7",
4589+ "csstype": "^3.0.2"
4590+ }
4591+ },
4592+ "electron-to-chromium": {
4593+ "version": "1.4.176",
4594+ "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.176.tgz",
4595+ "integrity": "sha512-92JdgyRlcNDwuy75MjuFSb3clt6DGJ2IXSpg0MCjKd3JV9eSmuUAIyWiGAp/EtT0z2D4rqbYqThQLV90maH3Zw=="
4596+ },
4597+ "error-ex": {
4598+ "version": "1.3.2",
4599+ "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz",
4600+ "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==",
4601+ "requires": {
4602+ "is-arrayish": "^0.2.1"
4603+ }
4604+ },
4605+ "esbuild": {
4606+ "version": "0.14.48",
4607+ "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.14.48.tgz",
4608+ "integrity": "sha512-w6N1Yn5MtqK2U1/WZTX9ZqUVb8IOLZkZ5AdHkT6x3cHDMVsYWC7WPdiLmx19w3i4Rwzy5LqsEMtVihG3e4rFzA==",
4609+ "dev": true,
4610+ "requires": {
4611+ "esbuild-android-64": "0.14.48",
4612+ "esbuild-android-arm64": "0.14.48",
4613+ "esbuild-darwin-64": "0.14.48",
4614+ "esbuild-darwin-arm64": "0.14.48",
4615+ "esbuild-freebsd-64": "0.14.48",
4616+ "esbuild-freebsd-arm64": "0.14.48",
4617+ "esbuild-linux-32": "0.14.48",
4618+ "esbuild-linux-64": "0.14.48",
4619+ "esbuild-linux-arm": "0.14.48",
4620+ "esbuild-linux-arm64": "0.14.48",
4621+ "esbuild-linux-mips64le": "0.14.48",
4622+ "esbuild-linux-ppc64le": "0.14.48",
4623+ "esbuild-linux-riscv64": "0.14.48",
4624+ "esbuild-linux-s390x": "0.14.48",
4625+ "esbuild-netbsd-64": "0.14.48",
4626+ "esbuild-openbsd-64": "0.14.48",
4627+ "esbuild-sunos-64": "0.14.48",
4628+ "esbuild-windows-32": "0.14.48",
4629+ "esbuild-windows-64": "0.14.48",
4630+ "esbuild-windows-arm64": "0.14.48"
4631+ }
4632+ },
4633+ "esbuild-android-64": {
4634+ "version": "0.14.48",
4635+ "resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.14.48.tgz",
4636+ "integrity": "sha512-3aMjboap/kqwCUpGWIjsk20TtxVoKck8/4Tu19rubh7t5Ra0Yrpg30Mt1QXXlipOazrEceGeWurXKeFJgkPOUg==",
4637+ "dev": true,
4638+ "optional": true
4639+ },
4640+ "esbuild-android-arm64": {
4641+ "version": "0.14.48",
4642+ "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.14.48.tgz",
4643+ "integrity": "sha512-vptI3K0wGALiDq+EvRuZotZrJqkYkN5282iAfcffjI5lmGG9G1ta/CIVauhY42MBXwEgDJkweiDcDMRLzBZC4g==",
4644+ "dev": true,
4645+ "optional": true
4646+ },
4647+ "esbuild-darwin-64": {
4648+ "version": "0.14.48",
4649+ "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.14.48.tgz",
4650+ "integrity": "sha512-gGQZa4+hab2Va/Zww94YbshLuWteyKGD3+EsVon8EWTWhnHFRm5N9NbALNbwi/7hQ/hM1Zm4FuHg+k6BLsl5UA==",
4651+ "dev": true,
4652+ "optional": true
4653+ },
4654+ "esbuild-darwin-arm64": {
4655+ "version": "0.14.48",
4656+ "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.48.tgz",
4657+ "integrity": "sha512-bFjnNEXjhZT+IZ8RvRGNJthLWNHV5JkCtuOFOnjvo5pC0sk2/QVk0Qc06g2PV3J0TcU6kaPC3RN9yy9w2PSLEA==",
4658+ "dev": true,
4659+ "optional": true
4660+ },
4661+ "esbuild-freebsd-64": {
4662+ "version": "0.14.48",
4663+ "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.48.tgz",
4664+ "integrity": "sha512-1NOlwRxmOsnPcWOGTB10JKAkYSb2nue0oM1AfHWunW/mv3wERfJmnYlGzL3UAOIUXZqW8GeA2mv+QGwq7DToqA==",
4665+ "dev": true,
4666+ "optional": true
4667+ },
4668+ "esbuild-freebsd-arm64": {
4669+ "version": "0.14.48",
4670+ "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.48.tgz",
4671+ "integrity": "sha512-gXqKdO8wabVcYtluAbikDH2jhXp+Klq5oCD5qbVyUG6tFiGhrC9oczKq3vIrrtwcxDQqK6+HDYK8Zrd4bCA9Gw==",
4672+ "dev": true,
4673+ "optional": true
4674+ },
4675+ "esbuild-linux-32": {
4676+ "version": "0.14.48",
4677+ "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.14.48.tgz",
4678+ "integrity": "sha512-ghGyDfS289z/LReZQUuuKq9KlTiTspxL8SITBFQFAFRA/IkIvDpnZnCAKTCjGXAmUqroMQfKJXMxyjJA69c/nQ==",
4679+ "dev": true,
4680+ "optional": true
4681+ },
4682+ "esbuild-linux-64": {
4683+ "version": "0.14.48",
4684+ "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.14.48.tgz",
4685+ "integrity": "sha512-vni3p/gppLMVZLghI7oMqbOZdGmLbbKR23XFARKnszCIBpEMEDxOMNIKPmMItQrmH/iJrL1z8Jt2nynY0bE1ug==",
4686+ "dev": true,
4687+ "optional": true
4688+ },
4689+ "esbuild-linux-arm": {
4690+ "version": "0.14.48",
4691+ "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.14.48.tgz",
4692+ "integrity": "sha512-+VfSV7Akh1XUiDNXgqgY1cUP1i2vjI+BmlyXRfVz5AfV3jbpde8JTs5Q9sYgaoq5cWfuKfoZB/QkGOI+QcL1Tw==",
4693+ "dev": true,
4694+ "optional": true
4695+ },
4696+ "esbuild-linux-arm64": {
4697+ "version": "0.14.48",
4698+ "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.48.tgz",
4699+ "integrity": "sha512-3CFsOlpoxlKPRevEHq8aAntgYGYkE1N9yRYAcPyng/p4Wyx0tPR5SBYsxLKcgPB9mR8chHEhtWYz6EZ+H199Zw==",
4700+ "dev": true,
4701+ "optional": true
4702+ },
4703+ "esbuild-linux-mips64le": {
4704+ "version": "0.14.48",
4705+ "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.48.tgz",
4706+ "integrity": "sha512-cs0uOiRlPp6ymknDnjajCgvDMSsLw5mST2UXh+ZIrXTj2Ifyf2aAP3Iw4DiqgnyYLV2O/v/yWBJx+WfmKEpNLA==",
4707+ "dev": true,
4708+ "optional": true
4709+ },
4710+ "esbuild-linux-ppc64le": {
4711+ "version": "0.14.48",
4712+ "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.48.tgz",
4713+ "integrity": "sha512-+2F0vJMkuI0Wie/wcSPDCqXvSFEELH7Jubxb7mpWrA/4NpT+/byjxDz0gG6R1WJoeDefcrMfpBx4GFNN1JQorQ==",
4714+ "dev": true,
4715+ "optional": true
4716+ },
4717+ "esbuild-linux-riscv64": {
4718+ "version": "0.14.48",
4719+ "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.48.tgz",
4720+ "integrity": "sha512-BmaK/GfEE+5F2/QDrIXteFGKnVHGxlnK9MjdVKMTfvtmudjY3k2t8NtlY4qemKSizc+QwyombGWTBDc76rxePA==",
4721+ "dev": true,
4722+ "optional": true
4723+ },
4724+ "esbuild-linux-s390x": {
4725+ "version": "0.14.48",
4726+ "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.48.tgz",
4727+ "integrity": "sha512-tndw/0B9jiCL+KWKo0TSMaUm5UWBLsfCKVdbfMlb3d5LeV9WbijZ8Ordia8SAYv38VSJWOEt6eDCdOx8LqkC4g==",
4728+ "dev": true,
4729+ "optional": true
4730+ },
4731+ "esbuild-netbsd-64": {
4732+ "version": "0.14.48",
4733+ "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.48.tgz",
4734+ "integrity": "sha512-V9hgXfwf/T901Lr1wkOfoevtyNkrxmMcRHyticybBUHookznipMOHoF41Al68QBsqBxnITCEpjjd4yAos7z9Tw==",
4735+ "dev": true,
4736+ "optional": true
4737+ },
4738+ "esbuild-openbsd-64": {
4739+ "version": "0.14.48",
4740+ "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.48.tgz",
4741+ "integrity": "sha512-+IHf4JcbnnBl4T52egorXMatil/za0awqzg2Vy6FBgPcBpisDWT2sVz/tNdrK9kAqj+GZG/jZdrOkj7wsrNTKA==",
4742+ "dev": true,
4743+ "optional": true
4744+ },
4745+ "esbuild-sunos-64": {
4746+ "version": "0.14.48",
4747+ "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.14.48.tgz",
4748+ "integrity": "sha512-77m8bsr5wOpOWbGi9KSqDphcq6dFeJyun8TA+12JW/GAjyfTwVtOnN8DOt6DSPUfEV+ltVMNqtXUeTeMAxl5KA==",
4749+ "dev": true,
4750+ "optional": true
4751+ },
4752+ "esbuild-windows-32": {
4753+ "version": "0.14.48",
4754+ "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.14.48.tgz",
4755+ "integrity": "sha512-EPgRuTPP8vK9maxpTGDe5lSoIBHGKO/AuxDncg5O3NkrPeLNdvvK8oywB0zGaAZXxYWfNNSHskvvDgmfVTguhg==",
4756+ "dev": true,
4757+ "optional": true
4758+ },
4759+ "esbuild-windows-64": {
4760+ "version": "0.14.48",
4761+ "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.14.48.tgz",
4762+ "integrity": "sha512-YmpXjdT1q0b8ictSdGwH3M8VCoqPpK1/UArze3X199w6u8hUx3V8BhAi1WjbsfDYRBanVVtduAhh2sirImtAvA==",
4763+ "dev": true,
4764+ "optional": true
4765+ },
4766+ "esbuild-windows-arm64": {
4767+ "version": "0.14.48",
4768+ "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.48.tgz",
4769+ "integrity": "sha512-HHaOMCsCXp0rz5BT2crTka6MPWVno121NKApsGs/OIW5QC0ggC69YMGs1aJct9/9FSUF4A1xNE/cLvgB5svR4g==",
4770+ "dev": true,
4771+ "optional": true
4772+ },
4773+ "escalade": {
4774+ "version": "3.1.1",
4775+ "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz",
4776+ "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw=="
4777+ },
4778+ "escape-string-regexp": {
4779+ "version": "1.0.5",
4780+ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
4781+ "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg=="
4782+ },
4783+ "estree-walker": {
4784+ "version": "2.0.2",
4785+ "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz",
4786+ "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==",
4787+ "dev": true
4788+ },
4789+ "fast-glob": {
4790+ "version": "3.2.11",
4791+ "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz",
4792+ "integrity": "sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==",
4793+ "dev": true,
4794+ "requires": {
4795+ "@nodelib/fs.stat": "^2.0.2",
4796+ "@nodelib/fs.walk": "^1.2.3",
4797+ "glob-parent": "^5.1.2",
4798+ "merge2": "^1.3.0",
4799+ "micromatch": "^4.0.4"
4800+ },
4801+ "dependencies": {
4802+ "glob-parent": {
4803+ "version": "5.1.2",
4804+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
4805+ "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
4806+ "dev": true,
4807+ "requires": {
4808+ "is-glob": "^4.0.1"
4809+ }
4810+ }
4811+ }
4812+ },
4813+ "fastq": {
4814+ "version": "1.13.0",
4815+ "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz",
4816+ "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==",
4817+ "dev": true,
4818+ "requires": {
4819+ "reusify": "^1.0.4"
4820+ }
4821+ },
4822+ "fill-range": {
4823+ "version": "7.0.1",
4824+ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
4825+ "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
4826+ "dev": true,
4827+ "requires": {
4828+ "to-regex-range": "^5.0.1"
4829+ }
4830+ },
4831+ "filter-obj": {
4832+ "version": "1.1.0",
4833+ "resolved": "https://registry.npmjs.org/filter-obj/-/filter-obj-1.1.0.tgz",
4834+ "integrity": "sha512-8rXg1ZnX7xzy2NGDVkBVaAy+lSlPNwad13BtgSlLuxfIslyt5Vg64U7tFcCt4WS1R0hvtnQybT/IyCkGZ3DpXQ=="
4835+ },
4836+ "find-root": {
4837+ "version": "1.1.0",
4838+ "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz",
4839+ "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng=="
4840+ },
4841+ "fraction.js": {
4842+ "version": "4.2.0",
4843+ "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.2.0.tgz",
4844+ "integrity": "sha512-MhLuK+2gUcnZe8ZHlaaINnQLl0xRIGRfcGk2yl8xoQAfHrSsL3rYu6FCmBdkdbhc9EPlwyGHewaRsvwRMJtAlA==",
4845+ "dev": true
4846+ },
4847+ "fsevents": {
4848+ "version": "2.3.2",
4849+ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
4850+ "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
4851+ "dev": true,
4852+ "optional": true
4853+ },
4854+ "function-bind": {
4855+ "version": "1.1.1",
4856+ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
4857+ "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A=="
4858+ },
4859+ "gensync": {
4860+ "version": "1.0.0-beta.2",
4861+ "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz",
4862+ "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg=="
4863+ },
4864+ "get-nonce": {
4865+ "version": "1.0.1",
4866+ "resolved": "https://registry.npmjs.org/get-nonce/-/get-nonce-1.0.1.tgz",
4867+ "integrity": "sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q=="
4868+ },
4869+ "glob-parent": {
4870+ "version": "6.0.2",
4871+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
4872+ "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==",
4873+ "dev": true,
4874+ "requires": {
4875+ "is-glob": "^4.0.3"
4876+ }
4877+ },
4878+ "globals": {
4879+ "version": "11.12.0",
4880+ "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz",
4881+ "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA=="
4882+ },
4883+ "has": {
4884+ "version": "1.0.3",
4885+ "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
4886+ "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
4887+ "requires": {
4888+ "function-bind": "^1.1.1"
4889+ }
4890+ },
4891+ "has-flag": {
4892+ "version": "3.0.0",
4893+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
4894+ "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw=="
4895+ },
4896+ "history": {
4897+ "version": "5.3.0",
4898+ "resolved": "https://registry.npmjs.org/history/-/history-5.3.0.tgz",
4899+ "integrity": "sha512-ZqaKwjjrAYUYfLG+htGaIIZ4nioX2L70ZUMIFysS3xvBsSG4x/n1V6TXV3N8ZYNuFGlDirFg32T7B6WOUPDYcQ==",
4900+ "requires": {
4901+ "@babel/runtime": "^7.7.6"
4902+ }
4903+ },
4904+ "hoist-non-react-statics": {
4905+ "version": "3.3.2",
4906+ "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz",
4907+ "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==",
4908+ "requires": {
4909+ "react-is": "^16.7.0"
4910+ }
4911+ },
4912+ "immer": {
4913+ "version": "9.0.15",
4914+ "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.15.tgz",
4915+ "integrity": "sha512-2eB/sswms9AEUSkOm4SbV5Y7Vmt/bKRwByd52jfLkW4OLYeaTP3EEiJ9agqU0O/tq6Dk62Zfj+TJSqfm1rLVGQ=="
4916+ },
4917+ "import-fresh": {
4918+ "version": "3.3.0",
4919+ "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
4920+ "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==",
4921+ "requires": {
4922+ "parent-module": "^1.0.0",
4923+ "resolve-from": "^4.0.0"
4924+ }
4925+ },
4926+ "invariant": {
4927+ "version": "2.2.4",
4928+ "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz",
4929+ "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==",
4930+ "requires": {
4931+ "loose-envify": "^1.0.0"
4932+ }
4933+ },
4934+ "is-arrayish": {
4935+ "version": "0.2.1",
4936+ "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
4937+ "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg=="
4938+ },
4939+ "is-binary-path": {
4940+ "version": "2.1.0",
4941+ "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
4942+ "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
4943+ "dev": true,
4944+ "requires": {
4945+ "binary-extensions": "^2.0.0"
4946+ }
4947+ },
4948+ "is-core-module": {
4949+ "version": "2.9.0",
4950+ "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.9.0.tgz",
4951+ "integrity": "sha512-+5FPy5PnwmO3lvfMb0AsoPaBG+5KHUI0wYFXOtYPnVVVspTFUuMZNfNaNVRt3FZadstu2c8x23vykRW/NBoU6A==",
4952+ "requires": {
4953+ "has": "^1.0.3"
4954+ }
4955+ },
4956+ "is-extglob": {
4957+ "version": "2.1.1",
4958+ "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
4959+ "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
4960+ "dev": true
4961+ },
4962+ "is-glob": {
4963+ "version": "4.0.3",
4964+ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
4965+ "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
4966+ "dev": true,
4967+ "requires": {
4968+ "is-extglob": "^2.1.1"
4969+ }
4970+ },
4971+ "is-number": {
4972+ "version": "7.0.0",
4973+ "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
4974+ "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
4975+ "dev": true
4976+ },
4977+ "js-tokens": {
4978+ "version": "4.0.0",
4979+ "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
4980+ "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="
4981+ },
4982+ "jsesc": {
4983+ "version": "2.5.2",
4984+ "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz",
4985+ "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA=="
4986+ },
4987+ "json-parse-even-better-errors": {
4988+ "version": "2.3.1",
4989+ "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz",
4990+ "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w=="
4991+ },
4992+ "json5": {
4993+ "version": "2.2.1",
4994+ "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz",
4995+ "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA=="
4996+ },
4997+ "lilconfig": {
4998+ "version": "2.0.5",
4999+ "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.0.5.tgz",
5000+ "integrity": "sha512-xaYmXZtTHPAw5m+xLN8ab9C+3a8YmV3asNSPOATITbtwrfbwaLJj8h66H1WMIpALCkqsIzK3h7oQ+PdX+LQ9Eg==",
5001+ "dev": true
5002+ },
5003+ "lines-and-columns": {
5004+ "version": "1.2.4",
5005+ "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
5006+ "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg=="
5007+ },
5008+ "lodash.chunk": {
5009+ "version": "4.2.0",
5010+ "resolved": "https://registry.npmjs.org/lodash.chunk/-/lodash.chunk-4.2.0.tgz",
5011+ "integrity": "sha512-ZzydJKfUHJwHa+hF5X66zLFCBrWn5GeF28OHEr4WVWtNDXlQ/IjWKPBiikqKo2ne0+v6JgCgJ0GzJp8k8bHC7w=="
5012+ },
5013+ "lodash.debounce": {
5014+ "version": "4.0.8",
5015+ "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz",
5016+ "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow=="
5017+ },
5018+ "lodash.isequal": {
5019+ "version": "4.5.0",
5020+ "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz",
5021+ "integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ=="
5022+ },
5023+ "loose-envify": {
5024+ "version": "1.4.0",
5025+ "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
5026+ "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
5027+ "requires": {
5028+ "js-tokens": "^3.0.0 || ^4.0.0"
5029+ }
5030+ },
5031+ "memoize-one": {
5032+ "version": "5.2.1",
5033+ "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-5.2.1.tgz",
5034+ "integrity": "sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q=="
5035+ },
5036+ "merge2": {
5037+ "version": "1.4.1",
5038+ "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
5039+ "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==",
5040+ "dev": true
5041+ },
5042+ "micromatch": {
5043+ "version": "4.0.5",
5044+ "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz",
5045+ "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==",
5046+ "dev": true,
5047+ "requires": {
5048+ "braces": "^3.0.2",
5049+ "picomatch": "^2.3.1"
5050+ }
5051+ },
5052+ "minimist": {
5053+ "version": "1.2.6",
5054+ "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz",
5055+ "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==",
5056+ "dev": true
5057+ },
5058+ "ms": {
5059+ "version": "2.1.2",
5060+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
5061+ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
5062+ },
5063+ "nanoid": {
5064+ "version": "3.3.4",
5065+ "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz",
5066+ "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==",
5067+ "dev": true
5068+ },
5069+ "node-releases": {
5070+ "version": "2.0.5",
5071+ "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.5.tgz",
5072+ "integrity": "sha512-U9h1NLROZTq9uE1SNffn6WuPDg8icmi3ns4rEl/oTfIle4iLjTliCzgTsbaIFMq/Xn078/lfY/BL0GWZ+psK4Q=="
5073+ },
5074+ "normalize-path": {
5075+ "version": "3.0.0",
5076+ "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
5077+ "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
5078+ "dev": true
5079+ },
5080+ "normalize-range": {
5081+ "version": "0.1.2",
5082+ "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz",
5083+ "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==",
5084+ "dev": true
5085+ },
5086+ "object-assign": {
5087+ "version": "4.1.1",
5088+ "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
5089+ "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg=="
5090+ },
5091+ "object-hash": {
5092+ "version": "3.0.0",
5093+ "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz",
5094+ "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==",
5095+ "dev": true
5096+ },
5097+ "parent-module": {
5098+ "version": "1.0.1",
5099+ "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
5100+ "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==",
5101+ "requires": {
5102+ "callsites": "^3.0.0"
5103+ }
5104+ },
5105+ "parse-json": {
5106+ "version": "5.2.0",
5107+ "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz",
5108+ "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==",
5109+ "requires": {
5110+ "@babel/code-frame": "^7.0.0",
5111+ "error-ex": "^1.3.1",
5112+ "json-parse-even-better-errors": "^2.3.0",
5113+ "lines-and-columns": "^1.1.6"
5114+ }
5115+ },
5116+ "path-parse": {
5117+ "version": "1.0.7",
5118+ "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
5119+ "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw=="
5120+ },
5121+ "path-type": {
5122+ "version": "4.0.0",
5123+ "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
5124+ "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw=="
5125+ },
5126+ "picocolors": {
5127+ "version": "1.0.0",
5128+ "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz",
5129+ "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ=="
5130+ },
5131+ "picomatch": {
5132+ "version": "2.3.1",
5133+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
5134+ "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
5135+ "dev": true
5136+ },
5137+ "pify": {
5138+ "version": "2.3.0",
5139+ "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
5140+ "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==",
5141+ "dev": true
5142+ },
5143+ "postcss": {
5144+ "version": "8.4.14",
5145+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.14.tgz",
5146+ "integrity": "sha512-E398TUmfAYFPBSdzgeieK2Y1+1cpdxJx8yXbK/m57nRhKSmk1GB2tO4lbLBtlkfPQTDKfe4Xqv1ASWPpayPEig==",
5147+ "dev": true,
5148+ "requires": {
5149+ "nanoid": "^3.3.4",
5150+ "picocolors": "^1.0.0",
5151+ "source-map-js": "^1.0.2"
5152+ }
5153+ },
5154+ "postcss-import": {
5155+ "version": "14.1.0",
5156+ "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-14.1.0.tgz",
5157+ "integrity": "sha512-flwI+Vgm4SElObFVPpTIT7SU7R3qk2L7PyduMcokiaVKuWv9d/U+Gm/QAd8NDLuykTWTkcrjOeD2Pp1rMeBTGw==",
5158+ "dev": true,
5159+ "requires": {
5160+ "postcss-value-parser": "^4.0.0",
5161+ "read-cache": "^1.0.0",
5162+ "resolve": "^1.1.7"
5163+ }
5164+ },
5165+ "postcss-js": {
5166+ "version": "4.0.0",
5167+ "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.0.0.tgz",
5168+ "integrity": "sha512-77QESFBwgX4irogGVPgQ5s07vLvFqWr228qZY+w6lW599cRlK/HmnlivnnVUxkjHnCu4J16PDMHcH+e+2HbvTQ==",
5169+ "dev": true,
5170+ "requires": {
5171+ "camelcase-css": "^2.0.1"
5172+ }
5173+ },
5174+ "postcss-load-config": {
5175+ "version": "3.1.4",
5176+ "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-3.1.4.tgz",
5177+ "integrity": "sha512-6DiM4E7v4coTE4uzA8U//WhtPwyhiim3eyjEMFCnUpzbrkK9wJHgKDT2mR+HbtSrd/NubVaYTOpSpjUl8NQeRg==",
5178+ "dev": true,
5179+ "requires": {
5180+ "lilconfig": "^2.0.5",
5181+ "yaml": "^1.10.2"
5182+ }
5183+ },
5184+ "postcss-nested": {
5185+ "version": "5.0.6",
5186+ "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-5.0.6.tgz",
5187+ "integrity": "sha512-rKqm2Fk0KbA8Vt3AdGN0FB9OBOMDVajMG6ZCf/GoHgdxUJ4sBFp0A/uMIRm+MJUdo33YXEtjqIz8u7DAp8B7DA==",
5188+ "dev": true,
5189+ "requires": {
5190+ "postcss-selector-parser": "^6.0.6"
5191+ }
5192+ },
5193+ "postcss-selector-parser": {
5194+ "version": "6.0.10",
5195+ "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.10.tgz",
5196+ "integrity": "sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==",
5197+ "dev": true,
5198+ "requires": {
5199+ "cssesc": "^3.0.0",
5200+ "util-deprecate": "^1.0.2"
5201+ }
5202+ },
5203+ "postcss-value-parser": {
5204+ "version": "4.2.0",
5205+ "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz",
5206+ "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==",
5207+ "dev": true
5208+ },
5209+ "prop-types": {
5210+ "version": "15.8.1",
5211+ "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
5212+ "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==",
5213+ "requires": {
5214+ "loose-envify": "^1.4.0",
5215+ "object-assign": "^4.1.1",
5216+ "react-is": "^16.13.1"
5217+ }
5218+ },
5219+ "query-string": {
5220+ "version": "7.1.1",
5221+ "resolved": "https://registry.npmjs.org/query-string/-/query-string-7.1.1.tgz",
5222+ "integrity": "sha512-MplouLRDHBZSG9z7fpuAAcI7aAYjDLhtsiVZsevsfaHWDS2IDdORKbSd1kWUA+V4zyva/HZoSfpwnYMMQDhb0w==",
5223+ "requires": {
5224+ "decode-uri-component": "^0.2.0",
5225+ "filter-obj": "^1.1.0",
5226+ "split-on-first": "^1.0.0",
5227+ "strict-uri-encode": "^2.0.0"
5228+ }
5229+ },
5230+ "queue-microtask": {
5231+ "version": "1.2.3",
5232+ "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
5233+ "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==",
5234+ "dev": true
5235+ },
5236+ "quick-lru": {
5237+ "version": "5.1.1",
5238+ "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz",
5239+ "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==",
5240+ "dev": true
5241+ },
5242+ "react": {
5243+ "version": "17.0.2",
5244+ "resolved": "https://registry.npmjs.org/react/-/react-17.0.2.tgz",
5245+ "integrity": "sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==",
5246+ "requires": {
5247+ "loose-envify": "^1.1.0",
5248+ "object-assign": "^4.1.1"
5249+ }
5250+ },
5251+ "react-dom": {
5252+ "version": "17.0.2",
5253+ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz",
5254+ "integrity": "sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA==",
5255+ "requires": {
5256+ "loose-envify": "^1.1.0",
5257+ "object-assign": "^4.1.1",
5258+ "scheduler": "^0.20.2"
5259+ }
5260+ },
5261+ "react-hook-form": {
5262+ "version": "7.33.1",
5263+ "resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.33.1.tgz",
5264+ "integrity": "sha512-ydTfTxEJdvgjCZBj5DDXRc58oTEfnFupEwwTAQ9FSKzykEJkX+3CiAkGtAMiZG7IPWHuzgT6AOBfogiKhUvKgg==",
5265+ "requires": {}
5266+ },
5267+ "react-is": {
5268+ "version": "16.13.1",
5269+ "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
5270+ "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
5271+ },
5272+ "react-refresh": {
5273+ "version": "0.10.0",
5274+ "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.10.0.tgz",
5275+ "integrity": "sha512-PgidR3wST3dDYKr6b4pJoqQFpPGNKDSCDx4cZoshjXipw3LzO7mG1My2pwEzz2JVkF+inx3xRpDeQLFQGH/hsQ==",
5276+ "dev": true
5277+ },
5278+ "react-remove-scroll": {
5279+ "version": "2.5.4",
5280+ "resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.5.4.tgz",
5281+ "integrity": "sha512-xGVKJJr0SJGQVirVFAUZ2k1QLyO6m+2fy0l8Qawbp5Jgrv3DeLalrfMNBFSlmz5kriGGzsVBtGVnf4pTKIhhWA==",
5282+ "requires": {
5283+ "react-remove-scroll-bar": "^2.3.3",
5284+ "react-style-singleton": "^2.2.1",
5285+ "tslib": "^2.1.0",
5286+ "use-callback-ref": "^1.3.0",
5287+ "use-sidecar": "^1.1.2"
5288+ },
5289+ "dependencies": {
5290+ "tslib": {
5291+ "version": "2.4.0",
5292+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz",
5293+ "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ=="
5294+ }
5295+ }
5296+ },
5297+ "react-remove-scroll-bar": {
5298+ "version": "2.3.3",
5299+ "resolved": "https://registry.npmjs.org/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.3.tgz",
5300+ "integrity": "sha512-i9GMNWwpz8XpUpQ6QlevUtFjHGqnPG4Hxs+wlIJntu/xcsZVEpJcIV71K3ZkqNy2q3GfgvkD7y6t/Sv8ofYSbw==",
5301+ "requires": {
5302+ "react-style-singleton": "^2.2.1",
5303+ "tslib": "^2.0.0"
5304+ },
5305+ "dependencies": {
5306+ "tslib": {
5307+ "version": "2.4.0",
5308+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz",
5309+ "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ=="
5310+ }
5311+ }
5312+ },
5313+ "react-router": {
5314+ "version": "6.3.0",
5315+ "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.3.0.tgz",
5316+ "integrity": "sha512-7Wh1DzVQ+tlFjkeo+ujvjSqSJmkt1+8JO+T5xklPlgrh70y7ogx75ODRW0ThWhY7S+6yEDks8TYrtQe/aoboBQ==",
5317+ "requires": {
5318+ "history": "^5.2.0"
5319+ }
5320+ },
5321+ "react-router-dom": {
5322+ "version": "6.3.0",
5323+ "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.3.0.tgz",
5324+ "integrity": "sha512-uaJj7LKytRxZNQV8+RbzJWnJ8K2nPsOOEuX7aQstlMZKQT0164C+X2w6bnkqU3sjtLvpd5ojrezAyfZ1+0sStw==",
5325+ "requires": {
5326+ "history": "^5.2.0",
5327+ "react-router": "6.3.0"
5328+ }
5329+ },
5330+ "react-select": {
5331+ "version": "5.4.0",
5332+ "resolved": "https://registry.npmjs.org/react-select/-/react-select-5.4.0.tgz",
5333+ "integrity": "sha512-CjE9RFLUvChd5SdlfG4vqxZd55AZJRrLrHzkQyTYeHlpOztqcgnyftYAolJ0SGsBev6zAs6qFrjm6KU3eo2hzg==",
5334+ "requires": {
5335+ "@babel/runtime": "^7.12.0",
5336+ "@emotion/cache": "^11.4.0",
5337+ "@emotion/react": "^11.8.1",
5338+ "@types/react-transition-group": "^4.4.0",
5339+ "memoize-one": "^5.0.0",
5340+ "prop-types": "^15.6.0",
5341+ "react-transition-group": "^4.3.0"
5342+ }
5343+ },
5344+ "react-style-singleton": {
5345+ "version": "2.2.1",
5346+ "resolved": "https://registry.npmjs.org/react-style-singleton/-/react-style-singleton-2.2.1.tgz",
5347+ "integrity": "sha512-ZWj0fHEMyWkHzKYUr2Bs/4zU6XLmq9HsgBURm7g5pAVfyn49DgUiNgY2d4lXRlYSiCif9YBGpQleewkcqddc7g==",
5348+ "requires": {
5349+ "get-nonce": "^1.0.0",
5350+ "invariant": "^2.2.4",
5351+ "tslib": "^2.0.0"
5352+ },
5353+ "dependencies": {
5354+ "tslib": {
5355+ "version": "2.4.0",
5356+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz",
5357+ "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ=="
5358+ }
5359+ }
5360+ },
5361+ "react-transition-group": {
5362+ "version": "4.4.2",
5363+ "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.2.tgz",
5364+ "integrity": "sha512-/RNYfRAMlZwDSr6z4zNKV6xu53/e2BuaBbGhbyYIXTrmgu/bGHzmqOs7mJSJBHy9Ud+ApHx3QjrkKSp1pxvlFg==",
5365+ "requires": {
5366+ "@babel/runtime": "^7.5.5",
5367+ "dom-helpers": "^5.0.1",
5368+ "loose-envify": "^1.4.0",
5369+ "prop-types": "^15.6.2"
5370+ }
5371+ },
5372+ "read-cache": {
5373+ "version": "1.0.0",
5374+ "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz",
5375+ "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==",
5376+ "dev": true,
5377+ "requires": {
5378+ "pify": "^2.3.0"
5379+ }
5380+ },
5381+ "readdirp": {
5382+ "version": "3.6.0",
5383+ "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
5384+ "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
5385+ "dev": true,
5386+ "requires": {
5387+ "picomatch": "^2.2.1"
5388+ }
5389+ },
5390+ "regenerator-runtime": {
5391+ "version": "0.13.9",
5392+ "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz",
5393+ "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA=="
5394+ },
5395+ "remove-markdown-and-html": {
5396+ "version": "0.1.0",
5397+ "resolved": "https://registry.npmjs.org/remove-markdown-and-html/-/remove-markdown-and-html-0.1.0.tgz",
5398+ "integrity": "sha512-Sy03RJ/R/FBbK6wutBKKIyEVMQS+TzSpGc8pBxwrh0LiqyVIaD/LkitUABIJJ59iryhvrPTmS8dzd3DoLdopHg=="
5399+ },
5400+ "resolve": {
5401+ "version": "1.22.1",
5402+ "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz",
5403+ "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==",
5404+ "requires": {
5405+ "is-core-module": "^2.9.0",
5406+ "path-parse": "^1.0.7",
5407+ "supports-preserve-symlinks-flag": "^1.0.0"
5408+ }
5409+ },
5410+ "resolve-from": {
5411+ "version": "4.0.0",
5412+ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
5413+ "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g=="
5414+ },
5415+ "reusify": {
5416+ "version": "1.0.4",
5417+ "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
5418+ "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==",
5419+ "dev": true
5420+ },
5421+ "rollup": {
5422+ "version": "2.75.7",
5423+ "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.75.7.tgz",
5424+ "integrity": "sha512-VSE1iy0eaAYNCxEXaleThdFXqZJ42qDBatAwrfnPlENEZ8erQ+0LYX4JXOLPceWfZpV1VtZwZ3dFCuOZiSyFtQ==",
5425+ "dev": true,
5426+ "requires": {
5427+ "fsevents": "~2.3.2"
5428+ }
5429+ },
5430+ "run-parallel": {
5431+ "version": "1.2.0",
5432+ "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
5433+ "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==",
5434+ "dev": true,
5435+ "requires": {
5436+ "queue-microtask": "^1.2.2"
5437+ }
5438+ },
5439+ "safe-buffer": {
5440+ "version": "5.1.2",
5441+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
5442+ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
5443+ },
5444+ "scheduler": {
5445+ "version": "0.20.2",
5446+ "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.20.2.tgz",
5447+ "integrity": "sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ==",
5448+ "requires": {
5449+ "loose-envify": "^1.1.0",
5450+ "object-assign": "^4.1.1"
5451+ }
5452+ },
5453+ "semver": {
5454+ "version": "6.3.0",
5455+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
5456+ "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw=="
5457+ },
5458+ "source-map": {
5459+ "version": "0.5.7",
5460+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
5461+ "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ=="
5462+ },
5463+ "source-map-js": {
5464+ "version": "1.0.2",
5465+ "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz",
5466+ "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==",
5467+ "dev": true
5468+ },
5469+ "split-on-first": {
5470+ "version": "1.1.0",
5471+ "resolved": "https://registry.npmjs.org/split-on-first/-/split-on-first-1.1.0.tgz",
5472+ "integrity": "sha512-43ZssAJaMusuKWL8sKUBQXHWOpq8d6CfN/u1p4gUzfJkM05C8rxTmYrkIPTXapZpORA6LkkzcUulJ8FqA7Uudw=="
5473+ },
5474+ "strict-uri-encode": {
5475+ "version": "2.0.0",
5476+ "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz",
5477+ "integrity": "sha512-QwiXZgpRcKkhTj2Scnn++4PKtWsH0kpzZ62L2R6c/LUVYv7hVnZqcg2+sMuT6R7Jusu1vviK/MFsu6kNJfWlEQ=="
5478+ },
5479+ "stylis": {
5480+ "version": "4.0.13",
5481+ "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.0.13.tgz",
5482+ "integrity": "sha512-xGPXiFVl4YED9Jh7Euv2V220mriG9u4B2TA6Ybjc1catrstKD2PpIdU3U0RKpkVBC2EhmL/F0sPCr9vrFTNRag=="
5483+ },
5484+ "supports-color": {
5485+ "version": "5.5.0",
5486+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
5487+ "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
5488+ "requires": {
5489+ "has-flag": "^3.0.0"
5490+ }
5491+ },
5492+ "supports-preserve-symlinks-flag": {
5493+ "version": "1.0.0",
5494+ "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
5495+ "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w=="
5496+ },
5497+ "tailwindcss": {
5498+ "version": "3.1.4",
5499+ "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.1.4.tgz",
5500+ "integrity": "sha512-NrxbFV4tYsga/hpWbRyUfIaBrNMXDxx5BsHgBS4v5tlyjf+sDsgBg5m9OxjrXIqAS/uR9kicxLKP+bEHI7BSeQ==",
5501+ "dev": true,
5502+ "requires": {
5503+ "arg": "^5.0.2",
5504+ "chokidar": "^3.5.3",
5505+ "color-name": "^1.1.4",
5506+ "detective": "^5.2.1",
5507+ "didyoumean": "^1.2.2",
5508+ "dlv": "^1.1.3",
5509+ "fast-glob": "^3.2.11",
5510+ "glob-parent": "^6.0.2",
5511+ "is-glob": "^4.0.3",
5512+ "lilconfig": "^2.0.5",
5513+ "normalize-path": "^3.0.0",
5514+ "object-hash": "^3.0.0",
5515+ "picocolors": "^1.0.0",
5516+ "postcss": "^8.4.14",
5517+ "postcss-import": "^14.1.0",
5518+ "postcss-js": "^4.0.0",
5519+ "postcss-load-config": "^3.1.4",
5520+ "postcss-nested": "5.0.6",
5521+ "postcss-selector-parser": "^6.0.10",
5522+ "postcss-value-parser": "^4.2.0",
5523+ "quick-lru": "^5.1.1",
5524+ "resolve": "^1.22.0"
5525+ },
5526+ "dependencies": {
5527+ "color-name": {
5528+ "version": "1.1.4",
5529+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
5530+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
5531+ "dev": true
5532+ }
5533+ }
5534+ },
5535+ "tailwindcss-labeled-groups": {
5536+ "version": "0.0.2",
5537+ "resolved": "https://registry.npmjs.org/tailwindcss-labeled-groups/-/tailwindcss-labeled-groups-0.0.2.tgz",
5538+ "integrity": "sha512-leOVv9h2K9WDHoXPXVBOmTJgWECVkpVFc/hjrwuqGUEtNxvRvuOtCjenu9ppY+pJtky5INJUqDCNa8pS3AbYmw==",
5539+ "dev": true,
5540+ "requires": {}
5541+ },
5542+ "to-fast-properties": {
5543+ "version": "2.0.0",
5544+ "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz",
5545+ "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog=="
5546+ },
5547+ "to-regex-range": {
5548+ "version": "5.0.1",
5549+ "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
5550+ "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
5551+ "dev": true,
5552+ "requires": {
5553+ "is-number": "^7.0.0"
5554+ }
5555+ },
5556+ "tslib": {
5557+ "version": "1.14.1",
5558+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
5559+ "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
5560+ },
5561+ "typescript": {
5562+ "version": "4.7.4",
5563+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.4.tgz",
5564+ "integrity": "sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ==",
5565+ "dev": true
5566+ },
5567+ "update-browserslist-db": {
5568+ "version": "1.0.4",
5569+ "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.4.tgz",
5570+ "integrity": "sha512-jnmO2BEGUjsMOe/Fg9u0oczOe/ppIDZPebzccl1yDWGLFP16Pa1/RM5wEoKYPG2zstNcDuAStejyxsOuKINdGA==",
5571+ "requires": {
5572+ "escalade": "^3.1.1",
5573+ "picocolors": "^1.0.0"
5574+ }
5575+ },
5576+ "urbit-ob": {
5577+ "version": "5.0.1",
5578+ "resolved": "https://registry.npmjs.org/urbit-ob/-/urbit-ob-5.0.1.tgz",
5579+ "integrity": "sha512-qGNAwu87XNkW3g8ah4fUwmh2EKXtsdhEbyEiE5qX4Op17rhLH3HSkvu8g9z+MhqX51Uz9sf8ktvqJj/IRwETIQ==",
5580+ "requires": {
5581+ "bn.js": "^4.11.8",
5582+ "lodash.chunk": "^4.2.0",
5583+ "lodash.isequal": "^4.5.0"
5584+ }
5585+ },
5586+ "use-callback-ref": {
5587+ "version": "1.3.0",
5588+ "resolved": "https://registry.npmjs.org/use-callback-ref/-/use-callback-ref-1.3.0.tgz",
5589+ "integrity": "sha512-3FT9PRuRdbB9HfXhEq35u4oZkvpJ5kuYbpqhCfmiZyReuRgpnhDlbr2ZEnnuS0RrJAPn6l23xjFg9kpDM+Ms7w==",
5590+ "requires": {
5591+ "tslib": "^2.0.0"
5592+ },
5593+ "dependencies": {
5594+ "tslib": {
5595+ "version": "2.4.0",
5596+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz",
5597+ "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ=="
5598+ }
5599+ }
5600+ },
5601+ "use-sidecar": {
5602+ "version": "1.1.2",
5603+ "resolved": "https://registry.npmjs.org/use-sidecar/-/use-sidecar-1.1.2.tgz",
5604+ "integrity": "sha512-epTbsLuzZ7lPClpz2TyryBfztm7m+28DlEv2ZCQ3MDr5ssiwyOwGH/e5F9CkfWjJ1t4clvI58yF822/GUkjjhw==",
5605+ "requires": {
5606+ "detect-node-es": "^1.1.0",
5607+ "tslib": "^2.0.0"
5608+ },
5609+ "dependencies": {
5610+ "tslib": {
5611+ "version": "2.4.0",
5612+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz",
5613+ "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ=="
5614+ }
5615+ }
5616+ },
5617+ "use-sync-external-store": {
5618+ "version": "1.1.0",
5619+ "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.1.0.tgz",
5620+ "integrity": "sha512-SEnieB2FPKEVne66NpXPd1Np4R1lTNKfjuy3XdIoPQKYBAFdzbzSZlSn1KJZUiihQLQC5Znot4SBz1EOTBwQAQ==",
5621+ "requires": {}
5622+ },
5623+ "util-deprecate": {
5624+ "version": "1.0.2",
5625+ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
5626+ "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
5627+ "dev": true
5628+ },
5629+ "vite": {
5630+ "version": "2.9.13",
5631+ "resolved": "https://registry.npmjs.org/vite/-/vite-2.9.13.tgz",
5632+ "integrity": "sha512-AsOBAaT0AD7Mhe8DuK+/kE4aWYFMx/i0ZNi98hJclxb4e0OhQcZYUrvLjIaQ8e59Ui7txcvKMiJC1yftqpQoDw==",
5633+ "dev": true,
5634+ "requires": {
5635+ "esbuild": "^0.14.27",
5636+ "fsevents": "~2.3.2",
5637+ "postcss": "^8.4.13",
5638+ "resolve": "^1.22.0",
5639+ "rollup": "^2.59.0"
5640+ }
5641+ },
5642+ "vite-plugin-html-config": {
5643+ "version": "1.0.8",
5644+ "resolved": "https://registry.npmjs.org/vite-plugin-html-config/-/vite-plugin-html-config-1.0.8.tgz",
5645+ "integrity": "sha512-3tTtBQO+6zpC8uzAAfj3FWygj+V6H6F9fEt5KtB3j5UHsRYP0yLpTHsMvubXtqCXbKDp1oOakYYSjprqYcbrpA==",
5646+ "dev": true,
5647+ "requires": {}
5648+ },
5649+ "vite-plugin-rewrite-all": {
5650+ "version": "0.1.2",
5651+ "resolved": "https://registry.npmjs.org/vite-plugin-rewrite-all/-/vite-plugin-rewrite-all-0.1.2.tgz",
5652+ "integrity": "sha512-hBFuG043kbixgZ/ke9SzKhkO6P8a5ryxD0CmZTe+/Cz17RIKi7uSeNUJy79V4FgavZ7pWVRg0tqVwJ7lP/A2/Q==",
5653+ "dev": true,
5654+ "requires": {
5655+ "connect-history-api-fallback": "^1.6.0"
5656+ }
5657+ },
5658+ "xtend": {
5659+ "version": "4.0.2",
5660+ "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
5661+ "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==",
5662+ "dev": true
5663+ },
5664+ "yaml": {
5665+ "version": "1.10.2",
5666+ "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz",
5667+ "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg=="
5668+ },
5669+ "zustand": {
5670+ "version": "4.0.0-rc.1",
5671+ "resolved": "https://registry.npmjs.org/zustand/-/zustand-4.0.0-rc.1.tgz",
5672+ "integrity": "sha512-qgcs7zLqBdHu0PuT3GW4WCIY5SgXdsv30GQMu9Qpp1BA2aS+sNS8l4x0hWuyEhjXkN+701aGWawhKDv6oWJAcw==",
5673+ "requires": {
5674+ "use-sync-external-store": "1.1.0"
5675+ }
5676+ }
5677+ }
5678+}
ui/package.jsonnew file+48
@@ -0,0 +1,48 @@
1+{
2+ "name": "sphinx",
3+ "version": "0.0.0",
4+ "private": true,
5+ "scripts": {
6+ "dev": "vite",
7+ "build": "tsc && vite build",
8+ "serve": "vite preview",
9+ "test": "tsc --noEmit",
10+ "tsc": "tsc --noEmit"
11+ },
12+ "dependencies": {
13+ "@heroicons/react": "^1.0.6",
14+ "@radix-ui/react-dropdown-menu": "^0.1.6",
15+ "@radix-ui/react-select": "^0.1.1",
16+ "@radix-ui/react-toggle-group": "^0.1.5",
17+ "@tanstack/react-query": "^4.29.5",
18+ "@urbit/api": "2.2",
19+ "@urbit/http-api": "^2.0.0",
20+ "big-integer": "^1.6.51",
21+ "classnames": "^2.3.1",
22+ "color2k": "^2.0.2",
23+ "lodash.debounce": "^4.0.8",
24+ "query-string": "^7.1.1",
25+ "react": "^17.0.2",
26+ "react-dom": "^17.0.2",
27+ "react-hook-form": "^7.33.1",
28+ "react-router-dom": "^6.3.0",
29+ "react-select": "^5.4.0",
30+ "remove-markdown-and-html": "^0.1.0",
31+ "urbit-ob": "^5.0.1",
32+ "zustand": "^4.0.0-rc.1"
33+ },
34+ "devDependencies": {
35+ "@types/lodash.debounce": "^4.0.7",
36+ "@types/react": "^17.0.0",
37+ "@types/react-dom": "^17.0.0",
38+ "@urbit/vite-plugin-urbit": "^0.8.0",
39+ "@vitejs/plugin-react-refresh": "^1.3.1",
40+ "autoprefixer": "^10.4.7",
41+ "postcss": "^8.4.14",
42+ "postcss-import": "^14.1.0",
43+ "tailwindcss": "^3.1.4",
44+ "tailwindcss-labeled-groups": "^0.0.2",
45+ "typescript": "^4.3.2",
46+ "vite": "^2.9.13"
47+ }
48+}
ui/postcss.config.jsnew file+8
@@ -0,0 +1,8 @@
1+module.exports = {
2+ plugins: [
3+ require('postcss-import'),
4+ require('tailwindcss/nesting'),
5+ require('tailwindcss'),
6+ require('autoprefixer'),
7+ ]
8+}
ui/public/android-chrome-512x512.pngnew file

Binary file not shown.

ui/public/manifest.jsonnew file+14
@@ -0,0 +1,14 @@
1+{
2+ "name": "sphinx",
3+ "short_name": "sphinx",
4+ "icons": [
5+ {
6+ "src": "/apps/sphinx/android-chrome-512x512.png",
7+ "sizes": "512x512",
8+ "type": "image/png"
9+ }
10+ ],
11+ "theme_color": "#ffffff",
12+ "background_color": "#ffffff",
13+ "display": "standalone"
14+}
ui/src/api.tsnew file+12
@@ -0,0 +1,12 @@
1+import Urbit from "@urbit/http-api";
2+
3+const api = new Urbit('', '', window.desk);
4+api.ship = window.ship;
5+
6+// @urbit/http-api 2.x adds `window.addEventListener('beforeunload', this.delete)`
7+// unbound, so its beacon is sent to `${location dir}/undefined` (404) and the
8+// channel is left open until eyre's 12h timeout. Replace it with a bound one.
9+window.removeEventListener('beforeunload', api.delete);
10+window.addEventListener('beforeunload', () => api.delete());
11+
12+export default api;
ui/src/app.tsxnew file+55
@@ -0,0 +1,55 @@
1+import React from 'react';
2+import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
3+import { BrowserRouter, Route, Routes } from 'react-router-dom';
4+import { CenterColumn } from './components/CenterColumn';
5+import { Layout } from './components/Layout';
6+import { AllListings } from './manage-listings/AllListings';
7+import { Apps } from './manage-listings/Apps';
8+import { Groups } from './manage-listings/Groups';
9+import { MyListings } from './manage-listings/MyListings';
10+import { Notebooks } from './manage-listings/Notebooks';
11+import { Post } from './manage-listings/Post';
12+import { Search } from './pages/Search';
13+import { Tag } from './pages/Tag';
14+
15+const queryClient = new QueryClient();
16+
17+function Main() {
18+ return (
19+ <Routes>
20+ <Route element={<Layout />}>
21+ <Route element={<CenterColumn />}>
22+ <Route path="/" element={<Search />} />
23+ <Route path="/search" element={<Search />} />
24+ <Route path="/search/:lookup" element={<Search />} />
25+ <Route path="/search/:lookup/:limit/:page" element={<Search />} />
26+ <Route path="/tags" element={<Tag />} />
27+ <Route path="/tags/:tag" element={<Tag />} />
28+ <Route path="/tags/:tag/:limit/:page" element={<Tag />} />
29+ </Route>
30+ <Route path="/manage-listings">
31+ <Route element={<CenterColumn />}>
32+ <Route index element={<MyListings />} />
33+ <Route path="all" element={<AllListings />} />
34+ <Route path="all/:limit/:page" element={<AllListings />} />
35+ <Route path="post" element={<Post />} />
36+ <Route path="apps" element={<Apps />} />
37+ <Route path="groups" element={<Groups />} />
38+ </Route>
39+ <Route path="posts" element={<Notebooks />} />
40+ <Route path="posts/:ship/:name" element={<Notebooks />} />
41+ </Route>
42+ </Route>
43+ </Routes>
44+ );
45+}
46+
47+export function App() {
48+ return (
49+ <QueryClientProvider client={queryClient}>
50+ <BrowserRouter basename='/apps/sphinx'>
51+ <Main />
52+ </BrowserRouter>
53+ </QueryClientProvider>
54+ )
55+}
ui/src/assets/apple-touch-icon.pngnew file

Binary file not shown.

ui/src/assets/favicon.iconew file

Binary file not shown.

ui/src/assets/favicon.svgnew file+12
@@ -0,0 +1,12 @@
1+<svg width="513" height="513" viewBox="0 0 513 513" fill="none" xmlns="http://www.w3.org/2000/svg">
2+<style>
3+.icon-color { fill: #000000; }
4+@media (prefers-color-scheme: dark) {
5+ .icon-color { fill: #ffffff; }
6+}
7+</style>
8+<path d="M247.634 122.758C247.634 147.519 238.15 162.538 219.182 171.468C198.239 181.21 184.804 197.853 178.876 220.584C172.159 245.751 153.981 260.364 129.481 259.552C109.723 259.146 94.7075 249.404 86.014 231.138C79.2963 216.931 70.6028 204.753 56.7723 197.041C50.4497 193.388 43.732 190.952 36.6192 188.923C16.4661 183.24 1.84525 166.597 0.264615 145.896C-1.71118 121.135 7.37747 103.274 27.5305 93.1266C49.6594 82.5728 63.49 65.1184 69.4173 41.1695C75.3447 16.8145 95.8929 2.60752 122.369 4.6371C137.385 5.85484 148.844 13.5672 157.538 25.7447C163.465 34.2689 168.602 43.199 174.529 51.3173C181.642 61.4652 191.126 67.9598 202.586 72.019C208.118 74.0486 214.045 76.0781 219.182 78.9195C238.15 88.6615 247.634 104.492 247.634 122.758Z" class="icon-color" />
9+<path d="M512.01 355.757C511.615 372.806 503.712 387.824 486.325 396.349C463.406 407.714 449.18 425.981 442.067 450.335C435.745 471.037 419.543 484.026 398.6 485.65C377.657 487.274 359.084 476.72 350.391 457.236C340.512 434.505 323.915 420.704 300.601 414.209C258.714 403.249 254.762 350.48 279.262 328.561C283.609 324.908 288.351 321.254 293.488 318.819C314.036 308.671 327.076 292.029 333.399 270.109C338.931 250.219 350.786 236.824 370.939 232.765C393.858 228.3 415.197 235.2 426.261 259.555C436.535 282.287 453.132 295.682 476.446 302.582C500.551 309.889 512.01 326.937 512.01 355.757Z" class="icon-color" />
10+<path d="M463.786 51.3199C462.6 58.2204 461.415 65.121 459.439 71.6156C453.117 93.1291 454.697 113.425 466.157 132.909C476.431 150.363 476.036 168.629 465.762 185.678C455.883 202.32 440.472 210.033 421.899 210.033C417.157 210.033 412.415 208.815 408.069 207.191C384.359 199.073 361.44 200.697 339.706 214.498C310.069 233.17 271.739 206.379 268.973 178.371C268.182 169.441 268.182 160.511 271.344 152.393C280.037 130.067 276.481 109.366 266.997 89.07C262.65 80.1398 259.094 70.8038 259.094 60.6559C259.489 27.3709 290.311 3.42188 321.529 11.9461C331.408 14.7875 341.287 18.4407 351.956 18.4407C364.206 18.4407 374.875 14.3816 385.94 9.10469C393.052 5.45146 400.956 2.20414 408.859 0.580478C434.544 -3.88459 461.02 18.0348 462.996 44.8252C462.996 47.2607 463.391 49.2903 463.391 51.7258C463.391 51.3199 463.786 51.3199 463.786 51.3199Z" class="icon-color" />
11+<path d="M235.757 342.773C234.571 349.268 233.781 356.168 231.805 362.663C225.483 384.176 227.063 404.878 238.523 424.362C257.095 456.429 237.337 498.239 197.822 501.486C192.684 501.892 187.152 500.674 182.015 499.05C157.515 490.526 134.201 491.744 112.072 505.951C82.8304 524.217 44.8952 497.833 41.7339 470.636C40.9436 461.706 40.5485 453.182 43.7097 444.658C52.4032 421.521 48.8468 399.601 38.1775 378.088C33.0405 367.94 30.2743 356.98 31.4598 345.209C33.8308 322.883 53.9839 302.587 76.1127 300.964C84.4111 300.558 92.3142 301.37 99.8222 304.211C120.766 312.329 140.524 309.488 159.886 298.528C174.507 290.004 190.314 286.757 206.12 294.469C224.692 304.617 234.966 320.448 235.757 342.773Z" class="icon-color" />
12+</svg>
ui/src/assets/safari-pinned-tab.svgnew file+54
@@ -0,0 +1,54 @@
1+<?xml version="1.0" standalone="no"?>
2+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
3+ "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
4+<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
5+ width="700.000000pt" height="700.000000pt" viewBox="0 0 700.000000 700.000000"
6+ preserveAspectRatio="xMidYMid meet">
7+<metadata>
8+Created by potrace 1.14, written by Peter Selinger 2001-2017
9+</metadata>
10+<g transform="translate(0.000000,700.000000) scale(0.100000,-0.100000)"
11+fill="#000000" stroke="none">
12+<path d="M5565 6989 c-16 -5 -39 -11 -50 -13 -54 -12 -116 -37 -230 -91 -219
13+-105 -335 -135 -495 -131 -63 2 -126 7 -140 10 -14 4 -36 9 -50 12 -14 3 -79
14+21 -145 41 -205 61 -361 54 -525 -23 -239 -113 -392 -356 -392 -625 0 -110 25
15+-201 107 -389 85 -197 116 -320 121 -480 3 -137 -12 -231 -60 -370 -15 -41
16+-30 -97 -33 -125 -8 -58 -8 -190 0 -255 27 -220 225 -440 475 -527 67 -24 92
17+-27 197 -27 109 0 127 3 189 28 37 16 100 47 140 70 174 103 316 141 521 140
18+146 0 208 -10 362 -58 171 -54 291 -54 449 -1 294 99 498 442 448 755 -4 25
19+-9 50 -10 55 -2 6 -7 24 -10 40 -4 17 -36 86 -71 153 -60 117 -113 253 -128
20+332 -4 19 -8 91 -10 160 -4 126 8 227 40 336 24 82 65 283 60 297 -2 6 -6 43
21+-10 81 -8 97 -22 150 -62 231 -44 90 -71 126 -148 200 -123 117 -255 175 -415
22+180 -52 2 -108 -1 -125 -6z"/>
23+<path d="M1445 6923 c-38 -8 -106 -31 -150 -52 -187 -90 -284 -214 -354 -455
24+-59 -201 -123 -321 -243 -451 -81 -88 -154 -143 -295 -222 -64 -35 -135 -79
25+-157 -96 -100 -76 -187 -210 -223 -347 -21 -80 -24 -308 -4 -390 22 -91 84
26+-209 146 -277 102 -112 188 -163 385 -228 307 -100 451 -229 620 -550 61 -115
27+94 -161 164 -228 52 -50 156 -117 181 -117 8 0 16 -4 19 -9 16 -26 274 -53
28+356 -37 14 3 37 7 53 10 71 12 165 55 237 109 122 90 201 216 265 420 51 165
29+96 258 172 359 86 114 212 216 358 290 147 75 226 139 292 238 36 53 80 162
30+89 216 3 22 8 42 10 46 3 4 7 53 9 109 10 221 -44 374 -180 512 -67 68 -167
31+136 -253 173 -31 14 -66 29 -77 33 -11 5 -47 19 -80 31 -164 59 -294 148 -377
32+257 -25 32 -97 137 -160 233 -131 199 -185 263 -272 324 -147 103 -335 138
33+-531 99z"/>
34+<path d="M5070 3824 c-177 -38 -296 -111 -399 -245 -36 -46 -88 -160 -122
35+-264 -103 -321 -254 -508 -534 -660 -184 -100 -292 -208 -352 -350 -113 -268
36+-56 -593 138 -785 81 -80 154 -122 300 -171 152 -51 233 -88 322 -147 139 -93
37+274 -254 346 -415 83 -185 208 -309 376 -372 84 -32 139 -40 260 -39 145 1
38+248 34 370 117 121 82 205 205 266 388 113 340 278 537 601 714 145 80 234
39+172 290 300 86 195 64 503 -49 694 -50 85 -141 172 -224 216 -37 19 -120 53
40+-184 76 -197 67 -303 129 -425 246 -92 87 -158 179 -230 323 -102 202 -207
41+301 -380 360 -82 28 -272 36 -370 14z"/>
42+<path d="M2395 3017 c-76 -22 -110 -37 -270 -119 -72 -38 -195 -82 -252 -93
43+-127 -22 -184 -24 -293 -10 -86 11 -114 17 -179 40 -132 47 -193 58 -317 57
44+-103 0 -176 -18 -268 -64 -142 -72 -258 -190 -325 -331 -95 -200 -84 -408 34
45+-666 95 -209 136 -366 136 -528 1 -142 -12 -213 -67 -380 -22 -66 -27 -97 -27
46+-198 -1 -66 2 -142 6 -169 29 -183 195 -384 394 -476 186 -87 369 -86 533 2
47+41 23 102 55 135 73 73 39 196 80 290 95 69 12 250 15 283 6 9 -3 38 -7 64
48+-11 26 -3 87 -17 135 -31 48 -14 113 -32 143 -41 211 -56 483 46 643 242 48
49+58 120 194 131 245 3 14 8 36 12 50 13 50 13 225 0 285 -19 81 -35 123 -94
50+240 -96 188 -122 287 -127 468 -2 115 7 188 40 317 52 202 68 337 50 423 -3
51+15 -7 39 -10 54 -8 38 -40 125 -58 159 -8 16 -24 45 -33 64 -28 53 -150 172
52+-229 222 -106 68 -172 89 -295 94 -88 3 -118 0 -185 -19z"/>
53+</g>
54+</svg>
ui/src/components/CenterColumn.tsxnew file+6
@@ -0,0 +1,6 @@
1+import React from 'react';
2+import { Outlet } from 'react-router-dom';
3+
4+export const CenterColumn = () => (
5+ <div className="flex-1 flex flex-col max-w-2xl h-full w-full p-4 sm:py-12 sm:px-8 space-y-6">{<Outlet />}</div>
6+)
ui/src/components/ErrorMessage.tsxnew file+26
@@ -0,0 +1,26 @@
1+import cn from 'classnames';
2+import React from 'react';
3+import { FieldValues, LiteralUnion, RegisterOptions, useFormContext } from 'react-hook-form';
4+
5+type Validation = LiteralUnion<keyof RegisterOptions, string>;
6+
7+interface ErrorMessageProps<T extends FieldValues> {
8+ field: keyof T;
9+ messages: Partial<Record<Validation, string>>;
10+ className?: string;
11+}
12+
13+export function ErrorMessage<T extends FieldValues>({ field, messages, className }: ErrorMessageProps<T>) {
14+ const { formState } = useFormContext<T>();
15+ const error = formState.errors[field];
16+
17+ if (!error) {
18+ return null;
19+ }
20+
21+ return (
22+ <p className={cn('text-xs text-red-500', className)}>
23+ {messages[error.type as Validation]}
24+ </p>
25+ )
26+}
ui/src/components/Filter.tsxnew file+55
@@ -0,0 +1,55 @@
1+import React from 'react';
2+import * as Select from '@radix-ui/react-select';
3+import { PostFilter, PostType } from '../types/sphinx';
4+
5+interface FilterItemProps {
6+ title: PostFilter;
7+}
8+
9+const FilterItem = ({ title }: FilterItemProps) => {
10+ return (
11+ <Select.Item value={title} className="text-mauve cursor-default select-none relative py-2 pl-3 pr-9 focus:outline-none focus:ring-1 focus:ring-rosy font-semibold">
12+ <Select.ItemText>%{title}</Select.ItemText>
13+ <Select.ItemIndicator className="text-rosy absolute inset-y-0 right-0 flex items-center pr-4">
14+ <svg className="h-5 w-5" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor">
15+ <path fillRule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clipRule="evenodd" />
16+ </svg>
17+ </Select.ItemIndicator>
18+ </Select.Item>
19+ )
20+}
21+
22+const filters: PostFilter[] = ['all', 'app', 'group', 'content', 'other'];
23+
24+interface FilterProps<T extends string> {
25+ selected: T;
26+ onSelect: (value: T) => void;
27+ showAll?: boolean;
28+ className?: string;
29+}
30+
31+export function Filter<T extends string>({ selected, onSelect, className, showAll = true }: FilterProps<T>) {
32+ const options = showAll ? filters : filters.filter(f => f === 'all');
33+ return (
34+ <div className={className}>
35+ <Select.Root value={selected} onValueChange={onSelect}>
36+ <span className="sr-only">Filter Type</span>
37+ <Select.Trigger className="bg-linen flex justify-between w-full font-semibold border border-fawn/30 rounded-lg shadow-sm pl-3 pr-2 py-1.5 text-left cursor-default focus:outline-none focus:ring-1 focus:ring-rosy focus:border-rosy sm:text-sm">
38+ <Select.Value>%{selected}</Select.Value>
39+ <Select.Icon asChild>
40+ <svg className="h-5 w-5 text-rosy" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor">
41+ <path fillRule="evenodd" d="M10 3a1 1 0 01.707.293l3 3a1 1 0 01-1.414 1.414L10 5.414 7.707 7.707a1 1 0 01-1.414-1.414l3-3A1 1 0 0110 3zm-3.707 9.293a1 1 0 011.414 0L10 14.586l2.293-2.293a1 1 0 011.414 1.414l-3 3a1 1 0 01-1.414 0l-3-3a1 1 0 010-1.414z" clipRule="evenodd" />
42+ </svg>
43+ </Select.Icon>
44+ </Select.Trigger>
45+ <Select.Content className="z-10 w-full bg-linen shadow-lg max-h-60 rounded-md py-1 text-base ring-1 ring-rosy ring-opacity-5 overflow-auto focus:outline-none sm:text-sm">
46+ <Select.Viewport>
47+ {options.map(f => (
48+ <FilterItem key={f} title={f} />
49+ ))}
50+ </Select.Viewport>
51+ </Select.Content>
52+ </Select.Root>
53+ </div>
54+ )
55+}
ui/src/components/Layout.tsxnew file+75
@@ -0,0 +1,75 @@
1+import { MenuIcon } from '@heroicons/react/solid';
2+import * as DropdownMenu from '@radix-ui/react-dropdown-menu';
3+import cn from 'classnames';
4+import React from 'react';
5+import { NavLink, NavLinkProps, Outlet } from 'react-router-dom';
6+import useMedia from '../logic/useMedia';
7+import { BrowsingRoutes, PostingRoutes } from '../routes';
8+import { Meta } from './Meta';
9+
10+const DesktopNavLink = ({ to, children, ...props }: NavLinkProps) => (
11+ <li>
12+ <NavLink to={to} className={({ isActive }) => cn('hover:text-rosy transition-colors', isActive && 'underline')} {...props}>
13+ { children }
14+ </NavLink>
15+ </li>
16+)
17+
18+interface WrappedNavLinkProps extends NavLinkProps {
19+ navClassName: (props: { isActive: boolean }) => string;
20+}
21+
22+const WrappedNavLink = React.forwardRef<HTMLAnchorElement, WrappedNavLinkProps>(({ className, navClassName, ...props }, forwardedRef) => {
23+ return (
24+ <NavLink
25+ {...props}
26+ className={(props) => `${className} ${navClassName(props)}`}
27+ ref={forwardedRef}
28+ />
29+ );
30+});
31+
32+const MobileNavLink = ({ to, children }: NavLinkProps) => (
33+ <DropdownMenu.Item asChild>
34+ <WrappedNavLink to={to} navClassName={({ isActive }) => cn('block hover:text-rosy transition-colors', isActive && 'underline')}>
35+ { children }
36+ </WrappedNavLink>
37+ </DropdownMenu.Item>
38+)
39+
40+export const Layout = () => {
41+ const isMobile = useMedia('(max-width: 639px)');
42+
43+ return (
44+ <main className={cn("flex flex-col items-center h-full min-h-screen")}>
45+ <Outlet />
46+ <aside className='self-start mx-4 mb-6 mt-auto sm:m-0 sm:fixed left-4 bottom-4'>
47+ {isMobile ? (
48+ <DropdownMenu.Root>
49+ <DropdownMenu.Trigger className='button fixed bottom-6 right-4 p-2 rounded-full' aria-label='Open Menu'>
50+ <MenuIcon className='w-6 h-6' />
51+ </DropdownMenu.Trigger>
52+ <DropdownMenu.Content sideOffset={16} className='min-w-[200px] bg-linen shadow-lg rounded-xl'>
53+ <div className='p-4 space-y-3 text-right bg-fawn/30 rounded-xl'>
54+ {Object.entries(BrowsingRoutes).map(([k,v]) => <MobileNavLink key={v} to={v}>{k}</MobileNavLink>)}
55+ <DropdownMenu.Separator className='border-t-2 border-mauve'/>
56+ {Object.entries(PostingRoutes).map(([k,v]) => <MobileNavLink key={v} to={v}>{k}</MobileNavLink>)}
57+ </div>
58+ </DropdownMenu.Content>
59+ </DropdownMenu.Root>
60+ ) : (
61+ <nav className='w-24 mb-10'>
62+ <ul className='font-semibold text-sm space-y-2'>
63+ {Object.entries(BrowsingRoutes).map(([k,v]) => <DesktopNavLink key={v} to={v} end={k === 'tags'}>{k}</DesktopNavLink>)}
64+ </ul>
65+ <hr className='block my-4 border-mauve/60'/>
66+ <ul className='font-semibold text-sm space-y-2'>
67+ {Object.entries(PostingRoutes).map(([k,v]) => <DesktopNavLink key={v} to={v}>{k}</DesktopNavLink>)}
68+ </ul>
69+ </nav>
70+ )}
71+ <Meta className='text-sm'/>
72+ </aside>
73+ </main>
74+ )
75+}
ui/src/components/Listing.tsxnew file+74
@@ -0,0 +1,74 @@
1+import { UsersIcon, UserRemoveIcon } from '@heroicons/react/solid';
2+import { deSig } from '@urbit/api';
3+import React from 'react';
4+import { ListingImage } from './ListingImage';
5+import { Listing as ListingType } from '../types/sphinx';
6+import { channelURL, normalizeLink, refToURL } from '../utils';
7+import { Pals } from '../state/pals';
8+import { ChannelPreview } from '../types';
9+import { useChannelPreview } from '../state/groups';
10+
11+interface ListingProps extends ListingType {
12+ remove: (hash: string) => void;
13+ removePal: (ship: string) => void;
14+ outgoing: Pals;
15+}
16+
17+function getURL(link: string | { nest: string, where: string }, preview?: ChannelPreview) {
18+ if (typeof link === 'string') {
19+ return link;
20+ }
21+
22+ // Tlon routes channels under their group, which only the preview knows.
23+ // A post deep link (post/:authorId/:postId) would also need the author,
24+ // which listing refs don't carry, so link to the post's channel.
25+ if (!preview) {
26+ return '/apps/groups/';
27+ }
28+
29+ return channelURL(preview.group.flag, link.nest);
30+}
31+
32+export const Listing = ({ hash, time, source, post, remove, removePal, outgoing }: ListingProps) => {
33+ const cite = normalizeLink(post.link);
34+ const link = refToURL(cite);
35+ const preview = useChannelPreview(typeof link === 'object' ? link.nest : '');
36+ const hardURL = getURL(link, preview);
37+
38+ return (
39+ <article className='group-1 flex w-full'>
40+ <ListingImage {...post} className="hidden sm:inline-block w-24 h-24 rounded-xl" />
41+ <div className='flex-1 min-w-0 sm:ml-4'>
42+ <div className='flex items-center'>
43+ <ListingImage {...post} className="flex-none sm:hidden w-14 h-14 mr-2 mb-2 rounded-xl" />
44+ <a className='flex-1 min-w-0 mb-2 hover:text-rosy transition-colors' href={hardURL}>
45+ <h2 className='block font-semibold text-lg leading-none mb-1'>{post.title}</h2>
46+ <div className='font-mono text-xs space-x-3 truncate'>
47+ <strong>%{post.type}</strong>
48+ <span>{cite}</span>
49+ </div>
50+ </a>
51+ </div>
52+ <p className='mb-2 text-sm'>{post.description}</p>
53+ <div className='flex flex-col items-start sm:flex-row sm:items-center w-full font-mono text-xs text-zinc-500 sm:opacity-0 group-1-hover:opacity-100 transition-opacity'>
54+ <div className='flex items-center'>
55+ <span className='inline-flex items-center'>
56+ <span className='font-semibold font-sans mr-1'>by:</span>
57+ <span>{source}</span>
58+ {outgoing[deSig(source) || ''] && (
59+ <button className='group-2 relative inline-flex items-center justify-center px-2 hover:text-rosy' aria-label='Remove pal' title="Remove Pal" onClick={() => removePal(deSig(source) || '')}>
60+ <UsersIcon className='h-4 w-4 opacity-0 sm:opacity-100 group-2-hover:opacity-0' />
61+ <UserRemoveIcon className='absolute h-4 w-4 sm:opacity-0 group-2-hover:opacity-100' />
62+ </button>
63+ )}
64+ </span>
65+ <time dateTime={(new Date(time)).toISOString()} className="ml-3">
66+ {(new Date(time)).toLocaleString()}
67+ </time>
68+ </div>
69+ <button className='sm:ml-auto font-semibold font-sans hover:text-rosy bg-transparent border-0' onClick={() => remove(hash)}>remove</button>
70+ </div>
71+ </div>
72+ </article>
73+ )
74+}
ui/src/components/ListingImage.tsxnew file+26
@@ -0,0 +1,26 @@
1+import cn from 'classnames';
2+import React from 'react';
3+import { normalizeColor } from '../utils';
4+
5+interface ListingImageProps {
6+ image: string;
7+ color: string;
8+ className?: string;
9+ imageClasses?: string;
10+ colorClasses?: string;
11+}
12+
13+export const ListingImage = ({ image, color, className, imageClasses, colorClasses }: ListingImageProps) => {
14+ return image ? (
15+ <img
16+ src={image}
17+ className={cn('object-cover', className, imageClasses)}
18+ style={{ backgroundColor: color ? normalizeColor(color) : undefined }}
19+ />
20+ ) : (
21+ <div
22+ className={cn('bg-rosy/20', className, colorClasses)}
23+ style={{ backgroundColor: color ? normalizeColor(color) : undefined }}
24+ />
25+ )
26+}
ui/src/components/Listings.tsxnew file+41
@@ -0,0 +1,41 @@
1+import cn from 'classnames';
2+import React from 'react';
3+import { usePals } from '../state/pals';
4+import { Listing as ListingType } from '../types/sphinx';
5+import { Listing } from './Listing';
6+
7+interface ListingsProps {
8+ listings: ListingType[];
9+ remove: (hash: string) => void;
10+ className?: string;
11+}
12+
13+export const Listings = ({ listings, remove, className }: ListingsProps) => {
14+ const { installed, outgoing, remove: removePal } = usePals();
15+ if (!listings) {
16+ return null;
17+ }
18+
19+ if (listings.length === 0) {
20+ return (
21+ <div>
22+ <h2 className='text-xl font-semibold'>No Results</h2>
23+ {installed ? (
24+ <p>Try adding more <a href="/pals" className='underline'>pals</a> to see what others have shared</p>
25+ ) : (
26+ <p>Without pals installed you'll only see your own listings</p>
27+ )}
28+ </div>
29+ )
30+ }
31+
32+ return (
33+ <ul className={cn('space-y-6', className)}>
34+ {listings && listings.map(l => (
35+ <li key={l.hash}>
36+ <Listing {...l} outgoing={outgoing} remove={remove} removePal={removePal} />
37+ </li>
38+ ))}
39+ </ul>
40+ )
41+}
ui/src/components/Logo.tsxnew file+13
@@ -0,0 +1,13 @@
1+import React from 'react';
2+
3+interface LogoProps {
4+ className?: string;
5+}
6+
7+export const Logo = ({ className }: LogoProps) => {
8+ return (
9+ <svg className={className} fill="none" xmlns="http://www.w3.org/2000/svg" viewBox='0 0 179 58'>
10+ <path className='fill-current' d="M10.125 44.5c-1.66667 0-3.33333-.1875-5-.5625-1.66667-.375-3.0625-.875-4.1875-1.5l-.3125-7.125h3.6875l1.3125 4.5c1.5.9583 3.14583 1.4375 4.9375 1.4375 1.3333 0 2.375-.2917 3.125-.875.75-.5833 1.125-1.3542 1.125-2.3125 0-1-.375-1.8542-1.125-2.5625-.75-.7083-2.2708-1.5-4.5625-2.375-3.04167-1.1667-5.16667-2.3958-6.375-3.6875-1.20833-1.2917-1.8125-2.9167-1.8125-4.875 0-1.625.5-3.0625 1.5-4.3125s2.375-2.2292 4.125-2.9375c1.79167-.7083 3.8542-1.0625 6.1875-1.0625 1.2917 0 2.5833.125 3.875.375 1.3333.2083 2.4375.5208 3.3125.9375l.6875 7H17l-1.4375-4.375c-.4167-.25-.9167-.4375-1.5-.5625-.5833-.1667-1.1667-.25-1.75-.25-1.3333 0-2.41667.3125-3.25.9375-.79167.5833-1.1875 1.3542-1.1875 2.3125 0 1.0417.45833 1.9167 1.375 2.625.9583.7083 2.6458 1.5833 5.0625 2.625C17.0625 29.0417 19 30.25 20.125 31.5c1.1667 1.25 1.75 2.7917 1.75 4.625 0 2.5-1.1042 4.5208-3.3125 6.0625C16.3958 43.7292 13.5833 44.5 10.125 44.5ZM24.8125 57.75l-.1875-2.6875 3.875-1c0-.2083.0208-.625.0625-1.25s.0625-1.4375.0625-2.4375c.0417-1 .0833-2.1667.125-3.5s.0625-2.8125.0625-4.4375l.125-13.375c0-1.25-.0417-2.4167-.125-3.5s-.2292-2.1042-.4375-3.0625l-4-.875v-2.5625l10.1875-2.6875 1.5 1.0625-.4375 3.625.1875.0625c1.0417-1.5 2.2917-2.6875 3.75-3.5625S42.5833 16.25 44.25 16.25c2.0833 0 4 .5417 5.75 1.625 1.75 1.0417 3.1458 2.5417 4.1875 4.5 1.0833 1.9583 1.625 4.2917 1.625 7 0 2.75-.625 5.2708-1.875 7.5625-1.25 2.25-3 4.0625-5.25 5.4375s-4.875 2.0625-7.875 2.0625c-.7917 0-1.625-.0833-2.5-.25-.875-.125-1.6875-.3333-2.4375-.625V47.75c0 1.4583.0208 2.7917.0625 4 .0833 1.2083.1458 1.9792.1875 2.3125L41.25 55l-.1875 2.75h-16.25Zm16.125-17.3125c1.4583 0 2.7083-.3333 3.75-1 1.0833-.7083 1.9375-1.75 2.5625-3.125.625-1.4167.9375-3.1667.9375-5.25.0417-2.0833-.2708-3.8125-.9375-5.1875-.625-1.4167-1.4583-2.4792-2.5-3.1875-1.0417-.7083-2.2083-1.0625-3.5-1.0625-1.0417 0-2.0208.25-2.9375.75-.9167.4583-1.7292 1.1458-2.4375 2.0625v14.5c.6667.4583 1.4375.8333 2.3125 1.125.9167.25 1.8333.375 2.75.375ZM59.5625 44l-.1875-2.6875 3.875-1c.0833-.375.1458-1.1042.1875-2.1875.0417-1.0833.0833-2.3958.125-3.9375.0417-1.5833.0625-3.2292.0625-4.9375v-7.8125c0-1.4167-.0208-2.875-.0625-4.375 0-1.5-.0208-2.9375-.0625-4.3125 0-1.4167-.0208-2.6667-.0625-3.75-.0417-1.125-.0833-1.97917-.125-2.5625l-4.625-.625-.125-2.4375L69.375.5l1.5625 1c-.0417 1.29167-.1042 2.5625-.1875 3.8125-.0417 1.20833-.0833 2.54167-.125 4 0 1.4583-.0208 3.125-.0625 5-.0417 1.8333-.0833 4.0208-.125 6.5625l.1875.0625c1.3333-1.5833 2.75-2.75 4.25-3.5 1.5-.7917 3.1042-1.1875 4.8125-1.1875s3.25.4375 4.625 1.3125c1.4167.8333 2.5417 2.0833 3.375 3.75.8333 1.6667 1.25 3.7083 1.25 6.125v6.5c0 1.4167.0208 2.75.0625 4 .0833 1.2083.1667 2 .25 2.375l3.875 1L92.9375 44h-14.625l-.1875-2.6875 3.5625-1c.0833-.3333.1458-.8125.1875-1.4375.0417-.625.0625-1.3542.0625-2.1875C81.9792 35.8542 82 35 82 34.125v-5.75c0-1.625-.2708-2.9375-.8125-3.9375-.5-1.0417-1.1667-1.7917-2-2.25-.8333-.5-1.75-.75-2.75-.75-1.125 0-2.2083.2708-3.25.8125-1 .5-1.875 1.25-2.625 2.25v9.25c0 1.6667.0208 3.1042.0625 4.3125.0833 1.1667.1875 1.9167.3125 2.25l3.8125 1L74.5625 44h-15ZM95.1875 44 95 41.25l4.1875-.9375c.0417-.1667.0833-.5208.125-1.0625s.0833-1.25.125-2.125c.0417-.9167.0625-1.9792.0625-3.1875l.0625-4.75c0-1.2917-.0417-2.4792-.125-3.5625-.0833-1.125-.2292-2.1667-.4375-3.125l-4.1875-.875v-2.5625L105.5 16.375l1.438 1.0625c-.126 1.2917-.23 2.6042-.313 3.9375-.042 1.2917-.063 2.7917-.063 4.5v7.875c0 1.5417.021 2.9375.063 4.1875.083 1.25.187 2.0417.313 2.375l4.187.9375-.187 2.75H95.1875Zm7.9375-33.4375c-1.458 0-2.625-.4375-3.5-1.3125-.875-.91667-1.3125-2-1.3125-3.25 0-1.20833.4375-2.27083 1.3125-3.1875.875-.91667 2.042-1.375 3.5-1.375 1.458 0 2.604.45833 3.437 1.375.834.91667 1.25 1.97917 1.25 3.1875 0 1.25-.416 2.33333-1.25 3.25-.833.875-1.979 1.3125-3.437 1.3125ZM113.312 44l-.187-2.6875 3.875-1c.042-.1667.083-.5.125-1 .042-.5417.083-1.25.125-2.125.042-.9167.062-2 .062-3.25l.063-4.75c0-1.3333-.042-2.5417-.125-3.625-.083-1.0833-.229-2.1042-.438-3.0625l-4-.875v-2.5625L123 16.375l1.5 1.0625-.375 3.5.187.0625c1.334-1.5833 2.75-2.7708 4.25-3.5625 1.542-.7917 3.167-1.1875 4.876-1.1875 1.708 0 3.25.4375 4.624 1.3125 1.417.8333 2.542 2.0833 3.376 3.75.833 1.6667 1.25 3.7083 1.25 6.125v6.5c0 1.4167.02 2.75.062 4 .042 1.2083.125 2 .25 2.375l3.875 1L146.688 44H132l-.188-2.6875 3.626-1c.083-.3333.145-.8125.187-1.4375.042-.625.063-1.3542.063-2.1875.041-.8333.062-1.6875.062-2.5625v-5.75c0-1.625-.271-2.9375-.812-3.9375-.5-1.0417-1.167-1.7917-2-2.25-.834-.5-1.75-.75-2.75-.75-1.167 0-2.25.2708-3.25.8125-1 .5-1.876 1.25-2.626 2.25v9.25c0 1.5833.021 3 .063 4.25.083 1.2083.187 1.9792.313 2.3125l3.874 1L128.375 44h-15.063ZM178.562 44h-13.874l-.188-2.6875 2.938-1-5.626-7.375-1.937-2.4375-7.813-10.0625-2.937-1 .187-2.6875h13.626l.187 2.6875-2.625 1 4.5 5.875 1.938 2.5625 8.874 11.4375 2.938 1L178.562 44Zm-8.937-23.5625-2.625-1 .188-2.6875H177l.188 2.6875-2.938 1-7.312 8.4375-5.126 4.0625-5.312 7.375 2.938 1L159.25 44h-10.188l-.187-2.6875 2.937-1 8.063-9.8125L165 26.3125l4.625-5.875Z" />
11+ </svg>
12+ )
13+}
ui/src/components/Meta.tsxnew file+41
@@ -0,0 +1,41 @@
1+import { ChargeUpdateInitial, scryCharges } from '@urbit/api';
2+import React, { useEffect, useState } from 'react';
3+import api from '../api';
4+import { Logo } from './Logo';
5+
6+const SOURCE = 'github.com/iko-soy/sphinx';
7+
8+interface MetaProps {
9+ className?: string;
10+}
11+
12+export const Meta = ({ className }: MetaProps) => {
13+ const [version, setVersion] = useState('');
14+
15+ useEffect(() => {
16+ if (!version) {
17+ api.scry<ChargeUpdateInitial>(scryCharges).then(charges => {
18+ const version = charges.initial.sphinx?.version;
19+
20+ if (version) {
21+ setVersion(version);
22+ }
23+ })
24+ }
25+ }, []);
26+
27+ return (
28+ <footer className={className}>
29+ <div className='flex mb-2 space-x-3 items-end'>
30+ <Logo className="w-24 text-rosy" />
31+ {version && <span className='mb-[3px]'>v{version}</span>}
32+ </div>
33+ <a
34+ className="inline-block font-mono default-ring underline rounded-md hover:text-rosy"
35+ href={`https://${SOURCE}`}
36+ >
37+ {SOURCE}
38+ </a>
39+ </footer>
40+ )
41+}
ui/src/components/Paginator.tsxnew file+129
@@ -0,0 +1,129 @@
1+import { ArrowNarrowLeftIcon, ArrowNarrowRightIcon, DotsHorizontalIcon } from '@heroicons/react/solid';
2+import cn from 'classnames';
3+import React from 'react';
4+import { Link } from 'react-router-dom';
5+
6+interface PaginatorProps {
7+ linkBuilder: (page: number | null) => string | null;
8+ currentPage: number;
9+ pages: number;
10+ showNextPrev?: boolean;
11+ pagesShownLimit?: number;
12+ className?: string;
13+}
14+
15+interface Page {
16+ number: number;
17+ active?: boolean;
18+ ellipsis?: boolean;
19+}
20+
21+function calculateShownPages(currentPage: number, pages: number, pagesShownLimit: number): Page[] {
22+ const first = 1;
23+ const last = pages;
24+ const gap = Math.floor(pagesShownLimit / 2);
25+ const start = Math.max(1, Math.min(pages - pagesShownLimit, currentPage - gap));
26+ const end = Math.min(last, Math.max(first + pagesShownLimit, currentPage + gap));
27+ const firstEllipsis = (currentPage - first) > gap + 1 && start !== first;
28+ const lastEllipsis = (last - currentPage) > gap + 1 && end !== last;
29+
30+ const pageSet: Page[] = [];
31+
32+ if (start !== first) {
33+ pageSet.push({
34+ number: first,
35+ active: currentPage === first
36+ });
37+ }
38+
39+ if (firstEllipsis) {
40+ pageSet.push({
41+ number: 0,
42+ ellipsis: true,
43+ active: false
44+ });
45+ }
46+
47+ for (let number=start; number<=end; number++) {
48+ pageSet.push({ number, active: currentPage === number });
49+ }
50+
51+ if (lastEllipsis) {
52+ pageSet.push({
53+ number: 0,
54+ ellipsis: true,
55+ active: false
56+ });
57+ }
58+
59+ if (last !== end) {
60+ pageSet.push({
61+ number: last,
62+ active: currentPage === last
63+ })
64+ }
65+
66+ return pageSet;
67+}
68+
69+export const Paginator = ({ className, linkBuilder, currentPage, pages, showNextPrev = false, pagesShownLimit = 3 }: PaginatorProps) => {
70+ const normCurrent = currentPage + 1; //shift for 0 based indexing
71+ if (pages <= 1)
72+ return null;
73+
74+ const pageSet = calculateShownPages(normCurrent, pages, pagesShownLimit);
75+ const prevUrl = linkBuilder(currentPage - 1 >= 0 ? normCurrent - 1 : null);
76+ const nextUrl = linkBuilder(currentPage + 1 <= pages - 1 ? normCurrent + 1 : null);
77+
78+ return (
79+ <>
80+ {showNextPrev && (
81+ <div className="-mt-px w-0 flex-1 flex">
82+ {!prevUrl && (
83+ <span className='border-t-2 border-transparent pt-2 pl-1 inline-flex items-center text-sm font-medium text-zinc-300'>
84+ <ArrowNarrowLeftIcon className="mr-3 h-5 w-5" />
85+ Previous
86+ </span>
87+ )}
88+ {prevUrl && <Link to={prevUrl} className="border-t-2 border-transparent pt-2 pr-1 inline-flex items-center text-sm font-medium text-zinc-500 hover:text-zinc-700 hover:border-zinc-300">
89+ <ArrowNarrowLeftIcon className="mr-3 h-5 w-5 text-zinc-400" />
90+ Previous
91+ </Link>}
92+ </div>
93+ )}
94+ {pageSet.map((page, index) => {
95+ if (page.ellipsis)
96+ return <span key={index} className="border-transparent text-zinc-500 border-t-2 pt-2 px-4 inline-flex items-center text-sm font-medium"><DotsHorizontalIcon className='w-3 h-3' /></span>
97+
98+ return (
99+ <Link
100+ key={index}
101+ to={linkBuilder(page.number) || ''}
102+ className={cn(
103+ 'border-t-2 pt-2 px-4 inline-flex items-center text-sm font-medium',
104+ page.active && 'border-lavender/80 text-lavender',
105+ !page.active && 'border-transparent text-zinc-500 hover:text-zinc-700 hover:border-zinc-300'
106+ )}
107+ aria-current={page.active ? 'page' : undefined}
108+ >
109+ {page.number}
110+ </Link>
111+ )
112+ })}
113+ {showNextPrev && (
114+ <div className="-mt-px w-0 flex-1 flex justify-end">
115+ {!nextUrl && (
116+ <span className='border-t-2 border-transparent pt-2 pl-1 inline-flex items-center text-sm font-medium text-zinc-300'>
117+ Next
118+ <ArrowNarrowRightIcon className="ml-3 h-5 w-5" />
119+ </span>
120+ )}
121+ {nextUrl && <Link to={nextUrl} className="border-t-2 border-transparent pt-2 pl-1 inline-flex items-center text-sm font-medium text-zinc-500 hover:text-zinc-700 hover:border-zinc-300">
122+ Next
123+ <ArrowNarrowRightIcon className="ml-3 h-5 w-5 text-zinc-400" />
124+ </Link>}
125+ </div>
126+ )}
127+ </>
128+ );
129+};
ui/src/components/PostOptions.tsxnew file+56
@@ -0,0 +1,56 @@
1+import { CheckIcon } from '@heroicons/react/solid';
2+import cn from 'classnames';
3+import React from 'react';
4+import { useFormContext } from 'react-hook-form';
5+import { PostOption, PostOptionsForm } from '../types/sphinx';
6+import { normalizeColor } from '../utils';
7+
8+interface PostOptionsProps {
9+ options: PostOption[];
10+ showTags?: boolean;
11+ className?: string;
12+}
13+
14+export const PostOptions = ({ options, showTags = false, className }: PostOptionsProps) => {
15+ const { register } = useFormContext<PostOptionsForm>();
16+
17+ return (
18+ <ul className={cn('space-y-3', className)}>
19+ {options && options.map((o, index) => (
20+ <li key={o.key}>
21+ <input {...register('options')} id={o.key} value={o.key} type="checkbox" className='sr-only' />
22+ <label htmlFor={o.key} className='checked-bg-fawn group-1 relative grid grid-rows-[auto,auto] sm:grid-rows-1 grid-cols-[64px,1fr] sm:grid-cols-[64px,1fr,24px] w-full p-2 hover:bg-fawn cursor-pointer rounded-xl'>
23+ <div className='absolute z-10 top-7 left-7 flex items-center justify-center h-6 w-6 border-2 border-solid border-mauve rounded bg-linen/80'>
24+ <CheckIcon className='show-when-checked h-4 w-4 opacity-0' />
25+ </div>
26+ {o.post.image ? (
27+ <img
28+ src={o.post.image}
29+ className="show-when-checked w-16 h-16 col-span-1 object-cover rounded-lg opacity-60"
30+ loading={index > 15 ? 'lazy' : 'eager'}
31+ style={{ backgroundColor: o.post.color ? normalizeColor(o.post.color) : undefined }}
32+ />
33+ ) : (
34+ <div
35+ className='w-16 h-16 col-span-1 bg-rosy/20 rounded-lg'
36+ style={{ backgroundColor: o.post.color ? normalizeColor(o.post.color) : undefined }}
37+ />
38+ )}
39+ <div className='ml-4 min-w-0 sm:space-y-2'>
40+ <span className='block font-semibold text-lg leading-none mb-2 sm:mb-0'>{o.post.title}</span>
41+ <div className='flex flex-col sm:flex-row sm:items-center w-full text-xs space-y-2 sm:space-y-0 sm:space-x-3 truncate'>
42+ <strong className='font-mono'>%{o.post.type}</strong>
43+ {showTags && <p><strong>tags: </strong><em>{o.post.tags.join()}</em></p>}
44+ </div>
45+ <p className='hidden sm:block font-mono text-xs truncate'>{o.post.link.replace('web+urbitgraph://', '')}</p>
46+ </div>
47+ <div className='col-span-2 row-start-2 mt-2'>
48+ <p className='font-mono text-xs truncate sm:hidden'>{o.post.link.replace('web+urbitgraph://', '')}</p>
49+ <p className='text-sm'>{o.post.description}</p>
50+ </div>
51+ </label>
52+ </li>
53+ ))}
54+ </ul>
55+ )
56+}
ui/src/components/SearchInput.tsxnew file+32
@@ -0,0 +1,32 @@
1+import { SearchIcon } from '@heroicons/react/solid';
2+import cn from 'classnames';
3+import React, { ChangeEvent, useCallback } from 'react';
4+import { Spinner } from './Spinner';
5+
6+interface SearchInputProps {
7+ lookup: string;
8+ loading: boolean;
9+ className?: string;
10+ onChange: (value: string) => void;
11+}
12+
13+export const SearchInput = ({ lookup, loading, className, onChange }: SearchInputProps) => {
14+ const onInput = useCallback((event: ChangeEvent<HTMLInputElement>) => {
15+ const { value } = event.target;
16+ onChange(value);
17+ }, [onChange]);
18+
19+ return (
20+ <div className={cn('relative flex items-center', className)}>
21+ <SearchIcon className='flip absolute left-2 h-5 w-5' />
22+ <input
23+ type='text'
24+ value={lookup}
25+ onChange={onInput}
26+ placeholder="Search"
27+ className={cn('w-full py-1 pl-9 pr-2 bg-fawn/30 focus:outline-none focus:ring-2 ring-lavender rounded-lg border border-fawn/30')}
28+ />
29+ {loading && <Spinner className='absolute right-2 h-5 w-5' />}
30+ </div>
31+ )
32+}
ui/src/components/Spinner.tsxnew file+11
@@ -0,0 +1,11 @@
1+import cn from 'classnames';
2+import React from 'react';
3+
4+export const Spinner = ({ className }: { className: string }) => {
5+ return (
6+ <svg className={cn('spinner', className)} xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
7+ <circle cx="12" cy="12" r="10" className="stroke-current" strokeOpacity="0.4" strokeWidth="4"></circle>
8+ <path className="fill-current" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
9+ </svg>
10+ )
11+}
ui/src/components/TagCloud.tsxnew file+18
@@ -0,0 +1,18 @@
1+import cn from 'classnames';
2+import React from 'react';
3+import { NavLink } from 'react-router-dom';
4+
5+interface TagCloudProps {
6+ tags: [string, number][];
7+}
8+
9+export const TagCloud = ({ tags }: TagCloudProps) => (
10+ <section className='flex flex-wrap gap-2'>
11+ {tags.map(([t, count]) => (
12+ <NavLink key={t} to={`/tags/${t}`} className={({ isActive }) => cn("py-0.5 px-1.5 space-x-2 rounded-md font-semibold", isActive ? 'bg-lavender text-linen' : 'bg-fawn')}>
13+ <span>{t}</span>
14+ <span className='opacity-60'>{count}</span>
15+ </NavLink>
16+ ))}
17+ </section>
18+)
ui/src/components/TagField.tsxnew file+157
@@ -0,0 +1,157 @@
1+import React, { Component, KeyboardEventHandler, useCallback, useState } from 'react';
2+
3+import CreatableSelect from 'react-select/creatable';
4+import { ActionMeta, components, ControlProps, MultiValue, MultiValueGenericProps, MultiValueRemoveProps, OnChangeValue } from 'react-select';
5+import { XIcon } from '@heroicons/react/solid';
6+import { MAX_TAG_BYTES, MAX_TAGS, byteLength } from '../utils';
7+
8+export interface Option {
9+ readonly label: string;
10+ readonly value: string;
11+}
12+
13+const createOption = (label: string) => ({
14+ label,
15+ value: label,
16+});
17+
18+function Control({ children, ...props }: ControlProps<Option, true>) {
19+ return (
20+ <components.Control
21+ {...props}
22+ className="flex items-center w-full py-1 px-2 bg-fawn/30 focus:outline-none focus:ring-2 ring-lavender rounded-lg border border-fawn/30 cursor-text text-mauve"
23+ >
24+ {children}
25+ </components.Control>
26+ );
27+}
28+
29+function TagContainer({
30+ children,
31+ ...props
32+}: MultiValueGenericProps<Option, true>) {
33+ return (
34+ <components.MultiValueContainer {...props}>
35+ <div className="flex">{children}</div>
36+ </components.MultiValueContainer>
37+ );
38+}
39+
40+function TagLabel({ data }: { data: Option }) {
41+ const { value, label } = data;
42+ return (
43+ <div className="flex h-6 items-center rounded-l bg-lavender text-linen">
44+ <span className="p-1 font-semibold">{label || value}</span>
45+ </div>
46+ );
47+}
48+
49+function TagRemove(props: MultiValueRemoveProps<Option, true>) {
50+ return (
51+ <components.MultiValueRemove {...props}>
52+ <div className="flex h-full items-center rounded-r bg-lavender pr-1">
53+ <XIcon className="h-4 w-4 text-linen" />
54+ </div>
55+ </components.MultiValueRemove>
56+ );
57+}
58+
59+interface TagFieldProps {
60+ tags: MultiValue<Option>;
61+ onTags: (tags: MultiValue<Option>) => void;
62+ className?: string;
63+}
64+
65+export const TagField = ({ tags, onTags, className }: TagFieldProps) => {
66+ const [input, setInput] = useState('');
67+
68+ const handleChange = useCallback((
69+ value: OnChangeValue<Option, true>,
70+ actionMeta: ActionMeta<Option>
71+ ) => {
72+ onTags(value);
73+ }, []);
74+
75+ const handleInputChange = useCallback((value) => {
76+ setInput(value);
77+ }, []);
78+
79+ const handleKeyDown: KeyboardEventHandler<HTMLDivElement> = useCallback((event) => {
80+ if (!input) return;
81+
82+ switch (event.key) {
83+ case 'Enter':
84+ case 'Tab':
85+ // %sphinx drops listings with more than 8 tags and doesn't index
86+ // longer tags, so keep the input; Tab still moves on
87+ if (tags.length >= MAX_TAGS || byteLength(input) > MAX_TAG_BYTES) {
88+ if (event.key === 'Enter') event.preventDefault();
89+ return;
90+ }
91+
92+ event.preventDefault();
93+ setInput('');
94+ if (!tags.some(t => t.value === input)) {
95+ onTags([...tags, createOption(input)])
96+ }
97+ }
98+ }, [input, tags]);
99+
100+ return (
101+ <div className={className}>
102+ <CreatableSelect<Option, true>
103+ components={{
104+ ...components,
105+ Control,
106+ MultiValueContainer: TagContainer,
107+ MultiValueLabel: TagLabel,
108+ MultiValueRemove: TagRemove,
109+ DropdownIndicator: null
110+ }}
111+ styles={{
112+ control: (base) => ({}),
113+ input: (base) => ({
114+ ...base,
115+ padding: 0,
116+ margin: 0,
117+ }),
118+ clearIndicator: (base) => ({
119+ ...base,
120+ cursor: 'pointer',
121+ padding: 0
122+ }),
123+ multiValue: (base) => ({
124+ ...base,
125+ backgroundColor: '',
126+ margin: '0 2px',
127+ }),
128+ multiValueRemove: (base) => ({
129+ ...base,
130+ paddingRight: '',
131+ paddingLeft: '',
132+ '&:hover': {
133+ color: 'inherit',
134+ backgroundColor: 'inherit',
135+ },
136+ }),
137+ valueContainer: (base) => ({
138+ ...base,
139+ padding: 0
140+ })
141+ }}
142+ isOptionDisabled={() => tags.length >= MAX_TAGS}
143+ inputValue={input}
144+ isClearable
145+ isMulti
146+ menuIsOpen={false}
147+ onChange={handleChange}
148+ onInputChange={handleInputChange}
149+ onKeyDown={handleKeyDown}
150+ placeholder="Type something and press enter..."
151+ value={tags}
152+ />
153+ {byteLength(input) > MAX_TAG_BYTES && <div className='text-mauve/50 text-xs mt-1'>{MAX_TAG_BYTES} bytes per tag maximum</div>}
154+ {tags.length >= MAX_TAGS && <div className='text-mauve/50 text-xs mt-1'>{MAX_TAGS} tags maximum</div>}
155+ </div>
156+ );
157+}
ui/src/env.d.tsnew file+15
@@ -0,0 +1,15 @@
1+interface ImportMetaEnv extends Readonly<Record<string, string | boolean | undefined>> {
2+ /* Add custom env properties here */
3+}
4+
5+interface ImportMeta {
6+ readonly env: ImportMetaEnv;
7+}
8+
9+declare module 'remove-markdown-and-html' {
10+ export default function removeMd(input: string): string;
11+}
12+
13+declare module 'urbit-ob' {
14+ export function isValidPatp(patp: string): boolean;
15+}
ui/src/keys.tsnew file+14
@@ -0,0 +1,14 @@
1+import { QueryKey } from "@tanstack/react-query";
2+
3+export const GROUPS_KEY: QueryKey = ['groups'];
4+export const VATS_KEY: QueryKey = ['vats'];
5+export const PALS_KEY: QueryKey = ['pals'];
6+export const TAGS_KEY: QueryKey = ['tags'];
7+export const CHARGES_KEY: QueryKey = ['charges'];
8+export const APP_LISTINGS_KEY: QueryKey = ['app-listings'];
9+export const GROUP_LISTINGS_KEY: QueryKey = ['group-listings'];
10+export const POST_LISTINGS_KEY: QueryKey = ['post-listings'];
11+export const PUBLISHED_KEY: QueryKey = ['published'];
12+export const notesKey = (diary?: string): QueryKey => diary ? ['notes', diary] : ['notes'];
13+export const tagKey = (tag?: string) => (start: number, size: number): QueryKey => ['tag', tag || '', size, start];
14+export const lookupKey = (selected: string, lookup: string | undefined) => (start: number, size: number): QueryKey => ['lookup', selected, size.toString(), start.toString(), lookup || ''];
ui/src/logic/useMedia.tsnew file+25
@@ -0,0 +1,25 @@
1+import { useCallback, useEffect, useState } from 'react';
2+
3+export default function useMedia(mediaQuery: string) {
4+ const [match, setMatch] = useState(false);
5+
6+ const update = useCallback((e: MediaQueryListEvent) => {
7+ setMatch(e.matches);
8+ }, []);
9+
10+ useEffect(() => {
11+ const query = window.matchMedia(mediaQuery);
12+
13+ query.addEventListener('change', update);
14+ update({ matches: query.matches } as MediaQueryListEvent);
15+ return () => {
16+ query.removeEventListener('change', update);
17+ };
18+ }, [update, mediaQuery]);
19+
20+ return match;
21+}
22+
23+export function useIsMobile() {
24+ return useMedia('(max-width: 639px)');
25+}
ui/src/logic/utils.tsnew file+11
@@ -0,0 +1,11 @@
1+export function preSig(ship: string): string {
2+ if (!ship) {
3+ return '';
4+ }
5+
6+ if (ship.trim().startsWith('~')) {
7+ return ship.trim();
8+ }
9+
10+ return '~'.concat(ship.trim());
11+}
ui/src/main.tsxnew file+11
@@ -0,0 +1,11 @@
1+import React from 'react';
2+import ReactDOM from 'react-dom';
3+import { App } from './app';
4+import './styles/index.css';
5+
6+ReactDOM.render(
7+ <React.StrictMode>
8+ <App />
9+ </React.StrictMode>,
10+ document.getElementById('app')
11+);
ui/src/manage-listings/AllListings.tsxnew file+65
@@ -0,0 +1,65 @@
1+import React from 'react';
2+import { useMutation, useQueryClient } from '@tanstack/react-query';
3+import { useParams } from 'react-router-dom';
4+import api from '../api';
5+import { Listings } from '../components/Listings';
6+import { Paginator } from '../components/Paginator';
7+import { useSearch } from '../state/search';
8+import { Remove, Search } from '../types/sphinx';
9+import { PUBLISHED_KEY } from '../keys';
10+import { formatUd } from '../utils';
11+
12+interface RouteParams extends Record<string, string | undefined> {
13+ limit?: string;
14+ page?: string;
15+}
16+
17+export const AllListings = () => {
18+ const queryClient = useQueryClient();
19+ const {
20+ limit,
21+ page
22+ } = useParams<RouteParams>();
23+ const {
24+ results,
25+ pages,
26+ pageInt,
27+ linkBuild
28+ } = useSearch({
29+ key: (start, size) => ['all', start, size],
30+ fetcher: (start, size) => api.scry<Search>({
31+ app: 'sphinx',
32+ path: `/lookup/all/${formatUd(start)}/${formatUd(size)}`
33+ }),
34+ enabled: true,
35+ limit,
36+ page,
37+ linkPrefix: '/manage-listings/all'
38+ })
39+ const { mutate } = useMutation((hash: string) => {
40+ return api.poke<Remove>({
41+ app: 'sphinx',
42+ mark: 'remove',
43+ json: hash
44+ })
45+ }, {
46+ onSuccess: () => {
47+ queryClient.invalidateQueries(PUBLISHED_KEY);
48+ }
49+ });
50+
51+ return (
52+ <>
53+ <header className='flex items-center'>
54+ <h1 className='text-2xl font-semibold'>All Listings</h1>
55+ </header>
56+ {results && <div className='flex justify-end border-t border-zinc-300'>
57+ <Paginator pages={pages} currentPage={pageInt} linkBuilder={linkBuild} />
58+ </div>}
59+ <Listings listings={results.listings} remove={mutate} />
60+ {results && pages > 1 && <div className='flex justify-end border-t border-zinc-300'>
61+ <Paginator pages={pages} currentPage={pageInt} linkBuilder={linkBuild} />
62+ </div>}
63+ </>
64+ )
65+}
ui/src/manage-listings/Apps.tsxnew file+92
@@ -0,0 +1,92 @@
1+import React, { useCallback, useEffect, useState } from 'react';
2+import { FormProvider, useForm } from 'react-hook-form';
3+import { useMutation, useQueryClient } from '@tanstack/react-query';
4+import { Link } from 'react-router-dom';
5+import api from '../api';
6+import { PostOptions } from '../components/PostOptions';
7+import { Spinner } from '../components/Spinner';
8+import { useApps } from '../state/apps';
9+import { Declare, Listing, PostOption, PostOptionsForm } from '../types/sphinx';
10+import { APP_LISTINGS_KEY } from '../keys';
11+
12+function getAppKeys(apps: PostOption[]): string[] {
13+ return apps.map(({ key }) => key);
14+}
15+
16+export const Apps = () => {
17+ const { apps, loading } = useApps();
18+ const form = useForm<PostOptionsForm>({
19+ defaultValues: {
20+ options: []
21+ }
22+ });
23+ const { handleSubmit, reset, watch, setValue } = form;
24+ const options = watch('options');
25+
26+ const toggleAll = useCallback(() => {
27+ if (options.length !== apps.length) {
28+ setValue('options', getAppKeys(apps));
29+ } else {
30+ setValue('options', []);
31+ }
32+ }, [apps, options, setValue]);
33+
34+ const queryClient = useQueryClient();
35+ const { mutate } = useMutation(async (values: PostOptionsForm) => {
36+ return api.poke<Declare[]>({
37+ app: 'sphinx',
38+ mark: 'declarations',
39+ json: apps.filter(a => values.options.includes(a.key)).map(a => ({
40+ post: a.post,
41+ reach: 'friends'
42+ }))
43+ });
44+ }, {
45+ onSuccess: () => {
46+ queryClient.invalidateQueries(APP_LISTINGS_KEY);
47+ }
48+ })
49+
50+ const onSubmit = useCallback((values: PostOptionsForm) => {
51+ mutate(values)
52+ reset()
53+ }, [reset, mutate]);
54+
55+ return (
56+ <div className='w-full space-y-6 m-auto'>
57+ <header className='flex items-center'>
58+ <h1 className='text-2xl font-semibold'>Add Apps</h1>
59+ {apps.length > 0 && (
60+ <button className='p-2 ml-auto text-sm underline font-semibold' onClick={toggleAll}>
61+ {options.length !== apps.length && 'select all'}
62+ {options.length === apps.length && 'deselect all'}
63+ </button>
64+ )}
65+ </header>
66+ <FormProvider {...form}>
67+ <form onSubmit={handleSubmit(onSubmit)}>
68+ {apps.length === 0 && loading ? (
69+ <div className='flex items-center space-x-2 text-lavender'>
70+ <Spinner className='w-6 h-6' />
71+ <span>Checking apps...</span>
72+ </div>
73+ ) : apps.length === 0 && !loading ? (
74+ <h2 className='text-lavender'>All apps already indexed</h2>
75+ ) : (
76+ <PostOptions options={apps} />
77+ )}
78+ <div className='flex justify-between border-t border-zinc-300 py-3 mt-6'>
79+ <Link to="/search" className='flex items-center rounded-lg text-base font-semibold text-rosy bg-rosy/30 border-2 border-transparent hover:border-rosy leading-none py-2 px-3 transition-colors'>
80+ Back to Search
81+ </Link>
82+ {apps.length > 0 && (
83+ <button type="submit" className='flex items-center rounded-lg text-base font-semibold text-linen bg-rosy disabled:bg-zinc-200 disabled:text-zinc-400 disabled:border-transparent border-2 border-transparent hover:border-linen/60 leading-none py-2 px-3 transition-colors' disabled={options.length === 0}>
84+ Publish
85+ </button>
86+ )}
87+ </div>
88+ </form>
89+ </FormProvider>
90+ </div>
91+ );
92+}
ui/src/manage-listings/Groups.tsxnew file+99
@@ -0,0 +1,99 @@
1+import React, { useCallback, useEffect, useState } from 'react';
2+import { FormProvider, useForm } from 'react-hook-form';
3+import { useMutation, useQueryClient } from '@tanstack/react-query';
4+import { Link } from 'react-router-dom';
5+import api from '../api';
6+import { PostOptions } from '../components/PostOptions';
7+import { Spinner } from '../components/Spinner';
8+import { useGroups } from '../state/groups';
9+import { Declare, PostOptionsForm } from '../types/sphinx';
10+import { GROUP_LISTINGS_KEY } from '../keys';
11+
12+export const Groups = () => {
13+ const { groups, loading } = useGroups();
14+ const [firstLoad, setFirstLoad] = useState(true);
15+ const form = useForm<PostOptionsForm>({
16+ defaultValues: {
17+ options: []
18+ }
19+ });
20+ const { handleSubmit, reset, watch, setValue } = form;
21+ const options = watch('options');
22+
23+ useEffect(() => {
24+ if (groups.length > 0 && firstLoad) {
25+ reset({
26+ options: []
27+ })
28+
29+ setFirstLoad(false);
30+ }
31+ }, [groups, firstLoad]);
32+
33+ const toggleAll = useCallback(() => {
34+ if (options.length !== groups.length) {
35+ setValue('options', groups.map(g => g.key));
36+ } else {
37+ setValue('options', []);
38+ }
39+ }, [groups, options, setValue]);
40+
41+ const queryClient = useQueryClient();
42+ const { mutate } = useMutation(async (values: PostOptionsForm) => {
43+ return api.poke<Declare[]>({
44+ app: 'sphinx',
45+ mark: 'declarations',
46+ json: groups.filter(a => values.options.includes(a.key)).map(a => ({
47+ post: a.post,
48+ reach: 'friends'
49+ }))
50+ });
51+ }, {
52+ onSuccess: () => {
53+ queryClient.invalidateQueries(GROUP_LISTINGS_KEY)
54+ }
55+ })
56+
57+ const onSubmit = useCallback((values: PostOptionsForm) => {
58+ mutate(values);
59+ reset();
60+ }, [reset, mutate]);
61+
62+ return (
63+ <div className='w-full space-y-6 m-auto'>
64+ <header className='flex items-center'>
65+ <h1 className='text-2xl font-semibold'>Add Groups</h1>
66+ {groups.length > 0 && (
67+ <button className='p-2 ml-auto text-sm underline font-semibold' onClick={toggleAll}>
68+ {options.length !== groups.length && 'select all'}
69+ {options.length === groups.length && 'deselect all'}
70+ </button>
71+ )}
72+ </header>
73+ <FormProvider {...form}>
74+ <form onSubmit={handleSubmit(onSubmit)}>
75+ {groups.length === 0 && loading ? (
76+ <div className='flex items-center space-x-2 text-lavender'>
77+ <Spinner className='w-6 h-6' />
78+ <span>Checking groups...</span>
79+ </div>
80+ ) : groups.length === 0 && !loading ? (
81+ <h2 className='text-lavender'>All groups already indexed</h2>
82+ ) : (
83+ <PostOptions options={groups} />
84+ )}
85+ <div className='flex justify-between border-t border-zinc-300 py-3 mt-6'>
86+ <Link to="/search" className='flex items-center rounded-lg text-base font-semibold text-rosy bg-rosy/30 border-2 border-transparent hover:border-rosy leading-none py-2 px-3 transition-colors'>
87+ Back to Search
88+ </Link>
89+ {groups.length > 0 && (
90+ <button type="submit" className='flex items-center rounded-lg text-base font-semibold text-linen bg-rosy disabled:bg-zinc-200 disabled:text-zinc-400 disabled:border-transparent border-2 border-transparent hover:border-linen/60 leading-none py-2 px-3 transition-colors' disabled={options.length === 0}>
91+ Publish
92+ </button>
93+ )}
94+ </div>
95+ </form>
96+ </FormProvider>
97+ </div>
98+ );
99+}
ui/src/manage-listings/MyListings.tsxnew file+34
@@ -0,0 +1,34 @@
1+import React from 'react';
2+import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
3+import api from '../api';
4+import { Listings } from '../components/Listings';
5+import { Directory, Remove } from '../types/sphinx';
6+import { PUBLISHED_KEY } from '../keys';
7+
8+export const MyListings = () => {
9+ const queryClient = useQueryClient();
10+ const { data } = useQuery(PUBLISHED_KEY, () => api.scry<Directory>({
11+ app: 'sphinx',
12+ path: '/published'
13+ }));
14+ const { mutate } = useMutation((hash: string) => {
15+ return api.poke<Remove>({
16+ app: 'sphinx',
17+ mark: 'remove',
18+ json: hash
19+ })
20+ }, {
21+ onSuccess: () => {
22+ queryClient.invalidateQueries(PUBLISHED_KEY);
23+ }
24+ });
25+
26+ return (
27+ <div className='w-full space-y-6 m-auto'>
28+ <header className='flex items-center'>
29+ <h1 className='text-2xl font-semibold'>My Listings</h1>
30+ </header>
31+ <Listings listings={Object.values(data || {})} remove={mutate} className="mt-6" />
32+ </div>
33+ )
34+}
ui/src/manage-listings/Notebooks.tsxnew file+70
@@ -0,0 +1,70 @@
1+import cn from 'classnames';
2+import React from 'react';
3+import { NavLink, useParams } from 'react-router-dom';
4+import { Spinner } from '../components/Spinner';
5+import useMedia from '../logic/useMedia';
6+import { useNotebooks } from '../state/posts';
7+import { Posts } from './Posts';
8+import { getColor, getImage } from '../utils';
9+
10+export const Notebooks = () => {
11+ const { ship, name } = useParams<{ ship: string, name: string }>();
12+ const limited = useMedia('(max-width: 899px)');
13+ const { groups, notebooks, loading } = useNotebooks();
14+ const sortedNotebooks = Object.entries(notebooks)
15+ .sort(([,a], [,b]) => a.meta.title.localeCompare(b.meta.title));
16+
17+ return (
18+ <div className="flex-none flex flex-col max-w-5xl w-full p-4 sm:py-12 sm:px-8 space-y-6 sm:pl-32 xl:pl-8">
19+ <div className='flex items-start'>
20+ {((limited && !ship) || !limited) &&
21+ <aside className='sticky top-4 sm:top-12 flex-none flex flex-col sm:w-72 sm:h-[80vh] pt-14 sm:pt-0 mr-6 self-start'>
22+ <header className='flex-none fixed sm:static top-0 w-full p-4 pl-0 sm:p-0 bg-linen'>
23+ <h1 className='text-2xl font-semibold ml-2 sm:mb-6'>Add Posts</h1>
24+ </header>
25+ <ul className='flex-1 sm:overflow-y-auto'>
26+ {loading && <div className='flex items-center space-x-2 text-lavender mt-6'>
27+ <Spinner className='w-6 h-6' />
28+ <span>Loading notebooks...</span>
29+ </div>}
30+ {sortedNotebooks.map(([id, n], index) => {
31+ const [,group] = groups.find(([k]) => k === n.perms.group) || [];
32+ const image = group && (getImage(group.meta.image) || getImage(group.meta.cover) || '');
33+ const color = group && (getColor(group.meta.image) || getColor(group.meta.cover) || '');
34+
35+ return (
36+ <li key={id}>
37+ <NavLink to={`/manage-listings/posts/${id}`} className={({ isActive }) => cn('flex items-center p-2 space-x-2 leading-tight rounded-md hover:bg-fawn', isActive && 'bg-fawn')}>
38+ {group && image ? (
39+ <img
40+ src={image}
41+ className="flex-none w-10 h-10 object-cover rounded-md"
42+ loading={index > 15 ? 'lazy' : 'eager'}
43+ style={{ backgroundColor: color }}
44+ />
45+ ) : group ? (
46+ <div
47+ className='flex-none w-10 h-10 bg-rosy/20 rounded-md'
48+ style={{ backgroundColor: color }}
49+ />
50+ ) : null}
51+ <div className='flex flex-col min-w-0'>
52+ <strong className='w-full truncate'>{n.meta.title}</strong>
53+ {group && <span className='text-sm'>{group.meta.title}</span>}
54+ </div>
55+ </NavLink>
56+ </li>
57+ )}
58+ )}
59+ </ul>
60+ </aside>
61+ }
62+ {((limited && ship) || !limited) &&
63+ <section className='flex-1 min-w-0 space-y-6'>
64+ {!loading && notebooks && ship && name && <Posts ship={ship} name={name} />}
65+ </section>
66+ }
67+ </div>
68+ </div>
69+ )
70+}
ui/src/manage-listings/Post.tsxnew file+142
@@ -0,0 +1,142 @@
1+import debounce from 'lodash.debounce';
2+import React, { useCallback, useEffect, useRef, useState } from 'react';
3+import { FormProvider, useForm } from 'react-hook-form';
4+import { Link, useNavigate, useSearchParams } from 'react-router-dom';
5+import { MultiValue } from 'react-select';
6+import api from '../api';
7+import { ErrorMessage } from '../components/ErrorMessage';
8+import { Filter } from '../components/Filter';
9+import { Option, TagField } from '../components/TagField';
10+import { Declare, Post as PostForm, PostType } from '../types/sphinx';
11+import {
12+ MAX_DESCRIPTION_BYTES, MAX_TAG_BYTES, MAX_TAGS, MAX_TITLE_BYTES, MAX_URL_BYTES,
13+ byteLength, isListingImage, isListingLink
14+} from '../utils';
15+
16+function errorMessages(length: number, url?: string) {
17+ return {
18+ required: 'This field is required.',
19+ bytes: `The maximum length is ${length} bytes (accented letters and emoji count as 2-4).`,
20+ url
21+ }
22+}
23+
24+// lib/sphinx +lengths-valid counts UTF-8 bytes and drops longer listings silently
25+const maxBytes = (max: number) => ({ bytes: (value: string) => byteLength(value || '') <= max });
26+
27+// what lib/validate-url rejects, which %sphinx also drops silently
28+const URL_RULES = 'no spaces, #fragments, non-ASCII letters or characters like | [ ] { }';
29+
30+export const Post = () => {
31+ const [params] = useSearchParams();
32+ // ?tags= can bring in tags that TagField wouldn't take
33+ const defaultTags = params.getAll('tags')
34+ .filter((t, i, all) => t && byteLength(t) <= MAX_TAG_BYTES && all.indexOf(t) === i)
35+ .slice(0, MAX_TAGS)
36+ .map(t => ({ label: t, value: t}));
37+ const [tags, setTags] = useState<MultiValue<Option>>(defaultTags);
38+ const [image, setImage] = useState<string>('');
39+ const form = useForm<PostForm>({
40+ defaultValues: {
41+ title: params.get('title') || '',
42+ type: params.get('type') as PostType || 'other',
43+ link: params.get('link') || '',
44+ image: params.get('image') || '',
45+ description: params.get('description') || '',
46+ color: params.get('color') || ''
47+ }
48+ });
49+
50+ const { register, watch, reset, setValue, handleSubmit } = form;
51+
52+ const updateImg = useRef(debounce(setImage));
53+ const img = watch('image');
54+ const type = watch('type');
55+
56+ const onSubmit = useCallback((values: Omit<PostForm, 'tags'>) => {
57+ api.poke<Declare>({
58+ app: 'sphinx',
59+ mark: 'declare',
60+ json: {
61+ reach: 'friends',
62+ post: {
63+ ...values,
64+ tags: tags.map(t => t.value)
65+ }
66+ }
67+ })
68+ reset();
69+ setTags([]);
70+ }, [tags]);
71+
72+ useEffect(() => {
73+ register('type')
74+ }, []);
75+
76+ useEffect(() => {
77+ if (img) {
78+ updateImg.current(img)
79+ }
80+ }, [img]);
81+
82+ return (
83+ <div className='w-full space-y-6 m-auto'>
84+ <header>
85+ <h1 className='text-2xl font-semibold'>Add a Listing</h1>
86+ </header>
87+ <FormProvider {...form}>
88+ {/* only our checks: the browser's type="url" check refuses relative links like /1/group/~zod/x */}
89+ <form noValidate onSubmit={handleSubmit(onSubmit)}>
90+ <div className='flex w-full space-x-6'>
91+ <div className='flex-1 space-y-3'>
92+ <div>
93+ <label htmlFor='title' className='text-sm font-semibold'>Title</label>
94+ <div className='flex items-center space-x-2'>
95+ <input {...register('title', { required: true, validate: maxBytes(MAX_TITLE_BYTES) })} className='flex-1 w-full py-1 px-2 bg-fawn/30 focus:outline-none focus:ring-2 ring-lavender rounded-lg border border-fawn/30' placeholder='sphinx'/>
96+ <Filter selected={type} onSelect={(value) => setValue('type', value)} />
97+ </div>
98+ <ErrorMessage className='mt-1' field="title" messages={errorMessages(MAX_TITLE_BYTES)}/>
99+ </div>
100+ <div className='flex items-center space-x-6'>
101+ <div className='flex-1 space-y-3'>
102+ <div>
103+ <label htmlFor='image' className='text-sm font-semibold'>Image</label>
104+ <input type="url" {...register('image', {
105+ validate: { ...maxBytes(MAX_URL_BYTES), url: isListingImage }
106+ })} className='flex-1 w-full py-1 px-2 bg-fawn/30 focus:outline-none focus:ring-2 ring-lavender rounded-lg border border-fawn/30' placeholder='https://nyc3.digitaloceanspaces.com/...' />
107+ <ErrorMessage className='mt-1' field="image" messages={errorMessages(MAX_URL_BYTES, `Use a web address (https://host/path) with ${URL_RULES}.`)}/>
108+ </div>
109+ <div>
110+ <label htmlFor='link' className='text-sm font-semibold'>Link</label>
111+ <input type="url" {...register('link', { required: true, validate: { ...maxBytes(MAX_URL_BYTES), url: isListingLink } })} className='flex-1 w-full py-1 px-2 bg-fawn/30 focus:outline-none focus:ring-2 ring-lavender rounded-lg border border-fawn/30' placeholder='web+urbitgraph://~donmec-sallud/sphinx' />
112+ <ErrorMessage className='mt-1' field="link" messages={errorMessages(MAX_URL_BYTES, `Use a link with ${URL_RULES}.`)} />
113+ </div>
114+ </div>
115+ <img className='flex-none object-cover w-28 h-28 mt-4 border-2 border-dashed border-mauve/60 rounded-lg' src={image || undefined} />
116+ </div>
117+ <div>
118+ <label htmlFor='description' className='text-sm font-semibold'>Description</label>
119+ <textarea {...register('description', { required: true, validate: maxBytes(MAX_DESCRIPTION_BYTES) })} rows={2} className='align-middle w-full py-1 px-2 bg-fawn/30 focus:outline-none focus:ring-2 ring-lavender rounded-lg border border-fawn/30' placeholder='An app for answering your riddles' />
120+ <ErrorMessage className='mt-1' field="description" messages={errorMessages(MAX_DESCRIPTION_BYTES)} />
121+ </div>
122+ <div>
123+ <label className='text-sm font-semibold'>Tags</label>
124+ <TagField tags={tags} onTags={setTags} />
125+ </div>
126+ <div className='pt-3'>
127+ <div className='flex justify-between border-t border-zinc-300 py-3'>
128+ <Link to="/search" className='flex items-center rounded-lg text-base font-semibold text-rosy bg-rosy/30 border-2 border-transparent hover:border-rosy leading-none py-2 px-3 transition-colors'>
129+ Back to Search
130+ </Link>
131+ <button type="submit" className='flex items-center rounded-lg text-base font-semibold text-linen bg-rosy border-2 border-transparent hover:border-linen/60 leading-none py-2 px-3 transition-colors'>
132+ Publish
133+ </button>
134+ </div>
135+ </div>
136+ </div>
137+ </div>
138+ </form>
139+ </FormProvider>
140+ </div>
141+ )
142+}
ui/src/manage-listings/Posts.tsxnew file+122
@@ -0,0 +1,122 @@
1+import { ChevronLeftIcon } from '@heroicons/react/solid';
2+import React, { useCallback, useEffect, useState } from 'react';
3+import { FormProvider, useForm } from 'react-hook-form';
4+import { useMutation, useQueryClient } from '@tanstack/react-query';
5+import { Link } from 'react-router-dom';
6+import { MultiValue } from 'react-select';
7+import api from '../api';
8+import { Filter } from '../components/Filter';
9+import { PostOptions } from '../components/PostOptions';
10+import { Spinner } from '../components/Spinner';
11+import { TagField, Option } from '../components/TagField';
12+import useMedia from '../logic/useMedia';
13+import { usePosts } from '../state/posts';
14+import { Declare, PostOptionsForm, PostType } from '../types/sphinx';
15+import { POST_LISTINGS_KEY } from '../keys';
16+
17+interface PostsProps {
18+ ship: string;
19+ name: string;
20+}
21+
22+export const Posts = ({ ship, name }: PostsProps) => {
23+ const limited = useMedia('(max-width: 899px)');
24+ const [postType, setPostType] = useState<PostType>('content')
25+ const [tags, setTags] = useState<MultiValue<Option>>([{ label: 'post', value: 'post' }])
26+ const { loading, posts, notebook } = usePosts(ship, name, postType, tags.map(t => t.value));
27+ const [firstLoad, setFirstLoad] = useState(true);
28+ const form = useForm<PostOptionsForm>({
29+ defaultValues: {
30+ options: []
31+ }
32+ });
33+ const { handleSubmit, reset, watch, setValue } = form;
34+ const options = watch('options');
35+
36+ useEffect(() => {
37+ if (posts.length > 0 && firstLoad) {
38+ reset({
39+ options: []
40+ })
41+
42+ setFirstLoad(false);
43+ }
44+ }, [posts, firstLoad]);
45+
46+ const toggleAll = useCallback(() => {
47+ if (options.length !== posts.length) {
48+ setValue('options', posts.map(p => p.key));
49+ } else {
50+ setValue('options', []);
51+ }
52+ }, [posts, options, setValue]);
53+
54+ const queryClient = useQueryClient();
55+ const { mutate } = useMutation(async (values: PostOptionsForm) => {
56+ return api.poke<Declare[]>({
57+ app: 'sphinx',
58+ mark: 'declarations',
59+ json: posts.filter(a => values.options.includes(a.key)).map(a => ({
60+ post: a.post,
61+ reach: 'friends'
62+ }))
63+ });
64+ }, {
65+ onSuccess: () => {
66+ queryClient.invalidateQueries(POST_LISTINGS_KEY)
67+ }
68+ })
69+
70+ const onSubmit = useCallback((values: PostOptionsForm) => {
71+ mutate(values);
72+ reset();
73+ }, [reset, mutate]);
74+
75+ return (
76+ <>
77+ <header className='flex items-center'>
78+ {limited && (
79+ <Link to="/manage-listings/posts" className='flex items-center'>
80+ <ChevronLeftIcon className='h-6 w-6 text-mauve/60' />
81+ <h1 className='text-2xl font-semibold'>{notebook?.meta.title}</h1>
82+ </Link>
83+ )}
84+ {!limited && <h1 className='text-2xl font-semibold'>{notebook?.meta.title}</h1>}
85+ {posts.length > 0 && (
86+ <button className='p-1.5 ml-auto text-sm underline font-semibold' onClick={toggleAll}>
87+ {options.length !== posts.length && 'select all'}
88+ {options.length === posts.length && 'deselect all'}
89+ </button>
90+ )}
91+ </header>
92+ <div className='flex flex-col items-end sm:flex-row sm:items-center space-y-2 sm:space-y-0 sm:space-x-2'>
93+ <TagField tags={tags} onTags={setTags} className="flex-1 w-full"/>
94+ <Filter className='flex-none' selected={postType} onSelect={(value) => setPostType(value)} />
95+ </div>
96+ <FormProvider {...form}>
97+ <form onSubmit={handleSubmit(onSubmit)}>
98+ {posts.length === 0 && loading ? (
99+ <div className='flex items-center space-x-2 text-lavender'>
100+ <Spinner className='w-6 h-6' />
101+ <span>Checking posts...</span>
102+ </div>
103+ ) : posts.length === 0 && !loading ? (
104+ <h2 className='text-lavender'>All posts already indexed</h2>
105+ ) : (
106+ <PostOptions options={posts} showTags />
107+ )}
108+ <div className='flex justify-between border-t border-zinc-300 py-3 mt-6'>
109+ <Link to="/search" className='flex items-center rounded-lg text-base font-semibold text-rosy bg-rosy/30 border-2 border-transparent hover:border-rosy leading-none py-2 px-3 transition-colors'>
110+ Back to Search
111+ </Link>
112+ {posts.length > 0 && (
113+ <button type="submit" className='flex items-center rounded-lg text-base font-semibold text-linen bg-rosy disabled:bg-zinc-200 disabled:text-zinc-400 disabled:border-transparent border-2 border-transparent hover:border-linen/60 leading-none py-2 px-3 transition-colors' disabled={options.length === 0}>
114+ Publish
115+ </button>
116+ )}
117+ </div>
118+ </form>
119+ </FormProvider>
120+ </>
121+ );
122+}
ui/src/pages/Search.tsxnew file+113
@@ -0,0 +1,113 @@
1+import cn from 'classnames';
2+import React, { useCallback, useRef, useState } from 'react';
3+import debounce from 'lodash.debounce';
4+import { useMutation, useQueryClient } from '@tanstack/react-query';
5+import { useNavigate, useParams } from 'react-router-dom';
6+import { SearchInput } from '../components/SearchInput';
7+import { Listings } from '../components/Listings';
8+import { PostFilter, Remove, Search as SearchType } from '../types/sphinx';
9+import api from '../api';
10+import { Paginator } from '../components/Paginator';
11+import { Filter } from '../components/Filter';
12+import { PlusSmIcon } from '@heroicons/react/solid';
13+import { usePals } from '../state/pals';
14+import { TagCloud } from '../components/TagCloud';
15+import { useTags } from '../state/tags';
16+import { useSearch } from '../state/search';
17+import { encodeLookup, formatUd } from '../utils';
18+import { lookupKey } from '../keys';
19+
20+interface RouteParams extends Record<string, string | undefined> {
21+ lookup?: string;
22+ limit?: string;
23+ page?: string;
24+}
25+
26+export const Search = () => {
27+ const navigate = useNavigate();
28+ const {
29+ lookup,
30+ limit,
31+ page
32+ } = useParams<RouteParams>();
33+ const [selected, setSelected] = useState<PostFilter>('all')
34+ const [rawSearch, setRawSearch] = useState(lookup || '');
35+ const { installed: palsInstalled } = usePals();
36+
37+ const {
38+ size,
39+ start,
40+ pageInt,
41+ pages,
42+ results,
43+ isLoading,
44+ linkBuild
45+ } = useSearch({
46+ key: lookupKey(selected, lookup),
47+ fetcher: (start, size) => api.scry<SearchType>({
48+ app: 'sphinx',
49+ path: `/lookup/${selected}/${formatUd(start)}/${formatUd(size)}/${encodeLookup(lookup)}`
50+ }),
51+ enabled: !!lookup,
52+ limit,
53+ page,
54+ linkPrefix: `/search/${lookup}`
55+ });
56+ const tags = useTags();
57+ const queryClient = useQueryClient();
58+ const { mutate } = useMutation((hash: string) => {
59+ return api.poke<Remove>({
60+ app: 'sphinx',
61+ mark: 'remove',
62+ json: hash
63+ })
64+ }, {
65+ onSuccess: () => {
66+ queryClient.invalidateQueries(lookupKey(selected, lookup)(start, size))
67+ }
68+ });
69+
70+ const update = useRef(debounce((value: string) => {
71+ if (!value) {
72+ return;
73+ }
74+
75+ navigate(`/search/${value}/${size}/${page || '1'}`)
76+ }, 400))
77+
78+ const onChange = useCallback((value: string) => {
79+ setRawSearch(value);
80+ update.current(value);
81+ }, []);
82+
83+ return (
84+ <div className={cn('w-full space-y-6', !lookup && 'm-auto')}>
85+ <header className='flex items-center space-x-2'>
86+ <SearchInput className='flex-1' lookup={rawSearch} loading={!!lookup && isLoading} onChange={onChange} />
87+ <Filter selected={selected} onSelect={setSelected} className="min-w-0 sm:w-20" />
88+ </header>
89+ {!palsInstalled && (
90+ <div>
91+ <a href="/apps/landscape/search/~paldev/apps/~paldev/pals" className='inline-flex items-center py-1 px-2 mr-2 font-semibold bg-green-800 text-linen rounded-md'>
92+ <PlusSmIcon className='h-4 w-4' />
93+ install pals
94+ </a>
95+ to see listings from others
96+ </div>
97+ )}
98+ {lookup && results && <div className='flex justify-end border-t border-zinc-300'>
99+ <Paginator pages={pages} currentPage={pageInt} linkBuilder={linkBuild} />
100+ </div>}
101+ {lookup && <Listings listings={results.listings} remove={mutate} />}
102+ {!lookup && (
103+ <div className='space-y-2'>
104+ <h2 className='font-semibold'>top tags</h2>
105+ <TagCloud tags={tags.slice(0,12)} />
106+ </div>
107+ )}
108+ {results && pages > 1 && <div className='flex justify-end border-t border-zinc-300'>
109+ <Paginator pages={pages} currentPage={pageInt} linkBuilder={linkBuild} />
110+ </div>}
111+ </div>
112+ )
113+}
ui/src/pages/Tag.tsxnew file+82
@@ -0,0 +1,82 @@
1+import { PlusIcon, PlusSmIcon } from '@heroicons/react/solid';
2+import cn from 'classnames';
3+import qs from 'query-string';
4+import React from 'react';
5+import { useQueryClient, useMutation } from '@tanstack/react-query';
6+import { Link, useParams } from 'react-router-dom';
7+import api from '../api';
8+import { Listings } from '../components/Listings';
9+import { Paginator } from '../components/Paginator';
10+import { TagCloud } from '../components/TagCloud';
11+import { useSearch } from '../state/search';
12+import { useTags } from '../state/tags';
13+import { Remove, Search } from '../types/sphinx';
14+import { encodeLookup, formatUd } from '../utils';
15+import { tagKey } from '../keys';
16+
17+interface RouteParams extends Record<string, string | undefined> {
18+ tag?: string;
19+ limit?: string;
20+ page?: string;
21+}
22+
23+export const Tag = () => {
24+ const tags = useTags();
25+ const { tag, limit, page } = useParams<RouteParams>();
26+ const {
27+ size,
28+ start,
29+ pageInt,
30+ pages,
31+ results,
32+ linkBuild
33+ } = useSearch({
34+ key: tagKey(tag),
35+ fetcher: (start, size) => api.scry<Search>({
36+ app: 'sphinx',
37+ path: `/lookup/tag/${formatUd(start)}/${formatUd(size)}/${encodeLookup(tag)}`
38+ }),
39+ enabled: !!tag,
40+ limit,
41+ page,
42+ linkPrefix: `/tags/${tag}`
43+ });
44+ const queryClient = useQueryClient();
45+ const { mutate } = useMutation((hash: string) => {
46+ return api.poke<Remove>({
47+ app: 'sphinx',
48+ mark: 'remove',
49+ json: hash
50+ })
51+ }, {
52+ onSuccess: () => {
53+ queryClient.invalidateQueries(tagKey(tag)(start, size))
54+ }
55+ });
56+
57+ return (
58+ <div className={cn('w-full space-y-6', !tag && 'm-auto')}>
59+ {!tag && <h1 className='text-2xl font-semibold'>Tags</h1>}
60+ <div className={cn('h-[136px] overflow-y-auto', tag && 'mb-12')}>
61+ <TagCloud tags={tags} />
62+ </div>
63+ {tag && <header className='flex items-center justify-between'>
64+ <h1 className='text-2xl font-semibold leading-none'>{tag}</h1>
65+ <Link
66+ to={{ pathname: '/manage-listings/post', search: qs.stringify({ tags: [tag] }) }}
67+ className="inline-flex items-center px-2 pr-3 py-1 font-semibold text-linen bg-lavender hover:bg-rosy transition-colors rounded-lg"
68+ >
69+ <PlusSmIcon className='w-5 h-5' />
70+ <span>Add</span>
71+ </Link>
72+ </header>}
73+ {tag && results && <div className='flex justify-end border-t border-zinc-300'>
74+ <Paginator pages={pages} currentPage={pageInt} linkBuilder={linkBuild} />
75+ </div>}
76+ {tag && <Listings listings={results.listings} remove={mutate} />}
77+ {results && pages > 1 && <div className='flex justify-end border-t border-zinc-300'>
78+ <Paginator pages={pages} currentPage={pageInt} linkBuilder={linkBuild} />
79+ </div>}
80+ </div>
81+ )
82+}
ui/src/routes.tsnew file+16
@@ -0,0 +1,16 @@
1+export const BrowsingRoutes = {
2+ search: "/search",
3+ tags: "/tags",
4+ apps: "/tags/app",
5+ groups: "/tags/group",
6+ jobs: "/tags/job",
7+ 'my listings': "/manage-listings",
8+ 'all listings': "/manage-listings/all"
9+}
10+
11+export const PostingRoutes = {
12+ 'post listing': "/manage-listings/post",
13+ 'add apps': "/manage-listings/apps",
14+ 'add groups': "/manage-listings/groups",
15+ 'add posts': "/manage-listings/posts"
16+}
ui/src/state/apps.tsnew file+39
@@ -0,0 +1,39 @@
1+import { Charge, ChargeUpdateInitial, getPikes, Pike, Pikes, scryCharges } from "@urbit/api";
2+import { useQuery } from "@tanstack/react-query"
3+import api from "../api";
4+import { Post, Search } from "../types/sphinx";
5+import { APP_LISTINGS_KEY, CHARGES_KEY, VATS_KEY } from "../keys";
6+import { MAX_DESCRIPTION_BYTES, MAX_TITLE_BYTES, listingImage, truncateBytes } from "../utils";
7+
8+function getAppPost(app: string, pike: Pike, charge: Charge): Post {
9+ const ship = pike.sync?.ship || `~${window.ship}`;
10+
11+ return {
12+ type: 'app',
13+ title: truncateBytes(charge.title, MAX_TITLE_BYTES),
14+ // the desk on the publisher, which may differ from the local name
15+ // (|install ~ship %desk, =local %other)
16+ link: `/1/desk/${ship}/${pike.sync?.desk || app}`,
17+ description: truncateBytes(charge.info || charge.title, MAX_DESCRIPTION_BYTES),
18+ image: listingImage(charge.image),
19+ color: charge.color,
20+ tags: ['app']
21+ }
22+}
23+
24+export const useApps = () => {
25+ const { data: pikes, isLoading: pikesLoading } = useQuery(VATS_KEY, () => api.scry<Pikes>(getPikes));
26+ const { data: charges, isLoading: chargesLoading } = useQuery(CHARGES_KEY, () => api.scry<ChargeUpdateInitial>(scryCharges));
27+ const { data, isLoading } = useQuery(APP_LISTINGS_KEY, () => api.scry<Search>({
28+ app: 'sphinx',
29+ path: '/lookup/app/0/999'
30+ }));
31+
32+ return {
33+ loading: pikesLoading || chargesLoading || isLoading,
34+ apps: !pikes || !charges || !data ? [] : Object.entries(charges.initial)
35+ .filter(([k]) => k in pikes)
36+ .map(([k,v]) => ({ key: k, post: getAppPost(k, pikes[k], v) }))
37+ .filter(({ post }) => !data.listings.some(l => l.post.link === post.link || l.post.title === post.title))
38+ }
39+}
ui/src/state/groups.tsnew file+76
@@ -0,0 +1,76 @@
1+import { useQuery } from "@tanstack/react-query"
2+import api from "../api"
3+import { PostType, Search } from "../types/sphinx";
4+import { ChannelPreview, Groups } from "../types";
5+import { useMemo } from "react";
6+import { GROUPS_KEY, GROUP_LISTINGS_KEY } from "../keys";
7+import { MAX_DESCRIPTION_BYTES, MAX_TITLE_BYTES, getColor, getImage, isColor, listingImage, truncateBytes } from "../utils";
8+
9+export const usePublicGroups = () => {
10+ const { data, ...query } = useQuery(GROUPS_KEY,
11+ () => api.scry<Groups>({
12+ app: 'groups',
13+ path: '/groups/light'
14+ }),
15+ { initialData: {} }
16+ );
17+
18+ const groups = useMemo(() => {
19+ if (!data) return [];
20+ return Object.entries(data).filter(([,v]) => !v.secret);
21+ }, [data]);
22+
23+ return {
24+ ...query,
25+ groups
26+ }
27+}
28+
29+export const useGroups = () => {
30+ const { groups, isLoading: loading } = usePublicGroups();
31+ const { data: d, isLoading } = useQuery(GROUP_LISTINGS_KEY, () => api.scry<Search>({
32+ app: 'sphinx',
33+ path: '/lookup/group/0/999'
34+ }));
35+
36+ return {
37+ loading: loading || isLoading,
38+ groups: groups.map(([k,v]) => ({ key: k, post: {
39+ type: 'group' as PostType,
40+ title: truncateBytes(v.meta.title, MAX_TITLE_BYTES),
41+ link: `/1/group/${k}`, //`/apps/groups/groups/${k}`,
42+ image: listingImage(getImage(v.meta.image) || getImage(v.meta.cover)),
43+ color: getColor(v.meta.image) || getColor(v.meta.cover) || '',
44+ description: truncateBytes(v.meta.description, MAX_DESCRIPTION_BYTES),
45+ tags: ['group']
46+ }}))
47+ .filter(({ post }) => !d || d.listings.length === 0 || !d.listings.some(l => l.post.link === post.link || l.post.title === post.title))
48+ }
49+}
50+
51+export function useChannelPreview(nest: string): ChannelPreview | undefined {
52+ const { groups, isFetched } = usePublicGroups();
53+ const group = groups.find(([,g]) => {
54+ return !!g.channels[nest];
55+ });
56+
57+ // %groups asks the channel's host and answers once (mark channel-preview-1)
58+ const { data } = useQuery(['channel-preview', nest],
59+ () => api.subscribeOnce<ChannelPreview>('groups', `/v1/channels/${nest}/preview`, 5000),
60+ {
61+ // only for channels outside our groups, so wait until those are known
62+ enabled: isFetched && !!nest && !group,
63+ refetchOnMount: false,
64+ refetchOnWindowFocus: false,
65+ },
66+ );
67+
68+ return group ? {
69+ nest,
70+ meta: group[1].channels[nest].meta,
71+ group: {
72+ flag: group[0],
73+ meta: group[1].meta,
74+ }
75+ } : data;
76+}
ui/src/state/pals.tsnew file+62
@@ -0,0 +1,62 @@
1+import { ChargeUpdateInitial, scryCharges } from '@urbit/api';
2+import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
3+import api from '../api';
4+import { CHARGES_KEY, PALS_KEY } from '../keys';
5+
6+interface Pal {
7+ lists: string[];
8+ ack: true | null;
9+}
10+
11+export interface Pals {
12+ [k: string]: Pal;
13+}
14+
15+interface PalsData {
16+ incoming: Pals;
17+ outgoing: Pals;
18+ [k: string]: Pal | Pals;
19+}
20+
21+interface RemovePal {
22+ part: {
23+ ship: string;
24+ in: string[];
25+ }
26+}
27+
28+export const usePals = () => {
29+ const queryClient = useQueryClient();
30+ const { data: charges } = useQuery(CHARGES_KEY, () => {
31+ return api.scry<ChargeUpdateInitial>(scryCharges);
32+ })
33+ const { data } = useQuery(PALS_KEY, () => {
34+ return api.scry<PalsData>({
35+ app: 'pals',
36+ path: '/json'
37+ });
38+ });
39+ const { mutate: remove } = useMutation((pal: string) => {
40+ return api.poke<RemovePal>({
41+ app: 'pals',
42+ mark: 'pals-command',
43+ json: {
44+ part: {
45+ ship: pal,
46+ in: []
47+ }
48+ }
49+ })
50+ }, {
51+ onSuccess: () => {
52+ queryClient.invalidateQueries(PALS_KEY);
53+ }
54+ })
55+
56+ return {
57+ installed: !charges ? true : 'pals' in charges.initial,
58+ incoming: data ? Object.keys(data.incoming) : [],
59+ outgoing: data ? data.outgoing : {},
60+ remove
61+ }
62+}
ui/src/state/posts.tsnew file+108
@@ -0,0 +1,108 @@
1+import { useQuery } from "@tanstack/react-query"
2+import api from "../api"
3+import { PostType, Search } from "../types/sphinx";
4+import { usePublicGroups } from "./groups";
5+import { POST_LISTINGS_KEY, notesKey } from "../keys";
6+import { ChannelsResponse, Diary, GroupChannel, NoteContent, PagedChannelPosts, VerseInline, inlineToString } from "../types";
7+import { useMemo } from "react";
8+import { udToDec } from '@urbit/api';
9+import { MAX_DESCRIPTION_BYTES, MAX_TITLE_BYTES, listingImage, normalizeLink, truncateBytes } from "../utils";
10+
11+// notebooks are %channels channels of kind %diary, keyed by nest
12+// "diary/~ship/name" (the old %diary agent is gone from the %groups desk)
13+const DIARY_PREFIX = 'diary/';
14+
15+export const useNotebooks = () => {
16+ const { groups, isLoading: groupsLoading } = usePublicGroups();
17+ const { data, isLoading } = useQuery(notesKey(), () => api.scry<ChannelsResponse>({
18+ app: 'channels',
19+ path: '/v1/channels'
20+ }));
21+
22+ const notebooks = useMemo(() => {
23+ const nbs: Record<string, GroupChannel & Diary> = {};
24+ if (!data) return nbs;
25+
26+ Object.entries(data).forEach(([nest, v]) => {
27+ if (!nest.startsWith(DIARY_PREFIX)) return;
28+ const flag = nest.slice(DIARY_PREFIX.length);
29+ const group = groups.find(([g]) => g === v.perms.group);
30+ if (!group) return;
31+
32+ const channel = group[1].channels[nest];
33+ if (!channel) return;
34+
35+ if (channel.readers.length === 0) {
36+ nbs[flag] = { ...v, ...channel };
37+ }
38+ });
39+
40+ return nbs;
41+ }, [data, groups]);
42+
43+ return {
44+ notebooks,
45+ groups,
46+ loading: isLoading || groupsLoading
47+ }
48+}
49+
50+export const usePosts = (ship: string, name: string, type: PostType, tags: string[]) => {
51+ const flag = `${ship}/${name}`;
52+ const { notebooks, loading } = useNotebooks();
53+ const { data, isLoading } = useQuery(notesKey(flag), () => api.scry<PagedChannelPosts>({
54+ app: 'channels',
55+ path: `/v1/${DIARY_PREFIX}${flag}/posts/newest/9.999.999/outline`
56+ }));
57+ // every listing we have, ours or a mutual's, whatever its tags or type
58+ // (%sphinx refuses to publish a listing it already has)
59+ const { data: d, isLoading: postsLoading } = useQuery(POST_LISTINGS_KEY, () => api.scry<Search>({
60+ app: 'sphinx',
61+ path: '/lookup/all/0/9.999.999'
62+ }));
63+
64+ const items = data ? Object.entries(data.posts)
65+ .flatMap(([id, post]) => {
66+ if (!post) return []; // deleted post
67+ const diary = post.essay['kind-data']?.diary;
68+ return [{ key: id, post: {
69+ type,
70+ title: truncateBytes(diary?.title || '', MAX_TITLE_BYTES),
71+ link: getPermalink(flag, id),
72+ image: listingImage(diary?.image),
73+ color: '',
74+ description: getSnippet(post.essay.content),
75+ tags
76+ }}];
77+ }) : [];
78+
79+ // listings store refs; older ones may still be web+urbitgraph links
80+ const listed = useMemo(
81+ () => new Set((d?.listings || []).map(l => normalizeLink(l.post.link))),
82+ [d]
83+ );
84+ const posts = items.filter(p => !listed.has(p.post.link));
85+
86+ return {
87+ notebook: notebooks[flag],
88+ loading: loading || isLoading || postsLoading,
89+ posts
90+ }
91+}
92+
93+function getPermalink(flag: string, id: string): string {
94+ return `/1/chan/${DIARY_PREFIX}${flag}/note/${udToDec(id)}`;
95+}
96+
97+// the first paragraph with any text, as plain text
98+function getSnippet(content: NoteContent): string {
99+ const inlines = content.filter(c => 'inline' in c) as VerseInline[];
100+ for (const verse of inlines) {
101+ const text = verse.inline.map(inlineToString).join('').replace(/\s+/g, ' ').trim();
102+ if (text) {
103+ return truncateBytes(text, MAX_DESCRIPTION_BYTES);
104+ }
105+ }
106+
107+ return '';
108+}
ui/src/state/search.tsnew file+49
@@ -0,0 +1,49 @@
1+import { useCallback } from "react";
2+import { QueryKey, useQuery } from "@tanstack/react-query";
3+import { Search } from "../types/sphinx";
4+
5+interface UseSearchParams {
6+ key: (start: number, size: number) => QueryKey;
7+ fetcher: (start: number, size: number) => Promise<Search>;
8+ enabled: boolean;
9+ linkPrefix: string;
10+ limit?: string;
11+ page?: string;
12+}
13+
14+export const useSearch = ({ key, fetcher, enabled, limit, page, linkPrefix }: UseSearchParams) => {
15+ const size = parseInt(limit || '10', 10);
16+ const pageInt = parseInt(page || '1', 10) - 1;
17+ const start = pageInt * size;
18+
19+ const { data, ...query } = useQuery<Search>(key(start, size), () => fetcher(start, size), {
20+ enabled,
21+ keepPreviousData: true
22+ });
23+
24+ const total = data?.total || 0;
25+ const pages =
26+ total % size === 0
27+ ? total / size
28+ : Math.floor(total / size) + 1;
29+
30+ const linkBuild = useCallback((page) => {
31+ if (!page) {
32+ return null;
33+ }
34+
35+ return `${linkPrefix}/${size}/${page || 1}`
36+ }, [linkPrefix, size]);
37+
38+ return {
39+ results: data || {
40+ listings: []
41+ },
42+ ...query,
43+ size,
44+ pageInt,
45+ start,
46+ pages,
47+ linkBuild
48+ }
49+}
ui/src/state/tags.tsnew file+21
@@ -0,0 +1,21 @@
1+import { useMemo } from "react";
2+import { useQuery } from "@tanstack/react-query";
3+import api from "../api";
4+import { Tags } from "../types/sphinx";
5+import { TAGS_KEY } from "../keys";
6+
7+export const useTags = () => {
8+ const { data } = useQuery(TAGS_KEY, () => api.scry<Tags>({
9+ app: 'sphinx',
10+ path: '/tags'
11+ }));
12+
13+ return useMemo(() => data ? Object.entries(data).sort(([tagA, a], [tagB, b]) => {
14+ if (a === b) {
15+ return tagA.localeCompare(tagB);
16+ }
17+
18+ return b - a
19+ })
20+ : [], [data]);
21+}
ui/src/styles/base.cssnew file

No changes to the content.

ui/src/styles/components.cssnew file+16
@@ -0,0 +1,16 @@
1+.button {
2+ @apply flex items-center rounded-lg text-base font-semibold text-linen bg-rosy disabled:bg-zinc-200 disabled:text-zinc-400 disabled:border-transparent border-2 border-transparent hover:border-linen/60 leading-none py-2 px-3 transition-colors;
3+}
4+
5+input:checked + label .show-when-checked {
6+ @apply opacity-100;
7+}
8+
9+input:checked + .checked-bg-fawn,
10+input:checked + label .checked-bg-fawn {
11+ @apply bg-fawn;
12+}
13+
14+.spinner {
15+ @apply inline-flex items-center w-6 h-6 animate-spin;
16+}
ui/src/styles/index.cssnew file+8
@@ -0,0 +1,8 @@
1+@import 'tailwindcss/base';
2+@import './base';
3+
4+@import 'tailwindcss/components';
5+@import './components';
6+
7+@import 'tailwindcss/utilities';
8+@import './utilities';
ui/src/styles/utilities.cssnew file+3
@@ -0,0 +1,3 @@
1+.flip {
2+ transform: rotateY(180deg);
3+}
ui/src/types/index.tsnew file+304
@@ -0,0 +1,304 @@
1+export interface GroupMeta {
2+ title: string;
3+ description: string;
4+ image: string;
5+ cover: string;
6+}
7+
8+export interface Vessel {
9+ sects: string[];
10+ joined: number;
11+}
12+
13+export interface Fleet {
14+ [ship: string]: Vessel;
15+}
16+
17+export interface GroupChannel {
18+ meta: GroupMeta;
19+ readers: string[];
20+}
21+
22+export interface Channels {
23+ [nest: string]: GroupChannel;
24+}
25+
26+export interface Group {
27+ fleet: Fleet;
28+ channels: Channels;
29+ meta: GroupMeta;
30+ secret: boolean;
31+}
32+
33+export interface Groups {
34+ [flag: string]: Group;
35+}
36+
37+// %groups /v1/channels/<kind>/<ship>/<name>/preview (mark channel-preview-1).
38+// Previews built from our own groups only fill in flag and meta.
39+export interface GroupPreview {
40+ flag: string;
41+ meta: GroupMeta;
42+ time?: number;
43+ 'member-count'?: number;
44+ privacy?: 'public' | 'private' | 'secret';
45+}
46+
47+export interface ChannelPreview {
48+ nest: string;
49+ meta: GroupMeta;
50+ group: GroupPreview;
51+}
52+
53+export interface Ship {
54+ ship: string;
55+}
56+
57+export interface Italics {
58+ italics: Inline[];
59+}
60+
61+export interface Bold {
62+ bold: Inline[];
63+}
64+
65+export interface Strikethrough {
66+ strike: Inline[];
67+}
68+
69+export interface Break {
70+ break: null;
71+}
72+
73+export interface InlineCode {
74+ 'inline-code': string;
75+}
76+
77+export interface BlockCode {
78+ code: string;
79+}
80+
81+export interface Blockquote {
82+ blockquote: Inline[];
83+}
84+
85+/**
86+ A reference to the accompanying blocks, indexed at 0
87+*/
88+export interface BlockReference {
89+ block: {
90+ index: number;
91+ text: string;
92+ };
93+}
94+
95+export interface Tag {
96+ tag: string;
97+}
98+
99+export interface Link {
100+ link: {
101+ href: string;
102+ content: string;
103+ };
104+}
105+
106+export interface Task {
107+ task: {
108+ checked: boolean;
109+ content: Inline[];
110+ };
111+}
112+
113+// a role mention
114+export interface Sect {
115+ sect: string | null;
116+}
117+
118+export type Inline =
119+ | string
120+ | Bold
121+ | Italics
122+ | Strikethrough
123+ | Ship
124+ | Break
125+ | InlineCode
126+ | BlockCode
127+ | Blockquote
128+ | BlockReference
129+ | Tag
130+ | Link
131+ | Task
132+ | Sect;
133+
134+export type InlineKey =
135+ | 'italics'
136+ | 'bold'
137+ | 'strike'
138+ | 'blockquote'
139+ | 'inline-code'
140+ | 'block'
141+ | 'code'
142+ | 'tag'
143+ | 'link'
144+ | 'break';
145+
146+export function isBold(item: unknown): item is Bold {
147+ return typeof item === 'object' && item !== null && 'bold' in item;
148+}
149+
150+export function isItalics(item: unknown): item is Italics {
151+ return typeof item === 'object' && item !== null && 'italics' in item;
152+}
153+
154+export function isLink(item: unknown): item is Link {
155+ return typeof item === 'object' && item !== null && 'link' in item;
156+}
157+
158+export function isStrikethrough(item: unknown): item is Strikethrough {
159+ return typeof item === 'object' && item !== null && 'strike' in item;
160+}
161+
162+export function isBlockquote(item: unknown): item is Blockquote {
163+ return typeof item === 'object' && item !== null && 'blockquote' in item;
164+}
165+
166+export function isInlineCode(item: unknown): item is InlineCode {
167+ return typeof item === 'object' && item !== null && 'inline-code' in item;
168+}
169+
170+export function isBlockCode(item: unknown): item is BlockCode {
171+ return typeof item === 'object' && item !== null && 'code' in item;
172+}
173+
174+export function isBreak(item: unknown): item is Break {
175+ return typeof item === 'object' && item !== null && 'break' in item;
176+}
177+
178+export function isShip(item: unknown): item is Ship {
179+ return typeof item === 'object' && item !== null && 'ship' in item;
180+}
181+
182+export function isTag(item: unknown): item is Tag {
183+ return typeof item === 'object' && item !== null && 'tag' in item;
184+}
185+
186+export function isTask(item: unknown): item is Task {
187+ return typeof item === 'object' && item !== null && 'task' in item;
188+}
189+
190+// plain text of an inline; text runs carry their own whitespace
191+export function inlineToString(inline: Inline): string {
192+ if (typeof inline === 'string') {
193+ return inline;
194+ }
195+
196+ if (isBold(inline)) {
197+ return inline.bold.map(inlineToString).join('');
198+ }
199+
200+ if (isItalics(inline)) {
201+ return inline.italics.map(inlineToString).join('');
202+ }
203+
204+ if (isStrikethrough(inline)) {
205+ return inline.strike.map(inlineToString).join('');
206+ }
207+
208+ if (isLink(inline)) {
209+ return inline.link.content || inline.link.href;
210+ }
211+
212+ if (isBlockquote(inline)) {
213+ return inline.blockquote.map(inlineToString).join('');
214+ }
215+
216+ if (isInlineCode(inline)) {
217+ return inline['inline-code'];
218+ }
219+
220+ if (isBlockCode(inline)) {
221+ return inline.code;
222+ }
223+
224+ if (isTag(inline)) {
225+ return inline.tag;
226+ }
227+
228+ if (isTask(inline)) {
229+ return inline.task.content.map(inlineToString).join('');
230+ }
231+
232+ if (isShip(inline)) {
233+ return inline.ship;
234+ }
235+
236+ if (isBreak(inline)) {
237+ return ' ';
238+ }
239+
240+ return '';
241+}
242+
243+// story verses (lib/story-json): {inline: [...]} or {block: {...}}
244+export interface VerseInline {
245+ inline: Inline[];
246+}
247+
248+export interface VerseBlock {
249+ block: any;
250+}
251+
252+export type Verse = VerseInline | VerseBlock;
253+
254+export type NoteContent = Verse[];
255+
256+export interface DiaryPerm {
257+ writers: string[];
258+ group: string;
259+}
260+
261+export interface Diary {
262+ perms: DiaryPerm;
263+}
264+
265+// %channels /v1/channels (mark %channels): keyed by nest "<kind>/~ship/name";
266+// posts are always empty here
267+export interface ChannelSummary extends Diary {
268+ posts: Record<string, unknown>;
269+ order: string[];
270+ view: string;
271+ sort: string;
272+}
273+
274+export interface ChannelsResponse {
275+ [nest: string]: ChannelSummary;
276+}
277+
278+// %channels /v1/<kind>/~ship/name/posts/newest/<count>/outline
279+// (mark %channel-posts)
280+export interface ChannelEssay {
281+ content: NoteContent;
282+ author: string;
283+ sent: number;
284+ 'kind-data': {
285+ diary?: { title: string; image: string };
286+ heap?: string | null;
287+ chat?: { notice: null } | null;
288+ };
289+}
290+
291+export interface ChannelPost {
292+ seal: { id: string };
293+ revision: string;
294+ essay: ChannelEssay;
295+ type: 'post';
296+}
297+
298+export interface PagedChannelPosts {
299+ // keyed by @ud post id ("170.141..."); null for a deleted post
300+ posts: { [id: string]: ChannelPost | null };
301+ newer: string | null;
302+ older: string | null;
303+ total: number;
304+}
ui/src/types/sphinx.tsnew file+52
@@ -0,0 +1,52 @@
1+export type PostType = 'app' | 'group' | 'content' | 'other';
2+
3+export type PostFilter = 'all' | PostType;
4+
5+export interface Declare {
6+ reach: 'friends' | 'public' | 'private';
7+ post: Post
8+}
9+
10+export type Remove = string;
11+
12+export interface Post {
13+ title: string;
14+ type: PostType;
15+ description: string;
16+ image: string;
17+ color: string;
18+ tags: string[];
19+ link: string;
20+}
21+
22+export interface Listing {
23+ post: Post;
24+ hash: string;
25+ source: string;
26+ time: number;
27+}
28+
29+export type Search = {
30+ listings: Listing[];
31+ start: number;
32+ limit: number;
33+ size: number;
34+ total: number;
35+}
36+
37+export interface Directory {
38+ [hash: string]: Listing;
39+}
40+
41+export interface PostOption {
42+ post: Post;
43+ key: string;
44+}
45+
46+export interface PostOptionsForm {
47+ options: string[];
48+}
49+
50+export interface Tags {
51+ [key: string]: number;
52+}
ui/src/utils.tsnew file+196
@@ -0,0 +1,196 @@
1+import { stringToTa, uxToHex } from "@urbit/api";
2+import { parseToRgba } from "color2k";
3+import { isValidPatp } from "urbit-ob";
4+
5+export function encodeLookup(value: string | undefined) {
6+ if (!value) {
7+ return '';
8+ }
9+
10+ return stringToTa(value).replace('~.', '~~');
11+}
12+
13+export function isColor(color: string): boolean {
14+ try {
15+ parseToRgba(color);
16+ return true;
17+ } catch (error) {
18+ return false;
19+ }
20+}
21+
22+export function getColor(image: string): string | undefined {
23+ return isColor(image) ? image : undefined;
24+}
25+
26+export function getImage(image: string): string | undefined {
27+ return isColor(image) ? undefined : image;
28+}
29+
30+export function normalizeColor(color: string): string {
31+ if (color.startsWith('#')) {
32+ return color;
33+ }
34+
35+ return `#${uxToHex(color)}`
36+}
37+
38+export function normalizeLink(link: string): string {
39+ // ref or URL format
40+ if (!link.startsWith('web+urbitgraph://') || link.startsWith('http')) {
41+ return link;
42+ }
43+
44+ // old format
45+ const normLink = link.replace('web+urbitgraph://', '');
46+ const parts = normLink.split('/');
47+ const first = parts[0];
48+
49+ if (first !== 'group') {
50+ return `/1/desk/${normLink}`;
51+ }
52+
53+ if (parts.length === 3) {
54+ return `/1/group/${parts[1]}/${parts[2]}`;
55+ }
56+
57+ return `/1/chan/diary/${parts[4]}/${parts[5]}/note/${parts[6]}`
58+}
59+
60+// Tlon web routes (tlon-apps packages/app/navigation/linking.ts):
61+// /apps/groups/group/:groupId[/channel/:channelId], ids URI-encoded.
62+export function groupURL(flag: string): string {
63+ return `/apps/groups/group/${encodeURIComponent(flag)}`;
64+}
65+
66+export function channelURL(flag: string, nest: string): string {
67+ return `${groupURL(flag)}/channel/${encodeURIComponent(nest)}`;
68+}
69+
70+export function refToURL(cite: string): string | { nest: string, where: string } {
71+ // plain web links (e.g. manual listings) are used as they are
72+ if (/^https?:\/\//i.test(cite)) {
73+ return cite;
74+ }
75+
76+ const parts = cite.slice(1).split('/');
77+ if (parts[0] !== '1') {
78+ return '';
79+ }
80+
81+ const type = parts[1];
82+ if (type === 'desk') {
83+ const ship = parts[2];
84+ const desk = parts[3];
85+ return `/apps/landscape/search/${ship}/apps/${ship}/${desk}`;
86+ }
87+
88+ if (type === 'group') {
89+ const ship = parts[2];
90+ const name = parts[3];
91+ return groupURL(`${ship}/${name}`);
92+ }
93+
94+ const chanType = parts[2];
95+ const ship = parts[3];
96+ const name = parts[4];
97+ return {
98+ nest: `${chanType}/${ship}/${name}`,
99+ where: parts.slice(5).join('/'),
100+ }
101+}
102+
103+// a number as Hoon prints @ud: `slav %ud` reads 1.000 but not 1000
104+// (@urbit/api's decToUd turns 0 into '')
105+export function formatUd(n: number): string {
106+ return String(n).replace(/\B(?=(\d{3})+$)/g, '.');
107+}
108+
109+const encoder = new TextEncoder();
110+
111+// lib/sphinx +lengths-valid limits, in UTF-8 bytes
112+export const MAX_TITLE_BYTES = 77;
113+export const MAX_DESCRIPTION_BYTES = 256;
114+export const MAX_URL_BYTES = 1024;
115+export const MAX_TAGS = 8;
116+// the longest tag +catalog indexes
117+export const MAX_TAG_BYTES = 64;
118+
119+export function byteLength(text: string): number {
120+ return encoder.encode(text).length;
121+}
122+
123+// lib/validate-url (de-purl:html in zuse) as regular expressions: an optional
124+// scheme://host[:port] (host a DNS name or IPv4, or a ~ship without a port),
125+// then an optional /path and ?key=value&key=value query. No #fragment, no
126+// spaces or non-ASCII, none of | [ ] { } ^ ` \ and no '=' inside a value.
127+// %sphinx silently drops a listing whose image or link fails this.
128+const QUERY_CHAR = "(?:[A-Za-z0-9_.!~*'()+/?:,-]|%[0-9A-Fa-f]{2})";
129+const PATH_CHAR = "(?:[A-Za-z0-9_.!~*'()$&+,;=:@/-]|%[0-9A-Fa-f]{2})";
130+const PAIR = `${QUERY_CHAR}+(?:=${QUERY_CHAR}*)?`;
131+const PATH_QUERY = `(?:/${PATH_CHAR}*)?(?:[?](?:${PAIR}(?:[&;]${PAIR})*)?)?`;
132+const SCHEME = '[A-Za-z][A-Za-z0-9+.-]*://';
133+const LABEL = '[A-Za-z0-9](?:[A-Za-z0-9-]*[A-Za-z0-9])?';
134+const LAST_LABEL = '[A-Za-z](?:[A-Za-z0-9-]*[A-Za-z0-9])?';
135+const OCTET = '(?:0|[1-9][0-9]{0,2})';
136+const HOST = `(?:(?:${LABEL}[.])*${LAST_LABEL}|${OCTET}(?:[.]${OCTET}){3})(?::(?:0|[1-9][0-9]*))?`;
137+// the shape of a @p; isListingLink checks the syllables with isValidPatp
138+const SHIP = '~[a-z]{3}(?:[a-z]{3})?(?:--?[a-z]{6})*';
139+const IMAGE_RE = new RegExp(`^${SCHEME}${HOST}${PATH_QUERY}$`);
140+const LINK_RE = new RegExp(`^(?:${SCHEME}(?:${HOST}|(${SHIP})))?${PATH_QUERY}$`);
141+
142+export function isListingImage(image: string): boolean {
143+ return !image || (byteLength(image) <= MAX_URL_BYTES && IMAGE_RE.test(image));
144+}
145+
146+export function isListingLink(link: string): boolean {
147+ if (byteLength(link) > MAX_URL_BYTES) {
148+ return false;
149+ }
150+
151+ const match = LINK_RE.exec(link);
152+ return !!match && (!match[1] || isValidPatp(match[1]));
153+}
154+
155+// A listing image %sphinx accepts, or '' (so the listing goes out without
156+// one): http(s) URLs are percent-encoded by URL and lose their #fragment;
157+// anything else, data: URIs included (docket images may be one), is dropped.
158+export function listingImage(image: string | null | undefined): string {
159+ if (!image) {
160+ return '';
161+ }
162+
163+ try {
164+ const url = new URL(image);
165+ if (url.protocol !== 'http:' && url.protocol !== 'https:') {
166+ return '';
167+ }
168+
169+ url.hash = '';
170+ return isListingImage(url.href) ? url.href : '';
171+ } catch (e) {
172+ return '';
173+ }
174+}
175+
176+// %sphinx measures listing fields in UTF-8 bytes (lib/sphinx +lengths-valid)
177+// and silently drops listings that are too long, so cut text to at most `max`
178+// bytes on a code point boundary, marking the cut with an ellipsis.
179+export function truncateBytes(text: string, max: number): string {
180+ if (encoder.encode(text).length <= max) {
181+ return text;
182+ }
183+
184+ const ellipsis = '...';
185+ let out = '';
186+ let size = 0;
187+ for (const char of text) {
188+ size += encoder.encode(char).length;
189+ if (size > max - ellipsis.length) {
190+ break;
191+ }
192+ out += char;
193+ }
194+
195+ return `${out.trimEnd()}${ellipsis}`;
196+}
ui/src/vite-env.d.tsnew file+1
@@ -0,0 +1 @@
1+/// <reference types="vite/client" />
ui/src/window.tsnew file+8
@@ -0,0 +1,8 @@
1+declare global {
2+ interface Window {
3+ ship: string;
4+ desk: string;
5+ }
6+}
7+
8+export {};
ui/tailwind.config.jsnew file+19
@@ -0,0 +1,19 @@
1+/** @type {import('tailwindcss').Config} */
2+module.exports = {
3+ content: ['./index.html', './src/**/*.{js,ts,jsx,tsx}'],
4+ theme: {
5+ extend: {
6+ colors: {
7+ linen: '#FAEDE3',
8+ fawn: '#E7AB79',
9+ rosy: '#B25068',
10+ lavender: '#774360',
11+ mauve: '#4C3A51'
12+ }
13+ }
14+ },
15+ screens: {},
16+ plugins: [
17+ require('tailwindcss-labeled-groups')(['1', '2', '3'])
18+ ]
19+};
ui/tsconfig.jsonnew file+19
@@ -0,0 +1,19 @@
1+{
2+ "compilerOptions": {
3+ "target": "ESNext",
4+ "lib": ["DOM", "DOM.Iterable", "ESNext"],
5+ "allowJs": true,
6+ "skipLibCheck": false,
7+ "esModuleInterop": false,
8+ "allowSyntheticDefaultImports": true,
9+ "strict": true,
10+ "forceConsistentCasingInFileNames": true,
11+ "module": "ESNext",
12+ "moduleResolution": "Node",
13+ "resolveJsonModule": true,
14+ "isolatedModules": true,
15+ "noEmit": true,
16+ "jsx": "react"
17+ },
18+ "include": ["./src"]
19+}
ui/vite.config.tsnew file+20
@@ -0,0 +1,20 @@
1+import { loadEnv, defineConfig } from 'vite';
2+import reactRefresh from '@vitejs/plugin-react-refresh';
3+import { urbitPlugin } from '@urbit/vite-plugin-urbit';
4+
5+// https://vitejs.dev/config/
6+export default ({ mode }) => {
7+ Object.assign(process.env, loadEnv(mode, process.cwd()));
8+ const SHIP_URL = process.env.SHIP_URL || process.env.VITE_SHIP_URL || 'http://localhost:8080';
9+ console.log(SHIP_URL);
10+
11+ return defineConfig({
12+ plugins: [urbitPlugin({ base: 'sphinx', target: SHIP_URL, changeOrigin: true, secure: false }), reactRefresh()],
13+ // The entry chunk has no import or export, so esbuild 0.14 minifies it as
14+ // a sloppy-mode script and hoists the block-level functions in
15+ // @radix-ui/react-focus-scope and react-use-body-pointer-events in random
16+ // order: rebuilds would give a different bundle and glob hash. Browsers
17+ // run the bundle as a module, which is strict anyway.
18+ build: { rollupOptions: { output: { banner: '"use strict";' } } }
19+ });
20+};