├── .gitignore
├── public
├── favicon.ico
├── favicon-16x16.png
├── favicon-32x32.png
├── apple-touch-icon.png
├── playground
│ ├── janet.wasm
│ ├── jdocs_playground.js
│ └── playground.js
├── android-chrome-192x192.png
├── android-chrome-512x512.png
├── site.webmanifest
├── app.css
├── css
│ ├── atom-one-dark.css
│ └── atom-one-light.css
├── _app.js
├── _pylon.css
├── ace
│ └── mode-clojure.js
├── _water.css
├── _highlight.pack.js
└── alpine.min.js
├── Procfile
├── db
├── migrations
│ ├── 20200515161430-add-login-to-account.sql
│ ├── 20201209174006-create-table-link.sql
│ ├── 20200512174722-create-table-account.sql
│ ├── 20200512175404-create-table-package.sql
│ ├── 20200512175708-create-table-binding.sql
│ └── 20200512175731-create-table-example.sql
├── sql
│ ├── random.sql
│ └── search.sql
└── schema.sql
├── routes
├── sessions.janet
├── bindings.janet
├── playground.janet
├── home.janet
└── examples.janet
├── docker-compose.yml
├── .env.sample
├── console.janet
├── test
└── server-test.janet
├── project.janet
├── Dockerfile
├── post-receive-hook
├── main.janet
├── LICENSE
├── nginx.conf
├── README.md
├── seed.janet
└── helpers.janet
/.gitignore:
--------------------------------------------------------------------------------
1 | build
2 | /.env
3 | *.sqlite3
4 |
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/swlkr/janetdocs/HEAD/public/favicon.ico
--------------------------------------------------------------------------------
/Procfile:
--------------------------------------------------------------------------------
1 | web: janet main.janet
2 | release: cd /var/app && joy migrate
3 | seed: janet seed.janet
4 |
--------------------------------------------------------------------------------
/public/favicon-16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/swlkr/janetdocs/HEAD/public/favicon-16x16.png
--------------------------------------------------------------------------------
/public/favicon-32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/swlkr/janetdocs/HEAD/public/favicon-32x32.png
--------------------------------------------------------------------------------
/public/apple-touch-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/swlkr/janetdocs/HEAD/public/apple-touch-icon.png
--------------------------------------------------------------------------------
/public/playground/janet.wasm:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/swlkr/janetdocs/HEAD/public/playground/janet.wasm
--------------------------------------------------------------------------------
/public/android-chrome-192x192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/swlkr/janetdocs/HEAD/public/android-chrome-192x192.png
--------------------------------------------------------------------------------
/public/android-chrome-512x512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/swlkr/janetdocs/HEAD/public/android-chrome-512x512.png
--------------------------------------------------------------------------------
/db/migrations/20200515161430-add-login-to-account.sql:
--------------------------------------------------------------------------------
1 | -- up
2 | alter table account add login text not null default ''
3 |
4 | -- down
5 |
--------------------------------------------------------------------------------
/routes/sessions.janet:
--------------------------------------------------------------------------------
1 | (use joy)
2 |
3 |
4 | (defn destroy [request]
5 | (-> (redirect-to :home/index)
6 | (put :session @{})))
7 |
--------------------------------------------------------------------------------
/db/sql/random.sql:
--------------------------------------------------------------------------------
1 | select
2 | *
3 | from
4 | binding
5 | where
6 | binding.id = (abs(random()) % (select (select max(binding.id) from binding) + 1))
7 |
--------------------------------------------------------------------------------
/docker-compose.yml:
--------------------------------------------------------------------------------
1 | version: '3'
2 | services:
3 | web:
4 | tty: true
5 | env_file: .env
6 | volumes:
7 | - .:/var/app
8 | image: janetdocs
9 | ports:
10 | - "9003:9003"
11 |
--------------------------------------------------------------------------------
/.env.sample:
--------------------------------------------------------------------------------
1 | DATABASE_URL=janetdocs.sqlite3
2 | ENCRYPTION_KEY=2af90dc50f5f09a15b30c463042d4e27f63382382a4e04e073b985b5d0779366
3 | JOY_ENV=development
4 | PORT=9001
5 | GITHUB_CLIENT_ID=123456
6 | GITHUB_CLIENT_SECRET=654321
7 |
--------------------------------------------------------------------------------
/console.janet:
--------------------------------------------------------------------------------
1 | (use joy)
2 |
3 | (import dotenv)
4 | (dotenv/load)
5 |
6 | (db/connect (env :database-url))
7 |
8 | (repl nil
9 | (fn [_ y] (printf "%Q" y))
10 | (fiber/getenv (fiber/current)))
11 |
12 | (db/disconnect)
13 |
--------------------------------------------------------------------------------
/test/server-test.janet:
--------------------------------------------------------------------------------
1 | (import tester :prefix "" :exit true)
2 | (import "../main" :prefix "")
3 |
4 | (deftest
5 | (test "test the app"
6 | (= 200
7 | (let [response (app {:uri "/" :method :get})]
8 | (get response :status)))))
9 |
--------------------------------------------------------------------------------
/db/migrations/20201209174006-create-table-link.sql:
--------------------------------------------------------------------------------
1 |
2 | -- up
3 | CREATE TABLE link (
4 | source integer not null references binding(id),
5 | target integer not null references binding(id),
6 | PRIMARY KEY (source, target)
7 | );
8 |
9 | -- down
10 | DROP TABLE link;
11 |
--------------------------------------------------------------------------------
/public/site.webmanifest:
--------------------------------------------------------------------------------
1 | {"name":"","short_name":"","icons":[{"src":"/android-chrome-192x192.png","sizes":"192x192","type":"image/png"},{"src":"/android-chrome-512x512.png","sizes":"512x512","type":"image/png"}],"theme_color":"#ffffff","background_color":"#ffffff","display":"standalone"}
--------------------------------------------------------------------------------
/db/migrations/20200512174722-create-table-account.sql:
--------------------------------------------------------------------------------
1 | -- up
2 | create table account (
3 | id integer primary key,
4 | email text,
5 | access_token text not null,
6 | created_at integer not null default(strftime('%s', 'now')),
7 | updated_at integer
8 | )
9 |
10 | -- down
11 | drop table account
--------------------------------------------------------------------------------
/db/migrations/20200512175404-create-table-package.sql:
--------------------------------------------------------------------------------
1 | -- up
2 | create table package (
3 | id integer primary key,
4 | name text not null,
5 | url text not null,
6 | created_at integer not null default(strftime('%s', 'now')),
7 | updated_at integer
8 | )
9 |
10 | -- down
11 | drop table package
--------------------------------------------------------------------------------
/db/migrations/20200512175708-create-table-binding.sql:
--------------------------------------------------------------------------------
1 | -- up
2 | create table binding (
3 | id integer primary key,
4 | name text not null,
5 | docstring text,
6 | package_id integer references package(id),
7 | created_at integer not null default(strftime('%s', 'now')),
8 | updated_at integer
9 | )
10 |
11 | -- down
12 | drop table binding
13 |
--------------------------------------------------------------------------------
/db/migrations/20200512175731-create-table-example.sql:
--------------------------------------------------------------------------------
1 | -- up
2 | create table example (
3 | id integer primary key,
4 | body text not null,
5 | binding_id integer not null references binding(id),
6 | account_id integer not null references account(id),
7 | created_at integer not null default(strftime('%s', 'now')),
8 | updated_at integer
9 | )
10 |
11 | -- down
12 | drop table example
13 |
--------------------------------------------------------------------------------
/db/sql/search.sql:
--------------------------------------------------------------------------------
1 | select
2 | binding.id,
3 | binding.name,
4 | binding.docstring,
5 | binding.package_id,
6 | package.name as package,
7 | count(example.id) as examples
8 | from
9 | binding
10 | left outer join
11 | package on binding.package_id = package.id
12 | left outer join
13 | example on example.binding_id = binding.id
14 | where
15 | binding.name like ?
16 | group by
17 | binding.id
18 |
--------------------------------------------------------------------------------
/routes/bindings.janet:
--------------------------------------------------------------------------------
1 | (import joy :prefix "")
2 | (import ../helpers :prefix "")
3 | (import ./examples)
4 | (import uri)
5 |
6 |
7 | (defn show [request]
8 | (when-let [[name] (request :wildcard)
9 | name (uri/unescape name)
10 | name (string/replace "_q" "?" name)
11 | binding (first (db/query (slurp "db/sql/search.sql") [name]))]
12 |
13 | [:vstack {:spacing "m"}
14 | (binding-header binding)
15 | (examples/index (merge request {:binding binding}))]))
16 |
--------------------------------------------------------------------------------
/project.janet:
--------------------------------------------------------------------------------
1 | (declare-project
2 | :name "janetdocs"
3 | :description "JanetDocs is a community documentation site for the Janet programming language"
4 | :dependencies ["https://github.com/janet-lang/sqlite3"
5 | "https://github.com/joy-framework/dotenv"
6 | "https://github.com/joy-framework/http"
7 | "https://github.com/joy-framework/joy"]
8 |
9 | :author "Sean Walker"
10 | :license "MIT"
11 | :url "https://janetdocs.com"
12 | :repo "https://github.com/swlkr/janetdocs")
13 |
14 | (declare-executable
15 | :name "janetdocs"
16 | :entry "main.janet")
17 |
18 | (phony "server" []
19 | (os/shell "janet main.janet"))
20 |
21 | (phony "watch" []
22 | (os/shell "find . -name '*.janet' | entr -r -d janet main.janet"))
23 |
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM alpine:3.7
2 |
3 | RUN apk add --no-cache build-base curl curl-dev git
4 |
5 | # Create a non-root user to run the app as
6 | ARG USER=app
7 | ARG GROUP=app
8 | ARG UID=1101
9 | ARG GID=1101
10 |
11 | RUN addgroup -g $GID -S $GROUP
12 | RUN adduser -u $UID -S $USER -G $GROUP
13 |
14 | # Move to tmp and install janet
15 | RUN git clone https://github.com/janet-lang/janet.git /tmp/janet && \
16 | cd /tmp/janet && \
17 | make all test install
18 |
19 | RUN chmod 777 /usr/local/lib/janet
20 |
21 | # Use jpm to install joy
22 | RUN jpm install joy
23 |
24 | RUN chown -R $USER:$GROUP /usr/local/lib/janet
25 |
26 | # Create a place to mount or copy in your server
27 | RUN mkdir -p /var/app
28 | RUN chown -R $USER:$GROUP /var/app
29 |
30 | USER $USER
31 | WORKDIR /var/app
32 | COPY . ./
33 |
34 | ARG DEPS=false
35 | USER root
36 | RUN jpm deps
37 | USER $USER
38 |
39 | EXPOSE 9003
40 |
41 | CMD ["janet", "main.janet"]
42 |
--------------------------------------------------------------------------------
/post-receive-hook:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | app="janetdocs"
4 | working_tree="/home/sean/$app"
5 | port="9002"
6 |
7 | while read oldrev newrev ref
8 | do
9 | echo "Master ref received. Deploying master branch to production..."
10 |
11 | echo "Shutting down server..."
12 | pkill -f '$app'
13 |
14 | echo "Cloning new files"
15 | git --work-tree=$working_tree --git-dir=/home/sean/$app.git checkout -f
16 | cd $working_tree
17 |
18 | echo "Migrating database"
19 | DATABASE_URL=/home/sean/$app/$app-production.sqlite3 joy migrate
20 |
21 | # echo "Running jpm deps"
22 | # jpm deps
23 |
24 | echo "Starting server..."
25 | bash -c "exec -a $app janet main.janet $port &> app.log &"
26 |
27 | echo " /==============================="
28 | echo " | DEPLOYMENT COMPLETED"
29 | echo " | Target branch: master"
30 | echo " | Target folder: $working_tree"
31 | echo " \=============================="
32 |
33 | done
34 |
35 | exit 0
--------------------------------------------------------------------------------
/main.janet:
--------------------------------------------------------------------------------
1 | (import joy :prefix "")
2 | (import ./helpers :prefix "")
3 |
4 |
5 | (defroutes routes
6 | [:get "/" :home/index]
7 | [:delete "/sessions" :sessions/destroy]
8 | [:get "/github-auth" :home/github-auth]
9 | [:post "/searches" :home/searches]
10 | [:get "/bindings/random" :examples/random]
11 | [:get "/bindings/:binding-id/examples/form" :examples/form]
12 | [:get "/bindings/:binding-id/examples/new" :examples/new]
13 | [:post "/bindings/:binding-id/examples" :examples/create]
14 | [:get "/examples/:id/edit" :examples/edit]
15 | [:patch "/examples/:id" :examples/patch]
16 | [:delete "/examples/:id" :examples/destroy]
17 | [:get "/export.json" :examples/export]
18 | [:get "/playground/example/:id" :playground/example]
19 | [:get "/playground" :playground/home]
20 | [:get "/*" :bindings/show])
21 |
22 |
23 | (def app (app {:routes routes
24 | :layout layout
25 | :404 /404}))
26 |
27 |
28 | (defn main [& args]
29 | (db/connect (env :database-url))
30 | (server app (env :port) "0.0.0.0")
31 | (db/disconnect))
32 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 Sean Walker
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/db/schema.sql:
--------------------------------------------------------------------------------
1 | CREATE TABLE schema_migrations (version text primary key);
2 | CREATE TABLE account (
3 | id integer primary key,
4 | email text,
5 | access_token text not null,
6 | created_at integer not null default(strftime('%s', 'now')),
7 | updated_at integer
8 | , login text not null default '');
9 | CREATE TABLE package (
10 | id integer primary key,
11 | name text not null,
12 | url text not null,
13 | created_at integer not null default(strftime('%s', 'now')),
14 | updated_at integer
15 | );
16 | CREATE TABLE binding (
17 | id integer primary key,
18 | name text not null,
19 | docstring text,
20 | package_id integer references package(id),
21 | created_at integer not null default(strftime('%s', 'now')),
22 | updated_at integer
23 | );
24 | CREATE TABLE example (
25 | id integer primary key,
26 | body text not null,
27 | binding_id integer not null references binding(id),
28 | account_id integer not null references account(id),
29 | created_at integer not null default(strftime('%s', 'now')),
30 | updated_at integer
31 | );
32 | CREATE TABLE link (
33 | source integer not null references binding(id),
34 | target integer not null references binding(id),
35 | PRIMARY KEY (source, target)
36 | );
37 |
--------------------------------------------------------------------------------
/nginx.conf:
--------------------------------------------------------------------------------
1 | upstream janetdocs {
2 | server 127.0.0.1:9001;
3 | }
4 |
5 | server {
6 |
7 | server_name janetdocs.joyapps.xyz;
8 |
9 | access_log /var/log/nginx/janetdocs-access.log;
10 | error_log /var/log/nginx/janetdocs-error.log;
11 |
12 | keepalive_timeout 70;
13 |
14 | location / {
15 | gzip on;
16 | gzip_min_length 1100;
17 | gzip_buffers 4 32k;
18 | gzip_types text/css text/javascript text/xml text/plain text/x-component application/javascript application/x-javascript application/json application/xml application/rss+xml font/truetype application/x-font-ttf font/opentype application/vnd.ms-fontobject image/svg+xml;
19 | gzip_vary on;
20 | gzip_comp_level 6;
21 |
22 | proxy_pass http://janetdocs;
23 | proxy_http_version 1.1;
24 | proxy_set_header Upgrade $http_upgrade;
25 | proxy_set_header Connection $http_connection;
26 | proxy_set_header Host $http_host;
27 | proxy_set_header X-Forwarded-Proto $scheme;
28 | proxy_set_header X-Forwarded-For $remote_addr;
29 | proxy_set_header X-Forwarded-Port $server_port;
30 | }
31 |
32 | location ~ \.(gif|jpg|png|js|css|svg|ico)$ {
33 | root /home/sean/janetdocs/public;
34 | }
35 |
36 | add_header Strict-Transport-Security "max-age=15724800; includeSubdomains" always;
37 | }
38 |
--------------------------------------------------------------------------------
/public/app.css:
--------------------------------------------------------------------------------
1 | /* app.css */
2 |
3 | html, body {
4 | height: 100%;
5 | }
6 |
7 | .md-modal {
8 | position: fixed;
9 | top: 50%;
10 | left: 50%;
11 | width: 50%;
12 | max-width: 630px;
13 | min-width: 320px;
14 | margin: 0 auto;
15 | transform: translate(-50%, -50%);
16 | z-index: 2;
17 | background-color: var(--background-body);
18 | }
19 |
20 | .md-show {
21 | visibility: visible;
22 | }
23 |
24 | .md-content {
25 | padding: 20px;
26 | transform: scale(0.5);
27 | opacity: 0;
28 | transition: all 0.3s;
29 | }
30 |
31 | .md-show .md-content {
32 | transform: scale(1);
33 | opacity: 1;
34 | }
35 |
36 | .md-overlay {
37 | position: fixed;
38 | top: 0;
39 | left: 0;
40 | width: 100%;
41 | height: 100%;
42 | z-index: 1;
43 | visibility: hidden;
44 | opacity: 0;
45 | background-color: rgba(0,0,0,0.5);
46 | transition: all 0.3s;
47 | }
48 |
49 | .md-show.md-overlay {
50 | opacity: 1;
51 | visibility: visible;
52 | }
53 |
54 |
55 | @media (max-width: 415px) {
56 | hstack[responsive] {
57 | display: block;
58 | }
59 | }
60 |
61 | h2[responsive] {
62 | font-size: 1em;
63 | }
64 |
65 | @media (min-width: 415px) {
66 | h2[responsive] {
67 | font-size: 1.5em;
68 | }
69 | }
70 |
71 | textarea {
72 | font-family: monospace;
73 | }
74 |
75 | a.see-also {
76 | margin-left: 10px;
77 | }
78 |
--------------------------------------------------------------------------------
/routes/playground.janet:
--------------------------------------------------------------------------------
1 | (import joy :prefix "")
2 | (import ../helpers :prefix "")
3 |
4 | (defn playground [request code]
5 | (def html
6 | [:vstack {:spacing "l"}
7 | [:script {:src "/ace/ace.js"}]
8 | [:hstack {:spacing "s"}
9 | [:button {:id "run" :title="ctrl-enter"} "Run"]
10 | [:button {:id "format"} "Format"]
11 | [:spacer]]
12 | [:div {:id "code" :class "hljs" :style "height:60vh;"} (raw code)]
13 | [:pre {:id "output" :style "overflow:auto;"}]
14 | [:div {:id "hiddencode" :style "display:none;"}]
15 | [:script {:type "text/javascript" :src "/playground/playground.js" :async "false"}]
16 | [:script {:type "text/javascript" :src "/playground/janet.js" :async "false"}]
17 | [:script {:type "text/javascript" :src "/playground/jdocs_playground.js" :async "false"}]])
18 |
19 | (if (xhr? request)
20 | (text/html html)
21 | html))
22 |
23 |
24 | (defn home [request]
25 | (def code ```
26 | # Enter Janet code here and click "Run" or Ctrl-Enter
27 | (print "Hello, World!")
28 | ```)
29 | (playground request code))
30 |
31 | (defn example [request]
32 | (if-let [id (get-in request [:params :id])
33 | example (db/fetch [:example (scan-number id)])
34 | code (get example :body)]
35 | (playground request (string code "\n"))
36 | (home request)))
37 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # janetdocs
2 |
3 | A community documentation site for the [janet](https://janet-lang.org) programming language
4 |
5 | ## Install janet
6 |
7 | The first step is to get janet installed.
8 |
9 | This uses [homebrew](https://brew.sh) for simplicity, but feel free to come up with whatever vagrant, docker or nixOS thing you'd like:
10 |
11 | ```sh
12 | brew install janet
13 | ```
14 |
15 | ## Get Started
16 |
17 | After janet is installed there are a few steps to get this project up and running:
18 |
19 | 1. Clone this repo
20 |
21 | ```sh
22 | git clone https://github.com/swlkr/janetdocs.git
23 | ```
24 |
25 | 2. Move `.env.sample` to `.env`
26 |
27 | ```sh
28 | cd janetdocs
29 | mv `.env.sample` `.env`
30 | ```
31 |
32 | 3. Change the github client and secret ids to something real
33 |
34 | You can create your own github oauth app or whatever it's called now to get your keys to get github sign in working
35 |
36 | 4. Install deps
37 |
38 | ```sh
39 | # make sure you're in the janetdocs directory
40 | jpm deps
41 | ```
42 |
43 | 5. Migrate the database
44 |
45 | ```sh
46 | # make sure you're in the janetdocs directory
47 | joy migrate
48 | ```
49 |
50 | 6. Seed the database with the docs
51 |
52 | ```sh
53 | # make sure you're in the janetdocs directory
54 | janet seed.janet
55 | ```
56 |
57 | And that's it! You should be able to poke around at this point and see what's going on, by default the server starts on port 9001:
58 |
59 | ```sh
60 | # make sure you're in the janetdocs directory
61 | janet main.janet
62 | ```
63 |
--------------------------------------------------------------------------------
/public/css/atom-one-dark.css:
--------------------------------------------------------------------------------
1 | /*
2 |
3 | Atom One Dark by Daniel Gamage
4 | Original One Dark Syntax theme from https://github.com/atom/one-dark-syntax
5 |
6 | base: #282c34
7 | mono-1: #abb2bf
8 | mono-2: #818896
9 | mono-3: #5c6370
10 | hue-1: #56b6c2
11 | hue-2: #61aeee
12 | hue-3: #c678dd
13 | hue-4: #98c379
14 | hue-5: #e06c75
15 | hue-5-2: #be5046
16 | hue-6: #d19a66
17 | hue-6-2: #e6c07b
18 |
19 | */
20 |
21 | .hljs {
22 | display: block;
23 | overflow-x: auto;
24 | padding: 0.5em;
25 | color: #abb2bf;
26 | background: #282c34;
27 | }
28 |
29 | .hljs-comment,
30 | .hljs-quote {
31 | color: #5c6370;
32 | font-style: italic;
33 | }
34 |
35 | .hljs-doctag,
36 | .hljs-keyword,
37 | .hljs-formula {
38 | color: #c678dd;
39 | }
40 |
41 | .hljs-section,
42 | .hljs-name,
43 | .hljs-selector-tag,
44 | .hljs-deletion,
45 | .hljs-subst {
46 | color: #e06c75;
47 | }
48 |
49 | .hljs-literal {
50 | color: #56b6c2;
51 | }
52 |
53 | .hljs-string,
54 | .hljs-regexp,
55 | .hljs-addition,
56 | .hljs-attribute,
57 | .hljs-meta-string {
58 | color: #98c379;
59 | }
60 |
61 | .hljs-built_in,
62 | .hljs-class .hljs-title {
63 | color: #e6c07b;
64 | }
65 |
66 | .hljs-attr,
67 | .hljs-variable,
68 | .hljs-template-variable,
69 | .hljs-type,
70 | .hljs-selector-class,
71 | .hljs-selector-attr,
72 | .hljs-selector-pseudo,
73 | .hljs-number {
74 | color: #d19a66;
75 | }
76 |
77 | .hljs-symbol,
78 | .hljs-bullet,
79 | .hljs-link,
80 | .hljs-meta,
81 | .hljs-selector-id,
82 | .hljs-title {
83 | color: #61aeee;
84 | }
85 |
86 | .hljs-emphasis {
87 | font-style: italic;
88 | }
89 |
90 | .hljs-strong {
91 | font-weight: bold;
92 | }
93 |
94 | .hljs-link {
95 | text-decoration: underline;
96 | }
97 |
--------------------------------------------------------------------------------
/public/css/atom-one-light.css:
--------------------------------------------------------------------------------
1 | /*
2 |
3 | Atom One Light by Daniel Gamage
4 | Original One Light Syntax theme from https://github.com/atom/one-light-syntax
5 |
6 | base: #fafafa
7 | mono-1: #383a42
8 | mono-2: #686b77
9 | mono-3: #a0a1a7
10 | hue-1: #0184bb
11 | hue-2: #4078f2
12 | hue-3: #a626a4
13 | hue-4: #50a14f
14 | hue-5: #e45649
15 | hue-5-2: #c91243
16 | hue-6: #986801
17 | hue-6-2: #c18401
18 |
19 | */
20 |
21 | .hljs {
22 | display: block;
23 | overflow-x: auto;
24 | padding: 0.5em;
25 | color: #383a42;
26 | background: #fafafa;
27 | }
28 |
29 | .hljs-comment,
30 | .hljs-quote {
31 | color: #a0a1a7;
32 | font-style: italic;
33 | }
34 |
35 | .hljs-doctag,
36 | .hljs-keyword,
37 | .hljs-formula {
38 | color: #a626a4;
39 | }
40 |
41 | .hljs-section,
42 | .hljs-name,
43 | .hljs-selector-tag,
44 | .hljs-deletion,
45 | .hljs-subst {
46 | color: #e45649;
47 | }
48 |
49 | .hljs-literal {
50 | color: #0184bb;
51 | }
52 |
53 | .hljs-string,
54 | .hljs-regexp,
55 | .hljs-addition,
56 | .hljs-attribute,
57 | .hljs-meta-string {
58 | color: #50a14f;
59 | }
60 |
61 | .hljs-built_in,
62 | .hljs-class .hljs-title {
63 | color: #c18401;
64 | }
65 |
66 | .hljs-attr,
67 | .hljs-variable,
68 | .hljs-template-variable,
69 | .hljs-type,
70 | .hljs-selector-class,
71 | .hljs-selector-attr,
72 | .hljs-selector-pseudo,
73 | .hljs-number {
74 | color: #986801;
75 | }
76 |
77 | .hljs-symbol,
78 | .hljs-bullet,
79 | .hljs-link,
80 | .hljs-meta,
81 | .hljs-selector-id,
82 | .hljs-title {
83 | color: #4078f2;
84 | }
85 |
86 | .hljs-emphasis {
87 | font-style: italic;
88 | }
89 |
90 | .hljs-strong {
91 | font-weight: bold;
92 | }
93 |
94 | .hljs-link {
95 | text-decoration: underline;
96 | }
97 |
--------------------------------------------------------------------------------
/public/playground/jdocs_playground.js:
--------------------------------------------------------------------------------
1 | window.addEventListener("load", function (ev) {
2 |
3 | window.editor = ace.edit("code");
4 | window.editor.session.setMode("ace/mode/clojure");
5 | window.editor.session.setOptions({
6 | tabSize: 2,
7 | useSoftTabs: true,
8 | });
9 | editor.commands.addCommand({
10 | name: 'run',
11 | bindKey: {win: 'Ctrl-Enter', mac: 'Ctrl-Enter'},
12 | exec: function(editor) {
13 | window.doRunCode();
14 | },
15 | readOnly: true // false if this command should not apply in readOnly mode
16 | });
17 |
18 | function doRunCode() {
19 | let outputEl = document.querySelector('#output');
20 | let code = window.editor.getValue();
21 | outputEl.innerHTML = "running...";
22 | setTimeout(function() {window.run_janet_code(code, outputEl)}, 100);
23 | }
24 |
25 | function doFormatCode() {
26 | let userCode = window.editor.getValue();
27 | let code = "(import ./spork);" + "\n(def usercode ``````````" + userCode + "``````````) (spork/fmt/format-print usercode)";
28 | let result = window.run_janet_for_output(code);
29 | const suffix = 'RESULT> nil\n';
30 | if (!result.endsWith(suffix)) {
31 | alert("format failed: " + result);
32 | } else {
33 | let formattedCode = result.slice(0,-suffix.length);
34 | window.editor.setValue(formattedCode);
35 | }
36 | }
37 |
38 | document.querySelector("#run").addEventListener("click", function (e) {
39 | doRunCode();
40 | });
41 |
42 | document.querySelector("#format").addEventListener("click", function (e) {
43 | doFormatCode();
44 | });
45 |
46 | window.doRunCode = doRunCode;
47 | });
48 |
49 |
--------------------------------------------------------------------------------
/public/_app.js:
--------------------------------------------------------------------------------
1 | document.addEventListener('DOMContentLoaded', function() {
2 | document.querySelectorAll('pre code').forEach((block) => {
3 | hljs.highlightBlock(block);
4 | });
5 |
6 | setTimeout(function() {
7 | var params = new URLSearchParams(window.location.search)
8 | if(params.get('new') === '') {
9 | const ev = new Event('mouseenter');
10 | document.getElementById('add-example').dispatchEvent(ev);
11 |
12 | const ev1 = new Event('click');
13 | document.getElementById('add-example').dispatchEvent(ev1);
14 | }
15 | }, 10);
16 | });
17 |
18 | function highlight() {
19 | document.querySelectorAll('pre code').forEach((block) => {
20 | hljs.highlightBlock(block);
21 | });
22 | }
23 |
24 | function api(url, options) {
25 | var options = options || {};
26 | options.headers = options.headers || {};
27 | if(options.method.toLowerCase() !== 'get') {
28 | options['headers']['x-csrf-token'] = document.querySelector('meta[name="csrf-token"]').content;
29 | }
30 | options['headers']['x-requested-with'] = 'XMLHttpRequest'
31 |
32 | return fetch(url, options);
33 | }
34 |
35 |
36 | async function get(url, contentType) {
37 | var options = {
38 | method: 'get',
39 | headers: {
40 | 'content-type': 'application/json'
41 | }
42 | };
43 |
44 | var response = await api(url, options);
45 | if(contentType === "text/html") {
46 | return await response.text();
47 | } else {
48 | return await response.json();
49 | }
50 | }
51 |
52 |
53 | async function post(url, body, contentType) {
54 | var options = {
55 | method: 'post',
56 | headers: {
57 | 'content-type': 'application/json'
58 | },
59 | body: JSON.stringify(body)
60 | };
61 |
62 | var response = await api(url, options);
63 | if(contentType === "text/html") {
64 | return await response.text();
65 | } else {
66 | return await response.json();
67 | }
68 | }
69 |
70 |
71 | function searcher(url) {
72 | return {
73 | token: '',
74 | results: '',
75 |
76 | search: async function() {
77 | var html = await post(url, { token: this.token }, "text/html");
78 | this.results = html;
79 |
80 | setTimeout(function() {
81 | document.querySelectorAll('pre > code').forEach(function(el) {
82 | hljs.highlightBlock(el);
83 | });
84 | }, 0)
85 | },
86 |
87 | go: function() {
88 | Turbolinks.visit(document.querySelectorAll('.binding')[0].getAttribute('href'))
89 | }
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/public/_pylon.css:
--------------------------------------------------------------------------------
1 | /* pylon.css */
2 |
3 | hstack{display:flex;align-self:stretch;align-items:center;flex-direction:row}hstack[spacing=xl]>*{margin-right:40px}hstack[spacing=l]>*{margin-right:28px}hstack[spacing=m]>*{margin-right:20px}hstack[spacing=s]>*{margin-right:15px}hstack[spacing=xs]>*{margin-right:10px}hstack[spacing=xxs]>*{margin-right:6px}hstack[spacing]>:last-child{margin-right:0}hstack[align-y=top]{align-items:flex-start}hstack[align-y=center]{align-items:center}hstack[align-y=bottom]{align-items:flex-end}hstack[align-x=left]{justify-content:flex-start}hstack[align-x=center]{justify-content:center}hstack[align-x=right]{justify-content:flex-end}vstack{display:flex;align-self:stretch;flex-direction:column}vstack[spacing=xl]>*{margin-bottom:40px}vstack[spacing=l]>*{margin-bottom:28px}vstack[spacing=m]>*{margin-bottom:20px}vstack[spacing=s]>*{margin-bottom:15px}vstack[spacing=xs]>*{margin-bottom:10px}vstack[spacing=xxs]>*{margin-bottom:6px}vstack[spacing]>:last-child{margin-bottom:0}vstack[align-x=left]{align-items:flex-start}vstack[align-x=center]{align-items:center}vstack[align-x=right]{align-items:flex-end}vstack[align-y=top]{justify-content:flex-start}vstack[align-y=center]{justify-content:center}vstack[align-y=bottom]{justify-content:flex-end}list{display:flex;align-self:stretch;flex:1 1 auto;flex-direction:column}list>*{border-bottom:1px solid #d9ddde}list>*,list vstack{margin:0}list>:last-child{border-bottom:none}list[spacing=xl]>*{padding:40px 0}list[spacing=l]>*{padding:28px 0}list[spacing=m]>*{padding:20px 0}list[spacing=s]>*{padding:15px 0}list[spacing=xs]>*{padding:10px 0}list[spacing=xxs]>*{padding:6px 0}list[align-x=left]{align-items:flex-start}list[align-x=center]{align-items:center}list[align-x=right]{align-items:flex-end}list[align-y=top]{justify-content:flex-start}list[align-y=center]{justify-content:center}list[align-y=bottom]{justify-content:flex-end}spacer{flex:1}divider{background-color:#d9ddde;align-self:stretch}vstack>divider{margin:10px 0;height:1px}vstack[spacing]>divider{margin-top:0}hstack>divider{margin:0 10px;width:1px}hstack[spacing]>divider{margin-left:0}divider+list{margin-top:calc(-1*10px)}text{line-height:auto}text[font=title]{font-size:24px;font-weight:600}text[font=caption]{color:#999;font-size:13px}text[bold]{font-weight:700}text[underline=true],text[underline]{text-decoration:underline}text[underline=false]{text-decoration:none}view{display:flex;height:100%}.pylon{height:100%;padding:0;margin:0}[debug] *{outline:1px solid #009ddc!important}[stretch]{align-self:stretch;flex:1 1 auto}vstack[stretch]{height:100%}
4 |
--------------------------------------------------------------------------------
/public/playground/playground.js:
--------------------------------------------------------------------------------
1 | (function() {
2 | function htmlEscape(text) {
3 | //text = ansi_up.ansi_to_html(text);
4 | return text
5 | .replace(/&/g, "&")
6 | .replace(//g, ">")
8 | .replace(/"/g, """)
9 | .replace(/'/g, "'")
10 | .replace(/ /g, " ")
11 | .replace('\n', '
', 'g');
12 | }
13 |
14 | function cleanContentEditableInput(text) {
15 | text = text.replace(/\u00A0/g, " ");
16 | return text;
17 | }
18 |
19 | function print(text, isErr=false) {
20 | //if (arguments.length > 1) text = Array.prototype.slice.call(arguments).join(' ');
21 | var element = window.Module.outputElement;
22 | if (typeof(element) == "string") {
23 | window.Module.outputElement += text;
24 | } else if (!element) {
25 | console.log("No output element. Tried to print: " + text);
26 | } else {
27 | if (isErr) {
28 | element.innerHTML += '' + htmlEscape(text + '\n') + '';
29 | } else {
30 | element.innerHTML += htmlEscape(text);
31 | }
32 | element.scrollTop = element.scrollHeight; // focus on bottom
33 | }
34 | }
35 |
36 | function run_janet_for_output(code) {
37 | window.Module.outputElement = "";
38 | let cleanCode = cleanContentEditableInput(code);
39 | let result = window.run_janet(cleanCode);
40 | if (result != 0) {
41 | return "ERROR: " + result + "\n" + window.Module.outputElement;
42 | } else {
43 | return window.Module.outputElement;
44 | }
45 | }
46 |
47 | function run_janet_code(code, outputElement) {
48 | outputElement.innerHTML = "";
49 | window.Module.outputElement = outputElement;
50 | let cleanCode = cleanContentEditableInput(code);
51 | let result = window.run_janet(cleanCode);
52 | if (result != 0)
53 | window.Module.printErr("ERROREXIT: " + result + "\n");
54 | }
55 |
56 | var Module = {
57 | outputElement: null,
58 | preRun: [],
59 | print: function(x) {
60 | print(x + '\n', isErr=false);
61 | },
62 | printErr: function(text) {
63 | if (arguments.length > 1) text = Array.prototype.slice.call(arguments).join(' ');
64 | print(text + "\n", isErr=true);
65 | },
66 | postRun: [function() {
67 | window.run_janet_code = run_janet_code;
68 | window.run_janet_for_output = run_janet_for_output;
69 | window.run_janet = Module.cwrap("run_janet", 'number', ['string']);
70 | }],
71 | };
72 |
73 | window.Module = Module;
74 | })();
75 |
--------------------------------------------------------------------------------
/routes/home.janet:
--------------------------------------------------------------------------------
1 | (import joy :prefix "")
2 | (import ../helpers :prefix "")
3 | (import http)
4 | (import cipher)
5 | (import json)
6 | (import ./examples)
7 |
8 |
9 | (defn index [request]
10 | (let [examples (db/from :example
11 | :join/one [:account :binding]
12 | :order "example.created_at desc"
13 | :limit 30)]
14 |
15 | [:vstack {:align-x "center" :stretch "" :spacing "l"
16 | :x-data (string/format "searcher('%s')" (url-for :home/searches))}
17 | [:h1
18 | [:span "JanetDocs is a community documentation site for the "]
19 | [:a {:href "https://janet-lang.org"} "Janet programming language"]]
20 | [:input {:type "text" :name "token" :placeholder "search docs"
21 | :autofocus ""
22 | :style "width: 100%"
23 | :x-model "token"
24 | :x-on:keyup.debounce "search()"
25 | :x-on:keydown.enter.prevent "go()"}]
26 | [:div {:x-html "results" :style "width: 100%"}
27 | "Loading..."]
28 |
29 | [:vstack {:x-show "!token || token === ''"}
30 | [:h3 "Recent examples"]
31 | (examples/list examples)]]))
32 |
33 |
34 | (defn searches [request]
35 | (let [body (request :body)
36 | token (body :token)
37 | bindings (db/query (slurp "db/sql/search.sql") [(string token "%")])]
38 | (if (blank? token)
39 | (text/html [:div])
40 | (text/html
41 | [:vstack {:spacing "xl"}
42 | (foreach [binding bindings]
43 | [:vstack {:spacing "xs"}
44 | [:a {:class "binding" :href (binding-show-url binding)}
45 | (binding :name)]
46 | [:pre
47 | [:code {:class "clojure"}
48 | (binding :docstring)]]
49 | [:hstack
50 | [:strong (string (binding :examples) " " (singularize "examples" (binding :examples)))]
51 | [:spacer]
52 | [:a {:href (binding-show-url binding "?new=")}
53 | (if (zero? (binding :examples))
54 | "Add the first example"
55 | "Add a new example")]]])]))))
56 |
57 |
58 | (defn github-auth [request]
59 | (def code (get-in request [:query-string :code]))
60 |
61 | (def result (http/post "https://github.com/login/oauth/access_token"
62 | (string/format "client_id=%s&client_secret=%s&code=%s"
63 | (env :github-client-id)
64 | (env :github-client-secret)
65 | code)
66 | :headers {"Accept" "application/json"}))
67 |
68 |
69 | (def result (json/decode (result :body) true true))
70 |
71 | (def access-token (get result :access_token))
72 |
73 | (def auth-response (http/get "https://api.github.com/user"
74 | :headers {"Authorization" (string "token " access-token)}))
75 |
76 | (def auth-result (json/decode (auth-response :body) true true))
77 |
78 | (var account (db/find-by :account :where {:login (auth-result :login)}))
79 |
80 | (unless account
81 | (set account (db/insert :account {:login (auth-result :login)
82 | :access-token access-token})))
83 |
84 | (db/update :account (account :id) {:access-token access-token})
85 |
86 | (-> (redirect-to :home/index)
87 | (put-in [:session :login] (account :login))))
88 |
--------------------------------------------------------------------------------
/seed.janet:
--------------------------------------------------------------------------------
1 | (def allbindings (all-bindings))
2 |
3 | (import dotenv)
4 | (dotenv/load)
5 |
6 | (import joy)
7 |
8 | (def alldocs @[])
9 |
10 | (loop [b :in allbindings]
11 | (when (not= "allbindings" (string b))
12 | (do
13 | (def buf @"")
14 | (with-dyns [:out buf]
15 | (doc* b)
16 | (array/push alldocs {:name (string b) :docstring (string buf)})))))
17 |
18 | (joy/db/connect)
19 |
20 | (defn find-binding-id [name]
21 | (let [binding (joy/db/find-by :binding :where {:name name})]
22 | (if binding (binding :id) nil)))
23 |
24 |
25 | (loop [d :in alldocs]
26 | (let [b (find-binding-id (d :name))]
27 | (if b
28 | (joy/db/update :binding b {:docstring (d :docstring) # fix shadowed bindings and ? url problem
29 | :name (d :name)})
30 | (joy/db/insert :binding {:name (d :name)
31 | :docstring (d :docstring)}))))
32 |
33 | # Links that appear under "See also"
34 | (def links
35 | [
36 | ["%" "mod"]
37 | ["*" "product"]
38 | ["+" "sum"]
39 | ["+=" "inc"]
40 | ["->" "->>"]
41 | ["->>" "->"]
42 | ["accumulate" "reduce"]
43 | ["all" "some" "any?"]
44 | ["and" "band"]
45 | ["any?" "some" "all"]
46 | ["case" "match" "cond"]
47 | ["chr" "string/bytes" "string/from-bytes"]
48 | ["coro" "fiber/new"]
49 | ["defmacro" "macex"]
50 | ["defn" "defn-"]
51 | ["each" "eachk" "eachp"]
52 | ["ev/call" "ev/spawn"]
53 | ["ev/rselect" "ev/select"]
54 | ["ev/select" "ev/rselect"]
55 | ["ev/spawn" "ev/call"]
56 | ["false?" "true?" "truthy?"]
57 | ["fiber/new" "coro"]
58 | ["file/close" "file/open"]
59 | ["file/open" "file/close" "with"]
60 | ["file/popen" "os/spawn"]
61 | ["file/read" "slurp"]
62 | ["file/write" "spit"]
63 | ["filter" "keep"]
64 | ["find" "find-index"]
65 | ["find-index" "find"]
66 | ["first" "take" "last"]
67 | ["if-let" "when-let"]
68 | ["inc" "dec" "+="]
69 | ["keep" "filter"]
70 | ["keys" "values" "kvs" "pairs"]
71 | ["kvs" "pairs" "keys" "values"]
72 | ["match" "case"]
73 | ["mod" "%"]
74 | ["not" "complement" "bnot"]
75 | ["or" "bor"]
76 | ["pairs" "kvs" "keys" "values"]
77 | ["pp" "print" "printf"]
78 | ["print" "printf" "pp"]
79 | ["printf" "string/format"]
80 | ["prompt" "return"]
81 | ["put" "put-in"]
82 | ["put-in" "put"]
83 | ["reduce" "reduce2" "accumulate"]
84 | ["reduce2" "reduce"]
85 | ["return" "prompt"]
86 | ["slurp" "spit"]
87 | ["some" "all" "any?"]
88 | ["sort" "sort-by" "sorted"]
89 | ["sorted" "sorted-by" "sort"]
90 | ["string/bytes" "string/from-bytes" "chr"]
91 | ["string/format" "printf"]
92 | ["take" "first"]
93 | ["true?" "false?" "truthy?"]
94 | ["truthy?" "true?"]
95 | ["values" "keys" "kvs" "pairs"]
96 | ["when-let" "if-let"]])
97 |
98 |
99 | (each lnk links
100 | (let [src (first lnk)
101 | targets (drop 1 lnk)]
102 | (each t targets
103 | (let [source (find-binding-id src)
104 | target (find-binding-id t)
105 | exists (joy/db/find-by :link :where {:source (string source) :target (string target)})]
106 | (if (not (and source target))
107 | (errorf "Invalid link from '%s' (id=%s) to '%s'(id=%s)" src (string source) t (string target))
108 | (if (nil? exists)
109 | (joy/db/insert :link {:source source :target target})))))))
110 |
111 | (joy/db/disconnect)
112 |
--------------------------------------------------------------------------------
/helpers.janet:
--------------------------------------------------------------------------------
1 | (import joy :prefix "")
2 | (import uri)
3 |
4 |
5 | (defn binding-header [binding]
6 | [:vstack {:spacing "xs"}
7 | [:h1 (binding :name)]
8 | [:strong (get-in binding [:package :name] (binding :package))]
9 | [:pre
10 | [:code {:class "clojure"}
11 | (binding :docstring)]]])
12 |
13 |
14 | (defn binding-show-url [binding &opt url]
15 | (default url "")
16 | (def package (db/find :package (or (binding :package-id) 0)))
17 |
18 | (def name (string/replace "?" "_q" (binding :name)))
19 |
20 | (if package
21 | (string "/" (package :name) "/" name url)
22 | (string "/" (uri/escape name) url)))
23 |
24 |
25 | (defn singularize [str n]
26 | (if (one? n)
27 | (string/trimr str "s")
28 | str))
29 |
30 |
31 | (defn confirm-modal [request & body]
32 | [:div {:x-data "{ modalOpen: false, action: '' }"}
33 | body
34 | [:div {:class "md-modal" ::class "{'md-show': modalOpen}" :x-show "modalOpen" :@click.away "modalOpen = false"}
35 | [:div {:class "md-content"}
36 | [:vstack {:align-x "center"}
37 | [:h3 "Are you sure?"]
38 | [:hstack {:spacing "l" :align-x "center"}
39 | (form-with request {:method "POST" :x-bind:action "action"}
40 | [:input {:type "hidden" :name "_method" :value "DELETE"}]
41 | [:button {:type "submit"}
42 | "Yes, do it"])
43 | [:a {:href "#" :@click.prevent "modalOpen = false"}
44 | "No"]]]]]
45 | [:div {:class "md-overlay" ::class "{'md-show': modalOpen}"}]])
46 |
47 |
48 | (defn delete-button [request action]
49 | (confirm-modal request
50 | [:a {:href "#"
51 | :@click.prevent (string/format "action = '%s'; modalOpen = true" action)}
52 | "Delete"]))
53 |
54 |
55 | (defn current-account [request]
56 | (def login (get-in request [:session :login] ""))
57 | (db/find-by :account :where {:login login}))
58 |
59 |
60 | (defn menu [request]
61 | (def session (get request :session {}))
62 |
63 | [:vstack {:spacing "l"}
64 | [:hstack {:stretch "" :spacing "s"}
65 | [:a {:href (url-for :home/index)}
66 | "JanetDocs"]
67 | [:spacer]
68 | [:a {:href (url-for :playground/home)} "Playground"]
69 | [:a {:href (url-for :examples/random)}
70 | "I'm feeling lucky"]
71 |
72 | (if (get session :login)
73 | [:hstack {:spacing "m"}
74 | (form-with request (action-for :sessions/destroy)
75 | [:input {:type "hidden" :name "_method" :value "delete"}]
76 | [:input {:type "submit" :value "Sign out"}])]
77 |
78 | [:hstack {:spacing "m"}
79 | [:a {:href (string/format "https://github.com/login/oauth/authorize?client_id=%s"
80 | (env :github-client-id))}
81 | "GitHub sign in"]])]])
82 |
83 |
84 | (defn layout [{:body body :request request}]
85 | (text/html
86 | (doctype :html5)
87 | [:html {:lang "en"}
88 | [:head
89 | [:title "JanetDocs"]
90 | [:meta {:charset "utf-8"}]
91 | [:meta {:name "viewport" :content "width=device-width, initial-scale=1"}]
92 | [:meta {:name "csrf-token" :content (authenticity-token request)}]
93 | [:link {:rel "apple-touch-icon" :sizes "180x180" :href "/apple-touch-icon.png"}]
94 | [:link {:rel "icon" :type "image/png" :sizes "32x32" :href "/favicon-32x32.png"}]
95 | [:link {:rel "icon" :type "image/png" :sizes "16x16" :href "/favicon-16x16.png"}]
96 | [:link {:rel "manifest" :href "/site.webmanifest"}]
97 | [:link {:rel "stylesheet" :href "/css/atom-one-light.css" :media "(prefers-color-scheme: no-preference), (prefers-color-scheme: light)"}]
98 | [:link {:rel "stylesheet" :href "/css/atom-one-dark.css" :media "(prefers-color-scheme: dark)"}]
99 | [:link {:rel "stylesheet" :href "/_pylon.css"}]
100 | [:link {:rel "stylesheet" :href "/_water.css"}]
101 | [:link {:rel "stylesheet" :href "/app.css"}]
102 | [:script {:src "/_highlight.pack.js" :defer ""}]
103 | [:script {:src "/_app.js" :defer ""}]
104 | [:script {:src "/alpine.min.js" :defer ""}]]
105 |
106 |
107 | [:body
108 | [:vstack {:spacing "xl"}
109 | (menu request)
110 | body
111 | [:spacer]]]]))
112 |
113 |
114 | (defn /404 [request]
115 | (as-> (layout {:request request
116 | :body [:center
117 | [:h1 "Oops! 404!"]]}) ?
118 | (put ? :status 404)))
119 |
--------------------------------------------------------------------------------
/public/ace/mode-clojure.js:
--------------------------------------------------------------------------------
1 | define("ace/mode/clojure_highlight_rules",["require","exports","module","ace/lib/oop","ace/mode/text_highlight_rules"],function(e,t,n){"use strict";var r=e("../lib/oop"),i=e("./text_highlight_rules").TextHighlightRules,s=function(){var e="* *1 *2 *3 *agent* *allow-unresolved-vars* *assert* *clojure-version* *command-line-args* *compile-files* *compile-path* *e *err* *file* *flush-on-newline* *in* *macro-meta* *math-context* *ns* *out* *print-dup* *print-length* *print-level* *print-meta* *print-readably* *read-eval* *source-path* *use-context-classloader* *warn-on-reflection* + - -> ->> .. / < <= = == > > >= >= accessor aclone add-classpath add-watch agent agent-errors aget alength alias all-ns alter alter-meta! alter-var-root amap ancestors and apply areduce array-map aset aset-boolean aset-byte aset-char aset-double aset-float aset-int aset-long aset-short assert assoc assoc! assoc-in associative? atom await await-for await1 bases bean bigdec bigint binding bit-and bit-and-not bit-clear bit-flip bit-not bit-or bit-set bit-shift-left bit-shift-right bit-test bit-xor boolean boolean-array booleans bound-fn bound-fn* butlast byte byte-array bytes cast char char-array char-escape-string char-name-string char? chars chunk chunk-append chunk-buffer chunk-cons chunk-first chunk-next chunk-rest chunked-seq? class class? clear-agent-errors clojure-version coll? comment commute comp comparator compare compare-and-set! compile complement concat cond condp conj conj! cons constantly construct-proxy contains? count counted? create-ns create-struct cycle dec decimal? declare definline defmacro defmethod defmulti defn defn- defonce defstruct delay delay? deliver deref derive descendants destructure disj disj! dissoc dissoc! distinct distinct? doall doc dorun doseq dosync dotimes doto double double-array doubles drop drop-last drop-while empty empty? ensure enumeration-seq eval even? every? false? ffirst file-seq filter find find-doc find-ns find-var first float float-array float? floats flush fn fn? fnext for force format future future-call future-cancel future-cancelled? future-done? future? gen-class gen-interface gensym get get-in get-method get-proxy-class get-thread-bindings get-validator hash hash-map hash-set identical? identity if-let if-not ifn? import in-ns inc init-proxy instance? int int-array integer? interleave intern interpose into into-array ints io! isa? iterate iterator-seq juxt key keys keyword keyword? last lazy-cat lazy-seq let letfn line-seq list list* list? load load-file load-reader load-string loaded-libs locking long long-array longs loop macroexpand macroexpand-1 make-array make-hierarchy map map? mapcat max max-key memfn memoize merge merge-with meta method-sig methods min min-key mod name namespace neg? newline next nfirst nil? nnext not not-any? not-empty not-every? not= ns ns-aliases ns-imports ns-interns ns-map ns-name ns-publics ns-refers ns-resolve ns-unalias ns-unmap nth nthnext num number? odd? or parents partial partition pcalls peek persistent! pmap pop pop! pop-thread-bindings pos? pr pr-str prefer-method prefers primitives-classnames print print-ctor print-doc print-dup print-method print-namespace-doc print-simple print-special-doc print-str printf println println-str prn prn-str promise proxy proxy-call-with-super proxy-mappings proxy-name proxy-super push-thread-bindings pvalues quot rand rand-int range ratio? rational? rationalize re-find re-groups re-matcher re-matches re-pattern re-seq read read-line read-string reduce ref ref-history-count ref-max-history ref-min-history ref-set refer refer-clojure release-pending-sends rem remove remove-method remove-ns remove-watch repeat repeatedly replace replicate require reset! reset-meta! resolve rest resultset-seq reverse reversible? rseq rsubseq second select-keys send send-off seq seq? seque sequence sequential? set set-validator! set? short short-array shorts shutdown-agents slurp some sort sort-by sorted-map sorted-map-by sorted-set sorted-set-by sorted? special-form-anchor special-symbol? split-at split-with str stream? string? struct struct-map subs subseq subvec supers swap! symbol symbol? sync syntax-symbol-anchor take take-last take-nth take-while test the-ns time to-array to-array-2d trampoline transient tree-seq true? type unchecked-add unchecked-dec unchecked-divide unchecked-inc unchecked-multiply unchecked-negate unchecked-remainder unchecked-subtract underive unquote unquote-splicing update-in update-proxy use val vals var-get var-set var? vary-meta vec vector vector? when when-first when-let when-not while with-bindings with-bindings* with-in-str with-loading-context with-local-vars with-meta with-open with-out-str with-precision xml-seq zero? zipmap",t="throw try var def do fn if let loop monitor-enter monitor-exit new quote recur set!",n="true false nil",r=this.createKeywordMapper({keyword:t,"constant.language":n,"support.function":e},"identifier",!1," ");this.$rules={start:[{token:"comment",regex:";.*$"},{token:"keyword",regex:"[\\(|\\)]"},{token:"keyword",regex:"[\\'\\(]"},{token:"keyword",regex:"[\\[|\\]]"},{token:"keyword",regex:"[\\{|\\}|\\#\\{|\\#\\}]"},{token:"keyword",regex:"[\\&]"},{token:"keyword",regex:"[\\#\\^\\{]"},{token:"keyword",regex:"[\\%]"},{token:"keyword",regex:"[@]"},{token:"constant.numeric",regex:"0[xX][0-9a-fA-F]+\\b"},{token:"constant.numeric",regex:"[+-]?\\d+(?:(?:\\.\\d*)?(?:[eE][+-]?\\d+)?)?\\b"},{token:"constant.language",regex:"[!|\\$|%|&|\\*|\\-\\-|\\-|\\+\\+|\\+||=|!=|<=|>=|<>|<|>|!|&&]"},{token:r,regex:"[a-zA-Z_$][a-zA-Z0-9_$\\-]*\\b"},{token:"string",regex:'"',next:"string"},{token:"constant",regex:/:[^()\[\]{}'"\^%`,;\s]+/},{token:"string.regexp",regex:'/#"(?:\\.|(?:\\")|[^""\n])*"/g'}],string:[{token:"constant.language.escape",regex:"\\\\.|\\\\$"},{token:"string",regex:'[^"\\\\]+'},{token:"string",regex:'"',next:"start"}]}};r.inherits(s,i),t.ClojureHighlightRules=s}),define("ace/mode/matching_parens_outdent",["require","exports","module","ace/range"],function(e,t,n){"use strict";var r=e("../range").Range,i=function(){};(function(){this.checkOutdent=function(e,t){return/^\s+$/.test(e)?/^\s*\)/.test(t):!1},this.autoOutdent=function(e,t){var n=e.getLine(t),i=n.match(/^(\s*\))/);if(!i)return 0;var s=i[1].length,o=e.findMatchingBracket({row:t,column:s});if(!o||o.row==t)return 0;var u=this.$getIndent(e.getLine(o.row));e.replace(new r(t,0,t,s-1),u)},this.$getIndent=function(e){var t=e.match(/^(\s+)/);return t?t[1]:""}}).call(i.prototype),t.MatchingParensOutdent=i}),define("ace/mode/clojure",["require","exports","module","ace/lib/oop","ace/mode/text","ace/mode/clojure_highlight_rules","ace/mode/matching_parens_outdent"],function(e,t,n){"use strict";var r=e("../lib/oop"),i=e("./text").Mode,s=e("./clojure_highlight_rules").ClojureHighlightRules,o=e("./matching_parens_outdent").MatchingParensOutdent,u=function(){this.HighlightRules=s,this.$outdent=new o,this.$behaviour=this.$defaultBehaviour};r.inherits(u,i),function(){this.lineCommentStart=";",this.minorIndentFunctions=["defn","defn-","defmacro","def","deftest","testing"],this.$toIndent=function(e){return e.split("").map(function(e){return/\s/.exec(e)?e:" "}).join("")},this.$calculateIndent=function(e,t){var n=this.$getIndent(e),r=0,i,s;for(var o=e.length-1;o>=0;o--){s=e[o],s==="("?(r--,i=!0):s==="("||s==="["||s==="{"?(r--,i=!1):(s===")"||s==="]"||s==="}")&&r++;if(r<0)break}if(!(r<0&&i))return r<0&&!i?this.$toIndent(e.substring(0,o+1)):r>0?(n=n.substring(0,n.length-t.length),n):n;o+=1;var u=o,a="";for(;;){s=e[o];if(s===" "||s===" ")return this.minorIndentFunctions.indexOf(a)!==-1?this.$toIndent(e.substring(0,u-1)+t):this.$toIndent(e.substring(0,o+1));if(s===undefined)return this.$toIndent(e.substring(0,u-1)+t);a+=e[o],o++}},this.getNextLineIndent=function(e,t,n){return this.$calculateIndent(t,n)},this.checkOutdent=function(e,t,n){return this.$outdent.checkOutdent(t,n)},this.autoOutdent=function(e,t,n){this.$outdent.autoOutdent(t,n)},this.$id="ace/mode/clojure",this.snippetFileId="ace/snippets/clojure"}.call(u.prototype),t.Mode=u}); (function() {
2 | window.require(["ace/mode/clojure"], function(m) {
3 | if (typeof module == "object" && typeof exports == "object" && module) {
4 | module.exports = m;
5 | }
6 | });
7 | })();
8 |
--------------------------------------------------------------------------------
/routes/examples.janet:
--------------------------------------------------------------------------------
1 | (import joy :prefix "")
2 | (import ../helpers :prefix "")
3 | (import uri)
4 | (import json)
5 |
6 |
7 | (defn set-html [{:method method :input input :url url :ref ref}]
8 | (def method (or method "get"))
9 | (def f (if (= "post" method)
10 | (string/format "post('%s', %s, 'text/html')" url input)
11 | (string/format "get('%s', 'text/html')" url)))
12 | (string/format `%s.then(html => $refs.%s.innerHTML = html);` f ref))
13 |
14 |
15 | (defn list [examples]
16 | [:vstack {:spacing "xl"}
17 | (foreach [ex examples]
18 | [:vstack {:spacing "xs"}
19 | [:pre
20 | [:code {:class "clojure"}
21 | (ex :body)]]
22 | [:hstack {:spacing "m" :align-x "right"}
23 | [:a {:href (string "/" (uri/escape (get-in ex [:binding :name])))}
24 | (get-in ex [:binding :name])]
25 | [:a {:href (string "https://github.com/" (get-in ex [:account :login]))}
26 | (get-in ex [:account :login])]
27 | [:a {:href (url-for :playground/example {:id (get ex :id)})} "Playground"]]])])
28 |
29 | (defn format-see-also-link [link]
30 | (let [name (link :name)]
31 | [:a {
32 | :href (string "/" name)
33 | :class "see-also"}
34 | name]))
35 |
36 | (defn see-also [binding-id]
37 | (let [links (db/query `select
38 | binding.name
39 | from link
40 | join
41 | binding on link.target = binding.id
42 | where
43 | link.source = ?
44 | order
45 | by binding.name`
46 | [binding-id])]
47 | (if (empty? links)
48 | []
49 | [:hstack [:strong "See also:"] (map format-see-also-link links)])))
50 |
51 | (defn index [request]
52 | (def {:binding binding :session session} request)
53 | (def examples (db/query `select example.*, account.login as login
54 | from example
55 | join account on account.id = example.account_id
56 | where example.binding_id = ?
57 | order by example.created_at desc`
58 | [(binding :id)]))
59 |
60 | [:vstack {:spacing "xl" :x-data "{ editing: false, add: true, adding: false, examples: {} }" :@cancel-new "editing = false" :@cancel-edit "add = true" :@edit-example "add = false"}
61 | (see-also (binding :id))
62 | [:hstack
63 | [:strong (string (length examples) (singularize " examples" (length examples)))]
64 | [:spacer]
65 | (if (get session :login)
66 | [:span
67 | [:a {:x-show "add && !editing"
68 | :id "add-example"
69 | :style "cursor: pointer"
70 | :@mouseenter.once (set-html {:url (url-for :examples/form {:binding-id (binding :id)})
71 | :ref "form"})
72 | :@click.prevent "editing = true; $dispatch('new-example')"}
73 | "Add an example"]]
74 | [:span
75 | [:a {:href (string/format "https://github.com/login/oauth/authorize?client_id=%s"
76 | (env :github-client-id))}
77 | "Sign in to add an example"]])]
78 |
79 | [:vstack {:spacing "m"}
80 | [:div {:x-show "editing" :x-ref "form"}
81 | "Loading..."]
82 | [:vstack {:x-show "!editing" :spacing "xl"}
83 | (foreach [ex examples]
84 | [:vstack {:spacing "xs" :x-data "{ editing: false }" :@cancel-edit "editing = false"}
85 | [:div {:x-show "editing" :x-ref "editor"}]
86 | [:pre {:x-show "!editing"}
87 | [:code {:class "clojure"}
88 | (ex :body)]]
89 | [:hstack {:spacing "l"}
90 | [:a {:href (string "https://github.com/" (ex :login)) :x-show "!editing"}
91 | (ex :login)]
92 | [:spacer]
93 | [:a {:href (url-for :playground/example {:id (get ex :id)})} "Playground"]
94 | (when (= (get session :login)
95 | (ex :login))
96 | [:hstack {:spacing "l"}
97 | [:a {:x-show "!editing"
98 | :href (url-for :examples/edit ex)
99 | :@mouseenter.once (set-html {:url (url-for :examples/edit ex)
100 | :ref "editor"})
101 | :@click.prevent "editing = true; $dispatch('edit-example')"}
102 | "Edit"]
103 |
104 | [:span {:x-show "!editing"}
105 | (delete-button request (url-for :examples/destroy ex))]])]])]]])
106 |
107 |
108 | (defn form [request]
109 | (def {:params params :example example} request)
110 |
111 | (def html (form-for [request (if example :examples/patch :examples/create) {:id (get example :id) :binding-id (params :binding-id)}]
112 | [:vstack {:spacing "m" :x-data "{ preview: false, body: '' }" :x-init "() => { body = $refs.initialBody.value }"}
113 | [:textarea {:style "display: none" :x-ref "initialBody"}
114 | (get example :body)]
115 | [:vstack {:spacing "xs"}
116 | [:hstack {:spacing "m"}
117 | [:a {:href "#" :x-bind:style "!preview ? 'text-decoration: underline' : ''"
118 | :@click.prevent "preview = false"}
119 | "Edit"]
120 | [:a {:href "#"
121 | :x-bind:style "preview ? 'text-decoration: underline' : ''"
122 | :@click.prevent "preview = true; setTimeout(function() { highlight() }, 0)"}
123 | "Preview"]
124 | [:spacer]
125 | [:a {:href "" :@click.prevent (string
126 | "preview = false; "
127 | (if (get example :id) "$dispatch('cancel-edit')" "$dispatch('cancel-new')"))}
128 | "Cancel"]]
129 | [:pre
130 | [:code {:x-show "preview" :x-text "body" :class "clojure"}]]
131 | [:textarea {:x-show "!preview" :x-model "body" :rows "10" :name "body" :autofocus ""}
132 | (get example :body)]
133 | [:hstack
134 | [:div {:style "color: red"}
135 | (get-in request [:errors :body])]]
136 | [:vstack
137 | [:button {:type "submit"}
138 | "Save example"]]]]))
139 |
140 | (if (xhr? request)
141 | (text/html html)
142 | html))
143 |
144 |
145 | (defn new [request]
146 | (when-let [account (current-account request)
147 | binding (db/fetch [:binding (get-in request [:params :binding-id])])]
148 |
149 | (let [package (db/find :package (or (binding :package-id) 0))
150 | binding (merge binding {:package package})
151 | request (merge request {:binding binding})]
152 |
153 | [:vstack {:spacing "xl"}
154 | (binding-header binding)
155 | (let [result (form request)]
156 | (if (dictionary? result)
157 | (raw (get result :body))
158 | result))])))
159 |
160 |
161 | (defn create [request]
162 | (when-let [login (get-in request [:session :login])
163 | account (db/find-by :account :where {:login login})]
164 |
165 | (def {:body body :params params} request)
166 |
167 | (if (blank? (body :body))
168 | (new (merge request {:errors {:body "Body can't be blank"}}))
169 |
170 | (do
171 | (db/insert :example {:account-id (account :id)
172 | :binding-id (params :binding-id)
173 | :body (body :body)})
174 |
175 |
176 | (def binding (db/find :binding (params :binding-id)))
177 |
178 | (redirect (binding-show-url binding))))))
179 |
180 |
181 | (defn edit [request]
182 | (when-let [account (current-account request)
183 | example (db/fetch [:account account :example (scan-number (get-in request [:params :id] 0))])]
184 |
185 | (form (merge request {:example example}))))
186 |
187 |
188 | (defn patch [req]
189 | (when-let [account (current-account req)
190 | example (db/fetch [:account account :example (get-in req [:params :id] 0)])
191 | body (req :body)
192 | binding (db/find :binding (example :binding-id))]
193 |
194 | (if (blank? body)
195 | (edit (merge req {:error {:body "Body can't be blank"}}))
196 | (do
197 | (db/update :example example {:body (body :body)})
198 | (redirect (binding-show-url binding))))))
199 |
200 |
201 | (defn destroy [request]
202 | (when-let [account (current-account request)
203 | example (db/fetch [:account account :example (get-in request [:params :id])])]
204 |
205 | (db/delete :example (example :id))
206 |
207 | (def binding (db/find :binding (example :binding-id)))
208 |
209 | (redirect (binding-show-url binding))))
210 |
211 |
212 | (defn random [request]
213 | (let [binding (first (db/query (slurp "db/sql/random.sql")))]
214 |
215 | (def html
216 | [:vstack {:spacing "m"}
217 | (binding-header binding)
218 | (index (merge request {:binding binding}))])
219 |
220 | (if (xhr? request)
221 | (text/html html)
222 | html)))
223 |
224 |
225 | (defn export [request]
226 | (let [examples (->> (db/query `select example.body as example,
227 | account.login as gh_username,
228 | binding.name,
229 | binding.docstring,
230 | example.created_at
231 | from example
232 | join account on account.id = example.account_id
233 | join binding on binding.id = example.binding_id
234 | order by example.created_at desc`)
235 | (map |(update $ :docstring (partial string/format "%j"))))]
236 |
237 | @{:status 200
238 | :headers @{"Content-Type" "application/json; charset=utf-8"}
239 | :body (json/encode examples)}))
240 |
--------------------------------------------------------------------------------
/public/_water.css:
--------------------------------------------------------------------------------
1 | /* water.css */
2 |
3 | @charset "UTF-8";
4 |
5 | html, body {
6 | height: 100%;
7 | }
8 |
9 | :root {
10 | --background-body: #ffffff;
11 | --background: #efefef;
12 | --background-alt: #f7f7f7;
13 |
14 | --text-main: #363636;
15 | --text-bright: #333333;
16 | --text-muted: #999999;
17 | --text-cta: #fff;
18 |
19 | --links: #B10DC9;
20 | --focus: #B10DC9;
21 | --border: #dbdbdb;
22 | --code: #333333;
23 |
24 | --animation-duration: 0.1s;
25 | --button-hover: #dddddd;
26 |
27 | --form-placeholder: #949494;
28 | --form-text: #333333;
29 |
30 | --variable: #39a33c;
31 | --highlight: #ffff00;
32 | }
33 |
34 | @media (prefers-color-scheme: dark) {
35 | :root {
36 | --background-body: #202b38;
37 | --background: #161f27;
38 | --background-alt: #1a242f;
39 |
40 | --text-main: #dbdbdb;
41 | --text-bright: #ffffff;
42 | --text-muted: #717880;
43 | --text-cta: #fff;
44 |
45 | --links: hsla(292, 88%, 82%, 1.0);
46 | --focus: hsla(292, 88%, 82%, 1.0);
47 | --border: #1a242f;
48 | --code: #ffbe85;
49 |
50 | --animation-duration: 0.1s;
51 | --button-hover: #324759;
52 |
53 | --form-placeholder: #a9a9a9;
54 | --form-text: #ffffff;
55 |
56 | --variable: #d941e2;
57 | --highlight: #efdb43;
58 | }
59 | }
60 |
61 | body {
62 | font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif;
63 | line-height: 1.4;
64 |
65 | color: var(--text-main);
66 | background: var(--background-body);
67 |
68 | text-rendering: optimizeLegibility;
69 |
70 | max-width: 800px;
71 | margin: 20px auto;
72 | padding: 0 10px;
73 |
74 | overflow-x: hidden;
75 | }
76 |
77 | button, input, textarea {
78 | transition: background-color var(--animation-duration) linear,
79 | border-color var(--animation-duration) linear,
80 | color var(--animation-duration) linear,
81 | box-shadow var(--animation-duration) linear,
82 | transform var(--animation-duration) ease;
83 | }
84 |
85 | h1 {
86 | font-size: 2.2em;
87 | margin-top: 0;
88 | }
89 |
90 | h1,
91 | h2,
92 | h3,
93 | h4,
94 | h5,
95 | h6 {
96 | margin-bottom: 12px;
97 | }
98 |
99 | h1,
100 | h2,
101 | h3,
102 | h4,
103 | h5,
104 | h6,
105 | strong {
106 | color: var(--text-bright);
107 | }
108 |
109 | h1,
110 | h2,
111 | h3,
112 | h4,
113 | h5,
114 | h6,
115 | b,
116 | strong,
117 | th {
118 | font-weight: 600;
119 | }
120 |
121 | q:before {
122 | content: none;
123 | }
124 |
125 | q:after {
126 | content: none;
127 | }
128 |
129 | blockquote , q{
130 | border-left: 4px solid var(--focus);
131 | margin: 1.5em 0em;
132 | padding: 0.5em 1em;
133 | font-style: italic;
134 | }
135 |
136 | blockquote > footer {
137 | font-style: normal;
138 | border: 0;
139 | color: inherit;
140 | }
141 |
142 | blockquote cite {
143 | font-style: normal;
144 | }
145 |
146 | address {
147 | font-style: normal;
148 | }
149 |
150 | a[href^='mailto']::before {
151 | content: '📧 ';
152 | }
153 |
154 | a[href^='tel']::before {
155 | content: '📞 ';
156 | }
157 |
158 | a[href^='sms']::before {
159 | content: '💬 ';
160 | }
161 |
162 | mark {
163 | background-color: var(--highlight);
164 | border-radius: 2px;
165 | padding: 0px 2px 0px 2px;
166 | color: #000000;
167 | }
168 |
169 | button, select,
170 | input[type='submit'],
171 | input[type='button'],
172 | input[type='checkbox'],
173 | input[type='range'],
174 | input[type='radio'] {
175 | cursor: pointer;
176 | }
177 |
178 | input:not([type='checkbox']):not([type='radio']),
179 | select {
180 | box-sizing: border-box;
181 | display: block;
182 | width: 100%;
183 | }
184 |
185 | input:not([type='submit']),
186 | button,
187 | textarea,
188 | select {
189 | color: var(--form-text);
190 | background-color: var(--background);
191 |
192 | font-family: inherit;
193 | font-size: inherit;
194 |
195 | padding: 10px;
196 |
197 | border: none;
198 | border-radius: 6px;
199 | outline: none;
200 | }
201 |
202 | input[type='submit'] {
203 | width: auto;
204 | color: var(--links);
205 | background-color: transparent;
206 |
207 | font-family: inherit;
208 | font-size: inherit;
209 |
210 | padding: 10px;
211 |
212 | border: none;
213 | border-radius: 6px;
214 | outline: none;
215 | }
216 |
217 | input[type='submit']:hover {
218 | text-decoration: underline;
219 | }
220 |
221 | button,
222 | input[type='button'] {
223 | color: var(--text-cta);
224 | background-color: var(--links);
225 | }
226 |
227 | input,
228 | select,
229 | button,
230 | textarea {
231 | -webkit-appearance: none;
232 | }
233 |
234 | textarea {
235 | width: 100%;
236 | box-sizing: border-box;
237 | resize: vertical;
238 | }
239 |
240 | select {
241 | background: var(--background) var(--select-arrow) calc(100% - 12px) 50% / 12px no-repeat;
242 | padding-right: 35px;
243 | }
244 |
245 | select::-ms-expand {
246 | display: none;
247 | }
248 |
249 | select[multiple] {
250 | padding-right: 10px;
251 | background-image: none;
252 | overflow-y: auto;
253 | }
254 |
255 | button,
256 | input[type='button'] {
257 | padding: 15px 30px;
258 | }
259 |
260 | button:hover,
261 | input[type='button']:hover {
262 | background: var(--button-hover);
263 | }
264 |
265 | input:focus,
266 | select:focus,
267 | button:focus,
268 | textarea:focus {
269 | box-shadow: 0 0 0 2px var(--focus);
270 | }
271 |
272 | input[type='checkbox'],
273 | input[type='radio'] {
274 | position: relative;
275 | width: 14px;
276 | height: 14px;
277 | display: inline-block;
278 | vertical-align: middle;
279 | margin: 0;
280 | margin-right: 2px;
281 | }
282 |
283 | input[type='radio'] {
284 | border-radius: 50%;
285 | }
286 |
287 | input[type='checkbox']:checked,
288 | input[type='radio']:checked {
289 | background: var(--button-hover);
290 | }
291 |
292 | input[type='checkbox']:checked::before,
293 | input[type='radio']:checked::before {
294 | content: '•';
295 | display: block;
296 | position: absolute;
297 | left: 50%;
298 | top: 50%;
299 | transform: translateX(-50%) translateY(-50%);
300 | }
301 |
302 | input[type='checkbox']:checked::before {
303 | content: '✔';
304 | transform: translateY(-50%) translateY(0.5px) translateX(-6px);
305 | }
306 |
307 | input[type='checkbox']:active,
308 | input[type='radio']:active,
309 | input[type='button']:active,
310 | input[type='range']:active,
311 | button:active {
312 | transform: translateY(2px);
313 | }
314 |
315 | input:disabled,
316 | select:disabled,
317 | button:disabled,
318 | textarea:disabled {
319 | cursor: not-allowed;
320 | opacity: 0.5;
321 | }
322 |
323 | ::-webkit-input-placeholder {
324 | color: var(--form-placeholder);
325 | }
326 |
327 | ::-moz-placeholder {
328 | color: var(--form-placeholder);
329 | }
330 |
331 | ::-ms-input-placeholder {
332 | color: var(--form-placeholder);
333 | }
334 |
335 | ::placeholder {
336 | color: var(--form-placeholder);
337 | }
338 |
339 | fieldset {
340 | border: 1px var(--border) solid;
341 | border-radius: 6px;
342 | margin: 0;
343 | margin-bottom: 6px;
344 | padding: 20px;
345 | }
346 |
347 | legend {
348 | text-align: center;
349 | font-size: 0.9em;
350 | font-weight: 600;
351 | }
352 |
353 | input[type='range'] {
354 | margin: 10px 0;
355 | padding: 10px 0;
356 | background: transparent;
357 | }
358 |
359 | input[type='range']:focus {
360 | outline: none;
361 | }
362 |
363 | input[type='range']::-webkit-slider-runnable-track {
364 | width: 100%;
365 | height: 9.5px;
366 | transition: 0.2s;
367 | background: var(--background);
368 | border-radius: 3px;
369 | }
370 |
371 | input[type='range']::-webkit-slider-thumb {
372 | box-shadow: 0px 1px 1px #000000, 0px 0px 1px #0d0d0d;
373 | height: 20px;
374 | width: 20px;
375 | border-radius: 50%;
376 | background: var(--border);
377 | -webkit-appearance: none;
378 | margin-top: -7px;
379 | }
380 |
381 | input[type='range']:focus::-webkit-slider-runnable-track {
382 | background: var(--background);
383 | }
384 |
385 | input[type='range']::-moz-range-track {
386 | width: 100%;
387 | height: 9.5px;
388 | transition: 0.2s;
389 | background: var(--background);
390 | border-radius: 3px;
391 | }
392 |
393 | input[type='range']::-moz-range-thumb {
394 | box-shadow: 1px 1px 1px #000000, 0px 0px 1px #0d0d0d;
395 | height: 20px;
396 | width: 20px;
397 | border-radius: 50%;
398 | background: var(--border);
399 | }
400 |
401 | input[type='range']::-ms-track {
402 | width: 100%;
403 | height: 9.5px;
404 | background: transparent;
405 | border-color: transparent;
406 | border-width: 16px 0;
407 | color: transparent;
408 | }
409 |
410 | input[type='range']::-ms-fill-lower {
411 | background: var(--background);
412 | border: 0.2px solid #010101;
413 | border-radius: 3px;
414 | box-shadow: 1px 1px 1px #000000, 0px 0px 1px #0d0d0d;
415 | }
416 |
417 | input[type='range']::-ms-fill-upper {
418 | background: var(--background);
419 | border: 0.2px solid #010101;
420 | border-radius: 3px;
421 | box-shadow: 1px 1px 1px #000000, 0px 0px 1px #0d0d0d;
422 | }
423 |
424 | input[type='range']::-ms-thumb {
425 | box-shadow: 1px 1px 1px #000000, 0px 0px 1px #0d0d0d;
426 | border: 1px solid #000000;
427 | height: 20px;
428 | width: 20px;
429 | border-radius: 50%;
430 | background: var(--border);
431 | }
432 |
433 | input[type='range']:focus::-ms-fill-lower {
434 | background: var(--background);
435 | }
436 |
437 | input[type='range']:focus::-ms-fill-upper {
438 | background: var(--background);
439 | }
440 |
441 | a {
442 | text-decoration: none;
443 | color: var(--links);
444 | }
445 |
446 | a:hover {
447 | text-decoration: underline;
448 | }
449 |
450 | samp, time {
451 | background: var(--background);
452 | color: var(--code);
453 | padding: 2.5px 5px;
454 | border-radius: 6px;
455 | font-size: 1em;
456 | }
457 |
458 | pre {
459 | margin-top: 0;
460 | }
461 |
462 | pre > code {
463 | padding-top: 10px !important;
464 | padding: 10px;
465 | display: block;
466 | overflow-x: auto;
467 | }
468 |
469 | pre > code p {
470 | margin-bottom: 0;
471 | }
472 |
473 | var {
474 | color: var(--variable);
475 | font-style: normal;
476 | font-family: monospace;
477 | }
478 |
479 | kbd {
480 | background: var(--background);
481 | border: 1px solid var(--border);
482 | border-radius: 2px;
483 | color: var(--text-main);
484 | padding: 2px 4px 2px 4px;
485 | }
486 |
487 | img {
488 | max-width: 100%;
489 | height: auto;
490 | }
491 |
492 | hr {
493 | border: none;
494 | border-top: 1px solid var(--border);
495 | }
496 |
497 | table {
498 | border-collapse: collapse;
499 | margin-bottom: 10px;
500 | width: 100%;
501 | }
502 |
503 | td,
504 | th {
505 | padding: 6px;
506 | text-align: left;
507 | }
508 |
509 | thead {
510 | border-bottom: 1px solid var(--border);
511 | }
512 |
513 | tfoot {
514 | border-top: 1px solid var(--border);
515 | }
516 |
517 | tbody tr:nth-child(even) {
518 | background-color: var(--background-alt);
519 | }
520 |
521 | details {
522 | display: flex;
523 | flex-direction: column;
524 | align-items: flex-start;
525 | background-color: var(--background-alt);
526 | padding: 10px 10px 0;
527 | margin: 1em 0;
528 | border-radius: 6px;
529 | overflow: hidden;
530 | }
531 |
532 | details[open] {
533 | padding: 10px;
534 | }
535 |
536 | details > :last-child {
537 | margin-bottom: 0;
538 | }
539 |
540 | details[open] summary {
541 | margin-bottom: 10px;
542 | }
543 |
544 | summary {
545 | display: list-item;
546 | background-color: var(--background);
547 | padding: 10px;
548 | margin: -10px -10px 0;
549 | }
550 |
551 | details > :not(summary) {
552 | margin-top: 0;
553 | }
554 |
555 | summary::-webkit-details-marker {
556 | color: var(--text-main);
557 | }
558 |
559 | footer {
560 | border-top: 1px solid var(--background);
561 | padding-top: 10px;
562 | font-size: 0.8em;
563 | color: var(--text-muted);
564 | }
565 |
566 | aside {
567 | margin: 0;
568 | border-radius: 10px;
569 | background-color: var(--background-alt);
570 | padding: 20px;
571 | }
572 |
--------------------------------------------------------------------------------
/public/_highlight.pack.js:
--------------------------------------------------------------------------------
1 | /*
2 | Highlight.js 10.0.3 (a4b1bd2d)
3 | License: BSD-3-Clause
4 | Copyright (c) 2006-2020, Ivan Sagalaev
5 | */
6 | var hljs=function(){"use strict";function e(n){Object.freeze(n);var t="function"==typeof n;return Object.getOwnPropertyNames(n).forEach((function(r){!n.hasOwnProperty(r)||null===n[r]||"object"!=typeof n[r]&&"function"!=typeof n[r]||t&&("caller"===r||"callee"===r||"arguments"===r)||Object.isFrozen(n[r])||e(n[r])})),n}function n(e){return e.replace(/&/g,"&").replace(//g,">")}function t(e){var n,t={},r=Array.prototype.slice.call(arguments,1);for(n in e)t[n]=e[n];return r.forEach((function(e){for(n in e)t[n]=e[n]})),t}function r(e){return e.nodeName.toLowerCase()}var a=Object.freeze({__proto__:null,escapeHTML:n,inherit:t,nodeStream:function(e){var n=[];return function e(t,a){for(var i=t.firstChild;i;i=i.nextSibling)3===i.nodeType?a+=i.nodeValue.length:1===i.nodeType&&(n.push({event:"start",offset:a,node:i}),a=e(i,a),r(i).match(/br|hr|img|input/)||n.push({event:"stop",offset:a,node:i}));return a}(e,0),n},mergeStreams:function(e,t,a){var i=0,s="",o=[];function l(){return e.length&&t.length?e[0].offset!==t[0].offset?e[0].offset"}function u(e){s+=""+r(e)+">"}function d(e){("start"===e.event?c:u)(e.node)}for(;e.length||t.length;){var g=l();if(s+=n(a.substring(i,g[0].offset)),i=g[0].offset,g===e){o.reverse().forEach(u);do{d(g.splice(0,1)[0]),g=l()}while(g===e&&g.length&&g[0].offset===i);o.reverse().forEach(c)}else"start"===g[0].event?o.push(g[0].node):o.pop(),d(g.splice(0,1)[0])}return s+n(a.substr(i))}});const i="",s=e=>!!e.kind;class o{constructor(e,n){this.buffer="",this.classPrefix=n.classPrefix,e.walk(this)}addText(e){this.buffer+=n(e)}openNode(e){if(!s(e))return;let n=e.kind;e.sublanguage||(n=`${this.classPrefix}${n}`),this.span(n)}closeNode(e){s(e)&&(this.buffer+=i)}span(e){this.buffer+=``}value(){return this.buffer}}class l{constructor(){this.rootNode={children:[]},this.stack=[this.rootNode]}get top(){return this.stack[this.stack.length-1]}get root(){return this.rootNode}add(e){this.top.children.push(e)}openNode(e){let n={kind:e,children:[]};this.add(n),this.stack.push(n)}closeNode(){if(this.stack.length>1)return this.stack.pop()}closeAllNodes(){for(;this.closeNode(););}toJSON(){return JSON.stringify(this.rootNode,null,4)}walk(e){return this.constructor._walk(e,this.rootNode)}static _walk(e,n){return"string"==typeof n?e.addText(n):n.children&&(e.openNode(n),n.children.forEach(n=>this._walk(e,n)),e.closeNode(n)),e}static _collapse(e){e.children&&(e.children.every(e=>"string"==typeof e)?(e.text=e.children.join(""),delete e.children):e.children.forEach(e=>{"string"!=typeof e&&l._collapse(e)}))}}class c extends l{constructor(e){super(),this.options=e}addKeyword(e,n){""!==e&&(this.openNode(n),this.addText(e),this.closeNode())}addText(e){""!==e&&this.add(e)}addSublanguage(e,n){let t=e.root;t.kind=n,t.sublanguage=!0,this.add(t)}toHTML(){return new o(this,this.options).value()}finalize(){}}function u(e){return e&&e.source||e}const d="(-?)(\\b0[xX][a-fA-F0-9]+|(\\b\\d+(\\.\\d*)?|\\.\\d+)([eE][-+]?\\d+)?)",g={begin:"\\\\[\\s\\S]",relevance:0},h={className:"string",begin:"'",end:"'",illegal:"\\n",contains:[g]},f={className:"string",begin:'"',end:'"',illegal:"\\n",contains:[g]},p={begin:/\b(a|an|the|are|I'm|isn't|don't|doesn't|won't|but|just|should|pretty|simply|enough|gonna|going|wtf|so|such|will|you|your|they|like|more)\b/},m=function(e,n,r){var a=t({className:"comment",begin:e,end:n,contains:[]},r||{});return a.contains.push(p),a.contains.push({className:"doctag",begin:"(?:TODO|FIXME|NOTE|BUG|XXX):",relevance:0}),a},b=m("//","$"),v=m("/\\*","\\*/"),x=m("#","$");var _=Object.freeze({__proto__:null,IDENT_RE:"[a-zA-Z]\\w*",UNDERSCORE_IDENT_RE:"[a-zA-Z_]\\w*",NUMBER_RE:"\\b\\d+(\\.\\d+)?",C_NUMBER_RE:d,BINARY_NUMBER_RE:"\\b(0b[01]+)",RE_STARTERS_RE:"!|!=|!==|%|%=|&|&&|&=|\\*|\\*=|\\+|\\+=|,|-|-=|/=|/|:|;|<<|<<=|<=|<|===|==|=|>>>=|>>=|>=|>>>|>>|>|\\?|\\[|\\{|\\(|\\^|\\^=|\\||\\|=|\\|\\||~",BACKSLASH_ESCAPE:g,APOS_STRING_MODE:h,QUOTE_STRING_MODE:f,PHRASAL_WORDS_MODE:p,COMMENT:m,C_LINE_COMMENT_MODE:b,C_BLOCK_COMMENT_MODE:v,HASH_COMMENT_MODE:x,NUMBER_MODE:{className:"number",begin:"\\b\\d+(\\.\\d+)?",relevance:0},C_NUMBER_MODE:{className:"number",begin:d,relevance:0},BINARY_NUMBER_MODE:{className:"number",begin:"\\b(0b[01]+)",relevance:0},CSS_NUMBER_MODE:{className:"number",begin:"\\b\\d+(\\.\\d+)?(%|em|ex|ch|rem|vw|vh|vmin|vmax|cm|mm|in|pt|pc|px|deg|grad|rad|turn|s|ms|Hz|kHz|dpi|dpcm|dppx)?",relevance:0},REGEXP_MODE:{begin:/(?=\/[^\/\n]*\/)/,contains:[{className:"regexp",begin:/\//,end:/\/[gimuy]*/,illegal:/\n/,contains:[g,{begin:/\[/,end:/\]/,relevance:0,contains:[g]}]}]},TITLE_MODE:{className:"title",begin:"[a-zA-Z]\\w*",relevance:0},UNDERSCORE_TITLE_MODE:{className:"title",begin:"[a-zA-Z_]\\w*",relevance:0},METHOD_GUARD:{begin:"\\.\\s*[a-zA-Z_]\\w*",relevance:0}}),E="of and for in not or if then".split(" ");function R(e,n){return n?+n:(t=e,E.includes(t.toLowerCase())?0:1);var t}const N=n,w=t,{nodeStream:y,mergeStreams:O}=a;return function(n){var r=[],a={},i={},s=[],o=!0,l=/((^(<[^>]+>|\t|)+|(?:\n)))/gm,d="Could not find the language '{}', did you forget to load/include a language module?",g={noHighlightRe:/^(no-?highlight)$/i,languageDetectRe:/\blang(?:uage)?-([\w-]+)\b/i,classPrefix:"hljs-",tabReplace:null,useBR:!1,languages:void 0,__emitter:c};function h(e){return g.noHighlightRe.test(e)}function f(e,n,t,r){var a={code:n,language:e};T("before:highlight",a);var i=a.result?a.result:p(a.language,a.code,t,r);return i.code=a.code,T("after:highlight",i),i}function p(e,n,r,i){var s=n;function l(e,n){var t=v.case_insensitive?n[0].toLowerCase():n[0];return e.keywords.hasOwnProperty(t)&&e.keywords[t]}function c(){null!=_.subLanguage?function(){if(""!==k){var e="string"==typeof _.subLanguage;if(!e||a[_.subLanguage]){var n=e?p(_.subLanguage,k,!0,E[_.subLanguage]):m(k,_.subLanguage.length?_.subLanguage:void 0);_.relevance>0&&(T+=n.relevance),e&&(E[_.subLanguage]=n.top),w.addSublanguage(n.emitter,n.language)}else w.addText(k)}}():function(){var e,n,t,r;if(_.keywords){for(n=0,_.lexemesRe.lastIndex=0,t=_.lexemesRe.exec(k),r="";t;){r+=k.substring(n,t.index);var a=null;(e=l(_,t))?(w.addText(r),r="",T+=e[1],a=e[0],w.addKeyword(t[0],a)):r+=t[0],n=_.lexemesRe.lastIndex,t=_.lexemesRe.exec(k)}r+=k.substr(n),w.addText(r)}else w.addText(k)}(),k=""}function h(e){e.className&&w.openNode(e.className),_=Object.create(e,{parent:{value:_}})}var f={};function b(n,t){var a,i=t&&t[0];if(k+=n,null==i)return c(),0;if("begin"==f.type&&"end"==t.type&&f.index==t.index&&""===i){if(k+=s.slice(t.index,t.index+1),!o)throw(a=Error("0 width match regex")).languageName=e,a.badRule=f.rule,a;return 1}if(f=t,"begin"===t.type)return function(e){var n=e[0],t=e.rule;return t.__onBegin&&(t.__onBegin(e)||{}).ignoreMatch?function(e){return 0===_.matcher.regexIndex?(k+=e[0],1):(B=!0,0)}(n):(t&&t.endSameAsBegin&&(t.endRe=RegExp(n.replace(/[-\/\\^$*+?.()|[\]{}]/g,"\\$&"),"m")),t.skip?k+=n:(t.excludeBegin&&(k+=n),c(),t.returnBegin||t.excludeBegin||(k=n)),h(t),t.returnBegin?0:n.length)}(t);if("illegal"===t.type&&!r)throw(a=Error('Illegal lexeme "'+i+'" for mode "'+(_.className||"")+'"')).mode=_,a;if("end"===t.type){var l=function(e){var n=e[0],t=s.substr(e.index),r=function e(n,t){if(function(e,n){var t=e&&e.exec(n);return t&&0===t.index}(n.endRe,t)){for(;n.endsParent&&n.parent;)n=n.parent;return n}if(n.endsWithParent)return e(n.parent,t)}(_,t);if(r){var a=_;a.skip?k+=n:(a.returnEnd||a.excludeEnd||(k+=n),c(),a.excludeEnd&&(k=n));do{_.className&&w.closeNode(),_.skip||_.subLanguage||(T+=_.relevance),_=_.parent}while(_!==r.parent);return r.starts&&(r.endSameAsBegin&&(r.starts.endRe=r.endRe),h(r.starts)),a.returnEnd?0:n.length}}(t);if(null!=l)return l}if("illegal"===t.type&&""===i)return 1;if(A>1e5&&A>3*t.index)throw Error("potential infinite loop, way more iterations than matches");return k+=i,i.length}var v=M(e);if(!v)throw console.error(d.replace("{}",e)),Error('Unknown language: "'+e+'"');!function(e){function n(n,t){return RegExp(u(n),"m"+(e.case_insensitive?"i":"")+(t?"g":""))}class r{constructor(){this.matchIndexes={},this.regexes=[],this.matchAt=1,this.position=0}addRule(e,n){n.position=this.position++,this.matchIndexes[this.matchAt]=n,this.regexes.push([n,e]),this.matchAt+=function(e){return RegExp(e.toString()+"|").exec("").length-1}(e)+1}compile(){0===this.regexes.length&&(this.exec=()=>null);let e=this.regexes.map(e=>e[1]);this.matcherRe=n(function(e,n){for(var t=/\[(?:[^\\\]]|\\.)*\]|\(\??|\\([1-9][0-9]*)|\\./,r=0,a="",i=0;i0&&(a+="|"),a+="(";o.length>0;){var l=t.exec(o);if(null==l){a+=o;break}a+=o.substring(0,l.index),o=o.substring(l.index+l[0].length),"\\"==l[0][0]&&l[1]?a+="\\"+(+l[1]+s):(a+=l[0],"("==l[0]&&r++)}a+=")"}return a}(e),!0),this.lastIndex=0}exec(e){this.matcherRe.lastIndex=this.lastIndex;let n=this.matcherRe.exec(e);if(!n)return null;let t=n.findIndex((e,n)=>n>0&&null!=e),r=this.matchIndexes[t];return Object.assign(n,r)}}class a{constructor(){this.rules=[],this.multiRegexes=[],this.count=0,this.lastIndex=0,this.regexIndex=0}getMatcher(e){if(this.multiRegexes[e])return this.multiRegexes[e];let n=new r;return this.rules.slice(e).forEach(([e,t])=>n.addRule(e,t)),n.compile(),this.multiRegexes[e]=n,n}considerAll(){this.regexIndex=0}addRule(e,n){this.rules.push([e,n]),"begin"===n.type&&this.count++}exec(e){let n=this.getMatcher(this.regexIndex);n.lastIndex=this.lastIndex;let t=n.exec(e);return t&&(this.regexIndex+=t.position+1,this.regexIndex===this.count&&(this.regexIndex=0)),t}}function i(e){let n=e.input[e.index-1],t=e.input[e.index+e[0].length];if("."===n||"."===t)return{ignoreMatch:!0}}if(e.contains&&e.contains.includes("self"))throw Error("ERR: contains `self` is not supported at the top-level of a language. See documentation.");!function r(s,o){s.compiled||(s.compiled=!0,s.__onBegin=null,s.keywords=s.keywords||s.beginKeywords,s.keywords&&(s.keywords=function(e,n){var t={};return"string"==typeof e?r("keyword",e):Object.keys(e).forEach((function(n){r(n,e[n])})),t;function r(e,r){n&&(r=r.toLowerCase()),r.split(" ").forEach((function(n){var r=n.split("|");t[r[0]]=[e,R(r[0],r[1])]}))}}(s.keywords,e.case_insensitive)),s.lexemesRe=n(s.lexemes||/\w+/,!0),o&&(s.beginKeywords&&(s.begin="\\b("+s.beginKeywords.split(" ").join("|")+")(?=\\b|\\s)",s.__onBegin=i),s.begin||(s.begin=/\B|\b/),s.beginRe=n(s.begin),s.endSameAsBegin&&(s.end=s.begin),s.end||s.endsWithParent||(s.end=/\B|\b/),s.end&&(s.endRe=n(s.end)),s.terminator_end=u(s.end)||"",s.endsWithParent&&o.terminator_end&&(s.terminator_end+=(s.end?"|":"")+o.terminator_end)),s.illegal&&(s.illegalRe=n(s.illegal)),null==s.relevance&&(s.relevance=1),s.contains||(s.contains=[]),s.contains=[].concat(...s.contains.map((function(e){return function(e){return e.variants&&!e.cached_variants&&(e.cached_variants=e.variants.map((function(n){return t(e,{variants:null},n)}))),e.cached_variants?e.cached_variants:function e(n){return!!n&&(n.endsWithParent||e(n.starts))}(e)?t(e,{starts:e.starts?t(e.starts):null}):Object.isFrozen(e)?t(e):e}("self"===e?s:e)}))),s.contains.forEach((function(e){r(e,s)})),s.starts&&r(s.starts,o),s.matcher=function(e){let n=new a;return e.contains.forEach(e=>n.addRule(e.begin,{rule:e,type:"begin"})),e.terminator_end&&n.addRule(e.terminator_end,{type:"end"}),e.illegal&&n.addRule(e.illegal,{type:"illegal"}),n}(s))}(e)}(v);var x,_=i||v,E={},w=new g.__emitter(g);!function(){for(var e=[],n=_;n!==v;n=n.parent)n.className&&e.unshift(n.className);e.forEach(e=>w.openNode(e))}();var y,O,k="",T=0,L=0,A=0,B=!1;try{for(_.matcher.considerAll();A++,B?B=!1:(_.matcher.lastIndex=L,_.matcher.considerAll()),y=_.matcher.exec(s);)O=b(s.substring(L,y.index),y),L=y.index+O;return b(s.substr(L)),w.closeAllNodes(),w.finalize(),x=w.toHTML(),{relevance:T,value:x,language:e,illegal:!1,emitter:w,top:_}}catch(n){if(n.message&&n.message.includes("Illegal"))return{illegal:!0,illegalBy:{msg:n.message,context:s.slice(L-100,L+100),mode:n.mode},sofar:x,relevance:0,value:N(s),emitter:w};if(o)return{relevance:0,value:N(s),emitter:w,language:e,top:_,errorRaised:n};throw n}}function m(e,n){n=n||g.languages||Object.keys(a);var t=function(e){const n={relevance:0,emitter:new g.__emitter(g),value:N(e),illegal:!1,top:E};return n.emitter.addText(e),n}(e),r=t;return n.filter(M).filter(k).forEach((function(n){var a=p(n,e,!1);a.language=n,a.relevance>r.relevance&&(r=a),a.relevance>t.relevance&&(r=t,t=a)})),r.language&&(t.second_best=r),t}function b(e){return g.tabReplace||g.useBR?e.replace(l,(function(e,n){return g.useBR&&"\n"===e?"
":g.tabReplace?n.replace(/\t/g,g.tabReplace):""})):e}function v(e){var n,t,r,a,s,o=function(e){var n,t=e.className+" ";if(t+=e.parentNode?e.parentNode.className:"",n=g.languageDetectRe.exec(t)){var r=M(n[1]);return r||(console.warn(d.replace("{}",n[1])),console.warn("Falling back to no-highlight mode for this block.",e)),r?n[1]:"no-highlight"}return t.split(/\s+/).find(e=>h(e)||M(e))}(e);h(o)||(T("before:highlightBlock",{block:e,language:o}),g.useBR?(n=document.createElement("div")).innerHTML=e.innerHTML.replace(/\n/g,"").replace(/
/g,"\n"):n=e,s=n.textContent,r=o?f(o,s,!0):m(s),(t=y(n)).length&&((a=document.createElement("div")).innerHTML=r.value,r.value=O(t,y(a),s)),r.value=b(r.value),T("after:highlightBlock",{block:e,result:r}),e.innerHTML=r.value,e.className=function(e,n,t){var r=n?i[n]:t,a=[e.trim()];return e.match(/\bhljs\b/)||a.push("hljs"),e.includes(r)||a.push(r),a.join(" ").trim()}(e.className,o,r.language),e.result={language:r.language,re:r.relevance},r.second_best&&(e.second_best={language:r.second_best.language,re:r.second_best.relevance}))}function x(){if(!x.called){x.called=!0;var e=document.querySelectorAll("pre code");r.forEach.call(e,v)}}const E={disableAutodetect:!0,name:"Plain text"};function M(e){return e=(e||"").toLowerCase(),a[e]||a[i[e]]}function k(e){var n=M(e);return n&&!n.disableAutodetect}function T(e,n){var t=e;s.forEach((function(e){e[t]&&e[t](n)}))}Object.assign(n,{highlight:f,highlightAuto:m,fixMarkup:b,highlightBlock:v,configure:function(e){g=w(g,e)},initHighlighting:x,initHighlightingOnLoad:function(){window.addEventListener("DOMContentLoaded",x,!1)},registerLanguage:function(e,t){var r;try{r=t(n)}catch(n){if(console.error("Language definition for '{}' could not be registered.".replace("{}",e)),!o)throw n;console.error(n),r=E}r.name||(r.name=e),a[e]=r,r.rawDefinition=t.bind(null,n),r.aliases&&r.aliases.forEach((function(n){i[n]=e}))},listLanguages:function(){return Object.keys(a)},getLanguage:M,requireLanguage:function(e){var n=M(e);if(n)return n;throw Error("The '{}' language is required, but not loaded.".replace("{}",e))},autoDetection:k,inherit:w,addPlugin:function(e,n){s.push(e)}}),n.debugMode=function(){o=!1},n.safeMode=function(){o=!0},n.versionString="10.0.3";for(const n in _)"object"==typeof _[n]&&e(_[n]);return Object.assign(n,_),n}({})}();"object"==typeof exports&&"undefined"!=typeof module&&(module.exports=hljs);hljs.registerLanguage("clojure",function(){"use strict";return function(e){var t="def defonce defprotocol defstruct defmulti defmethod defn- defn defmacro deftype defrecord",n={"builtin-name":t+" cond apply if-not if-let if not not= = < > <= >= == + / * - rem quot neg? pos? delay? symbol? keyword? true? false? integer? empty? coll? list? set? ifn? fn? associative? sequential? sorted? counted? reversible? number? decimal? class? distinct? isa? float? rational? reduced? ratio? odd? even? char? seq? vector? string? map? nil? contains? zero? instance? not-every? not-any? libspec? -> ->> .. . inc compare do dotimes mapcat take remove take-while drop letfn drop-last take-last drop-while while intern condp case reduced cycle split-at split-with repeat replicate iterate range merge zipmap declare line-seq sort comparator sort-by dorun doall nthnext nthrest partition eval doseq await await-for let agent atom send send-off release-pending-sends add-watch mapv filterv remove-watch agent-error restart-agent set-error-handler error-handler set-error-mode! error-mode shutdown-agents quote var fn loop recur throw try monitor-enter monitor-exit macroexpand macroexpand-1 for dosync and or when when-not when-let comp juxt partial sequence memoize constantly complement identity assert peek pop doto proxy first rest cons cast coll last butlast sigs reify second ffirst fnext nfirst nnext meta with-meta ns in-ns create-ns import refer keys select-keys vals key val rseq name namespace promise into transient persistent! conj! assoc! dissoc! pop! disj! use class type num float double short byte boolean bigint biginteger bigdec print-method print-dup throw-if printf format load compile get-in update-in pr pr-on newline flush read slurp read-line subvec with-open memfn time re-find re-groups rand-int rand mod locking assert-valid-fdecl alias resolve ref deref refset swap! reset! set-validator! compare-and-set! alter-meta! reset-meta! commute get-validator alter ref-set ref-history-count ref-min-history ref-max-history ensure sync io! new next conj set! to-array future future-call into-array aset gen-class reduce map filter find empty hash-map hash-set sorted-map sorted-map-by sorted-set sorted-set-by vec vector seq flatten reverse assoc dissoc list disj get union difference intersection extend extend-type extend-protocol int nth delay count concat chunk chunk-buffer chunk-append chunk-first chunk-rest max min dec unchecked-inc-int unchecked-inc unchecked-dec-inc unchecked-dec unchecked-negate unchecked-add-int unchecked-add unchecked-subtract-int unchecked-subtract chunk-next chunk-cons chunked-seq? prn vary-meta lazy-seq spread list* str find-keyword keyword symbol gensym force rationalize"},r="[a-zA-Z_\\-!.?+*=<>'][a-zA-Z_\\-!.?+*=<>'0-9/;:]*",a={begin:r,relevance:0},s={className:"number",begin:"[-+]?\\d+(\\.\\d+)?",relevance:0},o=e.inherit(e.QUOTE_STRING_MODE,{illegal:null}),i=e.COMMENT("#","$",{relevance:0}),c={className:"literal",begin:/\b(true|false|nil)\b/},d={begin:"[\\[\\{]",end:"[\\]\\}]"},l={className:"comment",begin:"\\^"+r},m=e.COMMENT("\\^\\{","\\}"),u={className:"symbol",begin:"[:]{1,2}"+r},p={begin:"\\(",end:"\\)"},f={endsWithParent:!0,relevance:0},h={keywords:n,lexemes:r,className:"name",begin:r,starts:f},y=[p,o,l,m,i,u,d,s,c,a],g={beginKeywords:t,lexemes:r,end:'(\\[|\\#|\\d|"|:|\\{|\\)|\\(|$)',contains:[{className:"title",begin:r,relevance:0,excludeEnd:!0,endsParent:!0}].concat(y)};return p.contains=[e.COMMENT("comment",""),g,h,f],f.contains=y,d.contains=y,m.contains=[d],{name:"Clojure",aliases:["clj"],illegal:/\S/,contains:[p,o,l,m,i,u,d,s,c]}}}());
7 |
--------------------------------------------------------------------------------
/public/alpine.min.js:
--------------------------------------------------------------------------------
1 | (function(a,b){"object"==typeof exports&&"undefined"!=typeof module?module.exports=b():"function"==typeof define&&define.amd?define(b):(a=a||self,a.Alpine=b())})(this,function(){'use strict';function a(a,b,c){return b in a?Object.defineProperty(a,b,{value:c,enumerable:!0,configurable:!0,writable:!0}):a[b]=c,a}function b(a,b){var c=Object.keys(a);if(Object.getOwnPropertySymbols){var d=Object.getOwnPropertySymbols(a);b&&(d=d.filter(function(b){return Object.getOwnPropertyDescriptor(a,b).enumerable})),c.push.apply(c,d)}return c}function c(c){for(var d,e=1;e{"loading"==document.readyState?document.addEventListener("DOMContentLoaded",a):a()})}function e(b){for(var c=b.concat(),a=0;a{const b=o(a.name),c=b.match(_),d=b.match(/:([a-zA-Z\-:]+)/),e=b.match(/\.[^.\]]+(?=[^\]]*$)/g)||[];return{type:c?c[1]:null,value:d?d[1]:null,modifiers:e.map(a=>a.replace(".","")),expression:a.value}}).filter(a=>!b||a.type===b)}function n(a){return["disabled","checked","required","readonly","hidden","open","selected","autofocus","itemscope","multiple","novalidate","allowfullscreen","allowpaymentrequest","formnovalidate","autoplay","controls","loop","muted","playsinline","default","ismap","reversed","async","defer","nomodule"].includes(a)}function o(a){return a.startsWith("@")?a.replace("@","x-on:"):a.startsWith(":")?a.replace(":","x-bind:"):a}function p(a,b,c=!1){if(c)return b();const d=m(a,"transition"),e=m(a,"show")[0];if(e&&e.modifiers.includes("transition")){let c=e.modifiers;if(c.includes("out")&&!c.includes("in"))return b();const d=c.includes("in")&&c.includes("out");c=d?c.filter((a,b)=>bb>c.indexOf("out")):c,s(a,c,d,b)}else 0{},d)}function s(a,b,c,d){const e=c?t(b,"duration",150):t(b,"duration",150)/2,f={duration:e,origin:t(b,"origin","center"),first:{opacity:1,scale:100},second:{opacity:0,scale:t(b,"scale",95)}};u(a,b,()=>{},d,f)}function t(a,b,c){if(-1===a.indexOf(b))return c;const d=a[a.indexOf(b)+1];if(!d)return c;if("scale"===b&&!z(d))return c;if("duration"===b){let a=d.match(/([0-9]+)ms/);if(a)return a[1]}return"origin"===b&&["top","right","left","center","bottom"].includes(a[a.indexOf(b)+2])?[d,a[a.indexOf(b)+2]].join(" "):d}function u(a,b,c,d,e){const f=a.style.opacity,g=a.style.transform,h=a.style.transformOrigin,i=!b.includes("opacity")&&!b.includes("scale"),j=i||b.includes("opacity"),k=i||b.includes("scale"),l={start(){j&&(a.style.opacity=e.first.opacity),k&&(a.style.transform=`scale(${e.first.scale/100})`)},during(){k&&(a.style.transformOrigin=e.origin),a.style.transitionProperty=[j?`opacity`:``,k?`transform`:``].join(" ").trim(),a.style.transitionDuration=`${e.duration/1e3}s`,a.style.transitionTimingFunction=`cubic-bezier(0.4, 0.0, 0.2, 1)`},show(){c()},end(){j&&(a.style.opacity=e.second.opacity),k&&(a.style.transform=`scale(${e.second.scale/100})`)},hide(){d()},cleanup(){j&&(a.style.opacity=f),k&&(a.style.transform=g),k&&(a.style.transformOrigin=h),a.style.transitionProperty=null,a.style.transitionDuration=null,a.style.transitionTimingFunction=null}};y(a,l)}function v(a,b,c){const d=(b.find(a=>"enter"===a.value)||{expression:""}).expression.split(" ").filter(a=>""!==a),e=(b.find(a=>"enter-start"===a.value)||{expression:""}).expression.split(" ").filter(a=>""!==a),f=(b.find(a=>"enter-end"===a.value)||{expression:""}).expression.split(" ").filter(a=>""!==a);x(a,d,e,f,c,()=>{})}function w(a,b,c){const d=(b.find(a=>"leave"===a.value)||{expression:""}).expression.split(" ").filter(a=>""!==a),e=(b.find(a=>"leave-start"===a.value)||{expression:""}).expression.split(" ").filter(a=>""!==a),f=(b.find(a=>"leave-end"===a.value)||{expression:""}).expression.split(" ").filter(a=>""!==a);x(a,d,e,f,()=>{},c)}function x(a,b,c,d,e,f){const g=a.__x_original_classes||[],h={start(){a.classList.add(...c)},during(){a.classList.add(...b)},show(){e()},end(){a.classList.remove(...c.filter(a=>!g.includes(a))),a.classList.add(...d)},hide(){f()},cleanup(){a.classList.remove(...b.filter(a=>!g.includes(a))),a.classList.remove(...d.filter(a=>!g.includes(a)))}};y(a,h)}function y(a,b){b.start(),b.during(),requestAnimationFrame(()=>{let c=1e3*+getComputedStyle(a).transitionDuration.replace(/,.*/,"").replace("s","");b.show(),requestAnimationFrame(()=>{b.end(),setTimeout(()=>{b.hide(),a.isConnected&&b.cleanup()},c)})})}function z(a){return!isNaN(a)}function A(a,b,c,d,e){"template"!==b.tagName.toLowerCase()&&console.warn("Alpine: [x-for] directive should only be added to tags.");const{single:f,bunch:g,iterator1:h,iterator2:j}=B(c);var k;const l=m(b,"if")[0];k=l&&!a.evaluateReturnExpression(b,l.expression)?[]:a.evaluateReturnExpression(b,g,e);var n=b;k.forEach((c,e,g)=>{const i=C(a,b,f,h,j,c,e,g);let k=n.nextElementSibling;if(k&&void 0!==k.__x_for_key){if(k.__x_for_key!==i)for(var l=k;l;){if(l.__x_for_key===i){b.parentElement.insertBefore(l,k),k=l;break}l=!!(l.nextElementSibling&&void 0!==l.nextElementSibling.__x_for_key)&&l.nextElementSibling}delete k.__x_for_key;let d={};d[f]=c,h&&(d[h]=e),j&&(d[j]=g),k.__x_for=d,a.updateElements(k,()=>k.__x_for)}else{const i=document.importNode(b.content,!0);1!==i.childElementCount&&console.warn("Alpine: tag with [x-for] encountered with multiple element roots. Make sure only has a single child node."),b.parentElement.insertBefore(i,k),k=n.nextElementSibling,p(k,()=>{},d);let l={};l[f]=c,h&&(l[h]=e),j&&(l[j]=g),k.__x_for=l,a.initializeElements(k,()=>k.__x_for)}k.__x_for_key=i,n=k});for(var o=!!(n.nextElementSibling&&void 0!==n.nextElementSibling.__x_for_key)&&n.nextElementSibling;o;){const a=o,b=o.nextElementSibling;q(o,()=>{a.remove()}),o=!!(b&&void 0!==b.__x_for_key)&&b}}function B(a){const b=/,([^,\}\]]*)(?:,([^,\}\]]*))?$/,c=/^\(|\)$/g,d=/([\s\S]*?)\s+(?:in|of)\s+([\s\S]*)/,e=a.match(d);if(!e)return;const f={bunch:e[2].trim()},g=e[1].trim().replace(c,""),h=g.match(b);return h?(f.single=g.replace(b,"").trim(),f.iterator1=h[1].trim(),h[2]&&(f.iterator2=h[2].trim())):f.single=g,f}function C(a,b,c,d,e,f,g,h){const i=m(b,"bind").filter(a=>"key"===a.value)[0];let j={[c]:f};return d&&(j[d]=g),e&&(j[e]=h),i?a.evaluateReturnExpression(b,i.expression,()=>j):g}function D(a,b,c,d,f){var g=a.evaluateReturnExpression(b,d,f);if("value"===c){if(void 0===g&&d.match(/\./).length&&(g=""),"radio"===b.type)b.checked=b.value==g;else if("checkbox"===b.type){if(Array.isArray(g)){let a=!1;g.forEach(c=>{c==b.value&&(a=!0)}),b.checked=a}else b.checked=!!g;"string"==typeof g&&(b.value=g)}else"SELECT"===b.tagName?E(b,g):b.value=g;}else if("class"!==c)n(c)?g?b.setAttribute(c,""):b.removeAttribute(c):b.setAttribute(c,g);else if(Array.isArray(g)){const a=b.__x_original_classes||[];b.setAttribute("class",e(a.concat(g)).join(" "))}else if("object"==typeof g)Object.keys(g).forEach(a=>{g[a]?a.split(" ").forEach(a=>b.classList.add(a)):a.split(" ").forEach(a=>b.classList.remove(a))});else{const a=b.__x_original_classes||[],c=g.split(" ");b.setAttribute("class",e(a.concat(c)).join(" "))}}function E(a,b){const c=[].concat(b).map(a=>a+"");Array.from(a.options).forEach(a=>{a.selected=c.includes(a.value||a.text)})}function F(a,b,c,d,e=!1){const f=()=>{b.style.display="none"},g=()=>{1===b.style.length&&"none"===b.style.display?b.removeAttribute("style"):b.style.removeProperty("display")};if(!0===e)return void(c?g():f());const h=a=>{c?(""!==b.style.display&&p(b,()=>{g()}),a(()=>{})):"none"===b.style.display?a(()=>{}):q(b,()=>{a(()=>{f()})})};return d.includes("immediate")?void h(a=>a()):void(a.showDirectiveLastElement&&!a.showDirectiveLastElement.contains(b)&&a.executeAndClearRemainingShowDirectiveStack(),a.showDirectiveStack.push(h),a.showDirectiveLastElement=b)}function G(a,b,c,d,e){"template"!==b.nodeName.toLowerCase()&&console.warn(`Alpine: [x-if] directive should only be added to tags. See https://github.com/alpinejs/alpine#x-if`);const f=b.nextElementSibling&&!0===b.nextElementSibling.__x_inserted_me;if(c&&!f){const c=document.importNode(b.content,!0);b.parentElement.insertBefore(c,b.nextElementSibling),b.nextElementSibling.__x_inserted_me=!0,p(b.nextElementSibling,()=>{},d),a.initializeElements(b.nextElementSibling,e)}else!c&&f&&q(b.nextElementSibling,()=>{b.nextElementSibling.remove()},d)}function H(a,b,c,d,f,g={}){if(d.includes("away")){let h=i=>{b.contains(i.target)||1>b.offsetWidth&&1>b.offsetHeight||(I(a,f,i,g),d.includes("once")&&document.removeEventListener(c,h))};document.addEventListener(c,h)}else{let h=d.includes("window")?window:d.includes("document")?document:b,j=i=>{if((h===window||h===document)&&!document.body.contains(b))return void h.removeEventListener(c,j);if(!(J(c)&&K(i,d))){d.includes("prevent")&&i.preventDefault(),d.includes("stop")&&i.stopPropagation();const b=I(a,f,i,g);!1===b?i.preventDefault():d.includes("once")&&h.removeEventListener(c,j)}};if(d.includes("debounce")){let a=d[d.indexOf("debounce")+1]||"invalid-wait",b=z(a.split("ms")[0])?+a.split("ms")[0]:250;j=i(j,b)}h.addEventListener(c,j)}}function I(a,b,d,e){return a.evaluateCommandExpression(d.target,b,()=>c({},e(),{$event:d}))}function J(a){return["keydown","keyup"].includes(a)}function K(a,b){let c=b.filter(a=>!["window","document","prevent","stop"].includes(a));if(c.includes("debounce")){let a=c.indexOf("debounce");c.splice(a,z((c[a+1]||"invalid-wait").split("ms")[0])?2:1)}if(0===c.length)return!1;if(1===c.length&&c[0]===L(a.key))return!1;const d=["ctrl","shift","alt","meta","cmd","super"].filter(a=>c.includes(a));if(c=c.filter(a=>!d.includes(a)),0(("cmd"===b||"super"===b)&&(b="meta"),a[`${b}Key`]));if(b.length===d.length&&c[0]===L(a.key))return!1}return!0}function L(a){return"/"===a?"slash":" "===a||"Spacebar"===a?"space":g(a)}function M(a,b,d,e,f){var g="select"===b.tagName.toLowerCase()||["checkbox","radio"].includes(b.type)||d.includes("lazy")?"change":"input";H(a,b,g,d,`${e} = rightSideOfExpression($event, ${e})`,()=>c({},f(),{rightSideOfExpression:N(b,d,e)}))}function N(a,b,c){return"radio"!==a.type||a.hasAttribute("name")||a.setAttribute("name",c),(c,d)=>{if(c instanceof CustomEvent&&c.detail)return c.detail;if("checkbox"===a.type)return Array.isArray(d)?c.target.checked?d.concat([c.target.value]):d.filter(a=>a!==c.target.value):c.target.checked;if("select"===a.tagName.toLowerCase()&&a.multiple)return b.includes("number")?Array.from(c.target.selectedOptions).map(a=>{const b=a.value||a.text,c=b?parseFloat(b):null;return isNaN(c)?b:c}):Array.from(c.target.selectedOptions).map(a=>a.value||a.text);else{const a=c.target.value,d=a?parseFloat(a):null;return b.includes("number")?isNaN(d)?a:d:b.includes("trim")?a.trim():a}}}function O(a){return void 0===a}function P(a){return"function"==typeof a}function Q(a){return"object"==typeof a}function R(a,b){oa.set(a,b)}function S(a,b){return a.valueIsObservable(b)?a.getProxy(b):b}function T(a){return ka.call(a,"value")&&(a.value=pa(a.value)),a}function U(a,b,c){const d=ma.call(ha(c),ia(c));d.forEach(d=>{let e=ga(c,d);e.configurable||(e=Y(a,e,S)),da(b,d,e)}),ja(b)}function V(a,b){return a.valueIsObservable(b)?a.getReadOnlyProxy(b):b}function W(a){let b;return aa(a)?b=[]:Q(a)&&(b={}),b}function X(a){if(null===a)return!1;if("object"!=typeof a)return!1;if(aa(a))return!0;const b=ba(a);return b===sa||null===b||null===ba(b)}function Y(a,b,c){const{set:d,get:e}=b;return ka.call(b,"value")?b.value=c(a,b.value):(!O(e)&&(b.get=function(){return c(a,e.call(pa(this)))}),!O(d)&&(b.set=function(b){d.call(pa(this),a.unwrapProxy(b))})),b}function Z(a,b){let c=new wa({valueMutated(a,c){b(a,c)}});return{data:c.getProxy(a),membrane:c}}function $(a,b){let c=a.unwrapProxy(b),d={};return Object.keys(c).forEach(a=>{["$el","$refs","$nextTick","$watch"].includes(a)||(d[a]=c[a])}),d}const _=/^x-(on|bind|data|text|html|model|if|for|show|cloak|transition|ref)\b/,{isArray:aa}=Array,{getPrototypeOf:ba,create:ca,defineProperty:da,defineProperties:ea,isExtensible:fa,getOwnPropertyDescriptor:ga,getOwnPropertyNames:ha,getOwnPropertySymbols:ia,preventExtensions:ja,hasOwnProperty:ka}=Object,{push:la,concat:ma,map:na}=Array.prototype,oa=new WeakMap,pa=a=>oa.get(a)||a;class qa{constructor(a,b){this.originalTarget=b,this.membrane=a}get(a,b){const{originalTarget:c,membrane:d}=this,e=c[b],{valueObserved:f}=d;return f(c,b),d.getProxy(e)}set(a,b,c){const{originalTarget:d,membrane:{valueMutated:e}}=this,f=d[b];return f===c?"length"===b&&aa(d)&&e(d,b):(d[b]=c,e(d,b)),!0}deleteProperty(a,b){const{originalTarget:c,membrane:{valueMutated:d}}=this;return delete c[b],d(c,b),!0}apply(a,b,c){}construct(a,b,c){}has(a,b){const{originalTarget:c,membrane:{valueObserved:d}}=this;return d(c,b),b in c}ownKeys(a){const{originalTarget:b}=this;return ma.call(ha(b),ia(b))}isExtensible(a){const b=fa(a);if(!b)return b;const{originalTarget:c,membrane:d}=this,e=fa(c);return e||U(d,a,c),e}setPrototypeOf(a,b){}getPrototypeOf(a){const{originalTarget:b}=this;return ba(b)}getOwnPropertyDescriptor(a,b){const{originalTarget:c,membrane:d}=this,{valueObserved:e}=this.membrane;e(c,b);let f=ga(c,b);if(O(f))return f;const g=ga(a,b);return O(g)?(f=Y(d,f,S),f.configurable||da(a,b,f),f):g}preventExtensions(a){const{originalTarget:b,membrane:c}=this;return U(c,a,b),ja(b),!0}defineProperty(a,b,c){const{originalTarget:d,membrane:e}=this,{valueMutated:f}=e,{configurable:g}=c;if(ka.call(c,"writable")&&!ka.call(c,"value")){const a=ga(d,b);c.value=a.value}return da(d,b,T(c)),!1===g&&da(a,b,Y(e,c,S)),f(d,b),!0}}class ra{constructor(a,b){this.originalTarget=b,this.membrane=a}get(a,b){const{membrane:c,originalTarget:d}=this,e=d[b],{valueObserved:f}=c;return f(d,b),c.getReadOnlyProxy(e)}set(a,b,c){return!1}deleteProperty(a,b){return!1}apply(a,b,c){}construct(a,b,c){}has(a,b){const{originalTarget:c,membrane:{valueObserved:d}}=this;return d(c,b),b in c}ownKeys(a){const{originalTarget:b}=this;return ma.call(ha(b),ia(b))}setPrototypeOf(a,b){}getOwnPropertyDescriptor(a,b){const{originalTarget:c,membrane:d}=this,{valueObserved:e}=d;e(c,b);let f=ga(c,b);if(O(f))return f;const g=ga(a,b);return O(g)?(f=Y(d,f,V),ka.call(f,"set")&&(f.set=void 0),f.configurable||da(a,b,f),f):g}preventExtensions(a){return!1}defineProperty(a,b,c){return!1}}const sa=Object.prototype,ta=()=>{},ua=()=>{},va=a=>a;class wa{constructor(a){if(this.valueDistortion=va,this.valueMutated=ua,this.valueObserved=ta,this.valueIsObservable=X,this.objectGraph=new WeakMap,!O(a)){const{valueDistortion:b,valueMutated:c,valueObserved:d,valueIsObservable:e}=a;this.valueDistortion=P(b)?b:va,this.valueMutated=P(c)?c:ua,this.valueObserved=P(d)?d:ta,this.valueIsObservable=P(e)?e:X}}getProxy(a){const b=pa(a),c=this.valueDistortion(b);if(this.valueIsObservable(c)){const d=this.getReactiveState(b,c);return d.readOnly===a?a:d.reactive}return c}getReadOnlyProxy(a){a=pa(a);const b=this.valueDistortion(a);return this.valueIsObservable(b)?this.getReactiveState(a,b).readOnly:b}unwrapProxy(a){return pa(a)}getReactiveState(a,b){const{objectGraph:c}=this;let d=c.get(b);if(d)return d;const e=this;return d={get reactive(){const c=new qa(e,b),d=new Proxy(W(b),c);return R(d,a),da(this,"reactive",{value:d}),d},get readOnly(){const c=new ra(e,b),d=new Proxy(W(b),c);return R(d,a),da(this,"readOnly",{value:d}),d}},c.set(b,d),d}}class xa{constructor(a,b=null){this.$el=a;const c=this.$el.getAttribute("x-data"),d=""===c?"{}":c,e=this.$el.getAttribute("x-init");this.unobservedData=b?b:j(d,{});let{membrane:f,data:g}=this.wrapDataInObservable(this.unobservedData);this.$data=g,this.membrane=f,this.unobservedData.$el=this.$el,this.unobservedData.$refs=this.getRefsProxy(),this.nextTickStack=[],this.unobservedData.$nextTick=a=>{this.nextTickStack.push(a)},this.watchers={},this.unobservedData.$watch=(a,b)=>{this.watchers[a]||(this.watchers[a]=[]),this.watchers[a].push(b)},this.showDirectiveStack=[],this.showDirectiveLastElement;var h;e&&!b&&(this.pauseReactivity=!0,h=this.evaluateReturnExpression(this.$el,e),this.pauseReactivity=!1),this.initializeElements(this.$el),this.listenForNewElementsToInitialize(),"function"==typeof h&&h.call(this.$data)}getUnobservedData(){return $(this.membrane,this.$data)}wrapDataInObservable(a){var b=this;let c=i(function(){b.updateElements(b.$el)},0);return Z(a,(a,d)=>{b.watchers[d]?b.watchers[d].forEach(b=>b(a[d])):Object.keys(b.watchers).filter(a=>a.includes(".")).forEach(c=>{let e=c.split(".");d!==e[e.length-1]||e.reduce((e,f)=>(Object.is(a,e)&&b.watchers[c].forEach(b=>b(a[d])),e[f]),b.getUnobservedData())}),b.pauseReactivity||c()})}walkAndSkipNestedComponents(a,b,c=()=>{}){h(a,a=>a.hasAttribute("x-data")&&!a.isSameNode(this.$el)?(a.__x||c(a),!1):b(a))}initializeElements(a,b=()=>{}){for(this.walkAndSkipNestedComponents(a,a=>void 0===a.__x_for_key&&void this.initializeElement(a,b),a=>{a.__x=new xa(a)}),this.executeAndClearRemainingShowDirectiveStack();0{}){for(this.walkAndSkipNestedComponents(a,a=>!!(void 0===a.__x_for_key||a.isSameNode(this.$el))&&void this.updateElement(a,b),a=>{a.__x=new xa(a)}),this.executeAndClearRemainingShowDirectiveStack();0new Promise(b=>{a(a=>{b(a)})})).reduce((a,b)=>a.then(()=>b.then(a=>a())),Promise.resolve(()=>{})),this.showDirectiveStack=[],this.showDirectiveLastElement=void 0}updateElement(a,b){this.resolveBoundAttributes(a,!1,b)}registerListeners(a,b){m(a).forEach(({type:c,value:d,modifiers:e,expression:f})=>{"on"===c?H(this,a,d,e,f,b):"model"===c?M(this,a,e,f,b):void 0})}resolveBoundAttributes(a,b=!1,c){let d=m(a);d.forEach(({type:e,value:f,modifiers:g,expression:h})=>{switch(e){case"model":D(this,a,"value",h,c);break;case"bind":if("template"===a.tagName.toLowerCase()&&"key"===f)return;D(this,a,f,h,c);break;case"text":var i=this.evaluateReturnExpression(a,h,c);void 0===i&&h.match(/\./).length&&(i=""),a.textContent=i;break;case"html":a.innerHTML=this.evaluateReturnExpression(a,h,c);break;case"show":var i=this.evaluateReturnExpression(a,h,c);F(this,a,i,g,b);break;case"if":if(0"for"===a.type).length)return;var i=this.evaluateReturnExpression(a,h,c);G(this,a,i,b,c);break;case"for":A(this,a,h,b,c);break;case"cloak":a.removeAttribute("x-cloak");}})}evaluateReturnExpression(a,b,d=()=>{}){return j(b,this.$data,c({},d(),{$dispatch:this.getDispatchFunction(a)}))}evaluateCommandExpression(a,b,d=()=>{}){return k(b,this.$data,c({},d(),{$dispatch:this.getDispatchFunction(a)}))}getDispatchFunction(a){return(b,c={})=>{a.dispatchEvent(new CustomEvent(b,{detail:c,bubbles:!0}))}}listenForNewElementsToInitialize(){const a=this.$el,b=new MutationObserver(a=>{for(let b=0;b{this.$data[a]!==c[a]&&(this.$data[a]=c[a])})}01!==a.nodeType||a.__x_inserted_me?void 0:a.matches("[x-data]")?void(a.__x=new xa(a)):void this.initializeElements(a))}});b.observe(a,{childList:!0,attributes:!0,subtree:!0})}getRefsProxy(){var a=this;return new Proxy({},{get(b,c){if("$isAlpineProxy"===c)return!0;var d;return a.walkAndSkipNestedComponents(a.$el,a=>{a.hasAttribute("x-ref")&&a.getAttribute("x-ref")===c&&(d=a)}),d}})}}const ya={start:async function(){f()||(await d()),this.discoverComponents(a=>{this.initializeComponent(a)}),document.addEventListener("turbolinks:load",()=>{this.discoverUninitializedComponents(a=>{this.initializeComponent(a)})}),this.listenForNewUninitializedComponentsAtRunTime(a=>{this.initializeComponent(a)})},discoverComponents:function(a){const b=document.querySelectorAll("[x-data]");b.forEach(b=>{a(b)})},discoverUninitializedComponents:function(a,b=null){const c=(b||document).querySelectorAll("[x-data]");Array.from(c).filter(a=>void 0===a.__x).forEach(b=>{a(b)})},listenForNewUninitializedComponentsAtRunTime:function(){const a=document.querySelector("body"),b=new MutationObserver(a=>{for(let b=0;b{1!==a.nodeType||a.parentElement&&a.parentElement.closest("[x-data]")||this.discoverUninitializedComponents(a=>{this.initializeComponent(a)},a.parentElement)})});b.observe(a,{childList:!0,attributes:!0,subtree:!0})},initializeComponent:function(a){a.__x||(a.__x=new xa(a))},clone:function(a,b){b.__x||(b.__x=new xa(b,a.getUnobservedData()))}};return f()||(window.Alpine=ya,window.deferLoadingAlpine?window.deferLoadingAlpine(function(){window.Alpine.start()}):window.Alpine.start()),ya});
2 |
--------------------------------------------------------------------------------