detached 8151903

New structure and embedding ok

commit
8151903479fcc444669587532292894717a4fe85
author
bnema · · 2023-09-12 17:30 UTC
parent
dfcd2ef
signature
unsigned
54 files · +2128 -991

this diff is incomplete: 2 files are too large to show. the totals above count everything; clone the repository to read the rest.

M .gitignore +1 -0
@@ -7,3 +7,4 @@ logs/error.log
77 logs/http.log
88 logs/docker.log
99 gordon.yml
10+bun.lockb
@@ -7,3 +7,4 @@ logs/error.log
7 logs/http.log7 logs/http.log
8 logs/docker.log8 logs/docker.log
9 gordon.yml9 gordon.yml
10+bun.lockb
A cmd/main.go +10 -0
@@ -0,0 +1,10 @@
1+package main
2+
3+import (
4+ "github.com/bnema/gordon/internal/app"
5+)
6+
7+func main() {
8+ a := app.NewApp()
9+ a.Start()
10+}
@@ -0,0 +1,10 @@
1+package main
2+
3+import (
4+ "github.com/bnema/gordon/internal/app"
5+)
6+
7+func main() {
8+ a := app.NewApp()
9+ a.Start()
10+}
A go.mod +21 -0
@@ -0,0 +1,21 @@
1+module github.com/bnema/gordon
2+
3+go 1.21.1
4+
5+require (
6+ github.com/PuerkitoBio/goquery v1.8.1
7+ github.com/labstack/echo/v4 v4.11.1
8+)
9+
10+require (
11+ github.com/andybalholm/cascadia v1.3.1 // indirect
12+ github.com/labstack/gommon v0.4.0 // indirect
13+ github.com/mattn/go-colorable v0.1.13 // indirect
14+ github.com/mattn/go-isatty v0.0.19 // indirect
15+ github.com/valyala/bytebufferpool v1.0.0 // indirect
16+ github.com/valyala/fasttemplate v1.2.2 // indirect
17+ golang.org/x/crypto v0.11.0 // indirect
18+ golang.org/x/net v0.12.0 // indirect
19+ golang.org/x/sys v0.10.0 // indirect
20+ golang.org/x/text v0.11.0 // indirect
21+)
@@ -0,0 +1,21 @@
1+module github.com/bnema/gordon
2+
3+go 1.21.1
4+
5+require (
6+ github.com/PuerkitoBio/goquery v1.8.1
7+ github.com/labstack/echo/v4 v4.11.1
8+)
9+
10+require (
11+ github.com/andybalholm/cascadia v1.3.1 // indirect
12+ github.com/labstack/gommon v0.4.0 // indirect
13+ github.com/mattn/go-colorable v0.1.13 // indirect
14+ github.com/mattn/go-isatty v0.0.19 // indirect
15+ github.com/valyala/bytebufferpool v1.0.0 // indirect
16+ github.com/valyala/fasttemplate v1.2.2 // indirect
17+ golang.org/x/crypto v0.11.0 // indirect
18+ golang.org/x/net v0.12.0 // indirect
19+ golang.org/x/sys v0.10.0 // indirect
20+ golang.org/x/text v0.11.0 // indirect
21+)
A go.sum +77 -0 generated file: collapsed
A internal/app/app.go +61 -0
@@ -0,0 +1,61 @@
1+package app
2+
3+import (
4+ "fmt"
5+ "io/fs"
6+
7+ "github.com/bnema/gordon/internal/gotemplate"
8+ "github.com/bnema/gordon/internal/webui"
9+)
10+
11+const (
12+ BuildVersion = "0.0.2"
13+ BuildDir = "tmp"
14+)
15+
16+type App struct {
17+ TemplateFS fs.FS
18+ PublicFS fs.FS
19+ BuildVersion string
20+ BuildDir string
21+}
22+
23+func (*App) GetTemplateFS() fs.FS {
24+ return gotemplate.TemplateFS
25+}
26+
27+func (*App) GetPublicFS() fs.FS {
28+ return webui.PublicFS
29+}
30+
31+func (*App) GetBuildVersion() string {
32+ return BuildVersion
33+}
34+
35+func (*App) GetBuildDir() string {
36+ return BuildDir
37+}
38+
39+func NewApp() *App {
40+ return &App{
41+ TemplateFS: gotemplate.TemplateFS,
42+ PublicFS: webui.PublicFS,
43+ BuildVersion: BuildVersion,
44+ BuildDir: BuildDir,
45+ }
46+}
47+
48+func (a *App) Start() {
49+ fmt.Println("Starting app")
50+
51+ // LS in the template directory
52+ entries, err := fs.ReadDir(a.TemplateFS, ".") // List the root directory
53+ if err != nil {
54+ fmt.Println("Error reading directory:", err)
55+ return
56+ }
57+
58+ for _, entry := range entries {
59+ fmt.Println(entry.Name())
60+ }
61+}
@@ -0,0 +1,61 @@
1+package app
2+
3+import (
4+ "fmt"
5+ "io/fs"
6+
7+ "github.com/bnema/gordon/internal/gotemplate"
8+ "github.com/bnema/gordon/internal/webui"
9+)
10+
11+const (
12+ BuildVersion = "0.0.2"
13+ BuildDir = "tmp"
14+)
15+
16+type App struct {
17+ TemplateFS fs.FS
18+ PublicFS fs.FS
19+ BuildVersion string
20+ BuildDir string
21+}
22+
23+func (*App) GetTemplateFS() fs.FS {
24+ return gotemplate.TemplateFS
25+}
26+
27+func (*App) GetPublicFS() fs.FS {
28+ return webui.PublicFS
29+}
30+
31+func (*App) GetBuildVersion() string {
32+ return BuildVersion
33+}
34+
35+func (*App) GetBuildDir() string {
36+ return BuildDir
37+}
38+
39+func NewApp() *App {
40+ return &App{
41+ TemplateFS: gotemplate.TemplateFS,
42+ PublicFS: webui.PublicFS,
43+ BuildVersion: BuildVersion,
44+ BuildDir: BuildDir,
45+ }
46+}
47+
48+func (a *App) Start() {
49+ fmt.Println("Starting app")
50+
51+ // LS in the template directory
52+ entries, err := fs.ReadDir(a.TemplateFS, ".") // List the root directory
53+ if err != nil {
54+ fmt.Println("Error reading directory:", err)
55+ return
56+ }
57+
58+ for _, entry := range entries {
59+ fmt.Println(entry.Name())
60+ }
61+}
A internal/gotemplate/embed.go +13 -0
@@ -0,0 +1,13 @@
1+package gotemplate
2+
3+import (
4+ "embed"
5+
6+ "github.com/labstack/echo/v4"
7+)
8+
9+// Embedding templates directories
10+
11+//go:embed models/*
12+var template embed.FS
13+var TemplateFS = echo.MustSubFS(template, "models")
@@ -0,0 +1,13 @@
1+package gotemplate
2+
3+import (
4+ "embed"
5+
6+ "github.com/labstack/echo/v4"
7+)
8+
9+// Embedding templates directories
10+
11+//go:embed models/*
12+var template embed.FS
13+var TemplateFS = echo.MustSubFS(template, "models")
A internal/gotemplate/models/html/admin/dashboard.gohtml +9 -0
@@ -0,0 +1,9 @@
1+<div id="dashboard">
2+ <h1
3+ class="text-5xl fw100 animate-bounce-alt animate-count-infinite animate-duration-1s"
4+ >
5+ Hello World from dashboard.html
6+ </h1>
7+ <!-- We load Chart.js here to avoid loading it in every page end when all the rest is loaded -->
8+ <script src="libs/chart.js"></script>
9+</div>
@@ -0,0 +1,9 @@
1+<div id="dashboard">
2+ <h1
3+ class="text-5xl fw100 animate-bounce-alt animate-count-infinite animate-duration-1s"
4+ >
5+ Hello World from dashboard.html
6+ </h1>
7+ <!-- We load Chart.js here to avoid loading it in every page end when all the rest is loaded -->
8+ <script src="libs/chart.js"></script>
9+</div>
A internal/gotemplate/models/html/admin/index.gohtml +124 -0
@@ -0,0 +1,124 @@
1+<!-- @format -->
2+
3+<!DOCTYPE html>
4+<html lang="en">
5+ <head>
6+ <meta charset="UTF-8" />
7+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
8+ <title>{{ .header.meta.title }}</title>
9+ <meta name="description" content="{{ .Header.Meta.Description }}" />
10+ <meta name="keywords" content="{{ .Header.Meta.Keywords }}" />
11+ <!-- Custom CSS + Tailwind -->
12+ <link rel="stylesheet" href="/assets/css/tailwind.css" />
13+ <!-- Iconoir -->
14+ <link rel="stylesheet" href="/libs/iconoir.css" />
15+ <!-- Alpine -->
16+ <script src="/libs/alpine.min.js"></script>
17+ <!-- HTMX min js -->
18+ <script src="/libs/htmx.min.js"></script>
19+ <!-- HTMX SSE -->
20+ <script src="/libs/htmx-sse.js"></script>
21+ <!-- Custom JS from assets/js -->
22+ <script src="assets/js/custom.js"></script>
23+ </head>
24+ <body class="IBMPlexSans bg-zinc-200 md:p-8 flex">
25+ <!-- Left Menu -->
26+ <div class="w-1/5 flex flex-col space-evenly">
27+ <!-- Logo -->
28+ <div id="logo-mascot-leftnav" class="flex justify-center p-4">
29+ <div class="circle-shadow flex justify-center w-100">
30+ <img
31+ src="/assets/imgs/gordon-mascot-hq-trsp.png"
32+ alt="logo"
33+ class="sm:h-24 h-32 xl:h-48"
34+ />
35+ </div>
36+ </div>
37+ <!-- Site Name + Version -->
38+ <div
39+ class="p-4 flex flex-col bg-gordonmascot-lblue rounded-lg shadow space-y-4"
40+ >
41+ <div class="w-full flex justify-center">
42+ <h1
43+ class="gordon-title text-2xl lg:text-4xl xl:text-5xl text-gordonmascot-hblue tracking-tighter"
44+ >
45+ Gordon
46+ </h1>
47+ <span class="gordon-v-subtitle text-gordonmascot-mblue text-sm"
48+ >v0.0.1</span
49+ >
50+ </div>
51+ <!--(Navigation) -->
52+ <div id="menu-leftnav" class="w-full">
53+ <ul
54+ class="flex flex-col md:space-y-6 md:py-8 font-semibold text-gray-100 text-lg md:text-2xl md:pl-4"
55+ >
56+ <li class="flex items-center">
57+ <i class="iconoir-dashboard-speed mr-2 md:text-3xl"></i>
58+ <a href="index.html">Dashboard</a>
59+ </li>
60+ <li class="flex items-center">
61+ <i class="iconoir-server mr-2 md:text-3xl"></i>
62+ <a href="#manager">Manager</a>
63+ </li>
64+ <li class="flex items-center">
65+ <i class="iconoir-community mr-2 md:text-3xl"></i>
66+ <a href="#users">Users</a>
67+ </li>
68+ <li class="flex items-center">
69+ <i class="iconoir-database-settings mr-2 md:text-3xl"></i>
70+ <a href="#gordon-settings">Settings</a>
71+ </li>
72+ </ul>
73+ </div>
74+
75+ <div class="w-full h-24 bg-gordonmascot-mblue rounded-lg"></div>
76+ <!-- Mock menu item -->
77+ </div>
78+ </div>
79+
80+ <!-- Main Content including the navbar -->
81+ <div class="flex-1 flex flex-col md:pt-10 space-y-4 ml-4">
82+ <!-- Search Nav within the main content -->
83+ <div class="mb-4 flex justify-end">
84+ <div class="w-72 h-10 bg-gray-300 rounded-lg">
85+ <!-- Search input with iconir search -->
86+ <div class="flex justify-between items-center h-full px-2">
87+ <input
88+ type="text"
89+ class="w-full h-full bg-transparent outline-none"
90+ placeholder="Search"
91+ />
92+ <i class="iconoir-search"></i>
93+ </div>
94+ </div>
95+ <!-- Mock search or other element -->
96+ </div>
97+
98+ <!-- Cards section -->
99+ <div class="flex space-x-4 flex-grow">
100+ <!-- Main Card on the Left -->
101+ <div class="w-4/6 bg-white p-4 rounded-md shadow mb-4">
102+ <div class="w-full rounded-sm bg-gray-300"></div>
103+ <!-- Mock main card -->
104+ </div>
105+
106+ <!-- Two Cards on the Right -->
107+ <div class="w-2/6 flex flex-col flex-justify-start">
108+ <div class="bg-white p-4 rounded-md shadow mb-4">
109+ <div class="w-full h-44 rounded-sm bg-gray-300"></div>
110+ <!-- Mock card -->
111+ </div>
112+ <div class="bg-white p-4 rounded-md shadow mb-4">
113+ <div class="w-full h-44 rounded-sm bg-gray-300"></div>
114+ <!-- Mock card -->
115+ </div>
116+ <div class="bg-white p-4 rounded-md shadow mb-4">
117+ <div class="w-full h-44 rounded-sm bg-gray-300"></div>
118+ <!-- Mock card -->
119+ </div>
120+ </div>
121+ </div>
122+ </div>
123+ </body>
124+</html>
@@ -0,0 +1,124 @@
1+<!-- @format -->
2+
3+<!DOCTYPE html>
4+<html lang="en">
5+ <head>
6+ <meta charset="UTF-8" />
7+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
8+ <title>{{ .header.meta.title }}</title>
9+ <meta name="description" content="{{ .Header.Meta.Description }}" />
10+ <meta name="keywords" content="{{ .Header.Meta.Keywords }}" />
11+ <!-- Custom CSS + Tailwind -->
12+ <link rel="stylesheet" href="/assets/css/tailwind.css" />
13+ <!-- Iconoir -->
14+ <link rel="stylesheet" href="/libs/iconoir.css" />
15+ <!-- Alpine -->
16+ <script src="/libs/alpine.min.js"></script>
17+ <!-- HTMX min js -->
18+ <script src="/libs/htmx.min.js"></script>
19+ <!-- HTMX SSE -->
20+ <script src="/libs/htmx-sse.js"></script>
21+ <!-- Custom JS from assets/js -->
22+ <script src="assets/js/custom.js"></script>
23+ </head>
24+ <body class="IBMPlexSans bg-zinc-200 md:p-8 flex">
25+ <!-- Left Menu -->
26+ <div class="w-1/5 flex flex-col space-evenly">
27+ <!-- Logo -->
28+ <div id="logo-mascot-leftnav" class="flex justify-center p-4">
29+ <div class="circle-shadow flex justify-center w-100">
30+ <img
31+ src="/assets/imgs/gordon-mascot-hq-trsp.png"
32+ alt="logo"
33+ class="sm:h-24 h-32 xl:h-48"
34+ />
35+ </div>
36+ </div>
37+ <!-- Site Name + Version -->
38+ <div
39+ class="p-4 flex flex-col bg-gordonmascot-lblue rounded-lg shadow space-y-4"
40+ >
41+ <div class="w-full flex justify-center">
42+ <h1
43+ class="gordon-title text-2xl lg:text-4xl xl:text-5xl text-gordonmascot-hblue tracking-tighter"
44+ >
45+ Gordon
46+ </h1>
47+ <span class="gordon-v-subtitle text-gordonmascot-mblue text-sm"
48+ >v0.0.1</span
49+ >
50+ </div>
51+ <!--(Navigation) -->
52+ <div id="menu-leftnav" class="w-full">
53+ <ul
54+ class="flex flex-col md:space-y-6 md:py-8 font-semibold text-gray-100 text-lg md:text-2xl md:pl-4"
55+ >
56+ <li class="flex items-center">
57+ <i class="iconoir-dashboard-speed mr-2 md:text-3xl"></i>
58+ <a href="index.html">Dashboard</a>
59+ </li>
60+ <li class="flex items-center">
61+ <i class="iconoir-server mr-2 md:text-3xl"></i>
62+ <a href="#manager">Manager</a>
63+ </li>
64+ <li class="flex items-center">
65+ <i class="iconoir-community mr-2 md:text-3xl"></i>
66+ <a href="#users">Users</a>
67+ </li>
68+ <li class="flex items-center">
69+ <i class="iconoir-database-settings mr-2 md:text-3xl"></i>
70+ <a href="#gordon-settings">Settings</a>
71+ </li>
72+ </ul>
73+ </div>
74+
75+ <div class="w-full h-24 bg-gordonmascot-mblue rounded-lg"></div>
76+ <!-- Mock menu item -->
77+ </div>
78+ </div>
79+
80+ <!-- Main Content including the navbar -->
81+ <div class="flex-1 flex flex-col md:pt-10 space-y-4 ml-4">
82+ <!-- Search Nav within the main content -->
83+ <div class="mb-4 flex justify-end">
84+ <div class="w-72 h-10 bg-gray-300 rounded-lg">
85+ <!-- Search input with iconir search -->
86+ <div class="flex justify-between items-center h-full px-2">
87+ <input
88+ type="text"
89+ class="w-full h-full bg-transparent outline-none"
90+ placeholder="Search"
91+ />
92+ <i class="iconoir-search"></i>
93+ </div>
94+ </div>
95+ <!-- Mock search or other element -->
96+ </div>
97+
98+ <!-- Cards section -->
99+ <div class="flex space-x-4 flex-grow">
100+ <!-- Main Card on the Left -->
101+ <div class="w-4/6 bg-white p-4 rounded-md shadow mb-4">
102+ <div class="w-full rounded-sm bg-gray-300"></div>
103+ <!-- Mock main card -->
104+ </div>
105+
106+ <!-- Two Cards on the Right -->
107+ <div class="w-2/6 flex flex-col flex-justify-start">
108+ <div class="bg-white p-4 rounded-md shadow mb-4">
109+ <div class="w-full h-44 rounded-sm bg-gray-300"></div>
110+ <!-- Mock card -->
111+ </div>
112+ <div class="bg-white p-4 rounded-md shadow mb-4">
113+ <div class="w-full h-44 rounded-sm bg-gray-300"></div>
114+ <!-- Mock card -->
115+ </div>
116+ <div class="bg-white p-4 rounded-md shadow mb-4">
117+ <div class="w-full h-44 rounded-sm bg-gray-300"></div>
118+ <!-- Mock card -->
119+ </div>
120+ </div>
121+ </div>
122+ </div>
123+ </body>
124+</html>
A internal/gotemplate/models/html/admin/install.gohtml +137 -0
@@ -0,0 +1,137 @@
1+<!DOCTYPE html>
2+<html lang="en">
3+ <head>
4+ <meta charset="UTF-8" />
5+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6+ <title>{{ .header.meta.title }}</title>
7+ <meta name="description" content="{{ .Header.Meta.Description }}" />
8+ <meta name="keywords" content="{{ .Header.Meta.Keywords }}" />
9+ <!-- Custom CSS + Tailwind -->
10+ <link rel="stylesheet" href="/assets/css/tailwind.css" />
11+ <!-- Iconoir -->
12+ <link rel="stylesheet" href="/libs/iconoir.css" />
13+ <!-- Alpine -->
14+ <script src="/libs/alpine.min.js"></script>
15+ <!-- HTMX min js -->
16+ <script src="/libs/htmx.min.js"></script>
17+ <!-- HTMX SSE -->
18+ <script src="/libs/htmx-sse.js"></script>
19+ <!-- Custom JS from assets/js -->
20+ <script src="/assets/js/custom.js"></script>
21+ </head>
22+
23+ <body
24+ class="IBMPlexSans bg-zinc-200 md:p-8 flex flex-col items-center"
25+ hx-boost="true"
26+ >
27+ <!-- Logo and Title -->
28+ <div
29+ id="logo-mascot"
30+ class="flex flex-col justify-center items-center p-4 mb-4"
31+ >
32+ <div class="circle-shadow flex justify-center w-100">
33+ <img
34+ src="/assets/imgs/gordon-mascot-hq-trsp.png"
35+ alt="logo"
36+ class="sm:h-24 h-32 xl:h-48"
37+ />
38+ </div>
39+ <div class="flex justify-center mt-4">
40+ <h1
41+ class="gordon-title text-2xl lg:text-4xl xl:text-5xl text-gordonmascot-hblue tracking-tighter"
42+ >
43+ Gordon
44+ </h1>
45+ <span class="gordon-v-subtitle text-gordonmascot-mblue text-sm ml-2"
46+ >v0.0.1</span
47+ >
48+ </div>
49+ </div>
50+
51+ <!-- Main Content -->
52+ <div class="bg-white p-4 rounded-md shadow mb-4 w-2/3">
53+ <!-- Install Traefik -->
54+ <div id="install-traefik">
55+ <div class="flex flex-col items-center">
56+ <h2 class="text-2xl font-semibold text-gray-800">
57+ 1 - Install Traefik
58+ </h2>
59+ <!-- Dual view left : install procedure / right : SSE log installation -->
60+ <div class="flex flex-col md:flex-row justify-items-center w-full">
61+ <!-- Left -->
62+ <div class="w-full md:w-1/2 p-4">
63+ <form
64+ id="install-traefik-form"
65+ action="/admin/install/traefik"
66+ method="POST"
67+ hx-post="/admin/install/traefik"
68+ hx-swap="outerHTML"
69+ >
70+ <h2 class="">1.1 - Set your top domain name</h2>
71+ <input
72+ type="text"
73+ name="topdomain"
74+ id="topdomain"
75+ class="w-full py-2 px-4 my-2 border border-gray-300 rounded-md"
76+ placeholder="example.com"
77+ />
78+ <h2>1.2 - Set your admin email (a reachable one)</h2>
79+ <input
80+ type="text"
81+ name="adminemail"
82+ id="adminemail"
83+ class="w-full p-2 border border-gray-300 rounded-md"
84+ placeholder="admin@example.com"
85+ />
86+ <button
87+ type="submit"
88+ class="w-full p-2 bg-gordonmascot-hblue text-slate-100 rounded-md mt-4"
89+ >
90+ Save & Install Traefik
91+ </button>
92+ </form>
93+ </div>
94+ <!-- Right -->
95+ <div class="w-full md:w-1/2 p-4 text-slate-100">
96+ <div
97+ class="flex flex-col items-center bg-gordonmascot-hblue rounded-md"
98+ >
99+ <div class="w-full h-64 overflow-y-scroll-auto p-4">
100+ <div
101+ class="flex flex-col space-y-2"
102+ hx-ext="sse"
103+ sse-connect="/admin/install/traefik/sse"
104+ >
105+ <!-- One item -->
106+ <div class="flex flex-row items-center">
107+ <span class="">[INFO]</span>
108+ <span class="">Traefik installed</span>
109+ </div>
110+ <!-- One item -->
111+ <div class="flex flex-row items-center">
112+ <span class="">[INFO]</span>
113+ <span class="ml-2">Traefik started</span>
114+ </div>
115+ <!-- One item -->
116+ <div class="flex flex-row items-center">
117+ <span class="">[INFO]</span>
118+ <span class="ml-2"
119+ >Traefik configuration file created</span
120+ >
121+ </div>
122+ <!-- One item -->
123+ <div class="flex flex-row items-center">
124+ <span class="">[INFO]</span>
125+ <span class="">Traefik configuration file updated</span>
126+ </div>
127+ </div>
128+ </div>
129+ </div>
130+ </div>
131+ </div>
132+ </div>
133+ </div>
134+ <!-- End Install Traefik -->
135+ </div>
136+ </body>
137+</html>
@@ -0,0 +1,137 @@
1+<!DOCTYPE html>
2+<html lang="en">
3+ <head>
4+ <meta charset="UTF-8" />
5+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6+ <title>{{ .header.meta.title }}</title>
7+ <meta name="description" content="{{ .Header.Meta.Description }}" />
8+ <meta name="keywords" content="{{ .Header.Meta.Keywords }}" />
9+ <!-- Custom CSS + Tailwind -->
10+ <link rel="stylesheet" href="/assets/css/tailwind.css" />
11+ <!-- Iconoir -->
12+ <link rel="stylesheet" href="/libs/iconoir.css" />
13+ <!-- Alpine -->
14+ <script src="/libs/alpine.min.js"></script>
15+ <!-- HTMX min js -->
16+ <script src="/libs/htmx.min.js"></script>
17+ <!-- HTMX SSE -->
18+ <script src="/libs/htmx-sse.js"></script>
19+ <!-- Custom JS from assets/js -->
20+ <script src="/assets/js/custom.js"></script>
21+ </head>
22+
23+ <body
24+ class="IBMPlexSans bg-zinc-200 md:p-8 flex flex-col items-center"
25+ hx-boost="true"
26+ >
27+ <!-- Logo and Title -->
28+ <div
29+ id="logo-mascot"
30+ class="flex flex-col justify-center items-center p-4 mb-4"
31+ >
32+ <div class="circle-shadow flex justify-center w-100">
33+ <img
34+ src="/assets/imgs/gordon-mascot-hq-trsp.png"
35+ alt="logo"
36+ class="sm:h-24 h-32 xl:h-48"
37+ />
38+ </div>
39+ <div class="flex justify-center mt-4">
40+ <h1
41+ class="gordon-title text-2xl lg:text-4xl xl:text-5xl text-gordonmascot-hblue tracking-tighter"
42+ >
43+ Gordon
44+ </h1>
45+ <span class="gordon-v-subtitle text-gordonmascot-mblue text-sm ml-2"
46+ >v0.0.1</span
47+ >
48+ </div>
49+ </div>
50+
51+ <!-- Main Content -->
52+ <div class="bg-white p-4 rounded-md shadow mb-4 w-2/3">
53+ <!-- Install Traefik -->
54+ <div id="install-traefik">
55+ <div class="flex flex-col items-center">
56+ <h2 class="text-2xl font-semibold text-gray-800">
57+ 1 - Install Traefik
58+ </h2>
59+ <!-- Dual view left : install procedure / right : SSE log installation -->
60+ <div class="flex flex-col md:flex-row justify-items-center w-full">
61+ <!-- Left -->
62+ <div class="w-full md:w-1/2 p-4">
63+ <form
64+ id="install-traefik-form"
65+ action="/admin/install/traefik"
66+ method="POST"
67+ hx-post="/admin/install/traefik"
68+ hx-swap="outerHTML"
69+ >
70+ <h2 class="">1.1 - Set your top domain name</h2>
71+ <input
72+ type="text"
73+ name="topdomain"
74+ id="topdomain"
75+ class="w-full py-2 px-4 my-2 border border-gray-300 rounded-md"
76+ placeholder="example.com"
77+ />
78+ <h2>1.2 - Set your admin email (a reachable one)</h2>
79+ <input
80+ type="text"
81+ name="adminemail"
82+ id="adminemail"
83+ class="w-full p-2 border border-gray-300 rounded-md"
84+ placeholder="admin@example.com"
85+ />
86+ <button
87+ type="submit"
88+ class="w-full p-2 bg-gordonmascot-hblue text-slate-100 rounded-md mt-4"
89+ >
90+ Save & Install Traefik
91+ </button>
92+ </form>
93+ </div>
94+ <!-- Right -->
95+ <div class="w-full md:w-1/2 p-4 text-slate-100">
96+ <div
97+ class="flex flex-col items-center bg-gordonmascot-hblue rounded-md"
98+ >
99+ <div class="w-full h-64 overflow-y-scroll-auto p-4">
100+ <div
101+ class="flex flex-col space-y-2"
102+ hx-ext="sse"
103+ sse-connect="/admin/install/traefik/sse"
104+ >
105+ <!-- One item -->
106+ <div class="flex flex-row items-center">
107+ <span class="">[INFO]</span>
108+ <span class="">Traefik installed</span>
109+ </div>
110+ <!-- One item -->
111+ <div class="flex flex-row items-center">
112+ <span class="">[INFO]</span>
113+ <span class="ml-2">Traefik started</span>
114+ </div>
115+ <!-- One item -->
116+ <div class="flex flex-row items-center">
117+ <span class="">[INFO]</span>
118+ <span class="ml-2"
119+ >Traefik configuration file created</span
120+ >
121+ </div>
122+ <!-- One item -->
123+ <div class="flex flex-row items-center">
124+ <span class="">[INFO]</span>
125+ <span class="">Traefik configuration file updated</span>
126+ </div>
127+ </div>
128+ </div>
129+ </div>
130+ </div>
131+ </div>
132+ </div>
133+ </div>
134+ <!-- End Install Traefik -->
135+ </div>
136+ </body>
137+</html>
A internal/gotemplate/models/html/admin/manager.gohtml +0 -0

no textual change.

A internal/gotemplate/models/html/admin/user.gohtml +0 -0

no textual change.

A internal/gotemplate/models/html/fragments/components.gohtml +33 -0
@@ -0,0 +1,33 @@
1+<!-- @format -->
2+
3+<div id="header">
4+ <h1
5+ class="text-5xl fw100 animate-bounce-alt animate-count-infinite animate-duration-1s"
6+ >
7+ {{ .body.header.helloworld }}
8+ </h1>
9+</div>
10+
11+<div id="hello">
12+ <h1
13+ class="text-5xl fw100 animate-bounce-alt animate-count-infinite animate-duration-1s"
14+ >
15+ {{ .body.div.hello }}
16+ </h1>
17+</div>
18+<div
19+ id="header"
20+ hx-get="/htmx"
21+ hx-headers='{"HX-Fragment": "header"}'
22+ hx-trigger="load"
23+ hx-swap="outerHTML"
24+></div>
25+
26+<!-- App Fragment -->
27+<div
28+ id="app"
29+ hx-get="/htmx"
30+ hx-headers='{"HX-Fragment": "hello"}'
31+ hx-trigger="load"
32+ hx-swap="outerHTML"
33+></div>
@@ -0,0 +1,33 @@
1+<!-- @format -->
2+
3+<div id="header">
4+ <h1
5+ class="text-5xl fw100 animate-bounce-alt animate-count-infinite animate-duration-1s"
6+ >
7+ {{ .body.header.helloworld }}
8+ </h1>
9+</div>
10+
11+<div id="hello">
12+ <h1
13+ class="text-5xl fw100 animate-bounce-alt animate-count-infinite animate-duration-1s"
14+ >
15+ {{ .body.div.hello }}
16+ </h1>
17+</div>
18+<div
19+ id="header"
20+ hx-get="/htmx"
21+ hx-headers='{"HX-Fragment": "header"}'
22+ hx-trigger="load"
23+ hx-swap="outerHTML"
24+></div>
25+
26+<!-- App Fragment -->
27+<div
28+ id="app"
29+ hx-get="/htmx"
30+ hx-headers='{"HX-Fragment": "hello"}'
31+ hx-trigger="load"
32+ hx-swap="outerHTML"
33+></div>
A internal/gotemplate/models/html/strings.yml +23 -0
@@ -0,0 +1,23 @@
1+en:
2+ header:
3+ meta:
4+ title: Gordon - Admin Dashboard
5+ description: Admin dashboard for Gordon
6+ keywords: gordon, admin, dashboard
7+ body:
8+ header:
9+ helloworld: Hello World!
10+ div:
11+ hello: Hello component loaded from a template!
12+
13+fr:
14+ header:
15+ meta:
16+ title: Gordon - Tableau de bord administrateur
17+ description: Tableau de bord administrateur pour Gordon
18+ keywords: gordon, admin, dashboard
19+ body:
20+ header:
21+ helloworld: Bonjour le monde!
22+ div:
23+ hello: Composant de salut chargé à partir d'un modèle!
@@ -0,0 +1,23 @@
1+en:
2+ header:
3+ meta:
4+ title: Gordon - Admin Dashboard
5+ description: Admin dashboard for Gordon
6+ keywords: gordon, admin, dashboard
7+ body:
8+ header:
9+ helloworld: Hello World!
10+ div:
11+ hello: Hello component loaded from a template!
12+
13+fr:
14+ header:
15+ meta:
16+ title: Gordon - Tableau de bord administrateur
17+ description: Tableau de bord administrateur pour Gordon
18+ keywords: gordon, admin, dashboard
19+ body:
20+ header:
21+ helloworld: Bonjour le monde!
22+ div:
23+ hello: Composant de salut chargé à partir d'un modèle!
A internal/gotemplate/models/txt/test.txt +0 -0

no textual change.

A internal/httpserve/handler/adminroutes.go +5 -0
@@ -0,0 +1,5 @@
1+package handlers
2+
3+import ()
4+
5+
@@ -0,0 +1,5 @@
1+package handlers
2+
3+import ()
4+
5+
A internal/httpserve/handler/htmx.go +0 -0

no textual change.

A internal/httpserve/handler/static.go +0 -0

no textual change.

A internal/httpserve/middleware/detectcolorscheme.go +0 -0

no textual change.

A internal/httpserve/middleware/detectlang.go +0 -0

no textual change.

A internal/httpserve/middleware/secure.go +0 -0

no textual change.

A internal/httpserve/middleware/tmp/build-errors.log +1 -0
@@ -0,0 +1,1 @@
1+exit status 1⏎̸
@@ -0,0 +1,1 @@
1+exit status 1⏎̸
A internal/httpserve/router.go +0 -0

no textual change.

A internal/webui/embed.go +14 -0
@@ -0,0 +1,14 @@
1+package webui
2+
3+import (
4+ "embed"
5+
6+ "github.com/labstack/echo/v4"
7+)
8+
9+// Embedding the public directory
10+//
11+//go:embed public/*
12+var public embed.FS
13+
14+var PublicFS = echo.MustSubFS(public, "internal/webui/public")
@@ -0,0 +1,14 @@
1+package webui
2+
3+import (
4+ "embed"
5+
6+ "github.com/labstack/echo/v4"
7+)
8+
9+// Embedding the public directory
10+//
11+//go:embed public/*
12+var public embed.FS
13+
14+var PublicFS = echo.MustSubFS(public, "internal/webui/public")
A internal/webui/public/404.gohtml +12 -0
@@ -0,0 +1,12 @@
1+<!DOCTYPE html>
2+<html lang="en">
3+ <head>
4+ <meta charset="UTF-8" />
5+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6+ <title>Error 404</title>
7+ </head>
8+ <body>
9+ <h1>Error 404</h1>
10+ <p>Page not found</p>
11+ </body>
12+</html>
@@ -0,0 +1,12 @@
1+<!DOCTYPE html>
2+<html lang="en">
3+ <head>
4+ <meta charset="UTF-8" />
5+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6+ <title>Error 404</title>
7+ </head>
8+ <body>
9+ <h1>Error 404</h1>
10+ <p>Page not found</p>
11+ </body>
12+</html>
A internal/webui/public/500.gohtml +12 -0
@@ -0,0 +1,12 @@
1+<!DOCTYPE html>
2+<html lang="en">
3+ <head>
4+ <meta charset="UTF-8" />
5+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6+ <title>Error 500</title>
7+ </head>
8+ <body>
9+ <h1>500 Internal Server Error</h1>
10+ <p>Something went really wrong o/</p>
11+ </body>
12+</html>
@@ -0,0 +1,12 @@
1+<!DOCTYPE html>
2+<html lang="en">
3+ <head>
4+ <meta charset="UTF-8" />
5+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6+ <title>Error 500</title>
7+ </head>
8+ <body>
9+ <h1>500 Internal Server Error</h1>
10+ <p>Something went really wrong o/</p>
11+ </body>
12+</html>
A internal/webui/public/android-chrome-192x192.png +0 -0 binary file: no text diff

binary file: no text diff

A internal/webui/public/android-chrome-512x512.png +0 -0 binary file: no text diff

binary file: no text diff

A internal/webui/public/apple-touch-icon.png +0 -0 binary file: no text diff

binary file: no text diff

A internal/webui/public/assets/css/custom.css +116 -0
@@ -0,0 +1,116 @@
1+/**
2+ * Path: internal/ui/public/assets/css/custom.css
3+ *
4+ * @format
5+ */
6+
7+/* Embeded path : assets/css/cutsom.css */
8+
9+@tailwind base;
10+@tailwind components;
11+@tailwind utilities;
12+
13+/* Import IBM Plex Fonts */
14+@font-face {
15+ font-family: "IBMPlexSans-Bold";
16+ src: url("/assets/fonts/IBMPlex/IBMPlexSans-Bold.woff2") format("woff2");
17+ font-weight: bold;
18+ font-style: normal;
19+}
20+
21+@font-face {
22+ font-family: "IBMPlexSans-Regular";
23+ src: url("/assets/fonts/IBMPlex/IBMPlexSans-Regular.woff2") format("woff2");
24+ font-weight: normal;
25+ font-style: normal;
26+}
27+
28+/* Import Jetbrains Mono Nerd Font */
29+@font-face {
30+ font-family: "JetBrainsMono-Nerd-Font-Regular";
31+ src: url("/assets/fonts/JetBrainsMonoNerd/JetBrainsMonoNerdFontMono-Regular.woff2")
32+ format("woff2");
33+ font-weight: normal;
34+ font-style: normal;
35+}
36+
37+@font-face {
38+ font-family: "LilitaOne-Regular";
39+ src: url("/assets/fonts/LilitaOne/LilitaOne-Regular.ttf") format("truetype");
40+ font-weight: normal;
41+ font-style: normal;
42+}
43+
44+.fade-me-out.htmx-swapping {
45+ opacity: 0;
46+ transition: opacity 1s ease-out;
47+}
48+
49+/* View transition */
50+@keyframes fade-in {
51+ from {
52+ opacity: 0;
53+ }
54+}
55+
56+@keyframes fade-out {
57+ to {
58+ opacity: 0;
59+ }
60+}
61+
62+@keyframes slide-from-right {
63+ from {
64+ transform: translateX(90px);
65+ }
66+}
67+
68+@keyframes slide-to-left {
69+ to {
70+ transform: translateX(-90px);
71+ }
72+}
73+
74+.slide-it {
75+ view-transition-name: slide-it;
76+}
77+
78+::view-transition-old(slide-it) {
79+ animation: 180ms cubic-bezier(0.4, 0, 1, 1) both fade-out,
80+ 600ms cubic-bezier(0.4, 0, 0.2, 1) both slide-to-left;
81+}
82+::view-transition-new(slide-it) {
83+ animation: 420ms cubic-bezier(0, 0, 0.2, 1) 90ms both fade-in,
84+ 600ms cubic-bezier(0.4, 0, 0.2, 1) both slide-from-right;
85+}
86+
87+.gordon-title {
88+ font-family: "LilitaOne-Regular", sans-serif;
89+
90+}
91+
92+.IBMPlexSans {
93+ font-family: "IBMPlexSans-Regular", sans-serif;
94+}
95+
96+.circle-shadow {
97+ width: 100%;
98+ position: relative;
99+}
100+
101+.circle-shadow::after {
102+ position: absolute;
103+ width: 50%;
104+ height: 0.4rem;
105+ margin: auto;
106+ background: rgba(0, 0, 0, 0.1);
107+ border-radius: 50%;
108+ z-index: -1;
109+ bottom: 2%;
110+ content: "";
111+ box-shadow: 0 0 1px 0.3rem rgba(0, 0, 0, 0.1);
112+}
113+
114+.iconoir {
115+ margin-right: 8px;
116+}
@@ -0,0 +1,116 @@
1+/**
2+ * Path: internal/ui/public/assets/css/custom.css
3+ *
4+ * @format
5+ */
6+
7+/* Embeded path : assets/css/cutsom.css */
8+
9+@tailwind base;
10+@tailwind components;
11+@tailwind utilities;
12+
13+/* Import IBM Plex Fonts */
14+@font-face {
15+ font-family: "IBMPlexSans-Bold";
16+ src: url("/assets/fonts/IBMPlex/IBMPlexSans-Bold.woff2") format("woff2");
17+ font-weight: bold;
18+ font-style: normal;
19+}
20+
21+@font-face {
22+ font-family: "IBMPlexSans-Regular";
23+ src: url("/assets/fonts/IBMPlex/IBMPlexSans-Regular.woff2") format("woff2");
24+ font-weight: normal;
25+ font-style: normal;
26+}
27+
28+/* Import Jetbrains Mono Nerd Font */
29+@font-face {
30+ font-family: "JetBrainsMono-Nerd-Font-Regular";
31+ src: url("/assets/fonts/JetBrainsMonoNerd/JetBrainsMonoNerdFontMono-Regular.woff2")
32+ format("woff2");
33+ font-weight: normal;
34+ font-style: normal;
35+}
36+
37+@font-face {
38+ font-family: "LilitaOne-Regular";
39+ src: url("/assets/fonts/LilitaOne/LilitaOne-Regular.ttf") format("truetype");
40+ font-weight: normal;
41+ font-style: normal;
42+}
43+
44+.fade-me-out.htmx-swapping {
45+ opacity: 0;
46+ transition: opacity 1s ease-out;
47+}
48+
49+/* View transition */
50+@keyframes fade-in {
51+ from {
52+ opacity: 0;
53+ }
54+}
55+
56+@keyframes fade-out {
57+ to {
58+ opacity: 0;
59+ }
60+}
61+
62+@keyframes slide-from-right {
63+ from {
64+ transform: translateX(90px);
65+ }
66+}
67+
68+@keyframes slide-to-left {
69+ to {
70+ transform: translateX(-90px);
71+ }
72+}
73+
74+.slide-it {
75+ view-transition-name: slide-it;
76+}
77+
78+::view-transition-old(slide-it) {
79+ animation: 180ms cubic-bezier(0.4, 0, 1, 1) both fade-out,
80+ 600ms cubic-bezier(0.4, 0, 0.2, 1) both slide-to-left;
81+}
82+::view-transition-new(slide-it) {
83+ animation: 420ms cubic-bezier(0, 0, 0.2, 1) 90ms both fade-in,
84+ 600ms cubic-bezier(0.4, 0, 0.2, 1) both slide-from-right;
85+}
86+
87+.gordon-title {
88+ font-family: "LilitaOne-Regular", sans-serif;
89+
90+}
91+
92+.IBMPlexSans {
93+ font-family: "IBMPlexSans-Regular", sans-serif;
94+}
95+
96+.circle-shadow {
97+ width: 100%;
98+ position: relative;
99+}
100+
101+.circle-shadow::after {
102+ position: absolute;
103+ width: 50%;
104+ height: 0.4rem;
105+ margin: auto;
106+ background: rgba(0, 0, 0, 0.1);
107+ border-radius: 50%;
108+ z-index: -1;
109+ bottom: 2%;
110+ content: "";
111+ box-shadow: 0 0 1px 0.3rem rgba(0, 0, 0, 0.1);
112+}
113+
114+.iconoir {
115+ margin-right: 8px;
116+}
A internal/webui/public/assets/css/tailwind.css +1046 -0
@@ -0,0 +1,1046 @@
1+/**
2+ * Path: internal/ui/public/assets/css/custom.css
3+ *
4+ * @format
5+ */
6+
7+/* Embeded path : assets/css/cutsom.css */
8+
9+/*! tailwindcss v3.3.3 | MIT License | https://tailwindcss.com
10+ */
11+
12+/*
13+1. Prevent padding and border from affecting element width. (https://github.com/mozdevs/cssremedy/issues/4)
14+2. Allow adding a border to an element by just adding a border-width. (https://github.com/tailwindcss/tailwindcss/pull/116)
15+*/
16+
17+*,
18+::before,
19+::after {
20+ box-sizing: border-box;
21+ /* 1 */
22+ border-width: 0;
23+ /* 2 */
24+ border-style: solid;
25+ /* 2 */
26+ border-color: #e5e7eb;
27+ /* 2 */
28+}
29+
30+::before,
31+::after {
32+ --tw-content: '';
33+}
34+
35+/*
36+1. Use a consistent sensible line-height in all browsers.
37+2. Prevent adjustments of font size after orientation changes in iOS.
38+3. Use a more readable tab size.
39+4. Use the user's configured `sans` font-family by default.
40+5. Use the user's configured `sans` font-feature-settings by default.
41+6. Use the user's configured `sans` font-variation-settings by default.
42+*/
43+
44+html {
45+ line-height: 1.5;
46+ /* 1 */
47+ -webkit-text-size-adjust: 100%;
48+ /* 2 */
49+ -moz-tab-size: 4;
50+ /* 3 */
51+ -o-tab-size: 4;
52+ tab-size: 4;
53+ /* 3 */
54+ font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
55+ /* 4 */
56+ font-feature-settings: normal;
57+ /* 5 */
58+ font-variation-settings: normal;
59+ /* 6 */
60+}
61+
62+/*
63+1. Remove the margin in all browsers.
64+2. Inherit line-height from `html` so users can set them as a class directly on the `html` element.
65+*/
66+
67+body {
68+ margin: 0;
69+ /* 1 */
70+ line-height: inherit;
71+ /* 2 */
72+}
73+
74+/*
75+1. Add the correct height in Firefox.
76+2. Correct the inheritance of border color in Firefox. (https://bugzilla.mozilla.org/show_bug.cgi?id=190655)
77+3. Ensure horizontal rules are visible by default.
78+*/
79+
80+hr {
81+ height: 0;
82+ /* 1 */
83+ color: inherit;
84+ /* 2 */
85+ border-top-width: 1px;
86+ /* 3 */
87+}
88+
89+/*
90+Add the correct text decoration in Chrome, Edge, and Safari.
91+*/
92+
93+abbr:where([title]) {
94+ -webkit-text-decoration: underline dotted;
95+ text-decoration: underline dotted;
96+}
97+
98+/*
99+Remove the default font size and weight for headings.
100+*/
101+
102+h1,
103+h2,
104+h3,
105+h4,
106+h5,
107+h6 {
108+ font-size: inherit;
109+ font-weight: inherit;
110+}
111+
112+/*
113+Reset links to optimize for opt-in styling instead of opt-out.
114+*/
115+
116+a {
117+ color: inherit;
118+ text-decoration: inherit;
119+}
120+
121+/*
122+Add the correct font weight in Edge and Safari.
123+*/
124+
125+b,
126+strong {
127+ font-weight: bolder;
128+}
129+
130+/*
131+1. Use the user's configured `mono` font family by default.
132+2. Correct the odd `em` font sizing in all browsers.
133+*/
134+
135+code,
136+kbd,
137+samp,
138+pre {
139+ font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
140+ /* 1 */
141+ font-size: 1em;
142+ /* 2 */
143+}
144+
145+/*
146+Add the correct font size in all browsers.
147+*/
148+
149+small {
150+ font-size: 80%;
151+}
152+
153+/*
154+Prevent `sub` and `sup` elements from affecting the line height in all browsers.
155+*/
156+
157+sub,
158+sup {
159+ font-size: 75%;
160+ line-height: 0;
161+ position: relative;
162+ vertical-align: baseline;
163+}
164+
165+sub {
166+ bottom: -0.25em;
167+}
168+
169+sup {
170+ top: -0.5em;
171+}
172+
173+/*
174+1. Remove text indentation from table contents in Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=999088, https://bugs.webkit.org/show_bug.cgi?id=201297)
175+2. Correct table border color inheritance in all Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=935729, https://bugs.webkit.org/show_bug.cgi?id=195016)
176+3. Remove gaps between table borders by default.
177+*/
178+
179+table {
180+ text-indent: 0;
181+ /* 1 */
182+ border-color: inherit;
183+ /* 2 */
184+ border-collapse: collapse;
185+ /* 3 */
186+}
187+
188+/*
189+1. Change the font styles in all browsers.
190+2. Remove the margin in Firefox and Safari.
191+3. Remove default padding in all browsers.
192+*/
193+
194+button,
195+input,
196+optgroup,
197+select,
198+textarea {
199+ font-family: inherit;
200+ /* 1 */
201+ font-feature-settings: inherit;
202+ /* 1 */
203+ font-variation-settings: inherit;
204+ /* 1 */
205+ font-size: 100%;
206+ /* 1 */
207+ font-weight: inherit;
208+ /* 1 */
209+ line-height: inherit;
210+ /* 1 */
211+ color: inherit;
212+ /* 1 */
213+ margin: 0;
214+ /* 2 */
215+ padding: 0;
216+ /* 3 */
217+}
218+
219+/*
220+Remove the inheritance of text transform in Edge and Firefox.
221+*/
222+
223+button,
224+select {
225+ text-transform: none;
226+}
227+
228+/*
229+1. Correct the inability to style clickable types in iOS and Safari.
230+2. Remove default button styles.
231+*/
232+
233+button,
234+[type='button'],
235+[type='reset'],
236+[type='submit'] {
237+ -webkit-appearance: button;
238+ /* 1 */
239+ background-color: transparent;
240+ /* 2 */
241+ background-image: none;
242+ /* 2 */
243+}
244+
245+/*
246+Use the modern Firefox focus style for all focusable elements.
247+*/
248+
249+:-moz-focusring {
250+ outline: auto;
251+}
252+
253+/*
254+Remove the additional `:invalid` styles in Firefox. (https://github.com/mozilla/gecko-dev/blob/2f9eacd9d3d995c937b4251a5557d95d494c9be1/layout/style/res/forms.css#L728-L737)
255+*/
256+
257+:-moz-ui-invalid {
258+ box-shadow: none;
259+}
260+
261+/*
262+Add the correct vertical alignment in Chrome and Firefox.
263+*/
264+
265+progress {
266+ vertical-align: baseline;
267+}
268+
269+/*
270+Correct the cursor style of increment and decrement buttons in Safari.
271+*/
272+
273+::-webkit-inner-spin-button,
274+::-webkit-outer-spin-button {
275+ height: auto;
276+}
277+
278+/*
279+1. Correct the odd appearance in Chrome and Safari.
280+2. Correct the outline style in Safari.
281+*/
282+
283+[type='search'] {
284+ -webkit-appearance: textfield;
285+ /* 1 */
286+ outline-offset: -2px;
287+ /* 2 */
288+}
289+
290+/*
291+Remove the inner padding in Chrome and Safari on macOS.
292+*/
293+
294+::-webkit-search-decoration {
295+ -webkit-appearance: none;
296+}
297+
298+/*
299+1. Correct the inability to style clickable types in iOS and Safari.
300+2. Change font properties to `inherit` in Safari.
301+*/
302+
303+::-webkit-file-upload-button {
304+ -webkit-appearance: button;
305+ /* 1 */
306+ font: inherit;
307+ /* 2 */
308+}
309+
310+/*
311+Add the correct display in Chrome and Safari.
312+*/
313+
314+summary {
315+ display: list-item;
316+}
317+
318+/*
319+Removes the default spacing and border for appropriate elements.
320+*/
321+
322+blockquote,
323+dl,
324+dd,
325+h1,
326+h2,
327+h3,
328+h4,
329+h5,
330+h6,
331+hr,
332+figure,
333+p,
334+pre {
335+ margin: 0;
336+}
337+
338+fieldset {
339+ margin: 0;
340+ padding: 0;
341+}
342+
343+legend {
344+ padding: 0;
345+}
346+
347+ol,
348+ul,
349+menu {
350+ list-style: none;
351+ margin: 0;
352+ padding: 0;
353+}
354+
355+/*
356+Reset default styling for dialogs.
357+*/
358+
359+dialog {
360+ padding: 0;
361+}
362+
363+/*
364+Prevent resizing textareas horizontally by default.
365+*/
366+
367+textarea {
368+ resize: vertical;
369+}
370+
371+/*
372+1. Reset the default placeholder opacity in Firefox. (https://github.com/tailwindlabs/tailwindcss/issues/3300)
373+2. Set the default placeholder color to the user's configured gray 400 color.
374+*/
375+
376+input::-moz-placeholder, textarea::-moz-placeholder {
377+ opacity: 1;
378+ /* 1 */
379+ color: #9ca3af;
380+ /* 2 */
381+}
382+
383+input::placeholder,
384+textarea::placeholder {
385+ opacity: 1;
386+ /* 1 */
387+ color: #9ca3af;
388+ /* 2 */
389+}
390+
391+/*
392+Set the default cursor for buttons.
393+*/
394+
395+button,
396+[role="button"] {
397+ cursor: pointer;
398+}
399+
400+/*
401+Make sure disabled buttons don't get the pointer cursor.
402+*/
403+
404+:disabled {
405+ cursor: default;
406+}
407+
408+/*
409+1. Make replaced elements `display: block` by default. (https://github.com/mozdevs/cssremedy/issues/14)
410+2. Add `vertical-align: middle` to align replaced elements more sensibly by default. (https://github.com/jensimmons/cssremedy/issues/14#issuecomment-634934210)
411+ This can trigger a poorly considered lint error in some tools but is included by design.
412+*/
413+
414+img,
415+svg,
416+video,
417+canvas,
418+audio,
419+iframe,
420+embed,
421+object {
422+ display: block;
423+ /* 1 */
424+ vertical-align: middle;
425+ /* 2 */
426+}
427+
428+/*
429+Constrain images and videos to the parent width and preserve their intrinsic aspect ratio. (https://github.com/mozdevs/cssremedy/issues/14)
430+*/
431+
432+img,
433+video {
434+ max-width: 100%;
435+ height: auto;
436+}
437+
438+/* Make elements with the HTML hidden attribute stay hidden by default */
439+
440+[hidden] {
441+ display: none;
442+}
443+
444+*, ::before, ::after {
445+ --tw-border-spacing-x: 0;
446+ --tw-border-spacing-y: 0;
447+ --tw-translate-x: 0;
448+ --tw-translate-y: 0;
449+ --tw-rotate: 0;
450+ --tw-skew-x: 0;
451+ --tw-skew-y: 0;
452+ --tw-scale-x: 1;
453+ --tw-scale-y: 1;
454+ --tw-pan-x: ;
455+ --tw-pan-y: ;
456+ --tw-pinch-zoom: ;
457+ --tw-scroll-snap-strictness: proximity;
458+ --tw-gradient-from-position: ;
459+ --tw-gradient-via-position: ;
460+ --tw-gradient-to-position: ;
461+ --tw-ordinal: ;
462+ --tw-slashed-zero: ;
463+ --tw-numeric-figure: ;
464+ --tw-numeric-spacing: ;
465+ --tw-numeric-fraction: ;
466+ --tw-ring-inset: ;
467+ --tw-ring-offset-width: 0px;
468+ --tw-ring-offset-color: #fff;
469+ --tw-ring-color: rgb(59 130 246 / 0.5);
470+ --tw-ring-offset-shadow: 0 0 #0000;
471+ --tw-ring-shadow: 0 0 #0000;
472+ --tw-shadow: 0 0 #0000;
473+ --tw-shadow-colored: 0 0 #0000;
474+ --tw-blur: ;
475+ --tw-brightness: ;
476+ --tw-contrast: ;
477+ --tw-grayscale: ;
478+ --tw-hue-rotate: ;
479+ --tw-invert: ;
480+ --tw-saturate: ;
481+ --tw-sepia: ;
482+ --tw-drop-shadow: ;
483+ --tw-backdrop-blur: ;
484+ --tw-backdrop-brightness: ;
485+ --tw-backdrop-contrast: ;
486+ --tw-backdrop-grayscale: ;
487+ --tw-backdrop-hue-rotate: ;
488+ --tw-backdrop-invert: ;
489+ --tw-backdrop-opacity: ;
490+ --tw-backdrop-saturate: ;
491+ --tw-backdrop-sepia: ;
492+}
493+
494+::backdrop {
495+ --tw-border-spacing-x: 0;
496+ --tw-border-spacing-y: 0;
497+ --tw-translate-x: 0;
498+ --tw-translate-y: 0;
499+ --tw-rotate: 0;
500+ --tw-skew-x: 0;
501+ --tw-skew-y: 0;
502+ --tw-scale-x: 1;
503+ --tw-scale-y: 1;
504+ --tw-pan-x: ;
505+ --tw-pan-y: ;
506+ --tw-pinch-zoom: ;
507+ --tw-scroll-snap-strictness: proximity;
508+ --tw-gradient-from-position: ;
509+ --tw-gradient-via-position: ;
510+ --tw-gradient-to-position: ;
511+ --tw-ordinal: ;
512+ --tw-slashed-zero: ;
513+ --tw-numeric-figure: ;
514+ --tw-numeric-spacing: ;
515+ --tw-numeric-fraction: ;
516+ --tw-ring-inset: ;
517+ --tw-ring-offset-width: 0px;
518+ --tw-ring-offset-color: #fff;
519+ --tw-ring-color: rgb(59 130 246 / 0.5);
520+ --tw-ring-offset-shadow: 0 0 #0000;
521+ --tw-ring-shadow: 0 0 #0000;
522+ --tw-shadow: 0 0 #0000;
523+ --tw-shadow-colored: 0 0 #0000;
524+ --tw-blur: ;
525+ --tw-brightness: ;
526+ --tw-contrast: ;
527+ --tw-grayscale: ;
528+ --tw-hue-rotate: ;
529+ --tw-invert: ;
530+ --tw-saturate: ;
531+ --tw-sepia: ;
532+ --tw-drop-shadow: ;
533+ --tw-backdrop-blur: ;
534+ --tw-backdrop-brightness: ;
535+ --tw-backdrop-contrast: ;
536+ --tw-backdrop-grayscale: ;
537+ --tw-backdrop-hue-rotate: ;
538+ --tw-backdrop-invert: ;
539+ --tw-backdrop-opacity: ;
540+ --tw-backdrop-saturate: ;
541+ --tw-backdrop-sepia: ;
542+}
543+
544+.my-2 {
545+ margin-top: 0.5rem;
546+ margin-bottom: 0.5rem;
547+}
548+
549+.mb-4 {
550+ margin-bottom: 1rem;
551+}
552+
553+.ml-2 {
554+ margin-left: 0.5rem;
555+}
556+
557+.ml-4 {
558+ margin-left: 1rem;
559+}
560+
561+.mr-2 {
562+ margin-right: 0.5rem;
563+}
564+
565+.mt-4 {
566+ margin-top: 1rem;
567+}
568+
569+.flex {
570+ display: flex;
571+}
572+
573+.h-10 {
574+ height: 2.5rem;
575+}
576+
577+.h-24 {
578+ height: 6rem;
579+}
580+
581+.h-32 {
582+ height: 8rem;
583+}
584+
585+.h-44 {
586+ height: 11rem;
587+}
588+
589+.h-64 {
590+ height: 16rem;
591+}
592+
593+.h-full {
594+ height: 100%;
595+}
596+
597+.w-1\/5 {
598+ width: 20%;
599+}
600+
601+.w-2\/6 {
602+ width: 33.333333%;
603+}
604+
605+.w-4\/6 {
606+ width: 66.666667%;
607+}
608+
609+.w-72 {
610+ width: 18rem;
611+}
612+
613+.w-full {
614+ width: 100%;
615+}
616+
617+.w-2\/3 {
618+ width: 66.666667%;
619+}
620+
621+.w-screen {
622+ width: 100vw;
623+}
624+
625+.w-96 {
626+ width: 24rem;
627+}
628+
629+.flex-1 {
630+ flex: 1 1 0%;
631+}
632+
633+.flex-grow {
634+ flex-grow: 1;
635+}
636+
637+.flex-row {
638+ flex-direction: row;
639+}
640+
641+.flex-col {
642+ flex-direction: column;
643+}
644+
645+.items-center {
646+ align-items: center;
647+}
648+
649+.justify-end {
650+ justify-content: flex-end;
651+}
652+
653+.justify-center {
654+ justify-content: center;
655+}
656+
657+.justify-between {
658+ justify-content: space-between;
659+}
660+
661+.justify-items-center {
662+ justify-items: center;
663+}
664+
665+.space-x-4 > :not([hidden]) ~ :not([hidden]) {
666+ --tw-space-x-reverse: 0;
667+ margin-right: calc(1rem * var(--tw-space-x-reverse));
668+ margin-left: calc(1rem * calc(1 - var(--tw-space-x-reverse)));
669+}
670+
671+.space-y-2 > :not([hidden]) ~ :not([hidden]) {
672+ --tw-space-y-reverse: 0;
673+ margin-top: calc(0.5rem * calc(1 - var(--tw-space-y-reverse)));
674+ margin-bottom: calc(0.5rem * var(--tw-space-y-reverse));
675+}
676+
677+.space-y-4 > :not([hidden]) ~ :not([hidden]) {
678+ --tw-space-y-reverse: 0;
679+ margin-top: calc(1rem * calc(1 - var(--tw-space-y-reverse)));
680+ margin-bottom: calc(1rem * var(--tw-space-y-reverse));
681+}
682+
683+.space-x-3 > :not([hidden]) ~ :not([hidden]) {
684+ --tw-space-x-reverse: 0;
685+ margin-right: calc(0.75rem * var(--tw-space-x-reverse));
686+ margin-left: calc(0.75rem * calc(1 - var(--tw-space-x-reverse)));
687+}
688+
689+.space-y-3 > :not([hidden]) ~ :not([hidden]) {
690+ --tw-space-y-reverse: 0;
691+ margin-top: calc(0.75rem * calc(1 - var(--tw-space-y-reverse)));
692+ margin-bottom: calc(0.75rem * var(--tw-space-y-reverse));
693+}
694+
695+.overflow-y-scroll {
696+ overflow-y: scroll;
697+}
698+
699+.rounded-lg {
700+ border-radius: 0.5rem;
701+}
702+
703+.rounded-md {
704+ border-radius: 0.375rem;
705+}
706+
707+.rounded-sm {
708+ border-radius: 0.125rem;
709+}
710+
711+.border {
712+ border-width: 1px;
713+}
714+
715+.border-gray-300 {
716+ --tw-border-opacity: 1;
717+ border-color: rgb(209 213 219 / var(--tw-border-opacity));
718+}
719+
720+.bg-gordonmascot-lblue {
721+ --tw-bg-opacity: 1;
722+ background-color: rgb(0 123 192 / var(--tw-bg-opacity));
723+}
724+
725+.bg-gordonmascot-mblue {
726+ --tw-bg-opacity: 1;
727+ background-color: rgb(0 82 147 / var(--tw-bg-opacity));
728+}
729+
730+.bg-gray-300 {
731+ --tw-bg-opacity: 1;
732+ background-color: rgb(209 213 219 / var(--tw-bg-opacity));
733+}
734+
735+.bg-transparent {
736+ background-color: transparent;
737+}
738+
739+.bg-white {
740+ --tw-bg-opacity: 1;
741+ background-color: rgb(255 255 255 / var(--tw-bg-opacity));
742+}
743+
744+.bg-zinc-200 {
745+ --tw-bg-opacity: 1;
746+ background-color: rgb(228 228 231 / var(--tw-bg-opacity));
747+}
748+
749+.bg-gordonmascot-hblue {
750+ --tw-bg-opacity: 1;
751+ background-color: rgb(1 30 92 / var(--tw-bg-opacity));
752+}
753+
754+.bg-zinc-400 {
755+ --tw-bg-opacity: 1;
756+ background-color: rgb(161 161 170 / var(--tw-bg-opacity));
757+}
758+
759+.p-4 {
760+ padding: 1rem;
761+}
762+
763+.p-2 {
764+ padding: 0.5rem;
765+}
766+
767+.px-2 {
768+ padding-left: 0.5rem;
769+ padding-right: 0.5rem;
770+}
771+
772+.px-6 {
773+ padding-left: 1.5rem;
774+ padding-right: 1.5rem;
775+}
776+
777+.py-2 {
778+ padding-top: 0.5rem;
779+ padding-bottom: 0.5rem;
780+}
781+
782+.px-4 {
783+ padding-left: 1rem;
784+ padding-right: 1rem;
785+}
786+
787+.text-2xl {
788+ font-size: 1.5rem;
789+ line-height: 2rem;
790+}
791+
792+.text-5xl {
793+ font-size: 3rem;
794+ line-height: 1;
795+}
796+
797+.text-lg {
798+ font-size: 1.125rem;
799+ line-height: 1.75rem;
800+}
801+
802+.text-sm {
803+ font-size: 0.875rem;
804+ line-height: 1.25rem;
805+}
806+
807+.text-xl {
808+ font-size: 1.25rem;
809+ line-height: 1.75rem;
810+}
811+
812+.font-semibold {
813+ font-weight: 600;
814+}
815+
816+.tracking-tighter {
817+ letter-spacing: -0.05em;
818+}
819+
820+.text-gordonmascot-hblue {
821+ --tw-text-opacity: 1;
822+ color: rgb(1 30 92 / var(--tw-text-opacity));
823+}
824+
825+.text-gordonmascot-mblue {
826+ --tw-text-opacity: 1;
827+ color: rgb(0 82 147 / var(--tw-text-opacity));
828+}
829+
830+.text-gray-100 {
831+ --tw-text-opacity: 1;
832+ color: rgb(243 244 246 / var(--tw-text-opacity));
833+}
834+
835+.text-gray-800 {
836+ --tw-text-opacity: 1;
837+ color: rgb(31 41 55 / var(--tw-text-opacity));
838+}
839+
840+.text-slate-400 {
841+ --tw-text-opacity: 1;
842+ color: rgb(148 163 184 / var(--tw-text-opacity));
843+}
844+
845+.text-slate-100 {
846+ --tw-text-opacity: 1;
847+ color: rgb(241 245 249 / var(--tw-text-opacity));
848+}
849+
850+.shadow {
851+ --tw-shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1);
852+ --tw-shadow-colored: 0 1px 3px 0 var(--tw-shadow-color), 0 1px 2px -1px var(--tw-shadow-color);
853+ box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
854+}
855+
856+.outline-none {
857+ outline: 2px solid transparent;
858+ outline-offset: 2px;
859+}
860+
861+/* Import IBM Plex Fonts */
862+
863+@font-face {
864+ font-family: "IBMPlexSans-Bold";
865+
866+ src: url("/assets/fonts/IBMPlex/IBMPlexSans-Bold.woff2") format("woff2");
867+
868+ font-weight: bold;
869+
870+ font-style: normal;
871+}
872+
873+@font-face {
874+ font-family: "IBMPlexSans-Regular";
875+
876+ src: url("/assets/fonts/IBMPlex/IBMPlexSans-Regular.woff2") format("woff2");
877+
878+ font-weight: normal;
879+
880+ font-style: normal;
881+}
882+
883+/* Import Jetbrains Mono Nerd Font */
884+
885+@font-face {
886+ font-family: "JetBrainsMono-Nerd-Font-Regular";
887+
888+ src: url("/assets/fonts/JetBrainsMonoNerd/JetBrainsMonoNerdFontMono-Regular.woff2")
889+ format("woff2");
890+
891+ font-weight: normal;
892+
893+ font-style: normal;
894+}
895+
896+@font-face {
897+ font-family: "LilitaOne-Regular";
898+
899+ src: url("/assets/fonts/LilitaOne/LilitaOne-Regular.ttf") format("truetype");
900+
901+ font-weight: normal;
902+
903+ font-style: normal;
904+}
905+
906+.fade-me-out.htmx-swapping {
907+ opacity: 0;
908+ transition: opacity 1s ease-out;
909+}
910+
911+/* View transition */
912+
913+@keyframes fade-in {
914+ from {
915+ opacity: 0;
916+ }
917+}
918+
919+@keyframes fade-out {
920+ to {
921+ opacity: 0;
922+ }
923+}
924+
925+@keyframes slide-from-right {
926+ from {
927+ transform: translateX(90px);
928+ }
929+}
930+
931+@keyframes slide-to-left {
932+ to {
933+ transform: translateX(-90px);
934+ }
935+}
936+
937+.slide-it {
938+ view-transition-name: slide-it;
939+}
940+
941+::view-transition-old(slide-it) {
942+ animation: 180ms cubic-bezier(0.4, 0, 1, 1) both fade-out,
943+ 600ms cubic-bezier(0.4, 0, 0.2, 1) both slide-to-left;
944+}
945+
946+::view-transition-new(slide-it) {
947+ animation: 420ms cubic-bezier(0, 0, 0.2, 1) 90ms both fade-in,
948+ 600ms cubic-bezier(0.4, 0, 0.2, 1) both slide-from-right;
949+}
950+
951+.gordon-title {
952+ font-family: "LilitaOne-Regular", sans-serif;
953+}
954+
955+.IBMPlexSans {
956+ font-family: "IBMPlexSans-Regular", sans-serif;
957+}
958+
959+.circle-shadow {
960+ width: 100%;
961+ position: relative;
962+}
963+
964+.circle-shadow::after {
965+ position: absolute;
966+ width: 50%;
967+ height: 0.4rem;
968+ margin: auto;
969+ background: rgba(0, 0, 0, 0.1);
970+ border-radius: 50%;
971+ z-index: -1;
972+ bottom: 2%;
973+ content: "";
974+ box-shadow: 0 0 1px 0.3rem rgba(0, 0, 0, 0.1);
975+}
976+
977+.iconoir {
978+ margin-right: 8px;
979+}
980+
981+@media (min-width: 640px) {
982+ .sm\:h-24 {
983+ height: 6rem;
984+ }
985+}
986+
987+@media (min-width: 768px) {
988+ .md\:w-1\/2 {
989+ width: 50%;
990+ }
991+
992+ .md\:flex-row {
993+ flex-direction: row;
994+ }
995+
996+ .md\:space-y-6 > :not([hidden]) ~ :not([hidden]) {
997+ --tw-space-y-reverse: 0;
998+ margin-top: calc(1.5rem * calc(1 - var(--tw-space-y-reverse)));
999+ margin-bottom: calc(1.5rem * var(--tw-space-y-reverse));
1000+ }
1001+
1002+ .md\:p-8 {
1003+ padding: 2rem;
1004+ }
1005+
1006+ .md\:py-8 {
1007+ padding-top: 2rem;
1008+ padding-bottom: 2rem;
1009+ }
1010+
1011+ .md\:pl-4 {
1012+ padding-left: 1rem;
1013+ }
1014+
1015+ .md\:pt-10 {
1016+ padding-top: 2.5rem;
1017+ }
1018+
1019+ .md\:text-2xl {
1020+ font-size: 1.5rem;
1021+ line-height: 2rem;
1022+ }
1023+
1024+ .md\:text-3xl {
1025+ font-size: 1.875rem;
1026+ line-height: 2.25rem;
1027+ }
1028+}
1029+
1030+@media (min-width: 1024px) {
1031+ .lg\:text-4xl {
1032+ font-size: 2.25rem;
1033+ line-height: 2.5rem;
1034+ }
1035+}
1036+
1037+@media (min-width: 1280px) {
1038+ .xl\:h-48 {
1039+ height: 12rem;
1040+ }
1041+
1042+ .xl\:text-5xl {
1043+ font-size: 3rem;
1044+ line-height: 1;
1045+ }
1046+}
@@ -0,0 +1,1046 @@
1+/**
2+ * Path: internal/ui/public/assets/css/custom.css
3+ *
4+ * @format
5+ */
6+
7+/* Embeded path : assets/css/cutsom.css */
8+
9+/*! tailwindcss v3.3.3 | MIT License | https://tailwindcss.com
10+ */
11+
12+/*
13+1. Prevent padding and border from affecting element width. (https://github.com/mozdevs/cssremedy/issues/4)
14+2. Allow adding a border to an element by just adding a border-width. (https://github.com/tailwindcss/tailwindcss/pull/116)
15+*/
16+
17+*,
18+::before,
19+::after {
20+ box-sizing: border-box;
21+ /* 1 */
22+ border-width: 0;
23+ /* 2 */
24+ border-style: solid;
25+ /* 2 */
26+ border-color: #e5e7eb;
27+ /* 2 */
28+}
29+
30+::before,
31+::after {
32+ --tw-content: '';
33+}
34+
35+/*
36+1. Use a consistent sensible line-height in all browsers.
37+2. Prevent adjustments of font size after orientation changes in iOS.
38+3. Use a more readable tab size.
39+4. Use the user's configured `sans` font-family by default.
40+5. Use the user's configured `sans` font-feature-settings by default.
41+6. Use the user's configured `sans` font-variation-settings by default.
42+*/
43+
44+html {
45+ line-height: 1.5;
46+ /* 1 */
47+ -webkit-text-size-adjust: 100%;
48+ /* 2 */
49+ -moz-tab-size: 4;
50+ /* 3 */
51+ -o-tab-size: 4;
52+ tab-size: 4;
53+ /* 3 */
54+ font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
55+ /* 4 */
56+ font-feature-settings: normal;
57+ /* 5 */
58+ font-variation-settings: normal;
59+ /* 6 */
60+}
61+
62+/*
63+1. Remove the margin in all browsers.
64+2. Inherit line-height from `html` so users can set them as a class directly on the `html` element.
65+*/
66+
67+body {
68+ margin: 0;
69+ /* 1 */
70+ line-height: inherit;
71+ /* 2 */
72+}
73+
74+/*
75+1. Add the correct height in Firefox.
76+2. Correct the inheritance of border color in Firefox. (https://bugzilla.mozilla.org/show_bug.cgi?id=190655)
77+3. Ensure horizontal rules are visible by default.
78+*/
79+
80+hr {
81+ height: 0;
82+ /* 1 */
83+ color: inherit;
84+ /* 2 */
85+ border-top-width: 1px;
86+ /* 3 */
87+}
88+
89+/*
90+Add the correct text decoration in Chrome, Edge, and Safari.
91+*/
92+
93+abbr:where([title]) {
94+ -webkit-text-decoration: underline dotted;
95+ text-decoration: underline dotted;
96+}
97+
98+/*
99+Remove the default font size and weight for headings.
100+*/
101+
102+h1,
103+h2,
104+h3,
105+h4,
106+h5,
107+h6 {
108+ font-size: inherit;
109+ font-weight: inherit;
110+}
111+
112+/*
113+Reset links to optimize for opt-in styling instead of opt-out.
114+*/
115+
116+a {
117+ color: inherit;
118+ text-decoration: inherit;
119+}
120+
121+/*
122+Add the correct font weight in Edge and Safari.
123+*/
124+
125+b,
126+strong {
127+ font-weight: bolder;
128+}
129+
130+/*
131+1. Use the user's configured `mono` font family by default.
132+2. Correct the odd `em` font sizing in all browsers.
133+*/
134+
135+code,
136+kbd,
137+samp,
138+pre {
139+ font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
140+ /* 1 */
141+ font-size: 1em;
142+ /* 2 */
143+}
144+
145+/*
146+Add the correct font size in all browsers.
147+*/
148+
149+small {
150+ font-size: 80%;
151+}
152+
153+/*
154+Prevent `sub` and `sup` elements from affecting the line height in all browsers.
155+*/
156+
157+sub,
158+sup {
159+ font-size: 75%;
160+ line-height: 0;
161+ position: relative;
162+ vertical-align: baseline;
163+}
164+
165+sub {
166+ bottom: -0.25em;
167+}
168+
169+sup {
170+ top: -0.5em;
171+}
172+
173+/*
174+1. Remove text indentation from table contents in Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=999088, https://bugs.webkit.org/show_bug.cgi?id=201297)
175+2. Correct table border color inheritance in all Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=935729, https://bugs.webkit.org/show_bug.cgi?id=195016)
176+3. Remove gaps between table borders by default.
177+*/
178+
179+table {
180+ text-indent: 0;
181+ /* 1 */
182+ border-color: inherit;
183+ /* 2 */
184+ border-collapse: collapse;
185+ /* 3 */
186+}
187+
188+/*
189+1. Change the font styles in all browsers.
190+2. Remove the margin in Firefox and Safari.
191+3. Remove default padding in all browsers.
192+*/
193+
194+button,
195+input,
196+optgroup,
197+select,
198+textarea {
199+ font-family: inherit;
200+ /* 1 */
201+ font-feature-settings: inherit;
202+ /* 1 */
203+ font-variation-settings: inherit;
204+ /* 1 */
205+ font-size: 100%;
206+ /* 1 */
207+ font-weight: inherit;
208+ /* 1 */
209+ line-height: inherit;
210+ /* 1 */
211+ color: inherit;
212+ /* 1 */
213+ margin: 0;
214+ /* 2 */
215+ padding: 0;
216+ /* 3 */
217+}
218+
219+/*
220+Remove the inheritance of text transform in Edge and Firefox.
221+*/
222+
223+button,
224+select {
225+ text-transform: none;
226+}
227+
228+/*
229+1. Correct the inability to style clickable types in iOS and Safari.
230+2. Remove default button styles.
231+*/
232+
233+button,
234+[type='button'],
235+[type='reset'],
236+[type='submit'] {
237+ -webkit-appearance: button;
238+ /* 1 */
239+ background-color: transparent;
240+ /* 2 */
241+ background-image: none;
242+ /* 2 */
243+}
244+
245+/*
246+Use the modern Firefox focus style for all focusable elements.
247+*/
248+
249+:-moz-focusring {
250+ outline: auto;
251+}
252+
253+/*
254+Remove the additional `:invalid` styles in Firefox. (https://github.com/mozilla/gecko-dev/blob/2f9eacd9d3d995c937b4251a5557d95d494c9be1/layout/style/res/forms.css#L728-L737)
255+*/
256+
257+:-moz-ui-invalid {
258+ box-shadow: none;
259+}
260+
261+/*
262+Add the correct vertical alignment in Chrome and Firefox.
263+*/
264+
265+progress {
266+ vertical-align: baseline;
267+}
268+
269+/*
270+Correct the cursor style of increment and decrement buttons in Safari.
271+*/
272+
273+::-webkit-inner-spin-button,
274+::-webkit-outer-spin-button {
275+ height: auto;
276+}
277+
278+/*
279+1. Correct the odd appearance in Chrome and Safari.
280+2. Correct the outline style in Safari.
281+*/
282+
283+[type='search'] {
284+ -webkit-appearance: textfield;
285+ /* 1 */
286+ outline-offset: -2px;
287+ /* 2 */
288+}
289+
290+/*
291+Remove the inner padding in Chrome and Safari on macOS.
292+*/
293+
294+::-webkit-search-decoration {
295+ -webkit-appearance: none;
296+}
297+
298+/*
299+1. Correct the inability to style clickable types in iOS and Safari.
300+2. Change font properties to `inherit` in Safari.
301+*/
302+
303+::-webkit-file-upload-button {
304+ -webkit-appearance: button;
305+ /* 1 */
306+ font: inherit;
307+ /* 2 */
308+}
309+
310+/*
311+Add the correct display in Chrome and Safari.
312+*/
313+
314+summary {
315+ display: list-item;
316+}
317+
318+/*
319+Removes the default spacing and border for appropriate elements.
320+*/
321+
322+blockquote,
323+dl,
324+dd,
325+h1,
326+h2,
327+h3,
328+h4,
329+h5,
330+h6,
331+hr,
332+figure,
333+p,
334+pre {
335+ margin: 0;
336+}
337+
338+fieldset {
339+ margin: 0;
340+ padding: 0;
341+}
342+
343+legend {
344+ padding: 0;
345+}
346+
347+ol,
348+ul,
349+menu {
350+ list-style: none;
351+ margin: 0;
352+ padding: 0;
353+}
354+
355+/*
356+Reset default styling for dialogs.
357+*/
358+
359+dialog {
360+ padding: 0;
361+}
362+
363+/*
364+Prevent resizing textareas horizontally by default.
365+*/
366+
367+textarea {
368+ resize: vertical;
369+}
370+
371+/*
372+1. Reset the default placeholder opacity in Firefox. (https://github.com/tailwindlabs/tailwindcss/issues/3300)
373+2. Set the default placeholder color to the user's configured gray 400 color.
374+*/
375+
376+input::-moz-placeholder, textarea::-moz-placeholder {
377+ opacity: 1;
378+ /* 1 */
379+ color: #9ca3af;
380+ /* 2 */
381+}
382+
383+input::placeholder,
384+textarea::placeholder {
385+ opacity: 1;
386+ /* 1 */
387+ color: #9ca3af;
388+ /* 2 */
389+}
390+
391+/*
392+Set the default cursor for buttons.
393+*/
394+
395+button,
396+[role="button"] {
397+ cursor: pointer;
398+}
399+
400+/*
401+Make sure disabled buttons don't get the pointer cursor.
402+*/
403+
404+:disabled {
405+ cursor: default;
406+}
407+
408+/*
409+1. Make replaced elements `display: block` by default. (https://github.com/mozdevs/cssremedy/issues/14)
410+2. Add `vertical-align: middle` to align replaced elements more sensibly by default. (https://github.com/jensimmons/cssremedy/issues/14#issuecomment-634934210)
411+ This can trigger a poorly considered lint error in some tools but is included by design.
412+*/
413+
414+img,
415+svg,
416+video,
417+canvas,
418+audio,
419+iframe,
420+embed,
421+object {
422+ display: block;
423+ /* 1 */
424+ vertical-align: middle;
425+ /* 2 */
426+}
427+
428+/*
429+Constrain images and videos to the parent width and preserve their intrinsic aspect ratio. (https://github.com/mozdevs/cssremedy/issues/14)
430+*/
431+
432+img,
433+video {
434+ max-width: 100%;
435+ height: auto;
436+}
437+
438+/* Make elements with the HTML hidden attribute stay hidden by default */
439+
440+[hidden] {
441+ display: none;
442+}
443+
444+*, ::before, ::after {
445+ --tw-border-spacing-x: 0;
446+ --tw-border-spacing-y: 0;
447+ --tw-translate-x: 0;
448+ --tw-translate-y: 0;
449+ --tw-rotate: 0;
450+ --tw-skew-x: 0;
451+ --tw-skew-y: 0;
452+ --tw-scale-x: 1;
453+ --tw-scale-y: 1;
454+ --tw-pan-x: ;
455+ --tw-pan-y: ;
456+ --tw-pinch-zoom: ;
457+ --tw-scroll-snap-strictness: proximity;
458+ --tw-gradient-from-position: ;
459+ --tw-gradient-via-position: ;
460+ --tw-gradient-to-position: ;
461+ --tw-ordinal: ;
462+ --tw-slashed-zero: ;
463+ --tw-numeric-figure: ;
464+ --tw-numeric-spacing: ;
465+ --tw-numeric-fraction: ;
466+ --tw-ring-inset: ;
467+ --tw-ring-offset-width: 0px;
468+ --tw-ring-offset-color: #fff;
469+ --tw-ring-color: rgb(59 130 246 / 0.5);
470+ --tw-ring-offset-shadow: 0 0 #0000;
471+ --tw-ring-shadow: 0 0 #0000;
472+ --tw-shadow: 0 0 #0000;
473+ --tw-shadow-colored: 0 0 #0000;
474+ --tw-blur: ;
475+ --tw-brightness: ;
476+ --tw-contrast: ;
477+ --tw-grayscale: ;
478+ --tw-hue-rotate: ;
479+ --tw-invert: ;
480+ --tw-saturate: ;
481+ --tw-sepia: ;
482+ --tw-drop-shadow: ;
483+ --tw-backdrop-blur: ;
484+ --tw-backdrop-brightness: ;
485+ --tw-backdrop-contrast: ;
486+ --tw-backdrop-grayscale: ;
487+ --tw-backdrop-hue-rotate: ;
488+ --tw-backdrop-invert: ;
489+ --tw-backdrop-opacity: ;
490+ --tw-backdrop-saturate: ;
491+ --tw-backdrop-sepia: ;
492+}
493+
494+::backdrop {
495+ --tw-border-spacing-x: 0;
496+ --tw-border-spacing-y: 0;
497+ --tw-translate-x: 0;
498+ --tw-translate-y: 0;
499+ --tw-rotate: 0;
500+ --tw-skew-x: 0;
501+ --tw-skew-y: 0;
502+ --tw-scale-x: 1;
503+ --tw-scale-y: 1;
504+ --tw-pan-x: ;
505+ --tw-pan-y: ;
506+ --tw-pinch-zoom: ;
507+ --tw-scroll-snap-strictness: proximity;
508+ --tw-gradient-from-position: ;
509+ --tw-gradient-via-position: ;
510+ --tw-gradient-to-position: ;
511+ --tw-ordinal: ;
512+ --tw-slashed-zero: ;
513+ --tw-numeric-figure: ;
514+ --tw-numeric-spacing: ;
515+ --tw-numeric-fraction: ;
516+ --tw-ring-inset: ;
517+ --tw-ring-offset-width: 0px;
518+ --tw-ring-offset-color: #fff;
519+ --tw-ring-color: rgb(59 130 246 / 0.5);
520+ --tw-ring-offset-shadow: 0 0 #0000;
521+ --tw-ring-shadow: 0 0 #0000;
522+ --tw-shadow: 0 0 #0000;
523+ --tw-shadow-colored: 0 0 #0000;
524+ --tw-blur: ;
525+ --tw-brightness: ;
526+ --tw-contrast: ;
527+ --tw-grayscale: ;
528+ --tw-hue-rotate: ;
529+ --tw-invert: ;
530+ --tw-saturate: ;
531+ --tw-sepia: ;
532+ --tw-drop-shadow: ;
533+ --tw-backdrop-blur: ;
534+ --tw-backdrop-brightness: ;
535+ --tw-backdrop-contrast: ;
536+ --tw-backdrop-grayscale: ;
537+ --tw-backdrop-hue-rotate: ;
538+ --tw-backdrop-invert: ;
539+ --tw-backdrop-opacity: ;
540+ --tw-backdrop-saturate: ;
541+ --tw-backdrop-sepia: ;
542+}
543+
544+.my-2 {
545+ margin-top: 0.5rem;
546+ margin-bottom: 0.5rem;
547+}
548+
549+.mb-4 {
550+ margin-bottom: 1rem;
551+}
552+
553+.ml-2 {
554+ margin-left: 0.5rem;
555+}
556+
557+.ml-4 {
558+ margin-left: 1rem;
559+}
560+
561+.mr-2 {
562+ margin-right: 0.5rem;
563+}
564+
565+.mt-4 {
566+ margin-top: 1rem;
567+}
568+
569+.flex {
570+ display: flex;
571+}
572+
573+.h-10 {
574+ height: 2.5rem;
575+}
576+
577+.h-24 {
578+ height: 6rem;
579+}
580+
581+.h-32 {
582+ height: 8rem;
583+}
584+
585+.h-44 {
586+ height: 11rem;
587+}
588+
589+.h-64 {
590+ height: 16rem;
591+}
592+
593+.h-full {
594+ height: 100%;
595+}
596+
597+.w-1\/5 {
598+ width: 20%;
599+}
600+
601+.w-2\/6 {
602+ width: 33.333333%;
603+}
604+
605+.w-4\/6 {
606+ width: 66.666667%;
607+}
608+
609+.w-72 {
610+ width: 18rem;
611+}
612+
613+.w-full {
614+ width: 100%;
615+}
616+
617+.w-2\/3 {
618+ width: 66.666667%;
619+}
620+
621+.w-screen {
622+ width: 100vw;
623+}
624+
625+.w-96 {
626+ width: 24rem;
627+}
628+
629+.flex-1 {
630+ flex: 1 1 0%;
631+}
632+
633+.flex-grow {
634+ flex-grow: 1;
635+}
636+
637+.flex-row {
638+ flex-direction: row;
639+}
640+
641+.flex-col {
642+ flex-direction: column;
643+}
644+
645+.items-center {
646+ align-items: center;
647+}
648+
649+.justify-end {
650+ justify-content: flex-end;
651+}
652+
653+.justify-center {
654+ justify-content: center;
655+}
656+
657+.justify-between {
658+ justify-content: space-between;
659+}
660+
661+.justify-items-center {
662+ justify-items: center;
663+}
664+
665+.space-x-4 > :not([hidden]) ~ :not([hidden]) {
666+ --tw-space-x-reverse: 0;
667+ margin-right: calc(1rem * var(--tw-space-x-reverse));
668+ margin-left: calc(1rem * calc(1 - var(--tw-space-x-reverse)));
669+}
670+
671+.space-y-2 > :not([hidden]) ~ :not([hidden]) {
672+ --tw-space-y-reverse: 0;
673+ margin-top: calc(0.5rem * calc(1 - var(--tw-space-y-reverse)));
674+ margin-bottom: calc(0.5rem * var(--tw-space-y-reverse));
675+}
676+
677+.space-y-4 > :not([hidden]) ~ :not([hidden]) {
678+ --tw-space-y-reverse: 0;
679+ margin-top: calc(1rem * calc(1 - var(--tw-space-y-reverse)));
680+ margin-bottom: calc(1rem * var(--tw-space-y-reverse));
681+}
682+
683+.space-x-3 > :not([hidden]) ~ :not([hidden]) {
684+ --tw-space-x-reverse: 0;
685+ margin-right: calc(0.75rem * var(--tw-space-x-reverse));
686+ margin-left: calc(0.75rem * calc(1 - var(--tw-space-x-reverse)));
687+}
688+
689+.space-y-3 > :not([hidden]) ~ :not([hidden]) {
690+ --tw-space-y-reverse: 0;
691+ margin-top: calc(0.75rem * calc(1 - var(--tw-space-y-reverse)));
692+ margin-bottom: calc(0.75rem * var(--tw-space-y-reverse));
693+}
694+
695+.overflow-y-scroll {
696+ overflow-y: scroll;
697+}
698+
699+.rounded-lg {
700+ border-radius: 0.5rem;
701+}
702+
703+.rounded-md {
704+ border-radius: 0.375rem;
705+}
706+
707+.rounded-sm {
708+ border-radius: 0.125rem;
709+}
710+
711+.border {
712+ border-width: 1px;
713+}
714+
715+.border-gray-300 {
716+ --tw-border-opacity: 1;
717+ border-color: rgb(209 213 219 / var(--tw-border-opacity));
718+}
719+
720+.bg-gordonmascot-lblue {
721+ --tw-bg-opacity: 1;
722+ background-color: rgb(0 123 192 / var(--tw-bg-opacity));
723+}
724+
725+.bg-gordonmascot-mblue {
726+ --tw-bg-opacity: 1;
727+ background-color: rgb(0 82 147 / var(--tw-bg-opacity));
728+}
729+
730+.bg-gray-300 {
731+ --tw-bg-opacity: 1;
732+ background-color: rgb(209 213 219 / var(--tw-bg-opacity));
733+}
734+
735+.bg-transparent {
736+ background-color: transparent;
737+}
738+
739+.bg-white {
740+ --tw-bg-opacity: 1;
741+ background-color: rgb(255 255 255 / var(--tw-bg-opacity));
742+}
743+
744+.bg-zinc-200 {
745+ --tw-bg-opacity: 1;
746+ background-color: rgb(228 228 231 / var(--tw-bg-opacity));
747+}
748+
749+.bg-gordonmascot-hblue {
750+ --tw-bg-opacity: 1;
751+ background-color: rgb(1 30 92 / var(--tw-bg-opacity));
752+}
753+
754+.bg-zinc-400 {
755+ --tw-bg-opacity: 1;
756+ background-color: rgb(161 161 170 / var(--tw-bg-opacity));
757+}
758+
759+.p-4 {
760+ padding: 1rem;
761+}
762+
763+.p-2 {
764+ padding: 0.5rem;
765+}
766+
767+.px-2 {
768+ padding-left: 0.5rem;
769+ padding-right: 0.5rem;
770+}
771+
772+.px-6 {
773+ padding-left: 1.5rem;
774+ padding-right: 1.5rem;
775+}
776+
777+.py-2 {
778+ padding-top: 0.5rem;
779+ padding-bottom: 0.5rem;
780+}
781+
782+.px-4 {
783+ padding-left: 1rem;
784+ padding-right: 1rem;
785+}
786+
787+.text-2xl {
788+ font-size: 1.5rem;
789+ line-height: 2rem;
790+}
791+
792+.text-5xl {
793+ font-size: 3rem;
794+ line-height: 1;
795+}
796+
797+.text-lg {
798+ font-size: 1.125rem;
799+ line-height: 1.75rem;
800+}
801+
802+.text-sm {
803+ font-size: 0.875rem;
804+ line-height: 1.25rem;
805+}
806+
807+.text-xl {
808+ font-size: 1.25rem;
809+ line-height: 1.75rem;
810+}
811+
812+.font-semibold {
813+ font-weight: 600;
814+}
815+
816+.tracking-tighter {
817+ letter-spacing: -0.05em;
818+}
819+
820+.text-gordonmascot-hblue {
821+ --tw-text-opacity: 1;
822+ color: rgb(1 30 92 / var(--tw-text-opacity));
823+}
824+
825+.text-gordonmascot-mblue {
826+ --tw-text-opacity: 1;
827+ color: rgb(0 82 147 / var(--tw-text-opacity));
828+}
829+
830+.text-gray-100 {
831+ --tw-text-opacity: 1;
832+ color: rgb(243 244 246 / var(--tw-text-opacity));
833+}
834+
835+.text-gray-800 {
836+ --tw-text-opacity: 1;
837+ color: rgb(31 41 55 / var(--tw-text-opacity));
838+}
839+
840+.text-slate-400 {
841+ --tw-text-opacity: 1;
842+ color: rgb(148 163 184 / var(--tw-text-opacity));
843+}
844+
845+.text-slate-100 {
846+ --tw-text-opacity: 1;
847+ color: rgb(241 245 249 / var(--tw-text-opacity));
848+}
849+
850+.shadow {
851+ --tw-shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1);
852+ --tw-shadow-colored: 0 1px 3px 0 var(--tw-shadow-color), 0 1px 2px -1px var(--tw-shadow-color);
853+ box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
854+}
855+
856+.outline-none {
857+ outline: 2px solid transparent;
858+ outline-offset: 2px;
859+}
860+
861+/* Import IBM Plex Fonts */
862+
863+@font-face {
864+ font-family: "IBMPlexSans-Bold";
865+
866+ src: url("/assets/fonts/IBMPlex/IBMPlexSans-Bold.woff2") format("woff2");
867+
868+ font-weight: bold;
869+
870+ font-style: normal;
871+}
872+
873+@font-face {
874+ font-family: "IBMPlexSans-Regular";
875+
876+ src: url("/assets/fonts/IBMPlex/IBMPlexSans-Regular.woff2") format("woff2");
877+
878+ font-weight: normal;
879+
880+ font-style: normal;
881+}
882+
883+/* Import Jetbrains Mono Nerd Font */
884+
885+@font-face {
886+ font-family: "JetBrainsMono-Nerd-Font-Regular";
887+
888+ src: url("/assets/fonts/JetBrainsMonoNerd/JetBrainsMonoNerdFontMono-Regular.woff2")
889+ format("woff2");
890+
891+ font-weight: normal;
892+
893+ font-style: normal;
894+}
895+
896+@font-face {
897+ font-family: "LilitaOne-Regular";
898+
899+ src: url("/assets/fonts/LilitaOne/LilitaOne-Regular.ttf") format("truetype");
900+
901+ font-weight: normal;
902+
903+ font-style: normal;
904+}
905+
906+.fade-me-out.htmx-swapping {
907+ opacity: 0;
908+ transition: opacity 1s ease-out;
909+}
910+
911+/* View transition */
912+
913+@keyframes fade-in {
914+ from {
915+ opacity: 0;
916+ }
917+}
918+
919+@keyframes fade-out {
920+ to {
921+ opacity: 0;
922+ }
923+}
924+
925+@keyframes slide-from-right {
926+ from {
927+ transform: translateX(90px);
928+ }
929+}
930+
931+@keyframes slide-to-left {
932+ to {
933+ transform: translateX(-90px);
934+ }
935+}
936+
937+.slide-it {
938+ view-transition-name: slide-it;
939+}
940+
941+::view-transition-old(slide-it) {
942+ animation: 180ms cubic-bezier(0.4, 0, 1, 1) both fade-out,
943+ 600ms cubic-bezier(0.4, 0, 0.2, 1) both slide-to-left;
944+}
945+
946+::view-transition-new(slide-it) {
947+ animation: 420ms cubic-bezier(0, 0, 0.2, 1) 90ms both fade-in,
948+ 600ms cubic-bezier(0.4, 0, 0.2, 1) both slide-from-right;
949+}
950+
951+.gordon-title {
952+ font-family: "LilitaOne-Regular", sans-serif;
953+}
954+
955+.IBMPlexSans {
956+ font-family: "IBMPlexSans-Regular", sans-serif;
957+}
958+
959+.circle-shadow {
960+ width: 100%;
961+ position: relative;
962+}
963+
964+.circle-shadow::after {
965+ position: absolute;
966+ width: 50%;
967+ height: 0.4rem;
968+ margin: auto;
969+ background: rgba(0, 0, 0, 0.1);
970+ border-radius: 50%;
971+ z-index: -1;
972+ bottom: 2%;
973+ content: "";
974+ box-shadow: 0 0 1px 0.3rem rgba(0, 0, 0, 0.1);
975+}
976+
977+.iconoir {
978+ margin-right: 8px;
979+}
980+
981+@media (min-width: 640px) {
982+ .sm\:h-24 {
983+ height: 6rem;
984+ }
985+}
986+
987+@media (min-width: 768px) {
988+ .md\:w-1\/2 {
989+ width: 50%;
990+ }
991+
992+ .md\:flex-row {
993+ flex-direction: row;
994+ }
995+
996+ .md\:space-y-6 > :not([hidden]) ~ :not([hidden]) {
997+ --tw-space-y-reverse: 0;
998+ margin-top: calc(1.5rem * calc(1 - var(--tw-space-y-reverse)));
999+ margin-bottom: calc(1.5rem * var(--tw-space-y-reverse));
1000+ }
1001+
1002+ .md\:p-8 {
1003+ padding: 2rem;
1004+ }
1005+
1006+ .md\:py-8 {
1007+ padding-top: 2rem;
1008+ padding-bottom: 2rem;
1009+ }
1010+
1011+ .md\:pl-4 {
1012+ padding-left: 1rem;
1013+ }
1014+
1015+ .md\:pt-10 {
1016+ padding-top: 2.5rem;
1017+ }
1018+
1019+ .md\:text-2xl {
1020+ font-size: 1.5rem;
1021+ line-height: 2rem;
1022+ }
1023+
1024+ .md\:text-3xl {
1025+ font-size: 1.875rem;
1026+ line-height: 2.25rem;
1027+ }
1028+}
1029+
1030+@media (min-width: 1024px) {
1031+ .lg\:text-4xl {
1032+ font-size: 2.25rem;
1033+ line-height: 2.5rem;
1034+ }
1035+}
1036+
1037+@media (min-width: 1280px) {
1038+ .xl\:h-48 {
1039+ height: 12rem;
1040+ }
1041+
1042+ .xl\:text-5xl {
1043+ font-size: 3rem;
1044+ line-height: 1;
1045+ }
1046+}
A internal/webui/public/assets/fonts/IBMPlex/IBMPlexSans-Bold.woff2 +0 -0 binary file: no text diff

binary file: no text diff

A internal/webui/public/assets/fonts/IBMPlex/IBMPlexSans-Light.woff2 +0 -0 binary file: no text diff

binary file: no text diff

A internal/webui/public/assets/fonts/IBMPlex/IBMPlexSans-Medium.woff2 +0 -0 binary file: no text diff

binary file: no text diff

A internal/webui/public/assets/fonts/IBMPlex/IBMPlexSans-Regular.woff2 +0 -0 binary file: no text diff

binary file: no text diff

A internal/webui/public/assets/fonts/IBMPlex/IBMPlexSans-Thin.woff2 +0 -0 binary file: no text diff

binary file: no text diff

A internal/webui/public/assets/fonts/JetBrainsMonoNerd/JetBrainsMonoNerdFont-Bold.woff2 +0 -0 binary file: no text diff

binary file: no text diff

A internal/webui/public/assets/fonts/JetBrainsMonoNerd/JetBrainsMonoNerdFont-Regular.woff2 +0 -0 binary file: no text diff

binary file: no text diff

A internal/webui/public/assets/fonts/JetBrainsMonoNerd/JetBrainsMonoNerdFontMono-Regular.ttf +0 -0 binary file: no text diff

binary file: no text diff

A internal/webui/public/assets/fonts/LilitaOne/LilitaOne-Regular.ttf +0 -0 binary file: no text diff

binary file: no text diff

A internal/webui/public/assets/fonts/LilitaOne/LilitaOne-Regular.woff2 +0 -0 binary file: no text diff

binary file: no text diff

A internal/webui/public/assets/imgs/gordon-mascot-hq-trsp.png +0 -0 binary file: no text diff

binary file: no text diff

A internal/webui/public/assets/imgs/gordon-mascot-mq-trsp.png +0 -0 binary file: no text diff

binary file: no text diff

A internal/webui/public/assets/imgs/gordon-mascot.png +0 -0 binary file: no text diff

binary file: no text diff

A internal/webui/public/favicon-16x16.png +0 -0 binary file: no text diff

binary file: no text diff

A internal/webui/public/favicon-32x32.png +0 -0 binary file: no text diff

binary file: no text diff

A internal/webui/public/favicon.ico +0 -0 binary file: no text diff

binary file: no text diff

A internal/webui/public/libs/alpine.min.js +5 -0 generated file: collapsed
A internal/webui/public/libs/chart.js +20 -0 too large to show in the browser

too large to show in the browser view raw

A internal/webui/public/libs/htmx-sse.js +322 -0
@@ -0,0 +1,322 @@
1+/*
2+Server Sent Events Extension
3+============================
4+This extension adds support for Server Sent Events to htmx. See /www/extensions/sse.md for usage instructions.
5+
6+*/
7+
8+(function(){
9+
10+ /** @type {import("../htmx").HtmxInternalApi} */
11+ var api;
12+
13+ htmx.defineExtension("sse", {
14+
15+ /**
16+ * Init saves the provided reference to the internal HTMX API.
17+ *
18+ * @param {import("../htmx").HtmxInternalApi} api
19+ * @returns void
20+ */
21+ init: function(apiRef) {
22+ // store a reference to the internal API.
23+ api = apiRef;
24+
25+ // set a function in the public API for creating new EventSource objects
26+ if (htmx.createEventSource == undefined) {
27+ htmx.createEventSource = createEventSource;
28+ }
29+ },
30+
31+ /**
32+ * onEvent handles all events passed to this extension.
33+ *
34+ * @param {string} name
35+ * @param {Event} evt
36+ * @returns void
37+ */
38+ onEvent: function(name, evt) {
39+
40+ switch (name) {
41+
42+ // Try to remove remove an EventSource when elements are removed
43+ case "htmx:beforeCleanupElement":
44+ var internalData = api.getInternalData(evt.target)
45+ if (internalData.sseEventSource) {
46+ internalData.sseEventSource.close();
47+ }
48+ return;
49+
50+ // Try to create EventSources when elements are processed
51+ case "htmx:afterProcessNode":
52+ createEventSourceOnElement(evt.target);
53+ }
54+ }
55+ });
56+
57+ ///////////////////////////////////////////////
58+ // HELPER FUNCTIONS
59+ ///////////////////////////////////////////////
60+
61+
62+ /**
63+ * createEventSource is the default method for creating new EventSource objects.
64+ * it is hoisted into htmx.config.createEventSource to be overridden by the user, if needed.
65+ *
66+ * @param {string} url
67+ * @returns EventSource
68+ */
69+ function createEventSource(url) {
70+ return new EventSource(url, {withCredentials:true});
71+ }
72+
73+ function splitOnWhitespace(trigger) {
74+ return trigger.trim().split(/\s+/);
75+ }
76+
77+ function getLegacySSEURL(elt) {
78+ var legacySSEValue = api.getAttributeValue(elt, "hx-sse");
79+ if (legacySSEValue) {
80+ var values = splitOnWhitespace(legacySSEValue);
81+ for (var i = 0; i < values.length; i++) {
82+ var value = values[i].split(/:(.+)/);
83+ if (value[0] === "connect") {
84+ return value[1];
85+ }
86+ }
87+ }
88+ }
89+
90+ function getLegacySSESwaps(elt) {
91+ var legacySSEValue = api.getAttributeValue(elt, "hx-sse");
92+ var returnArr = [];
93+ if (legacySSEValue) {
94+ var values = splitOnWhitespace(legacySSEValue);
95+ for (var i = 0; i < values.length; i++) {
96+ var value = values[i].split(/:(.+)/);
97+ if (value[0] === "swap") {
98+ returnArr.push(value[1]);
99+ }
100+ }
101+ }
102+ return returnArr;
103+ }
104+
105+ /**
106+ * createEventSourceOnElement creates a new EventSource connection on the provided element.
107+ * If a usable EventSource already exists, then it is returned. If not, then a new EventSource
108+ * is created and stored in the element's internalData.
109+ * @param {HTMLElement} elt
110+ * @param {number} retryCount
111+ * @returns {EventSource | null}
112+ */
113+ function createEventSourceOnElement(elt, retryCount) {
114+
115+ if (elt == null) {
116+ return null;
117+ }
118+
119+ var internalData = api.getInternalData(elt);
120+
121+ // get URL from element's attribute
122+ var sseURL = api.getAttributeValue(elt, "sse-connect");
123+
124+
125+ if (sseURL == undefined) {
126+ var legacyURL = getLegacySSEURL(elt)
127+ if (legacyURL) {
128+ sseURL = legacyURL;
129+ } else {
130+ return null;
131+ }
132+ }
133+
134+ // Connect to the EventSource
135+ var source = htmx.createEventSource(sseURL);
136+ internalData.sseEventSource = source;
137+
138+ // Create event handlers
139+ source.onerror = function (err) {
140+
141+ // Log an error event
142+ api.triggerErrorEvent(elt, "htmx:sseError", {error:err, source:source});
143+
144+ // If parent no longer exists in the document, then clean up this EventSource
145+ if (maybeCloseSSESource(elt)) {
146+ return;
147+ }
148+
149+ // Otherwise, try to reconnect the EventSource
150+ if (source.readyState === EventSource.CLOSED) {
151+ retryCount = retryCount || 0;
152+ var timeout = Math.random() * (2 ^ retryCount) * 500;
153+ window.setTimeout(function() {
154+ createEventSourceOnElement(elt, Math.min(7, retryCount+1));
155+ }, timeout);
156+ }
157+ };
158+
159+ source.onopen = function (evt) {
160+ api.triggerEvent(elt, "htmx:sseOpen", {source: source});
161+ }
162+
163+ // Add message handlers for every `sse-swap` attribute
164+ queryAttributeOnThisOrChildren(elt, "sse-swap").forEach(function(child) {
165+
166+ var sseSwapAttr = api.getAttributeValue(child, "sse-swap");
167+ if (sseSwapAttr) {
168+ var sseEventNames = sseSwapAttr.split(",");
169+ } else {
170+ var sseEventNames = getLegacySSESwaps(child);
171+ }
172+
173+ for (var i = 0 ; i < sseEventNames.length ; i++) {
174+ var sseEventName = sseEventNames[i].trim();
175+ var listener = function(event) {
176+
177+ // If the parent is missing then close SSE and remove listener
178+ if (maybeCloseSSESource(elt)) {
179+ source.removeEventListener(sseEventName, listener);
180+ return;
181+ }
182+
183+ // swap the response into the DOM and trigger a notification
184+ swap(child, event.data);
185+ api.triggerEvent(elt, "htmx:sseMessage", event);
186+ };
187+
188+ // Register the new listener
189+ api.getInternalData(elt).sseEventListener = listener;
190+ source.addEventListener(sseEventName, listener);
191+ }
192+ });
193+
194+ // Add message handlers for every `hx-trigger="sse:*"` attribute
195+ queryAttributeOnThisOrChildren(elt, "hx-trigger").forEach(function(child) {
196+
197+ var sseEventName = api.getAttributeValue(child, "hx-trigger");
198+ if (sseEventName == null) {
199+ return;
200+ }
201+
202+ // Only process hx-triggers for events with the "sse:" prefix
203+ if (sseEventName.slice(0, 4) != "sse:") {
204+ return;
205+ }
206+
207+ var listener = function(event) {
208+
209+ // If parent is missing, then close SSE and remove listener
210+ if (maybeCloseSSESource(elt)) {
211+ source.removeEventListener(sseEventName, listener);
212+ return;
213+ }
214+
215+ // Trigger events to be handled by the rest of htmx
216+ htmx.trigger(child, sseEventName, event);
217+ htmx.trigger(child, "htmx:sseMessage", event);
218+ }
219+
220+ // Register the new listener
221+ api.getInternalData(elt).sseEventListener = listener;
222+ source.addEventListener(sseEventName.slice(4), listener);
223+ });
224+ }
225+
226+ /**
227+ * maybeCloseSSESource confirms that the parent element still exists.
228+ * If not, then any associated SSE source is closed and the function returns true.
229+ *
230+ * @param {HTMLElement} elt
231+ * @returns boolean
232+ */
233+ function maybeCloseSSESource(elt) {
234+ if (!api.bodyContains(elt)) {
235+ var source = api.getInternalData(elt).sseEventSource;
236+ if (source != undefined) {
237+ source.close();
238+ // source = null
239+ return true;
240+ }
241+ }
242+ return false;
243+ }
244+
245+ /**
246+ * queryAttributeOnThisOrChildren returns all nodes that contain the requested attributeName, INCLUDING THE PROVIDED ROOT ELEMENT.
247+ *
248+ * @param {HTMLElement} elt
249+ * @param {string} attributeName
250+ */
251+ function queryAttributeOnThisOrChildren(elt, attributeName) {
252+
253+ var result = [];
254+
255+ // If the parent element also contains the requested attribute, then add it to the results too.
256+ if (api.hasAttribute(elt, attributeName) || api.hasAttribute(elt, "hx-sse")) {
257+ result.push(elt);
258+ }
259+
260+ // Search all child nodes that match the requested attribute
261+ elt.querySelectorAll("[" + attributeName + "], [data-" + attributeName + "], [hx-sse], [data-hx-sse]").forEach(function(node) {
262+ result.push(node);
263+ });
264+
265+ return result;
266+ }
267+
268+ /**
269+ * @param {HTMLElement} elt
270+ * @param {string} content
271+ */
272+ function swap(elt, content) {
273+
274+ api.withExtensions(elt, function(extension) {
275+ content = extension.transformResponse(content, null, elt);
276+ });
277+
278+ var swapSpec = api.getSwapSpecification(elt);
279+ var target = api.getTarget(elt);
280+ var settleInfo = api.makeSettleInfo(elt);
281+
282+ api.selectAndSwap(swapSpec.swapStyle, target, elt, content, settleInfo);
283+
284+ settleInfo.elts.forEach(function (elt) {
285+ if (elt.classList) {
286+ elt.classList.add(htmx.config.settlingClass);
287+ }
288+ api.triggerEvent(elt, 'htmx:beforeSettle');
289+ });
290+
291+ // Handle settle tasks (with delay if requested)
292+ if (swapSpec.settleDelay > 0) {
293+ setTimeout(doSettle(settleInfo), swapSpec.settleDelay);
294+ } else {
295+ doSettle(settleInfo)();
296+ }
297+ }
298+
299+ /**
300+ * doSettle mirrors much of the functionality in htmx that
301+ * settles elements after their content has been swapped.
302+ * TODO: this should be published by htmx, and not duplicated here
303+ * @param {import("../htmx").HtmxSettleInfo} settleInfo
304+ * @returns () => void
305+ */
306+ function doSettle(settleInfo) {
307+
308+ return function() {
309+ settleInfo.tasks.forEach(function (task) {
310+ task.call();
311+ });
312+
313+ settleInfo.elts.forEach(function (elt) {
314+ if (elt.classList) {
315+ elt.classList.remove(htmx.config.settlingClass);
316+ }
317+ api.triggerEvent(elt, 'htmx:afterSettle');
318+ });
319+ }
320+ }
321+
322+})();⏎̸
@@ -0,0 +1,322 @@
1+/*
2+Server Sent Events Extension
3+============================
4+This extension adds support for Server Sent Events to htmx. See /www/extensions/sse.md for usage instructions.
5+
6+*/
7+
8+(function(){
9+
10+ /** @type {import("../htmx").HtmxInternalApi} */
11+ var api;
12+
13+ htmx.defineExtension("sse", {
14+
15+ /**
16+ * Init saves the provided reference to the internal HTMX API.
17+ *
18+ * @param {import("../htmx").HtmxInternalApi} api
19+ * @returns void
20+ */
21+ init: function(apiRef) {
22+ // store a reference to the internal API.
23+ api = apiRef;
24+
25+ // set a function in the public API for creating new EventSource objects
26+ if (htmx.createEventSource == undefined) {
27+ htmx.createEventSource = createEventSource;
28+ }
29+ },
30+
31+ /**
32+ * onEvent handles all events passed to this extension.
33+ *
34+ * @param {string} name
35+ * @param {Event} evt
36+ * @returns void
37+ */
38+ onEvent: function(name, evt) {
39+
40+ switch (name) {
41+
42+ // Try to remove remove an EventSource when elements are removed
43+ case "htmx:beforeCleanupElement":
44+ var internalData = api.getInternalData(evt.target)
45+ if (internalData.sseEventSource) {
46+ internalData.sseEventSource.close();
47+ }
48+ return;
49+
50+ // Try to create EventSources when elements are processed
51+ case "htmx:afterProcessNode":
52+ createEventSourceOnElement(evt.target);
53+ }
54+ }
55+ });
56+
57+ ///////////////////////////////////////////////
58+ // HELPER FUNCTIONS
59+ ///////////////////////////////////////////////
60+
61+
62+ /**
63+ * createEventSource is the default method for creating new EventSource objects.
64+ * it is hoisted into htmx.config.createEventSource to be overridden by the user, if needed.
65+ *
66+ * @param {string} url
67+ * @returns EventSource
68+ */
69+ function createEventSource(url) {
70+ return new EventSource(url, {withCredentials:true});
71+ }
72+
73+ function splitOnWhitespace(trigger) {
74+ return trigger.trim().split(/\s+/);
75+ }
76+
77+ function getLegacySSEURL(elt) {
78+ var legacySSEValue = api.getAttributeValue(elt, "hx-sse");
79+ if (legacySSEValue) {
80+ var values = splitOnWhitespace(legacySSEValue);
81+ for (var i = 0; i < values.length; i++) {
82+ var value = values[i].split(/:(.+)/);
83+ if (value[0] === "connect") {
84+ return value[1];
85+ }
86+ }
87+ }
88+ }
89+
90+ function getLegacySSESwaps(elt) {
91+ var legacySSEValue = api.getAttributeValue(elt, "hx-sse");
92+ var returnArr = [];
93+ if (legacySSEValue) {
94+ var values = splitOnWhitespace(legacySSEValue);
95+ for (var i = 0; i < values.length; i++) {
96+ var value = values[i].split(/:(.+)/);
97+ if (value[0] === "swap") {
98+ returnArr.push(value[1]);
99+ }
100+ }
101+ }
102+ return returnArr;
103+ }
104+
105+ /**
106+ * createEventSourceOnElement creates a new EventSource connection on the provided element.
107+ * If a usable EventSource already exists, then it is returned. If not, then a new EventSource
108+ * is created and stored in the element's internalData.
109+ * @param {HTMLElement} elt
110+ * @param {number} retryCount
111+ * @returns {EventSource | null}
112+ */
113+ function createEventSourceOnElement(elt, retryCount) {
114+
115+ if (elt == null) {
116+ return null;
117+ }
118+
119+ var internalData = api.getInternalData(elt);
120+
121+ // get URL from element's attribute
122+ var sseURL = api.getAttributeValue(elt, "sse-connect");
123+
124+
125+ if (sseURL == undefined) {
126+ var legacyURL = getLegacySSEURL(elt)
127+ if (legacyURL) {
128+ sseURL = legacyURL;
129+ } else {
130+ return null;
131+ }
132+ }
133+
134+ // Connect to the EventSource
135+ var source = htmx.createEventSource(sseURL);
136+ internalData.sseEventSource = source;
137+
138+ // Create event handlers
139+ source.onerror = function (err) {
140+
141+ // Log an error event
142+ api.triggerErrorEvent(elt, "htmx:sseError", {error:err, source:source});
143+
144+ // If parent no longer exists in the document, then clean up this EventSource
145+ if (maybeCloseSSESource(elt)) {
146+ return;
147+ }
148+
149+ // Otherwise, try to reconnect the EventSource
150+ if (source.readyState === EventSource.CLOSED) {
151+ retryCount = retryCount || 0;
152+ var timeout = Math.random() * (2 ^ retryCount) * 500;
153+ window.setTimeout(function() {
154+ createEventSourceOnElement(elt, Math.min(7, retryCount+1));
155+ }, timeout);
156+ }
157+ };
158+
159+ source.onopen = function (evt) {
160+ api.triggerEvent(elt, "htmx:sseOpen", {source: source});
161+ }
162+
163+ // Add message handlers for every `sse-swap` attribute
164+ queryAttributeOnThisOrChildren(elt, "sse-swap").forEach(function(child) {
165+
166+ var sseSwapAttr = api.getAttributeValue(child, "sse-swap");
167+ if (sseSwapAttr) {
168+ var sseEventNames = sseSwapAttr.split(",");
169+ } else {
170+ var sseEventNames = getLegacySSESwaps(child);
171+ }
172+
173+ for (var i = 0 ; i < sseEventNames.length ; i++) {
174+ var sseEventName = sseEventNames[i].trim();
175+ var listener = function(event) {
176+
177+ // If the parent is missing then close SSE and remove listener
178+ if (maybeCloseSSESource(elt)) {
179+ source.removeEventListener(sseEventName, listener);
180+ return;
181+ }
182+
183+ // swap the response into the DOM and trigger a notification
184+ swap(child, event.data);
185+ api.triggerEvent(elt, "htmx:sseMessage", event);
186+ };
187+
188+ // Register the new listener
189+ api.getInternalData(elt).sseEventListener = listener;
190+ source.addEventListener(sseEventName, listener);
191+ }
192+ });
193+
194+ // Add message handlers for every `hx-trigger="sse:*"` attribute
195+ queryAttributeOnThisOrChildren(elt, "hx-trigger").forEach(function(child) {
196+
197+ var sseEventName = api.getAttributeValue(child, "hx-trigger");
198+ if (sseEventName == null) {
199+ return;
200+ }
201+
202+ // Only process hx-triggers for events with the "sse:" prefix
203+ if (sseEventName.slice(0, 4) != "sse:") {
204+ return;
205+ }
206+
207+ var listener = function(event) {
208+
209+ // If parent is missing, then close SSE and remove listener
210+ if (maybeCloseSSESource(elt)) {
211+ source.removeEventListener(sseEventName, listener);
212+ return;
213+ }
214+
215+ // Trigger events to be handled by the rest of htmx
216+ htmx.trigger(child, sseEventName, event);
217+ htmx.trigger(child, "htmx:sseMessage", event);
218+ }
219+
220+ // Register the new listener
221+ api.getInternalData(elt).sseEventListener = listener;
222+ source.addEventListener(sseEventName.slice(4), listener);
223+ });
224+ }
225+
226+ /**
227+ * maybeCloseSSESource confirms that the parent element still exists.
228+ * If not, then any associated SSE source is closed and the function returns true.
229+ *
230+ * @param {HTMLElement} elt
231+ * @returns boolean
232+ */
233+ function maybeCloseSSESource(elt) {
234+ if (!api.bodyContains(elt)) {
235+ var source = api.getInternalData(elt).sseEventSource;
236+ if (source != undefined) {
237+ source.close();
238+ // source = null
239+ return true;
240+ }
241+ }
242+ return false;
243+ }
244+
245+ /**
246+ * queryAttributeOnThisOrChildren returns all nodes that contain the requested attributeName, INCLUDING THE PROVIDED ROOT ELEMENT.
247+ *
248+ * @param {HTMLElement} elt
249+ * @param {string} attributeName
250+ */
251+ function queryAttributeOnThisOrChildren(elt, attributeName) {
252+
253+ var result = [];
254+
255+ // If the parent element also contains the requested attribute, then add it to the results too.
256+ if (api.hasAttribute(elt, attributeName) || api.hasAttribute(elt, "hx-sse")) {
257+ result.push(elt);
258+ }
259+
260+ // Search all child nodes that match the requested attribute
261+ elt.querySelectorAll("[" + attributeName + "], [data-" + attributeName + "], [hx-sse], [data-hx-sse]").forEach(function(node) {
262+ result.push(node);
263+ });
264+
265+ return result;
266+ }
267+
268+ /**
269+ * @param {HTMLElement} elt
270+ * @param {string} content
271+ */
272+ function swap(elt, content) {
273+
274+ api.withExtensions(elt, function(extension) {
275+ content = extension.transformResponse(content, null, elt);
276+ });
277+
278+ var swapSpec = api.getSwapSpecification(elt);
279+ var target = api.getTarget(elt);
280+ var settleInfo = api.makeSettleInfo(elt);
281+
282+ api.selectAndSwap(swapSpec.swapStyle, target, elt, content, settleInfo);
283+
284+ settleInfo.elts.forEach(function (elt) {
285+ if (elt.classList) {
286+ elt.classList.add(htmx.config.settlingClass);
287+ }
288+ api.triggerEvent(elt, 'htmx:beforeSettle');
289+ });
290+
291+ // Handle settle tasks (with delay if requested)
292+ if (swapSpec.settleDelay > 0) {
293+ setTimeout(doSettle(settleInfo), swapSpec.settleDelay);
294+ } else {
295+ doSettle(settleInfo)();
296+ }
297+ }
298+
299+ /**
300+ * doSettle mirrors much of the functionality in htmx that
301+ * settles elements after their content has been swapped.
302+ * TODO: this should be published by htmx, and not duplicated here
303+ * @param {import("../htmx").HtmxSettleInfo} settleInfo
304+ * @returns () => void
305+ */
306+ function doSettle(settleInfo) {
307+
308+ return function() {
309+ settleInfo.tasks.forEach(function (task) {
310+ task.call();
311+ });
312+
313+ settleInfo.elts.forEach(function (elt) {
314+ if (elt.classList) {
315+ elt.classList.remove(htmx.config.settlingClass);
316+ }
317+ api.triggerEvent(elt, 'htmx:afterSettle');
318+ });
319+ }
320+ }
321+
322+})();⏎̸
A internal/webui/public/libs/htmx.min.js +1 -0
@@ -0,0 +1,1 @@
1+(function(e,t){if(typeof define==="function"&&define.amd){define([],t)}else if(typeof module==="object"&&module.exports){module.exports=t()}else{e.htmx=e.htmx||t()}})(typeof self!=="undefined"?self:this,function(){return function(){"use strict";var G={onLoad:t,process:Nt,on:le,off:ue,trigger:oe,ajax:xr,find:b,findAll:f,closest:d,values:function(e,t){var r=er(e,t||"post");return r.values},remove:U,addClass:B,removeClass:n,toggleClass:V,takeClass:j,defineExtension:Rr,removeExtension:Or,logAll:X,logNone:F,logger:null,config:{historyEnabled:true,historyCacheSize:10,refreshOnHistoryMiss:false,defaultSwapStyle:"innerHTML",defaultSwapDelay:0,defaultSettleDelay:20,includeIndicatorStyles:true,indicatorClass:"htmx-indicator",requestClass:"htmx-request",addedClass:"htmx-added",settlingClass:"htmx-settling",swappingClass:"htmx-swapping",allowEval:true,allowScriptTags:true,inlineScriptNonce:"",attributesToSettle:["class","style","width","height"],withCredentials:false,timeout:0,wsReconnectDelay:"full-jitter",wsBinaryType:"blob",disableSelector:"[hx-disable], [data-hx-disable]",useTemplateFragments:false,scrollBehavior:"smooth",defaultFocusScroll:false,getCacheBusterParam:false,globalViewTransitions:false,methodsThatUseUrlParams:["get"],selfRequestsOnly:false},parseInterval:v,_:e,createEventSource:function(e){return new EventSource(e,{withCredentials:true})},createWebSocket:function(e){var t=new WebSocket(e,[]);t.binaryType=G.config.wsBinaryType;return t},version:"1.9.5"};var C={addTriggerHandler:bt,bodyContains:re,canAccessLocalStorage:M,findThisElement:he,filterValues:ar,hasAttribute:o,getAttributeValue:Z,getClosestAttributeValue:Y,getClosestMatch:c,getExpressionVars:gr,getHeaders:ir,getInputValues:er,getInternalData:ee,getSwapSpecification:sr,getTriggerSpecs:Ge,getTarget:de,makeFragment:l,mergeObjects:ne,makeSettleInfo:S,oobSwap:me,querySelectorExt:ie,selectAndSwap:De,settleImmediately:Wt,shouldCancel:Qe,triggerEvent:oe,triggerErrorEvent:ae,withExtensions:w};var R=["get","post","put","delete","patch"];var O=R.map(function(e){return"[hx-"+e+"], [data-hx-"+e+"]"}).join(", ");function v(e){if(e==undefined){return undefined}if(e.slice(-2)=="ms"){return parseFloat(e.slice(0,-2))||undefined}if(e.slice(-1)=="s"){return parseFloat(e.slice(0,-1))*1e3||undefined}if(e.slice(-1)=="m"){return parseFloat(e.slice(0,-1))*1e3*60||undefined}return parseFloat(e)||undefined}function J(e,t){return e.getAttribute&&e.getAttribute(t)}function o(e,t){return e.hasAttribute&&(e.hasAttribute(t)||e.hasAttribute("data-"+t))}function Z(e,t){return J(e,t)||J(e,"data-"+t)}function u(e){return e.parentElement}function K(){return document}function c(e,t){while(e&&!t(e)){e=u(e)}return e?e:null}function T(e,t,r){var n=Z(t,r);var i=Z(t,"hx-disinherit");if(e!==t&&i&&(i==="*"||i.split(" ").indexOf(r)>=0)){return"unset"}else{return n}}function Y(t,r){var n=null;c(t,function(e){return n=T(t,e,r)});if(n!=="unset"){return n}}function h(e,t){var r=e.matches||e.matchesSelector||e.msMatchesSelector||e.mozMatchesSelector||e.webkitMatchesSelector||e.oMatchesSelector;return r&&r.call(e,t)}function q(e){var t=/<([a-z][^\/\0>\x20\t\r\n\f]*)/i;var r=t.exec(e);if(r){return r[1].toLowerCase()}else{return""}}function i(e,t){var r=new DOMParser;var n=r.parseFromString(e,"text/html");var i=n.body;while(t>0){t--;i=i.firstChild}if(i==null){i=K().createDocumentFragment()}return i}function H(e){return e.match(/<body/)}function l(e){var t=!H(e);if(G.config.useTemplateFragments&&t){var r=i("<body><template>"+e+"</template></body>",0);return r.querySelector("template").content}else{var n=q(e);switch(n){case"thead":case"tbody":case"tfoot":case"colgroup":case"caption":return i("<table>"+e+"</table>",1);case"col":return i("<table><colgroup>"+e+"</colgroup></table>",2);case"tr":return i("<table><tbody>"+e+"</tbody></table>",2);case"td":case"th":return i("<table><tbody><tr>"+e+"</tr></tbody></table>",3);case"script":return i("<div>"+e+"</div>",1);default:return i(e,0)}}}function Q(e){if(e){e()}}function L(e,t){return Object.prototype.toString.call(e)==="[object "+t+"]"}function A(e){return L(e,"Function")}function N(e){return L(e,"Object")}function ee(e){var t="htmx-internal-data";var r=e[t];if(!r){r=e[t]={}}return r}function I(e){var t=[];if(e){for(var r=0;r<e.length;r++){t.push(e[r])}}return t}function te(e,t){if(e){for(var r=0;r<e.length;r++){t(e[r])}}}function P(e){var t=e.getBoundingClientRect();var r=t.top;var n=t.bottom;return r<window.innerHeight&&n>=0}function re(e){if(e.getRootNode&&e.getRootNode()instanceof window.ShadowRoot){return K().body.contains(e.getRootNode().host)}else{return K().body.contains(e)}}function k(e){return e.trim().split(/\s+/)}function ne(e,t){for(var r in t){if(t.hasOwnProperty(r)){e[r]=t[r]}}return e}function y(e){try{return JSON.parse(e)}catch(e){x(e);return null}}function M(){var e="htmx:localStorageTest";try{localStorage.setItem(e,e);localStorage.removeItem(e);return true}catch(e){return false}}function D(t){try{var e=new URL(t);if(e){t=e.pathname+e.search}if(!t.match("^/$")){t=t.replace(/\/+$/,"")}return t}catch(e){return t}}function e(e){return hr(K().body,function(){return eval(e)})}function t(t){var e=G.on("htmx:load",function(e){t(e.detail.elt)});return e}function X(){G.logger=function(e,t,r){if(console){console.log(t,e,r)}}}function F(){G.logger=null}function b(e,t){if(t){return e.querySelector(t)}else{return b(K(),e)}}function f(e,t){if(t){return e.querySelectorAll(t)}else{return f(K(),e)}}function U(e,t){e=s(e);if(t){setTimeout(function(){U(e);e=null},t)}else{e.parentElement.removeChild(e)}}function B(e,t,r){e=s(e);if(r){setTimeout(function(){B(e,t);e=null},r)}else{e.classList&&e.classList.add(t)}}function n(e,t,r){e=s(e);if(r){setTimeout(function(){n(e,t);e=null},r)}else{if(e.classList){e.classList.remove(t);if(e.classList.length===0){e.removeAttribute("class")}}}}function V(e,t){e=s(e);e.classList.toggle(t)}function j(e,t){e=s(e);te(e.parentElement.children,function(e){n(e,t)});B(e,t)}function d(e,t){e=s(e);if(e.closest){return e.closest(t)}else{do{if(e==null||h(e,t)){return e}}while(e=e&&u(e));return null}}function r(e){var t=e.trim();if(t.startsWith("<")&&t.endsWith("/>")){return t.substring(1,t.length-2)}else{return t}}function W(e,t){if(t.indexOf("closest ")===0){return[d(e,r(t.substr(8)))]}else if(t.indexOf("find ")===0){return[b(e,r(t.substr(5)))]}else if(t.indexOf("next ")===0){return[_(e,r(t.substr(5)))]}else if(t.indexOf("previous ")===0){return[z(e,r(t.substr(9)))]}else if(t==="document"){return[document]}else if(t==="window"){return[window]}else if(t==="body"){return[document.body]}else{return K().querySelectorAll(r(t))}}var _=function(e,t){var r=K().querySelectorAll(t);for(var n=0;n<r.length;n++){var i=r[n];if(i.compareDocumentPosition(e)===Node.DOCUMENT_POSITION_PRECEDING){return i}}};var z=function(e,t){var r=K().querySelectorAll(t);for(var n=r.length-1;n>=0;n--){var i=r[n];if(i.compareDocumentPosition(e)===Node.DOCUMENT_POSITION_FOLLOWING){return i}}};function ie(e,t){if(t){return W(e,t)[0]}else{return W(K().body,e)[0]}}function s(e){if(L(e,"String")){return b(e)}else{return e}}function $(e,t,r){if(A(t)){return{target:K().body,event:e,listener:t}}else{return{target:s(e),event:t,listener:r}}}function le(t,r,n){Hr(function(){var e=$(t,r,n);e.target.addEventListener(e.event,e.listener)});var e=A(r);return e?r:n}function ue(t,r,n){Hr(function(){var e=$(t,r,n);e.target.removeEventListener(e.event,e.listener)});return A(r)?r:n}var fe=K().createElement("output");function ce(e,t){var r=Y(e,t);if(r){if(r==="this"){return[he(e,t)]}else{var n=W(e,r);if(n.length===0){x('The selector "'+r+'" on '+t+" returned no matches!");return[fe]}else{return n}}}}function he(e,t){return c(e,function(e){return Z(e,t)!=null})}function de(e){var t=Y(e,"hx-target");if(t){if(t==="this"){return he(e,"hx-target")}else{return ie(e,t)}}else{var r=ee(e);if(r.boosted){return K().body}else{return e}}}function ve(e){var t=G.config.attributesToSettle;for(var r=0;r<t.length;r++){if(e===t[r]){return true}}return false}function ge(t,r){te(t.attributes,function(e){if(!r.hasAttribute(e.name)&&ve(e.name)){t.removeAttribute(e.name)}});te(r.attributes,function(e){if(ve(e.name)){t.setAttribute(e.name,e.value)}})}function pe(e,t){var r=Tr(t);for(var n=0;n<r.length;n++){var i=r[n];try{if(i.isInlineSwap(e)){return true}}catch(e){x(e)}}return e==="outerHTML"}function me(e,i,a){var t="#"+J(i,"id");var o="outerHTML";if(e==="true"){}else if(e.indexOf(":")>0){o=e.substr(0,e.indexOf(":"));t=e.substr(e.indexOf(":")+1,e.length)}else{o=e}var r=K().querySelectorAll(t);if(r){te(r,function(e){var t;var r=i.cloneNode(true);t=K().createDocumentFragment();t.appendChild(r);if(!pe(o,e)){t=r}var n={shouldSwap:true,target:e,fragment:t};if(!oe(e,"htmx:oobBeforeSwap",n))return;e=n.target;if(n["shouldSwap"]){ke(o,e,e,t,a)}te(a.elts,function(e){oe(e,"htmx:oobAfterSwap",n)})});i.parentNode.removeChild(i)}else{i.parentNode.removeChild(i);ae(K().body,"htmx:oobErrorNoTarget",{content:i})}return e}function xe(e,t,r){var n=Y(e,"hx-select-oob");if(n){var i=n.split(",");for(let e=0;e<i.length;e++){var a=i[e].split(":",2);var o=a[0].trim();if(o.indexOf("#")===0){o=o.substring(1)}var s=a[1]||"true";var l=t.querySelector("#"+o);if(l){me(s,l,r)}}}te(f(t,"[hx-swap-oob], [data-hx-swap-oob]"),function(e){var t=Z(e,"hx-swap-oob");if(t!=null){me(t,e,r)}})}function ye(e){te(f(e,"[hx-preserve], [data-hx-preserve]"),function(e){var t=Z(e,"id");var r=K().getElementById(t);if(r!=null){e.parentNode.replaceChild(r,e)}})}function be(o,e,s){te(e.querySelectorAll("[id]"),function(e){var t=J(e,"id");if(t&&t.length>0){var r=t.replace("'","\\'");var n=e.tagName.replace(":","\\:");var i=o.querySelector(n+"[id='"+r+"']");if(i&&i!==o){var a=e.cloneNode();ge(e,i);s.tasks.push(function(){ge(e,a)})}}})}function we(e){return function(){n(e,G.config.addedClass);Nt(e);St(e);Se(e);oe(e,"htmx:load")}}function Se(e){var t="[autofocus]";var r=h(e,t)?e:e.querySelector(t);if(r!=null){r.focus()}}function a(e,t,r,n){be(e,r,n);while(r.childNodes.length>0){var i=r.firstChild;B(i,G.config.addedClass);e.insertBefore(i,t);if(i.nodeType!==Node.TEXT_NODE&&i.nodeType!==Node.COMMENT_NODE){n.tasks.push(we(i))}}}function Ee(e,t){var r=0;while(r<e.length){t=(t<<5)-t+e.charCodeAt(r++)|0}return t}function Ce(e){var t=0;if(e.attributes){for(var r=0;r<e.attributes.length;r++){var n=e.attributes[r];if(n.value){t=Ee(n.name,t);t=Ee(n.value,t)}}}return t}function Re(t){var r=ee(t);if(r.onHandlers){for(let e=0;e<r.onHandlers.length;e++){const n=r.onHandlers[e];t.removeEventListener(n.event,n.listener)}delete r.onHandlers}}function Oe(e){var t=ee(e);if(t.timeout){clearTimeout(t.timeout)}if(t.webSocket){t.webSocket.close()}if(t.sseEventSource){t.sseEventSource.close()}if(t.listenerInfos){te(t.listenerInfos,function(e){if(e.on){e.on.removeEventListener(e.trigger,e.listener)}})}if(t.initHash){t.initHash=null}Re(e)}function g(e){oe(e,"htmx:beforeCleanupElement");Oe(e);if(e.children){te(e.children,function(e){g(e)})}}function Te(t,e,r){if(t.tagName==="BODY"){return Ie(t,e,r)}else{var n;var i=t.previousSibling;a(u(t),t,e,r);if(i==null){n=u(t).firstChild}else{n=i.nextSibling}ee(t).replacedWith=n;r.elts=r.elts.filter(function(e){return e!=t});while(n&&n!==t){if(n.nodeType===Node.ELEMENT_NODE){r.elts.push(n)}n=n.nextElementSibling}g(t);u(t).removeChild(t)}}function qe(e,t,r){return a(e,e.firstChild,t,r)}function He(e,t,r){return a(u(e),e,t,r)}function Le(e,t,r){return a(e,null,t,r)}function Ae(e,t,r){return a(u(e),e.nextSibling,t,r)}function Ne(e,t,r){g(e);return u(e).removeChild(e)}function Ie(e,t,r){var n=e.firstChild;a(e,n,t,r);if(n){while(n.nextSibling){g(n.nextSibling);e.removeChild(n.nextSibling)}g(n);e.removeChild(n)}}function Pe(e,t,r){var n=r||Y(e,"hx-select");if(n){var i=K().createDocumentFragment();te(t.querySelectorAll(n),function(e){i.appendChild(e)});t=i}return t}function ke(e,t,r,n,i){switch(e){case"none":return;case"outerHTML":Te(r,n,i);return;case"afterbegin":qe(r,n,i);return;case"beforebegin":He(r,n,i);return;case"beforeend":Le(r,n,i);return;case"afterend":Ae(r,n,i);return;case"delete":Ne(r,n,i);return;default:var a=Tr(t);for(var o=0;o<a.length;o++){var s=a[o];try{var l=s.handleSwap(e,r,n,i);if(l){if(typeof l.length!=="undefined"){for(var u=0;u<l.length;u++){var f=l[u];if(f.nodeType!==Node.TEXT_NODE&&f.nodeType!==Node.COMMENT_NODE){i.tasks.push(we(f))}}}return}}catch(e){x(e)}}if(e==="innerHTML"){Ie(r,n,i)}else{ke(G.config.defaultSwapStyle,t,r,n,i)}}}function Me(e){if(e.indexOf("<title")>-1){var t=e.replace(/<svg(\s[^>]*>|>)([\s\S]*?)<\/svg>/gim,"");var r=t.match(/<title(\s[^>]*>|>)([\s\S]*?)<\/title>/im);if(r){return r[2]}}}function De(e,t,r,n,i,a){i.title=Me(n);var o=l(n);if(o){xe(r,o,i);o=Pe(r,o,a);ye(o);return ke(e,r,t,o,i)}}function Xe(e,t,r){var n=e.getResponseHeader(t);if(n.indexOf("{")===0){var i=y(n);for(var a in i){if(i.hasOwnProperty(a)){var o=i[a];if(!N(o)){o={value:o}}oe(r,a,o)}}}else{var s=n.split(",");for(var l=0;l<s.length;l++){oe(r,s[l].trim(),[])}}}var Fe=/\s/;var p=/[\s,]/;var Ue=/[_$a-zA-Z]/;var Be=/[_$a-zA-Z0-9]/;var Ve=['"',"'","/"];var je=/[^\s]/;function We(e){var t=[];var r=0;while(r<e.length){if(Ue.exec(e.charAt(r))){var n=r;while(Be.exec(e.charAt(r+1))){r++}t.push(e.substr(n,r-n+1))}else if(Ve.indexOf(e.charAt(r))!==-1){var i=e.charAt(r);var n=r;r++;while(r<e.length&&e.charAt(r)!==i){if(e.charAt(r)==="\\"){r++}r++}t.push(e.substr(n,r-n+1))}else{var a=e.charAt(r);t.push(a)}r++}return t}function _e(e,t,r){return Ue.exec(e.charAt(0))&&e!=="true"&&e!=="false"&&e!=="this"&&e!==r&&t!=="."}function ze(e,t,r){if(t[0]==="["){t.shift();var n=1;var i=" return (function("+r+"){ return (";var a=null;while(t.length>0){var o=t[0];if(o==="]"){n--;if(n===0){if(a===null){i=i+"true"}t.shift();i+=")})";try{var s=hr(e,function(){return Function(i)()},function(){return true});s.source=i;return s}catch(e){ae(K().body,"htmx:syntax:error",{error:e,source:i});return null}}}else if(o==="["){n++}if(_e(o,a,r)){i+="(("+r+"."+o+") ? ("+r+"."+o+") : (window."+o+"))"}else{i=i+o}a=t.shift()}}}function m(e,t){var r="";while(e.length>0&&!e[0].match(t)){r+=e.shift()}return r}var $e="input, textarea, select";function Ge(e){var t=Z(e,"hx-trigger");var r=[];if(t){var n=We(t);do{m(n,je);var i=n.length;var a=m(n,/[,\[\s]/);if(a!==""){if(a==="every"){var o={trigger:"every"};m(n,je);o.pollInterval=v(m(n,/[,\[\s]/));m(n,je);var s=ze(e,n,"event");if(s){o.eventFilter=s}r.push(o)}else if(a.indexOf("sse:")===0){r.push({trigger:"sse",sseEvent:a.substr(4)})}else{var l={trigger:a};var s=ze(e,n,"event");if(s){l.eventFilter=s}while(n.length>0&&n[0]!==","){m(n,je);var u=n.shift();if(u==="changed"){l.changed=true}else if(u==="once"){l.once=true}else if(u==="consume"){l.consume=true}else if(u==="delay"&&n[0]===":"){n.shift();l.delay=v(m(n,p))}else if(u==="from"&&n[0]===":"){n.shift();var f=m(n,p);if(f==="closest"||f==="find"||f==="next"||f==="previous"){n.shift();f+=" "+m(n,p)}l.from=f}else if(u==="target"&&n[0]===":"){n.shift();l.target=m(n,p)}else if(u==="throttle"&&n[0]===":"){n.shift();l.throttle=v(m(n,p))}else if(u==="queue"&&n[0]===":"){n.shift();l.queue=m(n,p)}else if((u==="root"||u==="threshold")&&n[0]===":"){n.shift();l[u]=m(n,p)}else{ae(e,"htmx:syntax:error",{token:n.shift()})}}r.push(l)}}if(n.length===i){ae(e,"htmx:syntax:error",{token:n.shift()})}m(n,je)}while(n[0]===","&&n.shift())}if(r.length>0){return r}else if(h(e,"form")){return[{trigger:"submit"}]}else if(h(e,'input[type="button"], input[type="submit"]')){return[{trigger:"click"}]}else if(h(e,$e)){return[{trigger:"change"}]}else{return[{trigger:"click"}]}}function Je(e){ee(e).cancelled=true}function Ze(e,t,r){var n=ee(e);n.timeout=setTimeout(function(){if(re(e)&&n.cancelled!==true){if(!tt(r,e,Pt("hx:poll:trigger",{triggerSpec:r,target:e}))){t(e)}Ze(e,t,r)}},r.pollInterval)}function Ke(e){return location.hostname===e.hostname&&J(e,"href")&&J(e,"href").indexOf("#")!==0}function Ye(t,r,e){if(t.tagName==="A"&&Ke(t)&&(t.target===""||t.target==="_self")||t.tagName==="FORM"){r.boosted=true;var n,i;if(t.tagName==="A"){n="get";i=t.href}else{var a=J(t,"method");n=a?a.toLowerCase():"get";if(n==="get"){}i=J(t,"action")}e.forEach(function(e){rt(t,function(e,t){if(d(e,G.config.disableSelector)){g(e);return}se(n,i,e,t)},r,e,true)})}}function Qe(e,t){if(e.type==="submit"||e.type==="click"){if(t.tagName==="FORM"){return true}if(h(t,'input[type="submit"], button')&&d(t,"form")!==null){return true}if(t.tagName==="A"&&t.href&&(t.getAttribute("href")==="#"||t.getAttribute("href").indexOf("#")!==0)){return true}}return false}function et(e,t){return ee(e).boosted&&e.tagName==="A"&&t.type==="click"&&(t.ctrlKey||t.metaKey)}function tt(e,t,r){var n=e.eventFilter;if(n){try{return n.call(t,r)!==true}catch(e){ae(K().body,"htmx:eventFilter:error",{error:e,source:n.source});return true}}return false}function rt(a,o,e,s,l){var u=ee(a);var t;if(s.from){t=W(a,s.from)}else{t=[a]}if(s.changed){t.forEach(function(e){var t=ee(e);t.lastValue=e.value})}te(t,function(n){var i=function(e){if(!re(a)){n.removeEventListener(s.trigger,i);return}if(et(a,e)){return}if(l||Qe(e,a)){e.preventDefault()}if(tt(s,a,e)){return}var t=ee(e);t.triggerSpec=s;if(t.handledFor==null){t.handledFor=[]}if(t.handledFor.indexOf(a)<0){t.handledFor.push(a);if(s.consume){e.stopPropagation()}if(s.target&&e.target){if(!h(e.target,s.target)){return}}if(s.once){if(u.triggeredOnce){return}else{u.triggeredOnce=true}}if(s.changed){var r=ee(n);if(r.lastValue===n.value){return}r.lastValue=n.value}if(u.delayed){clearTimeout(u.delayed)}if(u.throttle){return}if(s.throttle){if(!u.throttle){o(a,e);u.throttle=setTimeout(function(){u.throttle=null},s.throttle)}}else if(s.delay){u.delayed=setTimeout(function(){o(a,e)},s.delay)}else{oe(a,"htmx:trigger");o(a,e)}}};if(e.listenerInfos==null){e.listenerInfos=[]}e.listenerInfos.push({trigger:s.trigger,listener:i,on:n});n.addEventListener(s.trigger,i)})}var nt=false;var it=null;function at(){if(!it){it=function(){nt=true};window.addEventListener("scroll",it);setInterval(function(){if(nt){nt=false;te(K().querySelectorAll("[hx-trigger='revealed'],[data-hx-trigger='revealed']"),function(e){ot(e)})}},200)}}function ot(t){if(!o(t,"data-hx-revealed")&&P(t)){t.setAttribute("data-hx-revealed","true");var e=ee(t);if(e.initHash){oe(t,"revealed")}else{t.addEventListener("htmx:afterProcessNode",function(e){oe(t,"revealed")},{once:true})}}}function st(e,t,r){var n=k(r);for(var i=0;i<n.length;i++){var a=n[i].split(/:(.+)/);if(a[0]==="connect"){lt(e,a[1],0)}if(a[0]==="send"){ft(e)}}}function lt(s,r,n){if(!re(s)){return}if(r.indexOf("/")==0){var e=location.hostname+(location.port?":"+location.port:"");if(location.protocol=="https:"){r="wss://"+e+r}else if(location.protocol=="http:"){r="ws://"+e+r}}var t=G.createWebSocket(r);t.onerror=function(e){ae(s,"htmx:wsError",{error:e,socket:t});ut(s)};t.onclose=function(e){if([1006,1012,1013].indexOf(e.code)>=0){var t=ct(n);setTimeout(function(){lt(s,r,n+1)},t)}};t.onopen=function(e){n=0};ee(s).webSocket=t;t.addEventListener("message",function(e){if(ut(s)){return}var t=e.data;w(s,function(e){t=e.transformResponse(t,null,s)});var r=S(s);var n=l(t);var i=I(n.children);for(var a=0;a<i.length;a++){var o=i[a];me(Z(o,"hx-swap-oob")||"true",o,r)}Wt(r.tasks)})}function ut(e){if(!re(e)){ee(e).webSocket.close();return true}}function ft(u){var f=c(u,function(e){return ee(e).webSocket!=null});if(f){u.addEventListener(Ge(u)[0].trigger,function(e){var t=ee(f).webSocket;var r=ir(u,f);var n=er(u,"post");var i=n.errors;var a=n.values;var o=gr(u);var s=ne(a,o);var l=ar(s,u);l["HEADERS"]=r;if(i&&i.length>0){oe(u,"htmx:validation:halted",i);return}t.send(JSON.stringify(l));if(Qe(e,u)){e.preventDefault()}})}else{ae(u,"htmx:noWebSocketSourceError")}}function ct(e){var t=G.config.wsReconnectDelay;if(typeof t==="function"){return t(e)}if(t==="full-jitter"){var r=Math.min(e,6);var n=1e3*Math.pow(2,r);return n*Math.random()}x('htmx.config.wsReconnectDelay must either be a function or the string "full-jitter"')}function ht(e,t,r){var n=k(r);for(var i=0;i<n.length;i++){var a=n[i].split(/:(.+)/);if(a[0]==="connect"){dt(e,a[1])}if(a[0]==="swap"){vt(e,a[1])}}}function dt(t,e){var r=G.createEventSource(e);r.onerror=function(e){ae(t,"htmx:sseError",{error:e,source:r});pt(t)};ee(t).sseEventSource=r}function vt(a,o){var s=c(a,mt);if(s){var l=ee(s).sseEventSource;var u=function(e){if(pt(s)){return}if(!re(a)){l.removeEventListener(o,u);return}var t=e.data;w(a,function(e){t=e.transformResponse(t,null,a)});var r=sr(a);var n=de(a);var i=S(a);De(r.swapStyle,n,a,t,i);Wt(i.tasks);oe(a,"htmx:sseMessage",e)};ee(a).sseListener=u;l.addEventListener(o,u)}else{ae(a,"htmx:noSSESourceError")}}function gt(e,t,r){var n=c(e,mt);if(n){var i=ee(n).sseEventSource;var a=function(){if(!pt(n)){if(re(e)){t(e)}else{i.removeEventListener(r,a)}}};ee(e).sseListener=a;i.addEventListener(r,a)}else{ae(e,"htmx:noSSESourceError")}}function pt(e){if(!re(e)){ee(e).sseEventSource.close();return true}}function mt(e){return ee(e).sseEventSource!=null}function xt(e,t,r,n){var i=function(){if(!r.loaded){r.loaded=true;t(e)}};if(n){setTimeout(i,n)}else{i()}}function yt(t,i,e){var a=false;te(R,function(r){if(o(t,"hx-"+r)){var n=Z(t,"hx-"+r);a=true;i.path=n;i.verb=r;e.forEach(function(e){bt(t,e,i,function(e,t){if(d(e,G.config.disableSelector)){g(e);return}se(r,n,e,t)})})}});return a}function bt(n,e,t,r){if(e.sseEvent){gt(n,r,e.sseEvent)}else if(e.trigger==="revealed"){at();rt(n,r,t,e);ot(n)}else if(e.trigger==="intersect"){var i={};if(e.root){i.root=ie(n,e.root)}if(e.threshold){i.threshold=parseFloat(e.threshold)}var a=new IntersectionObserver(function(e){for(var t=0;t<e.length;t++){var r=e[t];if(r.isIntersecting){oe(n,"intersect");break}}},i);a.observe(n);rt(n,r,t,e)}else if(e.trigger==="load"){if(!tt(e,n,Pt("load",{elt:n}))){xt(n,r,t,e.delay)}}else if(e.pollInterval){t.polling=true;Ze(n,r,e)}else{rt(n,r,t,e)}}function wt(e){if(G.config.allowScriptTags&&(e.type==="text/javascript"||e.type==="module"||e.type==="")){var t=K().createElement("script");te(e.attributes,function(e){t.setAttribute(e.name,e.value)});t.textContent=e.textContent;t.async=false;if(G.config.inlineScriptNonce){t.nonce=G.config.inlineScriptNonce}var r=e.parentElement;try{r.insertBefore(t,e)}catch(e){x(e)}finally{if(e.parentElement){e.parentElement.removeChild(e)}}}}function St(e){if(h(e,"script")){wt(e)}te(f(e,"script"),function(e){wt(e)})}function Et(){return document.querySelector("[hx-boost], [data-hx-boost]")}function Ct(e){if(!document.evaluate)return[];let t=null;const r=[];const n=document.evaluate('//*[@*[ starts-with(name(), "hx-on:") or starts-with(name(), "data-hx-on:") ]]',e);while(t=n.iterateNext())r.push(t);return r}function Rt(e){if(e.querySelectorAll){var t=Et()?", a":"";var r=e.querySelectorAll(O+t+", form, [type='submit'], [hx-sse], [data-hx-sse], [hx-ws],"+" [data-hx-ws], [hx-ext], [data-hx-ext], [hx-trigger], [data-hx-trigger], [hx-on], [data-hx-on]");return r}else{return[]}}function Ot(e){var n=s("#"+J(e,"form"))||d(e,"form");if(!n){return}var t=function(e){var t=d(e.target,"button, input[type='submit']");if(t!==null){var r=ee(n);r.lastButtonClicked=t}};e.addEventListener("click",t);e.addEventListener("focusin",t);e.addEventListener("focusout",function(e){var t=ee(n);t.lastButtonClicked=null})}function Tt(e){var t=We(e);var r=0;for(let e=0;e<t.length;e++){const n=t[e];if(n==="{"){r++}else if(n==="}"){r--}}return r}function qt(t,e,r){var n=ee(t);n.onHandlers=[];var i;var a=function(e){return hr(t,function(){if(!i){i=new Function("event",r)}i.call(t,e)})};t.addEventListener(e,a);n.onHandlers.push({event:e,listener:a})}function Ht(e){var t=Z(e,"hx-on");if(t){var r={};var n=t.split("\n");var i=null;var a=0;while(n.length>0){var o=n.shift();var s=o.match(/^\s*([a-zA-Z:\-]+:)(.*)/);if(a===0&&s){o.split(":");i=s[1].slice(0,-1);r[i]=s[2]}else{r[i]+=o}a+=Tt(o)}for(var l in r){qt(e,l,r[l])}}}function Lt(t){Re(t);for(var e=0;e<t.attributes.length;e++){var r=t.attributes[e].name;var n=t.attributes[e].value;if(r.startsWith("hx-on:")||r.startsWith("data-hx-on:")){let e=r.slice(r.indexOf(":")+1);if(e.startsWith(":"))e="htmx"+e;qt(t,e,n)}}}function At(t){if(d(t,G.config.disableSelector)){g(t);return}var r=ee(t);if(r.initHash!==Ce(t)){Oe(t);r.initHash=Ce(t);Ht(t);oe(t,"htmx:beforeProcessNode");if(t.value){r.lastValue=t.value}var e=Ge(t);var n=yt(t,r,e);if(!n){if(Y(t,"hx-boost")==="true"){Ye(t,r,e)}else if(o(t,"hx-trigger")){e.forEach(function(e){bt(t,e,r,function(){})})}}if(t.tagName==="FORM"||J(t,"type")==="submit"&&o(t,"form")){Ot(t)}var i=Z(t,"hx-sse");if(i){ht(t,r,i)}var a=Z(t,"hx-ws");if(a){st(t,r,a)}oe(t,"htmx:afterProcessNode")}}function Nt(e){e=s(e);if(d(e,G.config.disableSelector)){g(e);return}At(e);te(Rt(e),function(e){At(e)});te(Ct(e),Lt)}function It(e){return e.replace(/([a-z0-9])([A-Z])/g,"$1-$2").toLowerCase()}function Pt(e,t){var r;if(window.CustomEvent&&typeof window.CustomEvent==="function"){r=new CustomEvent(e,{bubbles:true,cancelable:true,detail:t})}else{r=K().createEvent("CustomEvent");r.initCustomEvent(e,true,true,t)}return r}function ae(e,t,r){oe(e,t,ne({error:t},r))}function kt(e){return e==="htmx:afterProcessNode"}function w(e,t){te(Tr(e),function(e){try{t(e)}catch(e){x(e)}})}function x(e){if(console.error){console.error(e)}else if(console.log){console.log("ERROR: ",e)}}function oe(e,t,r){e=s(e);if(r==null){r={}}r["elt"]=e;var n=Pt(t,r);if(G.logger&&!kt(t)){G.logger(e,t,r)}if(r.error){x(r.error);oe(e,"htmx:error",{errorInfo:r})}var i=e.dispatchEvent(n);var a=It(t);if(i&&a!==t){var o=Pt(a,n.detail);i=i&&e.dispatchEvent(o)}w(e,function(e){i=i&&e.onEvent(t,n)!==false});return i}var Mt=location.pathname+location.search;function Dt(){var e=K().querySelector("[hx-history-elt],[data-hx-history-elt]");return e||K().body}function Xt(e,t,r,n){if(!M()){return}e=D(e);var i=y(localStorage.getItem("htmx-history-cache"))||[];for(var a=0;a<i.length;a++){if(i[a].url===e){i.splice(a,1);break}}var o={url:e,content:t,title:r,scroll:n};oe(K().body,"htmx:historyItemCreated",{item:o,cache:i});i.push(o);while(i.length>G.config.historyCacheSize){i.shift()}while(i.length>0){try{localStorage.setItem("htmx-history-cache",JSON.stringify(i));break}catch(e){ae(K().body,"htmx:historyCacheError",{cause:e,cache:i});i.shift()}}}function Ft(e){if(!M()){return null}e=D(e);var t=y(localStorage.getItem("htmx-history-cache"))||[];for(var r=0;r<t.length;r++){if(t[r].url===e){return t[r]}}return null}function Ut(e){var t=G.config.requestClass;var r=e.cloneNode(true);te(f(r,"."+t),function(e){n(e,t)});return r.innerHTML}function Bt(){var e=Dt();var t=Mt||location.pathname+location.search;var r=K().querySelector('[hx-history="false" i],[data-hx-history="false" i]');if(!r){oe(K().body,"htmx:beforeHistorySave",{path:t,historyElt:e});Xt(t,Ut(e),K().title,window.scrollY)}if(G.config.historyEnabled)history.replaceState({htmx:true},K().title,window.location.href)}function Vt(e){if(G.config.getCacheBusterParam){e=e.replace(/org\.htmx\.cache-buster=[^&]*&?/,"");if(e.endsWith("&")||e.endsWith("?")){e=e.slice(0,-1)}}if(G.config.historyEnabled){history.pushState({htmx:true},"",e)}Mt=e}function jt(e){if(G.config.historyEnabled)history.replaceState({htmx:true},"",e);Mt=e}function Wt(e){te(e,function(e){e.call()})}function _t(a){var e=new XMLHttpRequest;var o={path:a,xhr:e};oe(K().body,"htmx:historyCacheMiss",o);e.open("GET",a,true);e.setRequestHeader("HX-History-Restore-Request","true");e.onload=function(){if(this.status>=200&&this.status<400){oe(K().body,"htmx:historyCacheMissLoad",o);var e=l(this.response);e=e.querySelector("[hx-history-elt],[data-hx-history-elt]")||e;var t=Dt();var r=S(t);var n=Me(this.response);if(n){var i=b("title");if(i){i.innerHTML=n}else{window.document.title=n}}Ie(t,e,r);Wt(r.tasks);Mt=a;oe(K().body,"htmx:historyRestore",{path:a,cacheMiss:true,serverResponse:this.response})}else{ae(K().body,"htmx:historyCacheMissLoadError",o)}};e.send()}function zt(e){Bt();e=e||location.pathname+location.search;var t=Ft(e);if(t){var r=l(t.content);var n=Dt();var i=S(n);Ie(n,r,i);Wt(i.tasks);document.title=t.title;setTimeout(function(){window.scrollTo(0,t.scroll)},0);Mt=e;oe(K().body,"htmx:historyRestore",{path:e,item:t})}else{if(G.config.refreshOnHistoryMiss){window.location.reload(true)}else{_t(e)}}}function $t(e){var t=ce(e,"hx-indicator");if(t==null){t=[e]}te(t,function(e){var t=ee(e);t.requestCount=(t.requestCount||0)+1;e.classList["add"].call(e.classList,G.config.requestClass)});return t}function Gt(e){te(e,function(e){var t=ee(e);t.requestCount=(t.requestCount||0)-1;if(t.requestCount===0){e.classList["remove"].call(e.classList,G.config.requestClass)}})}function Jt(e,t){for(var r=0;r<e.length;r++){var n=e[r];if(n.isSameNode(t)){return true}}return false}function Zt(e){if(e.name===""||e.name==null||e.disabled){return false}if(e.type==="button"||e.type==="submit"||e.tagName==="image"||e.tagName==="reset"||e.tagName==="file"){return false}if(e.type==="checkbox"||e.type==="radio"){return e.checked}return true}function Kt(e,t,r){if(e!=null&&t!=null){var n=r[e];if(n===undefined){r[e]=t}else if(Array.isArray(n)){if(Array.isArray(t)){r[e]=n.concat(t)}else{n.push(t)}}else{if(Array.isArray(t)){r[e]=[n].concat(t)}else{r[e]=[n,t]}}}}function Yt(t,r,n,e,i){if(e==null||Jt(t,e)){return}else{t.push(e)}if(Zt(e)){var a=J(e,"name");var o=e.value;if(e.multiple){o=I(e.querySelectorAll("option:checked")).map(function(e){return e.value})}if(e.files){o=I(e.files)}Kt(a,o,r);if(i){Qt(e,n)}}if(h(e,"form")){var s=e.elements;te(s,function(e){Yt(t,r,n,e,i)})}}function Qt(e,t){if(e.willValidate){oe(e,"htmx:validation:validate");if(!e.checkValidity()){t.push({elt:e,message:e.validationMessage,validity:e.validity});oe(e,"htmx:validation:failed",{message:e.validationMessage,validity:e.validity})}}}function er(e,t){var r=[];var n={};var i={};var a=[];var o=ee(e);var s=h(e,"form")&&e.noValidate!==true||Z(e,"hx-validate")==="true";if(o.lastButtonClicked){s=s&&o.lastButtonClicked.formNoValidate!==true}if(t!=="get"){Yt(r,i,a,d(e,"form"),s)}Yt(r,n,a,e,s);if(o.lastButtonClicked||e.tagName==="BUTTON"||e.tagName==="INPUT"&&J(e,"type")==="submit"){var l=o.lastButtonClicked||e;var u=J(l,"name");Kt(u,l.value,i)}var f=ce(e,"hx-include");te(f,function(e){Yt(r,n,a,e,s);if(!h(e,"form")){te(e.querySelectorAll($e),function(e){Yt(r,n,a,e,s)})}});n=ne(n,i);return{errors:a,values:n}}function tr(e,t,r){if(e!==""){e+="&"}if(String(r)==="[object Object]"){r=JSON.stringify(r)}var n=encodeURIComponent(r);e+=encodeURIComponent(t)+"="+n;return e}function rr(e){var t="";for(var r in e){if(e.hasOwnProperty(r)){var n=e[r];if(Array.isArray(n)){te(n,function(e){t=tr(t,r,e)})}else{t=tr(t,r,n)}}}return t}function nr(e){var t=new FormData;for(var r in e){if(e.hasOwnProperty(r)){var n=e[r];if(Array.isArray(n)){te(n,function(e){t.append(r,e)})}else{t.append(r,n)}}}return t}function ir(e,t,r){var n={"HX-Request":"true","HX-Trigger":J(e,"id"),"HX-Trigger-Name":J(e,"name"),"HX-Target":Z(t,"id"),"HX-Current-URL":K().location.href};cr(e,"hx-headers",false,n);if(r!==undefined){n["HX-Prompt"]=r}if(ee(e).boosted){n["HX-Boosted"]="true"}return n}function ar(t,e){var r=Y(e,"hx-params");if(r){if(r==="none"){return{}}else if(r==="*"){return t}else if(r.indexOf("not ")===0){te(r.substr(4).split(","),function(e){e=e.trim();delete t[e]});return t}else{var n={};te(r.split(","),function(e){e=e.trim();n[e]=t[e]});return n}}else{return t}}function or(e){return J(e,"href")&&J(e,"href").indexOf("#")>=0}function sr(e,t){var r=t?t:Y(e,"hx-swap");var n={swapStyle:ee(e).boosted?"innerHTML":G.config.defaultSwapStyle,swapDelay:G.config.defaultSwapDelay,settleDelay:G.config.defaultSettleDelay};if(ee(e).boosted&&!or(e)){n["show"]="top"}if(r){var i=k(r);if(i.length>0){n["swapStyle"]=i[0];for(var a=1;a<i.length;a++){var o=i[a];if(o.indexOf("swap:")===0){n["swapDelay"]=v(o.substr(5))}if(o.indexOf("settle:")===0){n["settleDelay"]=v(o.substr(7))}if(o.indexOf("transition:")===0){n["transition"]=o.substr(11)==="true"}if(o.indexOf("scroll:")===0){var s=o.substr(7);var l=s.split(":");var u=l.pop();var f=l.length>0?l.join(":"):null;n["scroll"]=u;n["scrollTarget"]=f}if(o.indexOf("show:")===0){var c=o.substr(5);var l=c.split(":");var h=l.pop();var f=l.length>0?l.join(":"):null;n["show"]=h;n["showTarget"]=f}if(o.indexOf("focus-scroll:")===0){var d=o.substr("focus-scroll:".length);n["focusScroll"]=d=="true"}}}}return n}function lr(e){return Y(e,"hx-encoding")==="multipart/form-data"||h(e,"form")&&J(e,"enctype")==="multipart/form-data"}function ur(t,r,n){var i=null;w(r,function(e){if(i==null){i=e.encodeParameters(t,n,r)}});if(i!=null){return i}else{if(lr(r)){return nr(n)}else{return rr(n)}}}function S(e){return{tasks:[],elts:[e]}}function fr(e,t){var r=e[0];var n=e[e.length-1];if(t.scroll){var i=null;if(t.scrollTarget){i=ie(r,t.scrollTarget)}if(t.scroll==="top"&&(r||i)){i=i||r;i.scrollTop=0}if(t.scroll==="bottom"&&(n||i)){i=i||n;i.scrollTop=i.scrollHeight}}if(t.show){var i=null;if(t.showTarget){var a=t.showTarget;if(t.showTarget==="window"){a="body"}i=ie(r,a)}if(t.show==="top"&&(r||i)){i=i||r;i.scrollIntoView({block:"start",behavior:G.config.scrollBehavior})}if(t.show==="bottom"&&(n||i)){i=i||n;i.scrollIntoView({block:"end",behavior:G.config.scrollBehavior})}}}function cr(e,t,r,n){if(n==null){n={}}if(e==null){return n}var i=Z(e,t);if(i){var a=i.trim();var o=r;if(a==="unset"){return null}if(a.indexOf("javascript:")===0){a=a.substr(11);o=true}else if(a.indexOf("js:")===0){a=a.substr(3);o=true}if(a.indexOf("{")!==0){a="{"+a+"}"}var s;if(o){s=hr(e,function(){return Function("return ("+a+")")()},{})}else{s=y(a)}for(var l in s){if(s.hasOwnProperty(l)){if(n[l]==null){n[l]=s[l]}}}}return cr(u(e),t,r,n)}function hr(e,t,r){if(G.config.allowEval){return t()}else{ae(e,"htmx:evalDisallowedError");return r}}function dr(e,t){return cr(e,"hx-vars",true,t)}function vr(e,t){return cr(e,"hx-vals",false,t)}function gr(e){return ne(dr(e),vr(e))}function pr(t,r,n){if(n!==null){try{t.setRequestHeader(r,n)}catch(e){t.setRequestHeader(r,encodeURIComponent(n));t.setRequestHeader(r+"-URI-AutoEncoded","true")}}}function mr(t){if(t.responseURL&&typeof URL!=="undefined"){try{var e=new URL(t.responseURL);return e.pathname+e.search}catch(e){ae(K().body,"htmx:badResponseUrl",{url:t.responseURL})}}}function E(e,t){return e.getAllResponseHeaders().match(t)}function xr(e,t,r){e=e.toLowerCase();if(r){if(r instanceof Element||L(r,"String")){return se(e,t,null,null,{targetOverride:s(r),returnPromise:true})}else{return se(e,t,s(r.source),r.event,{handler:r.handler,headers:r.headers,values:r.values,targetOverride:s(r.target),swapOverride:r.swap,returnPromise:true})}}else{return se(e,t,null,null,{returnPromise:true})}}function yr(e){var t=[];while(e){t.push(e);e=e.parentElement}return t}function br(e,t,r){var n=new URL(t,document.location.href);var i=document.location.origin;var a=i===n.origin;if(G.config.selfRequestsOnly){if(!a){return false}}return oe(e,"htmx:validateUrl",ne({url:n,sameHost:a},r))}function se(e,t,n,r,i,M){var a=null;var o=null;i=i!=null?i:{};if(i.returnPromise&&typeof Promise!=="undefined"){var s=new Promise(function(e,t){a=e;o=t})}if(n==null){n=K().body}var D=i.handler||Sr;if(!re(n)){return}var l=i.targetOverride||de(n);if(l==null||l==fe){ae(n,"htmx:targetError",{target:Z(n,"hx-target")});return}if(!M){var X=function(){return se(e,t,n,r,i,true)};var F={target:l,elt:n,path:t,verb:e,triggeringEvent:r,etc:i,issueRequest:X};if(oe(n,"htmx:confirm",F)===false){return}}var u=n;var f=ee(n);var c=Y(n,"hx-sync");var h=null;var d=false;if(c){var v=c.split(":");var g=v[0].trim();if(g==="this"){u=he(n,"hx-sync")}else{u=ie(n,g)}c=(v[1]||"drop").trim();f=ee(u);if(c==="drop"&&f.xhr&&f.abortable!==true){return}else if(c==="abort"){if(f.xhr){return}else{d=true}}else if(c==="replace"){oe(u,"htmx:abort")}else if(c.indexOf("queue")===0){var U=c.split(" ");h=(U[1]||"last").trim()}}if(f.xhr){if(f.abortable){oe(u,"htmx:abort")}else{if(h==null){if(r){var p=ee(r);if(p&&p.triggerSpec&&p.triggerSpec.queue){h=p.triggerSpec.queue}}if(h==null){h="last"}}if(f.queuedRequests==null){f.queuedRequests=[]}if(h==="first"&&f.queuedRequests.length===0){f.queuedRequests.push(function(){se(e,t,n,r,i)})}else if(h==="all"){f.queuedRequests.push(function(){se(e,t,n,r,i)})}else if(h==="last"){f.queuedRequests=[];f.queuedRequests.push(function(){se(e,t,n,r,i)})}return}}var m=new XMLHttpRequest;f.xhr=m;f.abortable=d;var x=function(){f.xhr=null;f.abortable=false;if(f.queuedRequests!=null&&f.queuedRequests.length>0){var e=f.queuedRequests.shift();e()}};var y=Y(n,"hx-prompt");if(y){var b=prompt(y);if(b===null||!oe(n,"htmx:prompt",{prompt:b,target:l})){Q(a);x();return s}}var w=Y(n,"hx-confirm");if(w){if(!confirm(w)){Q(a);x();return s}}var S=ir(n,l,b);if(i.headers){S=ne(S,i.headers)}var E=er(n,e);var C=E.errors;var R=E.values;if(i.values){R=ne(R,i.values)}var B=gr(n);var O=ne(R,B);var T=ar(O,n);if(e!=="get"&&!lr(n)){S["Content-Type"]="application/x-www-form-urlencoded"}if(G.config.getCacheBusterParam&&e==="get"){T["org.htmx.cache-buster"]=J(l,"id")||"true"}if(t==null||t===""){t=K().location.href}var q=cr(n,"hx-request");var V=ee(n).boosted;var H=G.config.methodsThatUseUrlParams.indexOf(e)>=0;var L={boosted:V,useUrlParams:H,parameters:T,unfilteredParameters:O,headers:S,target:l,verb:e,errors:C,withCredentials:i.credentials||q.credentials||G.config.withCredentials,timeout:i.timeout||q.timeout||G.config.timeout,path:t,triggeringEvent:r};if(!oe(n,"htmx:configRequest",L)){Q(a);x();return s}t=L.path;e=L.verb;S=L.headers;T=L.parameters;C=L.errors;H=L.useUrlParams;if(C&&C.length>0){oe(n,"htmx:validation:halted",L);Q(a);x();return s}var j=t.split("#");var W=j[0];var A=j[1];var N=t;if(H){N=W;var _=Object.keys(T).length!==0;if(_){if(N.indexOf("?")<0){N+="?"}else{N+="&"}N+=rr(T);if(A){N+="#"+A}}}if(!br(n,N,L)){ae(n,"htmx:invalidPath",L);return}m.open(e.toUpperCase(),N,true);m.overrideMimeType("text/html");m.withCredentials=L.withCredentials;m.timeout=L.timeout;if(q.noHeaders){}else{for(var I in S){if(S.hasOwnProperty(I)){var z=S[I];pr(m,I,z)}}}var P={xhr:m,target:l,requestConfig:L,etc:i,boosted:V,pathInfo:{requestPath:t,finalRequestPath:N,anchor:A}};m.onload=function(){try{var e=yr(n);P.pathInfo.responsePath=mr(m);D(n,P);Gt(k);oe(n,"htmx:afterRequest",P);oe(n,"htmx:afterOnLoad",P);if(!re(n)){var t=null;while(e.length>0&&t==null){var r=e.shift();if(re(r)){t=r}}if(t){oe(t,"htmx:afterRequest",P);oe(t,"htmx:afterOnLoad",P)}}Q(a);x()}catch(e){ae(n,"htmx:onLoadError",ne({error:e},P));throw e}};m.onerror=function(){Gt(k);ae(n,"htmx:afterRequest",P);ae(n,"htmx:sendError",P);Q(o);x()};m.onabort=function(){Gt(k);ae(n,"htmx:afterRequest",P);ae(n,"htmx:sendAbort",P);Q(o);x()};m.ontimeout=function(){Gt(k);ae(n,"htmx:afterRequest",P);ae(n,"htmx:timeout",P);Q(o);x()};if(!oe(n,"htmx:beforeRequest",P)){Q(a);x();return s}var k=$t(n);te(["loadstart","loadend","progress","abort"],function(t){te([m,m.upload],function(e){e.addEventListener(t,function(e){oe(n,"htmx:xhr:"+t,{lengthComputable:e.lengthComputable,loaded:e.loaded,total:e.total})})})});oe(n,"htmx:beforeSend",P);var $=H?null:ur(m,n,T);m.send($);return s}function wr(e,t){var r=t.xhr;var n=null;var i=null;if(E(r,/HX-Push:/i)){n=r.getResponseHeader("HX-Push");i="push"}else if(E(r,/HX-Push-Url:/i)){n=r.getResponseHeader("HX-Push-Url");i="push"}else if(E(r,/HX-Replace-Url:/i)){n=r.getResponseHeader("HX-Replace-Url");i="replace"}if(n){if(n==="false"){return{}}else{return{type:i,path:n}}}var a=t.pathInfo.finalRequestPath;var o=t.pathInfo.responsePath;var s=Y(e,"hx-push-url");var l=Y(e,"hx-replace-url");var u=ee(e).boosted;var f=null;var c=null;if(s){f="push";c=s}else if(l){f="replace";c=l}else if(u){f="push";c=o||a}if(c){if(c==="false"){return{}}if(c==="true"){c=o||a}if(t.pathInfo.anchor&&c.indexOf("#")===-1){c=c+"#"+t.pathInfo.anchor}return{type:f,path:c}}else{return{}}}function Sr(l,u){var f=u.xhr;var c=u.target;var e=u.etc;if(!oe(l,"htmx:beforeOnLoad",u))return;if(E(f,/HX-Trigger:/i)){Xe(f,"HX-Trigger",l)}if(E(f,/HX-Location:/i)){Bt();var t=f.getResponseHeader("HX-Location");var h;if(t.indexOf("{")===0){h=y(t);t=h["path"];delete h["path"]}xr("GET",t,h).then(function(){Vt(t)});return}if(E(f,/HX-Redirect:/i)){location.href=f.getResponseHeader("HX-Redirect");return}if(E(f,/HX-Refresh:/i)){if("true"===f.getResponseHeader("HX-Refresh")){location.reload();return}}if(E(f,/HX-Retarget:/i)){u.target=K().querySelector(f.getResponseHeader("HX-Retarget"))}var d=wr(l,u);var r=f.status>=200&&f.status<400&&f.status!==204;var v=f.response;var n=f.status>=400;var i=ne({shouldSwap:r,serverResponse:v,isError:n},u);if(!oe(c,"htmx:beforeSwap",i))return;c=i.target;v=i.serverResponse;n=i.isError;u.target=c;u.failed=n;u.successful=!n;if(i.shouldSwap){if(f.status===286){Je(l)}w(l,function(e){v=e.transformResponse(v,f,l)});if(d.type){Bt()}var a=e.swapOverride;if(E(f,/HX-Reswap:/i)){a=f.getResponseHeader("HX-Reswap")}var h=sr(l,a);c.classList.add(G.config.swappingClass);var g=null;var p=null;var o=function(){try{var e=document.activeElement;var t={};try{t={elt:e,start:e?e.selectionStart:null,end:e?e.selectionEnd:null}}catch(e){}var r;if(E(f,/HX-Reselect:/i)){r=f.getResponseHeader("HX-Reselect")}var n=S(c);De(h.swapStyle,c,l,v,n,r);if(t.elt&&!re(t.elt)&&J(t.elt,"id")){var i=document.getElementById(J(t.elt,"id"));var a={preventScroll:h.focusScroll!==undefined?!h.focusScroll:!G.config.defaultFocusScroll};if(i){if(t.start&&i.setSelectionRange){try{i.setSelectionRange(t.start,t.end)}catch(e){}}i.focus(a)}}c.classList.remove(G.config.swappingClass);te(n.elts,function(e){if(e.classList){e.classList.add(G.config.settlingClass)}oe(e,"htmx:afterSwap",u)});if(E(f,/HX-Trigger-After-Swap:/i)){var o=l;if(!re(l)){o=K().body}Xe(f,"HX-Trigger-After-Swap",o)}var s=function(){te(n.tasks,function(e){e.call()});te(n.elts,function(e){if(e.classList){e.classList.remove(G.config.settlingClass)}oe(e,"htmx:afterSettle",u)});if(d.type){if(d.type==="push"){Vt(d.path);oe(K().body,"htmx:pushedIntoHistory",{path:d.path})}else{jt(d.path);oe(K().body,"htmx:replacedInHistory",{path:d.path})}}if(u.pathInfo.anchor){var e=b("#"+u.pathInfo.anchor);if(e){e.scrollIntoView({block:"start",behavior:"auto"})}}if(n.title){var t=b("title");if(t){t.innerHTML=n.title}else{window.document.title=n.title}}fr(n.elts,h);if(E(f,/HX-Trigger-After-Settle:/i)){var r=l;if(!re(l)){r=K().body}Xe(f,"HX-Trigger-After-Settle",r)}Q(g)};if(h.settleDelay>0){setTimeout(s,h.settleDelay)}else{s()}}catch(e){ae(l,"htmx:swapError",u);Q(p);throw e}};var s=G.config.globalViewTransitions;if(h.hasOwnProperty("transition")){s=h.transition}if(s&&oe(l,"htmx:beforeTransition",u)&&typeof Promise!=="undefined"&&document.startViewTransition){var m=new Promise(function(e,t){g=e;p=t});var x=o;o=function(){document.startViewTransition(function(){x();return m})}}if(h.swapDelay>0){setTimeout(o,h.swapDelay)}else{o()}}if(n){ae(l,"htmx:responseError",ne({error:"Response Status Error Code "+f.status+" from "+u.pathInfo.requestPath},u))}}var Er={};function Cr(){return{init:function(e){return null},onEvent:function(e,t){return true},transformResponse:function(e,t,r){return e},isInlineSwap:function(e){return false},handleSwap:function(e,t,r,n){return false},encodeParameters:function(e,t,r){return null}}}function Rr(e,t){if(t.init){t.init(C)}Er[e]=ne(Cr(),t)}function Or(e){delete Er[e]}function Tr(e,r,n){if(e==undefined){return r}if(r==undefined){r=[]}if(n==undefined){n=[]}var t=Z(e,"hx-ext");if(t){te(t.split(","),function(e){e=e.replace(/ /g,"");if(e.slice(0,7)=="ignore:"){n.push(e.slice(7));return}if(n.indexOf(e)<0){var t=Er[e];if(t&&r.indexOf(t)<0){r.push(t)}}})}return Tr(u(e),r,n)}var qr=false;K().addEventListener("DOMContentLoaded",function(){qr=true});function Hr(e){if(qr||K().readyState==="complete"){e()}else{K().addEventListener("DOMContentLoaded",e)}}function Lr(){if(G.config.includeIndicatorStyles!==false){K().head.insertAdjacentHTML("beforeend","<style> ."+G.config.indicatorClass+"{opacity:0;transition: opacity 200ms ease-in;} ."+G.config.requestClass+" ."+G.config.indicatorClass+"{opacity:1} ."+G.config.requestClass+"."+G.config.indicatorClass+"{opacity:1} </style>")}}function Ar(){var e=K().querySelector('meta[name="htmx-config"]');if(e){return y(e.content)}else{return null}}function Nr(){var e=Ar();if(e){G.config=ne(G.config,e)}}Hr(function(){Nr();Lr();var e=K().body;Nt(e);var t=K().querySelectorAll("[hx-trigger='restored'],[data-hx-trigger='restored']");e.addEventListener("htmx:abort",function(e){var t=e.target;var r=ee(t);if(r&&r.xhr){r.xhr.abort()}});var r=window.onpopstate;window.onpopstate=function(e){if(e.state&&e.state.htmx){zt();te(t,function(e){oe(e,"htmx:restored",{document:K(),triggerEvent:oe})})}else{if(r){r(e)}}};setTimeout(function(){oe(e,"htmx:load",{});e=null},0)});return G}()});⏎̸
@@ -0,0 +1,1 @@
1+(function(e,t){if(typeof define==="function"&&define.amd){define([],t)}else if(typeof module==="object"&&module.exports){module.exports=t()}else{e.htmx=e.htmx||t()}})(typeof self!=="undefined"?self:this,function(){return function(){"use strict";var G={onLoad:t,process:Nt,on:le,off:ue,trigger:oe,ajax:xr,find:b,findAll:f,closest:d,values:function(e,t){var r=er(e,t||"post");return r.values},remove:U,addClass:B,removeClass:n,toggleClass:V,takeClass:j,defineExtension:Rr,removeExtension:Or,logAll:X,logNone:F,logger:null,config:{historyEnabled:true,historyCacheSize:10,refreshOnHistoryMiss:false,defaultSwapStyle:"innerHTML",defaultSwapDelay:0,defaultSettleDelay:20,includeIndicatorStyles:true,indicatorClass:"htmx-indicator",requestClass:"htmx-request",addedClass:"htmx-added",settlingClass:"htmx-settling",swappingClass:"htmx-swapping",allowEval:true,allowScriptTags:true,inlineScriptNonce:"",attributesToSettle:["class","style","width","height"],withCredentials:false,timeout:0,wsReconnectDelay:"full-jitter",wsBinaryType:"blob",disableSelector:"[hx-disable], [data-hx-disable]",useTemplateFragments:false,scrollBehavior:"smooth",defaultFocusScroll:false,getCacheBusterParam:false,globalViewTransitions:false,methodsThatUseUrlParams:["get"],selfRequestsOnly:false},parseInterval:v,_:e,createEventSource:function(e){return new EventSource(e,{withCredentials:true})},createWebSocket:function(e){var t=new WebSocket(e,[]);t.binaryType=G.config.wsBinaryType;return t},version:"1.9.5"};var C={addTriggerHandler:bt,bodyContains:re,canAccessLocalStorage:M,findThisElement:he,filterValues:ar,hasAttribute:o,getAttributeValue:Z,getClosestAttributeValue:Y,getClosestMatch:c,getExpressionVars:gr,getHeaders:ir,getInputValues:er,getInternalData:ee,getSwapSpecification:sr,getTriggerSpecs:Ge,getTarget:de,makeFragment:l,mergeObjects:ne,makeSettleInfo:S,oobSwap:me,querySelectorExt:ie,selectAndSwap:De,settleImmediately:Wt,shouldCancel:Qe,triggerEvent:oe,triggerErrorEvent:ae,withExtensions:w};var R=["get","post","put","delete","patch"];var O=R.map(function(e){return"[hx-"+e+"], [data-hx-"+e+"]"}).join(", ");function v(e){if(e==undefined){return undefined}if(e.slice(-2)=="ms"){return parseFloat(e.slice(0,-2))||undefined}if(e.slice(-1)=="s"){return parseFloat(e.slice(0,-1))*1e3||undefined}if(e.slice(-1)=="m"){return parseFloat(e.slice(0,-1))*1e3*60||undefined}return parseFloat(e)||undefined}function J(e,t){return e.getAttribute&&e.getAttribute(t)}function o(e,t){return e.hasAttribute&&(e.hasAttribute(t)||e.hasAttribute("data-"+t))}function Z(e,t){return J(e,t)||J(e,"data-"+t)}function u(e){return e.parentElement}function K(){return document}function c(e,t){while(e&&!t(e)){e=u(e)}return e?e:null}function T(e,t,r){var n=Z(t,r);var i=Z(t,"hx-disinherit");if(e!==t&&i&&(i==="*"||i.split(" ").indexOf(r)>=0)){return"unset"}else{return n}}function Y(t,r){var n=null;c(t,function(e){return n=T(t,e,r)});if(n!=="unset"){return n}}function h(e,t){var r=e.matches||e.matchesSelector||e.msMatchesSelector||e.mozMatchesSelector||e.webkitMatchesSelector||e.oMatchesSelector;return r&&r.call(e,t)}function q(e){var t=/<([a-z][^\/\0>\x20\t\r\n\f]*)/i;var r=t.exec(e);if(r){return r[1].toLowerCase()}else{return""}}function i(e,t){var r=new DOMParser;var n=r.parseFromString(e,"text/html");var i=n.body;while(t>0){t--;i=i.firstChild}if(i==null){i=K().createDocumentFragment()}return i}function H(e){return e.match(/<body/)}function l(e){var t=!H(e);if(G.config.useTemplateFragments&&t){var r=i("<body><template>"+e+"</template></body>",0);return r.querySelector("template").content}else{var n=q(e);switch(n){case"thead":case"tbody":case"tfoot":case"colgroup":case"caption":return i("<table>"+e+"</table>",1);case"col":return i("<table><colgroup>"+e+"</colgroup></table>",2);case"tr":return i("<table><tbody>"+e+"</tbody></table>",2);case"td":case"th":return i("<table><tbody><tr>"+e+"</tr></tbody></table>",3);case"script":return i("<div>"+e+"</div>",1);default:return i(e,0)}}}function Q(e){if(e){e()}}function L(e,t){return Object.prototype.toString.call(e)==="[object "+t+"]"}function A(e){return L(e,"Function")}function N(e){return L(e,"Object")}function ee(e){var t="htmx-internal-data";var r=e[t];if(!r){r=e[t]={}}return r}function I(e){var t=[];if(e){for(var r=0;r<e.length;r++){t.push(e[r])}}return t}function te(e,t){if(e){for(var r=0;r<e.length;r++){t(e[r])}}}function P(e){var t=e.getBoundingClientRect();var r=t.top;var n=t.bottom;return r<window.innerHeight&&n>=0}function re(e){if(e.getRootNode&&e.getRootNode()instanceof window.ShadowRoot){return K().body.contains(e.getRootNode().host)}else{return K().body.contains(e)}}function k(e){return e.trim().split(/\s+/)}function ne(e,t){for(var r in t){if(t.hasOwnProperty(r)){e[r]=t[r]}}return e}function y(e){try{return JSON.parse(e)}catch(e){x(e);return null}}function M(){var e="htmx:localStorageTest";try{localStorage.setItem(e,e);localStorage.removeItem(e);return true}catch(e){return false}}function D(t){try{var e=new URL(t);if(e){t=e.pathname+e.search}if(!t.match("^/$")){t=t.replace(/\/+$/,"")}return t}catch(e){return t}}function e(e){return hr(K().body,function(){return eval(e)})}function t(t){var e=G.on("htmx:load",function(e){t(e.detail.elt)});return e}function X(){G.logger=function(e,t,r){if(console){console.log(t,e,r)}}}function F(){G.logger=null}function b(e,t){if(t){return e.querySelector(t)}else{return b(K(),e)}}function f(e,t){if(t){return e.querySelectorAll(t)}else{return f(K(),e)}}function U(e,t){e=s(e);if(t){setTimeout(function(){U(e);e=null},t)}else{e.parentElement.removeChild(e)}}function B(e,t,r){e=s(e);if(r){setTimeout(function(){B(e,t);e=null},r)}else{e.classList&&e.classList.add(t)}}function n(e,t,r){e=s(e);if(r){setTimeout(function(){n(e,t);e=null},r)}else{if(e.classList){e.classList.remove(t);if(e.classList.length===0){e.removeAttribute("class")}}}}function V(e,t){e=s(e);e.classList.toggle(t)}function j(e,t){e=s(e);te(e.parentElement.children,function(e){n(e,t)});B(e,t)}function d(e,t){e=s(e);if(e.closest){return e.closest(t)}else{do{if(e==null||h(e,t)){return e}}while(e=e&&u(e));return null}}function r(e){var t=e.trim();if(t.startsWith("<")&&t.endsWith("/>")){return t.substring(1,t.length-2)}else{return t}}function W(e,t){if(t.indexOf("closest ")===0){return[d(e,r(t.substr(8)))]}else if(t.indexOf("find ")===0){return[b(e,r(t.substr(5)))]}else if(t.indexOf("next ")===0){return[_(e,r(t.substr(5)))]}else if(t.indexOf("previous ")===0){return[z(e,r(t.substr(9)))]}else if(t==="document"){return[document]}else if(t==="window"){return[window]}else if(t==="body"){return[document.body]}else{return K().querySelectorAll(r(t))}}var _=function(e,t){var r=K().querySelectorAll(t);for(var n=0;n<r.length;n++){var i=r[n];if(i.compareDocumentPosition(e)===Node.DOCUMENT_POSITION_PRECEDING){return i}}};var z=function(e,t){var r=K().querySelectorAll(t);for(var n=r.length-1;n>=0;n--){var i=r[n];if(i.compareDocumentPosition(e)===Node.DOCUMENT_POSITION_FOLLOWING){return i}}};function ie(e,t){if(t){return W(e,t)[0]}else{return W(K().body,e)[0]}}function s(e){if(L(e,"String")){return b(e)}else{return e}}function $(e,t,r){if(A(t)){return{target:K().body,event:e,listener:t}}else{return{target:s(e),event:t,listener:r}}}function le(t,r,n){Hr(function(){var e=$(t,r,n);e.target.addEventListener(e.event,e.listener)});var e=A(r);return e?r:n}function ue(t,r,n){Hr(function(){var e=$(t,r,n);e.target.removeEventListener(e.event,e.listener)});return A(r)?r:n}var fe=K().createElement("output");function ce(e,t){var r=Y(e,t);if(r){if(r==="this"){return[he(e,t)]}else{var n=W(e,r);if(n.length===0){x('The selector "'+r+'" on '+t+" returned no matches!");return[fe]}else{return n}}}}function he(e,t){return c(e,function(e){return Z(e,t)!=null})}function de(e){var t=Y(e,"hx-target");if(t){if(t==="this"){return he(e,"hx-target")}else{return ie(e,t)}}else{var r=ee(e);if(r.boosted){return K().body}else{return e}}}function ve(e){var t=G.config.attributesToSettle;for(var r=0;r<t.length;r++){if(e===t[r]){return true}}return false}function ge(t,r){te(t.attributes,function(e){if(!r.hasAttribute(e.name)&&ve(e.name)){t.removeAttribute(e.name)}});te(r.attributes,function(e){if(ve(e.name)){t.setAttribute(e.name,e.value)}})}function pe(e,t){var r=Tr(t);for(var n=0;n<r.length;n++){var i=r[n];try{if(i.isInlineSwap(e)){return true}}catch(e){x(e)}}return e==="outerHTML"}function me(e,i,a){var t="#"+J(i,"id");var o="outerHTML";if(e==="true"){}else if(e.indexOf(":")>0){o=e.substr(0,e.indexOf(":"));t=e.substr(e.indexOf(":")+1,e.length)}else{o=e}var r=K().querySelectorAll(t);if(r){te(r,function(e){var t;var r=i.cloneNode(true);t=K().createDocumentFragment();t.appendChild(r);if(!pe(o,e)){t=r}var n={shouldSwap:true,target:e,fragment:t};if(!oe(e,"htmx:oobBeforeSwap",n))return;e=n.target;if(n["shouldSwap"]){ke(o,e,e,t,a)}te(a.elts,function(e){oe(e,"htmx:oobAfterSwap",n)})});i.parentNode.removeChild(i)}else{i.parentNode.removeChild(i);ae(K().body,"htmx:oobErrorNoTarget",{content:i})}return e}function xe(e,t,r){var n=Y(e,"hx-select-oob");if(n){var i=n.split(",");for(let e=0;e<i.length;e++){var a=i[e].split(":",2);var o=a[0].trim();if(o.indexOf("#")===0){o=o.substring(1)}var s=a[1]||"true";var l=t.querySelector("#"+o);if(l){me(s,l,r)}}}te(f(t,"[hx-swap-oob], [data-hx-swap-oob]"),function(e){var t=Z(e,"hx-swap-oob");if(t!=null){me(t,e,r)}})}function ye(e){te(f(e,"[hx-preserve], [data-hx-preserve]"),function(e){var t=Z(e,"id");var r=K().getElementById(t);if(r!=null){e.parentNode.replaceChild(r,e)}})}function be(o,e,s){te(e.querySelectorAll("[id]"),function(e){var t=J(e,"id");if(t&&t.length>0){var r=t.replace("'","\\'");var n=e.tagName.replace(":","\\:");var i=o.querySelector(n+"[id='"+r+"']");if(i&&i!==o){var a=e.cloneNode();ge(e,i);s.tasks.push(function(){ge(e,a)})}}})}function we(e){return function(){n(e,G.config.addedClass);Nt(e);St(e);Se(e);oe(e,"htmx:load")}}function Se(e){var t="[autofocus]";var r=h(e,t)?e:e.querySelector(t);if(r!=null){r.focus()}}function a(e,t,r,n){be(e,r,n);while(r.childNodes.length>0){var i=r.firstChild;B(i,G.config.addedClass);e.insertBefore(i,t);if(i.nodeType!==Node.TEXT_NODE&&i.nodeType!==Node.COMMENT_NODE){n.tasks.push(we(i))}}}function Ee(e,t){var r=0;while(r<e.length){t=(t<<5)-t+e.charCodeAt(r++)|0}return t}function Ce(e){var t=0;if(e.attributes){for(var r=0;r<e.attributes.length;r++){var n=e.attributes[r];if(n.value){t=Ee(n.name,t);t=Ee(n.value,t)}}}return t}function Re(t){var r=ee(t);if(r.onHandlers){for(let e=0;e<r.onHandlers.length;e++){const n=r.onHandlers[e];t.removeEventListener(n.event,n.listener)}delete r.onHandlers}}function Oe(e){var t=ee(e);if(t.timeout){clearTimeout(t.timeout)}if(t.webSocket){t.webSocket.close()}if(t.sseEventSource){t.sseEventSource.close()}if(t.listenerInfos){te(t.listenerInfos,function(e){if(e.on){e.on.removeEventListener(e.trigger,e.listener)}})}if(t.initHash){t.initHash=null}Re(e)}function g(e){oe(e,"htmx:beforeCleanupElement");Oe(e);if(e.children){te(e.children,function(e){g(e)})}}function Te(t,e,r){if(t.tagName==="BODY"){return Ie(t,e,r)}else{var n;var i=t.previousSibling;a(u(t),t,e,r);if(i==null){n=u(t).firstChild}else{n=i.nextSibling}ee(t).replacedWith=n;r.elts=r.elts.filter(function(e){return e!=t});while(n&&n!==t){if(n.nodeType===Node.ELEMENT_NODE){r.elts.push(n)}n=n.nextElementSibling}g(t);u(t).removeChild(t)}}function qe(e,t,r){return a(e,e.firstChild,t,r)}function He(e,t,r){return a(u(e),e,t,r)}function Le(e,t,r){return a(e,null,t,r)}function Ae(e,t,r){return a(u(e),e.nextSibling,t,r)}function Ne(e,t,r){g(e);return u(e).removeChild(e)}function Ie(e,t,r){var n=e.firstChild;a(e,n,t,r);if(n){while(n.nextSibling){g(n.nextSibling);e.removeChild(n.nextSibling)}g(n);e.removeChild(n)}}function Pe(e,t,r){var n=r||Y(e,"hx-select");if(n){var i=K().createDocumentFragment();te(t.querySelectorAll(n),function(e){i.appendChild(e)});t=i}return t}function ke(e,t,r,n,i){switch(e){case"none":return;case"outerHTML":Te(r,n,i);return;case"afterbegin":qe(r,n,i);return;case"beforebegin":He(r,n,i);return;case"beforeend":Le(r,n,i);return;case"afterend":Ae(r,n,i);return;case"delete":Ne(r,n,i);return;default:var a=Tr(t);for(var o=0;o<a.length;o++){var s=a[o];try{var l=s.handleSwap(e,r,n,i);if(l){if(typeof l.length!=="undefined"){for(var u=0;u<l.length;u++){var f=l[u];if(f.nodeType!==Node.TEXT_NODE&&f.nodeType!==Node.COMMENT_NODE){i.tasks.push(we(f))}}}return}}catch(e){x(e)}}if(e==="innerHTML"){Ie(r,n,i)}else{ke(G.config.defaultSwapStyle,t,r,n,i)}}}function Me(e){if(e.indexOf("<title")>-1){var t=e.replace(/<svg(\s[^>]*>|>)([\s\S]*?)<\/svg>/gim,"");var r=t.match(/<title(\s[^>]*>|>)([\s\S]*?)<\/title>/im);if(r){return r[2]}}}function De(e,t,r,n,i,a){i.title=Me(n);var o=l(n);if(o){xe(r,o,i);o=Pe(r,o,a);ye(o);return ke(e,r,t,o,i)}}function Xe(e,t,r){var n=e.getResponseHeader(t);if(n.indexOf("{")===0){var i=y(n);for(var a in i){if(i.hasOwnProperty(a)){var o=i[a];if(!N(o)){o={value:o}}oe(r,a,o)}}}else{var s=n.split(",");for(var l=0;l<s.length;l++){oe(r,s[l].trim(),[])}}}var Fe=/\s/;var p=/[\s,]/;var Ue=/[_$a-zA-Z]/;var Be=/[_$a-zA-Z0-9]/;var Ve=['"',"'","/"];var je=/[^\s]/;function We(e){var t=[];var r=0;while(r<e.length){if(Ue.exec(e.charAt(r))){var n=r;while(Be.exec(e.charAt(r+1))){r++}t.push(e.substr(n,r-n+1))}else if(Ve.indexOf(e.charAt(r))!==-1){var i=e.charAt(r);var n=r;r++;while(r<e.length&&e.charAt(r)!==i){if(e.charAt(r)==="\\"){r++}r++}t.push(e.substr(n,r-n+1))}else{var a=e.charAt(r);t.push(a)}r++}return t}function _e(e,t,r){return Ue.exec(e.charAt(0))&&e!=="true"&&e!=="false"&&e!=="this"&&e!==r&&t!=="."}function ze(e,t,r){if(t[0]==="["){t.shift();var n=1;var i=" return (function("+r+"){ return (";var a=null;while(t.length>0){var o=t[0];if(o==="]"){n--;if(n===0){if(a===null){i=i+"true"}t.shift();i+=")})";try{var s=hr(e,function(){return Function(i)()},function(){return true});s.source=i;return s}catch(e){ae(K().body,"htmx:syntax:error",{error:e,source:i});return null}}}else if(o==="["){n++}if(_e(o,a,r)){i+="(("+r+"."+o+") ? ("+r+"."+o+") : (window."+o+"))"}else{i=i+o}a=t.shift()}}}function m(e,t){var r="";while(e.length>0&&!e[0].match(t)){r+=e.shift()}return r}var $e="input, textarea, select";function Ge(e){var t=Z(e,"hx-trigger");var r=[];if(t){var n=We(t);do{m(n,je);var i=n.length;var a=m(n,/[,\[\s]/);if(a!==""){if(a==="every"){var o={trigger:"every"};m(n,je);o.pollInterval=v(m(n,/[,\[\s]/));m(n,je);var s=ze(e,n,"event");if(s){o.eventFilter=s}r.push(o)}else if(a.indexOf("sse:")===0){r.push({trigger:"sse",sseEvent:a.substr(4)})}else{var l={trigger:a};var s=ze(e,n,"event");if(s){l.eventFilter=s}while(n.length>0&&n[0]!==","){m(n,je);var u=n.shift();if(u==="changed"){l.changed=true}else if(u==="once"){l.once=true}else if(u==="consume"){l.consume=true}else if(u==="delay"&&n[0]===":"){n.shift();l.delay=v(m(n,p))}else if(u==="from"&&n[0]===":"){n.shift();var f=m(n,p);if(f==="closest"||f==="find"||f==="next"||f==="previous"){n.shift();f+=" "+m(n,p)}l.from=f}else if(u==="target"&&n[0]===":"){n.shift();l.target=m(n,p)}else if(u==="throttle"&&n[0]===":"){n.shift();l.throttle=v(m(n,p))}else if(u==="queue"&&n[0]===":"){n.shift();l.queue=m(n,p)}else if((u==="root"||u==="threshold")&&n[0]===":"){n.shift();l[u]=m(n,p)}else{ae(e,"htmx:syntax:error",{token:n.shift()})}}r.push(l)}}if(n.length===i){ae(e,"htmx:syntax:error",{token:n.shift()})}m(n,je)}while(n[0]===","&&n.shift())}if(r.length>0){return r}else if(h(e,"form")){return[{trigger:"submit"}]}else if(h(e,'input[type="button"], input[type="submit"]')){return[{trigger:"click"}]}else if(h(e,$e)){return[{trigger:"change"}]}else{return[{trigger:"click"}]}}function Je(e){ee(e).cancelled=true}function Ze(e,t,r){var n=ee(e);n.timeout=setTimeout(function(){if(re(e)&&n.cancelled!==true){if(!tt(r,e,Pt("hx:poll:trigger",{triggerSpec:r,target:e}))){t(e)}Ze(e,t,r)}},r.pollInterval)}function Ke(e){return location.hostname===e.hostname&&J(e,"href")&&J(e,"href").indexOf("#")!==0}function Ye(t,r,e){if(t.tagName==="A"&&Ke(t)&&(t.target===""||t.target==="_self")||t.tagName==="FORM"){r.boosted=true;var n,i;if(t.tagName==="A"){n="get";i=t.href}else{var a=J(t,"method");n=a?a.toLowerCase():"get";if(n==="get"){}i=J(t,"action")}e.forEach(function(e){rt(t,function(e,t){if(d(e,G.config.disableSelector)){g(e);return}se(n,i,e,t)},r,e,true)})}}function Qe(e,t){if(e.type==="submit"||e.type==="click"){if(t.tagName==="FORM"){return true}if(h(t,'input[type="submit"], button')&&d(t,"form")!==null){return true}if(t.tagName==="A"&&t.href&&(t.getAttribute("href")==="#"||t.getAttribute("href").indexOf("#")!==0)){return true}}return false}function et(e,t){return ee(e).boosted&&e.tagName==="A"&&t.type==="click"&&(t.ctrlKey||t.metaKey)}function tt(e,t,r){var n=e.eventFilter;if(n){try{return n.call(t,r)!==true}catch(e){ae(K().body,"htmx:eventFilter:error",{error:e,source:n.source});return true}}return false}function rt(a,o,e,s,l){var u=ee(a);var t;if(s.from){t=W(a,s.from)}else{t=[a]}if(s.changed){t.forEach(function(e){var t=ee(e);t.lastValue=e.value})}te(t,function(n){var i=function(e){if(!re(a)){n.removeEventListener(s.trigger,i);return}if(et(a,e)){return}if(l||Qe(e,a)){e.preventDefault()}if(tt(s,a,e)){return}var t=ee(e);t.triggerSpec=s;if(t.handledFor==null){t.handledFor=[]}if(t.handledFor.indexOf(a)<0){t.handledFor.push(a);if(s.consume){e.stopPropagation()}if(s.target&&e.target){if(!h(e.target,s.target)){return}}if(s.once){if(u.triggeredOnce){return}else{u.triggeredOnce=true}}if(s.changed){var r=ee(n);if(r.lastValue===n.value){return}r.lastValue=n.value}if(u.delayed){clearTimeout(u.delayed)}if(u.throttle){return}if(s.throttle){if(!u.throttle){o(a,e);u.throttle=setTimeout(function(){u.throttle=null},s.throttle)}}else if(s.delay){u.delayed=setTimeout(function(){o(a,e)},s.delay)}else{oe(a,"htmx:trigger");o(a,e)}}};if(e.listenerInfos==null){e.listenerInfos=[]}e.listenerInfos.push({trigger:s.trigger,listener:i,on:n});n.addEventListener(s.trigger,i)})}var nt=false;var it=null;function at(){if(!it){it=function(){nt=true};window.addEventListener("scroll",it);setInterval(function(){if(nt){nt=false;te(K().querySelectorAll("[hx-trigger='revealed'],[data-hx-trigger='revealed']"),function(e){ot(e)})}},200)}}function ot(t){if(!o(t,"data-hx-revealed")&&P(t)){t.setAttribute("data-hx-revealed","true");var e=ee(t);if(e.initHash){oe(t,"revealed")}else{t.addEventListener("htmx:afterProcessNode",function(e){oe(t,"revealed")},{once:true})}}}function st(e,t,r){var n=k(r);for(var i=0;i<n.length;i++){var a=n[i].split(/:(.+)/);if(a[0]==="connect"){lt(e,a[1],0)}if(a[0]==="send"){ft(e)}}}function lt(s,r,n){if(!re(s)){return}if(r.indexOf("/")==0){var e=location.hostname+(location.port?":"+location.port:"");if(location.protocol=="https:"){r="wss://"+e+r}else if(location.protocol=="http:"){r="ws://"+e+r}}var t=G.createWebSocket(r);t.onerror=function(e){ae(s,"htmx:wsError",{error:e,socket:t});ut(s)};t.onclose=function(e){if([1006,1012,1013].indexOf(e.code)>=0){var t=ct(n);setTimeout(function(){lt(s,r,n+1)},t)}};t.onopen=function(e){n=0};ee(s).webSocket=t;t.addEventListener("message",function(e){if(ut(s)){return}var t=e.data;w(s,function(e){t=e.transformResponse(t,null,s)});var r=S(s);var n=l(t);var i=I(n.children);for(var a=0;a<i.length;a++){var o=i[a];me(Z(o,"hx-swap-oob")||"true",o,r)}Wt(r.tasks)})}function ut(e){if(!re(e)){ee(e).webSocket.close();return true}}function ft(u){var f=c(u,function(e){return ee(e).webSocket!=null});if(f){u.addEventListener(Ge(u)[0].trigger,function(e){var t=ee(f).webSocket;var r=ir(u,f);var n=er(u,"post");var i=n.errors;var a=n.values;var o=gr(u);var s=ne(a,o);var l=ar(s,u);l["HEADERS"]=r;if(i&&i.length>0){oe(u,"htmx:validation:halted",i);return}t.send(JSON.stringify(l));if(Qe(e,u)){e.preventDefault()}})}else{ae(u,"htmx:noWebSocketSourceError")}}function ct(e){var t=G.config.wsReconnectDelay;if(typeof t==="function"){return t(e)}if(t==="full-jitter"){var r=Math.min(e,6);var n=1e3*Math.pow(2,r);return n*Math.random()}x('htmx.config.wsReconnectDelay must either be a function or the string "full-jitter"')}function ht(e,t,r){var n=k(r);for(var i=0;i<n.length;i++){var a=n[i].split(/:(.+)/);if(a[0]==="connect"){dt(e,a[1])}if(a[0]==="swap"){vt(e,a[1])}}}function dt(t,e){var r=G.createEventSource(e);r.onerror=function(e){ae(t,"htmx:sseError",{error:e,source:r});pt(t)};ee(t).sseEventSource=r}function vt(a,o){var s=c(a,mt);if(s){var l=ee(s).sseEventSource;var u=function(e){if(pt(s)){return}if(!re(a)){l.removeEventListener(o,u);return}var t=e.data;w(a,function(e){t=e.transformResponse(t,null,a)});var r=sr(a);var n=de(a);var i=S(a);De(r.swapStyle,n,a,t,i);Wt(i.tasks);oe(a,"htmx:sseMessage",e)};ee(a).sseListener=u;l.addEventListener(o,u)}else{ae(a,"htmx:noSSESourceError")}}function gt(e,t,r){var n=c(e,mt);if(n){var i=ee(n).sseEventSource;var a=function(){if(!pt(n)){if(re(e)){t(e)}else{i.removeEventListener(r,a)}}};ee(e).sseListener=a;i.addEventListener(r,a)}else{ae(e,"htmx:noSSESourceError")}}function pt(e){if(!re(e)){ee(e).sseEventSource.close();return true}}function mt(e){return ee(e).sseEventSource!=null}function xt(e,t,r,n){var i=function(){if(!r.loaded){r.loaded=true;t(e)}};if(n){setTimeout(i,n)}else{i()}}function yt(t,i,e){var a=false;te(R,function(r){if(o(t,"hx-"+r)){var n=Z(t,"hx-"+r);a=true;i.path=n;i.verb=r;e.forEach(function(e){bt(t,e,i,function(e,t){if(d(e,G.config.disableSelector)){g(e);return}se(r,n,e,t)})})}});return a}function bt(n,e,t,r){if(e.sseEvent){gt(n,r,e.sseEvent)}else if(e.trigger==="revealed"){at();rt(n,r,t,e);ot(n)}else if(e.trigger==="intersect"){var i={};if(e.root){i.root=ie(n,e.root)}if(e.threshold){i.threshold=parseFloat(e.threshold)}var a=new IntersectionObserver(function(e){for(var t=0;t<e.length;t++){var r=e[t];if(r.isIntersecting){oe(n,"intersect");break}}},i);a.observe(n);rt(n,r,t,e)}else if(e.trigger==="load"){if(!tt(e,n,Pt("load",{elt:n}))){xt(n,r,t,e.delay)}}else if(e.pollInterval){t.polling=true;Ze(n,r,e)}else{rt(n,r,t,e)}}function wt(e){if(G.config.allowScriptTags&&(e.type==="text/javascript"||e.type==="module"||e.type==="")){var t=K().createElement("script");te(e.attributes,function(e){t.setAttribute(e.name,e.value)});t.textContent=e.textContent;t.async=false;if(G.config.inlineScriptNonce){t.nonce=G.config.inlineScriptNonce}var r=e.parentElement;try{r.insertBefore(t,e)}catch(e){x(e)}finally{if(e.parentElement){e.parentElement.removeChild(e)}}}}function St(e){if(h(e,"script")){wt(e)}te(f(e,"script"),function(e){wt(e)})}function Et(){return document.querySelector("[hx-boost], [data-hx-boost]")}function Ct(e){if(!document.evaluate)return[];let t=null;const r=[];const n=document.evaluate('//*[@*[ starts-with(name(), "hx-on:") or starts-with(name(), "data-hx-on:") ]]',e);while(t=n.iterateNext())r.push(t);return r}function Rt(e){if(e.querySelectorAll){var t=Et()?", a":"";var r=e.querySelectorAll(O+t+", form, [type='submit'], [hx-sse], [data-hx-sse], [hx-ws],"+" [data-hx-ws], [hx-ext], [data-hx-ext], [hx-trigger], [data-hx-trigger], [hx-on], [data-hx-on]");return r}else{return[]}}function Ot(e){var n=s("#"+J(e,"form"))||d(e,"form");if(!n){return}var t=function(e){var t=d(e.target,"button, input[type='submit']");if(t!==null){var r=ee(n);r.lastButtonClicked=t}};e.addEventListener("click",t);e.addEventListener("focusin",t);e.addEventListener("focusout",function(e){var t=ee(n);t.lastButtonClicked=null})}function Tt(e){var t=We(e);var r=0;for(let e=0;e<t.length;e++){const n=t[e];if(n==="{"){r++}else if(n==="}"){r--}}return r}function qt(t,e,r){var n=ee(t);n.onHandlers=[];var i;var a=function(e){return hr(t,function(){if(!i){i=new Function("event",r)}i.call(t,e)})};t.addEventListener(e,a);n.onHandlers.push({event:e,listener:a})}function Ht(e){var t=Z(e,"hx-on");if(t){var r={};var n=t.split("\n");var i=null;var a=0;while(n.length>0){var o=n.shift();var s=o.match(/^\s*([a-zA-Z:\-]+:)(.*)/);if(a===0&&s){o.split(":");i=s[1].slice(0,-1);r[i]=s[2]}else{r[i]+=o}a+=Tt(o)}for(var l in r){qt(e,l,r[l])}}}function Lt(t){Re(t);for(var e=0;e<t.attributes.length;e++){var r=t.attributes[e].name;var n=t.attributes[e].value;if(r.startsWith("hx-on:")||r.startsWith("data-hx-on:")){let e=r.slice(r.indexOf(":")+1);if(e.startsWith(":"))e="htmx"+e;qt(t,e,n)}}}function At(t){if(d(t,G.config.disableSelector)){g(t);return}var r=ee(t);if(r.initHash!==Ce(t)){Oe(t);r.initHash=Ce(t);Ht(t);oe(t,"htmx:beforeProcessNode");if(t.value){r.lastValue=t.value}var e=Ge(t);var n=yt(t,r,e);if(!n){if(Y(t,"hx-boost")==="true"){Ye(t,r,e)}else if(o(t,"hx-trigger")){e.forEach(function(e){bt(t,e,r,function(){})})}}if(t.tagName==="FORM"||J(t,"type")==="submit"&&o(t,"form")){Ot(t)}var i=Z(t,"hx-sse");if(i){ht(t,r,i)}var a=Z(t,"hx-ws");if(a){st(t,r,a)}oe(t,"htmx:afterProcessNode")}}function Nt(e){e=s(e);if(d(e,G.config.disableSelector)){g(e);return}At(e);te(Rt(e),function(e){At(e)});te(Ct(e),Lt)}function It(e){return e.replace(/([a-z0-9])([A-Z])/g,"$1-$2").toLowerCase()}function Pt(e,t){var r;if(window.CustomEvent&&typeof window.CustomEvent==="function"){r=new CustomEvent(e,{bubbles:true,cancelable:true,detail:t})}else{r=K().createEvent("CustomEvent");r.initCustomEvent(e,true,true,t)}return r}function ae(e,t,r){oe(e,t,ne({error:t},r))}function kt(e){return e==="htmx:afterProcessNode"}function w(e,t){te(Tr(e),function(e){try{t(e)}catch(e){x(e)}})}function x(e){if(console.error){console.error(e)}else if(console.log){console.log("ERROR: ",e)}}function oe(e,t,r){e=s(e);if(r==null){r={}}r["elt"]=e;var n=Pt(t,r);if(G.logger&&!kt(t)){G.logger(e,t,r)}if(r.error){x(r.error);oe(e,"htmx:error",{errorInfo:r})}var i=e.dispatchEvent(n);var a=It(t);if(i&&a!==t){var o=Pt(a,n.detail);i=i&&e.dispatchEvent(o)}w(e,function(e){i=i&&e.onEvent(t,n)!==false});return i}var Mt=location.pathname+location.search;function Dt(){var e=K().querySelector("[hx-history-elt],[data-hx-history-elt]");return e||K().body}function Xt(e,t,r,n){if(!M()){return}e=D(e);var i=y(localStorage.getItem("htmx-history-cache"))||[];for(var a=0;a<i.length;a++){if(i[a].url===e){i.splice(a,1);break}}var o={url:e,content:t,title:r,scroll:n};oe(K().body,"htmx:historyItemCreated",{item:o,cache:i});i.push(o);while(i.length>G.config.historyCacheSize){i.shift()}while(i.length>0){try{localStorage.setItem("htmx-history-cache",JSON.stringify(i));break}catch(e){ae(K().body,"htmx:historyCacheError",{cause:e,cache:i});i.shift()}}}function Ft(e){if(!M()){return null}e=D(e);var t=y(localStorage.getItem("htmx-history-cache"))||[];for(var r=0;r<t.length;r++){if(t[r].url===e){return t[r]}}return null}function Ut(e){var t=G.config.requestClass;var r=e.cloneNode(true);te(f(r,"."+t),function(e){n(e,t)});return r.innerHTML}function Bt(){var e=Dt();var t=Mt||location.pathname+location.search;var r=K().querySelector('[hx-history="false" i],[data-hx-history="false" i]');if(!r){oe(K().body,"htmx:beforeHistorySave",{path:t,historyElt:e});Xt(t,Ut(e),K().title,window.scrollY)}if(G.config.historyEnabled)history.replaceState({htmx:true},K().title,window.location.href)}function Vt(e){if(G.config.getCacheBusterParam){e=e.replace(/org\.htmx\.cache-buster=[^&]*&?/,"");if(e.endsWith("&")||e.endsWith("?")){e=e.slice(0,-1)}}if(G.config.historyEnabled){history.pushState({htmx:true},"",e)}Mt=e}function jt(e){if(G.config.historyEnabled)history.replaceState({htmx:true},"",e);Mt=e}function Wt(e){te(e,function(e){e.call()})}function _t(a){var e=new XMLHttpRequest;var o={path:a,xhr:e};oe(K().body,"htmx:historyCacheMiss",o);e.open("GET",a,true);e.setRequestHeader("HX-History-Restore-Request","true");e.onload=function(){if(this.status>=200&&this.status<400){oe(K().body,"htmx:historyCacheMissLoad",o);var e=l(this.response);e=e.querySelector("[hx-history-elt],[data-hx-history-elt]")||e;var t=Dt();var r=S(t);var n=Me(this.response);if(n){var i=b("title");if(i){i.innerHTML=n}else{window.document.title=n}}Ie(t,e,r);Wt(r.tasks);Mt=a;oe(K().body,"htmx:historyRestore",{path:a,cacheMiss:true,serverResponse:this.response})}else{ae(K().body,"htmx:historyCacheMissLoadError",o)}};e.send()}function zt(e){Bt();e=e||location.pathname+location.search;var t=Ft(e);if(t){var r=l(t.content);var n=Dt();var i=S(n);Ie(n,r,i);Wt(i.tasks);document.title=t.title;setTimeout(function(){window.scrollTo(0,t.scroll)},0);Mt=e;oe(K().body,"htmx:historyRestore",{path:e,item:t})}else{if(G.config.refreshOnHistoryMiss){window.location.reload(true)}else{_t(e)}}}function $t(e){var t=ce(e,"hx-indicator");if(t==null){t=[e]}te(t,function(e){var t=ee(e);t.requestCount=(t.requestCount||0)+1;e.classList["add"].call(e.classList,G.config.requestClass)});return t}function Gt(e){te(e,function(e){var t=ee(e);t.requestCount=(t.requestCount||0)-1;if(t.requestCount===0){e.classList["remove"].call(e.classList,G.config.requestClass)}})}function Jt(e,t){for(var r=0;r<e.length;r++){var n=e[r];if(n.isSameNode(t)){return true}}return false}function Zt(e){if(e.name===""||e.name==null||e.disabled){return false}if(e.type==="button"||e.type==="submit"||e.tagName==="image"||e.tagName==="reset"||e.tagName==="file"){return false}if(e.type==="checkbox"||e.type==="radio"){return e.checked}return true}function Kt(e,t,r){if(e!=null&&t!=null){var n=r[e];if(n===undefined){r[e]=t}else if(Array.isArray(n)){if(Array.isArray(t)){r[e]=n.concat(t)}else{n.push(t)}}else{if(Array.isArray(t)){r[e]=[n].concat(t)}else{r[e]=[n,t]}}}}function Yt(t,r,n,e,i){if(e==null||Jt(t,e)){return}else{t.push(e)}if(Zt(e)){var a=J(e,"name");var o=e.value;if(e.multiple){o=I(e.querySelectorAll("option:checked")).map(function(e){return e.value})}if(e.files){o=I(e.files)}Kt(a,o,r);if(i){Qt(e,n)}}if(h(e,"form")){var s=e.elements;te(s,function(e){Yt(t,r,n,e,i)})}}function Qt(e,t){if(e.willValidate){oe(e,"htmx:validation:validate");if(!e.checkValidity()){t.push({elt:e,message:e.validationMessage,validity:e.validity});oe(e,"htmx:validation:failed",{message:e.validationMessage,validity:e.validity})}}}function er(e,t){var r=[];var n={};var i={};var a=[];var o=ee(e);var s=h(e,"form")&&e.noValidate!==true||Z(e,"hx-validate")==="true";if(o.lastButtonClicked){s=s&&o.lastButtonClicked.formNoValidate!==true}if(t!=="get"){Yt(r,i,a,d(e,"form"),s)}Yt(r,n,a,e,s);if(o.lastButtonClicked||e.tagName==="BUTTON"||e.tagName==="INPUT"&&J(e,"type")==="submit"){var l=o.lastButtonClicked||e;var u=J(l,"name");Kt(u,l.value,i)}var f=ce(e,"hx-include");te(f,function(e){Yt(r,n,a,e,s);if(!h(e,"form")){te(e.querySelectorAll($e),function(e){Yt(r,n,a,e,s)})}});n=ne(n,i);return{errors:a,values:n}}function tr(e,t,r){if(e!==""){e+="&"}if(String(r)==="[object Object]"){r=JSON.stringify(r)}var n=encodeURIComponent(r);e+=encodeURIComponent(t)+"="+n;return e}function rr(e){var t="";for(var r in e){if(e.hasOwnProperty(r)){var n=e[r];if(Array.isArray(n)){te(n,function(e){t=tr(t,r,e)})}else{t=tr(t,r,n)}}}return t}function nr(e){var t=new FormData;for(var r in e){if(e.hasOwnProperty(r)){var n=e[r];if(Array.isArray(n)){te(n,function(e){t.append(r,e)})}else{t.append(r,n)}}}return t}function ir(e,t,r){var n={"HX-Request":"true","HX-Trigger":J(e,"id"),"HX-Trigger-Name":J(e,"name"),"HX-Target":Z(t,"id"),"HX-Current-URL":K().location.href};cr(e,"hx-headers",false,n);if(r!==undefined){n["HX-Prompt"]=r}if(ee(e).boosted){n["HX-Boosted"]="true"}return n}function ar(t,e){var r=Y(e,"hx-params");if(r){if(r==="none"){return{}}else if(r==="*"){return t}else if(r.indexOf("not ")===0){te(r.substr(4).split(","),function(e){e=e.trim();delete t[e]});return t}else{var n={};te(r.split(","),function(e){e=e.trim();n[e]=t[e]});return n}}else{return t}}function or(e){return J(e,"href")&&J(e,"href").indexOf("#")>=0}function sr(e,t){var r=t?t:Y(e,"hx-swap");var n={swapStyle:ee(e).boosted?"innerHTML":G.config.defaultSwapStyle,swapDelay:G.config.defaultSwapDelay,settleDelay:G.config.defaultSettleDelay};if(ee(e).boosted&&!or(e)){n["show"]="top"}if(r){var i=k(r);if(i.length>0){n["swapStyle"]=i[0];for(var a=1;a<i.length;a++){var o=i[a];if(o.indexOf("swap:")===0){n["swapDelay"]=v(o.substr(5))}if(o.indexOf("settle:")===0){n["settleDelay"]=v(o.substr(7))}if(o.indexOf("transition:")===0){n["transition"]=o.substr(11)==="true"}if(o.indexOf("scroll:")===0){var s=o.substr(7);var l=s.split(":");var u=l.pop();var f=l.length>0?l.join(":"):null;n["scroll"]=u;n["scrollTarget"]=f}if(o.indexOf("show:")===0){var c=o.substr(5);var l=c.split(":");var h=l.pop();var f=l.length>0?l.join(":"):null;n["show"]=h;n["showTarget"]=f}if(o.indexOf("focus-scroll:")===0){var d=o.substr("focus-scroll:".length);n["focusScroll"]=d=="true"}}}}return n}function lr(e){return Y(e,"hx-encoding")==="multipart/form-data"||h(e,"form")&&J(e,"enctype")==="multipart/form-data"}function ur(t,r,n){var i=null;w(r,function(e){if(i==null){i=e.encodeParameters(t,n,r)}});if(i!=null){return i}else{if(lr(r)){return nr(n)}else{return rr(n)}}}function S(e){return{tasks:[],elts:[e]}}function fr(e,t){var r=e[0];var n=e[e.length-1];if(t.scroll){var i=null;if(t.scrollTarget){i=ie(r,t.scrollTarget)}if(t.scroll==="top"&&(r||i)){i=i||r;i.scrollTop=0}if(t.scroll==="bottom"&&(n||i)){i=i||n;i.scrollTop=i.scrollHeight}}if(t.show){var i=null;if(t.showTarget){var a=t.showTarget;if(t.showTarget==="window"){a="body"}i=ie(r,a)}if(t.show==="top"&&(r||i)){i=i||r;i.scrollIntoView({block:"start",behavior:G.config.scrollBehavior})}if(t.show==="bottom"&&(n||i)){i=i||n;i.scrollIntoView({block:"end",behavior:G.config.scrollBehavior})}}}function cr(e,t,r,n){if(n==null){n={}}if(e==null){return n}var i=Z(e,t);if(i){var a=i.trim();var o=r;if(a==="unset"){return null}if(a.indexOf("javascript:")===0){a=a.substr(11);o=true}else if(a.indexOf("js:")===0){a=a.substr(3);o=true}if(a.indexOf("{")!==0){a="{"+a+"}"}var s;if(o){s=hr(e,function(){return Function("return ("+a+")")()},{})}else{s=y(a)}for(var l in s){if(s.hasOwnProperty(l)){if(n[l]==null){n[l]=s[l]}}}}return cr(u(e),t,r,n)}function hr(e,t,r){if(G.config.allowEval){return t()}else{ae(e,"htmx:evalDisallowedError");return r}}function dr(e,t){return cr(e,"hx-vars",true,t)}function vr(e,t){return cr(e,"hx-vals",false,t)}function gr(e){return ne(dr(e),vr(e))}function pr(t,r,n){if(n!==null){try{t.setRequestHeader(r,n)}catch(e){t.setRequestHeader(r,encodeURIComponent(n));t.setRequestHeader(r+"-URI-AutoEncoded","true")}}}function mr(t){if(t.responseURL&&typeof URL!=="undefined"){try{var e=new URL(t.responseURL);return e.pathname+e.search}catch(e){ae(K().body,"htmx:badResponseUrl",{url:t.responseURL})}}}function E(e,t){return e.getAllResponseHeaders().match(t)}function xr(e,t,r){e=e.toLowerCase();if(r){if(r instanceof Element||L(r,"String")){return se(e,t,null,null,{targetOverride:s(r),returnPromise:true})}else{return se(e,t,s(r.source),r.event,{handler:r.handler,headers:r.headers,values:r.values,targetOverride:s(r.target),swapOverride:r.swap,returnPromise:true})}}else{return se(e,t,null,null,{returnPromise:true})}}function yr(e){var t=[];while(e){t.push(e);e=e.parentElement}return t}function br(e,t,r){var n=new URL(t,document.location.href);var i=document.location.origin;var a=i===n.origin;if(G.config.selfRequestsOnly){if(!a){return false}}return oe(e,"htmx:validateUrl",ne({url:n,sameHost:a},r))}function se(e,t,n,r,i,M){var a=null;var o=null;i=i!=null?i:{};if(i.returnPromise&&typeof Promise!=="undefined"){var s=new Promise(function(e,t){a=e;o=t})}if(n==null){n=K().body}var D=i.handler||Sr;if(!re(n)){return}var l=i.targetOverride||de(n);if(l==null||l==fe){ae(n,"htmx:targetError",{target:Z(n,"hx-target")});return}if(!M){var X=function(){return se(e,t,n,r,i,true)};var F={target:l,elt:n,path:t,verb:e,triggeringEvent:r,etc:i,issueRequest:X};if(oe(n,"htmx:confirm",F)===false){return}}var u=n;var f=ee(n);var c=Y(n,"hx-sync");var h=null;var d=false;if(c){var v=c.split(":");var g=v[0].trim();if(g==="this"){u=he(n,"hx-sync")}else{u=ie(n,g)}c=(v[1]||"drop").trim();f=ee(u);if(c==="drop"&&f.xhr&&f.abortable!==true){return}else if(c==="abort"){if(f.xhr){return}else{d=true}}else if(c==="replace"){oe(u,"htmx:abort")}else if(c.indexOf("queue")===0){var U=c.split(" ");h=(U[1]||"last").trim()}}if(f.xhr){if(f.abortable){oe(u,"htmx:abort")}else{if(h==null){if(r){var p=ee(r);if(p&&p.triggerSpec&&p.triggerSpec.queue){h=p.triggerSpec.queue}}if(h==null){h="last"}}if(f.queuedRequests==null){f.queuedRequests=[]}if(h==="first"&&f.queuedRequests.length===0){f.queuedRequests.push(function(){se(e,t,n,r,i)})}else if(h==="all"){f.queuedRequests.push(function(){se(e,t,n,r,i)})}else if(h==="last"){f.queuedRequests=[];f.queuedRequests.push(function(){se(e,t,n,r,i)})}return}}var m=new XMLHttpRequest;f.xhr=m;f.abortable=d;var x=function(){f.xhr=null;f.abortable=false;if(f.queuedRequests!=null&&f.queuedRequests.length>0){var e=f.queuedRequests.shift();e()}};var y=Y(n,"hx-prompt");if(y){var b=prompt(y);if(b===null||!oe(n,"htmx:prompt",{prompt:b,target:l})){Q(a);x();return s}}var w=Y(n,"hx-confirm");if(w){if(!confirm(w)){Q(a);x();return s}}var S=ir(n,l,b);if(i.headers){S=ne(S,i.headers)}var E=er(n,e);var C=E.errors;var R=E.values;if(i.values){R=ne(R,i.values)}var B=gr(n);var O=ne(R,B);var T=ar(O,n);if(e!=="get"&&!lr(n)){S["Content-Type"]="application/x-www-form-urlencoded"}if(G.config.getCacheBusterParam&&e==="get"){T["org.htmx.cache-buster"]=J(l,"id")||"true"}if(t==null||t===""){t=K().location.href}var q=cr(n,"hx-request");var V=ee(n).boosted;var H=G.config.methodsThatUseUrlParams.indexOf(e)>=0;var L={boosted:V,useUrlParams:H,parameters:T,unfilteredParameters:O,headers:S,target:l,verb:e,errors:C,withCredentials:i.credentials||q.credentials||G.config.withCredentials,timeout:i.timeout||q.timeout||G.config.timeout,path:t,triggeringEvent:r};if(!oe(n,"htmx:configRequest",L)){Q(a);x();return s}t=L.path;e=L.verb;S=L.headers;T=L.parameters;C=L.errors;H=L.useUrlParams;if(C&&C.length>0){oe(n,"htmx:validation:halted",L);Q(a);x();return s}var j=t.split("#");var W=j[0];var A=j[1];var N=t;if(H){N=W;var _=Object.keys(T).length!==0;if(_){if(N.indexOf("?")<0){N+="?"}else{N+="&"}N+=rr(T);if(A){N+="#"+A}}}if(!br(n,N,L)){ae(n,"htmx:invalidPath",L);return}m.open(e.toUpperCase(),N,true);m.overrideMimeType("text/html");m.withCredentials=L.withCredentials;m.timeout=L.timeout;if(q.noHeaders){}else{for(var I in S){if(S.hasOwnProperty(I)){var z=S[I];pr(m,I,z)}}}var P={xhr:m,target:l,requestConfig:L,etc:i,boosted:V,pathInfo:{requestPath:t,finalRequestPath:N,anchor:A}};m.onload=function(){try{var e=yr(n);P.pathInfo.responsePath=mr(m);D(n,P);Gt(k);oe(n,"htmx:afterRequest",P);oe(n,"htmx:afterOnLoad",P);if(!re(n)){var t=null;while(e.length>0&&t==null){var r=e.shift();if(re(r)){t=r}}if(t){oe(t,"htmx:afterRequest",P);oe(t,"htmx:afterOnLoad",P)}}Q(a);x()}catch(e){ae(n,"htmx:onLoadError",ne({error:e},P));throw e}};m.onerror=function(){Gt(k);ae(n,"htmx:afterRequest",P);ae(n,"htmx:sendError",P);Q(o);x()};m.onabort=function(){Gt(k);ae(n,"htmx:afterRequest",P);ae(n,"htmx:sendAbort",P);Q(o);x()};m.ontimeout=function(){Gt(k);ae(n,"htmx:afterRequest",P);ae(n,"htmx:timeout",P);Q(o);x()};if(!oe(n,"htmx:beforeRequest",P)){Q(a);x();return s}var k=$t(n);te(["loadstart","loadend","progress","abort"],function(t){te([m,m.upload],function(e){e.addEventListener(t,function(e){oe(n,"htmx:xhr:"+t,{lengthComputable:e.lengthComputable,loaded:e.loaded,total:e.total})})})});oe(n,"htmx:beforeSend",P);var $=H?null:ur(m,n,T);m.send($);return s}function wr(e,t){var r=t.xhr;var n=null;var i=null;if(E(r,/HX-Push:/i)){n=r.getResponseHeader("HX-Push");i="push"}else if(E(r,/HX-Push-Url:/i)){n=r.getResponseHeader("HX-Push-Url");i="push"}else if(E(r,/HX-Replace-Url:/i)){n=r.getResponseHeader("HX-Replace-Url");i="replace"}if(n){if(n==="false"){return{}}else{return{type:i,path:n}}}var a=t.pathInfo.finalRequestPath;var o=t.pathInfo.responsePath;var s=Y(e,"hx-push-url");var l=Y(e,"hx-replace-url");var u=ee(e).boosted;var f=null;var c=null;if(s){f="push";c=s}else if(l){f="replace";c=l}else if(u){f="push";c=o||a}if(c){if(c==="false"){return{}}if(c==="true"){c=o||a}if(t.pathInfo.anchor&&c.indexOf("#")===-1){c=c+"#"+t.pathInfo.anchor}return{type:f,path:c}}else{return{}}}function Sr(l,u){var f=u.xhr;var c=u.target;var e=u.etc;if(!oe(l,"htmx:beforeOnLoad",u))return;if(E(f,/HX-Trigger:/i)){Xe(f,"HX-Trigger",l)}if(E(f,/HX-Location:/i)){Bt();var t=f.getResponseHeader("HX-Location");var h;if(t.indexOf("{")===0){h=y(t);t=h["path"];delete h["path"]}xr("GET",t,h).then(function(){Vt(t)});return}if(E(f,/HX-Redirect:/i)){location.href=f.getResponseHeader("HX-Redirect");return}if(E(f,/HX-Refresh:/i)){if("true"===f.getResponseHeader("HX-Refresh")){location.reload();return}}if(E(f,/HX-Retarget:/i)){u.target=K().querySelector(f.getResponseHeader("HX-Retarget"))}var d=wr(l,u);var r=f.status>=200&&f.status<400&&f.status!==204;var v=f.response;var n=f.status>=400;var i=ne({shouldSwap:r,serverResponse:v,isError:n},u);if(!oe(c,"htmx:beforeSwap",i))return;c=i.target;v=i.serverResponse;n=i.isError;u.target=c;u.failed=n;u.successful=!n;if(i.shouldSwap){if(f.status===286){Je(l)}w(l,function(e){v=e.transformResponse(v,f,l)});if(d.type){Bt()}var a=e.swapOverride;if(E(f,/HX-Reswap:/i)){a=f.getResponseHeader("HX-Reswap")}var h=sr(l,a);c.classList.add(G.config.swappingClass);var g=null;var p=null;var o=function(){try{var e=document.activeElement;var t={};try{t={elt:e,start:e?e.selectionStart:null,end:e?e.selectionEnd:null}}catch(e){}var r;if(E(f,/HX-Reselect:/i)){r=f.getResponseHeader("HX-Reselect")}var n=S(c);De(h.swapStyle,c,l,v,n,r);if(t.elt&&!re(t.elt)&&J(t.elt,"id")){var i=document.getElementById(J(t.elt,"id"));var a={preventScroll:h.focusScroll!==undefined?!h.focusScroll:!G.config.defaultFocusScroll};if(i){if(t.start&&i.setSelectionRange){try{i.setSelectionRange(t.start,t.end)}catch(e){}}i.focus(a)}}c.classList.remove(G.config.swappingClass);te(n.elts,function(e){if(e.classList){e.classList.add(G.config.settlingClass)}oe(e,"htmx:afterSwap",u)});if(E(f,/HX-Trigger-After-Swap:/i)){var o=l;if(!re(l)){o=K().body}Xe(f,"HX-Trigger-After-Swap",o)}var s=function(){te(n.tasks,function(e){e.call()});te(n.elts,function(e){if(e.classList){e.classList.remove(G.config.settlingClass)}oe(e,"htmx:afterSettle",u)});if(d.type){if(d.type==="push"){Vt(d.path);oe(K().body,"htmx:pushedIntoHistory",{path:d.path})}else{jt(d.path);oe(K().body,"htmx:replacedInHistory",{path:d.path})}}if(u.pathInfo.anchor){var e=b("#"+u.pathInfo.anchor);if(e){e.scrollIntoView({block:"start",behavior:"auto"})}}if(n.title){var t=b("title");if(t){t.innerHTML=n.title}else{window.document.title=n.title}}fr(n.elts,h);if(E(f,/HX-Trigger-After-Settle:/i)){var r=l;if(!re(l)){r=K().body}Xe(f,"HX-Trigger-After-Settle",r)}Q(g)};if(h.settleDelay>0){setTimeout(s,h.settleDelay)}else{s()}}catch(e){ae(l,"htmx:swapError",u);Q(p);throw e}};var s=G.config.globalViewTransitions;if(h.hasOwnProperty("transition")){s=h.transition}if(s&&oe(l,"htmx:beforeTransition",u)&&typeof Promise!=="undefined"&&document.startViewTransition){var m=new Promise(function(e,t){g=e;p=t});var x=o;o=function(){document.startViewTransition(function(){x();return m})}}if(h.swapDelay>0){setTimeout(o,h.swapDelay)}else{o()}}if(n){ae(l,"htmx:responseError",ne({error:"Response Status Error Code "+f.status+" from "+u.pathInfo.requestPath},u))}}var Er={};function Cr(){return{init:function(e){return null},onEvent:function(e,t){return true},transformResponse:function(e,t,r){return e},isInlineSwap:function(e){return false},handleSwap:function(e,t,r,n){return false},encodeParameters:function(e,t,r){return null}}}function Rr(e,t){if(t.init){t.init(C)}Er[e]=ne(Cr(),t)}function Or(e){delete Er[e]}function Tr(e,r,n){if(e==undefined){return r}if(r==undefined){r=[]}if(n==undefined){n=[]}var t=Z(e,"hx-ext");if(t){te(t.split(","),function(e){e=e.replace(/ /g,"");if(e.slice(0,7)=="ignore:"){n.push(e.slice(7));return}if(n.indexOf(e)<0){var t=Er[e];if(t&&r.indexOf(t)<0){r.push(t)}}})}return Tr(u(e),r,n)}var qr=false;K().addEventListener("DOMContentLoaded",function(){qr=true});function Hr(e){if(qr||K().readyState==="complete"){e()}else{K().addEventListener("DOMContentLoaded",e)}}function Lr(){if(G.config.includeIndicatorStyles!==false){K().head.insertAdjacentHTML("beforeend","<style> ."+G.config.indicatorClass+"{opacity:0;transition: opacity 200ms ease-in;} ."+G.config.requestClass+" ."+G.config.indicatorClass+"{opacity:1} ."+G.config.requestClass+"."+G.config.indicatorClass+"{opacity:1} </style>")}}function Ar(){var e=K().querySelector('meta[name="htmx-config"]');if(e){return y(e.content)}else{return null}}function Nr(){var e=Ar();if(e){G.config=ne(G.config,e)}}Hr(function(){Nr();Lr();var e=K().body;Nt(e);var t=K().querySelectorAll("[hx-trigger='restored'],[data-hx-trigger='restored']");e.addEventListener("htmx:abort",function(e){var t=e.target;var r=ee(t);if(r&&r.xhr){r.xhr.abort()}});var r=window.onpopstate;window.onpopstate=function(e){if(e.state&&e.state.htmx){zt();te(t,function(e){oe(e,"htmx:restored",{document:K(),triggerEvent:oe})})}else{if(r){r(e)}}};setTimeout(function(){oe(e,"htmx:load",{});e=null},0)});return G}()});⏎̸
A internal/webui/public/libs/iconoir.css +22 -0 too large to show in the browser

too large to show in the browser view raw

A internal/webui/public/site.webmanifest +1 -0
@@ -0,0 +1,1 @@
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"}⏎̸
@@ -0,0 +1,1 @@
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"}⏎̸
D package-lock.json +0 -991 generated file: collapsed
A pkg/utils/htmx/htmlfragments.go +42 -0
@@ -0,0 +1,42 @@
1+package htmx
2+
3+import (
4+ "bytes"
5+
6+ "github.com/PuerkitoBio/goquery"
7+
8+)
9+
10+// GetHTMLFragmentByID returns the HTML fragment with the specified id
11+func GetHTMLFragmentByID(id string, data interface{}, a *app.App, ac *app.Config) (string, error) {
12+ // 1. Render the template
13+ renderer, err := templating.GetHTMLRenderer("components.gohtml", ac.GetTemplateFS(), a)
14+ if err != nil {
15+ return "", err
16+ }
17+
18+ renderedHTML, err := renderer.Render(data, a)
19+ if err != nil {
20+ return "", err
21+ }
22+
23+ // 2. Parse the rendered HTML with goquery
24+ doc, err := goquery.NewDocumentFromReader(bytes.NewReader([]byte(renderedHTML)))
25+ if err != nil {
26+ return "", err
27+ }
28+
29+ // 3. Find the div with the specified id
30+ fragmentContent, err := doc.Find("#" + id).Html()
31+ if err != nil {
32+ return "", err
33+ }
34+
35+ if fragmentcontent == "" {
36+ return "", err
37+ }
38+
39+ return fragmentContent, nil
40+}
41+
42+
@@ -0,0 +1,42 @@
1+package htmx
2+
3+import (
4+ "bytes"
5+
6+ "github.com/PuerkitoBio/goquery"
7+
8+)
9+
10+// GetHTMLFragmentByID returns the HTML fragment with the specified id
11+func GetHTMLFragmentByID(id string, data interface{}, a *app.App, ac *app.Config) (string, error) {
12+ // 1. Render the template
13+ renderer, err := templating.GetHTMLRenderer("components.gohtml", ac.GetTemplateFS(), a)
14+ if err != nil {
15+ return "", err
16+ }
17+
18+ renderedHTML, err := renderer.Render(data, a)
19+ if err != nil {
20+ return "", err
21+ }
22+
23+ // 2. Parse the rendered HTML with goquery
24+ doc, err := goquery.NewDocumentFromReader(bytes.NewReader([]byte(renderedHTML)))
25+ if err != nil {
26+ return "", err
27+ }
28+
29+ // 3. Find the div with the specified id
30+ fragmentContent, err := doc.Find("#" + id).Html()
31+ if err != nil {
32+ return "", err
33+ }
34+
35+ if fragmentcontent == "" {
36+ return "", err
37+ }
38+
39+ return fragmentContent, nil
40+}
41+
42+

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 7

Tags 106

↑↓ moveenter openesc close