126 Commits
Author SHA1 Message Date
SansanandClaude Opus 5.5 9b5a3c58c6 Pin the frontend image to v1.3.0
CI / test (push) Successful in 14s
CI / integration (push) Successful in 19s
CI / publish (push) Skipped
CI / docker (push) Successful in 22s
The server image used musicfrontend:latest, so it got whatever frontend was
newest when it was built. Pin the version instead, and bump it when a new
frontend is released.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 22:17:38 +02:00
SansanandClaude Opus 5.5 8da5468efb Show sync times as minutes and seconds
CI / integration (push) Successful in 19s
CI / test (push) Successful in 23s
CI / publish (push) Skipped
CI / docker (push) Successful in 46s
time_spent and total_time are now "MM:SS" instead of "HH:MM:SS". A sync longer
than an hour keeps counting minutes, e.g. "62:03".

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 22:07:02 +02:00
SansanandClaude Opus 5.5 439ffede18 Build the image with Go 1.26
CI / integration (push) Successful in 18s
CI / test (push) Successful in 21s
CI / publish (push) Skipped
CI / docker (push) Successful in 50s
The Prometheus client and the golang.org/x updates raised go.mod to Go 1.26,
so the Docker build with golang:1.25-alpine failed in go mod download.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 19:59:05 +02:00
SansanandClaude Opus 5.5 c70eb4d13c Add GET /api/v1/download/linux-package
CI / docker (push) Failing after 20s
CI / test (push) Successful in 23s
CI / integration (push) Successful in 25s
CI / publish (push) Skipped
Redirects to the newest MusicPlayer release's _linux.tar.gz, which has the
icon, a menu entry and install.sh. /download/linux keeps serving the bare
.x86_64, which updating in place needs. Releases without the package get 404.

Closes #34

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 19:40:22 +02:00
SansanandClaude Opus 5.5 bb8de5548d Add alternative names and cover art for soundtracks
CI / docker (push) Failing after 22s
CI / integration (push) Successful in 26s
CI / test (push) Successful in 26s
CI / publish (push) Skipped
Alternative names (#32):
- PUT /api/v1/soundtracks/{uuid}/alternative-names replaces a soundtrack's
  alternative names (trimmed, deduplicated, without the soundtrack's own name).
- alternative_names is in the soundtrack and statistics responses.
- /find matches them too and shows which name matched.

Covers (#12), stored in COVERS_PATH and off when it is not set:
- GET, PUT (upload) and DELETE /api/v1/soundtracks/{uuid}/cover, and
  PUT .../cover/source to pick a SteamGridDB game or AniList anime by ID.
  Uploaded and picked covers are never replaced automatically.
- With STEAMGRIDDB_API_KEY, a background job searches SteamGridDB, then
  AniList, by name, alternative names and the name without bracketed parts,
  at startup, after a sync and after names change. Search results are ranked
  by matching words, so "Civilization IV" gets "Sid Meier's Civilization IV".
- cover_modified (Unix seconds) is in the soundtrack and statistics responses,
  so clients can cache covers.

The new columns are added to migration 000006, which is not released yet.

Closes #12, closes #32

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 21:57:18 +02:00
SansanandClaude Opus 5.5 f79f51ea4c Expose Prometheus metrics on a separate port
CI / integration (push) Failing after 14s
CI / docker (push) Failing after 20s
CI / test (push) Successful in 1m10s
CI / publish (push) Skipped
Metrics are served on METRICS_PORT (default 2112, "off" to disable), never on
the public port. Besides the Go runtime and process metrics this adds:

- http_requests_total and http_request_duration_seconds per route pattern,
  from an Echo middleware.
- musicserver_songs_requested_total and musicserver_songs_played_total by
  pick mode (random, low, classic). The mode is now stored with each queued
  song (migration 000006, not released yet).
- Library size, sync duration, last successful sync, broken songs from the
  last full sync, and the database connection pool.

Refs #35, #36, #37

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 21:57:58 +02:00
Sansan c62b65d7cd Add GET /api/v1/character/details with each image's change time
CI / integration (push) Successful in 21s
CI / test (push) Successful in 23s
CI / publish (push) Skipped
CI / docker (push) Successful in 48s
Returns every character image with when it was last changed, in Unix seconds,
so clients can cache the images and download only the ones that changed.
2026-10-07 21:57:26 +02:00
Sansan 76a1b946eb Stop browsers from caching songs
CI / docker (push) Successful in 1m6s
CI / test (push) Successful in 22s
CI / integration (push) Successful in 23s
CI / publish (push) Skipped
/music/rand and the other song endpoints return a different song from the
same URL, but the responses had a Last-Modified header and no Cache-Control,
so browsers cached them. The same song played again and the server never
picked a new one, so /music/addQue added nothing. Send Cache-Control:
no-store again, as the server did before the rewrite.

Also allow the Cache-Control request header in CORS, which the frontend
sends to bypass responses that browsers have already cached.
2026-10-07 20:09:30 +02:00
Sansan d31bf3551c Allow CORS origins from CORS_ALLOWED_ORIGINS
CI / test (push) Successful in 23s
CI / publish (push) Skipped
CI / docker (push) Successful in 46s
CI / integration (push) Successful in 19s
Echo compares allowed origins literally, so "https://*" and "http://*" never
matched a real origin and no CORS headers were sent. The allowed origins now
come from CORS_ALLOWED_ORIGINS (comma-separated, checked at startup). When it
is empty, only same-origin requests work, which is enough for the bundled
frontend.

Credentials are no longer allowed since the API uses Bearer tokens. Browsers
may now send Range and X-Queue-Id and read X-Queue-Id and Content-Range.
2026-10-07 20:03:13 +02:00
Sansan a705d7b476 Store each client's play queue in the database
The queue lived in memory and was shared by all clients, so a restart or a
finished sync cleared it. Every client now has its own queue in the new
queue and queue_song tables (added to the undeployed migration 000006).

The music endpoints return the queue ID in the X-Queue-Id header and expect
it back. A request without an ID, or with an ended one, starts a new queue.
/music/reset ends the queue and returns a new ID, and a sync ends all
running queues. Ended queues are kept as history.

The deprecated legacy routes without the /api/v1 prefix are removed.
2026-10-07 20:03:03 +02:00
Sansan b5dc42b654 Load every soundtrack when the search page opens
CI / integration (push) Successful in 18s
CI / test (push) Successful in 21s
CI / publish (push) Skipped
CI / docker (push) Successful in 44s
2026-10-07 16:46:31 +02:00
Sansan 080bacae80 Add GET /api/v1/statistics/soundtracks with every soundtrack and its songs
CI / integration (push) Successful in 18s
CI / test (push) Successful in 22s
CI / publish (push) Skipped
CI / docker (push) Successful in 41s
The other soundtrack statistics are capped at 100, so a client that shows every soundtrack (the MusicPlayer statistics tab) had no way to get them all. This one has no limit and is sorted by name.
2026-10-06 23:14:49 +02:00
Sansan fc7d787014 Serve the frontend's config.js with the API password
CI / docker (push) Successful in 47s
CI / integration (push) Successful in 17s
CI / test (push) Successful in 21s
CI / publish (push) Skipped
The bundled frontend gets a token with API_PASSWORD from config.js. The server now
generates config.js from its own config, so setting API_PASSWORD on the server
container is enough.
2026-10-06 19:01:17 +02:00
Sansan 6da96f79e7 Add a command to write the OpenAPI spec without a server
CI / test (push) Successful in 28s
CI / integration (push) Successful in 39s
CI / publish (push) Skipped
CI / docker (push) Successful in 51s
`just openapi [dir]` (go run ./cmd/openapi) writes openapi.json (3.1) and openapi-3.0.json without a database or configuration. A test checks it matches the spec the server serves.
2026-10-06 17:01:12 +02:00
Sansan 973ebf224b Generate the OpenAPI spec with Huma instead of swag
CI / integration (push) Successful in 49s
CI / docker (push) Successful in 1m0s
CI / test (push) Successful in 1m6s
CI / publish (push) Skipped
The spec is now built from the same calls that register the routes, so it
can't drift from the router like the swag comments did (all /api/v1
routes were missing).

- /api/v1 endpoints are typed Huma operations; the spec is OpenAPI 3.1 at
  /openapi.json (3.0 at /openapi-3.0.json, YAML too), docs at /docs.
  /openapi and /swagger/* redirect there
- Bearer token security is declared per operation; token creation and
  the new GET /api/v1/health are public
- Legacy routes use the same handlers, are hidden from the spec and keep
  the Deprecation header
- /sync/reset is hidden (debug only); the /sync/new, /sync/quick and
  /sync/new/full aliases are removed (use /sync and /sync/full)
- Invalid parameters return 422 (validation); every error is
  {"error": "..."}; empty lists are [] instead of null
- /sync/progress is documented as progress or result (oneOf)
- Tests validate the spec and check real responses of every documented
  operation against it (kin-openapi)
- Removed swag annotations, cmd/docs, echo-swagger and the swag tool
2026-10-06 16:31:06 +02:00
Sansan 0ec2425f78 Return every error as {"error": "..."}
Echo errors, middleware and handlers used three different formats (message object, error object, bare string). One error handler now writes all of them the same way; status codes are unchanged.
2026-10-06 16:21:14 +02:00
Sansan bc7d406e41 Remove Godot OpenAPI generator script
It produced code that doesn't parse in Godot 4. Typed response classes will be generated in MusicPlayer instead (Sansan/MusicPlayer#40).
2026-10-06 16:12:05 +02:00
Sansan 2c3e97190d Prefer UUIDs in the API (Phase 3 of the UUID migration)
CI / docker (push) Successful in 46s
CI / integration (push) Successful in 23s
CI / test (push) Successful in 30s
CI / publish (push) Skipped
- New /api/v1 endpoints: GET /soundtracks, /soundtracks/{uuid},
  /songs/{uuid} and /songs/{uuid}/file (streams the song, Range support,
  locked during sync)
- UUIDs added to every response with soundtracks or songs: queue info and
  list (SoundtrackUuid, SongUuid) and statistics (soundtrack_uuid,
  song_uuid). Existing fields stay for backward compatibility
- Play counts and broken-song removal use song UUIDs instead of
  soundtrack ID + song name, so songs with the same name are counted
  separately
- Statistics return an empty song list for soundtracks without songs
  instead of a single empty entry
- The legacy .id file cleanup stays until Phase 4 (#31)

Closes #29
2026-10-06 15:54:41 +02:00
Sansan 8c974a49cc Merge workflows into one CI pipeline
CI / test (push) Successful in 31s
CI / integration (push) Successful in 39s
CI / publish (push) Skipped
CI / docker (push) Successful in 54s
- Unit tests, integration tests and the Docker build check run in
  parallel on branches and pull requests
- Integration tests run on every push instead of only manually
- Branch builds only build amd64 and check the arm64 cross-compile in the
  test job; both platforms are built and pushed only for version tags,
  after all tests pass
- Docker layers cached through the runner cache, Go module and build
  caches mounted in the Dockerfile
- A newer push to the same branch cancels the running pipeline
2026-10-06 15:35:32 +02:00
Sansan 9db61956d3 Publish Docker image when a version tag is pushed
Build / test (push) Successful in 8s
Build / docker (push) Successful in 49s
Releases are triggered by tags like v5.0.0 instead of version branches.
2026-10-06 15:24:06 +02:00
Sansan bd250ecaee Run tests in CI and build multi-arch Docker images
Build / test (push) Successful in 38s
Build / docker (push) Successful in 2m2s
- Build (main, develop): vet and unit tests, then a linux/amd64 and
  linux/arm64 image build without pushing
- Publish (version branches): same tests, then build and push both
  platforms
- Integration tests (manual): run the testcontainers suite
2026-10-06 15:22:13 +02:00
Sansan 59dfff38bc Clean up build tooling and Dockerfile
- Dockerfile cross-compiles Go for the target platform (amd64/arm64
  without emulation), uses templ pinned in go.mod, runs as uid 1000 on
  alpine and lets FRONTEND_IMAGE pin the frontend version
- justfile: tools via go tool, `test` (unit) and `test-integration`
  (uses the active docker context), no hardcoded paths, no tailwind or
  frontend recipes
- Removed app.yaml, init.sh, tailwind.config.js and the tracked .idea
  folder
2026-10-06 15:21:46 +02:00
Sansan 7b144ae419 Rewrite tests to run without a database
- Unit tests use an in-memory fake database (internal/testutil/fakedb),
  temp folders and httptest; `go test ./...` needs no Docker or env vars
- Integration tests (build tag "integration") start PostgreSQL with
  testcontainers: migrations step by step, SQL dumps (skipped if
  missing) and a full sync against a real database
- Removed tests that only checked copies of the logic or had empty
  bodies, the broken root integration_test.go, compose.test.yaml and
  .env.test with hardcoded paths
- testMusic MP3s replaced with tiny placeholders (sync never decodes
  audio), 194 MB -> 168 KB
2026-10-06 15:20:31 +02:00
Sansan 090e794460 Restructure backend into services and fix security, crash and sync issues
Security
- Serve character images through os.Root so names like ../ can't escape
  the characters folder
- Sync start and /sync/reset are POST only (legacy and /api/v1)
- /api/v1/token/cleanup requires a token, password compared in constant
  time, tokens no longer logged
- Echo's rate limiter replaces the custom one; TRUSTED_PROXIES enables
  X-Forwarded-For for reverse proxies

Crashes and races
- Sync state lives in SyncService with atomics and a mutex instead of
  unsynchronised globals (fixes concurrent map writes during full sync)
- Only one sync can run; /api/v1 sync and music routes are locked during
  sync like the legacy ones
- No log.Fatal outside startup: errors become 4xx/5xx responses
- Search uses an in-order character match instead of unescaped regexes
- Empty queue / no songs return 404 instead of panicking or looping

Behaviour
- Sync result is computed once and stays the same between polls
- Swagger and /openapi serve the embedded spec
- Shutdown stops HTTP before closing the database
- Expired tokens are deleted with a context that outlives the request
- Files are served with Range support and correct content types; audio
  has no write deadline

Performance
- Migration 000006 adds soundtrack.fingerprint (names, sizes, mtimes) so
  unchanged folders are skipped without reading any files
- Songs are reconciled per soundtrack with one query plus needed writes;
  renames keep play counts
- Moved MUSIC_PATH updates soundtrack and song paths
- .id cleanup only runs for changed soundtracks or a full sync
- Classic random uses one SQL query; Gitea release lookups are cached
  with a timeout

Structure
- internal/config reads all environment variables once
- sqlc emits a Querier interface; backend globals become services
  injected into handlers
- One route registration shared by legacy and /api/v1
- Removed dead code (dbHelper.go, unused middleware, duplicate Gitea
  functions, embedded Swagger UI copy) and lib/pq
- templ and swag pinned as go tools
2026-10-06 15:20:14 +02:00
Sansan 75b6f0c1cf Remove frontend source from cmd
The frontend is built separately and copied into the Docker image from
the musicfrontend image.
2026-10-06 15:19:49 +02:00
Sansan 2406fe9eb6 Ignore database dumps
Build / build (push) Failing after 34s
2026-10-05 18:49:15 +02:00
Sansan 581d91f78b Fixed workflow file
Build / build (push) Successful in 39s
Publish / publish (push) Successful in 49s
2026-09-26 17:16:23 +02:00
Sansan a8a2602f50 #9 Major routes refactor and expansion, #15 Added API for statistics, Added search cache backend and functionality tests, Backend sync improvements
Build / build (push) Successful in 56s
2026-09-26 16:48:40 +02:00
Sansan e86c0f8e04 Combine Issue #28 (UUID Phase 2 - NOT NULL) into migration 000005
- Add NOT NULL constraints to soundtrack.uuid, song.uuid, and song.soundtrack_uuid
- Add corresponding DROP NOT NULL in down migration
- Update header comments to reflect combined Phase 1 & 2

This eliminates the need for a separate migration 000007 while maintaining
proper rollback capability. The NOT NULL constraints are added AFTER
all UUID backfills are complete, ensuring data integrity.

Generated by Mistral Vibe.
Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
2026-07-28 14:16:04 +02:00
Sansan eda60e0c07 Added fuzzy finder to search, made sync check as middleware, .id file is never used
Build / build (push) Successful in 45s
2026-07-02 09:30:24 +02:00
Sansan a8df738108 #9 Changed the term game to soundtrack everywhere
Build / build (push) Successful in 45s
2026-06-29 18:39:09 +02:00
Sansan dbef39b828 Merge pull request 'Feature/statistics api' (#26) from feature/statistics-api into develop
Build / build (push) Successful in 51s
Reviewed-on: #26
2026-06-14 11:48:36 +02:00
Sansan 4e5bdc4ee2 Fixed some small bugs after merge 2026-06-14 11:30:58 +02:00
Sansan 0894d65ec5 Merge branch 'develop' into feature/statistics-api
# Conflicts:
#	internal/backend/music.go
#	internal/backend/sync.go
#	internal/server/server.go
#	internal/server/syncHandler.go
#	internal/server/sync_handler_test.go
#	internal/server/test_helpers.go
#	internal/server/zz_music_handler_test.go
2026-06-13 11:51:56 +02:00
Sansan 4033899a68 Merge pull request 'Feature/session token api' (#25) from feature/session-token-api into develop
Build / build (push) Successful in 50s
Reviewed-on: #25
2026-06-13 11:30:08 +02:00
Sansan c6a07e69e7 Fixed some small bugs. Frontend is now included in the docker image 2026-06-13 11:26:52 +02:00
Sansan 6d4a034753 Fix duplicate import in routes.go
Generated by Mistral Vibe.
Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
2026-06-08 20:44:17 +02:00
SansanandMistral Vibe b0418b4f38 feat: Add id column to song table and prep for UUID migration
- Add id serial4 PK to song table (was composite PK)
- Update queries to use soundtrack_id + path
- Add UUID columns to soundtrack and song (nullable)
- Add migration tracking table

TODO: Run sqlc generate, then create backfill migration (000008)

Generated by Mistral Vibe.
Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
2026-06-08 20:36:12 +02:00
Sansan 176848bb6d feat: Add deprecation notice for global Dbpool and Ctx variables
- Enhanced TODO comment to clearly mark Dbpool and Ctx as DEPRECATED
- Direct developers to use Database struct from database.go instead
- Migration test already includes manual data insertion (5 games, 8 songs)

Generated by Mistral Vibe.
Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
2026-06-08 20:36:12 +02:00
SansanandMistral Vibe fb387901cf test: Add migration test with manual data insertion
- TestMigrationsStepByStep: tests incremental migration workflow
  - Step 1: Apply first 4 migrations (creates game, song tables)
  - Step 2: Manually insert 5 games with 8 songs
  - Step 3: Apply migration 5 (rename game→soundtrack)
  - Step 4: Verify data preserved in soundtrack table
- Helper functions: cleanupDB, createTestDB, applyMigrations
- Tests data integrity through full migration cycle

Requires: DB_HOST, DB_PORT, DB_USERNAME, DB_PASSWORD env vars
Run: migrate -path internal/db/migrations -database "postgres://user:pass@host:port/db?sslmode=disable" up N

Generated by Mistral Vibe.
Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
2026-06-08 20:36:12 +02:00
Sansan 0f29c33b1a test: Add statistics test with manual data insertion
- TestStatisticsEndpoints: tests /api/v1/statistics/summary endpoint
- TestPartialMigrationThenSyncThenComplete: tests migration + sync workflow
- insertTestData: helper to insert 5 soundtracks with 8 songs
- getTestToken: helper to get auth token for tests
- Updated other test files to use FindAllSoundtracks instead of FindAllGames

Generated by Mistral Vibe.
Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
2026-06-08 20:36:12 +02:00
Sansan cec408187d feat: Rename game to soundtrack throughout codebase
- Database migration: rename game table to soundtrack
- Rename game_name to soundtrack_name, game_id to soundtrack_id
- Update all SQL queries in soundtrack.sql, song.sql, song_list.sql, statistics.sql
- Regenerate sqlc code (soundtrack.sql.go, song.sql.go, etc.)
- Update backend: music.go, sync.go, statistics.go
- Update server: musicHandler.go, syncHandler.go, routes.go
- Update frontend: hello.go
- Keep URL paths as /games for backward compatibility

Generated by Mistral Vibe.
Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
2026-06-08 20:36:12 +02:00
Sansan c60f40d7e3 feat: Complete DI cleanup - migrate test helpers to Database struct
- Update internal/db/test_helpers.go to use Database struct instead of globals
- Update internal/server/test_helpers.go to use TestDatabase.Pool
- Add TODO comment to old Dbpool/Ctx globals in dbHelper.go
- Remove db.Testf() usage from production code (kept for deprecated /dbtest endpoint)

Generated by Mistral Vibe.
Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
2026-06-08 20:36:12 +02:00
Sansan 2f407f6eef feat: Add deprecation middleware for legacy endpoints
- Create middleware/deprecation.go with DeprecationMiddleware
- Adds Warning and Deprecation headers to old endpoints
- Apply middleware to all non-/api/v1 routes:
  /version, /dbtest, /health, /character*, /download*, /sync/*,
  /music/*
- Message: 'Deprecated: This endpoint is deprecated. Use /api/v1/ endpoints instead.'

Generated by Mistral Vibe.
Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
2026-06-08 20:36:12 +02:00
Sansan 4c2db11cc5 feat: Implement Statistics API with 8 endpoints under /api/v1/statistics/
- Add statistics.sql with 8 SQL queries for play count statistics
- Generate repository code via sqlc
- Add backend/statistics.go with business logic
- Add server/statistics_handler.go with Echo handlers
- Register protected routes under /api/v1/statistics/ with token auth
- Endpoints: games/most-played, games/least-played, games/never-played,
  games/last-played, games/oldest-played, songs/most-played,
  songs/least-played, summary

Generated by Mistral Vibe.
Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
2026-06-08 20:33:29 +02:00
Sansan 06cbad708d feat: Remove global db.Dbpool with dependency injection (Phase 0)
- Add Database struct in internal/db/database.go with Pool, Ctx, and RunMigrations()
- Update server.go to use Database struct with NewServerInstance()
- Add backend.go with InitBackend(), BackendRepo(), BackendCtx(), BackendPool()
- Update music.go and sync.go to use BackendRepo() and BackendCtx() instead of db.Dbpool/db.Ctx
- Update token_handler.go to accept pool parameter
- Update routes.go to use s.db.Pool for middleware
- Update cmd/main.go to use NewServerInstance() and HTTPServer()
- Update test_helpers.go to initialize backend with test database
- Update test files to use backend.BackendPool() and backend.BackendCtx()

Benefits:
- Easier to mock database for unit tests
- Follows Go best practices (dependency injection)
- Better architecture with explicit dependencies
- RunMigrations() replaces old Migrate_db() function

Note: Global db.Dbpool and db.Ctx still exist in dbHelper.go for backward compatibility
with test_helpers.go, but production code no longer uses them.

Generated by Mistral Vibe.
Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
2026-06-08 20:33:29 +02:00
Sansan 89e884fae9 feat: Implement Session Token System with /api/v1 base path
- Add migration 000004 for sessions table and performance indexes
- Create session.sql queries for CRUD operations
- Generate session repository code with sqlc
- Create token auth middleware for Echo framework
- Create token handler with create/delete/cleanup endpoints
- Add /api/v1 router with token authentication infrastructure
- Update dbHelper.go to use Up() instead of Migrate(2)
- Update server.go to initialize token handler
- Existing endpoints remain functional (to be deprecated)

New endpoints:
- POST /api/v1/token - Create new session token
- DELETE /api/v1/token - Invalidate token
- POST /api/v1/token/cleanup - Remove expired sessions

Generated by Mistral Vibe.
Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
2026-06-08 20:33:29 +02:00
Sansan 24a9111333 feat: Remove global db.Dbpool with dependency injection (Phase 0)
- Add Database struct in internal/db/database.go with Pool, Ctx, and RunMigrations()
- Update server.go to use Database struct with NewServerInstance()
- Add backend.go with InitBackend(), BackendRepo(), BackendCtx(), BackendPool()
- Update music.go and sync.go to use BackendRepo() and BackendCtx() instead of db.Dbpool/db.Ctx
- Update token_handler.go to accept pool parameter
- Update routes.go to use s.db.Pool for middleware
- Update cmd/main.go to use NewServerInstance() and HTTPServer()
- Update test_helpers.go to initialize backend with test database
- Update test files to use backend.BackendPool() and backend.BackendCtx()

Benefits:
- Easier to mock database for unit tests
- Follows Go best practices (dependency injection)
- Better architecture with explicit dependencies
- RunMigrations() replaces old Migrate_db() function

Note: Global db.Dbpool and db.Ctx still exist in dbHelper.go for backward compatibility
with test_helpers.go, but production code no longer uses them.

Generated by Mistral Vibe.
Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
2026-06-08 20:15:38 +02:00
Sansan 6cc014ffa3 feat: Implement Session Token System with /api/v1 base path
- Add migration 000004 for sessions table and performance indexes
- Create session.sql queries for CRUD operations
- Generate session repository code with sqlc
- Create token auth middleware for Echo framework
- Create token handler with create/delete/cleanup endpoints
- Add /api/v1 router with token authentication infrastructure
- Update dbHelper.go to use Up() instead of Migrate(2)
- Update server.go to initialize token handler
- Existing endpoints remain functional (to be deprecated)

New endpoints:
- POST /api/v1/token - Create new session token
- DELETE /api/v1/token - Invalidate token
- POST /api/v1/token/cleanup - Remove expired sessions

Generated by Mistral Vibe.
Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
2026-06-08 20:15:38 +02:00
Sansan 8f8b555ea5 Refactor handlers and update changelog for 5.0.0-Beta
Build / build (push) Successful in 48s
- Split IndexHandler into HealthHandler, VersionHandler, and CharacterHandler
- Rename index.go to version.go in backend
- Change VersionData.Changelog from string to []string
- Add changelog entries for issues #16-#23
- Remove TestDB function and related code
- Fix import ordering in several files

Closes #21, #22
References #16, #17, #18, #19, #20, #23

Generated by Mistral Vibe.
Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
2026-06-08 20:08:06 +02:00
Sansan a446dad7b6 Make pool and poolSong global variables
Build / build (push) Successful in 48s
2026-05-26 20:54:12 +02:00
Sansan d152ec1f11 fix: use podman-compose (installed via Homebrew) instead of podman compose
Build / build (push) Successful in 45s
2026-05-23 21:57:15 +02:00
Sansan 7a3934babf fix: use 'podman compose' instead of 'podman-compose'
Build / build (push) Successful in 41s
2026-05-23 20:18:25 +02:00
Sansan 08f539abd9 test: add justfile commands for running integration tests with podman
Build / build (push) Successful in 43s
2026-05-23 20:02:25 +02:00
Sansan 87a1a2d89a test: reduce testMusic size for faster CI runs
Build / build (push) Successful in 47s
2026-05-23 19:41:10 +02:00
Sansan 1ada52f5f8 test: add test data directories (testMusic and testCharacters) 2026-05-23 01:06:43 +02:00
Sansan 92b82da3af test: add simple unit tests for backend and logging packages
Build / build (push) Successful in 31s
2026-05-22 22:49:25 +02:00
Sansan b71072f6c8 fix: remove tailwind from dockerfile and add podman-build command
Build / build (push) Successful in 33s
2026-05-22 22:31:10 +02:00
Sansan d481be04a7 Fix YAML formatting in Gitea workflows
Build / build (push) Failing after 2m7s
2026-05-21 23:45:23 +02:00
Sansan 870f1787cb Fix for workflow 2026-05-21 23:35:26 +02:00
Sansan 89c31c2856 Replace all log.Println and fmt.Printf with Zap structured logging 2026-05-21 23:24:55 +02:00
Sansan f0653489d6 Added some files 2026-05-21 22:25:31 +02:00
Sansan d0fbba86f1 Remove frontend-build from build command 2026-05-21 09:56:23 +02:00
Sansan bd0e7f4a8d Add frontend-build command to justfile 2026-05-21 09:54:12 +02:00
Sansan b5926e3b31 Fix frontend build by updating dependencies and ESLint configuration 2026-05-21 09:51:14 +02:00
Sansan 37909139de Add Zap logging framework with structured logging for Echo and Grafana 2026-05-20 22:29:45 +02:00
Sansan 82252ce1ff Use latest for templ CLI in justfile 2026-05-20 22:08:37 +02:00
Sansan 1dab9d6e7c Update all dependencies including templ CLI to latest versions 2026-05-20 22:05:39 +02:00
Sansan b80ad90eab Add echo-swagger/v2 for Echo v5 compatibility 2026-05-20 22:00:52 +02:00
Sansan 2cff8d16d7 Upgrade Echo framework from v4 to v5 2026-05-20 21:56:06 +02:00
Sansan 12f18ba12c Replace Tailwind CSS with pure CSS for frontend 2026-05-20 21:30:20 +02:00
Sansan 6e2c381d90 Update generate_godot_openapi.py to pass base_url as parameter to _init 2026-05-20 21:23:09 +02:00
Sansan efca22834b Update generate_godot_openapi.py to take file input and generate one file per API tag 2026-05-20 21:19:20 +02:00
Sansan e57609725e Add Swag annotations to all handler endpoints for OpenAPI documentation 2026-05-18 21:50:53 +02:00
Sansan fabd6a6931 Fix OpenAPI endpoint to serve swagger.json directly 2026-05-18 21:46:51 +02:00
Sansan f03e001bdd Add swag-generate to justfile and include in build 2026-05-18 21:44:58 +02:00
Sansan 1d77ae491c Add OpenAPI endpoint at /openapi with Swagger documentation 2026-05-18 21:43:06 +02:00
Sansan c0d1aaa4d1 Update Echo framework to v5.1.1 2026-05-18 21:36:50 +02:00
Sansan 76aaa884fa Change domain from sanplex.tech to sanplex.xyz 2026-05-18 21:27:34 +02:00
Sansan 290d79ef5e Changed how time are sent to frontend during sync
Build / build (push) Successful in 40s
2025-11-15 14:55:03 +01:00
Sansan aa0b8275e7 Fix so that ending slash doesn't matter for characters path
Build / build (push) Successful in 40s
2025-11-08 12:04:44 +01:00
Sansan c369b13fae Added characters to Dockerfile
Build / build (push) Successful in 39s
Publish / publish (push) Successful in 47s
2025-11-08 11:54:51 +01:00
Sansan bef915ac6d Fixed gitea script
Build / build (push) Successful in 39s
2025-11-07 21:10:40 +01:00
Sansan cff777f278 Small fixes to getting character images
Build / build (push) Successful in 44s
Publish / publish (push) Successful in 51s
2025-11-07 20:24:46 +01:00
Sansan 61cab73ffc Small fix to update song played
Build / build (push) Successful in 50s
2025-10-26 20:40:48 +01:00
Sansan a6294e46f2 Small changes to sync progress
Build / build (push) Successful in 52s
2025-09-19 22:10:27 +02:00
Sansan 5f91643b4d Added time to sync and progress respond
Build / build (push) Successful in 1m58s
2025-08-30 13:36:45 +02:00
Sansan 806e88adeb #1 - Created request to check newest version of the app
Build / build (push) Successful in 2m35s
#2 - Added request to download the newest version of the app
#3 - Added request to check progress during sync
#4 - Now blocking all request while sync is in progress
#5 - Implemented ants for thread pooling
#6 - Changed the sync request to now only start the sync
2025-08-23 11:36:03 +02:00
Sansan 0d1c69d95e Fix 25
Build / build (push) Successful in 42s
Publish / publish (push) Successful in 57s
2025-06-07 22:31:29 +02:00
Sansan b024c0b747 Fixed go.mod 2025-06-05 13:18:21 +02:00
Sansan 75ee924783 Added little logging 2025-06-05 13:15:15 +02:00
Sansan f86c33d5e6 Removed gitea-ci 2025-06-05 13:15:15 +02:00
Sansan ef41d0fa11 Fix 24 2025-06-05 13:15:15 +02:00
Sansan fd666dd3fa Fix 23 2025-06-05 13:15:15 +02:00
Sansan 231867de40 Fix 22 2025-06-05 13:15:15 +02:00
Sansan 9a9d318771 Fix 21 2025-06-05 13:15:15 +02:00
Sansan f06a7fe927 Fix 20 2025-06-05 13:15:15 +02:00
Sansan 0f017407ff Fix 19 2025-06-05 13:15:15 +02:00
Sansan 29ba39f5fe Fix 18 2025-06-05 13:15:15 +02:00
Sansan 8d01fe100a Fix 17 2025-06-05 13:15:15 +02:00
Sansan 2821774215 Fix 16 2025-06-05 13:15:15 +02:00
Sansan 00f0981ce4 Fix 15 2025-06-05 13:15:15 +02:00
Sansan 53a9031cb0 Fix 14 2025-06-05 13:15:15 +02:00
Sansan 85204026bb Fix 13 2025-06-05 13:15:15 +02:00
Sansan 1ffddd1154 Testar release 2025-06-05 13:15:15 +02:00
Sansan a4ef66a3f8 Fix 12 2025-06-05 13:15:15 +02:00
Sansan 478de6e3d4 Fix 11 2025-06-05 13:15:12 +02:00
Sansan 052b699025 Even more Actions 2025-06-05 13:11:38 +02:00
Sansan 999668fc9c Actions tests 2025-06-05 13:11:38 +02:00
Sansan 11e6233753 More gitea actions 2025-06-05 13:11:38 +02:00
Sansan 3f73ea1f5e Started added gitea actions 2025-06-05 13:10:06 +02:00
Sansan d15d1422da Added function to create a new database if it doesn't exist 2025-04-13 18:39:30 +02:00
Sansan 73d85adc42 Updated dockerfile to make sure that it works after all changes 2025-01-28 15:33:25 +01:00
Sansan d653463f58 Moved around more code. Implemented more sqlc. Added support to generate swagger.
Added support for profiling. Removed the pkg module altogether.
Everything except old sync is now using code generated by sqlc.
2025-01-15 16:04:14 +01:00
Sansan db8214cb02 Added support for fetching character images from the server 2025-01-14 10:01:48 +01:00
Sansan 5b640375c3 Reorganized the code, moved more things to the new part 2025-01-13 16:08:54 +01:00
Sansan 034ba35fbb Replaced the gin framwwork with echo 2025-01-13 11:57:48 +01:00
Sansan 8e2d22b899 Updated .gitignore and added justfile 2025-01-09 14:34:43 +01:00
Sansan 5577070b8d Changed addPlayed 2024-12-31 13:25:46 +01:00
Sansan 59ff51393f Removed logging 2024-12-30 18:01:12 +01:00
Sansan 26c5e6e4ef Small change on search page 2024-12-29 09:43:20 +01:00
Sansan a5f8e1b2ba Added search
Added a search page and fixed som error with migration
2024-12-26 14:55:47 +01:00
Sansan 2a537d2398 Fixed error with docker 2024-12-19 12:55:17 +01:00
Sansan 5ab19e16e5 Added a new sync that uses hash
Added a new sync that uses hash and sqlc for the queries. Added db
migration. Started adding a config file.
2024-12-19 12:11:20 +01:00
Sansan 8fa93d580d Added concurrent sync, added search page. Other small changes 2024-10-04 20:19:40 +02:00
Sansan fafa044c9b Removed som logging during sync 2024-08-17 19:19:57 +02:00
237 changed files with 17554 additions and 34312 deletions

No files matched your search

+1 -1
View File
@@ -6,7 +6,7 @@ tmp_dir = "tmp"
bin = "./tmp/main" bin = "./tmp/main"
cmd = "go build -o ./tmp/main ./cmd" cmd = "go build -o ./tmp/main ./cmd"
delay = 1000 delay = 1000
exclude_dir = ["assets", "tmp", "vendor", "testdata", "frontend", "swagger", "cmd/frontend", "cmd/swagger"] exclude_dir = ["assets", "tmp", "vendor", "testdata"]
exclude_file = [] exclude_file = []
exclude_regex = ["_test.go"] exclude_regex = ["_test.go"]
exclude_unchanged = false exclude_unchanged = false
+25
View File
@@ -0,0 +1,25 @@
# Directories
.gitea
git
.idea
testMusic
testCharacters
# Files
Dockerfile
docker-compose*
compose.yaml
.dockerignore
.gitignore
*.pprof
main
conf.yaml
.env
# Test files and fixtures
*_test.go
internal/testutil
*_dump.sql
# OS
.DS_Store
+107
View File
@@ -0,0 +1,107 @@
name: CI
# Branches and pull requests: unit tests, integration tests and a check that the image builds (amd64 only).
# Version tags (v1.2.3): the same tests, then build amd64 + arm64 and push the image.
on:
push:
branches:
- main
- develop
tags:
- "v*.*.*"
pull_request:
workflow_dispatch:
# A newer push to the same branch cancels the run that is still going.
concurrency:
group: ci-${{ gitea.ref }}
cancel-in-progress: true
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version-file: go.mod
- name: Generate templ components
run: go tool templ generate
- name: Vet
run: go vet ./... && go vet -tags integration ./...
- name: Unit tests
run: go test -race ./...
- name: Cross-compile for arm64
run: GOOS=linux GOARCH=arm64 CGO_ENABLED=0 go build -o /dev/null ./cmd
integration:
runs-on: ubuntu-latest
env:
# The test helper stops its own container, so the reaper container is not needed.
TESTCONTAINERS_RYUK_DISABLED: "true"
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version-file: go.mod
- name: Generate templ components
run: go tool templ generate
- name: Integration tests (PostgreSQL via testcontainers)
run: go test -tags integration -race -timeout 15m ./internal/db/... ./internal/backend/...
# Checks that the image builds. Runs in parallel with the tests; nothing is pushed.
docker:
if: ${{ !startsWith(gitea.ref, 'refs/tags/') }}
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: docker/setup-buildx-action@v3
with:
config-inline: |
[registry."gitea.sanplex.xyz/sansan"]
http = true
insecure = true
- name: Login to Gitea
uses: docker/login-action@v3
with:
registry: gitea.sanplex.xyz
username: ${{ github.repository_owner }}
password: ${{ secrets.TOKEN }}
- name: Build (amd64)
uses: docker/build-push-action@v6
with:
context: .
platforms: linux/amd64
push: false
cache-from: type=gha
cache-to: type=gha,mode=max,ignore-error=true
# Only for version tags, and only when all tests have passed.
publish:
if: ${{ startsWith(gitea.ref, 'refs/tags/v') }}
needs: [test, integration]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: docker/setup-buildx-action@v3
with:
config-inline: |
[registry."gitea.sanplex.xyz/sansan"]
http = true
insecure = true
- name: Login to Gitea
uses: docker/login-action@v3
with:
registry: gitea.sanplex.xyz
username: ${{ github.repository_owner }}
password: ${{ secrets.TOKEN }}
- name: Build and push (amd64 + arm64)
uses: docker/build-push-action@v6
with:
context: .
platforms: linux/amd64,linux/arm64
push: true
cache-from: type=gha
tags: |
gitea.sanplex.xyz/sansan/musicserver:${{ gitea.ref_name }}
gitea.sanplex.xyz/sansan/musicserver:latest
+19 -1
View File
@@ -1 +1,19 @@
tmp tmp
.DS_Store
.idea
*templ.go
conf.yaml
compose.yaml
.env
cpu.pprof
main
# Database dumps
*_dump.sql
# Generated with `just openapi`
/openapi.json
/openapi-3.0.json
# Local cover images (COVERS_PATH)
/covers/
-8
View File
@@ -1,8 +0,0 @@
# Default ignored files
/shelf/
/workspace.xml
# Editor-based HTTP Client requests
/httpRequests/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml
-16
View File
@@ -1,16 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<module version="4">
<component name="Go" enabled="true">
<buildTags>
<option name="customFlags">
<array>
<option value="prod" />
</array>
</option>
</buildTags>
</component>
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>
-5
View File
@@ -1,5 +0,0 @@
<component name="ProjectCodeStyleConfiguration">
<state>
<option name="PREFERRED_PROJECT_CODE_STYLE" value="Default" />
</state>
</component>
-29
View File
@@ -1,29 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="DataSourceManagerImpl" format="xml" multifile-model="true">
<data-source source="LOCAL" name="music_prod@192.168.86.100" uuid="e63caf71-2b1a-400d-9cc4-4b87b1f9b807">
<driver-ref>postgresql</driver-ref>
<synchronize>true</synchronize>
<jdbc-driver>org.postgresql.Driver</jdbc-driver>
<jdbc-url>jdbc:postgresql://192.168.86.100:5432/music_prod</jdbc-url>
</data-source>
<data-source source="LOCAL" name="music_test@192.168.86.100" uuid="d063e147-d7f0-48db-9f04-57a108261ef1">
<driver-ref>postgresql</driver-ref>
<synchronize>true</synchronize>
<jdbc-driver>org.postgresql.Driver</jdbc-driver>
<jdbc-url>jdbc:postgresql://192.168.86.100:5432/music_test</jdbc-url>
</data-source>
<data-source source="LOCAL" name="music_test@ssh.sanplex.xyz" uuid="a9cf3eb8-abc2-479b-9f27-12b4cbbfc321">
<driver-ref>postgresql</driver-ref>
<synchronize>true</synchronize>
<jdbc-driver>org.postgresql.Driver</jdbc-driver>
<jdbc-url>jdbc:postgresql://ssh.sanplex.xyz:9432/music_test</jdbc-url>
</data-source>
<data-source source="LOCAL" name="music_prod@ssh.sanplex.xyz" uuid="20917ace-4e9a-4273-bdb7-13ebc774cbba">
<driver-ref>postgresql</driver-ref>
<synchronize>true</synchronize>
<jdbc-driver>org.postgresql.Driver</jdbc-driver>
<jdbc-url>jdbc:postgresql://ssh.sanplex.xyz:9432/music_prod</jdbc-url>
</data-source>
</component>
</project>
-8
View File
@@ -1,8 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/MusicServer.iml" filepath="$PROJECT_DIR$/.idea/MusicServer.iml" />
</modules>
</component>
</project>
Generated
-6
View File
@@ -1,6 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>
+38 -25
View File
@@ -1,30 +1,43 @@
FROM golang:1.22.2-alpine as build_go # The frontend is built and published separately. Bump this when a new frontend is released.
ARG FRONTEND_IMAGE=gitea.sanplex.xyz/sansan/musicfrontend:v1.3.0
COPY go.* /music-server/ # Stage 1: Build the backend on the build machine and cross-compile for the target platform,
COPY ./cmd/*.go /music-server/cmd/ # so multi-platform builds need no emulation.
COPY ./cmd/swagger /music-server/cmd/swagger FROM --platform=$BUILDPLATFORM golang:1.26-alpine AS build
COPY ./pkg /music-server/pkg/ ARG TARGETOS TARGETARCH
WORKDIR /app
COPY go.mod go.sum ./
RUN --mount=type=cache,target=/go/pkg/mod go mod download
COPY cmd/ ./cmd/
COPY internal/ ./internal/
RUN --mount=type=cache,target=/go/pkg/mod --mount=type=cache,target=/root/.cache/go-build \
go tool templ generate
RUN --mount=type=cache,target=/go/pkg/mod --mount=type=cache,target=/root/.cache/go-build \
CGO_ENABLED=0 GOOS=$TARGETOS GOARCH=$TARGETARCH \
go build -trimpath -ldflags="-s -w" -tags timetzdata -o main ./cmd
#WORKDIR /music-server/ # Stage 2: Frontend static files (the same for every platform)
#RUN go mod download FROM --platform=$BUILDPLATFORM ${FRONTEND_IMAGE} AS frontend
WORKDIR /music-server/cmd # Stage 3: Final image. No RUN steps here, so no emulation is needed for other architectures.
FROM alpine:3.22
RUN go build -o /music-server/MusicServer COPY --from=build /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
WORKDIR /app
# Stage 2, distribution container COPY --from=build /app/main .
FROM golang:1.16-alpine COPY --from=frontend /usr/share/nginx/html /frontend
EXPOSE 8080
VOLUME /sorted
VOLUME /frontend
ENV DB_HOST ""
ENV DB_PORT ""
ENV DB_USERNAME ""
ENV DB_PASSWORD ""
ENV DB_NAME ""
COPY --from=build_go /music-server/MusicServer .
COPY ./songs/ ./songs/ COPY ./songs/ ./songs/
CMD ./MusicServer # The music volume must be readable by uid 1000, and writable for the .id file cleanup during sync.
USER 1000:1000
EXPOSE 8080
# Prometheus metrics (METRICS_PORT). Keep it off the public proxy.
EXPOSE 2112
VOLUME /sorted
VOLUME /characters
# Required: DB_HOST, DB_PORT, DB_USERNAME, DB_PASSWORD, DB_NAME, MUSIC_PATH, CHARACTERS_PATH
# Covers (optional): COVERS_PATH, a writable folder such as a /covers volume, turns covers on.
# STEAMGRIDDB_API_KEY also turns on the automatic search (SteamGridDB, then AniList).
ENV PORT=8080
CMD ["./main"]
-8
View File
@@ -1,8 +0,0 @@
application: musicserver
version: 2.2.0
runtime: go115
api_version: go1
handlers:
- url: /.*
script: _go_app
-21
View File
@@ -1,21 +0,0 @@
.DS_Store
node_modules
/dist
# local env files
.env.local
.env.*.local
# Log files
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
# Editor directories and files
.vscode
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
-24
View File
@@ -1,24 +0,0 @@
# music-randomizer-vue
## Project setup
```
npm install
```
### Compiles and hot-reloads for development
```
npm run serve
```
### Compiles and minifies for production
```
npm run build
```
### Lints and fixes files
```
npm run lint
```
### Customize configuration
See [Configuration Reference](https://cli.vuejs.org/config/).
-5
View File
@@ -1,5 +0,0 @@
module.exports = {
presets: [
'@vue/cli-plugin-babel/preset'
]
}
-26
View File
@@ -1,26 +0,0 @@
const express = require("express");
const path = require("path");
const routes = require("./routes.js");
const app = express();
const cors = require("cors");
/* const bodyParser = require("body-parser"); */
const PORT = process.env.PORT || 5005;
const mainUrl = "test";
console.log(`Server started on port ${PORT}`);
//app.use(bodyParser.json());
//Routes
/* app.use(express.static(path.join(__dirname, "public"))); */
/* app.use(express.static(path.join(__dirname, "assets"))); */
app.use(express.static(path.join(__dirname)));
app.use(express.static(path.join(__dirname, "dist")));
/* app.use(express.static(path.join(__dirname, "public"))); */
/* console.log(__dirname); */
app.use(cors());
app.use(routes);
app.listen(PORT, "0.0.0.0");
-29100
View File
File diff suppressed because it is too large. Load diff
-51
View File
@@ -1,51 +0,0 @@
{
"name": "music-randomizer-vue",
"version": "0.1.0",
"private": true,
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build",
"lint": "vue-cli-service lint"
},
"dependencies": {
"axios": "^0.21.1",
"config.js": "^0.1.0",
"core-js": "^3.8.2",
"cors": "^2.8.5",
"express": "^4.17.1",
"nodemon": "^2.0.7",
"vue": "^3.0.5",
"vue-axios": "^3.2.2",
"vuex": "^4.0.0-rc.2"
},
"devDependencies": {
"@vue/cli-plugin-babel": "^4.5.10",
"@vue/cli-plugin-eslint": "^4.5.10",
"@vue/cli-service": "^4.5.10",
"@vue/compiler-sfc": "^3.0.5",
"babel-eslint": "^10.1.0",
"eslint": "^6.7.2",
"eslint-plugin-vue": "^7.4.1"
},
"eslintConfig": {
"root": true,
"env": {
"node": true
},
"extends": [
"plugin:vue/vue3-essential",
"eslint:recommended"
],
"parserOptions": {
"parser": "babel-eslint"
},
"rules": {
"no-debugger": 1
}
},
"browserslist": [
"> 1%",
"last 2 versions",
"not dead"
]
}
@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="black" width="36px" height="36px"><path d="M0 0h24v24H0z" fill="none"/><path d="M12 2C6.47 2 2 6.47 2 12s4.47 10 10 10 10-4.47 10-10S17.53 2 12 2zm5 13.59L15.59 17 12 13.41 8.41 17 7 15.59 10.59 12 7 8.41 8.41 7 12 10.59 15.59 7 17 8.41 13.41 12 17 15.59z"/></svg>

Before

Width:  |  Height:  |  Size: 330 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 103 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 109 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 222 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 224 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 151 KiB

Binary file not shown.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 302 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 129 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 161 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 136 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 185 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 101 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 788 B

Binary file not shown.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

-19
View File
@@ -1,19 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
<link rel="preconnect" href="https://fonts.gstatic.com">
<link href="https://fonts.googleapis.com/css2?family=Roboto&display=swap" rel="stylesheet">
<title><%= htmlWebpackPlugin.options.title %></title>
</head>
<body>
<noscript>
<strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
</noscript>
<div id="app"></div>
<!-- built files will be auto injected -->
</body>
</html>
@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="black" width="36px" height="36px"><path d="M0 0h24v24H0V0z" fill="none"/><path d="M7.41 8.59L12 13.17l4.59-4.58L18 10l-6 6-6-6 1.41-1.41z"/></svg>

Before

Width:  |  Height:  |  Size: 212 B

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="black" width="36px" height="36px"><path d="M0 0h24v24H0z" fill="none"/><path d="M7.41 15.41L12 10.83l4.59 4.58L18 14l-6-6-6 6z"/></svg>

Before

Width:  |  Height:  |  Size: 201 B

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 24 24" viewBox="0 0 24 24" fill="black" width="36px" height="36px"><g><rect fill="none" height="24" width="24"/></g><g><path d="M13,8c0-2.21-1.79-4-4-4S5,5.79,5,8s1.79,4,4,4S13,10.21,13,8z M15,10v2h3v3h2v-3h3v-2h-3V7h-2v3H15z M1,18v2h16v-2 c0-2.66-5.33-4-8-4S1,15.34,1,18z"/></g></svg>

Before

Width:  |  Height:  |  Size: 352 B

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 24 24" viewBox="0 0 24 24" fill="black" width="36px" height="36px"><g><rect fill="none" height="24" width="24"/></g><g><path d="M14,8c0-2.21-1.79-4-4-4S6,5.79,6,8s1.79,4,4,4S14,10.21,14,8z M17,10v2h6v-2H17z M2,18v2h16v-2c0-2.66-5.33-4-8-4 S2,15.34,2,18z"/></g></svg>

Before

Width:  |  Height:  |  Size: 333 B

Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
-147
View File
@@ -1,147 +0,0 @@
<template>
<the-header @start-sound-test="startSoundTest"></the-header>
<the-main ref="theMain"></the-main>
</template>
<script>
import TheHeader from "./components/layout/TheHeader.vue";
import TheMain from "./components/layout/TheMain.vue";
export default {
components: {
TheHeader,
TheMain,
},
data() {
return {
screenWidth: 1000,
};
},
computed: {
displayWhenDesktop() {
if (this.screenWidth > 600) {
return true;
} else {
return false;
}
},
},
methods: {
startSoundTest() {
this.$refs.theMain.startSoundTest();
},
},
mounted() {
this.screenWidth = window.innerWidth;
window.addEventListener("resize", () => (this.screenWidth = window.innerWidth));
},
};
</script>
<style>
* {
margin: 0;
padding: 0;
font-family: Helvetica;
}
button {
background: rgb(54, 54, 54);
border-radius: 10px;
border-color: #ff9c00;
color: #ff9c00;
font-size: 1em;
padding: 10px;
outline: none;
}
.app {
display: flex;
height: 100vh;
}
body {
background-color: #555;
}
/* Global modal stuff */
.modalAni-enter-from,
.modalAni-leave-to {
opacity: 0;
transform: translateY(-20px);
}
.modalAni-enter-to,
.modalAni-leave-from {
opacity: 1;
}
.modalAni-enter-active,
.modalAni-leave-active {
transition: all 0.25s ease-out;
}
.modal {
position: fixed; /* Stay in place */
z-index: 10; /* Sit on top */
left: 0;
top: 0;
width: 100%; /* Full width */
height: 100%; /* Full height */
overflow: hidden;
background-color: rgb(0, 0, 0); /* Fallback color */
background-color: rgba(0, 0, 0, 0.5); /* Black w/ opacity */
}
.modalContainer {
background-color: #eeeeee;
margin: 10% auto; /* 15% from the top and centered */
border: 1px solid #888;
width: 50%; /* Could be more or less, depending on screen size */
}
.modalWrapper {
display: flex;
position: relative;
flex-wrap: wrap;
padding: 10px 40px;
}
.modalWrapper:last-child {
margin-bottom: 50px;
}
.closeModalImg {
position: absolute;
right: 8px;
top: 8px;
cursor: pointer;
opacity: 70%;
}
.modal h1 {
color: black;
margin-left: auto;
margin-right: auto;
padding-top: 10px;
font-size: 1.9rem;
}
.modal p {
color: black;
}
@media only screen and (max-width: 1000px) {
.modalContainer {
margin: 10% auto; /* 15% from the top and centered */
width: 93%; /* Could be more or less, depending on screen size */
}
.modalWrapper {
padding: 10px 10px;
}
.modalWrapper:last-child {
margin-bottom: 10px;
}
.modal h1 {
padding-top: 10px;
font-size: 1.6rem;
}
}
</style>
-3
View File
@@ -1,3 +0,0 @@
export default {
hostname: "$HOSTNAME",
}
@@ -1,95 +0,0 @@
<template>
<!-- <div class="currentlyPlayingDiv">
<div class="textWrapper">
<transition-group name="displayingInfo" appear>
<p v-if="currentTrackHidden" :key="1">????????</p>
<p v-else :key="2">{{ currentGame }}</p>
<p v-if="currentTrackHidden" :key="3">??????</p>
<p v-else :key="4">{{ currentTrack }}</p>
</transition-group>
</div>
</div> -->
<div class="currentlyPlayingDiv">
<transition name="displayingInfo">
<div v-if="currentTrackHidden" class="textWrapper">
<p>????????</p>
<p>??????</p>
</div>
<div v-else class="textWrapper">
<p>{{ currentGame }}</p>
<p>{{ currentTrack }}</p>
</div>
</transition>
</div>
</template>
<script>
import { mapState } from "vuex";
export default {
computed: {
...mapState(["currentGame", "currentTrack", "currentTrackHidden"]),
},
};
</script>
<style scoped>
.displayingInfo-enter-from,
.displayingInfo-leave-to {
opacity: 0;
}
.displayingInfo-enter-to,
.displayingInfo-leave-from {
opacity: 1;
}
.displayingInfo-enter-active {
transition: opacity 0.7s ease-out;
}
.displayingInfo-leave-active {
display: none;
}
.currentlyPlayingDiv {
display: flex;
flex-wrap: wrap;
justify-content: center;
width: 60vw;
height: 27vh;
margin-right: 0.5vw;
color: #ff8800;
background-color: #333;
border-radius: 10px;
text-align: center;
overflow: hidden;
}
.currentlyPlayingDiv .textWrapper {
padding: 0.75vw;
}
.currentlyPlayingDiv .textWrapper p {
width: 100%;
font-size: 2.3em;
}
.currentlyPlayingDiv p:first-child {
margin-top: 1.5vw;
margin-bottom: 1.5vw;
font-size: 2.8em;
}
@media only screen and (max-width: 1000px) {
.currentlyPlayingDiv {
width: 100vw;
height: 35vw;
margin-right: 0;
border-radius: 0px;
align-content: center;
}
.currentlyPlayingDiv .textWrapper p {
font-size: 1.1em;
}
.currentlyPlayingDiv p:first-child {
margin-bottom: 2vw;
font-size: 1.4em;
}
}
</style>
@@ -1,170 +0,0 @@
<template>
<div class="inspirationDiv">
<div class="inspirationHeader">
<div class="inspirationTitle">
<h1>Inspiration</h1>
</div>
<div class="searchInput">
<input
v-model="searchInputText"
type="text"
@input="searchGame()"
ref="inputField"
/>
</div>
<button @click="clearSearch()">Clear</button>
</div>
<transition-group
tag="ul"
name="inspirationList"
class="inspirationList"
ref="inspirationList"
>
<li v-for="game in showingGamesList" class="inspirationEntry" :key="game">
{{ game }}
</li>
</transition-group>
</div>
</template>
<script>
import arne from '../../arne.js'
import {mapState} from "vuex";
export default {
data() {
return {
allGamesList: [],
showingGamesList: [],
scrollDown: true,
searchInputText: "",
};
},
computed: {
...mapState(["reloadGamesList"]),
},
watch: {
reloadGamesList(newValue) {
if (newValue) {
this.reloadGames();
this.$store.dispatch("reloadGamesList", false);
}
}
},
methods: {
clearSearch() {
this.searchInputText = "";
this.searchGame();
},
searchGame() {
this.showingGamesList = [];
for (const game of this.allGamesList) {
if (this.searchInputText === "" ||
game.toLowerCase().replace(/\s/g, "")
.includes(this.searchInputText.toLowerCase().replace(/\s/g, ""))) {
this.showingGamesList.push(game);
}
}
if (this.searchInputText.replace(/\s/g, "") !== "") {
this.showingGamesList.sort((n1, n2) => {
if (n1 > n2) {
return 1;
}
if (n1 < n2) {
return -1;
}
return 0;
});
}
},
scrollInspiration() {
let inspirationListDOM = document.querySelector(".inspirationList");
let scrollSpeed = 1;
let currentScrollLocation = 0;
currentScrollLocation = inspirationListDOM.scrollTop;
this.scrollDown
? inspirationListDOM.scrollBy(0, scrollSpeed)
: inspirationListDOM.scrollBy(0, -scrollSpeed);
if (currentScrollLocation === inspirationListDOM.scrollTop) {
this.scrollDown = !this.scrollDown;
}
},
reloadGames() {
this.axios({
method: "get",
url: `${arne.hostname}/music/all`,
})
.then((response) => {
this.allGamesList = response.data;
this.searchInputText = "";
this.searchGame();
this.$store.dispatch("updateHowManyGames", this.allGamesList.length);
})
.catch(function(error) {
console.log(error);
});
}
},
mounted() {
this.reloadGames();
window.setInterval(() => {
this.scrollInspiration();
}, 40);
},
};
</script>
<style scoped>
.inspirationDiv {
width: 38vw;
height: 20vh;
color: white;
}
.inspirationTitle {
display: flex;
flex: auto;
align-items: flex-start;
justify-content: flex-start;
padding: 5px 10px;
}
.searchInput {
display: flex;
flex: auto;
align-items: flex-end;
justify-content: flex-end;
padding: 0 10px;
}
.inspirationHeader {
display: flex;
background-color: #333;
height: 5vh;
justify-content: center;
align-items: center;
}
.inspirationList {
display: inline-block;
background-color: rgb(66, 66, 66);
width: 38vw;
height: 22vh;
list-style: none;
overflow: hidden;
}
.inspirationEntry {
width: 100%;
max-width: 38vw;
padding: 0.3vh 0.8vh;
font-size: 1.2rem;
}
@media only screen and (max-width: 1000px) {
.inspirationDiv {
display: none;
}
}
</style>
@@ -1,78 +0,0 @@
<template>
<transition name="modalAni">
<div v-if="show" class="modal" @click="checkIfClickShouldCloseModal">
<div class="modalContainer">
<div class="modalWrapper">
<img
class="closeModalImg"
src="cancel-black-36dp.svg"
alt="closeModalIMG"
@click="closeModal"
/>
<h1>Music Player Randomizer v0.1</h1>
<p class="descriptionText">
Try your video game music knowledge with this VGM randomizer,
invite your friends and see who is the best.
</p>
<p class="creditText">
Back-end done by Sebastian Olsson,
<a href="https://twitter.com/Raida91">Twitter</a>
</p>
<p class="creditText">
Front-end done by Peter Johansson,
<a href="https://twitter.com/WebDevPJ">Twitter</a>
</p>
<!-- <p class="patchNotesText">
Full patch notes can be found
<a href="https://www.youtube.com/watch?v=dQw4w9WgXcQ">here</a>
</p> -->
</div>
</div>
</div>
</transition>
</template>
<script>
export default {
data() {
return {
show: false,
};
},
methods: {
closeModal() {
this.show = false;
},
openModal() {
this.show = true;
},
checkIfClickShouldCloseModal(event) {
if (event.target.classList[0] === "modal") {
this.closeModal();
}
},
},
};
</script>
<style scoped>
p {
font-size: 1.2rem;
width: 100%;
}
.descriptionText {
margin-top: 35px;
}
.creditText {
margin-top: 30px;
}
.creditText:nth-child(5) {
margin-top: 0px;
}
.patchNotesText {
margin-top: 20px;
}
</style>
@@ -1,160 +0,0 @@
<template>
<transition name="modalAni">
<div v-if="show" class="modal" @click="checkIfClickShouldCloseModal">
<div class="modalContainer">
<div class="modalWrapper">
<img
class="closeModalImg"
src="cancel-black-36dp.svg"
alt="closeModalIMG"
@click="closeModal"
/>
<h1 @click="test">{{ playerName }}, choose your fighter!</h1>
<div class="fighterDiv">
<div class="fighter" @click="chooseFighter('Adol')">
<img src="characters/Adol.png" alt="adol" />
<p>Adol Christin</p>
</div>
<div class="fighter" @click="chooseFighter('Link')">
<img src="characters/Link.png" alt="link" />
<p>Link</p>
</div>
<div class="fighter" @click="chooseFighter('Barbarian')">
<img src="characters/Barbarian.png" alt="barbarian" />
<p>Barbarian</p>
</div>
<div class="fighter" @click="chooseFighter('Layton')">
<img src="characters/Layton.png" alt="layton" />
<p>Professor Layton</p>
</div>
<div class="fighter" @click="chooseFighter('Kiryu')">
<img src="characters/Kiryu.png" alt="kiryu" />
<p>Kazuma Kiryu</p>
</div>
<div class="fighter" @click="chooseFighter('Miles')">
<img src="characters/Miles.png" alt="miles" />
<p>Miles Edgeworth</p>
</div>
<div class="fighter" @click="chooseFighter('Lemmings')">
<img src="characters/Lemmings.png" alt="lemmings" />
<p>Lemmings</p>
</div>
<div class="fighter" @click="chooseFighter('Samus')">
<img src="characters/Samus.png" alt="samus" />
<p>Samus</p>
</div>
<div class="fighter" @click="chooseFighter('Kratos')">
<img src="characters/Kratos.png" alt="kratos" />
<p>Kratos</p>
</div>
<div class="fighter" @click="chooseFighter('Aloy')">
<img src="characters/Aloy.png" alt="aloy" />
<p>Aloy</p>
</div>
<div class="fighter" @click="chooseFighter('Sora')">
<img src="characters/Sora.png" alt="sora" />
<p>Sora</p>
</div>
<div class="fighter" @click="chooseFighter('Raiden')">
<img src="characters/Raiden.png" alt="raiden" />
<p>Raiden</p>
</div>
<div class="fighter" @click="chooseFighter('PaperMario')">
<img src="characters/PaperMario.png" alt="paper mario" />
<p>Paper Mario</p>
</div>
</div>
</div>
</div>
</div>
</transition>
</template>
<script>
export default {
data() {
return {
show: false,
playerName: "",
};
},
methods: {
closeModal() {
this.show = false;
},
openModal(playerName) {
this.playerName = playerName;
this.show = true;
},
checkIfClickShouldCloseModal(event) {
if (event.target.classList[0] === "modal") {
this.closeModal();
}
},
chooseFighter(profilePicSrc) {
let payload = {
playerName: this.playerName,
profile: "characters/" + profilePicSrc + ".png",
};
this.$store.dispatch("changePlayerProfile", payload);
this.closeModal();
},
},
};
</script>
<style scoped>
.modalContainer {
width: 80%; /* Could be more or less, depending on screen size */
}
.fighterDiv {
display: flex;
width: 100%;
justify-content: center;
margin-top: 30px;
flex-wrap: wrap;
}
.fighterDiv img {
width: 180px;
height: 90px;
}
.fighter {
display: flex;
flex-wrap: wrap;
justify-content: center;
text-align: center;
width: 14vw;
margin-top: 30px;
}
.fighter > * {
width: 100%;
}
.fighter:hover {
outline: 1px solid rgb(128, 83, 0);
outline-offset: 2px;
cursor: pointer;
}
.fighter p {
margin-top: 8px;
font-size: 1.3rem;
}
@media only screen and (max-width: 1000px) {
.modalContainer {
width: 95%; /* Could be more or less, depending on screen size */
}
.fighterDiv {
margin-top: 30px;
}
.fighterDiv img {
width: 80px;
height: 40px;
}
.fighter {
width: 25vw;
}
}
</style>
@@ -1,111 +0,0 @@
<template>
<div class="extraButtonsDiv">
<button @click="resetPlaylist">Reset playlist</button>
<button @click="resetPoints">Reset points</button>
<button @click="syncGames">Sync games</button>
<button @click="startSoundTest">Sound test</button>
</div>
</template>
<script>
import arne from '../../arne.js'
export default {
data() {
return {
emptyPlaylist: [],
};
},
methods: {
async resetPoints() {
this.$store.dispatch("resetPlayerScore");
this.$store.dispatch("resetPlayerWelcomed");
this.$store.dispatch("resetPlayerMatchPoint");
this.$store.dispatch("setRoundStarted", false);
},
async resetPlaylist() {
await this.APIresetPlaylist();
this.$store.dispatch("updatePlaylistHistory", this.emptyPlaylist);
this.$store.dispatch("setCurrentlyLoadingTrack", "N/A");
this.$store.dispatch("setCurrentTrackHidden", false);
},
async syncGames() {
await this.APIsyncGames();
await this.APIresetPlaylist();
this.$store.dispatch("resetPlayerScore");
this.$store.dispatch("resetPlayerWelcomed");
this.$store.dispatch("resetPlayerMatchPoint");
this.$store.dispatch("setRoundStarted", false);
this.$store.dispatch("updatePlaylistHistory", this.emptyPlaylist);
this.$store.dispatch("setCurrentlyLoadingTrack", "N/A");
this.$store.dispatch("setCurrentTrackHidden", false);
this.$store.dispatch("reloadGamesList", true);
},
startSoundTest() {
this.$emit("start-sound-test");
},
APIresetPlaylist() {
return new Promise((resolve, reject) => {
this.axios({
method: "get",
url: `${arne.hostname}/music/reset`,
})
.then(() => {
resolve();
})
.catch(function(error) {
console.log(error);
reject();
});
});
},
APIsyncGames() {
return new Promise((resolve, reject) => {
this.axios({
method: "get",
url: `${arne.hostname}/sync`,
})
.then(() => {
resolve();
})
.catch(function(error) {
console.log(error);
reject();
});
});
},
},
};
</script>
<style scoped>
.extraButtonsDiv {
display: flex;
margin-top: 2px;
margin-left: 10px;
}
button {
display: flex;
align-items: center;
height: 65%;
margin-right: 0.4vw;
border-radius: 10px;
border-width: 1px;
}
@media only screen and (max-width: 1000px) {
.extraButtonsDiv {
display: flex;
position: relative;
flex-wrap: wrap;
justify-content: center;
}
button {
width: 51vw;
height: 40px;
margin-bottom: 10px;
justify-content: center;
}
}
</style>
@@ -1,136 +0,0 @@
<template>
<div
v-if="show"
class="mobileMenu"
@click="checkIfClickShouldCloseMobileMenu"
>
<transition name="mobileMenuAni">
<div v-if="showContent" class="mobileMenuContainer">
<div class="mobileMenuWrapper">
<h1>Menu</h1>
<button class="settingsButton" @click="showSettingsModal">
Settings
</button>
<button class="statisticsButton" @click="showStatisticsModal">
Statistics
</button>
<button class="aboutButton" @click="showAboutModal">
About
</button>
<h1>Control</h1>
<extra-buttons
@start-sound-test="startSoundTest"
></extra-buttons>
</div>
</div>
</transition>
</div>
</template>
<script>
import extraButtons from "./extraButtons.vue";
export default {
components: {
extraButtons,
},
data() {
return {
show: false,
showContent: false,
};
},
methods: {
closeMobileMenu() {
this.showContent = false;
setTimeout(() => {
this.show = false;
}, 250);
},
openMobileMenu() {
this.show = true;
},
openMobileMenuContent() {
this.showContent = true;
},
checkIfClickShouldCloseMobileMenu(event) {
if (event.target.classList[0] === "mobileMenu") {
this.closeMobileMenu();
}
},
showSettingsModal() {
this.show = false;
this.showContent = false;
this.$emit("show-settings-modal");
},
showStatisticsModal() {
this.show = false;
this.showContent = false;
this.$emit("show-statistics-modal");
},
showAboutModal() {
this.show = false;
this.showContent = false;
this.$emit("show-about-modal");
},
startSoundTest() {
this.$emit("start-sound-test");
},
},
};
</script>
<style scoped>
.mobileMenuAni-enter-from,
.mobileMenuAni-leave-to {
opacity: 0.6;
transform: translateX(80vw);
}
.mobileMenuAni-enter-to,
.mobileMenuAni-leave-from {
opacity: 1;
transform: translateX(0vw);
}
.mobileMenuAni-enter-active,
.mobileMenuAni-leave-active {
transition: all 0.3s ease-out;
}
.mobileMenu {
position: fixed;
z-index: 8;
right: 0;
bottom: 0;
width: 100%;
height: 100%;
overflow: hidden;
background-color: rgb(0, 0, 0);
background-color: rgba(0, 0, 0, 0.5);
}
.mobileMenuContainer {
background-color: #c4c4c4;
width: 80vw;
height: 100%;
margin-left: 20%;
}
.mobileMenuWrapper {
display: flex;
position: relative;
flex-wrap: wrap;
justify-content: center;
}
h1 {
margin: 10px 0px;
width: 100%;
text-align: center;
}
button {
width: 51vw;
height: 40px;
margin-bottom: 10px;
}
</style>
@@ -1,354 +0,0 @@
<template>
<div class="playersWindowDiv">
<div @click="toggleDisplay" class="playerListTitle">
<img v-if="display" class="arrow arrowToggle" src="keyboard_arrow_up-black-36dp.svg" />
<img v-else class="arrow arrowToggle" src="keyboard_arrow_down-black-36dp.svg" />
<h1>Players</h1>
<img
src="person_add_alt_1-black-36dp.svg"
alt="addPlayer"
class="addPlayerIMG"
@click="toggleNewPlayerInput()"
/>
</div>
<transition-group tag="div" v-if="display" name="playerList" class="playerList">
<div class="player" v-for="player in listOfPlayers" :key="player.playerName">
<p>{{ player.playerName }}: {{ player.score }}</p>
<img
class="profilePicture"
:src="player.profile"
@click="openCharacterModal(player.playerName)"
/>
<button @click="changeScore(player.playerName, 1)">+1</button>
<button @click="changeScore(player.playerName, -1)">-1</button>
<img
src="person_remove-black-36dp.svg"
@click="removePlayer(player.playerName)"
alt=""
/>
</div>
<div class="newPlayerInput" v-if="showNewPlayerInput === true">
<input
v-model="newPlayerInputText"
type="text"
@keypress.enter="addNewPlayer()"
ref="inputField"
placeholder="Player name"
/>
<button @click="addNewPlayer()">Add</button>
</div>
</transition-group>
<winning-modal ref="winningModal"></winning-modal>
<character-modal ref="characterModal"></character-modal>
</div>
</template>
<script>
import { mapState } from "vuex";
import winningModal from "../items/winningModal.vue";
import characterModal from "../items/characterModal.vue";
export default {
components: {
winningModal,
characterModal,
},
data() {
return {
showNewPlayerInput: false,
newPlayerInputText: "",
display: true,
};
},
computed: {
...mapState(["listOfPlayers", "winningScore"]),
},
methods: {
removePlayer(playerName) {
this.$store.dispatch("removePlayer", playerName);
},
newPlayerValidation() {
/* Validation variables */
let errors = [];
let newName = this.newPlayerInputText;
/* Check for empty value */
if (newName.trim() === "") {
errors.push("No player name was entered");
}
/* Prepare data of players and check for already entered ones */
let copyOfPlayerList = this.listOfPlayers;
let arrayOfPlayers = copyOfPlayerList.map((player) => player.playerName.toLowerCase());
if (arrayOfPlayers.includes(newName.toLowerCase())) {
errors.push("This player already exists");
}
/* Check amount of players */
if (arrayOfPlayers.length > 6) {
errors.push("Too many players already exists");
}
/* If everything went fine, return an empty */
return errors;
},
addNewPlayer() {
let errors = this.newPlayerValidation();
if (errors.length === 0) {
this.$store.dispatch("addNewPlayer", this.newPlayerInputText);
this.newPlayerInputText = "";
} else {
console.log(errors);
}
},
toggleNewPlayerInput() {
this.showNewPlayerInput = !this.showNewPlayerInput;
if (this.showNewPlayerInput === true) {
this.$nextTick(() => this.$refs.inputField.focus());
}
},
changeScore(playerName, score) {
let payload = {
playerName: playerName,
score: score,
};
this.$store.dispatch("changePlayerScore", payload);
for (let i = 0; i < this.listOfPlayers.length; i++) {
/* If a player received their first point */
if (this.listOfPlayers[i].score == 1 && this.listOfPlayers[i].welcomed === false) {
let payload = {
playerName: playerName,
welcomeSet: true,
};
this.$store.dispatch("changePlayerWelcomed", payload);
this.$emit("play-welcome-sound");
}
/* If a player reach match point */
if (this.listOfPlayers[i].score === this.winningScore-1) {
let payload = {
playerName: playerName,
matchPointSet: true,
};
this.$store.dispatch("changePlayerMatchPoint", payload);
this.$emit("play-match-point-sound");
}
/* If a player won */
if (this.listOfPlayers[i].score === this.winningScore) {
this.$refs.winningModal.openModal(this.listOfPlayers[i].playerName);
this.$emit("play-winning-sound");
}
}
},
openCharacterModal(playerName) {
this.$refs.characterModal.openModal(playerName);
},
getProfileSrc(profileToGet) {
console.log(this.listOfPlayers[0]);
let src = `characters/${profileToGet}`;
console.log(src);
return src;
},
toggleDisplay(event) {
if (event.target.classList[0] != "addPlayerIMG") {
if (window.innerWidth < 600) {
this.display = !this.display;
}
}
},
},
};
</script>
<style scoped>
.playerList-enter-from,
.playerList-leave-to {
opacity: 0;
}
.playerList-enter-to,
.playerList-leave-from {
opacity: 1;
}
.playerList-enter-active {
transition: all 0.5s ease-out;
}
.playerList-leave-active {
position: absolute;
transition: all 0.2s ease-in;
}
.playerList-move {
transition: 0.25s;
transition-property: transform, opacity;
}
.playerList-move.newPlayerInput {
transition: 0.2s;
transition-property: transform;
}
/* End of Animation block */
.playersWindowDiv {
display: inline-block;
width: 38vw;
color: white;
}
.playerListTitle {
display: flex;
width: 100%;
background-color: #333;
height: 5vh;
align-content: center;
align-items: center;
text-align: center;
}
.playerListTitle h1 {
text-align: center;
position: relative;
margin-left: auto;
margin-right: auto;
flex-grow: 100;
}
.playerListTitle .addPlayerIMG {
justify-self: flex-end;
margin-left: auto;
margin-right: 5px;
flex-grow: 1;
filter: invert(66%) sepia(96%) saturate(2783%) hue-rotate(1deg) brightness(105%) contrast(103%);
}
.playerListTitle .arrow {
flex-grow: 1;
}
.playerListTitle .arrowToggle {
display: none;
}
.playerList {
display: inline-block;
background-color: rgb(66, 66, 66);
min-height: 37vh;
}
.playerList .player {
display: flex;
flex-wrap: nowrap;
justify-content: flex-end;
width: 38vw;
height: 6vh;
font-size: 1.8rem;
align-content: center;
align-items: center;
}
.playerList .player p {
margin-left: 5px;
margin-right: auto;
}
.playerList .player .profilePicture {
width: 100px;
height: 50px;
background-color: red;
margin-right: 2vw;
cursor: pointer;
}
.playerList .player button {
align-content: center;
padding: 3px;
width: 50px;
height: 4vh;
margin-right: 0.6vw;
line-height: 0;
}
.playerList .player button:last-of-type {
margin-right: 3vw;
}
.playerList .player img {
margin-right: 5px;
}
.newPlayerInput {
display: flex;
width: 38vw;
height: 50px;
align-items: center;
justify-content: center;
padding: 5px 0;
background-color: rgb(107, 106, 106);
}
.newPlayerInput p {
font-size: 1.3rem;
flex-grow: 1;
text-align: center;
}
.newPlayerInput input {
height: 70%;
width: 250px;
font-size: 1.5rem;
margin: 0 5px;
text-align: center;
}
.newPlayerInput button {
margin: 0 10px;
height: 80%;
align-self: center;
}
@media only screen and (max-width: 1000px) {
.playersWindowDiv {
width: 100%;
}
.playerListTitle {
height: 10vw;
font-size: 0.8rem;
}
.playerListTitle .addPlayerIMG {
height: 9vw;
}
.playerListTitle .arrowToggle {
display: block;
max-height: 100%;
left: 0;
filter: invert(77%) sepia(8%) saturate(6%) hue-rotate(317deg) brightness(95%) contrast(87%);
}
.playerList {
width: 100%;
height: 60vw;
min-height: 190px;
overflow: scroll;
}
.playerList .player {
width: 100vw;
height: 12vw;
font-size: 1rem;
}
.playerList .player .profilePicture {
width: 60px;
height: 30px;
margin-right: 1.5vw;
}
.playerList .player button {
align-content: center;
padding: 3px;
width: 45px;
height: 10vw;
margin-right: 1vw;
line-height: 0;
}
.newPlayerInput {
width: 100%;
height: 30px;
}
.newPlayerInput input {
height: 90%;
width: 200px;
font-size: 1.2rem;
}
.newPlayerInput button {
margin: 0 10px;
height: 40px;
border-radius: 2px;
}
}
</style>
@@ -1,191 +0,0 @@
<template>
<div class="playlistHistoryDiv">
<div @click="toggleDisplay" class="playlistHistoryTitle">
<h1>Playlist history</h1>
<img v-if="display" src="keyboard_arrow_up-black-36dp.svg" alt="" />
<img v-else src="keyboard_arrow_down-black-36dp.svg" alt="" />
</div>
<transition-group
tag="div"
v-if="display"
name="playlistHistory"
class="playlistHistory"
ref="playlistHistory"
>
<div
class="track"
v-for="track in playlistHistory"
:key="track.SongNo"
@click="playSelectedTrack(track, $event)"
>
<p
v-if="checkIfHidden(track, playlistHistory)"
:class="{ activeTrack: track.CurrentlyPlaying }"
>
??? - ???
</p>
<p v-else-if="track.Game !== ''" :class="{ activeTrack: track.CurrentlyPlaying }">
{{ track.SongNo + 1 }}. {{ track.Game }} -
{{ displayTrack(track.Song) }}
</p>
<span v-if="currentlyLoadingTrack === track.SongNo" class="loadingTrack">
-- Loading --
</span>
</div>
</transition-group>
</div>
</template>
<script>
import { mapState } from "vuex";
export default {
data() {
return {
display: true,
};
},
computed: {
...mapState(["playlistHistory", "currentTrackHidden", "currentlyLoadingTrack"]),
},
methods: {
checkIfHidden(track, playlistHistory) {
return track.SongNo === playlistHistory.length - 1 && this.currentTrackHidden;
},
displayTrack(trackName) {
/* Todo: Is this if-check necessary? */
if (trackName === undefined) {
return "";
} else {
return trackName.replace(".mp3", "");
}
},
playSelectedTrack(track, event) {
console.log(event.path);
this.$store.dispatch("setCurrentlyLoadingTrack", track.SongNo);
this.$emit("play-selected-track", track);
},
scrollToBottom() {
if (this.display) {
this.$nextTick(() => {
this.$refs.playlistHistory.$el.scrollTop = this.$refs.playlistHistory.$el.scrollHeight;
});
}
},
toggleDisplay() {
if (window.innerWidth < 600) {
this.display = !this.display;
}
},
},
created() {
if (window.innerWidth < 600) {
this.display = false;
}
},
};
</script>
<style scoped>
/* Scroll */
.playlistHistory::-webkit-scrollbar {
width: 17px;
}
.playlistHistory {
scrollbar-color: #4f5253c2;
}
.playlistHistory::-webkit-scrollbar-track {
background: #393c4179;
border-radius: 5px;
}
.playlistHistory::-webkit-scrollbar-thumb {
background-color: #6d7679c2;
border-radius: 5px;
border: 2px solid #3c434e79;
}
/* End of Scroll */
.playlistHistoryDiv {
display: inline-block;
width: 60vw;
color: white;
margin-right: 0.5vw;
}
.playlistHistoryTitle {
display: flex;
background-color: #333;
height: 5vh;
justify-content: center;
align-items: center;
}
.playlistHistoryTitle img {
display: none;
}
.playlistHistory {
background-color: rgb(66, 66, 66);
width: 60vw;
height: 37vh;
overflow-x: hidden;
overflow-y: scroll;
}
.playlistHistory .track {
display: flex;
flex-wrap: nowrap;
justify-content: flex-start;
width: 57vw;
height: auto;
min-height: 30px;
line-height: 1.5;
font-size: 1.1rem;
align-items: center;
padding: 0.3vh 0.6vh;
cursor: pointer;
}
.playlistHistory .track:nth-child(even) {
background-color: #4e4e4e;
}
.playlistHistory .activeTrack {
color: yellow;
}
.loadingTrack {
color: #ff9c00;
margin-left: 20px;
}
@media only screen and (max-width: 1000px) {
.playlistHistory::-webkit-scrollbar {
width: 5px;
}
.playlistHistoryDiv {
width: 100%;
margin: 0 0 0.3vw;
}
.playlistHistoryTitle {
height: 10vw;
font-size: 0.8rem;
}
.playlistHistoryTitle img {
display: block;
position: absolute;
max-height: 100%;
left: 0;
filter: invert(77%) sepia(8%) saturate(6%) hue-rotate(317deg) brightness(95%) contrast(87%);
}
.playlistHistory {
width: 100vw;
height: 56vw;
}
.playlistHistory .track {
width: 98vw;
font-size: 0.8rem;
padding: 1.5vw 1vw;
}
.loadingTrack {
display: none;
}
}
</style>
@@ -1,209 +0,0 @@
<template>
<!-- Round Settings, Stop after current, Don't hide title -->
<transition name="modalAni">
<div v-if="show" class="modal" @click="checkIfClickShouldCloseModal">
<div class="modalContainer">
<div class="modalWrapper">
<img
class="closeModalImg"
src="cancel-black-36dp.svg"
alt="closeModalIMG"
@click="closeModal"
/>
<h1>Settings</h1>
<div class="checkboxDiv">
<input
type="checkbox"
name="stopAfterCurrent"
id="stopAfterCurrent"
v-model="checkboxStopAfterCurrent"
@change="updateOptionStopAfterCurrent"
/>
<label for="stopAfterCurrent">Stop after current</label>
</div>
<div class="checkboxDiv">
<input
type="checkbox"
name="hideTitle"
id="hideTitle"
v-model="checkboxHideTitle"
@change="updateOptionHideTitle"
/>
<label for="hideTitle">Hide next track</label>
</div>
<div class="checkboxDiv">
<input
type="checkbox"
name="addPlayed"
id="addPlayed"
v-model="checkboxAddPlayed"
@change="updateOptionAddPlayed"
/>
<label for="addPlayed">Turn on played to database</label>
</div>
<div class="checkboxDiv">
<input
type="checkbox"
name="lowPlayed"
id="lowPlayed"
v-model="checkboxLowPlayed"
@change="updateOptionLowPlayed"
/>
<label for="lowPlayed">Use low played mode</label>
</div>
<div class="winningScoreDiv">
<span>Winning Score: {{ winningScore }}</span>
<button
:class="{ disabled: roundStarted }"
:disabled="roundStarted"
@click="changeScore(-1)"
>
-1
</button>
<button
:class="{ disabled: roundStarted }"
:disabled="roundStarted"
@click="changeScore(1)"
>
+1
</button>
</div>
</div>
</div>
</div>
</transition>
</template>
<script>
import { mapState } from "vuex";
export default {
data() {
return {
show: false,
checkboxStopAfterCurrent: false,
checkboxHideTitle: false,
checkboxAddPlayed: false,
checkboxLowPlayed: false,
};
},
computed: {
...mapState(["winningScore", "roundStarted", "stopAfterCurrent", "hideNextTrack", "addPlayed", "lowPlayed"]),
},
methods: {
closeModal() {
this.show = false;
},
openModal() {
this.show = true;
},
checkIfClickShouldCloseModal(event) {
if (event.target.classList[0] === "modal") {
this.closeModal();
}
},
updateOptionHideTitle() {
if (this.checkboxHideTitle) {
this.$store.dispatch("updateHideNextTitle", true);
} else {
this.$store.dispatch("updateHideNextTitle", false);
}
},
updateOptionAddPlayed() {
if (this.checkboxAddPlayed) {
this.$store.dispatch("updateAddPlayed", true);
} else {
this.$store.dispatch("updateAddPlayed", false);
}
},
updateOptionLowPlayed() {
if (this.checkboxLowPlayed) {
this.$store.dispatch("updateLowPlayed", true);
} else {
this.$store.dispatch("updateLowPlayed", false);
}
},
updateOptionStopAfterCurrent() {
if (this.checkboxStopAfterCurrent) {
this.$store.dispatch("updateStopAfterCurrent", true);
} else {
this.$store.dispatch("updateStopAfterCurrent", false);
}
},
changeScore(score) {
if (score < 0) {
this.$store.dispatch("setWinningScore", -1);
} else {
this.$store.dispatch("setWinningScore", 1);
}
},
},
mounted() {
this.checkboxStopAfterCurrent = this.stopAfterCurrent;
this.checkboxHideTitle = this.hideNextTrack;
this.checkboxAddPlayed = this.addPlayed;
this.checkboxLowPlayed = this.lowPlayed;
},
};
</script>
<style scoped>
.winningScoreDiv {
width: 100%;
display: inline-flex;
align-items: center;
flex-wrap: nowrap;
margin-top: 30px;
}
.checkboxDiv {
margin: 5px;
width: 100%;
}
.checkboxDiv:first-of-type {
margin-top: 20px;
}
.checkboxDiv input {
transform: scale(1.3);
}
.checkboxDiv label {
margin-left: 10px;
font-size: 1.5rem;
}
.winningScoreDiv span {
font-size: 1.7rem;
margin-right: 10px;
width: 245px;
}
.winningScoreDiv button {
display: flex;
width: 50px;
height: 33px;
background: rgb(16, 99, 194);
color: rgb(235, 235, 235);
border-color: rgb(161, 161, 161);
justify-content: center;
align-items: center;
line-height: 0;
font-size: 1.5rem;
margin: 3px;
}
.disabled {
opacity: 50%;
}
@media only screen and (max-width: 1000px) {
.checkboxDiv label {
font-size: 1.3rem;
}
.winningScoreDiv span {
font-size: 1.3rem;
margin-right: 10px;
width: 245px;
}
}
</style>
@@ -1,68 +0,0 @@
<template>
<transition name="modalAni">
<div v-if="show" class="modal" @click="checkIfClickShouldCloseModal">
<div class="modalContainer">
<div class="modalWrapper">
<img
class="closeModalImg"
src="cancel-black-36dp.svg"
alt="closeModalIMG"
@click="closeModal"
/>
<h1>Statistics</h1>
<p>Total amount of games in the playlist: {{ howManyGames }}</p>
</div>
</div>
</div>
</transition>
</template>
<script>
import { mapState } from "vuex";
export default {
data() {
return {
show: false,
};
},
computed: {
...mapState(["howManyGames"]),
},
methods: {
closeModal() {
this.show = false;
},
openModal() {
this.show = true;
},
checkIfClickShouldCloseModal(event) {
if (event.target.classList[0] === "modal") {
this.closeModal();
}
},
},
};
</script>
<style scoped>
p {
font-size: 1.2rem;
width: 100%;
margin-top: 30px;
}
.descriptionText {
margin-top: 35px;
}
.creditText {
margin-top: 30px;
}
.creditText:nth-child(5) {
margin-top: 0px;
}
.patchNotesText {
margin-top: 20px;
}
</style>
@@ -1,50 +0,0 @@
<template>
<transition name="modalAni">
<div v-if="show" class="modal" @click="checkIfClickShouldCloseModal">
<div class="modalContainer">
<div class="modalWrapper">
<img
class="closeModalImg"
src="cancel-black-36dp.svg"
alt="closeModalIMG"
@click="closeModal"
/>
<h1>{{ playerName }} won!!</h1>
</div>
</div>
</div>
</transition>
</template>
<script>
export default {
data() {
return {
show: false,
playerName: "",
};
},
methods: {
closeModal() {
this.show = false;
},
showPeter() {
let randomNumber = Math.floor(Math.random() * 10);
console.log(randomNumber);
console.log("Test");
return randomNumber < 2;
},
openModal(playerName) {
this.playerName = playerName;
this.show = true;
},
checkIfClickShouldCloseModal(event) {
if (event.target.classList[0] === "modal") {
this.closeModal();
}
},
},
};
</script>
<style scoped></style>
@@ -1,441 +0,0 @@
<template>
<footer>
<div class="audioAndButtonsDiv">
<div class="audioButtonsDiv">
<button
class="bigButton"
:class="{ disabled: disableButtons }"
:disabled="disableButtons"
@click="randomizeTrack()"
>
<p v-if="!disableButtons"><u>R</u>andomize new track</p>
<p v-else>Loading...</p>
</button>
<button class="bigButton" @click="showAnswer()"><u>S</u>how answer</button>
</div>
<div class="audioDiv">
<audio
controls
class="audioPlayer"
:src="currentTrackSrcFile"
ref="audioPlayer"
:onended="trackHasEnded"
></audio>
</div>
</div>
</footer>
</template>
<script>
import { mapState } from "vuex";
import arne from "../../arne.js";
export default {
data() {
return {
currentTrackSrcFile: "",
disableButtons: false,
loadingBar: "",
};
},
computed: {
...mapState([
"stopAfterCurrent",
"localPlaylist",
"hideNextTrack",
"roundStarted",
"specialTrackIsPlaying",
"addPlayed",
"lowPlayed",
]),
},
methods: {
async randomizeTrack() {
console.log("Randomizing track");
/* Prevents anyone from changing the winning score after the round has started */
if (this.roundStarted === false) {
this.$store.dispatch("setRoundStarted", true);
}
let trackAddedToQue = false;
this.disableButtons = true;
let copyOfPlaylist = this.localPlaylist;
setTimeout(() => this.isHidden = false, 2000);
//If the local playlist of MP3s is empty, wait for a new track to load
if (copyOfPlaylist.length === 0) {
console.log("No track preloaded, loading a new one");
if (this.lowPlayed) {
await this.APIgetRandomizedLowTrack();
} else {
await this.APIgetRandomizedTrack();
}
if (this.addPlayed) {
await this.APIaddPlayed();
}
await this.APIaddToQue();
trackAddedToQue = true;
}
//Update the source file for the media player (binded property to Audio tag in the template)
this.currentTrackSrcFile = window.URL.createObjectURL(copyOfPlaylist[0]);
if (!trackAddedToQue) {
if (this.addPlayed) {
await this.APIaddPlayed();
}
await this.APIaddToQue();
}
await this.APIgetPlaylistHistory();
this.$refs.audioPlayer.play();
this.$emit("scroll-to-bottom-playlist-history");
copyOfPlaylist.shift();
if (this.hideNextTrack) {
this.$store.dispatch("setCurrentTrackHidden", true);
} else {
this.$store.dispatch("setCurrentTrackHidden", false);
}
await this.APIgetInfoAboutCurrentTrack();
await this.randomizeTrackInAdvance();
this.disableButtons = false;
},
async randomizeTrackInAdvance() {
console.log("Randomizing track in advance");
try {
if (this.lowPlayed) {
await this.APIgetRandomizedLowTrack();
} else {
await this.APIgetRandomizedTrack();
}
} catch (error) {
console.log(error);
console.log("Error: A track couldn't be loaded in advance");
}
return new Promise((resolve) => {
resolve();
});
},
async playSpecificTrack(track) {
await this.APIplaySpecificTrack(track.SongNo);
this.$store.dispatch("setCurrentlyLoadingTrack", "");
await this.APIgetPlaylistHistory();
this.$store.dispatch("setCurrentTrackHidden", false);
await this.APIgetInfoAboutCurrentTrack();
},
showAnswer() {
this.$store.dispatch("setCurrentTrackHidden", false);
},
startSoundTest() {
this.$refs.audioPlayer.pause();
this.currentTrackSrcFile = "sounds/check.mp3";
this.$store.dispatch("setSpecialTrackIsPlaying", true);
this.$nextTick(() => {
this.$refs.audioPlayer.currentTime = 0;
this.$refs.audioPlayer.play();
});
},
playWelcomeSound() {
let randomNumber = Math.floor(Math.random() * 10);
this.$refs.audioPlayer.pause();
if (randomNumber === 0) {
this.currentTrackSrcFile = "sounds/sound1.mp3";
} else if (randomNumber < 5) {
this.currentTrackSrcFile = "sounds/intro_short.mp3";
} else {
this.currentTrackSrcFile = "sounds/intro_long.mp3";
}
this.$store.dispatch("setSpecialTrackIsPlaying", true);
this.$nextTick(() => {
this.$refs.audioPlayer.currentTime = 0;
this.$refs.audioPlayer.play();
});
},
playMatchSound() {
this.$refs.audioPlayer.pause();
this.currentTrackSrcFile = "sounds/sound0.mp3";
this.$store.dispatch("setSpecialTrackIsPlaying", true);
this.$nextTick(() => {
this.$refs.audioPlayer.currentTime = 0;
this.$refs.audioPlayer.play();
});
},
playWinningSound() {
this.$refs.audioPlayer.pause();
this.currentTrackSrcFile = "sounds/winning.mp3";
this.$store.dispatch("setSpecialTrackIsPlaying", true);
this.$nextTick(() => {
this.$refs.audioPlayer.currentTime = 0;
this.$refs.audioPlayer.play();
});
},
APIgetRandomizedTrack() {
return new Promise((resolve, reject) => {
this.axios({
method: "get",
url: `${arne.hostname}/music/rand`,
responseType: "blob",
onDownloadProgress: (progressEvent) => {
let percentCompleted = Math.round(
(progressEvent.loaded * 100) / progressEvent.total
);
if (percentCompleted % 10 === 0) {
//Debug for slow downloading
//console.log(percentCompleted);
}
},
})
.then((response) => {
let mp3 = new Blob([response.data], { type: "audio/mp3" });
this.$store.dispatch("updateLocalPlaylist", mp3);
this.$nextTick(() => {
resolve();
});
})
.catch(function(error) {
console.log("An error happened when fetching the track");
console.log(error);
reject();
});
});
},
APIgetRandomizedLowTrack() {
return new Promise((resolve, reject) => {
this.axios({
method: "get",
url: `${arne.hostname}/music/rand/low`,
responseType: "blob",
onDownloadProgress: (progressEvent) => {
let percentCompleted = Math.round(
(progressEvent.loaded * 100) / progressEvent.total
);
if (percentCompleted % 10 === 0) {
//Debug for slow downloading
//console.log(percentCompleted);
}
},
})
.then((response) => {
let mp3 = new Blob([response.data], { type: "audio/mp3" });
this.$store.dispatch("updateLocalPlaylist", mp3);
this.$nextTick(() => {
resolve();
});
})
.catch(function(error) {
console.log("An error happened when fetching the track");
console.log(error);
reject();
});
});
},
APIaddPlayed() {
return new Promise((resolve, reject) => {
this.axios({
method: "get",
url: `${arne.hostname}/music/addPlayed`,
})
.then(() => {
resolve(false);
})
.catch(function(error) {
console.log(error);
reject();
});
});
},
APIaddToQue() {
return new Promise((resolve, reject) => {
this.axios({
method: "get",
url: `${arne.hostname}/music/addQue`,
})
.then(() => {
resolve(false);
})
.catch(function(error) {
console.log(error);
reject();
});
});
},
APIgetInfoAboutCurrentTrack() {
return new Promise((resolve, reject) => {
this.axios({
method: "get",
url: `${arne.hostname}/music/info`,
})
.then((response) => {
let gameInfoObject = {
game: response.data.Game,
track: response.data.Song.replace(".mp3", ""),
songNo: response.data.SongNo,
};
this.$store.dispatch("setCurrentGame", gameInfoObject.game);
this.$store.dispatch("setCurrentTrack", gameInfoObject.track);
resolve(false);
})
.catch(function(error) {
console.log(error);
reject();
});
});
},
APIgetPlaylistHistory() {
return new Promise((resolve, reject) => {
this.axios({
method: "get",
url: `${arne.hostname}/music/list`,
})
.then((response) => {
let tracklistArray = response.data;
this.$store.dispatch("updatePlaylistHistory", tracklistArray);
resolve();
})
.catch(function(error) {
console.log(error);
reject();
});
});
},
APIplaySpecificTrack(trackNumber) {
return new Promise((resolve, reject) => {
this.axios({
method: "get",
url: `${arne.hostname}/music?song=${trackNumber}`,
responseType: "blob",
})
.then((response) => {
let mp3 = new Blob([response.data], { type: "audio/mp3" });
this.currentTrackSrcFile = window.URL.createObjectURL(mp3);
this.$nextTick(() => {
this.$refs.audioPlayer.play();
resolve();
});
})
.catch(function(error) {
console.log(error);
reject();
});
});
},
trackHasEnded() {
if (this.specialTrackIsPlaying) {
this.$store.dispatch("setSpecialTrackIsPlaying", false);
return 0;
}
if (!this.stopAfterCurrent) {
this.randomizeTrack();
}
},
},
async mounted() {
await this.APIgetPlaylistHistory();
},
};
</script>
<style scoped>
footer {
display: flex;
position: absolute;
bottom: 0;
justify-content: flex-end;
width: 100%;
}
.audioAndButtonsDiv {
display: flex;
flex-wrap: wrap;
width: 80vw;
margin-right: 1vh;
}
.audioButtonsDiv {
display: flex;
flex-direction: row-reverse;
width: 100%;
margin-bottom: 2vh;
align-items: center;
}
.audioButtonsDiv button:nth-child(1) {
margin-right: 3vw;
width: 200px;
}
.audioButtonsDiv button:nth-child(2) {
margin-right: 25vw;
width: 220px;
}
.audioButtonsDiv .bigButton {
height: 7vh;
}
.disabled {
opacity: 0.5;
}
.audioDiv {
width: 100%;
}
.audioDiv audio {
width: 100%;
font-size: 2rem;
}
audio::-webkit-media-controls-panel {
background-color: rgb(185, 185, 185);
}
audio::-webkit-media-controls-current-time-display {
color: rgb(0, 0, 0);
font-size: 4em;
}
audio::-webkit-media-controls-time-remaining-display {
color: rgb(0, 0, 0);
font-size: 4em;
}
@media only screen and (max-width: 1000px) {
footer {
position: static;
justify-content: center;
}
.audioAndButtonsDiv {
width: 100vw;
margin: 0;
}
.audioButtonsDiv {
margin-bottom: 2vw;
font-size: 1rem;
}
.audioButtonsDiv button:nth-child(1) {
margin: 0;
width: 50vw;
border-radius: 2px;
}
.audioButtonsDiv button:nth-child(2) {
margin: 0;
width: 50vw;
border-radius: 2px;
}
.audioButtonsDiv .bigButton {
height: 22vw;
}
.disabled {
opacity: 0.5;
}
.audioDiv {
width: 100%;
}
.audioDiv audio {
font-size: 1rem;
}
audio::-webkit-media-controls-panel {
background-color: rgb(185, 185, 185);
border-radius: 2px;
}
audio::-webkit-media-controls-current-time-display {
color: rgb(0, 0, 0);
font-size: 2em;
}
audio::-webkit-media-controls-time-remaining-display {
color: rgb(0, 0, 0);
font-size: 2em;
}
}
</style>
@@ -1,139 +0,0 @@
<template>
<nav>
<p class="title">Music Player Randomizer</p>
<div class="navMenuWrapper">
<button class="settingsButton" @click="showSettingsModal">
Settings
</button>
<button class="statisticsButton" @click="showStatisticsModal">
Statistics
</button>
<button class="aboutButton" @click="showAboutModal">About</button>
</div>
<p v-if="!$parent.displayWhenDesktop" class="mobileMenuButton" @click="showMobileMenu">
Menu
</p>
<settingsModal ref="settingsModal"></settingsModal>
<statisticsModal ref="statisticsModal"></statisticsModal>
<aboutModal ref="aboutModal"></aboutModal>
<mobileMenu
ref="mobileMenu"
@start-sound-test="startSoundTest"
@show-settings-modal="showSettingsModal"
@show-statistics-modal="showStatisticsModal"
@show-about-modal="showAboutModal"
></mobileMenu>
</nav>
</template>
<script>
import aboutModal from "../items/aboutModal.vue";
import statisticsModal from "../items/statisticsModal.vue";
import settingsModal from "../items/settingsModal.vue";
import mobileMenu from "../items/mobileMenu.vue";
export default {
components: {
aboutModal,
settingsModal,
statisticsModal,
mobileMenu,
},
methods: {
playSelectedTrack(track) {
this.$refs.theFooter.playSpecificTrack(track);
},
scrollToBottomPlaylistHistory() {
this.$refs.playlistHistory.scrollToBottom();
},
showAboutModal() {
this.$refs.aboutModal.openModal();
},
showSettingsModal() {
this.$refs.settingsModal.openModal();
},
showStatisticsModal() {
this.$refs.statisticsModal.openModal();
},
showMobileMenu() {
this.$refs.mobileMenu.openMobileMenu();
this.showMobileMenuContent();
},
showMobileMenuContent() {
setTimeout(() => {
this.$refs.mobileMenu.openMobileMenuContent();
}, 20);
},
startSoundTest() {
this.$emit("start-sound-test");
},
},
};
</script>
<style scoped>
nav {
background: #333;
display: flex;
align-content: center;
align-items: center;
width: 100%;
height: 5vh;
}
.title {
color: #fff;
font-size: 2rem;
margin-left: 2vw;
font-style: normal;
}
.navMenuWrapper {
margin-left: auto;
height: 5vh;
}
.navMenuWrapper button {
background: #333;
color: #ff9c00;
font-size: 1.3rem;
outline: none;
cursor: pointer;
border: none;
border-radius: 3px;
height: 100%;
padding: 0 20px;
}
.navMenuWrapper button:hover {
background-color: #555;
}
/* Mobile */
@media only screen and (max-width: 1000px) {
nav {
justify-content: center;
height: 10vw;
}
.title {
font-size: 1.2rem;
margin: 0;
padding: 0;
width: 100%;
margin-left: 5px;
/* text-align: ; */
}
.navMenuWrapper {
display: none;
}
.mobileMenuButton {
color: white;
background: grey;
padding: 6px;
border-top-left-radius: 7px;
border-bottom-left-radius: 7px;
}
}
</style>
@@ -1,103 +0,0 @@
<template>
<div class="theMainDiv">
<div class="mainFirstRow">
<currently-playing></currently-playing>
<inspiration-window></inspiration-window>
</div>
<div class="mainSecondRow">
<playlist-history
ref="playlistHistory"
@play-selected-track="playSelectedTrack"
></playlist-history>
<players-window
@play-welcome-sound="playWelcomeSound"
@play-match-point-sound="playMatchSound"
@play-winning-sound="playWinningSound"
></players-window>
</div>
<extra-buttons
v-if="$parent.displayWhenDesktop"
@start-sound-test="startSoundTest"
></extra-buttons>
<the-footer
ref="theFooter"
@scroll-to-bottom-playlist-history="scrollToBottomPlaylistHistory"
></the-footer>
<!-- <the-footer ref="theFooter"></the-footer> -->
</div>
</template>
<script>
import currentlyPlaying from "../items/CurrentlyPlaying.vue";
import inspirationWindow from "../items/InspirationWindow.vue";
import playersWindow from "../items/playersWindow.vue";
import playlistHistory from "../items/playlistHistory.vue";
import extraButtons from "../items/extraButtons.vue";
import theFooter from "./TheFooter.vue";
export default {
components: {
currentlyPlaying,
playersWindow,
playlistHistory,
inspirationWindow,
extraButtons,
theFooter,
},
methods: {
playSelectedTrack(track) {
this.$refs.theFooter.playSpecificTrack(track);
},
scrollToBottomPlaylistHistory() {
this.$refs.playlistHistory.scrollToBottom();
},
startSoundTest() {
this.$refs.theFooter.startSoundTest();
},
playWelcomeSound() {
this.$refs.theFooter.playWelcomeSound();
},
playMatchSound() {
this.$refs.theFooter.playMatchSound();
},
playWinningSound() {
this.$refs.theFooter.playWinningSound();
},
},
};
</script>
<style scoped>
.theMainDiv {
display: flex;
flex-wrap: wrap;
width: 100%;
}
.mainFirstRow {
display: flex;
flex-wrap: nowrap;
width: 100%;
margin: 0.5vw;
}
.mainSecondRow {
display: flex;
flex-wrap: nowrap;
width: 100%;
margin: 0 0.5vw;
}
@media only screen and (max-width: 1000px) {
.mainFirstRow {
margin: 0;
margin-top: 0.5vw;
}
.mainSecondRow {
display: flex;
flex-wrap: wrap;
width: 100%;
margin: 0;
margin-top: 0.5vw;
}
}
</style>
-261
View File
@@ -1,261 +0,0 @@
import { createApp } from "vue";
import { createStore } from "vuex";
import App from "./App.vue";
import axios from "axios";
import VueAxios from "vue-axios";
const store = createStore({
state() {
return {
currentGame: "",
currentTrack: ``,
currentTrackHidden: false,
currentlyLoadingTrack: "",
specialTrackIsPlaying: false,
someoneHasWon: false,
winningScore: 20,
roundStarted: false,
reloadGamesList: false,
listOfPlayers: [],
localPlaylist: [],
playlistHistory: [
{
SongNo: "",
Game: "",
Song: "",
},
],
/* Stats */
howManyGames: 0,
/* Options */
stopAfterCurrent: true,
hideNextTrack: true,
addPlayed: true,
lowPlayed: false,
};
},
mutations: {
setCurrentGame(state, payload) {
state.currentGame = payload;
},
setCurrentTrack(state, payload) {
state.currentTrack = payload;
},
setCurrentTrackHidden(state, payload) {
state.currentTrackHidden = payload;
},
setCurrentlyLoadingTrack(state, payload) {
state.currentlyLoadingTrack = payload;
},
setSpecialTrackIsPlaying(state, payload) {
state.specialTrackIsPlaying = payload;
},
setSomeoneHasWon(state, payload) {
state.someoneHasWon = payload;
},
setWinningScore(state, payload) {
state.winningScore += payload;
},
setRoundStarted(state, payload) {
state.roundStarted = payload;
},
updateListOfPlayers(state, payload) {
state.listOfPlayers = payload;
},
changePlayerScore(state, payload) {
state.listOfPlayers[payload.indexOfPlayer].score += payload.scoreToChange;
},
changePlayerWelcomed(state, payload) {
state.listOfPlayers[payload.indexOfPlayer].welcomed = payload.playerWelcomeTrueOrFalse;
},
changePlayerMatchPoint(state, payload) {
state.listOfPlayers[payload.indexOfPlayer].matchPoint = payload.playerMatchPointTrueOrFalse;
},
changePlayerProfile(state, payload) {
state.listOfPlayers[payload.indexOfPlayer].profile = payload.profileSrc;
},
resetPlayerScore(state, payload) {
state.listOfPlayers = payload;
},
resetPlayerWelcomed(state, payload) {
state.listOfPlayers = payload;
},
resetPlayerMatchPoint(state, payload) {
state.listOfPlayers = payload;
},
updateLocalPlaylist(state, payload) {
state.localPlaylist.push(payload);
},
updatePlaylistHistory(state, payload) {
state.playlistHistory = payload;
},
updateHowManyGames(state, payload) {
state.howManyGames = payload;
},
reloadGamesList(state, payload) {
state.reloadGamesList = payload;
},
updateStopAfterCurrent(state, payload) {
state.stopAfterCurrent = payload;
},
updateHideNextTitle(state, payload) {
state.hideNextTrack = payload;
},
updateAddPlayed(state, payload) {
state.addPlayed = payload;
},
updateLowPlayed(state, payload) {
state.lowPlayed = payload;
},
},
actions: {
setCurrentGame(context, payload) {
context.commit("setCurrentGame", payload);
},
setCurrentTrack(context, payload) {
context.commit("setCurrentTrack", payload);
},
setCurrentTrackHidden(context, payload) {
context.commit("setCurrentTrackHidden", payload);
},
setCurrentlyLoadingTrack(context, payload) {
context.commit("setCurrentlyLoadingTrack", payload);
},
setSpecialTrackIsPlaying(context, payload) {
context.commit("setSpecialTrackIsPlaying", payload);
},
setSomeoneHasWon(context, payload) {
context.commit("someoneHasWon", payload);
},
setWinningScore(context, payload) {
context.commit("setWinningScore", payload);
},
setRoundStarted(context, payload) {
context.commit("setRoundStarted", payload);
},
removePlayer(context, payload) {
let newPlayerList = this.state.listOfPlayers.filter(
(player) => player.playerName != payload
);
context.commit("updateListOfPlayers", newPlayerList);
},
addNewPlayer(context, payload) {
let newPlayerList = this.state.listOfPlayers;
let newPlayer = {
playerName: payload,
score: 0,
welcomed: false,
matchPoint: false,
profile: "characters/noCharacter.png",
};
newPlayerList.push(newPlayer);
context.commit("updateListOfPlayers", newPlayerList);
},
changePlayerScore(context, payload) {
let copyOfPlayerList = this.state.listOfPlayers;
let indexOfPlayer = copyOfPlayerList.findIndex(
(player) => player.playerName === payload.playerName
);
let scoreToChange = payload.score;
context.commit("changePlayerScore", {
indexOfPlayer,
scoreToChange,
});
},
changePlayerWelcomed(context, payload) {
let copyOfPlayerList = this.state.listOfPlayers;
let indexOfPlayer = copyOfPlayerList.findIndex(
(player) => player.playerName === payload.playerName
);
let playerWelcomeTrueOrFalse = payload.welcomeSet;
context.commit("changePlayerWelcomed", {
indexOfPlayer,
playerWelcomeTrueOrFalse,
});
},
changePlayerMatchPoint(context, payload) {
let copyOfPlayerList = this.state.listOfPlayers;
let indexOfPlayer = copyOfPlayerList.findIndex(
(player) => player.playerName === payload.playerName
);
let playerMatchPointTrueOrFalse = payload.matchPointSet;
context.commit("changePlayerMatchPoint", {
indexOfPlayer,
playerMatchPointTrueOrFalse,
});
},
changePlayerProfile(context, payload) {
let copyOfPlayerList = this.state.listOfPlayers;
let indexOfPlayer = copyOfPlayerList.findIndex(
(player) => player.playerName === payload.playerName
);
let profileSrc = payload.profile;
context.commit("changePlayerProfile", {
indexOfPlayer,
profileSrc,
});
},
resetPlayerScore(context) {
/* The JSON.parse and JSON.stringify parts are used to make a copy that doesn't affect the original */
let copyOfPlayerList = JSON.parse(JSON.stringify(this.state.listOfPlayers));
for (let i = 0; i < copyOfPlayerList.length; i++) {
copyOfPlayerList[i].score = 0;
}
context.commit("resetPlayerScore", copyOfPlayerList);
},
resetPlayerWelcomed(context) {
/* The JSON.parse and JSON.stringify parts are used to make a copy that doesn't affect the original */
let copyOfPlayerList = JSON.parse(JSON.stringify(this.state.listOfPlayers));
for (let i = 0; i < copyOfPlayerList.length; i++) {
copyOfPlayerList[i].welcomed = false;
}
context.commit("resetPlayerWelcomed", copyOfPlayerList);
},
resetPlayerMatchPoint(context) {
/* The JSON.parse and JSON.stringify parts are used to make a copy that doesn't affect the original */
let copyOfPlayerList = JSON.parse(JSON.stringify(this.state.listOfPlayers));
for (let i = 0; i < copyOfPlayerList.length; i++) {
copyOfPlayerList[i].matchPoint = false;
}
context.commit("resetPlayerMatchPoint", copyOfPlayerList);
},
updateLocalPlaylist(context, payload) {
context.commit("updateLocalPlaylist", payload);
},
updatePlaylistHistory(context, payload) {
context.commit("updatePlaylistHistory", payload);
},
updateHowManyGames(context, payload) {
context.commit("updateHowManyGames", payload);
},
reloadGamesList(context, payload) {
context.commit("reloadGamesList", payload);
},
updateStopAfterCurrent(context, payload) {
context.commit("updateStopAfterCurrent", payload);
},
updateHideNextTitle(context, payload) {
context.commit("updateHideNextTitle", payload);
},
updateAddPlayed(context, payload) {
context.commit("updateAddPlayed", payload);
},
updateLowPlayed(context, payload) {
context.commit("updateLowPlayed", payload);
},
},
getters: {
/* Empty ATM */
/* getListOfPlayers: (state) => {
return state.listOfPlayers;
}, */
},
});
const app = createApp(App);
app.use(store);
app.use(VueAxios, axios);
app.mount("#app");
+32 -7
View File
@@ -1,17 +1,42 @@
package main package main
import ( import (
"embed" "context"
"music-server/pkg/conf" "os/signal"
"syscall"
"time"
"music-server/internal/logging"
"music-server/internal/server"
"go.uber.org/zap"
) )
//go:embed swagger const shutdownTimeout = 5 * time.Second
var swagger embed.FS
func main() { func main() {
conf.SetupDb() ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM)
defer stop()
conf.SetupRestServer(swagger) s := server.NewServerInstance()
conf.CloseDb() serveErr := make(chan error, 1)
go func() { serveErr <- s.ListenAndServe() }()
select {
case err := <-serveErr:
if err != nil {
logging.GetLogger().Fatal("HTTP server error", zap.Error(err))
}
case <-ctx.Done():
stop()
logging.GetLogger().Info("Shutting down gracefully, press Ctrl+C again to force")
}
shutdownCtx, cancel := context.WithTimeout(context.Background(), shutdownTimeout)
defer cancel()
if err := s.Shutdown(shutdownCtx); err != nil {
logging.GetLogger().Error("Server forced to shutdown with error", zap.Error(err))
}
logging.GetLogger().Info("Graceful shutdown complete")
} }
+51
View File
@@ -0,0 +1,51 @@
// Command openapi writes the MusicServer API description without starting the server.
//
// go run ./cmd/openapi -out .
//
// It writes openapi.json (OpenAPI 3.1) and openapi-3.0.json (OpenAPI 3.0, for tools
// that don't support 3.1 yet). A running server serves the same files at /openapi.json
// and /openapi-3.0.json.
package main
import (
"flag"
"fmt"
"os"
"path/filepath"
"music-server/internal/server"
)
func main() {
out := flag.String("out", ".", "directory to write openapi.json and openapi-3.0.json to")
flag.Parse()
if err := run(*out); err != nil {
fmt.Fprintln(os.Stderr, "openapi:", err)
os.Exit(1)
}
}
func run(out string) error {
spec := server.OpenAPISpec()
v31, err := spec.MarshalJSON()
if err != nil {
return err
}
v30, err := spec.Downgrade()
if err != nil {
return err
}
if err := os.MkdirAll(out, 0o755); err != nil {
return err
}
for name, data := range map[string][]byte{"openapi.json": v31, "openapi-3.0.json": v30} {
path := filepath.Join(out, name)
if err := os.WriteFile(path, data, 0o644); err != nil {
return err
}
fmt.Println("Wrote", path)
}
return nil
}
+28
View File
@@ -0,0 +1,28 @@
package main
import (
"encoding/json"
"os"
"path/filepath"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestRunWritesBothVersions(t *testing.T) {
dir := t.TempDir()
require.NoError(t, run(dir))
for name, version := range map[string]string{"openapi.json": "3.1.0", "openapi-3.0.json": "3.0.3"} {
data, err := os.ReadFile(filepath.Join(dir, name))
require.NoError(t, err)
var spec struct {
OpenAPI string `json:"openapi"`
Paths map[string]any `json:"paths"`
}
require.NoError(t, json.Unmarshal(data, &spec), name)
assert.Equal(t, version, spec.OpenAPI, name)
assert.Contains(t, spec.Paths, "/api/v1/music/info", name)
}
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 665 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 628 B

-60
View File
@@ -1,60 +0,0 @@
<!-- HTML for static distribution bundle build -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Swagger UI</title>
<link rel="stylesheet" type="text/css" href="./swagger-ui.css" />
<link rel="icon" type="image/png" href="./favicon-32x32.png" sizes="32x32" />
<link rel="icon" type="image/png" href="./favicon-16x16.png" sizes="16x16" />
<style>
html
{
box-sizing: border-box;
overflow: -moz-scrollbars-vertical;
overflow-y: scroll;
}
*,
*:before,
*:after
{
box-sizing: inherit;
}
body
{
margin:0;
background: #fafafa;
}
</style>
</head>
<body>
<div id="swagger-ui"></div>
<script src="./swagger-ui-bundle.js" charset="UTF-8"> </script>
<script src="./swagger-ui-standalone-preset.js" charset="UTF-8"> </script>
<script>
window.onload = function() {
// Begin Swagger UI call region
const ui = SwaggerUIBundle({
url: "./swagger.yaml",
dom_id: '#swagger-ui',
deepLinking: true,
presets: [
SwaggerUIBundle.presets.apis,
SwaggerUIStandalonePreset
],
plugins: [
SwaggerUIBundle.plugins.DownloadUrl
],
layout: "StandaloneLayout"
});
// End Swagger UI call region
window.ui = ui;
};
</script>
</body>
</html>
-75
View File
@@ -1,75 +0,0 @@
<!doctype html>
<html lang="en-US">
<head>
<title>Swagger UI: OAuth2 Redirect</title>
</head>
<body>
<script>
'use strict';
function run () {
var oauth2 = window.opener.swaggerUIRedirectOauth2;
var sentState = oauth2.state;
var redirectUrl = oauth2.redirectUrl;
var isValid, qp, arr;
if (/code|token|error/.test(window.location.hash)) {
qp = window.location.hash.substring(1);
} else {
qp = location.search.substring(1);
}
arr = qp.split("&");
arr.forEach(function (v,i,_arr) { _arr[i] = '"' + v.replace('=', '":"') + '"';});
qp = qp ? JSON.parse('{' + arr.join() + '}',
function (key, value) {
return key === "" ? value : decodeURIComponent(value);
}
) : {};
isValid = qp.state === sentState;
if ((
oauth2.auth.schema.get("flow") === "accessCode" ||
oauth2.auth.schema.get("flow") === "authorizationCode" ||
oauth2.auth.schema.get("flow") === "authorization_code"
) && !oauth2.auth.code) {
if (!isValid) {
oauth2.errCb({
authId: oauth2.auth.name,
source: "auth",
level: "warning",
message: "Authorization may be unsafe, passed state was changed in server Passed state wasn't returned from auth server"
});
}
if (qp.code) {
delete oauth2.state;
oauth2.auth.code = qp.code;
oauth2.callback({auth: oauth2.auth, redirectUrl: redirectUrl});
} else {
let oauthErrorMsg;
if (qp.error) {
oauthErrorMsg = "["+qp.error+"]: " +
(qp.error_description ? qp.error_description+ ". " : "no accessCode received from the server. ") +
(qp.error_uri ? "More info: "+qp.error_uri : "");
}
oauth2.errCb({
authId: oauth2.auth.name,
source: "auth",
level: "error",
message: oauthErrorMsg || "[Authorization failed]: no accessCode received from the server"
});
}
} else {
oauth2.callback({auth: oauth2.auth, token: qp, isValid: isValid, redirectUrl: redirectUrl});
}
window.close();
}
window.addEventListener('DOMContentLoaded', function () {
run();
});
</script>
</body>
</html>
-3
View File
@@ -1,3 +0,0 @@
/*! For license information please see swagger-ui-bundle.js.LICENSE.txt */
!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.SwaggerUIBundle=t():e.SwaggerUIBundle=t()}(this,(function(){return function(e){var t={};function n(r){if(t[r])return t[r].exports;var o=t[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,n),o.l=!0,o.exports}return n.m=e,n.c=t,n.d=function(e,t,r){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(n.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)n.d(r,o,function(t){return e[t]}.bind(null,o));return r},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="/dist",n(n.s=479)}([function(e,t,n){"use strict";e.exports=n(555)},function(e,t,n){e.exports=function(){"use strict";var e=Array.prototype.slice;function t(e,t){t&&(e.prototype=Object.create(t.prototype)),e.prototype.constructor=e}function n(e){return i(e)?e:J(e)}function r(e){return u(e)?e:K(e)}function o(e){return s(e)?e:Y(e)}function a(e){return i(e)&&!c(e)?e:G(e)}function i(e){return!(!e||!e[f])}function u(e){return!(!e||!e[p])}function s(e){return!(!e||!e[h])}function c(e){return u(e)||s(e)}function l(e){return!(!e||!e[d])}t(r,n),t(o,n),t(a,n),n.isIterable=i,n.isKeyed=u,n.isIndexed=s,n.isAssociative=c,n.isOrdered=l,n.Keyed=r,n.Indexed=o,n.Set=a;var f="@@__IMMUTABLE_ITERABLE__@@",p="@@__IMMUTABLE_KEYED__@@",h="@@__IMMUTABLE_INDEXED__@@",d="@@__IMMUTABLE_ORDERED__@@",m="delete",v=5,g=1<<v,y=g-1,b={},w={value:!1},x={value:!1};function E(e){return e.value=!1,e}function _(e){e&&(e.value=!0)}function S(){}function k(e,t){t=t||0;for(var n=Math.max(0,e.length-t),r=new Array(n),o=0;o<n;o++)r[o]=e[o+t];return r}function A(e){return void 0===e.size&&(e.size=e.__iterate(C)),e.size}function O(e,t){if("number"!=typeof t){var n=t>>>0;if(""+n!==t||4294967295===n)return NaN;t=n}return t<0?A(e)+t:t}function C(){return!0}function j(e,t,n){return(0===e||void 0!==n&&e<=-n)&&(void 0===t||void 0!==n&&t>=n)}function T(e,t){return P(e,t,0)}function I(e,t){return P(e,t,t)}function P(e,t,n){return void 0===e?n:e<0?Math.max(0,t+e):void 0===t?e:Math.min(t,e)}var N=0,M=1,R=2,D="function"==typeof Symbol&&Symbol.iterator,L="@@iterator",B=D||L;function F(e){this.next=e}function z(e,t,n,r){var o=0===e?t:1===e?n:[t,n];return r?r.value=o:r={value:o,done:!1},r}function U(){return{value:void 0,done:!0}}function q(e){return!!H(e)}function V(e){return e&&"function"==typeof e.next}function W(e){var t=H(e);return t&&t.call(e)}function H(e){var t=e&&(D&&e[D]||e[L]);if("function"==typeof t)return t}function $(e){return e&&"number"==typeof e.length}function J(e){return null==e?ie():i(e)?e.toSeq():ce(e)}function K(e){return null==e?ie().toKeyedSeq():i(e)?u(e)?e.toSeq():e.fromEntrySeq():ue(e)}function Y(e){return null==e?ie():i(e)?u(e)?e.entrySeq():e.toIndexedSeq():se(e)}function G(e){return(null==e?ie():i(e)?u(e)?e.entrySeq():e:se(e)).toSetSeq()}F.prototype.toString=function(){return"[Iterator]"},F.KEYS=N,F.VALUES=M,F.ENTRIES=R,F.prototype.inspect=F.prototype.toSource=function(){return this.toString()},F.prototype[B]=function(){return this},t(J,n),J.of=function(){return J(arguments)},J.prototype.toSeq=function(){return this},J.prototype.toString=function(){return this.__toString("Seq {","}")},J.prototype.cacheResult=function(){return!this._cache&&this.__iterateUncached&&(this._cache=this.entrySeq().toArray(),this.size=this._cache.length),this},J.prototype.__iterate=function(e,t){return fe(this,e,t,!0)},J.prototype.__iterator=function(e,t){return pe(this,e,t,!0)},t(K,J),K.prototype.toKeyedSeq=function(){return this},t(Y,J),Y.of=function(){return Y(arguments)},Y.prototype.toIndexedSeq=function(){return this},Y.prototype.toString=function(){return this.__toString("Seq [","]")},Y.prototype.__iterate=function(e,t){return fe(this,e,t,!1)},Y.prototype.__iterator=function(e,t){return pe(this,e,t,!1)},t(G,J),G.of=function(){return G(arguments)},G.prototype.toSetSeq=function(){return this},J.isSeq=ae,J.Keyed=K,J.Set=G,J.Indexed=Y;var Q,Z,X,ee="@@__IMMUTABLE_SEQ__@@";function te(e){this._array=e,this.size=e.length}function ne(e){var t=Object.keys(e);this._object=e,this._keys=t,this.size=t.length}function re(e){this._iterable=e,this.size=e.length||e.size}function oe(e){this._iterator=e,this._iteratorCache=[]}function ae(e){return!(!e||!e[ee])}function ie(){return Q||(Q=new te([]))}function ue(e){var t=Array.isArray(e)?new te(e).fromEntrySeq():V(e)?new oe(e).fromEntrySeq():q(e)?new re(e).fromEntrySeq():"object"==typeof e?new ne(e):void 0;if(Line truncated
//# sourceMappingURL=swagger-ui-bundle.js.map
-1
View File
@@ -1 +0,0 @@
{"version":3,"sources":["webpack://SwaggerUIBundle/webpack/universalModuleDefinition","webpack://SwaggerUIBundle/webpack/bootstrap","webpack://SwaggerUIBundle/./node_modules/react/index.js","webpack://SwaggerUIBundle/./node_modules/immutable/dist/immutable.js","webpack://SwaggerUIBundle/./node_modules/@babel/runtime-corejs3/core-js-stable/instance/concat.js","webpack://SwaggerUIBundle/./node_modules/@babel/runtime-corejs3/helpers/defineProperty.js","webpack://SwaggerUIBundle/./node_modules/@babel/runtime-corejs3/core-js-stable/instance/map.js","webpack://SwaggerUIBundle/./node_modules/@babel/runtime-corejs3/helpers/classCallCheck.js","webpack://SwaggerUIBundle/./node_modules/@babel/runtime-corejs3/helpers/createClass.js","webpack://SwaggerUIBundle/./src/core/utils.js","webpack://SwaggerUIBundle/./node_modules/@babel/runtime-corejs3/helpers/inherits.js","webpack://SwaggerUIBundle/./node_modules/@babel/runtime-corejs3/helpers/createSuper.js","webpack://SwaggerUIBundle/./node_modules/@babel/runtime-corejs3/helpers/assertThisInitialized.js","webpack://SwaggerUIBundle/./node_modules/prop-types/index.js","webpack://SwaggerUIBundle/./node_modules/@babel/runtime-corejs3/core-js-stable/instance/filter.js","webpack://SwaggerUIBundle/./node_modules/@babel/runtime-corejs3/helpers/slicedToArray.js","webpack://SwaggerUIBundle/./node_modules/@babel/runtime-corejs3/helpers/toConsumableArray.js","webpack://SwaggerUIBundle/./node_modules/@babel/runtime-corejs3/core-js-stable/object/keys.js","webpack://SwaggerUIBundle/./node_modules/core-js-pure/internals/export.js","webpack://SwaggerUIBundle/./node_modules/core-js-pure/internals/global.js","webpack://SwaggerUIBundle/./node_modules/reselect/es/defaultMemoize.js","webpack://SwaggerUIBundle/./node_modules/reselect/es/index.js","webpack://SwaggerUIBundle/./node_modules/@babel/runtime-corejs3/helpers/typeof.js","webpack://SwaggerUIBundle/./node_modules/@babel/runtime-corejs3/core-js-stable/instance/index-of.js","webpack://SwaggerUIBundle/./node_modules/@babel/runtime-corejs3/core-js-stable/instance/slice.js","webpack://SwaggerUIBundle/./node_modules/@babel/runtime-corejs3/core-js-stable/array/is-array.js","webpack://SwaggerUIBundle/./node_modules/@babel/runtime-corejs3/core-js-stable/instance/for-each.js","webpack://SwaggerUIBundle/./node_modules/@babel/runtime-corejs3/core-js-stable/object/assign.js","webpack://SwaggerUIBundle/./node_modules/@babel/runtime-corejs3/helpers/objectSpread2.js","webpack://SwaggerUIBundle/./node_modules/@babel/runtime-corejs3/helpers/extends.js","webpack://SwaggerUIBundle/./node_modules/core-js-pure/internals/function-uncurry-this.js","webpack://SwaggerUIBundle/./src/core/window.js","webpack://SwaggerUIBundle/./node_modules/react-immutable-proptypes/dist/ImmutablePropTypes.js","webpack://SwaggerUIBundle/./node_modules/@babel/runtime-corejs3/core-js-stable/json/stringify.js","webpack://SwaggerUIBundle/./node_modules/@babel/runtime-corejs3/core-js-stable/instance/reduce.js","webpack://SwaggerUIBundle/./node_modules/@babel/runtime-corejs3/core-js-stable/instance/includes.js","webpack://SwaggerUIBundle/./node_modules/core-js-pure/internals/an-object.js","webpack://SwaggerUIBundle/./node_modules/core-js-pure/internals/fails.js","webpack://SwaggerUIBundle/./node_modules/core-js-pure/internals/path.js","webpack://SwaggerUIBundle/./node_modules/core-js-pure/internals/object-is-prototype-of.js","webpack://SwaggerUIBundle/./node_modules/core-js-pure/internals/function-call.js","webpack://SwaggerUIBundle/./node_modules/core-js-pure/internals/is-pure.js","webpack://SwaggerUIBundle/./src/core/plugins/oas3/helpers.jsx","webpack://SwaggerUIBundle/./node_modules/core-js-pure/internals/well-known-symbol.js","webpack://SwaggerUIBundle/./node_modules/core-js-pure/internals/entry-virtual.js","webpack://SwaggerUIBundle/./node_modules/core-js-pure/internals/is-callable.js","webpack://SwaggerUIBundle/./node_modules/lodash/get.js","webpack://SwaggerUIBundle/./node_modules/@babel/runtime-corejs3/regenerator/index.js","webpack://SwaggerUIBundle/./node_modules/core-js-pure/internals/is-object.js","webpack://SwaggerUIBundle/./node_modules/core-js-pure/internals/a-callable.js","webpack://SwaggerUIBundle/./node_modules/core-js-pure/internals/has-own-property.js","webpack://SwaggerUIBundle/./node_modules/core-js-pure/internals/define-well-known-symbol.js","webpack://SwaggerUIBundle/./node_modules/core-js-pure/internals/iterate.js","webpack://SwaggerUIBundle/./node_modules/@babel/runtime-corejs3/core-js-stable/instance/bind.js","webpack://SwaggerUIBundle/./node_modules/core-js-pure/internals/descriptors.js","webpack://SwaggerUIBundle/./src/core/plugins/spec/actions.js","webpack://SwaggerUIBundle/./node_modules/classnames/index.js","webpack://SwaggerUIBundle/./node_modules/core-js-pure/internals/function-bind-context.js","webpack://SwaggerUIBundle/./node_modules/@babel/runtime-corejs3/core-js-stable/instance/find.js","webpack://SwaggerUIBundle/./node_modules/@babel/runtime-corejs3/hLine truncated
-3
View File
@@ -1,3 +0,0 @@
/*! For license information please see swagger-ui-es-bundle-core.js.LICENSE.txt */
module.exports=function(e){var t={};function n(r){if(t[r])return t[r].exports;var a=t[r]={i:r,l:!1,exports:{}};return e[r].call(a.exports,a,a.exports,n),a.l=!0,a.exports}return n.m=e,n.c=t,n.d=function(e,t,r){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(n.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var a in e)n.d(r,a,function(t){return e[t]}.bind(null,a));return r},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="/dist",n(n.s=452)}([function(e,t){e.exports=require("react")},function(e,t){e.exports=require("immutable")},function(e,t,n){e.exports=n(492)},function(e,t,n){var r=n(178);e.exports=function(e,t,n){return t in e?r(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e},e.exports.__esModule=!0,e.exports.default=e.exports},function(e,t,n){e.exports=n(522)},function(e,t){e.exports=function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")},e.exports.__esModule=!0,e.exports.default=e.exports},function(e,t,n){var r=n(178);function a(e,t){for(var n=0;n<t.length;n++){var a=t[n];a.enumerable=a.enumerable||!1,a.configurable=!0,"value"in a&&(a.writable=!0),r(e,a.key,a)}}e.exports=function(e,t,n){return t&&a(e.prototype,t),n&&a(e,n),r(e,"prototype",{writable:!1}),e},e.exports.__esModule=!0,e.exports.default=e.exports},function(e,t,n){"use strict";(function(e){n.d(t,"z",(function(){return be})),n.d(t,"i",(function(){return Ee})),n.d(t,"v",(function(){return xe})),n.d(t,"r",(function(){return Se})),n.d(t,"t",(function(){return we})),n.d(t,"s",(function(){return je})),n.d(t,"p",(function(){return Oe})),n.d(t,"u",(function(){return Ce})),n.d(t,"x",(function(){return _e})),n.d(t,"y",(function(){return Ae})),n.d(t,"J",(function(){return ke})),n.d(t,"f",(function(){return Ie})),n.d(t,"n",(function(){return Pe})),n.d(t,"h",(function(){return Te})),n.d(t,"D",(function(){return Re})),n.d(t,"K",(function(){return Me})),n.d(t,"o",(function(){return ze})),n.d(t,"C",(function(){return Ve})),n.d(t,"a",(function(){return Fe})),n.d(t,"H",(function(){return Je})),n.d(t,"b",(function(){return We})),n.d(t,"G",(function(){return He})),n.d(t,"F",(function(){return $e})),n.d(t,"E",(function(){return Ke})),n.d(t,"k",(function(){return Ye})),n.d(t,"d",(function(){return Ge})),n.d(t,"g",(function(){return Ze})),n.d(t,"m",(function(){return Xe})),n.d(t,"l",(function(){return Qe})),n.d(t,"e",(function(){return et})),n.d(t,"I",(function(){return tt})),n.d(t,"w",(function(){return nt})),n.d(t,"A",(function(){return rt})),n.d(t,"B",(function(){return at})),n.d(t,"j",(function(){return ot})),n.d(t,"c",(function(){return it})),n.d(t,"q",(function(){return ct}));var r=n(14),a=n.n(r),o=(n(13),n(19)),i=n.n(o),s=n(56),c=n.n(s),u=n(22),l=n.n(u),p=n(4),f=n.n(p),d=n(83),h=n.n(d),m=n(2),v=n.n(m),g=n(23),y=n.n(g),b=n(12),E=n.n(b),x=n(15),S=n.n(x),w=(n(50),n(31)),j=n.n(w),O=n(24),C=n.n(O),_=n(194),A=n.n(_),k=n(21),I=n.n(k),P=n(74),T=n.n(P),R=(n(32),n(30)),N=n.n(R),M=n(20),q=n.n(M),D=n(55),B=n.n(D),U=n(106),L=n.n(U),z=n(104),V=n.n(z),F=n(1),J=n.n(F),W=n(418),H=n(419),$=n.n(H),K=n(244),Y=n.n(K),G=n(107),Z=n.n(G),X=n(420),Q=n.n(X),ee=n(306),te=n.n(ee),ne=n(102),re=n.n(ne),ae=n(103),oe=n.n(ae),ie=n(133),se=n(28),ce=n(424),ue=n.n(ce),le=n(138),pe=n(117),fe=n.n(pe),de=n(425),he=n.n(de),me=n(73),ve=n.n(me),ge="default",ye=function(e){return J.a.Iterable.isIterable(e)};function be(e){return we(e)?ye(e)?e.toJS():e:{}}function Ee(e){var t,n;if(ye(e))return e;if(e instanceof se.a.File)return e;if(!we(e))return e;if(l()(e))return f()(n=J.a.Seq(e)).call(n,Ee).toList();if(oe()(h()(e))){var r,a=function(e){if(!oe()(h()(e)))return e;var t,n={},r="_**[]",a={},o=c()(h()(e).call(e));try{for(o.s();!(t=o.n()).done;){var i=t.value;if(n[i[0]]||a[i[0]]&&a[i[0]].containsMultiple){var s,u,l,p;if(!a[i[0]])a[i[0]]={containsMultiple:!0,length:1},n[v()(l=v()(p="".concat(i[0])).call(p,r)).call(l,a[i[0]].length)]=n[i[0]],delete n[i[0]];a[i[0]].length+=1,n[v()(s=v()(u="".concat(i[0])).call(u,r)).call(s,a[i[0]].length)]=i[1]}else n[i[0]]=i[1]}}catch(e){o.e(e)}finally{o.f()}return n}(e);return f()(r=J.a.OrderedMap(a)).call(r,Ee)}return f()(t=J.a.OrderedMap(e)).call(t,Ee)}function xe(e){return l()(e)?e:[e]}function Se(e){return"function"==typeof e}function we(e){return!!e&&"object"===i()(e)}function je(e){return"function"==typeof e}function Oe(e){return l()(e)}var Ce=Z.a;function _e(e,t){var n;return j()(n=S()(e)).call(n,(function(n,r){return n[r]=t(e[r],r),n}),{})}function Ae(e,t){var n;return j()(n=S()(e)).call(n,(function(n,r){var a=t(e[r],r);retuLine truncated
//# sourceMappingURL=swagger-ui-es-bundle-core.js.map
@@ -1 +0,0 @@
{"version":3,"sources":["webpack://SwaggerUIBundle/webpack/bootstrap","webpack://SwaggerUIBundle/external \"react\"","webpack://SwaggerUIBundle/external \"immutable\"","webpack://SwaggerUIBundle/./node_modules/@babel/runtime-corejs3/core-js-stable/instance/concat.js","webpack://SwaggerUIBundle/./node_modules/@babel/runtime-corejs3/helpers/defineProperty.js","webpack://SwaggerUIBundle/./node_modules/@babel/runtime-corejs3/core-js-stable/instance/map.js","webpack://SwaggerUIBundle/./node_modules/@babel/runtime-corejs3/helpers/classCallCheck.js","webpack://SwaggerUIBundle/./node_modules/@babel/runtime-corejs3/helpers/createClass.js","webpack://SwaggerUIBundle/./src/core/utils.js","webpack://SwaggerUIBundle/./node_modules/@babel/runtime-corejs3/helpers/inherits.js","webpack://SwaggerUIBundle/./node_modules/@babel/runtime-corejs3/helpers/createSuper.js","webpack://SwaggerUIBundle/./node_modules/@babel/runtime-corejs3/helpers/assertThisInitialized.js","webpack://SwaggerUIBundle/external \"prop-types\"","webpack://SwaggerUIBundle/./node_modules/@babel/runtime-corejs3/core-js-stable/instance/filter.js","webpack://SwaggerUIBundle/./node_modules/@babel/runtime-corejs3/helpers/slicedToArray.js","webpack://SwaggerUIBundle/./node_modules/@babel/runtime-corejs3/helpers/toConsumableArray.js","webpack://SwaggerUIBundle/./node_modules/@babel/runtime-corejs3/core-js-stable/object/keys.js","webpack://SwaggerUIBundle/./node_modules/core-js-pure/internals/export.js","webpack://SwaggerUIBundle/./node_modules/core-js-pure/internals/global.js","webpack://SwaggerUIBundle/external \"reselect\"","webpack://SwaggerUIBundle/./node_modules/@babel/runtime-corejs3/helpers/typeof.js","webpack://SwaggerUIBundle/./node_modules/@babel/runtime-corejs3/core-js-stable/instance/index-of.js","webpack://SwaggerUIBundle/./node_modules/@babel/runtime-corejs3/core-js-stable/instance/slice.js","webpack://SwaggerUIBundle/./node_modules/@babel/runtime-corejs3/core-js-stable/array/is-array.js","webpack://SwaggerUIBundle/./node_modules/@babel/runtime-corejs3/core-js-stable/instance/for-each.js","webpack://SwaggerUIBundle/./node_modules/@babel/runtime-corejs3/core-js-stable/object/assign.js","webpack://SwaggerUIBundle/./node_modules/@babel/runtime-corejs3/helpers/objectSpread2.js","webpack://SwaggerUIBundle/./node_modules/@babel/runtime-corejs3/helpers/extends.js","webpack://SwaggerUIBundle/./node_modules/core-js-pure/internals/function-uncurry-this.js","webpack://SwaggerUIBundle/./src/core/window.js","webpack://SwaggerUIBundle/external \"react-immutable-proptypes\"","webpack://SwaggerUIBundle/./node_modules/@babel/runtime-corejs3/core-js-stable/json/stringify.js","webpack://SwaggerUIBundle/./node_modules/@babel/runtime-corejs3/core-js-stable/instance/reduce.js","webpack://SwaggerUIBundle/./node_modules/@babel/runtime-corejs3/core-js-stable/instance/includes.js","webpack://SwaggerUIBundle/./node_modules/core-js-pure/internals/an-object.js","webpack://SwaggerUIBundle/./node_modules/core-js-pure/internals/fails.js","webpack://SwaggerUIBundle/./node_modules/core-js-pure/internals/path.js","webpack://SwaggerUIBundle/./node_modules/core-js-pure/internals/object-is-prototype-of.js","webpack://SwaggerUIBundle/./node_modules/core-js-pure/internals/function-call.js","webpack://SwaggerUIBundle/./node_modules/core-js-pure/internals/is-pure.js","webpack://SwaggerUIBundle/./src/core/plugins/oas3/helpers.jsx","webpack://SwaggerUIBundle/./node_modules/core-js-pure/internals/well-known-symbol.js","webpack://SwaggerUIBundle/./node_modules/core-js-pure/internals/entry-virtual.js","webpack://SwaggerUIBundle/./node_modules/core-js-pure/internals/is-callable.js","webpack://SwaggerUIBundle/./node_modules/lodash/get.js","webpack://SwaggerUIBundle/./node_modules/@babel/runtime-corejs3/regenerator/index.js","webpack://SwaggerUIBundle/./node_modules/core-js-pure/internals/is-object.js","webpack://SwaggerUIBundle/./node_modules/core-js-pure/internals/a-callable.js","webpack://SwaggerUIBundle/./node_modules/core-js-pure/internals/has-own-property.js","webpack://SwaggerUIBundle/./node_modules/core-js-pure/internals/define-well-known-symbol.js","webpack://SwaggerUIBundle/./node_modules/core-js-pure/internals/iterate.js","webpack://SwaggerUIBundle/./node_modules/@babel/runtime-corejs3/core-js-stable/instance/bind.js","webpack://SwaggerUIBundle/./node_modules/core-js-pure/internals/descriptors.js","webpack://SwaggerUIBundle/./src/core/plugins/spec/actions.js","webpack://SwaggerUIBundle/external \"classnames\"","webpack://SwaggerUIBundle/./node_modules/core-js-pure/internals/function-bind-context.js","webpack://SwaggerUIBundle/./node_modules/@babel/runtime-corejs3/core-js-stable/instance/find.js","webpack://SwaggerUIBundle/./node_modules/@babel/runtime-corejs3/helpers/createForOfIteratorHelper.js","webpack://SwaggerUIBundle/./node_modules/core-js-pure/internals/get-built-in.js","webpack://SwaggerUIBundle/./node_modules/lodash/isArray.js","webpack://SwaggerUIBundle/./node_modules/@babel/ruLine truncated
-3
View File
@@ -1,3 +0,0 @@
/*! For license information please see swagger-ui-es-bundle.js.LICENSE.txt */
module.exports=function(e){var t={};function n(r){if(t[r])return t[r].exports;var o=t[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,n),o.l=!0,o.exports}return n.m=e,n.c=t,n.d=function(e,t,r){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(n.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)n.d(r,o,function(t){return e[t]}.bind(null,o));return r},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="/dist",n(n.s=479)}([function(e,t,n){"use strict";e.exports=n(555)},function(e,t,n){e.exports=function(){"use strict";var e=Array.prototype.slice;function t(e,t){t&&(e.prototype=Object.create(t.prototype)),e.prototype.constructor=e}function n(e){return i(e)?e:J(e)}function r(e){return u(e)?e:K(e)}function o(e){return s(e)?e:Y(e)}function a(e){return i(e)&&!c(e)?e:G(e)}function i(e){return!(!e||!e[f])}function u(e){return!(!e||!e[p])}function s(e){return!(!e||!e[h])}function c(e){return u(e)||s(e)}function l(e){return!(!e||!e[d])}t(r,n),t(o,n),t(a,n),n.isIterable=i,n.isKeyed=u,n.isIndexed=s,n.isAssociative=c,n.isOrdered=l,n.Keyed=r,n.Indexed=o,n.Set=a;var f="@@__IMMUTABLE_ITERABLE__@@",p="@@__IMMUTABLE_KEYED__@@",h="@@__IMMUTABLE_INDEXED__@@",d="@@__IMMUTABLE_ORDERED__@@",m="delete",v=5,g=1<<v,y=g-1,b={},w={value:!1},x={value:!1};function E(e){return e.value=!1,e}function _(e){e&&(e.value=!0)}function S(){}function k(e,t){t=t||0;for(var n=Math.max(0,e.length-t),r=new Array(n),o=0;o<n;o++)r[o]=e[o+t];return r}function A(e){return void 0===e.size&&(e.size=e.__iterate(C)),e.size}function O(e,t){if("number"!=typeof t){var n=t>>>0;if(""+n!==t||4294967295===n)return NaN;t=n}return t<0?A(e)+t:t}function C(){return!0}function j(e,t,n){return(0===e||void 0!==n&&e<=-n)&&(void 0===t||void 0!==n&&t>=n)}function T(e,t){return P(e,t,0)}function I(e,t){return P(e,t,t)}function P(e,t,n){return void 0===e?n:e<0?Math.max(0,t+e):void 0===t?e:Math.min(t,e)}var N=0,M=1,R=2,D="function"==typeof Symbol&&Symbol.iterator,L="@@iterator",B=D||L;function F(e){this.next=e}function z(e,t,n,r){var o=0===e?t:1===e?n:[t,n];return r?r.value=o:r={value:o,done:!1},r}function U(){return{value:void 0,done:!0}}function q(e){return!!H(e)}function V(e){return e&&"function"==typeof e.next}function W(e){var t=H(e);return t&&t.call(e)}function H(e){var t=e&&(D&&e[D]||e[L]);if("function"==typeof t)return t}function $(e){return e&&"number"==typeof e.length}function J(e){return null==e?ie():i(e)?e.toSeq():ce(e)}function K(e){return null==e?ie().toKeyedSeq():i(e)?u(e)?e.toSeq():e.fromEntrySeq():ue(e)}function Y(e){return null==e?ie():i(e)?u(e)?e.entrySeq():e.toIndexedSeq():se(e)}function G(e){return(null==e?ie():i(e)?u(e)?e.entrySeq():e:se(e)).toSetSeq()}F.prototype.toString=function(){return"[Iterator]"},F.KEYS=N,F.VALUES=M,F.ENTRIES=R,F.prototype.inspect=F.prototype.toSource=function(){return this.toString()},F.prototype[B]=function(){return this},t(J,n),J.of=function(){return J(arguments)},J.prototype.toSeq=function(){return this},J.prototype.toString=function(){return this.__toString("Seq {","}")},J.prototype.cacheResult=function(){return!this._cache&&this.__iterateUncached&&(this._cache=this.entrySeq().toArray(),this.size=this._cache.length),this},J.prototype.__iterate=function(e,t){return fe(this,e,t,!0)},J.prototype.__iterator=function(e,t){return pe(this,e,t,!0)},t(K,J),K.prototype.toKeyedSeq=function(){return this},t(Y,J),Y.of=function(){return Y(arguments)},Y.prototype.toIndexedSeq=function(){return this},Y.prototype.toString=function(){return this.__toString("Seq [","]")},Y.prototype.__iterate=function(e,t){return fe(this,e,t,!1)},Y.prototype.__iterator=function(e,t){return pe(this,e,t,!1)},t(G,J),G.of=function(){return G(arguments)},G.prototype.toSetSeq=function(){return this},J.isSeq=ae,J.Keyed=K,J.Set=G,J.Indexed=Y;var Q,Z,X,ee="@@__IMMUTABLE_SEQ__@@";function te(e){this._array=e,this.size=e.length}function ne(e){var t=Object.keys(e);this._object=e,this._keys=t,this.size=t.length}function re(e){this._iterable=e,this.size=e.length||e.size}function oe(e){this._iterator=e,this._iteratorCache=[]}function ae(e){return!(!e||!e[ee])}function ie(){return Q||(Q=new te([]))}function ue(e){var t=Array.isArray(e)?new te(e).fromEntrySeq():V(e)?new oe(e).fromEntrySeq():q(e)?new re(e).fromEntrySeq():"object"==typeof e?new ne(e):void 0;if(!t)throw new TypeError("Expected Array or iterable object of [k, v] entries, or keyed object: "+e);return t}function se(e){var t=le(e);if(!t)throw new TypeError("Expected Array or iterable object of values: "+e);return tLine truncated
//# sourceMappingURL=swagger-ui-es-bundle.js.map
-1
View File
@@ -1 +0,0 @@
{"version":3,"sources":["webpack://SwaggerUIBundle/webpack/bootstrap","webpack://SwaggerUIBundle/./node_modules/react/index.js","webpack://SwaggerUIBundle/./node_modules/immutable/dist/immutable.js","webpack://SwaggerUIBundle/./node_modules/@babel/runtime-corejs3/core-js-stable/instance/concat.js","webpack://SwaggerUIBundle/./node_modules/@babel/runtime-corejs3/helpers/defineProperty.js","webpack://SwaggerUIBundle/./node_modules/@babel/runtime-corejs3/core-js-stable/instance/map.js","webpack://SwaggerUIBundle/./node_modules/@babel/runtime-corejs3/helpers/classCallCheck.js","webpack://SwaggerUIBundle/./node_modules/@babel/runtime-corejs3/helpers/createClass.js","webpack://SwaggerUIBundle/./src/core/utils.js","webpack://SwaggerUIBundle/./node_modules/@babel/runtime-corejs3/helpers/inherits.js","webpack://SwaggerUIBundle/./node_modules/@babel/runtime-corejs3/helpers/createSuper.js","webpack://SwaggerUIBundle/./node_modules/@babel/runtime-corejs3/helpers/assertThisInitialized.js","webpack://SwaggerUIBundle/./node_modules/prop-types/index.js","webpack://SwaggerUIBundle/./node_modules/@babel/runtime-corejs3/core-js-stable/instance/filter.js","webpack://SwaggerUIBundle/./node_modules/@babel/runtime-corejs3/helpers/slicedToArray.js","webpack://SwaggerUIBundle/./node_modules/@babel/runtime-corejs3/helpers/toConsumableArray.js","webpack://SwaggerUIBundle/./node_modules/@babel/runtime-corejs3/core-js-stable/object/keys.js","webpack://SwaggerUIBundle/./node_modules/core-js-pure/internals/export.js","webpack://SwaggerUIBundle/./node_modules/core-js-pure/internals/global.js","webpack://SwaggerUIBundle/./node_modules/reselect/es/defaultMemoize.js","webpack://SwaggerUIBundle/./node_modules/reselect/es/index.js","webpack://SwaggerUIBundle/./node_modules/@babel/runtime-corejs3/helpers/typeof.js","webpack://SwaggerUIBundle/./node_modules/@babel/runtime-corejs3/core-js-stable/instance/index-of.js","webpack://SwaggerUIBundle/./node_modules/@babel/runtime-corejs3/core-js-stable/instance/slice.js","webpack://SwaggerUIBundle/./node_modules/@babel/runtime-corejs3/core-js-stable/array/is-array.js","webpack://SwaggerUIBundle/./node_modules/@babel/runtime-corejs3/core-js-stable/instance/for-each.js","webpack://SwaggerUIBundle/./node_modules/@babel/runtime-corejs3/core-js-stable/object/assign.js","webpack://SwaggerUIBundle/./node_modules/@babel/runtime-corejs3/helpers/objectSpread2.js","webpack://SwaggerUIBundle/./node_modules/@babel/runtime-corejs3/helpers/extends.js","webpack://SwaggerUIBundle/./node_modules/core-js-pure/internals/function-uncurry-this.js","webpack://SwaggerUIBundle/./src/core/window.js","webpack://SwaggerUIBundle/./node_modules/react-immutable-proptypes/dist/ImmutablePropTypes.js","webpack://SwaggerUIBundle/./node_modules/@babel/runtime-corejs3/core-js-stable/json/stringify.js","webpack://SwaggerUIBundle/./node_modules/@babel/runtime-corejs3/core-js-stable/instance/reduce.js","webpack://SwaggerUIBundle/./node_modules/@babel/runtime-corejs3/core-js-stable/instance/includes.js","webpack://SwaggerUIBundle/./node_modules/core-js-pure/internals/an-object.js","webpack://SwaggerUIBundle/./node_modules/core-js-pure/internals/fails.js","webpack://SwaggerUIBundle/./node_modules/core-js-pure/internals/path.js","webpack://SwaggerUIBundle/./node_modules/core-js-pure/internals/object-is-prototype-of.js","webpack://SwaggerUIBundle/./node_modules/core-js-pure/internals/function-call.js","webpack://SwaggerUIBundle/./node_modules/core-js-pure/internals/is-pure.js","webpack://SwaggerUIBundle/./src/core/plugins/oas3/helpers.jsx","webpack://SwaggerUIBundle/./node_modules/core-js-pure/internals/well-known-symbol.js","webpack://SwaggerUIBundle/./node_modules/core-js-pure/internals/entry-virtual.js","webpack://SwaggerUIBundle/./node_modules/core-js-pure/internals/is-callable.js","webpack://SwaggerUIBundle/./node_modules/lodash/get.js","webpack://SwaggerUIBundle/./node_modules/@babel/runtime-corejs3/regenerator/index.js","webpack://SwaggerUIBundle/./node_modules/core-js-pure/internals/is-object.js","webpack://SwaggerUIBundle/./node_modules/core-js-pure/internals/a-callable.js","webpack://SwaggerUIBundle/./node_modules/core-js-pure/internals/has-own-property.js","webpack://SwaggerUIBundle/./node_modules/core-js-pure/internals/define-well-known-symbol.js","webpack://SwaggerUIBundle/./node_modules/core-js-pure/internals/iterate.js","webpack://SwaggerUIBundle/./node_modules/@babel/runtime-corejs3/core-js-stable/instance/bind.js","webpack://SwaggerUIBundle/./node_modules/core-js-pure/internals/descriptors.js","webpack://SwaggerUIBundle/./src/core/plugins/spec/actions.js","webpack://SwaggerUIBundle/./node_modules/classnames/index.js","webpack://SwaggerUIBundle/./node_modules/core-js-pure/internals/function-bind-context.js","webpack://SwaggerUIBundle/./node_modules/@babel/runtime-corejs3/core-js-stable/instance/find.js","webpack://SwaggerUIBundle/./node_modules/@babel/runtime-corejs3/helpers/createForOfIteratorHelper.js","webpack://SwaggerUIBundlLine truncated
@@ -1,3 +0,0 @@
/*! For license information please see swagger-ui-standalone-preset.js.LICENSE.txt */
!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.SwaggerUIStandalonePreset=e():t.SwaggerUIStandalonePreset=e()}(this,(function(){return function(t){var e={};function n(r){if(e[r])return e[r].exports;var i=e[r]={i:r,l:!1,exports:{}};return t[r].call(i.exports,i,i.exports,n),i.l=!0,i.exports}return n.m=t,n.c=e,n.d=function(t,e,r){n.o(t,e)||Object.defineProperty(t,e,{enumerable:!0,get:r})},n.r=function(t){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},n.t=function(t,e){if(1&e&&(t=n(t)),8&e)return t;if(4&e&&"object"==typeof t&&t&&t.__esModule)return t;var r=Object.create(null);if(n.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:t}),2&e&&"string"!=typeof t)for(var i in t)n.d(r,i,function(e){return t[e]}.bind(null,i));return r},n.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return n.d(e,"a",e),e},n.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},n.p="/dist",n(n.s=247)}([function(t,e,n){"use strict";var r=n(1),i=n(72),o=n(6),u=n(15),s=n(74).f,a=n(256),c=n(16),f=n(25),l=n(51),p=n(20),h=function(t){var e=function(n,r,o){if(this instanceof e){switch(arguments.length){case 0:return new t;case 1:return new t(n);case 2:return new t(n,r)}return new t(n,r,o)}return i(t,this,arguments)};return e.prototype=t.prototype,e};t.exports=function(t,e){var n,i,d,y,v,g,w,M,_=t.target,L=t.global,x=t.stat,m=t.proto,j=L?r:x?r[_]:(r[_]||{}).prototype,b=L?c:c[_]||l(c,_,{})[_],N=b.prototype;for(d in e)n=!a(L?d:_+(x?".":"#")+d,t.forced)&&j&&p(j,d),v=b[d],n&&(g=t.noTargetGet?(M=s(j,d))&&M.value:j[d]),y=n&&g?g:e[d],n&&typeof v==typeof y||(w=t.bind&&n?f(y,r):t.wrap&&n?h(y):m&&u(y)?o(y):y,(t.sham||y&&y.sham||v&&v.sham)&&l(w,"sham",!0),l(b,d,w),m&&(p(c,i=_+"Prototype")||l(c,i,{}),l(c[i],d,y),t.real&&N&&!N[d]&&l(N,d,y)))}},function(t,e,n){(function(e){var n=function(t){return t&&t.Math==Math&&t};t.exports=n("object"==typeof globalThis&&globalThis)||n("object"==typeof window&&window)||n("object"==typeof self&&self)||n("object"==typeof e&&e)||function(){return this}()||Function("return this")()}).call(this,n(33))},function(t,e,n){"use strict";t.exports=n(320)},function(t,e,n){t.exports=function(){"use strict";var t=Array.prototype.slice;function e(t,e){e&&(t.prototype=Object.create(e.prototype)),t.prototype.constructor=t}function n(t){return u(t)?t:J(t)}function r(t){return s(t)?t:Z(t)}function i(t){return a(t)?t:X(t)}function o(t){return u(t)&&!c(t)?t:V(t)}function u(t){return!(!t||!t[l])}function s(t){return!(!t||!t[p])}function a(t){return!(!t||!t[h])}function c(t){return s(t)||a(t)}function f(t){return!(!t||!t[d])}e(r,n),e(i,n),e(o,n),n.isIterable=u,n.isKeyed=s,n.isIndexed=a,n.isAssociative=c,n.isOrdered=f,n.Keyed=r,n.Indexed=i,n.Set=o;var l="@@__IMMUTABLE_ITERABLE__@@",p="@@__IMMUTABLE_KEYED__@@",h="@@__IMMUTABLE_INDEXED__@@",d="@@__IMMUTABLE_ORDERED__@@",y="delete",v=5,g=1<<v,w=g-1,M={},_={value:!1},L={value:!1};function x(t){return t.value=!1,t}function m(t){t&&(t.value=!0)}function j(){}function b(t,e){e=e||0;for(var n=Math.max(0,t.length-e),r=new Array(n),i=0;i<n;i++)r[i]=t[i+e];return r}function N(t){return void 0===t.size&&(t.size=t.__iterate(D)),t.size}function S(t,e){if("number"!=typeof e){var n=e>>>0;if(""+n!==e||4294967295===n)return NaN;e=n}return e<0?N(t)+e:e}function D(){return!0}function I(t,e,n){return(0===t||void 0!==n&&t<=-n)&&(void 0===e||void 0!==n&&e>=n)}function A(t,e){return C(t,e,0)}function T(t,e){return C(t,e,e)}function C(t,e,n){return void 0===t?n:t<0?Math.max(0,e+t):void 0===e?t:Math.min(e,t)}var E=0,O=1,z=2,k="function"==typeof Symbol&&Symbol.iterator,U="@@iterator",Y=k||U;function R(t){this.next=t}function P(t,e,n,r){var i=0===t?e:1===t?n:[e,n];return r?r.value=i:r={value:i,done:!1},r}function Q(){return{value:void 0,done:!0}}function B(t){return!!W(t)}function F(t){return t&&"function"==typeof t.next}function G(t){var e=W(t);return e&&e.call(t)}function W(t){var e=t&&(k&&t[k]||t[U]);if("function"==typeof e)return e}function q(t){return t&&"number"==typeof t.length}function J(t){return null==t?ut():u(t)?t.toSeq():ct(t)}function Z(t){return null==t?ut().toKeyedSeq():u(t)?s(t)?t.toSeq():t.fromEntrySeq():st(t)}function X(t){return null==t?ut():u(t)?s(t)?t.entrySeq():t.toIndexedSeq():at(t)}function V(t){return(null==t?ut():u(t)?s(t)?t.entrySeq():t:at(t)).toSetSeq()}R.prototype.toString=function(){return"[Iterator]"},R.KEYS=E,R.VALUES=O,R.ENTRIES=z,R.prototype.inspect=R.prototype.toSource=function(){return this.toString()},R.prototype[Y]=function(){return this},e(J,n),J.of=function(){return J(arguments)},J.prototype.toSeq=function(){return this},J.prototype.toString=function(){return this.__toString("Seq {","}")},J.prototype.cacheResult=function(){return!this._cache&&this.__iterateUncached&&(this._cache=this.entrySeq().Line truncated
//# sourceMappingURL=swagger-ui-standalone-preset.js.map
@@ -1 +0,0 @@
{"version":3,"sources":["webpack://SwaggerUIStandalonePreset/webpack/universalModuleDefinition","webpack://SwaggerUIStandalonePreset/webpack/bootstrap","webpack://SwaggerUIStandalonePreset/./node_modules/core-js-pure/internals/export.js","webpack://SwaggerUIStandalonePreset/./node_modules/core-js-pure/internals/global.js","webpack://SwaggerUIStandalonePreset/./node_modules/react/index.js","webpack://SwaggerUIStandalonePreset/./node_modules/immutable/dist/immutable.js","webpack://SwaggerUIStandalonePreset/./node_modules/core-js-pure/internals/an-object.js","webpack://SwaggerUIStandalonePreset/./node_modules/core-js-pure/internals/fails.js","webpack://SwaggerUIStandalonePreset/./node_modules/core-js-pure/internals/function-uncurry-this.js","webpack://SwaggerUIStandalonePreset/./node_modules/@babel/runtime-corejs3/core-js-stable/instance/concat.js","webpack://SwaggerUIStandalonePreset/./node_modules/@babel/runtime-corejs3/core-js-stable/array/is-array.js","webpack://SwaggerUIStandalonePreset/./node_modules/core-js-pure/internals/object-is-prototype-of.js","webpack://SwaggerUIStandalonePreset/./node_modules/core-js-pure/internals/is-pure.js","webpack://SwaggerUIStandalonePreset/./node_modules/core-js-pure/internals/function-call.js","webpack://SwaggerUIStandalonePreset/./node_modules/core-js-pure/internals/define-well-known-symbol.js","webpack://SwaggerUIStandalonePreset/./node_modules/core-js-pure/internals/well-known-symbol.js","webpack://SwaggerUIStandalonePreset/./node_modules/core-js-pure/internals/entry-virtual.js","webpack://SwaggerUIStandalonePreset/./node_modules/core-js-pure/internals/is-callable.js","webpack://SwaggerUIStandalonePreset/./node_modules/core-js-pure/internals/path.js","webpack://SwaggerUIStandalonePreset/./node_modules/core-js-pure/internals/a-callable.js","webpack://SwaggerUIStandalonePreset/./node_modules/core-js-pure/internals/descriptors.js","webpack://SwaggerUIStandalonePreset/./node_modules/core-js-pure/internals/is-object.js","webpack://SwaggerUIStandalonePreset/./node_modules/core-js-pure/internals/has-own-property.js","webpack://SwaggerUIStandalonePreset/./node_modules/core-js-pure/internals/iterate.js","webpack://SwaggerUIStandalonePreset/./node_modules/@babel/runtime-corejs3/core-js-stable/instance/for-each.js","webpack://SwaggerUIStandalonePreset/./node_modules/@babel/runtime-corejs3/core-js-stable/instance/map.js","webpack://SwaggerUIStandalonePreset/./src/core/utils.js","webpack://SwaggerUIStandalonePreset/./node_modules/core-js-pure/internals/function-bind-context.js","webpack://SwaggerUIStandalonePreset/./node_modules/@babel/runtime-corejs3/helpers/defineProperty.js","webpack://SwaggerUIStandalonePreset/./node_modules/core-js-pure/internals/to-object.js","webpack://SwaggerUIStandalonePreset/./node_modules/core-js-pure/internals/object-define-property.js","webpack://SwaggerUIStandalonePreset/./node_modules/inherits/inherits_browser.js","webpack://SwaggerUIStandalonePreset/./node_modules/safe-buffer/index.js","webpack://SwaggerUIStandalonePreset/./node_modules/@babel/runtime-corejs3/helpers/typeof.js","webpack://SwaggerUIStandalonePreset/./node_modules/core-js-pure/internals/get-built-in.js","webpack://SwaggerUIStandalonePreset/(webpack)/buildin/global.js","webpack://SwaggerUIStandalonePreset/./node_modules/core-js-pure/internals/length-of-array-like.js","webpack://SwaggerUIStandalonePreset/./node_modules/lodash/isArray.js","webpack://SwaggerUIStandalonePreset/./node_modules/core-js-pure/internals/get-map-iterator.js","webpack://SwaggerUIStandalonePreset/./node_modules/@babel/runtime-corejs3/helpers/classCallCheck.js","webpack://SwaggerUIStandalonePreset/./node_modules/@babel/runtime-corejs3/helpers/createClass.js","webpack://SwaggerUIStandalonePreset/./node_modules/@babel/runtime-corejs3/helpers/inherits.js","webpack://SwaggerUIStandalonePreset/./node_modules/@babel/runtime-corejs3/helpers/createSuper.js","webpack://SwaggerUIStandalonePreset/./node_modules/core-js-pure/internals/to-indexed-object.js","webpack://SwaggerUIStandalonePreset/./node_modules/core-js-pure/internals/array-iteration.js","webpack://SwaggerUIStandalonePreset/./node_modules/lodash/_root.js","webpack://SwaggerUIStandalonePreset/./node_modules/@babel/runtime-corejs3/helpers/assertThisInitialized.js","webpack://SwaggerUIStandalonePreset/./node_modules/@babel/runtime-corejs3/core-js-stable/instance/filter.js","webpack://SwaggerUIStandalonePreset/./node_modules/@babel/runtime-corejs3/core-js-stable/object/keys.js","webpack://SwaggerUIStandalonePreset/./node_modules/core-js-pure/internals/classof.js","webpack://SwaggerUIStandalonePreset/./node_modules/lodash/memoize.js","webpack://SwaggerUIStandalonePreset/./node_modules/@babel/runtime-corejs3/helpers/toConsumableArray.js","webpack://SwaggerUIStandalonePreset/./node_modules/core-js-pure/internals/classof-raw.js","webpack://SwaggerUIStandalonePreset/./node_modules/core-js-pure/internals/create-non-enumerable-property.js","webpack://SwaggerUIStandalonePresetLine truncated
-4
View File
@@ -1,4 +0,0 @@
.swagger-ui{color:#3b4151;
/*! normalize.css v7.0.0 | MIT License | github.com/necolas/normalize.css */font-family:sans-serif}.swagger-ui html{-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%;line-height:1.15}.swagger-ui body{margin:0}.swagger-ui article,.swagger-ui aside,.swagger-ui footer,.swagger-ui header,.swagger-ui nav,.swagger-ui section{display:block}.swagger-ui h1{font-size:2em;margin:.67em 0}.swagger-ui figcaption,.swagger-ui figure,.swagger-ui main{display:block}.swagger-ui figure{margin:1em 40px}.swagger-ui hr{box-sizing:content-box;height:0;overflow:visible}.swagger-ui pre{font-family:monospace,monospace;font-size:1em}.swagger-ui a{-webkit-text-decoration-skip:objects;background-color:transparent}.swagger-ui abbr[title]{border-bottom:none;text-decoration:underline;-webkit-text-decoration:underline dotted;text-decoration:underline dotted}.swagger-ui b,.swagger-ui strong{font-weight:inherit;font-weight:bolder}.swagger-ui code,.swagger-ui kbd,.swagger-ui samp{font-family:monospace,monospace;font-size:1em}.swagger-ui dfn{font-style:italic}.swagger-ui mark{background-color:#ff0;color:#000}.swagger-ui small{font-size:80%}.swagger-ui sub,.swagger-ui sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}.swagger-ui sub{bottom:-.25em}.swagger-ui sup{top:-.5em}.swagger-ui audio,.swagger-ui video{display:inline-block}.swagger-ui audio:not([controls]){display:none;height:0}.swagger-ui img{border-style:none}.swagger-ui svg:not(:root){overflow:hidden}.swagger-ui button,.swagger-ui input,.swagger-ui optgroup,.swagger-ui select,.swagger-ui textarea{font-family:sans-serif;font-size:100%;line-height:1.15;margin:0}.swagger-ui button,.swagger-ui input{overflow:visible}.swagger-ui button,.swagger-ui select{text-transform:none}.swagger-ui [type=reset],.swagger-ui [type=submit],.swagger-ui button,.swagger-ui html [type=button]{-webkit-appearance:button}.swagger-ui [type=button]::-moz-focus-inner,.swagger-ui [type=reset]::-moz-focus-inner,.swagger-ui [type=submit]::-moz-focus-inner,.swagger-ui button::-moz-focus-inner{border-style:none;padding:0}.swagger-ui [type=button]:-moz-focusring,.swagger-ui [type=reset]:-moz-focusring,.swagger-ui [type=submit]:-moz-focusring,.swagger-ui button:-moz-focusring{outline:1px dotted ButtonText}.swagger-ui fieldset{padding:.35em .75em .625em}.swagger-ui legend{box-sizing:border-box;color:inherit;display:table;max-width:100%;padding:0;white-space:normal}.swagger-ui progress{display:inline-block;vertical-align:baseline}.swagger-ui textarea{overflow:auto}.swagger-ui [type=checkbox],.swagger-ui [type=radio]{box-sizing:border-box;padding:0}.swagger-ui [type=number]::-webkit-inner-spin-button,.swagger-ui [type=number]::-webkit-outer-spin-button{height:auto}.swagger-ui [type=search]{-webkit-appearance:textfield;outline-offset:-2px}.swagger-ui [type=search]::-webkit-search-cancel-button,.swagger-ui [type=search]::-webkit-search-decoration{-webkit-appearance:none}.swagger-ui ::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}.swagger-ui details,.swagger-ui menu{display:block}.swagger-ui summary{display:list-item}.swagger-ui canvas{display:inline-block}.swagger-ui [hidden],.swagger-ui template{display:none}.swagger-ui .debug *{outline:1px solid gold}.swagger-ui .debug-white *{outline:1px solid #fff}.swagger-ui .debug-black *{outline:1px solid #000}.swagger-ui .debug-grid{background:transparent url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAYAAADED76LAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyhpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNi1jMTExIDc5LjE1ODMyNSwgMjAxNS8wOS8xMC0wMToxMDoyMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6MTRDOTY4N0U2N0VFMTFFNjg2MzZDQjkwNkQ4MjgwMEIiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6MTRDOTY4N0Q2N0VFMTFFNjg2MzZDQjkwNkQ4MjgwMEIiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTUgKE1hY2ludG9zaCkiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo3NjcyQkQ3NjY3QzUxMUU2QjJCQ0UyNDA4MTAwMjE3MSIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo3NjcyQkQ3NzY3QzUxMUU2QjJCQ0UyNDA4MTAwMjE3MSIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PsBS+GMAAAAjSURBVHjaYvz//z8DLsD4gcGXiYEAGBIKGBne//fFpwAgwAB98AaF2pjlUQAAAABJRU5ErkJggg==) repeat 0 0}.swagger-ui .debug-grid-16{background:transparent url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyhpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eLine truncated
/*# sourceMappingURL=swagger-ui.css.map*/
-1
View File
@@ -1 +0,0 @@
{"version":3,"sources":["webpack:///./src/style/main.scss","webpack:///./src/style/_type.scss","webpack:///./src/style/_variables.scss","webpack:///./node_modules/tachyons-sass/scss/_normalize.scss","webpack:///./node_modules/tachyons-sass/scss/_debug-children.scss","webpack:///./node_modules/tachyons-sass/scss/_debug-grid.scss","webpack:///./node_modules/tachyons-sass/scss/_box-sizing.scss","webpack:///./node_modules/tachyons-sass/scss/_aspect-ratios.scss","webpack:///./node_modules/tachyons-sass/scss/_images.scss","webpack:///./node_modules/tachyons-sass/scss/_background-size.scss","webpack:///./node_modules/tachyons-sass/scss/_background-position.scss","webpack:///./node_modules/tachyons-sass/scss/_outlines.scss","webpack:///./node_modules/tachyons-sass/scss/_borders.scss","webpack:///./node_modules/tachyons-sass/scss/_border-colors.scss","webpack:///./node_modules/tachyons-sass/scss/_border-radius.scss","webpack:///./node_modules/tachyons-sass/scss/_border-style.scss","webpack:///./node_modules/tachyons-sass/scss/_border-widths.scss","webpack:///./node_modules/tachyons-sass/scss/_box-shadow.scss","webpack:///./node_modules/tachyons-sass/scss/_code.scss","webpack:///./node_modules/tachyons-sass/scss/_coordinates.scss","webpack:///./node_modules/tachyons-sass/scss/_clears.scss","webpack:///./node_modules/tachyons-sass/scss/_flexbox.scss","webpack:///./node_modules/tachyons-sass/scss/_display.scss","webpack:///./node_modules/tachyons-sass/scss/_floats.scss","webpack:///./node_modules/tachyons-sass/scss/_font-family.scss","webpack:///./node_modules/tachyons-sass/scss/_font-style.scss","webpack:///./node_modules/tachyons-sass/scss/_font-weight.scss","webpack:///./node_modules/tachyons-sass/scss/_forms.scss","webpack:///./node_modules/tachyons-sass/scss/_heights.scss","webpack:///./node_modules/tachyons-sass/scss/_letter-spacing.scss","webpack:///./node_modules/tachyons-sass/scss/_line-height.scss","webpack:///./node_modules/tachyons-sass/scss/_links.scss","webpack:///./node_modules/tachyons-sass/scss/_lists.scss","webpack:///./node_modules/tachyons-sass/scss/_max-widths.scss","webpack:///./node_modules/tachyons-sass/scss/_widths.scss","webpack:///./node_modules/tachyons-sass/scss/_overflow.scss","webpack:///./node_modules/tachyons-sass/scss/_position.scss","webpack:///./node_modules/tachyons-sass/scss/_opacity.scss","webpack:///./node_modules/tachyons-sass/scss/_rotations.scss","webpack:///./node_modules/tachyons-sass/scss/_skins.scss","webpack:///./node_modules/tachyons-sass/scss/_skins-pseudo.scss","webpack:///./node_modules/tachyons-sass/scss/_spacing.scss","webpack:///./node_modules/tachyons-sass/scss/_variables.scss","webpack:///./node_modules/tachyons-sass/scss/_negative-margins.scss","webpack:///./node_modules/tachyons-sass/scss/_tables.scss","webpack:///./node_modules/tachyons-sass/scss/_text-decoration.scss","webpack:///./node_modules/tachyons-sass/scss/_text-align.scss","webpack:///./node_modules/tachyons-sass/scss/_text-transform.scss","webpack:///./node_modules/tachyons-sass/scss/_type-scale.scss","webpack:///./node_modules/tachyons-sass/scss/_typography.scss","webpack:///./node_modules/tachyons-sass/scss/_utilities.scss","webpack:///./node_modules/tachyons-sass/scss/_visibility.scss","webpack:///./node_modules/tachyons-sass/scss/_white-space.scss","webpack:///./node_modules/tachyons-sass/scss/_vertical-align.scss","webpack:///./node_modules/tachyons-sass/scss/_hovers.scss","webpack:///./node_modules/tachyons-sass/scss/_z-index.scss","webpack:///./node_modules/tachyons-sass/scss/_nested.scss","webpack:///./src/style/_layout.scss","webpack:///./src/style/_buttons.scss","webpack:///./src/style/_mixins.scss","webpack:///./src/style/_form.scss","webpack:///./src/style/_modal.scss","webpack:///./src/style/_models.scss","webpack:///./src/style/_servers.scss","webpack:///./src/style/_table.scss","webpack:///./src/style/_topbar.scss","webpack:///./src/style/_information.scss","webpack:///./src/style/_authorize.scss","webpack:///./src/style/_errors.scss","webpack:///./src/style/_split-pane-mode.scss","webpack:///./src/style/_markdown.scss"],"names":[],"mappings":"AAAA,YCII,aCYU;ECTd,4EFLI,sBDqhCJ,CGrgCA,iBAEE,0BACA,8BAFA,gBH4gCF,CGhgCA,iBACE,QHkgCF,CG3/BA,gHAME,aH6/BF,CGr/BA,eACE,cACA,cHu/BF,CG5+BA,2DAGE,aH++BF,CGx+BA,mBACE,eH0+BF,CGl+BA,eACE,uBACA,SACA,gBHu+BF,CG/9BA,gBACE,gCACA,aHm+BF,CGx9BA,cAEE,qCADA,4BH69BF,CGp9BA,wBACE,mBACA,0BACA,yEHy9BF,CGl9BA,iCAEE,oBASA,kBH28BF,CGn8BA,kDAGE,gCACA,aH28BF,CGp8BA,gBACE,iBHs8BF,CG/7BA,iBACE,sBACA,UHi8BF,CG17BA,kBACE,aH47BF,CGp7BA,gCAEE,cACA,cACA,kBACA,uBHs7BF,CGn7BA,gBACE,aHq7BF,CGl7BA,gBACE,SHo7BF,CG16BA,oCAEE,oBH46BF,CGr6BA,kCACE,aACA,QHu6BF,CGh6BA,gBACE,iBHk6BF,CG35BA,2BACE,eH65BF,CGl5BA,kGAKE,uBACA,eACA,iBACA,QHw5BF,CGh5BA,qCAEE,gBHm5BF,CG34BA,sCAEE,mBH84BF,CGr4BA,qGAIE,yBHw4BF,CGj4BA,wKAIE,kBACA,SHm4BF,CG53BA,4JAIE,6BH83BF,CGv3BA,qBACE,0BHy3BF,CG/2BA,mBACE,sBACA,cACA,cACA,eACA,UACA,kBHu3BF,CG/2BA,qBACE,qBACA,uBHm3BF,CG52BA,qBACE,aH82BF,CGt2BA,qDAEE,sBACA,SH02BLine truncated
-3
View File
@@ -1,3 +0,0 @@
/*! For license information please see swagger-ui.js.LICENSE.txt */
!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.SwaggerUICore=t():e.SwaggerUICore=t()}(this,(function(){return function(e){var t={};function n(r){if(t[r])return t[r].exports;var a=t[r]={i:r,l:!1,exports:{}};return e[r].call(a.exports,a,a.exports,n),a.l=!0,a.exports}return n.m=e,n.c=t,n.d=function(e,t,r){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(n.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var a in e)n.d(r,a,function(t){return e[t]}.bind(null,a));return r},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="/dist",n(n.s=452)}([function(e,t){e.exports=require("react")},function(e,t){e.exports=require("immutable")},function(e,t,n){e.exports=n(492)},function(e,t,n){var r=n(178);e.exports=function(e,t,n){return t in e?r(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e},e.exports.__esModule=!0,e.exports.default=e.exports},function(e,t,n){e.exports=n(522)},function(e,t){e.exports=function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")},e.exports.__esModule=!0,e.exports.default=e.exports},function(e,t,n){var r=n(178);function a(e,t){for(var n=0;n<t.length;n++){var a=t[n];a.enumerable=a.enumerable||!1,a.configurable=!0,"value"in a&&(a.writable=!0),r(e,a.key,a)}}e.exports=function(e,t,n){return t&&a(e.prototype,t),n&&a(e,n),r(e,"prototype",{writable:!1}),e},e.exports.__esModule=!0,e.exports.default=e.exports},function(e,t,n){"use strict";(function(e){n.d(t,"z",(function(){return be})),n.d(t,"i",(function(){return Ee})),n.d(t,"v",(function(){return xe})),n.d(t,"r",(function(){return Se})),n.d(t,"t",(function(){return we})),n.d(t,"s",(function(){return je})),n.d(t,"p",(function(){return Oe})),n.d(t,"u",(function(){return Ce})),n.d(t,"x",(function(){return _e})),n.d(t,"y",(function(){return Ae})),n.d(t,"J",(function(){return ke})),n.d(t,"f",(function(){return Ie})),n.d(t,"n",(function(){return Pe})),n.d(t,"h",(function(){return Te})),n.d(t,"D",(function(){return Re})),n.d(t,"K",(function(){return Me})),n.d(t,"o",(function(){return ze})),n.d(t,"C",(function(){return Ve})),n.d(t,"a",(function(){return Fe})),n.d(t,"H",(function(){return Je})),n.d(t,"b",(function(){return We})),n.d(t,"G",(function(){return He})),n.d(t,"F",(function(){return $e})),n.d(t,"E",(function(){return Ke})),n.d(t,"k",(function(){return Ye})),n.d(t,"d",(function(){return Ge})),n.d(t,"g",(function(){return Ze})),n.d(t,"m",(function(){return Xe})),n.d(t,"l",(function(){return Qe})),n.d(t,"e",(function(){return et})),n.d(t,"I",(function(){return tt})),n.d(t,"w",(function(){return nt})),n.d(t,"A",(function(){return rt})),n.d(t,"B",(function(){return at})),n.d(t,"j",(function(){return ot})),n.d(t,"c",(function(){return it})),n.d(t,"q",(function(){return ct}));var r=n(14),a=n.n(r),o=(n(13),n(19)),i=n.n(o),s=n(56),c=n.n(s),u=n(22),l=n.n(u),p=n(4),f=n.n(p),d=n(83),h=n.n(d),m=n(2),v=n.n(m),g=n(23),y=n.n(g),b=n(12),E=n.n(b),x=n(15),S=n.n(x),w=(n(50),n(31)),j=n.n(w),O=n(24),C=n.n(O),_=n(194),A=n.n(_),k=n(21),I=n.n(k),P=n(74),T=n.n(P),R=(n(32),n(30)),N=n.n(R),M=n(20),q=n.n(M),D=n(55),B=n.n(D),U=n(106),L=n.n(U),z=n(104),V=n.n(z),F=n(1),J=n.n(F),W=n(418),H=n(419),$=n.n(H),K=n(244),Y=n.n(K),G=n(107),Z=n.n(G),X=n(420),Q=n.n(X),ee=n(306),te=n.n(ee),ne=n(102),re=n.n(ne),ae=n(103),oe=n.n(ae),ie=n(133),se=n(28),ce=n(424),ue=n.n(ce),le=n(138),pe=n(117),fe=n.n(pe),de=n(425),he=n.n(de),me=n(73),ve=n.n(me),ge="default",ye=function(e){return J.a.Iterable.isIterable(e)};function be(e){return we(e)?ye(e)?e.toJS():e:{}}function Ee(e){var t,n;if(ye(e))return e;if(e instanceof se.a.File)return e;if(!we(e))return e;if(l()(e))return f()(n=J.a.Seq(e)).call(n,Ee).toList();if(oe()(h()(e))){var r,a=function(e){if(!oe()(h()(e)))return e;var t,n={},r="_**[]",a={},o=c()(h()(e).call(e));try{for(o.s();!(t=o.n()).done;){var i=t.value;if(n[i[0]]||a[i[0]]&&a[i[0]].containsMultiple){var s,u,l,p;if(!a[i[0]])a[i[0]]={containsMultiple:!0,length:1},n[v()(l=v()(p="".concat(i[0])).call(p,r)).call(l,a[i[0]].length)]=n[i[0]],delete n[i[0]];a[i[0]].length+=1,n[v()(s=v()(u="".concat(i[0])).call(u,r)).call(s,a[i[0]].length)]=i[1]}else n[i[0]]=i[1]}}catch(e){o.e(e)}finally{o.f()}return n}(e);return f()(r=J.a.OrderedMap(a)).call(r,Ee)}return f()(t=J.a.OrderedMap(e)).call(t,Ee)}function xe(e){return l()(e)?e:[e]}function Se(e){return"function"==typeof e}function we(e){return!!e&&"object"===i()(e)}function je(e){return"function"==typeof e}functiLine truncated
//# sourceMappingURL=swagger-ui.js.map
-1
View File
@@ -1 +0,0 @@
{"version":3,"sources":["webpack://SwaggerUICore/webpack/universalModuleDefinition","webpack://SwaggerUICore/webpack/bootstrap","webpack://SwaggerUICore/external \"react\"","webpack://SwaggerUICore/external \"immutable\"","webpack://SwaggerUICore/./node_modules/@babel/runtime-corejs3/core-js-stable/instance/concat.js","webpack://SwaggerUICore/./node_modules/@babel/runtime-corejs3/helpers/defineProperty.js","webpack://SwaggerUICore/./node_modules/@babel/runtime-corejs3/core-js-stable/instance/map.js","webpack://SwaggerUICore/./node_modules/@babel/runtime-corejs3/helpers/classCallCheck.js","webpack://SwaggerUICore/./node_modules/@babel/runtime-corejs3/helpers/createClass.js","webpack://SwaggerUICore/./src/core/utils.js","webpack://SwaggerUICore/./node_modules/@babel/runtime-corejs3/helpers/inherits.js","webpack://SwaggerUICore/./node_modules/@babel/runtime-corejs3/helpers/createSuper.js","webpack://SwaggerUICore/./node_modules/@babel/runtime-corejs3/helpers/assertThisInitialized.js","webpack://SwaggerUICore/external \"prop-types\"","webpack://SwaggerUICore/./node_modules/@babel/runtime-corejs3/core-js-stable/instance/filter.js","webpack://SwaggerUICore/./node_modules/@babel/runtime-corejs3/helpers/slicedToArray.js","webpack://SwaggerUICore/./node_modules/@babel/runtime-corejs3/helpers/toConsumableArray.js","webpack://SwaggerUICore/./node_modules/@babel/runtime-corejs3/core-js-stable/object/keys.js","webpack://SwaggerUICore/./node_modules/core-js-pure/internals/export.js","webpack://SwaggerUICore/./node_modules/core-js-pure/internals/global.js","webpack://SwaggerUICore/external \"reselect\"","webpack://SwaggerUICore/./node_modules/@babel/runtime-corejs3/helpers/typeof.js","webpack://SwaggerUICore/./node_modules/@babel/runtime-corejs3/core-js-stable/instance/index-of.js","webpack://SwaggerUICore/./node_modules/@babel/runtime-corejs3/core-js-stable/instance/slice.js","webpack://SwaggerUICore/./node_modules/@babel/runtime-corejs3/core-js-stable/array/is-array.js","webpack://SwaggerUICore/./node_modules/@babel/runtime-corejs3/core-js-stable/instance/for-each.js","webpack://SwaggerUICore/./node_modules/@babel/runtime-corejs3/core-js-stable/object/assign.js","webpack://SwaggerUICore/./node_modules/@babel/runtime-corejs3/helpers/objectSpread2.js","webpack://SwaggerUICore/./node_modules/@babel/runtime-corejs3/helpers/extends.js","webpack://SwaggerUICore/./node_modules/core-js-pure/internals/function-uncurry-this.js","webpack://SwaggerUICore/./src/core/window.js","webpack://SwaggerUICore/external \"react-immutable-proptypes\"","webpack://SwaggerUICore/./node_modules/@babel/runtime-corejs3/core-js-stable/json/stringify.js","webpack://SwaggerUICore/./node_modules/@babel/runtime-corejs3/core-js-stable/instance/reduce.js","webpack://SwaggerUICore/./node_modules/@babel/runtime-corejs3/core-js-stable/instance/includes.js","webpack://SwaggerUICore/./node_modules/core-js-pure/internals/an-object.js","webpack://SwaggerUICore/./node_modules/core-js-pure/internals/fails.js","webpack://SwaggerUICore/./node_modules/core-js-pure/internals/path.js","webpack://SwaggerUICore/./node_modules/core-js-pure/internals/object-is-prototype-of.js","webpack://SwaggerUICore/./node_modules/core-js-pure/internals/function-call.js","webpack://SwaggerUICore/./node_modules/core-js-pure/internals/is-pure.js","webpack://SwaggerUICore/./src/core/plugins/oas3/helpers.jsx","webpack://SwaggerUICore/./node_modules/core-js-pure/internals/well-known-symbol.js","webpack://SwaggerUICore/./node_modules/core-js-pure/internals/entry-virtual.js","webpack://SwaggerUICore/./node_modules/core-js-pure/internals/is-callable.js","webpack://SwaggerUICore/./node_modules/lodash/get.js","webpack://SwaggerUICore/./node_modules/@babel/runtime-corejs3/regenerator/index.js","webpack://SwaggerUICore/./node_modules/core-js-pure/internals/is-object.js","webpack://SwaggerUICore/./node_modules/core-js-pure/internals/a-callable.js","webpack://SwaggerUICore/./node_modules/core-js-pure/internals/has-own-property.js","webpack://SwaggerUICore/./node_modules/core-js-pure/internals/define-well-known-symbol.js","webpack://SwaggerUICore/./node_modules/core-js-pure/internals/iterate.js","webpack://SwaggerUICore/./node_modules/@babel/runtime-corejs3/core-js-stable/instance/bind.js","webpack://SwaggerUICore/./node_modules/core-js-pure/internals/descriptors.js","webpack://SwaggerUICore/./src/core/plugins/spec/actions.js","webpack://SwaggerUICore/external \"classnames\"","webpack://SwaggerUICore/./node_modules/core-js-pure/internals/function-bind-context.js","webpack://SwaggerUICore/./node_modules/@babel/runtime-corejs3/core-js-stable/instance/find.js","webpack://SwaggerUICore/./node_modules/@babel/runtime-corejs3/helpers/createForOfIteratorHelper.js","webpack://SwaggerUICore/./node_modules/core-js-pure/internals/get-built-in.js","webpack://SwaggerUICore/./node_modules/lodash/isArray.js","webpack://SwaggerUICore/./node_modules/@babel/runtime-corejs3/helpers/objectWithoutProperties.js","webpack://SLine truncated
-346
View File
@@ -1,346 +0,0 @@
openapi: 3.0.3
info:
version: "3.2"
title: "Music Server"
description: "Upgraded Go version and the version of all dependencies. Fixed som more bugs."
contact:
email: "zarnor91@gmail.com"
servers:
- url: https://music.sanplex.xyz/
description: Main (production) server
- url: https://tmusic.sanplex.xyz/
description: Test server
- url: http://localhost:8080
description: Local server
tags:
- name: "Music"
description: "Endpoints for the music"
- name: "Version"
description: "Information about the application"
- name: "Sync"
description: "Sync the database with the folders"
paths:
/music:
get:
tags:
- "Music"
summary: "Get song"
description: "Get a specified song from the que, if invalid number it will be the first or the last song in que"
operationId: "getSong"
parameters:
- name: "song"
in: "query"
schema:
type: integer
description: "The number the song has in the que"
required: true
responses:
"200":
description: "The specified file"
content:
audio/mpeg:
schema:
type: object
format: binary
"500":
description: "Something went wrong on the server"
/music/soundTest:
get:
tags:
- "Music"
summary: "Start a sound test"
description: "Get a sound check song"
operationId: "getSoundCheckSong"
responses:
"200":
description: "A file"
content:
audio/mpeg:
schema:
type: object
format: binary
"500":
description: "Something went wrong on the server"
/music/rand:
get:
tags:
- "Music"
summary: "Get random song"
description: "Takes a random song from a random game"
operationId: "getRandom"
responses:
"200":
description: "A file"
content:
audio/mpeg:
schema:
type: object
format: binary
"500":
description: "Something went wrong on the server"
/music/rand/low:
get:
tags:
- "Music"
summary: "Get random song"
description: "Takes a random song from a random game but increases the chance for games that haven't been played"
operationId: "getRandomLow"
responses:
"200":
description: "A file"
content:
audio/mpeg:
schema:
type: object
format: binary
"500":
description: "Something went wrong on the server"
/music/info:
get:
tags:
- "Music"
summary: "Get info of current song"
description: "Return the info of the song currently playing"
operationId: "getInfo"
responses:
"200":
description: "Info of current song"
content:
application/json:
schema:
$ref: '#/components/schemas/info'
"500":
description: "Something went wrong on the server"
/music/list:
get:
tags:
- "Music"
summary: "Gets song que"
description: "Gets a list of all songs that have been fetched"
operationId: "getList"
responses:
"200":
description: "A list"
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/list'
"500":
description: "Something went wrong on the server"
/music/next:
get:
tags:
- "Music"
summary: "Get next song"
description: "Gets next song in the song que, if there is no more a new random song will be generated."
operationId: "getNext"
responses:
"200":
description: "A file"
content:
audio/mpeg:
schema:
type: object
format: binary
"500":
description: "Something went wrong on the server"
/music/previous:
get:
tags:
- "Music"
summary: "Get previous song"
description: "Gets previous song in the song que, if there is no more the first song will be returns."
operationId: "getPrevious"
responses:
"200":
description: "A file"
content:
audio/mpeg:
schema:
type: object
format: binary
"500":
description: "Something went wrong on the server"
/music/all:
get:
tags:
- "Music"
summary: "Gets all games"
description: "Gets a list of all games that is in the database"
operationId: "getAll"
responses:
"200":
description: "A list"
content:
application/json:
schema:
type: array
items:
type: string
example: ["God of War", "Final Fantasy VII"]
"500":
description: "Something went wrong on the server"
/music/all/order:
get:
tags:
- "Music"
summary: "Gets all games in order"
description: "Gets a ordered list of all games that is in the database"
operationId: "getAll"
responses:
"200":
description: "A list"
content:
application/json:
schema:
type: array
items:
type: string
example: [ "God of War", "Final Fantasy VII" ]
"500":
description: "Something went wrong on the server"
/music/all/random:
get:
tags:
- "Music"
summary: "Gets all games in random order"
description: "Gets a list of all games that is in the database in random order"
operationId: "getAllRandom"
responses:
"200":
description: "A list"
content:
application/json:
schema:
type: array
items:
type: string
example: ["Final Fantasy VII", "God of War"]
"500":
description: "Something went wrong on the server"
/music/played:
put:
tags:
- "Music"
summary: "Increase played"
description: "Increase the number of times the current game has been played"
operationId: "setPlayed"
responses:
"202":
description: "Accepted"
"401":
description: "Bad Request"
"500":
description: "Something went wrong on the server"
/music/addQue:
get:
tags:
- "Music"
summary: "Adds last song to que"
description: "Adds the last fetched song to the song que"
operationId: "addQue"
responses:
"200":
description: "OK"
"401":
description: "Bad Request"
"500":
description: "Something went wrong on the server"
/music/reset:
get:
tags:
- "Music"
summary: "Resets the song que"
description: "Resets the song que for a new match"
operationId: "reset"
responses:
"200":
description: "successful operation"
"500":
description: "Something went wrong on the server"
/version:
get:
tags:
- "Version"
summary: "Returns pet inventories by status"
description: "Returns a map of status codes to quantities"
operationId: "getVersionInfo"
responses:
"200":
description: "successful operation"
content:
application/json:
schema:
$ref: '#/components/schemas/versionInfo'
/sync:
get:
tags:
- "Sync"
summary: "Sync games"
description: "Sync the database with the folders"
operationId: "sync"
responses:
"200":
description: "successful operation"
"500":
description: "Something went wrong on the server"
components:
schemas:
list:
type: object
properties:
Game:
type: string
example: God of War
Song:
type: string
example: Main Theme.mp3
CurrentlyPlaying:
type: boolean
example: true
description: Only included on the one that's playing
SongNo:
type: integer
example: 3
info:
type: object
properties:
Game:
type: string
example: God of War
GamePlayed:
type: integer
example: 10
Song:
type: string
example: Main Theme.mp3
SongPlayed:
type: integer
example: 10
SongNo:
type: integer
example: 3
versionInfo:
type: object
properties:
version:
type: string
example: 0.5.1
changelog:
type: string
example: "Added shadow to build fat jars. Added support to give property files through arguments."
history:
type: array
items:
$ref: '#/components/schemas/historyInfo'
historyInfo:
type: object
properties:
version:
type: string
example: 0.5.0
changelog:
type: string
example: "Updated kotlin version, gradle version and al libs. Added connection to database with exposed. Added new endpoints."
+155
View File
@@ -0,0 +1,155 @@
/* Pure CSS styles for Music Search */
:root {
/* Light mode colors (default) */
--bg-primary: #f3f4f6;
--bg-secondary: #e5e7eb;
--bg-tertiary: #dcfce7;
--text-primary: #000;
--text-secondary: #374151;
--border-primary: #9ca3af;
--border-focus: #6b7280;
--accent-primary: #f97316;
--accent-hover: #ea580c;
--shadow-color: rgba(0, 0, 0, 0.1);
}
[data-theme="dark"] {
/* Dark mode colors matching frontend */
--bg-primary: #555;
--bg-secondary: #333;
--bg-tertiary: #2a2a2a;
--text-primary: #fff;
--text-secondary: #ff9c00;
--border-primary: #666;
--border-focus: #ff9c00;
--accent-primary: #ff9c00;
--accent-hover: #e68a00;
--shadow-color: rgba(0, 0, 0, 0.3);
}
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
html, body {
height: 100%;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
line-height: 1.5;
background-color: var(--bg-primary);
color: var(--text-primary);
transition: background-color 0.3s ease, color 0.3s ease;
}
main {
max-width: 1200px;
margin: 0 auto;
padding: 1rem;
}
#search-container {
text-align: center;
margin-bottom: 2rem;
}
#search_term {
width: 60vw;
max-width: 600px;
font-size: 1.5rem;
padding: 0.5rem;
border: 1px solid var(--border-primary);
border-radius: 0.5rem;
background-color: var(--bg-secondary);
color: var(--text-primary);
}
#search_term:focus {
outline: none;
border-color: var(--border-focus);
}
#clear {
font-size: 1.5rem;
padding: 0.5rem 1rem;
border: none;
border-radius: 0.5rem;
background-color: var(--accent-primary);
color: var(--text-primary);
cursor: pointer;
margin-left: 1rem;
}
#clear:hover {
background-color: var(--accent-hover);
}
#games-container {
font-size: 1.5rem;
}
.game-text {
color: var(--text-primary);
word-break: break-word;
}
/* Dark mode toggle */
#dark-mode-toggle {
position: fixed;
top: 1rem;
right: 1rem;
font-size: 1.2rem;
padding: 0.4rem 0.8rem;
border: none;
border-radius: 0.5rem;
background-color: var(--bg-secondary);
color: var(--text-primary);
cursor: pointer;
z-index: 1000;
transition: all 0.3s ease;
}
#dark-mode-toggle:hover {
background-color: var(--border-primary);
}
/* Game result cards */
.bg-green-100 {
background-color: var(--bg-tertiary);
}
.p-4 {
padding: 1rem;
}
.shadow-md {
box-shadow: 0 4px 6px -1px var(--shadow-color), 0 2px 4px -2px var(--shadow-color);
}
.rounded-lg {
border-radius: 0.5rem;
}
.mt-6 {
margin-top: 1.5rem;
}
.matched-name {
margin: 0.25rem 0 0;
font-size: 0.9rem;
color: var(--text-secondary);
}
/* Responsive adjustments */
@media (max-width: 768px) {
#search_term {
width: 80vw;
font-size: 1.2rem;
}
#clear {
font-size: 1.2rem;
padding: 0.4rem 0.8rem;
}
}
+3476
View File
File diff suppressed because it is too large. Load diff
+18
View File
@@ -0,0 +1,18 @@
package web
templ Base() {
<!DOCTYPE html>
<html lang="en" data-theme="dark">
<head>
<meta charset="utf-8"/>
<title>Music Search</title>
<link href="assets/css/styles.css" rel="stylesheet"/>
<script src="assets/js/htmx.min.js"></script>
</head>
<body>
<main>
{ children... }
</main>
</body>
</html>
}
+6
View File
@@ -0,0 +1,6 @@
package web
import "embed"
//go:embed "assets"
var Assets embed.FS
+75
View File
@@ -0,0 +1,75 @@
package web
import (
"net/http"
"strings"
"music-server/internal/backend"
"music-server/internal/logging"
"go.uber.org/zap"
)
// NewSearchHandler returns a handler that renders the soundtracks matching the posted search term.
func NewSearchHandler(cache *backend.SearchCache) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if err := r.ParseForm(); err != nil {
http.Error(w, "Bad Request", http.StatusBadRequest)
return
}
soundtracks, err := cache.Get(r.Context())
if err != nil {
logging.GetLogger().Error("Failed to load search data", zap.Error(err))
http.Error(w, "Internal Server Error", http.StatusInternalServerError)
return
}
results := search(r.FormValue("search_term"), soundtracks)
if err := FoundSoundtracks(results).Render(r.Context(), w); err != nil {
logging.GetLogger().Error("Failed to render search results", zap.Error(err))
http.Error(w, "Internal Server Error", http.StatusInternalServerError)
}
})
}
// SearchResult is a soundtrack found by search. MatchedName is the alternative name that
// matched, or empty when the soundtrack's own name matched.
type SearchResult struct {
Name string
MatchedName string
}
// search returns the soundtracks matching searchText: exact matches first, then matches
// ignoring spaces and special characters, then matches with the letters in order. Each
// step tries the soundtrack's own name before its alternative names.
func search(searchText string, soundtrackData []backend.SoundtrackData) []SearchResult {
var results []SearchResult
seen := make(map[string]bool)
add := func(match func(backend.SearchName) bool) {
for _, data := range soundtrackData {
if seen[data.Original] {
continue
}
matched, ok := "", match(data.SearchName)
for _, alternative := range data.Alternatives {
if ok {
break
}
matched, ok = alternative.Original, match(alternative)
}
if ok {
results = append(results, SearchResult{Name: data.Original, MatchedName: matched})
seen[data.Original] = true
}
}
}
lowercase := strings.ToLower(searchText)
cleaned := backend.CleanSearchTerm(searchText)
add(func(n backend.SearchName) bool { return strings.Contains(n.Lowercase, lowercase) })
add(func(n backend.SearchName) bool { return strings.Contains(n.Cleaned, cleaned) })
add(func(n backend.SearchName) bool { return backend.MatchesSubsequence(cleaned, n.Cleaned) })
return results
}
+52
View File
@@ -0,0 +1,52 @@
package web
templ SearchForm() {
@Base() {
<button id="dark-mode-toggle">🌙</button>
<input id="search_term" name="search_term" type="text" hx-post="/find" hx-trigger="load, keyup changed delay:0.25s" hx-target="#soundtracks-container"/>
<button type="button" id="clear" name="clear">Clear</button>
<div id="soundtracks-container"></div>
<script>
document.addEventListener('readystatechange', () => {
if (document.readyState == 'complete') {
document.getElementById("search_term").focus();
// Initialize theme from localStorage (default to dark)
const savedTheme = localStorage.getItem('theme') || 'dark';
document.documentElement.setAttribute('data-theme', savedTheme);
document.getElementById('dark-mode-toggle').textContent = savedTheme === 'dark' ? '☀️' : '🌙';
}
});
// Dark mode toggle functionality
document.getElementById("dark-mode-toggle").addEventListener("click", function() {
const html = document.documentElement;
const currentTheme = html.getAttribute('data-theme');
const newTheme = currentTheme === 'dark' ? 'light' : 'dark';
html.setAttribute('data-theme', newTheme);
localStorage.setItem('theme', newTheme);
// Update toggle button text
this.textContent = newTheme === 'dark' ? '☀️' : '🌙';
});
document.getElementById("clear").addEventListener("click", function (event) {
document.getElementById("search_term").value = "";
htmx.ajax('POST', '/find', '#soundtracks-container');
document.getElementById("search_term").focus();
});
</script>
}
}
templ FoundSoundtracks(soundtracks []SearchResult) {
for _, soundtrack := range soundtracks {
<div class="bg-green-100 p-4 shadow-md rounded-lg mt-6">
<p class="soundtrack-text">{ soundtrack.Name }</p>
if soundtrack.MatchedName != "" {
<p class="matched-name">Also known as { soundtrack.MatchedName }</p>
}
</div>
}
}
+143
View File
@@ -0,0 +1,143 @@
package web
import (
"context"
"errors"
"net/http"
"net/http/httptest"
"net/url"
"strings"
"testing"
"music-server/internal/backend"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
var soundtracks = []string{
"Call of Duty: Modern Warfare",
"Final Fantasy VII",
"Joe & Mac",
"Kingdom Hearts",
"Lemmings (SNES + Mega Drive)",
"MG",
"Metal Gear Solid 4 - Guns of the Patriots",
"Pokémon HeartGold & SoulSilver",
"Resident Evil 2 (Remake)",
"Ys III - Wanderers from Ys (+The Oath in Felghana)",
}
func newCache(names []string, alternatives ...map[string][]string) *backend.SearchCache {
soundtracks := make([]backend.SearchSoundtrack, len(names))
for i, name := range names {
soundtracks[i] = backend.SearchSoundtrack{Name: name}
for _, a := range alternatives {
soundtracks[i].AlternativeNames = a[name]
}
}
return backend.NewSearchCache(func(context.Context) ([]backend.SearchSoundtrack, error) { return soundtracks, nil })
}
// names returns the soundtrack names of results.
func names(results []SearchResult) []string {
var n []string
for _, r := range results {
n = append(n, r.Name)
}
return n
}
func searchData(t *testing.T) []backend.SoundtrackData {
data, err := newCache(soundtracks).Get(context.Background())
require.NoError(t, err)
return data
}
func TestSearch(t *testing.T) {
data := searchData(t)
tests := []struct {
query string
want []string
}{
// Exact (case-insensitive) substring
{"resident", []string{"Resident Evil 2 (Remake)"}},
// Ignoring spaces and special characters
{"joeandmac", []string{"Joe & Mac"}},
{"snes+mega", []string{"Lemmings (SNES + Mega Drive)"}},
{"pokemon", []string{"Pokémon HeartGold & SoulSilver"}},
// Letters in order
{"codmw", []string{"Call of Duty: Modern Warfare"}},
{"mgs4gotp", []string{"Metal Gear Solid 4 - Guns of the Patriots"}},
{"re2r", []string{"Resident Evil 2 (Remake)"}},
// No match
{"zzz", nil},
// Regex special characters are plain text
{"(remake)", []string{"Resident Evil 2 (Remake)"}},
{"[", nil},
}
for _, tt := range tests {
t.Run(tt.query, func(t *testing.T) {
assert.Equal(t, tt.want, names(search(tt.query, data)))
})
}
}
func TestSearchEmptyReturnsEverything(t *testing.T) {
assert.Equal(t, soundtracks, names(search("", searchData(t))))
}
func TestSearchOrdering(t *testing.T) {
// "MG" is an exact match, "Metal Gear Solid..." only matches by letters in order.
results := names(search("mg", searchData(t)))
require.GreaterOrEqual(t, len(results), 2)
assert.Equal(t, "MG", results[0])
assert.Contains(t, results, "Metal Gear Solid 4 - Guns of the Patriots")
}
func TestSearchAlternativeNames(t *testing.T) {
data, err := newCache(soundtracks, map[string][]string{
"Final Fantasy VII": {"FF7", "ファイナルファンタジーVII"},
"Kingdom Hearts": {"KH"},
}).Get(context.Background())
require.NoError(t, err)
assert.Equal(t, []SearchResult{{Name: "Final Fantasy VII", MatchedName: "FF7"}}, search("ff7", data))
assert.Equal(t, []SearchResult{{Name: "Final Fantasy VII", MatchedName: "ファイナルファンタジーVII"}}, search("ファイナル", data))
assert.Equal(t, []SearchResult{{Name: "Final Fantasy VII"}}, search("fantasy", data),
"no matched name when the soundtrack's own name matches")
// An exact match on an alternative name comes before a letters-in-order match on a name.
results := search("kh", data)
require.NotEmpty(t, results)
assert.Equal(t, SearchResult{Name: "Kingdom Hearts", MatchedName: "KH"}, results[0])
}
func TestFoundSoundtracksShowsMatchedName(t *testing.T) {
var out strings.Builder
require.NoError(t, FoundSoundtracks([]SearchResult{
{Name: "Final Fantasy VII", MatchedName: "FF7"}, {Name: "Kingdom Hearts"},
}).Render(context.Background(), &out))
assert.Contains(t, out.String(), "Final Fantasy VII")
assert.Contains(t, out.String(), "Also known as FF7")
assert.Equal(t, 1, strings.Count(out.String(), "Also known as"))
}
func TestSearchHandler(t *testing.T) {
handler := NewSearchHandler(newCache(soundtracks))
req := httptest.NewRequest(http.MethodPost, "/find", strings.NewReader(url.Values{"search_term": {"kingdom"}}.Encode()))
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
rec := httptest.NewRecorder()
handler.ServeHTTP(rec, req)
assert.Equal(t, http.StatusOK, rec.Code)
assert.Contains(t, rec.Body.String(), "Kingdom Hearts")
assert.NotContains(t, rec.Body.String(), "Final Fantasy")
}
func TestSearchHandlerLoadError(t *testing.T) {
cache := backend.NewSearchCache(func(context.Context) ([]backend.SearchSoundtrack, error) { return nil, errors.New("db down") })
rec := httptest.NewRecorder()
NewSearchHandler(cache).ServeHTTP(rec, httptest.NewRequest(http.MethodPost, "/find", nil))
assert.Equal(t, http.StatusInternalServerError, rec.Code)
}
+102 -33
View File
@@ -1,42 +1,111 @@
module music-server module music-server
go 1.22.2 go 1.26.0
require ( require (
github.com/gin-contrib/static v1.1.2 github.com/MShekow/directory-checksum v1.4.18
github.com/gin-gonic/gin v1.10.0 github.com/a-h/templ v0.3.1020
github.com/jackc/pgtype v1.14.3 github.com/docker/go-connections v0.6.0 // indirect
github.com/jackc/pgx/v5 v5.5.5 github.com/golang-migrate/migrate/v4 v4.19.1
github.com/jackc/pgx/v5 v5.9.2
github.com/labstack/echo/v5 v5.3.0
github.com/lib/pq v1.12.3 // indirect
github.com/spf13/afero v1.15.0
github.com/stretchr/testify v1.12.1
github.com/testcontainers/testcontainers-go v0.42.0
go.uber.org/zap v1.28.0
) )
require ( require (
github.com/bytedance/sonic v1.11.6 // indirect github.com/danielgtaylor/huma/v2 v2.39.1
github.com/bytedance/sonic/loader v0.1.1 // indirect github.com/getkin/kin-openapi v0.149.0
github.com/cloudwego/base64x v0.1.4 // indirect github.com/google/uuid v1.6.0
github.com/cloudwego/iasm v0.2.0 // indirect github.com/prometheus/client_golang v1.25.0
github.com/gabriel-vasile/mimetype v1.4.3 // indirect github.com/prometheus/client_model v0.6.3
github.com/gin-contrib/sse v0.1.0 // indirect golang.org/x/sync v0.23.0
github.com/go-playground/locales v0.14.1 // indirect )
github.com/go-playground/universal-translator v0.18.1 // indirect
github.com/go-playground/validator/v10 v10.20.0 // indirect require (
github.com/goccy/go-json v0.10.2 // indirect dario.cat/mergo v1.0.2 // indirect
github.com/jackc/pgio v1.0.0 // indirect github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c // indirect
github.com/Microsoft/go-winio v0.6.2 // indirect
github.com/a-h/parse v0.0.0-20250122154542-74294addb73e // indirect
github.com/andybalholm/brotli v1.2.2 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/cli/browser v1.3.0 // indirect
github.com/containerd/errdefs v1.0.0 // indirect
github.com/containerd/errdefs/pkg v0.3.0 // indirect
github.com/containerd/log v0.1.0 // indirect
github.com/containerd/platforms v0.2.1 // indirect
github.com/cpuguy83/dockercfg v0.3.2 // indirect
github.com/distribution/reference v0.6.0 // indirect
github.com/docker/go-units v0.5.0 // indirect
github.com/ebitengine/purego v0.10.0 // indirect
github.com/fatih/color v1.16.0 // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/fsnotify/fsnotify v1.7.0 // indirect
github.com/go-errors/errors v1.5.1 // indirect
github.com/go-logr/logr v1.4.3 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-ole/go-ole v1.2.6 // indirect
github.com/go-openapi/jsonpointer v0.22.5 // indirect
github.com/go-openapi/swag/jsonname v0.25.5 // indirect
github.com/gorilla/mux v1.8.1 // indirect
github.com/jackc/pgerrcode v0.0.0-20220416144525-469b46aa5efa // indirect
github.com/jackc/pgpassfile v1.0.0 // indirect github.com/jackc/pgpassfile v1.0.0 // indirect
github.com/jackc/pgservicefile v0.0.0-20231201235250-de7065d80cb9 // indirect github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect
github.com/json-iterator/go v1.1.12 // indirect github.com/jackc/puddle/v2 v2.2.2 // indirect
github.com/klauspost/cpuid/v2 v2.2.7 // indirect github.com/klauspost/compress v1.20.1 // indirect
github.com/leodido/go-urn v1.4.0 // indirect github.com/kylelemons/godebug v1.1.0 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect github.com/labstack/echo/v4 v4.15.4 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/labstack/gommon v0.5.0 // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect
github.com/pelletier/go-toml/v2 v2.2.2 // indirect github.com/magiconair/properties v1.8.10 // indirect
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/mattn/go-colorable v0.1.15 // indirect
github.com/ugorji/go/codec v1.2.12 // indirect github.com/mattn/go-isatty v0.0.23 // indirect
golang.org/x/arch v0.8.0 // indirect github.com/moby/docker-image-spec v1.3.1 // indirect
golang.org/x/crypto v0.23.0 // indirect github.com/moby/go-archive v0.2.0 // indirect
golang.org/x/net v0.25.0 // indirect github.com/moby/moby/api v1.54.1 // indirect
golang.org/x/sys v0.20.0 // indirect github.com/moby/moby/client v0.4.0 // indirect
golang.org/x/text v0.15.0 // indirect github.com/moby/patternmatcher v0.6.1 // indirect
google.golang.org/protobuf v1.34.1 // indirect github.com/moby/sys/sequential v0.6.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect github.com/moby/sys/user v0.4.0 // indirect
github.com/moby/sys/userns v0.1.0 // indirect
github.com/moby/term v0.5.2 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/natefinch/atomic v1.0.1 // indirect
github.com/oasdiff/yaml v0.1.1 // indirect
github.com/oasdiff/yaml3 v0.0.14 // indirect
github.com/opencontainers/go-digest v1.0.0 // indirect
github.com/opencontainers/image-spec v1.1.1 // indirect
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect
github.com/prometheus/common v0.72.0 // indirect
github.com/prometheus/procfs v0.22.0 // indirect
github.com/santhosh-tekuri/jsonschema/v6 v6.0.3 // indirect
github.com/shirou/gopsutil/v4 v4.26.3 // indirect
github.com/sirupsen/logrus v1.9.4 // indirect
github.com/tklauser/go-sysconf v0.3.16 // indirect
github.com/tklauser/numcpus v0.11.0 // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect
github.com/valyala/fasttemplate v1.2.2 // indirect
github.com/yusufpapurcu/wmi v1.2.4 // indirect
go.opentelemetry.io/auto/sdk v1.2.1 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 // indirect
go.opentelemetry.io/otel v1.41.0 // indirect
go.opentelemetry.io/otel/metric v1.41.0 // indirect
go.opentelemetry.io/otel/trace v1.41.0 // indirect
go.uber.org/multierr v1.10.0 // indirect
go.yaml.in/yaml/v3 v3.0.5 // indirect
golang.org/x/crypto v0.57.0 // indirect
golang.org/x/mod v0.41.0 // indirect
golang.org/x/net v0.59.0 // indirect
golang.org/x/sys v0.48.0 // indirect
golang.org/x/text v0.42.0 // indirect
golang.org/x/time v0.15.0 // indirect
golang.org/x/tools v0.49.0 // indirect
google.golang.org/protobuf v1.36.12 // indirect
) )
tool github.com/a-h/templ/cmd/templ
+248 -279
View File
@@ -1,290 +1,259 @@
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= dario.cat/mergo v1.0.2 h1:85+piFYR1tMbRrLcDwR18y4UKJ3aH1Tbzi24VRW1TK8=
github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= dario.cat/mergo v1.0.2/go.mod h1:E/hbnu0NxMFBjpMIE34DRGLWqDy0g5FuKDhCb31ngxA=
github.com/bytedance/sonic v1.11.6 h1:oUp34TzMlL+OY1OUWxHqsdkgC/Zfc85zGqw9siXjrc0= github.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6 h1:He8afgbRMd7mFxO99hRNu+6tazq8nFF9lIwo9JFroBk=
github.com/bytedance/sonic v1.11.6/go.mod h1:LysEHSvpvDySVdC2f87zGWf6CIKJcAvqab1ZaiQtds4= github.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6/go.mod h1:8o94RPi1/7XTJvwPpRSzSUedZrtlirdB3r9Z20bi2f8=
github.com/bytedance/sonic/loader v0.1.1 h1:c+e5Pt1k/cy5wMveRDyk2X4B9hF4g7an8N3zCYjJFNM= github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c h1:udKWzYgxTojEKWjV8V+WSxDXJ4NFATAsZjh8iIbsQIg=
github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU= github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/0Y= github.com/MShekow/directory-checksum v1.4.18 h1:1nPPVl7uREa6WMTAPKoWW/GylhnASs0C9C+GPiwLwXA=
github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w= github.com/MShekow/directory-checksum v1.4.18/go.mod h1:iUupsPb0X0BumQQymLrpD5Pkqe/CbV13OSgosw1oFc4=
github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg= github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY= github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= github.com/a-h/parse v0.0.0-20250122154542-74294addb73e h1:HjVbSQHy+dnlS6C3XajZ69NYAb5jbGNfHanvm1+iYlo=
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/a-h/parse v0.0.0-20250122154542-74294addb73e/go.mod h1:3mnrkvGpurZ4ZrTDbYU84xhwXW2TjTKShSwjRi2ihfQ=
github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/a-h/templ v0.3.1020 h1:ypAT/L5ySWEnZ6Zft/5yfoWXYYkhFNvEFOeeqecg4tw=
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/a-h/templ v0.3.1020/go.mod h1:A2DlK61v+K+NRoGnhmYbNYVmtYHcFO5/AisMvBdDxTM=
github.com/andybalholm/brotli v1.2.2 h1:HzTuoo2ErYQqf5qvcJInB8uvqSVxRttzkFexPWtnceM=
github.com/andybalholm/brotli v1.2.2/go.mod h1:rzTDkvFWvIrjDXZHkuS16NPggd91W3kUSvPlQ1pLaKY=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cli/browser v1.3.0 h1:LejqCrpWr+1pRqmEPDGnTZOjsMe7sehifLynZJuqJpo=
github.com/cli/browser v1.3.0/go.mod h1:HH8s+fOAxjhQoBUAsKuPCbqUuxZDhQ2/aD+SzsEfBTk=
github.com/containerd/errdefs v1.0.0 h1:tg5yIfIlQIrxYtu9ajqY42W3lpS19XqdxRQeEwYG8PI=
github.com/containerd/errdefs v1.0.0/go.mod h1:+YBYIdtsnF4Iw6nWZhJcqGSg/dwvV7tyJ/kCkyJ2k+M=
github.com/containerd/errdefs/pkg v0.3.0 h1:9IKJ06FvyNlexW690DXuQNx2KA2cUJXx151Xdx3ZPPE=
github.com/containerd/errdefs/pkg v0.3.0/go.mod h1:NJw6s9HwNuRhnjJhM7pylWwMyAkmCQvQ4GpJHEqRLVk=
github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I=
github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo=
github.com/containerd/platforms v0.2.1 h1:zvwtM3rz2YHPQsF2CHYM8+KtB5dvhISiXh5ZpSBQv6A=
github.com/containerd/platforms v0.2.1/go.mod h1:XHCb+2/hzowdiut9rkudds9bE5yJ7npe7dG/wG+uFPw=
github.com/cpuguy83/dockercfg v0.3.2 h1:DlJTyZGBDlXqUZ2Dk2Q3xHs/FtnooJJVaad2S9GKorA=
github.com/cpuguy83/dockercfg v0.3.2/go.mod h1:sugsbF4//dDlL/i+S+rtpIWp+5h0BHJHfjj5/jFyUJc=
github.com/creack/pty v1.1.24 h1:bJrF4RRfyJnbTJqzRLHzcGaZK1NeM5kTC9jGgovnR1s=
github.com/creack/pty v1.1.24/go.mod h1:08sCNb52WyoAwi2QDyzUCTgcvVFhUzewun7wtTfvcwE=
github.com/danielgtaylor/huma/v2 v2.39.1 h1:0kwF4ltQoYZ+IU55VPy+BcGekzgF44R64daTGde1H+g=
github.com/danielgtaylor/huma/v2 v2.39.1/go.mod h1:zcnQ38duIJ3VUHwFaBoZ6x8T+KN/mr33oyqxcj0HTug=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/dhui/dktest v0.4.6 h1:+DPKyScKSEp3VLtbMDHcUq6V5Lm5zfZZVb0Sk7Ahom4=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dhui/dktest v0.4.6/go.mod h1:JHTSYDtKkvFNFHJKqCzVzqXecyv+tKt8EzceOmQOgbU=
github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0= github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk=
github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk= github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= github.com/dlclark/regexp2 v1.11.0 h1:G/nrcoOa7ZXlpoa/91N3X7mM3r8eIlMBBJZvsz/mxKI=
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= github.com/dlclark/regexp2 v1.11.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
github.com/gin-contrib/static v1.1.2 h1:c3kT4bFkUJn2aoRU3s6XnMjJT8J6nNWJkR0NglqmlZ4= github.com/docker/docker v28.3.3+incompatible h1:Dypm25kh4rmk49v1eiVbsAtpAsYURjYkaKubwuBdxEI=
github.com/gin-contrib/static v1.1.2/go.mod h1:Fw90ozjHCmZBWbgrsqrDvO28YbhKEKzKp8GixhR4yLw= github.com/docker/docker v28.3.3+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/gin-gonic/gin v1.10.0 h1:nTuyha1TYqgedzytsKYqna+DfLos46nTv2ygFy86HFU= github.com/docker/go-connections v0.6.0 h1:LlMG9azAe1TqfR7sO+NJttz1gy6KO7VJBh+pMmjSD94=
github.com/gin-gonic/gin v1.10.0/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y= github.com/docker/go-connections v0.6.0/go.mod h1:AahvXYshr6JgfUJGdDCs2b5EZG/vmaMAntpSFH5BFKE=
github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= github.com/ebitengine/purego v0.10.0 h1:QIw4xfpWT6GWTzaW5XEKy3HXoqrJGx1ijYHzTF0/ISU=
github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/ebitengine/purego v0.10.0/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ=
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
github.com/go-playground/validator/v10 v10.20.0 h1:K9ISHbSaI0lyB2eWMPJo+kOS/FBExVwjEviJTixqxL8= github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
github.com/go-playground/validator/v10 v10.20.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM= github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/fxamacker/cbor/v2 v2.9.2 h1:X4Ksno9+x3cz0TZv69ec1hxP/+tymuR8PXQJyDwfh78=
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= github.com/fxamacker/cbor/v2 v2.9.2/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ=
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/getkin/kin-openapi v0.149.0 h1:ZbhmVJ4yq5RZDUsyP8lcBcGMsjsaTqXEFt6isdtMDfA=
github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/getkin/kin-openapi v0.149.0/go.mod h1:1+BHDzstro+P5CKtPy1X4PfofnFgmRe6uvMy9+r9fKY=
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= github.com/go-chi/chi/v5 v5.3.1 h1:3j4HZLGZQ3JpMCrPJF/Jl3mYJfWLKBfNJ6quurUGCf8=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/go-chi/chi/v5 v5.3.1/go.mod h1:R+tYY2hNuVUUjxoPtqUdgBqevM9s9njzkTLutVsOCto=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/go-errors/errors v1.5.1 h1:ZwEMSLRCapFLflTpT7NKaAc7ukJ8ZPEjzlxt8rPN8bk=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/go-errors/errors v1.5.1/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og=
github.com/jackc/chunkreader v1.0.0 h1:4s39bBR8ByfqH+DKm8rQA3E1LHZWB9XWcrz8fqaZbe0= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo= github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
github.com/jackc/chunkreader/v2 v2.0.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk= github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/jackc/chunkreader/v2 v2.0.1 h1:i+RDz65UE+mmpjTfyz0MoVTnzeYxroil2G82ki7MGG8= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
github.com/jackc/chunkreader/v2 v2.0.1/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
github.com/jackc/pgconn v0.0.0-20190420214824-7e0022ef6ba3/go.mod h1:jkELnwuX+w9qN5YIfX0fl88Ehu4XC3keFuOJJk9pcnA= github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
github.com/jackc/pgconn v0.0.0-20190824142844-760dd75542eb/go.mod h1:lLjNuW/+OfW9/pnVKPazfWOgNfH2aPem8YQ7ilXGvJE= github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
github.com/jackc/pgconn v0.0.0-20190831204454-2fabfa3c18b7/go.mod h1:ZJKsE/KZfsUgOEh9hBm+xYTstcNHg7UPMVJqRfQxq4s= github.com/go-openapi/jsonpointer v0.22.5 h1:8on/0Yp4uTb9f4XvTrM2+1CPrV05QPZXu+rvu2o9jcA=
github.com/jackc/pgconn v1.8.0/go.mod h1:1C2Pb36bGIP9QHGBYCjnyhqu7Rv3sGshaQUvmfGIB/o= github.com/go-openapi/jsonpointer v0.22.5/go.mod h1:gyUR3sCvGSWchA2sUBJGluYMbe1zazrYWIkWPjjMUY0=
github.com/jackc/pgconn v1.9.0/go.mod h1:YctiPyvzfU11JFxoXokUOOKQXQmDMoJL9vJzHH8/2JY= github.com/go-openapi/swag/jsonname v0.25.5 h1:8p150i44rv/Drip4vWI3kGi9+4W9TdI3US3uUYSFhSo=
github.com/jackc/pgconn v1.9.1-0.20210724152538-d89c8390a530/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI= github.com/go-openapi/swag/jsonname v0.25.5/go.mod h1:jNqqikyiAK56uS7n8sLkdaNY/uq6+D2m2LANat09pKU=
github.com/jackc/pgconn v1.14.3 h1:bVoTr12EGANZz66nZPkMInAV/KHD2TxH9npjXXgiB3w= github.com/go-openapi/testify/v2 v2.4.0 h1:8nsPrHVCWkQ4p8h1EsRVymA2XABB4OT40gcvAu+voFM=
github.com/jackc/pgconn v1.14.3/go.mod h1:RZbme4uasqzybK2RK5c65VsHxoyaml09lx3tXOcO/VM= github.com/go-openapi/testify/v2 v2.4.0/go.mod h1:HCPmvFFnheKK2BuwSA0TbbdxJ3I16pjwMkYkP4Ywn54=
github.com/jackc/pgio v1.0.0 h1:g12B9UwVnzGhueNavwioyEEpAmqMe1E/BN9ES+8ovkE= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2/go.mod h1:fGZlG77KXmcq05nJLRkk0+p82V8B8Dw8KN2/V9c/OAE= github.com/golang-migrate/migrate/v4 v4.19.1 h1:OCyb44lFuQfYXYLx1SCxPZQGU7mcaZ7gH9yH4jSFbBA=
github.com/jackc/pgmock v0.0.0-20201204152224-4fe30f7445fd/go.mod h1:hrBW0Enj2AZTNpt/7Y5rr2xe/9Mn757Wtb2xeBzPv2c= github.com/golang-migrate/migrate/v4 v4.19.1/go.mod h1:CTcgfjxhaUtsLipnLoQRWCrjYXycRz/g5+RWDuYgPrE=
github.com/jackc/pgmock v0.0.0-20210724152146-4ad1a8207f65/go.mod h1:5R2h2EEX+qri8jOWMbJCtaPWkrrNc7OHwsp2TCqp7ak= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY=
github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ=
github.com/jackc/pgerrcode v0.0.0-20220416144525-469b46aa5efa h1:s+4MhCQ6YrzisK6hFJUX53drDT4UsSW3DEhKn0ifuHw=
github.com/jackc/pgerrcode v0.0.0-20220416144525-469b46aa5efa/go.mod h1:a/s9Lp5W7n/DD0VrVoyJ00FbP2ytTPDVOivvn2bMlds=
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
github.com/jackc/pgproto3 v1.1.0 h1:FYYE4yRw+AgI8wXIinMlNjBbp/UitDJwfj5LqqewP1A= github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo=
github.com/jackc/pgproto3 v1.1.0/go.mod h1:eR5FA3leWg7p9aeAqi37XOTgTIbkABlvcPB3E5rlc78= github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190420180111-c116219b62db/go.mod h1:bhq50y+xrl9n5mRYyCBFKkpRVTLYJVWeCc+mEAI3yXA= github.com/jackc/pgx/v5 v5.9.2 h1:3ZhOzMWnR4yJ+RW1XImIPsD1aNSz4T4fyP7zlQb56hw=
github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190609003834-432c2951c711/go.mod h1:uH0AWtUmuShn0bcesswc4aBTWGvw0cAxIJp+6OB//Wg= github.com/jackc/pgx/v5 v5.9.2/go.mod h1:mal1tBGAFfLHvZzaYh77YS/eC6IX9OWbRV1QIIM0Jn4=
github.com/jackc/pgproto3/v2 v2.0.0-rc3/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM= github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo=
github.com/jackc/pgproto3/v2 v2.0.0-rc3.0.20190831210041-4c03ce451f29/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM= github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
github.com/jackc/pgproto3/v2 v2.0.6/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= github.com/klauspost/compress v1.20.1 h1:T7kKElXUMXrUJ2E9QhQhxFtcK5rPyLdsGZvdbLMPdiQ=
github.com/jackc/pgproto3/v2 v2.1.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= github.com/klauspost/compress v1.20.1/go.mod h1:LUdAzn7YLVvxLpc7y3V1m40wESHTgc1422pwwBSKYuI=
github.com/jackc/pgproto3/v2 v2.3.3 h1:1HLSx5H+tXR9pW3in3zaztoEwQYRC9SQaYUHjTSUOag= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/jackc/pgproto3/v2 v2.3.3/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/jackc/pgservicefile v0.0.0-20231201235250-de7065d80cb9 h1:L0QtFUgDarD7Fpv9jeVMgy/+Ec0mtnmYuImjTz6dtDA= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
github.com/jackc/pgservicefile v0.0.0-20231201235250-de7065d80cb9/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
github.com/jackc/pgtype v0.0.0-20190421001408-4ed0de4755e0/go.mod h1:hdSHsc1V01CGwFsrv11mJRHWJ6aifDLfdV3aVjFF0zg= github.com/labstack/echo/v4 v4.15.4 h1:DL45vVYa+BWE+XuW+zZNd9H0YEdZ80UAWJGcTVW4EVs=
github.com/jackc/pgtype v0.0.0-20190824184912-ab885b375b90/go.mod h1:KcahbBH1nCMSo2DXpzsoWOAfFkdEtEJpPbVLq8eE+mc= github.com/labstack/echo/v4 v4.15.4/go.mod h1:CuMetKIRwsuO/qlAgMq+KTAalwGoB/h4tC+yPdrTj1g=
github.com/jackc/pgtype v0.0.0-20190828014616-a8802b16cc59/go.mod h1:MWlu30kVJrUS8lot6TQqcg7mtthZ9T0EoIBFiJcmcyw= github.com/labstack/echo/v5 v5.3.0 h1:KT74Mprk053PQEHwSZdeCDIz1BigTZOZhavMD0c9Fjs=
github.com/jackc/pgtype v1.8.1-0.20210724151600-32e20a603178/go.mod h1:C516IlIV9NKqfsMCXTdChteoXmwgUceqaLfjg2e3NlM= github.com/labstack/echo/v5 v5.3.0/go.mod h1:Q3j2+clBRgJr0O3DDONQeXNsM7RHgSwUhcuo47unqm8=
github.com/jackc/pgtype v1.14.0/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4= github.com/labstack/gommon v0.5.0 h1:6VSQ2NOzsnEJ5W6+84E0RbcaDDmgB6NIAzWCczTEe6c=
github.com/jackc/pgtype v1.14.3 h1:h6W9cPuHsRWQFTWUZMAKMgG5jSwQI0Zurzdvlx3Plus= github.com/labstack/gommon v0.5.0/go.mod h1:Rzlg7HHy1maLfzBYGg9NZcVuz1sA68HHhLjhcEllYE0=
github.com/jackc/pgtype v1.14.3/go.mod h1:aKeozOde08iifGosdJpz9MBZonJOUJxqNpPBcMJTlVA= github.com/lib/pq v1.12.3 h1:tTWxr2YLKwIvK90ZXEw8GP7UFHtcbTtty8zsI+YjrfQ=
github.com/jackc/pgx/v4 v4.0.0-20190420224344-cc3461e65d96/go.mod h1:mdxmSJJuR08CZQyj1PVQBHy9XOp5p8/SHH6a0psbY9Y= github.com/lib/pq v1.12.3/go.mod h1:/p+8NSbOcwzAEI7wiMXFlgydTwcgTr3OSKMsD2BitpA=
github.com/jackc/pgx/v4 v4.0.0-20190421002000-1b8f0016e912/go.mod h1:no/Y67Jkk/9WuGR0JG/JseM9irFbnEPbuWV2EELPNuM= github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4=
github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQnOEnf1dqHGpw7JmHqHc1NxDoalibchSk9/RWuDc= github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I=
github.com/jackc/pgx/v4 v4.12.1-0.20210724153913-640aa07df17c/go.mod h1:1QD0+tgSXP7iUjYm9C1NxKhny7lq6ee99u/z+IHFcgs= github.com/magiconair/properties v1.8.10 h1:s31yESBquKXCV9a/ScB3ESkOjUYYv+X0rg8SYxI99mE=
github.com/jackc/pgx/v4 v4.18.2 h1:xVpYkNR5pk5bMCZGfClbO962UIqVABcAGt7ha1s/FeU= github.com/magiconair/properties v1.8.10/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
github.com/jackc/pgx/v4 v4.18.2/go.mod h1:Ey4Oru5tH5sB6tV7hDmfWFahwF15Eb7DNXlRKx2CkVw= github.com/mattn/go-colorable v0.1.15 h1:+u9SLTRGnXv73cEsnsmoZBom+dMU88B2M0aDcWy0/jY=
github.com/jackc/pgx/v5 v5.5.5 h1:amBjrZVmksIdNjxGW/IiIMzxMKZFelXbUoPNb+8sjQw= github.com/mattn/go-colorable v0.1.15/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
github.com/jackc/pgx/v5 v5.5.5/go.mod h1:ez9gk+OAat140fv9ErkZDYFWmXLfV+++K0uAOiwgm1A= github.com/mattn/go-isatty v0.0.23 h1:cYwCQTQf3HB6xUC+BtyCLZNr7IzbOmoZbmssVNzSyiQ=
github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/mattn/go-isatty v0.0.23/go.mod h1:nMCL3Zebbrt45jsMDgnfIwz6ydEQApk5oEI3HqDio6A=
github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0=
github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo=
github.com/jackc/puddle v1.3.0 h1:eHK/5clGOatcjX3oWGBO/MpxpbHzSwud5EWTSCI+MX0= github.com/moby/go-archive v0.2.0 h1:zg5QDUM2mi0JIM9fdQZWC7U8+2ZfixfTYoHL7rWUcP8=
github.com/jackc/puddle v1.3.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/moby/go-archive v0.2.0/go.mod h1:mNeivT14o8xU+5q1YnNrkQVpK+dnNe/K6fHqnTg4qPU=
github.com/jackc/puddle/v2 v2.2.1 h1:RhxXJtFG022u4ibrCSMSiu5aOq1i77R3OHKNJj77OAk= github.com/moby/moby/api v1.54.1 h1:TqVzuJkOLsgLDDwNLmYqACUuTehOHRGKiPhvH8V3Nn4=
github.com/jackc/puddle/v2 v2.2.1/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= github.com/moby/moby/api v1.54.1/go.mod h1:+RQ6wluLwtYaTd1WnPLykIDPekkuyD/ROWQClE83pzs=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/moby/moby/client v0.4.0 h1:S+2XegzHQrrvTCvF6s5HFzcrywWQmuVnhOXe2kiWjIw=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/moby/moby/client v0.4.0/go.mod h1:QWPbvWchQbxBNdaLSpoKpCdf5E+WxFAgNHogCWDoa7g=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/moby/patternmatcher v0.6.1 h1:qlhtafmr6kgMIJjKJMDmMWq7WLkKIo23hsrpR3x084U=
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/moby/patternmatcher v0.6.1/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc=
github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM= github.com/moby/sys/sequential v0.6.0 h1:qrx7XFUd/5DxtqcoH1h438hF5TmOvzC/lspjy7zgvCU=
github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= github.com/moby/sys/sequential v0.6.0/go.mod h1:uyv8EUTrca5PnDsdMGXhZe6CCe8U/UiTWd+lL+7b/Ko=
github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M= github.com/moby/sys/user v0.4.0 h1:jhcMKit7SA80hivmFJcbB1vqmw//wU61Zdui2eQXuMs=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/moby/sys/user v0.4.0/go.mod h1:bG+tYYYJgaMtRKgEmuueC0hJEAZWwtIbZTB+85uoHjs=
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/moby/sys/userns v0.1.0 h1:tVLXkFOxVu9A64/yh59slHVv9ahO9UIev4JZusOLG/g=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/moby/sys/userns v0.1.0/go.mod h1:IHUYgu/kao6N8YZlp9Cf444ySSvCmDlmzUcYfDHOl28=
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= github.com/moby/term v0.5.2 h1:6qk3FJAFDs6i/q3W/pQ97SX192qKfZgGjCQqfCJkgzQ=
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= github.com/moby/term v0.5.2/go.mod h1:d3djjFCrjnB+fl8NJux+EJzu0msscUP+f8it8hPkFLc=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw= github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= github.com/natefinch/atomic v1.0.1 h1:ZPYKxkqQOx3KZ+RsbnP/YsgvxWQPGxjC0oBt2AhwV0A=
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= github.com/natefinch/atomic v1.0.1/go.mod h1:N/D/ELrljoqDyT3rZrsUmtsuzvHkeB/wWjHV22AZRbM=
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/oasdiff/yaml v0.1.1 h1:6nHx+pn9gBRM6YpBlFZFQGCCd1nuvqOBtTD3KKTgGxY=
github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/oasdiff/yaml v0.1.1/go.mod h1:EYJNoyktvWMJ0Hmhx+6qTaqMOsalUaRGT8Sj1hNcegU=
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/oasdiff/yaml3 v0.0.14 h1:aLJee3hxBK2H5wdXd9iPcIXb93Nty1Ge0pT171eHtkw=
github.com/lib/pq v1.10.2 h1:AqzbZs4ZoCBp+GtejcpCpcxM3zlSMx29dXbUSeVtJb8= github.com/oasdiff/yaml3 v0.0.14/go.mod h1:csto2xfDjYccdUn/yw/bPjj/cYTdp6HtFA0J4TWG+gg=
github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040=
github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/opencontainers/image-spec v1.1.1/go.mod h1:qpqAh3Dmcf36wStyyWU+kCeDgrGnAve2nCC8+7h8Q0M=
github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM=
github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 h1:o4JXh1EVt9k/+g42oCprj/FisM4qX9L3sZB3upGN2ZU=
github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8= github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE= github.com/prometheus/client_golang v1.25.0 h1:cDtW1TcFsMi1RJc8khwCKB4VhzwV04aKqbYtNOXuiK0=
github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= github.com/prometheus/client_golang v1.25.0/go.mod h1:j2X/4/kaQHLPnmyEU8zjmkndo1T317VpCIQEml8LTKk=
github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU= github.com/prometheus/client_model v0.6.3 h1:O0jaTVAYNxTHYInEPFJt5I3+sN8zqBtVMPTB1qyxiEo=
github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc= github.com/prometheus/client_model v0.6.3/go.mod h1:gpN5P9S7Rr6Yr92PiQ+Ixvhf6JZEkF1dnxsYL2aPBEM=
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= github.com/prometheus/common v0.72.0 h1:tAYsE+sPJxIncDAobm4H5aQjmox9ZxEIIqPbiffa8G4=
github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4= github.com/prometheus/common v0.72.0/go.mod h1:77NWqAQ2tXT7BIK40qjJdw5Acrsrg1TlHAnsQi3i6mk=
github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= github.com/prometheus/procfs v0.22.0 h1:6q9+/JL9IKAPbCmBrv9n5O5Ty3NKnciV5X7YGw0oics=
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= github.com/prometheus/procfs v0.22.0/go.mod h1:CvmFr/GVhIjIvWJZW3tgkODBQMRIf0EyWMQLHCHab58=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
github.com/santhosh-tekuri/jsonschema/v6 v6.0.3 h1:1EYB5IzjZawrrnELUi78f9fPu57HuXjmddZPjrls/28=
github.com/santhosh-tekuri/jsonschema/v6 v6.0.3/go.mod h1:JXeL+ps8p7/KNMjDQk3TCwPpBy0wYklyWTfbkIzdIFU=
github.com/shirou/gopsutil/v4 v4.26.3 h1:2ESdQt90yU3oXF/CdOlRCJxrP+Am1aBYubTMTfxJ1qc=
github.com/shirou/gopsutil/v4 v4.26.3/go.mod h1:LZ6ewCSkBqUpvSOf+LsTGnRinC6iaNUNMGBtDkJBaLQ=
github.com/sirupsen/logrus v1.9.4 h1:TsZE7l11zFCLZnZ+teH4Umoq5BhEIfIzfRDZ1Uzql2w=
github.com/sirupsen/logrus v1.9.4/go.mod h1:ftWc9WdOfJ0a92nsE2jF5u5ZwH8Bv2zdeOC42RjbV2g=
github.com/spf13/afero v1.15.0 h1:b/YBCLWAJdFWJTN9cLhiXXcD7mzKn9Dm86dNnfyQw1I=
github.com/spf13/afero v1.15.0/go.mod h1:NC2ByUVxtQs4b3sIUphxK0NioZnmxgyCrfzeuq8lxMg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.5.3 h1:jmXUvGomnU1o3W/V5h2VEradbpJDwGrzugQQvL0POH4=
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= github.com/stretchr/objx v0.5.3/go.mod h1:rDQraq+vQZU7Fde9LOZLr8Tax6zZvy4kuNKF+QYS+U0=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.12.1 h1:EuwCh5fleGS7H32xRwO3wRGT7DxrDhLAT6FF8MpWDWE=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.12.1/go.mod h1:MDEgiDPPsNp5cuIrHPPCyornHKgEVbtFUmoNlxoYthg=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/testcontainers/testcontainers-go v0.42.0 h1:He3IhTzTZOygSXLJPMX7n44XtK+qhjat1nI9cneBbUY=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/testcontainers/testcontainers-go v0.42.0/go.mod h1:vZjdY1YmUA1qEForxOIOazfsrdyORJAbhi0bp8plN30=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/tklauser/go-sysconf v0.3.16 h1:frioLaCQSsF5Cy1jgRBrzr6t502KIIwQ0MArYICU0nA=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/tklauser/go-sysconf v0.3.16/go.mod h1:/qNL9xxDhc7tx3HSRsLWNnuzbVfh3e7gh/BmM179nYI=
github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= github.com/tklauser/numcpus v0.11.0 h1:nSTwhKH5e1dMNsCdVBukSZrURJRoHbSEQjdEbY+9RXw=
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= github.com/tklauser/numcpus v0.11.0/go.mod h1:z+LwcLq54uWZTX0u/bGobaV34u6V7KNlTZejzM6/3MQ=
github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo=
github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q= github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= github.com/xyproto/randomstring v1.2.0 h1:y7PXAEBM3XlwJjPG2JQg4voxBYZ4+hPgRdGKCfU8wik=
go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= github.com/xyproto/randomstring v1.2.0/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E=
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0=
go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64=
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 h1:F7Jx+6hwnZ41NSFTO5q4LYDtJRXBf2PD0rNBkeB/lus=
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0/go.mod h1:UHB22Z8QsdRDrnAtX4PntOl36ajSxcdUMt1sF7Y6E7Q=
go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= go.opentelemetry.io/otel v1.41.0 h1:YlEwVsGAlCvczDILpUXpIpPSL/VPugt7zHThEMLce1c=
golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= go.opentelemetry.io/otel v1.41.0/go.mod h1:Yt4UwgEKeT05QbLwbyHXEwhnjxNO6D8L5PQP51/46dE=
golang.org/x/arch v0.8.0 h1:3wRIsP3pM4yUptoR96otTUOXI367OS0+c9eeRi9doIc= go.opentelemetry.io/otel/metric v1.41.0 h1:rFnDcs4gRzBcsO9tS8LCpgR0dxg4aaxWlJxCno7JlTQ=
golang.org/x/arch v0.8.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys= go.opentelemetry.io/otel/metric v1.41.0/go.mod h1:xPvCwd9pU0VN8tPZYzDZV/BMj9CM9vs00GuBjeKhJps=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= go.opentelemetry.io/otel/sdk v1.36.0 h1:b6SYIuLRs88ztox4EyrvRti80uXIFy+Sqzoh9kFULbs=
golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= go.opentelemetry.io/otel/sdk v1.36.0/go.mod h1:+lC+mTgD+MUWfjJubi2vvXWcVxyr9rmlshZni72pXeY=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= go.opentelemetry.io/otel/sdk/metric v1.36.0 h1:r0ntwwGosWGaa0CrSt8cuNuTcccMXERFwHX4dThiPis=
golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= go.opentelemetry.io/otel/sdk/metric v1.36.0/go.mod h1:qTNOhFDfKRwX0yXOqJYegL5WRaW376QbB7P4Pb0qva4=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= go.opentelemetry.io/otel/trace v1.41.0 h1:Vbk2co6bhj8L59ZJ6/xFTskY+tGAbOnCtQGVVa9TIN0=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= go.opentelemetry.io/otel/trace v1.41.0/go.mod h1:U1NU4ULCoxeDKc09yCWdWe+3QoyweJcISEVa1RBzOis=
golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= go.uber.org/multierr v1.10.0 h1:S0h4aNzvfcFsC3dRF1jLoaov7oRaKqRGC/pUEJ2yvPQ=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= go.uber.org/multierr v1.10.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= go.uber.org/zap v1.28.0 h1:IZzaP1Fv73/T/pBMLk4VutPl36uNC+OSUh3JLG3FIjo=
golang.org/x/crypto v0.20.0/go.mod h1:Xwo95rrVNIoSMx9wa1JroENMToLWn3RNVrTBpLHgZPQ= go.uber.org/zap v1.28.0/go.mod h1:rDLpOi171uODNm/mxFcuYWxDsqWSAVkFdX4XojSKg/Q=
golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI= go.yaml.in/yaml/v2 v2.4.4 h1:tuyd0P+2Ont/d6e2rl3be67goVK4R6deVxCUX5vyPaQ=
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= go.yaml.in/yaml/v2 v2.4.4/go.mod h1:gMZqIpDtDqOfM0uNfy0SkpRhvUryYH0Z6wdMYcacYXQ=
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= go.yaml.in/yaml/v3 v3.0.5 h1:N6y/pJk8buWs9NY5ERU2HSMfm+IuD/OtfdAnq6kESPw=
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= go.yaml.in/yaml/v3 v3.0.5/go.mod h1:HVTZu1O7/Vkt2N+BFy8Zza+lnLsABggaTM2ZpNIGuKg=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/crypto v0.57.0 h1:3ZVCjf8Ggz7zneR/EHRVx68Ctf+2pmIMP2UFhh9cC6M=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/crypto v0.57.0/go.mod h1:Fdz0i5U6CoizGwLda9DttjSk6qlZo25zYNtR+ycvuZA=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.41.0 h1:qJmnOUb4YB+FsEuM3HcWucdZASCPGhsX6uljO6pog0c=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/mod v0.41.0/go.mod h1:Ek9pY8RKWXwsWvd3rQiHYtMqkjSUV+s1Rj7j4H5Ur6o=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.59.0 h1:5zfYln+w5XCxwrnMMJPufRgNoXEaGxl0wo5GqPXyues=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.59.0/go.mod h1:2DA/G1UfVbCpQPeWTmMPGY7Cs2PkBkwu743bVX5PIVg=
golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/sync v0.23.0 h1:KameEIfc1IkluZyXWLn39Wd4tURc6GbCiISGiZm2bQk=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/sync v0.23.0/go.mod h1:sUUOizhqBxiL6pEWpqNLUiaJn1ShEbZ6BBqskPbjZm0=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= golang.org/x/sys v0.48.0 h1:bbX/i/6MgT9BVLM9RT1thmxL04yeTAhbEz4SyadbXoo=
golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac= golang.org/x/sys v0.48.0/go.mod h1:hNLxWAXmnKAxqDtdwIYC4bM9oQPEecfsnNMuSxOs3og=
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= golang.org/x/term v0.46.0 h1:3+OXuTbaKDgwk8jTi3aSLHRlmWqHEUDUtxnbFigO4YE=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/term v0.46.0/go.mod h1:+K02xbkittuwc0Am4abfA3Fc+XRGXkvBXNO88NCXPoc=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/text v0.42.0 h1:JbOZXgfeCPU9gacVtYliJqOhD+zhrEqK4LfdpmlUZqI=
golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= golang.org/x/text v0.42.0/go.mod h1:ojzP1Z+2QtioaF8DTtO8K5q7JWVVYwZKenzujK0Zd0E=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/time v0.15.0 h1:bbrp8t3bGUeFOx08pvsMYRTCVSMk89u4tKbNOZbp88U=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/time v0.15.0/go.mod h1:Y4YMaQmXwGQZoFaVFk4YpCt4FLQMYKZe9oeV/f4MSno=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/tools v0.49.0 h1:3NI7VXzL9+1WZD52Dx2ttoPwD5DWrFGpl9mFZDlmisI=
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/tools v0.49.0/go.mod h1:SJNXV9DBKT0UbdttsQjbfJlAE/q+y36++zo3uL3N0Oo=
golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= google.golang.org/protobuf v1.36.12 h1:pJOKDDOyeXErUroCihFAd5LQuwXBSpVnKGrj5o/fwxc=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= google.golang.org/protobuf v1.36.12/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk=
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190425163242-31fd60d6bfdc/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190823170909-c4a336ef6a2f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg=
google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gotest.tools/v3 v3.5.2 h1:7koQfIKdy+I8UTetycgUqXWSDwpgv193Ka+qRsmBY8Q=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gotest.tools/v3 v3.5.2/go.mod h1:LtdLGcnqToBH83WByAAi/wiwSFCArdFIUV/xxN4pcjA=
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= pgregory.net/rapid v1.2.0 h1:keKAYRcjm+e1F0oAuU5F5+YPAWcyxNNRK2wud503Gnk=
nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50= pgregory.net/rapid v1.2.0/go.mod h1:PY5XlDGj0+V1FCq0o192FdRhpKHGTRIWBgqjDBTrq04=
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
-17
View File
@@ -1,17 +0,0 @@
#! /bin/sh
#envsubst < ./frontend/src/arne.js
sed -i 's^$HOSTNAME^'"$HOSTNAME"'^g' ./frontend/src/arne.js
cat ./frontend/src/arne.js
cd ./frontend/
npm install
npm run build
cd ..
./MusicServer
+90
View File
@@ -0,0 +1,90 @@
package backend
import (
"errors"
"io/fs"
"os"
"path/filepath"
"strings"
)
// CharacterService serves character images from a single directory.
type CharacterService struct {
root *os.Root
}
// NewCharacterService opens the characters directory. Files outside it can never be served.
func NewCharacterService(path string) (*CharacterService, error) {
root, err := os.OpenRoot(path)
if err != nil {
return nil, err
}
return &CharacterService{root: root}, nil
}
// List returns the file names of all character images.
func (c *CharacterService) List() ([]string, error) {
entries, err := fs.ReadDir(c.root.FS(), ".")
if err != nil {
return nil, err
}
characters := []string{}
for _, entry := range entries {
if !entry.IsDir() && isImage(entry.Name()) {
characters = append(characters, entry.Name())
}
}
return characters, nil
}
// CharacterDetails is a character image with the time its file was last changed, so a
// client that caches images knows when to download one again.
type CharacterDetails struct {
Name string `json:"name" doc:"File name of the character image"`
Modified int64 `json:"modified" doc:"When the image was last changed, in Unix seconds"`
}
// ListDetails returns all character images with the time each was last changed.
func (c *CharacterService) ListDetails() ([]CharacterDetails, error) {
entries, err := fs.ReadDir(c.root.FS(), ".")
if err != nil {
return nil, err
}
characters := []CharacterDetails{}
for _, entry := range entries {
if entry.IsDir() || !isImage(entry.Name()) {
continue
}
info, err := entry.Info()
if err != nil {
return nil, err
}
characters = append(characters, CharacterDetails{Name: entry.Name(), Modified: info.ModTime().Unix()})
}
return characters, nil
}
// Open opens the character image with the given file name.
func (c *CharacterService) Open(name string) (*os.File, error) {
if name == "" || name != filepath.Base(name) || !isImage(name) {
return nil, ErrInvalidName
}
f, err := c.root.Open(name)
if errors.Is(err, fs.ErrNotExist) {
return nil, ErrNotFound
}
return f, err
}
// Close releases the characters directory.
func (c *CharacterService) Close() error {
return c.root.Close()
}
func isImage(name string) bool {
switch strings.ToLower(filepath.Ext(name)) {
case ".jpg", ".jpeg", ".png":
return true
}
return false
}
Loaded 100 of 237 files, more files were not shown because too many files have changed in this diff. Show more