diff --git a/crud/.server/api/board.go b/crud/.server/api/board.go
index 321f29a..b6d354f 100644
--- a/crud/.server/api/board.go
+++ b/crud/.server/api/board.go
@@ -2,9 +2,9 @@ package api
import (
"context"
- "crud/sqlite"
"fmt"
"html/template"
+ "crud/sqlite"
"net/http"
"strconv"
)
diff --git a/crud/.show-it b/crud/.show-it
index e06118b..7803143 100644
--- a/crud/.show-it
+++ b/crud/.show-it
@@ -2,7 +2,8 @@ clear
cp .user.db user.db
ls -l
echo "The CRUD Example"
+echo "the user data is taken from https://jsonplaceholder.typicode.com/users"
---PAUSE---
-micro index.html board-content.html sample.go
+micro index.html sample.go board-content.html
xdg-open http://localhost:8080
./.crud
diff --git a/crud/users.json b/crud/users.json
new file mode 100644
index 0000000..82a0056
--- /dev/null
+++ b/crud/users.json
@@ -0,0 +1,232 @@
+[
+ {
+ "id": 1,
+ "name": "Leanne Graham",
+ "username": "Bret",
+ "email": "Sincere@april.biz",
+ "address": {
+ "street": "Kulas Light",
+ "suite": "Apt. 556",
+ "city": "Gwenborough",
+ "zipcode": "92998-3874",
+ "geo": {
+ "lat": "-37.3159",
+ "lng": "81.1496"
+ }
+ },
+ "phone": "1-770-736-8031 x56442",
+ "website": "hildegard.org",
+ "company": {
+ "name": "Romaguera-Crona",
+ "catchPhrase": "Multi-layered client-server neural-net",
+ "bs": "harness real-time e-markets"
+ }
+ },
+ {
+ "id": 2,
+ "name": "Ervin Howell",
+ "username": "Antonette",
+ "email": "Shanna@melissa.tv",
+ "address": {
+ "street": "Victor Plains",
+ "suite": "Suite 879",
+ "city": "Wisokyburgh",
+ "zipcode": "90566-7771",
+ "geo": {
+ "lat": "-43.9509",
+ "lng": "-34.4618"
+ }
+ },
+ "phone": "010-692-6593 x09125",
+ "website": "anastasia.net",
+ "company": {
+ "name": "Deckow-Crist",
+ "catchPhrase": "Proactive didactic contingency",
+ "bs": "synergize scalable supply-chains"
+ }
+ },
+ {
+ "id": 3,
+ "name": "Clementine Bauch",
+ "username": "Samantha",
+ "email": "Nathan@yesenia.net",
+ "address": {
+ "street": "Douglas Extension",
+ "suite": "Suite 847",
+ "city": "McKenziehaven",
+ "zipcode": "59590-4157",
+ "geo": {
+ "lat": "-68.6102",
+ "lng": "-47.0653"
+ }
+ },
+ "phone": "1-463-123-4447",
+ "website": "ramiro.info",
+ "company": {
+ "name": "Romaguera-Jacobson",
+ "catchPhrase": "Face to face bifurcated interface",
+ "bs": "e-enable strategic applications"
+ }
+ },
+ {
+ "id": 4,
+ "name": "Patricia Lebsack",
+ "username": "Karianne",
+ "email": "Julianne.OConner@kory.org",
+ "address": {
+ "street": "Hoeger Mall",
+ "suite": "Apt. 692",
+ "city": "South Elvis",
+ "zipcode": "53919-4257",
+ "geo": {
+ "lat": "29.4572",
+ "lng": "-164.2990"
+ }
+ },
+ "phone": "493-170-9623 x156",
+ "website": "kale.biz",
+ "company": {
+ "name": "Robel-Corkery",
+ "catchPhrase": "Multi-tiered zero tolerance productivity",
+ "bs": "transition cutting-edge web services"
+ }
+ },
+ {
+ "id": 5,
+ "name": "Chelsey Dietrich",
+ "username": "Kamren",
+ "email": "Lucio_Hettinger@annie.ca",
+ "address": {
+ "street": "Skiles Walks",
+ "suite": "Suite 351",
+ "city": "Roscoeview",
+ "zipcode": "33263",
+ "geo": {
+ "lat": "-31.8129",
+ "lng": "62.5342"
+ }
+ },
+ "phone": "(254)954-1289",
+ "website": "demarco.info",
+ "company": {
+ "name": "Keebler LLC",
+ "catchPhrase": "User-centric fault-tolerant solution",
+ "bs": "revolutionize end-to-end systems"
+ }
+ },
+ {
+ "id": 6,
+ "name": "Mrs. Dennis Schulist",
+ "username": "Leopoldo_Corkery",
+ "email": "Karley_Dach@jasper.info",
+ "address": {
+ "street": "Norberto Crossing",
+ "suite": "Apt. 950",
+ "city": "South Christy",
+ "zipcode": "23505-1337",
+ "geo": {
+ "lat": "-71.4197",
+ "lng": "71.7478"
+ }
+ },
+ "phone": "1-477-935-8478 x6430",
+ "website": "ola.org",
+ "company": {
+ "name": "Considine-Lockman",
+ "catchPhrase": "Synchronised bottom-line interface",
+ "bs": "e-enable innovative applications"
+ }
+ },
+ {
+ "id": 7,
+ "name": "Kurtis Weissnat",
+ "username": "Elwyn.Skiles",
+ "email": "Telly.Hoeger@billy.biz",
+ "address": {
+ "street": "Rex Trail",
+ "suite": "Suite 280",
+ "city": "Howemouth",
+ "zipcode": "58804-1099",
+ "geo": {
+ "lat": "24.8918",
+ "lng": "21.8984"
+ }
+ },
+ "phone": "210.067.6132",
+ "website": "elvis.io",
+ "company": {
+ "name": "Johns Group",
+ "catchPhrase": "Configurable multimedia task-force",
+ "bs": "generate enterprise e-tailers"
+ }
+ },
+ {
+ "id": 8,
+ "name": "Nicholas Runolfsdottir V",
+ "username": "Maxime_Nienow",
+ "email": "Sherwood@rosamond.me",
+ "address": {
+ "street": "Ellsworth Summit",
+ "suite": "Suite 729",
+ "city": "Aliyaview",
+ "zipcode": "45169",
+ "geo": {
+ "lat": "-14.3990",
+ "lng": "-120.7677"
+ }
+ },
+ "phone": "586.493.6943 x140",
+ "website": "jacynthe.com",
+ "company": {
+ "name": "Abernathy Group",
+ "catchPhrase": "Implemented secondary concept",
+ "bs": "e-enable extensible e-tailers"
+ }
+ },
+ {
+ "id": 9,
+ "name": "Glenna Reichert",
+ "username": "Delphine",
+ "email": "Chaim_McDermott@dana.io",
+ "address": {
+ "street": "Dayna Park",
+ "suite": "Suite 449",
+ "city": "Bartholomebury",
+ "zipcode": "76495-3109",
+ "geo": {
+ "lat": "24.6463",
+ "lng": "-168.8889"
+ }
+ },
+ "phone": "(775)976-6794 x41206",
+ "website": "conrad.com",
+ "company": {
+ "name": "Yost and Sons",
+ "catchPhrase": "Switchable contextually-based project",
+ "bs": "aggregate real-time technologies"
+ }
+ },
+ {
+ "id": 10,
+ "name": "Clementina DuBuque",
+ "username": "Moriah.Stanton",
+ "email": "Rey.Padberg@karina.biz",
+ "address": {
+ "street": "Kattie Turnpike",
+ "suite": "Suite 198",
+ "city": "Lebsackbury",
+ "zipcode": "31428-2261",
+ "geo": {
+ "lat": "-38.2386",
+ "lng": "57.2232"
+ }
+ },
+ "phone": "024-648-3804",
+ "website": "ambrose.net",
+ "company": {
+ "name": "Hoeger LLC",
+ "catchPhrase": "Centralized empowering task-force",
+ "bs": "target end-to-end models"
+ }
+ }
+]
diff --git a/lcars/.log b/lcars/.log
deleted file mode 100644
index 9a5aea1..0000000
--- a/lcars/.log
+++ /dev/null
@@ -1,3 +0,0 @@
-2025/09/30 11:18:25 Failed to create internal StateDB: SQL logic error: near ")": syntax error (1)
-2025/09/30 11:20:30 Failed to create internal StateDB: SQL logic error: near ")": syntax error (1)
- client_max_body_size 100m;
diff --git a/lcars/embed/create_state_db.sql b/lcars/lcars_v0/embed/create_state_db.sql
similarity index 100%
rename from lcars/embed/create_state_db.sql
rename to lcars/lcars_v0/embed/create_state_db.sql
diff --git a/lcars/embed/crew.json b/lcars/lcars_v0/embed/crew.json
similarity index 100%
rename from lcars/embed/crew.json
rename to lcars/lcars_v0/embed/crew.json
diff --git a/lcars/embed/messages.json b/lcars/lcars_v0/embed/messages.json
similarity index 100%
rename from lcars/embed/messages.json
rename to lcars/lcars_v0/embed/messages.json
diff --git a/lcars/experiments.go b/lcars/lcars_v0/experiments.go
similarity index 100%
rename from lcars/experiments.go
rename to lcars/lcars_v0/experiments.go
diff --git a/lcars/frontend/assets/Antonio-Bold.woff b/lcars/lcars_v0/frontend/assets/Antonio-Bold.woff
similarity index 100%
rename from lcars/frontend/assets/Antonio-Bold.woff
rename to lcars/lcars_v0/frontend/assets/Antonio-Bold.woff
diff --git a/lcars/frontend/assets/Antonio-Bold.woff2 b/lcars/lcars_v0/frontend/assets/Antonio-Bold.woff2
similarity index 100%
rename from lcars/frontend/assets/Antonio-Bold.woff2
rename to lcars/lcars_v0/frontend/assets/Antonio-Bold.woff2
diff --git a/lcars/frontend/assets/Antonio-Regular.woff b/lcars/lcars_v0/frontend/assets/Antonio-Regular.woff
similarity index 100%
rename from lcars/frontend/assets/Antonio-Regular.woff
rename to lcars/lcars_v0/frontend/assets/Antonio-Regular.woff
diff --git a/lcars/frontend/assets/Antonio-Regular.woff2 b/lcars/lcars_v0/frontend/assets/Antonio-Regular.woff2
similarity index 100%
rename from lcars/frontend/assets/Antonio-Regular.woff2
rename to lcars/lcars_v0/frontend/assets/Antonio-Regular.woff2
diff --git a/lcars/frontend/assets/beep1.mp3 b/lcars/lcars_v0/frontend/assets/beep1.mp3
similarity index 100%
rename from lcars/frontend/assets/beep1.mp3
rename to lcars/lcars_v0/frontend/assets/beep1.mp3
diff --git a/lcars/frontend/assets/beep2.mp3 b/lcars/lcars_v0/frontend/assets/beep2.mp3
similarity index 100%
rename from lcars/frontend/assets/beep2.mp3
rename to lcars/lcars_v0/frontend/assets/beep2.mp3
diff --git a/lcars/frontend/assets/beep3.mp3 b/lcars/lcars_v0/frontend/assets/beep3.mp3
similarity index 100%
rename from lcars/frontend/assets/beep3.mp3
rename to lcars/lcars_v0/frontend/assets/beep3.mp3
diff --git a/lcars/frontend/assets/beep4.mp3 b/lcars/lcars_v0/frontend/assets/beep4.mp3
similarity index 100%
rename from lcars/frontend/assets/beep4.mp3
rename to lcars/lcars_v0/frontend/assets/beep4.mp3
diff --git a/lcars/frontend/assets/classic.css b/lcars/lcars_v0/frontend/assets/classic.css
similarity index 100%
rename from lcars/frontend/assets/classic.css
rename to lcars/lcars_v0/frontend/assets/classic.css
diff --git a/lcars/frontend/assets/lcars.js b/lcars/lcars_v0/frontend/assets/lcars.js
similarity index 100%
rename from lcars/frontend/assets/lcars.js
rename to lcars/lcars_v0/frontend/assets/lcars.js
diff --git a/lcars/frontend/assets/lower-decks-padd.css b/lcars/lcars_v0/frontend/assets/lower-decks-padd.css
similarity index 100%
rename from lcars/frontend/assets/lower-decks-padd.css
rename to lcars/lcars_v0/frontend/assets/lower-decks-padd.css
diff --git a/lcars/frontend/assets/lower-decks.css b/lcars/lcars_v0/frontend/assets/lower-decks.css
similarity index 100%
rename from lcars/frontend/assets/lower-decks.css
rename to lcars/lcars_v0/frontend/assets/lower-decks.css
diff --git a/lcars/frontend/assets/nemesis-blue.css b/lcars/lcars_v0/frontend/assets/nemesis-blue.css
similarity index 100%
rename from lcars/frontend/assets/nemesis-blue.css
rename to lcars/lcars_v0/frontend/assets/nemesis-blue.css
diff --git a/lcars/frontend/index copy 2.html b/lcars/lcars_v0/frontend/index copy 2.html
similarity index 100%
rename from lcars/frontend/index copy 2.html
rename to lcars/lcars_v0/frontend/index copy 2.html
diff --git a/lcars/frontend/index copy.html b/lcars/lcars_v0/frontend/index copy.html
similarity index 100%
rename from lcars/frontend/index copy.html
rename to lcars/lcars_v0/frontend/index copy.html
diff --git a/lcars/frontend/index.html b/lcars/lcars_v0/frontend/index.html
similarity index 100%
rename from lcars/frontend/index.html
rename to lcars/lcars_v0/frontend/index.html
diff --git a/lcars/go.mod b/lcars/lcars_v0/go.mod
similarity index 100%
rename from lcars/go.mod
rename to lcars/lcars_v0/go.mod
diff --git a/lcars/go.sum b/lcars/lcars_v0/go.sum
similarity index 100%
rename from lcars/go.sum
rename to lcars/lcars_v0/go.sum
diff --git a/lcars/interval/interval.go b/lcars/lcars_v0/interval/interval.go
similarity index 100%
rename from lcars/interval/interval.go
rename to lcars/lcars_v0/interval/interval.go
diff --git a/lcars/main.go b/lcars/lcars_v0/main.go
similarity index 100%
rename from lcars/main.go
rename to lcars/lcars_v0/main.go
diff --git a/lcars/server/server.go b/lcars/lcars_v0/server/server.go
similarity index 100%
rename from lcars/server/server.go
rename to lcars/lcars_v0/server/server.go
diff --git a/lcars/server/taskengine.go b/lcars/lcars_v0/server/taskengine.go
similarity index 100%
rename from lcars/server/taskengine.go
rename to lcars/lcars_v0/server/taskengine.go
diff --git a/lcars/sqlite/database.go b/lcars/lcars_v0/sqlite/database.go
similarity index 100%
rename from lcars/sqlite/database.go
rename to lcars/lcars_v0/sqlite/database.go
diff --git a/lcars/sqlite/description.md b/lcars/lcars_v0/sqlite/description.md
similarity index 100%
rename from lcars/sqlite/description.md
rename to lcars/lcars_v0/sqlite/description.md
diff --git a/lcars_v1/embed/create_state_db.sql b/lcars/lcars_v1/embed/create_state_db.sql
similarity index 100%
rename from lcars_v1/embed/create_state_db.sql
rename to lcars/lcars_v1/embed/create_state_db.sql
diff --git a/lcars_v1/embed/crew.json b/lcars/lcars_v1/embed/crew.json
similarity index 100%
rename from lcars_v1/embed/crew.json
rename to lcars/lcars_v1/embed/crew.json
diff --git a/lcars_v1/embed/messages.json b/lcars/lcars_v1/embed/messages.json
similarity index 100%
rename from lcars_v1/embed/messages.json
rename to lcars/lcars_v1/embed/messages.json
diff --git a/lcars_v1/experiments.go b/lcars/lcars_v1/experiments.go
similarity index 100%
rename from lcars_v1/experiments.go
rename to lcars/lcars_v1/experiments.go
diff --git a/lcars_v1/frontend/assets/Antonio-Bold.woff b/lcars/lcars_v1/frontend/assets/Antonio-Bold.woff
similarity index 100%
rename from lcars_v1/frontend/assets/Antonio-Bold.woff
rename to lcars/lcars_v1/frontend/assets/Antonio-Bold.woff
diff --git a/lcars_v1/frontend/assets/Antonio-Bold.woff2 b/lcars/lcars_v1/frontend/assets/Antonio-Bold.woff2
similarity index 100%
rename from lcars_v1/frontend/assets/Antonio-Bold.woff2
rename to lcars/lcars_v1/frontend/assets/Antonio-Bold.woff2
diff --git a/lcars_v1/frontend/assets/Antonio-Regular.woff b/lcars/lcars_v1/frontend/assets/Antonio-Regular.woff
similarity index 100%
rename from lcars_v1/frontend/assets/Antonio-Regular.woff
rename to lcars/lcars_v1/frontend/assets/Antonio-Regular.woff
diff --git a/lcars_v1/frontend/assets/Antonio-Regular.woff2 b/lcars/lcars_v1/frontend/assets/Antonio-Regular.woff2
similarity index 100%
rename from lcars_v1/frontend/assets/Antonio-Regular.woff2
rename to lcars/lcars_v1/frontend/assets/Antonio-Regular.woff2
diff --git a/lcars_v1/frontend/assets/alert.png b/lcars/lcars_v1/frontend/assets/alert.png
similarity index 100%
rename from lcars_v1/frontend/assets/alert.png
rename to lcars/lcars_v1/frontend/assets/alert.png
diff --git a/lcars_v1/frontend/assets/beep1.mp3 b/lcars/lcars_v1/frontend/assets/beep1.mp3
similarity index 100%
rename from lcars_v1/frontend/assets/beep1.mp3
rename to lcars/lcars_v1/frontend/assets/beep1.mp3
diff --git a/lcars_v1/frontend/assets/beep2.mp3 b/lcars/lcars_v1/frontend/assets/beep2.mp3
similarity index 100%
rename from lcars_v1/frontend/assets/beep2.mp3
rename to lcars/lcars_v1/frontend/assets/beep2.mp3
diff --git a/lcars_v1/frontend/assets/beep3.mp3 b/lcars/lcars_v1/frontend/assets/beep3.mp3
similarity index 100%
rename from lcars_v1/frontend/assets/beep3.mp3
rename to lcars/lcars_v1/frontend/assets/beep3.mp3
diff --git a/lcars_v1/frontend/assets/beep4.mp3 b/lcars/lcars_v1/frontend/assets/beep4.mp3
similarity index 100%
rename from lcars_v1/frontend/assets/beep4.mp3
rename to lcars/lcars_v1/frontend/assets/beep4.mp3
diff --git a/lcars_v1/frontend/assets/classic.css b/lcars/lcars_v1/frontend/assets/classic.css
similarity index 100%
rename from lcars_v1/frontend/assets/classic.css
rename to lcars/lcars_v1/frontend/assets/classic.css
diff --git a/lcars_v1/frontend/assets/lcars.js b/lcars/lcars_v1/frontend/assets/lcars.js
similarity index 100%
rename from lcars_v1/frontend/assets/lcars.js
rename to lcars/lcars_v1/frontend/assets/lcars.js
diff --git a/lcars_v1/frontend/assets/lower-decks-padd.css b/lcars/lcars_v1/frontend/assets/lower-decks-padd.css
similarity index 100%
rename from lcars_v1/frontend/assets/lower-decks-padd.css
rename to lcars/lcars_v1/frontend/assets/lower-decks-padd.css
diff --git a/lcars_v1/frontend/assets/lower-decks.css b/lcars/lcars_v1/frontend/assets/lower-decks.css
similarity index 100%
rename from lcars_v1/frontend/assets/lower-decks.css
rename to lcars/lcars_v1/frontend/assets/lower-decks.css
diff --git a/lcars_v1/frontend/assets/nemesis-blue.css b/lcars/lcars_v1/frontend/assets/nemesis-blue.css
similarity index 100%
rename from lcars_v1/frontend/assets/nemesis-blue.css
rename to lcars/lcars_v1/frontend/assets/nemesis-blue.css
diff --git a/lcars_v1/frontend/crew/index.html b/lcars/lcars_v1/frontend/crew/index.html
similarity index 100%
rename from lcars_v1/frontend/crew/index.html
rename to lcars/lcars_v1/frontend/crew/index.html
diff --git a/lcars_v1/frontend/index.html b/lcars/lcars_v1/frontend/index.html
similarity index 100%
rename from lcars_v1/frontend/index.html
rename to lcars/lcars_v1/frontend/index.html
diff --git a/lcars_v1/frontend/tinyserver.go b/lcars/lcars_v1/frontend/tinyserver.go
similarity index 100%
rename from lcars_v1/frontend/tinyserver.go
rename to lcars/lcars_v1/frontend/tinyserver.go
diff --git a/lcars_v1/go.mod b/lcars/lcars_v1/go.mod
similarity index 100%
rename from lcars_v1/go.mod
rename to lcars/lcars_v1/go.mod
diff --git a/lcars_v1/go.sum b/lcars/lcars_v1/go.sum
similarity index 100%
rename from lcars_v1/go.sum
rename to lcars/lcars_v1/go.sum
diff --git a/lcars_v1/interval/interval.go b/lcars/lcars_v1/interval/interval.go
similarity index 100%
rename from lcars_v1/interval/interval.go
rename to lcars/lcars_v1/interval/interval.go
diff --git a/lcars_v1/main.go b/lcars/lcars_v1/main.go
similarity index 100%
rename from lcars_v1/main.go
rename to lcars/lcars_v1/main.go
diff --git a/lcars_v1/notes.txt b/lcars/lcars_v1/notes.txt
similarity index 100%
rename from lcars_v1/notes.txt
rename to lcars/lcars_v1/notes.txt
diff --git a/lcars_v1/server/server.go b/lcars/lcars_v1/server/server.go
similarity index 100%
rename from lcars_v1/server/server.go
rename to lcars/lcars_v1/server/server.go
diff --git a/lcars_v1/server/taskengine.go b/lcars/lcars_v1/server/taskengine.go
similarity index 100%
rename from lcars_v1/server/taskengine.go
rename to lcars/lcars_v1/server/taskengine.go
diff --git a/lcars_v1/sqlite/database.go b/lcars/lcars_v1/sqlite/database.go
similarity index 100%
rename from lcars_v1/sqlite/database.go
rename to lcars/lcars_v1/sqlite/database.go
diff --git a/lcars_v2/embed/create_state_db.sql b/lcars/lcars_v2/embed/create_state_db.sql
similarity index 100%
rename from lcars_v2/embed/create_state_db.sql
rename to lcars/lcars_v2/embed/create_state_db.sql
diff --git a/lcars_v2/embed/crew.json b/lcars/lcars_v2/embed/crew.json
similarity index 100%
rename from lcars_v2/embed/crew.json
rename to lcars/lcars_v2/embed/crew.json
diff --git a/lcars_v2/embed/messages.json b/lcars/lcars_v2/embed/messages.json
similarity index 100%
rename from lcars_v2/embed/messages.json
rename to lcars/lcars_v2/embed/messages.json
diff --git a/lcars_v2/eventbus/eventbus.go b/lcars/lcars_v2/eventbus/eventbus.go
similarity index 100%
rename from lcars_v2/eventbus/eventbus.go
rename to lcars/lcars_v2/eventbus/eventbus.go
diff --git a/lcars_v2/experiments.go b/lcars/lcars_v2/experiments.go
similarity index 100%
rename from lcars_v2/experiments.go
rename to lcars/lcars_v2/experiments.go
diff --git a/lcars_v2/frontend/assets/Antonio-Bold.woff b/lcars/lcars_v2/frontend/assets/Antonio-Bold.woff
similarity index 100%
rename from lcars_v2/frontend/assets/Antonio-Bold.woff
rename to lcars/lcars_v2/frontend/assets/Antonio-Bold.woff
diff --git a/lcars_v2/frontend/assets/Antonio-Bold.woff2 b/lcars/lcars_v2/frontend/assets/Antonio-Bold.woff2
similarity index 100%
rename from lcars_v2/frontend/assets/Antonio-Bold.woff2
rename to lcars/lcars_v2/frontend/assets/Antonio-Bold.woff2
diff --git a/lcars_v2/frontend/assets/Antonio-Regular.woff b/lcars/lcars_v2/frontend/assets/Antonio-Regular.woff
similarity index 100%
rename from lcars_v2/frontend/assets/Antonio-Regular.woff
rename to lcars/lcars_v2/frontend/assets/Antonio-Regular.woff
diff --git a/lcars_v2/frontend/assets/Antonio-Regular.woff2 b/lcars/lcars_v2/frontend/assets/Antonio-Regular.woff2
similarity index 100%
rename from lcars_v2/frontend/assets/Antonio-Regular.woff2
rename to lcars/lcars_v2/frontend/assets/Antonio-Regular.woff2
diff --git a/lcars_v2/frontend/assets/alert.png b/lcars/lcars_v2/frontend/assets/alert.png
similarity index 100%
rename from lcars_v2/frontend/assets/alert.png
rename to lcars/lcars_v2/frontend/assets/alert.png
diff --git a/lcars_v2/frontend/assets/beep1.mp3 b/lcars/lcars_v2/frontend/assets/beep1.mp3
similarity index 100%
rename from lcars_v2/frontend/assets/beep1.mp3
rename to lcars/lcars_v2/frontend/assets/beep1.mp3
diff --git a/lcars_v2/frontend/assets/beep2.mp3 b/lcars/lcars_v2/frontend/assets/beep2.mp3
similarity index 100%
rename from lcars_v2/frontend/assets/beep2.mp3
rename to lcars/lcars_v2/frontend/assets/beep2.mp3
diff --git a/lcars_v2/frontend/assets/beep3.mp3 b/lcars/lcars_v2/frontend/assets/beep3.mp3
similarity index 100%
rename from lcars_v2/frontend/assets/beep3.mp3
rename to lcars/lcars_v2/frontend/assets/beep3.mp3
diff --git a/lcars_v2/frontend/assets/beep4.mp3 b/lcars/lcars_v2/frontend/assets/beep4.mp3
similarity index 100%
rename from lcars_v2/frontend/assets/beep4.mp3
rename to lcars/lcars_v2/frontend/assets/beep4.mp3
diff --git a/lcars_v2/frontend/assets/classic.css b/lcars/lcars_v2/frontend/assets/classic.css
similarity index 100%
rename from lcars_v2/frontend/assets/classic.css
rename to lcars/lcars_v2/frontend/assets/classic.css
diff --git a/lcars_v2/frontend/assets/lcars.js b/lcars/lcars_v2/frontend/assets/lcars.js
similarity index 100%
rename from lcars_v2/frontend/assets/lcars.js
rename to lcars/lcars_v2/frontend/assets/lcars.js
diff --git a/lcars_v2/frontend/assets/lower-decks-padd.css b/lcars/lcars_v2/frontend/assets/lower-decks-padd.css
similarity index 100%
rename from lcars_v2/frontend/assets/lower-decks-padd.css
rename to lcars/lcars_v2/frontend/assets/lower-decks-padd.css
diff --git a/lcars_v2/frontend/assets/lower-decks.css b/lcars/lcars_v2/frontend/assets/lower-decks.css
similarity index 100%
rename from lcars_v2/frontend/assets/lower-decks.css
rename to lcars/lcars_v2/frontend/assets/lower-decks.css
diff --git a/lcars_v2/frontend/assets/nemesis-blue.css b/lcars/lcars_v2/frontend/assets/nemesis-blue.css
similarity index 100%
rename from lcars_v2/frontend/assets/nemesis-blue.css
rename to lcars/lcars_v2/frontend/assets/nemesis-blue.css
diff --git a/lcars_v2/frontend/crew/index.html b/lcars/lcars_v2/frontend/crew/index.html
similarity index 100%
rename from lcars_v2/frontend/crew/index.html
rename to lcars/lcars_v2/frontend/crew/index.html
diff --git a/lcars_v2/frontend/index.html b/lcars/lcars_v2/frontend/index.html
similarity index 100%
rename from lcars_v2/frontend/index.html
rename to lcars/lcars_v2/frontend/index.html
diff --git a/lcars_v2/frontend/tinyserver.go b/lcars/lcars_v2/frontend/tinyserver.go
similarity index 100%
rename from lcars_v2/frontend/tinyserver.go
rename to lcars/lcars_v2/frontend/tinyserver.go
diff --git a/lcars_v2/go.mod b/lcars/lcars_v2/go.mod
similarity index 100%
rename from lcars_v2/go.mod
rename to lcars/lcars_v2/go.mod
diff --git a/lcars_v2/go.sum b/lcars/lcars_v2/go.sum
similarity index 100%
rename from lcars_v2/go.sum
rename to lcars/lcars_v2/go.sum
diff --git a/lcars_v2/interval/interval.go b/lcars/lcars_v2/interval/interval.go
similarity index 100%
rename from lcars_v2/interval/interval.go
rename to lcars/lcars_v2/interval/interval.go
diff --git a/lcars_v2/main.go b/lcars/lcars_v2/main.go
similarity index 100%
rename from lcars_v2/main.go
rename to lcars/lcars_v2/main.go
diff --git a/lcars_v2/notes.txt b/lcars/lcars_v2/notes.txt
similarity index 100%
rename from lcars_v2/notes.txt
rename to lcars/lcars_v2/notes.txt
diff --git a/lcars_v2/server/server.go b/lcars/lcars_v2/server/server.go
similarity index 100%
rename from lcars_v2/server/server.go
rename to lcars/lcars_v2/server/server.go
diff --git a/lcars_v2/server/taskengine.go b/lcars/lcars_v2/server/taskengine.go
similarity index 100%
rename from lcars_v2/server/taskengine.go
rename to lcars/lcars_v2/server/taskengine.go
diff --git a/lcars_v2/sqlite/database.go b/lcars/lcars_v2/sqlite/database.go
similarity index 100%
rename from lcars_v2/sqlite/database.go
rename to lcars/lcars_v2/sqlite/database.go
diff --git a/lcars_v3/embed/create_state_db.sql b/lcars/lcars_v3/embed/create_state_db.sql
similarity index 100%
rename from lcars_v3/embed/create_state_db.sql
rename to lcars/lcars_v3/embed/create_state_db.sql
diff --git a/lcars_v3/embed/crew.json b/lcars/lcars_v3/embed/crew.json
similarity index 100%
rename from lcars_v3/embed/crew.json
rename to lcars/lcars_v3/embed/crew.json
diff --git a/lcars_v3/embed/messages.json b/lcars/lcars_v3/embed/messages.json
similarity index 100%
rename from lcars_v3/embed/messages.json
rename to lcars/lcars_v3/embed/messages.json
diff --git a/lcars_v3/eventbus/eventbus.go b/lcars/lcars_v3/eventbus/eventbus.go
similarity index 100%
rename from lcars_v3/eventbus/eventbus.go
rename to lcars/lcars_v3/eventbus/eventbus.go
diff --git a/lcars_v3/experiments.go b/lcars/lcars_v3/experiments.go
similarity index 100%
rename from lcars_v3/experiments.go
rename to lcars/lcars_v3/experiments.go
diff --git a/lcars_v3/frontend/assets/Antonio-Bold.woff b/lcars/lcars_v3/frontend/assets/Antonio-Bold.woff
similarity index 100%
rename from lcars_v3/frontend/assets/Antonio-Bold.woff
rename to lcars/lcars_v3/frontend/assets/Antonio-Bold.woff
diff --git a/lcars_v3/frontend/assets/Antonio-Bold.woff2 b/lcars/lcars_v3/frontend/assets/Antonio-Bold.woff2
similarity index 100%
rename from lcars_v3/frontend/assets/Antonio-Bold.woff2
rename to lcars/lcars_v3/frontend/assets/Antonio-Bold.woff2
diff --git a/lcars_v3/frontend/assets/Antonio-Regular.woff b/lcars/lcars_v3/frontend/assets/Antonio-Regular.woff
similarity index 100%
rename from lcars_v3/frontend/assets/Antonio-Regular.woff
rename to lcars/lcars_v3/frontend/assets/Antonio-Regular.woff
diff --git a/lcars_v3/frontend/assets/Antonio-Regular.woff2 b/lcars/lcars_v3/frontend/assets/Antonio-Regular.woff2
similarity index 100%
rename from lcars_v3/frontend/assets/Antonio-Regular.woff2
rename to lcars/lcars_v3/frontend/assets/Antonio-Regular.woff2
diff --git a/lcars_v3/frontend/assets/alert.png b/lcars/lcars_v3/frontend/assets/alert.png
similarity index 100%
rename from lcars_v3/frontend/assets/alert.png
rename to lcars/lcars_v3/frontend/assets/alert.png
diff --git a/lcars_v3/frontend/assets/beep1.mp3 b/lcars/lcars_v3/frontend/assets/beep1.mp3
similarity index 100%
rename from lcars_v3/frontend/assets/beep1.mp3
rename to lcars/lcars_v3/frontend/assets/beep1.mp3
diff --git a/lcars_v3/frontend/assets/beep2.mp3 b/lcars/lcars_v3/frontend/assets/beep2.mp3
similarity index 100%
rename from lcars_v3/frontend/assets/beep2.mp3
rename to lcars/lcars_v3/frontend/assets/beep2.mp3
diff --git a/lcars_v3/frontend/assets/beep3.mp3 b/lcars/lcars_v3/frontend/assets/beep3.mp3
similarity index 100%
rename from lcars_v3/frontend/assets/beep3.mp3
rename to lcars/lcars_v3/frontend/assets/beep3.mp3
diff --git a/lcars_v3/frontend/assets/beep4.mp3 b/lcars/lcars_v3/frontend/assets/beep4.mp3
similarity index 100%
rename from lcars_v3/frontend/assets/beep4.mp3
rename to lcars/lcars_v3/frontend/assets/beep4.mp3
diff --git a/lcars_v3/frontend/assets/classic.css b/lcars/lcars_v3/frontend/assets/classic.css
similarity index 100%
rename from lcars_v3/frontend/assets/classic.css
rename to lcars/lcars_v3/frontend/assets/classic.css
diff --git a/lcars_v3/frontend/assets/lcars.js b/lcars/lcars_v3/frontend/assets/lcars.js
similarity index 100%
rename from lcars_v3/frontend/assets/lcars.js
rename to lcars/lcars_v3/frontend/assets/lcars.js
diff --git a/lcars_v3/frontend/assets/lower-decks-padd.css b/lcars/lcars_v3/frontend/assets/lower-decks-padd.css
similarity index 100%
rename from lcars_v3/frontend/assets/lower-decks-padd.css
rename to lcars/lcars_v3/frontend/assets/lower-decks-padd.css
diff --git a/lcars_v3/frontend/assets/lower-decks.css b/lcars/lcars_v3/frontend/assets/lower-decks.css
similarity index 100%
rename from lcars_v3/frontend/assets/lower-decks.css
rename to lcars/lcars_v3/frontend/assets/lower-decks.css
diff --git a/lcars_v3/frontend/assets/nemesis-blue.css b/lcars/lcars_v3/frontend/assets/nemesis-blue.css
similarity index 100%
rename from lcars_v3/frontend/assets/nemesis-blue.css
rename to lcars/lcars_v3/frontend/assets/nemesis-blue.css
diff --git a/lcars_v3/frontend/crew/index.html b/lcars/lcars_v3/frontend/crew/index.html
similarity index 100%
rename from lcars_v3/frontend/crew/index.html
rename to lcars/lcars_v3/frontend/crew/index.html
diff --git a/lcars_v3/frontend/index.html b/lcars/lcars_v3/frontend/index.html
similarity index 100%
rename from lcars_v3/frontend/index.html
rename to lcars/lcars_v3/frontend/index.html
diff --git a/lcars_v3/frontend/tinyserver.go b/lcars/lcars_v3/frontend/tinyserver.go
similarity index 100%
rename from lcars_v3/frontend/tinyserver.go
rename to lcars/lcars_v3/frontend/tinyserver.go
diff --git a/lcars_v3/go.mod b/lcars/lcars_v3/go.mod
similarity index 100%
rename from lcars_v3/go.mod
rename to lcars/lcars_v3/go.mod
diff --git a/lcars_v3/go.sum b/lcars/lcars_v3/go.sum
similarity index 100%
rename from lcars_v3/go.sum
rename to lcars/lcars_v3/go.sum
diff --git a/lcars_v3/interval/interval.go b/lcars/lcars_v3/interval/interval.go
similarity index 100%
rename from lcars_v3/interval/interval.go
rename to lcars/lcars_v3/interval/interval.go
diff --git a/lcars_v3/main.go b/lcars/lcars_v3/main.go
similarity index 100%
rename from lcars_v3/main.go
rename to lcars/lcars_v3/main.go
diff --git a/lcars_v3/notes.txt b/lcars/lcars_v3/notes.txt
similarity index 100%
rename from lcars_v3/notes.txt
rename to lcars/lcars_v3/notes.txt
diff --git a/lcars_v3/server/server.go b/lcars/lcars_v3/server/server.go
similarity index 100%
rename from lcars_v3/server/server.go
rename to lcars/lcars_v3/server/server.go
diff --git a/lcars_v3/server/taskengine.go b/lcars/lcars_v3/server/taskengine.go
similarity index 100%
rename from lcars_v3/server/taskengine.go
rename to lcars/lcars_v3/server/taskengine.go
diff --git a/lcars_v3/sqlite/database.go b/lcars/lcars_v3/sqlite/database.go
similarity index 100%
rename from lcars_v3/sqlite/database.go
rename to lcars/lcars_v3/sqlite/database.go
diff --git a/lcars_v3/state/events.go b/lcars/lcars_v3/state/events.go
similarity index 100%
rename from lcars_v3/state/events.go
rename to lcars/lcars_v3/state/events.go
diff --git a/lcars_v4/embed/create_state_db.sql b/lcars/lcars_v4/embed/create_state_db.sql
similarity index 100%
rename from lcars_v4/embed/create_state_db.sql
rename to lcars/lcars_v4/embed/create_state_db.sql
diff --git a/lcars_v4/embed/crew.json b/lcars/lcars_v4/embed/crew.json
similarity index 100%
rename from lcars_v4/embed/crew.json
rename to lcars/lcars_v4/embed/crew.json
diff --git a/lcars_v4/embed/messages.json b/lcars/lcars_v4/embed/messages.json
similarity index 100%
rename from lcars_v4/embed/messages.json
rename to lcars/lcars_v4/embed/messages.json
diff --git a/lcars_v4/eventbus/eventbus.go b/lcars/lcars_v4/eventbus/eventbus.go
similarity index 100%
rename from lcars_v4/eventbus/eventbus.go
rename to lcars/lcars_v4/eventbus/eventbus.go
diff --git a/lcars_v4/experiments.go b/lcars/lcars_v4/experiments.go
similarity index 100%
rename from lcars_v4/experiments.go
rename to lcars/lcars_v4/experiments.go
diff --git a/lcars_v4/frontend/assets/Antonio-Bold.woff b/lcars/lcars_v4/frontend/assets/Antonio-Bold.woff
similarity index 100%
rename from lcars_v4/frontend/assets/Antonio-Bold.woff
rename to lcars/lcars_v4/frontend/assets/Antonio-Bold.woff
diff --git a/lcars_v4/frontend/assets/Antonio-Bold.woff2 b/lcars/lcars_v4/frontend/assets/Antonio-Bold.woff2
similarity index 100%
rename from lcars_v4/frontend/assets/Antonio-Bold.woff2
rename to lcars/lcars_v4/frontend/assets/Antonio-Bold.woff2
diff --git a/lcars_v4/frontend/assets/Antonio-Regular.woff b/lcars/lcars_v4/frontend/assets/Antonio-Regular.woff
similarity index 100%
rename from lcars_v4/frontend/assets/Antonio-Regular.woff
rename to lcars/lcars_v4/frontend/assets/Antonio-Regular.woff
diff --git a/lcars_v4/frontend/assets/Antonio-Regular.woff2 b/lcars/lcars_v4/frontend/assets/Antonio-Regular.woff2
similarity index 100%
rename from lcars_v4/frontend/assets/Antonio-Regular.woff2
rename to lcars/lcars_v4/frontend/assets/Antonio-Regular.woff2
diff --git a/lcars_v4/frontend/assets/alert.png b/lcars/lcars_v4/frontend/assets/alert.png
similarity index 100%
rename from lcars_v4/frontend/assets/alert.png
rename to lcars/lcars_v4/frontend/assets/alert.png
diff --git a/lcars_v4/frontend/assets/beep1.mp3 b/lcars/lcars_v4/frontend/assets/beep1.mp3
similarity index 100%
rename from lcars_v4/frontend/assets/beep1.mp3
rename to lcars/lcars_v4/frontend/assets/beep1.mp3
diff --git a/lcars_v4/frontend/assets/beep2.mp3 b/lcars/lcars_v4/frontend/assets/beep2.mp3
similarity index 100%
rename from lcars_v4/frontend/assets/beep2.mp3
rename to lcars/lcars_v4/frontend/assets/beep2.mp3
diff --git a/lcars_v4/frontend/assets/beep3.mp3 b/lcars/lcars_v4/frontend/assets/beep3.mp3
similarity index 100%
rename from lcars_v4/frontend/assets/beep3.mp3
rename to lcars/lcars_v4/frontend/assets/beep3.mp3
diff --git a/lcars_v4/frontend/assets/beep4.mp3 b/lcars/lcars_v4/frontend/assets/beep4.mp3
similarity index 100%
rename from lcars_v4/frontend/assets/beep4.mp3
rename to lcars/lcars_v4/frontend/assets/beep4.mp3
diff --git a/lcars_v4/frontend/assets/classic.css b/lcars/lcars_v4/frontend/assets/classic.css
similarity index 100%
rename from lcars_v4/frontend/assets/classic.css
rename to lcars/lcars_v4/frontend/assets/classic.css
diff --git a/lcars_v4/frontend/assets/lcars.js b/lcars/lcars_v4/frontend/assets/lcars.js
similarity index 100%
rename from lcars_v4/frontend/assets/lcars.js
rename to lcars/lcars_v4/frontend/assets/lcars.js
diff --git a/lcars_v4/frontend/assets/lower-decks-padd.css b/lcars/lcars_v4/frontend/assets/lower-decks-padd.css
similarity index 100%
rename from lcars_v4/frontend/assets/lower-decks-padd.css
rename to lcars/lcars_v4/frontend/assets/lower-decks-padd.css
diff --git a/lcars_v4/frontend/assets/lower-decks.css b/lcars/lcars_v4/frontend/assets/lower-decks.css
similarity index 100%
rename from lcars_v4/frontend/assets/lower-decks.css
rename to lcars/lcars_v4/frontend/assets/lower-decks.css
diff --git a/lcars_v4/frontend/assets/nemesis-blue.css b/lcars/lcars_v4/frontend/assets/nemesis-blue.css
similarity index 100%
rename from lcars_v4/frontend/assets/nemesis-blue.css
rename to lcars/lcars_v4/frontend/assets/nemesis-blue.css
diff --git a/lcars_v4/frontend/crew/index.html b/lcars/lcars_v4/frontend/crew/index.html
similarity index 100%
rename from lcars_v4/frontend/crew/index.html
rename to lcars/lcars_v4/frontend/crew/index.html
diff --git a/lcars_v4/frontend/index.html b/lcars/lcars_v4/frontend/index.html
similarity index 100%
rename from lcars_v4/frontend/index.html
rename to lcars/lcars_v4/frontend/index.html
diff --git a/lcars_v4/frontend/tinyserver.go b/lcars/lcars_v4/frontend/tinyserver.go
similarity index 100%
rename from lcars_v4/frontend/tinyserver.go
rename to lcars/lcars_v4/frontend/tinyserver.go
diff --git a/lcars_v4/go.mod b/lcars/lcars_v4/go.mod
similarity index 100%
rename from lcars_v4/go.mod
rename to lcars/lcars_v4/go.mod
diff --git a/lcars_v4/go.sum b/lcars/lcars_v4/go.sum
similarity index 100%
rename from lcars_v4/go.sum
rename to lcars/lcars_v4/go.sum
diff --git a/lcars_v4/interval/interval.go b/lcars/lcars_v4/interval/interval.go
similarity index 100%
rename from lcars_v4/interval/interval.go
rename to lcars/lcars_v4/interval/interval.go
diff --git a/lcars_v4/main.go b/lcars/lcars_v4/main.go
similarity index 100%
rename from lcars_v4/main.go
rename to lcars/lcars_v4/main.go
diff --git a/lcars_v4/notes.txt b/lcars/lcars_v4/notes.txt
similarity index 100%
rename from lcars_v4/notes.txt
rename to lcars/lcars_v4/notes.txt
diff --git a/lcars_v4/server/server.go b/lcars/lcars_v4/server/server.go
similarity index 100%
rename from lcars_v4/server/server.go
rename to lcars/lcars_v4/server/server.go
diff --git a/lcars_v4/server/taskengine.go b/lcars/lcars_v4/server/taskengine.go
similarity index 100%
rename from lcars_v4/server/taskengine.go
rename to lcars/lcars_v4/server/taskengine.go
diff --git a/lcars_v4/sqlite/database.go b/lcars/lcars_v4/sqlite/database.go
similarity index 100%
rename from lcars_v4/sqlite/database.go
rename to lcars/lcars_v4/sqlite/database.go
diff --git a/lcars_v4/state/events.go b/lcars/lcars_v4/state/events.go
similarity index 100%
rename from lcars_v4/state/events.go
rename to lcars/lcars_v4/state/events.go
diff --git a/lcars/lcars_v5/api/board.go b/lcars/lcars_v5/api/board.go
new file mode 100644
index 0000000..68b0c3e
--- /dev/null
+++ b/lcars/lcars_v5/api/board.go
@@ -0,0 +1,125 @@
+package api
+
+import (
+ "context"
+ "fmt"
+ "html/template"
+ "ld/sqlite"
+ "net/http"
+ "strconv"
+)
+
+const baseQuery = `SELECT u.id, u.name, u.username, u.email, u.phone, u.website, a.street, a.suite, a.zipcode, a.city, c.name as company, c.catch_phrase, c.bs
+ FROM user u
+ JOIN company c ON u.company_id = c.id
+ JOIN address a ON u.address_id = a.id
+ `
+
+func Board(ctx context.Context, db *sqlite.Database, templ *template.Template) http.Handler {
+ return http.HandlerFunc(
+
+ func(w http.ResponseWriter, r *http.Request) {
+
+ w.Header().Set("Content-Type", "text/html")
+
+ records, err := sqlite.NoRowsOk(db.ReadRecords(ctx, baseQuery+";"))
+ if err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
+
+ // Execute template with proper error handling
+ if err := templ.ExecuteTemplate(w, "board", sqlite.Record{"records": records}); err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
+ },
+ )
+}
+
+func DeleteRecord(ctx context.Context, db *sqlite.Database, templ *template.Template) http.Handler {
+ // Implementation of DeleteRecord handler
+ return http.HandlerFunc(
+
+ func(w http.ResponseWriter, r *http.Request) {
+
+ id, err := strconv.ParseInt(r.PathValue("id"), 10, 64)
+ if err != nil {
+ w.WriteHeader(http.StatusInternalServerError)
+ w.Write([]byte(err.Error()))
+ }
+
+ // fmt.Println("DeleteRecord handler called ", id)
+
+ if err := db.DeleteRecord(ctx, "user", "id", id); err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
+
+ // Redirect or respond with success
+ http.Redirect(w, r, "/board", http.StatusSeeOther)
+ },
+ )
+}
+
+func EditRecord(ctx context.Context, db *sqlite.Database, templ *template.Template) http.Handler {
+ // Implementation of EditRecord handler
+ return http.HandlerFunc(
+
+ func(w http.ResponseWriter, r *http.Request) {
+
+ // fmt.Println("EditRecord handler called")
+
+ id, err := strconv.ParseInt(r.PathValue("id"), 10, 64)
+ if err != nil {
+ w.WriteHeader(http.StatusInternalServerError)
+ w.Write([]byte(err.Error()))
+ }
+
+ records, err := db.ReadRecords(ctx, baseQuery+" WHERE u.id = ?;", id)
+ if err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
+
+ rec := records[0]
+
+ // fmt.Printf("Record to edit: %+v\n", rec)
+
+ w.Header().Set("Content-Type", "text/html")
+
+ // Execute template with proper error handling
+ if err := templ.ExecuteTemplate(w, "edit-user", rec); err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
+
+ },
+ )
+}
+
+func PatchRecord(ctx context.Context, db *sqlite.Database, templ *template.Template) http.Handler {
+ // Implementation of PatchRecord handler
+ return http.HandlerFunc(
+
+ func(w http.ResponseWriter, r *http.Request) {
+
+ fmt.Println("PatchRecord handler called")
+
+ // id, err := strconv.ParseInt(r.PathValue("id"), 10, 64)
+ // if err != nil {
+ // w.WriteHeader(http.StatusInternalServerError)
+ // w.Write([]byte(err.Error()))
+ // }
+
+ // if err := db.DeleteRecord(ctx, "user", "id", id); err != nil {
+ // http.Error(w, err.Error(), http.StatusInternalServerError)
+ // return
+ // }
+
+ // Redirect or respond with success
+ http.Redirect(w, r, "/board", http.StatusSeeOther)
+
+ },
+ )
+}
diff --git a/lcars/lcars_v5/datastar/consts.go b/lcars/lcars_v5/datastar/consts.go
new file mode 100644
index 0000000..9b896fa
--- /dev/null
+++ b/lcars/lcars_v5/datastar/consts.go
@@ -0,0 +1,115 @@
+// This is auto-generated by Datastar. DO NOT EDIT.
+
+package datastar
+
+import "time"
+
+const (
+ DatastarKey = "datastar"
+ Version = "1.0.0-beta.11"
+ VersionClientByteSize = 40026
+ VersionClientByteSizeGzip = 14900
+
+ //region Default durations
+
+ // The default duration for retrying SSE on connection reset. This is part of the underlying retry mechanism of SSE.
+ DefaultSseRetryDuration = 1000 * time.Millisecond
+
+ //endregion Default durations
+
+ //region Default strings
+
+ // The default attributes for element use when executing scripts. It is a set of key-value pairs delimited by a newline \\n character.
+ DefaultExecuteScriptAttributes = "type module"
+
+ //endregion Default strings
+
+ //region Dataline literals
+ SelectorDatalineLiteral = "selector "
+ MergeModeDatalineLiteral = "mergeMode "
+ FragmentsDatalineLiteral = "fragments "
+ UseViewTransitionDatalineLiteral = "useViewTransition "
+ SignalsDatalineLiteral = "signals "
+ OnlyIfMissingDatalineLiteral = "onlyIfMissing "
+ PathsDatalineLiteral = "paths "
+ ScriptDatalineLiteral = "script "
+ AttributesDatalineLiteral = "attributes "
+ AutoRemoveDatalineLiteral = "autoRemove "
+ //endregion Dataline literals
+)
+
+var (
+ //region Default booleans
+
+ // Should fragments be merged using the ViewTransition API?
+ DefaultFragmentsUseViewTransitions = false
+
+ // Should a given set of signals merge if they are missing?
+ DefaultMergeSignalsOnlyIfMissing = false
+
+ // Should script element remove itself after execution?
+ DefaultExecuteScriptAutoRemove = true
+
+ //endregion Default booleans
+)
+
+//region Enums
+
+//region The mode in which a fragment is merged into the DOM.
+type FragmentMergeMode string
+
+const (
+ // Default value for FragmentMergeMode
+ // Morphs the fragment into the existing element using idiomorph.
+ DefaultFragmentMergeMode = FragmentMergeModeMorph
+
+ // Morphs the fragment into the existing element using idiomorph.
+ FragmentMergeModeMorph FragmentMergeMode = "morph"
+
+ // Replaces the inner HTML of the existing element.
+ FragmentMergeModeInner FragmentMergeMode = "inner"
+
+ // Replaces the outer HTML of the existing element.
+ FragmentMergeModeOuter FragmentMergeMode = "outer"
+
+ // Prepends the fragment to the existing element.
+ FragmentMergeModePrepend FragmentMergeMode = "prepend"
+
+ // Appends the fragment to the existing element.
+ FragmentMergeModeAppend FragmentMergeMode = "append"
+
+ // Inserts the fragment before the existing element.
+ FragmentMergeModeBefore FragmentMergeMode = "before"
+
+ // Inserts the fragment after the existing element.
+ FragmentMergeModeAfter FragmentMergeMode = "after"
+
+ // Upserts the attributes of the existing element.
+ FragmentMergeModeUpsertAttributes FragmentMergeMode = "upsertAttributes"
+
+)
+//endregion FragmentMergeMode
+
+//region The type protocol on top of SSE which allows for core pushed based communication between the server and the client.
+type EventType string
+
+const (
+ // An event for merging HTML fragments into the DOM.
+ EventTypeMergeFragments EventType = "datastar-merge-fragments"
+
+ // An event for merging signals.
+ EventTypeMergeSignals EventType = "datastar-merge-signals"
+
+ // An event for removing HTML fragments from the DOM.
+ EventTypeRemoveFragments EventType = "datastar-remove-fragments"
+
+ // An event for removing signals.
+ EventTypeRemoveSignals EventType = "datastar-remove-signals"
+
+ // An event for executing elements in the browser.
+ EventTypeExecuteScript EventType = "datastar-execute-script"
+
+)
+//endregion EventType
+
+//endregion Enums
\ No newline at end of file
diff --git a/lcars/lcars_v5/datastar/execute-script-sugar.go b/lcars/lcars_v5/datastar/execute-script-sugar.go
new file mode 100644
index 0000000..310b9fa
--- /dev/null
+++ b/lcars/lcars_v5/datastar/execute-script-sugar.go
@@ -0,0 +1,234 @@
+package datastar
+
+import (
+ "encoding/json"
+ "fmt"
+ "net/http"
+ "net/url"
+ "strings"
+ "time"
+)
+
+// ConsoleLog is a convenience method for [see.ExecuteScript].
+// It is equivalent to calling [see.ExecuteScript] with [see.WithScript] option set to `console.log(msg)`.
+func (sse *ServerSentEventGenerator) ConsoleLog(msg string, opts ...ExecuteScriptOption) error {
+ call := fmt.Sprintf("console.log(%q)", msg)
+ return sse.ExecuteScript(call, opts...)
+}
+
+// ConsoleLogf is a convenience method for [see.ExecuteScript].
+// It is equivalent to calling [see.ExecuteScript] with [see.WithScript] option set to `console.log(fmt.Sprintf(format, args...))`.
+func (sse *ServerSentEventGenerator) ConsoleLogf(format string, args ...any) error {
+ return sse.ConsoleLog(fmt.Sprintf(format, args...))
+}
+
+// ConsoleError is a convenience method for [see.ExecuteScript].
+// It is equivalent to calling [see.ExecuteScript] with [see.WithScript] option set to `console.error(msg)`.
+func (sse *ServerSentEventGenerator) ConsoleError(err error, opts ...ExecuteScriptOption) error {
+ call := fmt.Sprintf("console.error(%q)", err.Error())
+ return sse.ExecuteScript(call, opts...)
+}
+
+// Redirectf is a convenience method for [see.ExecuteScript].
+// It sends a redirect event to the client formatted using [fmt.Sprintf].
+func (sse *ServerSentEventGenerator) Redirectf(format string, args ...any) error {
+ url := fmt.Sprintf(format, args...)
+ return sse.Redirect(url)
+}
+
+// Redirect is a convenience method for [see.ExecuteScript].
+// It sends a redirect event to the client .
+func (sse *ServerSentEventGenerator) Redirect(url string, opts ...ExecuteScriptOption) error {
+ js := fmt.Sprintf("setTimeout(() => window.location.href = %q)", url)
+ return sse.ExecuteScript(js, opts...)
+}
+
+// dispatchCustomEventOptions holds the configuration data
+// modified by [DispatchCustomEventOption]s
+// for dispatching custom events to the client.
+type dispatchCustomEventOptions struct {
+ EventID string
+ RetryDuration time.Duration
+ Selector string
+ Bubbles bool
+ Cancelable bool
+ Composed bool
+}
+
+// DispatchCustomEventOption configures one custom
+// server-sent event.
+type DispatchCustomEventOption func(*dispatchCustomEventOptions)
+
+// WithDispatchCustomEventEventID configures an optional event ID for the custom event.
+// The client message field [lastEventId] will be set to this value.
+// If the next event does not have an event ID, the last used event ID will remain.
+//
+// [lastEventId]: https://developer.mozilla.org/en-US/docs/Web/API/MessageEvent/lastEventId
+func WithDispatchCustomEventEventID(id string) DispatchCustomEventOption {
+ return func(o *dispatchCustomEventOptions) {
+ o.EventID = id
+ }
+}
+
+// WithDispatchCustomEventRetryDuration overrides the [DefaultSseRetryDuration] for one custom event.
+func WithDispatchCustomEventRetryDuration(retryDuration time.Duration) DispatchCustomEventOption {
+ return func(o *dispatchCustomEventOptions) {
+ o.RetryDuration = retryDuration
+ }
+}
+
+// WithDispatchCustomEventSelector replaces the default custom event target `document` with a
+// [CSS selector]. If the selector matches multiple HTML elements, the event will be dispatched
+// from each one. For example, if the selector is `#my-element`, the event will be dispatched
+// from the element with the ID `my-element`. If the selector is `main > section`, the event will be dispatched
+// from each `` element which is a direct child of the `` element.
+//
+// [CSS selector]: https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_selectors
+func WithDispatchCustomEventSelector(selector string) DispatchCustomEventOption {
+ return func(o *dispatchCustomEventOptions) {
+ o.Selector = selector
+ }
+}
+
+// WithDispatchCustomEventBubbles overrides the default custom [event bubbling] `true` value.
+// Setting bubbling to `false` is equivalent to calling `event.stopPropagation()` Javascript
+// command on the client side for the dispatched event. This prevents the event from triggering
+// event handlers of its parent elements.
+//
+// [event bubbling]: https://developer.mozilla.org/en-US/docs/Learn_web_development/Core/Scripting/Event_bubbling
+func WithDispatchCustomEventBubbles(bubbles bool) DispatchCustomEventOption {
+ return func(o *dispatchCustomEventOptions) {
+ o.Bubbles = bubbles
+ }
+}
+
+// WithDispatchCustomEventCancelable overrides the default custom [event cancelability] `true` value.
+// Setting cancelability to `false` is blocks `event.preventDefault()` Javascript
+// command on the client side for the dispatched event.
+//
+// [event cancelability]: https://developer.mozilla.org/en-US/docs/Web/API/Event/cancelable
+func WithDispatchCustomEventCancelable(cancelable bool) DispatchCustomEventOption {
+ return func(o *dispatchCustomEventOptions) {
+ o.Cancelable = cancelable
+ }
+}
+
+// WithDispatchCustomEventComposed overrides the default custom [event composed] `true` value.
+// It indicates whether or not the event will propagate across the shadow HTML DOM boundary into
+// the document DOM tree. When `false`, the shadow root will be the last node to be offered the event.
+//
+// [event composed]: https://developer.mozilla.org/en-US/docs/Web/API/Event/composed
+func WithDispatchCustomEventComposed(composed bool) DispatchCustomEventOption {
+ return func(o *dispatchCustomEventOptions) {
+ o.Composed = composed
+ }
+}
+
+// DispatchCustomEvent is a convenience method for dispatching a custom event by executing
+// a client side script via [sse.ExecuteScript] call. The detail struct is marshaled to JSON and
+// passed as a parameter to the event.
+func (sse *ServerSentEventGenerator) DispatchCustomEvent(eventName string, detail any, opts ...DispatchCustomEventOption) error {
+ if eventName == "" {
+ return fmt.Errorf("eventName is required")
+ }
+
+ detailsJSON, err := json.Marshal(detail)
+ if err != nil {
+ return fmt.Errorf("failed to marshal detail: %w", err)
+ }
+
+ const defaultSelector = "document"
+ options := dispatchCustomEventOptions{
+ EventID: "",
+ RetryDuration: DefaultSseRetryDuration,
+ Selector: defaultSelector,
+ Bubbles: true,
+ Cancelable: true,
+ Composed: true,
+ }
+
+ for _, opt := range opts {
+ opt(&options)
+ }
+
+ elementsJS := `[document]`
+ if options.Selector != "" && options.Selector != defaultSelector {
+ elementsJS = fmt.Sprintf(`document.querySelectorAll(%q)`, options.Selector)
+ }
+
+ js := fmt.Sprintf(`
+const elements = %s
+
+const event = new CustomEvent(%q, {
+ bubbles: %t,
+ cancelable: %t,
+ composed: %t,
+ detail: %s,
+});
+
+elements.forEach((element) => {
+ element.dispatchEvent(event);
+});
+ `,
+ elementsJS,
+ eventName,
+ options.Bubbles,
+ options.Cancelable,
+ options.Composed,
+ string(detailsJSON),
+ )
+
+ executeOptions := make([]ExecuteScriptOption, 0)
+ if options.EventID != "" {
+ executeOptions = append(executeOptions, WithExecuteScriptEventID(options.EventID))
+ }
+ if options.RetryDuration != 0 {
+ executeOptions = append(executeOptions, WithExecuteScriptRetryDuration(options.RetryDuration))
+ }
+
+ return sse.ExecuteScript(js, executeOptions...)
+
+}
+
+// ReplaceURL replaces the current URL in the browser's history.
+func (sse *ServerSentEventGenerator) ReplaceURL(u url.URL, opts ...ExecuteScriptOption) error {
+ js := fmt.Sprintf(`window.history.replaceState({}, "", %q)`, u.String())
+ return sse.ExecuteScript(js, opts...)
+}
+
+// ReplaceURLQuerystring is a convenience wrapper for [sse.ReplaceURL] that replaces the query
+// string of the current URL request with new a new query built from the provided values.
+func (sse *ServerSentEventGenerator) ReplaceURLQuerystring(r *http.Request, values url.Values, opts ...ExecuteScriptOption) error {
+ // TODO: rename this function to ReplaceURLQuery
+ u := *r.URL
+ u.RawQuery = values.Encode()
+ return sse.ReplaceURL(u, opts...)
+}
+
+// Prefetch is a convenience wrapper for [sse.ExecuteScript] that prefetches the provided links.
+// It follows the Javascript [speculation rules API] prefetch specification.
+//
+// [speculation rules API]: https://developer.mozilla.org/en-US/docs/Web/API/Speculation_Rules_API
+func (sse *ServerSentEventGenerator) Prefetch(urls ...string) error {
+ wrappedURLs := make([]string, len(urls))
+ for i, url := range urls {
+ wrappedURLs[i] = fmt.Sprintf(`"%s"`, url)
+ }
+ script := fmt.Sprintf(`
+{
+ "prefetch": [
+ {
+ "source": "list",
+ "urls": [
+ %s
+ ]
+ }
+ ]
+}
+ `, strings.Join(wrappedURLs, ",\n\t\t\t\t"))
+ return sse.ExecuteScript(
+ script,
+ WithExecuteScriptAutoRemove(false),
+ WithExecuteScriptAttributes("type speculationrules"),
+ )
+}
diff --git a/lcars/lcars_v5/datastar/execute.go b/lcars/lcars_v5/datastar/execute.go
new file mode 100644
index 0000000..5b838c6
--- /dev/null
+++ b/lcars/lcars_v5/datastar/execute.go
@@ -0,0 +1,112 @@
+package datastar
+
+import (
+ "fmt"
+ "strconv"
+ "strings"
+ "time"
+)
+
+// executeScriptOptions hold script options that will be translated to [SSEEventOptions].
+type executeScriptOptions struct {
+ EventID string
+ RetryDuration time.Duration
+ Attributes []string
+ AutoRemove *bool
+}
+
+// ExecuteScriptOption configures script execution event that will be sent to the client.
+type ExecuteScriptOption func(*executeScriptOptions)
+
+// WithExecuteScriptEventID configures an optional event ID for the script execution event.
+// The client message field [lastEventId] will be set to this value.
+// If the next event does not have an event ID, the last used event ID will remain.
+//
+// [lastEventId]: https://developer.mozilla.org/en-US/docs/Web/API/MessageEvent/lastEventId
+func WithExecuteScriptEventID(id string) ExecuteScriptOption {
+ return func(o *executeScriptOptions) {
+ o.EventID = id
+ }
+}
+
+// WithExecuteScriptRetryDuration overrides the [DefaultSseRetryDuration] for this script
+// execution only.
+func WithExecuteScriptRetryDuration(retryDuration time.Duration) ExecuteScriptOption {
+ return func(o *executeScriptOptions) {
+ o.RetryDuration = retryDuration
+ }
+}
+
+// WithExecuteScriptAttributes overrides the default script attribute
+// value `type module`, which renders as `
+
+
+