diff --git a/srv/content/arpa_n_gon.hy b/srv/content/arpa_n_gon.hy
new file mode 100644
index 0000000..d5d8dba
--- /dev/null
+++ b/srv/content/arpa_n_gon.hy
@@ -0,0 +1,57 @@
+(import yaml [safe-load])
+
+(setv ones-names [
+ "hena"
+ "di"
+ "tri"
+ "tetra"
+ "penta"
+ "hexa"
+ "hepta"
+ "octa"
+ "ennea"])
+
+(setv tens-names [
+ "decagon"
+ "icosi"
+ "triconta"
+ "tetraconta"
+ "pentaconta"
+ "hexaconta"
+ "heptaconta"
+ "octaconta"
+ "enneaconta"])
+
+(defn n-gon-name [n]
+ (when (> 10 n)
+ (return (+ (get ones-names (- n 1)) "gon")))
+
+ (when (= n 11)
+ (return "undecagon"))
+
+ (when (= n 12)
+ (return "dodecagon"))
+
+ (when (> 20 n)
+ (return (+ (get ones-names (- n 1)) "decagon")))
+
+ (when (= 20 n)
+ (return "icosagon"))
+
+ (let [[modc r] (divmod n 10)]
+ (+ (get tens-names (- modc 1)) "kai" (get ones-names (- r 1)) "gon")))
+
+(defn get-members []
+ (with [f (open "www/src/data/arpa-n-gon.yaml" "r")]
+ (return (get (safe-load f) "members"))))
+
+(defn get-member-by-domain [members domain]
+ (for [[idx member] (enumerate members)]
+ (when (= (get member "arpa-domain") domain)
+ (return #(idx member)))))
+
+(defn next-member [members domain]
+ (get members (% (+ (get (get-member-by-domain members domain) 0) 1) (len members))))
+
+(defn prev-member [members domain]
+ (get members (% (- (get (get-member-by-domain members domain) 0) 1) (len members))))
diff --git a/srv/content/file_io.hy b/srv/content/file_io.hy
index d11f4ca..e04f3ba 100644
--- a/srv/content/file_io.hy
+++ b/srv/content/file_io.hy
@@ -11,13 +11,16 @@
(. (check-output (.group sequence 1) :shell True :executable "/bin/bash" :env hy-env) (decode) (strip)))
data))
-(defn parse-html-file [path #** kwargs]
+(defn parse-html-file [path [no-exec False] #** kwargs]
(with [f (open path "r")]
(setv data (.read f)))
(for [[k v] (.items kwargs)]
(setv data (.replace data f"{"{"}{k}{"}"}" (str v))))
-
+
+ (when no-exec
+ (return data))
+
(execute-bash data))
(defn send-raw-file [path]
diff --git a/srv/content/router.hy b/srv/content/router.hy
index 8c23a4e..5830ff2 100644
--- a/srv/content/router.hy
+++ b/srv/content/router.hy
@@ -4,6 +4,7 @@
(import hyrule.collections [assoc])
(import content.file-io [parse-html-file send-raw-file])
(import content.comments [create-comment])
+(import content.arpa-n-gon :as arpa-n-gon)
(import re)
(import functools [lru-cache])
(import os.path [isdir :as dir? isfile :as file? abspath])
@@ -81,15 +82,36 @@
:if (setx value (. request (get "route") (get "parameters") (get param None)))
#(param value)))))))
-(defn shtml-file-response [file [code 200] [template-params {}]]
+(defn require-params [#* params [otherwise (fn [#* _] (error 409 "missing required parameters"))]]
+ (fn [f]
+ (fn [method post request #** kwargs]
+ (if (all (lfor param params (in param (. request (get "route") (get "parameters") (keys)))))
+ (f method post request #** kwargs)
+ (otherwise method post request #** kwargs)))))
+
+(defn 303-if-not-arpa [f]
+ (fn [method path request]
+ (if (. request (get "headers") (get "Host") (endswith "arpa"))
+ (f method path request)
+ (dict
+ :code 303
+ :headers {"Location" f"http://natalieee.net.8.f.9.e.0.7.4.0.1.0.0.2.ip6.arpa/{(. request (get "route") (get "unparsed_route"))}"}))))
+
+(defn shtml-file-response [file [code 200] [no-exec False] [template-params {}]]
(dict
:code code
:headers {"Connection" "keep-alive" "Keep-Alive" "timeout=5 max=200"}
- :body (parse-html-file f"./www/site/html/{file}" #** template-params)))
+ :body (parse-html-file f"./www/site/html/{file}" :no-exec no-exec #** template-params)))
(defn raw-file-response [file [code 200]]
(dict :code code #** (dict (zip ["headers" "body"] (send-raw-file f"./www/site/{file}")))))
+(defn+ match-request [{method "method" {path "path"} "route" :as request}]
+ ;; (try
+ ((get (routes.get-route-by-path path) method) method path request))
+ ;; (except [Exception]
+ ;; (return (error 500 "server error")))))
+
(defn [(route "/" "GET")] /home #route-args (shtml-file-response "home.html"))
(defn [(route "/html/*" "GET") (if-file-exists :base-path "./www/site/html" :otherwise (error 404 "not found"))] /html/* #route-args (shtml-file-response path))
(defn [lru-cache (route "/assets/*" "GET") (if-file-exists :base-path "./www/site/" :otherwise (error 404 "not found"))] /assets/* #route-args (raw-file-response path))
@@ -97,6 +119,22 @@
(defn [(route "/comment" "POST")] /comments #route-args (create-comment request))
(defn [lru-cache (route "/robots.txt" "GET") ] /robots #route-args (dict :code 200 :headers {"Content-Type" "text/plain"} :body "User-agent *\nDisallow: /\n"))
-(defn+ match-request [{method "method" {path "path"} "route" :as request}]
- ((get (routes.get-route-by-path path) method) method path request))
-
+;; *.arpa web n-gon
+(setv members (arpa-n-gon.get-members))
+
+(defn [(route "/arpa-n-gon" GET) 303-if-not-arpa] /arpa-n-gon #route-args (shtml-file-response "arpa-n-gon.html" :template-params (dict :n_gon (arpa-n-gon.n-gon-name (len members)) :n_gon_inc (arpa-n-gon.n-gon-name (+ (len members) 1)) :n (len members))))
+
+(defn [(route "/arpa-n-gon/nav" GET) 303-if-not-arpa (forward-params "current" "style") (require-params "current") ] /arpa-n-gon/nav #route-args [current [style None]]
+ (shtml-file-response "arpa-n-gon-nav.html" :no-exec True :template-params (dict
+ :style style
+ :next (+ "http://" (get (arpa-n-gon.next-member members current) "arpa-domain"))
+ :prev (+ "http://" (get (arpa-n-gon.prev-member members current) "arpa-domain"))
+ :n_gon (arpa-n-gon.n-gon-name (len members)))))
+
+(defn [(route "/arpa-n-gon/next" GET) 303-if-not-arpa (forward-params "current" )(require-params "current")] /arpa-n-gon/next #route-args [current] (dict
+ :code 303
+ :headers {"Location" (+ "http://" (get (arpa-n-gon.next-member members current) "arpa-domain"))}))
+
+(defn [(route "/arpa-n-gon/prev" GET) 303-if-not-arpa (forward-params "current") (require-params "current")] /arpa-n-gon/next #route-args [current] (dict
+ :code 303
+ :headers {"Location" (+ "http://" (get (arpa-n-gon.prev-member members current) "arpa-domain"))}))
diff --git a/srv/http_utils/request.hy b/srv/http_utils/request.hy
index 8fbe7f7..360370f 100644
--- a/srv/http_utils/request.hy
+++ b/srv/http_utils/request.hy
@@ -43,7 +43,8 @@
segments))
- :parameters (parse-url-encoded query))))
+ :parameters (parse-url-encoded query)
+ :unparsed-route route)))
(assoc "version" http-version)
(assoc "headers" (hashable-dict
diff --git a/www/src/assets/arpa-n-gon.css b/www/src/assets/arpa-n-gon.css
new file mode 100644
index 0000000..4adb060
--- /dev/null
+++ b/www/src/assets/arpa-n-gon.css
@@ -0,0 +1,25 @@
+:root {
+ --link: #33b1ff;
+ --visited-link: #be95ff;
+}
+
+body {
+ margin: 0;
+ display: flex;
+
+ div {
+ display: flex;
+ gap: 1ch;
+ font-size: 13px;
+ font-family: 'Liberation Mono', monospace;
+
+ > a {
+ text-underline-offset: 2px;
+ color: var(--link);
+
+ &:visited {
+ color: var(--visited-link);
+ }
+ }
+ }
+}
diff --git a/www/src/assets/style.css b/www/src/assets/style.css
index a0527db..6841903 100644
--- a/www/src/assets/style.css
+++ b/www/src/assets/style.css
@@ -191,6 +191,9 @@ body {
justify-content: flex-start;
> footnote > * { margin-top: 2px; }
+ > footnote > iframe {
+ border: none;
+ }
> a {
margin: 0 !important;
@@ -415,3 +418,10 @@ div.thought-list{
}
}
}
+
+.arpa-n-gon-list {
+ > li {
+ background: var(--alt-bg);
+ margin: 10px;
+ }
+}
diff --git a/www/src/data/arpa-n-gon-linking-anchors.html b/www/src/data/arpa-n-gon-linking-anchors.html
new file mode 100644
index 0000000..7fb76b2
--- /dev/null
+++ b/www/src/data/arpa-n-gon-linking-anchors.html
@@ -0,0 +1,3 @@
+prev
+*.arpa web n-gon
+next
diff --git a/www/src/data/arpa-n-gon-linking-iframe.html b/www/src/data/arpa-n-gon-linking-iframe.html
new file mode 100644
index 0000000..7d3d65b
--- /dev/null
+++ b/www/src/data/arpa-n-gon-linking-iframe.html
@@ -0,0 +1 @@
+
diff --git a/www/src/data/arpa-n-gon.yaml b/www/src/data/arpa-n-gon.yaml
new file mode 100644
index 0000000..18a448b
--- /dev/null
+++ b/www/src/data/arpa-n-gon.yaml
@@ -0,0 +1,5 @@
+members:
+ - name: natalie
+ arpa-domain: natalieee.net.8.f.9.e.0.7.4.0.1.0.0.2.ip6.arpa
+ description: natalieee.net arpa domain
+
diff --git a/www/src/pages/arpa-n-gon-nav.hy b/www/src/pages/arpa-n-gon-nav.hy
new file mode 100644
index 0000000..3b558d7
--- /dev/null
+++ b/www/src/pages/arpa-n-gon-nav.hy
@@ -0,0 +1,8 @@
+'(html
+ (head
+ (link (:rel stylesheet :href "{style}" :type text/css)))
+ (body
+ (div
+ (a (:href "{prev}" :target _parent) <-)
+ (a (:href "http://natalieee.net.8.f.9.e.0.7.4.0.1.0.0.2.ip6.arpa/arpa-n-gon" :target _parent) "*.arpa web {n_gon}")
+ (a (:href "{next}" :target _parent) ->))))
diff --git a/www/src/pages/arpa-n-gon.hy b/www/src/pages/arpa-n-gon.hy
new file mode 100644
index 0000000..80edafc
--- /dev/null
+++ b/www/src/pages/arpa-n-gon.hy
@@ -0,0 +1,62 @@
+(page
+ :title ".arpa web {n_gon}"
+ :description "the homepage for the .arpa web {n_gon}"
+ `((section
+ (h1 "the *.arpa web {n_gon}")
+ (p "a web {n_gon} (read: webring with {n} members) for anyone with a domain under the arpa tld or any subdomain thereof."))
+
+ (section
+ (h2 "members")
+ (ol (:class "arpa-n-gon-list")
+ ~(do
+ (import yaml [safe-load])
+ (with [f (open "data/arpa-n-gon.yaml")]
+ (setv members (get (safe-load f) "members")))
+
+ (hy.models.Expression (lfor member members
+ `(li (div
+ (div "member: " (a (:href ~(get member "arpa-domain") :title ~(get member "arpa-domain")) ~(get member "name")))
+ (div "domain: " ~(get member "arpa-domain")
+ (div "description: " ~(get member "description"))))))))))
+
+ (section
+ (h2 "joining")
+ (p "anyone meeting all of the following criteria is permitted to join this webring:")
+ (ul
+ (li "own a domain under the arpa tld")
+ (li "have a site accessible under that domain")
+ (li "on that site, have at least one instance of page elements complying with the section on acceptable notation of membership")
+ (li "be deemed by natalie to be generally acceptable; this is a low bar, and functionally translates to "don't be an asshole""))
+
+ (p "should $READER align with the above conditions, and is interested in joining this web {n_gon} (thus making it a web {n_gon_inc}), $READER may send an e-mail containing their website's url to "
+ (a (:href "mailto:{n_gon}@8.f.9.e.0.7.4.0.1.0.0.2.ip6.arpa") "{n_gon}@8.f.9.e.0.7.4.0.1.0.0.2.ip6.arpa")))
+
+ (section
+ (h2 "acceptable notation of membership")
+ (p "there are two main modes of noting one's affiliation with this web {n_gon}, what is appropriate for $READER's website will depend on their preferences regarding loading of external resources.")
+
+ (br)
+ (h3 "1: iframe")
+ (p "the first option is to include an iframe linking to the navigation for the webring. this option is funnier, because requesting that natalieee.net renders the iframe contents allows
+ this server to return html containing the appropriate n-gon for the current member count. in order to conform with the css of some site, a style param can be passed in the iframe's src attribute,
+ which will get loaded as a stylesheet.")
+
+ (figure
+ (figcaption "iframe web {n_gon} html")
+ (code ~(run #[[syntax-hl data/arpa-n-gon-linking-iframe.html]])))
+
+ (br)
+ (h3 "2: anchors")
+ (p "the second option is to include various anchor tags. this option is less funny, because instead of asking natalieee.net for the appropriate n-gon, it simply labels the web {n_gon} as a web n-gon.")
+
+ (figure
+ (figcaption "anchor web {n_gon} html")
+ (code ~(run #[[syntax-hl data/arpa-n-gon-linking-anchors.html]])))
+
+ (p "of the above methods, one must appear anywhere within a site a number of times greater than 0. a valid website can include one of these
+ only once (on a webring page, should the site have a page dedicated to that), or on each page as with this site's footer.")
+
+ (br)
+ (h3 "proper linking")
+ (p "the `current` parameter in any given web {n_gon} related url should be set to the domain of one's site. in this one's case, this parameter gets set to natalieee.net.8.f.9.e.0.7.4.0.1.0.0.2.ip6.arpa. this is
+ the mechanism that allows the server to properly link to the next or previous site in the {n_gon}."))))
diff --git a/www/src/templates/footer.hy b/www/src/templates/footer.hy
index be4cfa0..321970d 100644
--- a/www/src/templates/footer.hy
+++ b/www/src/templates/footer.hy
@@ -15,8 +15,10 @@
(div
(footnote (:style "margin-top: 5px") "▖▖▖▖▘▖▖▖▖▘▌▖▖▖▘")
(footnote (:style "margin-top: 5px")
- (div (:style "flex-direction: row; width: 14ch; gap: 2ch; margin-right: 5px;")
+ (div (:style "display: flex; flex-direction: row; width: 14ch; gap: 1ch; margin-right: 5px;")
(a (:href "https://stellophiliac.github.io/roboring/0x6e6174/previous") "<-")
(a (:href "https://stellophiliac.github.io/roboring") "roboring")
- (a (:href "https://stellophiliac.github.io/roboring/0x6e6174/next") "->"))))
+ (a (:href "https://stellophiliac.github.io/roboring/0x6e6174/next") "->"))
+
+ (iframe (:src "/arpa-n-gon/nav?current=natalieee.net.8.f.9.e.0.7.4.0.1.0.0.2.ip6.arpa&style=/assets/arpa-n-gon.css"))))
(span ~(run "git log -1 --format=%h"))))