Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
164 commits
Select commit Hold shift + click to select a range
3d1c570
fixed tailscale-serve commit
thestumonkey Jan 28, 2026
ab48fd6
Merge pull request #141 from Ushadow-io/mainfix
thestumonkey Jan 28, 2026
eb201f5
Omi app logs (#142)
thestumonkey Jan 29, 2026
5588246
Omi app logs (#143)
thestumonkey Jan 29, 2026
c259226
Add debug logging for service deployment
thestumonkey Jan 29, 2026
ca2b0af
simplified to just use ushadow network
thestumonkey Jan 29, 2026
6fceb9a
added nbetwork fixes and chronicle combined audio
thestumonkey Jan 29, 2026
b709610
fixed chronicle port issue
thestumonkey Jan 30, 2026
4cdd66a
updated openmem
thestumonkey Jan 30, 2026
a9729e5
added pull logic if image not found
thestumonkey Jan 30, 2026
d6e34e8
added locked neo4j driver version
thestumonkey Jan 30, 2026
0616abf
added mobile session logger
thestumonkey Jan 30, 2026
7821266
added pixi
thestumonkey Jan 30, 2026
dc614b2
Convert chronicle to git submodule
thestumonkey Feb 1, 2026
75211c0
Remove orphaned vibe-kanban submodule entry
thestumonkey Feb 1, 2026
70a9ede
Add automatic sparse checkout configuration via git hooks
thestumonkey Feb 1, 2026
33b4236
Add Makefile targets for building/pushing Chronicle and Mycelia to GHCR
thestumonkey Feb 1, 2026
3f0b8f3
Add OpenMemory (mem0) as submodule with build support
thestumonkey Feb 1, 2026
5e75d85
chat and memories
thestumonkey Feb 1, 2026
9ba036d
new convo page
thestumonkey Feb 2, 2026
cf81775
9548 simpler deploys (#145)
thestumonkey Feb 2, 2026
44390e1
feat: Add Keycloak OAuth theme matching Ushadow design system
thestumonkey Feb 2, 2026
97c913e
security: Move Keycloak credentials to environment variables
thestumonkey Feb 2, 2026
198f02a
Kaycloak
thestumonkey Feb 2, 2026
9936bd9
memorycards and dualstream recording
thestumonkey Feb 2, 2026
b192c01
Merge PR #147: Add Keycloak OAuth theme and security improvements
thestumonkey Feb 2, 2026
28d262a
feat: Add Keycloak OAuth implementation
thestumonkey Feb 2, 2026
dd21556
F13f auth complete (#149)
thestumonkey Feb 2, 2026
cfb6d50
Revert "F13f auth complete (#149)" (#150)
thestumonkey Feb 2, 2026
00cffb9
F13f auth complete (#151)
thestumonkey Feb 2, 2026
cb13bd5
feat: Add automatic Keycloak redirect URI registration
thestumonkey Feb 2, 2026
fdd7521
Merge origin/dev into f13f-auth-complete
thestumonkey Feb 2, 2026
54b3ee6
feat: Add Keycloak SSO integration with conversation sharing (#152)
thestumonkey Feb 3, 2026
588a3cf
Add ingress configuration UI to DeployToK8sModal
thestumonkey Feb 3, 2026
5e68c01
feat: Add kubernetes cluster ingress configuration
thestumonkey Feb 3, 2026
fd09c19
Merge remote-tracking branch 'origin/dev' into dual-convo
thestumonkey Feb 3, 2026
224a441
fix: Resolve merge conflict in App.tsx - keep KeycloakAuthProvider
thestumonkey Feb 3, 2026
bb78374
fix: Resolve merge conflicts in ConversationDetailPage - add share fu…
thestumonkey Feb 3, 2026
b0ed4cc
feat: Add Keycloak user compatibility across all routers
thestumonkey Feb 3, 2026
1ccf8e3
fix: Resolve merge conflicts in keycloak_user_sync - use display_name
thestumonkey Feb 3, 2026
b6faaf3
fix: Handle Keycloak user dict in /users/me endpoint
thestumonkey Feb 3, 2026
b777879
feat: Add token bridging to audio relay WebSocket
thestumonkey Feb 3, 2026
407b9fc
fix: Add codec parameter to audio relay destinations
thestumonkey Feb 3, 2026
f04d9ad
fixed audiorelay codec
thestumonkey Feb 3, 2026
af6f7c0
upgraded mobile
thestumonkey Feb 3, 2026
bc9d487
Add Chronicle-powered dashboard with recent activities
thestumonkey Feb 2, 2026
59d0c69
added postgres as default
thestumonkey Feb 3, 2026
e555d09
added kc realm
thestumonkey Feb 3, 2026
505b651
made mycelia default service
thestumonkey Feb 3, 2026
2612045
aded method indeox for claude
thestumonkey Feb 3, 2026
47522f4
feat: Add env sync tool to sync .env with .env.example (#154)
skywinder Feb 3, 2026
cba356a
aded method indeox for claude
thestumonkey Feb 3, 2026
caae949
fixed bad docker mount and added kc sub
thestumonkey Feb 4, 2026
4edcf1e
fixed kc user details
thestumonkey Feb 4, 2026
48b1e43
extended token lifespan until refresh complete
thestumonkey Feb 4, 2026
f215eea
used standar kc lib
thestumonkey Feb 4, 2026
d20e5e5
fixced keycloak aiuth
thestumonkey Feb 4, 2026
59430bb
fixed default KC
thestumonkey Feb 4, 2026
a6f38fe
updated service ui
thestumonkey Feb 4, 2026
07d7c81
added share
thestumonkey Feb 4, 2026
3dcf459
updated anon auth
thestumonkey Feb 4, 2026
7917378
changed uniode to machine name
thestumonkey Feb 4, 2026
cda0885
added tags and build services
thestumonkey Feb 5, 2026
965eb2f
deploy tweaks
thestumonkey Feb 5, 2026
e68c9d9
taghs
thestumonkey Feb 5, 2026
c6ec0f8
updated ush client
thestumonkey Feb 5, 2026
22b2aa9
refactored url proxy
thestumonkey Feb 6, 2026
efa20d1
auth tweaks
thestumonkey Feb 6, 2026
c4717bc
environments
thestumonkey Feb 6, 2026
853cbd8
updated mobile to use KC
thestumonkey Feb 6, 2026
9ecc733
updated docker manager and script
thestumonkey Feb 6, 2026
54b4ef6
externals support
thestumonkey Feb 6, 2026
28cef23
addfunnel
thestumonkey Feb 6, 2026
8818b1a
fixed kc token
thestumonkey Feb 6, 2026
c694a5e
added backend vars for mycelai
thestumonkey Feb 6, 2026
e3671a8
bits n pieces
thestumonkey Feb 6, 2026
b37d600
added images
thestumonkey Feb 6, 2026
4f9d628
fixed keycloak login
thestumonkey Feb 6, 2026
b1bee31
fixed wizard startup studff
thestumonkey Feb 6, 2026
6294302
amend getting started, added util scritps
thestumonkey Feb 7, 2026
08ac76c
Disable New Architecture for Android build compatibility
thestumonkey Feb 7, 2026
d5797fb
Fix Android build: Enable Jetifier and configure build properties
thestumonkey Feb 7, 2026
cad167c
Add custom Expo config plugin to fix AndroidManifest merge conflict
thestumonkey Feb 7, 2026
a1cb792
Fix AndroidManifest plugin to specify appComponentFactory value
thestumonkey Feb 7, 2026
7f8e18b
Update eas.json with App Store Connect App ID
thestumonkey Feb 10, 2026
0a4508c
Add BGTaskSchedulerPermittedIdentifiers for iOS background processing
thestumonkey Feb 10, 2026
afacb9e
Add ITSAppUsesNonExemptEncryption flag for iOS
thestumonkey Feb 10, 2026
f74fc41
moved keycloak url
thestumonkey Feb 10, 2026
34ae3b7
using hostip for kc
thestumonkey Feb 10, 2026
4bb3c9c
protect against login loop
thestumonkey Feb 10, 2026
49334d4
Bump iOS build number to 4
thestumonkey Feb 10, 2026
c54135a
move to using standard keycloak admin
thestumonkey Feb 11, 2026
e109f75
updated kc and mongo urls
thestumonkey Feb 11, 2026
b307c22
more kc madness
thestumonkey Feb 11, 2026
385f651
General lamcher (#156)
thestumonkey Feb 12, 2026
06cc6c7
fixed launcher login
thestumonkey Feb 13, 2026
ae4faf4
updated pixi
thestumonkey Feb 14, 2026
e84d563
Claude/awesome volhard (#157)
thestumonkey Feb 14, 2026
6e2800e
mobile deploy
thestumonkey Feb 14, 2026
f695d1d
added command to build to testflgiht
thestumonkey Feb 16, 2026
90f1a72
Mobile kc auth (#158)
thestumonkey Feb 16, 2026
930c6d7
k8s stuff
thestumonkey Feb 16, 2026
9b121ed
k8s stuff
thestumonkey Feb 17, 2026
563b2d7
added k8s deploy
thestumonkey Feb 17, 2026
3d83f9b
removedd kc enabled
thestumonkey Feb 17, 2026
ca93cfc
Merge branch 'dev' of github.com:Ushadow-io/Ushadow into pink/k8s-dev
thestumonkey Feb 17, 2026
2e09e37
kanban ticket move and workmux
thestumonkey Feb 17, 2026
013f9fa
chore(launcher): release v0.8.1
thestumonkey Feb 18, 2026
252c314
improved tests (#160)
thestumonkey Feb 18, 2026
b47b315
mobile connection updates
thestumonkey Feb 19, 2026
480180a
mobile login
thestumonkey Feb 19, 2026
a819ad1
Merge branch 'dev' of github.com:Ushadow-io/Ushadow into orangedev
thestumonkey Feb 19, 2026
bf19d07
kanban hooks
thestumonkey Feb 19, 2026
603abbf
changed claude command
thestumonkey Feb 20, 2026
3af608d
Merge branch 'dev' of github.com:Ushadow-io/Ushadow into kanbann
thestumonkey Feb 20, 2026
8e9aa50
Kanbann (#161)
thestumonkey Feb 20, 2026
3388b3f
chore(launcher): release v0.8.2
thestumonkey Feb 20, 2026
7560de0
launcher build fix
thestumonkey Feb 20, 2026
b921868
Merge branch 'dev' of github.com:Ushadow-io/Ushadow into kanbann
thestumonkey Feb 20, 2026
cff5d5d
fixced dev origin branch worktree creation
thestumonkey Feb 20, 2026
5785f58
chore(launcher): release v0.8.3
thestumonkey Feb 20, 2026
2465a66
chore(launcher): release v0.8.4
thestumonkey Feb 20, 2026
993b31a
tweaks to mac launcher build
thestumonkey Feb 20, 2026
1d04e70
chore(launcher): release v0.8.5
thestumonkey Feb 20, 2026
0a9e82c
launcher build fixes
thestumonkey Feb 20, 2026
37f9fc8
chore(launcher): release v0.8.6
thestumonkey Feb 20, 2026
2b307b5
chore(launcher): release v0.8.7
thestumonkey Feb 20, 2026
414dc17
mobile lock screen & refresh
thestumonkey Feb 20, 2026
f917c3e
Merge branch 'dev' of github.com:Ushadow-io/Ushadow into orangedev
thestumonkey Feb 20, 2026
3a7a855
chore(launcher): release v0.8.8
thestumonkey Feb 20, 2026
c007f5d
wait for kc
thestumonkey Feb 20, 2026
17665f8
fixed menu wrap
thestumonkey Feb 20, 2026
a6f4853
launcher fixes
thestumonkey Feb 20, 2026
d993c19
Merge branch 'dev' of github.com:Ushadow-io/Ushadow into kanbann
thestumonkey Feb 20, 2026
7338455
chore(launcher): release v0.8.9
thestumonkey Feb 20, 2026
f612ed9
launcher
thestumonkey Feb 20, 2026
276db54
chore(launcher): release v0.8.10
thestumonkey Feb 20, 2026
c6fc941
code signing
thestumonkey Feb 20, 2026
64e3521
chore(launcher): release v0.8.11
thestumonkey Feb 20, 2026
1e9587e
vsarious fixes to wizard and startup
thestumonkey Feb 20, 2026
f8e6b41
app signinbg for apple
thestumonkey Feb 20, 2026
665d091
chore(launcher): release v0.8.12
thestumonkey Feb 20, 2026
7431e65
chore(launcher): release v0.8.13
thestumonkey Feb 20, 2026
ef12c93
chore(launcher): release v0.8.14
thestumonkey Feb 21, 2026
57456e9
tweaks
thestumonkey Feb 21, 2026
3cb8e5a
Merge branch 'dev' of github.com:Ushadow-io/Ushadow into dev
thestumonkey Feb 21, 2026
a807403
mastadon mobile (#162)
thestumonkey Feb 21, 2026
e4bc674
disabled apple notary
thestumonkey Feb 21, 2026
094614e
Merge branch 'dev' of github.com:Ushadow-io/Ushadow into kanbann
thestumonkey Feb 21, 2026
feb3e48
Merge branch 'main' into dev
thestumonkey Feb 21, 2026
b973aec
chore(launcher): release v0.8.15
thestumonkey Feb 21, 2026
c037eda
turned on dual mobile mpde
thestumonkey Feb 21, 2026
21fe5eb
bypass sign
thestumonkey Feb 21, 2026
bfa52b6
Merge branch 'dev' of github.com:Ushadow-io/Ushadow into kanbann
thestumonkey Feb 21, 2026
1dc74b5
chore(launcher): release v0.8.16
thestumonkey Feb 21, 2026
66b443c
workmux + release tweak
thestumonkey Feb 21, 2026
8ef2441
mobile fixes for fastlane
thestumonkey Feb 21, 2026
9fe3fea
Merge branch 'dev' of github.com:Ushadow-io/Ushadow into orangedev
thestumonkey Feb 21, 2026
de53286
added testflight url for mobile
thestumonkey Feb 21, 2026
9a3c2d0
added claude page
thestumonkey Feb 22, 2026
14bcdee
Merge branch 'dev' of github.com:Ushadow-io/Ushadow into launcher/lau…
thestumonkey Feb 22, 2026
16c01d0
addded feature flag
thestumonkey Feb 22, 2026
20e7e5b
bluesky
thestumonkey Feb 22, 2026
2b1f543
Update image references in chronicle-compose.yaml
thestumonkey Feb 22, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
4 changes: 3 additions & 1 deletion .claude/plugins/test-automation/plugin.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
"skills": [
"skills/spec.md",
"skills/qa-test-cases.md",
"skills/automate-tests.md"
"skills/automate-tests.md",
"skills/debug-robot-browser.md",
"skills/debug-robot-api.md"
]
}
323 changes: 323 additions & 0 deletions .claude/plugins/test-automation/skills/debug-robot-api.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,323 @@
---
name: debug-robot-api
description: This skill should be used when the user asks to "debug robot api tests", "fix a failing api test", "diagnose a robot api test failure", "why is my robot api test failing", or "run api tests and fix them". Drives a fast run-parse-fix cycle for Robot Framework API tests using RequestsLibrary.
---

## Purpose

Drive a fast debug cycle for failing Robot Framework API tests:
**run with debug logging → parse output for HTTP details → identify cause → fix → verify**.

API tests fail at the HTTP layer (status codes, response bodies, auth tokens) — not the DOM. The debug workflow is entirely different from browser tests.

---

## Step 1 — Run with debug logging

```bash
# All API tests with verbose HTTP output
cd robot_tests && pixi run robot --loglevel DEBUG api/

# Single suite (fastest)
cd robot_tests && pixi run robot --loglevel DEBUG api/keycloak_auth.robot

# Single test by name
cd robot_tests && pixi run robot --loglevel DEBUG --test "TC-KC-001*" api/keycloak_auth.robot
```

`--loglevel DEBUG` logs the full request URL, headers, and response body for every HTTP call. Without it, you only see the status code.

---

## Step 2 — Parse the failure output

### output.xml — status codes and response bodies

```bash
# All FAIL lines with surrounding context
python3 -c "
import xml.etree.ElementTree as ET
try:
tree = ET.parse('robot_tests/output.xml')
for msg in tree.getroot().iter('msg'):
if msg.get('level') == 'FAIL' or (msg.text and 'status' in (msg.text or '').lower()):
print(msg.text[:300])
print('---')
except: pass
" 2>/dev/null | head -80

# Quick grep for HTTP status codes in output
grep -o 'status.*[0-9]\{3\}\|[0-9]\{3\}.*status\|HTTPError\|ConnectionError\|FAIL' \
robot_tests/output.xml | sort -u | head -20

# Response body at failure point
grep -o '.\{0,50\}response\|body\|detail.\{0,200\}' robot_tests/output.xml | head -20
```

### log.html — easiest to read

Open in a browser for full formatted output with collapsible sections:
```bash
open robot_tests/log.html
```

### Backend container logs

Often the clearest signal — shows the actual exception or validation error:
```bash
docker logs ushadow-test-backend-test-1 --tail 50

# Follow while running tests
docker logs ushadow-test-backend-test-1 -f
```

---

## Step 3 — Identify the failure pattern

### Pattern A: Connection refused / backend not ready

**Symptom:**
```
ConnectionError: HTTPConnectionPool(host='localhost', port=8200): Max retries exceeded
```

**Cause:** Backend container not running or still starting.

**Diagnosis:**
```bash
# Check container status
docker ps | grep ushadow-test

# Check if backend responds
curl -s http://localhost:8200/health | python3 -m json.tool

# Start containers if needed
cd robot_tests && make start
```

**Fix:** Wait for containers before running. The suite setup handles this — if containers are already running it reuses them. If not, run `make start` first or ensure the suite setup keyword is included.

---

### Pattern B: 401 Unauthorized

**Symptom:**
```
Expected status 200 but got 401
```

**Cause:** Missing auth token, expired token, or wrong client credentials.

**Diagnosis:**
```bash
# Check if token endpoint works
curl -s -X POST http://localhost:8181/realms/ushadow/protocol/openid-connect/token \
-d "grant_type=password&client_id=ushadow-frontend&username=kctest@example.com&password=TestKeycloak123!" \
| python3 -m json.tool

# Check if test user exists in Keycloak
TOKEN=$(curl -s -X POST http://localhost:8181/realms/master/protocol/openid-connect/token \
-d "grant_type=password&client_id=admin-cli&username=admin&password=admin" \
| python3 -c "import sys,json; print(json.load(sys.stdin)['access_token'])")
curl -s -H "Authorization: Bearer $TOKEN" \
"http://localhost:8181/admin/realms/ushadow/users?email=kctest@example.com" | python3 -m json.tool
```

**Common fixes:**
- Test user not created → suite setup should call `Ensure Keycloak Test User Exists`
- Wrong client_id in token request → check `KEYCLOAK_CLIENT_ID` in `test_env.py` (should be `ushadow-frontend` or `ushadow-cli`)
- Token expired mid-suite → refresh in suite setup or request a fresh token per test

---

### Pattern C: 403 Forbidden

**Symptom:**
```
Expected status 200 but got 403
```

**Cause:** Token present but insufficient permissions, or using wrong client type.

**Common case — introspection with public client:**
Keycloak's token introspection endpoint (`/protocol/openid-connect/token/introspect`) requires a **confidential client** with client credentials. The `ushadow-frontend` client is public and will get 401/403.

**Fix:**
```robot
# Check status gracefully — skip if introspection not supported
${response}= POST On Session ... expected_status=any
IF '${response.status_code}' in ['401', '403']
Skip Token introspection requires confidential client (public client limitation)
END
Should Be Equal As Integers ${response.status_code} 200
```

Or use the CLI client (`ushadow-cli`) if it's configured as confidential:
```robot
# Use CLI client for introspection
${token}= Get Token Via CLI Client
```

---

### Pattern D: 404 Not Found

**Symptom:**
```
Expected status 200 but got 404
```

**Cause:** Endpoint path is wrong, or the route doesn't exist.

**Diagnosis:**
```bash
# Check what routes are registered on the backend
curl -s http://localhost:8200/openapi.json | python3 -c "
import sys, json
spec = json.load(sys.stdin)
for path in sorted(spec.get('paths', {}).keys()):
print(path)
" | grep -i auth

# Or view Swagger UI
open http://localhost:8200/docs
```

**Fix:** Correct the endpoint path in the robot file. Check the backend's router to confirm the exact path.

---

### Pattern E: Response body mismatch

**Symptom:**
```
'expected_field' != 'actual_field'
Should Be Equal As Strings FAIL
```

**Cause:** The response JSON structure changed, or the test is checking the wrong key.

**Diagnosis:**
```bash
# Make the call manually and inspect the actual response
curl -s -X POST http://localhost:8200/api/auth/token \
-H "Content-Type: application/json" \
-d '{"code":"test","code_verifier":"test","redirect_uri":"http://localhost:3001/oauth/callback"}' \
| python3 -m json.tool
```

Check the actual field names in the response vs what the test asserts. Common mismatches:
- `access_token` vs `token`
- `user_id` vs `id`
- Nested vs flat structure (`user.email` vs `email`)

---

### Pattern F: Suite setup failure

**Symptom:** Tests show as `NOT RUN` or the suite itself fails before any tests execute.

**Diagnosis:**
```bash
# Check the first FAIL message
grep -m5 'FAIL\|ERROR' robot_tests/output.xml

# Check container health
docker ps --format "table {{.Names}}\t{{.Status}}" | grep ushadow-test
```

**Common causes:**
- MongoDB not cleared (`✓ MongoDB test database cleared` should appear in console)
- Keycloak not reachable at `http://localhost:8181`
- Backend health check failing at `http://localhost:8200/health`

---

## Step 4 — Common fixes reference

### Auth keywords (from `resources/auth_keywords.robot`)

```robot
# Get a token for the test user
${TOKEN}= Get Keycloak Token ${KEYCLOAK_TEST_EMAIL} ${KEYCLOAK_TEST_PASSWORD}

# Ensure the test user exists (idempotent — safe to call in setup)
Ensure Keycloak Test User Exists

# Create auth header dict
${HEADERS}= Create Dictionary Authorization=Bearer ${TOKEN}
```

### Session management

```robot
# Create a session pointing at the backend
Create Session api ${BACKEND_URL} headers=${HEADERS}

# Make a call
${resp}= GET On Session api /api/auth/me expected_status=200

# Log full response for debugging
Log Response: ${resp.status_code} ${resp.text}
```

### Graceful skip vs fail

```robot
# Skip if feature not available (e.g. confidential client not configured)
${resp}= POST On Session api ${ENDPOINT} expected_status=any
Skip If '${resp.status_code}' == '501' Feature not implemented

# Assert with helpful message
Should Be Equal As Integers ${resp.status_code} 200
... Expected 200 but got ${resp.status_code}: ${resp.text}
```

---

## Step 5 — Fix and verify

```bash
# Re-run with debug logging to confirm fix
cd robot_tests && pixi run robot --loglevel DEBUG api/keycloak_auth.robot
```

Expected output when passing:
```
TC-KC-001: Authenticate with Keycloak Direct Grant | PASS |
TC-KC-002: OAuth Authorization Code Flow (skip) | SKIP |
TC-KC-003: Validate Access Token | PASS |
TC-KC-004: Introspect Access Token (skip) | SKIP |
TC-KC-005: Refresh Access Token | PASS |
TC-KC-006: Logout and Revoke Tokens | PASS |
6 tests, 4 passed, 0 failed, 2 skipped
```

---

## Environment quick reference

| Service | Port | URL |
|---------|------|-----|
| Backend | 8200 | `http://localhost:8200` |
| Keycloak (test) | 8181 | `http://localhost:8181` |
| MongoDB (test) | 27118 | `mongodb://localhost:27118` |
| Redis (test) | 6480 | `redis://localhost:6480` |

Keycloak admin: `admin` / `admin`
Test user: `kctest@example.com` / `TestKeycloak123!`
Realm: `ushadow`
Frontend client: `ushadow-frontend` (public)
CLI client: `ushadow-cli` (confidential, for direct grant)

## Key files

| File | Purpose |
|------|---------|
| `robot_tests/api/keycloak_auth.robot` | Keycloak auth test suite |
| `robot_tests/resources/auth_keywords.robot` | Shared auth keywords |
| `robot_tests/resources/setup/test_env.py` | URLs, ports, credentials |
| `robot_tests/resources/setup/suite_setup.robot` | Container start/stop |
| `robot_tests/output.xml` | Last run results |
| `robot_tests/log.html` | Human-readable log (open in browser) |
Loading