From 2433b865da8394eb4b288d8cec68cde115a02243 Mon Sep 17 00:00:00 2001 From: luxick Date: Wed, 15 Oct 2025 10:01:47 +0200 Subject: [PATCH] Init --- .github/copilot-instructions.md | 1 + .github/go.instructions.md | 373 +++ .github/used-prompts/deploying.md | 107 + .gitignore | 36 + cmd/estus-shots/main.go | 119 + cmd/luxtools/main.go | 119 + deploy/estus-shots.service | 19 + deploy/luxtools.service | 19 + go.mod | 3 + internal/server/server.go | 189 ++ internal/server/server_test.go | 129 + internal/server/template_data.go | 84 + media/demo.txt | 1 + web/embed.go | 8 + web/static/lib/htmx.2.0.7.min.js | 1 + .../tuicss/fonts/Perfect DOS VGA 437 Win.ttf | Bin 0 -> 82676 bytes .../lib/tuicss/fonts/Perfect DOS VGA 437.ttf | Bin 0 -> 81192 bytes web/static/lib/tuicss/fonts/dos437.txt | 72 + .../lib/tuicss/images/bg-blue-black.png | Bin 0 -> 166 bytes .../lib/tuicss/images/bg-blue-white.png | Bin 0 -> 168 bytes .../lib/tuicss/images/bg-cyan-black.png | Bin 0 -> 168 bytes .../lib/tuicss/images/bg-cyan-white.png | Bin 0 -> 165 bytes .../lib/tuicss/images/bg-green-black.png | Bin 0 -> 168 bytes .../lib/tuicss/images/bg-green-white.png | Bin 0 -> 165 bytes .../lib/tuicss/images/bg-orange-black.png | Bin 0 -> 168 bytes .../lib/tuicss/images/bg-orange-white.png | Bin 0 -> 165 bytes .../lib/tuicss/images/bg-purple-black.png | Bin 0 -> 168 bytes .../lib/tuicss/images/bg-purple-white.png | Bin 0 -> 165 bytes web/static/lib/tuicss/images/bg-red-black.png | Bin 0 -> 166 bytes web/static/lib/tuicss/images/bg-red-white.png | Bin 0 -> 165 bytes .../lib/tuicss/images/bg-yellow-black.png | Bin 0 -> 168 bytes .../lib/tuicss/images/bg-yellow-white.png | Bin 0 -> 165 bytes web/static/lib/tuicss/images/scroll-blue.png | Bin 0 -> 166 bytes web/static/lib/tuicss/images/scroll-cyan.png | Bin 0 -> 168 bytes web/static/lib/tuicss/images/scroll-green.png | Bin 0 -> 167 bytes .../lib/tuicss/images/scroll-orange.png | Bin 0 -> 167 bytes .../lib/tuicss/images/scroll-purple.png | Bin 0 -> 168 bytes web/static/lib/tuicss/images/scroll-red.png | Bin 0 -> 167 bytes web/static/lib/tuicss/images/scroll-white.png | Bin 0 -> 168 bytes .../lib/tuicss/images/scroll-yellow.png | Bin 0 -> 167 bytes web/static/lib/tuicss/tuicss.css | 2704 +++++++++++++++++ web/static/lib/tuicss/tuicss.js | 256 ++ web/static/lib/tuicss/tuicss.min.css | 1 + web/static/lib/tuicss/tuicss.min.js | 1 + web/templates/admin.html | 28 + web/templates/index.html | 45 + web/templates/layout.html | 19 + web/templates/menubar.html | 25 + 48 files changed, 4359 insertions(+) create mode 100644 .github/copilot-instructions.md create mode 100644 .github/go.instructions.md create mode 100644 .github/used-prompts/deploying.md create mode 100644 .gitignore create mode 100644 cmd/estus-shots/main.go create mode 100644 cmd/luxtools/main.go create mode 100644 deploy/estus-shots.service create mode 100644 deploy/luxtools.service create mode 100644 go.mod create mode 100644 internal/server/server.go create mode 100644 internal/server/server_test.go create mode 100644 internal/server/template_data.go create mode 100644 media/demo.txt create mode 100644 web/embed.go create mode 100644 web/static/lib/htmx.2.0.7.min.js create mode 100644 web/static/lib/tuicss/fonts/Perfect DOS VGA 437 Win.ttf create mode 100644 web/static/lib/tuicss/fonts/Perfect DOS VGA 437.ttf create mode 100644 web/static/lib/tuicss/fonts/dos437.txt create mode 100644 web/static/lib/tuicss/images/bg-blue-black.png create mode 100644 web/static/lib/tuicss/images/bg-blue-white.png create mode 100644 web/static/lib/tuicss/images/bg-cyan-black.png create mode 100644 web/static/lib/tuicss/images/bg-cyan-white.png create mode 100644 web/static/lib/tuicss/images/bg-green-black.png create mode 100644 web/static/lib/tuicss/images/bg-green-white.png create mode 100644 web/static/lib/tuicss/images/bg-orange-black.png create mode 100644 web/static/lib/tuicss/images/bg-orange-white.png create mode 100644 web/static/lib/tuicss/images/bg-purple-black.png create mode 100644 web/static/lib/tuicss/images/bg-purple-white.png create mode 100644 web/static/lib/tuicss/images/bg-red-black.png create mode 100644 web/static/lib/tuicss/images/bg-red-white.png create mode 100644 web/static/lib/tuicss/images/bg-yellow-black.png create mode 100644 web/static/lib/tuicss/images/bg-yellow-white.png create mode 100644 web/static/lib/tuicss/images/scroll-blue.png create mode 100644 web/static/lib/tuicss/images/scroll-cyan.png create mode 100644 web/static/lib/tuicss/images/scroll-green.png create mode 100644 web/static/lib/tuicss/images/scroll-orange.png create mode 100644 web/static/lib/tuicss/images/scroll-purple.png create mode 100644 web/static/lib/tuicss/images/scroll-red.png create mode 100644 web/static/lib/tuicss/images/scroll-white.png create mode 100644 web/static/lib/tuicss/images/scroll-yellow.png create mode 100644 web/static/lib/tuicss/tuicss.css create mode 100644 web/static/lib/tuicss/tuicss.js create mode 100644 web/static/lib/tuicss/tuicss.min.css create mode 100644 web/static/lib/tuicss/tuicss.min.js create mode 100644 web/templates/admin.html create mode 100755 web/templates/index.html create mode 100644 web/templates/layout.html create mode 100644 web/templates/menubar.html diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md new file mode 100644 index 0000000..fa755ff --- /dev/null +++ b/.github/copilot-instructions.md @@ -0,0 +1 @@ +- Do not end with a summary or explanation \ No newline at end of file diff --git a/.github/go.instructions.md b/.github/go.instructions.md new file mode 100644 index 0000000..a956d62 --- /dev/null +++ b/.github/go.instructions.md @@ -0,0 +1,373 @@ +--- +description: 'Instructions for writing Go code following idiomatic Go practices and community standards' +applyTo: '**/*.go,**/go.mod,**/go.sum' +--- + +# Go Development Instructions + +Follow idiomatic Go practices and community standards when writing Go code. These instructions are based on [Effective Go](https://go.dev/doc/effective_go), [Go Code Review Comments](https://go.dev/wiki/CodeReviewComments), and [Google's Go Style Guide](https://google.github.io/styleguide/go/). + +## General Instructions + +- Write simple, clear, and idiomatic Go code +- Favor clarity and simplicity over cleverness +- Follow the principle of least surprise +- Keep the happy path left-aligned (minimize indentation) +- Return early to reduce nesting +- Prefer early return over if-else chains; use `if condition { return }` pattern to avoid else blocks +- Make the zero value useful +- Write self-documenting code with clear, descriptive names +- Document exported types, functions, methods, and packages +- Use Go modules for dependency management +- Leverage the Go standard library instead of reinventing the wheel (e.g., use `strings.Builder` for string concatenation, `filepath.Join` for path construction) +- Prefer standard library solutions over custom implementations when functionality exists +- Write comments in English by default; translate only upon user request +- Avoid using emoji in code and comments + +## Naming Conventions + +### Packages + +- Use lowercase, single-word package names +- Avoid underscores, hyphens, or mixedCaps +- Choose names that describe what the package provides, not what it contains +- Avoid generic names like `util`, `common`, or `base` +- Package names should be singular, not plural + +#### Package Declaration Rules (CRITICAL): +- **NEVER duplicate `package` declarations** - each Go file must have exactly ONE `package` line +- When editing an existing `.go` file: + - **PRESERVE** the existing `package` declaration - do not add another one + - If you need to replace the entire file content, start with the existing package name +- When creating a new `.go` file: + - **BEFORE writing any code**, check what package name other `.go` files in the same directory use + - Use the SAME package name as existing files in that directory + - If it's a new directory, use the directory name as the package name + - Write **exactly one** `package ` line at the very top of the file +- When using file creation or replacement tools: + - **ALWAYS verify** the target file doesn't already have a `package` declaration before adding one + - If replacing file content, include only ONE `package` declaration in the new content + - **NEVER** create files with multiple `package` lines or duplicate declarations + +### Variables and Functions + +- Use mixedCaps or MixedCaps (camelCase) rather than underscores +- Keep names short but descriptive +- Use single-letter variables only for very short scopes (like loop indices) +- Exported names start with a capital letter +- Unexported names start with a lowercase letter +- Avoid stuttering (e.g., avoid `http.HTTPServer`, prefer `http.Server`) + +### Interfaces + +- Name interfaces with -er suffix when possible (e.g., `Reader`, `Writer`, `Formatter`) +- Single-method interfaces should be named after the method (e.g., `Read` → `Reader`) +- Keep interfaces small and focused + +### Constants + +- Use MixedCaps for exported constants +- Use mixedCaps for unexported constants +- Group related constants using `const` blocks +- Consider using typed constants for better type safety + +## Code Style and Formatting + +### Formatting + +- Always use `gofmt` to format code +- Use `goimports` to manage imports automatically +- Keep line length reasonable (no hard limit, but consider readability) +- Add blank lines to separate logical groups of code + +### Comments + +- Strive for self-documenting code; prefer clear variable names, function names, and code structure over comments +- Write comments only when necessary to explain complex logic, business rules, or non-obvious behavior +- Write comments in complete sentences in English by default +- Translate comments to other languages only upon specific user request +- Start sentences with the name of the thing being described +- Package comments should start with "Package [name]" +- Use line comments (`//`) for most comments +- Use block comments (`/* */`) sparingly, mainly for package documentation +- Document why, not what, unless the what is complex +- Avoid emoji in comments and code + +### Error Handling + +- Check errors immediately after the function call +- Don't ignore errors using `_` unless you have a good reason (document why) +- Wrap errors with context using `fmt.Errorf` with `%w` verb +- Create custom error types when you need to check for specific errors +- Place error returns as the last return value +- Name error variables `err` +- Keep error messages lowercase and don't end with punctuation + +## Architecture and Project Structure + +### Package Organization + +- Follow standard Go project layout conventions +- Keep `main` packages in `cmd/` directory +- Put reusable packages in `pkg/` or `internal/` +- Use `internal/` for packages that shouldn't be imported by external projects +- Group related functionality into packages +- Avoid circular dependencies + +### Dependency Management + +- Use Go modules (`go.mod` and `go.sum`) +- Keep dependencies minimal +- Regularly update dependencies for security patches +- Use `go mod tidy` to clean up unused dependencies +- Vendor dependencies only when necessary + +## Type Safety and Language Features + +### Type Definitions + +- Define types to add meaning and type safety +- Use struct tags for JSON, XML, database mappings +- Prefer explicit type conversions +- Use type assertions carefully and check the second return value +- Prefer generics over unconstrained types; when an unconstrained type is truly needed, use the predeclared alias `any` instead of `interface{}` (Go 1.18+) + +### Pointers vs Values + +- Use pointer receivers for large structs or when you need to modify the receiver +- Use value receivers for small structs and when immutability is desired +- Use pointer parameters when you need to modify the argument or for large structs +- Use value parameters for small structs and when you want to prevent modification +- Be consistent within a type's method set +- Consider the zero value when choosing pointer vs value receivers + +### Interfaces and Composition + +- Accept interfaces, return concrete types +- Keep interfaces small (1-3 methods is ideal) +- Use embedding for composition +- Define interfaces close to where they're used, not where they're implemented +- Don't export interfaces unless necessary + +## Concurrency + +### Goroutines + +- Be cautious about creating goroutines in libraries; prefer letting the caller control concurrency +- If you must create goroutines in libraries, provide clear documentation and cleanup mechanisms +- Always know how a goroutine will exit +- Use `sync.WaitGroup` or channels to wait for goroutines +- Avoid goroutine leaks by ensuring cleanup + +### Channels + +- Use channels to communicate between goroutines +- Don't communicate by sharing memory; share memory by communicating +- Close channels from the sender side, not the receiver +- Use buffered channels when you know the capacity +- Use `select` for non-blocking operations + +### Synchronization + +- Use `sync.Mutex` for protecting shared state +- Keep critical sections small +- Use `sync.RWMutex` when you have many readers +- Choose between channels and mutexes based on the use case: use channels for communication, mutexes for protecting state +- Use `sync.Once` for one-time initialization +- WaitGroup usage by Go version: + - If `go >= 1.25` in `go.mod`, use the new `WaitGroup.Go` method ([documentation](https://pkg.go.dev/sync#WaitGroup)): + ```go + var wg sync.WaitGroup + wg.Go(task1) + wg.Go(task2) + wg.Wait() + ``` + - If `go < 1.25`, use the classic `Add`/`Done` pattern + +## Error Handling Patterns + +### Creating Errors + +- Use `errors.New` for simple static errors +- Use `fmt.Errorf` for dynamic errors +- Create custom error types for domain-specific errors +- Export error variables for sentinel errors +- Use `errors.Is` and `errors.As` for error checking + +### Error Propagation + +- Add context when propagating errors up the stack +- Don't log and return errors (choose one) +- Handle errors at the appropriate level +- Consider using structured errors for better debugging + +## API Design + +### HTTP Handlers + +- Use `http.HandlerFunc` for simple handlers +- Implement `http.Handler` for handlers that need state +- Use middleware for cross-cutting concerns +- Set appropriate status codes and headers +- Handle errors gracefully and return appropriate error responses +- Router usage by Go version: + - If `go >= 1.22`, prefer the enhanced `net/http` `ServeMux` with pattern-based routing and method matching + - If `go < 1.22`, use the classic `ServeMux` and handle methods/paths manually (or use a third-party router when justified) + +### JSON APIs + +- Use struct tags to control JSON marshaling +- Validate input data +- Use pointers for optional fields +- Consider using `json.RawMessage` for delayed parsing +- Handle JSON errors appropriately + +### HTTP Clients + +- Keep the client struct focused on configuration and dependencies only (e.g., base URL, `*http.Client`, auth, default headers). It must not store per-request state +- Do not store or cache `*http.Request` inside the client struct, and do not persist request-specific state across calls; instead, construct a fresh request per method invocation +- Methods should accept `context.Context` and input parameters, assemble the `*http.Request` locally (or via a short-lived builder/helper created per call), then call `c.httpClient.Do(req)` +- If request-building logic is reused, factor it into unexported helper functions or a per-call builder type; never keep `http.Request` (URL params, body, headers) as fields on the long-lived client +- Ensure the underlying `*http.Client` is configured (timeouts, transport) and is safe for concurrent use; avoid mutating `Transport` after first use +- Always set headers on the request instance you’re sending, and close response bodies (`defer resp.Body.Close()`), handling errors appropriately + +## Performance Optimization + +### Memory Management + +- Minimize allocations in hot paths +- Reuse objects when possible (consider `sync.Pool`) +- Use value receivers for small structs +- Preallocate slices when size is known +- Avoid unnecessary string conversions + +### I/O: Readers and Buffers + +- Most `io.Reader` streams are consumable once; reading advances state. Do not assume a reader can be re-read without special handling +- If you must read data multiple times, buffer it once and recreate readers on demand: + - Use `io.ReadAll` (or a limited read) to obtain `[]byte`, then create fresh readers via `bytes.NewReader(buf)` or `bytes.NewBuffer(buf)` for each reuse + - For strings, use `strings.NewReader(s)`; you can `Seek(0, io.SeekStart)` on `*bytes.Reader` to rewind +- For HTTP requests, do not reuse a consumed `req.Body`. Instead: + - Keep the original payload as `[]byte` and set `req.Body = io.NopCloser(bytes.NewReader(buf))` before each send + - Prefer configuring `req.GetBody` so the transport can recreate the body for redirects/retries: `req.GetBody = func() (io.ReadCloser, error) { return io.NopCloser(bytes.NewReader(buf)), nil }` +- To duplicate a stream while reading, use `io.TeeReader` (copy to a buffer while passing through) or write to multiple sinks with `io.MultiWriter` +- Reusing buffered readers: call `(*bufio.Reader).Reset(r)` to attach to a new underlying reader; do not expect it to “rewind” unless the source supports seeking +- For large payloads, avoid unbounded buffering; consider streaming, `io.LimitReader`, or on-disk temporary storage to control memory + +- Use `io.Pipe` to stream without buffering the whole payload: + - Write to `*io.PipeWriter` in a separate goroutine while the reader consumes + - Always close the writer; use `CloseWithError(err)` on failures + - `io.Pipe` is for streaming, not rewinding or making readers reusable + +- **Warning:** When using `io.Pipe` (especially with multipart writers), all writes must be performed in strict, sequential order. Do not write concurrently or out of order—multipart boundaries and chunk order must be preserved. Out-of-order or parallel writes can corrupt the stream and result in errors. + +- Streaming multipart/form-data with `io.Pipe`: + - `pr, pw := io.Pipe()`; `mw := multipart.NewWriter(pw)`; use `pr` as the HTTP request body + - Set `Content-Type` to `mw.FormDataContentType()` + - In a goroutine: write all parts to `mw` in the correct order; on error `pw.CloseWithError(err)`; on success `mw.Close()` then `pw.Close()` + - Do not store request/in-flight form state on a long-lived client; build per call + - Streamed bodies are not rewindable; for retries/redirects, buffer small payloads or provide `GetBody` + +### Profiling + +- Use built-in profiling tools (`pprof`) +- Benchmark critical code paths +- Profile before optimizing +- Focus on algorithmic improvements first +- Consider using `testing.B` for benchmarks + +## Testing + +### Test Organization + +- Keep tests in the same package (white-box testing) +- Use `_test` package suffix for black-box testing +- Name test files with `_test.go` suffix +- Place test files next to the code they test + +### Writing Tests + +- Use table-driven tests for multiple test cases +- Name tests descriptively using `Test_functionName_scenario` +- Use subtests with `t.Run` for better organization +- Test both success and error cases +- Consider using `testify` or similar libraries when they add value, but don't over-complicate simple tests + +### Test Helpers + +- Mark helper functions with `t.Helper()` +- Create test fixtures for complex setup +- Use `testing.TB` interface for functions used in tests and benchmarks +- Clean up resources using `t.Cleanup()` + +## Security Best Practices + +### Input Validation + +- Validate all external input +- Use strong typing to prevent invalid states +- Sanitize data before using in SQL queries +- Be careful with file paths from user input +- Validate and escape data for different contexts (HTML, SQL, shell) + +### Cryptography + +- Use standard library crypto packages +- Don't implement your own cryptography +- Use crypto/rand for random number generation +- Store passwords using bcrypt, scrypt, or argon2 (consider golang.org/x/crypto for additional options) +- Use TLS for network communication + +## Documentation + +### Code Documentation + +- Prioritize self-documenting code through clear naming and structure +- Document all exported symbols with clear, concise explanations +- Start documentation with the symbol name +- Write documentation in English by default +- Use examples in documentation when helpful +- Keep documentation close to code +- Update documentation when code changes +- Avoid emoji in documentation and comments + +### README and Documentation Files + +- Include clear setup instructions +- Document dependencies and requirements +- Provide usage examples +- Document configuration options +- Include troubleshooting section + +## Tools and Development Workflow + +### Essential Tools + +- `go fmt`: Format code +- `go vet`: Find suspicious constructs +- `golangci-lint`: Additional linting (golint is deprecated) +- `go test`: Run tests +- `go mod`: Manage dependencies +- `go generate`: Code generation + +### Development Practices + +- Run tests before committing +- Use pre-commit hooks for formatting and linting +- Keep commits focused and atomic +- Write meaningful commit messages +- Review diffs before committing + +## Common Pitfalls to Avoid + +- Not checking errors +- Ignoring race conditions +- Creating goroutine leaks +- Not using defer for cleanup +- Modifying maps concurrently +- Not understanding nil interfaces vs nil pointers +- Forgetting to close resources (files, connections) +- Using global variables unnecessarily +- Over-using unconstrained types (e.g., `any`); prefer specific types or generic type parameters with constraints. If an unconstrained type is required, use `any` rather than `interface{}` +- Not considering the zero value of types +- **Creating duplicate `package` declarations** - this is a compile error; always check existing files before adding package declarations diff --git a/.github/used-prompts/deploying.md b/.github/used-prompts/deploying.md new file mode 100644 index 0000000..aabe746 --- /dev/null +++ b/.github/used-prompts/deploying.md @@ -0,0 +1,107 @@ +## Overview + +Deploy `estus-shots` to the personal Fedora server manually—no CI/CD required. The application runs behind Nginx via a reverse proxy and is supervised by `systemd`. + +## Prerequisites + +- Fedora (server) with SSH access for a user that can `sudo` without a passwordless setup. +- Nim toolchain installed locally (for `nim`/`nimble`). +- Server already provisioned with Nim runtime dependencies. +- Existing Nginx site definition that proxies traffic to the `estus-shots` service port (defaults to `127.0.0.1:9000`). + +## One-time server setup + +1. Create deployment directories on the server: + ```fish + ssh user@server 'sudo mkdir -p /opt/estus-shots/bin /opt/estus-shots/config && sudo chown ${USER}:${USER} /opt/estus-shots -R' + ``` +2. Copy the `systemd` unit and enable it: + ```fish + printf '%s\n' "[Unit]" \ + "Description=estus-shots web service" \ + "After=network.target" \ + "" \ + "[Service]" \ + "Type=simple" \ + "ExecStart=/opt/estus-shots/bin/estus-shots" \ + "Restart=on-failure" \ + "RestartSec=5" \ + "User=www-data" \ + "WorkingDirectory=/opt/estus-shots" \ + "Environment=LOG_LEVEL=info" \ + "" \ + "[Install]" \ + "WantedBy=multi-user.target" \ + | ssh user@server 'sudo tee /etc/systemd/system/estus-shots.service' + + ssh user@server 'sudo systemctl daemon-reload && sudo systemctl enable estus-shots.service' + ``` +3. Ensure Nginx reverse proxy points to `127.0.0.1:9000` and reload it once configured: + ```fish + ssh user@server 'sudo systemctl restart nginx' + ``` + +## Deployment script + +Save the following as `scripts/deploy.fish` (or another preferred location) and make it executable with `chmod +x scripts/deploy.fish`. + +```fish +#!/usr/bin/env fish + +set -e + +set SERVER user@server +set TARGET_DIR /opt/estus-shots +set BIN_NAME estus-shots + +echo 'Building project locally (release)...' +nimble build -y + +echo 'Uploading binary...' +scp bin/$BIN_NAME $SERVER:$TARGET_DIR/bin/ + +echo 'Uploading static assets...' +scp -r src/static $SERVER:$TARGET_DIR/ + +echo 'Restarting services...' +ssh $SERVER 'sudo systemctl restart estus-shots.service' +ssh $SERVER 'sudo systemctl restart nginx' + +echo 'Deployment finished.' +``` + +> The script prompts for the SSH password and any required `sudo` password on the server. + +## Manual deployment steps + +1. Build the project locally: + ```fish + nimble build -y + ``` +2. Copy the new build output and static assets: + ```fish + scp bin/estus-shots user@server:/opt/estus-shots/bin/ + scp -r src/static user@server:/opt/estus-shots/ + ``` +3. Restart the service and, if needed, Nginx: + ```fish + ssh user@server 'sudo systemctl restart estus-shots.service' + ssh user@server 'sudo systemctl restart nginx' + ``` + +## Verification + +- Check service status: + ```fish + ssh user@server 'systemctl status estus-shots.service --no-pager' + ``` +- Review recent logs: + ```fish + ssh user@server 'journalctl -u estus-shots.service -n 50 --no-pager' + ``` + +## Troubleshooting tips + +- If the service fails, run it manually on the server to capture stdout/stderr: `bin/estus-shots`. +- Ensure SELinux contexts allow Nginx to proxy (`setsebool -P httpd_can_network_connect 1`). +- Validate reverse proxy config: `sudo nginx -t`. \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5033616 --- /dev/null +++ b/.gitignore @@ -0,0 +1,36 @@ +# Build outputs +bin/ +build/ + +# Go tool artifacts +*.test +coverage.out + +# Compiled binaries and objects +*.exe +*.dll +*.lib +*.obj +*.o +*.so +*.dylib +*.a +*.pdb +*.ilk +*.map + +# Logs and temporary files +*.log +*.out +*.err +*.tmp +*.temp + +# Editor and tool artifacts +*.swp +*~ +.DS_Store +Thumbs.db +.idea/ +.vscode/ + diff --git a/cmd/estus-shots/main.go b/cmd/estus-shots/main.go new file mode 100644 index 0000000..8859dce --- /dev/null +++ b/cmd/estus-shots/main.go @@ -0,0 +1,119 @@ +package main + +import ( + "context" + "encoding/json" + "errors" + "flag" + "log" + "net/http" + "os" + "os/signal" + "path/filepath" + "syscall" + "time" + + "estus-shots/internal/server" +) + +type appConfig struct { + MediaDir string `json:"media_dir"` +} + +func main() { + cfg := resolveConfig() + + srv, err := server.New(server.Config{MediaDir: cfg.MediaDir}) + if err != nil { + log.Fatalf("failed to configure server: %v", err) + } + + httpServer := &http.Server{ + Addr: srv.Address(), + Handler: srv.Router(), + ReadTimeout: 15 * time.Second, + WriteTimeout: 15 * time.Second, + IdleTimeout: 60 * time.Second, + } + + log.Printf( + "Estus Shots web server running on http://127.0.0.1%s (media: %s)", + srv.Address(), + cfg.MediaDir, + ) + + go func() { + if err := httpServer.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) { + log.Fatalf("server error: %v", err) + } + }() + + ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM) + defer stop() + + <-ctx.Done() + shutdownCtx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + + if err := httpServer.Shutdown(shutdownCtx); err != nil { + log.Printf("graceful shutdown failed: %v", err) + } else { + log.Println("server stopped") + } +} + +func resolveConfig() appConfig { + mediaDirFlag := flag.String("media-dir", "", "path to the media directory served at /media") + configPath := flag.String("config", "", "optional path to a JSON config file") + flag.Parse() + + cfg := appConfig{} + if *configPath != "" { + fileCfg, err := loadConfig(*configPath) + if err != nil { + log.Fatalf("failed to read config file: %v", err) + } + cfg = fileCfg + } + + if *mediaDirFlag != "" { + cfg.MediaDir = *mediaDirFlag + } + + if cfg.MediaDir == "" { + cfg.MediaDir = defaultMediaDir() + } + + return cfg +} + +func loadConfig(path string) (appConfig, error) { + data, err := os.ReadFile(path) + if err != nil { + return appConfig{}, err + } + + cfg := appConfig{} + if err := json.Unmarshal(data, &cfg); err != nil { + return appConfig{}, err + } + return cfg, nil +} + +func defaultMediaDir() string { + if cwd, err := os.Getwd(); err == nil { + candidate := filepath.Join(cwd, "media") + if info, err := os.Stat(candidate); err == nil && info.IsDir() { + return candidate + } + } + + if exe, err := os.Executable(); err == nil { + candidate := filepath.Join(filepath.Dir(exe), "media") + if info, err := os.Stat(candidate); err == nil && info.IsDir() { + return candidate + } + } + + return filepath.Join(".", "media") +} diff --git a/cmd/luxtools/main.go b/cmd/luxtools/main.go new file mode 100644 index 0000000..8859dce --- /dev/null +++ b/cmd/luxtools/main.go @@ -0,0 +1,119 @@ +package main + +import ( + "context" + "encoding/json" + "errors" + "flag" + "log" + "net/http" + "os" + "os/signal" + "path/filepath" + "syscall" + "time" + + "estus-shots/internal/server" +) + +type appConfig struct { + MediaDir string `json:"media_dir"` +} + +func main() { + cfg := resolveConfig() + + srv, err := server.New(server.Config{MediaDir: cfg.MediaDir}) + if err != nil { + log.Fatalf("failed to configure server: %v", err) + } + + httpServer := &http.Server{ + Addr: srv.Address(), + Handler: srv.Router(), + ReadTimeout: 15 * time.Second, + WriteTimeout: 15 * time.Second, + IdleTimeout: 60 * time.Second, + } + + log.Printf( + "Estus Shots web server running on http://127.0.0.1%s (media: %s)", + srv.Address(), + cfg.MediaDir, + ) + + go func() { + if err := httpServer.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) { + log.Fatalf("server error: %v", err) + } + }() + + ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM) + defer stop() + + <-ctx.Done() + shutdownCtx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + + if err := httpServer.Shutdown(shutdownCtx); err != nil { + log.Printf("graceful shutdown failed: %v", err) + } else { + log.Println("server stopped") + } +} + +func resolveConfig() appConfig { + mediaDirFlag := flag.String("media-dir", "", "path to the media directory served at /media") + configPath := flag.String("config", "", "optional path to a JSON config file") + flag.Parse() + + cfg := appConfig{} + if *configPath != "" { + fileCfg, err := loadConfig(*configPath) + if err != nil { + log.Fatalf("failed to read config file: %v", err) + } + cfg = fileCfg + } + + if *mediaDirFlag != "" { + cfg.MediaDir = *mediaDirFlag + } + + if cfg.MediaDir == "" { + cfg.MediaDir = defaultMediaDir() + } + + return cfg +} + +func loadConfig(path string) (appConfig, error) { + data, err := os.ReadFile(path) + if err != nil { + return appConfig{}, err + } + + cfg := appConfig{} + if err := json.Unmarshal(data, &cfg); err != nil { + return appConfig{}, err + } + return cfg, nil +} + +func defaultMediaDir() string { + if cwd, err := os.Getwd(); err == nil { + candidate := filepath.Join(cwd, "media") + if info, err := os.Stat(candidate); err == nil && info.IsDir() { + return candidate + } + } + + if exe, err := os.Executable(); err == nil { + candidate := filepath.Join(filepath.Dir(exe), "media") + if info, err := os.Stat(candidate); err == nil && info.IsDir() { + return candidate + } + } + + return filepath.Join(".", "media") +} diff --git a/deploy/estus-shots.service b/deploy/estus-shots.service new file mode 100644 index 0000000..72a2244 --- /dev/null +++ b/deploy/estus-shots.service @@ -0,0 +1,19 @@ +[Unit] +Description=estus-shots web service +After=network.target + +[Service] +Type=simple +ExecStart=/opt/estus-shots/bin/estus-shots +WorkingDirectory=/opt/estus-shots +Restart=on-failure +RestartSec=5 +User=estus-shots +Group=estus-shots +Environment=LOG_LEVEL=info +Environment=PORT=9000 +StandardOutput=journal +StandardError=journal + +[Install] +WantedBy=multi-user.target diff --git a/deploy/luxtools.service b/deploy/luxtools.service new file mode 100644 index 0000000..72a2244 --- /dev/null +++ b/deploy/luxtools.service @@ -0,0 +1,19 @@ +[Unit] +Description=estus-shots web service +After=network.target + +[Service] +Type=simple +ExecStart=/opt/estus-shots/bin/estus-shots +WorkingDirectory=/opt/estus-shots +Restart=on-failure +RestartSec=5 +User=estus-shots +Group=estus-shots +Environment=LOG_LEVEL=info +Environment=PORT=9000 +StandardOutput=journal +StandardError=journal + +[Install] +WantedBy=multi-user.target diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..ea544b7 --- /dev/null +++ b/go.mod @@ -0,0 +1,3 @@ +module estus-shots + +go 1.22.0 diff --git a/internal/server/server.go b/internal/server/server.go new file mode 100644 index 0000000..6d0d802 --- /dev/null +++ b/internal/server/server.go @@ -0,0 +1,189 @@ +package server + +import ( + "fmt" + "html" + "html/template" + "io/fs" + "log" + "net/http" + "os" + "path/filepath" + "strings" + "sync" + "time" + + webbundle "estus-shots/web" +) + +const ( + address = ":5000" + htmlContentType = "text/html; charset=utf-8" + notFoundTemplate = ` +
+
+ Error +

Route %s not found.

+
+
+ ` +) + +// Config contains the runtime options for the HTTP server. +type Config struct { + MediaDir string +} + +// Server hosts the Estus Shots HTTP handlers. +type Server struct { + mux *http.ServeMux + templates *template.Template + staticFS fs.FS + mediaFS http.FileSystem + + counterMu sync.Mutex + clickCount int +} + +// New constructs a configured Server ready to serve requests. +func New(cfg Config) (*Server, error) { + if strings.TrimSpace(cfg.MediaDir) == "" { + return nil, fmt.Errorf("media directory is required") + } + + mediaDir := filepath.Clean(cfg.MediaDir) + + info, err := os.Stat(mediaDir) + if err != nil { + return nil, fmt.Errorf("media directory check failed: %w", err) + } + if !info.IsDir() { + return nil, fmt.Errorf("media directory must be a directory: %s", mediaDir) + } + + // Parse all templates + tmpl, err := template.ParseFS(webbundle.Content, "templates/*.html") + if err != nil { + return nil, fmt.Errorf("failed to parse templates: %w", err) + } + + staticFS, err := fs.Sub(webbundle.Content, "static") + if err != nil { + return nil, fmt.Errorf("failed to prepare static assets: %w", err) + } + + s := &Server{ + mux: http.NewServeMux(), + templates: tmpl, + staticFS: staticFS, + mediaFS: http.Dir(mediaDir), + } + + s.registerRoutes() + return s, nil +} + +// Router exposes the configured http.Handler for the server. +func (s *Server) Router() http.Handler { + return s.mux +} + +// Address returns the default listen address for the server. +func (s *Server) Address() string { + return address +} + +func (s *Server) registerRoutes() { + staticHandler := http.FileServer(http.FS(s.staticFS)) + mediaHandler := http.FileServer(s.mediaFS) + + s.mux.Handle("/static/", http.StripPrefix("/static/", allowGetHead(staticHandler))) + s.mux.Handle("/media/", http.StripPrefix("/media/", allowGetHead(mediaHandler))) + s.mux.HandleFunc("/", s.handleRequest) +} + +func (s *Server) handleRequest(w http.ResponseWriter, r *http.Request) { + switch r.URL.Path { + case "/": + data := DefaultMenuBar() + s.renderTemplate(w, http.StatusOK, "index.html", data) + case "/admin": + data := AdminMenuBar() + data.Title = "Admin Panel" + s.renderTemplate(w, http.StatusOK, "admin.html", data) + case "/counter": + s.handleCounter(w, r) + case "/time": + s.sendHTMLString(w, http.StatusOK, renderTime(time.Now())) + default: + s.sendHTMLString(w, http.StatusNotFound, fmt.Sprintf(notFoundTemplate, html.EscapeString(r.URL.Path))) + } +} + +func (s *Server) handleCounter(w http.ResponseWriter, r *http.Request) { + if r.Method == http.MethodPost || r.Method == http.MethodPut { + s.counterMu.Lock() + s.clickCount++ + s.counterMu.Unlock() + } + + s.counterMu.Lock() + count := s.clickCount + s.counterMu.Unlock() + + s.sendHTMLString(w, http.StatusOK, renderCounter(count)) +} + +func (s *Server) renderTemplate(w http.ResponseWriter, status int, name string, data interface{}) { + w.Header().Set("Content-Type", htmlContentType) + w.WriteHeader(status) + + if err := s.templates.ExecuteTemplate(w, name, data); err != nil { + log.Printf("template execution failed: %v", err) + http.Error(w, "Internal Server Error", http.StatusInternalServerError) + } +} + +func (s *Server) sendHTML(w http.ResponseWriter, status int, body []byte) { + w.Header().Set("Content-Type", htmlContentType) + w.WriteHeader(status) + if len(body) > 0 { + if _, err := w.Write(body); err != nil { + log.Printf("write response failed: %v", err) + } + } +} + +func (s *Server) sendHTMLString(w http.ResponseWriter, status int, body string) { + s.sendHTML(w, status, []byte(body)) +} + +func renderCounter(count int) string { + return fmt.Sprintf(` +
+

Clicks: %d

+ +
+ `, count) +} + +func renderTime(now time.Time) string { + return fmt.Sprintf(` +
+

Server time: %s

+
+ `, now.Format("2006-01-02 15:04:05")) +} + +func allowGetHead(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + switch r.Method { + case http.MethodGet, http.MethodHead: + next.ServeHTTP(w, r) + default: + http.NotFound(w, r) + } + }) +} diff --git a/internal/server/server_test.go b/internal/server/server_test.go new file mode 100644 index 0000000..a09e614 --- /dev/null +++ b/internal/server/server_test.go @@ -0,0 +1,129 @@ +package server + +import ( + "net/http" + "net/http/httptest" + "os" + "path/filepath" + "strings" + "testing" + "time" +) + +func TestRenderCounter(t *testing.T) { + html := renderCounter(7) + if !strings.Contains(html, "Clicks:") { + t.Fatalf("expected counter markup to include label") + } + if !strings.Contains(html, "> 7<") { + t.Fatalf("expected counter value in markup, got %q", html) + } +} + +func TestRenderTime(t *testing.T) { + now := time.Date(2024, time.August, 1, 12, 34, 56, 0, time.UTC) + html := renderTime(now) + expected := "2024-08-01 12:34:56" + if !strings.Contains(html, expected) { + t.Fatalf("expected formatted timestamp %s in markup", expected) + } +} + +func TestCounterEndpoint(t *testing.T) { + srv := mustNewServer(t, nil) + + req := httptest.NewRequest(http.MethodPost, "/counter", nil) + resp := httptest.NewRecorder() + + srv.Router().ServeHTTP(resp, req) + + if resp.Code != http.StatusOK { + t.Fatalf("expected status 200, got %d", resp.Code) + } + + body := resp.Body.String() + if !strings.Contains(body, "> 1<") { + t.Fatalf("expected counter to increment to 1, body: %q", body) + } +} + +func TestNotFound(t *testing.T) { + srv := mustNewServer(t, nil) + + req := httptest.NewRequest(http.MethodGet, "/unknown", nil) + resp := httptest.NewRecorder() + + srv.Router().ServeHTTP(resp, req) + + if resp.Code != http.StatusNotFound { + t.Fatalf("expected 404, got %d", resp.Code) + } + if !strings.Contains(resp.Body.String(), "Route /unknown not found.") { + t.Fatalf("expected not found message, got %q", resp.Body.String()) + } +} + +func TestStaticFileServing(t *testing.T) { + srv := mustNewServer(t, nil) + + req := httptest.NewRequest(http.MethodGet, "/static/lib/htmx.2.0.7.min.js", nil) + resp := httptest.NewRecorder() + + srv.Router().ServeHTTP(resp, req) + + if resp.Code != http.StatusOK { + t.Fatalf("expected static asset to load, got status %d", resp.Code) + } + if resp.Body.Len() == 0 { + t.Fatalf("expected static asset response body") + } +} + +func TestMediaServing(t *testing.T) { + var demoName string + srv := mustNewServer(t, func(dir string) { + demoName = filepath.Join(dir, "demo.txt") + if err := os.WriteFile(demoName, []byte("demo media file"), 0o644); err != nil { + t.Fatalf("failed to seed media file: %v", err) + } + }) + + req := httptest.NewRequest(http.MethodGet, "/media/demo.txt", nil) + resp := httptest.NewRecorder() + + srv.Router().ServeHTTP(resp, req) + + if resp.Code != http.StatusOK { + t.Fatalf("expected public asset to load, got status %d", resp.Code) + } + body := resp.Body.String() + if !strings.Contains(body, "demo media file") { + t.Fatalf("unexpected asset body: %q", body) + } +} + +func TestNewRequiresMediaDir(t *testing.T) { + if _, err := New(Config{}); err == nil { + t.Fatalf("expected error when media dir is empty") + } + + missing := filepath.Join(t.TempDir(), "missing") + if _, err := New(Config{MediaDir: missing}); err == nil { + t.Fatalf("expected error when media dir does not exist") + } +} + +func mustNewServer(t *testing.T, setup func(string)) *Server { + t.Helper() + + mediaDir := t.TempDir() + if setup != nil { + setup(mediaDir) + } + + srv, err := New(Config{MediaDir: mediaDir}) + if err != nil { + t.Fatalf("failed to create server: %v", err) + } + return srv +} diff --git a/internal/server/template_data.go b/internal/server/template_data.go new file mode 100644 index 0000000..64d4bb5 --- /dev/null +++ b/internal/server/template_data.go @@ -0,0 +1,84 @@ +package server + +// This file defines the data structures and helper functions for the template system. +// +// The template system uses Go's html/template package to provide: +// - Dynamic menu bars that can be customized per page +// - Template inheritance via layout.html +// - Type-safe data passing via structs +// +// To create a new page with a custom menu: +// 1. Create a PageData struct with your menu configuration +// 2. Call s.renderTemplate(w, status, "yourpage.html", data) +// 3. In yourpage.html, use {{template "layout" .}} and define content blocks +// +// See TEMPLATE_GUIDE.md for detailed examples and usage patterns. + +// PageData holds the data passed to page templates. +type PageData struct { + Title string + MenuGroups []MenuGroup + ShowClock bool +} + +// MenuGroup represents a dropdown menu in the navbar. +type MenuGroup struct { + Label string + Items []MenuItem +} + +// MenuItem represents a single menu item. +type MenuItem struct { + Label string + URL string + IsDivider bool +} + +// DefaultMenuBar returns the standard menu configuration. +func DefaultMenuBar() PageData { + return PageData{ + ShowClock: true, + MenuGroups: []MenuGroup{ + { + Label: "File", + Items: []MenuItem{ + {Label: "New", URL: "#!"}, + {Label: "Open", URL: "#!"}, + {Label: "Save", URL: "#!"}, + {Label: "Save As", URL: "#!"}, + {IsDivider: true}, + {Label: "Exit", URL: "#!"}, + }, + }, + { + Label: "Edit", + Items: []MenuItem{ + {Label: "Cut", URL: "#!"}, + {Label: "Copy", URL: "#!"}, + {Label: "Paste", URL: "#!"}, + }, + }, + { + Label: "Help", + Items: []MenuItem{ + {Label: "Documentation", URL: "#!"}, + {Label: "About", URL: "#!"}, + }, + }, + }, + } +} + +// AdminMenuBar returns a menu configuration with admin options. +func AdminMenuBar() PageData { + data := DefaultMenuBar() + data.MenuGroups = append(data.MenuGroups, MenuGroup{ + Label: "Admin", + Items: []MenuItem{ + {Label: "Users", URL: "/admin/users"}, + {Label: "Settings", URL: "/admin/settings"}, + {Label: "Logs", URL: "/admin/logs"}, + }, + }) + return data +} diff --git a/media/demo.txt b/media/demo.txt new file mode 100644 index 0000000..18afc57 --- /dev/null +++ b/media/demo.txt @@ -0,0 +1 @@ +This is a demo media file served from the configurable media handler. diff --git a/web/embed.go b/web/embed.go new file mode 100644 index 0000000..ffc6adf --- /dev/null +++ b/web/embed.go @@ -0,0 +1,8 @@ +package web + +import "embed" + +// Content holds the HTML templates and static assets for the web UI. +// +//go:embed templates/* static +var Content embed.FS diff --git a/web/static/lib/htmx.2.0.7.min.js b/web/static/lib/htmx.2.0.7.min.js new file mode 100644 index 0000000..d49e662 --- /dev/null +++ b/web/static/lib/htmx.2.0.7.min.js @@ -0,0 +1 @@ +var htmx=function(){"use strict";const Q={onLoad:null,process:null,on:null,off:null,trigger:null,ajax:null,find:null,findAll:null,closest:null,values:function(e,t){const n=dn(e,t||"post");return n.values},remove:null,addClass:null,removeClass:null,toggleClass:null,takeClass:null,swap:null,defineExtension:null,removeExtension:null,logAll:null,logNone:null,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:"",inlineStyleNonce:"",attributesToSettle:["class","style","width","height"],withCredentials:false,timeout:0,wsReconnectDelay:"full-jitter",wsBinaryType:"blob",disableSelector:"[hx-disable], [data-hx-disable]",scrollBehavior:"instant",defaultFocusScroll:false,getCacheBusterParam:false,globalViewTransitions:false,methodsThatUseUrlParams:["get","delete"],selfRequestsOnly:true,ignoreTitle:false,scrollIntoViewOnBoost:true,triggerSpecsCache:null,disableInheritance:false,responseHandling:[{code:"204",swap:false},{code:"[23]..",swap:true},{code:"[45]..",swap:false,error:true}],allowNestedOobSwaps:true,historyRestoreAsHxRequest:true,reportValidityOfForms:false},parseInterval:null,location:location,_:null,version:"2.0.7"};Q.onLoad=V;Q.process=Mt;Q.on=xe;Q.off=be;Q.trigger=ae;Q.ajax=Ln;Q.find=f;Q.findAll=x;Q.closest=g;Q.remove=_;Q.addClass=K;Q.removeClass=G;Q.toggleClass=W;Q.takeClass=Z;Q.swap=ze;Q.defineExtension=_n;Q.removeExtension=zn;Q.logAll=j;Q.logNone=$;Q.parseInterval=d;Q._=e;const n={addTriggerHandler:St,bodyContains:se,canAccessLocalStorage:B,findThisElement:Se,filterValues:yn,swap:ze,hasAttribute:s,getAttributeValue:a,getClosestAttributeValue:ne,getClosestMatch:q,getExpressionVars:Tn,getHeaders:mn,getInputValues:dn,getInternalData:oe,getSwapSpecification:bn,getTriggerSpecs:st,getTarget:Ee,makeFragment:P,mergeObjects:le,makeSettleInfo:Sn,oobSwap:He,querySelectorExt:ue,settleImmediately:Yt,shouldCancel:ht,triggerEvent:ae,triggerErrorEvent:fe,withExtensions:Vt};const de=["get","post","put","delete","patch"];const T=de.map(function(e){return"[hx-"+e+"], [data-hx-"+e+"]"}).join(", ");function d(e){if(e==undefined){return undefined}let t=NaN;if(e.slice(-2)=="ms"){t=parseFloat(e.slice(0,-2))}else if(e.slice(-1)=="s"){t=parseFloat(e.slice(0,-1))*1e3}else if(e.slice(-1)=="m"){t=parseFloat(e.slice(0,-1))*1e3*60}else{t=parseFloat(e)}return isNaN(t)?undefined:t}function ee(e,t){return e instanceof Element&&e.getAttribute(t)}function s(e,t){return!!e.hasAttribute&&(e.hasAttribute(t)||e.hasAttribute("data-"+t))}function a(e,t){return ee(e,t)||ee(e,"data-"+t)}function u(e){const t=e.parentElement;if(!t&&e.parentNode instanceof ShadowRoot)return e.parentNode;return t}function te(){return document}function y(e,t){return e.getRootNode?e.getRootNode({composed:t}):te()}function q(e,t){while(e&&!t(e)){e=u(e)}return e||null}function o(e,t,n){const r=a(t,n);const o=a(t,"hx-disinherit");var i=a(t,"hx-inherit");if(e!==t){if(Q.config.disableInheritance){if(i&&(i==="*"||i.split(" ").indexOf(n)>=0)){return r}else{return null}}if(o&&(o==="*"||o.split(" ").indexOf(n)>=0)){return"unset"}}return r}function ne(t,n){let r=null;q(t,function(e){return!!(r=o(t,ce(e),n))});if(r!=="unset"){return r}}function h(e,t){return e instanceof Element&&e.matches(t)}function A(e){const t=/<([a-z][^\/\0>\x20\t\r\n\f]*)/i;const n=t.exec(e);if(n){return n[1].toLowerCase()}else{return""}}function L(e){const t=new DOMParser;return t.parseFromString(e,"text/html")}function N(e,t){while(t.childNodes.length>0){e.append(t.childNodes[0])}}function r(e){const t=te().createElement("script");ie(e.attributes,function(e){t.setAttribute(e.name,e.value)});t.textContent=e.textContent;t.async=false;if(Q.config.inlineScriptNonce){t.nonce=Q.config.inlineScriptNonce}return t}function i(e){return e.matches("script")&&(e.type==="text/javascript"||e.type==="module"||e.type==="")}function I(e){Array.from(e.querySelectorAll("script")).forEach(e=>{if(i(e)){const t=r(e);const n=e.parentNode;try{n.insertBefore(t,e)}catch(e){R(e)}finally{e.remove()}}})}function P(e){const t=e.replace(/]*)?>[\s\S]*?<\/head>/i,"");const n=A(t);let r;if(n==="html"){r=new DocumentFragment;const i=L(e);N(r,i.body);r.title=i.title}else if(n==="body"){r=new DocumentFragment;const i=L(t);N(r,i.body);r.title=i.title}else{const i=L('");r=i.querySelector("template").content;r.title=i.title;var o=r.querySelector("title");if(o&&o.parentNode===r){o.remove();r.title=o.innerText}}if(r){if(Q.config.allowScriptTags){I(r)}else{r.querySelectorAll("script").forEach(e=>e.remove())}}return r}function re(e){if(e){e()}}function t(e,t){return Object.prototype.toString.call(e)==="[object "+t+"]"}function D(e){return typeof e==="function"}function k(e){return t(e,"Object")}function oe(e){const t="htmx-internal-data";let n=e[t];if(!n){n=e[t]={}}return n}function F(t){const n=[];if(t){for(let e=0;e=0}function se(e){return e.getRootNode({composed:true})===document}function X(e){return e.trim().split(/\s+/)}function le(e,t){for(const n in t){if(t.hasOwnProperty(n)){e[n]=t[n]}}return e}function v(e){try{return JSON.parse(e)}catch(e){R(e);return null}}function B(){const e="htmx:sessionStorageTest";try{sessionStorage.setItem(e,e);sessionStorage.removeItem(e);return true}catch(e){return false}}function U(e){const t=new URL(e,"http://x");if(t){e=t.pathname+t.search}if(e!="/"){e=e.replace(/\/+$/,"")}return e}function e(e){return On(te().body,function(){return eval(e)})}function V(t){const e=Q.on("htmx:load",function(e){t(e.detail.elt)});return e}function j(){Q.logger=function(e,t,n){if(console){console.log(t,e,n)}}}function $(){Q.logger=null}function f(e,t){if(typeof e!=="string"){return e.querySelector(t)}else{return f(te(),e)}}function x(e,t){if(typeof e!=="string"){return e.querySelectorAll(t)}else{return x(te(),e)}}function b(){return window}function _(e,t){e=w(e);if(t){b().setTimeout(function(){_(e);e=null},t)}else{u(e).removeChild(e)}}function ce(e){return e instanceof Element?e:null}function z(e){return e instanceof HTMLElement?e:null}function J(e){return typeof e==="string"?e:null}function p(e){return e instanceof Element||e instanceof Document||e instanceof DocumentFragment?e:null}function K(e,t,n){e=ce(w(e));if(!e){return}if(n){b().setTimeout(function(){K(e,t);e=null},n)}else{e.classList&&e.classList.add(t)}}function G(e,t,n){let r=ce(w(e));if(!r){return}if(n){b().setTimeout(function(){G(r,t);r=null},n)}else{if(r.classList){r.classList.remove(t);if(r.classList.length===0){r.removeAttribute("class")}}}}function W(e,t){e=w(e);e.classList.toggle(t)}function Z(e,t){e=w(e);ie(e.parentElement.children,function(e){G(e,t)});K(ce(e),t)}function g(e,t){e=ce(w(e));if(e){return e.closest(t)}return null}function l(e,t){return e.substring(0,t.length)===t}function Y(e,t){return e.substring(e.length-t.length)===t}function pe(e){const t=e.trim();if(l(t,"<")&&Y(t,"/>")){return t.substring(1,t.length-2)}else{return t}}function m(t,r,n){if(r.indexOf("global ")===0){return m(t,r.slice(7),true)}t=w(t);const o=[];{let t=0;let n=0;for(let e=0;e"){t--}}if(n0){const r=pe(o.shift());let e;if(r.indexOf("closest ")===0){e=g(ce(t),pe(r.slice(8)))}else if(r.indexOf("find ")===0){e=f(p(t),pe(r.slice(5)))}else if(r==="next"||r==="nextElementSibling"){e=ce(t).nextElementSibling}else if(r.indexOf("next ")===0){e=ge(t,pe(r.slice(5)),!!n)}else if(r==="previous"||r==="previousElementSibling"){e=ce(t).previousElementSibling}else if(r.indexOf("previous ")===0){e=me(t,pe(r.slice(9)),!!n)}else if(r==="document"){e=document}else if(r==="window"){e=window}else if(r==="body"){e=document.body}else if(r==="root"){e=y(t,!!n)}else if(r==="host"){e=t.getRootNode().host}else{s.push(r)}if(e){i.push(e)}}if(s.length>0){const e=s.join(",");const c=p(y(t,!!n));i.push(...F(c.querySelectorAll(e)))}return i}var ge=function(t,e,n){const r=p(y(t,n)).querySelectorAll(e);for(let e=0;e=0;e--){const o=r[e];if(o.compareDocumentPosition(t)===Node.DOCUMENT_POSITION_FOLLOWING){return o}}};function ue(e,t){if(typeof e!=="string"){return m(e,t)[0]}else{return m(te().body,e)[0]}}function w(e,t){if(typeof e==="string"){return f(p(t)||document,e)}else{return e}}function ye(e,t,n,r){if(D(t)){return{target:te().body,event:J(e),listener:t,options:n}}else{return{target:w(e),event:J(t),listener:n,options:r}}}function xe(t,n,r,o){Gn(function(){const e=ye(t,n,r,o);e.target.addEventListener(e.event,e.listener,e.options)});const e=D(n);return e?n:r}function be(t,n,r){Gn(function(){const e=ye(t,n,r);e.target.removeEventListener(e.event,e.listener)});return D(n)?n:r}const ve=te().createElement("output");function we(t,n){const e=ne(t,n);if(e){if(e==="this"){return[Se(t,n)]}else{const r=m(t,e);const o=/(^|,)(\s*)inherit(\s*)($|,)/.test(e);if(o){const i=ce(q(t,function(e){return e!==t&&s(ce(e),n)}));if(i){r.push(...we(i,n))}}if(r.length===0){R('The selector "'+e+'" on '+n+" returned no matches!");return[ve]}else{return r}}}}function Se(e,t){return ce(q(e,function(e){return a(ce(e),t)!=null}))}function Ee(e){const t=ne(e,"hx-target");if(t){if(t==="this"){return Se(e,"hx-target")}else{return ue(e,t)}}else{const n=oe(e);if(n.boosted){return te().body}else{return e}}}function Ce(e){return Q.config.attributesToSettle.includes(e)}function Oe(t,n){ie(Array.from(t.attributes),function(e){if(!n.hasAttribute(e.name)&&Ce(e.name)){t.removeAttribute(e.name)}});ie(n.attributes,function(e){if(Ce(e.name)){t.setAttribute(e.name,e.value)}})}function Re(t,e){const n=Jn(e);for(let e=0;e0){s=e.substring(0,e.indexOf(":"));n=e.substring(e.indexOf(":")+1)}else{s=e}o.removeAttribute("hx-swap-oob");o.removeAttribute("data-hx-swap-oob");const r=m(t,n,false);if(r.length){ie(r,function(e){let t;const n=o.cloneNode(true);t=te().createDocumentFragment();t.appendChild(n);if(!Re(s,e)){t=p(n)}const r={shouldSwap:true,target:e,fragment:t};if(!ae(e,"htmx:oobBeforeSwap",r))return;e=r.target;if(r.shouldSwap){qe(t);$e(s,e,e,t,i);Te()}ie(i.elts,function(e){ae(e,"htmx:oobAfterSwap",r)})});o.parentNode.removeChild(o)}else{o.parentNode.removeChild(o);fe(te().body,"htmx:oobErrorNoTarget",{content:o})}return e}function Te(){const e=f("#--htmx-preserve-pantry--");if(e){for(const t of[...e.children]){const n=f("#"+t.id);n.parentNode.moveBefore(t,n);n.remove()}e.remove()}}function qe(e){ie(x(e,"[hx-preserve], [data-hx-preserve]"),function(e){const t=a(e,"id");const n=te().getElementById(t);if(n!=null){if(e.moveBefore){let e=f("#--htmx-preserve-pantry--");if(e==null){te().body.insertAdjacentHTML("afterend","
");e=f("#--htmx-preserve-pantry--")}e.moveBefore(n,null)}else{e.parentNode.replaceChild(n,e)}}})}function Ae(l,e,c){ie(e.querySelectorAll("[id]"),function(t){const n=ee(t,"id");if(n&&n.length>0){const r=n.replace("'","\\'");const o=t.tagName.replace(":","\\:");const e=p(l);const i=e&&e.querySelector(o+"[id='"+r+"']");if(i&&i!==e){const s=t.cloneNode();Oe(t,i);c.tasks.push(function(){Oe(t,s)})}}})}function Le(e){return function(){G(e,Q.config.addedClass);Mt(ce(e));Ne(p(e));ae(e,"htmx:load")}}function Ne(e){const t="[autofocus]";const n=z(h(e,t)?e:e.querySelector(t));if(n!=null){n.focus()}}function c(e,t,n,r){Ae(e,n,r);while(n.childNodes.length>0){const o=n.firstChild;K(ce(o),Q.config.addedClass);e.insertBefore(o,t);if(o.nodeType!==Node.TEXT_NODE&&o.nodeType!==Node.COMMENT_NODE){r.tasks.push(Le(o))}}}function Ie(e,t){let n=0;while(n0}function ze(h,d,p,g){if(!g){g={}}let m=null;let n=null;let e=function(){re(g.beforeSwapCallback);h=w(h);const r=g.contextElement?y(g.contextElement,false):te();const e=document.activeElement;let t={};t={elt:e,start:e?e.selectionStart:null,end:e?e.selectionEnd:null};const o=Sn(h);if(p.swapStyle==="textContent"){h.textContent=d}else{let n=P(d);o.title=g.title||n.title;if(g.historyRequest){n=n.querySelector("[hx-history-elt],[data-hx-history-elt]")||n}if(g.selectOOB){const i=g.selectOOB.split(",");for(let t=0;t0){b().setTimeout(n,p.settleDelay)}else{n()}};let t=Q.config.globalViewTransitions;if(p.hasOwnProperty("transition")){t=p.transition}const r=g.contextElement||te();if(t&&ae(r,"htmx:beforeTransition",g.eventInfo)&&typeof Promise!=="undefined"&&document.startViewTransition){const o=new Promise(function(e,t){m=e;n=t});const i=e;e=function(){document.startViewTransition(function(){i();return o})}}try{if(p?.swapDelay&&p.swapDelay>0){b().setTimeout(e,p.swapDelay)}else{e()}}catch(e){fe(r,"htmx:swapError",g.eventInfo);re(n);throw e}}function Je(e,t,n){const r=e.getResponseHeader(t);if(r.indexOf("{")===0){const o=v(r);for(const i in o){if(o.hasOwnProperty(i)){let e=o[i];if(k(e)){n=e.target!==undefined?e.target:n}else{e={value:e}}ae(n,i,e)}}}else{const s=r.split(",");for(let e=0;e0){const s=o[0];if(s==="]"){e--;if(e===0){if(n===null){t=t+"true"}o.shift();t+=")})";try{const l=On(r,function(){return Function(t)()},function(){return true});l.source=t;return l}catch(e){fe(te().body,"htmx:syntax:error",{error:e,source:t});return null}}}else if(s==="["){e++}if(tt(s,n,i)){t+="(("+i+"."+s+") ? ("+i+"."+s+") : (window."+s+"))"}else{t=t+s}n=o.shift()}}}function O(e,t){let n="";while(e.length>0&&!t.test(e[0])){n+=e.shift()}return n}function rt(e){let t;if(e.length>0&&Ye.test(e[0])){e.shift();t=O(e,Qe).trim();e.shift()}else{t=O(e,E)}return t}const ot="input, textarea, select";function it(e,t,n){const r=[];const o=et(t);do{O(o,C);const l=o.length;const c=O(o,/[,\[\s]/);if(c!==""){if(c==="every"){const u={trigger:"every"};O(o,C);u.pollInterval=d(O(o,/[,\[\s]/));O(o,C);var i=nt(e,o,"event");if(i){u.eventFilter=i}r.push(u)}else{const f={trigger:c};var i=nt(e,o,"event");if(i){f.eventFilter=i}O(o,C);while(o.length>0&&o[0]!==","){const a=o.shift();if(a==="changed"){f.changed=true}else if(a==="once"){f.once=true}else if(a==="consume"){f.consume=true}else if(a==="delay"&&o[0]===":"){o.shift();f.delay=d(O(o,E))}else if(a==="from"&&o[0]===":"){o.shift();if(Ye.test(o[0])){var s=rt(o)}else{var s=O(o,E);if(s==="closest"||s==="find"||s==="next"||s==="previous"){o.shift();const h=rt(o);if(h.length>0){s+=" "+h}}}f.from=s}else if(a==="target"&&o[0]===":"){o.shift();f.target=rt(o)}else if(a==="throttle"&&o[0]===":"){o.shift();f.throttle=d(O(o,E))}else if(a==="queue"&&o[0]===":"){o.shift();f.queue=O(o,E)}else if(a==="root"&&o[0]===":"){o.shift();f[a]=rt(o)}else if(a==="threshold"&&o[0]===":"){o.shift();f[a]=O(o,E)}else{fe(e,"htmx:syntax:error",{token:o.shift()})}O(o,C)}r.push(f)}}if(o.length===l){fe(e,"htmx:syntax:error",{token:o.shift()})}O(o,C)}while(o[0]===","&&o.shift());if(n){n[t]=r}return r}function st(e){const t=a(e,"hx-trigger");let n=[];if(t){const r=Q.config.triggerSpecsCache;n=r&&r[t]||it(e,t,r)}if(n.length>0){return n}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,ot)){return[{trigger:"change"}]}else{return[{trigger:"click"}]}}function lt(e){oe(e).cancelled=true}function ct(e,t,n){const r=oe(e);r.timeout=b().setTimeout(function(){if(se(e)&&r.cancelled!==true){if(!pt(n,e,Bt("hx:poll:trigger",{triggerSpec:n,target:e}))){t(e)}ct(e,t,n)}},n.pollInterval)}function ut(e){return location.hostname===e.hostname&&ee(e,"href")&&ee(e,"href").indexOf("#")!==0}function ft(e){return g(e,Q.config.disableSelector)}function at(t,n,e){if(t instanceof HTMLAnchorElement&&ut(t)&&(t.target===""||t.target==="_self")||t.tagName==="FORM"&&String(ee(t,"method")).toLowerCase()!=="dialog"){n.boosted=true;let r,o;if(t.tagName==="A"){r="get";o=ee(t,"href")}else{const i=ee(t,"method");r=i?i.toLowerCase():"get";o=ee(t,"action");if(o==null||o===""){o=location.href}if(r==="get"&&o.includes("?")){o=o.replace(/\?[^#]+/,"")}}e.forEach(function(e){gt(t,function(e,t){const n=ce(e);if(ft(n)){S(n);return}he(r,o,n,t)},n,e,true)})}}function ht(e,t){if(e.type==="submit"&&t.tagName==="FORM"){return true}else if(e.type==="click"){const n=t.closest('input[type="submit"], button');if(n&&n.form&&n.type==="submit"){return true}const r=t.closest("a");const o=/^#.+/;if(r&&r.href&&!o.test(r.getAttribute("href"))){return true}}return false}function dt(e,t){return oe(e).boosted&&e instanceof HTMLAnchorElement&&t.type==="click"&&(t.ctrlKey||t.metaKey)}function pt(e,t,n){const r=e.eventFilter;if(r){try{return r.call(t,n)!==true}catch(e){const o=r.source;fe(te().body,"htmx:eventFilter:error",{error:e,source:o});return true}}return false}function gt(l,c,e,u,f){const a=oe(l);let t;if(u.from){t=m(l,u.from)}else{t=[l]}if(u.changed){if(!("lastValue"in a)){a.lastValue=new WeakMap}t.forEach(function(e){if(!a.lastValue.has(u)){a.lastValue.set(u,new WeakMap)}a.lastValue.get(u).set(e,e.value)})}ie(t,function(i){const s=function(e){if(!se(l)){i.removeEventListener(u.trigger,s);return}if(dt(l,e)){return}if(f||ht(e,i)){e.preventDefault()}if(pt(u,l,e)){return}const t=oe(e);t.triggerSpec=u;if(t.handledFor==null){t.handledFor=[]}if(t.handledFor.indexOf(l)<0){t.handledFor.push(l);if(u.consume){e.stopPropagation()}if(u.target&&e.target){if(!h(ce(e.target),u.target)){return}}if(u.once){if(a.triggeredOnce){return}else{a.triggeredOnce=true}}if(u.changed){const n=e.target;const r=n.value;const o=a.lastValue.get(u);if(o.has(n)&&o.get(n)===r){return}o.set(n,r)}if(a.delayed){clearTimeout(a.delayed)}if(a.throttle){return}if(u.throttle>0){if(!a.throttle){ae(l,"htmx:trigger");c(l,e);a.throttle=b().setTimeout(function(){a.throttle=null},u.throttle)}}else if(u.delay>0){a.delayed=b().setTimeout(function(){ae(l,"htmx:trigger");c(l,e)},u.delay)}else{ae(l,"htmx:trigger");c(l,e)}}};if(e.listenerInfos==null){e.listenerInfos=[]}e.listenerInfos.push({trigger:u.trigger,listener:s,on:i});i.addEventListener(u.trigger,s)})}let mt=false;let yt=null;function xt(){if(!yt){yt=function(){mt=true};window.addEventListener("scroll",yt);window.addEventListener("resize",yt);setInterval(function(){if(mt){mt=false;ie(te().querySelectorAll("[hx-trigger*='revealed'],[data-hx-trigger*='revealed']"),function(e){bt(e)})}},200)}}function bt(e){if(!s(e,"data-hx-revealed")&&M(e)){e.setAttribute("data-hx-revealed","true");const t=oe(e);if(t.initHash){ae(e,"revealed")}else{e.addEventListener("htmx:afterProcessNode",function(){ae(e,"revealed")},{once:true})}}}function vt(e,t,n,r){const o=function(){if(!n.loaded){n.loaded=true;ae(e,"htmx:trigger");t(e)}};if(r>0){b().setTimeout(o,r)}else{o()}}function wt(t,n,e){let i=false;ie(de,function(r){if(s(t,"hx-"+r)){const o=a(t,"hx-"+r);i=true;n.path=o;n.verb=r;e.forEach(function(e){St(t,e,n,function(e,t){const n=ce(e);if(ft(n)){S(n);return}he(r,o,n,t)})})}});return i}function St(r,e,t,n){if(e.trigger==="revealed"){xt();gt(r,n,t,e);bt(ce(r))}else if(e.trigger==="intersect"){const o={};if(e.root){o.root=ue(r,e.root)}if(e.threshold){o.threshold=parseFloat(e.threshold)}const i=new IntersectionObserver(function(t){for(let e=0;e0){t.polling=true;ct(ce(r),n,e)}else{gt(r,n,t,e)}}function Et(e){const t=ce(e);if(!t){return false}const n=t.attributes;for(let e=0;e", "+e).join(""));return o}else{return[]}}function Tt(e){const t=At(e.target);const n=Nt(e);if(n){n.lastButtonClicked=t}}function qt(e){const t=Nt(e);if(t){t.lastButtonClicked=null}}function At(e){return g(ce(e),"button, input[type='submit']")}function Lt(e){return e.form||g(e,"form")}function Nt(e){const t=At(e.target);if(!t){return}const n=Lt(t);if(!n){return}return oe(n)}function It(e){e.addEventListener("click",Tt);e.addEventListener("focusin",Tt);e.addEventListener("focusout",qt)}function Pt(t,e,n){const r=oe(t);if(!Array.isArray(r.onHandlers)){r.onHandlers=[]}let o;const i=function(e){On(t,function(){if(ft(t)){return}if(!o){o=new Function("event",n)}o.call(t,e)})};t.addEventListener(e,i);r.onHandlers.push({event:e,listener:i})}function Dt(t){De(t);for(let e=0;eQ.config.historyCacheSize){i.shift()}while(i.length>0){try{sessionStorage.setItem("htmx-history-cache",JSON.stringify(i));break}catch(e){fe(te().body,"htmx:historyCacheError",{cause:e,cache:i});i.shift()}}}function Jt(t){if(!B()){return null}t=U(t);const n=v(sessionStorage.getItem("htmx-history-cache"))||[];for(let e=0;e=200&&this.status<400){r.response=this.response;ae(te().body,"htmx:historyCacheMissLoad",r);ze(r.historyElt,r.response,n,{contextElement:r.historyElt,historyRequest:true});$t(r.path);ae(te().body,"htmx:historyRestore",{path:e,cacheMiss:true,serverResponse:r.response})}else{fe(te().body,"htmx:historyCacheMissLoadError",r)}};if(ae(te().body,"htmx:historyCacheMiss",r)){t.send()}}function en(e){Gt();e=e||location.pathname+location.search;const t=Jt(e);if(t){const n={swapStyle:"innerHTML",swapDelay:0,settleDelay:0,scroll:t.scroll};const r={path:e,item:t,historyElt:_t(),swapSpec:n};if(ae(te().body,"htmx:historyCacheHit",r)){ze(r.historyElt,t.content,n,{contextElement:r.historyElt,title:t.title});$t(r.path);ae(te().body,"htmx:historyRestore",r)}}else{if(Q.config.refreshOnHistoryMiss){Q.location.reload(true)}else{Qt(e)}}}function tn(e){let t=we(e,"hx-indicator");if(t==null){t=[e]}ie(t,function(e){const t=oe(e);t.requestCount=(t.requestCount||0)+1;e.classList.add.call(e.classList,Q.config.requestClass)});return t}function nn(e){let t=we(e,"hx-disabled-elt");if(t==null){t=[]}ie(t,function(e){const t=oe(e);t.requestCount=(t.requestCount||0)+1;e.setAttribute("disabled","");e.setAttribute("data-disabled-by-htmx","")});return t}function rn(e,t){ie(e.concat(t),function(e){const t=oe(e);t.requestCount=(t.requestCount||1)-1});ie(e,function(e){const t=oe(e);if(t.requestCount===0){e.classList.remove.call(e.classList,Q.config.requestClass)}});ie(t,function(e){const t=oe(e);if(t.requestCount===0){e.removeAttribute("disabled");e.removeAttribute("data-disabled-by-htmx")}})}function on(t,n){for(let e=0;en.indexOf(e)<0)}else{e=e.filter(e=>e!==n)}r.delete(t);ie(e,e=>r.append(t,e))}}function un(e){if(e instanceof HTMLSelectElement&&e.multiple){return F(e.querySelectorAll("option:checked")).map(function(e){return e.value})}if(e instanceof HTMLInputElement&&e.files){return F(e.files)}return e.value}function fn(t,n,r,e,o){if(e==null||on(t,e)){return}else{t.push(e)}if(sn(e)){const i=ee(e,"name");ln(i,un(e),n);if(o){an(e,r)}}if(e instanceof HTMLFormElement){ie(e.elements,function(e){if(t.indexOf(e)>=0){cn(e.name,un(e),n)}else{t.push(e)}if(o){an(e,r)}});new FormData(e).forEach(function(e,t){if(e instanceof File&&e.name===""){return}ln(t,e,n)})}}function an(e,t){const n=e;if(n.willValidate){ae(n,"htmx:validation:validate");if(!n.checkValidity()){if(ae(n,"htmx:validation:failed",{message:n.validationMessage,validity:n.validity})&&!t.length&&Q.config.reportValidityOfForms){n.reportValidity()}t.push({elt:n,message:n.validationMessage,validity:n.validity})}}}function hn(n,e){for(const t of e.keys()){n.delete(t)}e.forEach(function(e,t){n.append(t,e)});return n}function dn(e,t){const n=[];const r=new FormData;const o=new FormData;const i=[];const s=oe(e);if(s.lastButtonClicked&&!se(s.lastButtonClicked)){s.lastButtonClicked=null}let l=e instanceof HTMLFormElement&&e.noValidate!==true||a(e,"hx-validate")==="true";if(s.lastButtonClicked){l=l&&s.lastButtonClicked.formNoValidate!==true}if(t!=="get"){fn(n,o,i,Lt(e),l)}fn(n,r,i,e,l);if(s.lastButtonClicked||e.tagName==="BUTTON"||e.tagName==="INPUT"&&ee(e,"type")==="submit"){const u=s.lastButtonClicked||e;const f=ee(u,"name");ln(f,u.value,o)}const c=we(e,"hx-include");ie(c,function(e){fn(n,r,i,ce(e),l);if(!h(e,"form")){ie(p(e).querySelectorAll(ot),function(e){fn(n,r,i,e,l)})}});hn(r,o);return{errors:i,formData:r,values:kn(r)}}function pn(e,t,n){if(e!==""){e+="&"}if(String(n)==="[object Object]"){n=JSON.stringify(n)}const r=encodeURIComponent(n);e+=encodeURIComponent(t)+"="+r;return e}function gn(e){e=Pn(e);let n="";e.forEach(function(e,t){n=pn(n,t,e)});return n}function mn(e,t,n){const r={"HX-Request":"true","HX-Trigger":ee(e,"id"),"HX-Trigger-Name":ee(e,"name"),"HX-Target":a(t,"id"),"HX-Current-URL":location.href};Cn(e,"hx-headers",false,r);if(n!==undefined){r["HX-Prompt"]=n}if(oe(e).boosted){r["HX-Boosted"]="true"}return r}function yn(n,e){const t=ne(e,"hx-params");if(t){if(t==="none"){return new FormData}else if(t==="*"){return n}else if(t.indexOf("not ")===0){ie(t.slice(4).split(","),function(e){e=e.trim();n.delete(e)});return n}else{const r=new FormData;ie(t.split(","),function(t){t=t.trim();if(n.has(t)){n.getAll(t).forEach(function(e){r.append(t,e)})}});return r}}else{return n}}function xn(e){return!!ee(e,"href")&&ee(e,"href").indexOf("#")>=0}function bn(e,t){const n=t||ne(e,"hx-swap");const r={swapStyle:oe(e).boosted?"innerHTML":Q.config.defaultSwapStyle,swapDelay:Q.config.defaultSwapDelay,settleDelay:Q.config.defaultSettleDelay};if(Q.config.scrollIntoViewOnBoost&&oe(e).boosted&&!xn(e)){r.show="top"}if(n){const s=X(n);if(s.length>0){for(let e=0;e0?o.join(":"):null;r.scroll=u;r.scrollTarget=i}else if(l.indexOf("show:")===0){const f=l.slice(5);var o=f.split(":");const a=o.pop();var i=o.length>0?o.join(":"):null;r.show=a;r.showTarget=i}else if(l.indexOf("focus-scroll:")===0){const h=l.slice("focus-scroll:".length);r.focusScroll=h=="true"}else if(e==0){r.swapStyle=l}else{R("Unknown modifier in hx-swap: "+l)}}}}return r}function vn(e){return ne(e,"hx-encoding")==="multipart/form-data"||h(e,"form")&&ee(e,"enctype")==="multipart/form-data"}function wn(t,n,r){let o=null;Vt(n,function(e){if(o==null){o=e.encodeParameters(t,r,n)}});if(o!=null){return o}else{if(vn(n)){return hn(new FormData,Pn(r))}else{return gn(r)}}}function Sn(e){return{tasks:[],elts:[e]}}function En(e,t){const n=e[0];const r=e[e.length-1];if(t.scroll){var o=null;if(t.scrollTarget){o=ce(ue(n,t.scrollTarget))}if(t.scroll==="top"&&(n||o)){o=o||n;o.scrollTop=0}if(t.scroll==="bottom"&&(r||o)){o=o||r;o.scrollTop=o.scrollHeight}if(typeof t.scroll==="number"){b().setTimeout(function(){window.scrollTo(0,t.scroll)},0)}}if(t.show){var o=null;if(t.showTarget){let e=t.showTarget;if(t.showTarget==="window"){e="body"}o=ce(ue(n,e))}if(t.show==="top"&&(n||o)){o=o||n;o.scrollIntoView({block:"start",behavior:Q.config.scrollBehavior})}if(t.show==="bottom"&&(r||o)){o=o||r;o.scrollIntoView({block:"end",behavior:Q.config.scrollBehavior})}}}function Cn(r,e,o,i,s){if(i==null){i={}}if(r==null){return i}const l=a(r,e);if(l){let e=l.trim();let t=o;if(e==="unset"){return null}if(e.indexOf("javascript:")===0){e=e.slice(11);t=true}else if(e.indexOf("js:")===0){e=e.slice(3);t=true}if(e.indexOf("{")!==0){e="{"+e+"}"}let n;if(t){n=On(r,function(){if(s){return Function("event","return ("+e+")").call(r,s)}else{return Function("return ("+e+")").call(r)}},{})}else{n=v(e)}for(const c in n){if(n.hasOwnProperty(c)){if(i[c]==null){i[c]=n[c]}}}}return Cn(ce(u(r)),e,o,i,s)}function On(e,t,n){if(Q.config.allowEval){return t()}else{fe(e,"htmx:evalDisallowedError");return n}}function Rn(e,t,n){return Cn(e,"hx-vars",true,n,t)}function Hn(e,t,n){return Cn(e,"hx-vals",false,n,t)}function Tn(e,t){return le(Rn(e,t),Hn(e,t))}function qn(t,n,r){if(r!==null){try{t.setRequestHeader(n,r)}catch(e){t.setRequestHeader(n,encodeURIComponent(r));t.setRequestHeader(n+"-URI-AutoEncoded","true")}}}function An(t){if(t.responseURL){try{const e=new URL(t.responseURL);return e.pathname+e.search}catch(e){fe(te().body,"htmx:badResponseUrl",{url:t.responseURL})}}}function H(e,t){return t.test(e.getAllResponseHeaders())}function Ln(t,n,r){t=t.toLowerCase();if(r){if(r instanceof Element||typeof r==="string"){return he(t,n,null,null,{targetOverride:w(r)||ve,returnPromise:true})}else{let e=w(r.target);if(r.target&&!e||r.source&&!e&&!w(r.source)){e=ve}return he(t,n,w(r.source),r.event,{handler:r.handler,headers:r.headers,values:r.values,targetOverride:e,swapOverride:r.swap,select:r.select,returnPromise:true})}}else{return he(t,n,null,null,{returnPromise:true})}}function Nn(e){const t=[];while(e){t.push(e);e=e.parentElement}return t}function In(e,t,n){const r=new URL(t,location.protocol!=="about:"?location.href:window.origin);const o=location.protocol!=="about:"?location.origin:window.origin;const i=o===r.origin;if(Q.config.selfRequestsOnly){if(!i){return false}}return ae(e,"htmx:validateUrl",le({url:r,sameHost:i},n))}function Pn(e){if(e instanceof FormData)return e;const t=new FormData;for(const n in e){if(e.hasOwnProperty(n)){if(e[n]&&typeof e[n].forEach==="function"){e[n].forEach(function(e){t.append(n,e)})}else if(typeof e[n]==="object"&&!(e[n]instanceof Blob)){t.append(n,JSON.stringify(e[n]))}else{t.append(n,e[n])}}}return t}function Dn(r,o,e){return new Proxy(e,{get:function(t,e){if(typeof e==="number")return t[e];if(e==="length")return t.length;if(e==="push"){return function(e){t.push(e);r.append(o,e)}}if(typeof t[e]==="function"){return function(){t[e].apply(t,arguments);r.delete(o);t.forEach(function(e){r.append(o,e)})}}if(t[e]&&t[e].length===1){return t[e][0]}else{return t[e]}},set:function(e,t,n){e[t]=n;r.delete(o);e.forEach(function(e){r.append(o,e)});return true}})}function kn(o){return new Proxy(o,{get:function(e,t){if(typeof t==="symbol"){const r=Reflect.get(e,t);if(typeof r==="function"){return function(){return r.apply(o,arguments)}}else{return r}}if(t==="toJSON"){return()=>Object.fromEntries(o)}if(t in e){if(typeof e[t]==="function"){return function(){return o[t].apply(o,arguments)}}}const n=o.getAll(t);if(n.length===0){return undefined}else if(n.length===1){return n[0]}else{return Dn(e,t,n)}},set:function(t,n,e){if(typeof n!=="string"){return false}t.delete(n);if(e&&typeof e.forEach==="function"){e.forEach(function(e){t.append(n,e)})}else if(typeof e==="object"&&!(e instanceof Blob)){t.append(n,JSON.stringify(e))}else{t.append(n,e)}return true},deleteProperty:function(e,t){if(typeof t==="string"){e.delete(t)}return true},ownKeys:function(e){return Reflect.ownKeys(Object.fromEntries(e))},getOwnPropertyDescriptor:function(e,t){return Reflect.getOwnPropertyDescriptor(Object.fromEntries(e),t)}})}function he(t,n,r,o,i,k){let s=null;let l=null;i=i!=null?i:{};if(i.returnPromise&&typeof Promise!=="undefined"){var e=new Promise(function(e,t){s=e;l=t})}if(r==null){r=te().body}const F=i.handler||Vn;const M=i.select||null;if(!se(r)){re(s);return e}const c=i.targetOverride||ce(Ee(r));if(c==null||c==ve){fe(r,"htmx:targetError",{target:ne(r,"hx-target")});re(l);return e}let u=oe(r);const f=u.lastButtonClicked;if(f){const A=ee(f,"formaction");if(A!=null){n=A}const L=ee(f,"formmethod");if(L!=null){if(de.includes(L.toLowerCase())){t=L}else{re(s);return e}}}const a=ne(r,"hx-confirm");if(k===undefined){const K=function(e){return he(t,n,r,o,i,!!e)};const G={target:c,elt:r,path:n,verb:t,triggeringEvent:o,etc:i,issueRequest:K,question:a};if(ae(r,"htmx:confirm",G)===false){re(s);return e}}let h=r;let d=ne(r,"hx-sync");let p=null;let X=false;if(d){const N=d.split(":");const I=N[0].trim();if(I==="this"){h=Se(r,"hx-sync")}else{h=ce(ue(r,I))}d=(N[1]||"drop").trim();u=oe(h);if(d==="drop"&&u.xhr&&u.abortable!==true){re(s);return e}else if(d==="abort"){if(u.xhr){re(s);return e}else{X=true}}else if(d==="replace"){ae(h,"htmx:abort")}else if(d.indexOf("queue")===0){const W=d.split(" ");p=(W[1]||"last").trim()}}if(u.xhr){if(u.abortable){ae(h,"htmx:abort")}else{if(p==null){if(o){const P=oe(o);if(P&&P.triggerSpec&&P.triggerSpec.queue){p=P.triggerSpec.queue}}if(p==null){p="last"}}if(u.queuedRequests==null){u.queuedRequests=[]}if(p==="first"&&u.queuedRequests.length===0){u.queuedRequests.push(function(){he(t,n,r,o,i)})}else if(p==="all"){u.queuedRequests.push(function(){he(t,n,r,o,i)})}else if(p==="last"){u.queuedRequests=[];u.queuedRequests.push(function(){he(t,n,r,o,i)})}re(s);return e}}const g=new XMLHttpRequest;u.xhr=g;u.abortable=X;const m=function(){u.xhr=null;u.abortable=false;if(u.queuedRequests!=null&&u.queuedRequests.length>0){const e=u.queuedRequests.shift();e()}};const B=ne(r,"hx-prompt");if(B){var y=prompt(B);if(y===null||!ae(r,"htmx:prompt",{prompt:y,target:c})){re(s);m();return e}}if(a&&!k){if(!confirm(a)){re(s);m();return e}}let x=mn(r,c,y);if(t!=="get"&&!vn(r)){x["Content-Type"]="application/x-www-form-urlencoded"}if(i.headers){x=le(x,i.headers)}const U=dn(r,t);let b=U.errors;const V=U.formData;if(i.values){hn(V,Pn(i.values))}const j=Pn(Tn(r,o));const v=hn(V,j);let w=yn(v,r);if(Q.config.getCacheBusterParam&&t==="get"){w.set("org.htmx.cache-buster",ee(c,"id")||"true")}if(n==null||n===""){n=location.href}const S=Cn(r,"hx-request");const $=oe(r).boosted;let E=Q.config.methodsThatUseUrlParams.indexOf(t)>=0;const C={boosted:$,useUrlParams:E,formData:w,parameters:kn(w),unfilteredFormData:v,unfilteredParameters:kn(v),headers:x,elt:r,target:c,verb:t,errors:b,withCredentials:i.credentials||S.credentials||Q.config.withCredentials,timeout:i.timeout||S.timeout||Q.config.timeout,path:n,triggeringEvent:o};if(!ae(r,"htmx:configRequest",C)){re(s);m();return e}n=C.path;t=C.verb;x=C.headers;w=Pn(C.parameters);b=C.errors;E=C.useUrlParams;if(b&&b.length>0){ae(r,"htmx:validation:halted",C);re(s);m();return e}const _=n.split("#");const z=_[0];const O=_[1];let R=n;if(E){R=z;const Z=!w.keys().next().done;if(Z){if(R.indexOf("?")<0){R+="?"}else{R+="&"}R+=gn(w);if(O){R+="#"+O}}}if(!In(r,R,C)){fe(r,"htmx:invalidPath",C);re(l);m();return e}g.open(t.toUpperCase(),R,true);g.overrideMimeType("text/html");g.withCredentials=C.withCredentials;g.timeout=C.timeout;if(S.noHeaders){}else{for(const D in x){if(x.hasOwnProperty(D)){const Y=x[D];qn(g,D,Y)}}}const H={xhr:g,target:c,requestConfig:C,etc:i,boosted:$,select:M,pathInfo:{requestPath:n,finalRequestPath:R,responsePath:null,anchor:O}};g.onload=function(){try{const t=Nn(r);H.pathInfo.responsePath=An(g);F(r,H);if(H.keepIndicators!==true){rn(T,q)}ae(r,"htmx:afterRequest",H);ae(r,"htmx:afterOnLoad",H);if(!se(r)){let e=null;while(t.length>0&&e==null){const n=t.shift();if(se(n)){e=n}}if(e){ae(e,"htmx:afterRequest",H);ae(e,"htmx:afterOnLoad",H)}}re(s)}catch(e){fe(r,"htmx:onLoadError",le({error:e},H));throw e}finally{m()}};g.onerror=function(){rn(T,q);fe(r,"htmx:afterRequest",H);fe(r,"htmx:sendError",H);re(l);m()};g.onabort=function(){rn(T,q);fe(r,"htmx:afterRequest",H);fe(r,"htmx:sendAbort",H);re(l);m()};g.ontimeout=function(){rn(T,q);fe(r,"htmx:afterRequest",H);fe(r,"htmx:timeout",H);re(l);m()};if(!ae(r,"htmx:beforeRequest",H)){re(s);m();return e}var T=tn(r);var q=nn(r);ie(["loadstart","loadend","progress","abort"],function(t){ie([g,g.upload],function(e){e.addEventListener(t,function(e){ae(r,"htmx:xhr:"+t,{lengthComputable:e.lengthComputable,loaded:e.loaded,total:e.total})})})});ae(r,"htmx:beforeSend",H);const J=E?null:wn(g,r,w);g.send(J);return e}function Fn(e,t){const n=t.xhr;let r=null;let o=null;if(H(n,/HX-Push:/i)){r=n.getResponseHeader("HX-Push");o="push"}else if(H(n,/HX-Push-Url:/i)){r=n.getResponseHeader("HX-Push-Url");o="push"}else if(H(n,/HX-Replace-Url:/i)){r=n.getResponseHeader("HX-Replace-Url");o="replace"}if(r){if(r==="false"){return{}}else{return{type:o,path:r}}}const i=t.pathInfo.finalRequestPath;const s=t.pathInfo.responsePath;const l=ne(e,"hx-push-url");const c=ne(e,"hx-replace-url");const u=oe(e).boosted;let f=null;let a=null;if(l){f="push";a=l}else if(c){f="replace";a=c}else if(u){f="push";a=s||i}if(a){if(a==="false"){return{}}if(a==="true"){a=s||i}if(t.pathInfo.anchor&&a.indexOf("#")===-1){a=a+"#"+t.pathInfo.anchor}return{type:f,path:a}}else{return{}}}function Mn(e,t){var n=new RegExp(e.code);return n.test(t.toString(10))}function Xn(e){for(var t=0;t`+`.${t}{opacity:0;visibility: hidden} `+`.${n} .${t}, .${n}.${t}{opacity:1;visibility: visible;transition: opacity 200ms ease-in}`+"")}}function Zn(){const e=te().querySelector('meta[name="htmx-config"]');if(e){return v(e.content)}else{return null}}function Yn(){const e=Zn();if(e){Q.config=le(Q.config,e)}}Gn(function(){Yn();Wn();let e=te().body;Mt(e);const t=te().querySelectorAll("[hx-trigger='restored'],[data-hx-trigger='restored']");e.addEventListener("htmx:abort",function(e){const t=e.target;const n=oe(t);if(n&&n.xhr){n.xhr.abort()}});const n=window.onpopstate?window.onpopstate.bind(window):null;window.onpopstate=function(e){if(e.state&&e.state.htmx){en();ie(t,function(e){ae(e,"htmx:restored",{document:te(),triggerEvent:ae})})}else{if(n){n(e)}}};b().setTimeout(function(){ae(e,"htmx:load",{});e=null},0)});return Q}(); \ No newline at end of file diff --git a/web/static/lib/tuicss/fonts/Perfect DOS VGA 437 Win.ttf b/web/static/lib/tuicss/fonts/Perfect DOS VGA 437 Win.ttf new file mode 100644 index 0000000000000000000000000000000000000000..d03b1c5e5780554a44cf7c8caf03d0da38d4de25 GIT binary patch literal 82676 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 literal 0 HcmV?d00001 diff --git a/web/static/lib/tuicss/fonts/Perfect DOS VGA 437.ttf b/web/static/lib/tuicss/fonts/Perfect DOS VGA 437.ttf new file mode 100644 index 0000000000000000000000000000000000000000..f5cbfc06fd489f01566cfaa1a41f5c260368d7b9 GIT binary patch literal 81192 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 literal 0 HcmV?d00001 diff --git a/web/static/lib/tuicss/fonts/dos437.txt b/web/static/lib/tuicss/fonts/dos437.txt new file mode 100644 index 0000000..d4860e2 --- /dev/null +++ b/web/static/lib/tuicss/fonts/dos437.txt @@ -0,0 +1,72 @@ + / +/(_____________ ____ +\ /______)\ | | +:\ | / \:| |:::::::::: : .. . : .. . . :. . + \_____| / | \| |______ +___ / ________ \... . . . +\______________ \ | | /.. . . . . . + \ |__| / +--x--x-----x----\______ |-/_____/-x--x-xx--x-- - -x -- - - -- - - - +. . . . . . . . . . . .\____|. . . . . . +------------------------------------------------------------------------------- +>> perfect dos vga 437 - general information >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> +------------------------------------------------------------------------------- + + "Perfect DOS VGA 437" and "Perfect DOS VGA 437 Win" are truetype fonts + designed to emulate the MS-DOS/Text mode standard font, used on VGA monitors, + with the 437 Codepage (standard US/International). This is a "bitmap" font, + meaning it emulates a bitmap font and can only be used at a given size (8 or + multiples of it like 16, 24, 32, etc). It's optimized for Flash too, so it + won't produce antialias if used at round positions. + + There are two fonts available. "Perfect DOS VGA 437" uses the original DOS + codepage 437. It should be used, for example, if you're opening DOS ASCII + files on notepad or another windows-based editor. Since it's faithful to the + original DOS codes, it won't accent correctly in windows ("" would produce + something different, not an "e" with an acute). + + There's also "Perfect DOS VGA 437 Win" which is the exactly same font adapted + to a windows codepage. This should use accented characters correctly but won't + work if you're opening a DOS-based text file. + + UPDATE: this is a new version, updated in august/2008. It has fixed leading + metrics for Mac systems. + +------------------------------------------------------------------------------- +>> perfect dos vga 437 - creation process >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> +------------------------------------------------------------------------------- + + This font was created to be used on a Flash-based ANSi viewer I'm working. To + create it, I created a small Quick Basic program to write all characters on + screen, + + CLS + FOR l = 0 TO 255 + charWrite 1 + (l MOD 20), 1 + (l \ 20) * 6 + (l MOD 2), LTRIM$(RTRIM$(STR$(l))) + CHR$(l) + NEXT + SUB charWrite (lin, col, char$) + DEF SEG = &HB800 + FOR i = 1 TO LEN(char$) + POKE ((lin - 1) * 160) + ((col - 2 + i) * 2), ASC(MID$(char$, i, 1)) + IF (i = LEN(char$)) THEN POKE ((lin - 1) * 160) + ((col - 2 + i) * 2) + 1, 113 + NEXT + END SUB + + Then captured the text screen using SCREEN THIEF (a very, very old screen + capture TSR program which converts text screens to images accurately). I then + recreated the font polygon by polygon on Fontlab, while looking at the image + on Photoshop. No conversion took place. + +------------------------------------------------------------------------------- +>> author >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> +------------------------------------------------------------------------------- + + zeh fernando remembers the old days. SMASH DAH FUCKING ENTAH. + + http://www.fatorcaos.com.br + + rorshack ^ maiden brazil + +------------------------------------------------------------------------------- +^zehPULLSdahTRICK^kudosOUTtoWHOkeepsITreal^smashDAHfuckingENTAH!!!^lowres4ever^ +------------------------------------------------------------------------------- diff --git a/web/static/lib/tuicss/images/bg-blue-black.png b/web/static/lib/tuicss/images/bg-blue-black.png new file mode 100644 index 0000000000000000000000000000000000000000..aa55706d4fc2a01a606f1c91cbaaedda135a476b GIT binary patch literal 166 zcmeAS@N?(olHy`uVBq!ia0vp^Od!m`1|*BN@u~nR#^NA%Cx&(BWL^R}Ea{HEjtmSN z`?>!lvI6;>1s;*b3=DinK$vl=HlH+5P_o1|q9iy!t)x7$D3zfgF*C13FE6!3!9>qM z&(O%3CHoCfk(j58V~9j}azaAHM|qDw=`4agK)|4Ojd}UawRf9=Di}On{an^LB{Ts5 Di0Ua8 literal 0 HcmV?d00001 diff --git a/web/static/lib/tuicss/images/bg-blue-white.png b/web/static/lib/tuicss/images/bg-blue-white.png new file mode 100644 index 0000000000000000000000000000000000000000..45409ed4487a5f274bd9b2d2519561339d4d3c63 GIT binary patch literal 168 zcmeAS@N?(olHy`uVBq!ia0vp^Od!m`1|*BN@u~nR#^NA%Cx&(BWL^R}Ea{HEjtmSN z`?>!lvI6;>1s;*b3=DinK$vl=HlH+5P_o1|q9iy!t)x7$D3zfgF*C13FE6!3!9>qM z&(O%3CHoCfk%Xs!lvI6;>1s;*b3=DinK$vl=HlH+5P_o1|q9iy!t)x7$D3zfgF*C13FE6!3!9>qM z&(O%3CHoCfk%XsdnzCR literal 0 HcmV?d00001 diff --git a/web/static/lib/tuicss/images/bg-cyan-white.png b/web/static/lib/tuicss/images/bg-cyan-white.png new file mode 100644 index 0000000000000000000000000000000000000000..41ce181372b25ec9aac9721da8d49c9373287e8d GIT binary patch literal 165 zcmeAS@N?(olHy`uVBq!ia0vp^Od!m`1|*BN@u~nR#^NA%Cx&(BWL^R}Ea{HEjtmSN z`?>!lvI6;>1s;*b3=DinK$vl=HlH+5P_o1|q9iy!t)x7$D3zfgF*C13FE6!3!9>qM z&(O%3CHoCfk*KGOV~9j}azez$NA?^BO&n}Mz>p=&$ literal 0 HcmV?d00001 diff --git a/web/static/lib/tuicss/images/bg-green-black.png b/web/static/lib/tuicss/images/bg-green-black.png new file mode 100644 index 0000000000000000000000000000000000000000..2f83f3c8398e007ed7ac47c90b41c203d98401ab GIT binary patch literal 168 zcmeAS@N?(olHy`uVBq!ia0vp^Od!m`1|*BN@u~nR#^NA%Cx&(BWL^R}Ea{HEjtmSN z`?>!lvI6;>1s;*b3=DinK$vl=HlH+5P_o1|q9iy!t)x7$D3zfgF*C13FE6!3!9>qM z&(O%3CHoCfk%Xs!lvI6;>1s;*b3=DinK$vl=HlH+5P_o1|q9iy!t)x7$D3zfgF*C13FE6!3!9>qM z&(O%3CHoCfk*KGOV~9j}azezx5ArM$jx5YTz>wg|xp3k8uri!lvI6;>1s;*b3=DinK$vl=HlH+5P_o1|q9iy!t)x7$D3zfgF*C13FE6!3!9>qM z&(O%3CHoCfk%Xszopr E01@OXQ~&?~ literal 0 HcmV?d00001 diff --git a/web/static/lib/tuicss/images/bg-orange-white.png b/web/static/lib/tuicss/images/bg-orange-white.png new file mode 100644 index 0000000000000000000000000000000000000000..8c82141e05d9084257b5d20ac79ab05b6d6d224c GIT binary patch literal 165 zcmeAS@N?(olHy`uVBq!ia0vp^Od!m`1|*BN@u~nR#^NA%Cx&(BWL^R}Ea{HEjtmSN z`?>!lvI6;>1s;*b3=DinK$vl=HlH+5P_o1|q9iy!t)x7$D3zfgF*C13FE6!3!9>qM z&(O%3CHoCfk*KGOV~9j}a)jWq5ArM$jx5YTz>wz4`F*X@|J6VR44$rjF6*2UngBVi BCrAJQ literal 0 HcmV?d00001 diff --git a/web/static/lib/tuicss/images/bg-purple-black.png b/web/static/lib/tuicss/images/bg-purple-black.png new file mode 100644 index 0000000000000000000000000000000000000000..240217f5de35d3f614d70b67c1376d8a9a0c9f23 GIT binary patch literal 168 zcmeAS@N?(olHy`uVBq!ia0vp^Od!m`1|*BN@u~nR#^NA%Cx&(BWL^R}Ea{HEjtmSN z`?>!lvI6;>1s;*b3=DinK$vl=HlH+5P_o1|q9iy!t)x7$D3zfgF*C13FE6!3!9>qM z&(O%3CHoCfk%XsT(6kL;P557)a196WH~00V>JKNkPCL#79TY8X6S{an^L HB{Ts58FnkZ literal 0 HcmV?d00001 diff --git a/web/static/lib/tuicss/images/bg-purple-white.png b/web/static/lib/tuicss/images/bg-purple-white.png new file mode 100644 index 0000000000000000000000000000000000000000..5ae0ca2ffc91db8605538260e858203a8758ee8c GIT binary patch literal 165 zcmeAS@N?(olHy`uVBq!ia0vp^Od!m`1|*BN@u~nR#^NA%Cx&(BWL^R}Ea{HEjtmSN z`?>!lvI6;>1s;*b3=DinK$vl=HlH+5P_o1|q9iy!t)x7$D3zfgF*C13FE6!3!9>qM z&(O%3CHoCfk*KGOV~9j}a>T(6kL)=NnmE{ifFbKBm*!lvI6;>1s;*b3=DinK$vl=HlH+5P_o1|q9iy!t)x7$D3zfgF*C13FE6!3!9>qM z&(O%3CHoCfk(j58V~9j}a>T&{ALcW5NIJ4G0|A4E8uM}suZ_(>6%3xPelF{r5}E*Z CASZhO literal 0 HcmV?d00001 diff --git a/web/static/lib/tuicss/images/bg-red-white.png b/web/static/lib/tuicss/images/bg-red-white.png new file mode 100644 index 0000000000000000000000000000000000000000..4470d9ba2d3909ecaf95eae8dadcc92438aa4926 GIT binary patch literal 165 zcmeAS@N?(olHy`uVBq!ia0vp^Od!m`1|*BN@u~nR#^NA%Cx&(BWL^R}Ea{HEjtmSN z`?>!lvI6;>1s;*b3=DinK$vl=HlH+5P_o1|q9iy!t)x7$D3zfgF*C13FE6!3!9>qM z&(O%3CHoCfk*KGOV~9j}a>T&{ALLmi99fuwfFa>6=fVQx@L-?<22WQ%mvv4FO#npJ BCkg-n literal 0 HcmV?d00001 diff --git a/web/static/lib/tuicss/images/bg-yellow-black.png b/web/static/lib/tuicss/images/bg-yellow-black.png new file mode 100644 index 0000000000000000000000000000000000000000..ace85f9d56e6d3e762a6354d34468ad5018d7d4c GIT binary patch literal 168 zcmeAS@N?(olHy`uVBq!ia0vp^Od!m`1|*BN@u~nR#^NA%Cx&(BWL^R}Ea{HEjtmSN z`?>!lvI6;>1s;*b3=DinK$vl=HlH+5P_o1|q9iy!t)x7$D3zfgF*C13FE6!3!9>qM z&(O%3CHoCfk%XsT}_hxW|OhwI%04jwpgfPuki8H@j!lvI6;>1s;*b3=DinK$vl=HlH+5P_o1|q9iy!t)x7$D3zfgF*C13FE6!3!9>qM z&(O%3CHoCfk*KGOV~9j}a>T}_hxQx>O&n}Mz>uBG!lvI6;>1s;*b3=DinK$vl=HlH+5P_o1|q9iy!t)x7$D3zfgF*C13FE6!3!9>qM z&(O%3CHoCfk(j58V~9j}a!NwP$N7vLGaOi$fq+4RfpK+Z(Ox5<3I!lvI6;>1s;*b3=DinK$vl=HlH+5P_o1|q9iy!t)x7$D3zfgF*C13FE6!3!9>qM z&(O%3CHoCfk%Xs!lvI6;>1s;*b3=DinK$vl=HlH+5P_o1|q9iy!t)x7$D3zfgF*C13FE6!3!9>qM z&(O%3CHoCfk+`ReV~9j}azaAH$N7n@hwBx1mBRk8Gnh_coBLlW*9WMC!PC{xWt~$( F69C4vDX{!lvI6;>1s;*b3=DinK$vl=HlH+5P_o1|q9iy!t)x7$D3zfgF*C13FE6!3!9>qM z&(O%3CHoCfk+`ReV~9j}azaAH$9h+Z!}V+i2RA&jXRvi+_xv#1+aIWe!PC{xWt~$( F69CqcDp~*l literal 0 HcmV?d00001 diff --git a/web/static/lib/tuicss/images/scroll-purple.png b/web/static/lib/tuicss/images/scroll-purple.png new file mode 100644 index 0000000000000000000000000000000000000000..67a0550bcbd4b3b5baa794caf504d945bd8bd093 GIT binary patch literal 168 zcmeAS@N?(olHy`uVBq!ia0vp^Od!m`1|*BN@u~nR#^NA%Cx&(BWL^R}Ea{HEjtmSN z`?>!lvI6;>1s;*b3=DinK$vl=HlH+5P_o1|q9iy!t)x7$D3zfgF*C13FE6!3!9>qM z&(O%3CHoCfk%Xs!lvI6;>1s;*b3=DinK$vl=HlH+5P_o1|q9iy!t)x7$D3zfgF*C13FE6!3!9>qM z&(O%3CHoCfk+`ReV~9j}azaAH$9h)g!}V+i2RA&jXE1xhHn(k)oB>b?gQu&X%Q~lo FCIHjBDo_9b literal 0 HcmV?d00001 diff --git a/web/static/lib/tuicss/images/scroll-white.png b/web/static/lib/tuicss/images/scroll-white.png new file mode 100644 index 0000000000000000000000000000000000000000..c972a5e2fad8dc9926510038770df249794cc1ec GIT binary patch literal 168 zcmeAS@N?(olHy`uVBq!ia0vp^Od!m`1|*BN@u~nR#^NA%Cx&(BWL^R}Ea{HEjtmSN z`?>!lvI6;>1s;*b3=DinK$vl=HlH+5P_o1|q9iy!t)x7$D3zfgF*C13FE6!3!9>qM z&(O%3CHoCfk%Xs`VEHY7Zstm$8U{~SKbLh* G2~7arUMao+ literal 0 HcmV?d00001 diff --git a/web/static/lib/tuicss/images/scroll-yellow.png b/web/static/lib/tuicss/images/scroll-yellow.png new file mode 100644 index 0000000000000000000000000000000000000000..e1a915c284f8fdf5d9acf5ef800f8c7b222c39fe GIT binary patch literal 167 zcmeAS@N?(olHy`uVBq!ia0vp^Od!m`1|*BN@u~nR#^NA%Cx&(BWL^R}Ea{HEjtmSN z`?>!lvI6;>1s;*b3=DinK$vl=HlH+5P_o1|q9iy!t)x7$D3zfgF*C13FE6!3!9>qM z&(O%3CHoCfk+`ReV~9j}azaAH$NHmOZU1=^ni7xJGdRbvzdb0&lnzwF;OXk;vd$@? F2>|9%D!l*z literal 0 HcmV?d00001 diff --git a/web/static/lib/tuicss/tuicss.css b/web/static/lib/tuicss/tuicss.css new file mode 100644 index 0000000..bde8521 --- /dev/null +++ b/web/static/lib/tuicss/tuicss.css @@ -0,0 +1,2704 @@ +@charset "UTF-8"; +/* Styles */ /* Font (Options: 'Lucida Console' or 'DOS') */ +/* Characters */ +/* Theme */ +/* Responsive */ +/* Scrool */ +/* Grid */ +@font-face { + font-family: "DOS"; + src: url("./fonts/Perfect DOS VGA 437 Win.ttf"); +} +/* Global Definitions */ +html { + font-family: "Lucida Console", "monospace"; + font-size: 18px; + box-sizing: border-box; +} + +body { + margin: 0px; +} + +*, *:before, *:after { + font-family: inherit; + font-size: inherit; + box-sizing: inherit; +} + +ul { + margin: 0px; + padding: 0px; + list-style-type: none; +} + +ul li { + list-style-type: none; +} + +ul li a { + display: block; +} + +a { + color: inherit; + text-decoration: none; +} + +span { + margin: 0px; +} + +hr { + border: none; + border-bottom: 2px solid rgb(255, 255, 255); +} + +input, select, textarea { + width: 200px; +} + +/* Font (Options: 'Lucida Console' or 'DOS') */ +/* Characters */ +/* Theme */ +/* Responsive */ +/* Scrool */ +/* Grid */ +@media only screen and (max-width : 600px) { + .hide-on-small-only, .hide-on-small-and-down { + display: none !important; + } +} + +@media only screen and (max-width : 992px) { + .hide-on-med-and-down { + display: none !important; + } +} + +@media only screen and (min-width : 601px) { + .hide-on-med-and-up { + display: none !important; + } +} + +@media only screen and (min-width: 600px) and (max-width: 992px) { + .hide-on-med-only { + display: none !important; + } +} + +@media only screen and (min-width : 993px) { + .hide-on-large-only { + display: none !important; + } +} + +@media only screen and (min-width : 1201px) { + .hide-on-extra-large-only { + display: none !important; + } +} + +@media only screen and (min-width : 1201px) { + .show-on-extra-large { + display: block !important; + } +} + +@media only screen and (min-width : 993px) { + .show-on-large { + display: block !important; + } +} + +@media only screen and (min-width: 600px) and (max-width: 992px) { + .show-on-medium { + display: block !important; + } +} + +@media only screen and (max-width : 600px) { + .show-on-small { + display: block !important; + } +} + +@media only screen and (min-width : 601px) { + .show-on-medium-and-up { + display: block !important; + } +} + +@media only screen and (max-width : 992px) { + .show-on-medium-and-down { + display: block !important; + } +} + +/* Font (Options: 'Lucida Console' or 'DOS') */ +/* Characters */ +/* Theme */ +/* Responsive */ +/* Scrool */ +/* Grid */ +/* Theme */ +.primary { + background-color: rgb(0, 0, 168); +} + +.primary-text { + color: rgb(0, 0, 168); +} + +.primary-border { + border-color: rgb(0, 0, 168); +} + +.primary-hover:hover { + background-color: rgb(0, 0, 168); +} + +.primary-text-hover:hover { + color: rgb(0, 0, 168); +} + +.primary-border-hover:hover { + border-color: rgb(0, 0, 168); +} + +.secondary { + background-color: rgb(168, 168, 168); +} + +.secondary-text { + color: rgb(168, 168, 168); +} + +.secondary-border { + border-color: rgb(168, 168, 168); +} + +.secondary-hover:hover { + background-color: rgb(168, 168, 168); +} + +.secondary-text-hover:hover { + color: rgb(168, 168, 168); +} + +.secondary-border-hover:hover { + border-color: rgb(168, 168, 168); +} + +.success { + background-color: rgb(0, 168, 0); +} + +.success-text { + color: rgb(0, 168, 0); +} + +.success-border { + border-color: rgb(0, 168, 0); +} + +.success-hover:hover { + background-color: rgb(0, 168, 0); +} + +.success-text-hover:hover { + color: rgb(0, 168, 0); +} + +.success-border-hover:hover { + border-color: rgb(0, 168, 0); +} + +.danger { + background-color: rgb(168, 0, 0); +} + +.danger-text { + color: rgb(168, 0, 0); +} + +.danger-border { + border-color: rgb(168, 0, 0); +} + +.danger-hover:hover { + background-color: rgb(168, 0, 0); +} + +.danger-text-hover:hover { + color: rgb(168, 0, 0); +} + +.danger-border-hover:hover { + border-color: rgb(168, 0, 0); +} + +.warning { + background-color: rgb(168, 168, 0); +} + +.warning-text { + color: rgb(168, 168, 0); +} + +.warning-border { + border-color: rgb(168, 168, 0); +} + +.warning-hover:hover { + background-color: rgb(168, 168, 0); +} + +.warning-text-hover:hover { + color: rgb(168, 168, 0); +} + +.warning-border-hover:hover { + border-color: rgb(168, 168, 0); +} + +.info { + background-color: rgb(0, 168, 168); +} + +.info-text { + color: rgb(0, 168, 168); +} + +.info-border { + border-color: rgb(0, 168, 168); +} + +.info-hover:hover { + background-color: rgb(0, 168, 168); +} + +.info-text-hover:hover { + color: rgb(0, 168, 168); +} + +.info-border-hover:hover { + border-color: rgb(0, 168, 168); +} + +/* 168 */ +.black-168 { + background-color: rgb(0, 0, 0) !important; +} + +.blue-168 { + background-color: rgb(0, 0, 168) !important; +} + +.green-168 { + background-color: rgb(0, 168, 0) !important; +} + +.cyan-168 { + background-color: rgb(0, 168, 168) !important; +} + +.red-168 { + background-color: rgb(168, 0, 0) !important; +} + +.purple-168 { + background-color: rgb(168, 0, 168) !important; +} + +.yellow-168 { + background-color: rgb(168, 168, 0) !important; +} + +.white-168 { + background-color: rgb(168, 168, 168) !important; +} + +.orange-168 { + background-color: rgb(168, 86, 0) !important; +} + +.black-168-text { + color: rgb(0, 0, 0) !important; +} + +.blue-168-text { + color: rgb(0, 0, 168) !important; +} + +.green-168-text { + color: rgb(0, 168, 0) !important; +} + +.cyan-168-text { + color: rgb(0, 168, 168) !important; +} + +.red-168-text { + color: rgb(168, 0, 0) !important; +} + +.purple-168-text { + color: rgb(168, 0, 168) !important; +} + +.yellow-168-text { + color: rgb(168, 168, 0) !important; +} + +.white-168-text { + color: rgb(168, 168, 168) !important; +} + +.orange-168-text { + color: rgb(168, 86, 0) !important; +} + +.black-168-border { + border-color: rgb(0, 0, 0) !important; +} + +.blue-168-border { + border-color: rgb(0, 0, 168) !important; +} + +.green-168-border { + border-color: rgb(0, 168, 0) !important; +} + +.cyan-168-border { + border-color: rgb(0, 168, 168) !important; +} + +.red-168-border { + border-color: rgb(168, 0, 0) !important; +} + +.purple-168-border { + border-color: rgb(168, 0, 168) !important; +} + +.yellow-168-border { + border-color: rgb(168, 168, 0) !important; +} + +.white-168-border { + border-color: rgb(168, 168, 168) !important; +} + +.orange-168-border { + border-color: rgb(168, 86, 0) !important; +} + +.black-168-hover:hover { + background-color: rgb(0, 0, 0) !important; +} + +.blue-168-hover:hover { + background-color: rgb(0, 0, 168) !important; +} + +.green-168-hover:hover { + background-color: rgb(0, 168, 0) !important; +} + +.cyan-168-hover:hover { + background-color: rgb(0, 168, 168) !important; +} + +.red-168-hover:hover { + background-color: rgb(168, 0, 0) !important; +} + +.purple-168-hover:hover { + background-color: rgb(168, 0, 168) !important; +} + +.yellow-168-hover:hover { + background-color: rgb(168, 168, 0) !important; +} + +.white-168-hover:hover { + background-color: rgb(168, 168, 168) !important; +} + +.orange-168-hover:hover { + background-color: rgb(168, 86, 0) !important; +} + +.black-168-text-hover:hover { + color: rgb(0, 0, 0) !important; +} + +.blue-168-text-hover:hover { + color: rgb(0, 0, 168) !important; +} + +.green-168-text-hover:hover { + color: rgb(0, 168, 0) !important; +} + +.cyan-168-text-hover:hover { + color: rgb(0, 168, 168) !important; +} + +.red-168-text-hover:hover { + color: rgb(168, 0, 0) !important; +} + +.purple-168-text-hover:hover { + color: rgb(168, 0, 168) !important; +} + +.yellow-168-text-hover:hover { + color: rgb(168, 168, 0) !important; +} + +.white-168-text-hover:hover { + color: rgb(168, 168, 168) !important; +} + +.orange-168-text-hover:hover { + color: rgb(168, 86, 0) !important; +} + +.black-168-border-hover:hover { + border-color: rgb(0, 0, 0) !important; +} + +.blue-168-border-hover:hover { + border-color: rgb(0, 0, 168) !important; +} + +.green-168-border-hover:hover { + border-color: rgb(0, 168, 0) !important; +} + +.cyan-168-border-hover:hover { + border-color: rgb(0, 168, 168) !important; +} + +.red-168-border-hover:hover { + border-color: rgb(168, 0, 0) !important; +} + +.purple-168-border-hover:hover { + border-color: rgb(168, 0, 168) !important; +} + +.yellow-168-border-hover:hover { + border-color: rgb(168, 168, 0) !important; +} + +.white-168-border-hover:hover { + border-color: rgb(168, 168, 168) !important; +} + +.orange-168-border-hover:hover { + border-color: rgb(168, 86, 0) !important; +} + +/* 255 */ +.black-255 { + background-color: rgb(0, 0, 0) !important; +} + +.blue-255 { + background-color: rgb(0, 0, 255) !important; +} + +.green-255 { + background-color: rgb(0, 255, 0) !important; +} + +.cyan-255 { + background-color: rgb(0, 255, 255) !important; +} + +.red-255 { + background-color: rgb(255, 0, 0) !important; +} + +.purple-255 { + background-color: rgb(255, 0, 255) !important; +} + +.yellow-255 { + background-color: rgb(255, 255, 0) !important; +} + +.white-255 { + background-color: rgb(255, 255, 255) !important; +} + +.orange-255 { + background-color: rgb(255, 168, 0) !important; +} + +.black-255-text { + color: rgb(0, 0, 0) !important; +} + +.blue-255-text { + color: rgb(0, 0, 255) !important; +} + +.green-255-text { + color: rgb(0, 255, 0) !important; +} + +.cyan-255-text { + color: rgb(0, 255, 255) !important; +} + +.red-255-text { + color: rgb(255, 0, 0) !important; +} + +.purple-255-text { + color: rgb(255, 0, 255) !important; +} + +.yellow-255-text { + color: rgb(255, 255, 0) !important; +} + +.white-255-text { + color: rgb(255, 255, 255) !important; +} + +.orange-255-text { + color: rgb(255, 168, 0) !important; +} + +.black-255-border { + border-color: rgb(0, 0, 0) !important; +} + +.blue-255-border { + border-color: rgb(0, 0, 255) !important; +} + +.green-255-border { + border-color: rgb(0, 255, 0) !important; +} + +.cyan-255-border { + border-color: rgb(0, 255, 255) !important; +} + +.red-255-border { + border-color: rgb(255, 0, 0) !important; +} + +.purple-255-border { + border-color: rgb(255, 0, 255) !important; +} + +.yellow-255-border { + border-color: rgb(255, 255, 0) !important; +} + +.white-255-border { + border-color: rgb(255, 255, 255) !important; +} + +.orange-255-border { + border-color: rgb(255, 168, 0) !important; +} + +.black-255-hover:hover { + background-color: rgb(0, 0, 0) !important; +} + +.blue-255-hover:hover { + background-color: rgb(0, 0, 255) !important; +} + +.green-255-hover:hover { + background-color: rgb(0, 255, 0) !important; +} + +.cyan-255-hover:hover { + background-color: rgb(0, 255, 255) !important; +} + +.red-255-hover:hover { + background-color: rgb(255, 0, 0) !important; +} + +.purple-255-hover:hover { + background-color: rgb(255, 0, 255) !important; +} + +.yellow-255-hover:hover { + background-color: rgb(255, 255, 0) !important; +} + +.white-255-hover:hover { + background-color: rgb(255, 255, 255) !important; +} + +.orange-255-hover:hover { + background-color: rgb(255, 168, 0) !important; +} + +.black-255-text-hover:hover { + color: rgb(0, 0, 0) !important; +} + +.blue-255-text-hover:hover { + color: rgb(0, 0, 255) !important; +} + +.green-255-text-hover:hover { + color: rgb(0, 255, 0) !important; +} + +.cyan-255-text-hover:hover { + color: rgb(0, 255, 255) !important; +} + +.red-255-text-hover:hover { + color: rgb(255, 0, 0) !important; +} + +.purple-255-text-hover:hover { + color: rgb(255, 0, 255) !important; +} + +.yellow-255-text-hover:hover { + color: rgb(255, 255, 0) !important; +} + +.white-255-text-hover:hover { + color: rgb(255, 255, 255) !important; +} + +.orange-255-text-hover:hover { + color: rgb(255, 168, 0) !important; +} + +.black-255-border-hover:hover { + border-color: rgb(0, 0, 0) !important; +} + +.blue-255-border-hover:hover { + border-color: rgb(0, 0, 255) !important; +} + +.green-255-border-hover:hover { + border-color: rgb(0, 255, 0) !important; +} + +.cyan-255-border-hover:hover { + border-color: rgb(0, 255, 255) !important; +} + +.red-255-border-hover:hover { + border-color: rgb(255, 0, 0) !important; +} + +.purple-255-border-hover:hover { + border-color: rgb(255, 0, 255) !important; +} + +.yellow-255-border-hover:hover { + border-color: rgb(255, 255, 0) !important; +} + +.white-255-border-hover:hover { + border-color: rgb(255, 255, 255) !important; +} + +.orange-255-border-hover:hover { + border-color: rgb(255, 168, 0) !important; +} + +/* Misc */ +.black { + background-color: black !important; +} + +.black-text { + color: black !important; +} + +.black-border { + border-color: black !important; +} + +.black-hover:hover { + background-color: black !important; +} + +.black-text-hover:hover { + color: black !important; +} + +.black-border-hover:hover { + border-color: black !important; +} + +.white { + background-color: white !important; +} + +.white-text { + color: white !important; +} + +.white-border { + border-color: white !important; +} + +.white-hover:hover { + background-color: white !important; +} + +.white-text-hover:hover { + color: white !important; +} + +.white-border-hover:hover { + border-color: white !important; +} + +.left { + float: left !important; +} + +.right { + float: right !important; +} + +.center { + text-align: center; +} + +.left-align { + text-align: left; +} + +.right-align { + text-align: right; +} + +.center-align { + text-align: center; +} + +.full-width { + width: 100% !important; +} + +.full-height { + height: 100% !important; +} + +.inline { + display: inline !important; +} + +.inline-block { + display: inline-block !important; +} + +.block { + display: block !important; +} + +.valign-top { + vertical-align: top !important; +} + +.valign-middle { + vertical-align: middle !important; +} + +.valign-bottom { + vertical-align: bottom !important; +} + +.fixed { + position: fixed !important; +} + +.absolute { + position: absolute !important; +} + +.relative { + position: relative !important; +} + +.static { + position: static !important; +} + +.no-shadow { + box-shadow: none !important; +} + +.no-padding { + padding: 0px !important; +} + +.no-border { + border: none !important; +} + +.content { + padding: 12px; +} + +.disable-select { + user-select: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; +} + +.cursor-pointer { + cursor: pointer !important; +} + +.cursor-default { + cursor: default !important; +} + +.disabled { + cursor: not-allowed !important; +} + +/* Components */ +.tui-button { + display: inline-block; + outline: 0; + padding: 1px 10px; + background-color: rgb(0, 168, 0); + color: black; + border: none; + cursor: pointer; + text-align: center; + box-shadow: 10px 10px black; + border-radius: 0px; + user-select: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; +} +.tui-button.disabled { + text-decoration: line-through; +} + +.tui-button:active { + background-color: rgb(0, 168, 168) !important; + color: black !important; + box-shadow: none !important; +} + +.tui-button:focus { + color: rgb(0, 255, 255) !important; +} + +input[type=button] { + width: initial; +} + +/* Font (Options: 'Lucida Console' or 'DOS') */ +/* Characters */ +/* Theme */ +/* Responsive */ +/* Scrool */ +/* Grid */ +.tui-checkbox { + display: block; + position: relative; + cursor: pointer; + color: white; + padding-left: 30px; + user-select: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; +} +.tui-checkbox.disabled { + color: rgb(168, 168, 168); +} + +.tui-checkbox input { + position: absolute; + opacity: 0; + cursor: pointer; + top: 0px; + left: 0px; + pointer-events: none; +} + +.tui-checkbox span { + position: absolute; + width: 10px; + height: 10px; + cursor: pointer; + top: 0px; + left: 0px; +} + +.tui-checkbox input:checked ~ span::after { + content: "[√]"; + color: rgb(0, 255, 255); +} + +.tui-checkbox input:not(checked) ~ span::after { + content: "[ ]"; +} + +.tui-divider { + border-bottom: 2px solid rgb(255, 255, 255); + display: block; +} + +.tui-black-divider { + border-bottom: 2px solid rgb(0, 0, 0); + display: block; +} + +.tui-dropdown { + position: relative; + display: inline-block; + cursor: pointer; + user-select: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; +} + +.tui-dropdown-content { + display: none; + position: absolute; + background-color: rgb(168, 168, 168); + min-width: 200px; + padding: 6px; + z-index: 9; +} + +.tui-dropdown-content ul { + border: 2px black solid; +} + +.tui-dropdown-content ul li { + display: block !important; + margin: 6px; +} + +.tui-dropdown-content ul li a:hover { + background-color: rgb(0, 168, 0); +} + +.tui-dropdown:hover > .tui-dropdown-content:first-of-type { + display: block; +} + +.tui-fieldset { + border: 6px white double; + padding: 12px; + background-color: inherit; + margin-bottom: 6px; +} +.tui-fieldset.no-legend { + margin-top: 6px; +} + +.tui-input-fieldset { + border-top: 6px white double; + border-bottom: 6px white double; + border-left: 2px white solid; + border-right: 2px white solid; + padding: 5px; + background-color: inherit; +} + +.tui-input-fieldset legend { + color: white; +} + +.tui-input-fieldset:hover { + border-color: yellow; +} + +.tui-input-fieldset:hover legend { + color: yellow; +} + +.tui-fieldset-button { + position: absolute; + top: 0px; + right: 16px; + color: white; + background-color: inherit; + z-index: 2; + border: none; + cursor: pointer; + outline: 0; + padding: 2px; + user-select: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; +} +.tui-fieldset-button.left { + right: initial; + left: 16px !important; +} +.tui-fieldset-button.bottom { + bottom: 0px; + top: initial; +} + +.tui-fieldset-text { + position: absolute; + bottom: 0px; + left: 16px; + color: white; + background-color: inherit; + z-index: 2; + padding: 2px; +} +.tui-fieldset-text.right { + left: initial; + right: 16px; +} +.tui-fieldset-text.top { + top: 0px; + bottom: initial; +} + +.tui-fieldset-button::before { + content: "["; +} + +.tui-fieldset-button::after { + content: "]"; +} + +.tui-fieldset-button:active { + color: rgb(0, 255, 255) !important; +} + +.tui-input { + background-color: rgb(0, 0, 0); + color: white; + outline: 0; + border: none; + border-radius: 0px; +} +.tui-input.disabled { + background-color: rgb(168, 168, 168); + color: black; +} + +.tui-input:focus { + background-color: rgb(255, 255, 0) !important; + color: black !important; +} + +.tui-nav { + width: 100%; + background-color: rgb(168, 168, 168); + padding: 0px 2px; + z-index: 9; + display: block; + position: fixed; +} + +.tui-nav ul li { + display: inline-block; + margin-left: 10px; + padding: 1px 3px; +} + +.tui-nav ul li a { + display: block; + user-select: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; +} + +.tui-nav ul li:hover { + background-color: rgb(0, 168, 0); +} + +.tui-panel { + background-color: rgb(0, 0, 168); + display: inline-block; + color: white; + box-shadow: 10px 10px black; +} + +.tui-panel-content { + padding: 12px; +} + +.tui-panel-header { + padding-top: 2px; + display: block; + background: white; + text-align: center; +} + +.tui-progress-bar { + display: block; + position: relative; + height: 20px; + width: 200px; + background-color: rgb(0, 168, 168); + overflow: hidden; +} + +.tui-progress { + position: absolute; + left: 0px; + background-color: rgb(0, 255, 255); + height: 100%; + display: inline-block; +} + +.tui-progress-bar .tui-indeterminate { + position: absolute; + left: 0px; + background-color: rgb(0, 255, 255); + height: 20px; + width: 20px; + display: inline-block; + animation: indeterminate 1s backwards; + animation-iteration-count: infinite; + animation-timing-function: linear; +} + +.tui-progress-label { + position: absolute; + top: 50%; + left: 50%; + transform: translateX(-50%) translateY(-50%); + z-index: 1; +} + +@keyframes indeterminate { + from { + margin-left: -10%; + } + to { + margin-left: 100%; + } +} +/* Font (Options: 'Lucida Console' or 'DOS') */ +/* Characters */ +/* Theme */ +/* Responsive */ +/* Scrool */ +/* Grid */ +.tui-radio { + display: block; + position: relative; + cursor: pointer; + color: white; + padding-left: 30px; + user-select: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; +} +.tui-radio.disabled { + color: rgb(168, 168, 168); +} + +.tui-radio input { + position: absolute; + opacity: 0; + cursor: pointer; + top: 0px; + left: 0px; + pointer-events: none; +} + +.tui-radio span { + position: absolute; + width: 10px; + height: 10px; + cursor: pointer; + top: 0px; + left: 0px; +} + +.tui-radio input:checked ~ span:after { + content: "(•)"; + color: rgb(0, 255, 255) !important; +} + +.tui-radio input:not(checked) ~ span:after { + content: "( )"; +} + +/* Font (Options: 'Lucida Console' or 'DOS') */ +/* Characters */ +/* Theme */ +/* Responsive */ +/* Scrool */ +/* Grid */ +/* Default */ +::-webkit-scrollbar { + width: 10px; +} + +::-webkit-scrollbar-track { + background-image: url(images/scroll-cyan.png); + background-repeat: repeat; +} + +::-webkit-scrollbar-thumb { + background-color: rgb(0, 168, 168); +} + +::-webkit-scrollbar-thumb:hover { + background-color: rgb(0, 168, 168); +} + +/* Styles */ +.tui-scroll-blue ::-webkit-scrollbar-track { + background-image: url(images/scroll-blue.png); +} +.tui-scroll-blue ::-webkit-scrollbar-thumb { + background-color: rgb(0, 0, 168); +} +.tui-scroll-blue ::-webkit-scrollbar-thumb:hover { + background-color: rgb(0, 0, 168); +} + +.tui-scroll-green ::-webkit-scrollbar-track { + background-image: url(images/scroll-green.png); +} +.tui-scroll-green ::-webkit-scrollbar-thumb { + background-color: rgb(0, 168, 0); +} +.tui-scroll-green ::-webkit-scrollbar-thumb:hover { + background-color: rgb(0, 168, 0); +} + +.tui-scroll-cyan ::-webkit-scrollbar-track { + background-image: url(images/scroll-cyan.png); +} +.tui-scroll-cyan ::-webkit-scrollbar-thumb { + background-color: rgb(0, 168, 168); +} +.tui-scroll-cyan ::-webkit-scrollbar-thumb:hover { + background-color: rgb(0, 168, 168); +} + +.tui-scroll-red ::-webkit-scrollbar-track { + background-image: url(images/scroll-red.png); +} +.tui-scroll-red ::-webkit-scrollbar-thumb { + background-color: rgb(168, 0, 0); +} +.tui-scroll-red ::-webkit-scrollbar-thumb:hover { + background-color: rgb(168, 0, 0); +} + +.tui-scroll-purple ::-webkit-scrollbar-track { + background-image: url(images/scroll-purple.png); +} +.tui-scroll-purple ::-webkit-scrollbar-thumb { + background-color: rgb(168, 0, 168); +} +.tui-scroll-purple ::-webkit-scrollbar-thumb:hover { + background-color: rgb(168, 0, 168); +} + +.tui-scroll-yellow ::-webkit-scrollbar-track { + background-image: url(images/scroll-yellow.png); +} +.tui-scroll-yellow ::-webkit-scrollbar-thumb { + background-color: rgb(168, 168, 0); +} +.tui-scroll-yellow ::-webkit-scrollbar-thumb:hover { + background-color: rgb(168, 168, 0); +} + +.tui-scroll-white ::-webkit-scrollbar-track { + background-image: url(images/scroll-white.png); +} +.tui-scroll-white ::-webkit-scrollbar-thumb { + background-color: rgb(168, 168, 168); +} +.tui-scroll-white ::-webkit-scrollbar-thumb:hover { + background-color: rgb(168, 168, 168); +} + +.tui-sidenav { + position: fixed; + top: 0px; + left: 0px; + background-color: rgb(0, 168, 168); + min-width: 200px; + box-shadow: 10px 10px black !important; + padding: 6px; + z-index: 10; + height: 100%; + z-index: 8; + display: none; +} +.tui-sidenav.right { + left: initial; + right: 0px; +} +.tui-sidenav.active { + display: block !important; +} + +.tui-sidenav ul { + margin-top: 20px; + border: 2px black solid; +} + +.tui-sidenav ul li { + display: block; + margin: 6px; +} + +.tui-sidenav ul li a { + display: block; + user-select: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; +} + +.tui-sidenav ul li:hover { + background-color: rgb(255, 255, 0); +} + +.tui-sidenav-button { + cursor: pointer; + user-select: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; +} + +.tui-statusbar { + width: 100%; + background-color: rgb(168, 168, 168); + padding: 0px 1px; + left: 0px; + bottom: 0px; + z-index: 9; + position: fixed; +} + +.tui-statusbar ul li { + display: inline-block; + margin-left: 10px; + padding: 2px 3px; +} + +.tui-statusbar ul li:active { + background-color: rgb(0, 0, 168); + color: white; +} + +.tui-statusbar ul li a { + user-select: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; +} + +.tui-statusbar-divider { + border-right: 2px black solid; + display: inline; + margin: 0px 3px; +} + +.tui-table { + border: 2px solid rgb(168, 168, 168); + padding: 5px; + border-collapse: collapse; +} +.tui-table.hovered-blue tbody tr:hover { + background-color: rgb(0, 0, 255) !important; + color: black; +} +.tui-table.hovered-green tbody tr:hover { + background-color: rgb(0, 255, 0) !important; + color: black; +} +.tui-table.hovered-cyan tbody tr:hover { + background-color: rgb(0, 255, 255) !important; + color: black; +} +.tui-table.hovered-red tbody tr:hover { + background-color: rgb(255, 0, 0) !important; + color: white; +} +.tui-table.hovered-purple tbody tr:hover { + background-color: rgb(255, 0, 255) !important; + color: white; +} +.tui-table.hovered-yellow tbody tr:hover { + background-color: rgb(255, 255, 0) !important; + color: black; +} +.tui-table.hovered-white tbody tr:hover { + background-color: rgb(255, 255, 255) !important; + color: black; +} +.tui-table.hovered-orange tbody tr:hover { + background-color: rgb(255, 168, 0) !important; + color: black; +} +.tui-table.hovered tbody tr:hover { + background-color: rgb(0, 255, 255) !important; + color: black; +} +.tui-table.striped-blue tbody tr:nth-child(even) { + background-color: rgb(0, 0, 168); +} +.tui-table.striped-green tbody tr:nth-child(even) { + background-color: rgb(0, 168, 0); +} +.tui-table.striped-cyan tbody tr:nth-child(even) { + background-color: rgb(0, 168, 168); +} +.tui-table.striped-red tbody tr:nth-child(even) { + background-color: rgb(168, 0, 0); +} +.tui-table.striped-purple tbody tr:nth-child(even) { + background-color: rgb(168, 0, 168); +} +.tui-table.striped-yellow tbody tr:nth-child(even) { + background-color: rgb(168, 168, 0); +} +.tui-table.striped-white tbody tr:nth-child(even) { + background-color: rgb(168, 168, 168); + color: black; +} +.tui-table.striped-orange tbody tr:nth-child(even) { + background-color: rgb(168, 86, 0); +} + +.tui-table tbody { + background-color: inherit; + color: white; +} + +.tui-table tbody tr td { + border-right: 2px solid rgb(168, 168, 168); + padding: 0px 2px; +} + +.tui-table thead { + background-color: inherit; + color: rgb(255, 255, 0); + text-align: center; +} + +.tui-table tfoot { + background-color: inherit; + color: rgb(255, 255, 0); + text-align: center; +} + +.tui-table-grid { + border-collapse: collapse; + width: 100%; +} + +.tui-table-grid thead tr td, +.tui-table-grid tbody tr td, +.tui-table-grid thead tr th, +.tui-table-grid tbody tr th { + border: 2px solid black; + padding: 10px; + vertical-align: top; +} + +.tui-tabs { + background-color: rgb(0, 0, 168); + width: 100%; + padding: 0px 10px 0px 10px; +} + +.tui-tabs ul li { + display: inline-block; +} + +.tui-tabs ul li a { + display: block; + user-select: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; +} + +.tui-tab { + padding: 2px 10px 0px 10px; + color: rgb(168, 168, 168); + cursor: pointer; +} +.tui-tab.active { + background-color: rgb(168, 168, 168); + color: rgb(0, 0, 168); +} +.tui-tab.disabled { + text-decoration: line-through; +} + +.tui-tab-content { + display: none; +} + +.tui-textarea { + background-color: inherit; + border: none; + padding: 0px; + color: rgb(255, 255, 0); + outline: none; +} +.tui-textarea.disabled { + background-color: rgb(168, 168, 168); + color: black; +} + +.tui-window { + background-color: rgb(0, 0, 168); + padding: 1px; + display: inline-block; + position: relative; + box-shadow: 10px 10px black; + color: white; +} + +.tui-screen-640-480 { + width: 640px; + height: 480px; +} + +.tui-screen-800-600 { + width: 800px; + height: 600px; +} + +.tui-screen-1024-768 { + width: 1024px; + height: 768px; +} + +.tui-screen-640-480, +.tui-screen-800-600, +.tui-screen-1024-768 { + position: relative; + overflow: hidden; +} +.tui-screen-640-480.bordered, +.tui-screen-800-600.bordered, +.tui-screen-1024-768.bordered { + border: 2px solid black; +} +.tui-screen-640-480.centered, +.tui-screen-800-600.centered, +.tui-screen-1024-768.centered { + margin: auto; + margin-top: 20px; +} + +.tui-datetime { + padding: 1px 0px 1px 0px; + margin-right: 10px; + float: right; +} + +.tui-shortcut { + float: right; +} + +.tui-shadow, .tui-shadow-1 { + box-shadow: 10px 10px black !important; +} + +.tui-shadow-2 { + box-shadow: 15px 15px black; +} + +.tui-shadow-3 { + box-shadow: 20px 20px black; +} + +.tui-shadow-4 { + box-shadow: 25px 25px black; +} + +.tui-shadow-5 { + box-shadow: 30px 30px black; +} + +.tui-shadow-left, .tui-shadow-left-1 { + box-shadow: -10px 10px black !important; +} + +.tui-shadow-left-2 { + box-shadow: -15px 15px black !important; +} + +.tui-shadow-left-3 { + box-shadow: -20px 20px black !important; +} + +.tui-shadow-left-4 { + box-shadow: -25px 25px black !important; +} + +.tui-shadow-left-5 { + box-shadow: -30px 30px black !important; +} + +.tui-no-shadow { + box-shadow: none !important; +} + +.tui-bg-blue-white { + background-image: url("./images/bg-blue-white.png"); + background-repeat: repeat; +} + +.tui-bg-blue-black { + background-image: url("./images/bg-blue-black.png"); + background-repeat: repeat; +} + +.tui-bg-green-white { + background-image: url("./images/bg-green-white.png"); + background-repeat: repeat; +} + +.tui-bg-green-black { + background-image: url("./images/bg-green-black.png"); + background-repeat: repeat; +} + +.tui-bg-cyan-white { + background-image: url("./images/bg-cyan-white.png"); + background-repeat: repeat; +} + +.tui-bg-cyan-black { + background-image: url("./images/bg-cyan-black.png"); + background-repeat: repeat; +} + +.tui-bg-red-white { + background-image: url("./images/bg-red-white.png"); + background-repeat: repeat; +} + +.tui-bg-red-black { + background-image: url("./images/bg-red-black.png"); + background-repeat: repeat; +} + +.tui-bg-purple-white { + background-image: url("./images/bg-purple-white.png"); + background-repeat: repeat; +} + +.tui-bg-purple-black { + background-image: url("./images/bg-purple-black.png"); + background-repeat: repeat; +} + +.tui-bg-yellow-white { + background-image: url("./images/bg-yellow-white.png"); + background-repeat: repeat; +} + +.tui-bg-yellow-black { + background-image: url("./images/bg-yellow-black.png"); + background-repeat: repeat; +} + +.tui-bg-orange-white { + background-image: url("./images/bg-orange-white.png"); + background-repeat: repeat; +} + +.tui-bg-orange-black { + background-image: url("./images/bg-orange-black.png"); + background-repeat: repeat; +} + +.tui-border-solid { + border-style: solid !important; + border-width: 2px !important; +} + +.tui-border-dashed { + border-style: dashed !important; + border-width: 2px !important; +} + +.tui-border-dotted { + border-style: dotted !important; + border-width: 2px !important; +} + +.tui-border-double { + border-style: double !important; + border-width: 6px !important; +} + +/* Font (Options: 'Lucida Console' or 'DOS') */ +/* Characters */ +/* Theme */ +/* Responsive */ +/* Scrool */ +/* Grid */ +.container { + margin: 0 auto; + max-width: 1280px; + width: 90%; +} + +@media only screen and (min-width : 601px) { + .container { + width: 85%; + } +} +@media only screen and (min-width : 993px) { + .container { + width: 70%; + } +} +.col .row { + margin-left: -0.75rem; + margin-right: -0.75rem; +} + +.section { + padding-top: 1rem; + padding-bottom: 1rem; +} +.section.no-pad { + padding: 0; +} +.section.no-pad-bot { + padding-bottom: 0; +} +.section.no-pad-top { + padding-top: 0; +} + +.row { + margin-left: auto; + margin-right: auto; + margin-bottom: 20px; +} +.row:after { + content: ""; + display: table; + clear: both; +} +.row .col { + float: left; + box-sizing: border-box; + padding: 0 0.75rem; + min-height: 1px; +} +.row .col[class*=push-], .row .col[class*=pull-] { + position: relative; +} +.row .col.s1 { + width: 8.3333333333%; + margin-left: auto; + left: auto; + right: auto; +} +.row .col.s2 { + width: 16.6666666667%; + margin-left: auto; + left: auto; + right: auto; +} +.row .col.s3 { + width: 25%; + margin-left: auto; + left: auto; + right: auto; +} +.row .col.s4 { + width: 33.3333333333%; + margin-left: auto; + left: auto; + right: auto; +} +.row .col.s5 { + width: 41.6666666667%; + margin-left: auto; + left: auto; + right: auto; +} +.row .col.s6 { + width: 50%; + margin-left: auto; + left: auto; + right: auto; +} +.row .col.s7 { + width: 58.3333333333%; + margin-left: auto; + left: auto; + right: auto; +} +.row .col.s8 { + width: 66.6666666667%; + margin-left: auto; + left: auto; + right: auto; +} +.row .col.s9 { + width: 75%; + margin-left: auto; + left: auto; + right: auto; +} +.row .col.s10 { + width: 83.3333333333%; + margin-left: auto; + left: auto; + right: auto; +} +.row .col.s11 { + width: 91.6666666667%; + margin-left: auto; + left: auto; + right: auto; +} +.row .col.s12 { + width: 100%; + margin-left: auto; + left: auto; + right: auto; +} +.row .col.offset-s1 { + margin-left: 8.3333333333%; +} +.row .col.pull-s1 { + right: 8.3333333333%; +} +.row .col.push-s1 { + left: 8.3333333333%; +} +.row .col.offset-s2 { + margin-left: 16.6666666667%; +} +.row .col.pull-s2 { + right: 16.6666666667%; +} +.row .col.push-s2 { + left: 16.6666666667%; +} +.row .col.offset-s3 { + margin-left: 25%; +} +.row .col.pull-s3 { + right: 25%; +} +.row .col.push-s3 { + left: 25%; +} +.row .col.offset-s4 { + margin-left: 33.3333333333%; +} +.row .col.pull-s4 { + right: 33.3333333333%; +} +.row .col.push-s4 { + left: 33.3333333333%; +} +.row .col.offset-s5 { + margin-left: 41.6666666667%; +} +.row .col.pull-s5 { + right: 41.6666666667%; +} +.row .col.push-s5 { + left: 41.6666666667%; +} +.row .col.offset-s6 { + margin-left: 50%; +} +.row .col.pull-s6 { + right: 50%; +} +.row .col.push-s6 { + left: 50%; +} +.row .col.offset-s7 { + margin-left: 58.3333333333%; +} +.row .col.pull-s7 { + right: 58.3333333333%; +} +.row .col.push-s7 { + left: 58.3333333333%; +} +.row .col.offset-s8 { + margin-left: 66.6666666667%; +} +.row .col.pull-s8 { + right: 66.6666666667%; +} +.row .col.push-s8 { + left: 66.6666666667%; +} +.row .col.offset-s9 { + margin-left: 75%; +} +.row .col.pull-s9 { + right: 75%; +} +.row .col.push-s9 { + left: 75%; +} +.row .col.offset-s10 { + margin-left: 83.3333333333%; +} +.row .col.pull-s10 { + right: 83.3333333333%; +} +.row .col.push-s10 { + left: 83.3333333333%; +} +.row .col.offset-s11 { + margin-left: 91.6666666667%; +} +.row .col.pull-s11 { + right: 91.6666666667%; +} +.row .col.push-s11 { + left: 91.6666666667%; +} +.row .col.offset-s12 { + margin-left: 100%; +} +.row .col.pull-s12 { + right: 100%; +} +.row .col.push-s12 { + left: 100%; +} +@media only screen and (min-width : 601px) { + .row .col.m1 { + width: 8.3333333333%; + margin-left: auto; + left: auto; + right: auto; + } + .row .col.m2 { + width: 16.6666666667%; + margin-left: auto; + left: auto; + right: auto; + } + .row .col.m3 { + width: 25%; + margin-left: auto; + left: auto; + right: auto; + } + .row .col.m4 { + width: 33.3333333333%; + margin-left: auto; + left: auto; + right: auto; + } + .row .col.m5 { + width: 41.6666666667%; + margin-left: auto; + left: auto; + right: auto; + } + .row .col.m6 { + width: 50%; + margin-left: auto; + left: auto; + right: auto; + } + .row .col.m7 { + width: 58.3333333333%; + margin-left: auto; + left: auto; + right: auto; + } + .row .col.m8 { + width: 66.6666666667%; + margin-left: auto; + left: auto; + right: auto; + } + .row .col.m9 { + width: 75%; + margin-left: auto; + left: auto; + right: auto; + } + .row .col.m10 { + width: 83.3333333333%; + margin-left: auto; + left: auto; + right: auto; + } + .row .col.m11 { + width: 91.6666666667%; + margin-left: auto; + left: auto; + right: auto; + } + .row .col.m12 { + width: 100%; + margin-left: auto; + left: auto; + right: auto; + } + .row .col.offset-m1 { + margin-left: 8.3333333333%; + } + .row .col.pull-m1 { + right: 8.3333333333%; + } + .row .col.push-m1 { + left: 8.3333333333%; + } + .row .col.offset-m2 { + margin-left: 16.6666666667%; + } + .row .col.pull-m2 { + right: 16.6666666667%; + } + .row .col.push-m2 { + left: 16.6666666667%; + } + .row .col.offset-m3 { + margin-left: 25%; + } + .row .col.pull-m3 { + right: 25%; + } + .row .col.push-m3 { + left: 25%; + } + .row .col.offset-m4 { + margin-left: 33.3333333333%; + } + .row .col.pull-m4 { + right: 33.3333333333%; + } + .row .col.push-m4 { + left: 33.3333333333%; + } + .row .col.offset-m5 { + margin-left: 41.6666666667%; + } + .row .col.pull-m5 { + right: 41.6666666667%; + } + .row .col.push-m5 { + left: 41.6666666667%; + } + .row .col.offset-m6 { + margin-left: 50%; + } + .row .col.pull-m6 { + right: 50%; + } + .row .col.push-m6 { + left: 50%; + } + .row .col.offset-m7 { + margin-left: 58.3333333333%; + } + .row .col.pull-m7 { + right: 58.3333333333%; + } + .row .col.push-m7 { + left: 58.3333333333%; + } + .row .col.offset-m8 { + margin-left: 66.6666666667%; + } + .row .col.pull-m8 { + right: 66.6666666667%; + } + .row .col.push-m8 { + left: 66.6666666667%; + } + .row .col.offset-m9 { + margin-left: 75%; + } + .row .col.pull-m9 { + right: 75%; + } + .row .col.push-m9 { + left: 75%; + } + .row .col.offset-m10 { + margin-left: 83.3333333333%; + } + .row .col.pull-m10 { + right: 83.3333333333%; + } + .row .col.push-m10 { + left: 83.3333333333%; + } + .row .col.offset-m11 { + margin-left: 91.6666666667%; + } + .row .col.pull-m11 { + right: 91.6666666667%; + } + .row .col.push-m11 { + left: 91.6666666667%; + } + .row .col.offset-m12 { + margin-left: 100%; + } + .row .col.pull-m12 { + right: 100%; + } + .row .col.push-m12 { + left: 100%; + } +} +@media only screen and (min-width : 993px) { + .row .col.l1 { + width: 8.3333333333%; + margin-left: auto; + left: auto; + right: auto; + } + .row .col.l2 { + width: 16.6666666667%; + margin-left: auto; + left: auto; + right: auto; + } + .row .col.l3 { + width: 25%; + margin-left: auto; + left: auto; + right: auto; + } + .row .col.l4 { + width: 33.3333333333%; + margin-left: auto; + left: auto; + right: auto; + } + .row .col.l5 { + width: 41.6666666667%; + margin-left: auto; + left: auto; + right: auto; + } + .row .col.l6 { + width: 50%; + margin-left: auto; + left: auto; + right: auto; + } + .row .col.l7 { + width: 58.3333333333%; + margin-left: auto; + left: auto; + right: auto; + } + .row .col.l8 { + width: 66.6666666667%; + margin-left: auto; + left: auto; + right: auto; + } + .row .col.l9 { + width: 75%; + margin-left: auto; + left: auto; + right: auto; + } + .row .col.l10 { + width: 83.3333333333%; + margin-left: auto; + left: auto; + right: auto; + } + .row .col.l11 { + width: 91.6666666667%; + margin-left: auto; + left: auto; + right: auto; + } + .row .col.l12 { + width: 100%; + margin-left: auto; + left: auto; + right: auto; + } + .row .col.offset-l1 { + margin-left: 8.3333333333%; + } + .row .col.pull-l1 { + right: 8.3333333333%; + } + .row .col.push-l1 { + left: 8.3333333333%; + } + .row .col.offset-l2 { + margin-left: 16.6666666667%; + } + .row .col.pull-l2 { + right: 16.6666666667%; + } + .row .col.push-l2 { + left: 16.6666666667%; + } + .row .col.offset-l3 { + margin-left: 25%; + } + .row .col.pull-l3 { + right: 25%; + } + .row .col.push-l3 { + left: 25%; + } + .row .col.offset-l4 { + margin-left: 33.3333333333%; + } + .row .col.pull-l4 { + right: 33.3333333333%; + } + .row .col.push-l4 { + left: 33.3333333333%; + } + .row .col.offset-l5 { + margin-left: 41.6666666667%; + } + .row .col.pull-l5 { + right: 41.6666666667%; + } + .row .col.push-l5 { + left: 41.6666666667%; + } + .row .col.offset-l6 { + margin-left: 50%; + } + .row .col.pull-l6 { + right: 50%; + } + .row .col.push-l6 { + left: 50%; + } + .row .col.offset-l7 { + margin-left: 58.3333333333%; + } + .row .col.pull-l7 { + right: 58.3333333333%; + } + .row .col.push-l7 { + left: 58.3333333333%; + } + .row .col.offset-l8 { + margin-left: 66.6666666667%; + } + .row .col.pull-l8 { + right: 66.6666666667%; + } + .row .col.push-l8 { + left: 66.6666666667%; + } + .row .col.offset-l9 { + margin-left: 75%; + } + .row .col.pull-l9 { + right: 75%; + } + .row .col.push-l9 { + left: 75%; + } + .row .col.offset-l10 { + margin-left: 83.3333333333%; + } + .row .col.pull-l10 { + right: 83.3333333333%; + } + .row .col.push-l10 { + left: 83.3333333333%; + } + .row .col.offset-l11 { + margin-left: 91.6666666667%; + } + .row .col.pull-l11 { + right: 91.6666666667%; + } + .row .col.push-l11 { + left: 91.6666666667%; + } + .row .col.offset-l12 { + margin-left: 100%; + } + .row .col.pull-l12 { + right: 100%; + } + .row .col.push-l12 { + left: 100%; + } +} +@media only screen and (min-width : 1201px) { + .row .col.xl1 { + width: 8.3333333333%; + margin-left: auto; + left: auto; + right: auto; + } + .row .col.xl2 { + width: 16.6666666667%; + margin-left: auto; + left: auto; + right: auto; + } + .row .col.xl3 { + width: 25%; + margin-left: auto; + left: auto; + right: auto; + } + .row .col.xl4 { + width: 33.3333333333%; + margin-left: auto; + left: auto; + right: auto; + } + .row .col.xl5 { + width: 41.6666666667%; + margin-left: auto; + left: auto; + right: auto; + } + .row .col.xl6 { + width: 50%; + margin-left: auto; + left: auto; + right: auto; + } + .row .col.xl7 { + width: 58.3333333333%; + margin-left: auto; + left: auto; + right: auto; + } + .row .col.xl8 { + width: 66.6666666667%; + margin-left: auto; + left: auto; + right: auto; + } + .row .col.xl9 { + width: 75%; + margin-left: auto; + left: auto; + right: auto; + } + .row .col.xl10 { + width: 83.3333333333%; + margin-left: auto; + left: auto; + right: auto; + } + .row .col.xl11 { + width: 91.6666666667%; + margin-left: auto; + left: auto; + right: auto; + } + .row .col.xl12 { + width: 100%; + margin-left: auto; + left: auto; + right: auto; + } + .row .col.offset-xl1 { + margin-left: 8.3333333333%; + } + .row .col.pull-xl1 { + right: 8.3333333333%; + } + .row .col.push-xl1 { + left: 8.3333333333%; + } + .row .col.offset-xl2 { + margin-left: 16.6666666667%; + } + .row .col.pull-xl2 { + right: 16.6666666667%; + } + .row .col.push-xl2 { + left: 16.6666666667%; + } + .row .col.offset-xl3 { + margin-left: 25%; + } + .row .col.pull-xl3 { + right: 25%; + } + .row .col.push-xl3 { + left: 25%; + } + .row .col.offset-xl4 { + margin-left: 33.3333333333%; + } + .row .col.pull-xl4 { + right: 33.3333333333%; + } + .row .col.push-xl4 { + left: 33.3333333333%; + } + .row .col.offset-xl5 { + margin-left: 41.6666666667%; + } + .row .col.pull-xl5 { + right: 41.6666666667%; + } + .row .col.push-xl5 { + left: 41.6666666667%; + } + .row .col.offset-xl6 { + margin-left: 50%; + } + .row .col.pull-xl6 { + right: 50%; + } + .row .col.push-xl6 { + left: 50%; + } + .row .col.offset-xl7 { + margin-left: 58.3333333333%; + } + .row .col.pull-xl7 { + right: 58.3333333333%; + } + .row .col.push-xl7 { + left: 58.3333333333%; + } + .row .col.offset-xl8 { + margin-left: 66.6666666667%; + } + .row .col.pull-xl8 { + right: 66.6666666667%; + } + .row .col.push-xl8 { + left: 66.6666666667%; + } + .row .col.offset-xl9 { + margin-left: 75%; + } + .row .col.pull-xl9 { + right: 75%; + } + .row .col.push-xl9 { + left: 75%; + } + .row .col.offset-xl10 { + margin-left: 83.3333333333%; + } + .row .col.pull-xl10 { + right: 83.3333333333%; + } + .row .col.push-xl10 { + left: 83.3333333333%; + } + .row .col.offset-xl11 { + margin-left: 91.6666666667%; + } + .row .col.pull-xl11 { + right: 91.6666666667%; + } + .row .col.push-xl11 { + left: 91.6666666667%; + } + .row .col.offset-xl12 { + margin-left: 100%; + } + .row .col.pull-xl12 { + right: 100%; + } + .row .col.push-xl12 { + left: 100%; + } +} + +.tui-modal { + position: absolute; + left: 0px; + right: 0px; + top: 100px; + z-index: 101; + display: none; +} +.tui-modal.active { + display: block !important; +} + +.tui-overlap { + position: absolute; + top: 0px; + left: 0px; + right: 0px; + bottom: 0px; + z-index: 100; + display: none; +} +.tui-overlap.active { + display: block !important; +} + +/* Chart container */ +.tui-chart-vertical { + position: relative; + background-color: black; +} + +.tui-chart-horizontal { + position: relative; + background-color: black; +} + +/* Chart display */ +.tui-chart-vertical .tui-chart-display { + display: flex; + position: absolute; + top: 0px; + left: 50px; + right: 0px; + bottom: 30px; + align-items: flex-end; + border-bottom: 2px solid white; + border-left: 2px solid white; +} +.tui-chart-vertical .tui-chart-display.no-x-axis { + bottom: 0px; +} +.tui-chart-vertical .tui-chart-display.no-y-axis { + left: 0px; +} + +.tui-chart-horizontal .tui-chart-display { + display: flex; + position: absolute; + flex-direction: column; + top: 0px; + left: 50px; + right: 0px; + bottom: 30px; + align-items: stretch; + border-bottom: 2px solid white; + border-left: 2px solid white; +} +.tui-chart-horizontal .tui-chart-display.no-x-axis { + bottom: 0px; +} +.tui-chart-horizontal .tui-chart-display.no-y-axis { + left: 0px; +} + +/* Chart X axis */ +.tui-chart-x-axis { + display: flex; + position: absolute; + height: 30px; + left: 50px; + right: 0px; + bottom: 0px; + line-height: 30px; +} + +/* Chart Y axis */ +.tui-chart-y-axis { + display: flex; + flex-direction: column; + position: absolute; + top: 0px; + left: 0px; + bottom: 30px; + width: 50px; +} + +/* Chart legends */ +.tui-chart-vertical .tui-chart-x-axis .tui-chart-legend { + flex: 0 1 100%; + text-align: center; +} + +.tui-chart-vertical .tui-chart-y-axis .tui-chart-legend { + flex: 1; + text-align: right; + padding-right: 2px; + display: flex; + align-items: flex-start; + justify-content: flex-end; +} + +.tui-chart-horizontal .tui-chart-x-axis .tui-chart-legend { + flex: 0 1 100%; + text-align: right; +} + +.tui-chart-horizontal .tui-chart-y-axis .tui-chart-legend { + flex: 1; + text-align: right; + padding-right: 2px; + display: flex; + align-items: center; + justify-content: flex-end; +} + +/* Chart value */ +.tui-chart-vertical .tui-chart-display .tui-chart-value { + flex: 0 1 100%; + text-align: center; + overflow: hidden; +} + +.tui-chart-horizontal .tui-chart-display .tui-chart-value { + flex: 1; + text-align: right; + display: flex; + align-items: center; + align-content: flex-start; + justify-content: flex-end; + overflow: hidden; +} \ No newline at end of file diff --git a/web/static/lib/tuicss/tuicss.js b/web/static/lib/tuicss/tuicss.js new file mode 100644 index 0000000..21c3b6d --- /dev/null +++ b/web/static/lib/tuicss/tuicss.js @@ -0,0 +1,256 @@ +/** + * Replacement for jQuery's $(document).ready() function. + * This is handy in making sure stuff fires after the DOM is ready to be touched. + * Stolen from:https://stackoverflow.com/a/53601942/344028 + * + * @param fn Callback. + */ +function domReady(fn) { + // If we're early to the party + document.addEventListener('DOMContentLoaded', fn); + + // If late; I mean on time. + if (document.readyState === 'interactive' || document.readyState === 'complete') { + fn(); + } +} + +/** + * TuiTabs controller + */ +function tabsController() { + // Get all the tab elements (typically li tags). + const tabs = document.getElementsByClassName('tui-tab'); + + if (!tabs.length) { + // No tabs found, return early and save a couple CPU cycles. + return; + } + + for (const tab of tabs) { + // Add click listeners to them. + tab.addEventListener('click', function (e) { + + // Check if the clicked tab is disabled + if(e.target.classList.contains("disabled")) { + return; + } + + // Remove the 'active' class from any and all tabs. + for (const otherTab of tabs) { + otherTab.classList.remove('active'); + } + + // Get the content element. + const tabContents = document.getElementsByClassName('tui-tab-content'); + + if (tabContents) { + for (const tabContent of tabContents) { + // Hide all tab contents. + tabContent.style.display = 'none'; + } + } else { + throw 'No tab content elements found.' + } + + // Get the id of the tab contents we want to show. + const tabContentId = e.target.getAttribute('data-tab-content'); + + if (tabContentId) { + const tabContent = document.getElementById(tabContentId); + if (tabContent) { + // Show the tab contents. + tabContent.style.display = 'block'; + } else { + throw 'No tab content element with id "' + tabContentId + '" found.'; + } + } + // We are not going to throw an error here, since we could make the tab do something else that a tab + // normally wouldn't do. + + // Set the clicked tab to have the 'active' class so we can use it in the next part. + e.target.classList.add('active'); + + }); + } + + // Grab the first tab with the active class. + const activeTab = document.querySelector('.tui-tab.active'); + if (activeTab) { + // Now click it 'click' it. + activeTab.click(); + } else { + // Nothing found, just click the first tab foud. + tabs[0].click() + } +} + +/** + * Date/time field controller + */ +function datetimeController() { + // Get date/time elements. + const clocks = document.getElementsByClassName('tui-datetime'); + + if (!clocks.length) { + // No date time elements found, return early and save a couple CPU cycles. + return; + } + + // Kick off our clock interval stuff. + datetimeInterval(); + + // Synchronize time and set interval to control the clocks + setTimeout(() => { + setInterval(datetimeInterval, 1000); + }, 1000 - new Date().getMilliseconds()); + + function datetimeInterval() { + for (const clock of clocks) { + if (clock === null) { + continue; + } + + // Get the format we want to display in the element. + let format = clock.getAttribute('data-format'); + + // parse out the date and time into constants. + const today = new Date(); + const month = (today.getMonth() + 1).toString().padStart(2, '0'); + const day = today.getDate().toString().padStart(2, '0'); + const dayOfWeek = (today.getDay() + 1).toString().padStart(2, '0'); + const year = today.getFullYear().toString(); + const hour = today.getHours().toString().padStart(2, '0'); + const hour12 = (parseInt(hour) + 24) % '12' || '12'; + const minute = today.getMinutes().toString().padStart(2, '0'); + const second = today.getSeconds().toString().padStart(2, '0'); + const ampm = parseInt(hour) >= 12 ? 'PM' : 'AM'; + + // Replace based on the format. + format = format.replace('M', month); + format = format.replace('d', day); + format = format.replace('e', dayOfWeek); + format = format.replace('y', year); + format = format.replace('H', hour); + format = format.replace('h', hour12); + format = format.replace('m', minute); + format = format.replace('s', second); + format = format.replace('a', ampm); + + // Show it in the element. + clock.innerHTML = format; + } + } +} + +/** + * Sidenav Controller + * There should only side navigation element at the moment. + */ +function sidenavController() { + // Get the side navigation button (there should be only one, but if not, we are getting the first one). + const sideNavButton = document.querySelector('.tui-sidenav-button'); + + if (!sideNavButton) { + // No side navigation button found, return early and save a couple CPU cycles. + return; + } + + // Add the click event listener to the buttons. + sideNavButton.addEventListener('click', () => { + // Get the side navigation element (there should be only one, but if not, we are getting the first one). + const sideNav = document.querySelector('.tui-sidenav'); + + if (sideNav) { + if (sideNav.classList.contains('active')) { + sideNav.classList.remove('active'); + } else { + sideNav.classList.add('active'); + } + } else { + throw 'No sidenav element found.' + } + }); +} + +/** + * Modal controller + */ +function modalController() { + // Get the overlap (overlay) element (there should be only one, but if not, we are getting the first one). + const tuiOverlap = document.querySelector('.tui-overlap'); + + if (!tuiOverlap) { + // No overlap found element, return early and save a couple CPU cycles. + return; + } + + // Find modal buttons. + const modalButtons = document.getElementsByClassName('tui-modal-button'); + for (const modalButton of modalButtons) { + // Add the click event listener to the buttons. + modalButton.addEventListener('click', (e) => { + // Show the overlap. + tuiOverlap.classList.add('active'); + + // Get the display element for the modal. + const modalId = e.target.getAttribute('data-modal'); + + if (modalId) { + const modal = document.getElementById(modalId); + + if (modal) { + // Show it. + modal.classList.add('active'); + } else { + throw 'No modal element with id of "' + modalId + '" found.'; + } + } else { + throw 'Modal close button data-modal attribute is empty or not set.' + } + }); + } + + // Find the close modal buttons. + const modalCloseButtons = document.getElementsByClassName('tui-modal-close-button'); + + if (modalButtons.length > 0 && !modalCloseButtons.length) { + // A modal without a close button, is a bad modal. + throw 'No modal close buttons found.' + } + + for (const modalCloseButton of modalCloseButtons) { + // Add the click event listener to the buttons. + modalCloseButton.addEventListener('click', (e) => { + // Hide the the overlap. + tuiOverlap.classList.remove('active'); + + // Get the display element id for the modal. + const modalId = e.target.getAttribute('data-modal'); + + if (modalId) { + // Get the modal element. + const modal = document.getElementById(modalId); + + if (modal) { + // Hide it. + modal.classList.remove('active'); + } else { + throw 'No modal element with id of "' + modalId + '" found.'; + } + } else { + throw 'Modal close button data-modal attribute is empty or not set.' + } + }); + } +} + +/** + * Init: This is at the bottom to make sure it is fired correctly. + */ +domReady(function () { + tabsController(); + datetimeController(); + sidenavController(); + modalController(); +}); diff --git a/web/static/lib/tuicss/tuicss.min.css b/web/static/lib/tuicss/tuicss.min.css new file mode 100644 index 0000000..a99923f --- /dev/null +++ b/web/static/lib/tuicss/tuicss.min.css @@ -0,0 +1 @@ +@charset "UTF-8";@font-face{font-family:DOS;src:url("fonts/Perfect DOS VGA 437 Win.ttf")}html{font-family:"Lucida Console",monospace;font-size:18px;box-sizing:border-box}body{margin:0}*,:after,:before{font-family:inherit;font-size:inherit;box-sizing:inherit}ul{margin:0;padding:0;list-style-type:none}ul li{list-style-type:none}ul li a{display:block}a{color:inherit;text-decoration:none}span{margin:0}hr{border:none;border-bottom:2px solid #fff}input,select,textarea{width:200px}@media only screen and (max-width :600px){.hide-on-small-and-down,.hide-on-small-only{display:none!important}}@media only screen and (max-width :992px){.hide-on-med-and-down{display:none!important}}@media only screen and (min-width :601px){.hide-on-med-and-up{display:none!important}}@media only screen and (min-width:600px) and (max-width:992px){.hide-on-med-only{display:none!important}}@media only screen and (min-width :993px){.hide-on-large-only{display:none!important}}@media only screen and (min-width :1201px){.hide-on-extra-large-only{display:none!important}}@media only screen and (min-width :1201px){.show-on-extra-large{display:block!important}}@media only screen and (min-width :993px){.show-on-large{display:block!important}}@media only screen and (min-width:600px) and (max-width:992px){.show-on-medium{display:block!important}}@media only screen and (max-width :600px){.show-on-small{display:block!important}}@media only screen and (min-width :601px){.show-on-medium-and-up{display:block!important}}@media only screen and (max-width :992px){.show-on-medium-and-down{display:block!important}}.primary{background-color:#0000a8}.primary-text{color:#0000a8}.primary-border{border-color:#0000a8}.primary-hover:hover{background-color:#0000a8}.primary-text-hover:hover{color:#0000a8}.primary-border-hover:hover{border-color:#0000a8}.secondary{background-color:#a8a8a8}.secondary-text{color:#a8a8a8}.secondary-border{border-color:#a8a8a8}.secondary-hover:hover{background-color:#a8a8a8}.secondary-text-hover:hover{color:#a8a8a8}.secondary-border-hover:hover{border-color:#a8a8a8}.success{background-color:#00a800}.success-text{color:#00a800}.success-border{border-color:#00a800}.success-hover:hover{background-color:#00a800}.success-text-hover:hover{color:#00a800}.success-border-hover:hover{border-color:#00a800}.danger{background-color:#a80000}.danger-text{color:#a80000}.danger-border{border-color:#a80000}.danger-hover:hover{background-color:#a80000}.danger-text-hover:hover{color:#a80000}.danger-border-hover:hover{border-color:#a80000}.warning{background-color:#a8a800}.warning-text{color:#a8a800}.warning-border{border-color:#a8a800}.warning-hover:hover{background-color:#a8a800}.warning-text-hover:hover{color:#a8a800}.warning-border-hover:hover{border-color:#a8a800}.info{background-color:#00a8a8}.info-text{color:#00a8a8}.info-border{border-color:#00a8a8}.info-hover:hover{background-color:#00a8a8}.info-text-hover:hover{color:#00a8a8}.info-border-hover:hover{border-color:#00a8a8}.black-168{background-color:#000!important}.blue-168{background-color:#0000a8!important}.green-168{background-color:#00a800!important}.cyan-168{background-color:#00a8a8!important}.red-168{background-color:#a80000!important}.purple-168{background-color:#a800a8!important}.yellow-168{background-color:#a8a800!important}.white-168{background-color:#a8a8a8!important}.orange-168{background-color:#a85600!important}.black-168-text{color:#000!important}.blue-168-text{color:#0000a8!important}.green-168-text{color:#00a800!important}.cyan-168-text{color:#00a8a8!important}.red-168-text{color:#a80000!important}.purple-168-text{color:#a800a8!important}.yellow-168-text{color:#a8a800!important}.white-168-text{color:#a8a8a8!important}.orange-168-text{color:#a85600!important}.black-168-border{border-color:#000!important}.blue-168-border{border-color:#0000a8!important}.green-168-border{border-color:#00a800!important}.cyan-168-border{border-color:#00a8a8!important}.red-168-border{border-color:#a80000!important}.purple-168-border{border-color:#a800a8!important}.yellow-168-border{border-color:#a8a800!important}.white-168-border{border-color:#a8a8a8!important}.orange-168-border{border-color:#a85600!important}.black-168-hover:hover{background-color:#000!important}.blue-168-hover:hover{background-color:#0000a8!important}.green-168-hover:hover{background-color:#00a800!important}.cyan-168-hover:hover{background-color:#00a8a8!important}.red-168-hover:hover{background-color:#a80000!important}.purple-168-hover:hover{background-color:#a800a8!important}.yellow-168-hover:hover{background-color:#a8a800!important}.white-168-hover:hover{background-color:#a8a8a8!important}.orange-168-hover:hover{background-color:#a85600!important}.black-168-text-hover:hover{color:#000!important}.blue-168-text-hover:hover{color:#0000a8!important}.green-168-text-hover:hover{color:#00a800!important}.cyan-168-text-hover:hover{color:#00a8a8!important}.red-168-text-hover:hover{color:#a80000!important}.purple-168-text-hover:hover{color:#a800a8!important}.yellow-168-text-hover:hover{color:#a8a800!important}.white-168-text-hover:hover{color:#a8a8a8!important}.orange-168-text-hover:hover{color:#a85600!important}.black-168-border-hover:hover{border-color:#000!important}.blue-168-border-hover:hover{border-color:#0000a8!important}.green-168-border-hover:hover{border-color:#00a800!important}.cyan-168-border-hover:hover{border-color:#00a8a8!important}.red-168-border-hover:hover{border-color:#a80000!important}.purple-168-border-hover:hover{border-color:#a800a8!important}.yellow-168-border-hover:hover{border-color:#a8a800!important}.white-168-border-hover:hover{border-color:#a8a8a8!important}.orange-168-border-hover:hover{border-color:#a85600!important}.black-255{background-color:#000!important}.blue-255{background-color:#00f!important}.green-255{background-color:#0f0!important}.cyan-255{background-color:#0ff!important}.red-255{background-color:red!important}.purple-255{background-color:#f0f!important}.yellow-255{background-color:#ff0!important}.white-255{background-color:#fff!important}.orange-255{background-color:#ffa800!important}.black-255-text{color:#000!important}.blue-255-text{color:#00f!important}.green-255-text{color:#0f0!important}.cyan-255-text{color:#0ff!important}.red-255-text{color:red!important}.purple-255-text{color:#f0f!important}.yellow-255-text{color:#ff0!important}.white-255-text{color:#fff!important}.orange-255-text{color:#ffa800!important}.black-255-border{border-color:#000!important}.blue-255-border{border-color:#00f!important}.green-255-border{border-color:#0f0!important}.cyan-255-border{border-color:#0ff!important}.red-255-border{border-color:red!important}.purple-255-border{border-color:#f0f!important}.yellow-255-border{border-color:#ff0!important}.white-255-border{border-color:#fff!important}.orange-255-border{border-color:#ffa800!important}.black-255-hover:hover{background-color:#000!important}.blue-255-hover:hover{background-color:#00f!important}.green-255-hover:hover{background-color:#0f0!important}.cyan-255-hover:hover{background-color:#0ff!important}.red-255-hover:hover{background-color:red!important}.purple-255-hover:hover{background-color:#f0f!important}.yellow-255-hover:hover{background-color:#ff0!important}.white-255-hover:hover{background-color:#fff!important}.orange-255-hover:hover{background-color:#ffa800!important}.black-255-text-hover:hover{color:#000!important}.blue-255-text-hover:hover{color:#00f!important}.green-255-text-hover:hover{color:#0f0!important}.cyan-255-text-hover:hover{color:#0ff!important}.red-255-text-hover:hover{color:red!important}.purple-255-text-hover:hover{color:#f0f!important}.yellow-255-text-hover:hover{color:#ff0!important}.white-255-text-hover:hover{color:#fff!important}.orange-255-text-hover:hover{color:#ffa800!important}.black-255-border-hover:hover{border-color:#000!important}.blue-255-border-hover:hover{border-color:#00f!important}.green-255-border-hover:hover{border-color:#0f0!important}.cyan-255-border-hover:hover{border-color:#0ff!important}.red-255-border-hover:hover{border-color:red!important}.purple-255-border-hover:hover{border-color:#f0f!important}.yellow-255-border-hover:hover{border-color:#ff0!important}.white-255-border-hover:hover{border-color:#fff!important}.orange-255-border-hover:hover{border-color:#ffa800!important}.black{background-color:#000!important}.black-text{color:#000!important}.black-border{border-color:#000!important}.black-hover:hover{background-color:#000!important}.black-text-hover:hover{color:#000!important}.black-border-hover:hover{border-color:#000!important}.white{background-color:#fff!important}.white-text{color:#fff!important}.white-border{border-color:#fff!important}.white-hover:hover{background-color:#fff!important}.white-text-hover:hover{color:#fff!important}.white-border-hover:hover{border-color:#fff!important}.left{float:left!important}.right{float:right!important}.center{text-align:center}.left-align{text-align:left}.right-align{text-align:right}.center-align{text-align:center}.full-width{width:100%!important}.full-height{height:100%!important}.inline{display:inline!important}.inline-block{display:inline-block!important}.block{display:block!important}.valign-top{vertical-align:top!important}.valign-middle{vertical-align:middle!important}.valign-bottom{vertical-align:bottom!important}.fixed{position:fixed!important}.absolute{position:absolute!important}.relative{position:relative!important}.static{position:static!important}.no-shadow{box-shadow:none!important}.no-padding{padding:0!important}.no-border{border:none!important}.content{padding:12px}.disable-select{user-select:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none}.cursor-pointer{cursor:pointer!important}.cursor-default{cursor:default!important}.disabled{cursor:not-allowed!important}.tui-button{display:inline-block;outline:0;padding:1px 10px;background-color:#00a800;color:#000;border:none;cursor:pointer;text-align:center;box-shadow:10px 10px #000;border-radius:0;user-select:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none}.tui-button.disabled{text-decoration:line-through}.tui-button:active{background-color:#00a8a8!important;color:#000!important;box-shadow:none!important}.tui-button:focus{color:#0ff!important}input[type=button]{width:initial}.tui-checkbox{display:block;position:relative;cursor:pointer;color:#fff;padding-left:30px;user-select:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none}.tui-checkbox.disabled{color:#a8a8a8}.tui-checkbox input{position:absolute;opacity:0;cursor:pointer;top:0;left:0;pointer-events:none}.tui-checkbox span{position:absolute;width:10px;height:10px;cursor:pointer;top:0;left:0}.tui-checkbox input:checked~span::after{content:"[√]";color:#0ff}.tui-checkbox input:not(checked)~span::after{content:"[ ]"}.tui-divider{border-bottom:2px solid #fff;display:block}.tui-black-divider{border-bottom:2px solid #000;display:block}.tui-dropdown{position:relative;display:inline-block;cursor:pointer;user-select:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none}.tui-dropdown-content{display:none;position:absolute;background-color:#a8a8a8;min-width:200px;padding:6px;z-index:9}.tui-dropdown-content ul{border:2px #000 solid}.tui-dropdown-content ul li{display:block!important;margin:6px}.tui-dropdown-content ul li a:hover{background-color:#00a800}.tui-dropdown:hover>.tui-dropdown-content:first-of-type{display:block}.tui-fieldset{border:6px #fff double;padding:12px;background-color:inherit;margin-bottom:6px}.tui-fieldset.no-legend{margin-top:6px}.tui-input-fieldset{border-top:6px #fff double;border-bottom:6px #fff double;border-left:2px #fff solid;border-right:2px #fff solid;padding:5px;background-color:inherit}.tui-input-fieldset legend{color:#fff}.tui-input-fieldset:hover{border-color:#ff0}.tui-input-fieldset:hover legend{color:#ff0}.tui-fieldset-button{position:absolute;top:0;right:16px;color:#fff;background-color:inherit;z-index:2;border:none;cursor:pointer;outline:0;padding:2px;user-select:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none}.tui-fieldset-button.left{right:initial;left:16px!important}.tui-fieldset-button.bottom{bottom:0;top:initial}.tui-fieldset-text{position:absolute;bottom:0;left:16px;color:#fff;background-color:inherit;z-index:2;padding:2px}.tui-fieldset-text.right{left:initial;right:16px}.tui-fieldset-text.top{top:0;bottom:initial}.tui-fieldset-button::before{content:"["}.tui-fieldset-button::after{content:"]"}.tui-fieldset-button:active{color:#0ff!important}.tui-input{background-color:#000;color:#fff;outline:0;border:none;border-radius:0}.tui-input.disabled{background-color:#a8a8a8;color:#000}.tui-input:focus{background-color:#ff0!important;color:#000!important}.tui-nav{width:100%;background-color:#a8a8a8;padding:0 2px;z-index:9;display:block;position:fixed}.tui-nav ul li{display:inline-block;margin-left:10px;padding:1px 3px}.tui-nav ul li a{display:block;user-select:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none}.tui-nav ul li:hover{background-color:#00a800}.tui-panel{background-color:#0000a8;display:inline-block;color:#fff;box-shadow:10px 10px #000}.tui-panel-content{padding:12px}.tui-panel-header{padding-top:2px;display:block;background:#fff;text-align:center}.tui-progress-bar{display:block;position:relative;height:20px;width:200px;background-color:#00a8a8;overflow:hidden}.tui-progress{position:absolute;left:0;background-color:#0ff;height:100%;display:inline-block}.tui-progress-bar .tui-indeterminate{position:absolute;left:0;background-color:#0ff;height:20px;width:20px;display:inline-block;animation:indeterminate 1s backwards;animation-iteration-count:infinite;animation-timing-function:linear}.tui-progress-label{position:absolute;top:50%;left:50%;transform:translateX(-50%) translateY(-50%);z-index:1}@keyframes indeterminate{from{margin-left:-10%}to{margin-left:100%}}.tui-radio{display:block;position:relative;cursor:pointer;color:#fff;padding-left:30px;user-select:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none}.tui-radio.disabled{color:#a8a8a8}.tui-radio input{position:absolute;opacity:0;cursor:pointer;top:0;left:0;pointer-events:none}.tui-radio span{position:absolute;width:10px;height:10px;cursor:pointer;top:0;left:0}.tui-radio input:checked~span:after{content:"(•)";color:#0ff!important}.tui-radio input:not(checked)~span:after{content:"( )"}::-webkit-scrollbar{width:10px}::-webkit-scrollbar-track{background-image:url(images/scroll-cyan.png);background-repeat:repeat}::-webkit-scrollbar-thumb{background-color:#00a8a8}::-webkit-scrollbar-thumb:hover{background-color:#00a8a8}.tui-scroll-blue ::-webkit-scrollbar-track{background-image:url(images/scroll-blue.png)}.tui-scroll-blue ::-webkit-scrollbar-thumb{background-color:#0000a8}.tui-scroll-blue ::-webkit-scrollbar-thumb:hover{background-color:#0000a8}.tui-scroll-green ::-webkit-scrollbar-track{background-image:url(images/scroll-green.png)}.tui-scroll-green ::-webkit-scrollbar-thumb{background-color:#00a800}.tui-scroll-green ::-webkit-scrollbar-thumb:hover{background-color:#00a800}.tui-scroll-cyan ::-webkit-scrollbar-track{background-image:url(images/scroll-cyan.png)}.tui-scroll-cyan ::-webkit-scrollbar-thumb{background-color:#00a8a8}.tui-scroll-cyan ::-webkit-scrollbar-thumb:hover{background-color:#00a8a8}.tui-scroll-red ::-webkit-scrollbar-track{background-image:url(images/scroll-red.png)}.tui-scroll-red ::-webkit-scrollbar-thumb{background-color:#a80000}.tui-scroll-red ::-webkit-scrollbar-thumb:hover{background-color:#a80000}.tui-scroll-purple ::-webkit-scrollbar-track{background-image:url(images/scroll-purple.png)}.tui-scroll-purple ::-webkit-scrollbar-thumb{background-color:#a800a8}.tui-scroll-purple ::-webkit-scrollbar-thumb:hover{background-color:#a800a8}.tui-scroll-yellow ::-webkit-scrollbar-track{background-image:url(images/scroll-yellow.png)}.tui-scroll-yellow ::-webkit-scrollbar-thumb{background-color:#a8a800}.tui-scroll-yellow ::-webkit-scrollbar-thumb:hover{background-color:#a8a800}.tui-scroll-white ::-webkit-scrollbar-track{background-image:url(images/scroll-white.png)}.tui-scroll-white ::-webkit-scrollbar-thumb{background-color:#a8a8a8}.tui-scroll-white ::-webkit-scrollbar-thumb:hover{background-color:#a8a8a8}.tui-sidenav{position:fixed;top:0;left:0;background-color:#00a8a8;min-width:200px;box-shadow:10px 10px #000!important;padding:6px;z-index:10;height:100%;z-index:8;display:none}.tui-sidenav.right{left:initial;right:0}.tui-sidenav.active{display:block!important}.tui-sidenav ul{margin-top:20px;border:2px #000 solid}.tui-sidenav ul li{display:block;margin:6px}.tui-sidenav ul li a{display:block;user-select:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none}.tui-sidenav ul li:hover{background-color:#ff0}.tui-sidenav-button{cursor:pointer;user-select:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none}.tui-statusbar{width:100%;background-color:#a8a8a8;padding:0 1px;left:0;bottom:0;z-index:9;position:fixed}.tui-statusbar ul li{display:inline-block;margin-left:10px;padding:2px 3px}.tui-statusbar ul li:active{background-color:#0000a8;color:#fff}.tui-statusbar ul li a{user-select:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none}.tui-statusbar-divider{border-right:2px #000 solid;display:inline;margin:0 3px}.tui-table{border:2px solid #a8a8a8;padding:5px;border-collapse:collapse}.tui-table.hovered-blue tbody tr:hover{background-color:#00f!important;color:#000}.tui-table.hovered-green tbody tr:hover{background-color:#0f0!important;color:#000}.tui-table.hovered-cyan tbody tr:hover{background-color:#0ff!important;color:#000}.tui-table.hovered-red tbody tr:hover{background-color:red!important;color:#fff}.tui-table.hovered-purple tbody tr:hover{background-color:#f0f!important;color:#fff}.tui-table.hovered-yellow tbody tr:hover{background-color:#ff0!important;color:#000}.tui-table.hovered-white tbody tr:hover{background-color:#fff!important;color:#000}.tui-table.hovered-orange tbody tr:hover{background-color:#ffa800!important;color:#000}.tui-table.hovered tbody tr:hover{background-color:#0ff!important;color:#000}.tui-table.striped-blue tbody tr:nth-child(even){background-color:#0000a8}.tui-table.striped-green tbody tr:nth-child(even){background-color:#00a800}.tui-table.striped-cyan tbody tr:nth-child(even){background-color:#00a8a8}.tui-table.striped-red tbody tr:nth-child(even){background-color:#a80000}.tui-table.striped-purple tbody tr:nth-child(even){background-color:#a800a8}.tui-table.striped-yellow tbody tr:nth-child(even){background-color:#a8a800}.tui-table.striped-white tbody tr:nth-child(even){background-color:#a8a8a8;color:#000}.tui-table.striped-orange tbody tr:nth-child(even){background-color:#a85600}.tui-table tbody{background-color:inherit;color:#fff}.tui-table tbody tr td{border-right:2px solid #a8a8a8;padding:0 2px}.tui-table thead{background-color:inherit;color:#ff0;text-align:center}.tui-table tfoot{background-color:inherit;color:#ff0;text-align:center}.tui-table-grid{border-collapse:collapse;width:100%}.tui-table-grid tbody tr td,.tui-table-grid tbody tr th,.tui-table-grid thead tr td,.tui-table-grid thead tr th{border:2px solid #000;padding:10px;vertical-align:top}.tui-tabs{background-color:#0000a8;width:100%;padding:0 10px 0 10px}.tui-tabs ul li{display:inline-block}.tui-tabs ul li a{display:block;user-select:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none}.tui-tab{padding:2px 10px 0 10px;color:#a8a8a8;cursor:pointer}.tui-tab.active{background-color:#a8a8a8;color:#0000a8}.tui-tab.disabled{text-decoration:line-through}.tui-tab-content{display:none}.tui-textarea{background-color:inherit;border:none;padding:0;color:#ff0;outline:0}.tui-textarea.disabled{background-color:#a8a8a8;color:#000}.tui-window{background-color:#0000a8;padding:1px;display:inline-block;position:relative;box-shadow:10px 10px #000;color:#fff}.tui-screen-640-480{width:640px;height:480px}.tui-screen-800-600{width:800px;height:600px}.tui-screen-1024-768{width:1024px;height:768px}.tui-screen-1024-768,.tui-screen-640-480,.tui-screen-800-600{position:relative;overflow:hidden}.tui-screen-1024-768.bordered,.tui-screen-640-480.bordered,.tui-screen-800-600.bordered{border:2px solid #000}.tui-screen-1024-768.centered,.tui-screen-640-480.centered,.tui-screen-800-600.centered{margin:auto;margin-top:20px}.tui-datetime{padding:1px 0 1px 0;margin-right:10px;float:right}.tui-shortcut{float:right}.tui-shadow,.tui-shadow-1{box-shadow:10px 10px #000!important}.tui-shadow-2{box-shadow:15px 15px #000}.tui-shadow-3{box-shadow:20px 20px #000}.tui-shadow-4{box-shadow:25px 25px #000}.tui-shadow-5{box-shadow:30px 30px #000}.tui-shadow-left,.tui-shadow-left-1{box-shadow:-10px 10px #000!important}.tui-shadow-left-2{box-shadow:-15px 15px #000!important}.tui-shadow-left-3{box-shadow:-20px 20px #000!important}.tui-shadow-left-4{box-shadow:-25px 25px #000!important}.tui-shadow-left-5{box-shadow:-30px 30px #000!important}.tui-no-shadow{box-shadow:none!important}.tui-bg-blue-white{background-image:url(images/bg-blue-white.png);background-repeat:repeat}.tui-bg-blue-black{background-image:url(images/bg-blue-black.png);background-repeat:repeat}.tui-bg-green-white{background-image:url(images/bg-green-white.png);background-repeat:repeat}.tui-bg-green-black{background-image:url(images/bg-green-black.png);background-repeat:repeat}.tui-bg-cyan-white{background-image:url(images/bg-cyan-white.png);background-repeat:repeat}.tui-bg-cyan-black{background-image:url(images/bg-cyan-black.png);background-repeat:repeat}.tui-bg-red-white{background-image:url(images/bg-red-white.png);background-repeat:repeat}.tui-bg-red-black{background-image:url(images/bg-red-black.png);background-repeat:repeat}.tui-bg-purple-white{background-image:url(images/bg-purple-white.png);background-repeat:repeat}.tui-bg-purple-black{background-image:url(images/bg-purple-black.png);background-repeat:repeat}.tui-bg-yellow-white{background-image:url(images/bg-yellow-white.png);background-repeat:repeat}.tui-bg-yellow-black{background-image:url(images/bg-yellow-black.png);background-repeat:repeat}.tui-bg-orange-white{background-image:url(images/bg-orange-white.png);background-repeat:repeat}.tui-bg-orange-black{background-image:url(images/bg-orange-black.png);background-repeat:repeat}.tui-border-solid{border-style:solid!important;border-width:2px!important}.tui-border-dashed{border-style:dashed!important;border-width:2px!important}.tui-border-dotted{border-style:dotted!important;border-width:2px!important}.tui-border-double{border-style:double!important;border-width:6px!important}.container{margin:0 auto;max-width:1280px;width:90%}@media only screen and (min-width :601px){.container{width:85%}}@media only screen and (min-width :993px){.container{width:70%}}.col .row{margin-left:-.75rem;margin-right:-.75rem}.section{padding-top:1rem;padding-bottom:1rem}.section.no-pad{padding:0}.section.no-pad-bot{padding-bottom:0}.section.no-pad-top{padding-top:0}.row{margin-left:auto;margin-right:auto;margin-bottom:20px}.row:after{content:"";display:table;clear:both}.row .col{float:left;box-sizing:border-box;padding:0 .75rem;min-height:1px}.row .col[class*=pull-],.row .col[class*=push-]{position:relative}.row .col.s1{width:8.3333333333%;margin-left:auto;left:auto;right:auto}.row .col.s2{width:16.6666666667%;margin-left:auto;left:auto;right:auto}.row .col.s3{width:25%;margin-left:auto;left:auto;right:auto}.row .col.s4{width:33.3333333333%;margin-left:auto;left:auto;right:auto}.row .col.s5{width:41.6666666667%;margin-left:auto;left:auto;right:auto}.row .col.s6{width:50%;margin-left:auto;left:auto;right:auto}.row .col.s7{width:58.3333333333%;margin-left:auto;left:auto;right:auto}.row .col.s8{width:66.6666666667%;margin-left:auto;left:auto;right:auto}.row .col.s9{width:75%;margin-left:auto;left:auto;right:auto}.row .col.s10{width:83.3333333333%;margin-left:auto;left:auto;right:auto}.row .col.s11{width:91.6666666667%;margin-left:auto;left:auto;right:auto}.row .col.s12{width:100%;margin-left:auto;left:auto;right:auto}.row .col.offset-s1{margin-left:8.3333333333%}.row .col.pull-s1{right:8.3333333333%}.row .col.push-s1{left:8.3333333333%}.row .col.offset-s2{margin-left:16.6666666667%}.row .col.pull-s2{right:16.6666666667%}.row .col.push-s2{left:16.6666666667%}.row .col.offset-s3{margin-left:25%}.row .col.pull-s3{right:25%}.row .col.push-s3{left:25%}.row .col.offset-s4{margin-left:33.3333333333%}.row .col.pull-s4{right:33.3333333333%}.row .col.push-s4{left:33.3333333333%}.row .col.offset-s5{margin-left:41.6666666667%}.row .col.pull-s5{right:41.6666666667%}.row .col.push-s5{left:41.6666666667%}.row .col.offset-s6{margin-left:50%}.row .col.pull-s6{right:50%}.row .col.push-s6{left:50%}.row .col.offset-s7{margin-left:58.3333333333%}.row .col.pull-s7{right:58.3333333333%}.row .col.push-s7{left:58.3333333333%}.row .col.offset-s8{margin-left:66.6666666667%}.row .col.pull-s8{right:66.6666666667%}.row .col.push-s8{left:66.6666666667%}.row .col.offset-s9{margin-left:75%}.row .col.pull-s9{right:75%}.row .col.push-s9{left:75%}.row .col.offset-s10{margin-left:83.3333333333%}.row .col.pull-s10{right:83.3333333333%}.row .col.push-s10{left:83.3333333333%}.row .col.offset-s11{margin-left:91.6666666667%}.row .col.pull-s11{right:91.6666666667%}.row .col.push-s11{left:91.6666666667%}.row .col.offset-s12{margin-left:100%}.row .col.pull-s12{right:100%}.row .col.push-s12{left:100%}@media only screen and (min-width :601px){.row .col.m1{width:8.3333333333%;margin-left:auto;left:auto;right:auto}.row .col.m2{width:16.6666666667%;margin-left:auto;left:auto;right:auto}.row .col.m3{width:25%;margin-left:auto;left:auto;right:auto}.row .col.m4{width:33.3333333333%;margin-left:auto;left:auto;right:auto}.row .col.m5{width:41.6666666667%;margin-left:auto;left:auto;right:auto}.row .col.m6{width:50%;margin-left:auto;left:auto;right:auto}.row .col.m7{width:58.3333333333%;margin-left:auto;left:auto;right:auto}.row .col.m8{width:66.6666666667%;margin-left:auto;left:auto;right:auto}.row .col.m9{width:75%;margin-left:auto;left:auto;right:auto}.row .col.m10{width:83.3333333333%;margin-left:auto;left:auto;right:auto}.row .col.m11{width:91.6666666667%;margin-left:auto;left:auto;right:auto}.row .col.m12{width:100%;margin-left:auto;left:auto;right:auto}.row .col.offset-m1{margin-left:8.3333333333%}.row .col.pull-m1{right:8.3333333333%}.row .col.push-m1{left:8.3333333333%}.row .col.offset-m2{margin-left:16.6666666667%}.row .col.pull-m2{right:16.6666666667%}.row .col.push-m2{left:16.6666666667%}.row .col.offset-m3{margin-left:25%}.row .col.pull-m3{right:25%}.row .col.push-m3{left:25%}.row .col.offset-m4{margin-left:33.3333333333%}.row .col.pull-m4{right:33.3333333333%}.row .col.push-m4{left:33.3333333333%}.row .col.offset-m5{margin-left:41.6666666667%}.row .col.pull-m5{right:41.6666666667%}.row .col.push-m5{left:41.6666666667%}.row .col.offset-m6{margin-left:50%}.row .col.pull-m6{right:50%}.row .col.push-m6{left:50%}.row .col.offset-m7{margin-left:58.3333333333%}.row .col.pull-m7{right:58.3333333333%}.row .col.push-m7{left:58.3333333333%}.row .col.offset-m8{margin-left:66.6666666667%}.row .col.pull-m8{right:66.6666666667%}.row .col.push-m8{left:66.6666666667%}.row .col.offset-m9{margin-left:75%}.row .col.pull-m9{right:75%}.row .col.push-m9{left:75%}.row .col.offset-m10{margin-left:83.3333333333%}.row .col.pull-m10{right:83.3333333333%}.row .col.push-m10{left:83.3333333333%}.row .col.offset-m11{margin-left:91.6666666667%}.row .col.pull-m11{right:91.6666666667%}.row .col.push-m11{left:91.6666666667%}.row .col.offset-m12{margin-left:100%}.row .col.pull-m12{right:100%}.row .col.push-m12{left:100%}}@media only screen and (min-width :993px){.row .col.l1{width:8.3333333333%;margin-left:auto;left:auto;right:auto}.row .col.l2{width:16.6666666667%;margin-left:auto;left:auto;right:auto}.row .col.l3{width:25%;margin-left:auto;left:auto;right:auto}.row .col.l4{width:33.3333333333%;margin-left:auto;left:auto;right:auto}.row .col.l5{width:41.6666666667%;margin-left:auto;left:auto;right:auto}.row .col.l6{width:50%;margin-left:auto;left:auto;right:auto}.row .col.l7{width:58.3333333333%;margin-left:auto;left:auto;right:auto}.row .col.l8{width:66.6666666667%;margin-left:auto;left:auto;right:auto}.row .col.l9{width:75%;margin-left:auto;left:auto;right:auto}.row .col.l10{width:83.3333333333%;margin-left:auto;left:auto;right:auto}.row .col.l11{width:91.6666666667%;margin-left:auto;left:auto;right:auto}.row .col.l12{width:100%;margin-left:auto;left:auto;right:auto}.row .col.offset-l1{margin-left:8.3333333333%}.row .col.pull-l1{right:8.3333333333%}.row .col.push-l1{left:8.3333333333%}.row .col.offset-l2{margin-left:16.6666666667%}.row .col.pull-l2{right:16.6666666667%}.row .col.push-l2{left:16.6666666667%}.row .col.offset-l3{margin-left:25%}.row .col.pull-l3{right:25%}.row .col.push-l3{left:25%}.row .col.offset-l4{margin-left:33.3333333333%}.row .col.pull-l4{right:33.3333333333%}.row .col.push-l4{left:33.3333333333%}.row .col.offset-l5{margin-left:41.6666666667%}.row .col.pull-l5{right:41.6666666667%}.row .col.push-l5{left:41.6666666667%}.row .col.offset-l6{margin-left:50%}.row .col.pull-l6{right:50%}.row .col.push-l6{left:50%}.row .col.offset-l7{margin-left:58.3333333333%}.row .col.pull-l7{right:58.3333333333%}.row .col.push-l7{left:58.3333333333%}.row .col.offset-l8{margin-left:66.6666666667%}.row .col.pull-l8{right:66.6666666667%}.row .col.push-l8{left:66.6666666667%}.row .col.offset-l9{margin-left:75%}.row .col.pull-l9{right:75%}.row .col.push-l9{left:75%}.row .col.offset-l10{margin-left:83.3333333333%}.row .col.pull-l10{right:83.3333333333%}.row .col.push-l10{left:83.3333333333%}.row .col.offset-l11{margin-left:91.6666666667%}.row .col.pull-l11{right:91.6666666667%}.row .col.push-l11{left:91.6666666667%}.row .col.offset-l12{margin-left:100%}.row .col.pull-l12{right:100%}.row .col.push-l12{left:100%}}@media only screen and (min-width :1201px){.row .col.xl1{width:8.3333333333%;margin-left:auto;left:auto;right:auto}.row .col.xl2{width:16.6666666667%;margin-left:auto;left:auto;right:auto}.row .col.xl3{width:25%;margin-left:auto;left:auto;right:auto}.row .col.xl4{width:33.3333333333%;margin-left:auto;left:auto;right:auto}.row .col.xl5{width:41.6666666667%;margin-left:auto;left:auto;right:auto}.row .col.xl6{width:50%;margin-left:auto;left:auto;right:auto}.row .col.xl7{width:58.3333333333%;margin-left:auto;left:auto;right:auto}.row .col.xl8{width:66.6666666667%;margin-left:auto;left:auto;right:auto}.row .col.xl9{width:75%;margin-left:auto;left:auto;right:auto}.row .col.xl10{width:83.3333333333%;margin-left:auto;left:auto;right:auto}.row .col.xl11{width:91.6666666667%;margin-left:auto;left:auto;right:auto}.row .col.xl12{width:100%;margin-left:auto;left:auto;right:auto}.row .col.offset-xl1{margin-left:8.3333333333%}.row .col.pull-xl1{right:8.3333333333%}.row .col.push-xl1{left:8.3333333333%}.row .col.offset-xl2{margin-left:16.6666666667%}.row .col.pull-xl2{right:16.6666666667%}.row .col.push-xl2{left:16.6666666667%}.row .col.offset-xl3{margin-left:25%}.row .col.pull-xl3{right:25%}.row .col.push-xl3{left:25%}.row .col.offset-xl4{margin-left:33.3333333333%}.row .col.pull-xl4{right:33.3333333333%}.row .col.push-xl4{left:33.3333333333%}.row .col.offset-xl5{margin-left:41.6666666667%}.row .col.pull-xl5{right:41.6666666667%}.row .col.push-xl5{left:41.6666666667%}.row .col.offset-xl6{margin-left:50%}.row .col.pull-xl6{right:50%}.row .col.push-xl6{left:50%}.row .col.offset-xl7{margin-left:58.3333333333%}.row .col.pull-xl7{right:58.3333333333%}.row .col.push-xl7{left:58.3333333333%}.row .col.offset-xl8{margin-left:66.6666666667%}.row .col.pull-xl8{right:66.6666666667%}.row .col.push-xl8{left:66.6666666667%}.row .col.offset-xl9{margin-left:75%}.row .col.pull-xl9{right:75%}.row .col.push-xl9{left:75%}.row .col.offset-xl10{margin-left:83.3333333333%}.row .col.pull-xl10{right:83.3333333333%}.row .col.push-xl10{left:83.3333333333%}.row .col.offset-xl11{margin-left:91.6666666667%}.row .col.pull-xl11{right:91.6666666667%}.row .col.push-xl11{left:91.6666666667%}.row .col.offset-xl12{margin-left:100%}.row .col.pull-xl12{right:100%}.row .col.push-xl12{left:100%}}.tui-modal{position:absolute;left:0;right:0;top:100px;z-index:101;display:none}.tui-modal.active{display:block!important}.tui-overlap{position:absolute;top:0;left:0;right:0;bottom:0;z-index:100;display:none}.tui-overlap.active{display:block!important}.tui-chart-vertical{position:relative;background-color:#000}.tui-chart-horizontal{position:relative;background-color:#000}.tui-chart-vertical .tui-chart-display{display:flex;position:absolute;top:0;left:50px;right:0;bottom:30px;align-items:flex-end;border-bottom:2px solid #fff;border-left:2px solid #fff}.tui-chart-vertical .tui-chart-display.no-x-axis{bottom:0}.tui-chart-vertical .tui-chart-display.no-y-axis{left:0}.tui-chart-horizontal .tui-chart-display{display:flex;position:absolute;flex-direction:column;top:0;left:50px;right:0;bottom:30px;align-items:stretch;border-bottom:2px solid #fff;border-left:2px solid #fff}.tui-chart-horizontal .tui-chart-display.no-x-axis{bottom:0}.tui-chart-horizontal .tui-chart-display.no-y-axis{left:0}.tui-chart-x-axis{display:flex;position:absolute;height:30px;left:50px;right:0;bottom:0;line-height:30px}.tui-chart-y-axis{display:flex;flex-direction:column;position:absolute;top:0;left:0;bottom:30px;width:50px}.tui-chart-vertical .tui-chart-x-axis .tui-chart-legend{flex:0 1 100%;text-align:center}.tui-chart-vertical .tui-chart-y-axis .tui-chart-legend{flex:1;text-align:right;padding-right:2px;display:flex;align-items:flex-start;justify-content:flex-end}.tui-chart-horizontal .tui-chart-x-axis .tui-chart-legend{flex:0 1 100%;text-align:right}.tui-chart-horizontal .tui-chart-y-axis .tui-chart-legend{flex:1;text-align:right;padding-right:2px;display:flex;align-items:center;justify-content:flex-end}.tui-chart-vertical .tui-chart-display .tui-chart-value{flex:0 1 100%;text-align:center;overflow:hidden}.tui-chart-horizontal .tui-chart-display .tui-chart-value{flex:1;text-align:right;display:flex;align-items:center;align-content:flex-start;justify-content:flex-end;overflow:hidden} \ No newline at end of file diff --git a/web/static/lib/tuicss/tuicss.min.js b/web/static/lib/tuicss/tuicss.min.js new file mode 100644 index 0000000..84c6325 --- /dev/null +++ b/web/static/lib/tuicss/tuicss.min.js @@ -0,0 +1 @@ +function domReady(t){document.addEventListener("DOMContentLoaded",t),"interactive"!==document.readyState&&"complete"!==document.readyState||t()}function tabsController(){const t=document.getElementsByClassName("tui-tab");if(!t.length)return;for(const e of t)e.addEventListener("click",function(e){if(e.target.classList.contains("disabled"))return;for(const e of t)e.classList.remove("active");const o=document.getElementsByClassName("tui-tab-content");if(!o)throw"No tab content elements found.";for(const t of o)t.style.display="none";const n=e.target.getAttribute("data-tab-content");if(n){const t=document.getElementById(n);if(!t)throw'No tab content element with id "'+n+'" found.';t.style.display="block"}e.target.classList.add("active")});const e=document.querySelector(".tui-tab.active");e?e.click():t[0].click()}function datetimeController(){const t=document.getElementsByClassName("tui-datetime");function e(){for(const e of t){if(null===e)continue;let t=e.getAttribute("data-format");const o=new Date,n=(o.getMonth()+1).toString().padStart(2,"0"),a=o.getDate().toString().padStart(2,"0"),c=(o.getDay()+1).toString().padStart(2,"0"),s=o.getFullYear().toString(),i=o.getHours().toString().padStart(2,"0"),l=(parseInt(i)+24)%"12"||"12",r=o.getMinutes().toString().padStart(2,"0"),d=o.getSeconds().toString().padStart(2,"0"),u=parseInt(i)>=12?"PM":"AM";t=(t=(t=(t=(t=(t=(t=(t=(t=t.replace("M",n)).replace("d",a)).replace("e",c)).replace("y",s)).replace("H",i)).replace("h",l)).replace("m",r)).replace("s",d)).replace("a",u),e.innerHTML=t}}t.length&&(e(),setTimeout(()=>{setInterval(e,1e3)},1e3-(new Date).getMilliseconds()))}function sidenavController(){const t=document.querySelector(".tui-sidenav-button");t&&t.addEventListener("click",()=>{const t=document.querySelector(".tui-sidenav");if(!t)throw"No sidenav element found.";t.classList.contains("active")?t.classList.remove("active"):t.classList.add("active")})}function modalController(){const t=document.querySelector(".tui-overlap");if(!t)return;const e=document.getElementsByClassName("tui-modal-button");for(const o of e)o.addEventListener("click",e=>{t.classList.add("active");const o=e.target.getAttribute("data-modal");if(!o)throw"Modal close button data-modal attribute is empty or not set.";{const t=document.getElementById(o);if(!t)throw'No modal element with id of "'+o+'" found.';t.classList.add("active")}});const o=document.getElementsByClassName("tui-modal-close-button");if(e.length>0&&!o.length)throw"No modal close buttons found.";for(const e of o)e.addEventListener("click",e=>{t.classList.remove("active");const o=e.target.getAttribute("data-modal");if(!o)throw"Modal close button data-modal attribute is empty or not set.";{const t=document.getElementById(o);if(!t)throw'No modal element with id of "'+o+'" found.';t.classList.remove("active")}})}domReady(function(){tabsController(),datetimeController(),sidenavController(),modalController()}); \ No newline at end of file diff --git a/web/templates/admin.html b/web/templates/admin.html new file mode 100644 index 0000000..3ebe83a --- /dev/null +++ b/web/templates/admin.html @@ -0,0 +1,28 @@ +{{template "layout" .}} + +{{define "title"}}Admin Panel · Estus Shots{{end}} + +{{define "content"}} +
+ Admin Panel +

+ This is an example admin page with a different menu bar that includes admin-specific options. +

+ +
+

System Status

+
+

Server: Running

+

Users: 42 active

+

Uptime: 7 days, 3 hours

+
+
+ +
+

Quick Actions

+ + + +
+
+{{end}} diff --git a/web/templates/index.html b/web/templates/index.html new file mode 100755 index 0000000..f7da25d --- /dev/null +++ b/web/templates/index.html @@ -0,0 +1,45 @@ +{{template "layout" .}} + +{{define "title"}}Estus Shots · Go + HTMX demo{{end}} + +{{define "content"}} +
+ Estus Shots control panel +

+ Estus Shots demonstrates a Go backend compiled into a single binary. The UI + uses TUI.CSS for a retro feel and HTMX for + partial page updates without JavaScript glue code. +

+ +
+

Interactive counter

+

+ Click the button to trigger an hx-post request. The response + replaces only the counter panel. +

+
+
Loading…
+
+
+ +
+

Server time

+

+ A periodic hx-get refresh keeps this panel in sync with the + server clock. +

+
+
Loading…
+
+
+
+{{end}} diff --git a/web/templates/layout.html b/web/templates/layout.html new file mode 100644 index 0000000..a9274cf --- /dev/null +++ b/web/templates/layout.html @@ -0,0 +1,19 @@ +{{define "layout"}} + + + + + + {{block "title" .}}Estus Shots{{end}} + + + + + + {{block "menubar" .}}{{end}} +
+ {{block "content" .}}{{end}} +
+ + +{{end}} diff --git a/web/templates/menubar.html b/web/templates/menubar.html new file mode 100644 index 0000000..62c86be --- /dev/null +++ b/web/templates/menubar.html @@ -0,0 +1,25 @@ +{{define "menubar"}} +
+{{end}}