diff --git a/.gitignore b/.gitignore index 46c7767..4ba8321 100644 --- a/.gitignore +++ b/.gitignore @@ -11,4 +11,4 @@ copy_executable_local.sh nostr_login_lite/ style_guide/ nostr-tools -.test_keys \ No newline at end of file +.test_keysadmin/cache/ diff --git a/.test_keys b/.test_keys new file mode 100644 index 0000000..f6cc519 --- /dev/null +++ b/.test_keys @@ -0,0 +1,2 @@ +ADMIN_PUBKEY='8ff74724ed641b3c28e5a86d7c5cbc49c37638ace8c6c38935860e7a5eedde0e' +SERVER_PRIVKEY='1111111111111111111111111111111111111111111111111111111111111111' diff --git a/admin/README.md b/admin/README.md deleted file mode 100644 index bb2c76b..0000000 --- a/admin/README.md +++ /dev/null @@ -1,133 +0,0 @@ -# C-Relay-PG PHP Admin Page - -A traditional PHP admin interface for the caching service that connects -directly to PostgreSQL, bypassing the NIP-44 64KB encryption limit of the -Nostr admin API. Handles thousands of followed pubkeys via server-side -pagination. - -## Quick Start - -### 1. Install PHP + PHP-FPM + PostgreSQL extension - -```bash -# Debian/Ubuntu -sudo apt install php-fpm php-pgsql - -# RHEL/Fedora/Alma -sudo dnf install php-fpm php-pgsql -``` - -### 2. Copy admin files to the server - -```bash -sudo mkdir -p /opt/c-relay-pg/admin -sudo cp -r admin/* /opt/c-relay-pg/admin/ -``` - -### 3. Configure database credentials - -Edit `/opt/c-relay-pg/admin/lib/config.php` and set the PostgreSQL -connection parameters to match your relay's `--db-*` flags: - -```php -return [ - 'db_host' => 'localhost', - 'db_port' => '5432', - 'db_name' => 'crelay', - 'db_user' => 'crelay', - 'db_password' => 'crelay', - // ... -]; -``` - -### 4. Set up HTTP Basic Auth - -```bash -sudo htpasswd -c /opt/c-relay-pg/admin/.htpasswd admin -# Enter a password when prompted -``` - -### 5. Add nginx location block - -Add this to your existing nginx server block (the one that proxies to -the relay on port 8888): - -```nginx -# PHP admin page for caching service -location /admin/ { - alias /opt/c-relay-pg/admin/; - index index.php; - - auth_basic "Relay Admin"; - auth_basic_user_file /opt/c-relay-pg/admin/.htpasswd; - - location ~ \.php$ { - fastcgi_pass unix:/run/php/php-fpm.sock; - fastcgi_index index.php; - include fastcgi_params; - fastcgi_param SCRIPT_FILENAME $request_filename; - } - - # Deny access to the lib/ directory (contains DB credentials) - location ^~ /admin/lib/ { - deny all; - } -} -``` - -> **Note:** The `fastcgi_pass` socket path varies by distro: -> - Debian/Ubuntu: `unix:/run/php/php8.2-fpm.sock` -> - RHEL/Fedora: `unix:/run/php-fpm/www.sock` -> -> Check with: `ls /run/php/` or `ls /run/php-fpm/` - -### 6. Reload nginx - -```bash -sudo nginx -t && sudo systemctl reload nginx -``` - -### 7. Visit the admin page - -``` -https://relay.yourdomain.com/admin/ -``` - -Enter the HTTP Basic Auth credentials you set in step 4. - -## Pages - -| Page | URL | Description | -|------|-----|-------------| -| Dashboard | `/admin/` | Service state, backfill progress, error summary, active target | -| Follows | `/admin/follows.php` | Paginated followed-pubkey table with names, event counts, relay status | -| Relays | `/admin/relays.php` | Per (author, relay) backfill progress with descriptive error statuses | -| Config | `/admin/config-edit.php` | Read/edit caching config values; bumps config generation on save | -| Inbox | `/admin/inbox.php` | Queue depth monitor for `caching_event_inbox` | - -## Security - -- **HTTP Basic Auth** protects all pages (nginx `auth_basic`) -- **`lib/` directory denied** via nginx (contains DB credentials) -- **PDO prepared statements** everywhere (no SQL injection) -- **HTTPS** via existing nginx SSL config -- **No CORS needed** — same origin as the relay - -## How It Works - -The PHP pages query PostgreSQL directly using PDO with the same -`crelay` database user the relay uses. The dashboard auto-refreshes -every 10 seconds via AJAX polling of `api/status.php`. Paginated tables -(follows, relays) use server-side pagination with `LIMIT`/`OFFSET`. - -The config editor writes to the `config` table and bumps -`caching_config_generation`, which the caching service detects and -hot-reloads — no relay restart needed. - -## Upgrading to Real-Time (Future) - -If you later need true push updates (sub-second), you can add a small -Node.js WebSocket server alongside the PHP pages that uses PostgreSQL -`LISTEN/NOTIFY` to push updates to connected browsers. The PHP pages -and JSON endpoints are reusable — the WebSocket server would just -replace the polling `fetch()` calls in the JavaScript. diff --git a/admin/api/auth.php b/admin/api/auth.php new file mode 100644 index 0000000..d4c56dc --- /dev/null +++ b/admin/api/auth.php @@ -0,0 +1,37 @@ +prepare("INSERT INTO auth_rules (rule_type, pattern_type, pattern_value) VALUES (?, 'pubkey', ?)")->execute([$input['rule_type'], $input['pattern_value']]); + json_response(['message' => 'Rule added']); + } elseif ($action === 'remove') { + $pdo->prepare("DELETE FROM auth_rules WHERE id = ?")->execute([intval($input['id'])]); + json_response(['message' => 'Rule removed']); + } elseif ($action === 'set_wot_level') { + $pdo->prepare("UPDATE config SET value = ? WHERE key = 'wot_level'")->execute([strval($input['level'])]); + json_response(['message' => 'WoT level set']); + } elseif ($action === 'sync_wot') { + json_response(['message' => 'WoT sync not available via PHP (requires relay)']); + } + } catch (PDOException $e) { json_response(['error' => $e->getMessage()]); } +} + +// GET: WoT status +if (isset($_GET['action']) && $_GET['action'] === 'wot') { + $level = $pdo->query("SELECT value FROM config WHERE key = 'wot_level'")->fetchColumn() ?: '0'; + $wl_count = 0; + try { $wl_count = intval($pdo->query("SELECT count(*) FROM auth_rules WHERE rule_type = 'whitelist'")->fetchColumn()); } catch (PDOException $e) {} + $descriptions = ['0' => 'Level 0: Open relay — anyone can read and write', '1' => 'Level 1: Write only — WoT users can write', '2' => 'Level 2: Full — WoT users only']; + json_response(['kind3_status' => 'N/A (PHP admin)', 'whitelist_count' => $wl_count, 'level_description' => $descriptions[$level] ?? $descriptions['0']]); +} + +// GET: auth rules +$rules = []; +try { $rules = $pdo->query("SELECT id, rule_type, pattern_type, pattern_value FROM auth_rules ORDER BY id")->fetchAll(); } catch (PDOException $e) {} +json_response(['rules' => $rules]); diff --git a/admin/api/caching.php b/admin/api/caching.php new file mode 100644 index 0000000..7b63e5b --- /dev/null +++ b/admin/api/caching.php @@ -0,0 +1,123 @@ +beginTransaction(); + $pdo->exec("UPDATE caching_followed_pubkeys + SET until_cursor = 0, backfill_complete = FALSE, + events_fetched = 0, + updated_at = EXTRACT(EPOCH FROM NOW())::BIGINT"); + // Also reset per-relay progress rows + $pdo->exec("UPDATE caching_backfill_relay_progress + SET complete = FALSE, events_fetched = 0, + until_cursor = 0, last_status = 'reset', + consecutive_errors = 0, + updated_at = EXTRACT(EPOCH FROM NOW())::BIGINT"); + // Bump config generation to trigger hot-reload + $pdo->exec("UPDATE config SET value = (COALESCE(value::int, 0) + 1)::text + WHERE key = 'caching_config_generation'"); + $pdo->commit(); + json_response(['ok' => true, 'message' => 'All backfill progress reset. Caching service will re-drain.']); + } catch (PDOException $e) { + $pdo->rollBack(); + json_response(['ok' => false, 'error' => $e->getMessage()], 500); + } + } elseif ($action === 'reset_user' && $pubkey) { + // Reset backfill progress for a single followed author. + try { + $pdo->beginTransaction(); + $stmt = $pdo->prepare("UPDATE caching_followed_pubkeys + SET until_cursor = 0, backfill_complete = FALSE, + events_fetched = 0, + updated_at = EXTRACT(EPOCH FROM NOW())::BIGINT + WHERE pubkey = ?"); + $stmt->execute([$pubkey]); + // Also reset per-relay progress for this author + $stmt2 = $pdo->prepare("UPDATE caching_backfill_relay_progress + SET complete = FALSE, events_fetched = 0, + until_cursor = 0, last_status = 'reset', + consecutive_errors = 0, + updated_at = EXTRACT(EPOCH FROM NOW())::BIGINT + WHERE author_pubkey = ?"); + $stmt2->execute([$pubkey]); + // Bump config generation to trigger hot-reload + $pdo->exec("UPDATE config SET value = (COALESCE(value::int, 0) + 1)::text + WHERE key = 'caching_config_generation'"); + $pdo->commit(); + json_response(['ok' => true, 'message' => "Backfill reset for pubkey. Caching service will re-fetch."]); + } catch (PDOException $e) { + $pdo->rollBack(); + json_response(['ok' => false, 'error' => $e->getMessage()], 500); + } + } else { + json_response(['ok' => false, 'error' => 'Unknown action'], 400); + } + exit; +} + +// Caching config values (for toggle controls) +$config = []; +try { + $cfg_rows = $pdo->query("SELECT key, value FROM config WHERE key IN ('caching_enabled','caching_inbox_enabled','caching_live_enabled','caching_backfill_enabled')")->fetchAll(); + foreach ($cfg_rows as $r) { $config[$r['key']] = $r['value']; } +} catch (PDOException $e) {} + +// Service state +$state = []; +try { $state = $pdo->query("SELECT * FROM caching_service_state WHERE id = 1")->fetch() ?: []; } catch (PDOException $e) {} + +// Active target +$active = ['pubkey' => '', 'relay' => '']; +try { $active = $pdo->query("SELECT active_pubkey AS pubkey, active_relay AS relay FROM caching_backfill_active WHERE id = 1")->fetch() ?: $active; } catch (PDOException $e) {} + +// Inbox +$inbox = ['pending' => 0, 'live' => 0, 'backfill' => 0]; +try { + $inbox = $pdo->query("SELECT COUNT(*) AS pending, COUNT(*) FILTER (WHERE source_class='live') AS live, COUNT(*) FILTER (WHERE source_class='backfill') AS backfill FROM caching_event_inbox")->fetch() ?: $inbox; +} catch (PDOException $e) {} + +// Follows (paginated, with names from profiles cache + per-relay progress) +$follows = []; +try { + $follows = $pdo->query(" + SELECT fp.pubkey, fp.is_root, fp.backfill_complete, fp.events_fetched, + fp.last_event_at, + p.name, p.display_name, + (SELECT count(*) FROM events WHERE pubkey = fp.pubkey) AS total_events, + (SELECT count(*) FROM caching_backfill_relay_progress WHERE author_pubkey = fp.pubkey) AS relay_count, + (SELECT count(*) FROM caching_backfill_relay_progress WHERE author_pubkey = fp.pubkey AND complete = false) AS relay_incomplete + FROM caching_followed_pubkeys fp + LEFT JOIN profiles p ON p.pubkey = fp.pubkey + ORDER BY fp.is_root DESC, fp.events_fetched DESC LIMIT 100 + ")->fetchAll(); + // Fetch per-relay progress for all followed pubkeys in one query + $relayProgress = []; + try { + $rpRows = $pdo->query(" + SELECT author_pubkey, relay_url, complete, events_fetched, until_cursor, last_status, updated_at + FROM caching_backfill_relay_progress + ORDER BY author_pubkey, events_fetched DESC + ")->fetchAll(); + foreach ($rpRows as $rp) { + $relayProgress[$rp['author_pubkey']][] = $rp; + } + } catch (PDOException $e) {} + foreach ($follows as &$f) { + $f['name'] = profile_display_name($f); + $f['npub'] = function_exists('hex_to_npub') ? hex_to_npub($f['pubkey']) : substr($f['pubkey'], 0, 20); + $f['relays'] = $relayProgress[$f['pubkey']] ?? []; + } +} catch (PDOException $e) {} + +json_response(['state' => $state, 'active' => $active, 'inbox' => $inbox, 'follows' => $follows, 'config' => $config]); diff --git a/admin/api/chart.php b/admin/api/chart.php new file mode 100644 index 0000000..ff16590 --- /dev/null +++ b/admin/api/chart.php @@ -0,0 +1,120 @@ +) and the terminal: + * + * curl http://localhost:8088/api/chart.php?range=hour + * curl http://localhost:8088/api/chart.php?range=day + * curl http://localhost:8088/api/chart.php?range=month + * curl http://localhost:8088/api/chart.php?range=year + * + * Caching: the hour chart is never cached (live). Day/month/year are + * cached to file with TTLs to avoid expensive queries on every request. + */ + +require_once __DIR__ . '/../lib/helpers.php'; +require_once __DIR__ . '/../lib/ascii_chart.php'; + +// --- Range configuration --- +$ranges = [ + 'hour' => ['span' => 3600, 'bin' => 45, 'bins' => 80, 'ttl' => 0, 'title' => 'New Events — Last Hour'], + 'day' => ['span' => 86400, 'bin' => 1080, 'bins' => 80, 'ttl' => 3600, 'title' => 'New Events — Last 24 Hours'], + 'month' => ['span' => 2592000, 'bin' => 32400, 'bins' => 80, 'ttl' => 86400, 'title' => 'New Events — Last 30 Days'], + 'year' => ['span' => 31536000, 'bin' => 394200, 'bins' => 80, 'ttl' => 2592000, 'title' => 'New Events — Last Year'], +]; + +$range = $_GET['range'] ?? 'hour'; +if (!isset($ranges[$range])) { + http_response_code(400); + header('Content-Type: text/plain; charset=utf-8'); + echo "Invalid range. Use: hour, day, month, or year.\n"; + exit; +} + +$cfg = $ranges[$range]; + +// --- Set content type --- +header('Content-Type: text/plain; charset=utf-8'); + +// --- Check cache --- +if ($cfg['ttl'] > 0) { + $cached = get_cached_chart($range, $cfg['ttl']); + if ($cached !== null) { + echo $cached; + exit; + } +} + +// --- Run binning query --- +$pdo = db(); +$now = time(); +$epoch = $now - $cfg['span']; +$bin_size = $cfg['bin']; +$num_bins = $cfg['bins']; + +try { + // Calculate the bin offset so the rightmost bin aligns with "now" + // bin index 0 = oldest, bin index (num_bins-1) = newest + $base_bin = (int)floor($epoch / $bin_size); + + $sql = "SELECT FLOOR(created_at / {$bin_size})::BIGINT - {$base_bin} AS bin, COUNT(*) AS cnt + FROM events + WHERE created_at >= {$epoch} + GROUP BY bin + ORDER BY bin"; + $rows = $pdo->query($sql)->fetchAll(); +} catch (PDOException $e) { + echo "Chart query failed: " . $e->getMessage() . "\n"; + exit; +} + +// --- Build bin array (zero-filled, fixed length) --- +// Index 0 = oldest, index N-1 = newest (natural time order from SQL) +$bins = build_bin_array($rows, $num_bins); + +// Reverse so newest bin is at index 0 (leftmost) and oldest at right. +// This matches the original text_graph.js display: new data enters +// from the left and proceeds rightward as it ages. +$bins = array_reverse($bins); + +// --- Render ASCII chart --- +$ascii = render_ascii_chart($bins, [ + 'title' => $cfg['title'], + 'max_height' => 11, + 'bin_duration' => $bin_size, + 'label_interval' => max(1, (int)floor($num_bins / 15)), // ~15 labels across +]); + +// --- Write to cache (if TTL > 0) --- +if ($cfg['ttl'] > 0) { + set_cached_chart($range, $ascii); +} + +echo $ascii; + + +// ================================ +// CACHE HELPERS +// ================================ + +function get_cache_dir(): string { + return __DIR__ . '/../cache'; +} + +function get_cached_chart(string $range, int $ttl): ?string { + $file = get_cache_dir() . "/chart_{$range}.txt"; + if (!file_exists($file)) return null; + if (filemtime($file) < (time() - $ttl)) return null; + $content = @file_get_contents($file); + return ($content !== false) ? $content : null; +} + +function set_cached_chart(string $range, string $ascii): void { + $dir = get_cache_dir(); + if (!is_dir($dir)) { + @mkdir($dir, 0775, true); + } + @file_put_contents($dir . "/chart_{$range}.txt", $ascii); +} diff --git a/admin/api/config.php b/admin/api/config.php new file mode 100644 index 0000000..423b3d8 --- /dev/null +++ b/admin/api/config.php @@ -0,0 +1,20 @@ + 'Missing key']); + try { + $pdo->prepare("UPDATE config SET value = ? WHERE key = ?")->execute([$value, $key]); + json_response(['message' => "Updated $key"]); + } catch (PDOException $e) { + json_response(['error' => $e->getMessage()]); + } +} + +$rows = $pdo->query("SELECT key, value FROM config ORDER BY key")->fetchAll(); +json_response(['config' => $rows]); diff --git a/admin/api/dm.php b/admin/api/dm.php new file mode 100644 index 0000000..9b27d08 --- /dev/null +++ b/admin/api/dm.php @@ -0,0 +1,16 @@ +prepare("SELECT id, pubkey, kind, created_at, content FROM events WHERE kind IN (4, 14, 15) ORDER BY created_at DESC LIMIT $limit"); +$rows->execute(); +$messages = $rows->fetchAll(); + +foreach ($messages as &$m) { + $m['created_at'] = date('Y-m-d H:i:s', intval($m['created_at'])); + $m['content'] = substr($m['content'] ?? '', 0, 300); +} + +json_response(['messages' => $messages]); diff --git a/admin/api/events.php b/admin/api/events.php new file mode 100644 index 0000000..d7f7dde --- /dev/null +++ b/admin/api/events.php @@ -0,0 +1,32 @@ +prepare("SELECT e.id, e.pubkey, e.kind, e.created_at, e.content, + p.name, p.display_name + FROM events e + LEFT JOIN profiles p ON p.pubkey = e.pubkey + $where_sql + ORDER BY e.created_at DESC LIMIT $limit OFFSET $offset"); +$rows->execute($params); +$events = $rows->fetchAll(); + +foreach ($events as &$e) { + $e['created_at'] = date('Y-m-d H:i:s', intval($e['created_at'])); + $e['content'] = substr($e['content'] ?? '', 0, 200); + // Resolve display name from profiles cache; fall back to truncated pubkey. + $best = profile_display_name($e); + $e['display_name'] = $best !== '' ? $best : substr($e['pubkey'] ?? '', 0, 16) . '…'; +} + +json_response(['events' => $events]); diff --git a/admin/api/ipbans.php b/admin/api/ipbans.php new file mode 100644 index 0000000..5e670ae --- /dev/null +++ b/admin/api/ipbans.php @@ -0,0 +1,35 @@ +prepare("INSERT INTO ip_bans (ip, banned_until, ban_count) VALUES (?, ?, 1) ON CONFLICT (ip) DO UPDATE SET banned_until = ?, ban_count = ip_bans.ban_count + 1")->execute([$input['ip'], $until, $until]); + json_response(['message' => 'IP banned']); + } elseif ($action === 'remove') { + $pdo->prepare("DELETE FROM ip_bans WHERE ip = ?")->execute([$input['ip']]); + json_response(['message' => 'Ban removed']); + } + } catch (PDOException $e) { json_response(['error' => $e->getMessage()]); } +} + +$now = time(); +$total = 0; $active = 0; $issued = 0; +$bans = []; +try { + $total = intval($pdo->query("SELECT count(*) FROM ip_bans")->fetchColumn()); + $active = intval($pdo->query("SELECT count(*) FROM ip_bans WHERE banned_until > $now")->fetchColumn()); + $issued = intval($pdo->query("SELECT COALESCE(sum(ban_count),0) FROM ip_bans")->fetchColumn()); + $bans = $pdo->query("SELECT ip, banned_until, ban_count, failures, authed_successfully, connection_attempts FROM ip_bans ORDER BY banned_until DESC LIMIT 100")->fetchAll(); + foreach ($bans as &$b) { + $b['status'] = intval($b['banned_until']) > $now ? 'banned' : 'expired'; + $b['banned_until'] = date('Y-m-d H:i:s', intval($b['banned_until'])); + } +} catch (PDOException $e) {} + +json_response(['total' => $total, 'active' => $active, 'issued' => $issued, 'bans' => $bans]); diff --git a/admin/api/profile.php b/admin/api/profile.php new file mode 100644 index 0000000..e28a9f9 --- /dev/null +++ b/admin/api/profile.php @@ -0,0 +1,38 @@ + + * Returns: { "pubkey": "...", "name": "...", "display_name": "...", + * "best_name": "...", "picture": "...", "nip05": "...", + * "about": "...", "website": "...", "lud16": "..." } + * or { "error": "not found" } with HTTP 404 if no profile is cached. + */ +require_once __DIR__ . '/../lib/helpers.php'; + +$pubkey = trim($_GET['pubkey'] ?? ''); +if (!preg_match('/^[0-9a-fA-F]{64}$/', $pubkey)) { + http_response_code(400); + json_response(['error' => 'Invalid pubkey']); +} + +$pdo = db(); +try { + $stmt = $pdo->prepare( + "SELECT pubkey, name, display_name, about, picture, banner, + nip05, website, lud16, lud06 + FROM profiles WHERE pubkey = ?" + ); + $stmt->execute([$pubkey]); + $row = $stmt->fetch(); + if (!$row) { + http_response_code(404); + json_response(['error' => 'not found']); + } + $row['best_name'] = profile_display_name($row); + json_response($row); +} catch (PDOException $e) { + http_response_code(500); + json_response(['error' => 'Database error']); +} diff --git a/admin/api/query.php b/admin/api/query.php new file mode 100644 index 0000000..6228713 --- /dev/null +++ b/admin/api/query.php @@ -0,0 +1,24 @@ + 'POST only']); +} + +$input = json_decode(file_get_contents('php://input'), true); +$sql = trim($input['sql'] ?? ''); + +if (!$sql) json_response(['error' => 'No query provided']); +if (!preg_match('/^\s*SELECT/i', $sql)) json_response(['error' => 'Only SELECT queries are allowed']); + +$start = microtime(true); +try { + $stmt = $pdo->query($sql); + $rows = $stmt->fetchAll(); + $time_ms = round((microtime(true) - $start) * 1000, 1); + json_response(['rows' => $rows, 'row_count' => count($rows), 'time_ms' => $time_ms]); +} catch (PDOException $e) { + json_response(['error' => $e->getMessage()]); +} diff --git a/admin/api/stats.php b/admin/api/stats.php new file mode 100644 index 0000000..cad2b9a --- /dev/null +++ b/admin/api/stats.php @@ -0,0 +1,154 @@ +query("SELECT pg_database_size(current_database())")->fetchColumn(); + $db_size = format_bytes(intval($bytes)); +} catch (PDOException $e) {} + +// Total events +$total_events = intval($pdo->query("SELECT COUNT(*) FROM events")->fetchColumn()); + +// Event rate: events with first_seen in last 10 seconds +$events_delta = 0; +try { + $events_delta = intval($pdo->query("SELECT COUNT(*) FROM events WHERE first_seen >= EXTRACT(EPOCH FROM NOW())::BIGINT - 10")->fetchColumn()); +} catch (PDOException $e) {} + +// Process info (from pg_stat_activity) +$process_id = '-'; +$ws_connections = '-'; +try { + $pid = $pdo->query("SELECT pg_backend_pid()")->fetchColumn(); + $process_id = strval($pid); + $ws_connections = intval($pdo->query("SELECT count(*) FROM pg_stat_activity WHERE state = 'active' AND pid != pg_backend_pid()")->fetchColumn()); +} catch (PDOException $e) {} + +// Active subscriptions +$active_subscriptions = 0; +try { + $active_subscriptions = intval($pdo->query("SELECT count(*) FROM subscriptions WHERE active = true")->fetchColumn()); +} catch (PDOException $e) {} + +// Memory/CPU (from /proc on Linux) +$memory_usage = '-'; +$cpu_usage = '-'; +$cpu_core = '-'; +if (is_readable('/proc/meminfo')) { + $mem = parse_ini_file('/proc/meminfo'); + $total = intval($mem['MemTotal'] ?? 0) * 1024; + $avail = intval($mem['MemAvailable'] ?? 0) * 1024; + if ($total > 0) $memory_usage = format_bytes($total - $avail) . ' / ' . format_bytes($total); +} +if (is_readable('/proc/cpuinfo')) { + $cores = intval(shell_exec('nproc 2>/dev/null') ?: 1); + $cpu_core = strval($cores) . ' cores'; +} +$cpu_usage = @file_get_contents('/proc/loadavg'); +if ($cpu_usage !== false) $cpu_usage = trim(explode(' ', $cpu_usage)[0] ?? '-'); + +// Oldest / newest event +$oldest_event = '-'; +$newest_event = '-'; +try { + $oldest = $pdo->query("SELECT to_timestamp(MIN(created_at)) FROM events")->fetchColumn(); + $newest = $pdo->query("SELECT to_timestamp(MAX(created_at)) FROM events")->fetchColumn(); + if ($oldest) $oldest_event = substr($oldest, 0, 19); + if ($newest) $newest_event = substr($newest, 0, 19); +} catch (PDOException $e) {} + +// Time-based stats +$now = time(); +$events_24h = 0; $events_7d = 0; $events_30d = 0; +try { + $events_24h = intval($pdo->query("SELECT COUNT(*) FROM events WHERE created_at >= $now - 86400")->fetchColumn()); + $events_7d = intval($pdo->query("SELECT COUNT(*) FROM events WHERE created_at >= $now - 604800")->fetchColumn()); + $events_30d = intval($pdo->query("SELECT COUNT(*) FROM events WHERE created_at >= $now - 2592000")->fetchColumn()); +} catch (PDOException $e) {} + +// Kind distribution +$kinds = []; +try { + $rows = $pdo->query("SELECT kind, COUNT(*) AS cnt FROM events GROUP BY kind ORDER BY cnt DESC LIMIT 20")->fetchAll(); + foreach ($rows as $r) { + $kinds[] = ['kind' => intval($r['kind']), 'count' => intval($r['cnt']), 'pct' => $total_events > 0 ? round(intval($r['cnt']) / $total_events * 100, 1) : 0]; + } +} catch (PDOException $e) {} + +// Top pubkeys (with names from profiles cache) +$top_pubkeys = []; +try { + $rows = $pdo->query(" + SELECT pubkey, COUNT(*) AS cnt + FROM events + GROUP BY pubkey + ORDER BY cnt DESC LIMIT 20 + ")->fetchAll(); + // Batch-resolve profile names from the profiles cache table. + $pubkeys = array_column($rows, 'pubkey'); + $pmap = profile_map($pubkeys); + foreach ($rows as $r) { + $pk = $r['pubkey']; + $prof = $pmap[$pk] ?? null; + $top_pubkeys[] = [ + 'pubkey' => $pk, + 'name' => $prof ? $prof['best_name'] : '', + 'count' => intval($r['cnt']), + 'pct' => $total_events > 0 ? round(intval($r['cnt']) / $total_events * 100, 1) : 0, + ]; + } +} catch (PDOException $e) {} + +// Name-field usage stats (from profiles cache) +$name_field_usage = ['both' => 0, 'name_only' => 0, 'display_only' => 0, 'neither' => 0, 'both_differ' => 0, 'total' => 0]; +try { + $row = $pdo->query(" + SELECT count(*) FILTER (WHERE name <> '' AND display_name <> '') AS both, + count(*) FILTER (WHERE name <> '' AND display_name = '') AS name_only, + count(*) FILTER (WHERE name = '' AND display_name <> '') AS display_only, + count(*) FILTER (WHERE name = '' AND display_name = '') AS neither, + count(*) FILTER (WHERE name <> '' AND display_name <> '' AND name <> display_name) AS both_differ, + count(*) AS total + FROM profiles + ")->fetch(); + if ($row) { + $name_field_usage = array_map('intval', $row); + } +} catch (PDOException $e) {} + +json_response([ + 'db_size' => $db_size, + 'total_events' => $total_events, + 'events_delta' => $events_delta, + 'process_id' => $process_id, + 'ws_connections' => $ws_connections, + 'active_subscriptions' => $active_subscriptions, + 'memory_usage' => $memory_usage, + 'cpu_usage' => $cpu_usage, + 'cpu_core' => $cpu_core, + 'oldest_event' => $oldest_event, + 'newest_event' => $newest_event, + 'events_24h' => $events_24h, + 'events_7d' => $events_7d, + 'events_30d' => $events_30d, + 'kinds' => $kinds, + 'top_pubkeys' => $top_pubkeys, + 'name_field_usage' => $name_field_usage, +]); + +/** Format bytes as human-readable. */ +function format_bytes(int $bytes): string { + if ($bytes < 1024) return $bytes . ' B'; + if ($bytes < 1048576) return round($bytes / 1024, 1) . ' KB'; + if ($bytes < 1073741824) return round($bytes / 1048576, 1) . ' MB'; + return round($bytes / 1073741824, 2) . ' GB'; +} diff --git a/admin/api/status.php b/admin/api/status.php deleted file mode 100644 index 897df67..0000000 --- a/admin/api/status.php +++ /dev/null @@ -1,69 +0,0 @@ -query("SELECT * FROM caching_service_state WHERE id = 1")->fetch(); - -// Active backfill target (table may not exist yet on fresh start) -$active = ['active_pubkey' => '', 'active_relay' => '']; -try { - $active = $pdo->query("SELECT active_pubkey, active_relay FROM caching_backfill_active WHERE id = 1")->fetch() ?: $active; -} catch (PDOException $e) { /* table doesn't exist yet */ } - -// Error relay summary (consecutive_errors column may not exist yet on fresh start) -$error_stats = ['auto_completed' => 0, 'error_count' => 0, 'timeout_count' => 0]; -try { - $error_stats = $pdo->query(" - SELECT - COUNT(*) FILTER (WHERE consecutive_errors >= 3) AS auto_completed, - COUNT(*) FILTER (WHERE last_status LIKE 'error%') AS error_count, - COUNT(*) FILTER (WHERE last_status = 'timeout') AS timeout_count - FROM caching_backfill_relay_progress - ")->fetch() ?: $error_stats; -} catch (PDOException $e) { /* column/table doesn't exist yet */ } - -// Inbox stats -$inbox = $pdo->query(" - SELECT - COUNT(*) AS pending, - COUNT(*) FILTER (WHERE source_class = 'live') AS live, - COUNT(*) FILTER (WHERE source_class = 'backfill') AS backfill - FROM caching_event_inbox -")->fetch(); - -// Event count -$events = $pdo->query("SELECT COUNT(*) AS total FROM events")->fetch(); - -// Heartbeat age -$hb_age = intval($state['heartbeat_at'] ?? 0); -$hb_ago = $hb_age > 0 ? time() - $hb_age : 0; - -json_response([ - 'service_state' => $state['service_state'] ?? 'unknown', - 'heartbeat_ago' => $hb_ago > 0 ? $hb_ago . 's ago' : 'never', - 'config_generation' => intval($state['config_generation'] ?? 0), - 'followed_count' => intval($state['followed_author_count'] ?? 0), - 'selected_relays' => intval($state['selected_relay_count'] ?? 0), - 'connected_relays' => intval($state['connected_relay_count'] ?? 0), - 'bf_complete' => intval($state['backfill_authors_complete'] ?? 0), - 'bf_total' => intval($state['backfill_authors_total'] ?? 0), - 'events_fetched' => intval($state['events_fetched'] ?? 0), - 'inbox_inserts' => intval($state['inbox_inserts'] ?? 0), - 'db_events' => intval($events['total'] ?? 0), - 'inbox_pending' => intval($inbox['pending'] ?? 0), - 'inbox_live' => intval($inbox['live'] ?? 0), - 'inbox_backfill' => intval($inbox['backfill'] ?? 0), - 'error_count' => intval($error_stats['error_count'] ?? 0), - 'timeout_count' => intval($error_stats['timeout_count'] ?? 0), - 'auto_completed' => intval($error_stats['auto_completed'] ?? 0), - 'active_pubkey' => $active['active_pubkey'] ?? '', - 'active_relay' => $active['active_relay'] ?? '', -]); diff --git a/admin/api/subscriptions.php b/admin/api/subscriptions.php new file mode 100644 index 0000000..471875b --- /dev/null +++ b/admin/api/subscriptions.php @@ -0,0 +1,11 @@ +query("SELECT id, sub_id, pubkey, filters, created_at, events_sent FROM subscriptions ORDER BY created_at DESC LIMIT 100")->fetchAll(); +} catch (PDOException $e) {} + +json_response(['subscriptions' => $subs]); diff --git a/admin/assets/app.js b/admin/assets/app.js new file mode 100644 index 0000000..6fac216 --- /dev/null +++ b/admin/assets/app.js @@ -0,0 +1,952 @@ +/* + * admin2 — Full PHP admin for C-Relay-PG. + * Replaces the 7457-line api/index.js with a lightweight AJAX-based + * controller that fetches data from PHP API endpoints (api/*.php) + * instead of Nostr WebSocket admin commands. + */ + +const REFRESH_MS = 10000; +let currentPage = 'statistics'; +let statsInterval = null; + +// HTML-escape helper for safe interpolation into innerHTML. +// Prevents stored XSS from user-controlled data (profile names, event +// content, config values, etc.) being parsed as HTML by the browser. +const esc = (s) => { + const str = String(s ?? ''); + return str.replace(/[&<>"']/g, (ch) => { + return '&#' + ch.charCodeAt(0) + ';'; + }); +}; + +// Auth state +let nlLite = null; +let userPubkey = null; +let isLoggedIn = false; +let relayAnimationTimer = null; + +// Server-rendered ASCII chart state +let currentChartRange = 'hour'; +let chartLoadTimer = null; + +// ================================ +// NAVIGATION +// ================================ + +function toggleNav() { + document.getElementById('side-nav').classList.toggle('open'); + document.getElementById('side-nav-overlay').classList.toggle('show'); +} + +document.getElementById('side-nav-overlay')?.addEventListener('click', toggleNav); + +document.querySelectorAll('.nav-item').forEach(btn => { + btn.addEventListener('click', () => { + const page = btn.getAttribute('data-page'); + switchPage(page); + document.getElementById('side-nav').classList.remove('open'); + document.getElementById('side-nav-overlay').classList.remove('show'); + }); +}); + +function switchPage(pageName) { + currentPage = pageName; + document.querySelectorAll('.nav-item').forEach(item => { + item.classList.remove('active'); + if (item.getAttribute('data-page') === pageName) item.classList.add('active'); + }); + + const sections = [ + 'databaseStatisticsSection', 'subscriptionDetailsSection', 'div_config', + 'authRulesSection', 'wotSection', 'ipBansSection', 'relayEventsSection', + 'cachingSection', 'nip17DMSection', 'sqlQuerySection' + ]; + sections.forEach(id => { const el = document.getElementById(id); if (el) el.style.display = 'none'; }); + + const pageMap = { + 'statistics': 'databaseStatisticsSection', + 'subscriptions': 'subscriptionDetailsSection', + 'configuration': 'div_config', + 'ip-bans': 'ipBansSection', + 'relay-events': 'relayEventsSection', + 'caching': 'cachingSection', + 'dm': 'nip17DMSection', + 'database': 'sqlQuerySection' + }; + + if (pageName === 'authorization') { + document.getElementById('authRulesSection').style.display = 'block'; + document.getElementById('wotSection').style.display = 'block'; + loadAuthRules(); + loadWotStatus(); + } else { + const target = pageMap[pageName]; + if (target) document.getElementById(target).style.display = 'block'; + } + + // Load data for the page + const loaders = { + 'statistics': loadStats, + 'subscriptions': loadSubscriptions, + 'configuration': loadConfig, + 'ip-bans': loadIpBans, + 'relay-events': loadEvents, + 'caching': loadCaching, + 'dm': loadDMs, + }; + if (loaders[pageName]) loaders[pageName](); + + // Start/stop auto-refresh for statistics + if (pageName === 'statistics') { + if (!statsInterval) { + loadStats(); + statsInterval = setInterval(loadStats, REFRESH_MS); + console.log('[admin2] auto-refresh started, interval:', REFRESH_MS, 'ms'); + } + } else { + if (statsInterval) { clearInterval(statsInterval); statsInterval = null; } + } +} + +// ================================ +// STATISTICS +// ================================ + +async function loadStats() { + console.log('[admin2] loading stats at', new Date().toLocaleTimeString()); + // Fire the RELAY letter animation on every refresh — visual indicator the page is updating + startRelayAnimation(); + try { + const res = await fetch('api/stats.php'); + if (!res.ok) { console.warn('[admin2] stats.php returned', res.status); return; } + const d = await res.json(); + console.log('[admin2] stats loaded — events:', d.total_events, 'rate:', d.events_delta, '/10s'); + + const set = (id, val) => { const el = document.getElementById(id); if (el) el.textContent = val; }; + set('db-size', d.db_size || '-'); + set('total-events', (d.total_events ?? 0).toLocaleString()); + set('process-id', d.process_id || '-'); + set('websocket-connections', d.ws_connections ?? '-'); + set('active-subscriptions', d.active_subscriptions ?? '-'); + set('memory-usage', d.memory_usage || '-'); + set('cpu-usage', d.cpu_usage || '-'); + set('cpu-core', d.cpu_core || '-'); + set('oldest-event', d.oldest_event || '-'); + set('newest-event', d.newest_event || '-'); + set('events-24h', (d.events_24h ?? 0).toLocaleString()); + set('events-7d', (d.events_7d ?? 0).toLocaleString()); + set('events-30d', (d.events_30d ?? 0).toLocaleString()); + + // Kind distribution + if (d.kinds) { + const tbody = document.getElementById('stats-kinds-table-body'); + tbody.innerHTML = d.kinds.map(k => + `${k.kind}${k.count.toLocaleString()}${k.pct}%` + ).join(''); + } + + // Top pubkeys + if (d.top_pubkeys) { + const tbody = document.getElementById('stats-pubkeys-table-body'); + tbody.innerHTML = d.top_pubkeys.map((p, i) => + `${i+1}${esc(p.name) || 'unknown'}${esc(p.pubkey.substring(0,16))}…${p.count.toLocaleString()}${p.pct}%` + ).join(''); + } + + // Name-field usage stats (from profiles cache) + if (d.name_field_usage && d.name_field_usage.total > 0) { + const u = d.name_field_usage; + const el = document.getElementById('name-field-usage'); + if (el) { + el.innerHTML = ` +
+ Profile name fields (${u.total} profiles): + Both: ${u.both} + name only: ${u.name_only} + display_name only: ${u.display_only} + Differ: ${u.both_differ} +
`; + } + } + + // Refresh the chart on every stats poll (server handles caching for non-hour ranges) + loadChart(currentChartRange); + } catch (e) { console.error('[admin2] stats error:', e); } +} + +// ================================ +// EVENT RATE CHART (server-rendered ASCII via chart.php) +// ================================ + +// Fetch the ASCII chart from the server and inject it into the div. +// The chart is rendered server-side as plain text — works in both +// browser and terminal (curl http://localhost:8088/api/chart.php?range=hour) +async function loadChart(range) { + const el = document.getElementById('event-rate-chart'); + if (!el) return; + try { + const res = await fetch('api/chart.php?range=' + encodeURIComponent(range)); + if (!res.ok) { el.textContent = 'Chart load failed (HTTP ' + res.status + ')'; return; } + const text = await res.text(); + el.textContent = text; + // Newest data is at the left (index 0) — scroll to start so it's visible + el.scrollLeft = 0; + } catch (e) { + console.error('[admin2] chart load error:', e); + el.textContent = 'Chart load error: ' + e.message; + } +} + +// Chart range tab click handlers +document.querySelectorAll('.chart-tab').forEach(tab => { + tab.addEventListener('click', () => { + const range = tab.getAttribute('data-range'); + if (!range || range === currentChartRange) return; + currentChartRange = range; + document.querySelectorAll('.chart-tab').forEach(t => t.classList.remove('active')); + tab.classList.add('active'); + loadChart(range); + }); +}); + +// ================================ +// SUBSCRIPTIONS +// ================================ + +async function loadSubscriptions() { + try { + const res = await fetch('api/subscriptions.php'); + const d = await res.json(); + const tbody = document.getElementById('subscription-details-table-body'); + if (!d.subscriptions || d.subscriptions.length === 0) { + tbody.innerHTML = 'No subscriptions active'; + return; + } + tbody.innerHTML = d.subscriptions.map(s => + `${esc(s.sub_id) || '-'}${esc((s.pubkey||'-').substring(0,16))}${esc(s.filters) || '-'}${esc(s.created) || '-'}${s.events_sent ?? 0}` + ).join(''); + } catch (e) { console.error('[admin2] subscriptions error:', e); } +} + +// ================================ +// CONFIGURATION +// ================================ + +async function loadConfig() { + try { + const res = await fetch('api/config.php'); + const d = await res.json(); + const tbody = document.getElementById('config-table-body'); + if (!d.config || d.config.length === 0) { + tbody.innerHTML = 'No config entries'; + return; + } + tbody.innerHTML = d.config.map(c => + `${esc(c.key)}${esc(c.value)}` + ).join(''); + } catch (e) { console.error('[admin2] config error:', e); } +} + +function editConfig(key) { + const newVal = prompt('Enter new value for ' + key + ':'); + if (newVal === null) return; + fetch('api/config.php', { + method: 'POST', + headers: {'Content-Type': 'application/json'}, + body: JSON.stringify({key, value: newVal}) + }).then(r => r.json()).then(d => { + alert(d.message || 'Saved'); + loadConfig(); + }).catch(e => alert('Error: ' + e)); +} + +// ================================ +// AUTH RULES +// ================================ + +async function loadAuthRules() { + try { + const res = await fetch('api/auth.php'); + const d = await res.json(); + const tbody = document.getElementById('authRulesTableBody'); + if (!d.rules || d.rules.length === 0) { + tbody.innerHTML = 'No auth rules'; + return; + } + tbody.innerHTML = d.rules.map(r => + `${esc(r.rule_type)}${esc(r.pattern_type)}${esc(r.pattern_value)}${esc(r.status) || 'active'}` + ).join(''); + } catch (e) { console.error('[admin2] auth error:', e); } +} + +async function addAuthRule(type) { + const pk = document.getElementById('authRulePubkey').value.trim(); + if (!pk) { alert('Enter a pubkey first'); return; } + const res = await fetch('api/auth.php', { + method: 'POST', + headers: {'Content-Type': 'application/json'}, + body: JSON.stringify({action: 'add', rule_type: type, pattern_value: pk}) + }); + const d = await res.json(); + alert(d.message || 'Done'); + loadAuthRules(); +} + +async function removeAuthRule(id) { + const res = await fetch('api/auth.php', { + method: 'POST', + headers: {'Content-Type': 'application/json'}, + body: JSON.stringify({action: 'remove', id}) + }); + const d = await res.json(); + alert(d.message || 'Done'); + loadAuthRules(); +} + +// ================================ +// WEB OF TRUST +// ================================ + +async function loadWotStatus() { + try { + const res = await fetch('api/auth.php?action=wot'); + const d = await res.json(); + const ind = document.getElementById('wotKind3Indicator'); + if (ind) ind.textContent = d.kind3_status || 'Unknown'; + const cnt = document.getElementById('wotWhitelistCount'); + if (cnt) cnt.textContent = d.whitelist_count ?? '—'; + const desc = document.getElementById('wotLevelDescription'); + if (desc) desc.textContent = d.level_description || ''; + } catch (e) { console.error('[admin2] wot error:', e); } +} + +async function setWotLevel(level) { + const res = await fetch('api/auth.php', { + method: 'POST', + headers: {'Content-Type': 'application/json'}, + body: JSON.stringify({action: 'set_wot_level', level}) + }); + const d = await res.json(); + alert(d.message || 'Done'); + loadWotStatus(); +} + +async function syncWot() { + const res = await fetch('api/auth.php', { + method: 'POST', + headers: {'Content-Type': 'application/json'}, + body: JSON.stringify({action: 'sync_wot'}) + }); + const d = await res.json(); + alert(d.message || 'Done'); + loadWotStatus(); +} + +// ================================ +// IP BANS +// ================================ + +async function loadIpBans() { + try { + const res = await fetch('api/ipbans.php'); + const d = await res.json(); + document.getElementById('ip-bans-total').textContent = d.total ?? '-'; + document.getElementById('ip-bans-active').textContent = d.active ?? '-'; + document.getElementById('ip-bans-issued').textContent = d.issued ?? '-'; + const tbody = document.getElementById('ip-bans-tbody'); + if (!d.bans || d.bans.length === 0) { + tbody.innerHTML = 'No IP bans'; + return; + } + tbody.innerHTML = d.bans.map(b => + `${esc(b.ip)}${esc(b.status)}${esc(b.banned_until)}${b.failures ?? 0}` + ).join(''); + } catch (e) { console.error('[admin2] ipbans error:', e); } +} + +async function addBan() { + const ip = document.getElementById('ban-ip-input').value.trim(); + const duration = document.getElementById('ban-duration-select').value; + if (!ip) { alert('Enter an IP address'); return; } + const res = await fetch('api/ipbans.php', { + method: 'POST', + headers: {'Content-Type': 'application/json'}, + body: JSON.stringify({action: 'add', ip, duration: parseInt(duration)}) + }); + const d = await res.json(); + document.getElementById('add-ban-status').textContent = d.message || 'Done'; + loadIpBans(); +} + +async function removeBan(ip) { + const res = await fetch('api/ipbans.php', { + method: 'POST', + headers: {'Content-Type': 'application/json'}, + body: JSON.stringify({action: 'remove', ip}) + }); + const d = await res.json(); + alert(d.message || 'Done'); + loadIpBans(); +} + +// ================================ +// RELAY EVENTS +// ================================ + +async function loadEvents() { + try { + const res = await fetch('api/events.php?limit=50'); + const d = await res.json(); + const tbody = document.getElementById('live-relay-events-table-body'); + if (!d.events || d.events.length === 0) { + tbody.innerHTML = 'No events'; + return; + } + tbody.innerHTML = d.events.map(e => + `${esc(e.created_at)}${e.kind}${esc(e.display_name || (e.pubkey||'').substring(0,16) + '…')}${esc((e.id||'').substring(0,16))}…${esc((e.content||'').substring(0,80))}` + ).join(''); + } catch (err) { console.error('[admin2] events error:', err); } +} + +// ================================ +// CACHING +// ================================ + +async function loadCaching() { + try { + const res = await fetch('api/caching.php'); + const d = await res.json(); + // Config toggle state + if (d.config) { + const enabled = d.config.caching_enabled === 'true'; + const inboxEnabled = d.config.caching_inbox_enabled === 'true'; + const enLabel = document.getElementById('caching-enabled-label'); + const enBtn = document.getElementById('caching-toggle-btn'); + const inLabel = document.getElementById('caching-inbox-enabled-label'); + const inBtn = document.getElementById('caching-inbox-toggle-btn'); + if (enLabel) enLabel.textContent = 'Caching: ' + (enabled ? 'ON' : 'OFF'); + if (enBtn) enBtn.textContent = enabled ? 'Turn OFF' : 'Turn ON'; + if (inLabel) inLabel.textContent = 'Inbox: ' + (inboxEnabled ? 'ON' : 'OFF'); + if (inBtn) inBtn.textContent = inboxEnabled ? 'Turn OFF' : 'Turn ON'; + } + // Service status + const ssEl = document.getElementById('caching-service-status'); + if (ssEl && d.state) { + const s = d.state; + const hb = s.heartbeat_at ? new Date(s.heartbeat_at * 1000).toLocaleTimeString() : '—'; + ssEl.innerHTML = `

State: ${esc(s.service_state)} | Follows: ${s.followed_author_count ?? 0} | Connected relays: ${s.connected_relay_count ?? 0}/${s.selected_relay_count ?? 0} | Backfill: ${s.backfill_authors_complete ?? 0}/${s.backfill_authors_total ?? 0} | Events fetched: ${s.events_fetched ?? 0} | Inbox inserts: ${s.inbox_inserts ?? 0} | Heartbeat: ${hb}

`; + } + // Inbox status + const isEl = document.getElementById('caching-inbox-status'); + if (isEl && d.inbox) { + isEl.innerHTML = `

Pending: ${d.inbox.pending} | Live: ${d.inbox.live} | Backfill: ${d.inbox.backfill}

`; + } + // Follows table + const tbody = document.getElementById('caching-follows-table-body'); + if (tbody && d.follows) { + if (d.follows.length === 0) { + tbody.innerHTML = 'No followed pubkeys'; + } else { + tbody.innerHTML = d.follows.map((f, i) => { + const npub = f.npub || f.pubkey.substring(0, 20); + const relaySummary = f.relay_incomplete > 0 + ? `${f.relay_count - f.relay_incomplete}/${f.relay_count} done` + : `${f.relay_count ?? 0} relays`; + // Per-relay detail row (hidden by default, toggle via click) + let relayDetail = ''; + if (f.relays && f.relays.length > 0) { + relayDetail = '
' + + f.relays.map(r => { + const statusIcon = r.complete ? '✓' : '⏳'; + const statusBadge = r.complete + ? `${esc(r.last_status || 'eose')}` + : `${esc(r.last_status || 'pending')}`; + const relayHost = r.relay_url.replace(/^wss?:\/\//, '').replace(/\/relay$/, ''); + return `
${statusIcon}${esc(relayHost)}${r.events_fetched} evts${statusBadge}
`; + }).join('') + + '
'; + } + const refreshBtn = ``; + return `${esc(f.name) || 'unknown'}${esc(npub)}…${f.is_root ? '✓' : ''}${f.total_events ?? 0}${f.backfill_complete ? '✓' : '…'}${relaySummary}
${relayDetail || 'No relay progress data'}
${refreshBtn}
`; + }).join(''); + } + } + // Active target + const fsEl = document.getElementById('caching-follows-status'); + if (fsEl) { + if (d.active && d.active.pubkey && d.active.relay) { + fsEl.innerHTML = `⚡ Backfilling: ${d.active.pubkey.substring(0,16)}… @ ${esc(d.active.relay)}`; + } else if (d.state && d.state.service_state === 'running') { + const incomplete = d.state.backfill_authors_complete < d.state.backfill_authors_total; + fsEl.innerHTML = incomplete + ? `⚡ Backfill in progress…` + : `✓ Backfill complete — listening for live events`; + } else { + fsEl.innerHTML = `✓ Caching complete`; + } + } + } catch (e) { console.error('[admin2] caching error:', e); } +} + +// Toggle caching_enabled config via the config API. +async function toggleCachingEnabled() { + try { + const res = await fetch('api/caching.php'); + const d = await res.json(); + const current = d.config?.caching_enabled === 'true'; + const newVal = current ? 'false' : 'true'; + await fetch('api/config.php', { + method: 'POST', + headers: {'Content-Type': 'application/json'}, + body: JSON.stringify({key: 'caching_enabled', value: newVal}) + }); + loadCaching(); + } catch (e) { console.error('[admin2] toggle caching error:', e); } +} + +// Toggle caching_inbox_enabled config via the config API. +async function toggleCachingInboxEnabled() { + try { + const res = await fetch('api/caching.php'); + const d = await res.json(); + const current = d.config?.caching_inbox_enabled === 'true'; + const newVal = current ? 'false' : 'true'; + await fetch('api/config.php', { + method: 'POST', + headers: {'Content-Type': 'application/json'}, + body: JSON.stringify({key: 'caching_inbox_enabled', value: newVal}) + }); + loadCaching(); + } catch (e) { console.error('[admin2] toggle inbox error:', e); } +} + +// Re-run all caching: resets backfill progress for all followed authors and +// bumps caching_config_generation so the running service hot-reloads and +// re-drains from the beginning. +async function rerunAllCaching() { + if (!confirm('Reset backfill progress for ALL followed authors? The caching service will re-download everything from scratch.')) return; + const btn = document.getElementById('caching-rerun-all-btn'); + if (btn) { btn.disabled = true; btn.textContent = 'Resetting…'; } + try { + const res = await fetch('api/caching.php', { + method: 'POST', + headers: {'Content-Type': 'application/json'}, + body: JSON.stringify({action: 'reset_all'}) + }); + const d = await res.json(); + if (d.ok) { + if (btn) { btn.textContent = '✓ Reset — re-draining'; } + setTimeout(() => { if (btn) { btn.disabled = false; btn.textContent = 'Re-run All Caching'; } loadCaching(); }, 2000); + } else { + alert('Reset failed: ' + (d.error || 'unknown error')); + if (btn) { btn.disabled = false; btn.textContent = 'Re-run All Caching'; } + } + } catch (e) { + console.error('[admin2] rerunAllCaching error:', e); + alert('Reset failed: ' + e.message); + if (btn) { btn.disabled = false; btn.textContent = 'Re-run All Caching'; } + } +} + +// Refresh a single user: resets backfill progress for one followed author +// and bumps caching_config_generation so the service re-fetches that author. +async function refreshCachingUser(pubkey, name) { + if (!confirm('Reset backfill progress for ' + (name || pubkey.substring(0, 16) + '…') + '? The caching service will re-download this user\'s events from scratch.')) return; + try { + const res = await fetch('api/caching.php', { + method: 'POST', + headers: {'Content-Type': 'application/json'}, + body: JSON.stringify({action: 'reset_user', pubkey: pubkey}) + }); + const d = await res.json(); + if (d.ok) { + loadCaching(); + } else { + alert('Refresh failed: ' + (d.error || 'unknown error')); + } + } catch (e) { + console.error('[admin2] refreshCachingUser error:', e); + alert('Refresh failed: ' + e.message); + } +} + +// ================================ +// DMs +// ================================ + +async function loadDMs() { + try { + const res = await fetch('api/dm.php?limit=50'); + const d = await res.json(); + const el = document.getElementById('dm-inbox'); + if (!d.messages || d.messages.length === 0) { + el.innerHTML = '
No messages found.
'; + return; + } + el.innerHTML = d.messages.map(m => + `
kind ${m.kind} from ${esc((m.pubkey||'').substring(0,16))}… at ${esc(m.created_at)}:
${esc((m.content||'').substring(0,200))}
` + ).join(''); + } catch (e) { console.error('[admin2] dm error:', e); } +} + +// ================================ +// SQL QUERY +// ================================ + +async function executeQuery() { + const sql = document.getElementById('sql-input').value.trim(); + if (!sql) { alert('Enter a SQL query'); return; } + if (!sql.toUpperCase().startsWith('SELECT')) { alert('Only SELECT queries are allowed'); return; } + try { + const res = await fetch('api/query.php', { + method: 'POST', + headers: {'Content-Type': 'application/json'}, + body: JSON.stringify({sql}) + }); + const d = await res.json(); + const info = document.getElementById('query-info'); + const tableDiv = document.getElementById('query-table'); + if (d.error) { + info.textContent = 'Error: ' + d.error; + tableDiv.innerHTML = ''; + return; + } + info.textContent = `${d.row_count} rows in ${d.time_ms}ms`; + if (d.rows && d.rows.length > 0) { + const cols = Object.keys(d.rows[0]); + let html = ''; + cols.forEach(c => html += ``); + html += ''; + d.rows.forEach(r => { + html += ''; + cols.forEach(c => html += ``); + html += ''; + }); + html += '
${c}
${r[c] ?? ''}
'; + tableDiv.innerHTML = html; + } else { + tableDiv.innerHTML = '

No rows returned.

'; + } + } catch (e) { console.error('[admin2] query error:', e); } +} + +// ================================ +// DARK MODE +// ================================ + +document.getElementById('nav-dark-mode-btn')?.addEventListener('click', () => { + document.body.classList.toggle('dark-mode'); + localStorage.setItem('admin2-dark-mode', document.body.classList.contains('dark-mode')); + const btn = document.getElementById('nav-dark-mode-btn'); + if (btn) btn.textContent = document.body.classList.contains('dark-mode') ? 'LIGHT MODE' : 'DARK MODE'; +}); + +if (localStorage.getItem('admin2-dark-mode') === 'true') { + document.body.classList.add('dark-mode'); + const btn = document.getElementById('nav-dark-mode-btn'); + if (btn) btn.textContent = 'LIGHT MODE'; +} + +// ================================ +// RELAY LETTER ANIMATION +// ================================ + +// Animate the RELAY letters with an underline sweep. Fires on every stats +// refresh so the user gets a visual cue that the page is updating. +function startRelayAnimation() { + const letters = document.querySelectorAll('.relay-letter'); + if (letters.length === 0) return; + + // Cancel any in-flight animation so rapid refreshes don't overlap + if (relayAnimationTimer) { clearTimeout(relayAnimationTimer); relayAnimationTimer = null; } + + let currentIndex = 0; + letters.forEach(l => l.classList.remove('underlined')); + + function animateLetter() { + letters.forEach(letter => letter.classList.remove('underlined')); + if (letters[currentIndex]) { + letters[currentIndex].classList.add('underlined'); + } + currentIndex++; + if (currentIndex > letters.length) { + // Sweep complete — clear underlines and pause before next refresh + letters.forEach(letter => letter.classList.remove('underlined')); + relayAnimationTimer = null; + return; + } + relayAnimationTimer = setTimeout(animateLetter, 100); + } + animateLetter(); +} + +// ================================ +// RELAY PUBKEY COPY-TO-CLIPBOARD +// ================================ + +document.getElementById('relay-pubkey-container')?.addEventListener('click', async () => { + const el = document.getElementById('relay-pubkey'); + if (!el || !el.textContent.trim()) return; + try { + await navigator.clipboard.writeText(el.textContent.replace(/\s+/g, '')); + const container = document.getElementById('relay-pubkey-container'); + container.classList.add('copied'); + setTimeout(() => container.classList.remove('copied'), 500); + } catch (e) { console.warn('[admin2] clipboard copy failed:', e); } +}); + +// ================================ +// AUTH — nostr_login_lite modal +// ================================ + +const loginModal = document.getElementById('login-modal'); +const loginModalContainer = document.getElementById('login-modal-container'); +const profileArea = document.getElementById('profile-area'); +const headerUserName = document.getElementById('header-user-name'); +const headerUserImage = document.getElementById('header-user-image'); +const logoutDropdown = document.getElementById('logout-dropdown'); + +function showLoginModal() { + if (loginModal && loginModalContainer) { + if (window.NOSTR_LOGIN_LITE && typeof window.NOSTR_LOGIN_LITE.embed === 'function') { + // Clear previous embed before re-embedding + loginModalContainer.innerHTML = ''; + window.NOSTR_LOGIN_LITE.embed('#login-modal-container', { seamless: true }); + } + loginModal.style.display = 'flex'; + } +} + +function hideLoginModal() { + if (loginModal) loginModal.style.display = 'none'; +} + +function showProfileInHeader() { + if (profileArea) profileArea.style.display = 'flex'; +} + +function hideProfileFromHeader() { + if (profileArea) profileArea.style.display = 'none'; +} + +// Toggle logout dropdown when clicking the profile area +profileArea?.addEventListener('click', (e) => { + // Only toggle if the click wasn't on the logout button itself + if (e.target.closest('.logout-btn')) return; + if (logoutDropdown) { + logoutDropdown.style.display = (logoutDropdown.style.display === 'none' || !logoutDropdown.style.display) ? 'block' : 'none'; + } +}); + +// Hide logout dropdown when clicking elsewhere +document.addEventListener('click', (e) => { + if (logoutDropdown && logoutDropdown.style.display === 'block' && !e.target.closest('#profile-area')) { + logoutDropdown.style.display = 'none'; + } +}); + +// Update header profile display from logged-in user's pubkey. +// Sets a placeholder from the npub immediately, then fetches the kind 0 +// profile event from public relays to populate the name + picture. +function updateProfileDisplay(pubkey) { + if (!pubkey) return; + let npub = ''; + try { + if (pubkey.length === 64 && /^[0-9a-fA-F]+$/.test(pubkey)) { + npub = window.NostrTools.nip19.npubEncode(pubkey); + } + } catch (err) { console.warn('[admin2] npub encode failed:', err); } + + // Placeholder until the profile fetch resolves + if (headerUserName) { + headerUserName.textContent = npub ? npub.substring(0, 16) + '…' : pubkey.substring(0, 16) + '…'; + } + if (headerUserImage) headerUserImage.style.display = 'none'; + + // Fetch kind 0 profile from public relays (same approach as original api page) + loadUserProfile(pubkey, npub); +} + +// Apply profile data to the header name + profile picture. +// Uses best_name from the server (resolved per profile_name_preference). +function applyProfileToHeader(name, picture) { + if (headerUserName) headerUserName.textContent = name || 'Anonymous User'; + if (headerUserImage && picture && typeof picture === 'string' && + (picture.startsWith('http://') || picture.startsWith('https://'))) { + headerUserImage.src = picture; + headerUserImage.style.display = 'block'; + headerUserImage.onerror = function() { this.style.display = 'none'; }; + } else if (headerUserImage) { + headerUserImage.style.display = 'none'; + } +} + +// Fetch the user's profile. Tries the local profiles cache first +// (admin/api/profile.php), then falls back to public relays if the +// relay has no cached kind-0 for this pubkey. +async function loadUserProfile(pubkey, npub) { + if (!pubkey) return; + + // Try local profiles cache first. + try { + const res = await fetch('api/profile.php?pubkey=' + encodeURIComponent(pubkey)); + if (res.ok) { + const profile = await res.json(); + if (profile && profile.best_name !== undefined) { + applyProfileToHeader(profile.best_name, profile.picture); + console.log('[admin2] profile loaded from local cache for', profile.best_name); + return; + } + } + } catch (e) { + // Local endpoint not available — fall through to public relays. + } + + // Fall back to public relays. + if (!window.NostrTools || !window.NostrTools.SimplePool) { + if (headerUserName) headerUserName.textContent = npub ? npub.substring(0, 16) + '…' : 'Anonymous User'; + return; + } + const relays = [ + 'wss://relay.damus.io', + 'wss://relay.nostr.band', + 'wss://nos.lol', + 'wss://relay.primal.net', + 'wss://relay.snort.social' + ]; + try { + const pool = new window.NostrTools.SimplePool(); + const timeoutPromise = new Promise((_, reject) => + setTimeout(() => reject(new Error('Profile query timeout')), 5000) + ); + const queryPromise = pool.querySync(relays, { + kinds: [0], + authors: [pubkey], + limit: 1 + }); + const events = await Promise.race([queryPromise, timeoutPromise]); + try { await pool.close(relays); } catch (e) {} + + if (events && events.length > 0) { + const profile = JSON.parse(events[0].content); + // Use best_name resolution: display_name first, then name. + const name = profile.display_name || profile.name || profile.displayName || 'Anonymous User'; + const picture = profile.picture || profile.image || null; + applyProfileToHeader(name, picture); + console.log('[admin2] profile loaded from public relays for', name); + } else { + if (headerUserName) headerUserName.textContent = 'Anonymous User'; + console.log('[admin2] no profile event found for', pubkey); + } + } catch (err) { + console.warn('[admin2] profile load failed:', err.message); + if (headerUserName) headerUserName.textContent = npub ? npub.substring(0, 16) + '…' : 'Error loading profile'; + } +} + +// Initialize nostr_login_lite and show modal if not already authenticated +async function initializeAuth() { + if (!window.NOSTR_LOGIN_LITE) { + console.warn('[admin2] NOSTR_LOGIN_LITE not loaded — skipping auth modal'); + return; + } + try { + await window.NOSTR_LOGIN_LITE.init({ + theme: 'default', + methods: { + extension: true, + local: true, + seedphrase: true, + readonly: true, + connect: true, + remote: true, + otp: false + }, + floatingTab: { enabled: false } + }); + nlLite = window.NOSTR_LOGIN_LITE; + console.log('[admin2] nostr_login_lite initialized'); + + // Check for existing auth state + let alreadyLoggedIn = false; + try { + const stored = localStorage.getItem('nostr_login_lite_auth'); + if (stored) { + const parsed = JSON.parse(stored); + if (parsed && parsed.pubkey) { + userPubkey = parsed.pubkey; + isLoggedIn = true; + alreadyLoggedIn = true; + showProfileInHeader(); + updateProfileDisplay(userPubkey); + hideLoginModal(); + console.log('[admin2] existing auth restored for', userPubkey); + } + } + } catch (e) { /* no stored auth */ } + + if (!alreadyLoggedIn) { + console.log('[admin2] no existing auth — showing login modal'); + showLoginModal(); + } + + // Listen for auth events + window.addEventListener('nlMethodSelected', (event) => { + const { pubkey, method, error } = event.detail || {}; + if (method && pubkey) { + userPubkey = pubkey; + isLoggedIn = true; + console.log('[admin2] login success via', method, pubkey); + hideLoginModal(); + showProfileInHeader(); + updateProfileDisplay(pubkey); + } else if (error) { + console.warn('[admin2] auth error:', error); + } + }); + + window.addEventListener('nlLogout', () => { + console.log('[admin2] logout event received'); + userPubkey = null; + isLoggedIn = false; + hideProfileFromHeader(); + if (logoutDropdown) logoutDropdown.style.display = 'none'; + showLoginModal(); + }); + + } catch (err) { + console.error('[admin2] nostr_login_lite init failed:', err); + } +} + +// Logout function — clears auth state and re-shows login modal +async function logout() { + console.log('[admin2] logging out...'); + try { + if (nlLite && typeof nlLite.logout === 'function') { + await nlLite.logout(); + } + } catch (e) { console.warn('[admin2] nlLite.logout error:', e); } + userPubkey = null; + isLoggedIn = false; + hideProfileFromHeader(); + if (logoutDropdown) logoutDropdown.style.display = 'none'; + showLoginModal(); + console.log('[admin2] logged out'); +} + +// ================================ +// INIT +// ================================ + +switchPage('statistics'); + +// Start the RELAY animation immediately on page load +startRelayAnimation(); + +// Initialize auth + load initial chart on DOM ready +document.addEventListener('DOMContentLoaded', () => { + setTimeout(initializeAuth, 100); + // Load the default (hour) chart immediately + loadChart(currentChartRange); +}); diff --git a/admin/assets/index.css b/admin/assets/index.css new file mode 100644 index 0000000..ffc80ed --- /dev/null +++ b/admin/assets/index.css @@ -0,0 +1,1679 @@ +:root { + /* Core Variables (7) */ + --primary-color: #000000; + --secondary-color: #ffffff; + --accent-color: #ff0000; + --muted-color: #dddddd; + --border-color: var(--muted-color); + --font-family: "Courier New", Courier, monospace; + --border-radius: 5px; + --border-width: 1px; + + /* Floating Tab Variables (8) */ + --tab-bg-logged-out: #ffffff; + --tab-bg-logged-in: #ffffff; + --tab-bg-opacity-logged-out: 0.9; + --tab-bg-opacity-logged-in: 0.2; + --tab-color-logged-out: #000000; + --tab-color-logged-in: #ffffff; + --tab-border-logged-out: #000000; + --tab-border-logged-in: #ff0000; + --tab-border-opacity-logged-out: 1.0; + --tab-border-opacity-logged-in: 0.1; +} + +/* Dark Mode Overrides */ +body.dark-mode { + --primary-color: #ffffff; + --secondary-color: #000000; + --accent-color: #ff0000; + --muted-color: #222222; + --border-color: var(--muted-color); + + + --tab-bg-logged-out: #000000; + --tab-color-logged-out: #ffffff; + --tab-border-logged-out: #ffffff; + --tab-bg-logged-in: #000000; + --tab-color-logged-in: #ffffff; + --tab-border-logged-in: #00ffff; +} + +* { + margin: 0; + padding: 0; + box-sizing: border-box; +} + +body { + font-family: var(--font-family); + background-color: var(--secondary-color); + color: var(--primary-color); + /* line-height: 1.4; */ + padding: 0; + max-width: none; + margin: 0; +} + +/* Header Styles */ +.main-header { + background-color: var(--secondary-color); + + padding: 15px 20px; + z-index: 100; + max-width: 1200px; + margin: 0 auto; +} + +.header-content { + display: flex; + justify-content: space-between; + align-items: center; + position: relative; +} + +.header-title { + margin: 0; + font-size: 24px; + font-weight: normal; + color: var(--primary-color); + border: none; + padding: 0; + text-align: left; +} + +.relay-info { + text-align: center; + flex: 1; + max-width: 150px; + margin: 0 auto; +} + +.relay-name { + font-size: 14px; + font-weight: bold; + color: var(--primary-color); + margin-bottom: 2px; +} + +.relay-pubkey-container { + border: 1px solid transparent; + border-radius: var(--border-radius); + padding: 4px; + margin-top: 4px; + cursor: pointer; + transition: border-color 0.2s ease; + background-color: var(--secondary-color); + display: inline-block; + width: fit-content; +} + +.relay-pubkey-container:hover { + border-color: var(--border-color); +} + +.relay-pubkey-container.copied { + border-color: var(--accent-color); + animation: flash-accent 0.5s ease-in-out; +} + +.relay-pubkey { + font-size: 8px; + color: var(--primary-color); + font-family: "Courier New", Courier, monospace; + line-height: 1.2; + white-space: pre-line; + text-align: center; +} + +@keyframes flash-accent { + 0% { border-color: var(--accent-color); } + 50% { border-color: var(--accent-color); } + 100% { border-color: transparent; } +} + +.relay-description { + font-size: 10px; + color: var(--primary-color); + margin-bottom: 0; + display: inline-block; + width: fit-content; + word-wrap: break-word; + overflow-wrap: break-word; +} + +.header-title { + margin: 0; + font-size: 24px; + font-weight: bolder; + color: var(--primary-color); + border: none; + padding: 0; + text-align: left; + display: flex; + gap: 2px; +} + +.relay-letter { + position: relative; + display: inline-block; + transition: all 0.05s ease; +} + +.relay-letter.underlined::after { + content: ''; + position: absolute; + bottom: -2px; + left: 0; + right: 0; + height: 2px; + background-color: var(--accent-color); +} + +.header-user-name { + display: block; + font-weight: 500; + color: var(--primary-color); + font-size: 10px; + text-align: center; + margin-top: 4px; +} + +.profile-area { + display: flex; + flex-direction: column; + align-items: center; + position: relative; + cursor: pointer; + padding: 8px 12px; + border-radius: var(--border-radius); + transition: background-color 0.2s ease; + /* margin-left: auto; */ +} + +.admin-label { + font-size: 10px; + color: var(--primary-color); + font-weight: normal; + margin-bottom: 4px; + text-align: center; +} + +.profile-container { + display: flex; + flex-direction: column; + align-items: center; + gap: 4px; +} + +.profile-area:hover { + background-color: rgba(0, 0, 0, 0.05); +} + +.profile-info { + display: flex; + align-items: center; + gap: 10px; +} + +.header-user-image { + width: 48px; /* 50% larger than 32px */ + height: 48px; /* 50% larger than 32px */ + border-radius: var(--border-radius); /* Curved corners like other elements */ + object-fit: cover; + border: 2px solid transparent; /* Invisible border */ + background-color: var(--secondary-color); +} + + +.logout-dropdown { + position: absolute; + top: 100%; + right: 0; + background-color: var(--secondary-color); + border: var(--border-width) solid var(--border-color); + border-radius: var(--border-radius); + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15); + min-width: 120px; + z-index: 200; + margin-top: 4px; +} + +.logout-btn { + width: 100%; + padding: 5px 10px; + background: none; + border: none; + color: var(--primary-color); + text-align: left; + cursor: pointer; + font-size: 10px; + font-family: var(--font-family); + border-radius: var(--border-radius); + transition: background-color 0.2s ease; +} + +.logout-btn:hover { + background-color: rgba(0, 0, 0, 0.1); +} + +/* Login Modal Styles */ +.login-modal-overlay { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background-color: rgba(0, 0, 0, 0.8); + display: flex; + justify-content: center; + align-items: center; + z-index: 1000; +} + +.login-modal-content { + background-color: var(--secondary-color); + border: var(--border-width) solid var(--border-color); + border-radius: var(--border-radius); + padding: 30px; + max-width: 400px; + width: 90%; + box-shadow: 0 10px 30px rgba(0, 0, 0, 0.3); +} + +h1 { + border-bottom: var(--border-width) solid var(--border-color); + padding-bottom: 10px; + margin-bottom: 30px; + font-weight: bold; + font-size: 24px; + font-family: var(--font-family); + color: var(--primary-color); +} + +h2 { + font-weight: normal; + text-align: center; + font-size: 16px; + font-family: var(--font-family); + color: var(--primary-color); +} + +h3 { + font-weight: normal; + font-size: 12px; + font-family: var(--font-family); + color: var(--primary-color); + padding-bottom: 10px; +} + +label { + display: block; + margin-bottom: 5px; + font-weight: lighter; + font-size: 10px; + font-family: var(--font-family); + color: var(--primary-color); +} + + + + +.section { + background: var(--secondary-color); + border: var(--border-width) solid var(--border-color); + border-radius: var(--border-radius); + padding: 20px; + margin-bottom: 20px; + margin-left: 5px; + margin-right:5px; +} + +.section-header { + display: flex; + justify-content: center; + align-items: center; + padding-bottom: 15px; +} + + + + + +.input-group { + margin-bottom: 15px; +} + + +input, +textarea, +select { + width: 100%; + padding: 8px; + background: var(--secondary-color); + color: var(--primary-color); + border: var(--border-width) solid var(--border-color); + border-radius: var(--border-radius); + font-family: var(--font-family); + font-size: 14px; + box-sizing: border-box; + transition: all 0.2s ease; +} + +input:focus, +textarea:focus, +select:focus { + border-color: var(--accent-color); + outline: none; +} + +button { + width: 100%; + padding: 8px; + background: var(--secondary-color); + color: var(--primary-color); + border: var(--border-width) solid var(--border-color); + border-radius: var(--border-radius); + font-family: var(--font-family); + font-size: 14px; + cursor: pointer; + margin: 5px 0; + font-weight: bold; + transition: all 0.2s ease; +} + +button:hover { + border-color: var(--accent-color); +} + +button:active { + background: var(--accent-color); + color: var(--secondary-color); +} + +button:disabled { + background-color: var(--muted-color); + color: var(--primary-color); + cursor: not-allowed; + border-color: var(--muted-color); +} + +/* Flash animation for refresh button */ +@keyframes flash-red { + 0% { border-color: var(--border-color); } + 50% { border-color: var(--accent-color); } + 100% { border-color: var(--border-color); } +} + +.flash-red { + animation: flash-red 1s ease-in-out; +} + +/* Flash animation for updated statistics values */ +@keyframes flash-value { + 0% { color: var(--primary-color); } + 50% { color: var(--accent-color); } + 100% { color: var(--primary-color); } +} + +.flash-value { + animation: flash-value 1s ease-in-out; +} + +/* Npub links styling */ +.npub-link { + color: var(--primary-color); + text-decoration: none; + font-weight: normal; + transition: color 0.2s ease; +} + +.npub-link:hover { + color: var(--accent-color); +} + +.status { + padding: 10px; + margin: 10px 0; + border: var(--border-width) solid var(--border-color); + border-radius: var(--border-radius); + font-weight: bold; + font-family: var(--font-family); + transition: all 0.2s ease; +} + +.status.connected { + background-color: var(--primary-color); + color: var(--secondary-color); +} + +.status.disconnected { + background-color: var(--secondary-color); + color: var(--primary-color); +} + +.status.authenticated { + background-color: var(--primary-color); + color: var(--secondary-color); +} + +.status.error { + background-color: var(--secondary-color); + color: var(--primary-color); + border-color: var(--accent-color); +} + + +.config-table { + border: 1px solid var(--border-color); + border-radius: var(--border-radius); + width: 100%; + border-collapse: separate; + border-spacing: 0; + margin: 10px 0; + overflow: hidden; +} + +.config-table th, +.config-table td { + border: 0.1px solid var(--muted-color); + padding: 4px; + text-align: left; + font-family: var(--font-family); + font-size: 10px; +} + +.config-table tbody tr:hover { + background-color: rgba(0, 0, 0, 0.05); +} + +.config-table-container { + overflow-x: auto; + max-width: 100%; +} + +.config-table th { + font-weight: bold; + height: 24px; /* Base height for tbody rows */ + line-height: 24px; /* Center text vertically */ +} + +.config-table td { + height: 16px; /* 50% taller than tbody rows would be */ + line-height: 16px; /* Center text vertically */ +} + +/* Inline config value inputs - remove borders and padding to fit seamlessly in table cells */ +.config-value-input { + border: none; + padding: 2px 4px; + background: transparent; + width: 100%; + min-height: auto; + font-family: inherit; + font-size: inherit; + color: inherit; + border-radius: 0; +} + +/* Relay Events Styles */ +.status-message { + margin-top: 10px; + padding: 8px; + border-radius: var(--border-radius); + font-size: 14px; + font-family: var(--font-family); + text-align: center; +} + +.relay-entry { + border: var(--border-width) solid var(--border-color); + border-radius: var(--border-radius); + padding: 10px; + margin-bottom: 10px; + background: var(--secondary-color); +} + +.config-value-input:focus { + border: 1px solid var(--accent-color); + background: var(--secondary-color); + outline: none; +} + +/* Config actions cell - clickable for saving */ +.config-actions-cell { + cursor: pointer; + transition: all 0.2s ease; + text-align: center !important; + font-weight: bold; + vertical-align: middle; + width: 60px; + min-width: 60px; + max-width: 60px; + padding: 8px 4px; +} + +.config-actions-cell:hover { + border: 1px solid var(--accent-color); + background-color: var(--muted-color); +} + +.json-display { + background-color: var(--secondary-color); + border: var(--border-width) solid var(--border-color); + border-radius: var(--border-radius); + padding: 10px; + font-family: var(--font-family); + font-size: 12px; + white-space: pre-wrap; + max-height: 300px; + overflow-y: auto; + margin: 10px 0; +} + +.log-panel { + height: 200px; + overflow-y: auto; + border: var(--border-width) solid var(--border-color); + border-radius: var(--border-radius); + padding: 10px; + font-size: 12px; + background-color: var(--secondary-color); + font-family: var(--font-family); +} + +.log-entry { + margin-bottom: 5px; + border-bottom: 1px solid var(--muted-color); + padding-bottom: 5px; +} + +.log-timestamp { + font-weight: bold; + font-family: var(--font-family); +} + +.inline-buttons { + display: flex; + gap: 10px; + flex-wrap: nowrap; +} + +.inline-buttons button { + flex: 1; +} + +.user-info { + padding: 10px; + border: var(--border-width) solid var(--border-color); + border-radius: var(--border-radius); + margin: 10px 0; + background-color: var(--secondary-color); +} + +.user-info-container { + display: flex; + flex-direction: column; + gap: 15px; +} + +.user-details { + order: -1; /* Show user details first when logged in */ +} + +.login-section { + text-align: center; +} + +.logout-section { + display: flex; + justify-content: flex-end; +} + +.login-logout-btn { + width: auto; + min-width: 120px; + padding: 12px 16px; + background: var(--secondary-color); + color: var(--primary-color); + border: var(--border-width) solid var(--border-color); + border-radius: var(--border-radius); + font-family: var(--font-family); + font-size: 14px; + font-weight: bold; + cursor: pointer; + transition: all 0.2s ease; + margin: 0; + flex-shrink: 0; +} + +.login-logout-btn:hover { + border-color: var(--accent-color); +} + +.login-logout-btn:active { + background: var(--accent-color); + color: var(--secondary-color); +} + +.login-logout-btn.logout-state { + background: var(--accent-color); + color: var(--secondary-color); + border-color: var(--accent-color); +} + +.login-logout-btn.logout-state:hover { + background: var(--primary-color); + border-color: var(--border-color); +} + +.user-pubkey { + font-family: var(--font-family); + font-size: 12px; + word-break: break-all; + margin: 5px 0; +} + +/* User profile header with image */ +.user-profile-header { + display: flex; + align-items: flex-start; + gap: 15px; +} + +.user-image-container { + flex-shrink: 0; +} + +.user-profile-image { + width: 60px; + height: 60px; + border-radius: var(--border-radius); + object-fit: cover; + border: 2px solid var(--border-color); + background-color: var(--bg-color); +} + +.user-text-info { + flex: 1; + min-width: 0; /* Allow text to wrap */ +} + +.hidden { + display: none; +} + + + +.countdown-btn { + width: auto; + min-width: 40px; + padding: 8px 12px; + background: var(--secondary-color); + color: var(--primary-color); + border: var(--border-width) solid var(--border-color); + border-radius: var(--border-radius); + font-family: var(--font-family); + font-size: 10px; + /* font-weight: bold; */ + cursor: pointer; + transition: all 0.2s ease; + margin-left: auto; + position: relative; +} + +.countdown-btn:hover::after { + content: "countdown"; + position: absolute; + top: -30px; + left: 50%; + transform: translateX(-50%); + background: var(--primary-color); + color: var(--secondary-color); + padding: 4px 8px; + border-radius: 4px; + font-size: 12px; + font-weight: normal; + white-space: nowrap; + z-index: 1000; + border: 1px solid var(--border-color); +} + +.auth-rules-controls { + margin-bottom: 15px; +} + +.section-header .status { + margin: 0; + padding: 5px 10px; + min-width: auto; + font-size: 12px; +} + +/* Auth Rule Input Sections Styling */ +.auth-rule-section { + border: var(--border-width) solid var(--border-color); + border-radius: var(--border-radius); + padding: 15px; + margin: 15px 0; + background-color: var(--secondary-color); +} + +.auth-rule-section h3 { + margin: 0 0 10px 0; + font-size: 14px; + font-weight: bold; + border-left: 4px solid var(--border-color); + padding-left: 8px; + font-family: var(--font-family); + color: var(--primary-color); +} + +.auth-rule-section p { + margin: 0 0 15px 0; + font-size: 13px; + color: var(--muted-color); + font-family: var(--font-family); +} + +.rule-status { + margin-top: 10px; + padding: 8px; + border: var(--border-width) solid var(--muted-color); + border-radius: var(--border-radius); + font-size: 12px; + min-height: 20px; + background-color: var(--secondary-color); + font-family: var(--font-family); + transition: all 0.2s ease; +} + +.rule-status.success { + border-color: #4CAF50; + background-color: #E8F5E8; + color: #2E7D32; +} + +.rule-status.error { + border-color: var(--accent-color); + background-color: #FFEBEE; + color: #C62828; +} + +.rule-status.warning { + border-color: #FF9800; + background-color: #FFF3E0; + color: #E65100; +} + +.warning-box { + border: var(--border-width) solid #FF9800; + border-radius: var(--border-radius); + background-color: #FFF3E0; + padding: 10px; + margin: 10px 0; + font-size: 13px; + color: #E65100; + font-family: var(--font-family); +} + +.warning-box strong { + color: #D84315; +} + +#login-section { + text-align: center; + padding: 20px; +} + +/* Floating tab styles */ +.floating-tab { + font-family: var(--font-family); + border-radius: var(--border-radius); + border: var(--border-width) solid; + transition: all 0.2s ease; +} + +.floating-tab--logged-out { + background: rgba(255, 255, 255, var(--tab-bg-opacity-logged-out)); + color: var(--tab-color-logged-out); + border-color: rgba(0, 0, 0, var(--tab-border-opacity-logged-out)); +} + +.floating-tab--logged-in { + background: rgba(0, 0, 0, var(--tab-bg-opacity-logged-in)); + color: var(--tab-color-logged-in); + border-color: rgba(255, 0, 0, var(--tab-border-opacity-logged-in)); +} + +.transition { + transition: all 0.2s ease; +} + +/* SQL Query Interface Styles */ +.query-selector { + margin-bottom: 15px; +} + +.query-selector select { + width: 100%; + padding: 8px; + background: var(--secondary-color); + color: var(--primary-color); + border: var(--border-width) solid var(--border-color); + border-radius: var(--border-radius); + font-family: var(--font-family); + font-size: 14px; + cursor: pointer; +} + +.query-selector select:focus { + border-color: var(--accent-color); + outline: none; +} + +.query-selector optgroup { + font-weight: bold; + color: var(--primary-color); +} + +.query-selector option { + padding: 4px; + background: var(--secondary-color); + color: var(--primary-color); +} + +.query-editor textarea { + width: 100%; + min-height: 120px; + resize: vertical; + font-family: "Courier New", Courier, monospace; + font-size: 12px; + line-height: 1.4; + tab-size: 4; + white-space: pre; +} + +.query-actions { + display: flex; + gap: 10px; + margin-top: 10px; +} + +.query-actions button { + flex: 1; + min-width: 120px; +} + +.primary-button { + background: var(--primary-color); + color: var(--secondary-color); + border-color: var(--primary-color); +} + +.primary-button:hover { + background: var(--secondary-color); + color: var(--primary-color); + border-color: var(--accent-color); +} + +.danger-button { + background: var(--accent-color); + color: var(--secondary-color); + border-color: var(--accent-color); +} + +.danger-button:hover { + background: var(--secondary-color); + color: var(--primary-color); + border-color: var(--accent-color); +} + +.query-info { + padding: 10px; + border: var(--border-width) solid var(--border-color); + border-radius: var(--border-radius); + margin: 10px 0; + font-family: var(--font-family); + font-size: 12px; + background-color: var(--secondary-color); +} + +.query-info-success { + border-color: #4CAF50; + background-color: #E8F5E8; + color: #2E7D32; +} + +.query-info-success span { + display: inline-block; + margin-right: 15px; +} + +.request-id { + font-family: "Courier New", Courier, monospace; + font-size: 10px; + opacity: 0.7; +} + +.error-message { + border-color: var(--accent-color); + background-color: #FFEBEE; + color: #C62828; + padding: 10px; + border-radius: var(--border-radius); + margin: 10px 0; + font-family: var(--font-family); + font-size: 12px; +} + +.sql-results-table { + border: 1px solid var(--border-color); + border-radius: var(--border-radius); + width: 100%; + border-collapse: separate; + border-spacing: 0; + margin: 10px 0; + overflow: hidden; + font-size: 11px; +} + +.sql-results-table th, +.sql-results-table td { + border: 0.1px solid var(--muted-color); + padding: 6px 8px; + text-align: left; + font-family: var(--font-family); + white-space: nowrap; + min-width: 100px; +} + +.sql-results-table th { + font-weight: bold; + background-color: rgba(0, 0, 0, 0.05); + position: sticky; + top: 0; + z-index: 10; +} + +.sql-results-table tbody tr:hover { + background-color: rgba(0, 0, 0, 0.05); +} + +.sql-results-table tbody tr:nth-child(even) { + background-color: rgba(0, 0, 0, 0.02); +} + +.no-results { + text-align: center; + font-style: italic; + color: var(--muted-color); + padding: 20px; + font-family: var(--font-family); +} + +.loading { + text-align: center; + font-style: italic; + color: var(--muted-color); + padding: 20px; + font-family: var(--font-family); +} + +/* Dark mode adjustments for SQL interface */ +body.dark-mode .query-info-success { + border-color: #4CAF50; + background-color: rgba(76, 175, 80, 0.1); + color: #81C784; +} + +body.dark-mode .error-message { + border-color: var(--accent-color); + background-color: rgba(244, 67, 54, 0.1); + color: #EF5350; +} + +body.dark-mode .sql-results-table th { + background-color: rgba(255, 255, 255, 0.05); +} + +body.dark-mode .sql-results-table tbody tr:hover { + background-color: rgba(255, 255, 255, 0.05); +} + +body.dark-mode .sql-results-table tbody tr:nth-child(even) { + background-color: rgba(255, 255, 255, 0.02); +} + + +/* Config Toggle Button Styles */ +.config-toggle-btn { + width: 24px; + height: 24px; + padding: 0; + background: var(--secondary-color); + border: var(--border-width) solid var(--border-color); + border-radius: var(--border-radius); + font-family: var(--font-family); + font-size: 14px; + cursor: pointer; + margin-left: 10px; + font-weight: bold; + transition: all 0.2s ease; + display: flex; + align-items: center; + justify-content: center; +} + +/* Toggle Button Styles */ +.toggle-btn { + width: auto; + min-width: 120px; + padding: 8px 12px; + background: var(--secondary-color); + color: var(--primary-color); + border: var(--border-width) solid var(--border-color); + border-radius: var(--border-radius); + font-family: var(--font-family); + font-size: 12px; + cursor: pointer; + transition: all 0.2s ease; + margin-left: auto; +} + +.toggle-btn:hover { + border-color: var(--accent-color); +} + +.toggle-btn:active { + background: var(--accent-color); + color: var(--secondary-color); +} + +.config-toggle-btn:hover { + border-color: var(--accent-color); +} + +.config-toggle-btn:active { + background: var(--accent-color); + color: var(--secondary-color); +} + +.config-toggle-btn[data-state="true"] { + color: var(--accent-color); +} + +.config-toggle-btn[data-state="false"] { + color: var(--primary-color); +} + +.config-toggle-btn[data-state="indeterminate"] { + background-color: var(--muted-color); + color: var(--primary-color); + cursor: not-allowed; + border-color: var(--muted-color); + +} + + +/* ================================ + REAL-TIME EVENT RATE CHART + ================================ */ + +.chart-container { + margin: 20px 0; + padding: 15px; + background: var(--secondary-color); + border: var(--border-width) solid var(--border-color); + border-radius: var(--border-radius); +} + +/* Chart range selector tabs (1H / 1D / 1M / 1Y) */ +.chart-range-tabs { + display: flex; + gap: 4px; + margin-bottom: 8px; +} + +.chart-tab { + padding: 4px 12px; + background: var(--secondary-color); + color: var(--primary-color); + border: var(--border-width) solid var(--border-color); + border-radius: var(--border-radius); + font-family: var(--font-family); + font-size: 11px; + cursor: pointer; + transition: all 0.15s ease; +} + +.chart-tab:hover { + border-color: var(--primary-color); +} + +.chart-tab.active { + background: var(--secondary-color); + color: var(--primary-color); + border-color: var(--primary-color); + font-weight: bold; +} + +/* Dim inactive tabs */ +.chart-tab:not(.active) { + color: var(--muted-color); + border-color: var(--muted-color); +} + +#event-rate-chart { + font-family: var(--font-family); + font-size: 12px; + line-height: 1.2; + color: var(--primary-color); + background: var(--secondary-color); + padding: 20px; + overflow-x: auto; + overflow-y: hidden; + white-space: pre; + border: var(--border-width) solid var(--border-color); + border-radius: var(--border-radius); + box-sizing: border-box; +} + +/* ================================ + SIDE NAVIGATION MENU + ================================ */ + +.side-nav { + position: fixed; + top: 0; + left: -300px; + width: 280px; + height: 100vh; + background: var(--secondary-color); + border-right: var(--border-width) solid var(--border-color); + z-index: 1000; + transition: left 0.3s ease; + overflow-y: auto; + padding-top: 80px; +} + +.side-nav.open { + left: 0; +} + +.side-nav-overlay { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: rgba(0, 0, 0, 0.5); + z-index: 999; + display: none; +} + +.side-nav-overlay.show { + display: block; +} + +.nav-menu { + list-style: none; + padding: 0; + margin: 0; +} + +.nav-menu li { + border-bottom: var(--border-width) solid var(--muted-color); +} + +.nav-menu li:last-child { + border-bottom: none; +} + +.nav-item { + display: block; + padding: 15px 20px; + color: var(--primary-color); + text-decoration: none; + font-family: var(--font-family); + font-size: 16px; + font-weight: bold; + transition: all 0.2s ease; + cursor: pointer; + border: 2px solid var(--secondary-color); + background: none; + width: 100%; + text-align: left; +} + +.nav-item:hover { + border: 2px solid var(--secondary-color); + background:var(--muted-color); + color: var(--accent-color); +} + +.nav-item.active { + text-decoration: underline; + padding-left: 16px; + } + +.nav-footer { + position: absolute; + bottom: 20px; + left: 0; + right: 0; + padding: 0 20px; + } + +.nav-footer-btn { + display: block; + width: 100%; + padding: 12px 20px; + margin-bottom: 8px; + color: var(--primary-color); + + border: 1px solid var(--border-color); + border-radius: 4px; + font-family: var(--font-family); + font-size: 14px; + font-weight: bold; + cursor: pointer; + transition: all 0.2s ease; + } + +.nav-footer-btn:hover { + background:var(--muted-color); + border-color: var(--accent-color); + } + +.nav-footer-btn:last-child { + margin-bottom: 0; + } + +.header-title.clickable { + cursor: pointer; + transition: all 0.2s ease; +} + +.header-title.clickable:hover { + opacity: 0.8; +} + +/* ================================ + SUBSCRIPTION TABLE COLLAPSIBLE GROUPS + ================================ */ + +/* Subscription group header styles */ +.subscription-group-header { + + font-weight: 500; + + cursor: pointer; + user-select: none; +} + +.subscription-group-header:hover { + background-color: var(--secondary-color); +} + +.expand-icon { + display: inline-block; + width: 20px; + transition: transform 0.2s ease; + font-size: 12px; +} + +/* Detail row styles */ +.subscription-detail-row { + /* background-color: var(--secondary-color); */ +} + +/* ================================ + WEB OF TRUST (WoT) STYLES + ================================ */ + +.wot-status-row, .wot-stats-row { + display: flex; + justify-content: space-between; + align-items: center; + padding: 8px 0; + font-size: 14px; +} + +.wot-indicator { + padding: 2px 10px; + border-radius: 4px; + font-weight: bold; + font-size: 12px; +} + +.wot-indicator.wot-found { background: #28a745; color: white; } +.wot-indicator.wot-missing { background: #dc3545; color: white; } +.wot-indicator.wot-unknown { background: #6c757d; color: white; } + +.wot-level-selector { padding: 10px 0; } +.wot-level-selector label { display: block; margin-bottom: 5px; font-weight: bold; } + +.wot-level-btn { min-width: 100px; } +.wot-level-btn.active { + background: var(--accent-color, #ff0000); + color: white; + border-color: var(--accent-color, #ff0000); +} + +.wot-level-description { + font-size: 12px; + color: var(--primary-color); + margin-top: 5px; + font-style: italic; + opacity: 0.8; +} + +/* Dark mode adjustments for WoT */ +body.dark-mode .wot-indicator.wot-found { background: #28a745; } +body.dark-mode .wot-indicator.wot-missing { background: #dc3545; } +body.dark-mode .wot-indicator.wot-unknown { background: #6c757d; } + +/* ================================ + ADMIN ACCESS GATE STYLES + ================================ */ + +/* Access Denied Overlay */ +.access-denied-overlay { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: rgba(0, 0, 0, 0.85); + z-index: 9999; + display: none; + justify-content: center; + align-items: center; +} + +.access-denied-content { + background: var(--card-bg); + border: 2px solid #dc3545; + border-radius: 12px; + padding: 40px 60px; + text-align: center; + max-width: 500px; + box-shadow: 0 10px 40px rgba(220, 53, 69, 0.3); +} + +.access-denied-icon { + font-size: 64px; + margin-bottom: 20px; +} + +.access-denied-content h2 { + color: #dc3545; + font-size: 32px; + margin-bottom: 20px; + letter-spacing: 2px; +} + +.access-denied-message { + font-size: 16px; + color: var(--primary-color); + margin-bottom: 10px; + line-height: 1.5; +} + +.access-denied-submessage { + font-size: 14px; + color: var(--muted-color); + margin-bottom: 30px; + font-style: italic; +} + +.access-denied-logout-btn { + background: #dc3545; + color: white; + border: none; + padding: 12px 40px; + font-size: 16px; + font-weight: bold; + border-radius: 6px; + cursor: pointer; + transition: all 0.3s ease; +} + +.access-denied-logout-btn:hover { + background: #c82333; + transform: translateY(-2px); + box-shadow: 0 4px 12px rgba(220, 53, 69, 0.4); +} + +/* Admin Verification Loading Overlay */ +.admin-verification-overlay { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: rgba(0, 0, 0, 0.8); + z-index: 9998; + display: none; + justify-content: center; + align-items: center; +} + +.admin-verification-content { + background: var(--card-bg); + border: 1px solid var(--border-color); + border-radius: 12px; + padding: 40px 60px; + text-align: center; + max-width: 450px; +} + +.admin-verification-content h3 { + color: var(--accent-color); + font-size: 20px; + margin-bottom: 15px; +} + +.admin-verification-content p { + color: var(--muted-color); + font-size: 14px; + margin-top: 15px; +} + +/* Spinner Animation */ +.spinner { + width: 50px; + height: 50px; + border: 4px solid var(--border-color); + border-top: 4px solid var(--accent-color); + border-radius: 50%; + animation: spin 1s linear infinite; + margin: 0 auto 20px; +} + +@keyframes spin { + 0% { transform: rotate(0deg); } + 100% { transform: rotate(360deg); } +} + +/* Dark mode adjustments */ +body.dark-mode .access-denied-content { + background: var(--card-bg); +} + +body.dark-mode .admin-verification-content { + background: var(--card-bg); +} + +.subscription-detail-row:hover { + background-color: var(--muted-color); +} + +/* Detail row cell styles */ +.subscription-detail-prefix { + padding-left: 30px; + font-family: 'Courier New', monospace; + font-size: 11px; + color: var(--muted-color); +} + +.subscription-detail-id { + font-family: 'Courier New', monospace; + font-size: 12px; +} + + +/* ================================ + IP BANS TABLE - compact rows + ================================ */ +#ip-bans-table td, #ip-bans-table th { + padding: 4px 8px; + line-height: 1.3; + font-size: 13px; +} +#ip-bans-table button { + padding: 2px 8px; + font-size: 12px; +} + +/* ===================================================================== + Profile name rendering hardening. + Handles hostile characters in user-controlled names: bidi overrides, + Zalgo/stacked combining marks, zero-width chars, newlines, and + very long names. The data is stored verbatim; these rules contain + the visual impact without altering the value. + ===================================================================== */ + +/* bdi isolates bidi text so U+202E (RTL override) in a name cannot + reverse surrounding table content. Applied via in app.js. */ +bdi { + unicode-bidi: isolate; +} + +/* Name cells in tables: prevent layout breakage. */ +#stats-pubkeys-table td:nth-child(2), +#caching-follows-table td:nth-child(1) { + max-width: 200px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + line-height: 1.4; + vertical-align: middle; +} + +/* Header user name: contain overflow from Zalgo/long names. */ +.header-user-name { + max-width: 180px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +/* Name-field usage stats panel */ +.name-usage-stats { + display: flex; + flex-wrap: wrap; + gap: 12px; + align-items: center; + padding: 8px 12px; + font-size: 12px; + color: var(--text-color); +} +.name-usage-label { + font-weight: bold; +} +.name-usage-item { + padding: 2px 8px; + border-radius: var(--border-radius); + background: var(--bg-color); + border: 1px solid var(--border-color); +} +.name-usage-differ { + font-weight: bold; + color: var(--accent-color); +} + +/* Caching follows table: expandable per-relay detail rows */ +.follows-row { + cursor: pointer; + transition: background 0.15s; +} +.follows-row:hover { + background: var(--hover-bg, rgba(255,255,255,0.05)); +} +.follows-detail td { + padding: 8px 12px; + background: var(--bg-color); + border-top: none; +} +.relay-progress-list { + display: flex; + flex-wrap: wrap; + gap: 6px 16px; + padding: 4px 0; +} +.relay-progress-row { + display: inline-flex; + align-items: center; + gap: 6px; + font-size: 12px; + white-space: nowrap; +} +.relay-icon { + font-size: 14px; +} +.relay-url { + color: var(--text-color); + max-width: 180px; + overflow: hidden; + text-overflow: ellipsis; +} +.relay-events { + color: var(--text-muted, #888); + font-size: 11px; +} +.relay-status { + font-size: 10px; + padding: 1px 6px; + border-radius: 3px; + text-transform: uppercase; + letter-spacing: 0.5px; +} +.relay-done { + background: rgba(40, 167, 69, 0.2); + color: #28a745; + border: 1px solid rgba(40, 167, 69, 0.3); +} +.relay-pending { + background: rgba(255, 193, 7, 0.2); + color: #ffc107; + border: 1px solid rgba(255, 193, 7, 0.3); +} + +/* Caching: per-user refresh button in detail row */ +.follows-detail-content { + display: flex; + flex-wrap: wrap; + align-items: flex-start; + gap: 8px 16px; +} +.follows-detail-actions { + margin-left: auto; +} +.refresh-user-btn { + font-size: 12px; + padding: 4px 12px; + cursor: pointer; + background: var(--accent-color, #007bff); + color: #fff; + border: none; + border-radius: var(--border-radius, 4px); + transition: opacity 0.15s; +} +.refresh-user-btn:hover { + opacity: 0.85; +} +.refresh-user-btn:active { + opacity: 0.7; +} diff --git a/admin/assets/nostr-lite.js b/admin/assets/nostr-lite.js new file mode 100644 index 0000000..c6773cf --- /dev/null +++ b/admin/assets/nostr-lite.js @@ -0,0 +1,4282 @@ +/** + * NOSTR_LOGIN_LITE - Authentication Library + * + * ⚠️ WARNING: THIS FILE IS AUTO-GENERATED - DO NOT EDIT MANUALLY! + * ⚠️ To make changes, edit lite/build.js and run: cd lite && node build.js + * ⚠️ Any manual edits to this file will be OVERWRITTEN when build.js runs! + * + * Two-file architecture: + * 1. Load nostr.bundle.js (official nostr-tools bundle) + * 2. Load nostr-lite.js (this file - NOSTR_LOGIN_LITE library with CSS-only themes) + * Generated on: 2025-10-01T14:18:10.269Z + */ + +// Verify dependencies are loaded +if (typeof window !== 'undefined') { + if (!window.NostrTools) { + console.error('NOSTR_LOGIN_LITE: nostr.bundle.js must be loaded first'); + throw new Error('Missing dependency: nostr.bundle.js'); + } + + console.log('NOSTR_LOGIN_LITE: Dependencies verified ✓'); + console.log('NOSTR_LOGIN_LITE: NostrTools available with keys:', Object.keys(window.NostrTools)); + console.log('NOSTR_LOGIN_LITE: NIP-06 available:', !!window.NostrTools.nip06); + console.log('NOSTR_LOGIN_LITE: NIP-46 available:', !!window.NostrTools.nip46); +} + +// ====================================== +// NOSTR_LOGIN_LITE Components +// ====================================== + +// ====================================== +// CSS-Only Theme System +// ====================================== + +const THEME_CSS = { + 'default': `/** + * NOSTR_LOGIN_LITE - Default Monospace Theme + * Black/white/red color scheme with monospace typography + * Simplified 14-variable system (6 core + 8 floating tab) + */ + +:root { + /* Core Variables (6) */ + --nl-primary-color: #000000; + --nl-secondary-color: #ffffff; + --nl-accent-color: #ff0000; + --nl-muted-color: #CCCCCC; + --nl-font-family: "Courier New", Courier, monospace; + --nl-border-radius: 15px; + --nl-border-width: 3px; + + /* Floating Tab Variables (8) */ + --nl-tab-bg-logged-out: #ffffff; + --nl-tab-bg-logged-in: #ffffff; + --nl-tab-bg-opacity-logged-out: 0.9; + --nl-tab-bg-opacity-logged-in: 0.2; + --nl-tab-color-logged-out: #000000; + --nl-tab-color-logged-in: #ffffff; + --nl-tab-border-logged-out: #000000; + --nl-tab-border-logged-in: #ff0000; + --nl-tab-border-opacity-logged-out: 1.0; + --nl-tab-border-opacity-logged-in: 0.1; +} + +/* Base component styles using simplified variables */ +.nl-component { + font-family: var(--nl-font-family); + color: var(--nl-primary-color); +} + +.nl-button { + background: var(--nl-secondary-color); + color: var(--nl-primary-color); + border: var(--nl-border-width) solid var(--nl-primary-color); + border-radius: var(--nl-border-radius); + font-family: var(--nl-font-family); + cursor: pointer; + transition: all 0.2s ease; +} + +.nl-button:hover { + border-color: var(--nl-accent-color); +} + +.nl-button:active { + background: var(--nl-accent-color); + color: var(--nl-secondary-color); +} + +.nl-input { + background: var(--nl-secondary-color); + color: var(--nl-primary-color); + border: var(--nl-border-width) solid var(--nl-primary-color); + border-radius: var(--nl-border-radius); + font-family: var(--nl-font-family); + box-sizing: border-box; +} + +.nl-input:focus { + border-color: var(--nl-accent-color); + outline: none; +} + +.nl-container { + background: var(--nl-secondary-color); + border: var(--nl-border-width) solid var(--nl-primary-color); + border-radius: var(--nl-border-radius); +} + +.nl-title, .nl-heading { + font-family: var(--nl-font-family); + color: var(--nl-primary-color); + margin: 0; +} + +.nl-text { + font-family: var(--nl-font-family); + color: var(--nl-primary-color); +} + +.nl-text--muted { + color: var(--nl-muted-color); +} + +.nl-icon { + font-family: var(--nl-font-family); + color: var(--nl-primary-color); +} + +/* Floating tab styles */ +.nl-floating-tab { + font-family: var(--nl-font-family); + border-radius: var(--nl-border-radius); + border: var(--nl-border-width) solid; + transition: all 0.2s ease; +} + +.nl-floating-tab--logged-out { + background: rgba(255, 255, 255, var(--nl-tab-bg-opacity-logged-out)); + color: var(--nl-tab-color-logged-out); + border-color: rgba(0, 0, 0, var(--nl-tab-border-opacity-logged-out)); +} + +.nl-floating-tab--logged-in { + background: rgba(0, 0, 0, var(--nl-tab-bg-opacity-logged-in)); + color: var(--nl-tab-color-logged-in); + border-color: rgba(255, 0, 0, var(--nl-tab-border-opacity-logged-in)); +} + +.nl-transition { + transition: all 0.2s ease; +}`, + 'dark': `/** + * NOSTR_LOGIN_LITE - Dark Monospace Theme + */ + +:root { + /* Core Variables (6) */ + --nl-primary-color: #white; + --nl-secondary-color: #black; + --nl-accent-color: #ff0000; + --nl-muted-color: #666666; + --nl-font-family: "Courier New", Courier, monospace; + --nl-border-radius: 15px; + --nl-border-width: 3px; + + /* Floating Tab Variables (8) */ + --nl-tab-bg-logged-out: #ffffff; + --nl-tab-bg-logged-in: #000000; + --nl-tab-bg-opacity-logged-out: 0.9; + --nl-tab-bg-opacity-logged-in: 0.8; + --nl-tab-color-logged-out: #000000; + --nl-tab-color-logged-in: #ffffff; + --nl-tab-border-logged-out: #000000; + --nl-tab-border-logged-in: #ff0000; + --nl-tab-border-opacity-logged-out: 1.0; + --nl-tab-border-opacity-logged-in: 0.9; +} + +/* Base component styles using simplified variables */ +.nl-component { + font-family: var(--nl-font-family); + color: var(--nl-primary-color); +} + +.nl-button { + background: var(--nl-secondary-color); + color: var(--nl-primary-color); + border: var(--nl-border-width) solid var(--nl-primary-color); + border-radius: var(--nl-border-radius); + font-family: var(--nl-font-family); + cursor: pointer; + transition: all 0.2s ease; +} + +.nl-button:hover { + border-color: var(--nl-accent-color); +} + +.nl-button:active { + background: var(--nl-accent-color); + color: var(--nl-secondary-color); +} + +.nl-input { + background: var(--nl-secondary-color); + color: var(--nl-primary-color); + border: var(--nl-border-width) solid var(--nl-primary-color); + border-radius: var(--nl-border-radius); + font-family: var(--nl-font-family); + box-sizing: border-box; +} + +.nl-input:focus { + border-color: var(--nl-accent-color); + outline: none; +} + +.nl-container { + background: var(--nl-secondary-color); + border: var(--nl-border-width) solid var(--nl-primary-color); + border-radius: var(--nl-border-radius); +} + +.nl-title, .nl-heading { + font-family: var(--nl-font-family); + color: var(--nl-primary-color); + margin: 0; +} + +.nl-text { + font-family: var(--nl-font-family); + color: var(--nl-primary-color); +} + +.nl-text--muted { + color: var(--nl-muted-color); +} + +.nl-icon { + font-family: var(--nl-font-family); + color: var(--nl-primary-color); +} + +/* Floating tab styles */ +.nl-floating-tab { + font-family: var(--nl-font-family); + border-radius: var(--nl-border-radius); + border: var(--nl-border-width) solid; + transition: all 0.2s ease; +} + +.nl-floating-tab--logged-out { + background: rgba(255, 255, 255, var(--nl-tab-bg-opacity-logged-out)); + color: var(--nl-tab-color-logged-out); + border-color: rgba(0, 0, 0, var(--nl-tab-border-opacity-logged-out)); +} + +.nl-floating-tab--logged-in { + background: rgba(0, 0, 0, var(--nl-tab-bg-opacity-logged-in)); + color: var(--nl-tab-color-logged-in); + border-color: rgba(255, 0, 0, var(--nl-tab-border-opacity-logged-in)); +} + +.nl-transition { + transition: all 0.2s ease; +}` +}; + +// Theme management functions +function injectThemeCSS(themeName = 'default') { + if (typeof document !== 'undefined') { + // Remove existing theme CSS + const existingStyle = document.getElementById('nl-theme-css'); + if (existingStyle) { + existingStyle.remove(); + } + + // Inject selected theme CSS + const themeCss = THEME_CSS[themeName] || THEME_CSS['default']; + const style = document.createElement('style'); + style.id = 'nl-theme-css'; + style.textContent = themeCss; + document.head.appendChild(style); + console.log('NOSTR_LOGIN_LITE: ' + themeName + ' theme CSS injected'); + } +} + +// Auto-inject default theme when DOM is ready +if (typeof document !== 'undefined') { + if (document.readyState === 'loading') { + document.addEventListener('DOMContentLoaded', () => injectThemeCSS('default')); + } else { + injectThemeCSS('default'); + } +} + +// ====================================== +// Modal UI Component +// ====================================== + + +class Modal { + constructor(options = {}) { + this.options = options; + this.container = null; + this.isVisible = false; + this.currentScreen = null; + this.isEmbedded = !!options.embedded; + this.embeddedContainer = options.embedded; + + // Initialize modal container and styles + this._initModal(); + } + + _initModal() { + // Create modal container + this.container = document.createElement('div'); + this.container.id = this.isEmbedded ? 'nl-modal-embedded' : 'nl-modal'; + + if (this.isEmbedded) { + // Embedded mode: inline positioning, no overlay + this.container.style.cssText = ` + position: relative; + display: none; + font-family: var(--nl-font-family, 'Courier New', monospace); + width: 100%; + `; + } else { + // Modal mode: fixed overlay + this.container.style.cssText = ` + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: rgba(0, 0, 0, 0.75); + display: none; + z-index: 10000; + font-family: var(--nl-font-family, 'Courier New', monospace); + `; + } + + // Create modal content + const modalContent = document.createElement('div'); + if (this.isEmbedded) { + // Embedded content: no centering margin, full width + modalContent.style.cssText = ` + position: relative; + background: var(--nl-secondary-color); + color: var(--nl-primary-color); + width: 100%; + border-radius: var(--nl-border-radius, 15px); + border: var(--nl-border-width) solid var(--nl-primary-color); + overflow: hidden; + `; + } else { + // Modal content: centered with margin, no fixed height + modalContent.style.cssText = ` + position: relative; + background: var(--nl-secondary-color); + color: var(--nl-primary-color); + width: 90%; + max-width: 400px; + margin: 50px auto; + border-radius: var(--nl-border-radius, 15px); + border: var(--nl-border-width) solid var(--nl-primary-color); + overflow: hidden; + `; + } + + // Header + const modalHeader = document.createElement('div'); + modalHeader.style.cssText = ` + padding: 20px 24px 0 24px; + display: flex; + justify-content: space-between; + align-items: center; + background: transparent; + border-bottom: none; + `; + + const modalTitle = document.createElement('h2'); + modalTitle.textContent = 'Nostr Login'; + modalTitle.style.cssText = ` + margin: 0; + font-size: 24px; + font-weight: 600; + color: var(--nl-primary-color); + font-family: var(--nl-font-family, 'Courier New', monospace); + `; + + modalHeader.appendChild(modalTitle); + + // Only add close button for non-embedded modals + // Embedded modals shouldn't have a close button because there's no way to reopen them + if (!this.isEmbedded) { + const closeButton = document.createElement('button'); + closeButton.innerHTML = '×'; + closeButton.onclick = () => this.close(); + closeButton.style.cssText = ` + background: var(--nl-secondary-color); + border: var(--nl-border-width) solid var(--nl-primary-color); + border-radius: 4px; + font-size: 28px; + color: var(--nl-primary-color); + cursor: pointer; + padding: 0; + width: 32px; + height: 32px; + display: flex; + align-items: center; + justify-content: center; + font-family: var(--nl-font-family, 'Courier New', monospace); + `; + closeButton.onmouseover = () => { + closeButton.style.borderColor = 'var(--nl-accent-color)'; + closeButton.style.background = 'var(--nl-secondary-color)'; + }; + closeButton.onmouseout = () => { + closeButton.style.borderColor = 'var(--nl-primary-color)'; + closeButton.style.background = 'var(--nl-secondary-color)'; + }; + + modalHeader.appendChild(closeButton); + } + + // Body + this.modalBody = document.createElement('div'); + this.modalBody.style.cssText = ` + padding: 24px; + background: transparent; + font-family: var(--nl-font-family, 'Courier New', monospace); + `; + + modalContent.appendChild(modalHeader); + // Add version element in bottom-right corner aligned with modal body + const versionElement = document.createElement('div'); + versionElement.textContent = 'v0.1.7'; + versionElement.style.cssText = ` + position: absolute; + bottom: 8px; + right: 24px; + font-size: 14px; + color: #666666; + font-family: var(--nl-font-family, 'Courier New', monospace); + pointer-events: none; + z-index: 1; + `; + modalContent.appendChild(versionElement); + + modalContent.appendChild(this.modalBody); + this.container.appendChild(modalContent); + + // Add to appropriate parent + if (this.isEmbedded && this.embeddedContainer) { + // Append to specified container for embedding + if (typeof this.embeddedContainer === 'string') { + const targetElement = document.querySelector(this.embeddedContainer); + if (targetElement) { + targetElement.appendChild(this.container); + } else { + console.error('NOSTR_LOGIN_LITE: Embedded container not found:', this.embeddedContainer); + document.body.appendChild(this.container); + } + } else if (this.embeddedContainer instanceof HTMLElement) { + this.embeddedContainer.appendChild(this.container); + } else { + console.error('NOSTR_LOGIN_LITE: Invalid embedded container'); + document.body.appendChild(this.container); + } + } else { + // Add to body for modal mode + document.body.appendChild(this.container); + } + + // Click outside to close (only for modal mode) + if (!this.isEmbedded) { + this.container.onclick = (e) => { + if (e.target === this.container) { + this.close(); + } + }; + } + + // Update theme + this.updateTheme(); + } + + updateTheme() { + // The theme will automatically update through CSS custom properties + // No manual styling needed - the CSS variables handle everything + } + + open(opts = {}) { + this.currentScreen = opts.startScreen; + this.isVisible = true; + this.container.style.display = 'block'; + + // Render login options + this._renderLoginOptions(); + } + + close() { + this.isVisible = false; + this.container.style.display = 'none'; + this.modalBody.innerHTML = ''; + } + + _renderLoginOptions() { + this.modalBody.innerHTML = ''; + + const options = []; + + // Extension option + if (this.options?.methods?.extension !== false) { + options.push({ + type: 'extension', + title: 'Browser Extension', + description: 'Use your browser extension', + icon: '🔌' + }); + } + + // Local key option + if (this.options?.methods?.local !== false) { + options.push({ + type: 'local', + title: 'Local Key', + description: 'Create or import your own key', + icon: '🔑' + }); + } + + // Seed Phrase option - only show if explicitly enabled + if (this.options?.methods?.seedphrase === true) { + options.push({ + type: 'seedphrase', + title: 'Seed Phrase', + description: 'Import from mnemonic seed phrase', + icon: '🌱' + }); + } + + // Nostr Connect option (check both 'connect' and 'remote' for compatibility) + if (this.options?.methods?.connect !== false && this.options?.methods?.remote !== false) { + options.push({ + type: 'connect', + title: 'Nostr Connect', + description: 'Connect with external signer', + icon: '🌐' + }); + } + + // Read-only option + if (this.options?.methods?.readonly !== false) { + options.push({ + type: 'readonly', + title: 'Read Only', + description: 'Browse without signing', + icon: '👁️' + }); + } + + // OTP/DM option + if (this.options?.methods?.otp !== false) { + options.push({ + type: 'otp', + title: 'DM/OTP', + description: 'Receive OTP via DM', + icon: '📱' + }); + } + + // Render each option + options.forEach(option => { + const button = document.createElement('button'); + button.onclick = () => this._handleOptionClick(option.type); + button.style.cssText = ` + display: flex; + align-items: center; + width: 100%; + padding: 16px; + margin-bottom: 12px; + background: var(--nl-secondary-color); + color: var(--nl-primary-color); + border: var(--nl-border-width) solid var(--nl-primary-color); + border-radius: var(--nl-border-radius); + cursor: pointer; + transition: all 0.2s; + font-family: var(--nl-font-family, 'Courier New', monospace); + `; + button.onmouseover = () => { + button.style.borderColor = 'var(--nl-accent-color)'; + button.style.background = 'var(--nl-secondary-color)'; + }; + button.onmouseout = () => { + button.style.borderColor = 'var(--nl-primary-color)'; + button.style.background = 'var(--nl-secondary-color)'; + }; + + const iconDiv = document.createElement('div'); + // Remove the icon entirely - no emojis or text-based icons + iconDiv.textContent = ''; + iconDiv.style.cssText = ` + font-size: 16px; + font-weight: bold; + margin-right: 16px; + width: 0px; + text-align: center; + color: var(--nl-primary-color); + font-family: var(--nl-font-family, 'Courier New', monospace); + `; + + const contentDiv = document.createElement('div'); + contentDiv.style.cssText = 'flex: 1; text-align: left;'; + + const titleDiv = document.createElement('div'); + titleDiv.textContent = option.title; + titleDiv.style.cssText = ` + font-weight: 600; + margin-bottom: 4px; + color: var(--nl-primary-color); + font-family: var(--nl-font-family, 'Courier New', monospace); + `; + + const descDiv = document.createElement('div'); + descDiv.textContent = option.description; + descDiv.style.cssText = ` + font-size: 14px; + color: #666666; + font-family: var(--nl-font-family, 'Courier New', monospace); + `; + + contentDiv.appendChild(titleDiv); + contentDiv.appendChild(descDiv); + + button.appendChild(iconDiv); + button.appendChild(contentDiv); + this.modalBody.appendChild(button); + }); + } + + _handleOptionClick(type) { + console.log('Selected login type:', type); + + // Handle different login types + switch (type) { + case 'extension': + this._handleExtension(); + break; + case 'local': + this._showLocalKeyScreen(); + break; + case 'seedphrase': + this._showSeedPhraseScreen(); + break; + case 'connect': + this._showConnectScreen(); + break; + case 'readonly': + this._handleReadonly(); + break; + case 'otp': + this._showOtpScreen(); + break; + } + } + + _handleExtension() { + // SIMPLIFIED ARCHITECTURE: Check for single extension at window.nostr or preserved extension + let extension = null; + + // Check if NostrLite instance has a preserved extension (real extension detected at init) + if (window.NOSTR_LOGIN_LITE?._instance?.preservedExtension) { + extension = window.NOSTR_LOGIN_LITE._instance.preservedExtension; + console.log('Modal: Using preserved extension:', extension.constructor?.name); + } + // Otherwise check current window.nostr + else if (window.nostr && this._isRealExtension(window.nostr)) { + extension = window.nostr; + console.log('Modal: Using current window.nostr extension:', extension.constructor?.name); + } + + if (!extension) { + console.log('Modal: No extension detected yet, waiting for deferred detection...'); + + // DEFERRED EXTENSION CHECK: Extensions like nos2x might load after our library + let attempts = 0; + const maxAttempts = 10; // Try for 2 seconds + const checkForExtension = () => { + attempts++; + + // Check again for preserved extension (might be set by deferred detection) + if (window.NOSTR_LOGIN_LITE?._instance?.preservedExtension) { + extension = window.NOSTR_LOGIN_LITE._instance.preservedExtension; + console.log('Modal: Found preserved extension after waiting:', extension.constructor?.name); + this._tryExtensionLogin(extension); + return; + } + + // Check current window.nostr again + if (window.nostr && this._isRealExtension(window.nostr)) { + extension = window.nostr; + console.log('Modal: Found extension at window.nostr after waiting:', extension.constructor?.name); + this._tryExtensionLogin(extension); + return; + } + + // Keep trying or give up + if (attempts < maxAttempts) { + setTimeout(checkForExtension, 200); + } else { + console.log('Modal: No browser extension found after waiting 2 seconds'); + this._showExtensionRequired(); + } + }; + + // Start checking after a brief delay + setTimeout(checkForExtension, 200); + return; + } + + // Use the single detected extension directly - no choice UI + console.log('Modal: Single extension mode - using extension directly'); + this._tryExtensionLogin(extension); + } + + _detectAllExtensions() { + const extensions = []; + const seenExtensions = new Set(); // Track extensions by object reference to avoid duplicates + + // Extension locations to check (in priority order) + const locations = [ + { path: 'window.navigator?.nostr', name: 'navigator.nostr', displayName: 'Standard Extension (navigator.nostr)', icon: '🌐', getter: () => window.navigator?.nostr }, + { path: 'window.webln?.nostr', name: 'webln.nostr', displayName: 'Alby WebLN Extension', icon: '⚡', getter: () => window.webln?.nostr }, + { path: 'window.alby?.nostr', name: 'alby.nostr', displayName: 'Alby Extension (Direct)', icon: '🐝', getter: () => window.alby?.nostr }, + { path: 'window.nos2x', name: 'nos2x', displayName: 'nos2x Extension', icon: '🔌', getter: () => window.nos2x }, + { path: 'window.flamingo?.nostr', name: 'flamingo.nostr', displayName: 'Flamingo Extension', icon: '🦩', getter: () => window.flamingo?.nostr }, + { path: 'window.mutiny?.nostr', name: 'mutiny.nostr', displayName: 'Mutiny Extension', icon: '⚔️', getter: () => window.mutiny?.nostr }, + { path: 'window.nostrich?.nostr', name: 'nostrich.nostr', displayName: 'Nostrich Extension', icon: '🐦', getter: () => window.nostrich?.nostr }, + { path: 'window.getAlby?.nostr', name: 'getAlby.nostr', displayName: 'getAlby Extension', icon: '🔧', getter: () => window.getAlby?.nostr } + ]; + + // Check each location + for (const location of locations) { + try { + const obj = location.getter(); + + console.log(`Modal: Checking ${location.name}:`, !!obj, obj?.constructor?.name); + + if (obj && this._isRealExtension(obj) && !seenExtensions.has(obj)) { + extensions.push({ + name: location.name, + displayName: location.displayName, + icon: location.icon, + extension: obj + }); + seenExtensions.add(obj); + console.log(`Modal: ✓ Detected extension at ${location.name} (${obj.constructor?.name})`); + } else if (obj) { + console.log(`Modal: ✗ Filtered out ${location.name} (${obj.constructor?.name})`); + } + } catch (e) { + // Location doesn't exist or can't be accessed + console.log(`Modal: ${location.name} not accessible:`, e.message); + } + } + + // Also check window.nostr but be extra careful to avoid our library + console.log('Modal: Checking window.nostr:', !!window.nostr, window.nostr?.constructor?.name); + + if (window.nostr) { + // Check if window.nostr is our WindowNostr facade with a preserved extension + if (window.nostr.constructor?.name === 'WindowNostr' && window.nostr.existingNostr) { + console.log('Modal: Found WindowNostr facade, checking existingNostr for preserved extension'); + const preservedExtension = window.nostr.existingNostr; + console.log('Modal: Preserved extension:', !!preservedExtension, preservedExtension?.constructor?.name); + + if (preservedExtension && this._isRealExtension(preservedExtension) && !seenExtensions.has(preservedExtension)) { + extensions.push({ + name: 'window.nostr.existingNostr', + displayName: 'Extension (preserved by WindowNostr)', + icon: '🔑', + extension: preservedExtension + }); + seenExtensions.add(preservedExtension); + console.log(`Modal: ✓ Detected preserved extension: ${preservedExtension.constructor?.name}`); + } + } + // Check if window.nostr is directly a real extension (not our facade) + else if (this._isRealExtension(window.nostr) && !seenExtensions.has(window.nostr)) { + extensions.push({ + name: 'window.nostr', + displayName: 'Extension (window.nostr)', + icon: '🔑', + extension: window.nostr + }); + seenExtensions.add(window.nostr); + console.log(`Modal: ✓ Detected extension at window.nostr: ${window.nostr.constructor?.name}`); + } else { + console.log(`Modal: ✗ Filtered out window.nostr (${window.nostr.constructor?.name}) - not a real extension`); + } + } + + return extensions; + } + + _isRealExtension(obj) { + console.log(`Modal: EXTENSIVE DEBUG - _isRealExtension called with:`, obj); + console.log(`Modal: Object type: ${typeof obj}`); + console.log(`Modal: Object truthy: ${!!obj}`); + + if (!obj || typeof obj !== 'object') { + console.log(`Modal: REJECT - Not an object`); + return false; + } + + console.log(`Modal: getPublicKey type: ${typeof obj.getPublicKey}`); + console.log(`Modal: signEvent type: ${typeof obj.signEvent}`); + + // Must have required Nostr methods + if (typeof obj.getPublicKey !== 'function' || typeof obj.signEvent !== 'function') { + console.log(`Modal: REJECT - Missing required methods`); + return false; + } + + // Exclude NostrTools library object + if (obj === window.NostrTools) { + console.log(`Modal: REJECT - Is NostrTools object`); + return false; + } + + // Use the EXACT SAME logic as the comprehensive test (lines 804-809) + // This is the key fix - match the comprehensive test's successful detection logic + const constructorName = obj.constructor?.name; + const objectKeys = Object.keys(obj); + + console.log(`Modal: Constructor name: "${constructorName}"`); + console.log(`Modal: Object keys: [${objectKeys.join(', ')}]`); + + // COMPREHENSIVE TEST LOGIC - Accept anything with required methods that's not our specific library classes + const isRealExtension = ( + typeof obj.getPublicKey === 'function' && + typeof obj.signEvent === 'function' && + constructorName !== 'WindowNostr' && // Our library class + constructorName !== 'NostrLite' // Our main class + ); + + console.log(`Modal: Using comprehensive test logic:`); + console.log(` Has getPublicKey: ${typeof obj.getPublicKey === 'function'}`); + console.log(` Has signEvent: ${typeof obj.signEvent === 'function'}`); + console.log(` Not WindowNostr: ${constructorName !== 'WindowNostr'}`); + console.log(` Not NostrLite: ${constructorName !== 'NostrLite'}`); + console.log(` Constructor: "${constructorName}"`); + + // Additional debugging for comparison + const extensionPropChecks = { + _isEnabled: !!obj._isEnabled, + enabled: !!obj.enabled, + kind: !!obj.kind, + _eventEmitter: !!obj._eventEmitter, + _scope: !!obj._scope, + _requests: !!obj._requests, + _pubkey: !!obj._pubkey, + name: !!obj.name, + version: !!obj.version, + description: !!obj.description + }; + + console.log(`Modal: Extension property analysis:`, extensionPropChecks); + + const hasExtensionProps = !!( + obj._isEnabled || obj.enabled || obj.kind || + obj._eventEmitter || obj._scope || obj._requests || obj._pubkey || + obj.name || obj.version || obj.description + ); + + const underscoreKeys = objectKeys.filter(key => key.startsWith('_')); + const hexToUint8Keys = objectKeys.filter(key => key.startsWith('_hex')); + console.log(`Modal: Underscore keys: [${underscoreKeys.join(', ')}]`); + console.log(`Modal: _hex* keys: [${hexToUint8Keys.join(', ')}]`); + + console.log(`Modal: Additional analysis:`); + console.log(` hasExtensionProps: ${hasExtensionProps}`); + console.log(` hasLibraryMethod (_hexToUint8Array): ${objectKeys.includes('_hexToUint8Array')}`); + + console.log(`Modal: COMPREHENSIVE TEST LOGIC RESULT: ${isRealExtension ? 'ACCEPT' : 'REJECT'}`); + console.log(`Modal: FINAL DECISION for ${constructorName}: ${isRealExtension ? 'ACCEPT' : 'REJECT'}`); + + return isRealExtension; + } + + _showExtensionChoice(extensions) { + this.modalBody.innerHTML = ''; + + const title = document.createElement('h3'); + title.textContent = 'Choose Browser Extension'; + title.style.cssText = ` + margin: 0 0 16px 0; + font-size: 18px; + font-weight: 600; + color: var(--nl-primary-color); + font-family: var(--nl-font-family, 'Courier New', monospace); + `; + + const description = document.createElement('p'); + description.textContent = `Found ${extensions.length} Nostr extensions. Choose which one to use:`; + description.style.cssText = ` + margin-bottom: 20px; + color: #666666; + font-size: 14px; + font-family: var(--nl-font-family, 'Courier New', monospace); + `; + + this.modalBody.appendChild(title); + this.modalBody.appendChild(description); + + // Create button for each extension + extensions.forEach((ext, index) => { + const button = document.createElement('button'); + button.onclick = () => this._tryExtensionLogin(ext.extension); + button.style.cssText = ` + display: flex; + align-items: center; + width: 100%; + padding: 16px; + margin-bottom: 12px; + background: var(--nl-secondary-color); + color: var(--nl-primary-color); + border: var(--nl-border-width) solid var(--nl-primary-color); + border-radius: var(--nl-border-radius); + cursor: pointer; + transition: all 0.2s; + text-align: left; + font-family: var(--nl-font-family, 'Courier New', monospace); + `; + + button.onmouseover = () => { + button.style.borderColor = 'var(--nl-accent-color)'; + button.style.background = 'var(--nl-secondary-color)'; + }; + button.onmouseout = () => { + button.style.borderColor = 'var(--nl-primary-color)'; + button.style.background = 'var(--nl-secondary-color)'; + }; + + const iconDiv = document.createElement('div'); + iconDiv.textContent = ext.icon; + iconDiv.style.cssText = ` + font-size: 24px; + margin-right: 16px; + width: 24px; + text-align: center; + `; + + const contentDiv = document.createElement('div'); + contentDiv.style.cssText = 'flex: 1;'; + + const nameDiv = document.createElement('div'); + nameDiv.textContent = ext.displayName; + nameDiv.style.cssText = ` + font-weight: 600; + margin-bottom: 4px; + color: var(--nl-primary-color); + font-family: var(--nl-font-family, 'Courier New', monospace); + `; + + const pathDiv = document.createElement('div'); + pathDiv.textContent = ext.name; + pathDiv.style.cssText = ` + font-size: 12px; + color: #666666; + font-family: var(--nl-font-family, 'Courier New', monospace); + `; + + contentDiv.appendChild(nameDiv); + contentDiv.appendChild(pathDiv); + + button.appendChild(iconDiv); + button.appendChild(contentDiv); + this.modalBody.appendChild(button); + }); + + // Add back button + const backButton = document.createElement('button'); + backButton.textContent = 'Back to Login Options'; + backButton.onclick = () => this._renderLoginOptions(); + backButton.style.cssText = this._getButtonStyle('secondary') + 'margin-top: 20px;'; + + this.modalBody.appendChild(backButton); + } + + async _tryExtensionLogin(extensionObj) { + try { + // Show loading state + this.modalBody.innerHTML = '
🔄 Connecting to extension...
'; + + // Get pubkey from extension + const pubkey = await extensionObj.getPublicKey(); + console.log('Extension provided pubkey:', pubkey); + + // Set extension method with the extension object + this._setAuthMethod('extension', { pubkey, extension: extensionObj }); + + } catch (error) { + console.error('Extension login failed:', error); + this._showError(`Extension login failed: ${error.message}`); + } + } + + _showLocalKeyScreen() { + this.modalBody.innerHTML = ''; + + const description = document.createElement('p'); + description.innerHTML = 'Enter your secret key in nsec or hex format, or generate new.'; + description.style.cssText = 'margin-bottom: 12px; color: #6b7280; font-size: 14px;'; + + const textarea = document.createElement('textarea'); + textarea.placeholder = 'Enter your secret key:\n• nsec1... (bech32 format)\n• 64-character hex string'; + textarea.style.cssText = ` + width: 100%; + height: 100px; + padding: 12px; + border: 1px solid #d1d5db; + border-radius: 6px; + margin-bottom: 12px; + resize: none; + font-family: monospace; + font-size: 14px; + box-sizing: border-box; + `; + + // Add real-time format detection + const formatHint = document.createElement('div'); + formatHint.style.cssText = 'margin-bottom: 16px; font-size: 12px; color: #6b7280; min-height: 16px;'; + + const importButton = document.createElement('button'); + importButton.textContent = 'Import Key'; + importButton.disabled = true; + importButton.onclick = () => { + if (!importButton.disabled) { + this._importLocalKey(textarea.value); + } + }; + + // Set initial disabled state + importButton.style.cssText = ` + display: block; + width: 100%; + padding: 12px; + border: var(--nl-border-width) solid var(--nl-muted-color); + border-radius: var(--nl-border-radius); + font-size: 16px; + font-weight: 500; + cursor: not-allowed; + transition: all 0.2s; + font-family: var(--nl-font-family, 'Courier New', monospace); + background: var(--nl-secondary-color); + color: var(--nl-muted-color); + `; + + textarea.oninput = () => { + const value = textarea.value.trim(); + if (!value) { + formatHint.textContent = ''; + // Disable button + importButton.disabled = true; + importButton.style.borderColor = 'var(--nl-muted-color)'; + importButton.style.color = 'var(--nl-muted-color)'; + importButton.style.cursor = 'not-allowed'; + return; + } + + const format = this._detectKeyFormat(value); + if (format === 'nsec') { + formatHint.textContent = '✅ Valid nsec format detected'; + formatHint.style.color = '#059669'; + // Enable button + importButton.disabled = false; + importButton.style.borderColor = 'var(--nl-primary-color)'; + importButton.style.color = 'var(--nl-primary-color)'; + importButton.style.cursor = 'pointer'; + } else if (format === 'hex') { + formatHint.textContent = '✅ Valid hex format detected'; + formatHint.style.color = '#059669'; + // Enable button + importButton.disabled = false; + importButton.style.borderColor = 'var(--nl-primary-color)'; + importButton.style.color = 'var(--nl-primary-color)'; + importButton.style.cursor = 'pointer'; + } else { + formatHint.textContent = '❌ Invalid key format - must be nsec1... or 64-character hex'; + formatHint.style.color = '#dc2626'; + // Disable button + importButton.disabled = true; + importButton.style.borderColor = 'var(--nl-muted-color)'; + importButton.style.color = 'var(--nl-muted-color)'; + importButton.style.cursor = 'not-allowed'; + } + }; + + const backButton = document.createElement('button'); + backButton.textContent = 'Back'; + backButton.onclick = () => this._renderLoginOptions(); + backButton.style.cssText = this._getButtonStyle('secondary') + 'margin-top: 12px;'; + + this.modalBody.appendChild(description); + this.modalBody.appendChild(textarea); + this.modalBody.appendChild(formatHint); + this.modalBody.appendChild(importButton); + this.modalBody.appendChild(backButton); + + // Add click handler for the "generate new" link + const generateLink = document.getElementById('generate-new'); + if (generateLink) { + generateLink.addEventListener('mouseenter', () => { + generateLink.style.color = 'var(--nl-accent-color)'; + }); + generateLink.addEventListener('mouseleave', () => { + generateLink.style.color = 'var(--nl-primary-color)'; + }); + generateLink.addEventListener('click', () => { + this._generateNewLocalKey(textarea, formatHint); + }); + } + } + + _generateNewLocalKey(textarea, formatHint) { + try { + // Generate a new secret key using NostrTools + const sk = window.NostrTools.generateSecretKey(); + const nsec = window.NostrTools.nip19.nsecEncode(sk); + + // Set the generated key in the textarea + textarea.value = nsec; + + // Trigger the oninput event to properly validate and enable the button + if (textarea.oninput) { + textarea.oninput(); + } + + console.log('Generated new local secret key (nsec format)'); + + } catch (error) { + console.error('Failed to generate local key:', error); + formatHint.textContent = '❌ Failed to generate key - NostrTools not available'; + formatHint.style.color = '#dc2626'; + } + } + + _createLocalKey() { + try { + const sk = window.NostrTools.generateSecretKey(); + const pk = window.NostrTools.getPublicKey(sk); + const nsec = window.NostrTools.nip19.nsecEncode(sk); + const npub = window.NostrTools.nip19.npubEncode(pk); + + this._showKeyDisplay(pk, nsec, 'created'); + } catch (error) { + this._showError('Failed to create key: ' + error.message); + } + } + + + + _detectKeyFormat(keyValue) { + const trimmed = keyValue.trim(); + + // Check for nsec format + if (trimmed.startsWith('nsec1') && trimmed.length === 63) { + try { + window.NostrTools.nip19.decode(trimmed); + return 'nsec'; + } catch { + return 'invalid'; + } + } + + // Check for hex format (64 characters, valid hex) + if (trimmed.length === 64 && /^[a-fA-F0-9]{64}$/.test(trimmed)) { + return 'hex'; + } + + return 'invalid'; + } + + _importLocalKey(keyValue) { + try { + const trimmed = keyValue.trim(); + if (!trimmed) { + throw new Error('Please enter a secret key'); + } + + const format = this._detectKeyFormat(trimmed); + let sk; + + if (format === 'nsec') { + // Decode nsec format - this returns Uint8Array + const decoded = window.NostrTools.nip19.decode(trimmed); + if (decoded.type !== 'nsec') { + throw new Error('Invalid nsec format'); + } + sk = decoded.data; // This is already Uint8Array + } else if (format === 'hex') { + // Convert hex string to Uint8Array + sk = this._hexToUint8Array(trimmed); + // Test that it's a valid secret key by trying to get public key + window.NostrTools.getPublicKey(sk); + } else { + throw new Error('Invalid key format. Please enter either nsec1... or 64-character hex string'); + } + + // Generate public key and encoded formats + const pk = window.NostrTools.getPublicKey(sk); + const nsec = window.NostrTools.nip19.nsecEncode(sk); + const npub = window.NostrTools.nip19.npubEncode(pk); + + this._showKeyDisplay(pk, nsec, 'imported'); + } catch (error) { + this._showError('Invalid key: ' + error.message); + } + } + + _hexToUint8Array(hex) { + // Convert hex string to Uint8Array + if (hex.length % 2 !== 0) { + throw new Error('Invalid hex string length'); + } + const bytes = new Uint8Array(hex.length / 2); + for (let i = 0; i < bytes.length; i++) { + bytes[i] = parseInt(hex.substr(i * 2, 2), 16); + } + return bytes; + } + + _showKeyDisplay(pubkey, nsec, action) { + this.modalBody.innerHTML = ''; + + const title = document.createElement('h3'); + title.textContent = `Key ${action} successfully!`; + title.style.cssText = 'margin: 0 0 16px 0; font-size: 18px; font-weight: 600; color: #059669;'; + + const warningDiv = document.createElement('div'); + warningDiv.textContent = '⚠️ Save your secret key securely!'; + warningDiv.style.cssText = 'background: #fef3c7; color: #92400e; padding: 12px; border-radius: 6px; margin-bottom: 16px; font-size: 12px;'; + + // Helper function to create copy button + const createCopyButton = (text, label) => { + const copyBtn = document.createElement('button'); + copyBtn.textContent = `Copy ${label}`; + copyBtn.style.cssText = ` + margin-left: 8px; + padding: 4px 8px; + font-size: 10px; + background: var(--nl-secondary-color); + color: var(--nl-primary-color); + border: 1px solid var(--nl-primary-color); + border-radius: 4px; + cursor: pointer; + font-family: var(--nl-font-family, 'Courier New', monospace); + `; + copyBtn.onclick = async (e) => { + e.preventDefault(); + try { + await navigator.clipboard.writeText(text); + const originalText = copyBtn.textContent; + copyBtn.textContent = '✓ Copied!'; + copyBtn.style.color = '#059669'; + setTimeout(() => { + copyBtn.textContent = originalText; + copyBtn.style.color = 'var(--nl-primary-color)'; + }, 2000); + } catch (err) { + console.error('Failed to copy:', err); + copyBtn.textContent = '✗ Failed'; + copyBtn.style.color = '#dc2626'; + setTimeout(() => { + copyBtn.textContent = originalText; + copyBtn.style.color = 'var(--nl-primary-color)'; + }, 2000); + } + }; + return copyBtn; + }; + + // Convert pubkey to hex for verification + const pubkeyHex = typeof pubkey === 'string' ? pubkey : Array.from(pubkey).map(b => b.toString(16).padStart(2, '0')).join(''); + + // Decode nsec to get secret key as hex + let secretKeyHex = ''; + try { + const decoded = window.NostrTools.nip19.decode(nsec); + secretKeyHex = Array.from(decoded.data).map(b => b.toString(16).padStart(2, '0')).join(''); + } catch (err) { + console.error('Failed to decode nsec for hex display:', err); + } + + // Secret Key Section + const nsecSection = document.createElement('div'); + nsecSection.style.cssText = 'margin-bottom: 16px;'; + + const nsecLabel = document.createElement('div'); + nsecLabel.innerHTML = 'Your Secret Key (nsec):'; + nsecLabel.style.cssText = 'margin-bottom: 4px; font-size: 12px; font-weight: 600;'; + + const nsecContainer = document.createElement('div'); + nsecContainer.style.cssText = 'margin-bottom: 8px;'; + + const nsecCode = document.createElement('code'); + nsecCode.textContent = nsec; + nsecCode.style.cssText = ` + display: block; + word-wrap: break-word; + overflow-wrap: break-word; + background: #f3f4f6; + padding: 6px; + border-radius: 4px; + font-size: 10px; + line-height: 1.3; + font-family: 'Courier New', monospace; + margin-bottom: 4px; + `; + + const nsecCopyBtn = createCopyButton(nsec, 'nsec'); + nsecCopyBtn.style.cssText += 'display: inline-block; margin-left: 0;'; + + nsecContainer.appendChild(nsecCode); + nsecContainer.appendChild(nsecCopyBtn); + nsecSection.appendChild(nsecLabel); + nsecSection.appendChild(nsecContainer); + + // Secret Key Hex Section + if (secretKeyHex) { + const secretHexLabel = document.createElement('div'); + secretHexLabel.innerHTML = 'Secret Key (hex):'; + secretHexLabel.style.cssText = 'margin-bottom: 4px; font-size: 12px; font-weight: 600;'; + + const secretHexContainer = document.createElement('div'); + secretHexContainer.style.cssText = 'margin-bottom: 8px;'; + + const secretHexCode = document.createElement('code'); + secretHexCode.textContent = secretKeyHex; + secretHexCode.style.cssText = ` + display: block; + word-wrap: break-word; + overflow-wrap: break-word; + background: #f3f4f6; + padding: 6px; + border-radius: 4px; + font-size: 10px; + line-height: 1.3; + font-family: 'Courier New', monospace; + margin-bottom: 4px; + `; + + const secretHexCopyBtn = createCopyButton(secretKeyHex, 'hex'); + secretHexCopyBtn.style.cssText += 'display: inline-block; margin-left: 0;'; + + secretHexContainer.appendChild(secretHexCode); + secretHexContainer.appendChild(secretHexCopyBtn); + nsecSection.appendChild(secretHexLabel); + nsecSection.appendChild(secretHexContainer); + } + + // Public Key Section + const npubSection = document.createElement('div'); + npubSection.style.cssText = 'margin-bottom: 16px;'; + + const npub = window.NostrTools.nip19.npubEncode(pubkey); + + const npubLabel = document.createElement('div'); + npubLabel.innerHTML = 'Your Public Key (npub):'; + npubLabel.style.cssText = 'margin-bottom: 4px; font-size: 12px; font-weight: 600;'; + + const npubContainer = document.createElement('div'); + npubContainer.style.cssText = 'margin-bottom: 8px;'; + + const npubCode = document.createElement('code'); + npubCode.textContent = npub; + npubCode.style.cssText = ` + display: block; + word-wrap: break-word; + overflow-wrap: break-word; + background: #f3f4f6; + padding: 6px; + border-radius: 4px; + font-size: 10px; + line-height: 1.3; + font-family: 'Courier New', monospace; + margin-bottom: 4px; + `; + + const npubCopyBtn = createCopyButton(npub, 'npub'); + npubCopyBtn.style.cssText += 'display: inline-block; margin-left: 0;'; + + npubContainer.appendChild(npubCode); + npubContainer.appendChild(npubCopyBtn); + npubSection.appendChild(npubLabel); + npubSection.appendChild(npubContainer); + + // Public Key Hex Section + const pubHexLabel = document.createElement('div'); + pubHexLabel.innerHTML = 'Public Key (hex):'; + pubHexLabel.style.cssText = 'margin-bottom: 4px; font-size: 12px; font-weight: 600;'; + + const pubHexContainer = document.createElement('div'); + pubHexContainer.style.cssText = ''; + + const pubHexCode = document.createElement('code'); + pubHexCode.textContent = pubkeyHex; + pubHexCode.style.cssText = ` + display: block; + word-wrap: break-word; + overflow-wrap: break-word; + background: #f3f4f6; + padding: 6px; + border-radius: 4px; + font-size: 10px; + line-height: 1.3; + font-family: 'Courier New', monospace; + margin-bottom: 4px; + `; + + const pubHexCopyBtn = createCopyButton(pubkeyHex, 'hex'); + pubHexCopyBtn.style.cssText += 'display: inline-block; margin-left: 0;'; + + pubHexContainer.appendChild(pubHexCode); + pubHexContainer.appendChild(pubHexCopyBtn); + npubSection.appendChild(pubHexLabel); + npubSection.appendChild(pubHexContainer); + + const continueButton = document.createElement('button'); + continueButton.textContent = 'Continue'; + continueButton.onclick = () => this._setAuthMethod('local', { secret: nsec, pubkey }); + continueButton.style.cssText = this._getButtonStyle(); + + this.modalBody.appendChild(title); + this.modalBody.appendChild(warningDiv); + this.modalBody.appendChild(nsecSection); + this.modalBody.appendChild(npubSection); + this.modalBody.appendChild(continueButton); + } + + _setAuthMethod(method, options = {}) { + console.log('Modal: _setAuthMethod called with:', method, options); + + // CRITICAL: Never install facade for extension methods - leave window.nostr as the extension + if (method === 'extension') { + console.log('Modal: Extension method - NOT installing facade, leaving window.nostr as extension'); + + // Save extension authentication state using global setAuthState function + if (typeof window.setAuthState === 'function') { + console.log('Modal: Saving extension auth state to storage'); + window.setAuthState({ method, ...options }, { isolateSession: this.options?.isolateSession }); + } + + // Emit auth method selection directly for extension + const event = new CustomEvent('nlMethodSelected', { + detail: { method, ...options } + }); + window.dispatchEvent(event); + + this.close(); + return; + } + + // FOR NON-EXTENSION METHODS: Force-install facade with resilience + console.log('Modal: Non-extension method - FORCE-INSTALLING facade with resilience:', method); + + // Store the current extension if any (for potential restoration later) + const currentExtension = (window.nostr?.constructor?.name !== 'WindowNostr') ? window.nostr : null; + + // Get NostrLite instance for facade operations + const nostrLiteInstance = window.NOSTR_LOGIN_LITE?._instance; + if (!nostrLiteInstance || typeof nostrLiteInstance._installFacade !== 'function') { + console.error('Modal: Cannot access NostrLite instance or _installFacade method'); + // Fallback: emit event anyway + const event = new CustomEvent('nlMethodSelected', { + detail: { method, ...options } + }); + window.dispatchEvent(event); + this.close(); + return; + } + + // IMMEDIATE FACADE INSTALLATION + console.log('Modal: Installing WindowNostr facade immediately for method:', method); + const preservedExtension = nostrLiteInstance.preservedExtension || currentExtension; + nostrLiteInstance._installFacade(preservedExtension, true); + console.log('Modal: WindowNostr facade force-installed, current window.nostr:', window.nostr?.constructor?.name); + + // DELAYED FACADE RESILIENCE - Reinstall after extension override attempts + const forceReinstallFacade = () => { + console.log('Modal: RESILIENCE CHECK - Current window.nostr after delay:', window.nostr?.constructor?.name); + + // If facade was overridden by extension, reinstall it + if (window.nostr?.constructor?.name !== 'WindowNostr') { + console.log('Modal: FACADE OVERRIDDEN! Force-reinstalling WindowNostr facade for user choice:', method); + nostrLiteInstance._installFacade(preservedExtension, true); + console.log('Modal: Resilient facade force-reinstall complete, window.nostr:', window.nostr?.constructor?.name); + + // Schedule another check in case of persistent extension override + setTimeout(() => { + if (window.nostr?.constructor?.name !== 'WindowNostr') { + console.log('Modal: PERSISTENT OVERRIDE! Final facade force-reinstall for method:', method); + nostrLiteInstance._installFacade(preservedExtension, true); + } + }, 1000); + } else { + console.log('Modal: Facade persistence verified - no override detected'); + } + }; + + // Schedule resilience checks at multiple intervals + setTimeout(forceReinstallFacade, 100); // Quick check + setTimeout(forceReinstallFacade, 500); // Main check + setTimeout(forceReinstallFacade, 1500); // Final check + + // Emit auth method selection + const event = new CustomEvent('nlMethodSelected', { + detail: { method, ...options } + }); + window.dispatchEvent(event); + + this.close(); + } + + _showError(message) { + this.modalBody.innerHTML = ''; + + const errorDiv = document.createElement('div'); + errorDiv.style.cssText = 'background: #fee2e2; color: #dc2626; padding: 16px; border-radius: 6px; margin-bottom: 16px;'; + errorDiv.innerHTML = `Error: ${message}`; + + const backButton = document.createElement('button'); + backButton.textContent = 'Back'; + backButton.onclick = () => this._renderLoginOptions(); + backButton.style.cssText = this._getButtonStyle('secondary'); + + this.modalBody.appendChild(errorDiv); + this.modalBody.appendChild(backButton); + } + + _showExtensionRequired() { + this.modalBody.innerHTML = ''; + + const title = document.createElement('h3'); + title.textContent = 'Browser Extension Required'; + title.style.cssText = 'margin: 0 0 16px 0; font-size: 18px; font-weight: 600;'; + + const message = document.createElement('p'); + message.innerHTML = ` + Please install a Nostr browser extension and refresh the page.

+ Important: If you have multiple extensions installed, please disable all but one to avoid conflicts. +

+ Popular extensions: Alby, nos2x, Flamingo + `; + message.style.cssText = 'margin-bottom: 20px; color: #6b7280; font-size: 14px; line-height: 1.4;'; + + const backButton = document.createElement('button'); + backButton.textContent = 'Back'; + backButton.onclick = () => this._renderLoginOptions(); + backButton.style.cssText = this._getButtonStyle('secondary'); + + this.modalBody.appendChild(title); + this.modalBody.appendChild(message); + this.modalBody.appendChild(backButton); + } + + _showConnectScreen() { + this.modalBody.innerHTML = ''; + + const description = document.createElement('p'); + description.textContent = 'Connect to a remote signer (bunker) server to use its keys for signing.'; + description.style.cssText = 'margin-bottom: 20px; color: #6b7280; font-size: 14px;'; + + const formGroup = document.createElement('div'); + formGroup.style.cssText = 'margin-bottom: 20px;'; + + const label = document.createElement('label'); + label.textContent = 'Bunker Public Key:'; + label.style.cssText = 'display: block; margin-bottom: 8px; font-weight: 500;'; + + const pubkeyInput = document.createElement('input'); + pubkeyInput.type = 'text'; + pubkeyInput.placeholder = 'bunker://pubkey?relay=..., bunker:hex, hex, or npub...'; + pubkeyInput.style.cssText = ` + width: 100%; + padding: 12px; + border: 1px solid #d1d5db; + border-radius: 6px; + margin-bottom: 12px; + font-family: monospace; + box-sizing: border-box; + `; + + // Add real-time bunker key validation + const formatHint = document.createElement('div'); + formatHint.style.cssText = 'margin-bottom: 16px; font-size: 12px; color: #6b7280; min-height: 16px;'; + + const connectButton = document.createElement('button'); + connectButton.textContent = 'Connect to Bunker'; + connectButton.disabled = true; + connectButton.onclick = () => { + if (!connectButton.disabled) { + this._handleNip46Connect(pubkeyInput.value); + } + }; + + // Set initial disabled state + connectButton.style.cssText = ` + display: block; + width: 100%; + padding: 12px; + border: var(--nl-border-width) solid var(--nl-muted-color); + border-radius: var(--nl-border-radius); + font-size: 16px; + font-weight: 500; + cursor: not-allowed; + transition: all 0.2s; + font-family: var(--nl-font-family, 'Courier New', monospace); + background: var(--nl-secondary-color); + color: var(--nl-muted-color); + margin-bottom: 12px; + `; + + pubkeyInput.oninput = () => { + const value = pubkeyInput.value.trim(); + if (!value) { + formatHint.textContent = ''; + // Disable button + connectButton.disabled = true; + connectButton.style.borderColor = 'var(--nl-muted-color)'; + connectButton.style.color = 'var(--nl-muted-color)'; + connectButton.style.cursor = 'not-allowed'; + return; + } + + const isValid = this._validateBunkerKey(value); + if (isValid) { + formatHint.textContent = '✅ Valid bunker connection format detected'; + formatHint.style.color = '#059669'; + // Enable button + connectButton.disabled = false; + connectButton.style.borderColor = 'var(--nl-primary-color)'; + connectButton.style.color = 'var(--nl-primary-color)'; + connectButton.style.cursor = 'pointer'; + } else { + formatHint.textContent = '❌ Invalid format - must be bunker://, npub, or 64-char hex'; + formatHint.style.color = '#dc2626'; + // Disable button + connectButton.disabled = true; + connectButton.style.borderColor = 'var(--nl-muted-color)'; + connectButton.style.color = 'var(--nl-muted-color)'; + connectButton.style.cursor = 'not-allowed'; + } + }; + + const backButton = document.createElement('button'); + backButton.textContent = 'Back'; + backButton.onclick = () => this._renderLoginOptions(); + backButton.style.cssText = this._getButtonStyle('secondary') + 'margin-top: 12px;'; + + formGroup.appendChild(label); + formGroup.appendChild(pubkeyInput); + formGroup.appendChild(formatHint); + + this.modalBody.appendChild(description); + this.modalBody.appendChild(formGroup); + this.modalBody.appendChild(connectButton); + this.modalBody.appendChild(backButton); + } + + _validateBunkerKey(bunkerKey) { + try { + const trimmed = bunkerKey.trim(); + + // Check for bunker:// format + if (trimmed.startsWith('bunker://')) { + // Should have format: bunker://pubkey or bunker://pubkey?param=value + const match = trimmed.match(/^bunker:\/\/([0-9a-fA-F]{64})(\?.*)?$/); + return !!match; + } + + // Check for npub format + if (trimmed.startsWith('npub1') && trimmed.length === 63) { + try { + if (window.NostrTools?.nip19) { + const decoded = window.NostrTools.nip19.decode(trimmed); + return decoded.type === 'npub'; + } + } catch { + return false; + } + } + + // Check for hex format (64 characters, valid hex) + if (trimmed.length === 64 && /^[a-fA-F0-9]{64}$/.test(trimmed)) { + return true; + } + + return false; + } catch (error) { + console.log('Bunker key validation failed:', error.message); + return false; + } + } + + _handleNip46Connect(bunkerPubkey) { + if (!bunkerPubkey || !bunkerPubkey.length) { + this._showError('Bunker pubkey is required'); + return; + } + + this._showNip46Connecting(bunkerPubkey); + this._performNip46Connect(bunkerPubkey); + } + + _showNip46Connecting(bunkerPubkey) { + this.modalBody.innerHTML = ''; + + const title = document.createElement('h3'); + title.textContent = 'Connecting to Remote Signer...'; + title.style.cssText = 'margin: 0 0 16px 0; font-size: 18px; font-weight: 600; color: #059669;'; + + const description = document.createElement('p'); + description.textContent = 'Establishing secure connection to your remote signer.'; + description.style.cssText = 'margin-bottom: 20px; color: #6b7280;'; + + // Normalize bunker pubkey for display (= show original format if bunker: prefix) + const displayPubkey = bunkerPubkey.startsWith('bunker:') || bunkerPubkey.startsWith('npub') || bunkerPubkey.length === 64 ? bunkerPubkey : bunkerPubkey; + + const bunkerInfo = document.createElement('div'); + bunkerInfo.style.cssText = 'background: #f1f5f9; padding: 12px; border-radius: 6px; margin-bottom: 20px; font-size: 14px;'; + bunkerInfo.innerHTML = ` + Connecting to bunker:
+ Connection: ${displayPubkey}
+ Connection string contains all necessary relay information. + `; + + const connectingDiv = document.createElement('div'); + connectingDiv.style.cssText = 'text-align: center; color: #6b7280;'; + connectingDiv.innerHTML = ` +
+
Please wait while we establish the connection...
+
This may take a few seconds
+ `; + + this.modalBody.appendChild(title); + this.modalBody.appendChild(description); + this.modalBody.appendChild(bunkerInfo); + this.modalBody.appendChild(connectingDiv); + } + + async _performNip46Connect(bunkerPubkey) { + try { + console.log('Starting NIP-46 connection to bunker:', bunkerPubkey); + + // Check if nostr-tools NIP-46 is available + if (!window.NostrTools?.nip46) { + throw new Error('nostr-tools NIP-46 module not available'); + } + + // Use nostr-tools to parse bunker input - this handles all formats correctly + console.log('Parsing bunker input with nostr-tools...'); + const bunkerPointer = await window.NostrTools.nip46.parseBunkerInput(bunkerPubkey); + + if (!bunkerPointer) { + throw new Error('Unable to parse bunker connection string or resolve NIP-05 identifier'); + } + + console.log('Parsed bunker pointer:', bunkerPointer); + + // Create local client keypair for this session + const localSecretKey = window.NostrTools.generateSecretKey(); + console.log('Generated local client keypair for NIP-46 session'); + + // Use nostr-tools BunkerSigner factory method (not constructor - it's private) + console.log('Creating nip46 BunkerSigner...'); + const signer = window.NostrTools.nip46.BunkerSigner.fromBunker(localSecretKey, bunkerPointer, { + onauth: (url) => { + console.log('Received auth URL from bunker:', url); + // Open auth URL in popup or redirect + window.open(url, '_blank', 'width=600,height=800'); + } + }); + + console.log('NIP-46 BunkerSigner created successfully'); + + // Skip ping test - NIP-46 works through relays, not direct connection + // Try to connect directly (this may trigger auth flow) + console.log('Attempting NIP-46 connect...'); + await signer.connect(); + console.log('NIP-46 connect successful'); + + // Get the user's public key from the bunker + console.log('Getting public key from bunker...'); + const userPubkey = await signer.getPublicKey(); + console.log('NIP-46 user public key:', userPubkey); + + // Store the NIP-46 authentication info + const nip46Info = { + pubkey: userPubkey, + signer: { + method: 'nip46', + remotePubkey: bunkerPointer.pubkey, + bunkerSigner: signer, + secret: bunkerPointer.secret, + relays: bunkerPointer.relays + } + }; + + console.log('NOSTR_LOGIN_LITE NIP-46 connection established successfully!'); + + // Set as current auth method + this._setAuthMethod('nip46', nip46Info); + return; + + } catch (error) { + console.error('NIP-46 connection failed:', error); + this._showNip46Error(error.message); + } + } + + _showNip46Error(message) { + this.modalBody.innerHTML = ''; + + const title = document.createElement('h3'); + title.textContent = 'Connection Failed'; + title.style.cssText = 'margin: 0 0 16px 0; font-size: 18px; font-weight: 600; color: #dc2626;'; + + const errorMsg = document.createElement('p'); + errorMsg.textContent = `Unable to connect to remote signer: ${message}`; + errorMsg.style.cssText = 'margin-bottom: 20px; color: #6b7280;'; + + const retryButton = document.createElement('button'); + retryButton.textContent = 'Try Again'; + retryButton.onclick = () => this._showConnectScreen(); + retryButton.style.cssText = this._getButtonStyle(); + + const backButton = document.createElement('button'); + backButton.textContent = 'Back to Options'; + backButton.onclick = () => this._renderLoginOptions(); + backButton.style.cssText = this._getButtonStyle('secondary') + 'margin-top: 12px;'; + + this.modalBody.appendChild(title); + this.modalBody.appendChild(errorMsg); + this.modalBody.appendChild(retryButton); + this.modalBody.appendChild(backButton); + } + + _handleReadonly() { + // Set read-only mode + this._setAuthMethod('readonly'); + } + + _showSeedPhraseScreen() { + this.modalBody.innerHTML = ''; + + const description = document.createElement('p'); + description.innerHTML = 'Enter your 12 or 24-word mnemonic seed phrase to derive Nostr accounts, or generate new.'; + description.style.cssText = 'margin-bottom: 12px; color: #6b7280; font-size: 14px;'; + + const textarea = document.createElement('textarea'); + // Remove default placeholder text as requested + textarea.placeholder = ''; + textarea.style.cssText = ` + width: 100%; + height: 100px; + padding: 12px; + border: 1px solid #d1d5db; + border-radius: 6px; + margin-bottom: 12px; + resize: none; + font-family: monospace; + font-size: 14px; + box-sizing: border-box; + `; + + // Add real-time mnemonic validation + const formatHint = document.createElement('div'); + formatHint.style.cssText = 'margin-bottom: 16px; font-size: 12px; color: #6b7280; min-height: 16px;'; + + const importButton = document.createElement('button'); + importButton.textContent = 'Import Accounts'; + importButton.disabled = true; + importButton.onclick = () => { + if (!importButton.disabled) { + this._importFromSeedPhrase(textarea.value); + } + }; + + // Set initial disabled state + importButton.style.cssText = ` + display: block; + width: 100%; + padding: 12px; + border: var(--nl-border-width) solid var(--nl-muted-color); + border-radius: var(--nl-border-radius); + font-size: 16px; + font-weight: 500; + cursor: not-allowed; + transition: all 0.2s; + font-family: var(--nl-font-family, 'Courier New', monospace); + background: var(--nl-secondary-color); + color: var(--nl-muted-color); + `; + + textarea.oninput = () => { + const value = textarea.value.trim(); + if (!value) { + formatHint.textContent = ''; + // Disable button + importButton.disabled = true; + importButton.style.borderColor = 'var(--nl-muted-color)'; + importButton.style.color = 'var(--nl-muted-color)'; + importButton.style.cursor = 'not-allowed'; + return; + } + + const isValid = this._validateMnemonic(value); + if (isValid) { + const wordCount = value.split(/\s+/).length; + formatHint.textContent = `✅ Valid ${wordCount}-word mnemonic detected`; + formatHint.style.color = '#059669'; + // Enable button + importButton.disabled = false; + importButton.style.borderColor = 'var(--nl-primary-color)'; + importButton.style.color = 'var(--nl-primary-color)'; + importButton.style.cursor = 'pointer'; + } else { + formatHint.textContent = '❌ Invalid mnemonic - must be 12 or 24 valid BIP-39 words'; + formatHint.style.color = '#dc2626'; + // Disable button + importButton.disabled = true; + importButton.style.borderColor = 'var(--nl-muted-color)'; + importButton.style.color = 'var(--nl-muted-color)'; + importButton.style.cursor = 'not-allowed'; + } + }; + + const backButton = document.createElement('button'); + backButton.textContent = 'Back'; + backButton.onclick = () => this._renderLoginOptions(); + backButton.style.cssText = this._getButtonStyle('secondary') + 'margin-top: 12px;'; + + this.modalBody.appendChild(description); + this.modalBody.appendChild(textarea); + this.modalBody.appendChild(formatHint); + this.modalBody.appendChild(importButton); + this.modalBody.appendChild(backButton); + + // Add click handler for the "generate new" link + const generateLink = document.getElementById('generate-new'); + if (generateLink) { + generateLink.addEventListener('mouseenter', () => { + generateLink.style.color = 'var(--nl-accent-color)'; + }); + generateLink.addEventListener('mouseleave', () => { + generateLink.style.color = 'var(--nl-primary-color)'; + }); + generateLink.addEventListener('click', () => { + this._generateNewSeedPhrase(textarea, formatHint); + }); + } + } + + _generateNewSeedPhrase(textarea, formatHint) { + try { + // Check if NIP-06 is available + if (!window.NostrTools?.nip06) { + throw new Error('NIP-06 not available in bundle'); + } + + // Generate a random 12-word mnemonic using NostrTools + const mnemonic = window.NostrTools.nip06.generateSeedWords(); + + // Set the generated mnemonic in the textarea + textarea.value = mnemonic; + + // Trigger the oninput event to properly validate and enable the button + if (textarea.oninput) { + textarea.oninput(); + } + + console.log('Generated new seed phrase:', mnemonic.split(/\s+/).length, 'words'); + + } catch (error) { + console.error('Failed to generate seed phrase:', error); + formatHint.textContent = '❌ Failed to generate seed phrase - NIP-06 not available'; + formatHint.style.color = '#dc2626'; + } + } + + _validateMnemonic(mnemonic) { + try { + // Check if NIP-06 is available + if (!window.NostrTools?.nip06) { + console.error('NIP-06 not available in bundle'); + return false; + } + + const words = mnemonic.trim().split(/\s+/); + + // Must be 12 or 24 words + if (words.length !== 12 && words.length !== 24) { + return false; + } + + // Try to validate using NostrTools nip06 - this will throw if invalid + window.NostrTools.nip06.privateKeyFromSeedWords(mnemonic, '', 0); + return true; + } catch (error) { + console.log('Mnemonic validation failed:', error.message); + return false; + } + } + + _importFromSeedPhrase(mnemonic) { + try { + const trimmed = mnemonic.trim(); + if (!trimmed) { + throw new Error('Please enter a mnemonic seed phrase'); + } + + // Validate the mnemonic + if (!this._validateMnemonic(trimmed)) { + throw new Error('Invalid mnemonic. Please enter a valid 12 or 24-word BIP-39 seed phrase'); + } + + // Generate accounts 0-5 using NIP-06 + const accounts = []; + for (let i = 0; i < 6; i++) { + try { + const privateKey = window.NostrTools.nip06.privateKeyFromSeedWords(trimmed, '', i); + const publicKey = window.NostrTools.getPublicKey(privateKey); + const nsec = window.NostrTools.nip19.nsecEncode(privateKey); + const npub = window.NostrTools.nip19.npubEncode(publicKey); + + accounts.push({ + index: i, + privateKey, + publicKey, + nsec, + npub + }); + } catch (error) { + console.error(`Failed to derive account ${i}:`, error); + } + } + + if (accounts.length === 0) { + throw new Error('Failed to derive any accounts from seed phrase'); + } + + console.log(`Successfully derived ${accounts.length} accounts from seed phrase`); + this._showAccountSelection(accounts); + + } catch (error) { + console.error('Seed phrase import failed:', error); + this._showError('Seed phrase import failed: ' + error.message); + } + } + + _showAccountSelection(accounts) { + this.modalBody.innerHTML = ''; + + const description = document.createElement('p'); + description.textContent = `Select which account to use (${accounts.length} accounts derived from seed phrase):`; + description.style.cssText = 'margin-bottom: 20px; color: #6b7280; font-size: 14px;'; + + this.modalBody.appendChild(description); + + // Create table for account selection + const table = document.createElement('table'); + table.style.cssText = ` + width: 100%; + border-collapse: collapse; + margin-bottom: 20px; + font-family: var(--nl-font-family, 'Courier New', monospace); + font-size: 12px; + `; + + // Table header + const thead = document.createElement('thead'); + thead.innerHTML = ` + + # + Use + + `; + table.appendChild(thead); + + // Table body + const tbody = document.createElement('tbody'); + accounts.forEach(account => { + const row = document.createElement('tr'); + row.style.cssText = 'border: 1px solid #d1d5db;'; + + const indexCell = document.createElement('td'); + indexCell.textContent = account.index; + indexCell.style.cssText = 'padding: 8px; text-align: center; border: 1px solid #d1d5db; font-weight: bold;'; + + const actionCell = document.createElement('td'); + actionCell.style.cssText = 'padding: 8px; border: 1px solid #d1d5db;'; + + // Show truncated npub in the button + const truncatedNpub = `${account.npub.slice(0, 12)}...${account.npub.slice(-8)}`; + + const selectButton = document.createElement('button'); + selectButton.textContent = truncatedNpub; + selectButton.onclick = () => this._selectAccount(account); + selectButton.style.cssText = ` + width: 100%; + padding: 8px 12px; + font-size: 11px; + background: var(--nl-secondary-color); + color: var(--nl-primary-color); + border: 1px solid var(--nl-primary-color); + border-radius: 4px; + cursor: pointer; + font-family: 'Courier New', monospace; + text-align: center; + `; + selectButton.onmouseover = () => { + selectButton.style.borderColor = 'var(--nl-accent-color)'; + }; + selectButton.onmouseout = () => { + selectButton.style.borderColor = 'var(--nl-primary-color)'; + }; + + actionCell.appendChild(selectButton); + + row.appendChild(indexCell); + row.appendChild(actionCell); + tbody.appendChild(row); + }); + table.appendChild(tbody); + + this.modalBody.appendChild(table); + + // Back button + const backButton = document.createElement('button'); + backButton.textContent = 'Back to Seed Phrase'; + backButton.onclick = () => this._showSeedPhraseScreen(); + backButton.style.cssText = this._getButtonStyle('secondary'); + + this.modalBody.appendChild(backButton); + } + + _selectAccount(account) { + console.log('Selected account:', account.index, account.npub); + + // Use the same auth method as local keys, but with seedphrase identifier + this._setAuthMethod('local', { + secret: account.nsec, + pubkey: account.publicKey, + source: 'seedphrase', + accountIndex: account.index + }); + } + + _showOtpScreen() { + // Placeholder for OTP functionality + this._showError('OTP/DM not yet implemented - coming soon!'); + } + + _getButtonStyle(type = 'primary') { + const baseStyle = ` + display: block; + width: 100%; + padding: 12px; + border: var(--nl-border-width) solid var(--nl-primary-color); + border-radius: var(--nl-border-radius); + font-size: 16px; + font-weight: 500; + cursor: pointer; + transition: all 0.2s; + font-family: var(--nl-font-family, 'Courier New', monospace); + `; + + if (type === 'primary') { + return baseStyle + ` + background: var(--nl-secondary-color); + color: var(--nl-primary-color); + `; + } else { + return baseStyle + ` + background: #cccccc; + color: var(--nl-primary-color); + `; + } + } + + // Public API + static init(options) { + if (Modal.instance) return Modal.instance; + Modal.instance = new Modal(options); + return Modal.instance; + } + + static getInstance() { + return Modal.instance; + } +} + +// Initialize global instance +let modalInstance = null; + +window.addEventListener('load', () => { + modalInstance = new Modal(); +}); + + +// ====================================== +// FloatingTab Component (Recovered from git history) +// ====================================== + +class FloatingTab { + constructor(modal, options = {}) { + this.modal = modal; + this.options = { + enabled: true, + hPosition: 1.0, // 0.0 = left, 1.0 = right + vPosition: 0.5, // 0.0 = top, 1.0 = bottom + offset: { x: 0, y: 0 }, + appearance: { + style: 'pill', // 'pill', 'square', 'circle' + theme: 'auto', // 'auto', 'light', 'dark' + icon: '', + text: 'Login', + iconOnly: false + }, + behavior: { + hideWhenAuthenticated: true, + showUserInfo: true, + autoSlide: true, + persistent: false + }, + getUserInfo: false, + getUserRelay: [], + ...options + }; + + this.userProfile = null; + this.container = null; + this.isVisible = false; + + if (this.options.enabled) { + this._init(); + } + } + + _init() { + console.log('FloatingTab: Initializing with options:', this.options); + this._createContainer(); + this._setupEventListeners(); + this._updateAppearance(); + this._position(); + this.show(); + } + + // Get authentication state from authoritative source (Global Storage-Based Function) + _getAuthState() { + return window.NOSTR_LOGIN_LITE?.getAuthState?.() || null; + } + + + _createContainer() { + // Remove existing floating tab if any + const existingTab = document.getElementById('nl-floating-tab'); + if (existingTab) { + existingTab.remove(); + } + + this.container = document.createElement('div'); + this.container.id = 'nl-floating-tab'; + this.container.className = 'nl-floating-tab'; + + // Base styles - positioning and behavior + this.container.style.cssText = ` + position: fixed; + z-index: 9999; + cursor: pointer; + user-select: none; + display: flex; + align-items: center; + justify-content: center; + transition: all 0.2s ease; + font-size: 14px; + font-weight: 500; + padding: 8px 16px; + min-width: 80px; + max-width: 200px; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + `; + + document.body.appendChild(this.container); + } + + _setupEventListeners() { + if (!this.container) return; + + // Click handler + this.container.addEventListener('click', (e) => { + e.preventDefault(); + e.stopPropagation(); + this._handleClick(); + }); + + // Hover effects + this.container.addEventListener('mouseenter', () => { + if (this.options.behavior.autoSlide) { + this._slideIn(); + } + }); + + this.container.addEventListener('mouseleave', () => { + if (this.options.behavior.autoSlide) { + this._slideOut(); + } + }); + + // Listen for authentication events + window.addEventListener('nlMethodSelected', (e) => { + console.log('🔍 FloatingTab: Authentication method selected event received'); + console.log('🔍 FloatingTab: Event detail:', e.detail); + this._handleAuth(e.detail); + }); + + window.addEventListener('nlAuthRestored', (e) => { + console.log('🔍 FloatingTab: ✅ Authentication restored event received'); + console.log('🔍 FloatingTab: Event detail:', e.detail); + console.log('🔍 FloatingTab: Calling _handleAuth with restored data...'); + this._handleAuth(e.detail); + }); + + window.addEventListener('nlLogout', () => { + console.log('🔍 FloatingTab: Logout event received'); + this._handleLogout(); + }); + + // Check for existing authentication state on initialization + window.addEventListener('load', () => { + setTimeout(() => { + this._checkExistingAuth(); + }, 1000); // Wait 1 second for all initialization to complete + }); + } + + // Check for existing authentication on page load + async _checkExistingAuth() { + console.log('🔍 FloatingTab: === _checkExistingAuth START ==='); + + try { + const storageKey = 'nostr_login_lite_auth'; + let storedAuth = null; + + // Try sessionStorage first, then localStorage + if (sessionStorage.getItem(storageKey)) { + storedAuth = JSON.parse(sessionStorage.getItem(storageKey)); + console.log('🔍 FloatingTab: Found auth in sessionStorage:', storedAuth.method); + } else if (localStorage.getItem(storageKey)) { + storedAuth = JSON.parse(localStorage.getItem(storageKey)); + console.log('🔍 FloatingTab: Found auth in localStorage:', storedAuth.method); + } + + if (storedAuth) { + // Check if stored auth is not expired + const maxAge = storedAuth.method === 'extension' ? 60 * 60 * 1000 : 24 * 60 * 60 * 1000; + if (Date.now() - storedAuth.timestamp <= maxAge) { + console.log('🔍 FloatingTab: Found valid stored auth, simulating auth event'); + + // Create auth data object for FloatingTab + const authData = { + method: storedAuth.method, + pubkey: storedAuth.pubkey + }; + + // For extensions, try to find the extension + if (storedAuth.method === 'extension') { + if (window.nostr && window.nostr.constructor?.name !== 'WindowNostr') { + authData.extension = window.nostr; + } + } + + await this._handleAuth(authData); + } else { + console.log('🔍 FloatingTab: Stored auth expired, clearing'); + sessionStorage.removeItem(storageKey); + localStorage.removeItem(storageKey); + } + } else { + console.log('🔍 FloatingTab: No existing authentication found'); + } + + } catch (error) { + console.error('🔍 FloatingTab: Error checking existing auth:', error); + } + + console.log('🔍 FloatingTab: === _checkExistingAuth END ==='); + } + + _handleClick() { + console.log('FloatingTab: Clicked'); + + const authState = this._getAuthState(); + if (authState && this.options.behavior.showUserInfo) { + // Show user menu or profile options + this._showUserMenu(); + } else { + // Always open login modal (consistent with login buttons) + if (this.modal) { + this.modal.open({ startScreen: 'login' }); + } + } + } + + // Check if object is a real extension (same logic as NostrLite._isRealExtension) + _isRealExtension(obj) { + if (!obj || typeof obj !== 'object') { + return false; + } + + // Must have required Nostr methods + if (typeof obj.getPublicKey !== 'function' || typeof obj.signEvent !== 'function') { + return false; + } + + // Exclude our own library classes + const constructorName = obj.constructor?.name; + if (constructorName === 'WindowNostr' || constructorName === 'NostrLite') { + return false; + } + + // Exclude NostrTools library object + if (obj === window.NostrTools) { + return false; + } + + // Conservative check: Look for common extension characteristics + const extensionIndicators = [ + '_isEnabled', 'enabled', 'kind', '_eventEmitter', '_scope', + '_requests', '_pubkey', 'name', 'version', 'description' + ]; + + const hasIndicators = extensionIndicators.some(prop => obj.hasOwnProperty(prop)); + + // Additional check: Extensions often have specific constructor patterns + const hasExtensionConstructor = constructorName && + constructorName !== 'Object' && + constructorName !== 'Function'; + + return hasIndicators || hasExtensionConstructor; + } + + // Try to login with extension and trigger proper persistence + async _tryExtensionLogin(extension) { + try { + console.log('FloatingTab: Attempting extension login'); + + // Get pubkey from extension + const pubkey = await extension.getPublicKey(); + console.log('FloatingTab: Extension provided pubkey:', pubkey); + + // Create extension auth data + const extensionAuth = { + method: 'extension', + pubkey: pubkey, + extension: extension + }; + + // **CRITICAL FIX**: Dispatch nlMethodSelected event to trigger persistence + console.log('FloatingTab: Dispatching nlMethodSelected for persistence'); + if (typeof window !== 'undefined') { + window.dispatchEvent(new CustomEvent('nlMethodSelected', { + detail: extensionAuth + })); + } + + // Also call our local _handleAuth for UI updates + await this._handleAuth(extensionAuth); + + } catch (error) { + console.error('FloatingTab: Extension login failed:', error); + // Fall back to opening modal + if (this.modal) { + this.modal.open({ startScreen: 'login' }); + } + } + } + + async _handleAuth(authData) { + console.log('🔍 FloatingTab: === _handleAuth START ==='); + console.log('🔍 FloatingTab: authData received:', authData); + + // Wait a brief moment for WindowNostr to process the authentication + setTimeout(async () => { + console.log('🔍 FloatingTab: Checking authentication state from authoritative source...'); + + const authState = this._getAuthState(); + const isAuthenticated = !!authState; + + console.log('🔍 FloatingTab: Authoritative auth state:', authState); + console.log('🔍 FloatingTab: Is authenticated:', isAuthenticated); + + if (isAuthenticated) { + console.log('🔍 FloatingTab: ✅ Authentication verified from authoritative source'); + } else { + console.error('🔍 FloatingTab: ❌ Authentication not found in authoritative source'); + } + + // Fetch user profile if enabled and we have a pubkey + if (this.options.getUserInfo && authData.pubkey) { + console.log('🔍 FloatingTab: getUserInfo enabled, fetching profile for:', authData.pubkey); + try { + const profile = await this._fetchUserProfile(authData.pubkey); + this.userProfile = profile; + console.log('🔍 FloatingTab: User profile fetched:', profile); + } catch (error) { + console.warn('🔍 FloatingTab: Failed to fetch user profile:', error); + this.userProfile = null; + } + } else { + console.log('🔍 FloatingTab: getUserInfo disabled or no pubkey, skipping profile fetch'); + } + + this._updateAppearance(); // Update UI based on authoritative state + + console.log('🔍 FloatingTab: hideWhenAuthenticated option:', this.options.behavior.hideWhenAuthenticated); + + if (this.options.behavior.hideWhenAuthenticated && isAuthenticated) { + console.log('🔍 FloatingTab: Hiding tab (hideWhenAuthenticated=true and authenticated)'); + this.hide(); + } else { + console.log('🔍 FloatingTab: Keeping tab visible'); + } + + }, 500); // Wait 500ms for WindowNostr to complete authentication processing + + console.log('🔍 FloatingTab: === _handleAuth END ==='); + } + + _handleLogout() { + console.log('FloatingTab: Handling logout'); + this.userProfile = null; + + if (this.options.behavior.hideWhenAuthenticated) { + this.show(); + } + + this._updateAppearance(); + } + + _showUserMenu() { + // Simple user menu - could be expanded + const menu = document.createElement('div'); + menu.style.cssText = ` + position: fixed; + background: var(--nl-secondary-color); + border: var(--nl-border-width) solid var(--nl-primary-color); + border-radius: var(--nl-border-radius); + padding: 12px; + z-index: 10000; + font-family: var(--nl-font-family); + box-shadow: 0 4px 12px rgba(0,0,0,0.15); + `; + + // Position near the floating tab + const tabRect = this.container.getBoundingClientRect(); + if (this.options.hPosition > 0.5) { + // Tab is on right side, show menu to the left + menu.style.right = (window.innerWidth - tabRect.left) + 'px'; + } else { + // Tab is on left side, show menu to the right + menu.style.left = tabRect.right + 'px'; + } + menu.style.top = tabRect.top + 'px'; + + // Menu content - use _getAuthState() as single source of truth + const authState = this._getAuthState(); + let userDisplay; + + if (authState?.pubkey) { + // Use profile name if available, otherwise pubkey + if (this.userProfile?.name || this.userProfile?.display_name) { + const userName = this.userProfile.name || this.userProfile.display_name; + userDisplay = userName.length > 16 ? userName.slice(0, 16) + '...' : userName; + } else { + userDisplay = authState.pubkey.slice(0, 8) + '...' + authState.pubkey.slice(-4); + } + } else { + userDisplay = 'Authenticated'; + } + + menu.innerHTML = ` +
${userDisplay}
+ + `; + + document.body.appendChild(menu); + + // Auto-remove menu after delay or on outside click + const removeMenu = () => menu.remove(); + setTimeout(removeMenu, 5000); + + document.addEventListener('click', function onOutsideClick(e) { + if (!menu.contains(e.target) && e.target !== this.container) { + removeMenu(); + document.removeEventListener('click', onOutsideClick); + } + }); + } + + _updateAppearance() { + if (!this.container) return; + + // Query authoritative source for all state information + const authState = this._getAuthState(); + const isAuthenticated = authState !== null; + + // Update content + if (isAuthenticated && this.options.behavior.showUserInfo) { + let display; + + // Use profile name if available, otherwise fall back to pubkey + if (this.userProfile?.name || this.userProfile?.display_name) { + const userName = this.userProfile.name || this.userProfile.display_name; + display = this.options.appearance.iconOnly + ? userName.slice(0, 8) + : userName; + } else if (authState?.pubkey) { + // Fallback to pubkey display + display = this.options.appearance.iconOnly + ? authState.pubkey.slice(0, 6) + : authState.pubkey.slice(0, 6) + '...'; + } else { + display = this.options.appearance.iconOnly ? 'User' : 'Authenticated'; + } + + this.container.textContent = display; + this.container.className = 'nl-floating-tab nl-floating-tab--logged-in'; + } else { + const display = this.options.appearance.iconOnly ? + this.options.appearance.icon : + (this.options.appearance.icon ? this.options.appearance.icon + ' ' + this.options.appearance.text : this.options.appearance.text); + + this.container.textContent = display; + this.container.className = 'nl-floating-tab nl-floating-tab--logged-out'; + } + + // Apply appearance styles based on current state + this._applyThemeStyles(); + } + + _applyThemeStyles() { + if (!this.container) return; + + // The CSS classes will handle the theming through CSS custom properties + // Additional style customizations can be added here if needed + + // Apply style variant + if (this.options.appearance.style === 'circle') { + this.container.style.borderRadius = '50%'; + this.container.style.width = '48px'; + this.container.style.height = '48px'; + this.container.style.minWidth = '48px'; + this.container.style.padding = '0'; + } else if (this.options.appearance.style === 'square') { + this.container.style.borderRadius = '4px'; + } else { + // pill style (default) + this.container.style.borderRadius = 'var(--nl-border-radius)'; + } + } + + async _fetchUserProfile(pubkey) { + if (!this.options.getUserInfo) { + console.log('FloatingTab: getUserInfo disabled, skipping profile fetch'); + return null; + } + + // Determine which relays to use + const relays = this.options.getUserRelay.length > 0 + ? this.options.getUserRelay + : ['wss://relay.damus.io', 'wss://nos.lol']; + + console.log('FloatingTab: Fetching profile from relays:', relays); + + try { + // Create a SimplePool instance for querying + const pool = new window.NostrTools.SimplePool(); + + // Query for kind 0 (user metadata) events + const events = await pool.querySync(relays, { + kinds: [0], + authors: [pubkey], + limit: 1 + }, { timeout: 5000 }); + + console.log('FloatingTab: Profile query returned', events.length, 'events'); + + if (events.length === 0) { + console.log('FloatingTab: No profile events found'); + return null; + } + + // Get the most recent event + const latestEvent = events.sort((a, b) => b.created_at - a.created_at)[0]; + + try { + const profile = JSON.parse(latestEvent.content); + console.log('FloatingTab: Parsed profile:', profile); + + // Find the best name from any key containing "name" (case-insensitive) + let bestName = null; + const nameKeys = Object.keys(profile).filter(key => + key.toLowerCase().includes('name') && + typeof profile[key] === 'string' && + profile[key].trim().length > 0 + ); + + if (nameKeys.length > 0) { + // Find the shortest name value + bestName = nameKeys + .map(key => profile[key].trim()) + .reduce((shortest, current) => + current.length < shortest.length ? current : shortest + ); + console.log('FloatingTab: Found name keys:', nameKeys, 'selected:', bestName); + } + + // Return relevant profile fields with the best name + return { + name: bestName, + display_name: profile.display_name || null, + about: profile.about || null, + picture: profile.picture || null, + nip05: profile.nip05 || null + }; + } catch (parseError) { + console.warn('FloatingTab: Failed to parse profile JSON:', parseError); + return null; + } + } catch (error) { + console.error('FloatingTab: Profile fetch error:', error); + return null; + } + } + + _position() { + if (!this.container) return; + + const padding = 16; // Distance from screen edge + + // Calculate position based on percentage + const x = this.options.hPosition * (window.innerWidth - this.container.offsetWidth - padding * 2) + padding + this.options.offset.x; + const y = this.options.vPosition * (window.innerHeight - this.container.offsetHeight - padding * 2) + padding + this.options.offset.y; + + this.container.style.left = x + 'px'; + this.container.style.top = y + 'px'; + + console.log('FloatingTab: Positioned at (' + x + ', ' + y + ')'); + } + + _slideIn() { + if (!this.container || !this.options.behavior.autoSlide) return; + + // Slide towards center slightly + const currentTransform = this.container.style.transform || ''; + if (this.options.hPosition > 0.5) { + this.container.style.transform = currentTransform + ' translateX(-8px)'; + } else { + this.container.style.transform = currentTransform + ' translateX(8px)'; + } + } + + _slideOut() { + if (!this.container || !this.options.behavior.autoSlide) return; + + // Reset position + this.container.style.transform = ''; + } + + show() { + if (!this.container) return; + this.container.style.display = 'flex'; + this.isVisible = true; + console.log('FloatingTab: Shown'); + } + + hide() { + if (!this.container) return; + this.container.style.display = 'none'; + this.isVisible = false; + console.log('FloatingTab: Hidden'); + } + + destroy() { + if (this.container) { + this.container.remove(); + this.container = null; + } + this.isVisible = false; + console.log('FloatingTab: Destroyed'); + } + + // Update options and re-apply + updateOptions(newOptions) { + this.options = { ...this.options, ...newOptions }; + if (this.container) { + this._updateAppearance(); + this._position(); + } + } + + // Get current state + getState() { + const authState = this._getAuthState(); + return { + isVisible: this.isVisible, + isAuthenticated: !!authState, + userInfo: authState, + options: this.options + }; + } +} + +// ====================================== +// Main NOSTR_LOGIN_LITE Library +// ====================================== + +// Extension Bridge for managing browser extensions +class ExtensionBridge { + constructor() { + this.extensions = new Map(); + this.primaryExtension = null; + this._detectExtensions(); + } + + _detectExtensions() { + // Common extension locations + const locations = [ + { path: 'window.nostr', name: 'Generic' }, + { path: 'window.alby?.nostr', name: 'Alby' }, + { path: 'window.nos2x?.nostr', name: 'nos2x' }, + { path: 'window.flamingo?.nostr', name: 'Flamingo' }, + { path: 'window.getAlby?.nostr', name: 'Alby Legacy' }, + { path: 'window.mutiny?.nostr', name: 'Mutiny' } + ]; + + for (const location of locations) { + try { + const obj = eval(location.path); + if (obj && typeof obj.getPublicKey === 'function') { + this.extensions.set(location.name, { + name: location.name, + extension: obj, + constructor: obj.constructor?.name || 'Unknown' + }); + + if (!this.primaryExtension) { + this.primaryExtension = this.extensions.get(location.name); + } + } + } catch (e) { + // Extension not available + } + } + } + + getAllExtensions() { + return Array.from(this.extensions.values()); + } + + getExtensionCount() { + return this.extensions.size; + } +} + +// Main NostrLite class +class NostrLite { + constructor() { + this.options = {}; + this.extensionBridge = new ExtensionBridge(); + this.initialized = false; + this.currentTheme = 'default'; + this.modal = null; + this.floatingTab = null; + } + + async init(options = {}) { + console.log('NOSTR_LOGIN_LITE: Initializing with options:', options); + + this.options = { + theme: 'default', + persistence: true, // Enable persistent authentication by default + isolateSession: false, // Use localStorage by default for cross-window persistence + methods: { + extension: true, + local: true, + seedphrase: false, + readonly: true, + connect: false, + otp: false + }, + floatingTab: { + enabled: false, + hPosition: 1.0, + vPosition: 0.5, + offset: { x: 0, y: 0 }, + appearance: { + style: 'pill', + theme: 'auto', + icon: '', + text: 'Login', + iconOnly: false + }, + behavior: { + hideWhenAuthenticated: true, + showUserInfo: true, + autoSlide: true, + persistent: false + }, + getUserInfo: false, + getUserRelay: [] + }, + ...options + }; + + // Apply the selected theme (CSS-only) + this.switchTheme(this.options.theme); + + // Always set up window.nostr facade to handle multiple extensions properly + console.log('🔍 NOSTR_LOGIN_LITE: Setting up facade before other initialization...'); + await this._setupWindowNostrFacade(); + console.log('🔍 NOSTR_LOGIN_LITE: Facade setup complete, continuing initialization...'); + + // Create modal during init (matching original git architecture) + this.modal = new Modal(this.options); + console.log('NOSTR_LOGIN_LITE: Modal created during init'); + + // Initialize floating tab if enabled + if (this.options.floatingTab.enabled) { + this.floatingTab = new FloatingTab(this.modal, this.options.floatingTab); + console.log('NOSTR_LOGIN_LITE: Floating tab initialized'); + } + + // Attempt to restore authentication state if persistence is enabled (AFTER facade is ready) + if (this.options.persistence) { + console.log('🔍 NOSTR_LOGIN_LITE: Persistence enabled, attempting auth restoration...'); + await this._attemptAuthRestore(); + } else { + console.log('🔍 NOSTR_LOGIN_LITE: Persistence disabled in options'); + } + + this.initialized = true; + console.log('NOSTR_LOGIN_LITE: Initialization complete'); + + return this; + } + + async _setupWindowNostrFacade() { + if (typeof window !== 'undefined') { + console.log('🔍 NOSTR_LOGIN_LITE: === EXTENSION-FIRST FACADE SETUP ==='); + console.log('🔍 NOSTR_LOGIN_LITE: Current window.nostr:', window.nostr); + console.log('🔍 NOSTR_LOGIN_LITE: Constructor:', window.nostr?.constructor?.name); + + // EXTENSION-FIRST ARCHITECTURE: Never interfere with real extensions + if (this._isRealExtension(window.nostr)) { + console.log('🔍 NOSTR_LOGIN_LITE: ✅ REAL EXTENSION DETECTED - WILL NOT INSTALL FACADE'); + console.log('🔍 NOSTR_LOGIN_LITE: Extension constructor:', window.nostr.constructor?.name); + console.log('🔍 NOSTR_LOGIN_LITE: Extensions will handle window.nostr directly'); + + // Store reference for persistence verification + this.detectedExtension = window.nostr; + this.hasExtension = true; + this.facadeInstalled = false; // We deliberately don't install facade for extensions + + console.log('🔍 NOSTR_LOGIN_LITE: Extension mode - no facade interference'); + return; // Don't install facade at all for extensions + } + + // NO EXTENSION: Install facade for local/NIP-46/readonly methods + console.log('🔍 NOSTR_LOGIN_LITE: ❌ No real extension detected'); + console.log('🔍 NOSTR_LOGIN_LITE: Installing facade for non-extension authentication'); + + this.hasExtension = false; + this._installFacade(window.nostr); // Install facade with any existing nostr object + + console.log('🔍 NOSTR_LOGIN_LITE: ✅ Facade installed for local/NIP-46/readonly methods'); + + // CRITICAL FIX: Immediately attempt to restore auth state after facade installation + if (this.facadeInstalled && window.nostr?.restoreAuthState) { + console.log('🔍 NOSTR_LOGIN_LITE: 🔄 IMMEDIATELY attempting auth restoration after facade installation'); + try { + const restoredAuth = await window.nostr.restoreAuthState(); + if (restoredAuth) { + console.log('🔍 NOSTR_LOGIN_LITE: ✅ Auth state restored immediately during facade setup!'); + console.log('🔍 NOSTR_LOGIN_LITE: Method:', restoredAuth.method); + console.log('🔍 NOSTR_LOGIN_LITE: Pubkey:', restoredAuth.pubkey); + + // Update facade's authState immediately + window.nostr.authState = restoredAuth; + } else { + console.log('🔍 NOSTR_LOGIN_LITE: ❌ No auth state to restore during facade setup'); + } + } catch (error) { + console.error('🔍 NOSTR_LOGIN_LITE: ❌ Error restoring auth during facade setup:', error); + } + } + } + } + + _installFacade(existingNostr = null, forceInstall = false) { + if (typeof window !== 'undefined' && (!this.facadeInstalled || forceInstall)) { + console.log('🔍 NOSTR_LOGIN_LITE: === _installFacade CALLED ==='); + console.log('🔍 NOSTR_LOGIN_LITE: existingNostr parameter:', existingNostr); + console.log('🔍 NOSTR_LOGIN_LITE: existingNostr constructor:', existingNostr?.constructor?.name); + console.log('🔍 NOSTR_LOGIN_LITE: window.nostr before installation:', window.nostr); + console.log('🔍 NOSTR_LOGIN_LITE: window.nostr constructor before:', window.nostr?.constructor?.name); + console.log('🔍 NOSTR_LOGIN_LITE: forceInstall flag:', forceInstall); + + const facade = new WindowNostr(this, existingNostr, { isolateSession: this.options.isolateSession }); + window.nostr = facade; + this.facadeInstalled = true; + + console.log('🔍 NOSTR_LOGIN_LITE: === FACADE INSTALLED FOR PERSISTENCE ==='); + console.log('🔍 NOSTR_LOGIN_LITE: window.nostr after installation:', window.nostr); + console.log('🔍 NOSTR_LOGIN_LITE: window.nostr constructor after:', window.nostr.constructor?.name); + console.log('🔍 NOSTR_LOGIN_LITE: facade.existingNostr:', window.nostr.existingNostr); + } else if (typeof window !== 'undefined') { + console.log('🔍 NOSTR_LOGIN_LITE: _installFacade skipped - facadeInstalled:', this.facadeInstalled, 'forceInstall:', forceInstall); + } + } + + // Conservative method to identify real browser extensions + _isRealExtension(obj) { + console.log('NOSTR_LOGIN_LITE: === _isRealExtension (Conservative) ==='); + console.log('NOSTR_LOGIN_LITE: obj:', obj); + console.log('NOSTR_LOGIN_LITE: typeof obj:', typeof obj); + + if (!obj || typeof obj !== 'object') { + console.log('NOSTR_LOGIN_LITE: ✗ Not an object'); + return false; + } + + // Must have required Nostr methods + if (typeof obj.getPublicKey !== 'function' || typeof obj.signEvent !== 'function') { + console.log('NOSTR_LOGIN_LITE: ✗ Missing required NIP-07 methods'); + return false; + } + + // Exclude our own library classes + const constructorName = obj.constructor?.name; + console.log('NOSTR_LOGIN_LITE: Constructor name:', constructorName); + + if (constructorName === 'WindowNostr' || constructorName === 'NostrLite') { + console.log('NOSTR_LOGIN_LITE: ✗ Is our library class - NOT an extension'); + return false; + } + + // Exclude NostrTools library object + if (obj === window.NostrTools) { + console.log('NOSTR_LOGIN_LITE: ✗ Is NostrTools object - NOT an extension'); + return false; + } + + // Conservative check: Look for common extension characteristics + // Real extensions usually have some of these internal properties + const extensionIndicators = [ + '_isEnabled', 'enabled', 'kind', '_eventEmitter', '_scope', + '_requests', '_pubkey', 'name', 'version', 'description' + ]; + + const hasIndicators = extensionIndicators.some(prop => obj.hasOwnProperty(prop)); + + // Additional check: Extensions often have specific constructor patterns + const hasExtensionConstructor = constructorName && + constructorName !== 'Object' && + constructorName !== 'Function'; + + const isExtension = hasIndicators || hasExtensionConstructor; + + console.log('NOSTR_LOGIN_LITE: Extension indicators found:', hasIndicators); + console.log('NOSTR_LOGIN_LITE: Has extension constructor:', hasExtensionConstructor); + console.log('NOSTR_LOGIN_LITE: Final result for', constructorName, ':', isExtension); + + return isExtension; + } + + launch(startScreen = 'login') { + console.log('NOSTR_LOGIN_LITE: Launching with screen:', startScreen); + + if (this.modal) { + this.modal.open({ startScreen }); + } else { + console.error('NOSTR_LOGIN_LITE: Modal not initialized - call init() first'); + } + } + + // Attempt to restore authentication state + async _attemptAuthRestore() { + try { + console.log('🔍 NOSTR_LOGIN_LITE: === _attemptAuthRestore START ==='); + console.log('🔍 NOSTR_LOGIN_LITE: hasExtension:', this.hasExtension); + console.log('🔍 NOSTR_LOGIN_LITE: facadeInstalled:', this.facadeInstalled); + console.log('🔍 NOSTR_LOGIN_LITE: window.nostr:', window.nostr?.constructor?.name); + + if (this.hasExtension) { + // EXTENSION MODE: Use custom extension persistence logic + console.log('🔍 NOSTR_LOGIN_LITE: Extension mode - using extension-specific restore'); + const restoredAuth = await this._attemptExtensionRestore(); + + if (restoredAuth) { + console.log('🔍 NOSTR_LOGIN_LITE: ✅ Extension auth restored successfully!'); + return restoredAuth; + } else { + console.log('🔍 NOSTR_LOGIN_LITE: ❌ Extension auth could not be restored'); + return null; + } + } else if (this.facadeInstalled && window.nostr?.restoreAuthState) { + // NON-EXTENSION MODE: Use facade persistence logic + console.log('🔍 NOSTR_LOGIN_LITE: Non-extension mode - using facade restore'); + const restoredAuth = await window.nostr.restoreAuthState(); + + if (restoredAuth) { + console.log('🔍 NOSTR_LOGIN_LITE: ✅ Facade auth restored successfully!'); + console.log('🔍 NOSTR_LOGIN_LITE: Method:', restoredAuth.method); + console.log('🔍 NOSTR_LOGIN_LITE: Pubkey:', restoredAuth.pubkey); + + // CRITICAL FIX: Activate facade resilience system for non-extension methods + // Extensions like nos2x can override our facade after page refresh + if (restoredAuth.method === 'local' || restoredAuth.method === 'nip46') { + console.log('🔍 NOSTR_LOGIN_LITE: 🛡️ Activating facade resilience system for page refresh'); + this._activateResilienceProtection(restoredAuth.method); + } + + // Handle NIP-46 reconnection requirement + if (restoredAuth.requiresReconnection) { + console.log('🔍 NOSTR_LOGIN_LITE: NIP-46 connection requires user reconnection'); + this._showReconnectionPrompt(restoredAuth); + } + + return restoredAuth; + } else { + console.log('🔍 NOSTR_LOGIN_LITE: ❌ Facade auth could not be restored'); + return null; + } + } else { + console.log('🔍 NOSTR_LOGIN_LITE: ❌ No restoration method available'); + console.log('🔍 NOSTR_LOGIN_LITE: hasExtension:', this.hasExtension); + console.log('🔍 NOSTR_LOGIN_LITE: facadeInstalled:', this.facadeInstalled); + console.log('🔍 NOSTR_LOGIN_LITE: window.nostr.restoreAuthState:', typeof window.nostr?.restoreAuthState); + return null; + } + + } catch (error) { + console.error('🔍 NOSTR_LOGIN_LITE: Auth restoration failed with error:', error); + console.error('🔍 NOSTR_LOGIN_LITE: Error stack:', error.stack); + return null; + } + } + + // Activate facade resilience protection against extension overrides + _activateResilienceProtection(method) { + console.log('🛡️ NOSTR_LOGIN_LITE: === ACTIVATING RESILIENCE PROTECTION ==='); + console.log('🛡️ NOSTR_LOGIN_LITE: Protecting facade for method:', method); + + // Store the current extension if any (for potential restoration later) + const preservedExtension = this.preservedExtension || + ((window.nostr?.constructor?.name !== 'WindowNostr') ? window.nostr : null); + + // DELAYED FACADE RESILIENCE - Reinstall after extension override attempts + const forceReinstallFacade = () => { + console.log('🛡️ NOSTR_LOGIN_LITE: RESILIENCE CHECK - Current window.nostr after delay:', window.nostr?.constructor?.name); + + // If facade was overridden by extension, reinstall it + if (window.nostr?.constructor?.name !== 'WindowNostr') { + console.log('🛡️ NOSTR_LOGIN_LITE: FACADE OVERRIDDEN! Force-reinstalling WindowNostr facade for user choice:', method); + this._installFacade(preservedExtension, true); + console.log('🛡️ NOSTR_LOGIN_LITE: Resilient facade force-reinstall complete, window.nostr:', window.nostr?.constructor?.name); + + // Schedule another check in case of persistent extension override + setTimeout(() => { + if (window.nostr?.constructor?.name !== 'WindowNostr') { + console.log('🛡️ NOSTR_LOGIN_LITE: PERSISTENT OVERRIDE! Final facade force-reinstall for method:', method); + this._installFacade(preservedExtension, true); + } + }, 1000); + } else { + console.log('🛡️ NOSTR_LOGIN_LITE: Facade persistence verified - no override detected'); + } + }; + + // Schedule resilience checks at multiple intervals (same as Modal) + setTimeout(forceReinstallFacade, 100); // Quick check + setTimeout(forceReinstallFacade, 500); // Main check + setTimeout(forceReinstallFacade, 1500); // Final check + + console.log('🛡️ NOSTR_LOGIN_LITE: Resilience protection scheduled for method:', method); + } + + // Extension-specific authentication restoration + async _attemptExtensionRestore() { + try { + console.log('🔍 NOSTR_LOGIN_LITE: === _attemptExtensionRestore START ==='); + + // Use a simple AuthManager instance for extension persistence + const authManager = new AuthManager({ isolateSession: this.options?.isolateSession }); + const storedAuth = await authManager.restoreAuthState(); + + if (!storedAuth || storedAuth.method !== 'extension') { + console.log('🔍 NOSTR_LOGIN_LITE: No extension auth state stored'); + return null; + } + + // Verify the extension is still available and working + if (!window.nostr || !this._isRealExtension(window.nostr)) { + console.log('🔍 NOSTR_LOGIN_LITE: Extension no longer available'); + authManager.clearAuthState(); // Clear invalid state + return null; + } + + try { + // Test that the extension still works with the same pubkey + const currentPubkey = await window.nostr.getPublicKey(); + if (currentPubkey !== storedAuth.pubkey) { + console.log('🔍 NOSTR_LOGIN_LITE: Extension pubkey changed, clearing state'); + authManager.clearAuthState(); + return null; + } + + console.log('🔍 NOSTR_LOGIN_LITE: ✅ Extension auth verification successful'); + + // Create extension auth data for UI restoration + const extensionAuth = { + method: 'extension', + pubkey: storedAuth.pubkey, + extension: window.nostr + }; + + // Dispatch restoration event so UI can update + if (typeof window !== 'undefined') { + console.log('🔍 NOSTR_LOGIN_LITE: Dispatching nlAuthRestored event for extension'); + window.dispatchEvent(new CustomEvent('nlAuthRestored', { + detail: extensionAuth + })); + } + + return extensionAuth; + + } catch (error) { + console.log('🔍 NOSTR_LOGIN_LITE: Extension verification failed:', error); + authManager.clearAuthState(); // Clear invalid state + return null; + } + + } catch (error) { + console.error('🔍 NOSTR_LOGIN_LITE: Extension restore failed:', error); + return null; + } + } + + // Show prompt for NIP-46 reconnection + _showReconnectionPrompt(authData) { + console.log('NOSTR_LOGIN_LITE: Showing reconnection prompt for NIP-46'); + + // Dispatch event that UI can listen to + if (typeof window !== 'undefined') { + window.dispatchEvent(new CustomEvent('nlReconnectionRequired', { + detail: { + method: authData.method, + pubkey: authData.pubkey, + connectionData: authData.connectionData, + message: 'Your NIP-46 session has expired. Please reconnect to continue.' + } + })); + } + } + + logout() { + console.log('NOSTR_LOGIN_LITE: Logout called'); + + // Clear legacy stored data + if (typeof localStorage !== 'undefined') { + localStorage.removeItem('nl_current'); + } + + // Clear current authentication state directly from storage + // This works for ALL methods including extensions (fixes the bug) + clearAuthState(); + + // Dispatch logout event for UI updates + if (typeof window !== 'undefined') { + window.dispatchEvent(new CustomEvent('nlLogout', { + detail: { timestamp: Date.now() } + })); + } + } + + // CSS-only theme switching + switchTheme(themeName) { + console.log('NOSTR_LOGIN_LITE: Switching to ' + themeName + ' theme'); + + if (THEME_CSS[themeName]) { + injectThemeCSS(themeName); + this.currentTheme = themeName; + + // Dispatch theme change event + if (typeof window !== 'undefined') { + window.dispatchEvent(new CustomEvent('nlThemeChanged', { + detail: { theme: themeName } + })); + } + + return { theme: themeName }; + } else { + console.warn("Theme '" + themeName + "' not found, using default"); + injectThemeCSS('default'); + this.currentTheme = 'default'; + return { theme: 'default' }; + } + } + + getCurrentTheme() { + return this.currentTheme; + } + + getAvailableThemes() { + return Object.keys(THEME_CSS); + } + + embed(container, options = {}) { + console.log('NOSTR_LOGIN_LITE: Creating embedded modal in container:', container); + + const embedOptions = { + ...this.options, + ...options, + embedded: container + }; + + // Create new modal instance for embedding + const embeddedModal = new Modal(embedOptions); + embeddedModal.open(); + + return embeddedModal; + } + + // Floating tab management methods + showFloatingTab() { + if (this.floatingTab) { + this.floatingTab.show(); + } else { + console.warn('NOSTR_LOGIN_LITE: Floating tab not enabled'); + } + } + + hideFloatingTab() { + if (this.floatingTab) { + this.floatingTab.hide(); + } + } + + toggleFloatingTab() { + if (this.floatingTab) { + if (this.floatingTab.isVisible) { + this.floatingTab.hide(); + } else { + this.floatingTab.show(); + } + } + } + + updateFloatingTab(options) { + if (this.floatingTab) { + this.floatingTab.updateOptions(options); + } + } + + getFloatingTabState() { + return this.floatingTab ? this.floatingTab.getState() : null; + } +} + +// ====================================== +// Simplified Authentication Manager (Unified Plaintext Storage) +// ====================================== + +// Simple authentication state manager - plaintext storage for maximum usability +class AuthManager { + constructor(options = {}) { + this.storageKey = 'nostr_login_lite_auth'; + this.currentAuthState = null; + + // Configure storage type based on isolateSession option + if (options.isolateSession) { + this.storage = sessionStorage; + console.log('🔐 AuthManager: Using sessionStorage for per-window isolation'); + } else { + this.storage = localStorage; + console.log('🔐 AuthManager: Using localStorage for cross-window persistence'); + } + + console.warn('🔐 SECURITY: Private keys stored unencrypted in browser storage'); + console.warn('🔐 For production apps, implement your own secure storage'); + } + + // Save authentication state using unified plaintext approach + async saveAuthState(authData) { + try { + console.log('🔐 AuthManager: Saving auth state with plaintext storage'); + console.warn('🔐 SECURITY: Private key will be stored unencrypted for maximum usability'); + + const authState = { + method: authData.method, + timestamp: Date.now(), + pubkey: authData.pubkey + }; + + switch (authData.method) { + case 'extension': + // For extensions, only store verification data - no secrets + authState.extensionVerification = { + constructor: authData.extension?.constructor?.name, + hasGetPublicKey: typeof authData.extension?.getPublicKey === 'function', + hasSignEvent: typeof authData.extension?.signEvent === 'function' + }; + console.log('🔐 AuthManager: Extension method - storing verification data only'); + break; + + case 'local': + // UNIFIED PLAINTEXT: Store secret key directly for maximum compatibility + if (authData.secret) { + authState.secret = authData.secret; + console.log('🔐 AuthManager: Local method - storing secret key in plaintext'); + console.warn('🔐 SECURITY: Secret key stored unencrypted for developer convenience'); + } + break; + + case 'nip46': + // For NIP-46, store connection parameters (no secrets) + if (authData.signer) { + authState.nip46 = { + remotePubkey: authData.signer.remotePubkey, + relays: authData.signer.relays, + // Don't store secret - user will need to reconnect + }; + console.log('🔐 AuthManager: NIP-46 method - storing connection parameters'); + } + break; + + case 'readonly': + // Read-only mode has no secrets to store + console.log('🔐 AuthManager: Read-only method - storing basic auth state'); + break; + + default: + throw new Error('Unknown auth method: ' + authData.method); + } + + this.storage.setItem(this.storageKey, JSON.stringify(authState)); + this.currentAuthState = authState; + console.log('🔐 AuthManager: Auth state saved successfully for method:', authData.method); + + } catch (error) { + console.error('🔐 AuthManager: Failed to save auth state:', error); + throw error; + } + } + + // Restore authentication state on page load + async restoreAuthState() { + try { + console.log('🔍 AuthManager: === restoreAuthState START ==='); + console.log('🔍 AuthManager: storageKey:', this.storageKey); + + const stored = this.storage.getItem(this.storageKey); + console.log('🔍 AuthManager: Storage raw value:', stored); + + if (!stored) { + console.log('🔍 AuthManager: ❌ No stored auth state found'); + return null; + } + + const authState = JSON.parse(stored); + console.log('🔍 AuthManager: ✅ Parsed stored auth state:', authState); + console.log('🔍 AuthManager: Method:', authState.method); + console.log('🔍 AuthManager: Timestamp:', authState.timestamp); + console.log('🔍 AuthManager: Age (ms):', Date.now() - authState.timestamp); + + // Check if stored state is too old (24 hours for most methods, 1 hour for extensions) + const maxAge = authState.method === 'extension' ? 60 * 60 * 1000 : 24 * 60 * 60 * 1000; + console.log('🔍 AuthManager: Max age for method:', maxAge, 'ms'); + + if (Date.now() - authState.timestamp > maxAge) { + console.log('🔍 AuthManager: ❌ Stored auth state expired, clearing'); + this.clearAuthState(); + return null; + } + + console.log('🔍 AuthManager: ✅ Auth state not expired, attempting restore for method:', authState.method); + + let result; + switch (authState.method) { + case 'extension': + console.log('🔍 AuthManager: Calling _restoreExtensionAuth...'); + result = await this._restoreExtensionAuth(authState); + break; + + case 'local': + console.log('🔍 AuthManager: Calling _restoreLocalAuth...'); + result = await this._restoreLocalAuth(authState); + break; + + case 'nip46': + console.log('🔍 AuthManager: Calling _restoreNip46Auth...'); + result = await this._restoreNip46Auth(authState); + break; + + case 'readonly': + console.log('🔍 AuthManager: Calling _restoreReadonlyAuth...'); + result = await this._restoreReadonlyAuth(authState); + break; + + default: + console.warn('🔍 AuthManager: ❌ Unknown auth method in stored state:', authState.method); + return null; + } + + console.log('🔍 AuthManager: Restore method result:', result); + console.log('🔍 AuthManager: === restoreAuthState END ==='); + return result; + + } catch (error) { + console.error('🔍 AuthManager: ❌ Failed to restore auth state:', error); + console.error('🔍 AuthManager: Error stack:', error.stack); + this.clearAuthState(); // Clear corrupted state + return null; + } + } + + async _restoreExtensionAuth(authState) { + console.log('🔍 AuthManager: === _restoreExtensionAuth START ==='); + console.log('🔍 AuthManager: authState:', authState); + console.log('🔍 AuthManager: window.nostr available:', !!window.nostr); + console.log('🔍 AuthManager: window.nostr constructor:', window.nostr?.constructor?.name); + + // SMART EXTENSION WAITING SYSTEM + // Extensions often load after our library, so we need to wait for them + const extension = await this._waitForExtension(authState, 3000); // Wait up to 3 seconds + + if (!extension) { + console.log('🔍 AuthManager: ❌ No extension found after waiting'); + return null; + } + + console.log('🔍 AuthManager: ✅ Extension found:', extension.constructor?.name); + + try { + // Verify extension still works and has same pubkey + const currentPubkey = await extension.getPublicKey(); + if (currentPubkey !== authState.pubkey) { + console.log('🔍 AuthManager: ❌ Extension pubkey changed, not restoring'); + console.log('🔍 AuthManager: Expected:', authState.pubkey); + console.log('🔍 AuthManager: Got:', currentPubkey); + return null; + } + + console.log('🔍 AuthManager: ✅ Extension auth restored successfully'); + return { + method: 'extension', + pubkey: authState.pubkey, + extension: extension + }; + + } catch (error) { + console.log('🔍 AuthManager: ❌ Extension verification failed:', error); + return null; + } + } + + // Smart extension waiting system - polls multiple locations for extensions + async _waitForExtension(authState, maxWaitMs = 3000) { + console.log('🔍 AuthManager: === _waitForExtension START ==='); + console.log('🔍 AuthManager: maxWaitMs:', maxWaitMs); + console.log('🔍 AuthManager: Looking for extension with constructor:', authState.extensionVerification?.constructor); + + const startTime = Date.now(); + const pollInterval = 100; // Check every 100ms + + // Extension locations to check (in priority order) + const extensionLocations = [ + { path: 'window.nostr', getter: () => window.nostr }, + { path: 'navigator.nostr', getter: () => navigator?.nostr }, + { path: 'window.navigator?.nostr', getter: () => window.navigator?.nostr }, + { path: 'window.alby?.nostr', getter: () => window.alby?.nostr }, + { path: 'window.webln?.nostr', getter: () => window.webln?.nostr }, + { path: 'window.nos2x', getter: () => window.nos2x }, + { path: 'window.flamingo?.nostr', getter: () => window.flamingo?.nostr }, + { path: 'window.mutiny?.nostr', getter: () => window.mutiny?.nostr } + ]; + + while (Date.now() - startTime < maxWaitMs) { + console.log('🔍 AuthManager: Polling for extensions... (elapsed:', Date.now() - startTime, 'ms)'); + + // If our facade is currently installed and blocking, temporarily remove it + let facadeRemoved = false; + let originalNostr = null; + if (window.nostr?.constructor?.name === 'WindowNostr') { + console.log('🔍 AuthManager: Temporarily removing our facade to check for real extensions'); + originalNostr = window.nostr; + window.nostr = window.nostr.existingNostr || undefined; + facadeRemoved = true; + } + + try { + // Check all extension locations + for (const location of extensionLocations) { + try { + const extension = location.getter(); + console.log('🔍 AuthManager: Checking', location.path, ':', !!extension, extension?.constructor?.name); + + if (this._isValidExtensionForRestore(extension, authState)) { + console.log('🔍 AuthManager: ✅ Found matching extension at', location.path); + + // Restore facade if we removed it + if (facadeRemoved && originalNostr) { + console.log('🔍 AuthManager: Restoring facade after finding extension'); + window.nostr = originalNostr; + } + + return extension; + } + } catch (error) { + console.log('🔍 AuthManager: Error checking', location.path, ':', error.message); + } + } + + // Restore facade if we removed it and haven't found an extension yet + if (facadeRemoved && originalNostr) { + window.nostr = originalNostr; + facadeRemoved = false; + } + + } catch (error) { + console.error('🔍 AuthManager: Error during extension polling:', error); + + // Restore facade if we removed it + if (facadeRemoved && originalNostr) { + window.nostr = originalNostr; + } + } + + // Wait before next poll + await new Promise(resolve => setTimeout(resolve, pollInterval)); + } + + console.log('🔍 AuthManager: ❌ Extension waiting timeout after', maxWaitMs, 'ms'); + return null; + } + + // Check if an extension is valid for restoration + _isValidExtensionForRestore(extension, authState) { + if (!extension || typeof extension !== 'object') { + return false; + } + + // Must have required Nostr methods + if (typeof extension.getPublicKey !== 'function' || + typeof extension.signEvent !== 'function') { + return false; + } + + // Must not be our own classes + const constructorName = extension.constructor?.name; + if (constructorName === 'WindowNostr' || constructorName === 'NostrLite') { + return false; + } + + // Must not be NostrTools + if (extension === window.NostrTools) { + return false; + } + + // If we have stored verification data, check constructor match + const verification = authState.extensionVerification; + if (verification && verification.constructor) { + if (constructorName !== verification.constructor) { + console.log('🔍 AuthManager: Constructor mismatch -', + 'expected:', verification.constructor, + 'got:', constructorName); + return false; + } + } + + console.log('🔍 AuthManager: ✅ Extension validation passed for:', constructorName); + return true; + } + + async _restoreLocalAuth(authState) { + console.log('🔐 AuthManager: === _restoreLocalAuth (Unified Plaintext) ==='); + + // Check for legacy encrypted format first + if (authState.encrypted) { + console.log('🔐 AuthManager: Detected LEGACY encrypted format - migrating to plaintext'); + console.warn('🔐 SECURITY: Converting from encrypted to plaintext storage for compatibility'); + + // Try to decrypt legacy format + const sessionPassword = sessionStorage.getItem('nostr_session_key'); + if (!sessionPassword) { + console.log('🔐 AuthManager: Legacy session password not found - user must re-login'); + return null; + } + + try { + console.warn('🔐 AuthManager: Legacy encryption system no longer supported - user must re-login'); + this.clearAuthState(); // Clear legacy format + return null; + } catch (error) { + console.error('🔐 AuthManager: Legacy decryption failed:', error); + this.clearAuthState(); // Clear corrupted legacy format + return null; + } + } + + // NEW UNIFIED PLAINTEXT FORMAT + if (!authState.secret) { + console.log('🔐 AuthManager: No secret found in plaintext format'); + return null; + } + + console.log('🔐 AuthManager: ✅ Local auth restored from plaintext storage'); + console.warn('🔐 SECURITY: Secret key was stored unencrypted'); + + return { + method: 'local', + pubkey: authState.pubkey, + secret: authState.secret + }; + } + + async _restoreNip46Auth(authState) { + if (!authState.nip46) { + console.log('🔐 AuthManager: No NIP-46 data found'); + return null; + } + + // For NIP-46, we can't automatically restore the connection + // because it requires the user to re-authenticate with the remote signer + // Instead, we return the connection parameters so the UI can prompt for reconnection + console.log('🔐 AuthManager: NIP-46 connection data found, requires user reconnection'); + return { + method: 'nip46', + pubkey: authState.pubkey, + requiresReconnection: true, + connectionData: authState.nip46 + }; + } + + async _restoreReadonlyAuth(authState) { + console.log('🔐 AuthManager: Read-only auth restored successfully'); + return { + method: 'readonly', + pubkey: authState.pubkey + }; + } + + // Clear stored authentication state + clearAuthState() { + this.storage.removeItem(this.storageKey); + sessionStorage.removeItem('nostr_session_key'); // Clear legacy session key + this.currentAuthState = null; + console.log('🔐 AuthManager: Auth state cleared from unified storage'); + } + + // Check if we have valid stored auth + hasStoredAuth() { + const stored = this.storage.getItem(this.storageKey); + return !!stored; + } + + // Get current auth method without full restoration + getStoredAuthMethod() { + try { + const stored = this.storage.getItem(this.storageKey); + if (!stored) return null; + + const authState = JSON.parse(stored); + return authState.method; + } catch { + return null; + } + } +} + +// ====================================== +// Global Authentication Functions (Single Source of Truth) +// ====================================== + +// Global authentication state (single source of truth) +let globalAuthState = null; +let globalAuthManager = null; + +// Initialize global auth manager (lazy initialization) +function getGlobalAuthManager() { + if (!globalAuthManager) { + // Default to localStorage for persistence across browser sessions + globalAuthManager = new AuthManager({ isolateSession: false }); + } + return globalAuthManager; +} + +// **UNIFIED GLOBAL FUNCTION**: Set authentication state (works for all methods) +function setAuthState(authData, options = {}) { + try { + console.log('🌐 setAuthState: Setting global auth state for method:', authData.method); + console.warn('🔐 SECURITY: Using unified plaintext storage for maximum compatibility'); + + // Store in memory + globalAuthState = authData; + + // Store in browser storage using AuthManager + const authManager = new AuthManager(options); + authManager.saveAuthState(authData); + + console.log('🌐 setAuthState: Auth state saved successfully'); + } catch (error) { + console.error('🌐 setAuthState: Failed to save auth state:', error); + throw error; + } +} + +// **UNIFIED GLOBAL FUNCTION**: Get authentication state (single source of truth) +function getAuthState() { + try { + // Always query from storage as the authoritative source + const authManager = getGlobalAuthManager(); + const storageKey = 'nostr_login_lite_auth'; + + // Check both session and local storage for compatibility + let stored = null; + if (sessionStorage.getItem(storageKey)) { + stored = sessionStorage.getItem(storageKey); + } else if (localStorage.getItem(storageKey)) { + stored = localStorage.getItem(storageKey); + } + + if (!stored) { + console.log('🌐 getAuthState: No auth state found in storage'); + globalAuthState = null; + return null; + } + + const authState = JSON.parse(stored); + console.log('🌐 getAuthState: Retrieved auth state:', authState.method); + + // Update in-memory cache + globalAuthState = authState; + return authState; + + } catch (error) { + console.error('🌐 getAuthState: Failed to get auth state:', error); + globalAuthState = null; + return null; + } +} + +// **UNIFIED GLOBAL FUNCTION**: Clear authentication state (works for all methods) +function clearAuthState() { + try { + console.log('🌐 clearAuthState: Clearing global auth state'); + + // Clear in-memory state + globalAuthState = null; + + // Clear from both storage types for thorough cleanup + const storageKey = 'nostr_login_lite_auth'; + localStorage.removeItem(storageKey); + sessionStorage.removeItem(storageKey); + sessionStorage.removeItem('nostr_session_key'); // Clear legacy session key + + console.log('🌐 clearAuthState: Auth state cleared from all storage locations'); + } catch (error) { + console.error('🌐 clearAuthState: Failed to clear auth state:', error); + } +} + +// NIP-07 compliant window.nostr provider +class WindowNostr { + constructor(nostrLite, existingNostr = null, options = {}) { + this.nostrLite = nostrLite; + this.authState = null; + this.existingNostr = existingNostr; + this.authenticatedExtension = null; + this.options = options; + this._setupEventListeners(); + } + + // Restore authentication state on page load + async restoreAuthState() { + console.log('🔍 WindowNostr: === restoreAuthState ==='); + + try { + // Use simplified AuthManager for consistent restore logic + const authManager = new AuthManager(this.options); + const restoredAuth = await authManager.restoreAuthState(); + + if (restoredAuth) { + console.log('🔍 WindowNostr: ✅ Auth state restored:', restoredAuth.method); + this.authState = restoredAuth; + + // Update global state + globalAuthState = restoredAuth; + + // Dispatch restoration event + if (typeof window !== 'undefined') { + window.dispatchEvent(new CustomEvent('nlAuthRestored', { + detail: restoredAuth + })); + } + + return restoredAuth; + } else { + console.log('🔍 WindowNostr: ❌ No auth state to restore'); + return null; + } + + } catch (error) { + console.error('🔍 WindowNostr: Auth restoration failed:', error); + return null; + } + } + + _setupEventListeners() { + // Listen for authentication events to store auth state + if (typeof window !== 'undefined') { + window.addEventListener('nlMethodSelected', async (event) => { + console.log('🔍 WindowNostr: nlMethodSelected event received:', event.detail); + this.authState = event.detail; + + // If extension method, capture the specific extension the user chose + if (event.detail.method === 'extension') { + this.authenticatedExtension = event.detail.extension; + console.log('🔍 WindowNostr: Captured authenticated extension:', this.authenticatedExtension?.constructor?.name); + } + + // Use unified global setAuthState function for all methods + try { + setAuthState(event.detail, this.options); + console.log('🔍 WindowNostr: Auth state saved via unified setAuthState'); + } catch (error) { + console.error('🔍 WindowNostr: Failed to save auth state:', error); + } + }); + + window.addEventListener('nlLogout', () => { + console.log('🔍 WindowNostr: nlLogout event received'); + this.authState = null; + this.authenticatedExtension = null; + + // Clear from unified storage + clearAuthState(); + console.log('🔍 WindowNostr: Auth state cleared via unified clearAuthState'); + }); + } + } + + async getPublicKey() { + if (!this.authState) { + throw new Error('Not authenticated - use NOSTR_LOGIN_LITE.launch()'); + } + + switch (this.authState.method) { + case 'extension': + // Use the captured authenticated extension, not current window.nostr + const ext = this.authenticatedExtension || this.authState.extension || this.existingNostr; + if (!ext) throw new Error('Extension not available'); + return await ext.getPublicKey(); + + case 'local': + case 'nip46': + return this.authState.pubkey; + + case 'readonly': + throw new Error('Read-only mode - cannot get public key'); + + default: + throw new Error('Unsupported auth method: ' + this.authState.method); + } + } + + async signEvent(event) { + if (!this.authState) { + throw new Error('Not authenticated - use NOSTR_LOGIN_LITE.launch()'); + } + + if (this.authState.method === 'readonly') { + throw new Error('Read-only mode - cannot sign events'); + } + + switch (this.authState.method) { + case 'extension': + // Use the captured authenticated extension, not current window.nostr + const ext = this.authenticatedExtension || this.authState.extension || this.existingNostr; + if (!ext) throw new Error('Extension not available'); + return await ext.signEvent(event); + + case 'local': { + // Use nostr-tools to sign with local secret key + const { nip19, finalizeEvent } = window.NostrTools; + let secretKey; + + if (this.authState.secret.startsWith('nsec')) { + const decoded = nip19.decode(this.authState.secret); + secretKey = decoded.data; + } else { + // Convert hex to Uint8Array + secretKey = this._hexToUint8Array(this.authState.secret); + } + + return finalizeEvent(event, secretKey); + } + + case 'nip46': { + // Use BunkerSigner for NIP-46 + if (!this.authState.signer?.bunkerSigner) { + throw new Error('NIP-46 signer not available'); + } + return await this.authState.signer.bunkerSigner.signEvent(event); + } + + default: + throw new Error('Unsupported auth method: ' + this.authState.method); + } + } + + async getRelays() { + // Return configured relays from nostr-lite options + return this.nostrLite.options?.relays || ['wss://relay.damus.io']; + } + + get nip04() { + return { + encrypt: async (pubkey, plaintext) => { + if (!this.authState) { + throw new Error('Not authenticated - use NOSTR_LOGIN_LITE.launch()'); + } + + if (this.authState.method === 'readonly') { + throw new Error('Read-only mode - cannot encrypt'); + } + + switch (this.authState.method) { + case 'extension': { + const ext = this.authenticatedExtension || this.authState.extension || this.existingNostr; + if (!ext) throw new Error('Extension not available'); + return await ext.nip04.encrypt(pubkey, plaintext); + } + + case 'local': { + const { nip04, nip19 } = window.NostrTools; + let secretKey; + + if (this.authState.secret.startsWith('nsec')) { + const decoded = nip19.decode(this.authState.secret); + secretKey = decoded.data; + } else { + secretKey = this._hexToUint8Array(this.authState.secret); + } + + return await nip04.encrypt(secretKey, pubkey, plaintext); + } + + case 'nip46': { + if (!this.authState.signer?.bunkerSigner) { + throw new Error('NIP-46 signer not available'); + } + return await this.authState.signer.bunkerSigner.nip04Encrypt(pubkey, plaintext); + } + + default: + throw new Error('Unsupported auth method: ' + this.authState.method); + } + }, + + decrypt: async (pubkey, ciphertext) => { + if (!this.authState) { + throw new Error('Not authenticated - use NOSTR_LOGIN_LITE.launch()'); + } + + if (this.authState.method === 'readonly') { + throw new Error('Read-only mode - cannot decrypt'); + } + + switch (this.authState.method) { + case 'extension': { + const ext = this.authenticatedExtension || this.authState.extension || this.existingNostr; + if (!ext) throw new Error('Extension not available'); + return await ext.nip04.decrypt(pubkey, ciphertext); + } + + case 'local': { + const { nip04, nip19 } = window.NostrTools; + let secretKey; + + if (this.authState.secret.startsWith('nsec')) { + const decoded = nip19.decode(this.authState.secret); + secretKey = decoded.data; + } else { + secretKey = this._hexToUint8Array(this.authState.secret); + } + + return await nip04.decrypt(secretKey, pubkey, ciphertext); + } + + case 'nip46': { + if (!this.authState.signer?.bunkerSigner) { + throw new Error('NIP-46 signer not available'); + } + return await this.authState.signer.bunkerSigner.nip04Decrypt(pubkey, ciphertext); + } + + default: + throw new Error('Unsupported auth method: ' + this.authState.method); + } + } + }; + } + + get nip44() { + return { + encrypt: async (pubkey, plaintext) => { + if (!this.authState) { + throw new Error('Not authenticated - use NOSTR_LOGIN_LITE.launch()'); + } + + if (this.authState.method === 'readonly') { + throw new Error('Read-only mode - cannot encrypt'); + } + + switch (this.authState.method) { + case 'extension': { + const ext = this.authenticatedExtension || this.authState.extension || this.existingNostr; + if (!ext) throw new Error('Extension not available'); + return await ext.nip44.encrypt(pubkey, plaintext); + } + + case 'local': { + const { nip44, nip19 } = window.NostrTools; + let secretKey; + + if (this.authState.secret.startsWith('nsec')) { + const decoded = nip19.decode(this.authState.secret); + secretKey = decoded.data; + } else { + secretKey = this._hexToUint8Array(this.authState.secret); + } + + return nip44.encrypt(plaintext, nip44.getConversationKey(secretKey, pubkey)); + } + + case 'nip46': { + if (!this.authState.signer?.bunkerSigner) { + throw new Error('NIP-46 signer not available'); + } + return await this.authState.signer.bunkerSigner.nip44Encrypt(pubkey, plaintext); + } + + default: + throw new Error('Unsupported auth method: ' + this.authState.method); + } + }, + + decrypt: async (pubkey, ciphertext) => { + if (!this.authState) { + throw new Error('Not authenticated - use NOSTR_LOGIN_LITE.launch()'); + } + + if (this.authState.method === 'readonly') { + throw new Error('Read-only mode - cannot decrypt'); + } + + switch (this.authState.method) { + case 'extension': { + const ext = this.authenticatedExtension || this.authState.extension || this.existingNostr; + if (!ext) throw new Error('Extension not available'); + return await ext.nip44.decrypt(pubkey, ciphertext); + } + + case 'local': { + const { nip44, nip19 } = window.NostrTools; + let secretKey; + + if (this.authState.secret.startsWith('nsec')) { + const decoded = nip19.decode(this.authState.secret); + secretKey = decoded.data; + } else { + secretKey = this._hexToUint8Array(this.authState.secret); + } + + return nip44.decrypt(ciphertext, nip44.getConversationKey(secretKey, pubkey)); + } + + case 'nip46': { + if (!this.authState.signer?.bunkerSigner) { + throw new Error('NIP-46 signer not available'); + } + return await this.authState.signer.bunkerSigner.nip44Decrypt(pubkey, ciphertext); + } + + default: + throw new Error('Unsupported auth method: ' + this.authState.method); + } + } + }; + } + + _hexToUint8Array(hex) { + if (hex.length % 2 !== 0) { + throw new Error('Invalid hex string length'); + } + const bytes = new Uint8Array(hex.length / 2); + for (let i = 0; i < bytes.length; i++) { + bytes[i] = parseInt(hex.substr(i * 2, 2), 16); + } + return bytes; + } +} + +// Initialize and export +if (typeof window !== 'undefined') { + const nostrLite = new NostrLite(); + + // Export main API + window.NOSTR_LOGIN_LITE = { + init: (options) => nostrLite.init(options), + launch: (startScreen) => nostrLite.launch(startScreen), + logout: () => nostrLite.logout(), + + // Embedded modal method + embed: (container, options) => nostrLite.embed(container, options), + + // CSS-only theme management API + switchTheme: (themeName) => nostrLite.switchTheme(themeName), + getCurrentTheme: () => nostrLite.getCurrentTheme(), + getAvailableThemes: () => nostrLite.getAvailableThemes(), + + // Floating tab management API + showFloatingTab: () => nostrLite.showFloatingTab(), + hideFloatingTab: () => nostrLite.hideFloatingTab(), + toggleFloatingTab: () => nostrLite.toggleFloatingTab(), + updateFloatingTab: (options) => nostrLite.updateFloatingTab(options), + getFloatingTabState: () => nostrLite.getFloatingTabState(), + + // Global authentication state management (single source of truth) + setAuthState: setAuthState, + getAuthState: getAuthState, + clearAuthState: clearAuthState, + + // Expose for debugging + _extensionBridge: nostrLite.extensionBridge, + _instance: nostrLite + }; + + console.log('NOSTR_LOGIN_LITE: Library loaded and ready'); + console.log('NOSTR_LOGIN_LITE: Use window.NOSTR_LOGIN_LITE.init(options) to initialize'); + console.log('NOSTR_LOGIN_LITE: Detected', nostrLite.extensionBridge.getExtensionCount(), 'browser extensions'); + console.warn('🔐 SECURITY: Unified plaintext storage enabled for maximum developer usability'); +} else { + // Node.js environment + module.exports = { NostrLite }; +} + diff --git a/admin/assets/nostr.bundle.js b/admin/assets/nostr.bundle.js new file mode 100644 index 0000000..5d106e4 --- /dev/null +++ b/admin/assets/nostr.bundle.js @@ -0,0 +1,11628 @@ +"use strict"; +var NostrTools = (() => { + var __defProp = Object.defineProperty; + var __getOwnPropDesc = Object.getOwnPropertyDescriptor; + var __getOwnPropNames = Object.getOwnPropertyNames; + var __hasOwnProp = Object.prototype.hasOwnProperty; + var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); + }; + var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; + }; + var __toCommonJS = (mod3) => __copyProps(__defProp({}, "__esModule", { value: true }), mod3); + + // index.ts + var nostr_tools_exports = {}; + __export(nostr_tools_exports, { + Relay: () => Relay, + SimplePool: () => SimplePool, + finalizeEvent: () => finalizeEvent, + fj: () => fakejson_exports, + generateSecretKey: () => generateSecretKey, + getEventHash: () => getEventHash, + getFilterLimit: () => getFilterLimit, + getPublicKey: () => getPublicKey, + kinds: () => kinds_exports, + matchFilter: () => matchFilter, + matchFilters: () => matchFilters, + mergeFilters: () => mergeFilters, + nip04: () => nip04_exports, + nip05: () => nip05_exports, + nip06: () => nip06_exports, + nip10: () => nip10_exports, + nip11: () => nip11_exports, + nip13: () => nip13_exports, + nip17: () => nip17_exports, + nip18: () => nip18_exports, + nip19: () => nip19_exports, + nip21: () => nip21_exports, + nip25: () => nip25_exports, + nip27: () => nip27_exports, + nip28: () => nip28_exports, + nip30: () => nip30_exports, + nip39: () => nip39_exports, + nip42: () => nip42_exports, + nip44: () => nip44_exports, + nip46: () => nip46_exports, + nip47: () => nip47_exports, + nip54: () => nip54_exports, + nip57: () => nip57_exports, + nip59: () => nip59_exports, + nip98: () => nip98_exports, + parseReferences: () => parseReferences, + serializeEvent: () => serializeEvent, + sortEvents: () => sortEvents, + utils: () => utils_exports2, + validateEvent: () => validateEvent, + verifiedSymbol: () => verifiedSymbol, + verifyEvent: () => verifyEvent + }); + + // node_modules/@noble/curves/node_modules/@noble/hashes/esm/_assert.js + function number(n) { + if (!Number.isSafeInteger(n) || n < 0) + throw new Error(`Wrong positive integer: ${n}`); + } + function bytes(b, ...lengths) { + if (!(b instanceof Uint8Array)) + throw new Error("Expected Uint8Array"); + if (lengths.length > 0 && !lengths.includes(b.length)) + throw new Error(`Expected Uint8Array of length ${lengths}, not of length=${b.length}`); + } + function hash(hash3) { + if (typeof hash3 !== "function" || typeof hash3.create !== "function") + throw new Error("Hash should be wrapped by utils.wrapConstructor"); + number(hash3.outputLen); + number(hash3.blockLen); + } + function exists(instance, checkFinished = true) { + if (instance.destroyed) + throw new Error("Hash instance has been destroyed"); + if (checkFinished && instance.finished) + throw new Error("Hash#digest() has already been called"); + } + function output(out, instance) { + bytes(out); + const min = instance.outputLen; + if (out.length < min) { + throw new Error(`digestInto() expects output buffer of length at least ${min}`); + } + } + + // node_modules/@noble/curves/node_modules/@noble/hashes/esm/crypto.js + var crypto = typeof globalThis === "object" && "crypto" in globalThis ? globalThis.crypto : void 0; + + // node_modules/@noble/curves/node_modules/@noble/hashes/esm/utils.js + var u8a = (a) => a instanceof Uint8Array; + var createView = (arr) => new DataView(arr.buffer, arr.byteOffset, arr.byteLength); + var rotr = (word, shift) => word << 32 - shift | word >>> shift; + var isLE = new Uint8Array(new Uint32Array([287454020]).buffer)[0] === 68; + if (!isLE) + throw new Error("Non little-endian hardware is not supported"); + function utf8ToBytes(str) { + if (typeof str !== "string") + throw new Error(`utf8ToBytes expected string, got ${typeof str}`); + return new Uint8Array(new TextEncoder().encode(str)); + } + function toBytes(data) { + if (typeof data === "string") + data = utf8ToBytes(data); + if (!u8a(data)) + throw new Error(`expected Uint8Array, got ${typeof data}`); + return data; + } + function concatBytes(...arrays) { + const r = new Uint8Array(arrays.reduce((sum, a) => sum + a.length, 0)); + let pad2 = 0; + arrays.forEach((a) => { + if (!u8a(a)) + throw new Error("Uint8Array expected"); + r.set(a, pad2); + pad2 += a.length; + }); + return r; + } + var Hash = class { + clone() { + return this._cloneInto(); + } + }; + var toStr = {}.toString; + function wrapConstructor(hashCons) { + const hashC = (msg) => hashCons().update(toBytes(msg)).digest(); + const tmp = hashCons(); + hashC.outputLen = tmp.outputLen; + hashC.blockLen = tmp.blockLen; + hashC.create = () => hashCons(); + return hashC; + } + function randomBytes(bytesLength = 32) { + if (crypto && typeof crypto.getRandomValues === "function") { + return crypto.getRandomValues(new Uint8Array(bytesLength)); + } + throw new Error("crypto.getRandomValues must be defined"); + } + + // node_modules/@noble/curves/node_modules/@noble/hashes/esm/_sha2.js + function setBigUint64(view, byteOffset, value, isLE4) { + if (typeof view.setBigUint64 === "function") + return view.setBigUint64(byteOffset, value, isLE4); + const _32n2 = BigInt(32); + const _u32_max = BigInt(4294967295); + const wh = Number(value >> _32n2 & _u32_max); + const wl = Number(value & _u32_max); + const h = isLE4 ? 4 : 0; + const l = isLE4 ? 0 : 4; + view.setUint32(byteOffset + h, wh, isLE4); + view.setUint32(byteOffset + l, wl, isLE4); + } + var SHA2 = class extends Hash { + constructor(blockLen, outputLen, padOffset, isLE4) { + super(); + this.blockLen = blockLen; + this.outputLen = outputLen; + this.padOffset = padOffset; + this.isLE = isLE4; + this.finished = false; + this.length = 0; + this.pos = 0; + this.destroyed = false; + this.buffer = new Uint8Array(blockLen); + this.view = createView(this.buffer); + } + update(data) { + exists(this); + const { view, buffer, blockLen } = this; + data = toBytes(data); + const len = data.length; + for (let pos = 0; pos < len; ) { + const take = Math.min(blockLen - this.pos, len - pos); + if (take === blockLen) { + const dataView = createView(data); + for (; blockLen <= len - pos; pos += blockLen) + this.process(dataView, pos); + continue; + } + buffer.set(data.subarray(pos, pos + take), this.pos); + this.pos += take; + pos += take; + if (this.pos === blockLen) { + this.process(view, 0); + this.pos = 0; + } + } + this.length += data.length; + this.roundClean(); + return this; + } + digestInto(out) { + exists(this); + output(out, this); + this.finished = true; + const { buffer, view, blockLen, isLE: isLE4 } = this; + let { pos } = this; + buffer[pos++] = 128; + this.buffer.subarray(pos).fill(0); + if (this.padOffset > blockLen - pos) { + this.process(view, 0); + pos = 0; + } + for (let i2 = pos; i2 < blockLen; i2++) + buffer[i2] = 0; + setBigUint64(view, blockLen - 8, BigInt(this.length * 8), isLE4); + this.process(view, 0); + const oview = createView(out); + const len = this.outputLen; + if (len % 4) + throw new Error("_sha2: outputLen should be aligned to 32bit"); + const outLen = len / 4; + const state = this.get(); + if (outLen > state.length) + throw new Error("_sha2: outputLen bigger than state"); + for (let i2 = 0; i2 < outLen; i2++) + oview.setUint32(4 * i2, state[i2], isLE4); + } + digest() { + const { buffer, outputLen } = this; + this.digestInto(buffer); + const res = buffer.slice(0, outputLen); + this.destroy(); + return res; + } + _cloneInto(to) { + to || (to = new this.constructor()); + to.set(...this.get()); + const { blockLen, buffer, length, finished, destroyed, pos } = this; + to.length = length; + to.pos = pos; + to.finished = finished; + to.destroyed = destroyed; + if (length % blockLen) + to.buffer.set(buffer); + return to; + } + }; + + // node_modules/@noble/curves/node_modules/@noble/hashes/esm/sha256.js + var Chi = (a, b, c) => a & b ^ ~a & c; + var Maj = (a, b, c) => a & b ^ a & c ^ b & c; + var SHA256_K = /* @__PURE__ */ new Uint32Array([ + 1116352408, + 1899447441, + 3049323471, + 3921009573, + 961987163, + 1508970993, + 2453635748, + 2870763221, + 3624381080, + 310598401, + 607225278, + 1426881987, + 1925078388, + 2162078206, + 2614888103, + 3248222580, + 3835390401, + 4022224774, + 264347078, + 604807628, + 770255983, + 1249150122, + 1555081692, + 1996064986, + 2554220882, + 2821834349, + 2952996808, + 3210313671, + 3336571891, + 3584528711, + 113926993, + 338241895, + 666307205, + 773529912, + 1294757372, + 1396182291, + 1695183700, + 1986661051, + 2177026350, + 2456956037, + 2730485921, + 2820302411, + 3259730800, + 3345764771, + 3516065817, + 3600352804, + 4094571909, + 275423344, + 430227734, + 506948616, + 659060556, + 883997877, + 958139571, + 1322822218, + 1537002063, + 1747873779, + 1955562222, + 2024104815, + 2227730452, + 2361852424, + 2428436474, + 2756734187, + 3204031479, + 3329325298 + ]); + var IV = /* @__PURE__ */ new Uint32Array([ + 1779033703, + 3144134277, + 1013904242, + 2773480762, + 1359893119, + 2600822924, + 528734635, + 1541459225 + ]); + var SHA256_W = /* @__PURE__ */ new Uint32Array(64); + var SHA256 = class extends SHA2 { + constructor() { + super(64, 32, 8, false); + this.A = IV[0] | 0; + this.B = IV[1] | 0; + this.C = IV[2] | 0; + this.D = IV[3] | 0; + this.E = IV[4] | 0; + this.F = IV[5] | 0; + this.G = IV[6] | 0; + this.H = IV[7] | 0; + } + get() { + const { A, B, C, D, E, F, G, H } = this; + return [A, B, C, D, E, F, G, H]; + } + set(A, B, C, D, E, F, G, H) { + this.A = A | 0; + this.B = B | 0; + this.C = C | 0; + this.D = D | 0; + this.E = E | 0; + this.F = F | 0; + this.G = G | 0; + this.H = H | 0; + } + process(view, offset) { + for (let i2 = 0; i2 < 16; i2++, offset += 4) + SHA256_W[i2] = view.getUint32(offset, false); + for (let i2 = 16; i2 < 64; i2++) { + const W15 = SHA256_W[i2 - 15]; + const W2 = SHA256_W[i2 - 2]; + const s0 = rotr(W15, 7) ^ rotr(W15, 18) ^ W15 >>> 3; + const s1 = rotr(W2, 17) ^ rotr(W2, 19) ^ W2 >>> 10; + SHA256_W[i2] = s1 + SHA256_W[i2 - 7] + s0 + SHA256_W[i2 - 16] | 0; + } + let { A, B, C, D, E, F, G, H } = this; + for (let i2 = 0; i2 < 64; i2++) { + const sigma1 = rotr(E, 6) ^ rotr(E, 11) ^ rotr(E, 25); + const T1 = H + sigma1 + Chi(E, F, G) + SHA256_K[i2] + SHA256_W[i2] | 0; + const sigma0 = rotr(A, 2) ^ rotr(A, 13) ^ rotr(A, 22); + const T2 = sigma0 + Maj(A, B, C) | 0; + H = G; + G = F; + F = E; + E = D + T1 | 0; + D = C; + C = B; + B = A; + A = T1 + T2 | 0; + } + A = A + this.A | 0; + B = B + this.B | 0; + C = C + this.C | 0; + D = D + this.D | 0; + E = E + this.E | 0; + F = F + this.F | 0; + G = G + this.G | 0; + H = H + this.H | 0; + this.set(A, B, C, D, E, F, G, H); + } + roundClean() { + SHA256_W.fill(0); + } + destroy() { + this.set(0, 0, 0, 0, 0, 0, 0, 0); + this.buffer.fill(0); + } + }; + var sha256 = /* @__PURE__ */ wrapConstructor(() => new SHA256()); + + // node_modules/@noble/curves/esm/abstract/utils.js + var utils_exports = {}; + __export(utils_exports, { + bitGet: () => bitGet, + bitLen: () => bitLen, + bitMask: () => bitMask, + bitSet: () => bitSet, + bytesToHex: () => bytesToHex, + bytesToNumberBE: () => bytesToNumberBE, + bytesToNumberLE: () => bytesToNumberLE, + concatBytes: () => concatBytes2, + createHmacDrbg: () => createHmacDrbg, + ensureBytes: () => ensureBytes, + equalBytes: () => equalBytes, + hexToBytes: () => hexToBytes, + hexToNumber: () => hexToNumber, + numberToBytesBE: () => numberToBytesBE, + numberToBytesLE: () => numberToBytesLE, + numberToHexUnpadded: () => numberToHexUnpadded, + numberToVarBytesBE: () => numberToVarBytesBE, + utf8ToBytes: () => utf8ToBytes2, + validateObject: () => validateObject + }); + var _0n = BigInt(0); + var _1n = BigInt(1); + var _2n = BigInt(2); + var u8a2 = (a) => a instanceof Uint8Array; + var hexes = /* @__PURE__ */ Array.from({ length: 256 }, (_, i2) => i2.toString(16).padStart(2, "0")); + function bytesToHex(bytes4) { + if (!u8a2(bytes4)) + throw new Error("Uint8Array expected"); + let hex2 = ""; + for (let i2 = 0; i2 < bytes4.length; i2++) { + hex2 += hexes[bytes4[i2]]; + } + return hex2; + } + function numberToHexUnpadded(num) { + const hex2 = num.toString(16); + return hex2.length & 1 ? `0${hex2}` : hex2; + } + function hexToNumber(hex2) { + if (typeof hex2 !== "string") + throw new Error("hex string expected, got " + typeof hex2); + return BigInt(hex2 === "" ? "0" : `0x${hex2}`); + } + function hexToBytes(hex2) { + if (typeof hex2 !== "string") + throw new Error("hex string expected, got " + typeof hex2); + const len = hex2.length; + if (len % 2) + throw new Error("padded hex string expected, got unpadded hex of length " + len); + const array = new Uint8Array(len / 2); + for (let i2 = 0; i2 < array.length; i2++) { + const j = i2 * 2; + const hexByte = hex2.slice(j, j + 2); + const byte = Number.parseInt(hexByte, 16); + if (Number.isNaN(byte) || byte < 0) + throw new Error("Invalid byte sequence"); + array[i2] = byte; + } + return array; + } + function bytesToNumberBE(bytes4) { + return hexToNumber(bytesToHex(bytes4)); + } + function bytesToNumberLE(bytes4) { + if (!u8a2(bytes4)) + throw new Error("Uint8Array expected"); + return hexToNumber(bytesToHex(Uint8Array.from(bytes4).reverse())); + } + function numberToBytesBE(n, len) { + return hexToBytes(n.toString(16).padStart(len * 2, "0")); + } + function numberToBytesLE(n, len) { + return numberToBytesBE(n, len).reverse(); + } + function numberToVarBytesBE(n) { + return hexToBytes(numberToHexUnpadded(n)); + } + function ensureBytes(title, hex2, expectedLength) { + let res; + if (typeof hex2 === "string") { + try { + res = hexToBytes(hex2); + } catch (e) { + throw new Error(`${title} must be valid hex string, got "${hex2}". Cause: ${e}`); + } + } else if (u8a2(hex2)) { + res = Uint8Array.from(hex2); + } else { + throw new Error(`${title} must be hex string or Uint8Array`); + } + const len = res.length; + if (typeof expectedLength === "number" && len !== expectedLength) + throw new Error(`${title} expected ${expectedLength} bytes, got ${len}`); + return res; + } + function concatBytes2(...arrays) { + const r = new Uint8Array(arrays.reduce((sum, a) => sum + a.length, 0)); + let pad2 = 0; + arrays.forEach((a) => { + if (!u8a2(a)) + throw new Error("Uint8Array expected"); + r.set(a, pad2); + pad2 += a.length; + }); + return r; + } + function equalBytes(b1, b2) { + if (b1.length !== b2.length) + return false; + for (let i2 = 0; i2 < b1.length; i2++) + if (b1[i2] !== b2[i2]) + return false; + return true; + } + function utf8ToBytes2(str) { + if (typeof str !== "string") + throw new Error(`utf8ToBytes expected string, got ${typeof str}`); + return new Uint8Array(new TextEncoder().encode(str)); + } + function bitLen(n) { + let len; + for (len = 0; n > _0n; n >>= _1n, len += 1) + ; + return len; + } + function bitGet(n, pos) { + return n >> BigInt(pos) & _1n; + } + var bitSet = (n, pos, value) => { + return n | (value ? _1n : _0n) << BigInt(pos); + }; + var bitMask = (n) => (_2n << BigInt(n - 1)) - _1n; + var u8n = (data) => new Uint8Array(data); + var u8fr = (arr) => Uint8Array.from(arr); + function createHmacDrbg(hashLen, qByteLen, hmacFn) { + if (typeof hashLen !== "number" || hashLen < 2) + throw new Error("hashLen must be a number"); + if (typeof qByteLen !== "number" || qByteLen < 2) + throw new Error("qByteLen must be a number"); + if (typeof hmacFn !== "function") + throw new Error("hmacFn must be a function"); + let v = u8n(hashLen); + let k = u8n(hashLen); + let i2 = 0; + const reset = () => { + v.fill(1); + k.fill(0); + i2 = 0; + }; + const h = (...b) => hmacFn(k, v, ...b); + const reseed = (seed = u8n()) => { + k = h(u8fr([0]), seed); + v = h(); + if (seed.length === 0) + return; + k = h(u8fr([1]), seed); + v = h(); + }; + const gen = () => { + if (i2++ >= 1e3) + throw new Error("drbg: tried 1000 values"); + let len = 0; + const out = []; + while (len < qByteLen) { + v = h(); + const sl = v.slice(); + out.push(sl); + len += v.length; + } + return concatBytes2(...out); + }; + const genUntil = (seed, pred) => { + reset(); + reseed(seed); + let res = void 0; + while (!(res = pred(gen()))) + reseed(); + reset(); + return res; + }; + return genUntil; + } + var validatorFns = { + bigint: (val) => typeof val === "bigint", + function: (val) => typeof val === "function", + boolean: (val) => typeof val === "boolean", + string: (val) => typeof val === "string", + stringOrUint8Array: (val) => typeof val === "string" || val instanceof Uint8Array, + isSafeInteger: (val) => Number.isSafeInteger(val), + array: (val) => Array.isArray(val), + field: (val, object) => object.Fp.isValid(val), + hash: (val) => typeof val === "function" && Number.isSafeInteger(val.outputLen) + }; + function validateObject(object, validators, optValidators = {}) { + const checkField = (fieldName, type, isOptional) => { + const checkVal = validatorFns[type]; + if (typeof checkVal !== "function") + throw new Error(`Invalid validator "${type}", expected function`); + const val = object[fieldName]; + if (isOptional && val === void 0) + return; + if (!checkVal(val, object)) { + throw new Error(`Invalid param ${String(fieldName)}=${val} (${typeof val}), expected ${type}`); + } + }; + for (const [fieldName, type] of Object.entries(validators)) + checkField(fieldName, type, false); + for (const [fieldName, type] of Object.entries(optValidators)) + checkField(fieldName, type, true); + return object; + } + + // node_modules/@noble/curves/esm/abstract/modular.js + var _0n2 = BigInt(0); + var _1n2 = BigInt(1); + var _2n2 = BigInt(2); + var _3n = BigInt(3); + var _4n = BigInt(4); + var _5n = BigInt(5); + var _8n = BigInt(8); + var _9n = BigInt(9); + var _16n = BigInt(16); + function mod(a, b) { + const result = a % b; + return result >= _0n2 ? result : b + result; + } + function pow(num, power, modulo) { + if (modulo <= _0n2 || power < _0n2) + throw new Error("Expected power/modulo > 0"); + if (modulo === _1n2) + return _0n2; + let res = _1n2; + while (power > _0n2) { + if (power & _1n2) + res = res * num % modulo; + num = num * num % modulo; + power >>= _1n2; + } + return res; + } + function pow2(x, power, modulo) { + let res = x; + while (power-- > _0n2) { + res *= res; + res %= modulo; + } + return res; + } + function invert(number4, modulo) { + if (number4 === _0n2 || modulo <= _0n2) { + throw new Error(`invert: expected positive integers, got n=${number4} mod=${modulo}`); + } + let a = mod(number4, modulo); + let b = modulo; + let x = _0n2, y = _1n2, u = _1n2, v = _0n2; + while (a !== _0n2) { + const q = b / a; + const r = b % a; + const m = x - u * q; + const n = y - v * q; + b = a, a = r, x = u, y = v, u = m, v = n; + } + const gcd2 = b; + if (gcd2 !== _1n2) + throw new Error("invert: does not exist"); + return mod(x, modulo); + } + function tonelliShanks(P) { + const legendreC = (P - _1n2) / _2n2; + let Q, S, Z; + for (Q = P - _1n2, S = 0; Q % _2n2 === _0n2; Q /= _2n2, S++) + ; + for (Z = _2n2; Z < P && pow(Z, legendreC, P) !== P - _1n2; Z++) + ; + if (S === 1) { + const p1div4 = (P + _1n2) / _4n; + return function tonelliFast(Fp3, n) { + const root = Fp3.pow(n, p1div4); + if (!Fp3.eql(Fp3.sqr(root), n)) + throw new Error("Cannot find square root"); + return root; + }; + } + const Q1div2 = (Q + _1n2) / _2n2; + return function tonelliSlow(Fp3, n) { + if (Fp3.pow(n, legendreC) === Fp3.neg(Fp3.ONE)) + throw new Error("Cannot find square root"); + let r = S; + let g = Fp3.pow(Fp3.mul(Fp3.ONE, Z), Q); + let x = Fp3.pow(n, Q1div2); + let b = Fp3.pow(n, Q); + while (!Fp3.eql(b, Fp3.ONE)) { + if (Fp3.eql(b, Fp3.ZERO)) + return Fp3.ZERO; + let m = 1; + for (let t2 = Fp3.sqr(b); m < r; m++) { + if (Fp3.eql(t2, Fp3.ONE)) + break; + t2 = Fp3.sqr(t2); + } + const ge2 = Fp3.pow(g, _1n2 << BigInt(r - m - 1)); + g = Fp3.sqr(ge2); + x = Fp3.mul(x, ge2); + b = Fp3.mul(b, g); + r = m; + } + return x; + }; + } + function FpSqrt(P) { + if (P % _4n === _3n) { + const p1div4 = (P + _1n2) / _4n; + return function sqrt3mod4(Fp3, n) { + const root = Fp3.pow(n, p1div4); + if (!Fp3.eql(Fp3.sqr(root), n)) + throw new Error("Cannot find square root"); + return root; + }; + } + if (P % _8n === _5n) { + const c1 = (P - _5n) / _8n; + return function sqrt5mod8(Fp3, n) { + const n2 = Fp3.mul(n, _2n2); + const v = Fp3.pow(n2, c1); + const nv = Fp3.mul(n, v); + const i2 = Fp3.mul(Fp3.mul(nv, _2n2), v); + const root = Fp3.mul(nv, Fp3.sub(i2, Fp3.ONE)); + if (!Fp3.eql(Fp3.sqr(root), n)) + throw new Error("Cannot find square root"); + return root; + }; + } + if (P % _16n === _9n) { + } + return tonelliShanks(P); + } + var FIELD_FIELDS = [ + "create", + "isValid", + "is0", + "neg", + "inv", + "sqrt", + "sqr", + "eql", + "add", + "sub", + "mul", + "pow", + "div", + "addN", + "subN", + "mulN", + "sqrN" + ]; + function validateField(field) { + const initial = { + ORDER: "bigint", + MASK: "bigint", + BYTES: "isSafeInteger", + BITS: "isSafeInteger" + }; + const opts = FIELD_FIELDS.reduce((map, val) => { + map[val] = "function"; + return map; + }, initial); + return validateObject(field, opts); + } + function FpPow(f2, num, power) { + if (power < _0n2) + throw new Error("Expected power > 0"); + if (power === _0n2) + return f2.ONE; + if (power === _1n2) + return num; + let p = f2.ONE; + let d = num; + while (power > _0n2) { + if (power & _1n2) + p = f2.mul(p, d); + d = f2.sqr(d); + power >>= _1n2; + } + return p; + } + function FpInvertBatch(f2, nums) { + const tmp = new Array(nums.length); + const lastMultiplied = nums.reduce((acc, num, i2) => { + if (f2.is0(num)) + return acc; + tmp[i2] = acc; + return f2.mul(acc, num); + }, f2.ONE); + const inverted = f2.inv(lastMultiplied); + nums.reduceRight((acc, num, i2) => { + if (f2.is0(num)) + return acc; + tmp[i2] = f2.mul(acc, tmp[i2]); + return f2.mul(acc, num); + }, inverted); + return tmp; + } + function nLength(n, nBitLength) { + const _nBitLength = nBitLength !== void 0 ? nBitLength : n.toString(2).length; + const nByteLength = Math.ceil(_nBitLength / 8); + return { nBitLength: _nBitLength, nByteLength }; + } + function Field(ORDER, bitLen3, isLE4 = false, redef = {}) { + if (ORDER <= _0n2) + throw new Error(`Expected Field ORDER > 0, got ${ORDER}`); + const { nBitLength: BITS, nByteLength: BYTES } = nLength(ORDER, bitLen3); + if (BYTES > 2048) + throw new Error("Field lengths over 2048 bytes are not supported"); + const sqrtP = FpSqrt(ORDER); + const f2 = Object.freeze({ + ORDER, + BITS, + BYTES, + MASK: bitMask(BITS), + ZERO: _0n2, + ONE: _1n2, + create: (num) => mod(num, ORDER), + isValid: (num) => { + if (typeof num !== "bigint") + throw new Error(`Invalid field element: expected bigint, got ${typeof num}`); + return _0n2 <= num && num < ORDER; + }, + is0: (num) => num === _0n2, + isOdd: (num) => (num & _1n2) === _1n2, + neg: (num) => mod(-num, ORDER), + eql: (lhs, rhs) => lhs === rhs, + sqr: (num) => mod(num * num, ORDER), + add: (lhs, rhs) => mod(lhs + rhs, ORDER), + sub: (lhs, rhs) => mod(lhs - rhs, ORDER), + mul: (lhs, rhs) => mod(lhs * rhs, ORDER), + pow: (num, power) => FpPow(f2, num, power), + div: (lhs, rhs) => mod(lhs * invert(rhs, ORDER), ORDER), + sqrN: (num) => num * num, + addN: (lhs, rhs) => lhs + rhs, + subN: (lhs, rhs) => lhs - rhs, + mulN: (lhs, rhs) => lhs * rhs, + inv: (num) => invert(num, ORDER), + sqrt: redef.sqrt || ((n) => sqrtP(f2, n)), + invertBatch: (lst) => FpInvertBatch(f2, lst), + cmov: (a, b, c) => c ? b : a, + toBytes: (num) => isLE4 ? numberToBytesLE(num, BYTES) : numberToBytesBE(num, BYTES), + fromBytes: (bytes4) => { + if (bytes4.length !== BYTES) + throw new Error(`Fp.fromBytes: expected ${BYTES}, got ${bytes4.length}`); + return isLE4 ? bytesToNumberLE(bytes4) : bytesToNumberBE(bytes4); + } + }); + return Object.freeze(f2); + } + function getFieldBytesLength(fieldOrder) { + if (typeof fieldOrder !== "bigint") + throw new Error("field order must be bigint"); + const bitLength = fieldOrder.toString(2).length; + return Math.ceil(bitLength / 8); + } + function getMinHashLength(fieldOrder) { + const length = getFieldBytesLength(fieldOrder); + return length + Math.ceil(length / 2); + } + function mapHashToField(key, fieldOrder, isLE4 = false) { + const len = key.length; + const fieldLen = getFieldBytesLength(fieldOrder); + const minLen = getMinHashLength(fieldOrder); + if (len < 16 || len < minLen || len > 1024) + throw new Error(`expected ${minLen}-1024 bytes of input, got ${len}`); + const num = isLE4 ? bytesToNumberBE(key) : bytesToNumberLE(key); + const reduced = mod(num, fieldOrder - _1n2) + _1n2; + return isLE4 ? numberToBytesLE(reduced, fieldLen) : numberToBytesBE(reduced, fieldLen); + } + + // node_modules/@noble/curves/esm/abstract/curve.js + var _0n3 = BigInt(0); + var _1n3 = BigInt(1); + function wNAF(c, bits) { + const constTimeNegate = (condition, item) => { + const neg = item.negate(); + return condition ? neg : item; + }; + const opts = (W) => { + const windows = Math.ceil(bits / W) + 1; + const windowSize = 2 ** (W - 1); + return { windows, windowSize }; + }; + return { + constTimeNegate, + unsafeLadder(elm, n) { + let p = c.ZERO; + let d = elm; + while (n > _0n3) { + if (n & _1n3) + p = p.add(d); + d = d.double(); + n >>= _1n3; + } + return p; + }, + precomputeWindow(elm, W) { + const { windows, windowSize } = opts(W); + const points = []; + let p = elm; + let base = p; + for (let window = 0; window < windows; window++) { + base = p; + points.push(base); + for (let i2 = 1; i2 < windowSize; i2++) { + base = base.add(p); + points.push(base); + } + p = base.double(); + } + return points; + }, + wNAF(W, precomputes, n) { + const { windows, windowSize } = opts(W); + let p = c.ZERO; + let f2 = c.BASE; + const mask = BigInt(2 ** W - 1); + const maxNumber = 2 ** W; + const shiftBy = BigInt(W); + for (let window = 0; window < windows; window++) { + const offset = window * windowSize; + let wbits = Number(n & mask); + n >>= shiftBy; + if (wbits > windowSize) { + wbits -= maxNumber; + n += _1n3; + } + const offset1 = offset; + const offset2 = offset + Math.abs(wbits) - 1; + const cond1 = window % 2 !== 0; + const cond2 = wbits < 0; + if (wbits === 0) { + f2 = f2.add(constTimeNegate(cond1, precomputes[offset1])); + } else { + p = p.add(constTimeNegate(cond2, precomputes[offset2])); + } + } + return { p, f: f2 }; + }, + wNAFCached(P, precomputesMap, n, transform) { + const W = P._WINDOW_SIZE || 1; + let comp = precomputesMap.get(P); + if (!comp) { + comp = this.precomputeWindow(P, W); + if (W !== 1) { + precomputesMap.set(P, transform(comp)); + } + } + return this.wNAF(W, comp, n); + } + }; + } + function validateBasic(curve) { + validateField(curve.Fp); + validateObject(curve, { + n: "bigint", + h: "bigint", + Gx: "field", + Gy: "field" + }, { + nBitLength: "isSafeInteger", + nByteLength: "isSafeInteger" + }); + return Object.freeze({ + ...nLength(curve.n, curve.nBitLength), + ...curve, + ...{ p: curve.Fp.ORDER } + }); + } + + // node_modules/@noble/curves/esm/abstract/weierstrass.js + function validatePointOpts(curve) { + const opts = validateBasic(curve); + validateObject(opts, { + a: "field", + b: "field" + }, { + allowedPrivateKeyLengths: "array", + wrapPrivateKey: "boolean", + isTorsionFree: "function", + clearCofactor: "function", + allowInfinityPoint: "boolean", + fromBytes: "function", + toBytes: "function" + }); + const { endo, Fp: Fp3, a } = opts; + if (endo) { + if (!Fp3.eql(a, Fp3.ZERO)) { + throw new Error("Endomorphism can only be defined for Koblitz curves that have a=0"); + } + if (typeof endo !== "object" || typeof endo.beta !== "bigint" || typeof endo.splitScalar !== "function") { + throw new Error("Expected endomorphism with beta: bigint and splitScalar: function"); + } + } + return Object.freeze({ ...opts }); + } + var { bytesToNumberBE: b2n, hexToBytes: h2b } = utils_exports; + var DER = { + Err: class DERErr extends Error { + constructor(m = "") { + super(m); + } + }, + _parseInt(data) { + const { Err: E } = DER; + if (data.length < 2 || data[0] !== 2) + throw new E("Invalid signature integer tag"); + const len = data[1]; + const res = data.subarray(2, len + 2); + if (!len || res.length !== len) + throw new E("Invalid signature integer: wrong length"); + if (res[0] & 128) + throw new E("Invalid signature integer: negative"); + if (res[0] === 0 && !(res[1] & 128)) + throw new E("Invalid signature integer: unnecessary leading zero"); + return { d: b2n(res), l: data.subarray(len + 2) }; + }, + toSig(hex2) { + const { Err: E } = DER; + const data = typeof hex2 === "string" ? h2b(hex2) : hex2; + if (!(data instanceof Uint8Array)) + throw new Error("ui8a expected"); + let l = data.length; + if (l < 2 || data[0] != 48) + throw new E("Invalid signature tag"); + if (data[1] !== l - 2) + throw new E("Invalid signature: incorrect length"); + const { d: r, l: sBytes } = DER._parseInt(data.subarray(2)); + const { d: s, l: rBytesLeft } = DER._parseInt(sBytes); + if (rBytesLeft.length) + throw new E("Invalid signature: left bytes after parsing"); + return { r, s }; + }, + hexFromSig(sig) { + const slice = (s2) => Number.parseInt(s2[0], 16) & 8 ? "00" + s2 : s2; + const h = (num) => { + const hex2 = num.toString(16); + return hex2.length & 1 ? `0${hex2}` : hex2; + }; + const s = slice(h(sig.s)); + const r = slice(h(sig.r)); + const shl = s.length / 2; + const rhl = r.length / 2; + const sl = h(shl); + const rl = h(rhl); + return `30${h(rhl + shl + 4)}02${rl}${r}02${sl}${s}`; + } + }; + var _0n4 = BigInt(0); + var _1n4 = BigInt(1); + var _2n3 = BigInt(2); + var _3n2 = BigInt(3); + var _4n2 = BigInt(4); + function weierstrassPoints(opts) { + const CURVE = validatePointOpts(opts); + const { Fp: Fp3 } = CURVE; + const toBytes4 = CURVE.toBytes || ((_c, point, _isCompressed) => { + const a = point.toAffine(); + return concatBytes2(Uint8Array.from([4]), Fp3.toBytes(a.x), Fp3.toBytes(a.y)); + }); + const fromBytes = CURVE.fromBytes || ((bytes4) => { + const tail = bytes4.subarray(1); + const x = Fp3.fromBytes(tail.subarray(0, Fp3.BYTES)); + const y = Fp3.fromBytes(tail.subarray(Fp3.BYTES, 2 * Fp3.BYTES)); + return { x, y }; + }); + function weierstrassEquation(x) { + const { a, b } = CURVE; + const x2 = Fp3.sqr(x); + const x3 = Fp3.mul(x2, x); + return Fp3.add(Fp3.add(x3, Fp3.mul(x, a)), b); + } + if (!Fp3.eql(Fp3.sqr(CURVE.Gy), weierstrassEquation(CURVE.Gx))) + throw new Error("bad generator point: equation left != right"); + function isWithinCurveOrder(num) { + return typeof num === "bigint" && _0n4 < num && num < CURVE.n; + } + function assertGE(num) { + if (!isWithinCurveOrder(num)) + throw new Error("Expected valid bigint: 0 < bigint < curve.n"); + } + function normPrivateKeyToScalar(key) { + const { allowedPrivateKeyLengths: lengths, nByteLength, wrapPrivateKey, n } = CURVE; + if (lengths && typeof key !== "bigint") { + if (key instanceof Uint8Array) + key = bytesToHex(key); + if (typeof key !== "string" || !lengths.includes(key.length)) + throw new Error("Invalid key"); + key = key.padStart(nByteLength * 2, "0"); + } + let num; + try { + num = typeof key === "bigint" ? key : bytesToNumberBE(ensureBytes("private key", key, nByteLength)); + } catch (error) { + throw new Error(`private key must be ${nByteLength} bytes, hex or bigint, not ${typeof key}`); + } + if (wrapPrivateKey) + num = mod(num, n); + assertGE(num); + return num; + } + const pointPrecomputes = /* @__PURE__ */ new Map(); + function assertPrjPoint(other) { + if (!(other instanceof Point4)) + throw new Error("ProjectivePoint expected"); + } + class Point4 { + constructor(px, py, pz) { + this.px = px; + this.py = py; + this.pz = pz; + if (px == null || !Fp3.isValid(px)) + throw new Error("x required"); + if (py == null || !Fp3.isValid(py)) + throw new Error("y required"); + if (pz == null || !Fp3.isValid(pz)) + throw new Error("z required"); + } + static fromAffine(p) { + const { x, y } = p || {}; + if (!p || !Fp3.isValid(x) || !Fp3.isValid(y)) + throw new Error("invalid affine point"); + if (p instanceof Point4) + throw new Error("projective point not allowed"); + const is0 = (i2) => Fp3.eql(i2, Fp3.ZERO); + if (is0(x) && is0(y)) + return Point4.ZERO; + return new Point4(x, y, Fp3.ONE); + } + get x() { + return this.toAffine().x; + } + get y() { + return this.toAffine().y; + } + static normalizeZ(points) { + const toInv = Fp3.invertBatch(points.map((p) => p.pz)); + return points.map((p, i2) => p.toAffine(toInv[i2])).map(Point4.fromAffine); + } + static fromHex(hex2) { + const P = Point4.fromAffine(fromBytes(ensureBytes("pointHex", hex2))); + P.assertValidity(); + return P; + } + static fromPrivateKey(privateKey) { + return Point4.BASE.multiply(normPrivateKeyToScalar(privateKey)); + } + _setWindowSize(windowSize) { + this._WINDOW_SIZE = windowSize; + pointPrecomputes.delete(this); + } + assertValidity() { + if (this.is0()) { + if (CURVE.allowInfinityPoint && !Fp3.is0(this.py)) + return; + throw new Error("bad point: ZERO"); + } + const { x, y } = this.toAffine(); + if (!Fp3.isValid(x) || !Fp3.isValid(y)) + throw new Error("bad point: x or y not FE"); + const left = Fp3.sqr(y); + const right = weierstrassEquation(x); + if (!Fp3.eql(left, right)) + throw new Error("bad point: equation left != right"); + if (!this.isTorsionFree()) + throw new Error("bad point: not in prime-order subgroup"); + } + hasEvenY() { + const { y } = this.toAffine(); + if (Fp3.isOdd) + return !Fp3.isOdd(y); + throw new Error("Field doesn't support isOdd"); + } + equals(other) { + assertPrjPoint(other); + const { px: X1, py: Y1, pz: Z1 } = this; + const { px: X2, py: Y2, pz: Z2 } = other; + const U1 = Fp3.eql(Fp3.mul(X1, Z2), Fp3.mul(X2, Z1)); + const U2 = Fp3.eql(Fp3.mul(Y1, Z2), Fp3.mul(Y2, Z1)); + return U1 && U2; + } + negate() { + return new Point4(this.px, Fp3.neg(this.py), this.pz); + } + double() { + const { a, b } = CURVE; + const b3 = Fp3.mul(b, _3n2); + const { px: X1, py: Y1, pz: Z1 } = this; + let X3 = Fp3.ZERO, Y3 = Fp3.ZERO, Z3 = Fp3.ZERO; + let t0 = Fp3.mul(X1, X1); + let t1 = Fp3.mul(Y1, Y1); + let t2 = Fp3.mul(Z1, Z1); + let t3 = Fp3.mul(X1, Y1); + t3 = Fp3.add(t3, t3); + Z3 = Fp3.mul(X1, Z1); + Z3 = Fp3.add(Z3, Z3); + X3 = Fp3.mul(a, Z3); + Y3 = Fp3.mul(b3, t2); + Y3 = Fp3.add(X3, Y3); + X3 = Fp3.sub(t1, Y3); + Y3 = Fp3.add(t1, Y3); + Y3 = Fp3.mul(X3, Y3); + X3 = Fp3.mul(t3, X3); + Z3 = Fp3.mul(b3, Z3); + t2 = Fp3.mul(a, t2); + t3 = Fp3.sub(t0, t2); + t3 = Fp3.mul(a, t3); + t3 = Fp3.add(t3, Z3); + Z3 = Fp3.add(t0, t0); + t0 = Fp3.add(Z3, t0); + t0 = Fp3.add(t0, t2); + t0 = Fp3.mul(t0, t3); + Y3 = Fp3.add(Y3, t0); + t2 = Fp3.mul(Y1, Z1); + t2 = Fp3.add(t2, t2); + t0 = Fp3.mul(t2, t3); + X3 = Fp3.sub(X3, t0); + Z3 = Fp3.mul(t2, t1); + Z3 = Fp3.add(Z3, Z3); + Z3 = Fp3.add(Z3, Z3); + return new Point4(X3, Y3, Z3); + } + add(other) { + assertPrjPoint(other); + const { px: X1, py: Y1, pz: Z1 } = this; + const { px: X2, py: Y2, pz: Z2 } = other; + let X3 = Fp3.ZERO, Y3 = Fp3.ZERO, Z3 = Fp3.ZERO; + const a = CURVE.a; + const b3 = Fp3.mul(CURVE.b, _3n2); + let t0 = Fp3.mul(X1, X2); + let t1 = Fp3.mul(Y1, Y2); + let t2 = Fp3.mul(Z1, Z2); + let t3 = Fp3.add(X1, Y1); + let t4 = Fp3.add(X2, Y2); + t3 = Fp3.mul(t3, t4); + t4 = Fp3.add(t0, t1); + t3 = Fp3.sub(t3, t4); + t4 = Fp3.add(X1, Z1); + let t5 = Fp3.add(X2, Z2); + t4 = Fp3.mul(t4, t5); + t5 = Fp3.add(t0, t2); + t4 = Fp3.sub(t4, t5); + t5 = Fp3.add(Y1, Z1); + X3 = Fp3.add(Y2, Z2); + t5 = Fp3.mul(t5, X3); + X3 = Fp3.add(t1, t2); + t5 = Fp3.sub(t5, X3); + Z3 = Fp3.mul(a, t4); + X3 = Fp3.mul(b3, t2); + Z3 = Fp3.add(X3, Z3); + X3 = Fp3.sub(t1, Z3); + Z3 = Fp3.add(t1, Z3); + Y3 = Fp3.mul(X3, Z3); + t1 = Fp3.add(t0, t0); + t1 = Fp3.add(t1, t0); + t2 = Fp3.mul(a, t2); + t4 = Fp3.mul(b3, t4); + t1 = Fp3.add(t1, t2); + t2 = Fp3.sub(t0, t2); + t2 = Fp3.mul(a, t2); + t4 = Fp3.add(t4, t2); + t0 = Fp3.mul(t1, t4); + Y3 = Fp3.add(Y3, t0); + t0 = Fp3.mul(t5, t4); + X3 = Fp3.mul(t3, X3); + X3 = Fp3.sub(X3, t0); + t0 = Fp3.mul(t3, t1); + Z3 = Fp3.mul(t5, Z3); + Z3 = Fp3.add(Z3, t0); + return new Point4(X3, Y3, Z3); + } + subtract(other) { + return this.add(other.negate()); + } + is0() { + return this.equals(Point4.ZERO); + } + wNAF(n) { + return wnaf.wNAFCached(this, pointPrecomputes, n, (comp) => { + const toInv = Fp3.invertBatch(comp.map((p) => p.pz)); + return comp.map((p, i2) => p.toAffine(toInv[i2])).map(Point4.fromAffine); + }); + } + multiplyUnsafe(n) { + const I = Point4.ZERO; + if (n === _0n4) + return I; + assertGE(n); + if (n === _1n4) + return this; + const { endo } = CURVE; + if (!endo) + return wnaf.unsafeLadder(this, n); + let { k1neg, k1, k2neg, k2 } = endo.splitScalar(n); + let k1p = I; + let k2p = I; + let d = this; + while (k1 > _0n4 || k2 > _0n4) { + if (k1 & _1n4) + k1p = k1p.add(d); + if (k2 & _1n4) + k2p = k2p.add(d); + d = d.double(); + k1 >>= _1n4; + k2 >>= _1n4; + } + if (k1neg) + k1p = k1p.negate(); + if (k2neg) + k2p = k2p.negate(); + k2p = new Point4(Fp3.mul(k2p.px, endo.beta), k2p.py, k2p.pz); + return k1p.add(k2p); + } + multiply(scalar) { + assertGE(scalar); + let n = scalar; + let point, fake; + const { endo } = CURVE; + if (endo) { + const { k1neg, k1, k2neg, k2 } = endo.splitScalar(n); + let { p: k1p, f: f1p } = this.wNAF(k1); + let { p: k2p, f: f2p } = this.wNAF(k2); + k1p = wnaf.constTimeNegate(k1neg, k1p); + k2p = wnaf.constTimeNegate(k2neg, k2p); + k2p = new Point4(Fp3.mul(k2p.px, endo.beta), k2p.py, k2p.pz); + point = k1p.add(k2p); + fake = f1p.add(f2p); + } else { + const { p, f: f2 } = this.wNAF(n); + point = p; + fake = f2; + } + return Point4.normalizeZ([point, fake])[0]; + } + multiplyAndAddUnsafe(Q, a, b) { + const G = Point4.BASE; + const mul3 = (P, a2) => a2 === _0n4 || a2 === _1n4 || !P.equals(G) ? P.multiplyUnsafe(a2) : P.multiply(a2); + const sum = mul3(this, a).add(mul3(Q, b)); + return sum.is0() ? void 0 : sum; + } + toAffine(iz) { + const { px: x, py: y, pz: z } = this; + const is0 = this.is0(); + if (iz == null) + iz = is0 ? Fp3.ONE : Fp3.inv(z); + const ax = Fp3.mul(x, iz); + const ay = Fp3.mul(y, iz); + const zz = Fp3.mul(z, iz); + if (is0) + return { x: Fp3.ZERO, y: Fp3.ZERO }; + if (!Fp3.eql(zz, Fp3.ONE)) + throw new Error("invZ was invalid"); + return { x: ax, y: ay }; + } + isTorsionFree() { + const { h: cofactor, isTorsionFree } = CURVE; + if (cofactor === _1n4) + return true; + if (isTorsionFree) + return isTorsionFree(Point4, this); + throw new Error("isTorsionFree() has not been declared for the elliptic curve"); + } + clearCofactor() { + const { h: cofactor, clearCofactor } = CURVE; + if (cofactor === _1n4) + return this; + if (clearCofactor) + return clearCofactor(Point4, this); + return this.multiplyUnsafe(CURVE.h); + } + toRawBytes(isCompressed = true) { + this.assertValidity(); + return toBytes4(Point4, this, isCompressed); + } + toHex(isCompressed = true) { + return bytesToHex(this.toRawBytes(isCompressed)); + } + } + Point4.BASE = new Point4(CURVE.Gx, CURVE.Gy, Fp3.ONE); + Point4.ZERO = new Point4(Fp3.ZERO, Fp3.ONE, Fp3.ZERO); + const _bits = CURVE.nBitLength; + const wnaf = wNAF(Point4, CURVE.endo ? Math.ceil(_bits / 2) : _bits); + return { + CURVE, + ProjectivePoint: Point4, + normPrivateKeyToScalar, + weierstrassEquation, + isWithinCurveOrder + }; + } + function validateOpts(curve) { + const opts = validateBasic(curve); + validateObject(opts, { + hash: "hash", + hmac: "function", + randomBytes: "function" + }, { + bits2int: "function", + bits2int_modN: "function", + lowS: "boolean" + }); + return Object.freeze({ lowS: true, ...opts }); + } + function weierstrass(curveDef) { + const CURVE = validateOpts(curveDef); + const { Fp: Fp3, n: CURVE_ORDER } = CURVE; + const compressedLen = Fp3.BYTES + 1; + const uncompressedLen = 2 * Fp3.BYTES + 1; + function isValidFieldElement(num) { + return _0n4 < num && num < Fp3.ORDER; + } + function modN2(a) { + return mod(a, CURVE_ORDER); + } + function invN(a) { + return invert(a, CURVE_ORDER); + } + const { ProjectivePoint: Point4, normPrivateKeyToScalar, weierstrassEquation, isWithinCurveOrder } = weierstrassPoints({ + ...CURVE, + toBytes(_c, point, isCompressed) { + const a = point.toAffine(); + const x = Fp3.toBytes(a.x); + const cat = concatBytes2; + if (isCompressed) { + return cat(Uint8Array.from([point.hasEvenY() ? 2 : 3]), x); + } else { + return cat(Uint8Array.from([4]), x, Fp3.toBytes(a.y)); + } + }, + fromBytes(bytes4) { + const len = bytes4.length; + const head = bytes4[0]; + const tail = bytes4.subarray(1); + if (len === compressedLen && (head === 2 || head === 3)) { + const x = bytesToNumberBE(tail); + if (!isValidFieldElement(x)) + throw new Error("Point is not on curve"); + const y2 = weierstrassEquation(x); + let y = Fp3.sqrt(y2); + const isYOdd = (y & _1n4) === _1n4; + const isHeadOdd = (head & 1) === 1; + if (isHeadOdd !== isYOdd) + y = Fp3.neg(y); + return { x, y }; + } else if (len === uncompressedLen && head === 4) { + const x = Fp3.fromBytes(tail.subarray(0, Fp3.BYTES)); + const y = Fp3.fromBytes(tail.subarray(Fp3.BYTES, 2 * Fp3.BYTES)); + return { x, y }; + } else { + throw new Error(`Point of length ${len} was invalid. Expected ${compressedLen} compressed bytes or ${uncompressedLen} uncompressed bytes`); + } + } + }); + const numToNByteStr = (num) => bytesToHex(numberToBytesBE(num, CURVE.nByteLength)); + function isBiggerThanHalfOrder(number4) { + const HALF = CURVE_ORDER >> _1n4; + return number4 > HALF; + } + function normalizeS(s) { + return isBiggerThanHalfOrder(s) ? modN2(-s) : s; + } + const slcNum = (b, from, to) => bytesToNumberBE(b.slice(from, to)); + class Signature { + constructor(r, s, recovery) { + this.r = r; + this.s = s; + this.recovery = recovery; + this.assertValidity(); + } + static fromCompact(hex2) { + const l = CURVE.nByteLength; + hex2 = ensureBytes("compactSignature", hex2, l * 2); + return new Signature(slcNum(hex2, 0, l), slcNum(hex2, l, 2 * l)); + } + static fromDER(hex2) { + const { r, s } = DER.toSig(ensureBytes("DER", hex2)); + return new Signature(r, s); + } + assertValidity() { + if (!isWithinCurveOrder(this.r)) + throw new Error("r must be 0 < r < CURVE.n"); + if (!isWithinCurveOrder(this.s)) + throw new Error("s must be 0 < s < CURVE.n"); + } + addRecoveryBit(recovery) { + return new Signature(this.r, this.s, recovery); + } + recoverPublicKey(msgHash) { + const { r, s, recovery: rec } = this; + const h = bits2int_modN(ensureBytes("msgHash", msgHash)); + if (rec == null || ![0, 1, 2, 3].includes(rec)) + throw new Error("recovery id invalid"); + const radj = rec === 2 || rec === 3 ? r + CURVE.n : r; + if (radj >= Fp3.ORDER) + throw new Error("recovery id 2 or 3 invalid"); + const prefix = (rec & 1) === 0 ? "02" : "03"; + const R = Point4.fromHex(prefix + numToNByteStr(radj)); + const ir = invN(radj); + const u1 = modN2(-h * ir); + const u2 = modN2(s * ir); + const Q = Point4.BASE.multiplyAndAddUnsafe(R, u1, u2); + if (!Q) + throw new Error("point at infinify"); + Q.assertValidity(); + return Q; + } + hasHighS() { + return isBiggerThanHalfOrder(this.s); + } + normalizeS() { + return this.hasHighS() ? new Signature(this.r, modN2(-this.s), this.recovery) : this; + } + toDERRawBytes() { + return hexToBytes(this.toDERHex()); + } + toDERHex() { + return DER.hexFromSig({ r: this.r, s: this.s }); + } + toCompactRawBytes() { + return hexToBytes(this.toCompactHex()); + } + toCompactHex() { + return numToNByteStr(this.r) + numToNByteStr(this.s); + } + } + const utils2 = { + isValidPrivateKey(privateKey) { + try { + normPrivateKeyToScalar(privateKey); + return true; + } catch (error) { + return false; + } + }, + normPrivateKeyToScalar, + randomPrivateKey: () => { + const length = getMinHashLength(CURVE.n); + return mapHashToField(CURVE.randomBytes(length), CURVE.n); + }, + precompute(windowSize = 8, point = Point4.BASE) { + point._setWindowSize(windowSize); + point.multiply(BigInt(3)); + return point; + } + }; + function getPublicKey2(privateKey, isCompressed = true) { + return Point4.fromPrivateKey(privateKey).toRawBytes(isCompressed); + } + function isProbPub(item) { + const arr = item instanceof Uint8Array; + const str = typeof item === "string"; + const len = (arr || str) && item.length; + if (arr) + return len === compressedLen || len === uncompressedLen; + if (str) + return len === 2 * compressedLen || len === 2 * uncompressedLen; + if (item instanceof Point4) + return true; + return false; + } + function getSharedSecret(privateA, publicB, isCompressed = true) { + if (isProbPub(privateA)) + throw new Error("first arg must be private key"); + if (!isProbPub(publicB)) + throw new Error("second arg must be public key"); + const b = Point4.fromHex(publicB); + return b.multiply(normPrivateKeyToScalar(privateA)).toRawBytes(isCompressed); + } + const bits2int = CURVE.bits2int || function(bytes4) { + const num = bytesToNumberBE(bytes4); + const delta = bytes4.length * 8 - CURVE.nBitLength; + return delta > 0 ? num >> BigInt(delta) : num; + }; + const bits2int_modN = CURVE.bits2int_modN || function(bytes4) { + return modN2(bits2int(bytes4)); + }; + const ORDER_MASK = bitMask(CURVE.nBitLength); + function int2octets(num) { + if (typeof num !== "bigint") + throw new Error("bigint expected"); + if (!(_0n4 <= num && num < ORDER_MASK)) + throw new Error(`bigint expected < 2^${CURVE.nBitLength}`); + return numberToBytesBE(num, CURVE.nByteLength); + } + function prepSig(msgHash, privateKey, opts = defaultSigOpts) { + if (["recovered", "canonical"].some((k) => k in opts)) + throw new Error("sign() legacy options not supported"); + const { hash: hash3, randomBytes: randomBytes3 } = CURVE; + let { lowS, prehash, extraEntropy: ent } = opts; + if (lowS == null) + lowS = true; + msgHash = ensureBytes("msgHash", msgHash); + if (prehash) + msgHash = ensureBytes("prehashed msgHash", hash3(msgHash)); + const h1int = bits2int_modN(msgHash); + const d = normPrivateKeyToScalar(privateKey); + const seedArgs = [int2octets(d), int2octets(h1int)]; + if (ent != null) { + const e = ent === true ? randomBytes3(Fp3.BYTES) : ent; + seedArgs.push(ensureBytes("extraEntropy", e)); + } + const seed = concatBytes2(...seedArgs); + const m = h1int; + function k2sig(kBytes) { + const k = bits2int(kBytes); + if (!isWithinCurveOrder(k)) + return; + const ik = invN(k); + const q = Point4.BASE.multiply(k).toAffine(); + const r = modN2(q.x); + if (r === _0n4) + return; + const s = modN2(ik * modN2(m + r * d)); + if (s === _0n4) + return; + let recovery = (q.x === r ? 0 : 2) | Number(q.y & _1n4); + let normS = s; + if (lowS && isBiggerThanHalfOrder(s)) { + normS = normalizeS(s); + recovery ^= 1; + } + return new Signature(r, normS, recovery); + } + return { seed, k2sig }; + } + const defaultSigOpts = { lowS: CURVE.lowS, prehash: false }; + const defaultVerOpts = { lowS: CURVE.lowS, prehash: false }; + function sign(msgHash, privKey, opts = defaultSigOpts) { + const { seed, k2sig } = prepSig(msgHash, privKey, opts); + const C = CURVE; + const drbg = createHmacDrbg(C.hash.outputLen, C.nByteLength, C.hmac); + return drbg(seed, k2sig); + } + Point4.BASE._setWindowSize(8); + function verify(signature, msgHash, publicKey, opts = defaultVerOpts) { + const sg = signature; + msgHash = ensureBytes("msgHash", msgHash); + publicKey = ensureBytes("publicKey", publicKey); + if ("strict" in opts) + throw new Error("options.strict was renamed to lowS"); + const { lowS, prehash } = opts; + let _sig = void 0; + let P; + try { + if (typeof sg === "string" || sg instanceof Uint8Array) { + try { + _sig = Signature.fromDER(sg); + } catch (derError) { + if (!(derError instanceof DER.Err)) + throw derError; + _sig = Signature.fromCompact(sg); + } + } else if (typeof sg === "object" && typeof sg.r === "bigint" && typeof sg.s === "bigint") { + const { r: r2, s: s2 } = sg; + _sig = new Signature(r2, s2); + } else { + throw new Error("PARSE"); + } + P = Point4.fromHex(publicKey); + } catch (error) { + if (error.message === "PARSE") + throw new Error(`signature must be Signature instance, Uint8Array or hex string`); + return false; + } + if (lowS && _sig.hasHighS()) + return false; + if (prehash) + msgHash = CURVE.hash(msgHash); + const { r, s } = _sig; + const h = bits2int_modN(msgHash); + const is = invN(s); + const u1 = modN2(h * is); + const u2 = modN2(r * is); + const R = Point4.BASE.multiplyAndAddUnsafe(P, u1, u2)?.toAffine(); + if (!R) + return false; + const v = modN2(R.x); + return v === r; + } + return { + CURVE, + getPublicKey: getPublicKey2, + getSharedSecret, + sign, + verify, + ProjectivePoint: Point4, + Signature, + utils: utils2 + }; + } + + // node_modules/@noble/curves/node_modules/@noble/hashes/esm/hmac.js + var HMAC = class extends Hash { + constructor(hash3, _key) { + super(); + this.finished = false; + this.destroyed = false; + hash(hash3); + const key = toBytes(_key); + this.iHash = hash3.create(); + if (typeof this.iHash.update !== "function") + throw new Error("Expected instance of class which extends utils.Hash"); + this.blockLen = this.iHash.blockLen; + this.outputLen = this.iHash.outputLen; + const blockLen = this.blockLen; + const pad2 = new Uint8Array(blockLen); + pad2.set(key.length > blockLen ? hash3.create().update(key).digest() : key); + for (let i2 = 0; i2 < pad2.length; i2++) + pad2[i2] ^= 54; + this.iHash.update(pad2); + this.oHash = hash3.create(); + for (let i2 = 0; i2 < pad2.length; i2++) + pad2[i2] ^= 54 ^ 92; + this.oHash.update(pad2); + pad2.fill(0); + } + update(buf) { + exists(this); + this.iHash.update(buf); + return this; + } + digestInto(out) { + exists(this); + bytes(out, this.outputLen); + this.finished = true; + this.iHash.digestInto(out); + this.oHash.update(out); + this.oHash.digestInto(out); + this.destroy(); + } + digest() { + const out = new Uint8Array(this.oHash.outputLen); + this.digestInto(out); + return out; + } + _cloneInto(to) { + to || (to = Object.create(Object.getPrototypeOf(this), {})); + const { oHash, iHash, finished, destroyed, blockLen, outputLen } = this; + to = to; + to.finished = finished; + to.destroyed = destroyed; + to.blockLen = blockLen; + to.outputLen = outputLen; + to.oHash = oHash._cloneInto(to.oHash); + to.iHash = iHash._cloneInto(to.iHash); + return to; + } + destroy() { + this.destroyed = true; + this.oHash.destroy(); + this.iHash.destroy(); + } + }; + var hmac = (hash3, key, message) => new HMAC(hash3, key).update(message).digest(); + hmac.create = (hash3, key) => new HMAC(hash3, key); + + // node_modules/@noble/curves/esm/_shortw_utils.js + function getHash(hash3) { + return { + hash: hash3, + hmac: (key, ...msgs) => hmac(hash3, key, concatBytes(...msgs)), + randomBytes + }; + } + function createCurve(curveDef, defHash) { + const create = (hash3) => weierstrass({ ...curveDef, ...getHash(hash3) }); + return Object.freeze({ ...create(defHash), create }); + } + + // node_modules/@noble/curves/esm/secp256k1.js + var secp256k1P = BigInt("0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f"); + var secp256k1N = BigInt("0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141"); + var _1n5 = BigInt(1); + var _2n4 = BigInt(2); + var divNearest = (a, b) => (a + b / _2n4) / b; + function sqrtMod(y) { + const P = secp256k1P; + const _3n5 = BigInt(3), _6n = BigInt(6), _11n = BigInt(11), _22n = BigInt(22); + const _23n = BigInt(23), _44n = BigInt(44), _88n = BigInt(88); + const b2 = y * y * y % P; + const b3 = b2 * b2 * y % P; + const b6 = pow2(b3, _3n5, P) * b3 % P; + const b9 = pow2(b6, _3n5, P) * b3 % P; + const b11 = pow2(b9, _2n4, P) * b2 % P; + const b22 = pow2(b11, _11n, P) * b11 % P; + const b44 = pow2(b22, _22n, P) * b22 % P; + const b88 = pow2(b44, _44n, P) * b44 % P; + const b176 = pow2(b88, _88n, P) * b88 % P; + const b220 = pow2(b176, _44n, P) * b44 % P; + const b223 = pow2(b220, _3n5, P) * b3 % P; + const t1 = pow2(b223, _23n, P) * b22 % P; + const t2 = pow2(t1, _6n, P) * b2 % P; + const root = pow2(t2, _2n4, P); + if (!Fp.eql(Fp.sqr(root), y)) + throw new Error("Cannot find square root"); + return root; + } + var Fp = Field(secp256k1P, void 0, void 0, { sqrt: sqrtMod }); + var secp256k1 = createCurve({ + a: BigInt(0), + b: BigInt(7), + Fp, + n: secp256k1N, + Gx: BigInt("55066263022277343669578718895168534326250603453777594175500187360389116729240"), + Gy: BigInt("32670510020758816978083085130507043184471273380659243275938904335757337482424"), + h: BigInt(1), + lowS: true, + endo: { + beta: BigInt("0x7ae96a2b657c07106e64479eac3434e99cf0497512f58995c1396c28719501ee"), + splitScalar: (k) => { + const n = secp256k1N; + const a1 = BigInt("0x3086d221a7d46bcde86c90e49284eb15"); + const b1 = -_1n5 * BigInt("0xe4437ed6010e88286f547fa90abfe4c3"); + const a2 = BigInt("0x114ca50f7a8e2f3f657c1108d9d44cfd8"); + const b2 = a1; + const POW_2_128 = BigInt("0x100000000000000000000000000000000"); + const c1 = divNearest(b2 * k, n); + const c2 = divNearest(-b1 * k, n); + let k1 = mod(k - c1 * a1 - c2 * a2, n); + let k2 = mod(-c1 * b1 - c2 * b2, n); + const k1neg = k1 > POW_2_128; + const k2neg = k2 > POW_2_128; + if (k1neg) + k1 = n - k1; + if (k2neg) + k2 = n - k2; + if (k1 > POW_2_128 || k2 > POW_2_128) { + throw new Error("splitScalar: Endomorphism failed, k=" + k); + } + return { k1neg, k1, k2neg, k2 }; + } + } + }, sha256); + var _0n5 = BigInt(0); + var fe = (x) => typeof x === "bigint" && _0n5 < x && x < secp256k1P; + var ge = (x) => typeof x === "bigint" && _0n5 < x && x < secp256k1N; + var TAGGED_HASH_PREFIXES = {}; + function taggedHash(tag, ...messages) { + let tagP = TAGGED_HASH_PREFIXES[tag]; + if (tagP === void 0) { + const tagH = sha256(Uint8Array.from(tag, (c) => c.charCodeAt(0))); + tagP = concatBytes2(tagH, tagH); + TAGGED_HASH_PREFIXES[tag] = tagP; + } + return sha256(concatBytes2(tagP, ...messages)); + } + var pointToBytes = (point) => point.toRawBytes(true).slice(1); + var numTo32b = (n) => numberToBytesBE(n, 32); + var modP = (x) => mod(x, secp256k1P); + var modN = (x) => mod(x, secp256k1N); + var Point = secp256k1.ProjectivePoint; + var GmulAdd = (Q, a, b) => Point.BASE.multiplyAndAddUnsafe(Q, a, b); + function schnorrGetExtPubKey(priv) { + let d_ = secp256k1.utils.normPrivateKeyToScalar(priv); + let p = Point.fromPrivateKey(d_); + const scalar = p.hasEvenY() ? d_ : modN(-d_); + return { scalar, bytes: pointToBytes(p) }; + } + function lift_x(x) { + if (!fe(x)) + throw new Error("bad x: need 0 < x < p"); + const xx = modP(x * x); + const c = modP(xx * x + BigInt(7)); + let y = sqrtMod(c); + if (y % _2n4 !== _0n5) + y = modP(-y); + const p = new Point(x, y, _1n5); + p.assertValidity(); + return p; + } + function challenge(...args) { + return modN(bytesToNumberBE(taggedHash("BIP0340/challenge", ...args))); + } + function schnorrGetPublicKey(privateKey) { + return schnorrGetExtPubKey(privateKey).bytes; + } + function schnorrSign(message, privateKey, auxRand = randomBytes(32)) { + const m = ensureBytes("message", message); + const { bytes: px, scalar: d } = schnorrGetExtPubKey(privateKey); + const a = ensureBytes("auxRand", auxRand, 32); + const t = numTo32b(d ^ bytesToNumberBE(taggedHash("BIP0340/aux", a))); + const rand = taggedHash("BIP0340/nonce", t, px, m); + const k_ = modN(bytesToNumberBE(rand)); + if (k_ === _0n5) + throw new Error("sign failed: k is zero"); + const { bytes: rx, scalar: k } = schnorrGetExtPubKey(k_); + const e = challenge(rx, px, m); + const sig = new Uint8Array(64); + sig.set(rx, 0); + sig.set(numTo32b(modN(k + e * d)), 32); + if (!schnorrVerify(sig, m, px)) + throw new Error("sign: Invalid signature produced"); + return sig; + } + function schnorrVerify(signature, message, publicKey) { + const sig = ensureBytes("signature", signature, 64); + const m = ensureBytes("message", message); + const pub = ensureBytes("publicKey", publicKey, 32); + try { + const P = lift_x(bytesToNumberBE(pub)); + const r = bytesToNumberBE(sig.subarray(0, 32)); + if (!fe(r)) + return false; + const s = bytesToNumberBE(sig.subarray(32, 64)); + if (!ge(s)) + return false; + const e = challenge(numTo32b(r), pointToBytes(P), m); + const R = GmulAdd(P, s, modN(-e)); + if (!R || !R.hasEvenY() || R.toAffine().x !== r) + return false; + return true; + } catch (error) { + return false; + } + } + var schnorr = /* @__PURE__ */ (() => ({ + getPublicKey: schnorrGetPublicKey, + sign: schnorrSign, + verify: schnorrVerify, + utils: { + randomPrivateKey: secp256k1.utils.randomPrivateKey, + lift_x, + pointToBytes, + numberToBytesBE, + bytesToNumberBE, + taggedHash, + mod + } + }))(); + + // node_modules/@noble/hashes/esm/crypto.js + var crypto2 = typeof globalThis === "object" && "crypto" in globalThis ? globalThis.crypto : void 0; + + // node_modules/@noble/hashes/esm/utils.js + var u8a3 = (a) => a instanceof Uint8Array; + var createView2 = (arr) => new DataView(arr.buffer, arr.byteOffset, arr.byteLength); + var rotr2 = (word, shift) => word << 32 - shift | word >>> shift; + var isLE2 = new Uint8Array(new Uint32Array([287454020]).buffer)[0] === 68; + if (!isLE2) + throw new Error("Non little-endian hardware is not supported"); + var hexes2 = Array.from({ length: 256 }, (v, i2) => i2.toString(16).padStart(2, "0")); + function bytesToHex2(bytes4) { + if (!u8a3(bytes4)) + throw new Error("Uint8Array expected"); + let hex2 = ""; + for (let i2 = 0; i2 < bytes4.length; i2++) { + hex2 += hexes2[bytes4[i2]]; + } + return hex2; + } + function hexToBytes2(hex2) { + if (typeof hex2 !== "string") + throw new Error("hex string expected, got " + typeof hex2); + const len = hex2.length; + if (len % 2) + throw new Error("padded hex string expected, got unpadded hex of length " + len); + const array = new Uint8Array(len / 2); + for (let i2 = 0; i2 < array.length; i2++) { + const j = i2 * 2; + const hexByte = hex2.slice(j, j + 2); + const byte = Number.parseInt(hexByte, 16); + if (Number.isNaN(byte) || byte < 0) + throw new Error("Invalid byte sequence"); + array[i2] = byte; + } + return array; + } + function utf8ToBytes3(str) { + if (typeof str !== "string") + throw new Error(`utf8ToBytes expected string, got ${typeof str}`); + return new Uint8Array(new TextEncoder().encode(str)); + } + function toBytes2(data) { + if (typeof data === "string") + data = utf8ToBytes3(data); + if (!u8a3(data)) + throw new Error(`expected Uint8Array, got ${typeof data}`); + return data; + } + function concatBytes3(...arrays) { + const r = new Uint8Array(arrays.reduce((sum, a) => sum + a.length, 0)); + let pad2 = 0; + arrays.forEach((a) => { + if (!u8a3(a)) + throw new Error("Uint8Array expected"); + r.set(a, pad2); + pad2 += a.length; + }); + return r; + } + var Hash2 = class { + clone() { + return this._cloneInto(); + } + }; + var isPlainObject = (obj) => Object.prototype.toString.call(obj) === "[object Object]" && obj.constructor === Object; + function checkOpts(defaults, opts) { + if (opts !== void 0 && (typeof opts !== "object" || !isPlainObject(opts))) + throw new Error("Options should be object or undefined"); + const merged = Object.assign(defaults, opts); + return merged; + } + function wrapConstructor2(hashCons) { + const hashC = (msg) => hashCons().update(toBytes2(msg)).digest(); + const tmp = hashCons(); + hashC.outputLen = tmp.outputLen; + hashC.blockLen = tmp.blockLen; + hashC.create = () => hashCons(); + return hashC; + } + function randomBytes2(bytesLength = 32) { + if (crypto2 && typeof crypto2.getRandomValues === "function") { + return crypto2.getRandomValues(new Uint8Array(bytesLength)); + } + throw new Error("crypto.getRandomValues must be defined"); + } + + // core.ts + var verifiedSymbol = Symbol("verified"); + var isRecord = (obj) => obj instanceof Object; + function validateEvent(event) { + if (!isRecord(event)) + return false; + if (typeof event.kind !== "number") + return false; + if (typeof event.content !== "string") + return false; + if (typeof event.created_at !== "number") + return false; + if (typeof event.pubkey !== "string") + return false; + if (!event.pubkey.match(/^[a-f0-9]{64}$/)) + return false; + if (!Array.isArray(event.tags)) + return false; + for (let i2 = 0; i2 < event.tags.length; i2++) { + let tag = event.tags[i2]; + if (!Array.isArray(tag)) + return false; + for (let j = 0; j < tag.length; j++) { + if (typeof tag[j] !== "string") + return false; + } + } + return true; + } + function sortEvents(events) { + return events.sort((a, b) => { + if (a.created_at !== b.created_at) { + return b.created_at - a.created_at; + } + return a.id.localeCompare(b.id); + }); + } + + // node_modules/@noble/hashes/esm/_assert.js + function number2(n) { + if (!Number.isSafeInteger(n) || n < 0) + throw new Error(`Wrong positive integer: ${n}`); + } + function bool(b) { + if (typeof b !== "boolean") + throw new Error(`Expected boolean, not ${b}`); + } + function bytes2(b, ...lengths) { + if (!(b instanceof Uint8Array)) + throw new Error("Expected Uint8Array"); + if (lengths.length > 0 && !lengths.includes(b.length)) + throw new Error(`Expected Uint8Array of length ${lengths}, not of length=${b.length}`); + } + function hash2(hash3) { + if (typeof hash3 !== "function" || typeof hash3.create !== "function") + throw new Error("Hash should be wrapped by utils.wrapConstructor"); + number2(hash3.outputLen); + number2(hash3.blockLen); + } + function exists2(instance, checkFinished = true) { + if (instance.destroyed) + throw new Error("Hash instance has been destroyed"); + if (checkFinished && instance.finished) + throw new Error("Hash#digest() has already been called"); + } + function output2(out, instance) { + bytes2(out); + const min = instance.outputLen; + if (out.length < min) { + throw new Error(`digestInto() expects output buffer of length at least ${min}`); + } + } + var assert = { + number: number2, + bool, + bytes: bytes2, + hash: hash2, + exists: exists2, + output: output2 + }; + var assert_default = assert; + + // node_modules/@noble/hashes/esm/_sha2.js + function setBigUint642(view, byteOffset, value, isLE4) { + if (typeof view.setBigUint64 === "function") + return view.setBigUint64(byteOffset, value, isLE4); + const _32n2 = BigInt(32); + const _u32_max = BigInt(4294967295); + const wh = Number(value >> _32n2 & _u32_max); + const wl = Number(value & _u32_max); + const h = isLE4 ? 4 : 0; + const l = isLE4 ? 0 : 4; + view.setUint32(byteOffset + h, wh, isLE4); + view.setUint32(byteOffset + l, wl, isLE4); + } + var SHA22 = class extends Hash2 { + constructor(blockLen, outputLen, padOffset, isLE4) { + super(); + this.blockLen = blockLen; + this.outputLen = outputLen; + this.padOffset = padOffset; + this.isLE = isLE4; + this.finished = false; + this.length = 0; + this.pos = 0; + this.destroyed = false; + this.buffer = new Uint8Array(blockLen); + this.view = createView2(this.buffer); + } + update(data) { + assert_default.exists(this); + const { view, buffer, blockLen } = this; + data = toBytes2(data); + const len = data.length; + for (let pos = 0; pos < len; ) { + const take = Math.min(blockLen - this.pos, len - pos); + if (take === blockLen) { + const dataView = createView2(data); + for (; blockLen <= len - pos; pos += blockLen) + this.process(dataView, pos); + continue; + } + buffer.set(data.subarray(pos, pos + take), this.pos); + this.pos += take; + pos += take; + if (this.pos === blockLen) { + this.process(view, 0); + this.pos = 0; + } + } + this.length += data.length; + this.roundClean(); + return this; + } + digestInto(out) { + assert_default.exists(this); + assert_default.output(out, this); + this.finished = true; + const { buffer, view, blockLen, isLE: isLE4 } = this; + let { pos } = this; + buffer[pos++] = 128; + this.buffer.subarray(pos).fill(0); + if (this.padOffset > blockLen - pos) { + this.process(view, 0); + pos = 0; + } + for (let i2 = pos; i2 < blockLen; i2++) + buffer[i2] = 0; + setBigUint642(view, blockLen - 8, BigInt(this.length * 8), isLE4); + this.process(view, 0); + const oview = createView2(out); + const len = this.outputLen; + if (len % 4) + throw new Error("_sha2: outputLen should be aligned to 32bit"); + const outLen = len / 4; + const state = this.get(); + if (outLen > state.length) + throw new Error("_sha2: outputLen bigger than state"); + for (let i2 = 0; i2 < outLen; i2++) + oview.setUint32(4 * i2, state[i2], isLE4); + } + digest() { + const { buffer, outputLen } = this; + this.digestInto(buffer); + const res = buffer.slice(0, outputLen); + this.destroy(); + return res; + } + _cloneInto(to) { + to || (to = new this.constructor()); + to.set(...this.get()); + const { blockLen, buffer, length, finished, destroyed, pos } = this; + to.length = length; + to.pos = pos; + to.finished = finished; + to.destroyed = destroyed; + if (length % blockLen) + to.buffer.set(buffer); + return to; + } + }; + + // node_modules/@noble/hashes/esm/sha256.js + var Chi2 = (a, b, c) => a & b ^ ~a & c; + var Maj2 = (a, b, c) => a & b ^ a & c ^ b & c; + var SHA256_K2 = new Uint32Array([ + 1116352408, + 1899447441, + 3049323471, + 3921009573, + 961987163, + 1508970993, + 2453635748, + 2870763221, + 3624381080, + 310598401, + 607225278, + 1426881987, + 1925078388, + 2162078206, + 2614888103, + 3248222580, + 3835390401, + 4022224774, + 264347078, + 604807628, + 770255983, + 1249150122, + 1555081692, + 1996064986, + 2554220882, + 2821834349, + 2952996808, + 3210313671, + 3336571891, + 3584528711, + 113926993, + 338241895, + 666307205, + 773529912, + 1294757372, + 1396182291, + 1695183700, + 1986661051, + 2177026350, + 2456956037, + 2730485921, + 2820302411, + 3259730800, + 3345764771, + 3516065817, + 3600352804, + 4094571909, + 275423344, + 430227734, + 506948616, + 659060556, + 883997877, + 958139571, + 1322822218, + 1537002063, + 1747873779, + 1955562222, + 2024104815, + 2227730452, + 2361852424, + 2428436474, + 2756734187, + 3204031479, + 3329325298 + ]); + var IV2 = new Uint32Array([ + 1779033703, + 3144134277, + 1013904242, + 2773480762, + 1359893119, + 2600822924, + 528734635, + 1541459225 + ]); + var SHA256_W2 = new Uint32Array(64); + var SHA2562 = class extends SHA22 { + constructor() { + super(64, 32, 8, false); + this.A = IV2[0] | 0; + this.B = IV2[1] | 0; + this.C = IV2[2] | 0; + this.D = IV2[3] | 0; + this.E = IV2[4] | 0; + this.F = IV2[5] | 0; + this.G = IV2[6] | 0; + this.H = IV2[7] | 0; + } + get() { + const { A, B, C, D, E, F, G, H } = this; + return [A, B, C, D, E, F, G, H]; + } + set(A, B, C, D, E, F, G, H) { + this.A = A | 0; + this.B = B | 0; + this.C = C | 0; + this.D = D | 0; + this.E = E | 0; + this.F = F | 0; + this.G = G | 0; + this.H = H | 0; + } + process(view, offset) { + for (let i2 = 0; i2 < 16; i2++, offset += 4) + SHA256_W2[i2] = view.getUint32(offset, false); + for (let i2 = 16; i2 < 64; i2++) { + const W15 = SHA256_W2[i2 - 15]; + const W2 = SHA256_W2[i2 - 2]; + const s0 = rotr2(W15, 7) ^ rotr2(W15, 18) ^ W15 >>> 3; + const s1 = rotr2(W2, 17) ^ rotr2(W2, 19) ^ W2 >>> 10; + SHA256_W2[i2] = s1 + SHA256_W2[i2 - 7] + s0 + SHA256_W2[i2 - 16] | 0; + } + let { A, B, C, D, E, F, G, H } = this; + for (let i2 = 0; i2 < 64; i2++) { + const sigma1 = rotr2(E, 6) ^ rotr2(E, 11) ^ rotr2(E, 25); + const T1 = H + sigma1 + Chi2(E, F, G) + SHA256_K2[i2] + SHA256_W2[i2] | 0; + const sigma0 = rotr2(A, 2) ^ rotr2(A, 13) ^ rotr2(A, 22); + const T2 = sigma0 + Maj2(A, B, C) | 0; + H = G; + G = F; + F = E; + E = D + T1 | 0; + D = C; + C = B; + B = A; + A = T1 + T2 | 0; + } + A = A + this.A | 0; + B = B + this.B | 0; + C = C + this.C | 0; + D = D + this.D | 0; + E = E + this.E | 0; + F = F + this.F | 0; + G = G + this.G | 0; + H = H + this.H | 0; + this.set(A, B, C, D, E, F, G, H); + } + roundClean() { + SHA256_W2.fill(0); + } + destroy() { + this.set(0, 0, 0, 0, 0, 0, 0, 0); + this.buffer.fill(0); + } + }; + var SHA224 = class extends SHA2562 { + constructor() { + super(); + this.A = 3238371032 | 0; + this.B = 914150663 | 0; + this.C = 812702999 | 0; + this.D = 4144912697 | 0; + this.E = 4290775857 | 0; + this.F = 1750603025 | 0; + this.G = 1694076839 | 0; + this.H = 3204075428 | 0; + this.outputLen = 28; + } + }; + var sha2562 = wrapConstructor2(() => new SHA2562()); + var sha224 = wrapConstructor2(() => new SHA224()); + + // utils.ts + var utils_exports2 = {}; + __export(utils_exports2, { + Queue: () => Queue, + QueueNode: () => QueueNode, + binarySearch: () => binarySearch, + bytesToHex: () => bytesToHex2, + hexToBytes: () => hexToBytes2, + insertEventIntoAscendingList: () => insertEventIntoAscendingList, + insertEventIntoDescendingList: () => insertEventIntoDescendingList, + normalizeURL: () => normalizeURL, + utf8Decoder: () => utf8Decoder, + utf8Encoder: () => utf8Encoder + }); + var utf8Decoder = new TextDecoder("utf-8"); + var utf8Encoder = new TextEncoder(); + function normalizeURL(url) { + try { + if (url.indexOf("://") === -1) + url = "wss://" + url; + let p = new URL(url); + p.pathname = p.pathname.replace(/\/+/g, "/"); + if (p.pathname.endsWith("/")) + p.pathname = p.pathname.slice(0, -1); + if (p.port === "80" && p.protocol === "ws:" || p.port === "443" && p.protocol === "wss:") + p.port = ""; + p.searchParams.sort(); + p.hash = ""; + return p.toString(); + } catch (e) { + throw new Error(`Invalid URL: ${url}`); + } + } + function insertEventIntoDescendingList(sortedArray, event) { + const [idx, found] = binarySearch(sortedArray, (b) => { + if (event.id === b.id) + return 0; + if (event.created_at === b.created_at) + return -1; + return b.created_at - event.created_at; + }); + if (!found) { + sortedArray.splice(idx, 0, event); + } + return sortedArray; + } + function insertEventIntoAscendingList(sortedArray, event) { + const [idx, found] = binarySearch(sortedArray, (b) => { + if (event.id === b.id) + return 0; + if (event.created_at === b.created_at) + return -1; + return event.created_at - b.created_at; + }); + if (!found) { + sortedArray.splice(idx, 0, event); + } + return sortedArray; + } + function binarySearch(arr, compare) { + let start = 0; + let end = arr.length - 1; + while (start <= end) { + const mid = Math.floor((start + end) / 2); + const cmp = compare(arr[mid]); + if (cmp === 0) { + return [mid, true]; + } + if (cmp < 0) { + end = mid - 1; + } else { + start = mid + 1; + } + } + return [start, false]; + } + var QueueNode = class { + value; + next = null; + prev = null; + constructor(message) { + this.value = message; + } + }; + var Queue = class { + first; + last; + constructor() { + this.first = null; + this.last = null; + } + enqueue(value) { + const newNode = new QueueNode(value); + if (!this.last) { + this.first = newNode; + this.last = newNode; + } else if (this.last === this.first) { + this.last = newNode; + this.last.prev = this.first; + this.first.next = newNode; + } else { + newNode.prev = this.last; + this.last.next = newNode; + this.last = newNode; + } + return true; + } + dequeue() { + if (!this.first) + return null; + if (this.first === this.last) { + const target2 = this.first; + this.first = null; + this.last = null; + return target2.value; + } + const target = this.first; + this.first = target.next; + if (this.first) { + this.first.prev = null; + } + return target.value; + } + }; + + // pure.ts + var JS = class { + generateSecretKey() { + return schnorr.utils.randomPrivateKey(); + } + getPublicKey(secretKey) { + return bytesToHex2(schnorr.getPublicKey(secretKey)); + } + finalizeEvent(t, secretKey) { + const event = t; + event.pubkey = bytesToHex2(schnorr.getPublicKey(secretKey)); + event.id = getEventHash(event); + event.sig = bytesToHex2(schnorr.sign(getEventHash(event), secretKey)); + event[verifiedSymbol] = true; + return event; + } + verifyEvent(event) { + if (typeof event[verifiedSymbol] === "boolean") + return event[verifiedSymbol]; + const hash3 = getEventHash(event); + if (hash3 !== event.id) { + event[verifiedSymbol] = false; + return false; + } + try { + const valid = schnorr.verify(event.sig, hash3, event.pubkey); + event[verifiedSymbol] = valid; + return valid; + } catch (err) { + event[verifiedSymbol] = false; + return false; + } + } + }; + function serializeEvent(evt) { + if (!validateEvent(evt)) + throw new Error("can't serialize event with wrong or missing properties"); + return JSON.stringify([0, evt.pubkey, evt.created_at, evt.kind, evt.tags, evt.content]); + } + function getEventHash(event) { + let eventHash = sha2562(utf8Encoder.encode(serializeEvent(event))); + return bytesToHex2(eventHash); + } + var i = new JS(); + var generateSecretKey = i.generateSecretKey; + var getPublicKey = i.getPublicKey; + var finalizeEvent = i.finalizeEvent; + var verifyEvent = i.verifyEvent; + + // kinds.ts + var kinds_exports = {}; + __export(kinds_exports, { + Application: () => Application, + BadgeAward: () => BadgeAward, + BadgeDefinition: () => BadgeDefinition, + BlockedRelaysList: () => BlockedRelaysList, + BookmarkList: () => BookmarkList, + Bookmarksets: () => Bookmarksets, + Calendar: () => Calendar, + CalendarEventRSVP: () => CalendarEventRSVP, + ChannelCreation: () => ChannelCreation, + ChannelHideMessage: () => ChannelHideMessage, + ChannelMessage: () => ChannelMessage, + ChannelMetadata: () => ChannelMetadata, + ChannelMuteUser: () => ChannelMuteUser, + ClassifiedListing: () => ClassifiedListing, + ClientAuth: () => ClientAuth, + CommunitiesList: () => CommunitiesList, + CommunityDefinition: () => CommunityDefinition, + CommunityPostApproval: () => CommunityPostApproval, + Contacts: () => Contacts, + CreateOrUpdateProduct: () => CreateOrUpdateProduct, + CreateOrUpdateStall: () => CreateOrUpdateStall, + Curationsets: () => Curationsets, + Date: () => Date2, + DirectMessageRelaysList: () => DirectMessageRelaysList, + DraftClassifiedListing: () => DraftClassifiedListing, + DraftLong: () => DraftLong, + Emojisets: () => Emojisets, + EncryptedDirectMessage: () => EncryptedDirectMessage, + EventDeletion: () => EventDeletion, + FileMetadata: () => FileMetadata, + FileServerPreference: () => FileServerPreference, + Followsets: () => Followsets, + GenericRepost: () => GenericRepost, + Genericlists: () => Genericlists, + GiftWrap: () => GiftWrap, + HTTPAuth: () => HTTPAuth, + Handlerinformation: () => Handlerinformation, + Handlerrecommendation: () => Handlerrecommendation, + Highlights: () => Highlights, + InterestsList: () => InterestsList, + Interestsets: () => Interestsets, + JobFeedback: () => JobFeedback, + JobRequest: () => JobRequest, + JobResult: () => JobResult, + Label: () => Label, + LightningPubRPC: () => LightningPubRPC, + LiveChatMessage: () => LiveChatMessage, + LiveEvent: () => LiveEvent, + LongFormArticle: () => LongFormArticle, + Metadata: () => Metadata, + Mutelist: () => Mutelist, + NWCWalletInfo: () => NWCWalletInfo, + NWCWalletRequest: () => NWCWalletRequest, + NWCWalletResponse: () => NWCWalletResponse, + NostrConnect: () => NostrConnect, + OpenTimestamps: () => OpenTimestamps, + Pinlist: () => Pinlist, + PrivateDirectMessage: () => PrivateDirectMessage, + ProblemTracker: () => ProblemTracker, + ProfileBadges: () => ProfileBadges, + PublicChatsList: () => PublicChatsList, + Reaction: () => Reaction, + RecommendRelay: () => RecommendRelay, + RelayList: () => RelayList, + Relaysets: () => Relaysets, + Report: () => Report, + Reporting: () => Reporting, + Repost: () => Repost, + Seal: () => Seal, + SearchRelaysList: () => SearchRelaysList, + ShortTextNote: () => ShortTextNote, + Time: () => Time, + UserEmojiList: () => UserEmojiList, + UserStatuses: () => UserStatuses, + Zap: () => Zap, + ZapGoal: () => ZapGoal, + ZapRequest: () => ZapRequest, + classifyKind: () => classifyKind, + isAddressableKind: () => isAddressableKind, + isEphemeralKind: () => isEphemeralKind, + isKind: () => isKind, + isRegularKind: () => isRegularKind, + isReplaceableKind: () => isReplaceableKind + }); + function isRegularKind(kind) { + return 1e3 <= kind && kind < 1e4 || [1, 2, 4, 5, 6, 7, 8, 16, 40, 41, 42, 43, 44].includes(kind); + } + function isReplaceableKind(kind) { + return [0, 3].includes(kind) || 1e4 <= kind && kind < 2e4; + } + function isEphemeralKind(kind) { + return 2e4 <= kind && kind < 3e4; + } + function isAddressableKind(kind) { + return 3e4 <= kind && kind < 4e4; + } + function classifyKind(kind) { + if (isRegularKind(kind)) + return "regular"; + if (isReplaceableKind(kind)) + return "replaceable"; + if (isEphemeralKind(kind)) + return "ephemeral"; + if (isAddressableKind(kind)) + return "parameterized"; + return "unknown"; + } + function isKind(event, kind) { + const kindAsArray = kind instanceof Array ? kind : [kind]; + return validateEvent(event) && kindAsArray.includes(event.kind) || false; + } + var Metadata = 0; + var ShortTextNote = 1; + var RecommendRelay = 2; + var Contacts = 3; + var EncryptedDirectMessage = 4; + var EventDeletion = 5; + var Repost = 6; + var Reaction = 7; + var BadgeAward = 8; + var Seal = 13; + var PrivateDirectMessage = 14; + var GenericRepost = 16; + var ChannelCreation = 40; + var ChannelMetadata = 41; + var ChannelMessage = 42; + var ChannelHideMessage = 43; + var ChannelMuteUser = 44; + var OpenTimestamps = 1040; + var GiftWrap = 1059; + var FileMetadata = 1063; + var LiveChatMessage = 1311; + var ProblemTracker = 1971; + var Report = 1984; + var Reporting = 1984; + var Label = 1985; + var CommunityPostApproval = 4550; + var JobRequest = 5999; + var JobResult = 6999; + var JobFeedback = 7e3; + var ZapGoal = 9041; + var ZapRequest = 9734; + var Zap = 9735; + var Highlights = 9802; + var Mutelist = 1e4; + var Pinlist = 10001; + var RelayList = 10002; + var BookmarkList = 10003; + var CommunitiesList = 10004; + var PublicChatsList = 10005; + var BlockedRelaysList = 10006; + var SearchRelaysList = 10007; + var InterestsList = 10015; + var UserEmojiList = 10030; + var DirectMessageRelaysList = 10050; + var FileServerPreference = 10096; + var NWCWalletInfo = 13194; + var LightningPubRPC = 21e3; + var ClientAuth = 22242; + var NWCWalletRequest = 23194; + var NWCWalletResponse = 23195; + var NostrConnect = 24133; + var HTTPAuth = 27235; + var Followsets = 3e4; + var Genericlists = 30001; + var Relaysets = 30002; + var Bookmarksets = 30003; + var Curationsets = 30004; + var ProfileBadges = 30008; + var BadgeDefinition = 30009; + var Interestsets = 30015; + var CreateOrUpdateStall = 30017; + var CreateOrUpdateProduct = 30018; + var LongFormArticle = 30023; + var DraftLong = 30024; + var Emojisets = 30030; + var Application = 30078; + var LiveEvent = 30311; + var UserStatuses = 30315; + var ClassifiedListing = 30402; + var DraftClassifiedListing = 30403; + var Date2 = 31922; + var Time = 31923; + var Calendar = 31924; + var CalendarEventRSVP = 31925; + var Handlerrecommendation = 31989; + var Handlerinformation = 31990; + var CommunityDefinition = 34550; + + // filter.ts + function matchFilter(filter, event) { + if (filter.ids && filter.ids.indexOf(event.id) === -1) { + return false; + } + if (filter.kinds && filter.kinds.indexOf(event.kind) === -1) { + return false; + } + if (filter.authors && filter.authors.indexOf(event.pubkey) === -1) { + return false; + } + for (let f2 in filter) { + if (f2[0] === "#") { + let tagName = f2.slice(1); + let values = filter[`#${tagName}`]; + if (values && !event.tags.find(([t, v]) => t === f2.slice(1) && values.indexOf(v) !== -1)) + return false; + } + } + if (filter.since && event.created_at < filter.since) + return false; + if (filter.until && event.created_at > filter.until) + return false; + return true; + } + function matchFilters(filters, event) { + for (let i2 = 0; i2 < filters.length; i2++) { + if (matchFilter(filters[i2], event)) { + return true; + } + } + return false; + } + function mergeFilters(...filters) { + let result = {}; + for (let i2 = 0; i2 < filters.length; i2++) { + let filter = filters[i2]; + Object.entries(filter).forEach(([property, values]) => { + if (property === "kinds" || property === "ids" || property === "authors" || property[0] === "#") { + result[property] = result[property] || []; + for (let v = 0; v < values.length; v++) { + let value = values[v]; + if (!result[property].includes(value)) + result[property].push(value); + } + } + }); + if (filter.limit && (!result.limit || filter.limit > result.limit)) + result.limit = filter.limit; + if (filter.until && (!result.until || filter.until > result.until)) + result.until = filter.until; + if (filter.since && (!result.since || filter.since < result.since)) + result.since = filter.since; + } + return result; + } + function getFilterLimit(filter) { + if (filter.ids && !filter.ids.length) + return 0; + if (filter.kinds && !filter.kinds.length) + return 0; + if (filter.authors && !filter.authors.length) + return 0; + for (const [key, value] of Object.entries(filter)) { + if (key[0] === "#" && Array.isArray(value) && !value.length) + return 0; + } + return Math.min( + Math.max(0, filter.limit ?? Infinity), + filter.ids?.length ?? Infinity, + filter.authors?.length && filter.kinds?.every((kind) => isReplaceableKind(kind)) ? filter.authors.length * filter.kinds.length : Infinity, + filter.authors?.length && filter.kinds?.every((kind) => isAddressableKind(kind)) && filter["#d"]?.length ? filter.authors.length * filter.kinds.length * filter["#d"].length : Infinity + ); + } + + // fakejson.ts + var fakejson_exports = {}; + __export(fakejson_exports, { + getHex64: () => getHex64, + getInt: () => getInt, + getSubscriptionId: () => getSubscriptionId, + matchEventId: () => matchEventId, + matchEventKind: () => matchEventKind, + matchEventPubkey: () => matchEventPubkey + }); + function getHex64(json, field) { + let len = field.length + 3; + let idx = json.indexOf(`"${field}":`) + len; + let s = json.slice(idx).indexOf(`"`) + idx + 1; + return json.slice(s, s + 64); + } + function getInt(json, field) { + let len = field.length; + let idx = json.indexOf(`"${field}":`) + len + 3; + let sliced = json.slice(idx); + let end = Math.min(sliced.indexOf(","), sliced.indexOf("}")); + return parseInt(sliced.slice(0, end), 10); + } + function getSubscriptionId(json) { + let idx = json.slice(0, 22).indexOf(`"EVENT"`); + if (idx === -1) + return null; + let pstart = json.slice(idx + 7 + 1).indexOf(`"`); + if (pstart === -1) + return null; + let start = idx + 7 + 1 + pstart; + let pend = json.slice(start + 1, 80).indexOf(`"`); + if (pend === -1) + return null; + let end = start + 1 + pend; + return json.slice(start + 1, end); + } + function matchEventId(json, id) { + return id === getHex64(json, "id"); + } + function matchEventPubkey(json, pubkey) { + return pubkey === getHex64(json, "pubkey"); + } + function matchEventKind(json, kind) { + return kind === getInt(json, "kind"); + } + + // nip42.ts + var nip42_exports = {}; + __export(nip42_exports, { + makeAuthEvent: () => makeAuthEvent + }); + function makeAuthEvent(relayURL, challenge2) { + return { + kind: ClientAuth, + created_at: Math.floor(Date.now() / 1e3), + tags: [ + ["relay", relayURL], + ["challenge", challenge2] + ], + content: "" + }; + } + + // helpers.ts + async function yieldThread() { + return new Promise((resolve) => { + const ch = new MessageChannel(); + const handler = () => { + ch.port1.removeEventListener("message", handler); + resolve(); + }; + ch.port1.addEventListener("message", handler); + ch.port2.postMessage(0); + ch.port1.start(); + }); + } + var alwaysTrue = (t) => { + t[verifiedSymbol] = true; + return true; + }; + + // abstract-relay.ts + var SendingOnClosedConnection = class extends Error { + constructor(message, relay) { + super(`Tried to send message '${message} on a closed connection to ${relay}.`); + this.name = "SendingOnClosedConnection"; + } + }; + var AbstractRelay = class { + url; + _connected = false; + onclose = null; + onnotice = (msg) => console.debug(`NOTICE from ${this.url}: ${msg}`); + baseEoseTimeout = 4400; + connectionTimeout = 4400; + publishTimeout = 4400; + pingFrequency = 2e4; + pingTimeout = 2e4; + openSubs = /* @__PURE__ */ new Map(); + enablePing; + connectionTimeoutHandle; + connectionPromise; + openCountRequests = /* @__PURE__ */ new Map(); + openEventPublishes = /* @__PURE__ */ new Map(); + ws; + incomingMessageQueue = new Queue(); + queueRunning = false; + challenge; + authPromise; + serial = 0; + verifyEvent; + _WebSocket; + constructor(url, opts) { + this.url = normalizeURL(url); + this.verifyEvent = opts.verifyEvent; + this._WebSocket = opts.websocketImplementation || WebSocket; + this.enablePing = opts.enablePing; + } + static async connect(url, opts) { + const relay = new AbstractRelay(url, opts); + await relay.connect(); + return relay; + } + closeAllSubscriptions(reason) { + for (let [_, sub] of this.openSubs) { + sub.close(reason); + } + this.openSubs.clear(); + for (let [_, ep] of this.openEventPublishes) { + ep.reject(new Error(reason)); + } + this.openEventPublishes.clear(); + for (let [_, cr] of this.openCountRequests) { + cr.reject(new Error(reason)); + } + this.openCountRequests.clear(); + } + get connected() { + return this._connected; + } + async connect() { + if (this.connectionPromise) + return this.connectionPromise; + this.challenge = void 0; + this.authPromise = void 0; + this.connectionPromise = new Promise((resolve, reject) => { + this.connectionTimeoutHandle = setTimeout(() => { + reject("connection timed out"); + this.connectionPromise = void 0; + this.onclose?.(); + this.closeAllSubscriptions("relay connection timed out"); + }, this.connectionTimeout); + try { + this.ws = new this._WebSocket(this.url); + } catch (err) { + clearTimeout(this.connectionTimeoutHandle); + reject(err); + return; + } + this.ws.onopen = () => { + clearTimeout(this.connectionTimeoutHandle); + this._connected = true; + if (this.enablePing) { + this.pingpong(); + } + resolve(); + }; + this.ws.onerror = (ev) => { + clearTimeout(this.connectionTimeoutHandle); + reject(ev.message || "websocket error"); + this._connected = false; + this.connectionPromise = void 0; + this.onclose?.(); + this.closeAllSubscriptions("relay connection errored"); + }; + this.ws.onclose = (ev) => { + clearTimeout(this.connectionTimeoutHandle); + reject(ev.message || "websocket closed"); + this._connected = false; + this.connectionPromise = void 0; + this.onclose?.(); + this.closeAllSubscriptions("relay connection closed"); + }; + this.ws.onmessage = this._onmessage.bind(this); + }); + return this.connectionPromise; + } + async waitForPingPong() { + return new Promise((res, err) => { + ; + this.ws && this.ws.on && this.ws.on("pong", () => res(true)) || err("ws can't listen for pong"); + this.ws && this.ws.ping && this.ws.ping(); + }); + } + async waitForDummyReq() { + return new Promise((resolve, _) => { + const sub = this.subscribe([{ ids: ["a".repeat(64)] }], { + oneose: () => { + sub.close(); + resolve(true); + }, + eoseTimeout: this.pingTimeout + 1e3 + }); + }); + } + async pingpong() { + if (this.ws?.readyState === 1) { + const result = await Promise.any([ + this.ws && this.ws.ping && this.ws.on ? this.waitForPingPong() : this.waitForDummyReq(), + new Promise((res) => setTimeout(() => res(false), this.pingTimeout)) + ]); + if (result) { + setTimeout(() => this.pingpong(), this.pingFrequency); + } else { + this.closeAllSubscriptions("pingpong timed out"); + this._connected = false; + this.onclose?.(); + this.ws?.close(); + } + } + } + async runQueue() { + this.queueRunning = true; + while (true) { + if (false === this.handleNext()) { + break; + } + await yieldThread(); + } + this.queueRunning = false; + } + handleNext() { + const json = this.incomingMessageQueue.dequeue(); + if (!json) { + return false; + } + const subid = getSubscriptionId(json); + if (subid) { + const so = this.openSubs.get(subid); + if (!so) { + return; + } + const id = getHex64(json, "id"); + const alreadyHave = so.alreadyHaveEvent?.(id); + so.receivedEvent?.(this, id); + if (alreadyHave) { + return; + } + } + try { + let data = JSON.parse(json); + switch (data[0]) { + case "EVENT": { + const so = this.openSubs.get(data[1]); + const event = data[2]; + if (this.verifyEvent(event) && matchFilters(so.filters, event)) { + so.onevent(event); + } + return; + } + case "COUNT": { + const id = data[1]; + const payload = data[2]; + const cr = this.openCountRequests.get(id); + if (cr) { + cr.resolve(payload.count); + this.openCountRequests.delete(id); + } + return; + } + case "EOSE": { + const so = this.openSubs.get(data[1]); + if (!so) + return; + so.receivedEose(); + return; + } + case "OK": { + const id = data[1]; + const ok = data[2]; + const reason = data[3]; + const ep = this.openEventPublishes.get(id); + if (ep) { + clearTimeout(ep.timeout); + if (ok) + ep.resolve(reason); + else + ep.reject(new Error(reason)); + this.openEventPublishes.delete(id); + } + return; + } + case "CLOSED": { + const id = data[1]; + const so = this.openSubs.get(id); + if (!so) + return; + so.closed = true; + so.close(data[2]); + return; + } + case "NOTICE": + this.onnotice(data[1]); + return; + case "AUTH": { + this.challenge = data[1]; + return; + } + } + } catch (err) { + return; + } + } + async send(message) { + if (!this.connectionPromise) + throw new SendingOnClosedConnection(message, this.url); + this.connectionPromise.then(() => { + this.ws?.send(message); + }); + } + async auth(signAuthEvent) { + const challenge2 = this.challenge; + if (!challenge2) + throw new Error("can't perform auth, no challenge was received"); + if (this.authPromise) + return this.authPromise; + this.authPromise = new Promise(async (resolve, reject) => { + try { + let evt = await signAuthEvent(makeAuthEvent(this.url, challenge2)); + let timeout = setTimeout(() => { + let ep = this.openEventPublishes.get(evt.id); + if (ep) { + ep.reject(new Error("auth timed out")); + this.openEventPublishes.delete(evt.id); + } + }, this.publishTimeout); + this.openEventPublishes.set(evt.id, { resolve, reject, timeout }); + this.send('["AUTH",' + JSON.stringify(evt) + "]"); + } catch (err) { + console.warn("subscribe auth function failed:", err); + } + }); + return this.authPromise; + } + async publish(event) { + const ret = new Promise((resolve, reject) => { + const timeout = setTimeout(() => { + const ep = this.openEventPublishes.get(event.id); + if (ep) { + ep.reject(new Error("publish timed out")); + this.openEventPublishes.delete(event.id); + } + }, this.publishTimeout); + this.openEventPublishes.set(event.id, { resolve, reject, timeout }); + }); + this.send('["EVENT",' + JSON.stringify(event) + "]"); + return ret; + } + async count(filters, params) { + this.serial++; + const id = params?.id || "count:" + this.serial; + const ret = new Promise((resolve, reject) => { + this.openCountRequests.set(id, { resolve, reject }); + }); + this.send('["COUNT","' + id + '",' + JSON.stringify(filters).substring(1)); + return ret; + } + subscribe(filters, params) { + const subscription = this.prepareSubscription(filters, params); + subscription.fire(); + return subscription; + } + prepareSubscription(filters, params) { + this.serial++; + const id = params.id || (params.label ? params.label + ":" : "sub:") + this.serial; + const subscription = new Subscription(this, id, filters, params); + this.openSubs.set(id, subscription); + return subscription; + } + close() { + this.closeAllSubscriptions("relay connection closed by us"); + this._connected = false; + this.onclose?.(); + this.ws?.close(); + } + _onmessage(ev) { + this.incomingMessageQueue.enqueue(ev.data); + if (!this.queueRunning) { + this.runQueue(); + } + } + }; + var Subscription = class { + relay; + id; + closed = false; + eosed = false; + filters; + alreadyHaveEvent; + receivedEvent; + onevent; + oneose; + onclose; + eoseTimeout; + eoseTimeoutHandle; + constructor(relay, id, filters, params) { + this.relay = relay; + this.filters = filters; + this.id = id; + this.alreadyHaveEvent = params.alreadyHaveEvent; + this.receivedEvent = params.receivedEvent; + this.eoseTimeout = params.eoseTimeout || relay.baseEoseTimeout; + this.oneose = params.oneose; + this.onclose = params.onclose; + this.onevent = params.onevent || ((event) => { + console.warn( + `onevent() callback not defined for subscription '${this.id}' in relay ${this.relay.url}. event received:`, + event + ); + }); + } + fire() { + this.relay.send('["REQ","' + this.id + '",' + JSON.stringify(this.filters).substring(1)); + this.eoseTimeoutHandle = setTimeout(this.receivedEose.bind(this), this.eoseTimeout); + } + receivedEose() { + if (this.eosed) + return; + clearTimeout(this.eoseTimeoutHandle); + this.eosed = true; + this.oneose?.(); + } + close(reason = "closed by caller") { + if (!this.closed && this.relay.connected) { + try { + this.relay.send('["CLOSE",' + JSON.stringify(this.id) + "]"); + } catch (err) { + if (err instanceof SendingOnClosedConnection) { + } else { + throw err; + } + } + this.closed = true; + } + this.relay.openSubs.delete(this.id); + this.onclose?.(reason); + } + }; + + // relay.ts + var _WebSocket; + try { + _WebSocket = WebSocket; + } catch { + } + var Relay = class extends AbstractRelay { + constructor(url) { + super(url, { verifyEvent, websocketImplementation: _WebSocket }); + } + static async connect(url) { + const relay = new Relay(url); + await relay.connect(); + return relay; + } + }; + + // abstract-pool.ts + var AbstractSimplePool = class { + relays = /* @__PURE__ */ new Map(); + seenOn = /* @__PURE__ */ new Map(); + trackRelays = false; + verifyEvent; + enablePing; + trustedRelayURLs = /* @__PURE__ */ new Set(); + _WebSocket; + constructor(opts) { + this.verifyEvent = opts.verifyEvent; + this._WebSocket = opts.websocketImplementation; + this.enablePing = opts.enablePing; + } + async ensureRelay(url, params) { + const rawUrl = url; + const debugEnabled = typeof window !== "undefined" && !!window.__SIMPLE_POOL_DEBUG__; + url = normalizeURL(url); + let relay = this.relays.get(url); + if (debugEnabled) { + console.log("🔎 SIMPLE_POOL ensureRelay START", { + rawUrl, + normalizedUrl: url, + hadRelay: !!relay, + relayMapKeysBefore: Array.from(this.relays.keys()) + }); + } + if (!relay) { + relay = new AbstractRelay(url, { + verifyEvent: this.trustedRelayURLs.has(url) ? alwaysTrue : this.verifyEvent, + websocketImplementation: this._WebSocket, + enablePing: this.enablePing + }); + relay.onclose = () => { + if (debugEnabled) { + console.log("🔎 SIMPLE_POOL ensureRelay onclose", { + normalizedUrl: url, + relayMapKeysBeforeDelete: Array.from(this.relays.keys()) + }); + } + this.relays.delete(url); + if (debugEnabled) { + console.log("🔎 SIMPLE_POOL ensureRelay onclose complete", { + normalizedUrl: url, + relayMapKeysAfterDelete: Array.from(this.relays.keys()) + }); + } + }; + if (params?.connectionTimeout) + relay.connectionTimeout = params.connectionTimeout; + this.relays.set(url, relay); + if (debugEnabled) { + console.log("🔎 SIMPLE_POOL ensureRelay created relay", { + normalizedUrl: url, + relayMapKeysAfterCreate: Array.from(this.relays.keys()) + }); + } + } + await relay.connect(); + if (debugEnabled) { + console.log("🔎 SIMPLE_POOL ensureRelay connected", { + normalizedUrl: url, + relayConnected: relay.connected, + relayMapKeysAfterConnect: Array.from(this.relays.keys()) + }); + } + return relay; + } + close(relays) { + relays.map(normalizeURL).forEach((url) => { + this.relays.get(url)?.close(); + this.relays.delete(url); + }); + } + subscribe(relays, filter, params) { + params.onauth = params.onauth || params.doauth; + const request = []; + for (let i2 = 0; i2 < relays.length; i2++) { + const url = normalizeURL(relays[i2]); + if (!request.find((r) => r.url === url)) { + request.push({ url, filter }); + } + } + return this.subscribeMap(request, params); + } + subscribeMany(relays, filters, params) { + params.onauth = params.onauth || params.doauth; + const debugEnabled = typeof window !== "undefined" && !!window.__SIMPLE_POOL_DEBUG__; + const request = []; + const uniqUrls = []; + for (let i2 = 0; i2 < relays.length; i2++) { + const url = normalizeURL(relays[i2]); + if (uniqUrls.indexOf(url) === -1) { + uniqUrls.push(url); + for (let f2 = 0; f2 < filters.length; f2++) { + request.push({ url, filter: filters[f2] }); + } + } + } + if (debugEnabled) { + console.log("🔎 SIMPLE_POOL subscribeMany", { + relaysInput: relays, + uniqUrls, + filtersCount: filters.length, + requestsCount: request.length + }); + } + return this.subscribeMap(request, params); + } + subscribeMap(requests, params) { + params.onauth = params.onauth || params.doauth; + if (this.trackRelays) { + params.receivedEvent = (relay, id) => { + let set = this.seenOn.get(id); + if (!set) { + set = /* @__PURE__ */ new Set(); + this.seenOn.set(id, set); + } + set.add(relay); + }; + } + const _knownIds = /* @__PURE__ */ new Set(); + const subs = []; + const eosesReceived = []; + let handleEose = (i2) => { + if (eosesReceived[i2]) + return; + eosesReceived[i2] = true; + if (eosesReceived.filter((a) => a).length === requests.length) { + params.oneose?.(); + handleEose = () => { + }; + } + }; + const closesReceived = []; + let handleClose = (i2, reason) => { + if (closesReceived[i2]) + return; + handleEose(i2); + closesReceived[i2] = reason; + if (closesReceived.filter((a) => a).length === requests.length) { + params.onclose?.(closesReceived); + handleClose = () => { + }; + } + }; + const localAlreadyHaveEventHandler = (id) => { + if (params.alreadyHaveEvent?.(id)) { + return true; + } + const have = _knownIds.has(id); + _knownIds.add(id); + return have; + }; + const debugEnabled = typeof window !== "undefined" && !!window.__SIMPLE_POOL_DEBUG__; + const allOpened = Promise.all( + requests.map(async ({ url, filter }, i2) => { + if (debugEnabled) { + console.log("🔎 SIMPLE_POOL subscribeMap request", { + index: i2, + url, + filterKinds: filter?.kinds, + hasAuthorFilter: !!filter?.authors, + hasPTagFilter: !!filter?.["#p"] + }); + } + let relay; + try { + relay = await this.ensureRelay(url, { + connectionTimeout: params.maxWait ? Math.max(params.maxWait * 0.8, params.maxWait - 1e3) : void 0 + }); + } catch (err) { + if (debugEnabled) { + console.log("🔎 SIMPLE_POOL subscribeMap ensureRelay FAILED", { + index: i2, + url, + error: err?.message || String(err) + }); + } + handleClose(i2, err?.message || String(err)); + return; + } + let subscription = relay.subscribe([filter], { + ...params, + oneose: () => handleEose(i2), + onclose: (reason) => { + if (reason.startsWith("auth-required: ") && params.onauth) { + relay.auth(params.onauth).then(() => { + relay.subscribe([filter], { + ...params, + oneose: () => handleEose(i2), + onclose: (reason2) => { + handleClose(i2, reason2); + }, + alreadyHaveEvent: localAlreadyHaveEventHandler, + eoseTimeout: params.maxWait + }); + }).catch((err) => { + handleClose(i2, `auth was required and attempted, but failed with: ${err}`); + }); + } else { + handleClose(i2, reason); + } + }, + alreadyHaveEvent: localAlreadyHaveEventHandler, + eoseTimeout: params.maxWait + }); + subs.push(subscription); + }) + ); + return { + async close(reason) { + await allOpened; + subs.forEach((sub) => { + sub.close(reason); + }); + } + }; + } + subscribeEose(relays, filter, params) { + params.onauth = params.onauth || params.doauth; + const subcloser = this.subscribe(relays, filter, { + ...params, + oneose() { + subcloser.close("closed automatically on eose"); + } + }); + return subcloser; + } + subscribeManyEose(relays, filters, params) { + params.onauth = params.onauth || params.doauth; + const subcloser = this.subscribeMany(relays, filters, { + ...params, + oneose() { + subcloser.close("closed automatically on eose"); + } + }); + return subcloser; + } + async querySync(relays, filter, params) { + return new Promise(async (resolve) => { + const events = []; + this.subscribeEose(relays, filter, { + ...params, + onevent(event) { + events.push(event); + }, + onclose(_) { + resolve(events); + } + }); + }); + } + async get(relays, filter, params) { + filter.limit = 1; + const events = await this.querySync(relays, filter, params); + events.sort((a, b) => b.created_at - a.created_at); + return events[0] || null; + } + publish(relays, event, options) { + const debugEnabled = typeof window !== "undefined" && !!window.__SIMPLE_POOL_DEBUG__; + const normalizedRelays = relays.map(normalizeURL); + if (debugEnabled) { + console.log("🔎 SIMPLE_POOL publish START", { + relaysInput: relays, + normalizedRelays, + eventKind: event?.kind, + eventId: event?.id + }); + } + return normalizedRelays.map(async (url, i2, arr) => { + if (arr.indexOf(url) !== i2) { + if (debugEnabled) { + console.log("🔎 SIMPLE_POOL publish duplicate URL", { url, index: i2 }); + } + return Promise.reject("duplicate url"); + } + let r = await this.ensureRelay(url); + if (debugEnabled) { + console.log("🔎 SIMPLE_POOL publish ensured relay", { + url, + relayConnected: r?.connected, + relayMapKeys: Array.from(this.relays.keys()) + }); + } + return r.publish(event).catch(async (err) => { + if (debugEnabled) { + console.log("🔎 SIMPLE_POOL publish ERROR", { + url, + error: err?.message || String(err) + }); + } + if (err instanceof Error && err.message.startsWith("auth-required: ") && options?.onauth) { + await r.auth(options.onauth); + return r.publish(event); + } + throw err; + }).then((reason) => { + if (debugEnabled) { + console.log("🔎 SIMPLE_POOL publish SUCCESS", { + url, + reason + }); + } + if (this.trackRelays) { + let set = this.seenOn.get(event.id); + if (!set) { + set = /* @__PURE__ */ new Set(); + this.seenOn.set(event.id, set); + } + set.add(r); + } + return reason; + }); + }); + } + listConnectionStatus() { + const map = /* @__PURE__ */ new Map(); + this.relays.forEach((relay, url) => map.set(url, relay.connected)); + return map; + } + destroy() { + this.relays.forEach((conn) => conn.close()); + this.relays = /* @__PURE__ */ new Map(); + } + }; + + // pool.ts + var _WebSocket2; + try { + _WebSocket2 = WebSocket; + } catch { + } + var SimplePool = class extends AbstractSimplePool { + constructor(options) { + super({ verifyEvent, websocketImplementation: _WebSocket2, ...options }); + } + }; + + // nip19.ts + var nip19_exports = {}; + __export(nip19_exports, { + BECH32_REGEX: () => BECH32_REGEX, + Bech32MaxSize: () => Bech32MaxSize, + NostrTypeGuard: () => NostrTypeGuard, + decode: () => decode, + decodeNostrURI: () => decodeNostrURI, + encodeBytes: () => encodeBytes, + naddrEncode: () => naddrEncode, + neventEncode: () => neventEncode, + noteEncode: () => noteEncode, + nprofileEncode: () => nprofileEncode, + npubEncode: () => npubEncode, + nsecEncode: () => nsecEncode + }); + + // node_modules/@scure/base/lib/esm/index.js + function assertNumber(n) { + if (!Number.isSafeInteger(n)) + throw new Error(`Wrong integer: ${n}`); + } + function chain(...args) { + const wrap = (a, b) => (c) => a(b(c)); + const encode = Array.from(args).reverse().reduce((acc, i2) => acc ? wrap(acc, i2.encode) : i2.encode, void 0); + const decode2 = args.reduce((acc, i2) => acc ? wrap(acc, i2.decode) : i2.decode, void 0); + return { encode, decode: decode2 }; + } + function alphabet(alphabet2) { + return { + encode: (digits) => { + if (!Array.isArray(digits) || digits.length && typeof digits[0] !== "number") + throw new Error("alphabet.encode input should be an array of numbers"); + return digits.map((i2) => { + assertNumber(i2); + if (i2 < 0 || i2 >= alphabet2.length) + throw new Error(`Digit index outside alphabet: ${i2} (alphabet: ${alphabet2.length})`); + return alphabet2[i2]; + }); + }, + decode: (input) => { + if (!Array.isArray(input) || input.length && typeof input[0] !== "string") + throw new Error("alphabet.decode input should be array of strings"); + return input.map((letter) => { + if (typeof letter !== "string") + throw new Error(`alphabet.decode: not string element=${letter}`); + const index = alphabet2.indexOf(letter); + if (index === -1) + throw new Error(`Unknown letter: "${letter}". Allowed: ${alphabet2}`); + return index; + }); + } + }; + } + function join(separator = "") { + if (typeof separator !== "string") + throw new Error("join separator should be string"); + return { + encode: (from) => { + if (!Array.isArray(from) || from.length && typeof from[0] !== "string") + throw new Error("join.encode input should be array of strings"); + for (let i2 of from) + if (typeof i2 !== "string") + throw new Error(`join.encode: non-string input=${i2}`); + return from.join(separator); + }, + decode: (to) => { + if (typeof to !== "string") + throw new Error("join.decode input should be string"); + return to.split(separator); + } + }; + } + function padding(bits, chr = "=") { + assertNumber(bits); + if (typeof chr !== "string") + throw new Error("padding chr should be string"); + return { + encode(data) { + if (!Array.isArray(data) || data.length && typeof data[0] !== "string") + throw new Error("padding.encode input should be array of strings"); + for (let i2 of data) + if (typeof i2 !== "string") + throw new Error(`padding.encode: non-string input=${i2}`); + while (data.length * bits % 8) + data.push(chr); + return data; + }, + decode(input) { + if (!Array.isArray(input) || input.length && typeof input[0] !== "string") + throw new Error("padding.encode input should be array of strings"); + for (let i2 of input) + if (typeof i2 !== "string") + throw new Error(`padding.decode: non-string input=${i2}`); + let end = input.length; + if (end * bits % 8) + throw new Error("Invalid padding: string should have whole number of bytes"); + for (; end > 0 && input[end - 1] === chr; end--) { + if (!((end - 1) * bits % 8)) + throw new Error("Invalid padding: string has too much padding"); + } + return input.slice(0, end); + } + }; + } + function normalize(fn) { + if (typeof fn !== "function") + throw new Error("normalize fn should be function"); + return { encode: (from) => from, decode: (to) => fn(to) }; + } + function convertRadix(data, from, to) { + if (from < 2) + throw new Error(`convertRadix: wrong from=${from}, base cannot be less than 2`); + if (to < 2) + throw new Error(`convertRadix: wrong to=${to}, base cannot be less than 2`); + if (!Array.isArray(data)) + throw new Error("convertRadix: data should be array"); + if (!data.length) + return []; + let pos = 0; + const res = []; + const digits = Array.from(data); + digits.forEach((d) => { + assertNumber(d); + if (d < 0 || d >= from) + throw new Error(`Wrong integer: ${d}`); + }); + while (true) { + let carry = 0; + let done = true; + for (let i2 = pos; i2 < digits.length; i2++) { + const digit = digits[i2]; + const digitBase = from * carry + digit; + if (!Number.isSafeInteger(digitBase) || from * carry / from !== carry || digitBase - digit !== from * carry) { + throw new Error("convertRadix: carry overflow"); + } + carry = digitBase % to; + digits[i2] = Math.floor(digitBase / to); + if (!Number.isSafeInteger(digits[i2]) || digits[i2] * to + carry !== digitBase) + throw new Error("convertRadix: carry overflow"); + if (!done) + continue; + else if (!digits[i2]) + pos = i2; + else + done = false; + } + res.push(carry); + if (done) + break; + } + for (let i2 = 0; i2 < data.length - 1 && data[i2] === 0; i2++) + res.push(0); + return res.reverse(); + } + var gcd = (a, b) => !b ? a : gcd(b, a % b); + var radix2carry = (from, to) => from + (to - gcd(from, to)); + function convertRadix2(data, from, to, padding2) { + if (!Array.isArray(data)) + throw new Error("convertRadix2: data should be array"); + if (from <= 0 || from > 32) + throw new Error(`convertRadix2: wrong from=${from}`); + if (to <= 0 || to > 32) + throw new Error(`convertRadix2: wrong to=${to}`); + if (radix2carry(from, to) > 32) { + throw new Error(`convertRadix2: carry overflow from=${from} to=${to} carryBits=${radix2carry(from, to)}`); + } + let carry = 0; + let pos = 0; + const mask = 2 ** to - 1; + const res = []; + for (const n of data) { + assertNumber(n); + if (n >= 2 ** from) + throw new Error(`convertRadix2: invalid data word=${n} from=${from}`); + carry = carry << from | n; + if (pos + from > 32) + throw new Error(`convertRadix2: carry overflow pos=${pos} from=${from}`); + pos += from; + for (; pos >= to; pos -= to) + res.push((carry >> pos - to & mask) >>> 0); + carry &= 2 ** pos - 1; + } + carry = carry << to - pos & mask; + if (!padding2 && pos >= from) + throw new Error("Excess padding"); + if (!padding2 && carry) + throw new Error(`Non-zero padding: ${carry}`); + if (padding2 && pos > 0) + res.push(carry >>> 0); + return res; + } + function radix(num) { + assertNumber(num); + return { + encode: (bytes4) => { + if (!(bytes4 instanceof Uint8Array)) + throw new Error("radix.encode input should be Uint8Array"); + return convertRadix(Array.from(bytes4), 2 ** 8, num); + }, + decode: (digits) => { + if (!Array.isArray(digits) || digits.length && typeof digits[0] !== "number") + throw new Error("radix.decode input should be array of strings"); + return Uint8Array.from(convertRadix(digits, num, 2 ** 8)); + } + }; + } + function radix2(bits, revPadding = false) { + assertNumber(bits); + if (bits <= 0 || bits > 32) + throw new Error("radix2: bits should be in (0..32]"); + if (radix2carry(8, bits) > 32 || radix2carry(bits, 8) > 32) + throw new Error("radix2: carry overflow"); + return { + encode: (bytes4) => { + if (!(bytes4 instanceof Uint8Array)) + throw new Error("radix2.encode input should be Uint8Array"); + return convertRadix2(Array.from(bytes4), 8, bits, !revPadding); + }, + decode: (digits) => { + if (!Array.isArray(digits) || digits.length && typeof digits[0] !== "number") + throw new Error("radix2.decode input should be array of strings"); + return Uint8Array.from(convertRadix2(digits, bits, 8, revPadding)); + } + }; + } + function unsafeWrapper(fn) { + if (typeof fn !== "function") + throw new Error("unsafeWrapper fn should be function"); + return function(...args) { + try { + return fn.apply(null, args); + } catch (e) { + } + }; + } + function checksum(len, fn) { + assertNumber(len); + if (typeof fn !== "function") + throw new Error("checksum fn should be function"); + return { + encode(data) { + if (!(data instanceof Uint8Array)) + throw new Error("checksum.encode: input should be Uint8Array"); + const checksum2 = fn(data).slice(0, len); + const res = new Uint8Array(data.length + len); + res.set(data); + res.set(checksum2, data.length); + return res; + }, + decode(data) { + if (!(data instanceof Uint8Array)) + throw new Error("checksum.decode: input should be Uint8Array"); + const payload = data.slice(0, -len); + const newChecksum = fn(payload).slice(0, len); + const oldChecksum = data.slice(-len); + for (let i2 = 0; i2 < len; i2++) + if (newChecksum[i2] !== oldChecksum[i2]) + throw new Error("Invalid checksum"); + return payload; + } + }; + } + var utils = { alphabet, chain, checksum, radix, radix2, join, padding }; + var base16 = chain(radix2(4), alphabet("0123456789ABCDEF"), join("")); + var base32 = chain(radix2(5), alphabet("ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"), padding(5), join("")); + var base32hex = chain(radix2(5), alphabet("0123456789ABCDEFGHIJKLMNOPQRSTUV"), padding(5), join("")); + var base32crockford = chain(radix2(5), alphabet("0123456789ABCDEFGHJKMNPQRSTVWXYZ"), join(""), normalize((s) => s.toUpperCase().replace(/O/g, "0").replace(/[IL]/g, "1"))); + var base64 = chain(radix2(6), alphabet("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"), padding(6), join("")); + var base64url = chain(radix2(6), alphabet("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"), padding(6), join("")); + var genBase58 = (abc) => chain(radix(58), alphabet(abc), join("")); + var base58 = genBase58("123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"); + var base58flickr = genBase58("123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ"); + var base58xrp = genBase58("rpshnaf39wBUDNEGHJKLM4PQRST7VWXYZ2bcdeCg65jkm8oFqi1tuvAxyz"); + var XMR_BLOCK_LEN = [0, 2, 3, 5, 6, 7, 9, 10, 11]; + var base58xmr = { + encode(data) { + let res = ""; + for (let i2 = 0; i2 < data.length; i2 += 8) { + const block = data.subarray(i2, i2 + 8); + res += base58.encode(block).padStart(XMR_BLOCK_LEN[block.length], "1"); + } + return res; + }, + decode(str) { + let res = []; + for (let i2 = 0; i2 < str.length; i2 += 11) { + const slice = str.slice(i2, i2 + 11); + const blockLen = XMR_BLOCK_LEN.indexOf(slice.length); + const block = base58.decode(slice); + for (let j = 0; j < block.length - blockLen; j++) { + if (block[j] !== 0) + throw new Error("base58xmr: wrong padding"); + } + res = res.concat(Array.from(block.slice(block.length - blockLen))); + } + return Uint8Array.from(res); + } + }; + var base58check = (sha2563) => chain(checksum(4, (data) => sha2563(sha2563(data))), base58); + var BECH_ALPHABET = chain(alphabet("qpzry9x8gf2tvdw0s3jn54khce6mua7l"), join("")); + var POLYMOD_GENERATORS = [996825010, 642813549, 513874426, 1027748829, 705979059]; + function bech32Polymod(pre) { + const b = pre >> 25; + let chk = (pre & 33554431) << 5; + for (let i2 = 0; i2 < POLYMOD_GENERATORS.length; i2++) { + if ((b >> i2 & 1) === 1) + chk ^= POLYMOD_GENERATORS[i2]; + } + return chk; + } + function bechChecksum(prefix, words, encodingConst = 1) { + const len = prefix.length; + let chk = 1; + for (let i2 = 0; i2 < len; i2++) { + const c = prefix.charCodeAt(i2); + if (c < 33 || c > 126) + throw new Error(`Invalid prefix (${prefix})`); + chk = bech32Polymod(chk) ^ c >> 5; + } + chk = bech32Polymod(chk); + for (let i2 = 0; i2 < len; i2++) + chk = bech32Polymod(chk) ^ prefix.charCodeAt(i2) & 31; + for (let v of words) + chk = bech32Polymod(chk) ^ v; + for (let i2 = 0; i2 < 6; i2++) + chk = bech32Polymod(chk); + chk ^= encodingConst; + return BECH_ALPHABET.encode(convertRadix2([chk % 2 ** 30], 30, 5, false)); + } + function genBech32(encoding) { + const ENCODING_CONST = encoding === "bech32" ? 1 : 734539939; + const _words = radix2(5); + const fromWords = _words.decode; + const toWords = _words.encode; + const fromWordsUnsafe = unsafeWrapper(fromWords); + function encode(prefix, words, limit2 = 90) { + if (typeof prefix !== "string") + throw new Error(`bech32.encode prefix should be string, not ${typeof prefix}`); + if (!Array.isArray(words) || words.length && typeof words[0] !== "number") + throw new Error(`bech32.encode words should be array of numbers, not ${typeof words}`); + const actualLength = prefix.length + 7 + words.length; + if (limit2 !== false && actualLength > limit2) + throw new TypeError(`Length ${actualLength} exceeds limit ${limit2}`); + prefix = prefix.toLowerCase(); + return `${prefix}1${BECH_ALPHABET.encode(words)}${bechChecksum(prefix, words, ENCODING_CONST)}`; + } + function decode2(str, limit2 = 90) { + if (typeof str !== "string") + throw new Error(`bech32.decode input should be string, not ${typeof str}`); + if (str.length < 8 || limit2 !== false && str.length > limit2) + throw new TypeError(`Wrong string length: ${str.length} (${str}). Expected (8..${limit2})`); + const lowered = str.toLowerCase(); + if (str !== lowered && str !== str.toUpperCase()) + throw new Error(`String must be lowercase or uppercase`); + str = lowered; + const sepIndex = str.lastIndexOf("1"); + if (sepIndex === 0 || sepIndex === -1) + throw new Error(`Letter "1" must be present between prefix and data only`); + const prefix = str.slice(0, sepIndex); + const _words2 = str.slice(sepIndex + 1); + if (_words2.length < 6) + throw new Error("Data must be at least 6 characters long"); + const words = BECH_ALPHABET.decode(_words2).slice(0, -6); + const sum = bechChecksum(prefix, words, ENCODING_CONST); + if (!_words2.endsWith(sum)) + throw new Error(`Invalid checksum in ${str}: expected "${sum}"`); + return { prefix, words }; + } + const decodeUnsafe = unsafeWrapper(decode2); + function decodeToBytes(str) { + const { prefix, words } = decode2(str, false); + return { prefix, words, bytes: fromWords(words) }; + } + return { encode, decode: decode2, decodeToBytes, decodeUnsafe, fromWords, fromWordsUnsafe, toWords }; + } + var bech32 = genBech32("bech32"); + var bech32m = genBech32("bech32m"); + var utf8 = { + encode: (data) => new TextDecoder().decode(data), + decode: (str) => new TextEncoder().encode(str) + }; + var hex = chain(radix2(4), alphabet("0123456789abcdef"), join(""), normalize((s) => { + if (typeof s !== "string" || s.length % 2) + throw new TypeError(`hex.decode: expected string, got ${typeof s} with length ${s.length}`); + return s.toLowerCase(); + })); + var CODERS = { + utf8, + hex, + base16, + base32, + base64, + base64url, + base58, + base58xmr + }; + var coderTypeError = `Invalid encoding type. Available types: ${Object.keys(CODERS).join(", ")}`; + + // nip19.ts + var NostrTypeGuard = { + isNProfile: (value) => /^nprofile1[a-z\d]+$/.test(value || ""), + isNEvent: (value) => /^nevent1[a-z\d]+$/.test(value || ""), + isNAddr: (value) => /^naddr1[a-z\d]+$/.test(value || ""), + isNSec: (value) => /^nsec1[a-z\d]{58}$/.test(value || ""), + isNPub: (value) => /^npub1[a-z\d]{58}$/.test(value || ""), + isNote: (value) => /^note1[a-z\d]+$/.test(value || ""), + isNcryptsec: (value) => /^ncryptsec1[a-z\d]+$/.test(value || "") + }; + var Bech32MaxSize = 5e3; + var BECH32_REGEX = /[\x21-\x7E]{1,83}1[023456789acdefghjklmnpqrstuvwxyz]{6,}/; + function integerToUint8Array(number4) { + const uint8Array = new Uint8Array(4); + uint8Array[0] = number4 >> 24 & 255; + uint8Array[1] = number4 >> 16 & 255; + uint8Array[2] = number4 >> 8 & 255; + uint8Array[3] = number4 & 255; + return uint8Array; + } + function decodeNostrURI(nip19code) { + try { + if (nip19code.startsWith("nostr:")) + nip19code = nip19code.substring(6); + return decode(nip19code); + } catch (_err) { + return { type: "invalid", data: null }; + } + } + function decode(code) { + let { prefix, words } = bech32.decode(code, Bech32MaxSize); + let data = new Uint8Array(bech32.fromWords(words)); + switch (prefix) { + case "nprofile": { + let tlv = parseTLV(data); + if (!tlv[0]?.[0]) + throw new Error("missing TLV 0 for nprofile"); + if (tlv[0][0].length !== 32) + throw new Error("TLV 0 should be 32 bytes"); + return { + type: "nprofile", + data: { + pubkey: bytesToHex2(tlv[0][0]), + relays: tlv[1] ? tlv[1].map((d) => utf8Decoder.decode(d)) : [] + } + }; + } + case "nevent": { + let tlv = parseTLV(data); + if (!tlv[0]?.[0]) + throw new Error("missing TLV 0 for nevent"); + if (tlv[0][0].length !== 32) + throw new Error("TLV 0 should be 32 bytes"); + if (tlv[2] && tlv[2][0].length !== 32) + throw new Error("TLV 2 should be 32 bytes"); + if (tlv[3] && tlv[3][0].length !== 4) + throw new Error("TLV 3 should be 4 bytes"); + return { + type: "nevent", + data: { + id: bytesToHex2(tlv[0][0]), + relays: tlv[1] ? tlv[1].map((d) => utf8Decoder.decode(d)) : [], + author: tlv[2]?.[0] ? bytesToHex2(tlv[2][0]) : void 0, + kind: tlv[3]?.[0] ? parseInt(bytesToHex2(tlv[3][0]), 16) : void 0 + } + }; + } + case "naddr": { + let tlv = parseTLV(data); + if (!tlv[0]?.[0]) + throw new Error("missing TLV 0 for naddr"); + if (!tlv[2]?.[0]) + throw new Error("missing TLV 2 for naddr"); + if (tlv[2][0].length !== 32) + throw new Error("TLV 2 should be 32 bytes"); + if (!tlv[3]?.[0]) + throw new Error("missing TLV 3 for naddr"); + if (tlv[3][0].length !== 4) + throw new Error("TLV 3 should be 4 bytes"); + return { + type: "naddr", + data: { + identifier: utf8Decoder.decode(tlv[0][0]), + pubkey: bytesToHex2(tlv[2][0]), + kind: parseInt(bytesToHex2(tlv[3][0]), 16), + relays: tlv[1] ? tlv[1].map((d) => utf8Decoder.decode(d)) : [] + } + }; + } + case "nsec": + return { type: prefix, data }; + case "npub": + case "note": + return { type: prefix, data: bytesToHex2(data) }; + default: + throw new Error(`unknown prefix ${prefix}`); + } + } + function parseTLV(data) { + let result = {}; + let rest = data; + while (rest.length > 0) { + let t = rest[0]; + let l = rest[1]; + let v = rest.slice(2, 2 + l); + rest = rest.slice(2 + l); + if (v.length < l) + throw new Error(`not enough data to read on TLV ${t}`); + result[t] = result[t] || []; + result[t].push(v); + } + return result; + } + function nsecEncode(key) { + return encodeBytes("nsec", key); + } + function npubEncode(hex2) { + return encodeBytes("npub", hexToBytes2(hex2)); + } + function noteEncode(hex2) { + return encodeBytes("note", hexToBytes2(hex2)); + } + function encodeBech32(prefix, data) { + let words = bech32.toWords(data); + return bech32.encode(prefix, words, Bech32MaxSize); + } + function encodeBytes(prefix, bytes4) { + return encodeBech32(prefix, bytes4); + } + function nprofileEncode(profile) { + let data = encodeTLV({ + 0: [hexToBytes2(profile.pubkey)], + 1: (profile.relays || []).map((url) => utf8Encoder.encode(url)) + }); + return encodeBech32("nprofile", data); + } + function neventEncode(event) { + let kindArray; + if (event.kind !== void 0) { + kindArray = integerToUint8Array(event.kind); + } + let data = encodeTLV({ + 0: [hexToBytes2(event.id)], + 1: (event.relays || []).map((url) => utf8Encoder.encode(url)), + 2: event.author ? [hexToBytes2(event.author)] : [], + 3: kindArray ? [new Uint8Array(kindArray)] : [] + }); + return encodeBech32("nevent", data); + } + function naddrEncode(addr) { + let kind = new ArrayBuffer(4); + new DataView(kind).setUint32(0, addr.kind, false); + let data = encodeTLV({ + 0: [utf8Encoder.encode(addr.identifier)], + 1: (addr.relays || []).map((url) => utf8Encoder.encode(url)), + 2: [hexToBytes2(addr.pubkey)], + 3: [new Uint8Array(kind)] + }); + return encodeBech32("naddr", data); + } + function encodeTLV(tlv) { + let entries = []; + Object.entries(tlv).reverse().forEach(([t, vs]) => { + vs.forEach((v) => { + let entry = new Uint8Array(v.length + 2); + entry.set([parseInt(t)], 0); + entry.set([v.length], 1); + entry.set(v, 2); + entries.push(entry); + }); + }); + return concatBytes3(...entries); + } + + // references.ts + var mentionRegex = /\bnostr:((note|npub|naddr|nevent|nprofile)1\w+)\b|#\[(\d+)\]/g; + function parseReferences(evt) { + let references = []; + for (let ref of evt.content.matchAll(mentionRegex)) { + if (ref[2]) { + try { + let { type, data } = decode(ref[1]); + switch (type) { + case "npub": { + references.push({ + text: ref[0], + profile: { pubkey: data, relays: [] } + }); + break; + } + case "nprofile": { + references.push({ + text: ref[0], + profile: data + }); + break; + } + case "note": { + references.push({ + text: ref[0], + event: { id: data, relays: [] } + }); + break; + } + case "nevent": { + references.push({ + text: ref[0], + event: data + }); + break; + } + case "naddr": { + references.push({ + text: ref[0], + address: data + }); + break; + } + } + } catch (err) { + } + } else if (ref[3]) { + let idx = parseInt(ref[3], 10); + let tag = evt.tags[idx]; + if (!tag) + continue; + switch (tag[0]) { + case "p": { + references.push({ + text: ref[0], + profile: { pubkey: tag[1], relays: tag[2] ? [tag[2]] : [] } + }); + break; + } + case "e": { + references.push({ + text: ref[0], + event: { id: tag[1], relays: tag[2] ? [tag[2]] : [] } + }); + break; + } + case "a": { + try { + let [kind, pubkey, identifier] = tag[1].split(":"); + references.push({ + text: ref[0], + address: { + identifier, + pubkey, + kind: parseInt(kind, 10), + relays: tag[2] ? [tag[2]] : [] + } + }); + } catch (err) { + } + break; + } + } + } + } + return references; + } + + // nip04.ts + var nip04_exports = {}; + __export(nip04_exports, { + decrypt: () => decrypt2, + encrypt: () => encrypt2 + }); + + // node_modules/@noble/ciphers/esm/_assert.js + function number3(n) { + if (!Number.isSafeInteger(n) || n < 0) + throw new Error(`positive integer expected, not ${n}`); + } + function bool2(b) { + if (typeof b !== "boolean") + throw new Error(`boolean expected, not ${b}`); + } + function isBytes(a) { + return a instanceof Uint8Array || a != null && typeof a === "object" && a.constructor.name === "Uint8Array"; + } + function bytes3(b, ...lengths) { + if (!isBytes(b)) + throw new Error("Uint8Array expected"); + if (lengths.length > 0 && !lengths.includes(b.length)) + throw new Error(`Uint8Array expected of length ${lengths}, not of length=${b.length}`); + } + function exists3(instance, checkFinished = true) { + if (instance.destroyed) + throw new Error("Hash instance has been destroyed"); + if (checkFinished && instance.finished) + throw new Error("Hash#digest() has already been called"); + } + function output3(out, instance) { + bytes3(out); + const min = instance.outputLen; + if (out.length < min) { + throw new Error(`digestInto() expects output buffer of length at least ${min}`); + } + } + + // node_modules/@noble/ciphers/esm/utils.js + var u8 = (arr) => new Uint8Array(arr.buffer, arr.byteOffset, arr.byteLength); + var u32 = (arr) => new Uint32Array(arr.buffer, arr.byteOffset, Math.floor(arr.byteLength / 4)); + var createView3 = (arr) => new DataView(arr.buffer, arr.byteOffset, arr.byteLength); + var isLE3 = new Uint8Array(new Uint32Array([287454020]).buffer)[0] === 68; + if (!isLE3) + throw new Error("Non little-endian hardware is not supported"); + function utf8ToBytes4(str) { + if (typeof str !== "string") + throw new Error(`string expected, got ${typeof str}`); + return new Uint8Array(new TextEncoder().encode(str)); + } + function toBytes3(data) { + if (typeof data === "string") + data = utf8ToBytes4(data); + else if (isBytes(data)) + data = data.slice(); + else + throw new Error(`Uint8Array expected, got ${typeof data}`); + return data; + } + function checkOpts2(defaults, opts) { + if (opts == null || typeof opts !== "object") + throw new Error("options must be defined"); + const merged = Object.assign(defaults, opts); + return merged; + } + function equalBytes2(a, b) { + if (a.length !== b.length) + return false; + let diff = 0; + for (let i2 = 0; i2 < a.length; i2++) + diff |= a[i2] ^ b[i2]; + return diff === 0; + } + var wrapCipher = (params, c) => { + Object.assign(c, params); + return c; + }; + function setBigUint643(view, byteOffset, value, isLE4) { + if (typeof view.setBigUint64 === "function") + return view.setBigUint64(byteOffset, value, isLE4); + const _32n2 = BigInt(32); + const _u32_max = BigInt(4294967295); + const wh = Number(value >> _32n2 & _u32_max); + const wl = Number(value & _u32_max); + const h = isLE4 ? 4 : 0; + const l = isLE4 ? 0 : 4; + view.setUint32(byteOffset + h, wh, isLE4); + view.setUint32(byteOffset + l, wl, isLE4); + } + + // node_modules/@noble/ciphers/esm/_polyval.js + var BLOCK_SIZE = 16; + var ZEROS16 = /* @__PURE__ */ new Uint8Array(16); + var ZEROS32 = u32(ZEROS16); + var POLY = 225; + var mul2 = (s0, s1, s2, s3) => { + const hiBit = s3 & 1; + return { + s3: s2 << 31 | s3 >>> 1, + s2: s1 << 31 | s2 >>> 1, + s1: s0 << 31 | s1 >>> 1, + s0: s0 >>> 1 ^ POLY << 24 & -(hiBit & 1) + }; + }; + var swapLE = (n) => (n >>> 0 & 255) << 24 | (n >>> 8 & 255) << 16 | (n >>> 16 & 255) << 8 | n >>> 24 & 255 | 0; + function _toGHASHKey(k) { + k.reverse(); + const hiBit = k[15] & 1; + let carry = 0; + for (let i2 = 0; i2 < k.length; i2++) { + const t = k[i2]; + k[i2] = t >>> 1 | carry; + carry = (t & 1) << 7; + } + k[0] ^= -hiBit & 225; + return k; + } + var estimateWindow = (bytes4) => { + if (bytes4 > 64 * 1024) + return 8; + if (bytes4 > 1024) + return 4; + return 2; + }; + var GHASH = class { + constructor(key, expectedLength) { + this.blockLen = BLOCK_SIZE; + this.outputLen = BLOCK_SIZE; + this.s0 = 0; + this.s1 = 0; + this.s2 = 0; + this.s3 = 0; + this.finished = false; + key = toBytes3(key); + bytes3(key, 16); + const kView = createView3(key); + let k0 = kView.getUint32(0, false); + let k1 = kView.getUint32(4, false); + let k2 = kView.getUint32(8, false); + let k3 = kView.getUint32(12, false); + const doubles = []; + for (let i2 = 0; i2 < 128; i2++) { + doubles.push({ s0: swapLE(k0), s1: swapLE(k1), s2: swapLE(k2), s3: swapLE(k3) }); + ({ s0: k0, s1: k1, s2: k2, s3: k3 } = mul2(k0, k1, k2, k3)); + } + const W = estimateWindow(expectedLength || 1024); + if (![1, 2, 4, 8].includes(W)) + throw new Error(`ghash: wrong window size=${W}, should be 2, 4 or 8`); + this.W = W; + const bits = 128; + const windows = bits / W; + const windowSize = this.windowSize = 2 ** W; + const items = []; + for (let w = 0; w < windows; w++) { + for (let byte = 0; byte < windowSize; byte++) { + let s0 = 0, s1 = 0, s2 = 0, s3 = 0; + for (let j = 0; j < W; j++) { + const bit = byte >>> W - j - 1 & 1; + if (!bit) + continue; + const { s0: d0, s1: d1, s2: d2, s3: d3 } = doubles[W * w + j]; + s0 ^= d0, s1 ^= d1, s2 ^= d2, s3 ^= d3; + } + items.push({ s0, s1, s2, s3 }); + } + } + this.t = items; + } + _updateBlock(s0, s1, s2, s3) { + s0 ^= this.s0, s1 ^= this.s1, s2 ^= this.s2, s3 ^= this.s3; + const { W, t, windowSize } = this; + let o0 = 0, o1 = 0, o2 = 0, o3 = 0; + const mask = (1 << W) - 1; + let w = 0; + for (const num of [s0, s1, s2, s3]) { + for (let bytePos = 0; bytePos < 4; bytePos++) { + const byte = num >>> 8 * bytePos & 255; + for (let bitPos = 8 / W - 1; bitPos >= 0; bitPos--) { + const bit = byte >>> W * bitPos & mask; + const { s0: e0, s1: e1, s2: e2, s3: e3 } = t[w * windowSize + bit]; + o0 ^= e0, o1 ^= e1, o2 ^= e2, o3 ^= e3; + w += 1; + } + } + } + this.s0 = o0; + this.s1 = o1; + this.s2 = o2; + this.s3 = o3; + } + update(data) { + data = toBytes3(data); + exists3(this); + const b32 = u32(data); + const blocks = Math.floor(data.length / BLOCK_SIZE); + const left = data.length % BLOCK_SIZE; + for (let i2 = 0; i2 < blocks; i2++) { + this._updateBlock(b32[i2 * 4 + 0], b32[i2 * 4 + 1], b32[i2 * 4 + 2], b32[i2 * 4 + 3]); + } + if (left) { + ZEROS16.set(data.subarray(blocks * BLOCK_SIZE)); + this._updateBlock(ZEROS32[0], ZEROS32[1], ZEROS32[2], ZEROS32[3]); + ZEROS32.fill(0); + } + return this; + } + destroy() { + const { t } = this; + for (const elm of t) { + elm.s0 = 0, elm.s1 = 0, elm.s2 = 0, elm.s3 = 0; + } + } + digestInto(out) { + exists3(this); + output3(out, this); + this.finished = true; + const { s0, s1, s2, s3 } = this; + const o32 = u32(out); + o32[0] = s0; + o32[1] = s1; + o32[2] = s2; + o32[3] = s3; + return out; + } + digest() { + const res = new Uint8Array(BLOCK_SIZE); + this.digestInto(res); + this.destroy(); + return res; + } + }; + var Polyval = class extends GHASH { + constructor(key, expectedLength) { + key = toBytes3(key); + const ghKey = _toGHASHKey(key.slice()); + super(ghKey, expectedLength); + ghKey.fill(0); + } + update(data) { + data = toBytes3(data); + exists3(this); + const b32 = u32(data); + const left = data.length % BLOCK_SIZE; + const blocks = Math.floor(data.length / BLOCK_SIZE); + for (let i2 = 0; i2 < blocks; i2++) { + this._updateBlock(swapLE(b32[i2 * 4 + 3]), swapLE(b32[i2 * 4 + 2]), swapLE(b32[i2 * 4 + 1]), swapLE(b32[i2 * 4 + 0])); + } + if (left) { + ZEROS16.set(data.subarray(blocks * BLOCK_SIZE)); + this._updateBlock(swapLE(ZEROS32[3]), swapLE(ZEROS32[2]), swapLE(ZEROS32[1]), swapLE(ZEROS32[0])); + ZEROS32.fill(0); + } + return this; + } + digestInto(out) { + exists3(this); + output3(out, this); + this.finished = true; + const { s0, s1, s2, s3 } = this; + const o32 = u32(out); + o32[0] = s0; + o32[1] = s1; + o32[2] = s2; + o32[3] = s3; + return out.reverse(); + } + }; + function wrapConstructorWithKey(hashCons) { + const hashC = (msg, key) => hashCons(key, msg.length).update(toBytes3(msg)).digest(); + const tmp = hashCons(new Uint8Array(16), 0); + hashC.outputLen = tmp.outputLen; + hashC.blockLen = tmp.blockLen; + hashC.create = (key, expectedLength) => hashCons(key, expectedLength); + return hashC; + } + var ghash = wrapConstructorWithKey((key, expectedLength) => new GHASH(key, expectedLength)); + var polyval = wrapConstructorWithKey((key, expectedLength) => new Polyval(key, expectedLength)); + + // node_modules/@noble/ciphers/esm/aes.js + var BLOCK_SIZE2 = 16; + var BLOCK_SIZE32 = 4; + var EMPTY_BLOCK = new Uint8Array(BLOCK_SIZE2); + var POLY2 = 283; + function mul22(n) { + return n << 1 ^ POLY2 & -(n >> 7); + } + function mul(a, b) { + let res = 0; + for (; b > 0; b >>= 1) { + res ^= a & -(b & 1); + a = mul22(a); + } + return res; + } + var sbox = /* @__PURE__ */ (() => { + let t = new Uint8Array(256); + for (let i2 = 0, x = 1; i2 < 256; i2++, x ^= mul22(x)) + t[i2] = x; + const box = new Uint8Array(256); + box[0] = 99; + for (let i2 = 0; i2 < 255; i2++) { + let x = t[255 - i2]; + x |= x << 8; + box[t[i2]] = (x ^ x >> 4 ^ x >> 5 ^ x >> 6 ^ x >> 7 ^ 99) & 255; + } + return box; + })(); + var invSbox = /* @__PURE__ */ sbox.map((_, j) => sbox.indexOf(j)); + var rotr32_8 = (n) => n << 24 | n >>> 8; + var rotl32_8 = (n) => n << 8 | n >>> 24; + function genTtable(sbox2, fn) { + if (sbox2.length !== 256) + throw new Error("Wrong sbox length"); + const T0 = new Uint32Array(256).map((_, j) => fn(sbox2[j])); + const T1 = T0.map(rotl32_8); + const T2 = T1.map(rotl32_8); + const T3 = T2.map(rotl32_8); + const T01 = new Uint32Array(256 * 256); + const T23 = new Uint32Array(256 * 256); + const sbox22 = new Uint16Array(256 * 256); + for (let i2 = 0; i2 < 256; i2++) { + for (let j = 0; j < 256; j++) { + const idx = i2 * 256 + j; + T01[idx] = T0[i2] ^ T1[j]; + T23[idx] = T2[i2] ^ T3[j]; + sbox22[idx] = sbox2[i2] << 8 | sbox2[j]; + } + } + return { sbox: sbox2, sbox2: sbox22, T0, T1, T2, T3, T01, T23 }; + } + var tableEncoding = /* @__PURE__ */ genTtable(sbox, (s) => mul(s, 3) << 24 | s << 16 | s << 8 | mul(s, 2)); + var tableDecoding = /* @__PURE__ */ genTtable(invSbox, (s) => mul(s, 11) << 24 | mul(s, 13) << 16 | mul(s, 9) << 8 | mul(s, 14)); + var xPowers = /* @__PURE__ */ (() => { + const p = new Uint8Array(16); + for (let i2 = 0, x = 1; i2 < 16; i2++, x = mul22(x)) + p[i2] = x; + return p; + })(); + function expandKeyLE(key) { + bytes3(key); + const len = key.length; + if (![16, 24, 32].includes(len)) + throw new Error(`aes: wrong key size: should be 16, 24 or 32, got: ${len}`); + const { sbox2 } = tableEncoding; + const k32 = u32(key); + const Nk = k32.length; + const subByte = (n) => applySbox(sbox2, n, n, n, n); + const xk = new Uint32Array(len + 28); + xk.set(k32); + for (let i2 = Nk; i2 < xk.length; i2++) { + let t = xk[i2 - 1]; + if (i2 % Nk === 0) + t = subByte(rotr32_8(t)) ^ xPowers[i2 / Nk - 1]; + else if (Nk > 6 && i2 % Nk === 4) + t = subByte(t); + xk[i2] = xk[i2 - Nk] ^ t; + } + return xk; + } + function expandKeyDecLE(key) { + const encKey = expandKeyLE(key); + const xk = encKey.slice(); + const Nk = encKey.length; + const { sbox2 } = tableEncoding; + const { T0, T1, T2, T3 } = tableDecoding; + for (let i2 = 0; i2 < Nk; i2 += 4) { + for (let j = 0; j < 4; j++) + xk[i2 + j] = encKey[Nk - i2 - 4 + j]; + } + encKey.fill(0); + for (let i2 = 4; i2 < Nk - 4; i2++) { + const x = xk[i2]; + const w = applySbox(sbox2, x, x, x, x); + xk[i2] = T0[w & 255] ^ T1[w >>> 8 & 255] ^ T2[w >>> 16 & 255] ^ T3[w >>> 24]; + } + return xk; + } + function apply0123(T01, T23, s0, s1, s2, s3) { + return T01[s0 << 8 & 65280 | s1 >>> 8 & 255] ^ T23[s2 >>> 8 & 65280 | s3 >>> 24 & 255]; + } + function applySbox(sbox2, s0, s1, s2, s3) { + return sbox2[s0 & 255 | s1 & 65280] | sbox2[s2 >>> 16 & 255 | s3 >>> 16 & 65280] << 16; + } + function encrypt(xk, s0, s1, s2, s3) { + const { sbox2, T01, T23 } = tableEncoding; + let k = 0; + s0 ^= xk[k++], s1 ^= xk[k++], s2 ^= xk[k++], s3 ^= xk[k++]; + const rounds = xk.length / 4 - 2; + for (let i2 = 0; i2 < rounds; i2++) { + const t02 = xk[k++] ^ apply0123(T01, T23, s0, s1, s2, s3); + const t12 = xk[k++] ^ apply0123(T01, T23, s1, s2, s3, s0); + const t22 = xk[k++] ^ apply0123(T01, T23, s2, s3, s0, s1); + const t32 = xk[k++] ^ apply0123(T01, T23, s3, s0, s1, s2); + s0 = t02, s1 = t12, s2 = t22, s3 = t32; + } + const t0 = xk[k++] ^ applySbox(sbox2, s0, s1, s2, s3); + const t1 = xk[k++] ^ applySbox(sbox2, s1, s2, s3, s0); + const t2 = xk[k++] ^ applySbox(sbox2, s2, s3, s0, s1); + const t3 = xk[k++] ^ applySbox(sbox2, s3, s0, s1, s2); + return { s0: t0, s1: t1, s2: t2, s3: t3 }; + } + function decrypt(xk, s0, s1, s2, s3) { + const { sbox2, T01, T23 } = tableDecoding; + let k = 0; + s0 ^= xk[k++], s1 ^= xk[k++], s2 ^= xk[k++], s3 ^= xk[k++]; + const rounds = xk.length / 4 - 2; + for (let i2 = 0; i2 < rounds; i2++) { + const t02 = xk[k++] ^ apply0123(T01, T23, s0, s3, s2, s1); + const t12 = xk[k++] ^ apply0123(T01, T23, s1, s0, s3, s2); + const t22 = xk[k++] ^ apply0123(T01, T23, s2, s1, s0, s3); + const t32 = xk[k++] ^ apply0123(T01, T23, s3, s2, s1, s0); + s0 = t02, s1 = t12, s2 = t22, s3 = t32; + } + const t0 = xk[k++] ^ applySbox(sbox2, s0, s3, s2, s1); + const t1 = xk[k++] ^ applySbox(sbox2, s1, s0, s3, s2); + const t2 = xk[k++] ^ applySbox(sbox2, s2, s1, s0, s3); + const t3 = xk[k++] ^ applySbox(sbox2, s3, s2, s1, s0); + return { s0: t0, s1: t1, s2: t2, s3: t3 }; + } + function getDst(len, dst) { + if (!dst) + return new Uint8Array(len); + bytes3(dst); + if (dst.length < len) + throw new Error(`aes: wrong destination length, expected at least ${len}, got: ${dst.length}`); + return dst; + } + function ctrCounter(xk, nonce, src, dst) { + bytes3(nonce, BLOCK_SIZE2); + bytes3(src); + const srcLen = src.length; + dst = getDst(srcLen, dst); + const ctr3 = nonce; + const c32 = u32(ctr3); + let { s0, s1, s2, s3 } = encrypt(xk, c32[0], c32[1], c32[2], c32[3]); + const src32 = u32(src); + const dst32 = u32(dst); + for (let i2 = 0; i2 + 4 <= src32.length; i2 += 4) { + dst32[i2 + 0] = src32[i2 + 0] ^ s0; + dst32[i2 + 1] = src32[i2 + 1] ^ s1; + dst32[i2 + 2] = src32[i2 + 2] ^ s2; + dst32[i2 + 3] = src32[i2 + 3] ^ s3; + let carry = 1; + for (let i3 = ctr3.length - 1; i3 >= 0; i3--) { + carry = carry + (ctr3[i3] & 255) | 0; + ctr3[i3] = carry & 255; + carry >>>= 8; + } + ({ s0, s1, s2, s3 } = encrypt(xk, c32[0], c32[1], c32[2], c32[3])); + } + const start = BLOCK_SIZE2 * Math.floor(src32.length / BLOCK_SIZE32); + if (start < srcLen) { + const b32 = new Uint32Array([s0, s1, s2, s3]); + const buf = u8(b32); + for (let i2 = start, pos = 0; i2 < srcLen; i2++, pos++) + dst[i2] = src[i2] ^ buf[pos]; + } + return dst; + } + function ctr32(xk, isLE4, nonce, src, dst) { + bytes3(nonce, BLOCK_SIZE2); + bytes3(src); + dst = getDst(src.length, dst); + const ctr3 = nonce; + const c32 = u32(ctr3); + const view = createView3(ctr3); + const src32 = u32(src); + const dst32 = u32(dst); + const ctrPos = isLE4 ? 0 : 12; + const srcLen = src.length; + let ctrNum = view.getUint32(ctrPos, isLE4); + let { s0, s1, s2, s3 } = encrypt(xk, c32[0], c32[1], c32[2], c32[3]); + for (let i2 = 0; i2 + 4 <= src32.length; i2 += 4) { + dst32[i2 + 0] = src32[i2 + 0] ^ s0; + dst32[i2 + 1] = src32[i2 + 1] ^ s1; + dst32[i2 + 2] = src32[i2 + 2] ^ s2; + dst32[i2 + 3] = src32[i2 + 3] ^ s3; + ctrNum = ctrNum + 1 >>> 0; + view.setUint32(ctrPos, ctrNum, isLE4); + ({ s0, s1, s2, s3 } = encrypt(xk, c32[0], c32[1], c32[2], c32[3])); + } + const start = BLOCK_SIZE2 * Math.floor(src32.length / BLOCK_SIZE32); + if (start < srcLen) { + const b32 = new Uint32Array([s0, s1, s2, s3]); + const buf = u8(b32); + for (let i2 = start, pos = 0; i2 < srcLen; i2++, pos++) + dst[i2] = src[i2] ^ buf[pos]; + } + return dst; + } + var ctr = wrapCipher({ blockSize: 16, nonceLength: 16 }, function ctr2(key, nonce) { + bytes3(key); + bytes3(nonce, BLOCK_SIZE2); + function processCtr(buf, dst) { + const xk = expandKeyLE(key); + const n = nonce.slice(); + const out = ctrCounter(xk, n, buf, dst); + xk.fill(0); + n.fill(0); + return out; + } + return { + encrypt: (plaintext, dst) => processCtr(plaintext, dst), + decrypt: (ciphertext, dst) => processCtr(ciphertext, dst) + }; + }); + function validateBlockDecrypt(data) { + bytes3(data); + if (data.length % BLOCK_SIZE2 !== 0) { + throw new Error(`aes/(cbc-ecb).decrypt ciphertext should consist of blocks with size ${BLOCK_SIZE2}`); + } + } + function validateBlockEncrypt(plaintext, pcks5, dst) { + let outLen = plaintext.length; + const remaining = outLen % BLOCK_SIZE2; + if (!pcks5 && remaining !== 0) + throw new Error("aec/(cbc-ecb): unpadded plaintext with disabled padding"); + const b = u32(plaintext); + if (pcks5) { + let left = BLOCK_SIZE2 - remaining; + if (!left) + left = BLOCK_SIZE2; + outLen = outLen + left; + } + const out = getDst(outLen, dst); + const o = u32(out); + return { b, o, out }; + } + function validatePCKS(data, pcks5) { + if (!pcks5) + return data; + const len = data.length; + if (!len) + throw new Error(`aes/pcks5: empty ciphertext not allowed`); + const lastByte = data[len - 1]; + if (lastByte <= 0 || lastByte > 16) + throw new Error(`aes/pcks5: wrong padding byte: ${lastByte}`); + const out = data.subarray(0, -lastByte); + for (let i2 = 0; i2 < lastByte; i2++) + if (data[len - i2 - 1] !== lastByte) + throw new Error(`aes/pcks5: wrong padding`); + return out; + } + function padPCKS(left) { + const tmp = new Uint8Array(16); + const tmp32 = u32(tmp); + tmp.set(left); + const paddingByte = BLOCK_SIZE2 - left.length; + for (let i2 = BLOCK_SIZE2 - paddingByte; i2 < BLOCK_SIZE2; i2++) + tmp[i2] = paddingByte; + return tmp32; + } + var ecb = wrapCipher({ blockSize: 16 }, function ecb2(key, opts = {}) { + bytes3(key); + const pcks5 = !opts.disablePadding; + return { + encrypt: (plaintext, dst) => { + bytes3(plaintext); + const { b, o, out: _out } = validateBlockEncrypt(plaintext, pcks5, dst); + const xk = expandKeyLE(key); + let i2 = 0; + for (; i2 + 4 <= b.length; ) { + const { s0, s1, s2, s3 } = encrypt(xk, b[i2 + 0], b[i2 + 1], b[i2 + 2], b[i2 + 3]); + o[i2++] = s0, o[i2++] = s1, o[i2++] = s2, o[i2++] = s3; + } + if (pcks5) { + const tmp32 = padPCKS(plaintext.subarray(i2 * 4)); + const { s0, s1, s2, s3 } = encrypt(xk, tmp32[0], tmp32[1], tmp32[2], tmp32[3]); + o[i2++] = s0, o[i2++] = s1, o[i2++] = s2, o[i2++] = s3; + } + xk.fill(0); + return _out; + }, + decrypt: (ciphertext, dst) => { + validateBlockDecrypt(ciphertext); + const xk = expandKeyDecLE(key); + const out = getDst(ciphertext.length, dst); + const b = u32(ciphertext); + const o = u32(out); + for (let i2 = 0; i2 + 4 <= b.length; ) { + const { s0, s1, s2, s3 } = decrypt(xk, b[i2 + 0], b[i2 + 1], b[i2 + 2], b[i2 + 3]); + o[i2++] = s0, o[i2++] = s1, o[i2++] = s2, o[i2++] = s3; + } + xk.fill(0); + return validatePCKS(out, pcks5); + } + }; + }); + var cbc = wrapCipher({ blockSize: 16, nonceLength: 16 }, function cbc2(key, iv, opts = {}) { + bytes3(key); + bytes3(iv, 16); + const pcks5 = !opts.disablePadding; + return { + encrypt: (plaintext, dst) => { + const xk = expandKeyLE(key); + const { b, o, out: _out } = validateBlockEncrypt(plaintext, pcks5, dst); + const n32 = u32(iv); + let s0 = n32[0], s1 = n32[1], s2 = n32[2], s3 = n32[3]; + let i2 = 0; + for (; i2 + 4 <= b.length; ) { + s0 ^= b[i2 + 0], s1 ^= b[i2 + 1], s2 ^= b[i2 + 2], s3 ^= b[i2 + 3]; + ({ s0, s1, s2, s3 } = encrypt(xk, s0, s1, s2, s3)); + o[i2++] = s0, o[i2++] = s1, o[i2++] = s2, o[i2++] = s3; + } + if (pcks5) { + const tmp32 = padPCKS(plaintext.subarray(i2 * 4)); + s0 ^= tmp32[0], s1 ^= tmp32[1], s2 ^= tmp32[2], s3 ^= tmp32[3]; + ({ s0, s1, s2, s3 } = encrypt(xk, s0, s1, s2, s3)); + o[i2++] = s0, o[i2++] = s1, o[i2++] = s2, o[i2++] = s3; + } + xk.fill(0); + return _out; + }, + decrypt: (ciphertext, dst) => { + validateBlockDecrypt(ciphertext); + const xk = expandKeyDecLE(key); + const n32 = u32(iv); + const out = getDst(ciphertext.length, dst); + const b = u32(ciphertext); + const o = u32(out); + let s0 = n32[0], s1 = n32[1], s2 = n32[2], s3 = n32[3]; + for (let i2 = 0; i2 + 4 <= b.length; ) { + const ps0 = s0, ps1 = s1, ps2 = s2, ps3 = s3; + s0 = b[i2 + 0], s1 = b[i2 + 1], s2 = b[i2 + 2], s3 = b[i2 + 3]; + const { s0: o0, s1: o1, s2: o2, s3: o3 } = decrypt(xk, s0, s1, s2, s3); + o[i2++] = o0 ^ ps0, o[i2++] = o1 ^ ps1, o[i2++] = o2 ^ ps2, o[i2++] = o3 ^ ps3; + } + xk.fill(0); + return validatePCKS(out, pcks5); + } + }; + }); + var cfb = wrapCipher({ blockSize: 16, nonceLength: 16 }, function cfb2(key, iv) { + bytes3(key); + bytes3(iv, 16); + function processCfb(src, isEncrypt, dst) { + const xk = expandKeyLE(key); + const srcLen = src.length; + dst = getDst(srcLen, dst); + const src32 = u32(src); + const dst32 = u32(dst); + const next32 = isEncrypt ? dst32 : src32; + const n32 = u32(iv); + let s0 = n32[0], s1 = n32[1], s2 = n32[2], s3 = n32[3]; + for (let i2 = 0; i2 + 4 <= src32.length; ) { + const { s0: e0, s1: e1, s2: e2, s3: e3 } = encrypt(xk, s0, s1, s2, s3); + dst32[i2 + 0] = src32[i2 + 0] ^ e0; + dst32[i2 + 1] = src32[i2 + 1] ^ e1; + dst32[i2 + 2] = src32[i2 + 2] ^ e2; + dst32[i2 + 3] = src32[i2 + 3] ^ e3; + s0 = next32[i2++], s1 = next32[i2++], s2 = next32[i2++], s3 = next32[i2++]; + } + const start = BLOCK_SIZE2 * Math.floor(src32.length / BLOCK_SIZE32); + if (start < srcLen) { + ({ s0, s1, s2, s3 } = encrypt(xk, s0, s1, s2, s3)); + const buf = u8(new Uint32Array([s0, s1, s2, s3])); + for (let i2 = start, pos = 0; i2 < srcLen; i2++, pos++) + dst[i2] = src[i2] ^ buf[pos]; + buf.fill(0); + } + xk.fill(0); + return dst; + } + return { + encrypt: (plaintext, dst) => processCfb(plaintext, true, dst), + decrypt: (ciphertext, dst) => processCfb(ciphertext, false, dst) + }; + }); + function computeTag(fn, isLE4, key, data, AAD) { + const h = fn.create(key, data.length + (AAD?.length || 0)); + if (AAD) + h.update(AAD); + h.update(data); + const num = new Uint8Array(16); + const view = createView3(num); + if (AAD) + setBigUint643(view, 0, BigInt(AAD.length * 8), isLE4); + setBigUint643(view, 8, BigInt(data.length * 8), isLE4); + h.update(num); + return h.digest(); + } + var gcm = wrapCipher({ blockSize: 16, nonceLength: 12, tagLength: 16 }, function gcm2(key, nonce, AAD) { + bytes3(nonce); + if (nonce.length === 0) + throw new Error("aes/gcm: empty nonce"); + const tagLength = 16; + function _computeTag(authKey, tagMask, data) { + const tag = computeTag(ghash, false, authKey, data, AAD); + for (let i2 = 0; i2 < tagMask.length; i2++) + tag[i2] ^= tagMask[i2]; + return tag; + } + function deriveKeys() { + const xk = expandKeyLE(key); + const authKey = EMPTY_BLOCK.slice(); + const counter = EMPTY_BLOCK.slice(); + ctr32(xk, false, counter, counter, authKey); + if (nonce.length === 12) { + counter.set(nonce); + } else { + const nonceLen = EMPTY_BLOCK.slice(); + const view = createView3(nonceLen); + setBigUint643(view, 8, BigInt(nonce.length * 8), false); + ghash.create(authKey).update(nonce).update(nonceLen).digestInto(counter); + } + const tagMask = ctr32(xk, false, counter, EMPTY_BLOCK); + return { xk, authKey, counter, tagMask }; + } + return { + encrypt: (plaintext) => { + bytes3(plaintext); + const { xk, authKey, counter, tagMask } = deriveKeys(); + const out = new Uint8Array(plaintext.length + tagLength); + ctr32(xk, false, counter, plaintext, out); + const tag = _computeTag(authKey, tagMask, out.subarray(0, out.length - tagLength)); + out.set(tag, plaintext.length); + xk.fill(0); + return out; + }, + decrypt: (ciphertext) => { + bytes3(ciphertext); + if (ciphertext.length < tagLength) + throw new Error(`aes/gcm: ciphertext less than tagLen (${tagLength})`); + const { xk, authKey, counter, tagMask } = deriveKeys(); + const data = ciphertext.subarray(0, -tagLength); + const passedTag = ciphertext.subarray(-tagLength); + const tag = _computeTag(authKey, tagMask, data); + if (!equalBytes2(tag, passedTag)) + throw new Error("aes/gcm: invalid ghash tag"); + const out = ctr32(xk, false, counter, data); + authKey.fill(0); + tagMask.fill(0); + xk.fill(0); + return out; + } + }; + }); + var limit = (name, min, max) => (value) => { + if (!Number.isSafeInteger(value) || min > value || value > max) + throw new Error(`${name}: invalid value=${value}, must be [${min}..${max}]`); + }; + var siv = wrapCipher({ blockSize: 16, nonceLength: 12, tagLength: 16 }, function siv2(key, nonce, AAD) { + const tagLength = 16; + const AAD_LIMIT = limit("AAD", 0, 2 ** 36); + const PLAIN_LIMIT = limit("plaintext", 0, 2 ** 36); + const NONCE_LIMIT = limit("nonce", 12, 12); + const CIPHER_LIMIT = limit("ciphertext", 16, 2 ** 36 + 16); + bytes3(nonce); + NONCE_LIMIT(nonce.length); + if (AAD) { + bytes3(AAD); + AAD_LIMIT(AAD.length); + } + function deriveKeys() { + const len = key.length; + if (len !== 16 && len !== 24 && len !== 32) + throw new Error(`key length must be 16, 24 or 32 bytes, got: ${len} bytes`); + const xk = expandKeyLE(key); + const encKey = new Uint8Array(len); + const authKey = new Uint8Array(16); + const n32 = u32(nonce); + let s0 = 0, s1 = n32[0], s2 = n32[1], s3 = n32[2]; + let counter = 0; + for (const derivedKey of [authKey, encKey].map(u32)) { + const d32 = u32(derivedKey); + for (let i2 = 0; i2 < d32.length; i2 += 2) { + const { s0: o0, s1: o1 } = encrypt(xk, s0, s1, s2, s3); + d32[i2 + 0] = o0; + d32[i2 + 1] = o1; + s0 = ++counter; + } + } + xk.fill(0); + return { authKey, encKey: expandKeyLE(encKey) }; + } + function _computeTag(encKey, authKey, data) { + const tag = computeTag(polyval, true, authKey, data, AAD); + for (let i2 = 0; i2 < 12; i2++) + tag[i2] ^= nonce[i2]; + tag[15] &= 127; + const t32 = u32(tag); + let s0 = t32[0], s1 = t32[1], s2 = t32[2], s3 = t32[3]; + ({ s0, s1, s2, s3 } = encrypt(encKey, s0, s1, s2, s3)); + t32[0] = s0, t32[1] = s1, t32[2] = s2, t32[3] = s3; + return tag; + } + function processSiv(encKey, tag, input) { + let block = tag.slice(); + block[15] |= 128; + return ctr32(encKey, true, block, input); + } + return { + encrypt: (plaintext) => { + bytes3(plaintext); + PLAIN_LIMIT(plaintext.length); + const { encKey, authKey } = deriveKeys(); + const tag = _computeTag(encKey, authKey, plaintext); + const out = new Uint8Array(plaintext.length + tagLength); + out.set(tag, plaintext.length); + out.set(processSiv(encKey, tag, plaintext)); + encKey.fill(0); + authKey.fill(0); + return out; + }, + decrypt: (ciphertext) => { + bytes3(ciphertext); + CIPHER_LIMIT(ciphertext.length); + const tag = ciphertext.subarray(-tagLength); + const { encKey, authKey } = deriveKeys(); + const plaintext = processSiv(encKey, tag, ciphertext.subarray(0, -tagLength)); + const expectedTag = _computeTag(encKey, authKey, plaintext); + encKey.fill(0); + authKey.fill(0); + if (!equalBytes2(tag, expectedTag)) + throw new Error("invalid polyval tag"); + return plaintext; + } + }; + }); + + // nip04.ts + function encrypt2(secretKey, pubkey, text) { + const privkey = secretKey instanceof Uint8Array ? bytesToHex2(secretKey) : secretKey; + const key = secp256k1.getSharedSecret(privkey, "02" + pubkey); + const normalizedKey = getNormalizedX(key); + let iv = Uint8Array.from(randomBytes2(16)); + let plaintext = utf8Encoder.encode(text); + let ciphertext = cbc(normalizedKey, iv).encrypt(plaintext); + let ctb64 = base64.encode(new Uint8Array(ciphertext)); + let ivb64 = base64.encode(new Uint8Array(iv.buffer)); + return `${ctb64}?iv=${ivb64}`; + } + function decrypt2(secretKey, pubkey, data) { + const privkey = secretKey instanceof Uint8Array ? bytesToHex2(secretKey) : secretKey; + let [ctb64, ivb64] = data.split("?iv="); + let key = secp256k1.getSharedSecret(privkey, "02" + pubkey); + let normalizedKey = getNormalizedX(key); + let iv = base64.decode(ivb64); + let ciphertext = base64.decode(ctb64); + let plaintext = cbc(normalizedKey, iv).decrypt(ciphertext); + return utf8Decoder.decode(plaintext); + } + function getNormalizedX(key) { + return key.slice(1, 33); + } + + // nip05.ts + var nip05_exports = {}; + __export(nip05_exports, { + NIP05_REGEX: () => NIP05_REGEX, + isNip05: () => isNip05, + isValid: () => isValid, + queryProfile: () => queryProfile, + searchDomain: () => searchDomain, + useFetchImplementation: () => useFetchImplementation + }); + var NIP05_REGEX = /^(?:([\w.+-]+)@)?([\w_-]+(\.[\w_-]+)+)$/; + var isNip05 = (value) => NIP05_REGEX.test(value || ""); + var _fetch; + try { + _fetch = fetch; + } catch (_) { + null; + } + function useFetchImplementation(fetchImplementation) { + _fetch = fetchImplementation; + } + async function searchDomain(domain, query = "") { + try { + const url = `https://${domain}/.well-known/nostr.json?name=${query}`; + const res = await _fetch(url, { redirect: "manual" }); + if (res.status !== 200) { + throw Error("Wrong response code"); + } + const json = await res.json(); + return json.names; + } catch (_) { + return {}; + } + } + async function queryProfile(fullname) { + const match = fullname.match(NIP05_REGEX); + if (!match) + return null; + const [, name = "_", domain] = match; + try { + const url = `https://${domain}/.well-known/nostr.json?name=${name}`; + const res = await _fetch(url, { redirect: "manual" }); + if (res.status !== 200) { + throw Error("Wrong response code"); + } + const json = await res.json(); + const pubkey = json.names[name]; + return pubkey ? { pubkey, relays: json.relays?.[pubkey] } : null; + } catch (_e) { + return null; + } + } + async function isValid(pubkey, nip05) { + const res = await queryProfile(nip05); + return res ? res.pubkey === pubkey : false; + } + + // nip06.ts + var nip06_exports = {}; + __export(nip06_exports, { + accountFromExtendedKey: () => accountFromExtendedKey, + accountFromSeedWords: () => accountFromSeedWords, + extendedKeysFromSeedWords: () => extendedKeysFromSeedWords, + generateSeedWords: () => generateSeedWords, + privateKeyFromSeedWords: () => privateKeyFromSeedWords, + validateWords: () => validateWords + }); + + // node_modules/@scure/bip39/esm/wordlists/english.js + var wordlist = `abandon +ability +able +about +above +absent +absorb +abstract +absurd +abuse +access +accident +account +accuse +achieve +acid +acoustic +acquire +across +act +action +actor +actress +actual +adapt +add +addict +address +adjust +admit +adult +advance +advice +aerobic +affair +afford +afraid +again +age +agent +agree +ahead +aim +air +airport +aisle +alarm +album +alcohol +alert +alien +all +alley +allow +almost +alone +alpha +already +also +alter +always +amateur +amazing +among +amount +amused +analyst +anchor +ancient +anger +angle +angry +animal +ankle +announce +annual +another +answer +antenna +antique +anxiety +any +apart +apology +appear +apple +approve +april +arch +arctic +area +arena +argue +arm +armed +armor +army +around +arrange +arrest +arrive +arrow +art +artefact +artist +artwork +ask +aspect +assault +asset +assist +assume +asthma +athlete +atom +attack +attend +attitude +attract +auction +audit +august +aunt +author +auto +autumn +average +avocado +avoid +awake +aware +away +awesome +awful +awkward +axis +baby +bachelor +bacon +badge +bag +balance +balcony +ball +bamboo +banana +banner +bar +barely +bargain +barrel +base +basic +basket +battle +beach +bean +beauty +because +become +beef +before +begin +behave +behind +believe +below +belt +bench +benefit +best +betray +better +between +beyond +bicycle +bid +bike +bind +biology +bird +birth +bitter +black +blade +blame +blanket +blast +bleak +bless +blind +blood +blossom +blouse +blue +blur +blush +board +boat +body +boil +bomb +bone +bonus +book +boost +border +boring +borrow +boss +bottom +bounce +box +boy +bracket +brain +brand +brass +brave +bread +breeze +brick +bridge +brief +bright +bring +brisk +broccoli +broken +bronze +broom +brother +brown +brush +bubble +buddy +budget +buffalo +build +bulb +bulk +bullet +bundle +bunker +burden +burger +burst +bus +business +busy +butter +buyer +buzz +cabbage +cabin +cable +cactus +cage +cake +call +calm +camera +camp +can +canal +cancel +candy +cannon +canoe +canvas +canyon +capable +capital +captain +car +carbon +card +cargo +carpet +carry +cart +case +cash +casino +castle +casual +cat +catalog +catch +category +cattle +caught +cause +caution +cave +ceiling +celery +cement +census +century +cereal +certain +chair +chalk +champion +change +chaos +chapter +charge +chase +chat +cheap +check +cheese +chef +cherry +chest +chicken +chief +child +chimney +choice +choose +chronic +chuckle +chunk +churn +cigar +cinnamon +circle +citizen +city +civil +claim +clap +clarify +claw +clay +clean +clerk +clever +click +client +cliff +climb +clinic +clip +clock +clog +close +cloth +cloud +clown +club +clump +cluster +clutch +coach +coast +coconut +code +coffee +coil +coin +collect +color +column +combine +come +comfort +comic +common +company +concert +conduct +confirm +congress +connect +consider +control +convince +cook +cool +copper +copy +coral +core +corn +correct +cost +cotton +couch +country +couple +course +cousin +cover +coyote +crack +cradle +craft +cram +crane +crash +crater +crawl +crazy +cream +credit +creek +crew +cricket +crime +crisp +critic +crop +cross +crouch +crowd +crucial +cruel +cruise +crumble +crunch +crush +cry +crystal +cube +culture +cup +cupboard +curious +current +curtain +curve +cushion +custom +cute +cycle +dad +damage +damp +dance +danger +daring +dash +daughter +dawn +day +deal +debate +debris +decade +december +decide +decline +decorate +decrease +deer +defense +define +defy +degree +delay +deliver +demand +demise +denial +dentist +deny +depart +depend +deposit +depth +deputy +derive +describe +desert +design +desk +despair +destroy +detail +detect +develop +device +devote +diagram +dial +diamond +diary +dice +diesel +diet +differ +digital +dignity +dilemma +dinner +dinosaur +direct +dirt +disagree +discover +disease +dish +dismiss +disorder +display +distance +divert +divide +divorce +dizzy +doctor +document +dog +doll +dolphin +domain +donate +donkey +donor +door +dose +double +dove +draft +dragon +drama +drastic +draw +dream +dress +drift +drill +drink +drip +drive +drop +drum +dry +duck +dumb +dune +during +dust +dutch +duty +dwarf +dynamic +eager +eagle +early +earn +earth +easily +east +easy +echo +ecology +economy +edge +edit +educate +effort +egg +eight +either +elbow +elder +electric +elegant +element +elephant +elevator +elite +else +embark +embody +embrace +emerge +emotion +employ +empower +empty +enable +enact +end +endless +endorse +enemy +energy +enforce +engage +engine +enhance +enjoy +enlist +enough +enrich +enroll +ensure +enter +entire +entry +envelope +episode +equal +equip +era +erase +erode +erosion +error +erupt +escape +essay +essence +estate +eternal +ethics +evidence +evil +evoke +evolve +exact +example +excess +exchange +excite +exclude +excuse +execute +exercise +exhaust +exhibit +exile +exist +exit +exotic +expand +expect +expire +explain +expose +express +extend +extra +eye +eyebrow +fabric +face +faculty +fade +faint +faith +fall +false +fame +family +famous +fan +fancy +fantasy +farm +fashion +fat +fatal +father +fatigue +fault +favorite +feature +february +federal +fee +feed +feel +female +fence +festival +fetch +fever +few +fiber +fiction +field +figure +file +film +filter +final +find +fine +finger +finish +fire +firm +first +fiscal +fish +fit +fitness +fix +flag +flame +flash +flat +flavor +flee +flight +flip +float +flock +floor +flower +fluid +flush +fly +foam +focus +fog +foil +fold +follow +food +foot +force +forest +forget +fork +fortune +forum +forward +fossil +foster +found +fox +fragile +frame +frequent +fresh +friend +fringe +frog +front +frost +frown +frozen +fruit +fuel +fun +funny +furnace +fury +future +gadget +gain +galaxy +gallery +game +gap +garage +garbage +garden +garlic +garment +gas +gasp +gate +gather +gauge +gaze +general +genius +genre +gentle +genuine +gesture +ghost +giant +gift +giggle +ginger +giraffe +girl +give +glad +glance +glare +glass +glide +glimpse +globe +gloom +glory +glove +glow +glue +goat +goddess +gold +good +goose +gorilla +gospel +gossip +govern +gown +grab +grace +grain +grant +grape +grass +gravity +great +green +grid +grief +grit +grocery +group +grow +grunt +guard +guess +guide +guilt +guitar +gun +gym +habit +hair +half +hammer +hamster +hand +happy +harbor +hard +harsh +harvest +hat +have +hawk +hazard +head +health +heart +heavy +hedgehog +height +hello +helmet +help +hen +hero +hidden +high +hill +hint +hip +hire +history +hobby +hockey +hold +hole +holiday +hollow +home +honey +hood +hope +horn +horror +horse +hospital +host +hotel +hour +hover +hub +huge +human +humble +humor +hundred +hungry +hunt +hurdle +hurry +hurt +husband +hybrid +ice +icon +idea +identify +idle +ignore +ill +illegal +illness +image +imitate +immense +immune +impact +impose +improve +impulse +inch +include +income +increase +index +indicate +indoor +industry +infant +inflict +inform +inhale +inherit +initial +inject +injury +inmate +inner +innocent +input +inquiry +insane +insect +inside +inspire +install +intact +interest +into +invest +invite +involve +iron +island +isolate +issue +item +ivory +jacket +jaguar +jar +jazz +jealous +jeans +jelly +jewel +job +join +joke +journey +joy +judge +juice +jump +jungle +junior +junk +just +kangaroo +keen +keep +ketchup +key +kick +kid +kidney +kind +kingdom +kiss +kit +kitchen +kite +kitten +kiwi +knee +knife +knock +know +lab +label +labor +ladder +lady +lake +lamp +language +laptop +large +later +latin +laugh +laundry +lava +law +lawn +lawsuit +layer +lazy +leader +leaf +learn +leave +lecture +left +leg +legal +legend +leisure +lemon +lend +length +lens +leopard +lesson +letter +level +liar +liberty +library +license +life +lift +light +like +limb +limit +link +lion +liquid +list +little +live +lizard +load +loan +lobster +local +lock +logic +lonely +long +loop +lottery +loud +lounge +love +loyal +lucky +luggage +lumber +lunar +lunch +luxury +lyrics +machine +mad +magic +magnet +maid +mail +main +major +make +mammal +man +manage +mandate +mango +mansion +manual +maple +marble +march +margin +marine +market +marriage +mask +mass +master +match +material +math +matrix +matter +maximum +maze +meadow +mean +measure +meat +mechanic +medal +media +melody +melt +member +memory +mention +menu +mercy +merge +merit +merry +mesh +message +metal +method +middle +midnight +milk +million +mimic +mind +minimum +minor +minute +miracle +mirror +misery +miss +mistake +mix +mixed +mixture +mobile +model +modify +mom +moment +monitor +monkey +monster +month +moon +moral +more +morning +mosquito +mother +motion +motor +mountain +mouse +move +movie +much +muffin +mule +multiply +muscle +museum +mushroom +music +must +mutual +myself +mystery +myth +naive +name +napkin +narrow +nasty +nation +nature +near +neck +need +negative +neglect +neither +nephew +nerve +nest +net +network +neutral +never +news +next +nice +night +noble +noise +nominee +noodle +normal +north +nose +notable +note +nothing +notice +novel +now +nuclear +number +nurse +nut +oak +obey +object +oblige +obscure +observe +obtain +obvious +occur +ocean +october +odor +off +offer +office +often +oil +okay +old +olive +olympic +omit +once +one +onion +online +only +open +opera +opinion +oppose +option +orange +orbit +orchard +order +ordinary +organ +orient +original +orphan +ostrich +other +outdoor +outer +output +outside +oval +oven +over +own +owner +oxygen +oyster +ozone +pact +paddle +page +pair +palace +palm +panda +panel +panic +panther +paper +parade +parent +park +parrot +party +pass +patch +path +patient +patrol +pattern +pause +pave +payment +peace +peanut +pear +peasant +pelican +pen +penalty +pencil +people +pepper +perfect +permit +person +pet +phone +photo +phrase +physical +piano +picnic +picture +piece +pig +pigeon +pill +pilot +pink +pioneer +pipe +pistol +pitch +pizza +place +planet +plastic +plate +play +please +pledge +pluck +plug +plunge +poem +poet +point +polar +pole +police +pond +pony +pool +popular +portion +position +possible +post +potato +pottery +poverty +powder +power +practice +praise +predict +prefer +prepare +present +pretty +prevent +price +pride +primary +print +priority +prison +private +prize +problem +process +produce +profit +program +project +promote +proof +property +prosper +protect +proud +provide +public +pudding +pull +pulp +pulse +pumpkin +punch +pupil +puppy +purchase +purity +purpose +purse +push +put +puzzle +pyramid +quality +quantum +quarter +question +quick +quit +quiz +quote +rabbit +raccoon +race +rack +radar +radio +rail +rain +raise +rally +ramp +ranch +random +range +rapid +rare +rate +rather +raven +raw +razor +ready +real +reason +rebel +rebuild +recall +receive +recipe +record +recycle +reduce +reflect +reform +refuse +region +regret +regular +reject +relax +release +relief +rely +remain +remember +remind +remove +render +renew +rent +reopen +repair +repeat +replace +report +require +rescue +resemble +resist +resource +response +result +retire +retreat +return +reunion +reveal +review +reward +rhythm +rib +ribbon +rice +rich +ride +ridge +rifle +right +rigid +ring +riot +ripple +risk +ritual +rival +river +road +roast +robot +robust +rocket +romance +roof +rookie +room +rose +rotate +rough +round +route +royal +rubber +rude +rug +rule +run +runway +rural +sad +saddle +sadness +safe +sail +salad +salmon +salon +salt +salute +same +sample +sand +satisfy +satoshi +sauce +sausage +save +say +scale +scan +scare +scatter +scene +scheme +school +science +scissors +scorpion +scout +scrap +screen +script +scrub +sea +search +season +seat +second +secret +section +security +seed +seek +segment +select +sell +seminar +senior +sense +sentence +series +service +session +settle +setup +seven +shadow +shaft +shallow +share +shed +shell +sheriff +shield +shift +shine +ship +shiver +shock +shoe +shoot +shop +short +shoulder +shove +shrimp +shrug +shuffle +shy +sibling +sick +side +siege +sight +sign +silent +silk +silly +silver +similar +simple +since +sing +siren +sister +situate +six +size +skate +sketch +ski +skill +skin +skirt +skull +slab +slam +sleep +slender +slice +slide +slight +slim +slogan +slot +slow +slush +small +smart +smile +smoke +smooth +snack +snake +snap +sniff +snow +soap +soccer +social +sock +soda +soft +solar +soldier +solid +solution +solve +someone +song +soon +sorry +sort +soul +sound +soup +source +south +space +spare +spatial +spawn +speak +special +speed +spell +spend +sphere +spice +spider +spike +spin +spirit +split +spoil +sponsor +spoon +sport +spot +spray +spread +spring +spy +square +squeeze +squirrel +stable +stadium +staff +stage +stairs +stamp +stand +start +state +stay +steak +steel +stem +step +stereo +stick +still +sting +stock +stomach +stone +stool +story +stove +strategy +street +strike +strong +struggle +student +stuff +stumble +style +subject +submit +subway +success +such +sudden +suffer +sugar +suggest +suit +summer +sun +sunny +sunset +super +supply +supreme +sure +surface +surge +surprise +surround +survey +suspect +sustain +swallow +swamp +swap +swarm +swear +sweet +swift +swim +swing +switch +sword +symbol +symptom +syrup +system +table +tackle +tag +tail +talent +talk +tank +tape +target +task +taste +tattoo +taxi +teach +team +tell +ten +tenant +tennis +tent +term +test +text +thank +that +theme +then +theory +there +they +thing +this +thought +three +thrive +throw +thumb +thunder +ticket +tide +tiger +tilt +timber +time +tiny +tip +tired +tissue +title +toast +tobacco +today +toddler +toe +together +toilet +token +tomato +tomorrow +tone +tongue +tonight +tool +tooth +top +topic +topple +torch +tornado +tortoise +toss +total +tourist +toward +tower +town +toy +track +trade +traffic +tragic +train +transfer +trap +trash +travel +tray +treat +tree +trend +trial +tribe +trick +trigger +trim +trip +trophy +trouble +truck +true +truly +trumpet +trust +truth +try +tube +tuition +tumble +tuna +tunnel +turkey +turn +turtle +twelve +twenty +twice +twin +twist +two +type +typical +ugly +umbrella +unable +unaware +uncle +uncover +under +undo +unfair +unfold +unhappy +uniform +unique +unit +universe +unknown +unlock +until +unusual +unveil +update +upgrade +uphold +upon +upper +upset +urban +urge +usage +use +used +useful +useless +usual +utility +vacant +vacuum +vague +valid +valley +valve +van +vanish +vapor +various +vast +vault +vehicle +velvet +vendor +venture +venue +verb +verify +version +very +vessel +veteran +viable +vibrant +vicious +victory +video +view +village +vintage +violin +virtual +virus +visa +visit +visual +vital +vivid +vocal +voice +void +volcano +volume +vote +voyage +wage +wagon +wait +walk +wall +walnut +want +warfare +warm +warrior +wash +wasp +waste +water +wave +way +wealth +weapon +wear +weasel +weather +web +wedding +weekend +weird +welcome +west +wet +whale +what +wheat +wheel +when +where +whip +whisper +wide +width +wife +wild +will +win +window +wine +wing +wink +winner +winter +wire +wisdom +wise +wish +witness +wolf +woman +wonder +wood +wool +word +work +world +worry +worth +wrap +wreck +wrestle +wrist +write +wrong +yard +year +yellow +you +young +youth +zebra +zero +zone +zoo`.split("\n"); + + // node_modules/@noble/hashes/esm/hmac.js + var HMAC2 = class extends Hash2 { + constructor(hash3, _key) { + super(); + this.finished = false; + this.destroyed = false; + assert_default.hash(hash3); + const key = toBytes2(_key); + this.iHash = hash3.create(); + if (typeof this.iHash.update !== "function") + throw new Error("Expected instance of class which extends utils.Hash"); + this.blockLen = this.iHash.blockLen; + this.outputLen = this.iHash.outputLen; + const blockLen = this.blockLen; + const pad2 = new Uint8Array(blockLen); + pad2.set(key.length > blockLen ? hash3.create().update(key).digest() : key); + for (let i2 = 0; i2 < pad2.length; i2++) + pad2[i2] ^= 54; + this.iHash.update(pad2); + this.oHash = hash3.create(); + for (let i2 = 0; i2 < pad2.length; i2++) + pad2[i2] ^= 54 ^ 92; + this.oHash.update(pad2); + pad2.fill(0); + } + update(buf) { + assert_default.exists(this); + this.iHash.update(buf); + return this; + } + digestInto(out) { + assert_default.exists(this); + assert_default.bytes(out, this.outputLen); + this.finished = true; + this.iHash.digestInto(out); + this.oHash.update(out); + this.oHash.digestInto(out); + this.destroy(); + } + digest() { + const out = new Uint8Array(this.oHash.outputLen); + this.digestInto(out); + return out; + } + _cloneInto(to) { + to || (to = Object.create(Object.getPrototypeOf(this), {})); + const { oHash, iHash, finished, destroyed, blockLen, outputLen } = this; + to = to; + to.finished = finished; + to.destroyed = destroyed; + to.blockLen = blockLen; + to.outputLen = outputLen; + to.oHash = oHash._cloneInto(to.oHash); + to.iHash = iHash._cloneInto(to.iHash); + return to; + } + destroy() { + this.destroyed = true; + this.oHash.destroy(); + this.iHash.destroy(); + } + }; + var hmac2 = (hash3, key, message) => new HMAC2(hash3, key).update(message).digest(); + hmac2.create = (hash3, key) => new HMAC2(hash3, key); + + // node_modules/@noble/hashes/esm/pbkdf2.js + function pbkdf2Init(hash3, _password, _salt, _opts) { + assert_default.hash(hash3); + const opts = checkOpts({ dkLen: 32, asyncTick: 10 }, _opts); + const { c, dkLen, asyncTick } = opts; + assert_default.number(c); + assert_default.number(dkLen); + assert_default.number(asyncTick); + if (c < 1) + throw new Error("PBKDF2: iterations (c) should be >= 1"); + const password = toBytes2(_password); + const salt2 = toBytes2(_salt); + const DK = new Uint8Array(dkLen); + const PRF = hmac2.create(hash3, password); + const PRFSalt = PRF._cloneInto().update(salt2); + return { c, dkLen, asyncTick, DK, PRF, PRFSalt }; + } + function pbkdf2Output(PRF, PRFSalt, DK, prfW, u) { + PRF.destroy(); + PRFSalt.destroy(); + if (prfW) + prfW.destroy(); + u.fill(0); + return DK; + } + function pbkdf2(hash3, password, salt2, opts) { + const { c, dkLen, DK, PRF, PRFSalt } = pbkdf2Init(hash3, password, salt2, opts); + let prfW; + const arr = new Uint8Array(4); + const view = createView2(arr); + const u = new Uint8Array(PRF.outputLen); + for (let ti = 1, pos = 0; pos < dkLen; ti++, pos += PRF.outputLen) { + const Ti = DK.subarray(pos, pos + PRF.outputLen); + view.setInt32(0, ti, false); + (prfW = PRFSalt._cloneInto(prfW)).update(arr).digestInto(u); + Ti.set(u.subarray(0, Ti.length)); + for (let ui = 1; ui < c; ui++) { + PRF._cloneInto(prfW).update(u).digestInto(u); + for (let i2 = 0; i2 < Ti.length; i2++) + Ti[i2] ^= u[i2]; + } + } + return pbkdf2Output(PRF, PRFSalt, DK, prfW, u); + } + + // node_modules/@noble/hashes/esm/_u64.js + var U32_MASK64 = BigInt(2 ** 32 - 1); + var _32n = BigInt(32); + function fromBig(n, le = false) { + if (le) + return { h: Number(n & U32_MASK64), l: Number(n >> _32n & U32_MASK64) }; + return { h: Number(n >> _32n & U32_MASK64) | 0, l: Number(n & U32_MASK64) | 0 }; + } + function split(lst, le = false) { + let Ah = new Uint32Array(lst.length); + let Al = new Uint32Array(lst.length); + for (let i2 = 0; i2 < lst.length; i2++) { + const { h, l } = fromBig(lst[i2], le); + [Ah[i2], Al[i2]] = [h, l]; + } + return [Ah, Al]; + } + var toBig = (h, l) => BigInt(h >>> 0) << _32n | BigInt(l >>> 0); + var shrSH = (h, l, s) => h >>> s; + var shrSL = (h, l, s) => h << 32 - s | l >>> s; + var rotrSH = (h, l, s) => h >>> s | l << 32 - s; + var rotrSL = (h, l, s) => h << 32 - s | l >>> s; + var rotrBH = (h, l, s) => h << 64 - s | l >>> s - 32; + var rotrBL = (h, l, s) => h >>> s - 32 | l << 64 - s; + var rotr32H = (h, l) => l; + var rotr32L = (h, l) => h; + var rotlSH = (h, l, s) => h << s | l >>> 32 - s; + var rotlSL = (h, l, s) => l << s | h >>> 32 - s; + var rotlBH = (h, l, s) => l << s - 32 | h >>> 64 - s; + var rotlBL = (h, l, s) => h << s - 32 | l >>> 64 - s; + function add(Ah, Al, Bh, Bl) { + const l = (Al >>> 0) + (Bl >>> 0); + return { h: Ah + Bh + (l / 2 ** 32 | 0) | 0, l: l | 0 }; + } + var add3L = (Al, Bl, Cl) => (Al >>> 0) + (Bl >>> 0) + (Cl >>> 0); + var add3H = (low, Ah, Bh, Ch) => Ah + Bh + Ch + (low / 2 ** 32 | 0) | 0; + var add4L = (Al, Bl, Cl, Dl) => (Al >>> 0) + (Bl >>> 0) + (Cl >>> 0) + (Dl >>> 0); + var add4H = (low, Ah, Bh, Ch, Dh) => Ah + Bh + Ch + Dh + (low / 2 ** 32 | 0) | 0; + var add5L = (Al, Bl, Cl, Dl, El) => (Al >>> 0) + (Bl >>> 0) + (Cl >>> 0) + (Dl >>> 0) + (El >>> 0); + var add5H = (low, Ah, Bh, Ch, Dh, Eh) => Ah + Bh + Ch + Dh + Eh + (low / 2 ** 32 | 0) | 0; + var u64 = { + fromBig, + split, + toBig, + shrSH, + shrSL, + rotrSH, + rotrSL, + rotrBH, + rotrBL, + rotr32H, + rotr32L, + rotlSH, + rotlSL, + rotlBH, + rotlBL, + add, + add3L, + add3H, + add4L, + add4H, + add5H, + add5L + }; + var u64_default = u64; + + // node_modules/@noble/hashes/esm/sha512.js + var [SHA512_Kh, SHA512_Kl] = u64_default.split([ + "0x428a2f98d728ae22", + "0x7137449123ef65cd", + "0xb5c0fbcfec4d3b2f", + "0xe9b5dba58189dbbc", + "0x3956c25bf348b538", + "0x59f111f1b605d019", + "0x923f82a4af194f9b", + "0xab1c5ed5da6d8118", + "0xd807aa98a3030242", + "0x12835b0145706fbe", + "0x243185be4ee4b28c", + "0x550c7dc3d5ffb4e2", + "0x72be5d74f27b896f", + "0x80deb1fe3b1696b1", + "0x9bdc06a725c71235", + "0xc19bf174cf692694", + "0xe49b69c19ef14ad2", + "0xefbe4786384f25e3", + "0x0fc19dc68b8cd5b5", + "0x240ca1cc77ac9c65", + "0x2de92c6f592b0275", + "0x4a7484aa6ea6e483", + "0x5cb0a9dcbd41fbd4", + "0x76f988da831153b5", + "0x983e5152ee66dfab", + "0xa831c66d2db43210", + "0xb00327c898fb213f", + "0xbf597fc7beef0ee4", + "0xc6e00bf33da88fc2", + "0xd5a79147930aa725", + "0x06ca6351e003826f", + "0x142929670a0e6e70", + "0x27b70a8546d22ffc", + "0x2e1b21385c26c926", + "0x4d2c6dfc5ac42aed", + "0x53380d139d95b3df", + "0x650a73548baf63de", + "0x766a0abb3c77b2a8", + "0x81c2c92e47edaee6", + "0x92722c851482353b", + "0xa2bfe8a14cf10364", + "0xa81a664bbc423001", + "0xc24b8b70d0f89791", + "0xc76c51a30654be30", + "0xd192e819d6ef5218", + "0xd69906245565a910", + "0xf40e35855771202a", + "0x106aa07032bbd1b8", + "0x19a4c116b8d2d0c8", + "0x1e376c085141ab53", + "0x2748774cdf8eeb99", + "0x34b0bcb5e19b48a8", + "0x391c0cb3c5c95a63", + "0x4ed8aa4ae3418acb", + "0x5b9cca4f7763e373", + "0x682e6ff3d6b2b8a3", + "0x748f82ee5defb2fc", + "0x78a5636f43172f60", + "0x84c87814a1f0ab72", + "0x8cc702081a6439ec", + "0x90befffa23631e28", + "0xa4506cebde82bde9", + "0xbef9a3f7b2c67915", + "0xc67178f2e372532b", + "0xca273eceea26619c", + "0xd186b8c721c0c207", + "0xeada7dd6cde0eb1e", + "0xf57d4f7fee6ed178", + "0x06f067aa72176fba", + "0x0a637dc5a2c898a6", + "0x113f9804bef90dae", + "0x1b710b35131c471b", + "0x28db77f523047d84", + "0x32caab7b40c72493", + "0x3c9ebe0a15c9bebc", + "0x431d67c49c100d4c", + "0x4cc5d4becb3e42b6", + "0x597f299cfc657e2a", + "0x5fcb6fab3ad6faec", + "0x6c44198c4a475817" + ].map((n) => BigInt(n))); + var SHA512_W_H = new Uint32Array(80); + var SHA512_W_L = new Uint32Array(80); + var SHA512 = class extends SHA22 { + constructor() { + super(128, 64, 16, false); + this.Ah = 1779033703 | 0; + this.Al = 4089235720 | 0; + this.Bh = 3144134277 | 0; + this.Bl = 2227873595 | 0; + this.Ch = 1013904242 | 0; + this.Cl = 4271175723 | 0; + this.Dh = 2773480762 | 0; + this.Dl = 1595750129 | 0; + this.Eh = 1359893119 | 0; + this.El = 2917565137 | 0; + this.Fh = 2600822924 | 0; + this.Fl = 725511199 | 0; + this.Gh = 528734635 | 0; + this.Gl = 4215389547 | 0; + this.Hh = 1541459225 | 0; + this.Hl = 327033209 | 0; + } + get() { + const { Ah, Al, Bh, Bl, Ch, Cl, Dh, Dl, Eh, El, Fh, Fl, Gh, Gl, Hh, Hl } = this; + return [Ah, Al, Bh, Bl, Ch, Cl, Dh, Dl, Eh, El, Fh, Fl, Gh, Gl, Hh, Hl]; + } + set(Ah, Al, Bh, Bl, Ch, Cl, Dh, Dl, Eh, El, Fh, Fl, Gh, Gl, Hh, Hl) { + this.Ah = Ah | 0; + this.Al = Al | 0; + this.Bh = Bh | 0; + this.Bl = Bl | 0; + this.Ch = Ch | 0; + this.Cl = Cl | 0; + this.Dh = Dh | 0; + this.Dl = Dl | 0; + this.Eh = Eh | 0; + this.El = El | 0; + this.Fh = Fh | 0; + this.Fl = Fl | 0; + this.Gh = Gh | 0; + this.Gl = Gl | 0; + this.Hh = Hh | 0; + this.Hl = Hl | 0; + } + process(view, offset) { + for (let i2 = 0; i2 < 16; i2++, offset += 4) { + SHA512_W_H[i2] = view.getUint32(offset); + SHA512_W_L[i2] = view.getUint32(offset += 4); + } + for (let i2 = 16; i2 < 80; i2++) { + const W15h = SHA512_W_H[i2 - 15] | 0; + const W15l = SHA512_W_L[i2 - 15] | 0; + const s0h = u64_default.rotrSH(W15h, W15l, 1) ^ u64_default.rotrSH(W15h, W15l, 8) ^ u64_default.shrSH(W15h, W15l, 7); + const s0l = u64_default.rotrSL(W15h, W15l, 1) ^ u64_default.rotrSL(W15h, W15l, 8) ^ u64_default.shrSL(W15h, W15l, 7); + const W2h = SHA512_W_H[i2 - 2] | 0; + const W2l = SHA512_W_L[i2 - 2] | 0; + const s1h = u64_default.rotrSH(W2h, W2l, 19) ^ u64_default.rotrBH(W2h, W2l, 61) ^ u64_default.shrSH(W2h, W2l, 6); + const s1l = u64_default.rotrSL(W2h, W2l, 19) ^ u64_default.rotrBL(W2h, W2l, 61) ^ u64_default.shrSL(W2h, W2l, 6); + const SUMl = u64_default.add4L(s0l, s1l, SHA512_W_L[i2 - 7], SHA512_W_L[i2 - 16]); + const SUMh = u64_default.add4H(SUMl, s0h, s1h, SHA512_W_H[i2 - 7], SHA512_W_H[i2 - 16]); + SHA512_W_H[i2] = SUMh | 0; + SHA512_W_L[i2] = SUMl | 0; + } + let { Ah, Al, Bh, Bl, Ch, Cl, Dh, Dl, Eh, El, Fh, Fl, Gh, Gl, Hh, Hl } = this; + for (let i2 = 0; i2 < 80; i2++) { + const sigma1h = u64_default.rotrSH(Eh, El, 14) ^ u64_default.rotrSH(Eh, El, 18) ^ u64_default.rotrBH(Eh, El, 41); + const sigma1l = u64_default.rotrSL(Eh, El, 14) ^ u64_default.rotrSL(Eh, El, 18) ^ u64_default.rotrBL(Eh, El, 41); + const CHIh = Eh & Fh ^ ~Eh & Gh; + const CHIl = El & Fl ^ ~El & Gl; + const T1ll = u64_default.add5L(Hl, sigma1l, CHIl, SHA512_Kl[i2], SHA512_W_L[i2]); + const T1h = u64_default.add5H(T1ll, Hh, sigma1h, CHIh, SHA512_Kh[i2], SHA512_W_H[i2]); + const T1l = T1ll | 0; + const sigma0h = u64_default.rotrSH(Ah, Al, 28) ^ u64_default.rotrBH(Ah, Al, 34) ^ u64_default.rotrBH(Ah, Al, 39); + const sigma0l = u64_default.rotrSL(Ah, Al, 28) ^ u64_default.rotrBL(Ah, Al, 34) ^ u64_default.rotrBL(Ah, Al, 39); + const MAJh = Ah & Bh ^ Ah & Ch ^ Bh & Ch; + const MAJl = Al & Bl ^ Al & Cl ^ Bl & Cl; + Hh = Gh | 0; + Hl = Gl | 0; + Gh = Fh | 0; + Gl = Fl | 0; + Fh = Eh | 0; + Fl = El | 0; + ({ h: Eh, l: El } = u64_default.add(Dh | 0, Dl | 0, T1h | 0, T1l | 0)); + Dh = Ch | 0; + Dl = Cl | 0; + Ch = Bh | 0; + Cl = Bl | 0; + Bh = Ah | 0; + Bl = Al | 0; + const All = u64_default.add3L(T1l, sigma0l, MAJl); + Ah = u64_default.add3H(All, T1h, sigma0h, MAJh); + Al = All | 0; + } + ({ h: Ah, l: Al } = u64_default.add(this.Ah | 0, this.Al | 0, Ah | 0, Al | 0)); + ({ h: Bh, l: Bl } = u64_default.add(this.Bh | 0, this.Bl | 0, Bh | 0, Bl | 0)); + ({ h: Ch, l: Cl } = u64_default.add(this.Ch | 0, this.Cl | 0, Ch | 0, Cl | 0)); + ({ h: Dh, l: Dl } = u64_default.add(this.Dh | 0, this.Dl | 0, Dh | 0, Dl | 0)); + ({ h: Eh, l: El } = u64_default.add(this.Eh | 0, this.El | 0, Eh | 0, El | 0)); + ({ h: Fh, l: Fl } = u64_default.add(this.Fh | 0, this.Fl | 0, Fh | 0, Fl | 0)); + ({ h: Gh, l: Gl } = u64_default.add(this.Gh | 0, this.Gl | 0, Gh | 0, Gl | 0)); + ({ h: Hh, l: Hl } = u64_default.add(this.Hh | 0, this.Hl | 0, Hh | 0, Hl | 0)); + this.set(Ah, Al, Bh, Bl, Ch, Cl, Dh, Dl, Eh, El, Fh, Fl, Gh, Gl, Hh, Hl); + } + roundClean() { + SHA512_W_H.fill(0); + SHA512_W_L.fill(0); + } + destroy() { + this.buffer.fill(0); + this.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + } + }; + var SHA512_224 = class extends SHA512 { + constructor() { + super(); + this.Ah = 2352822216 | 0; + this.Al = 424955298 | 0; + this.Bh = 1944164710 | 0; + this.Bl = 2312950998 | 0; + this.Ch = 502970286 | 0; + this.Cl = 855612546 | 0; + this.Dh = 1738396948 | 0; + this.Dl = 1479516111 | 0; + this.Eh = 258812777 | 0; + this.El = 2077511080 | 0; + this.Fh = 2011393907 | 0; + this.Fl = 79989058 | 0; + this.Gh = 1067287976 | 0; + this.Gl = 1780299464 | 0; + this.Hh = 286451373 | 0; + this.Hl = 2446758561 | 0; + this.outputLen = 28; + } + }; + var SHA512_256 = class extends SHA512 { + constructor() { + super(); + this.Ah = 573645204 | 0; + this.Al = 4230739756 | 0; + this.Bh = 2673172387 | 0; + this.Bl = 3360449730 | 0; + this.Ch = 596883563 | 0; + this.Cl = 1867755857 | 0; + this.Dh = 2520282905 | 0; + this.Dl = 1497426621 | 0; + this.Eh = 2519219938 | 0; + this.El = 2827943907 | 0; + this.Fh = 3193839141 | 0; + this.Fl = 1401305490 | 0; + this.Gh = 721525244 | 0; + this.Gl = 746961066 | 0; + this.Hh = 246885852 | 0; + this.Hl = 2177182882 | 0; + this.outputLen = 32; + } + }; + var SHA384 = class extends SHA512 { + constructor() { + super(); + this.Ah = 3418070365 | 0; + this.Al = 3238371032 | 0; + this.Bh = 1654270250 | 0; + this.Bl = 914150663 | 0; + this.Ch = 2438529370 | 0; + this.Cl = 812702999 | 0; + this.Dh = 355462360 | 0; + this.Dl = 4144912697 | 0; + this.Eh = 1731405415 | 0; + this.El = 4290775857 | 0; + this.Fh = 2394180231 | 0; + this.Fl = 1750603025 | 0; + this.Gh = 3675008525 | 0; + this.Gl = 1694076839 | 0; + this.Hh = 1203062813 | 0; + this.Hl = 3204075428 | 0; + this.outputLen = 48; + } + }; + var sha512 = wrapConstructor2(() => new SHA512()); + var sha512_224 = wrapConstructor2(() => new SHA512_224()); + var sha512_256 = wrapConstructor2(() => new SHA512_256()); + var sha384 = wrapConstructor2(() => new SHA384()); + + // node_modules/@scure/bip39/esm/index.js + var isJapanese = (wordlist2) => wordlist2[0] === "\u3042\u3044\u3053\u304F\u3057\u3093"; + function nfkd(str) { + if (typeof str !== "string") + throw new TypeError(`Invalid mnemonic type: ${typeof str}`); + return str.normalize("NFKD"); + } + function normalize2(str) { + const norm = nfkd(str); + const words = norm.split(" "); + if (![12, 15, 18, 21, 24].includes(words.length)) + throw new Error("Invalid mnemonic"); + return { nfkd: norm, words }; + } + function assertEntropy(entropy) { + assert_default.bytes(entropy, 16, 20, 24, 28, 32); + } + function generateMnemonic(wordlist2, strength = 128) { + assert_default.number(strength); + if (strength % 32 !== 0 || strength > 256) + throw new TypeError("Invalid entropy"); + return entropyToMnemonic(randomBytes2(strength / 8), wordlist2); + } + var calcChecksum = (entropy) => { + const bitsLeft = 8 - entropy.length / 4; + return new Uint8Array([sha2562(entropy)[0] >> bitsLeft << bitsLeft]); + }; + function getCoder(wordlist2) { + if (!Array.isArray(wordlist2) || wordlist2.length !== 2048 || typeof wordlist2[0] !== "string") + throw new Error("Worlist: expected array of 2048 strings"); + wordlist2.forEach((i2) => { + if (typeof i2 !== "string") + throw new Error(`Wordlist: non-string element: ${i2}`); + }); + return utils.chain(utils.checksum(1, calcChecksum), utils.radix2(11, true), utils.alphabet(wordlist2)); + } + function mnemonicToEntropy(mnemonic, wordlist2) { + const { words } = normalize2(mnemonic); + const entropy = getCoder(wordlist2).decode(words); + assertEntropy(entropy); + return entropy; + } + function entropyToMnemonic(entropy, wordlist2) { + assertEntropy(entropy); + const words = getCoder(wordlist2).encode(entropy); + return words.join(isJapanese(wordlist2) ? "\u3000" : " "); + } + function validateMnemonic(mnemonic, wordlist2) { + try { + mnemonicToEntropy(mnemonic, wordlist2); + } catch (e) { + return false; + } + return true; + } + var salt = (passphrase) => nfkd(`mnemonic${passphrase}`); + function mnemonicToSeedSync(mnemonic, passphrase = "") { + return pbkdf2(sha512, normalize2(mnemonic).nfkd, salt(passphrase), { c: 2048, dkLen: 64 }); + } + + // node_modules/@noble/hashes/esm/ripemd160.js + var Rho = new Uint8Array([7, 4, 13, 1, 10, 6, 15, 3, 12, 0, 9, 5, 2, 14, 11, 8]); + var Id = Uint8Array.from({ length: 16 }, (_, i2) => i2); + var Pi = Id.map((i2) => (9 * i2 + 5) % 16); + var idxL = [Id]; + var idxR = [Pi]; + for (let i2 = 0; i2 < 4; i2++) + for (let j of [idxL, idxR]) + j.push(j[i2].map((k) => Rho[k])); + var shifts = [ + [11, 14, 15, 12, 5, 8, 7, 9, 11, 13, 14, 15, 6, 7, 9, 8], + [12, 13, 11, 15, 6, 9, 9, 7, 12, 15, 11, 13, 7, 8, 7, 7], + [13, 15, 14, 11, 7, 7, 6, 8, 13, 14, 13, 12, 5, 5, 6, 9], + [14, 11, 12, 14, 8, 6, 5, 5, 15, 12, 15, 14, 9, 9, 8, 6], + [15, 12, 13, 13, 9, 5, 8, 6, 14, 11, 12, 11, 8, 6, 5, 5] + ].map((i2) => new Uint8Array(i2)); + var shiftsL = idxL.map((idx, i2) => idx.map((j) => shifts[i2][j])); + var shiftsR = idxR.map((idx, i2) => idx.map((j) => shifts[i2][j])); + var Kl = new Uint32Array([0, 1518500249, 1859775393, 2400959708, 2840853838]); + var Kr = new Uint32Array([1352829926, 1548603684, 1836072691, 2053994217, 0]); + var rotl = (word, shift) => word << shift | word >>> 32 - shift; + function f(group, x, y, z) { + if (group === 0) + return x ^ y ^ z; + else if (group === 1) + return x & y | ~x & z; + else if (group === 2) + return (x | ~y) ^ z; + else if (group === 3) + return x & z | y & ~z; + else + return x ^ (y | ~z); + } + var BUF = new Uint32Array(16); + var RIPEMD160 = class extends SHA22 { + constructor() { + super(64, 20, 8, true); + this.h0 = 1732584193 | 0; + this.h1 = 4023233417 | 0; + this.h2 = 2562383102 | 0; + this.h3 = 271733878 | 0; + this.h4 = 3285377520 | 0; + } + get() { + const { h0, h1, h2, h3, h4 } = this; + return [h0, h1, h2, h3, h4]; + } + set(h0, h1, h2, h3, h4) { + this.h0 = h0 | 0; + this.h1 = h1 | 0; + this.h2 = h2 | 0; + this.h3 = h3 | 0; + this.h4 = h4 | 0; + } + process(view, offset) { + for (let i2 = 0; i2 < 16; i2++, offset += 4) + BUF[i2] = view.getUint32(offset, true); + let al = this.h0 | 0, ar = al, bl = this.h1 | 0, br = bl, cl = this.h2 | 0, cr = cl, dl = this.h3 | 0, dr = dl, el = this.h4 | 0, er = el; + for (let group = 0; group < 5; group++) { + const rGroup = 4 - group; + const hbl = Kl[group], hbr = Kr[group]; + const rl = idxL[group], rr = idxR[group]; + const sl = shiftsL[group], sr = shiftsR[group]; + for (let i2 = 0; i2 < 16; i2++) { + const tl = rotl(al + f(group, bl, cl, dl) + BUF[rl[i2]] + hbl, sl[i2]) + el | 0; + al = el, el = dl, dl = rotl(cl, 10) | 0, cl = bl, bl = tl; + } + for (let i2 = 0; i2 < 16; i2++) { + const tr = rotl(ar + f(rGroup, br, cr, dr) + BUF[rr[i2]] + hbr, sr[i2]) + er | 0; + ar = er, er = dr, dr = rotl(cr, 10) | 0, cr = br, br = tr; + } + } + this.set(this.h1 + cl + dr | 0, this.h2 + dl + er | 0, this.h3 + el + ar | 0, this.h4 + al + br | 0, this.h0 + bl + cr | 0); + } + roundClean() { + BUF.fill(0); + } + destroy() { + this.destroyed = true; + this.buffer.fill(0); + this.set(0, 0, 0, 0, 0); + } + }; + var ripemd160 = wrapConstructor2(() => new RIPEMD160()); + + // node_modules/@scure/bip32/node_modules/@noble/curves/esm/abstract/utils.js + var utils_exports3 = {}; + __export(utils_exports3, { + bitGet: () => bitGet2, + bitLen: () => bitLen2, + bitMask: () => bitMask2, + bitSet: () => bitSet2, + bytesToHex: () => bytesToHex3, + bytesToNumberBE: () => bytesToNumberBE2, + bytesToNumberLE: () => bytesToNumberLE2, + concatBytes: () => concatBytes4, + createHmacDrbg: () => createHmacDrbg2, + ensureBytes: () => ensureBytes2, + equalBytes: () => equalBytes3, + hexToBytes: () => hexToBytes3, + hexToNumber: () => hexToNumber2, + numberToBytesBE: () => numberToBytesBE2, + numberToBytesLE: () => numberToBytesLE2, + numberToHexUnpadded: () => numberToHexUnpadded2, + numberToVarBytesBE: () => numberToVarBytesBE2, + utf8ToBytes: () => utf8ToBytes5, + validateObject: () => validateObject2 + }); + var _0n6 = BigInt(0); + var _1n6 = BigInt(1); + var _2n5 = BigInt(2); + var u8a4 = (a) => a instanceof Uint8Array; + var hexes3 = Array.from({ length: 256 }, (v, i2) => i2.toString(16).padStart(2, "0")); + function bytesToHex3(bytes4) { + if (!u8a4(bytes4)) + throw new Error("Uint8Array expected"); + let hex2 = ""; + for (let i2 = 0; i2 < bytes4.length; i2++) { + hex2 += hexes3[bytes4[i2]]; + } + return hex2; + } + function numberToHexUnpadded2(num) { + const hex2 = num.toString(16); + return hex2.length & 1 ? `0${hex2}` : hex2; + } + function hexToNumber2(hex2) { + if (typeof hex2 !== "string") + throw new Error("hex string expected, got " + typeof hex2); + return BigInt(hex2 === "" ? "0" : `0x${hex2}`); + } + function hexToBytes3(hex2) { + if (typeof hex2 !== "string") + throw new Error("hex string expected, got " + typeof hex2); + const len = hex2.length; + if (len % 2) + throw new Error("padded hex string expected, got unpadded hex of length " + len); + const array = new Uint8Array(len / 2); + for (let i2 = 0; i2 < array.length; i2++) { + const j = i2 * 2; + const hexByte = hex2.slice(j, j + 2); + const byte = Number.parseInt(hexByte, 16); + if (Number.isNaN(byte) || byte < 0) + throw new Error("Invalid byte sequence"); + array[i2] = byte; + } + return array; + } + function bytesToNumberBE2(bytes4) { + return hexToNumber2(bytesToHex3(bytes4)); + } + function bytesToNumberLE2(bytes4) { + if (!u8a4(bytes4)) + throw new Error("Uint8Array expected"); + return hexToNumber2(bytesToHex3(Uint8Array.from(bytes4).reverse())); + } + function numberToBytesBE2(n, len) { + return hexToBytes3(n.toString(16).padStart(len * 2, "0")); + } + function numberToBytesLE2(n, len) { + return numberToBytesBE2(n, len).reverse(); + } + function numberToVarBytesBE2(n) { + return hexToBytes3(numberToHexUnpadded2(n)); + } + function ensureBytes2(title, hex2, expectedLength) { + let res; + if (typeof hex2 === "string") { + try { + res = hexToBytes3(hex2); + } catch (e) { + throw new Error(`${title} must be valid hex string, got "${hex2}". Cause: ${e}`); + } + } else if (u8a4(hex2)) { + res = Uint8Array.from(hex2); + } else { + throw new Error(`${title} must be hex string or Uint8Array`); + } + const len = res.length; + if (typeof expectedLength === "number" && len !== expectedLength) + throw new Error(`${title} expected ${expectedLength} bytes, got ${len}`); + return res; + } + function concatBytes4(...arrays) { + const r = new Uint8Array(arrays.reduce((sum, a) => sum + a.length, 0)); + let pad2 = 0; + arrays.forEach((a) => { + if (!u8a4(a)) + throw new Error("Uint8Array expected"); + r.set(a, pad2); + pad2 += a.length; + }); + return r; + } + function equalBytes3(b1, b2) { + if (b1.length !== b2.length) + return false; + for (let i2 = 0; i2 < b1.length; i2++) + if (b1[i2] !== b2[i2]) + return false; + return true; + } + function utf8ToBytes5(str) { + if (typeof str !== "string") + throw new Error(`utf8ToBytes expected string, got ${typeof str}`); + return new Uint8Array(new TextEncoder().encode(str)); + } + function bitLen2(n) { + let len; + for (len = 0; n > _0n6; n >>= _1n6, len += 1) + ; + return len; + } + function bitGet2(n, pos) { + return n >> BigInt(pos) & _1n6; + } + var bitSet2 = (n, pos, value) => { + return n | (value ? _1n6 : _0n6) << BigInt(pos); + }; + var bitMask2 = (n) => (_2n5 << BigInt(n - 1)) - _1n6; + var u8n2 = (data) => new Uint8Array(data); + var u8fr2 = (arr) => Uint8Array.from(arr); + function createHmacDrbg2(hashLen, qByteLen, hmacFn) { + if (typeof hashLen !== "number" || hashLen < 2) + throw new Error("hashLen must be a number"); + if (typeof qByteLen !== "number" || qByteLen < 2) + throw new Error("qByteLen must be a number"); + if (typeof hmacFn !== "function") + throw new Error("hmacFn must be a function"); + let v = u8n2(hashLen); + let k = u8n2(hashLen); + let i2 = 0; + const reset = () => { + v.fill(1); + k.fill(0); + i2 = 0; + }; + const h = (...b) => hmacFn(k, v, ...b); + const reseed = (seed = u8n2()) => { + k = h(u8fr2([0]), seed); + v = h(); + if (seed.length === 0) + return; + k = h(u8fr2([1]), seed); + v = h(); + }; + const gen = () => { + if (i2++ >= 1e3) + throw new Error("drbg: tried 1000 values"); + let len = 0; + const out = []; + while (len < qByteLen) { + v = h(); + const sl = v.slice(); + out.push(sl); + len += v.length; + } + return concatBytes4(...out); + }; + const genUntil = (seed, pred) => { + reset(); + reseed(seed); + let res = void 0; + while (!(res = pred(gen()))) + reseed(); + reset(); + return res; + }; + return genUntil; + } + var validatorFns2 = { + bigint: (val) => typeof val === "bigint", + function: (val) => typeof val === "function", + boolean: (val) => typeof val === "boolean", + string: (val) => typeof val === "string", + isSafeInteger: (val) => Number.isSafeInteger(val), + array: (val) => Array.isArray(val), + field: (val, object) => object.Fp.isValid(val), + hash: (val) => typeof val === "function" && Number.isSafeInteger(val.outputLen) + }; + function validateObject2(object, validators, optValidators = {}) { + const checkField = (fieldName, type, isOptional) => { + const checkVal = validatorFns2[type]; + if (typeof checkVal !== "function") + throw new Error(`Invalid validator "${type}", expected function`); + const val = object[fieldName]; + if (isOptional && val === void 0) + return; + if (!checkVal(val, object)) { + throw new Error(`Invalid param ${String(fieldName)}=${val} (${typeof val}), expected ${type}`); + } + }; + for (const [fieldName, type] of Object.entries(validators)) + checkField(fieldName, type, false); + for (const [fieldName, type] of Object.entries(optValidators)) + checkField(fieldName, type, true); + return object; + } + + // node_modules/@scure/bip32/node_modules/@noble/curves/esm/abstract/modular.js + var _0n7 = BigInt(0); + var _1n7 = BigInt(1); + var _2n6 = BigInt(2); + var _3n3 = BigInt(3); + var _4n3 = BigInt(4); + var _5n2 = BigInt(5); + var _8n2 = BigInt(8); + var _9n2 = BigInt(9); + var _16n2 = BigInt(16); + function mod2(a, b) { + const result = a % b; + return result >= _0n7 ? result : b + result; + } + function pow3(num, power, modulo) { + if (modulo <= _0n7 || power < _0n7) + throw new Error("Expected power/modulo > 0"); + if (modulo === _1n7) + return _0n7; + let res = _1n7; + while (power > _0n7) { + if (power & _1n7) + res = res * num % modulo; + num = num * num % modulo; + power >>= _1n7; + } + return res; + } + function pow22(x, power, modulo) { + let res = x; + while (power-- > _0n7) { + res *= res; + res %= modulo; + } + return res; + } + function invert2(number4, modulo) { + if (number4 === _0n7 || modulo <= _0n7) { + throw new Error(`invert: expected positive integers, got n=${number4} mod=${modulo}`); + } + let a = mod2(number4, modulo); + let b = modulo; + let x = _0n7, y = _1n7, u = _1n7, v = _0n7; + while (a !== _0n7) { + const q = b / a; + const r = b % a; + const m = x - u * q; + const n = y - v * q; + b = a, a = r, x = u, y = v, u = m, v = n; + } + const gcd2 = b; + if (gcd2 !== _1n7) + throw new Error("invert: does not exist"); + return mod2(x, modulo); + } + function tonelliShanks2(P) { + const legendreC = (P - _1n7) / _2n6; + let Q, S, Z; + for (Q = P - _1n7, S = 0; Q % _2n6 === _0n7; Q /= _2n6, S++) + ; + for (Z = _2n6; Z < P && pow3(Z, legendreC, P) !== P - _1n7; Z++) + ; + if (S === 1) { + const p1div4 = (P + _1n7) / _4n3; + return function tonelliFast(Fp3, n) { + const root = Fp3.pow(n, p1div4); + if (!Fp3.eql(Fp3.sqr(root), n)) + throw new Error("Cannot find square root"); + return root; + }; + } + const Q1div2 = (Q + _1n7) / _2n6; + return function tonelliSlow(Fp3, n) { + if (Fp3.pow(n, legendreC) === Fp3.neg(Fp3.ONE)) + throw new Error("Cannot find square root"); + let r = S; + let g = Fp3.pow(Fp3.mul(Fp3.ONE, Z), Q); + let x = Fp3.pow(n, Q1div2); + let b = Fp3.pow(n, Q); + while (!Fp3.eql(b, Fp3.ONE)) { + if (Fp3.eql(b, Fp3.ZERO)) + return Fp3.ZERO; + let m = 1; + for (let t2 = Fp3.sqr(b); m < r; m++) { + if (Fp3.eql(t2, Fp3.ONE)) + break; + t2 = Fp3.sqr(t2); + } + const ge2 = Fp3.pow(g, _1n7 << BigInt(r - m - 1)); + g = Fp3.sqr(ge2); + x = Fp3.mul(x, ge2); + b = Fp3.mul(b, g); + r = m; + } + return x; + }; + } + function FpSqrt2(P) { + if (P % _4n3 === _3n3) { + const p1div4 = (P + _1n7) / _4n3; + return function sqrt3mod4(Fp3, n) { + const root = Fp3.pow(n, p1div4); + if (!Fp3.eql(Fp3.sqr(root), n)) + throw new Error("Cannot find square root"); + return root; + }; + } + if (P % _8n2 === _5n2) { + const c1 = (P - _5n2) / _8n2; + return function sqrt5mod8(Fp3, n) { + const n2 = Fp3.mul(n, _2n6); + const v = Fp3.pow(n2, c1); + const nv = Fp3.mul(n, v); + const i2 = Fp3.mul(Fp3.mul(nv, _2n6), v); + const root = Fp3.mul(nv, Fp3.sub(i2, Fp3.ONE)); + if (!Fp3.eql(Fp3.sqr(root), n)) + throw new Error("Cannot find square root"); + return root; + }; + } + if (P % _16n2 === _9n2) { + } + return tonelliShanks2(P); + } + var FIELD_FIELDS2 = [ + "create", + "isValid", + "is0", + "neg", + "inv", + "sqrt", + "sqr", + "eql", + "add", + "sub", + "mul", + "pow", + "div", + "addN", + "subN", + "mulN", + "sqrN" + ]; + function validateField2(field) { + const initial = { + ORDER: "bigint", + MASK: "bigint", + BYTES: "isSafeInteger", + BITS: "isSafeInteger" + }; + const opts = FIELD_FIELDS2.reduce((map, val) => { + map[val] = "function"; + return map; + }, initial); + return validateObject2(field, opts); + } + function FpPow2(f2, num, power) { + if (power < _0n7) + throw new Error("Expected power > 0"); + if (power === _0n7) + return f2.ONE; + if (power === _1n7) + return num; + let p = f2.ONE; + let d = num; + while (power > _0n7) { + if (power & _1n7) + p = f2.mul(p, d); + d = f2.sqr(d); + power >>= _1n7; + } + return p; + } + function FpInvertBatch2(f2, nums) { + const tmp = new Array(nums.length); + const lastMultiplied = nums.reduce((acc, num, i2) => { + if (f2.is0(num)) + return acc; + tmp[i2] = acc; + return f2.mul(acc, num); + }, f2.ONE); + const inverted = f2.inv(lastMultiplied); + nums.reduceRight((acc, num, i2) => { + if (f2.is0(num)) + return acc; + tmp[i2] = f2.mul(acc, tmp[i2]); + return f2.mul(acc, num); + }, inverted); + return tmp; + } + function nLength2(n, nBitLength) { + const _nBitLength = nBitLength !== void 0 ? nBitLength : n.toString(2).length; + const nByteLength = Math.ceil(_nBitLength / 8); + return { nBitLength: _nBitLength, nByteLength }; + } + function Field2(ORDER, bitLen3, isLE4 = false, redef = {}) { + if (ORDER <= _0n7) + throw new Error(`Expected Fp ORDER > 0, got ${ORDER}`); + const { nBitLength: BITS, nByteLength: BYTES } = nLength2(ORDER, bitLen3); + if (BYTES > 2048) + throw new Error("Field lengths over 2048 bytes are not supported"); + const sqrtP = FpSqrt2(ORDER); + const f2 = Object.freeze({ + ORDER, + BITS, + BYTES, + MASK: bitMask2(BITS), + ZERO: _0n7, + ONE: _1n7, + create: (num) => mod2(num, ORDER), + isValid: (num) => { + if (typeof num !== "bigint") + throw new Error(`Invalid field element: expected bigint, got ${typeof num}`); + return _0n7 <= num && num < ORDER; + }, + is0: (num) => num === _0n7, + isOdd: (num) => (num & _1n7) === _1n7, + neg: (num) => mod2(-num, ORDER), + eql: (lhs, rhs) => lhs === rhs, + sqr: (num) => mod2(num * num, ORDER), + add: (lhs, rhs) => mod2(lhs + rhs, ORDER), + sub: (lhs, rhs) => mod2(lhs - rhs, ORDER), + mul: (lhs, rhs) => mod2(lhs * rhs, ORDER), + pow: (num, power) => FpPow2(f2, num, power), + div: (lhs, rhs) => mod2(lhs * invert2(rhs, ORDER), ORDER), + sqrN: (num) => num * num, + addN: (lhs, rhs) => lhs + rhs, + subN: (lhs, rhs) => lhs - rhs, + mulN: (lhs, rhs) => lhs * rhs, + inv: (num) => invert2(num, ORDER), + sqrt: redef.sqrt || ((n) => sqrtP(f2, n)), + invertBatch: (lst) => FpInvertBatch2(f2, lst), + cmov: (a, b, c) => c ? b : a, + toBytes: (num) => isLE4 ? numberToBytesLE2(num, BYTES) : numberToBytesBE2(num, BYTES), + fromBytes: (bytes4) => { + if (bytes4.length !== BYTES) + throw new Error(`Fp.fromBytes: expected ${BYTES}, got ${bytes4.length}`); + return isLE4 ? bytesToNumberLE2(bytes4) : bytesToNumberBE2(bytes4); + } + }); + return Object.freeze(f2); + } + function hashToPrivateScalar(hash3, groupOrder, isLE4 = false) { + hash3 = ensureBytes2("privateHash", hash3); + const hashLen = hash3.length; + const minLen = nLength2(groupOrder).nByteLength + 8; + if (minLen < 24 || hashLen < minLen || hashLen > 1024) + throw new Error(`hashToPrivateScalar: expected ${minLen}-1024 bytes of input, got ${hashLen}`); + const num = isLE4 ? bytesToNumberLE2(hash3) : bytesToNumberBE2(hash3); + return mod2(num, groupOrder - _1n7) + _1n7; + } + + // node_modules/@scure/bip32/node_modules/@noble/curves/esm/abstract/curve.js + var _0n8 = BigInt(0); + var _1n8 = BigInt(1); + function wNAF2(c, bits) { + const constTimeNegate = (condition, item) => { + const neg = item.negate(); + return condition ? neg : item; + }; + const opts = (W) => { + const windows = Math.ceil(bits / W) + 1; + const windowSize = 2 ** (W - 1); + return { windows, windowSize }; + }; + return { + constTimeNegate, + unsafeLadder(elm, n) { + let p = c.ZERO; + let d = elm; + while (n > _0n8) { + if (n & _1n8) + p = p.add(d); + d = d.double(); + n >>= _1n8; + } + return p; + }, + precomputeWindow(elm, W) { + const { windows, windowSize } = opts(W); + const points = []; + let p = elm; + let base = p; + for (let window = 0; window < windows; window++) { + base = p; + points.push(base); + for (let i2 = 1; i2 < windowSize; i2++) { + base = base.add(p); + points.push(base); + } + p = base.double(); + } + return points; + }, + wNAF(W, precomputes, n) { + const { windows, windowSize } = opts(W); + let p = c.ZERO; + let f2 = c.BASE; + const mask = BigInt(2 ** W - 1); + const maxNumber = 2 ** W; + const shiftBy = BigInt(W); + for (let window = 0; window < windows; window++) { + const offset = window * windowSize; + let wbits = Number(n & mask); + n >>= shiftBy; + if (wbits > windowSize) { + wbits -= maxNumber; + n += _1n8; + } + const offset1 = offset; + const offset2 = offset + Math.abs(wbits) - 1; + const cond1 = window % 2 !== 0; + const cond2 = wbits < 0; + if (wbits === 0) { + f2 = f2.add(constTimeNegate(cond1, precomputes[offset1])); + } else { + p = p.add(constTimeNegate(cond2, precomputes[offset2])); + } + } + return { p, f: f2 }; + }, + wNAFCached(P, precomputesMap, n, transform) { + const W = P._WINDOW_SIZE || 1; + let comp = precomputesMap.get(P); + if (!comp) { + comp = this.precomputeWindow(P, W); + if (W !== 1) { + precomputesMap.set(P, transform(comp)); + } + } + return this.wNAF(W, comp, n); + } + }; + } + function validateBasic2(curve) { + validateField2(curve.Fp); + validateObject2(curve, { + n: "bigint", + h: "bigint", + Gx: "field", + Gy: "field" + }, { + nBitLength: "isSafeInteger", + nByteLength: "isSafeInteger" + }); + return Object.freeze({ + ...nLength2(curve.n, curve.nBitLength), + ...curve, + ...{ p: curve.Fp.ORDER } + }); + } + + // node_modules/@scure/bip32/node_modules/@noble/curves/esm/abstract/weierstrass.js + function validatePointOpts2(curve) { + const opts = validateBasic2(curve); + validateObject2(opts, { + a: "field", + b: "field" + }, { + allowedPrivateKeyLengths: "array", + wrapPrivateKey: "boolean", + isTorsionFree: "function", + clearCofactor: "function", + allowInfinityPoint: "boolean", + fromBytes: "function", + toBytes: "function" + }); + const { endo, Fp: Fp3, a } = opts; + if (endo) { + if (!Fp3.eql(a, Fp3.ZERO)) { + throw new Error("Endomorphism can only be defined for Koblitz curves that have a=0"); + } + if (typeof endo !== "object" || typeof endo.beta !== "bigint" || typeof endo.splitScalar !== "function") { + throw new Error("Expected endomorphism with beta: bigint and splitScalar: function"); + } + } + return Object.freeze({ ...opts }); + } + var { bytesToNumberBE: b2n2, hexToBytes: h2b2 } = utils_exports3; + var DER2 = { + Err: class DERErr2 extends Error { + constructor(m = "") { + super(m); + } + }, + _parseInt(data) { + const { Err: E } = DER2; + if (data.length < 2 || data[0] !== 2) + throw new E("Invalid signature integer tag"); + const len = data[1]; + const res = data.subarray(2, len + 2); + if (!len || res.length !== len) + throw new E("Invalid signature integer: wrong length"); + if (res[0] & 128) + throw new E("Invalid signature integer: negative"); + if (res[0] === 0 && !(res[1] & 128)) + throw new E("Invalid signature integer: unnecessary leading zero"); + return { d: b2n2(res), l: data.subarray(len + 2) }; + }, + toSig(hex2) { + const { Err: E } = DER2; + const data = typeof hex2 === "string" ? h2b2(hex2) : hex2; + if (!(data instanceof Uint8Array)) + throw new Error("ui8a expected"); + let l = data.length; + if (l < 2 || data[0] != 48) + throw new E("Invalid signature tag"); + if (data[1] !== l - 2) + throw new E("Invalid signature: incorrect length"); + const { d: r, l: sBytes } = DER2._parseInt(data.subarray(2)); + const { d: s, l: rBytesLeft } = DER2._parseInt(sBytes); + if (rBytesLeft.length) + throw new E("Invalid signature: left bytes after parsing"); + return { r, s }; + }, + hexFromSig(sig) { + const slice = (s2) => Number.parseInt(s2[0], 16) & 8 ? "00" + s2 : s2; + const h = (num) => { + const hex2 = num.toString(16); + return hex2.length & 1 ? `0${hex2}` : hex2; + }; + const s = slice(h(sig.s)); + const r = slice(h(sig.r)); + const shl = s.length / 2; + const rhl = r.length / 2; + const sl = h(shl); + const rl = h(rhl); + return `30${h(rhl + shl + 4)}02${rl}${r}02${sl}${s}`; + } + }; + var _0n9 = BigInt(0); + var _1n9 = BigInt(1); + var _2n7 = BigInt(2); + var _3n4 = BigInt(3); + var _4n4 = BigInt(4); + function weierstrassPoints2(opts) { + const CURVE = validatePointOpts2(opts); + const { Fp: Fp3 } = CURVE; + const toBytes4 = CURVE.toBytes || ((c, point, isCompressed) => { + const a = point.toAffine(); + return concatBytes4(Uint8Array.from([4]), Fp3.toBytes(a.x), Fp3.toBytes(a.y)); + }); + const fromBytes = CURVE.fromBytes || ((bytes4) => { + const tail = bytes4.subarray(1); + const x = Fp3.fromBytes(tail.subarray(0, Fp3.BYTES)); + const y = Fp3.fromBytes(tail.subarray(Fp3.BYTES, 2 * Fp3.BYTES)); + return { x, y }; + }); + function weierstrassEquation(x) { + const { a, b } = CURVE; + const x2 = Fp3.sqr(x); + const x3 = Fp3.mul(x2, x); + return Fp3.add(Fp3.add(x3, Fp3.mul(x, a)), b); + } + if (!Fp3.eql(Fp3.sqr(CURVE.Gy), weierstrassEquation(CURVE.Gx))) + throw new Error("bad generator point: equation left != right"); + function isWithinCurveOrder(num) { + return typeof num === "bigint" && _0n9 < num && num < CURVE.n; + } + function assertGE(num) { + if (!isWithinCurveOrder(num)) + throw new Error("Expected valid bigint: 0 < bigint < curve.n"); + } + function normPrivateKeyToScalar(key) { + const { allowedPrivateKeyLengths: lengths, nByteLength, wrapPrivateKey, n } = CURVE; + if (lengths && typeof key !== "bigint") { + if (key instanceof Uint8Array) + key = bytesToHex3(key); + if (typeof key !== "string" || !lengths.includes(key.length)) + throw new Error("Invalid key"); + key = key.padStart(nByteLength * 2, "0"); + } + let num; + try { + num = typeof key === "bigint" ? key : bytesToNumberBE2(ensureBytes2("private key", key, nByteLength)); + } catch (error) { + throw new Error(`private key must be ${nByteLength} bytes, hex or bigint, not ${typeof key}`); + } + if (wrapPrivateKey) + num = mod2(num, n); + assertGE(num); + return num; + } + const pointPrecomputes = /* @__PURE__ */ new Map(); + function assertPrjPoint(other) { + if (!(other instanceof Point4)) + throw new Error("ProjectivePoint expected"); + } + class Point4 { + constructor(px, py, pz) { + this.px = px; + this.py = py; + this.pz = pz; + if (px == null || !Fp3.isValid(px)) + throw new Error("x required"); + if (py == null || !Fp3.isValid(py)) + throw new Error("y required"); + if (pz == null || !Fp3.isValid(pz)) + throw new Error("z required"); + } + static fromAffine(p) { + const { x, y } = p || {}; + if (!p || !Fp3.isValid(x) || !Fp3.isValid(y)) + throw new Error("invalid affine point"); + if (p instanceof Point4) + throw new Error("projective point not allowed"); + const is0 = (i2) => Fp3.eql(i2, Fp3.ZERO); + if (is0(x) && is0(y)) + return Point4.ZERO; + return new Point4(x, y, Fp3.ONE); + } + get x() { + return this.toAffine().x; + } + get y() { + return this.toAffine().y; + } + static normalizeZ(points) { + const toInv = Fp3.invertBatch(points.map((p) => p.pz)); + return points.map((p, i2) => p.toAffine(toInv[i2])).map(Point4.fromAffine); + } + static fromHex(hex2) { + const P = Point4.fromAffine(fromBytes(ensureBytes2("pointHex", hex2))); + P.assertValidity(); + return P; + } + static fromPrivateKey(privateKey) { + return Point4.BASE.multiply(normPrivateKeyToScalar(privateKey)); + } + _setWindowSize(windowSize) { + this._WINDOW_SIZE = windowSize; + pointPrecomputes.delete(this); + } + assertValidity() { + if (this.is0()) { + if (CURVE.allowInfinityPoint) + return; + throw new Error("bad point: ZERO"); + } + const { x, y } = this.toAffine(); + if (!Fp3.isValid(x) || !Fp3.isValid(y)) + throw new Error("bad point: x or y not FE"); + const left = Fp3.sqr(y); + const right = weierstrassEquation(x); + if (!Fp3.eql(left, right)) + throw new Error("bad point: equation left != right"); + if (!this.isTorsionFree()) + throw new Error("bad point: not in prime-order subgroup"); + } + hasEvenY() { + const { y } = this.toAffine(); + if (Fp3.isOdd) + return !Fp3.isOdd(y); + throw new Error("Field doesn't support isOdd"); + } + equals(other) { + assertPrjPoint(other); + const { px: X1, py: Y1, pz: Z1 } = this; + const { px: X2, py: Y2, pz: Z2 } = other; + const U1 = Fp3.eql(Fp3.mul(X1, Z2), Fp3.mul(X2, Z1)); + const U2 = Fp3.eql(Fp3.mul(Y1, Z2), Fp3.mul(Y2, Z1)); + return U1 && U2; + } + negate() { + return new Point4(this.px, Fp3.neg(this.py), this.pz); + } + double() { + const { a, b } = CURVE; + const b3 = Fp3.mul(b, _3n4); + const { px: X1, py: Y1, pz: Z1 } = this; + let X3 = Fp3.ZERO, Y3 = Fp3.ZERO, Z3 = Fp3.ZERO; + let t0 = Fp3.mul(X1, X1); + let t1 = Fp3.mul(Y1, Y1); + let t2 = Fp3.mul(Z1, Z1); + let t3 = Fp3.mul(X1, Y1); + t3 = Fp3.add(t3, t3); + Z3 = Fp3.mul(X1, Z1); + Z3 = Fp3.add(Z3, Z3); + X3 = Fp3.mul(a, Z3); + Y3 = Fp3.mul(b3, t2); + Y3 = Fp3.add(X3, Y3); + X3 = Fp3.sub(t1, Y3); + Y3 = Fp3.add(t1, Y3); + Y3 = Fp3.mul(X3, Y3); + X3 = Fp3.mul(t3, X3); + Z3 = Fp3.mul(b3, Z3); + t2 = Fp3.mul(a, t2); + t3 = Fp3.sub(t0, t2); + t3 = Fp3.mul(a, t3); + t3 = Fp3.add(t3, Z3); + Z3 = Fp3.add(t0, t0); + t0 = Fp3.add(Z3, t0); + t0 = Fp3.add(t0, t2); + t0 = Fp3.mul(t0, t3); + Y3 = Fp3.add(Y3, t0); + t2 = Fp3.mul(Y1, Z1); + t2 = Fp3.add(t2, t2); + t0 = Fp3.mul(t2, t3); + X3 = Fp3.sub(X3, t0); + Z3 = Fp3.mul(t2, t1); + Z3 = Fp3.add(Z3, Z3); + Z3 = Fp3.add(Z3, Z3); + return new Point4(X3, Y3, Z3); + } + add(other) { + assertPrjPoint(other); + const { px: X1, py: Y1, pz: Z1 } = this; + const { px: X2, py: Y2, pz: Z2 } = other; + let X3 = Fp3.ZERO, Y3 = Fp3.ZERO, Z3 = Fp3.ZERO; + const a = CURVE.a; + const b3 = Fp3.mul(CURVE.b, _3n4); + let t0 = Fp3.mul(X1, X2); + let t1 = Fp3.mul(Y1, Y2); + let t2 = Fp3.mul(Z1, Z2); + let t3 = Fp3.add(X1, Y1); + let t4 = Fp3.add(X2, Y2); + t3 = Fp3.mul(t3, t4); + t4 = Fp3.add(t0, t1); + t3 = Fp3.sub(t3, t4); + t4 = Fp3.add(X1, Z1); + let t5 = Fp3.add(X2, Z2); + t4 = Fp3.mul(t4, t5); + t5 = Fp3.add(t0, t2); + t4 = Fp3.sub(t4, t5); + t5 = Fp3.add(Y1, Z1); + X3 = Fp3.add(Y2, Z2); + t5 = Fp3.mul(t5, X3); + X3 = Fp3.add(t1, t2); + t5 = Fp3.sub(t5, X3); + Z3 = Fp3.mul(a, t4); + X3 = Fp3.mul(b3, t2); + Z3 = Fp3.add(X3, Z3); + X3 = Fp3.sub(t1, Z3); + Z3 = Fp3.add(t1, Z3); + Y3 = Fp3.mul(X3, Z3); + t1 = Fp3.add(t0, t0); + t1 = Fp3.add(t1, t0); + t2 = Fp3.mul(a, t2); + t4 = Fp3.mul(b3, t4); + t1 = Fp3.add(t1, t2); + t2 = Fp3.sub(t0, t2); + t2 = Fp3.mul(a, t2); + t4 = Fp3.add(t4, t2); + t0 = Fp3.mul(t1, t4); + Y3 = Fp3.add(Y3, t0); + t0 = Fp3.mul(t5, t4); + X3 = Fp3.mul(t3, X3); + X3 = Fp3.sub(X3, t0); + t0 = Fp3.mul(t3, t1); + Z3 = Fp3.mul(t5, Z3); + Z3 = Fp3.add(Z3, t0); + return new Point4(X3, Y3, Z3); + } + subtract(other) { + return this.add(other.negate()); + } + is0() { + return this.equals(Point4.ZERO); + } + wNAF(n) { + return wnaf.wNAFCached(this, pointPrecomputes, n, (comp) => { + const toInv = Fp3.invertBatch(comp.map((p) => p.pz)); + return comp.map((p, i2) => p.toAffine(toInv[i2])).map(Point4.fromAffine); + }); + } + multiplyUnsafe(n) { + const I = Point4.ZERO; + if (n === _0n9) + return I; + assertGE(n); + if (n === _1n9) + return this; + const { endo } = CURVE; + if (!endo) + return wnaf.unsafeLadder(this, n); + let { k1neg, k1, k2neg, k2 } = endo.splitScalar(n); + let k1p = I; + let k2p = I; + let d = this; + while (k1 > _0n9 || k2 > _0n9) { + if (k1 & _1n9) + k1p = k1p.add(d); + if (k2 & _1n9) + k2p = k2p.add(d); + d = d.double(); + k1 >>= _1n9; + k2 >>= _1n9; + } + if (k1neg) + k1p = k1p.negate(); + if (k2neg) + k2p = k2p.negate(); + k2p = new Point4(Fp3.mul(k2p.px, endo.beta), k2p.py, k2p.pz); + return k1p.add(k2p); + } + multiply(scalar) { + assertGE(scalar); + let n = scalar; + let point, fake; + const { endo } = CURVE; + if (endo) { + const { k1neg, k1, k2neg, k2 } = endo.splitScalar(n); + let { p: k1p, f: f1p } = this.wNAF(k1); + let { p: k2p, f: f2p } = this.wNAF(k2); + k1p = wnaf.constTimeNegate(k1neg, k1p); + k2p = wnaf.constTimeNegate(k2neg, k2p); + k2p = new Point4(Fp3.mul(k2p.px, endo.beta), k2p.py, k2p.pz); + point = k1p.add(k2p); + fake = f1p.add(f2p); + } else { + const { p, f: f2 } = this.wNAF(n); + point = p; + fake = f2; + } + return Point4.normalizeZ([point, fake])[0]; + } + multiplyAndAddUnsafe(Q, a, b) { + const G = Point4.BASE; + const mul3 = (P, a2) => a2 === _0n9 || a2 === _1n9 || !P.equals(G) ? P.multiplyUnsafe(a2) : P.multiply(a2); + const sum = mul3(this, a).add(mul3(Q, b)); + return sum.is0() ? void 0 : sum; + } + toAffine(iz) { + const { px: x, py: y, pz: z } = this; + const is0 = this.is0(); + if (iz == null) + iz = is0 ? Fp3.ONE : Fp3.inv(z); + const ax = Fp3.mul(x, iz); + const ay = Fp3.mul(y, iz); + const zz = Fp3.mul(z, iz); + if (is0) + return { x: Fp3.ZERO, y: Fp3.ZERO }; + if (!Fp3.eql(zz, Fp3.ONE)) + throw new Error("invZ was invalid"); + return { x: ax, y: ay }; + } + isTorsionFree() { + const { h: cofactor, isTorsionFree } = CURVE; + if (cofactor === _1n9) + return true; + if (isTorsionFree) + return isTorsionFree(Point4, this); + throw new Error("isTorsionFree() has not been declared for the elliptic curve"); + } + clearCofactor() { + const { h: cofactor, clearCofactor } = CURVE; + if (cofactor === _1n9) + return this; + if (clearCofactor) + return clearCofactor(Point4, this); + return this.multiplyUnsafe(CURVE.h); + } + toRawBytes(isCompressed = true) { + this.assertValidity(); + return toBytes4(Point4, this, isCompressed); + } + toHex(isCompressed = true) { + return bytesToHex3(this.toRawBytes(isCompressed)); + } + } + Point4.BASE = new Point4(CURVE.Gx, CURVE.Gy, Fp3.ONE); + Point4.ZERO = new Point4(Fp3.ZERO, Fp3.ONE, Fp3.ZERO); + const _bits = CURVE.nBitLength; + const wnaf = wNAF2(Point4, CURVE.endo ? Math.ceil(_bits / 2) : _bits); + return { + CURVE, + ProjectivePoint: Point4, + normPrivateKeyToScalar, + weierstrassEquation, + isWithinCurveOrder + }; + } + function validateOpts2(curve) { + const opts = validateBasic2(curve); + validateObject2(opts, { + hash: "hash", + hmac: "function", + randomBytes: "function" + }, { + bits2int: "function", + bits2int_modN: "function", + lowS: "boolean" + }); + return Object.freeze({ lowS: true, ...opts }); + } + function weierstrass2(curveDef) { + const CURVE = validateOpts2(curveDef); + const { Fp: Fp3, n: CURVE_ORDER } = CURVE; + const compressedLen = Fp3.BYTES + 1; + const uncompressedLen = 2 * Fp3.BYTES + 1; + function isValidFieldElement(num) { + return _0n9 < num && num < Fp3.ORDER; + } + function modN2(a) { + return mod2(a, CURVE_ORDER); + } + function invN(a) { + return invert2(a, CURVE_ORDER); + } + const { ProjectivePoint: Point4, normPrivateKeyToScalar, weierstrassEquation, isWithinCurveOrder } = weierstrassPoints2({ + ...CURVE, + toBytes(c, point, isCompressed) { + const a = point.toAffine(); + const x = Fp3.toBytes(a.x); + const cat = concatBytes4; + if (isCompressed) { + return cat(Uint8Array.from([point.hasEvenY() ? 2 : 3]), x); + } else { + return cat(Uint8Array.from([4]), x, Fp3.toBytes(a.y)); + } + }, + fromBytes(bytes4) { + const len = bytes4.length; + const head = bytes4[0]; + const tail = bytes4.subarray(1); + if (len === compressedLen && (head === 2 || head === 3)) { + const x = bytesToNumberBE2(tail); + if (!isValidFieldElement(x)) + throw new Error("Point is not on curve"); + const y2 = weierstrassEquation(x); + let y = Fp3.sqrt(y2); + const isYOdd = (y & _1n9) === _1n9; + const isHeadOdd = (head & 1) === 1; + if (isHeadOdd !== isYOdd) + y = Fp3.neg(y); + return { x, y }; + } else if (len === uncompressedLen && head === 4) { + const x = Fp3.fromBytes(tail.subarray(0, Fp3.BYTES)); + const y = Fp3.fromBytes(tail.subarray(Fp3.BYTES, 2 * Fp3.BYTES)); + return { x, y }; + } else { + throw new Error(`Point of length ${len} was invalid. Expected ${compressedLen} compressed bytes or ${uncompressedLen} uncompressed bytes`); + } + } + }); + const numToNByteStr = (num) => bytesToHex3(numberToBytesBE2(num, CURVE.nByteLength)); + function isBiggerThanHalfOrder(number4) { + const HALF = CURVE_ORDER >> _1n9; + return number4 > HALF; + } + function normalizeS(s) { + return isBiggerThanHalfOrder(s) ? modN2(-s) : s; + } + const slcNum = (b, from, to) => bytesToNumberBE2(b.slice(from, to)); + class Signature { + constructor(r, s, recovery) { + this.r = r; + this.s = s; + this.recovery = recovery; + this.assertValidity(); + } + static fromCompact(hex2) { + const l = CURVE.nByteLength; + hex2 = ensureBytes2("compactSignature", hex2, l * 2); + return new Signature(slcNum(hex2, 0, l), slcNum(hex2, l, 2 * l)); + } + static fromDER(hex2) { + const { r, s } = DER2.toSig(ensureBytes2("DER", hex2)); + return new Signature(r, s); + } + assertValidity() { + if (!isWithinCurveOrder(this.r)) + throw new Error("r must be 0 < r < CURVE.n"); + if (!isWithinCurveOrder(this.s)) + throw new Error("s must be 0 < s < CURVE.n"); + } + addRecoveryBit(recovery) { + return new Signature(this.r, this.s, recovery); + } + recoverPublicKey(msgHash) { + const { r, s, recovery: rec } = this; + const h = bits2int_modN(ensureBytes2("msgHash", msgHash)); + if (rec == null || ![0, 1, 2, 3].includes(rec)) + throw new Error("recovery id invalid"); + const radj = rec === 2 || rec === 3 ? r + CURVE.n : r; + if (radj >= Fp3.ORDER) + throw new Error("recovery id 2 or 3 invalid"); + const prefix = (rec & 1) === 0 ? "02" : "03"; + const R = Point4.fromHex(prefix + numToNByteStr(radj)); + const ir = invN(radj); + const u1 = modN2(-h * ir); + const u2 = modN2(s * ir); + const Q = Point4.BASE.multiplyAndAddUnsafe(R, u1, u2); + if (!Q) + throw new Error("point at infinify"); + Q.assertValidity(); + return Q; + } + hasHighS() { + return isBiggerThanHalfOrder(this.s); + } + normalizeS() { + return this.hasHighS() ? new Signature(this.r, modN2(-this.s), this.recovery) : this; + } + toDERRawBytes() { + return hexToBytes3(this.toDERHex()); + } + toDERHex() { + return DER2.hexFromSig({ r: this.r, s: this.s }); + } + toCompactRawBytes() { + return hexToBytes3(this.toCompactHex()); + } + toCompactHex() { + return numToNByteStr(this.r) + numToNByteStr(this.s); + } + } + const utils2 = { + isValidPrivateKey(privateKey) { + try { + normPrivateKeyToScalar(privateKey); + return true; + } catch (error) { + return false; + } + }, + normPrivateKeyToScalar, + randomPrivateKey: () => { + const rand = CURVE.randomBytes(Fp3.BYTES + 8); + const num = hashToPrivateScalar(rand, CURVE_ORDER); + return numberToBytesBE2(num, CURVE.nByteLength); + }, + precompute(windowSize = 8, point = Point4.BASE) { + point._setWindowSize(windowSize); + point.multiply(BigInt(3)); + return point; + } + }; + function getPublicKey2(privateKey, isCompressed = true) { + return Point4.fromPrivateKey(privateKey).toRawBytes(isCompressed); + } + function isProbPub(item) { + const arr = item instanceof Uint8Array; + const str = typeof item === "string"; + const len = (arr || str) && item.length; + if (arr) + return len === compressedLen || len === uncompressedLen; + if (str) + return len === 2 * compressedLen || len === 2 * uncompressedLen; + if (item instanceof Point4) + return true; + return false; + } + function getSharedSecret(privateA, publicB, isCompressed = true) { + if (isProbPub(privateA)) + throw new Error("first arg must be private key"); + if (!isProbPub(publicB)) + throw new Error("second arg must be public key"); + const b = Point4.fromHex(publicB); + return b.multiply(normPrivateKeyToScalar(privateA)).toRawBytes(isCompressed); + } + const bits2int = CURVE.bits2int || function(bytes4) { + const num = bytesToNumberBE2(bytes4); + const delta = bytes4.length * 8 - CURVE.nBitLength; + return delta > 0 ? num >> BigInt(delta) : num; + }; + const bits2int_modN = CURVE.bits2int_modN || function(bytes4) { + return modN2(bits2int(bytes4)); + }; + const ORDER_MASK = bitMask2(CURVE.nBitLength); + function int2octets(num) { + if (typeof num !== "bigint") + throw new Error("bigint expected"); + if (!(_0n9 <= num && num < ORDER_MASK)) + throw new Error(`bigint expected < 2^${CURVE.nBitLength}`); + return numberToBytesBE2(num, CURVE.nByteLength); + } + function prepSig(msgHash, privateKey, opts = defaultSigOpts) { + if (["recovered", "canonical"].some((k) => k in opts)) + throw new Error("sign() legacy options not supported"); + const { hash: hash3, randomBytes: randomBytes3 } = CURVE; + let { lowS, prehash, extraEntropy: ent } = opts; + if (lowS == null) + lowS = true; + msgHash = ensureBytes2("msgHash", msgHash); + if (prehash) + msgHash = ensureBytes2("prehashed msgHash", hash3(msgHash)); + const h1int = bits2int_modN(msgHash); + const d = normPrivateKeyToScalar(privateKey); + const seedArgs = [int2octets(d), int2octets(h1int)]; + if (ent != null) { + const e = ent === true ? randomBytes3(Fp3.BYTES) : ent; + seedArgs.push(ensureBytes2("extraEntropy", e, Fp3.BYTES)); + } + const seed = concatBytes4(...seedArgs); + const m = h1int; + function k2sig(kBytes) { + const k = bits2int(kBytes); + if (!isWithinCurveOrder(k)) + return; + const ik = invN(k); + const q = Point4.BASE.multiply(k).toAffine(); + const r = modN2(q.x); + if (r === _0n9) + return; + const s = modN2(ik * modN2(m + r * d)); + if (s === _0n9) + return; + let recovery = (q.x === r ? 0 : 2) | Number(q.y & _1n9); + let normS = s; + if (lowS && isBiggerThanHalfOrder(s)) { + normS = normalizeS(s); + recovery ^= 1; + } + return new Signature(r, normS, recovery); + } + return { seed, k2sig }; + } + const defaultSigOpts = { lowS: CURVE.lowS, prehash: false }; + const defaultVerOpts = { lowS: CURVE.lowS, prehash: false }; + function sign(msgHash, privKey, opts = defaultSigOpts) { + const { seed, k2sig } = prepSig(msgHash, privKey, opts); + const C = CURVE; + const drbg = createHmacDrbg2(C.hash.outputLen, C.nByteLength, C.hmac); + return drbg(seed, k2sig); + } + Point4.BASE._setWindowSize(8); + function verify(signature, msgHash, publicKey, opts = defaultVerOpts) { + const sg = signature; + msgHash = ensureBytes2("msgHash", msgHash); + publicKey = ensureBytes2("publicKey", publicKey); + if ("strict" in opts) + throw new Error("options.strict was renamed to lowS"); + const { lowS, prehash } = opts; + let _sig = void 0; + let P; + try { + if (typeof sg === "string" || sg instanceof Uint8Array) { + try { + _sig = Signature.fromDER(sg); + } catch (derError) { + if (!(derError instanceof DER2.Err)) + throw derError; + _sig = Signature.fromCompact(sg); + } + } else if (typeof sg === "object" && typeof sg.r === "bigint" && typeof sg.s === "bigint") { + const { r: r2, s: s2 } = sg; + _sig = new Signature(r2, s2); + } else { + throw new Error("PARSE"); + } + P = Point4.fromHex(publicKey); + } catch (error) { + if (error.message === "PARSE") + throw new Error(`signature must be Signature instance, Uint8Array or hex string`); + return false; + } + if (lowS && _sig.hasHighS()) + return false; + if (prehash) + msgHash = CURVE.hash(msgHash); + const { r, s } = _sig; + const h = bits2int_modN(msgHash); + const is = invN(s); + const u1 = modN2(h * is); + const u2 = modN2(r * is); + const R = Point4.BASE.multiplyAndAddUnsafe(P, u1, u2)?.toAffine(); + if (!R) + return false; + const v = modN2(R.x); + return v === r; + } + return { + CURVE, + getPublicKey: getPublicKey2, + getSharedSecret, + sign, + verify, + ProjectivePoint: Point4, + Signature, + utils: utils2 + }; + } + + // node_modules/@scure/bip32/node_modules/@noble/curves/esm/_shortw_utils.js + function getHash2(hash3) { + return { + hash: hash3, + hmac: (key, ...msgs) => hmac2(hash3, key, concatBytes3(...msgs)), + randomBytes: randomBytes2 + }; + } + function createCurve2(curveDef, defHash) { + const create = (hash3) => weierstrass2({ ...curveDef, ...getHash2(hash3) }); + return Object.freeze({ ...create(defHash), create }); + } + + // node_modules/@scure/bip32/node_modules/@noble/curves/esm/secp256k1.js + var secp256k1P2 = BigInt("0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f"); + var secp256k1N2 = BigInt("0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141"); + var _1n10 = BigInt(1); + var _2n8 = BigInt(2); + var divNearest2 = (a, b) => (a + b / _2n8) / b; + function sqrtMod2(y) { + const P = secp256k1P2; + const _3n5 = BigInt(3), _6n = BigInt(6), _11n = BigInt(11), _22n = BigInt(22); + const _23n = BigInt(23), _44n = BigInt(44), _88n = BigInt(88); + const b2 = y * y * y % P; + const b3 = b2 * b2 * y % P; + const b6 = pow22(b3, _3n5, P) * b3 % P; + const b9 = pow22(b6, _3n5, P) * b3 % P; + const b11 = pow22(b9, _2n8, P) * b2 % P; + const b22 = pow22(b11, _11n, P) * b11 % P; + const b44 = pow22(b22, _22n, P) * b22 % P; + const b88 = pow22(b44, _44n, P) * b44 % P; + const b176 = pow22(b88, _88n, P) * b88 % P; + const b220 = pow22(b176, _44n, P) * b44 % P; + const b223 = pow22(b220, _3n5, P) * b3 % P; + const t1 = pow22(b223, _23n, P) * b22 % P; + const t2 = pow22(t1, _6n, P) * b2 % P; + const root = pow22(t2, _2n8, P); + if (!Fp2.eql(Fp2.sqr(root), y)) + throw new Error("Cannot find square root"); + return root; + } + var Fp2 = Field2(secp256k1P2, void 0, void 0, { sqrt: sqrtMod2 }); + var secp256k12 = createCurve2({ + a: BigInt(0), + b: BigInt(7), + Fp: Fp2, + n: secp256k1N2, + Gx: BigInt("55066263022277343669578718895168534326250603453777594175500187360389116729240"), + Gy: BigInt("32670510020758816978083085130507043184471273380659243275938904335757337482424"), + h: BigInt(1), + lowS: true, + endo: { + beta: BigInt("0x7ae96a2b657c07106e64479eac3434e99cf0497512f58995c1396c28719501ee"), + splitScalar: (k) => { + const n = secp256k1N2; + const a1 = BigInt("0x3086d221a7d46bcde86c90e49284eb15"); + const b1 = -_1n10 * BigInt("0xe4437ed6010e88286f547fa90abfe4c3"); + const a2 = BigInt("0x114ca50f7a8e2f3f657c1108d9d44cfd8"); + const b2 = a1; + const POW_2_128 = BigInt("0x100000000000000000000000000000000"); + const c1 = divNearest2(b2 * k, n); + const c2 = divNearest2(-b1 * k, n); + let k1 = mod2(k - c1 * a1 - c2 * a2, n); + let k2 = mod2(-c1 * b1 - c2 * b2, n); + const k1neg = k1 > POW_2_128; + const k2neg = k2 > POW_2_128; + if (k1neg) + k1 = n - k1; + if (k2neg) + k2 = n - k2; + if (k1 > POW_2_128 || k2 > POW_2_128) { + throw new Error("splitScalar: Endomorphism failed, k=" + k); + } + return { k1neg, k1, k2neg, k2 }; + } + } + }, sha2562); + var _0n10 = BigInt(0); + var Point2 = secp256k12.ProjectivePoint; + + // node_modules/@scure/bip32/lib/esm/index.js + var Point3 = secp256k12.ProjectivePoint; + var base58check2 = base58check(sha2562); + function bytesToNumber(bytes4) { + return BigInt(`0x${bytesToHex2(bytes4)}`); + } + function numberToBytes(num) { + return hexToBytes2(num.toString(16).padStart(64, "0")); + } + var MASTER_SECRET = utf8ToBytes3("Bitcoin seed"); + var BITCOIN_VERSIONS = { private: 76066276, public: 76067358 }; + var HARDENED_OFFSET = 2147483648; + var hash160 = (data) => ripemd160(sha2562(data)); + var fromU32 = (data) => createView2(data).getUint32(0, false); + var toU32 = (n) => { + if (!Number.isSafeInteger(n) || n < 0 || n > 2 ** 32 - 1) { + throw new Error(`Invalid number=${n}. Should be from 0 to 2 ** 32 - 1`); + } + const buf = new Uint8Array(4); + createView2(buf).setUint32(0, n, false); + return buf; + }; + var HDKey = class { + get fingerprint() { + if (!this.pubHash) { + throw new Error("No publicKey set!"); + } + return fromU32(this.pubHash); + } + get identifier() { + return this.pubHash; + } + get pubKeyHash() { + return this.pubHash; + } + get privateKey() { + return this.privKeyBytes || null; + } + get publicKey() { + return this.pubKey || null; + } + get privateExtendedKey() { + const priv = this.privateKey; + if (!priv) { + throw new Error("No private key"); + } + return base58check2.encode(this.serialize(this.versions.private, concatBytes3(new Uint8Array([0]), priv))); + } + get publicExtendedKey() { + if (!this.pubKey) { + throw new Error("No public key"); + } + return base58check2.encode(this.serialize(this.versions.public, this.pubKey)); + } + static fromMasterSeed(seed, versions = BITCOIN_VERSIONS) { + bytes2(seed); + if (8 * seed.length < 128 || 8 * seed.length > 512) { + throw new Error(`HDKey: wrong seed length=${seed.length}. Should be between 128 and 512 bits; 256 bits is advised)`); + } + const I = hmac2(sha512, MASTER_SECRET, seed); + return new HDKey({ + versions, + chainCode: I.slice(32), + privateKey: I.slice(0, 32) + }); + } + static fromExtendedKey(base58key, versions = BITCOIN_VERSIONS) { + const keyBuffer = base58check2.decode(base58key); + const keyView = createView2(keyBuffer); + const version = keyView.getUint32(0, false); + const opt = { + versions, + depth: keyBuffer[4], + parentFingerprint: keyView.getUint32(5, false), + index: keyView.getUint32(9, false), + chainCode: keyBuffer.slice(13, 45) + }; + const key = keyBuffer.slice(45); + const isPriv = key[0] === 0; + if (version !== versions[isPriv ? "private" : "public"]) { + throw new Error("Version mismatch"); + } + if (isPriv) { + return new HDKey({ ...opt, privateKey: key.slice(1) }); + } else { + return new HDKey({ ...opt, publicKey: key }); + } + } + static fromJSON(json) { + return HDKey.fromExtendedKey(json.xpriv); + } + constructor(opt) { + this.depth = 0; + this.index = 0; + this.chainCode = null; + this.parentFingerprint = 0; + if (!opt || typeof opt !== "object") { + throw new Error("HDKey.constructor must not be called directly"); + } + this.versions = opt.versions || BITCOIN_VERSIONS; + this.depth = opt.depth || 0; + this.chainCode = opt.chainCode; + this.index = opt.index || 0; + this.parentFingerprint = opt.parentFingerprint || 0; + if (!this.depth) { + if (this.parentFingerprint || this.index) { + throw new Error("HDKey: zero depth with non-zero index/parent fingerprint"); + } + } + if (opt.publicKey && opt.privateKey) { + throw new Error("HDKey: publicKey and privateKey at same time."); + } + if (opt.privateKey) { + if (!secp256k12.utils.isValidPrivateKey(opt.privateKey)) { + throw new Error("Invalid private key"); + } + this.privKey = typeof opt.privateKey === "bigint" ? opt.privateKey : bytesToNumber(opt.privateKey); + this.privKeyBytes = numberToBytes(this.privKey); + this.pubKey = secp256k12.getPublicKey(opt.privateKey, true); + } else if (opt.publicKey) { + this.pubKey = Point3.fromHex(opt.publicKey).toRawBytes(true); + } else { + throw new Error("HDKey: no public or private key provided"); + } + this.pubHash = hash160(this.pubKey); + } + derive(path) { + if (!/^[mM]'?/.test(path)) { + throw new Error('Path must start with "m" or "M"'); + } + if (/^[mM]'?$/.test(path)) { + return this; + } + const parts = path.replace(/^[mM]'?\//, "").split("/"); + let child = this; + for (const c of parts) { + const m = /^(\d+)('?)$/.exec(c); + if (!m || m.length !== 3) { + throw new Error(`Invalid child index: ${c}`); + } + let idx = +m[1]; + if (!Number.isSafeInteger(idx) || idx >= HARDENED_OFFSET) { + throw new Error("Invalid index"); + } + if (m[2] === "'") { + idx += HARDENED_OFFSET; + } + child = child.deriveChild(idx); + } + return child; + } + deriveChild(index) { + if (!this.pubKey || !this.chainCode) { + throw new Error("No publicKey or chainCode set"); + } + let data = toU32(index); + if (index >= HARDENED_OFFSET) { + const priv = this.privateKey; + if (!priv) { + throw new Error("Could not derive hardened child key"); + } + data = concatBytes3(new Uint8Array([0]), priv, data); + } else { + data = concatBytes3(this.pubKey, data); + } + const I = hmac2(sha512, this.chainCode, data); + const childTweak = bytesToNumber(I.slice(0, 32)); + const chainCode = I.slice(32); + if (!secp256k12.utils.isValidPrivateKey(childTweak)) { + throw new Error("Tweak bigger than curve order"); + } + const opt = { + versions: this.versions, + chainCode, + depth: this.depth + 1, + parentFingerprint: this.fingerprint, + index + }; + try { + if (this.privateKey) { + const added = mod2(this.privKey + childTweak, secp256k12.CURVE.n); + if (!secp256k12.utils.isValidPrivateKey(added)) { + throw new Error("The tweak was out of range or the resulted private key is invalid"); + } + opt.privateKey = added; + } else { + const added = Point3.fromHex(this.pubKey).add(Point3.fromPrivateKey(childTweak)); + if (added.equals(Point3.ZERO)) { + throw new Error("The tweak was equal to negative P, which made the result key invalid"); + } + opt.publicKey = added.toRawBytes(true); + } + return new HDKey(opt); + } catch (err) { + return this.deriveChild(index + 1); + } + } + sign(hash3) { + if (!this.privateKey) { + throw new Error("No privateKey set!"); + } + bytes2(hash3, 32); + return secp256k12.sign(hash3, this.privKey).toCompactRawBytes(); + } + verify(hash3, signature) { + bytes2(hash3, 32); + bytes2(signature, 64); + if (!this.publicKey) { + throw new Error("No publicKey set!"); + } + let sig; + try { + sig = secp256k12.Signature.fromCompact(signature); + } catch (error) { + return false; + } + return secp256k12.verify(sig, hash3, this.publicKey); + } + wipePrivateData() { + this.privKey = void 0; + if (this.privKeyBytes) { + this.privKeyBytes.fill(0); + this.privKeyBytes = void 0; + } + return this; + } + toJSON() { + return { + xpriv: this.privateExtendedKey, + xpub: this.publicExtendedKey + }; + } + serialize(version, key) { + if (!this.chainCode) { + throw new Error("No chainCode set"); + } + bytes2(key, 33); + return concatBytes3(toU32(version), new Uint8Array([this.depth]), toU32(this.parentFingerprint), toU32(this.index), this.chainCode, key); + } + }; + + // nip06.ts + var DERIVATION_PATH = `m/44'/1237'`; + function privateKeyFromSeedWords(mnemonic, passphrase, accountIndex = 0) { + let root = HDKey.fromMasterSeed(mnemonicToSeedSync(mnemonic, passphrase)); + let privateKey = root.derive(`${DERIVATION_PATH}/${accountIndex}'/0/0`).privateKey; + if (!privateKey) + throw new Error("could not derive private key"); + return privateKey; + } + function accountFromSeedWords(mnemonic, passphrase, accountIndex = 0) { + const root = HDKey.fromMasterSeed(mnemonicToSeedSync(mnemonic, passphrase)); + const seed = root.derive(`${DERIVATION_PATH}/${accountIndex}'/0/0`); + const publicKey = bytesToHex2(seed.publicKey.slice(1)); + const privateKey = seed.privateKey; + if (!privateKey || !publicKey) { + throw new Error("could not derive key pair"); + } + return { privateKey, publicKey }; + } + function extendedKeysFromSeedWords(mnemonic, passphrase, extendedAccountIndex = 0) { + let root = HDKey.fromMasterSeed(mnemonicToSeedSync(mnemonic, passphrase)); + let seed = root.derive(`${DERIVATION_PATH}/${extendedAccountIndex}'`); + let privateExtendedKey = seed.privateExtendedKey; + let publicExtendedKey = seed.publicExtendedKey; + if (!privateExtendedKey && !publicExtendedKey) + throw new Error("could not derive extended key pair"); + return { privateExtendedKey, publicExtendedKey }; + } + function accountFromExtendedKey(base58key, accountIndex = 0) { + let extendedKey = HDKey.fromExtendedKey(base58key); + let version = base58key.slice(0, 4); + let child = extendedKey.deriveChild(0).deriveChild(accountIndex); + let publicKey = bytesToHex2(child.publicKey.slice(1)); + if (!publicKey) + throw new Error("could not derive public key"); + if (version === "xprv") { + let privateKey = child.privateKey; + if (!privateKey) + throw new Error("could not derive private key"); + return { privateKey, publicKey }; + } + return { publicKey }; + } + function generateSeedWords() { + return generateMnemonic(wordlist); + } + function validateWords(words) { + return validateMnemonic(words, wordlist); + } + + // nip10.ts + var nip10_exports = {}; + __export(nip10_exports, { + parse: () => parse + }); + function parse(event) { + const result = { + reply: void 0, + root: void 0, + mentions: [], + profiles: [], + quotes: [] + }; + let maybeParent; + let maybeRoot; + for (let i2 = event.tags.length - 1; i2 >= 0; i2--) { + const tag = event.tags[i2]; + if (tag[0] === "e" && tag[1]) { + const [_, eTagEventId, eTagRelayUrl, eTagMarker, eTagAuthor] = tag; + const eventPointer = { + id: eTagEventId, + relays: eTagRelayUrl ? [eTagRelayUrl] : [], + author: eTagAuthor + }; + if (eTagMarker === "root") { + result.root = eventPointer; + continue; + } + if (eTagMarker === "reply") { + result.reply = eventPointer; + continue; + } + if (eTagMarker === "mention") { + result.mentions.push(eventPointer); + continue; + } + if (!maybeParent) { + maybeParent = eventPointer; + } else { + maybeRoot = eventPointer; + } + result.mentions.push(eventPointer); + continue; + } + if (tag[0] === "q" && tag[1]) { + const [_, eTagEventId, eTagRelayUrl] = tag; + result.quotes.push({ + id: eTagEventId, + relays: eTagRelayUrl ? [eTagRelayUrl] : [] + }); + } + if (tag[0] === "p" && tag[1]) { + result.profiles.push({ + pubkey: tag[1], + relays: tag[2] ? [tag[2]] : [] + }); + continue; + } + } + if (!result.root) { + result.root = maybeRoot || maybeParent || result.reply; + } + if (!result.reply) { + result.reply = maybeParent || result.root; + } + ; + [result.reply, result.root].forEach((ref) => { + if (!ref) + return; + let idx = result.mentions.indexOf(ref); + if (idx !== -1) { + result.mentions.splice(idx, 1); + } + if (ref.author) { + let author = result.profiles.find((p) => p.pubkey === ref.author); + if (author && author.relays) { + if (!ref.relays) { + ref.relays = []; + } + author.relays.forEach((url) => { + if (ref.relays?.indexOf(url) === -1) + ref.relays.push(url); + }); + author.relays = ref.relays; + } + } + }); + result.mentions.forEach((ref) => { + if (ref.author) { + let author = result.profiles.find((p) => p.pubkey === ref.author); + if (author && author.relays) { + if (!ref.relays) { + ref.relays = []; + } + author.relays.forEach((url) => { + if (ref.relays.indexOf(url) === -1) + ref.relays.push(url); + }); + author.relays = ref.relays; + } + } + }); + return result; + } + + // nip11.ts + var nip11_exports = {}; + __export(nip11_exports, { + fetchRelayInformation: () => fetchRelayInformation, + useFetchImplementation: () => useFetchImplementation2 + }); + var _fetch2; + try { + _fetch2 = fetch; + } catch { + } + function useFetchImplementation2(fetchImplementation) { + _fetch2 = fetchImplementation; + } + async function fetchRelayInformation(url) { + return await (await fetch(url.replace("ws://", "http://").replace("wss://", "https://"), { + headers: { Accept: "application/nostr+json" } + })).json(); + } + + // nip13.ts + var nip13_exports = {}; + __export(nip13_exports, { + fastEventHash: () => fastEventHash, + getPow: () => getPow, + minePow: () => minePow + }); + function getPow(hex2) { + let count = 0; + for (let i2 = 0; i2 < 64; i2 += 8) { + const nibble = parseInt(hex2.substring(i2, i2 + 8), 16); + if (nibble === 0) { + count += 32; + } else { + count += Math.clz32(nibble); + break; + } + } + return count; + } + function minePow(unsigned, difficulty) { + let count = 0; + const event = unsigned; + const tag = ["nonce", count.toString(), difficulty.toString()]; + event.tags.push(tag); + while (true) { + const now2 = Math.floor(new Date().getTime() / 1e3); + if (now2 !== event.created_at) { + count = 0; + event.created_at = now2; + } + tag[1] = (++count).toString(); + event.id = fastEventHash(event); + if (getPow(event.id) >= difficulty) { + break; + } + } + return event; + } + function fastEventHash(evt) { + return bytesToHex2( + sha2562(utf8Encoder.encode(JSON.stringify([0, evt.pubkey, evt.created_at, evt.kind, evt.tags, evt.content]))) + ); + } + + // nip17.ts + var nip17_exports = {}; + __export(nip17_exports, { + unwrapEvent: () => unwrapEvent2, + unwrapManyEvents: () => unwrapManyEvents2, + wrapEvent: () => wrapEvent2, + wrapManyEvents: () => wrapManyEvents2 + }); + + // nip59.ts + var nip59_exports = {}; + __export(nip59_exports, { + createRumor: () => createRumor, + createSeal: () => createSeal, + createWrap: () => createWrap, + unwrapEvent: () => unwrapEvent, + unwrapManyEvents: () => unwrapManyEvents, + wrapEvent: () => wrapEvent, + wrapManyEvents: () => wrapManyEvents + }); + + // nip44.ts + var nip44_exports = {}; + __export(nip44_exports, { + decrypt: () => decrypt3, + encrypt: () => encrypt3, + getConversationKey: () => getConversationKey, + v2: () => v2 + }); + + // node_modules/@noble/ciphers/esm/_poly1305.js + var u8to16 = (a, i2) => a[i2++] & 255 | (a[i2++] & 255) << 8; + var Poly1305 = class { + constructor(key) { + this.blockLen = 16; + this.outputLen = 16; + this.buffer = new Uint8Array(16); + this.r = new Uint16Array(10); + this.h = new Uint16Array(10); + this.pad = new Uint16Array(8); + this.pos = 0; + this.finished = false; + key = toBytes3(key); + bytes3(key, 32); + const t0 = u8to16(key, 0); + const t1 = u8to16(key, 2); + const t2 = u8to16(key, 4); + const t3 = u8to16(key, 6); + const t4 = u8to16(key, 8); + const t5 = u8to16(key, 10); + const t6 = u8to16(key, 12); + const t7 = u8to16(key, 14); + this.r[0] = t0 & 8191; + this.r[1] = (t0 >>> 13 | t1 << 3) & 8191; + this.r[2] = (t1 >>> 10 | t2 << 6) & 7939; + this.r[3] = (t2 >>> 7 | t3 << 9) & 8191; + this.r[4] = (t3 >>> 4 | t4 << 12) & 255; + this.r[5] = t4 >>> 1 & 8190; + this.r[6] = (t4 >>> 14 | t5 << 2) & 8191; + this.r[7] = (t5 >>> 11 | t6 << 5) & 8065; + this.r[8] = (t6 >>> 8 | t7 << 8) & 8191; + this.r[9] = t7 >>> 5 & 127; + for (let i2 = 0; i2 < 8; i2++) + this.pad[i2] = u8to16(key, 16 + 2 * i2); + } + process(data, offset, isLast = false) { + const hibit = isLast ? 0 : 1 << 11; + const { h, r } = this; + const r0 = r[0]; + const r1 = r[1]; + const r2 = r[2]; + const r3 = r[3]; + const r4 = r[4]; + const r5 = r[5]; + const r6 = r[6]; + const r7 = r[7]; + const r8 = r[8]; + const r9 = r[9]; + const t0 = u8to16(data, offset + 0); + const t1 = u8to16(data, offset + 2); + const t2 = u8to16(data, offset + 4); + const t3 = u8to16(data, offset + 6); + const t4 = u8to16(data, offset + 8); + const t5 = u8to16(data, offset + 10); + const t6 = u8to16(data, offset + 12); + const t7 = u8to16(data, offset + 14); + let h0 = h[0] + (t0 & 8191); + let h1 = h[1] + ((t0 >>> 13 | t1 << 3) & 8191); + let h2 = h[2] + ((t1 >>> 10 | t2 << 6) & 8191); + let h3 = h[3] + ((t2 >>> 7 | t3 << 9) & 8191); + let h4 = h[4] + ((t3 >>> 4 | t4 << 12) & 8191); + let h5 = h[5] + (t4 >>> 1 & 8191); + let h6 = h[6] + ((t4 >>> 14 | t5 << 2) & 8191); + let h7 = h[7] + ((t5 >>> 11 | t6 << 5) & 8191); + let h8 = h[8] + ((t6 >>> 8 | t7 << 8) & 8191); + let h9 = h[9] + (t7 >>> 5 | hibit); + let c = 0; + let d0 = c + h0 * r0 + h1 * (5 * r9) + h2 * (5 * r8) + h3 * (5 * r7) + h4 * (5 * r6); + c = d0 >>> 13; + d0 &= 8191; + d0 += h5 * (5 * r5) + h6 * (5 * r4) + h7 * (5 * r3) + h8 * (5 * r2) + h9 * (5 * r1); + c += d0 >>> 13; + d0 &= 8191; + let d1 = c + h0 * r1 + h1 * r0 + h2 * (5 * r9) + h3 * (5 * r8) + h4 * (5 * r7); + c = d1 >>> 13; + d1 &= 8191; + d1 += h5 * (5 * r6) + h6 * (5 * r5) + h7 * (5 * r4) + h8 * (5 * r3) + h9 * (5 * r2); + c += d1 >>> 13; + d1 &= 8191; + let d2 = c + h0 * r2 + h1 * r1 + h2 * r0 + h3 * (5 * r9) + h4 * (5 * r8); + c = d2 >>> 13; + d2 &= 8191; + d2 += h5 * (5 * r7) + h6 * (5 * r6) + h7 * (5 * r5) + h8 * (5 * r4) + h9 * (5 * r3); + c += d2 >>> 13; + d2 &= 8191; + let d3 = c + h0 * r3 + h1 * r2 + h2 * r1 + h3 * r0 + h4 * (5 * r9); + c = d3 >>> 13; + d3 &= 8191; + d3 += h5 * (5 * r8) + h6 * (5 * r7) + h7 * (5 * r6) + h8 * (5 * r5) + h9 * (5 * r4); + c += d3 >>> 13; + d3 &= 8191; + let d4 = c + h0 * r4 + h1 * r3 + h2 * r2 + h3 * r1 + h4 * r0; + c = d4 >>> 13; + d4 &= 8191; + d4 += h5 * (5 * r9) + h6 * (5 * r8) + h7 * (5 * r7) + h8 * (5 * r6) + h9 * (5 * r5); + c += d4 >>> 13; + d4 &= 8191; + let d5 = c + h0 * r5 + h1 * r4 + h2 * r3 + h3 * r2 + h4 * r1; + c = d5 >>> 13; + d5 &= 8191; + d5 += h5 * r0 + h6 * (5 * r9) + h7 * (5 * r8) + h8 * (5 * r7) + h9 * (5 * r6); + c += d5 >>> 13; + d5 &= 8191; + let d6 = c + h0 * r6 + h1 * r5 + h2 * r4 + h3 * r3 + h4 * r2; + c = d6 >>> 13; + d6 &= 8191; + d6 += h5 * r1 + h6 * r0 + h7 * (5 * r9) + h8 * (5 * r8) + h9 * (5 * r7); + c += d6 >>> 13; + d6 &= 8191; + let d7 = c + h0 * r7 + h1 * r6 + h2 * r5 + h3 * r4 + h4 * r3; + c = d7 >>> 13; + d7 &= 8191; + d7 += h5 * r2 + h6 * r1 + h7 * r0 + h8 * (5 * r9) + h9 * (5 * r8); + c += d7 >>> 13; + d7 &= 8191; + let d8 = c + h0 * r8 + h1 * r7 + h2 * r6 + h3 * r5 + h4 * r4; + c = d8 >>> 13; + d8 &= 8191; + d8 += h5 * r3 + h6 * r2 + h7 * r1 + h8 * r0 + h9 * (5 * r9); + c += d8 >>> 13; + d8 &= 8191; + let d9 = c + h0 * r9 + h1 * r8 + h2 * r7 + h3 * r6 + h4 * r5; + c = d9 >>> 13; + d9 &= 8191; + d9 += h5 * r4 + h6 * r3 + h7 * r2 + h8 * r1 + h9 * r0; + c += d9 >>> 13; + d9 &= 8191; + c = (c << 2) + c | 0; + c = c + d0 | 0; + d0 = c & 8191; + c = c >>> 13; + d1 += c; + h[0] = d0; + h[1] = d1; + h[2] = d2; + h[3] = d3; + h[4] = d4; + h[5] = d5; + h[6] = d6; + h[7] = d7; + h[8] = d8; + h[9] = d9; + } + finalize() { + const { h, pad: pad2 } = this; + const g = new Uint16Array(10); + let c = h[1] >>> 13; + h[1] &= 8191; + for (let i2 = 2; i2 < 10; i2++) { + h[i2] += c; + c = h[i2] >>> 13; + h[i2] &= 8191; + } + h[0] += c * 5; + c = h[0] >>> 13; + h[0] &= 8191; + h[1] += c; + c = h[1] >>> 13; + h[1] &= 8191; + h[2] += c; + g[0] = h[0] + 5; + c = g[0] >>> 13; + g[0] &= 8191; + for (let i2 = 1; i2 < 10; i2++) { + g[i2] = h[i2] + c; + c = g[i2] >>> 13; + g[i2] &= 8191; + } + g[9] -= 1 << 13; + let mask = (c ^ 1) - 1; + for (let i2 = 0; i2 < 10; i2++) + g[i2] &= mask; + mask = ~mask; + for (let i2 = 0; i2 < 10; i2++) + h[i2] = h[i2] & mask | g[i2]; + h[0] = (h[0] | h[1] << 13) & 65535; + h[1] = (h[1] >>> 3 | h[2] << 10) & 65535; + h[2] = (h[2] >>> 6 | h[3] << 7) & 65535; + h[3] = (h[3] >>> 9 | h[4] << 4) & 65535; + h[4] = (h[4] >>> 12 | h[5] << 1 | h[6] << 14) & 65535; + h[5] = (h[6] >>> 2 | h[7] << 11) & 65535; + h[6] = (h[7] >>> 5 | h[8] << 8) & 65535; + h[7] = (h[8] >>> 8 | h[9] << 5) & 65535; + let f2 = h[0] + pad2[0]; + h[0] = f2 & 65535; + for (let i2 = 1; i2 < 8; i2++) { + f2 = (h[i2] + pad2[i2] | 0) + (f2 >>> 16) | 0; + h[i2] = f2 & 65535; + } + } + update(data) { + exists3(this); + const { buffer, blockLen } = this; + data = toBytes3(data); + const len = data.length; + for (let pos = 0; pos < len; ) { + const take = Math.min(blockLen - this.pos, len - pos); + if (take === blockLen) { + for (; blockLen <= len - pos; pos += blockLen) + this.process(data, pos); + continue; + } + buffer.set(data.subarray(pos, pos + take), this.pos); + this.pos += take; + pos += take; + if (this.pos === blockLen) { + this.process(buffer, 0, false); + this.pos = 0; + } + } + return this; + } + destroy() { + this.h.fill(0); + this.r.fill(0); + this.buffer.fill(0); + this.pad.fill(0); + } + digestInto(out) { + exists3(this); + output3(out, this); + this.finished = true; + const { buffer, h } = this; + let { pos } = this; + if (pos) { + buffer[pos++] = 1; + for (; pos < 16; pos++) + buffer[pos] = 0; + this.process(buffer, 0, true); + } + this.finalize(); + let opos = 0; + for (let i2 = 0; i2 < 8; i2++) { + out[opos++] = h[i2] >>> 0; + out[opos++] = h[i2] >>> 8; + } + return out; + } + digest() { + const { buffer, outputLen } = this; + this.digestInto(buffer); + const res = buffer.slice(0, outputLen); + this.destroy(); + return res; + } + }; + function wrapConstructorWithKey2(hashCons) { + const hashC = (msg, key) => hashCons(key).update(toBytes3(msg)).digest(); + const tmp = hashCons(new Uint8Array(32)); + hashC.outputLen = tmp.outputLen; + hashC.blockLen = tmp.blockLen; + hashC.create = (key) => hashCons(key); + return hashC; + } + var poly1305 = wrapConstructorWithKey2((key) => new Poly1305(key)); + + // node_modules/@noble/ciphers/esm/_arx.js + var _utf8ToBytes = (str) => Uint8Array.from(str.split("").map((c) => c.charCodeAt(0))); + var sigma16 = _utf8ToBytes("expand 16-byte k"); + var sigma32 = _utf8ToBytes("expand 32-byte k"); + var sigma16_32 = u32(sigma16); + var sigma32_32 = u32(sigma32); + var sigma = sigma32_32.slice(); + function rotl2(a, b) { + return a << b | a >>> 32 - b; + } + function isAligned32(b) { + return b.byteOffset % 4 === 0; + } + var BLOCK_LEN = 64; + var BLOCK_LEN32 = 16; + var MAX_COUNTER = 2 ** 32 - 1; + var U32_EMPTY = new Uint32Array(); + function runCipher(core, sigma2, key, nonce, data, output4, counter, rounds) { + const len = data.length; + const block = new Uint8Array(BLOCK_LEN); + const b32 = u32(block); + const isAligned = isAligned32(data) && isAligned32(output4); + const d32 = isAligned ? u32(data) : U32_EMPTY; + const o32 = isAligned ? u32(output4) : U32_EMPTY; + for (let pos = 0; pos < len; counter++) { + core(sigma2, key, nonce, b32, counter, rounds); + if (counter >= MAX_COUNTER) + throw new Error("arx: counter overflow"); + const take = Math.min(BLOCK_LEN, len - pos); + if (isAligned && take === BLOCK_LEN) { + const pos32 = pos / 4; + if (pos % 4 !== 0) + throw new Error("arx: invalid block position"); + for (let j = 0, posj; j < BLOCK_LEN32; j++) { + posj = pos32 + j; + o32[posj] = d32[posj] ^ b32[j]; + } + pos += BLOCK_LEN; + continue; + } + for (let j = 0, posj; j < take; j++) { + posj = pos + j; + output4[posj] = data[posj] ^ block[j]; + } + pos += take; + } + } + function createCipher(core, opts) { + const { allowShortKeys, extendNonceFn, counterLength, counterRight, rounds } = checkOpts2({ allowShortKeys: false, counterLength: 8, counterRight: false, rounds: 20 }, opts); + if (typeof core !== "function") + throw new Error("core must be a function"); + number3(counterLength); + number3(rounds); + bool2(counterRight); + bool2(allowShortKeys); + return (key, nonce, data, output4, counter = 0) => { + bytes3(key); + bytes3(nonce); + bytes3(data); + const len = data.length; + if (!output4) + output4 = new Uint8Array(len); + bytes3(output4); + number3(counter); + if (counter < 0 || counter >= MAX_COUNTER) + throw new Error("arx: counter overflow"); + if (output4.length < len) + throw new Error(`arx: output (${output4.length}) is shorter than data (${len})`); + const toClean = []; + let l = key.length, k, sigma2; + if (l === 32) { + k = key.slice(); + toClean.push(k); + sigma2 = sigma32_32; + } else if (l === 16 && allowShortKeys) { + k = new Uint8Array(32); + k.set(key); + k.set(key, 16); + sigma2 = sigma16_32; + toClean.push(k); + } else { + throw new Error(`arx: invalid 32-byte key, got length=${l}`); + } + if (!isAligned32(nonce)) { + nonce = nonce.slice(); + toClean.push(nonce); + } + const k32 = u32(k); + if (extendNonceFn) { + if (nonce.length !== 24) + throw new Error(`arx: extended nonce must be 24 bytes`); + extendNonceFn(sigma2, k32, u32(nonce.subarray(0, 16)), k32); + nonce = nonce.subarray(16); + } + const nonceNcLen = 16 - counterLength; + if (nonceNcLen !== nonce.length) + throw new Error(`arx: nonce must be ${nonceNcLen} or 16 bytes`); + if (nonceNcLen !== 12) { + const nc = new Uint8Array(12); + nc.set(nonce, counterRight ? 0 : 12 - nonce.length); + nonce = nc; + toClean.push(nonce); + } + const n32 = u32(nonce); + runCipher(core, sigma2, k32, n32, data, output4, counter, rounds); + while (toClean.length > 0) + toClean.pop().fill(0); + return output4; + }; + } + + // node_modules/@noble/ciphers/esm/chacha.js + function chachaCore(s, k, n, out, cnt, rounds = 20) { + let y00 = s[0], y01 = s[1], y02 = s[2], y03 = s[3], y04 = k[0], y05 = k[1], y06 = k[2], y07 = k[3], y08 = k[4], y09 = k[5], y10 = k[6], y11 = k[7], y12 = cnt, y13 = n[0], y14 = n[1], y15 = n[2]; + let x00 = y00, x01 = y01, x02 = y02, x03 = y03, x04 = y04, x05 = y05, x06 = y06, x07 = y07, x08 = y08, x09 = y09, x10 = y10, x11 = y11, x12 = y12, x13 = y13, x14 = y14, x15 = y15; + for (let r = 0; r < rounds; r += 2) { + x00 = x00 + x04 | 0; + x12 = rotl2(x12 ^ x00, 16); + x08 = x08 + x12 | 0; + x04 = rotl2(x04 ^ x08, 12); + x00 = x00 + x04 | 0; + x12 = rotl2(x12 ^ x00, 8); + x08 = x08 + x12 | 0; + x04 = rotl2(x04 ^ x08, 7); + x01 = x01 + x05 | 0; + x13 = rotl2(x13 ^ x01, 16); + x09 = x09 + x13 | 0; + x05 = rotl2(x05 ^ x09, 12); + x01 = x01 + x05 | 0; + x13 = rotl2(x13 ^ x01, 8); + x09 = x09 + x13 | 0; + x05 = rotl2(x05 ^ x09, 7); + x02 = x02 + x06 | 0; + x14 = rotl2(x14 ^ x02, 16); + x10 = x10 + x14 | 0; + x06 = rotl2(x06 ^ x10, 12); + x02 = x02 + x06 | 0; + x14 = rotl2(x14 ^ x02, 8); + x10 = x10 + x14 | 0; + x06 = rotl2(x06 ^ x10, 7); + x03 = x03 + x07 | 0; + x15 = rotl2(x15 ^ x03, 16); + x11 = x11 + x15 | 0; + x07 = rotl2(x07 ^ x11, 12); + x03 = x03 + x07 | 0; + x15 = rotl2(x15 ^ x03, 8); + x11 = x11 + x15 | 0; + x07 = rotl2(x07 ^ x11, 7); + x00 = x00 + x05 | 0; + x15 = rotl2(x15 ^ x00, 16); + x10 = x10 + x15 | 0; + x05 = rotl2(x05 ^ x10, 12); + x00 = x00 + x05 | 0; + x15 = rotl2(x15 ^ x00, 8); + x10 = x10 + x15 | 0; + x05 = rotl2(x05 ^ x10, 7); + x01 = x01 + x06 | 0; + x12 = rotl2(x12 ^ x01, 16); + x11 = x11 + x12 | 0; + x06 = rotl2(x06 ^ x11, 12); + x01 = x01 + x06 | 0; + x12 = rotl2(x12 ^ x01, 8); + x11 = x11 + x12 | 0; + x06 = rotl2(x06 ^ x11, 7); + x02 = x02 + x07 | 0; + x13 = rotl2(x13 ^ x02, 16); + x08 = x08 + x13 | 0; + x07 = rotl2(x07 ^ x08, 12); + x02 = x02 + x07 | 0; + x13 = rotl2(x13 ^ x02, 8); + x08 = x08 + x13 | 0; + x07 = rotl2(x07 ^ x08, 7); + x03 = x03 + x04 | 0; + x14 = rotl2(x14 ^ x03, 16); + x09 = x09 + x14 | 0; + x04 = rotl2(x04 ^ x09, 12); + x03 = x03 + x04 | 0; + x14 = rotl2(x14 ^ x03, 8); + x09 = x09 + x14 | 0; + x04 = rotl2(x04 ^ x09, 7); + } + let oi = 0; + out[oi++] = y00 + x00 | 0; + out[oi++] = y01 + x01 | 0; + out[oi++] = y02 + x02 | 0; + out[oi++] = y03 + x03 | 0; + out[oi++] = y04 + x04 | 0; + out[oi++] = y05 + x05 | 0; + out[oi++] = y06 + x06 | 0; + out[oi++] = y07 + x07 | 0; + out[oi++] = y08 + x08 | 0; + out[oi++] = y09 + x09 | 0; + out[oi++] = y10 + x10 | 0; + out[oi++] = y11 + x11 | 0; + out[oi++] = y12 + x12 | 0; + out[oi++] = y13 + x13 | 0; + out[oi++] = y14 + x14 | 0; + out[oi++] = y15 + x15 | 0; + } + function hchacha(s, k, i2, o32) { + let x00 = s[0], x01 = s[1], x02 = s[2], x03 = s[3], x04 = k[0], x05 = k[1], x06 = k[2], x07 = k[3], x08 = k[4], x09 = k[5], x10 = k[6], x11 = k[7], x12 = i2[0], x13 = i2[1], x14 = i2[2], x15 = i2[3]; + for (let r = 0; r < 20; r += 2) { + x00 = x00 + x04 | 0; + x12 = rotl2(x12 ^ x00, 16); + x08 = x08 + x12 | 0; + x04 = rotl2(x04 ^ x08, 12); + x00 = x00 + x04 | 0; + x12 = rotl2(x12 ^ x00, 8); + x08 = x08 + x12 | 0; + x04 = rotl2(x04 ^ x08, 7); + x01 = x01 + x05 | 0; + x13 = rotl2(x13 ^ x01, 16); + x09 = x09 + x13 | 0; + x05 = rotl2(x05 ^ x09, 12); + x01 = x01 + x05 | 0; + x13 = rotl2(x13 ^ x01, 8); + x09 = x09 + x13 | 0; + x05 = rotl2(x05 ^ x09, 7); + x02 = x02 + x06 | 0; + x14 = rotl2(x14 ^ x02, 16); + x10 = x10 + x14 | 0; + x06 = rotl2(x06 ^ x10, 12); + x02 = x02 + x06 | 0; + x14 = rotl2(x14 ^ x02, 8); + x10 = x10 + x14 | 0; + x06 = rotl2(x06 ^ x10, 7); + x03 = x03 + x07 | 0; + x15 = rotl2(x15 ^ x03, 16); + x11 = x11 + x15 | 0; + x07 = rotl2(x07 ^ x11, 12); + x03 = x03 + x07 | 0; + x15 = rotl2(x15 ^ x03, 8); + x11 = x11 + x15 | 0; + x07 = rotl2(x07 ^ x11, 7); + x00 = x00 + x05 | 0; + x15 = rotl2(x15 ^ x00, 16); + x10 = x10 + x15 | 0; + x05 = rotl2(x05 ^ x10, 12); + x00 = x00 + x05 | 0; + x15 = rotl2(x15 ^ x00, 8); + x10 = x10 + x15 | 0; + x05 = rotl2(x05 ^ x10, 7); + x01 = x01 + x06 | 0; + x12 = rotl2(x12 ^ x01, 16); + x11 = x11 + x12 | 0; + x06 = rotl2(x06 ^ x11, 12); + x01 = x01 + x06 | 0; + x12 = rotl2(x12 ^ x01, 8); + x11 = x11 + x12 | 0; + x06 = rotl2(x06 ^ x11, 7); + x02 = x02 + x07 | 0; + x13 = rotl2(x13 ^ x02, 16); + x08 = x08 + x13 | 0; + x07 = rotl2(x07 ^ x08, 12); + x02 = x02 + x07 | 0; + x13 = rotl2(x13 ^ x02, 8); + x08 = x08 + x13 | 0; + x07 = rotl2(x07 ^ x08, 7); + x03 = x03 + x04 | 0; + x14 = rotl2(x14 ^ x03, 16); + x09 = x09 + x14 | 0; + x04 = rotl2(x04 ^ x09, 12); + x03 = x03 + x04 | 0; + x14 = rotl2(x14 ^ x03, 8); + x09 = x09 + x14 | 0; + x04 = rotl2(x04 ^ x09, 7); + } + let oi = 0; + o32[oi++] = x00; + o32[oi++] = x01; + o32[oi++] = x02; + o32[oi++] = x03; + o32[oi++] = x12; + o32[oi++] = x13; + o32[oi++] = x14; + o32[oi++] = x15; + } + var chacha20 = /* @__PURE__ */ createCipher(chachaCore, { + counterRight: false, + counterLength: 4, + allowShortKeys: false + }); + var xchacha20 = /* @__PURE__ */ createCipher(chachaCore, { + counterRight: false, + counterLength: 8, + extendNonceFn: hchacha, + allowShortKeys: false + }); + var ZEROS162 = /* @__PURE__ */ new Uint8Array(16); + var updatePadded = (h, msg) => { + h.update(msg); + const left = msg.length % 16; + if (left) + h.update(ZEROS162.subarray(left)); + }; + var ZEROS322 = /* @__PURE__ */ new Uint8Array(32); + function computeTag2(fn, key, nonce, data, AAD) { + const authKey = fn(key, nonce, ZEROS322); + const h = poly1305.create(authKey); + if (AAD) + updatePadded(h, AAD); + updatePadded(h, data); + const num = new Uint8Array(16); + const view = createView3(num); + setBigUint643(view, 0, BigInt(AAD ? AAD.length : 0), true); + setBigUint643(view, 8, BigInt(data.length), true); + h.update(num); + const res = h.digest(); + authKey.fill(0); + return res; + } + var _poly1305_aead = (xorStream) => (key, nonce, AAD) => { + const tagLength = 16; + bytes3(key, 32); + bytes3(nonce); + return { + encrypt: (plaintext, output4) => { + const plength = plaintext.length; + const clength = plength + tagLength; + if (output4) { + bytes3(output4, clength); + } else { + output4 = new Uint8Array(clength); + } + xorStream(key, nonce, plaintext, output4, 1); + const tag = computeTag2(xorStream, key, nonce, output4.subarray(0, -tagLength), AAD); + output4.set(tag, plength); + return output4; + }, + decrypt: (ciphertext, output4) => { + const clength = ciphertext.length; + const plength = clength - tagLength; + if (clength < tagLength) + throw new Error(`encrypted data must be at least ${tagLength} bytes`); + if (output4) { + bytes3(output4, plength); + } else { + output4 = new Uint8Array(plength); + } + const data = ciphertext.subarray(0, -tagLength); + const passedTag = ciphertext.subarray(-tagLength); + const tag = computeTag2(xorStream, key, nonce, data, AAD); + if (!equalBytes2(passedTag, tag)) + throw new Error("invalid tag"); + xorStream(key, nonce, data, output4, 1); + return output4; + } + }; + }; + var chacha20poly1305 = /* @__PURE__ */ wrapCipher({ blockSize: 64, nonceLength: 12, tagLength: 16 }, _poly1305_aead(chacha20)); + var xchacha20poly1305 = /* @__PURE__ */ wrapCipher({ blockSize: 64, nonceLength: 24, tagLength: 16 }, _poly1305_aead(xchacha20)); + + // node_modules/@noble/hashes/esm/hkdf.js + function extract(hash3, ikm, salt2) { + assert_default.hash(hash3); + if (salt2 === void 0) + salt2 = new Uint8Array(hash3.outputLen); + return hmac2(hash3, toBytes2(salt2), toBytes2(ikm)); + } + var HKDF_COUNTER = new Uint8Array([0]); + var EMPTY_BUFFER = new Uint8Array(); + function expand(hash3, prk, info, length = 32) { + assert_default.hash(hash3); + assert_default.number(length); + if (length > 255 * hash3.outputLen) + throw new Error("Length should be <= 255*HashLen"); + const blocks = Math.ceil(length / hash3.outputLen); + if (info === void 0) + info = EMPTY_BUFFER; + const okm = new Uint8Array(blocks * hash3.outputLen); + const HMAC3 = hmac2.create(hash3, prk); + const HMACTmp = HMAC3._cloneInto(); + const T = new Uint8Array(HMAC3.outputLen); + for (let counter = 0; counter < blocks; counter++) { + HKDF_COUNTER[0] = counter + 1; + HMACTmp.update(counter === 0 ? EMPTY_BUFFER : T).update(info).update(HKDF_COUNTER).digestInto(T); + okm.set(T, hash3.outputLen * counter); + HMAC3._cloneInto(HMACTmp); + } + HMAC3.destroy(); + HMACTmp.destroy(); + T.fill(0); + HKDF_COUNTER.fill(0); + return okm.slice(0, length); + } + + // nip44.ts + var minPlaintextSize = 1; + var maxPlaintextSize = 65535; + function getConversationKey(privkeyA, pubkeyB) { + const sharedX = secp256k1.getSharedSecret(privkeyA, "02" + pubkeyB).subarray(1, 33); + return extract(sha2562, sharedX, "nip44-v2"); + } + function getMessageKeys(conversationKey, nonce) { + const keys = expand(sha2562, conversationKey, nonce, 76); + return { + chacha_key: keys.subarray(0, 32), + chacha_nonce: keys.subarray(32, 44), + hmac_key: keys.subarray(44, 76) + }; + } + function calcPaddedLen(len) { + if (!Number.isSafeInteger(len) || len < 1) + throw new Error("expected positive integer"); + if (len <= 32) + return 32; + const nextPower = 1 << Math.floor(Math.log2(len - 1)) + 1; + const chunk = nextPower <= 256 ? 32 : nextPower / 8; + return chunk * (Math.floor((len - 1) / chunk) + 1); + } + function writeU16BE(num) { + if (!Number.isSafeInteger(num) || num < minPlaintextSize || num > maxPlaintextSize) + throw new Error("invalid plaintext size: must be between 1 and 65535 bytes"); + const arr = new Uint8Array(2); + new DataView(arr.buffer).setUint16(0, num, false); + return arr; + } + function pad(plaintext) { + const unpadded = utf8Encoder.encode(plaintext); + const unpaddedLen = unpadded.length; + const prefix = writeU16BE(unpaddedLen); + const suffix = new Uint8Array(calcPaddedLen(unpaddedLen) - unpaddedLen); + return concatBytes3(prefix, unpadded, suffix); + } + function unpad(padded) { + const unpaddedLen = new DataView(padded.buffer).getUint16(0); + const unpadded = padded.subarray(2, 2 + unpaddedLen); + if (unpaddedLen < minPlaintextSize || unpaddedLen > maxPlaintextSize || unpadded.length !== unpaddedLen || padded.length !== 2 + calcPaddedLen(unpaddedLen)) + throw new Error("invalid padding"); + return utf8Decoder.decode(unpadded); + } + function hmacAad(key, message, aad) { + if (aad.length !== 32) + throw new Error("AAD associated data must be 32 bytes"); + const combined = concatBytes3(aad, message); + return hmac2(sha2562, key, combined); + } + function decodePayload(payload) { + if (typeof payload !== "string") + throw new Error("payload must be a valid string"); + const plen = payload.length; + if (plen < 132 || plen > 87472) + throw new Error("invalid payload length: " + plen); + if (payload[0] === "#") + throw new Error("unknown encryption version"); + let data; + try { + data = base64.decode(payload); + } catch (error) { + throw new Error("invalid base64: " + error.message); + } + const dlen = data.length; + if (dlen < 99 || dlen > 65603) + throw new Error("invalid data length: " + dlen); + const vers = data[0]; + if (vers !== 2) + throw new Error("unknown encryption version " + vers); + return { + nonce: data.subarray(1, 33), + ciphertext: data.subarray(33, -32), + mac: data.subarray(-32) + }; + } + function encrypt3(plaintext, conversationKey, nonce = randomBytes2(32)) { + const { chacha_key, chacha_nonce, hmac_key } = getMessageKeys(conversationKey, nonce); + const padded = pad(plaintext); + const ciphertext = chacha20(chacha_key, chacha_nonce, padded); + const mac = hmacAad(hmac_key, ciphertext, nonce); + return base64.encode(concatBytes3(new Uint8Array([2]), nonce, ciphertext, mac)); + } + function decrypt3(payload, conversationKey) { + const { nonce, ciphertext, mac } = decodePayload(payload); + const { chacha_key, chacha_nonce, hmac_key } = getMessageKeys(conversationKey, nonce); + const calculatedMac = hmacAad(hmac_key, ciphertext, nonce); + if (!equalBytes2(calculatedMac, mac)) + throw new Error("invalid MAC"); + const padded = chacha20(chacha_key, chacha_nonce, ciphertext); + return unpad(padded); + } + var v2 = { + utils: { + getConversationKey, + calcPaddedLen + }, + encrypt: encrypt3, + decrypt: decrypt3 + }; + + // nip59.ts + var TWO_DAYS = 2 * 24 * 60 * 60; + var now = () => Math.round(Date.now() / 1e3); + var randomNow = () => Math.round(now() - Math.random() * TWO_DAYS); + var nip44ConversationKey = (privateKey, publicKey) => getConversationKey(privateKey, publicKey); + var nip44Encrypt = (data, privateKey, publicKey) => encrypt3(JSON.stringify(data), nip44ConversationKey(privateKey, publicKey)); + var nip44Decrypt = (data, privateKey) => JSON.parse(decrypt3(data.content, nip44ConversationKey(privateKey, data.pubkey))); + function createRumor(event, privateKey) { + const rumor = { + created_at: now(), + content: "", + tags: [], + ...event, + pubkey: getPublicKey(privateKey) + }; + rumor.id = getEventHash(rumor); + return rumor; + } + function createSeal(rumor, privateKey, recipientPublicKey) { + return finalizeEvent( + { + kind: Seal, + content: nip44Encrypt(rumor, privateKey, recipientPublicKey), + created_at: randomNow(), + tags: [] + }, + privateKey + ); + } + function createWrap(seal, recipientPublicKey) { + const randomKey = generateSecretKey(); + return finalizeEvent( + { + kind: GiftWrap, + content: nip44Encrypt(seal, randomKey, recipientPublicKey), + created_at: randomNow(), + tags: [["p", recipientPublicKey]] + }, + randomKey + ); + } + function wrapEvent(event, senderPrivateKey, recipientPublicKey) { + const rumor = createRumor(event, senderPrivateKey); + const seal = createSeal(rumor, senderPrivateKey, recipientPublicKey); + return createWrap(seal, recipientPublicKey); + } + function wrapManyEvents(event, senderPrivateKey, recipientsPublicKeys) { + if (!recipientsPublicKeys || recipientsPublicKeys.length === 0) { + throw new Error("At least one recipient is required."); + } + const senderPublicKey = getPublicKey(senderPrivateKey); + const wrappeds = [wrapEvent(event, senderPrivateKey, senderPublicKey)]; + recipientsPublicKeys.forEach((recipientPublicKey) => { + wrappeds.push(wrapEvent(event, senderPrivateKey, recipientPublicKey)); + }); + return wrappeds; + } + function unwrapEvent(wrap, recipientPrivateKey) { + const unwrappedSeal = nip44Decrypt(wrap, recipientPrivateKey); + return nip44Decrypt(unwrappedSeal, recipientPrivateKey); + } + function unwrapManyEvents(wrappedEvents, recipientPrivateKey) { + let unwrappedEvents = []; + wrappedEvents.forEach((e) => { + unwrappedEvents.push(unwrapEvent(e, recipientPrivateKey)); + }); + unwrappedEvents.sort((a, b) => a.created_at - b.created_at); + return unwrappedEvents; + } + + // nip17.ts + function createEvent(recipients, message, conversationTitle, replyTo) { + const baseEvent = { + created_at: Math.ceil(Date.now() / 1e3), + kind: PrivateDirectMessage, + tags: [], + content: message + }; + const recipientsArray = Array.isArray(recipients) ? recipients : [recipients]; + recipientsArray.forEach(({ publicKey, relayUrl }) => { + baseEvent.tags.push(relayUrl ? ["p", publicKey, relayUrl] : ["p", publicKey]); + }); + if (replyTo) { + baseEvent.tags.push(["e", replyTo.eventId, replyTo.relayUrl || "", "reply"]); + } + if (conversationTitle) { + baseEvent.tags.push(["subject", conversationTitle]); + } + return baseEvent; + } + function wrapEvent2(senderPrivateKey, recipient, message, conversationTitle, replyTo) { + const event = createEvent(recipient, message, conversationTitle, replyTo); + return wrapEvent(event, senderPrivateKey, recipient.publicKey); + } + function wrapManyEvents2(senderPrivateKey, recipients, message, conversationTitle, replyTo) { + if (!recipients || recipients.length === 0) { + throw new Error("At least one recipient is required."); + } + const senderPublicKey = getPublicKey(senderPrivateKey); + return [{ publicKey: senderPublicKey }, ...recipients].map( + (recipient) => wrapEvent2(senderPrivateKey, recipient, message, conversationTitle, replyTo) + ); + } + var unwrapEvent2 = unwrapEvent; + var unwrapManyEvents2 = unwrapManyEvents; + + // nip18.ts + var nip18_exports = {}; + __export(nip18_exports, { + finishRepostEvent: () => finishRepostEvent, + getRepostedEvent: () => getRepostedEvent, + getRepostedEventPointer: () => getRepostedEventPointer + }); + function finishRepostEvent(t, reposted, relayUrl, privateKey) { + let kind; + const tags = [...t.tags ?? [], ["e", reposted.id, relayUrl], ["p", reposted.pubkey]]; + if (reposted.kind === ShortTextNote) { + kind = Repost; + } else { + kind = GenericRepost; + tags.push(["k", String(reposted.kind)]); + } + return finalizeEvent( + { + kind, + tags, + content: t.content === "" || reposted.tags?.find((tag) => tag[0] === "-") ? "" : JSON.stringify(reposted), + created_at: t.created_at + }, + privateKey + ); + } + function getRepostedEventPointer(event) { + if (![Repost, GenericRepost].includes(event.kind)) { + return void 0; + } + let lastETag; + let lastPTag; + for (let i2 = event.tags.length - 1; i2 >= 0 && (lastETag === void 0 || lastPTag === void 0); i2--) { + const tag = event.tags[i2]; + if (tag.length >= 2) { + if (tag[0] === "e" && lastETag === void 0) { + lastETag = tag; + } else if (tag[0] === "p" && lastPTag === void 0) { + lastPTag = tag; + } + } + } + if (lastETag === void 0) { + return void 0; + } + return { + id: lastETag[1], + relays: [lastETag[2], lastPTag?.[2]].filter((x) => typeof x === "string"), + author: lastPTag?.[1] + }; + } + function getRepostedEvent(event, { skipVerification } = {}) { + const pointer = getRepostedEventPointer(event); + if (pointer === void 0 || event.content === "") { + return void 0; + } + let repostedEvent; + try { + repostedEvent = JSON.parse(event.content); + } catch (error) { + return void 0; + } + if (repostedEvent.id !== pointer.id) { + return void 0; + } + if (!skipVerification && !verifyEvent(repostedEvent)) { + return void 0; + } + return repostedEvent; + } + + // nip21.ts + var nip21_exports = {}; + __export(nip21_exports, { + NOSTR_URI_REGEX: () => NOSTR_URI_REGEX, + parse: () => parse2, + test: () => test + }); + var NOSTR_URI_REGEX = new RegExp(`nostr:(${BECH32_REGEX.source})`); + function test(value) { + return typeof value === "string" && new RegExp(`^${NOSTR_URI_REGEX.source}$`).test(value); + } + function parse2(uri) { + const match = uri.match(new RegExp(`^${NOSTR_URI_REGEX.source}$`)); + if (!match) + throw new Error(`Invalid Nostr URI: ${uri}`); + return { + uri: match[0], + value: match[1], + decoded: decode(match[1]) + }; + } + + // nip25.ts + var nip25_exports = {}; + __export(nip25_exports, { + finishReactionEvent: () => finishReactionEvent, + getReactedEventPointer: () => getReactedEventPointer + }); + function finishReactionEvent(t, reacted, privateKey) { + const inheritedTags = reacted.tags.filter((tag) => tag.length >= 2 && (tag[0] === "e" || tag[0] === "p")); + return finalizeEvent( + { + ...t, + kind: Reaction, + tags: [...t.tags ?? [], ...inheritedTags, ["e", reacted.id], ["p", reacted.pubkey]], + content: t.content ?? "+" + }, + privateKey + ); + } + function getReactedEventPointer(event) { + if (event.kind !== Reaction) { + return void 0; + } + let lastETag; + let lastPTag; + for (let i2 = event.tags.length - 1; i2 >= 0 && (lastETag === void 0 || lastPTag === void 0); i2--) { + const tag = event.tags[i2]; + if (tag.length >= 2) { + if (tag[0] === "e" && lastETag === void 0) { + lastETag = tag; + } else if (tag[0] === "p" && lastPTag === void 0) { + lastPTag = tag; + } + } + } + if (lastETag === void 0 || lastPTag === void 0) { + return void 0; + } + return { + id: lastETag[1], + relays: [lastETag[2], lastPTag[2]].filter((x) => x !== void 0), + author: lastPTag[1] + }; + } + + // nip27.ts + var nip27_exports = {}; + __export(nip27_exports, { + parse: () => parse3 + }); + var noCharacter = /\W/m; + var noURLCharacter = /\W |\W$|$|,| /m; + function* parse3(content) { + const max = content.length; + let prevIndex = 0; + let index = 0; + while (index < max) { + let u = content.indexOf(":", index); + if (u === -1) { + break; + } + if (content.substring(u - 5, u) === "nostr") { + const m = content.substring(u + 60).match(noCharacter); + const end = m ? u + 60 + m.index : max; + try { + let pointer; + let { data, type } = decode(content.substring(u + 1, end)); + switch (type) { + case "npub": + pointer = { pubkey: data }; + break; + case "nsec": + case "note": + index = end + 1; + continue; + default: + pointer = data; + } + if (prevIndex !== u - 5) { + yield { type: "text", text: content.substring(prevIndex, u - 5) }; + } + yield { type: "reference", pointer }; + index = end; + prevIndex = index; + continue; + } catch (_err) { + index = u + 1; + continue; + } + } else if (content.substring(u - 5, u) === "https" || content.substring(u - 4, u) === "http") { + const m = content.substring(u + 4).match(noURLCharacter); + const end = m ? u + 4 + m.index : max; + const prefixLen = content[u - 1] === "s" ? 5 : 4; + try { + let url = new URL(content.substring(u - prefixLen, end)); + if (url.hostname.indexOf(".") === -1) { + throw new Error("invalid url"); + } + if (prevIndex !== u - prefixLen) { + yield { type: "text", text: content.substring(prevIndex, u - prefixLen) }; + } + if (/\.(png|jpe?g|gif|webp)$/i.test(url.pathname)) { + yield { type: "image", url: url.toString() }; + index = end; + prevIndex = index; + continue; + } + if (/\.(mp4|avi|webm|mkv)$/i.test(url.pathname)) { + yield { type: "video", url: url.toString() }; + index = end; + prevIndex = index; + continue; + } + if (/\.(mp3|aac|ogg|opus)$/i.test(url.pathname)) { + yield { type: "audio", url: url.toString() }; + index = end; + prevIndex = index; + continue; + } + yield { type: "url", url: url.toString() }; + index = end; + prevIndex = index; + continue; + } catch (_err) { + index = end + 1; + continue; + } + } else if (content.substring(u - 3, u) === "wss" || content.substring(u - 2, u) === "ws") { + const m = content.substring(u + 4).match(noURLCharacter); + const end = m ? u + 4 + m.index : max; + const prefixLen = content[u - 1] === "s" ? 3 : 2; + try { + let url = new URL(content.substring(u - prefixLen, end)); + if (url.hostname.indexOf(".") === -1) { + throw new Error("invalid ws url"); + } + if (prevIndex !== u - prefixLen) { + yield { type: "text", text: content.substring(prevIndex, u - prefixLen) }; + } + yield { type: "relay", url: url.toString() }; + index = end; + prevIndex = index; + continue; + } catch (_err) { + index = end + 1; + continue; + } + } else { + index = u + 1; + continue; + } + } + if (prevIndex !== max) { + yield { type: "text", text: content.substring(prevIndex) }; + } + } + + // nip28.ts + var nip28_exports = {}; + __export(nip28_exports, { + channelCreateEvent: () => channelCreateEvent, + channelHideMessageEvent: () => channelHideMessageEvent, + channelMessageEvent: () => channelMessageEvent, + channelMetadataEvent: () => channelMetadataEvent, + channelMuteUserEvent: () => channelMuteUserEvent + }); + var channelCreateEvent = (t, privateKey) => { + let content; + if (typeof t.content === "object") { + content = JSON.stringify(t.content); + } else if (typeof t.content === "string") { + content = t.content; + } else { + return void 0; + } + return finalizeEvent( + { + kind: ChannelCreation, + tags: [...t.tags ?? []], + content, + created_at: t.created_at + }, + privateKey + ); + }; + var channelMetadataEvent = (t, privateKey) => { + let content; + if (typeof t.content === "object") { + content = JSON.stringify(t.content); + } else if (typeof t.content === "string") { + content = t.content; + } else { + return void 0; + } + return finalizeEvent( + { + kind: ChannelMetadata, + tags: [["e", t.channel_create_event_id], ...t.tags ?? []], + content, + created_at: t.created_at + }, + privateKey + ); + }; + var channelMessageEvent = (t, privateKey) => { + const tags = [["e", t.channel_create_event_id, t.relay_url, "root"]]; + if (t.reply_to_channel_message_event_id) { + tags.push(["e", t.reply_to_channel_message_event_id, t.relay_url, "reply"]); + } + return finalizeEvent( + { + kind: ChannelMessage, + tags: [...tags, ...t.tags ?? []], + content: t.content, + created_at: t.created_at + }, + privateKey + ); + }; + var channelHideMessageEvent = (t, privateKey) => { + let content; + if (typeof t.content === "object") { + content = JSON.stringify(t.content); + } else if (typeof t.content === "string") { + content = t.content; + } else { + return void 0; + } + return finalizeEvent( + { + kind: ChannelHideMessage, + tags: [["e", t.channel_message_event_id], ...t.tags ?? []], + content, + created_at: t.created_at + }, + privateKey + ); + }; + var channelMuteUserEvent = (t, privateKey) => { + let content; + if (typeof t.content === "object") { + content = JSON.stringify(t.content); + } else if (typeof t.content === "string") { + content = t.content; + } else { + return void 0; + } + return finalizeEvent( + { + kind: ChannelMuteUser, + tags: [["p", t.pubkey_to_mute], ...t.tags ?? []], + content, + created_at: t.created_at + }, + privateKey + ); + }; + + // nip30.ts + var nip30_exports = {}; + __export(nip30_exports, { + EMOJI_SHORTCODE_REGEX: () => EMOJI_SHORTCODE_REGEX, + matchAll: () => matchAll, + regex: () => regex, + replaceAll: () => replaceAll + }); + var EMOJI_SHORTCODE_REGEX = /:(\w+):/; + var regex = () => new RegExp(`\\B${EMOJI_SHORTCODE_REGEX.source}\\B`, "g"); + function* matchAll(content) { + const matches = content.matchAll(regex()); + for (const match of matches) { + try { + const [shortcode, name] = match; + yield { + shortcode, + name, + start: match.index, + end: match.index + shortcode.length + }; + } catch (_e) { + } + } + } + function replaceAll(content, replacer) { + return content.replaceAll(regex(), (shortcode, name) => { + return replacer({ + shortcode, + name + }); + }); + } + + // nip39.ts + var nip39_exports = {}; + __export(nip39_exports, { + useFetchImplementation: () => useFetchImplementation3, + validateGithub: () => validateGithub + }); + var _fetch3; + try { + _fetch3 = fetch; + } catch { + } + function useFetchImplementation3(fetchImplementation) { + _fetch3 = fetchImplementation; + } + async function validateGithub(pubkey, username, proof) { + try { + let res = await (await _fetch3(`https://gist.github.com/${username}/${proof}/raw`)).text(); + return res === `Verifying that I control the following Nostr public key: ${pubkey}`; + } catch (_) { + return false; + } + } + + // nip46.ts + var nip46_exports = {}; + __export(nip46_exports, { + BUNKER_REGEX: () => BUNKER_REGEX, + BunkerSigner: () => BunkerSigner, + createAccount: () => createAccount, + createNostrConnectURI: () => createNostrConnectURI, + fetchBunkerProviders: () => fetchBunkerProviders, + parseBunkerInput: () => parseBunkerInput, + parseNostrConnectURI: () => parseNostrConnectURI, + queryBunkerProfile: () => queryBunkerProfile, + toBunkerURL: () => toBunkerURL, + useFetchImplementation: () => useFetchImplementation4 + }); + var _fetch4; + try { + _fetch4 = fetch; + } catch { + } + function useFetchImplementation4(fetchImplementation) { + _fetch4 = fetchImplementation; + } + var BUNKER_REGEX = /^bunker:\/\/([0-9a-f]{64})\??([?\/\w:.=&%-]*)$/; + var EMAIL_REGEX = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; + function toBunkerURL(bunkerPointer) { + let bunkerURL = new URL(`bunker://${bunkerPointer.pubkey}`); + bunkerPointer.relays.forEach((relay) => { + bunkerURL.searchParams.append("relay", relay); + }); + if (bunkerPointer.secret) { + bunkerURL.searchParams.set("secret", bunkerPointer.secret); + } + return bunkerURL.toString(); + } + async function parseBunkerInput(input) { + let match = input.match(BUNKER_REGEX); + if (match) { + try { + const pubkey = match[1]; + const qs = new URLSearchParams(match[2]); + return { + pubkey, + relays: qs.getAll("relay"), + secret: qs.get("secret") + }; + } catch (_err) { + } + } + return queryBunkerProfile(input); + } + async function queryBunkerProfile(nip05) { + const match = nip05.match(NIP05_REGEX); + if (!match) + return null; + const [_, name = "_", domain] = match; + try { + const url = `https://${domain}/.well-known/nostr.json?name=${name}`; + const res = await (await _fetch4(url, { redirect: "error" })).json(); + let pubkey = res.names[name]; + let relays = res.nip46[pubkey] || []; + return { pubkey, relays, secret: null }; + } catch (_err) { + return null; + } + } + function createNostrConnectURI(params) { + if (!params.clientPubkey) { + throw new Error("clientPubkey is required."); + } + if (!params.relays || params.relays.length === 0) { + throw new Error("At least one relay is required."); + } + if (!params.secret) { + throw new Error("secret is required."); + } + const queryParams = new URLSearchParams(); + params.relays.forEach((relay) => { + queryParams.append("relay", relay); + }); + queryParams.append("secret", params.secret); + if (params.perms && params.perms.length > 0) { + queryParams.append("perms", params.perms.join(",")); + } + if (params.name) { + queryParams.append("name", params.name); + } + if (params.url) { + queryParams.append("url", params.url); + } + if (params.image) { + queryParams.append("image", params.image); + } + return `nostrconnect://${params.clientPubkey}?${queryParams.toString()}`; + } + function parseNostrConnectURI(uri) { + if (!uri.startsWith("nostrconnect://")) { + throw new Error('Invalid nostrconnect URI: Must start with "nostrconnect://".'); + } + const [protocolAndPubkey, queryString] = uri.split("?"); + if (!protocolAndPubkey || !queryString) { + throw new Error("Invalid nostrconnect URI: Missing query string."); + } + const clientPubkey = protocolAndPubkey.substring("nostrconnect://".length); + if (!clientPubkey) { + throw new Error("Invalid nostrconnect URI: Missing client-pubkey."); + } + const queryParams = new URLSearchParams(queryString); + const relays = queryParams.getAll("relay"); + if (relays.length === 0) { + throw new Error('Invalid nostrconnect URI: Missing "relay" parameter.'); + } + const secret = queryParams.get("secret"); + if (!secret) { + throw new Error('Invalid nostrconnect URI: Missing "secret" parameter.'); + } + const permsString = queryParams.get("perms"); + const perms = permsString ? permsString.split(",") : void 0; + const name = queryParams.get("name") || void 0; + const url = queryParams.get("url") || void 0; + const image = queryParams.get("image") || void 0; + return { + protocol: "nostrconnect", + clientPubkey, + params: { + relays, + secret, + perms, + name, + url, + image + }, + originalString: uri + }; + } + var BunkerSigner = class { + params; + pool; + subCloser; + isOpen; + serial; + idPrefix; + listeners; + waitingForAuth; + secretKey; + conversationKey; + bp; + cachedPubKey; + constructor(clientSecretKey, params) { + this.params = params; + this.pool = params.pool || new SimplePool(); + this.secretKey = clientSecretKey; + this.isOpen = false; + this.idPrefix = Math.random().toString(36).substring(7); + this.serial = 0; + this.listeners = {}; + this.waitingForAuth = {}; + } + static fromBunker(clientSecretKey, bp, params = {}) { + if (bp.relays.length === 0) { + throw new Error("No relays specified for this bunker"); + } + const signer = new BunkerSigner(clientSecretKey, params); + signer.conversationKey = getConversationKey(clientSecretKey, bp.pubkey); + signer.bp = bp; + signer.setupSubscription(params); + return signer; + } + static async fromURI(clientSecretKey, connectionURI, params = {}, maxWait = 3e5) { + const signer = new BunkerSigner(clientSecretKey, params); + const parsedURI = parseNostrConnectURI(connectionURI); + const clientPubkey = getPublicKey(clientSecretKey); + return new Promise((resolve, reject) => { + const timer = setTimeout(() => { + sub.close(); + reject(new Error(`Connection timed out after ${maxWait / 1e3} seconds`)); + }, maxWait); + const sub = signer.pool.subscribe( + parsedURI.params.relays, + { kinds: [NostrConnect], "#p": [clientPubkey] }, + { + onevent: async (event) => { + try { + const tempConvKey = getConversationKey(clientSecretKey, event.pubkey); + const decryptedContent = decrypt3(event.content, tempConvKey); + const response = JSON.parse(decryptedContent); + if (response.result === parsedURI.params.secret) { + clearTimeout(timer); + sub.close(); + signer.bp = { + pubkey: event.pubkey, + relays: parsedURI.params.relays, + secret: parsedURI.params.secret + }; + signer.conversationKey = getConversationKey(clientSecretKey, event.pubkey); + signer.setupSubscription(params); + resolve(signer); + } + } catch (e) { + console.warn("Failed to process potential connection event", e); + } + }, + onclose: () => { + clearTimeout(timer); + reject(new Error("Subscription closed before connection was established.")); + }, + maxWait + } + ); + }); + } + setupSubscription(params) { + const listeners = this.listeners; + const waitingForAuth = this.waitingForAuth; + const convKey = this.conversationKey; + this.subCloser = this.pool.subscribe( + this.bp.relays, + { kinds: [NostrConnect], authors: [this.bp.pubkey], "#p": [getPublicKey(this.secretKey)] }, + { + onevent: async (event) => { + const o = JSON.parse(decrypt3(event.content, convKey)); + const { id, result, error } = o; + if (result === "auth_url" && waitingForAuth[id]) { + delete waitingForAuth[id]; + if (params.onauth) { + params.onauth(error); + } else { + console.warn( + `nostr-tools/nip46: remote signer ${this.bp.pubkey} tried to send an "auth_url"='${error}' but there was no onauth() callback configured.` + ); + } + return; + } + let handler = listeners[id]; + if (handler) { + if (error) + handler.reject(error); + else if (result) + handler.resolve(result); + delete listeners[id]; + } + }, + onclose: () => { + this.subCloser = void 0; + } + } + ); + this.isOpen = true; + } + async close() { + this.isOpen = false; + this.subCloser.close(); + } + async sendRequest(method, params) { + return new Promise(async (resolve, reject) => { + try { + if (!this.isOpen) + throw new Error("this signer is not open anymore, create a new one"); + if (!this.subCloser) + this.setupSubscription(this.params); + this.serial++; + const id = `${this.idPrefix}-${this.serial}`; + const encryptedContent = encrypt3(JSON.stringify({ id, method, params }), this.conversationKey); + const verifiedEvent = finalizeEvent( + { + kind: NostrConnect, + tags: [["p", this.bp.pubkey]], + content: encryptedContent, + created_at: Math.floor(Date.now() / 1e3) + }, + this.secretKey + ); + this.listeners[id] = { resolve, reject }; + this.waitingForAuth[id] = true; + await Promise.any(this.pool.publish(this.bp.relays, verifiedEvent)); + } catch (err) { + reject(err); + } + }); + } + async ping() { + let resp = await this.sendRequest("ping", []); + if (resp !== "pong") + throw new Error(`result is not pong: ${resp}`); + } + async connect() { + await this.sendRequest("connect", [this.bp.pubkey, this.bp.secret || ""]); + } + async getPublicKey() { + if (!this.cachedPubKey) { + this.cachedPubKey = await this.sendRequest("get_public_key", []); + } + return this.cachedPubKey; + } + async signEvent(event) { + let resp = await this.sendRequest("sign_event", [JSON.stringify(event)]); + let signed = JSON.parse(resp); + if (verifyEvent(signed)) { + return signed; + } else { + throw new Error(`event returned from bunker is improperly signed: ${JSON.stringify(signed)}`); + } + } + async nip04Encrypt(thirdPartyPubkey, plaintext) { + return await this.sendRequest("nip04_encrypt", [thirdPartyPubkey, plaintext]); + } + async nip04Decrypt(thirdPartyPubkey, ciphertext) { + return await this.sendRequest("nip04_decrypt", [thirdPartyPubkey, ciphertext]); + } + async nip44Encrypt(thirdPartyPubkey, plaintext) { + return await this.sendRequest("nip44_encrypt", [thirdPartyPubkey, plaintext]); + } + async nip44Decrypt(thirdPartyPubkey, ciphertext) { + return await this.sendRequest("nip44_decrypt", [thirdPartyPubkey, ciphertext]); + } + }; + async function createAccount(bunker, params, username, domain, email, localSecretKey = generateSecretKey()) { + if (email && !EMAIL_REGEX.test(email)) + throw new Error("Invalid email"); + let rpc = BunkerSigner.fromBunker(localSecretKey, bunker.bunkerPointer, params); + let pubkey = await rpc.sendRequest("create_account", [username, domain, email || ""]); + rpc.bp.pubkey = pubkey; + await rpc.connect(); + return rpc; + } + async function fetchBunkerProviders(pool, relays) { + const events = await pool.querySync(relays, { + kinds: [Handlerinformation], + "#k": [NostrConnect.toString()] + }); + events.sort((a, b) => b.created_at - a.created_at); + const validatedBunkers = await Promise.all( + events.map(async (event, i2) => { + try { + const content = JSON.parse(event.content); + try { + if (events.findIndex((ev) => JSON.parse(ev.content).nip05 === content.nip05) !== i2) + return void 0; + } catch (err) { + } + const bp = await queryBunkerProfile(content.nip05); + if (bp && bp.pubkey === event.pubkey && bp.relays.length) { + return { + bunkerPointer: bp, + nip05: content.nip05, + domain: content.nip05.split("@")[1], + name: content.name || content.display_name, + picture: content.picture, + about: content.about, + website: content.website, + local: false + }; + } + } catch (err) { + return void 0; + } + }) + ); + return validatedBunkers.filter((b) => b !== void 0); + } + + // nip47.ts + var nip47_exports = {}; + __export(nip47_exports, { + makeNwcRequestEvent: () => makeNwcRequestEvent, + parseConnectionString: () => parseConnectionString + }); + function parseConnectionString(connectionString) { + const { host, pathname, searchParams } = new URL(connectionString); + const pubkey = pathname || host; + const relay = searchParams.get("relay"); + const secret = searchParams.get("secret"); + if (!pubkey || !relay || !secret) { + throw new Error("invalid connection string"); + } + return { pubkey, relay, secret }; + } + async function makeNwcRequestEvent(pubkey, secretKey, invoice) { + const content = { + method: "pay_invoice", + params: { + invoice + } + }; + const encryptedContent = encrypt2(secretKey, pubkey, JSON.stringify(content)); + const eventTemplate = { + kind: NWCWalletRequest, + created_at: Math.round(Date.now() / 1e3), + content: encryptedContent, + tags: [["p", pubkey]] + }; + return finalizeEvent(eventTemplate, secretKey); + } + + // nip54.ts + var nip54_exports = {}; + __export(nip54_exports, { + normalizeIdentifier: () => normalizeIdentifier + }); + function normalizeIdentifier(name) { + name = name.trim().toLowerCase(); + name = name.normalize("NFKC"); + return Array.from(name).map((char) => { + if (/\p{Letter}/u.test(char) || /\p{Number}/u.test(char)) { + return char; + } + return "-"; + }).join(""); + } + + // nip57.ts + var nip57_exports = {}; + __export(nip57_exports, { + getSatoshisAmountFromBolt11: () => getSatoshisAmountFromBolt11, + getZapEndpoint: () => getZapEndpoint, + makeZapReceipt: () => makeZapReceipt, + makeZapRequest: () => makeZapRequest, + useFetchImplementation: () => useFetchImplementation5, + validateZapRequest: () => validateZapRequest + }); + var _fetch5; + try { + _fetch5 = fetch; + } catch { + } + function useFetchImplementation5(fetchImplementation) { + _fetch5 = fetchImplementation; + } + async function getZapEndpoint(metadata) { + try { + let lnurl = ""; + let { lud06, lud16 } = JSON.parse(metadata.content); + if (lud06) { + let { words } = bech32.decode(lud06, 1e3); + let data = bech32.fromWords(words); + lnurl = utf8Decoder.decode(data); + } else if (lud16) { + let [name, domain] = lud16.split("@"); + lnurl = new URL(`/.well-known/lnurlp/${name}`, `https://${domain}`).toString(); + } else { + return null; + } + let res = await _fetch5(lnurl); + let body = await res.json(); + if (body.allowsNostr && body.nostrPubkey) { + return body.callback; + } + } catch (err) { + } + return null; + } + function makeZapRequest(params) { + let zr = { + kind: 9734, + created_at: Math.round(Date.now() / 1e3), + content: params.comment || "", + tags: [ + ["p", "pubkey" in params ? params.pubkey : params.event.pubkey], + ["amount", params.amount.toString()], + ["relays", ...params.relays] + ] + }; + if ("event" in params) { + zr.tags.push(["e", params.event.id]); + if (isReplaceableKind(params.event.kind)) { + const a = ["a", `${params.event.kind}:${params.event.pubkey}:`]; + zr.tags.push(a); + } else if (isAddressableKind(params.event.kind)) { + let d = params.event.tags.find(([t, v]) => t === "d" && v); + if (!d) + throw new Error("d tag not found or is empty"); + const a = ["a", `${params.event.kind}:${params.event.pubkey}:${d[1]}`]; + zr.tags.push(a); + } + zr.tags.push(["k", params.event.kind.toString()]); + } + return zr; + } + function validateZapRequest(zapRequestString) { + let zapRequest; + try { + zapRequest = JSON.parse(zapRequestString); + } catch (err) { + return "Invalid zap request JSON."; + } + if (!validateEvent(zapRequest)) + return "Zap request is not a valid Nostr event."; + if (!verifyEvent(zapRequest)) + return "Invalid signature on zap request."; + let p = zapRequest.tags.find(([t, v]) => t === "p" && v); + if (!p) + return "Zap request doesn't have a 'p' tag."; + if (!p[1].match(/^[a-f0-9]{64}$/)) + return "Zap request 'p' tag is not valid hex."; + let e = zapRequest.tags.find(([t, v]) => t === "e" && v); + if (e && !e[1].match(/^[a-f0-9]{64}$/)) + return "Zap request 'e' tag is not valid hex."; + let relays = zapRequest.tags.find(([t, v]) => t === "relays" && v); + if (!relays) + return "Zap request doesn't have a 'relays' tag."; + return null; + } + function makeZapReceipt({ + zapRequest, + preimage, + bolt11, + paidAt + }) { + let zr = JSON.parse(zapRequest); + let tagsFromZapRequest = zr.tags.filter(([t]) => t === "e" || t === "p" || t === "a"); + let zap = { + kind: 9735, + created_at: Math.round(paidAt.getTime() / 1e3), + content: "", + tags: [...tagsFromZapRequest, ["P", zr.pubkey], ["bolt11", bolt11], ["description", zapRequest]] + }; + if (preimage) { + zap.tags.push(["preimage", preimage]); + } + return zap; + } + function getSatoshisAmountFromBolt11(bolt11) { + if (bolt11.length < 50) { + return 0; + } + bolt11 = bolt11.substring(0, 50); + const idx = bolt11.lastIndexOf("1"); + if (idx === -1) { + return 0; + } + const hrp = bolt11.substring(0, idx); + if (!hrp.startsWith("lnbc")) { + return 0; + } + const amount = hrp.substring(4); + if (amount.length < 1) { + return 0; + } + const char = amount[amount.length - 1]; + const digit = char.charCodeAt(0) - "0".charCodeAt(0); + const isDigit = digit >= 0 && digit <= 9; + let cutPoint = amount.length - 1; + if (isDigit) { + cutPoint++; + } + if (cutPoint < 1) { + return 0; + } + const num = parseInt(amount.substring(0, cutPoint)); + switch (char) { + case "m": + return num * 1e5; + case "u": + return num * 100; + case "n": + return num / 10; + case "p": + return num / 1e4; + default: + return num * 1e8; + } + } + + // nip98.ts + var nip98_exports = {}; + __export(nip98_exports, { + getToken: () => getToken, + hashPayload: () => hashPayload, + unpackEventFromToken: () => unpackEventFromToken, + validateEvent: () => validateEvent2, + validateEventKind: () => validateEventKind, + validateEventMethodTag: () => validateEventMethodTag, + validateEventPayloadTag: () => validateEventPayloadTag, + validateEventTimestamp: () => validateEventTimestamp, + validateEventUrlTag: () => validateEventUrlTag, + validateToken: () => validateToken + }); + var _authorizationScheme = "Nostr "; + async function getToken(loginUrl, httpMethod, sign, includeAuthorizationScheme = false, payload) { + const event = { + kind: HTTPAuth, + tags: [ + ["u", loginUrl], + ["method", httpMethod] + ], + created_at: Math.round(new Date().getTime() / 1e3), + content: "" + }; + if (payload) { + event.tags.push(["payload", hashPayload(payload)]); + } + const signedEvent = await sign(event); + const authorizationScheme = includeAuthorizationScheme ? _authorizationScheme : ""; + return authorizationScheme + base64.encode(utf8Encoder.encode(JSON.stringify(signedEvent))); + } + async function validateToken(token, url, method) { + const event = await unpackEventFromToken(token).catch((error) => { + throw error; + }); + const valid = await validateEvent2(event, url, method).catch((error) => { + throw error; + }); + return valid; + } + async function unpackEventFromToken(token) { + if (!token) { + throw new Error("Missing token"); + } + token = token.replace(_authorizationScheme, ""); + const eventB64 = utf8Decoder.decode(base64.decode(token)); + if (!eventB64 || eventB64.length === 0 || !eventB64.startsWith("{")) { + throw new Error("Invalid token"); + } + const event = JSON.parse(eventB64); + return event; + } + function validateEventTimestamp(event) { + if (!event.created_at) { + return false; + } + return Math.round(new Date().getTime() / 1e3) - event.created_at < 60; + } + function validateEventKind(event) { + return event.kind === HTTPAuth; + } + function validateEventUrlTag(event, url) { + const urlTag = event.tags.find((t) => t[0] === "u"); + if (!urlTag) { + return false; + } + return urlTag.length > 0 && urlTag[1] === url; + } + function validateEventMethodTag(event, method) { + const methodTag = event.tags.find((t) => t[0] === "method"); + if (!methodTag) { + return false; + } + return methodTag.length > 0 && methodTag[1].toLowerCase() === method.toLowerCase(); + } + function hashPayload(payload) { + const hash3 = sha2562(utf8Encoder.encode(JSON.stringify(payload))); + return bytesToHex2(hash3); + } + function validateEventPayloadTag(event, payload) { + const payloadTag = event.tags.find((t) => t[0] === "payload"); + if (!payloadTag) { + return false; + } + const payloadHash = hashPayload(payload); + return payloadTag.length > 0 && payloadTag[1] === payloadHash; + } + async function validateEvent2(event, url, method, body) { + if (!verifyEvent(event)) { + throw new Error("Invalid nostr event, signature invalid"); + } + if (!validateEventKind(event)) { + throw new Error("Invalid nostr event, kind invalid"); + } + if (!validateEventTimestamp(event)) { + throw new Error("Invalid nostr event, created_at timestamp invalid"); + } + if (!validateEventUrlTag(event, url)) { + throw new Error("Invalid nostr event, url tag invalid"); + } + if (!validateEventMethodTag(event, method)) { + throw new Error("Invalid nostr event, method tag invalid"); + } + if (Boolean(body) && typeof body === "object" && Object.keys(body).length > 0) { + if (!validateEventPayloadTag(event, body)) { + throw new Error("Invalid nostr event, payload tag does not match request body hash"); + } + } + return true; + } + return __toCommonJS(nostr_tools_exports); +})(); diff --git a/admin/assets/style.css b/admin/assets/style.css deleted file mode 100644 index 37e5bda..0000000 --- a/admin/assets/style.css +++ /dev/null @@ -1,419 +0,0 @@ -/* - * C-Relay-PG Admin — PHP caching service admin pages. - * Styled to match the original api/index.css Nostr admin interface. - * Courier New monospace, black/white/red color scheme, dark mode by default. - */ - -:root { - /* Core Variables — matches api/index.css light mode (default) */ - --primary-color: #000000; - --secondary-color: #ffffff; - --accent-color: #ff0000; - --muted-color: #dddddd; - --border-color: var(--muted-color); - --font-family: "Courier New", Courier, monospace; - --border-radius: 5px; - --border-width: 1px; -} - -* { - margin: 0; - padding: 0; - box-sizing: border-box; -} - -body { - font-family: var(--font-family); - background-color: var(--secondary-color); - color: var(--primary-color); - padding: 0; - max-width: 1200px; - margin: 0 auto; -} - -a { - color: var(--primary-color); - text-decoration: none; -} -a:hover { color: var(--accent-color); } - -/* ================================ - SIDE NAVIGATION (matches original) - ================================ */ -.side-nav { - position: fixed; - top: 0; - left: -300px; - width: 280px; - height: 100vh; - background: var(--secondary-color); - border-right: var(--border-width) solid var(--border-color); - z-index: 1000; - transition: left 0.3s ease; - overflow-y: auto; - padding-top: 80px; -} -.side-nav.open { left: 0; } - -.side-nav-overlay { - position: fixed; - top: 0; left: 0; width: 100%; height: 100%; - background: rgba(0, 0, 0, 0.5); - z-index: 999; - display: none; -} -.side-nav-overlay.show { display: block; } - -.nav-menu { list-style: none; padding: 0; margin: 0; } -.nav-menu li { border-bottom: var(--border-width) solid var(--muted-color); } -.nav-menu li:last-child { border-bottom: none; } - -.nav-item { - display: block; - padding: 15px 20px; - color: var(--primary-color); - text-decoration: none; - font-family: var(--font-family); - font-size: 16px; - font-weight: bold; - transition: all 0.2s ease; - cursor: pointer; - border: 2px solid var(--secondary-color); - background: none; - width: 100%; - text-align: left; -} -.nav-item:hover { - background: var(--muted-color); - color: var(--accent-color); -} -.nav-item.active { - text-decoration: underline; - padding-left: 16px; -} - -.nav-footer { - position: absolute; - bottom: 20px; left: 0; right: 0; - padding: 0 20px; -} -.nav-footer-btn { - display: block; - width: 100%; - padding: 12px 20px; - margin-bottom: 8px; - color: var(--primary-color); - border: 1px solid var(--border-color); - border-radius: 4px; - font-family: var(--font-family); - font-size: 14px; - font-weight: bold; - cursor: pointer; - transition: all 0.2s ease; - background: none; -} -.nav-footer-btn:hover { - background: var(--muted-color); - border-color: var(--accent-color); -} - -/* ================================ - HEADER (matches original) - ================================ */ -.main-header { - background-color: var(--secondary-color); - padding: 15px 20px; - z-index: 100; - max-width: 1200px; - margin: 0 auto; -} -.header-content { - display: flex; - justify-content: space-between; - align-items: center; - position: relative; -} -.header-title { - margin: 0; - font-size: 24px; - font-weight: bolder; - color: var(--primary-color); - cursor: pointer; - transition: all 0.2s ease; -} -.header-title:hover { opacity: 0.8; } -.header-title .relay-letter { display: inline-block; } - -.menu-btn { - background: none; - border: var(--border-width) solid var(--border-color); - border-radius: var(--border-radius); - color: var(--primary-color); - font-family: var(--font-family); - font-size: 20px; - padding: 5px 12px; - cursor: pointer; - width: auto; - margin: 0; -} -.menu-btn:hover { border-color: var(--accent-color); } - -/* ================================ - SECTIONS (matches original) - ================================ */ -.section { - background: var(--secondary-color); - border: var(--border-width) solid var(--border-color); - border-radius: var(--border-radius); - padding: 20px; - margin-bottom: 20px; - margin-left: 5px; - margin-right: 5px; -} -.section-header { - display: flex; - justify-content: center; - align-items: center; - padding-bottom: 15px; - font-size: 16px; - font-weight: normal; - font-family: var(--font-family); - color: var(--primary-color); -} - -/* ================================ - TABLES (matches .config-table) - ================================ */ -.config-table { - border: 1px solid var(--border-color); - border-radius: var(--border-radius); - width: 100%; - border-collapse: separate; - border-spacing: 0; - margin: 10px 0; - overflow: hidden; -} -.config-table th, -.config-table td { - border: 0.1px solid var(--muted-color); - padding: 4px 8px; - text-align: left; - font-family: var(--font-family); - font-size: 10px; -} -.config-table th { - font-weight: bold; - height: 24px; - line-height: 24px; -} -.config-table tbody tr:hover { - background-color: rgba(0, 0, 0, 0.05); -} -.config-table-container { - overflow-x: auto; - max-width: 100%; -} - -/* ================================ - INPUTS / BUTTONS (matches original) - ================================ */ -input, textarea, select { - width: 100%; - padding: 8px; - background: var(--secondary-color); - color: var(--primary-color); - border: var(--border-width) solid var(--border-color); - border-radius: var(--border-radius); - font-family: var(--font-family); - font-size: 14px; - box-sizing: border-box; - transition: all 0.2s ease; -} -input:focus, textarea:focus, select:focus { - border-color: var(--accent-color); - outline: none; -} - -button { - width: 100%; - padding: 8px; - background: var(--secondary-color); - color: var(--primary-color); - border: var(--border-width) solid var(--border-color); - border-radius: var(--border-radius); - font-family: var(--font-family); - font-size: 14px; - cursor: pointer; - margin: 5px 0; - font-weight: bold; - transition: all 0.2s ease; -} -button:hover { border-color: var(--accent-color); } -button:active { - background: var(--accent-color); - color: var(--secondary-color); -} - -/* ================================ - STAT CARDS (dashboard) - ================================ */ -.cards { - display: grid; - grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); - gap: 10px; - margin-bottom: 20px; -} -.card { - background: var(--secondary-color); - border: var(--border-width) solid var(--border-color); - border-radius: var(--border-radius); - padding: 12px; -} -.card .label { - color: var(--muted-color); - font-size: 10px; - text-transform: uppercase; - letter-spacing: 0.5px; -} -.card .value { - font-size: 20px; - font-weight: bold; - margin-top: 4px; -} -.card .sub { - color: var(--muted-color); - font-size: 10px; - margin-top: 4px; -} - -/* ================================ - STATUS BADGES - ================================ */ -.badge { - display: inline-block; - padding: 2px 6px; - border-radius: 3px; - font-size: 10px; - font-weight: bold; - border: var(--border-width) solid var(--border-color); -} -.badge-success { border-color: #4caf50; color: #4caf50; } -.badge-error { border-color: var(--accent-color); color: var(--accent-color); } -.badge-warning { border-color: #ff9800; color: #ff9800; } -.badge-muted { border-color: var(--muted-color); color: var(--muted-color); } - -/* ================================ - STATUS INDICATORS - ================================ */ -.status-working { color: var(--accent-color); } -.status-complete { color: #4caf50; } -.status-error { color: var(--accent-color); } - -/* ================================ - PAGINATION - ================================ */ -.pagination { - display: flex; - justify-content: space-between; - align-items: center; - padding: 12px 0; - gap: 16px; -} -.pagination a { - padding: 6px 14px; - background: var(--secondary-color); - border: var(--border-width) solid var(--border-color); - border-radius: var(--border-radius); - color: var(--primary-color); - font-size: 14px; - width: auto; -} -.pagination a:hover { - border-color: var(--accent-color); - color: var(--accent-color); - text-decoration: none; -} -.pagination span { color: var(--muted-color); font-size: 12px; } - -/* ================================ - FILTERS BAR - ================================ */ -.filters { - display: flex; - gap: 10px; - margin-bottom: 16px; - flex-wrap: wrap; - align-items: center; -} -.filters select, .filters input { - width: auto; - min-width: 120px; -} -.filters input[type="text"] { min-width: 250px; } -.filters button { - width: auto; - margin: 0; - min-width: 80px; -} - -/* ================================ - CONFIG EDITOR FORM - ================================ */ -.config-form .row { - display: grid; - grid-template-columns: 250px 1fr; - gap: 12px; - padding: 12px 0; - border-bottom: 0.1px solid var(--muted-color); - align-items: start; -} -.config-form .row label { - font-weight: bold; - color: var(--primary-color); - font-size: 12px; -} -.config-form .row .hint { - color: var(--muted-color); - font-size: 10px; - margin-top: 4px; -} -.config-form button { - width: auto; - margin-top: 16px; - padding: 10px 24px; -} - -/* ================================ - MISC - ================================ */ -.pubkey { - font-family: var(--font-family); - font-size: 10px; - color: var(--muted-color); -} -.npub-link { - font-family: var(--font-family); - font-size: 10px; - color: var(--primary-color); - text-decoration: none; -} -.npub-link:hover { color: var(--accent-color); } - -h2 { - font-weight: normal; - text-align: center; - font-size: 16px; - font-family: var(--font-family); - color: var(--primary-color); - margin-bottom: 16px; -} - -/* ================================ - RESPONSIVE - ================================ */ -@media (max-width: 768px) { - .cards { grid-template-columns: 1fr 1fr; } - .config-form .row { grid-template-columns: 1fr; } - .filters { flex-direction: column; align-items: stretch; } - .filters select, .filters input, .filters button { width: 100%; } -} diff --git a/admin/cache/chart_day.txt b/admin/cache/chart_day.txt new file mode 100644 index 0000000..4d41a59 --- /dev/null +++ b/admin/cache/chart_day.txt @@ -0,0 +1,15 @@ + New Events — Last 24 Hours + + 11 | X + 10 | XX + 9 | XX + 8 | XX + 7 | XX X X + 6 | XX X X + 5 | XX X X + 4 | X XX X XX + 3 | X XXX X XX + 2 | X X X XXX X XX + 1 | X XX X X X X X X X X X X X X XX X X XXXX X X X X X XX + +-------------------------------------------------------------------------------- + 0s 1h 3h 4h 6h 7h 9h 10h 12h 13h 15h 16h 18h 19h 21h 22h diff --git a/admin/cache/chart_month.txt b/admin/cache/chart_month.txt new file mode 100644 index 0000000..2c53aab --- /dev/null +++ b/admin/cache/chart_month.txt @@ -0,0 +1,15 @@ + New Events — Last 30 Days + + 81 | X + 73 | XX X + 65 | XX X + 57 | XX X X X + 49 | X X XX XX X X X + 41 | X X X XX X X X XXX XXX XXX X X X X + 33 | X X X XXXX XX X X X XX XXX XXXXXXXX XX X X X X X XX + 25 |X XX XX XX XXXX XX XXX X XX XXXXXXXXXXXXXXXXXXXX XX XXX X XX XX XXXXX + 17 |X XXXXX XX XXXXXXXXXXXXXXX X XX XXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXX XX XXXXXXXX + 9 |XXX XXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXX + 1 |XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + +-------------------------------------------------------------------------------- + 0s 1d 3d 5d 7d 9d 11d 13d 15d 16d 18d 20d 22d 24d 26d 28d diff --git a/admin/cache/chart_year.txt b/admin/cache/chart_year.txt new file mode 100644 index 0000000..1c3f4be --- /dev/null +++ b/admin/cache/chart_year.txt @@ -0,0 +1,15 @@ + New Events — Last Year + +531 | X XX +478 | X X X XXX X +425 | X X XX X XX XXX X +372 | XXX XX X XX XXX X +319 |XXXXXXXXXXX X X X XXXXXXX X +266 |XXXXXXXXXXXX X XX XXX XXXXXXXXX X +213 |XXXXXXXXXXXXXX XXX XXXXXXXXXXXXX XX X +160 |XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX X X XXXX X +107 |XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XX XX XX X X X XX XXX X XXXXXXX X + 54 |XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXX + 1 |XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + +-------------------------------------------------------------------------------- + 0s 22d 45d 68d 91d 114d 136d 159d 182d 205d 228d 250d 273d 296d 319d 342d diff --git a/admin/config-edit.php b/admin/config-edit.php deleted file mode 100644 index 66acc7e..0000000 --- a/admin/config-edit.php +++ /dev/null @@ -1,99 +0,0 @@ -beginTransaction(); - foreach ($fields as $key) { - $val = $_POST[$key] ?? null; - if ($val === null) continue; - $pdo->prepare("UPDATE config SET value = ? WHERE key = ?")->execute([$val, $key]); - } - $gen = $pdo->query("SELECT value FROM config WHERE key = 'caching_config_generation'")->fetchColumn(); - $new_gen = intval($gen) + 1; - $pdo->prepare("UPDATE config SET value = ? WHERE key = 'caching_config_generation'")->execute([$new_gen]); - $pdo->commit(); - $message = "Configuration saved. Config generation bumped to $new_gen. The caching service will reload automatically."; - } catch (Exception $e) { - $pdo->rollBack(); - $error = 'Failed to save: ' . $e->getMessage(); - } -} - -$config_keys = [ - 'caching_root_npubs' => 'Root npubs (comma-separated npub... values)', - 'caching_bootstrap_relays' => 'Bootstrap relays (comma-separated wss://... URLs)', - 'caching_kinds' => 'Kinds to cache (comma-separated integers)', - 'caching_admin_kinds' => 'Admin kinds (* for all, or comma-separated)', - 'caching_live_enabled' => 'Live subscription enabled (true/false)', - 'caching_backfill_enabled' => 'Backfill enabled (true/false)', - 'caching_backfill_page_size' => 'Backfill page size (events per tick)', - 'caching_backfill_tick_interval_ms' => 'Backfill tick interval (ms)', - 'caching_follow_graph_refresh_seconds' => 'Follow graph refresh interval (seconds)', - 'caching_relay_discovery_refresh_seconds' => 'Relay discovery refresh (seconds)', - 'caching_max_followed_pubkeys' => 'Max followed pubkeys', - 'caching_max_upstream_relays' => 'Max upstream relays', - 'caching_max_relays_per_pubkey' => 'Max relays per pubkey', - 'caching_query_timeout_ms' => 'Query timeout (ms)', - 'caching_live_resubscribe_seconds' => 'Live resubscribe interval (seconds)', -]; - -$values = []; -foreach (array_keys($config_keys) as $key) { - $stmt = $pdo->prepare("SELECT value FROM config WHERE key = ?"); - $stmt->execute([$key]); - $values[$key] = $stmt->fetchColumn() ?: ''; -} - -admin_header('config', 'C-Relay-PG Admin — Config'); -?> - -
-
CACHING CONFIGURATION
- - -

- - -

- - -
- $label): ?> -
-
- -
-
-
- -
-
- - -
- -

- Saving bumps caching_config_generation so the caching service - detects the change and hot-reloads. No relay restart needed. -

-
- - diff --git a/admin/follows.php b/admin/follows.php deleted file mode 100644 index 3c6e390..0000000 --- a/admin/follows.php +++ /dev/null @@ -1,153 +0,0 @@ ->\'name\' ILIKE ? OR e.content::json->>\'display_name\' ILIKE ?)'; - $params[] = "%$search%"; $params[] = "%$search%"; $params[] = "%$search%"; -} -$where_sql = $where ? 'WHERE ' . implode(' AND ', $where) : ''; - -$sort_map = [ - 'events' => 'fp.events_fetched DESC', - 'name' => "COALESCE(e.content::json->>'display_name', e.content::json->>'name') ASC NULLS LAST", - 'recent' => 'fp.last_seen DESC', - 'complete' => 'fp.backfill_complete ASC, fp.events_fetched DESC', -]; -$sort_sql = $sort_map[$sort] ?? $sort_map['events']; - -$stmt = $pdo->prepare("SELECT COUNT(*) FROM caching_followed_pubkeys fp LEFT JOIN LATERAL (SELECT content FROM events WHERE pubkey = fp.pubkey AND kind = 0 ORDER BY created_at DESC LIMIT 1) e ON true $where_sql"); -$stmt->execute($params); -$total = intval($stmt->fetchColumn()); - -$sql = " - SELECT fp.pubkey, fp.is_root, fp.backfill_complete, fp.events_fetched, - fp.first_seen, fp.last_seen, - e.content::json->>'name' AS name, - e.content::json->>'display_name' AS display_name, - e.content::json->>'picture' AS picture, - e.content::json->>'nip05' AS nip05, - (SELECT COUNT(*) FROM events WHERE pubkey = fp.pubkey) AS total_events - FROM caching_followed_pubkeys fp - LEFT JOIN LATERAL (SELECT content FROM events WHERE pubkey = fp.pubkey AND kind = 0 ORDER BY created_at DESC LIMIT 1) e ON true - $where_sql - ORDER BY $sort_sql - LIMIT $per OFFSET $offset -"; -$stmt = $pdo->prepare($sql); -$stmt->execute($params); -$follows = $stmt->fetchAll(); - -admin_header('follows', 'C-Relay-PG Admin — Follows'); -?> - -
-
FOLLOWED PUBKEYS ( total)
- -
- - - - - - Clear - -
- -
- - - - - - - - - - - - - - 0, 'incomplete' => 0, 'errors' => 0]; - try { - $relay_count = $pdo->prepare("SELECT COUNT(*) AS total, COUNT(*) FILTER (WHERE complete = false) AS incomplete, COUNT(*) FILTER (WHERE last_status LIKE 'error%') AS errors FROM caching_backfill_relay_progress WHERE author_pubkey = ?"); - $relay_count->execute([$f['pubkey']]); - $rc = $relay_count->fetch() ?: $rc; - } catch (PDOException $ex) {} - ?> - - - - - - - - - - - - - - -
NamenpubRoot?Events in DBBackfillLast SeenRelays
- - - -
- - - unknown - -
root' : '' ?>✓ complete' - : 'in progress' ?> - 0): ?> - relays ( incomplete - 0): ?> - , errors - ) -
View relay details → - - - -
No followed pubkeys found.
-
- - -
- - diff --git a/admin/inbox.php b/admin/inbox.php deleted file mode 100644 index 901a617..0000000 --- a/admin/inbox.php +++ /dev/null @@ -1,111 +0,0 @@ -query(" - SELECT - COUNT(*) AS pending, - COUNT(*) FILTER (WHERE source_class = 'live') AS live, - COUNT(*) FILTER (WHERE source_class = 'backfill') AS backfill, - COUNT(*) FILTER (WHERE source_class = 'discovery') AS discovery, - COUNT(*) FILTER (WHERE priority = 0) AS high_priority, - COALESCE(EXTRACT(EPOCH FROM NOW())::BIGINT - MIN(received_at), 0) AS oldest_age - FROM caching_event_inbox -")->fetch() ?: ['pending' => 0, 'live' => 0, 'backfill' => 0, 'discovery' => 0, 'high_priority' => 0, 'oldest_age' => 0]; - -$recent = $pdo->query(" - SELECT event_id, event_json->>'pubkey' AS pubkey, event_json->>'kind' AS kind, - source_relay, source_class, priority, received_at - FROM caching_event_inbox - ORDER BY received_at DESC - LIMIT 20 -")->fetchAll(); - -admin_header('inbox', 'C-Relay-PG Admin — Inbox'); -?> - -
-
INBOX QUEUE MONITOR
- -
-
-
Pending Events
-
-
live, backfill, discovery
-
-
-
High Priority
-
-
priority = 0 (live events)
-
-
-
Oldest Pending
-
s
-
age of oldest event in queue
-
-
- - 300): ?> -

- ⚠ Oldest pending event is s old — the inbox poller may not be keeping up. - Check that caching_inbox_enabled = true in the config table and the relay is running. -

- -
- -
-
RECENT EVENTS IN QUEUE (last 20)
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Event IDPubkeyKindSource RelayClassPriorityReceived
Inbox is empty — all events have been dequeued.
-
-
- - - - diff --git a/admin/index.php b/admin/index.php index 29a6715..ebb6b27 100644 --- a/admin/index.php +++ b/admin/index.php @@ -1,158 +1,429 @@ query("SELECT * FROM caching_service_state WHERE id = 1")->fetch() ?: []; - -// Active backfill target (table may not exist yet on fresh start) -$active = ['active_pubkey' => '', 'active_relay' => '']; +// Fetch relay info for the header (from config table) +$relay_name = ''; +$relay_desc = ''; +$relay_pubkey = ''; +$relay_version = ''; try { - $active = $pdo->query("SELECT active_pubkey, active_relay FROM caching_backfill_active WHERE id = 1")->fetch() ?: $active; + $relay_name = $pdo->query("SELECT value FROM config WHERE key = 'relay_name'")->fetchColumn() ?: 'C-Relay-PG'; + $relay_desc = $pdo->query("SELECT value FROM config WHERE key = 'relay_description'")->fetchColumn() ?: ''; + $relay_pubkey = $pdo->query("SELECT value FROM config WHERE key = 'relay_pubkey'")->fetchColumn() ?: ''; + $relay_version = $pdo->query("SELECT value FROM config WHERE key = 'relay_version'")->fetchColumn() ?: ''; } catch (PDOException $e) {} -// Error relay summary -$error_stats = ['auto_completed' => 0, 'error_count' => 0, 'timeout_count' => 0, 'incomplete' => 0, 'total' => 0]; -try { - $error_stats = $pdo->query(" - SELECT - COUNT(*) FILTER (WHERE consecutive_errors >= 3) AS auto_completed, - COUNT(*) FILTER (WHERE last_status LIKE 'error%') AS error_count, - COUNT(*) FILTER (WHERE last_status = 'timeout') AS timeout_count, - COUNT(*) FILTER (WHERE complete = false) AS incomplete, - COUNT(*) AS total - FROM caching_backfill_relay_progress - ")->fetch() ?: $error_stats; -} catch (PDOException $e) {} - -// Inbox stats -$inbox = $pdo->query(" - SELECT - COUNT(*) AS pending, - COUNT(*) FILTER (WHERE source_class = 'live') AS live, - COUNT(*) FILTER (WHERE source_class = 'backfill') AS backfill, - COALESCE(EXTRACT(EPOCH FROM NOW())::BIGINT - MIN(received_at), 0) AS oldest_age - FROM caching_event_inbox -")->fetch() ?: ['pending' => 0, 'live' => 0, 'backfill' => 0, 'oldest_age' => 0]; - -// Event counts -$event_stats = $pdo->query("SELECT COUNT(*) AS total, COUNT(DISTINCT pubkey) AS authors FROM events")->fetch() ?: ['total' => 0, 'authors' => 0]; -$kind_stats = $pdo->query("SELECT kind, COUNT(*) AS cnt FROM events GROUP BY kind ORDER BY cnt DESC LIMIT 10")->fetchAll(); - -admin_header('dashboard', 'C-Relay-PG Admin — Dashboard'); -?> - -
-
CACHING SERVICE STATUS
-
-
-
Service State
-
-
Heartbeat:
-
-
-
Followed Authors
-
-
relays, connected
-
-
-
Backfill Progress
-
/
-
0 ? round(intval($state['backfill_authors_complete'] ?? 0) / intval($state['backfill_authors_total']) * 100) : 0 ?>% complete
-
-
-
Events Fetched
-
-
inbox inserts
-
-
-
Events in DB
-
-
authors
-
-
-
Inbox Pending
-
-
live, backfill
-
-
-
Error Relays
-
-
auto-completed
-
-
-
Config Generation
-
-
Updated
-
-
-
- -
-
ACTIVE BACKFILL TARGET
-
- -

⚡ Working on: @

- -

✓ Caching complete — no active backfill target

- -
-
- -
-
TOP EVENT KINDS
-
- - - - - - - -
KindCount
-
-
- - - +// Format npub (63 chars) into 3 lines of "xxxxxxx xxxxxxx xxxxxxx" +$formatted_npub = $relay_npub; +if (strlen($relay_npub) === 63) { + $line1 = substr($relay_npub, 0, 7) . ' ' . substr($relay_npub, 7, 7) . ' ' . substr($relay_npub, 14, 7); + $line2 = substr($relay_npub, 21, 7) . ' ' . substr($relay_npub, 28, 7) . ' ' . substr($relay_npub, 35, 7); + $line3 = substr($relay_npub, 42, 7) . ' ' . substr($relay_npub, 49, 7) . ' ' . substr($relay_npub, 56, 7); + $formatted_npub = $line1 . "\n" . $line2 . "\n" . $line3; +} +$display_name = $relay_version ? ($relay_name . ' ' . $relay_version) : $relay_name; +?> + + + + + + + C-Relay-PG Admin + + + + + + + + +
+ + +
+
+
+ R + E + L + A + Y +
+
+
+
+
+
+
+
+ +
+
+ + + + + + + + +
+
DATABASE STATISTICS
+ + +
+ + + + +
+
Loading chart...
+ + +
+
+ + + + + + + + + + + + + + +
MetricValue
Database Size-
Total Events-
Process ID-
WebSocket Connections-
Active Subscriptions-
Memory Usage-
CPU Usage-
CPU Core-
Oldest Event-
Newest Event-
+
+
+ + +
+ +
+ + + + + +
Event KindCountPercentage
Loading...
+
+
+ + +
+ +
+ + + + + + + +
PeriodEvents
Last 24 Hours-
Last 7 Days-
Last 30 Days-
+
+
+ + +
+ +
+ + + + + +
RankNamePubkeyEvent CountPercentage
Loading...
+
+
+ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/admin/lib/ascii_chart.php b/admin/lib/ascii_chart.php new file mode 100644 index 0000000..bb93593 --- /dev/null +++ b/admin/lib/ascii_chart.php @@ -0,0 +1,147 @@ + + * injection (white-space: pre) and terminal display via curl. + */ + +/** + * Render an ASCII bar chart from an array of bin counts. + * + * @param array $bins Array of integer counts (one per time bin, left=oldest) + * @param array $options { + * @var string $title Chart title (centered at top) + * @var int $max_height Chart height in rows (default 11) + * @var string $x_axis_label Label below the X-axis (default '') + * @var int $bin_duration Seconds per bin — for X-axis elapsed labels + * @var int $label_interval Label every N bins (default 5) + * } + * @return string The ASCII chart as a multi-line string. + */ +function render_ascii_chart(array $bins, array $options = []): string { + $title = $options['title'] ?? 'New Events'; + $max_height = $options['max_height'] ?? 11; + $x_axis_label = $options['x_axis_label'] ?? ''; + $bin_duration = $options['bin_duration'] ?? 10; + $label_interval = $options['label_interval'] ?? 5; + + $num_bins = count($bins); + if ($num_bins === 0) { + return "No data available.\n"; + } + + $max_count = max($bins); + if ($max_count < 1) $max_count = 1; // Avoid division by zero for all-empty bins + + // Scaling: each X represents scale_factor counts + $scale_factor = max(1, (int)ceil($max_count / $max_height)); + $scaled_max = (int)ceil($max_count / $scale_factor) * $scale_factor; + + $output = ''; + + // --- Title (centered) --- + $chart_width = 4 + $num_bins; // 4 = Y-axis number width (3) + separator (1) + if ($title !== '') { + $title_padding = (int)floor(($chart_width - strlen($title)) / 2); + if ($title_padding < 0) $title_padding = 0; + $output .= str_repeat(' ', $title_padding) . $title . "\n\n"; + } + + // --- Bar rows (top to bottom) --- + for ($row = $max_height; $row > 0; $row--) { + $row_count = ($row - 1) * $scale_factor + 1; + $line = str_pad((string)$row_count, 3, ' ', STR_PAD_LEFT) . ' |'; + + for ($i = 0; $i < $num_bins; $i++) { + $count = $bins[$i]; + $scaled_height = ($count > 0) ? (int)ceil($count / $scale_factor) : 0; + $line .= ($scaled_height >= $row) ? 'X' : ' '; + } + $output .= $line . "\n"; + } + + // --- X-axis line --- + $output .= ' +' . str_repeat('-', $num_bins) . "\n"; + + // --- X-axis labels (elapsed time every label_interval bins) --- + $label_line = ' '; + $labels = []; + for ($i = 0; $i < $num_bins; $i++) { + if ($i % $label_interval === 0) { + $elapsed_sec = $i * $bin_duration; + $labels[] = format_elapsed_time($elapsed_sec); + } + } + // Build label line with spacing + for ($i = 0; $i < count($labels); $i++) { + $label_line .= $labels[$i]; + if ($i < count($labels) - 1) { + $spacing = $label_interval - strlen($labels[$i]); + if ($spacing < 1) $spacing = 1; + $label_line .= str_repeat(' ', $spacing); + } + } + // Pad to match X-axis dash line length + $min_label_len = 4 + $num_bins; + if (strlen($label_line) < $min_label_len) { + $label_line .= str_repeat(' ', $min_label_len - strlen($label_line)); + } + $output .= $label_line . "\n"; + + // --- X-axis label (if provided) --- + if ($x_axis_label !== '') { + $label_pad = (int)floor(($num_bins - strlen($x_axis_label)) / 2); + if ($label_pad < 0) $label_pad = 0; + $output .= "\n" . ' ' . str_repeat(' ', $label_pad) . $x_axis_label . "\n"; + } + + return $output; +} + +/** + * Format an elapsed time in seconds as a compact label. + * < 60s → "Ns" + * < 1h → "Nm" + * < 1d → "Nh" + * else → "Nd" + */ +function format_elapsed_time(int $seconds): string { + if ($seconds < 60) { + return $seconds . 's'; + } elseif ($seconds < 3600) { + return (int)floor($seconds / 60) . 'm'; + } elseif ($seconds < 86400) { + return (int)floor($seconds / 3600) . 'h'; + } else { + return (int)floor($seconds / 86400) . 'd'; + } +} + +/** + * Build a fixed-length bin array from SQL query rows. + * + * The query returns only non-empty bins. This function creates a + * zero-filled array of $num_bins length and overlays the counts + * at the correct positions, so empty time slots show as blank + * columns — the chart always advances in time. + * + * @param array $rows Query rows with 'bin' (int) and 'cnt' (int) + * @param int $num_bins Total number of bins (fixed length) + * @return array Zero-filled array of counts + */ +function build_bin_array(array $rows, int $num_bins): array { + $bins = array_fill(0, $num_bins, 0); + foreach ($rows as $r) { + $idx = (int)$r['bin']; + if ($idx >= 0 && $idx < $num_bins) { + $bins[$idx] = (int)$r['cnt']; + } + } + return $bins; +} diff --git a/admin/lib/db.php b/admin/lib/db.php index 8c6de96..85afaef 100644 --- a/admin/lib/db.php +++ b/admin/lib/db.php @@ -12,14 +12,18 @@ function db(): PDO { static $pdo = null; if ($pdo === null) { $cfg = require __DIR__ . '/config.php'; + // Build DSN — supports both TCP (host=localhost) and Unix socket + // (host=/var/run/postgresql). Omit password if empty (peer auth). $dsn = sprintf( - 'pgsql:host=%s;port=%d;dbname=%s;user=%s;password=%s', + 'pgsql:host=%s;port=%d;dbname=%s;user=%s', $cfg['db_host'], $cfg['db_port'], $cfg['db_name'], - $cfg['db_user'], - $cfg['db_password'] + $cfg['db_user'] ); + if (!empty($cfg['db_password'])) { + $dsn .= ';password=' . $cfg['db_password']; + } try { $pdo = new PDO($dsn, null, null, [ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, diff --git a/admin/lib/helpers.php b/admin/lib/helpers.php index 032366c..1938676 100644 --- a/admin/lib/helpers.php +++ b/admin/lib/helpers.php @@ -126,6 +126,62 @@ function query_param(string $key, $default = null) { return $_GET[$key] ?? $default; } +/** + * Batch-resolve profiles from the profiles cache table. + * Returns [pubkey_hex => ['name'=>..., 'display_name'=>..., + * 'best_name'=>..., 'picture'=>..., 'nip05'=>...]]. + * Pubkeys with no cached profile are absent from the result. + */ +function profile_map(array $pubkeys): array { + if (empty($pubkeys)) return []; + $pdo = db(); + $map = []; + try { + // Build parameterized IN clause: WHERE pubkey = ANY(?) + // PDO PostgreSQL supports passing an array as a string literal. + $placeholders = implode(',', array_fill(0, count($pubkeys), '?')); + $stmt = $pdo->prepare( + "SELECT pubkey, name, display_name, picture, nip05 FROM profiles " + . "WHERE pubkey IN ($placeholders)" + ); + $stmt->execute(array_values($pubkeys)); + $rows = $stmt->fetchAll(); + foreach ($rows as $r) { + $map[$r['pubkey']] = [ + 'name' => $r['name'] ?? '', + 'display_name' => $r['display_name'] ?? '', + 'best_name' => profile_display_name($r), + 'picture' => $r['picture'] ?? '', + 'nip05' => $r['nip05'] ?? '', + ]; + } + } catch (PDOException $e) {} + return $map; +} + +/** + * Apply the profile_name_preference config key to resolve the display name. + * Never returns null. Returns '' if neither field is set. + */ +function profile_display_name(array $profile): string { + $name = $profile['name'] ?? ''; + $display_name = $profile['display_name'] ?? ''; + static $pref = null; + if ($pref === null) { + try { + $pdo = db(); + $pref = $pdo->query("SELECT value FROM config WHERE key = 'profile_name_preference'")->fetchColumn() ?: 'display_name'; + } catch (PDOException $e) { + $pref = 'display_name'; + } + } + if ($pref === 'name') { + return $name !== '' ? $name : $display_name; + } + // Default: prefer display_name, fall back to name. + return $display_name !== '' ? $display_name : $name; +} + /** * Render the shared HTML header with side navigation. * Pass the active page name to highlight the current nav item. diff --git a/admin/php_server.log b/admin/php_server.log new file mode 100644 index 0000000..601dac6 --- /dev/null +++ b/admin/php_server.log @@ -0,0 +1,8754 @@ +[Thu Jul 30 15:56:32 2026] PHP 8.4.23 Development Server (http://127.0.0.1:8088) started +[Thu Jul 30 15:56:36 2026] 127.0.0.1:56782 Accepted +[Thu Jul 30 15:56:36 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 15:56:36 2026] 127.0.0.1:56782 [200]: GET /api/stats.php +[Thu Jul 30 15:56:36 2026] 127.0.0.1:56782 Closing +[Thu Jul 30 15:56:36 2026] 127.0.0.1:56792 Accepted +[Thu Jul 30 15:56:36 2026] 127.0.0.1:56792 [200]: GET /api/chart.php?range=hour +[Thu Jul 30 15:56:36 2026] 127.0.0.1:56792 Closing +[Thu Jul 30 15:56:46 2026] 127.0.0.1:49262 Accepted +[Thu Jul 30 15:56:46 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 15:56:46 2026] 127.0.0.1:49262 [200]: GET /api/stats.php +[Thu Jul 30 15:56:46 2026] 127.0.0.1:49262 Closing +[Thu Jul 30 15:56:46 2026] 127.0.0.1:49266 Accepted +[Thu Jul 30 15:56:46 2026] 127.0.0.1:49266 [200]: GET /api/chart.php?range=hour +[Thu Jul 30 15:56:46 2026] 127.0.0.1:49266 Closing +[Thu Jul 30 15:56:56 2026] 127.0.0.1:58436 Accepted +[Thu Jul 30 15:56:56 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 15:56:56 2026] 127.0.0.1:58436 [200]: GET /api/stats.php +[Thu Jul 30 15:56:56 2026] 127.0.0.1:58436 Closing +[Thu Jul 30 15:56:56 2026] 127.0.0.1:58440 Accepted +[Thu Jul 30 15:56:56 2026] 127.0.0.1:58440 [200]: GET /api/chart.php?range=hour +[Thu Jul 30 15:56:56 2026] 127.0.0.1:58440 Closing +[Thu Jul 30 15:56:58 2026] 127.0.0.1:58450 Accepted +[Thu Jul 30 15:56:58 2026] 127.0.0.1:58450 [200]: GET / +[Thu Jul 30 15:56:58 2026] 127.0.0.1:58450 Closing +[Thu Jul 30 15:56:58 2026] 127.0.0.1:58460 Accepted +[Thu Jul 30 15:56:58 2026] 127.0.0.1:58460 [200]: GET /api/chart.php?range=hour +[Thu Jul 30 15:56:58 2026] 127.0.0.1:58460 Closing +[Thu Jul 30 15:56:58 2026] 127.0.0.1:58472 Accepted +[Thu Jul 30 15:56:58 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 15:56:58 2026] 127.0.0.1:58472 [200]: GET /api/stats.php +[Thu Jul 30 15:56:58 2026] 127.0.0.1:58472 Closing +[Thu Jul 30 15:56:58 2026] 127.0.0.1:58486 Accepted +[Thu Jul 30 15:56:58 2026] 127.0.0.1:58486 [200]: GET /api/chart.php?range=hour +[Thu Jul 30 15:56:58 2026] 127.0.0.1:58486 Closing +[Thu Jul 30 15:57:06 2026] 127.0.0.1:42862 Accepted +[Thu Jul 30 15:57:06 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 15:57:06 2026] 127.0.0.1:42862 [200]: GET /api/stats.php +[Thu Jul 30 15:57:06 2026] 127.0.0.1:42862 Closing +[Thu Jul 30 15:57:06 2026] 127.0.0.1:42868 Accepted +[Thu Jul 30 15:57:06 2026] 127.0.0.1:42868 [200]: GET /api/chart.php?range=hour +[Thu Jul 30 15:57:06 2026] 127.0.0.1:42868 Closing +[Thu Jul 30 15:57:16 2026] 127.0.0.1:39444 Accepted +[Thu Jul 30 15:57:16 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 15:57:16 2026] 127.0.0.1:39444 [200]: GET /api/stats.php +[Thu Jul 30 15:57:16 2026] 127.0.0.1:39444 Closing +[Thu Jul 30 15:57:16 2026] 127.0.0.1:39458 Accepted +[Thu Jul 30 15:57:16 2026] 127.0.0.1:39458 [200]: GET /api/chart.php?range=hour +[Thu Jul 30 15:57:16 2026] 127.0.0.1:39458 Closing +[Thu Jul 30 15:57:26 2026] 127.0.0.1:37650 Accepted +[Thu Jul 30 15:57:26 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 15:57:26 2026] 127.0.0.1:37650 [200]: GET /api/stats.php +[Thu Jul 30 15:57:26 2026] 127.0.0.1:37650 Closing +[Thu Jul 30 15:57:26 2026] 127.0.0.1:37666 Accepted +[Thu Jul 30 15:57:26 2026] 127.0.0.1:37666 [200]: GET /api/chart.php?range=hour +[Thu Jul 30 15:57:26 2026] 127.0.0.1:37666 Closing +[Thu Jul 30 15:57:28 2026] 127.0.0.1:37680 Accepted +[Thu Jul 30 15:57:28 2026] 127.0.0.1:37680 [200]: GET / +[Thu Jul 30 15:57:28 2026] 127.0.0.1:37680 Closing +[Thu Jul 30 15:57:28 2026] 127.0.0.1:37682 Accepted +[Thu Jul 30 15:57:28 2026] 127.0.0.1:37696 Accepted +[Thu Jul 30 15:57:28 2026] 127.0.0.1:37700 Accepted +[Thu Jul 30 15:57:28 2026] 127.0.0.1:37710 Accepted +[Thu Jul 30 15:57:28 2026] 127.0.0.1:37682 [200]: GET /assets/index.css +[Thu Jul 30 15:57:28 2026] 127.0.0.1:37696 [200]: GET /assets/nostr.bundle.js +[Thu Jul 30 15:57:28 2026] 127.0.0.1:37700 [200]: GET /assets/nostr-lite.js +[Thu Jul 30 15:57:28 2026] 127.0.0.1:37710 [200]: GET /assets/app.js +[Thu Jul 30 15:57:28 2026] 127.0.0.1:37682 Closing +[Thu Jul 30 15:57:28 2026] 127.0.0.1:37710 Closing +[Thu Jul 30 15:57:28 2026] 127.0.0.1:37700 Closing +[Thu Jul 30 15:57:28 2026] 127.0.0.1:37696 Closing +[Thu Jul 30 15:57:28 2026] 127.0.0.1:37716 Accepted +[Thu Jul 30 15:57:28 2026] 127.0.0.1:37716 [200]: GET /.well-known/appspecific/com.chrome.devtools.json +[Thu Jul 30 15:57:28 2026] 127.0.0.1:37716 Closing +[Thu Jul 30 15:57:28 2026] 127.0.0.1:37726 Accepted +[Thu Jul 30 15:57:28 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 15:57:28 2026] 127.0.0.1:37726 [200]: GET /api/stats.php +[Thu Jul 30 15:57:28 2026] 127.0.0.1:37726 Closing +[Thu Jul 30 15:57:28 2026] 127.0.0.1:37740 Accepted +[Thu Jul 30 15:57:28 2026] 127.0.0.1:37752 Accepted +[Thu Jul 30 15:57:28 2026] 127.0.0.1:37740 [200]: GET /api/chart.php?range=hour +[Thu Jul 30 15:57:28 2026] 127.0.0.1:37740 Closing +[Thu Jul 30 15:57:28 2026] 127.0.0.1:37754 Accepted +[Thu Jul 30 15:57:28 2026] 127.0.0.1:37752 [200]: GET /favicon.ico +[Thu Jul 30 15:57:28 2026] 127.0.0.1:37752 Closing +[Thu Jul 30 15:57:28 2026] 127.0.0.1:37758 Accepted +[Thu Jul 30 15:57:28 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 15:57:29 2026] 127.0.0.1:37754 [200]: GET /api/stats.php +[Thu Jul 30 15:57:29 2026] 127.0.0.1:37754 Closing +[Thu Jul 30 15:57:29 2026] 127.0.0.1:37758 [200]: GET /api/chart.php?range=hour +[Thu Jul 30 15:57:29 2026] 127.0.0.1:37758 Closing +[Thu Jul 30 15:57:29 2026] 127.0.0.1:37760 Accepted +[Thu Jul 30 15:57:29 2026] 127.0.0.1:37760 [200]: GET /api/chart.php?range=hour +[Thu Jul 30 15:57:29 2026] 127.0.0.1:37760 Closing +[Thu Jul 30 15:57:38 2026] 127.0.0.1:51134 Accepted +[Thu Jul 30 15:57:38 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 15:57:38 2026] 127.0.0.1:51134 [200]: GET /api/stats.php +[Thu Jul 30 15:57:38 2026] 127.0.0.1:51134 Closing +[Thu Jul 30 15:57:38 2026] 127.0.0.1:51146 Accepted +[Thu Jul 30 15:57:38 2026] 127.0.0.1:51146 [200]: GET /api/chart.php?range=hour +[Thu Jul 30 15:57:38 2026] 127.0.0.1:51146 Closing +[Thu Jul 30 15:57:39 2026] 127.0.0.1:51162 Accepted +[Thu Jul 30 15:57:39 2026] 127.0.0.1:51162 [200]: GET /api/subscriptions.php +[Thu Jul 30 15:57:39 2026] 127.0.0.1:51162 Closing +[Thu Jul 30 15:57:42 2026] 127.0.0.1:51178 Accepted +[Thu Jul 30 15:57:42 2026] 127.0.0.1:51178 [200]: GET /api/caching.php +[Thu Jul 30 15:57:42 2026] 127.0.0.1:51178 Closing +[Thu Jul 30 16:32:18 2026] 127.0.0.1:56610 Accepted +[Thu Jul 30 16:32:18 2026] 127.0.0.1:56610 [200]: GET /api/chart.php?range=year +[Thu Jul 30 16:32:18 2026] 127.0.0.1:56610 Closing +[Thu Jul 30 16:33:01 2026] 127.0.0.1:45180 Accepted +[Thu Jul 30 16:33:01 2026] 127.0.0.1:45180 [200]: GET /api/chart.php?range=month +[Thu Jul 30 16:33:01 2026] 127.0.0.1:45180 Closing +[Thu Jul 30 16:33:08 2026] 127.0.0.1:52132 Accepted +[Thu Jul 30 16:33:08 2026] 127.0.0.1:52132 [200]: GET /api/chart.php?range=day +[Thu Jul 30 16:33:08 2026] 127.0.0.1:52132 Closing +[Thu Jul 30 16:47:03 2026] 127.0.0.1:32860 Accepted +[Thu Jul 30 16:47:03 2026] 127.0.0.1:32860 [200]: GET / +[Thu Jul 30 16:47:03 2026] 127.0.0.1:32860 Closing +[Thu Jul 30 16:47:03 2026] 127.0.0.1:32864 Accepted +[Thu Jul 30 16:47:03 2026] 127.0.0.1:32864 [200]: GET /.well-known/appspecific/com.chrome.devtools.json +[Thu Jul 30 16:47:03 2026] 127.0.0.1:32864 Closing +[Thu Jul 30 16:47:03 2026] 127.0.0.1:32874 Accepted +[Thu Jul 30 16:47:03 2026] 127.0.0.1:32874 [200]: GET /assets/index.css +[Thu Jul 30 16:47:03 2026] 127.0.0.1:32874 Closing +[Thu Jul 30 16:47:03 2026] 127.0.0.1:32888 Accepted +[Thu Jul 30 16:47:03 2026] 127.0.0.1:32888 [200]: GET /assets/nostr.bundle.js +[Thu Jul 30 16:47:03 2026] 127.0.0.1:32900 Accepted +[Thu Jul 30 16:47:03 2026] 127.0.0.1:32912 Accepted +[Thu Jul 30 16:47:03 2026] 127.0.0.1:32888 Closing +[Thu Jul 30 16:47:03 2026] 127.0.0.1:32900 [200]: GET /assets/nostr-lite.js +[Thu Jul 30 16:47:03 2026] 127.0.0.1:32912 [200]: GET /assets/app.js +[Thu Jul 30 16:47:03 2026] 127.0.0.1:32900 Closing +[Thu Jul 30 16:47:03 2026] 127.0.0.1:32912 Closing +[Thu Jul 30 16:47:03 2026] 127.0.0.1:32920 Accepted +[Thu Jul 30 16:47:04 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 16:47:04 2026] 127.0.0.1:32920 [200]: GET /api/stats.php +[Thu Jul 30 16:47:04 2026] 127.0.0.1:32920 Closing +[Thu Jul 30 16:47:04 2026] 127.0.0.1:32922 Accepted +[Thu Jul 30 16:47:04 2026] 127.0.0.1:32934 Accepted +[Thu Jul 30 16:47:04 2026] 127.0.0.1:32922 [200]: GET /api/chart.php?range=hour +[Thu Jul 30 16:47:04 2026] 127.0.0.1:32922 Closing +[Thu Jul 30 16:47:04 2026] 127.0.0.1:32940 Accepted +[Thu Jul 30 16:47:04 2026] 127.0.0.1:32934 [200]: GET /favicon.ico +[Thu Jul 30 16:47:04 2026] 127.0.0.1:32934 Closing +[Thu Jul 30 16:47:04 2026] 127.0.0.1:32942 Accepted +[Thu Jul 30 16:47:04 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 16:47:04 2026] 127.0.0.1:32940 [200]: GET /api/stats.php +[Thu Jul 30 16:47:04 2026] 127.0.0.1:32940 Closing +[Thu Jul 30 16:47:04 2026] 127.0.0.1:32942 [200]: GET /api/chart.php?range=hour +[Thu Jul 30 16:47:04 2026] 127.0.0.1:32942 Closing +[Thu Jul 30 16:47:04 2026] 127.0.0.1:32946 Accepted +[Thu Jul 30 16:47:04 2026] 127.0.0.1:32946 [200]: GET /api/chart.php?range=hour +[Thu Jul 30 16:47:04 2026] 127.0.0.1:32946 Closing +[Thu Jul 30 16:47:05 2026] 127.0.0.1:32962 Accepted +[Thu Jul 30 16:47:05 2026] 127.0.0.1:32962 [200]: GET /api/profile.php?pubkey=8ff74724ed641b3c28e5a86d7c5cbc49c37638ace8c6c38935860e7a5eedde0e +[Thu Jul 30 16:47:05 2026] 127.0.0.1:32962 Closing +[Thu Jul 30 16:47:13 2026] 127.0.0.1:44000 Accepted +[Thu Jul 30 16:47:13 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 16:47:13 2026] 127.0.0.1:44000 [200]: GET /api/stats.php +[Thu Jul 30 16:47:13 2026] 127.0.0.1:44000 Closing +[Thu Jul 30 16:47:13 2026] 127.0.0.1:44016 Accepted +[Thu Jul 30 16:47:13 2026] 127.0.0.1:44016 [200]: GET /api/chart.php?range=hour +[Thu Jul 30 16:47:13 2026] 127.0.0.1:44016 Closing +[Thu Jul 30 16:47:18 2026] 127.0.0.1:38856 Accepted +[Thu Jul 30 16:47:18 2026] 127.0.0.1:38856 [200]: GET /api/events.php?limit=50 +[Thu Jul 30 16:47:18 2026] 127.0.0.1:38856 Closing +[Thu Jul 30 16:48:49 2026] 127.0.0.1:36120 Accepted +[Thu Jul 30 16:48:49 2026] 127.0.0.1:36120 [200]: GET /api/caching.php +[Thu Jul 30 16:48:49 2026] 127.0.0.1:36120 Closing +[Thu Jul 30 16:49:17 2026] 127.0.0.1:39304 Accepted +[Thu Jul 30 16:49:17 2026] 127.0.0.1:39304 [200]: GET / +[Thu Jul 30 16:49:17 2026] 127.0.0.1:39304 Closing +[Thu Jul 30 16:49:17 2026] 127.0.0.1:39312 Accepted +[Thu Jul 30 16:49:17 2026] 127.0.0.1:39312 [200]: GET /assets/index.css +[Thu Jul 30 16:49:17 2026] 127.0.0.1:39312 Closing +[Thu Jul 30 16:49:17 2026] 127.0.0.1:39322 Accepted +[Thu Jul 30 16:49:17 2026] 127.0.0.1:39324 Accepted +[Thu Jul 30 16:49:17 2026] 127.0.0.1:39322 [200]: GET /assets/nostr.bundle.js +[Thu Jul 30 16:49:17 2026] 127.0.0.1:39324 [200]: GET /assets/nostr-lite.js +[Thu Jul 30 16:49:17 2026] 127.0.0.1:39322 Closing +[Thu Jul 30 16:49:17 2026] 127.0.0.1:39324 Closing +[Thu Jul 30 16:49:17 2026] 127.0.0.1:39338 Accepted +[Thu Jul 30 16:49:17 2026] 127.0.0.1:39338 [200]: GET /assets/app.js +[Thu Jul 30 16:49:17 2026] 127.0.0.1:39338 Closing +[Thu Jul 30 16:49:17 2026] 127.0.0.1:39344 Accepted +[Thu Jul 30 16:49:17 2026] 127.0.0.1:39344 [200]: GET /.well-known/appspecific/com.chrome.devtools.json +[Thu Jul 30 16:49:17 2026] 127.0.0.1:39344 Closing +[Thu Jul 30 16:49:17 2026] 127.0.0.1:39354 Accepted +[Thu Jul 30 16:49:17 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 16:49:17 2026] 127.0.0.1:39354 [200]: GET /api/stats.php +[Thu Jul 30 16:49:17 2026] 127.0.0.1:39354 Closing +[Thu Jul 30 16:49:17 2026] 127.0.0.1:39370 Accepted +[Thu Jul 30 16:49:17 2026] 127.0.0.1:39380 Accepted +[Thu Jul 30 16:49:17 2026] 127.0.0.1:39370 [200]: GET /api/chart.php?range=hour +[Thu Jul 30 16:49:17 2026] 127.0.0.1:39370 Closing +[Thu Jul 30 16:49:17 2026] 127.0.0.1:39394 Accepted +[Thu Jul 30 16:49:17 2026] 127.0.0.1:39380 [200]: GET /favicon.ico +[Thu Jul 30 16:49:17 2026] 127.0.0.1:39380 Closing +[Thu Jul 30 16:49:17 2026] 127.0.0.1:39406 Accepted +[Thu Jul 30 16:49:17 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 16:49:18 2026] 127.0.0.1:39394 [200]: GET /api/stats.php +[Thu Jul 30 16:49:18 2026] 127.0.0.1:39394 Closing +[Thu Jul 30 16:49:18 2026] 127.0.0.1:39406 [200]: GET /api/chart.php?range=hour +[Thu Jul 30 16:49:18 2026] 127.0.0.1:39406 Closing +[Thu Jul 30 16:49:18 2026] 127.0.0.1:39412 Accepted +[Thu Jul 30 16:49:18 2026] 127.0.0.1:39412 [200]: GET /api/profile.php?pubkey=8ff74724ed641b3c28e5a86d7c5cbc49c37638ace8c6c38935860e7a5eedde0e +[Thu Jul 30 16:49:18 2026] 127.0.0.1:39412 Closing +[Thu Jul 30 16:49:18 2026] 127.0.0.1:39426 Accepted +[Thu Jul 30 16:49:18 2026] 127.0.0.1:39426 [200]: GET /api/chart.php?range=hour +[Thu Jul 30 16:49:18 2026] 127.0.0.1:39426 Closing +[Thu Jul 30 16:49:23 2026] 127.0.0.1:39436 Accepted +[Thu Jul 30 16:49:23 2026] 127.0.0.1:39436 [200]: GET /api/events.php?limit=50 +[Thu Jul 30 16:49:23 2026] 127.0.0.1:39436 Closing +[Thu Jul 30 16:49:42 2026] 127.0.0.1:59184 Accepted +[Thu Jul 30 16:49:42 2026] 127.0.0.1:59184 [200]: GET /api/caching.php +[Thu Jul 30 16:49:42 2026] 127.0.0.1:59184 Closing +[Thu Jul 30 17:48:32 2026] 127.0.0.1:40002 Accepted +[Thu Jul 30 17:48:32 2026] 127.0.0.1:40002 [200]: GET / +[Thu Jul 30 17:48:32 2026] 127.0.0.1:40002 Closing +[Thu Jul 30 17:48:32 2026] 127.0.0.1:40006 Accepted +[Thu Jul 30 17:48:32 2026] 127.0.0.1:40006 [200]: GET /assets/index.css +[Thu Jul 30 17:48:32 2026] 127.0.0.1:40006 Closing +[Thu Jul 30 17:48:32 2026] 127.0.0.1:40010 Accepted +[Thu Jul 30 17:48:32 2026] 127.0.0.1:40020 Accepted +[Thu Jul 30 17:48:32 2026] 127.0.0.1:40030 Accepted +[Thu Jul 30 17:48:32 2026] 127.0.0.1:40010 [200]: GET /assets/nostr.bundle.js +[Thu Jul 30 17:48:32 2026] 127.0.0.1:40020 [200]: GET /assets/nostr-lite.js +[Thu Jul 30 17:48:32 2026] 127.0.0.1:40030 [200]: GET /assets/app.js +[Thu Jul 30 17:48:32 2026] 127.0.0.1:40030 Closing +[Thu Jul 30 17:48:32 2026] 127.0.0.1:40010 Closing +[Thu Jul 30 17:48:32 2026] 127.0.0.1:40020 Closing +[Thu Jul 30 17:48:32 2026] 127.0.0.1:40038 Accepted +[Thu Jul 30 17:48:32 2026] 127.0.0.1:40052 Accepted +[Thu Jul 30 17:48:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 17:48:32 2026] 127.0.0.1:40038 [200]: GET /api/stats.php +[Thu Jul 30 17:48:32 2026] 127.0.0.1:40038 Closing +[Thu Jul 30 17:48:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 17:48:32 2026] 127.0.0.1:40052 [200]: GET /api/stats.php +[Thu Jul 30 17:48:32 2026] 127.0.0.1:40052 Closing +[Thu Jul 30 17:48:32 2026] 127.0.0.1:40068 Accepted +[Thu Jul 30 17:48:32 2026] 127.0.0.1:40076 Accepted +[Thu Jul 30 17:48:32 2026] 127.0.0.1:40068 [200]: GET /api/chart.php?range=hour +[Thu Jul 30 17:48:32 2026] 127.0.0.1:40068 Closing +[Thu Jul 30 17:48:32 2026] 127.0.0.1:40076 [200]: GET /favicon.ico +[Thu Jul 30 17:48:32 2026] 127.0.0.1:40076 Closing +[Thu Jul 30 17:48:32 2026] 127.0.0.1:40084 Accepted +[Thu Jul 30 17:48:33 2026] 127.0.0.1:40084 [200]: GET /api/chart.php?range=hour +[Thu Jul 30 17:48:33 2026] 127.0.0.1:40084 Closing +[Thu Jul 30 17:48:33 2026] 127.0.0.1:40088 Accepted +[Thu Jul 30 17:48:33 2026] 127.0.0.1:40088 [200]: GET /api/chart.php?range=hour +[Thu Jul 30 17:48:33 2026] 127.0.0.1:40088 Closing +[Thu Jul 30 17:48:33 2026] 127.0.0.1:40090 Accepted +[Thu Jul 30 17:48:33 2026] 127.0.0.1:40090 [200]: GET /api/profile.php?pubkey=8ff74724ed641b3c28e5a86d7c5cbc49c37638ace8c6c38935860e7a5eedde0e +[Thu Jul 30 17:48:33 2026] 127.0.0.1:40090 Closing +[Thu Jul 30 17:48:35 2026] 127.0.0.1:40092 Accepted +[Thu Jul 30 17:48:35 2026] 127.0.0.1:40092 [200]: GET /api/chart.php?range=day +[Thu Jul 30 17:48:35 2026] 127.0.0.1:40092 Closing +[Thu Jul 30 17:48:37 2026] 127.0.0.1:52116 Accepted +[Thu Jul 30 17:48:37 2026] 127.0.0.1:52116 [200]: GET /api/chart.php?range=month +[Thu Jul 30 17:48:37 2026] 127.0.0.1:52116 Closing +[Thu Jul 30 17:48:40 2026] 127.0.0.1:52120 Accepted +[Thu Jul 30 17:48:40 2026] 127.0.0.1:52120 [200]: GET /api/chart.php?range=year +[Thu Jul 30 17:48:40 2026] 127.0.0.1:52120 Closing +[Thu Jul 30 17:48:42 2026] 127.0.0.1:52128 Accepted +[Thu Jul 30 17:48:42 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 17:48:42 2026] 127.0.0.1:52128 [200]: GET /api/stats.php +[Thu Jul 30 17:48:42 2026] 127.0.0.1:52128 Closing +[Thu Jul 30 17:48:42 2026] 127.0.0.1:52144 Accepted +[Thu Jul 30 17:48:42 2026] 127.0.0.1:52144 [200]: GET /api/chart.php?range=year +[Thu Jul 30 17:48:42 2026] 127.0.0.1:52144 Closing +[Thu Jul 30 17:48:43 2026] 127.0.0.1:52160 Accepted +[Thu Jul 30 17:48:43 2026] 127.0.0.1:52160 [200]: GET /api/chart.php?range=hour +[Thu Jul 30 17:48:43 2026] 127.0.0.1:52160 Closing +[Thu Jul 30 17:48:44 2026] 127.0.0.1:52164 Accepted +[Thu Jul 30 17:48:44 2026] 127.0.0.1:52164 [200]: GET /api/chart.php?range=day +[Thu Jul 30 17:48:44 2026] 127.0.0.1:52164 Closing +[Thu Jul 30 17:48:46 2026] 127.0.0.1:52178 Accepted +[Thu Jul 30 17:48:46 2026] 127.0.0.1:52178 [200]: GET /api/chart.php?range=hour +[Thu Jul 30 17:48:46 2026] 127.0.0.1:52178 Closing +[Thu Jul 30 17:48:48 2026] 127.0.0.1:45848 Accepted +[Thu Jul 30 17:48:48 2026] 127.0.0.1:45848 [200]: GET /api/caching.php +[Thu Jul 30 17:48:48 2026] 127.0.0.1:45848 Closing +[Thu Jul 30 18:40:01 2026] 127.0.0.1:49216 Accepted +[Thu Jul 30 18:40:01 2026] 127.0.0.1:49216 [200]: GET / +[Thu Jul 30 18:40:01 2026] 127.0.0.1:49216 Closing +[Thu Jul 30 18:40:01 2026] 127.0.0.1:49220 Accepted +[Thu Jul 30 18:40:01 2026] 127.0.0.1:49220 [200]: GET /assets/index.css +[Thu Jul 30 18:40:01 2026] 127.0.0.1:49234 Accepted +[Thu Jul 30 18:40:01 2026] 127.0.0.1:49248 Accepted +[Thu Jul 30 18:40:01 2026] 127.0.0.1:49220 Closing +[Thu Jul 30 18:40:01 2026] 127.0.0.1:49264 Accepted +[Thu Jul 30 18:40:01 2026] 127.0.0.1:49234 [200]: GET /assets/nostr.bundle.js +[Thu Jul 30 18:40:01 2026] 127.0.0.1:49264 [200]: GET /assets/app.js +[Thu Jul 30 18:40:01 2026] 127.0.0.1:49248 [200]: GET /assets/nostr-lite.js +[Thu Jul 30 18:40:01 2026] 127.0.0.1:49264 Closing +[Thu Jul 30 18:40:01 2026] 127.0.0.1:49234 Closing +[Thu Jul 30 18:40:01 2026] 127.0.0.1:49248 Closing +[Thu Jul 30 18:40:01 2026] 127.0.0.1:49270 Accepted +[Thu Jul 30 18:40:03 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 18:40:03 2026] 127.0.0.1:49270 [200]: GET /api/stats.php +[Thu Jul 30 18:40:03 2026] 127.0.0.1:49270 Closing +[Thu Jul 30 18:40:03 2026] 127.0.0.1:49284 Accepted +[Thu Jul 30 18:40:03 2026] 127.0.0.1:49292 Accepted +[Thu Jul 30 18:40:03 2026] 127.0.0.1:49284 [200]: GET /api/chart.php?range=hour +[Thu Jul 30 18:40:03 2026] 127.0.0.1:49284 Closing +[Thu Jul 30 18:40:03 2026] 127.0.0.1:49294 Accepted +[Thu Jul 30 18:40:03 2026] 127.0.0.1:49292 [200]: GET /favicon.ico +[Thu Jul 30 18:40:03 2026] 127.0.0.1:49292 Closing +[Thu Jul 30 18:40:03 2026] 127.0.0.1:49308 Accepted +[Thu Jul 30 18:40:03 2026] 127.0.0.1:49294 [200]: GET /api/profile.php?pubkey=8ff74724ed641b3c28e5a86d7c5cbc49c37638ace8c6c38935860e7a5eedde0e +[Thu Jul 30 18:40:03 2026] 127.0.0.1:49294 Closing +[Thu Jul 30 18:40:03 2026] 127.0.0.1:49318 Accepted +[Thu Jul 30 18:40:03 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 18:40:03 2026] 127.0.0.1:49308 [200]: GET /api/stats.php +[Thu Jul 30 18:40:03 2026] 127.0.0.1:49308 Closing +[Thu Jul 30 18:40:03 2026] 127.0.0.1:49318 [200]: GET /api/chart.php?range=hour +[Thu Jul 30 18:40:03 2026] 127.0.0.1:49318 Closing +[Thu Jul 30 18:40:03 2026] 127.0.0.1:49326 Accepted +[Thu Jul 30 18:40:03 2026] 127.0.0.1:49326 [200]: GET /api/chart.php?range=hour +[Thu Jul 30 18:40:03 2026] 127.0.0.1:49326 Closing +[Thu Jul 30 18:40:05 2026] 127.0.0.1:49328 Accepted +[Thu Jul 30 18:40:05 2026] 127.0.0.1:49328 [200]: GET /api/chart.php?range=day +[Thu Jul 30 18:40:05 2026] 127.0.0.1:49328 Closing +[Thu Jul 30 18:40:06 2026] 127.0.0.1:55346 Accepted +[Thu Jul 30 18:40:06 2026] 127.0.0.1:55346 [200]: GET /api/chart.php?range=month +[Thu Jul 30 18:40:06 2026] 127.0.0.1:55346 Closing +[Thu Jul 30 18:40:07 2026] 127.0.0.1:55362 Accepted +[Thu Jul 30 18:40:07 2026] 127.0.0.1:55362 [200]: GET /api/chart.php?range=year +[Thu Jul 30 18:40:07 2026] 127.0.0.1:55362 Closing +[Thu Jul 30 18:40:08 2026] 127.0.0.1:55366 Accepted +[Thu Jul 30 18:40:08 2026] 127.0.0.1:55366 [200]: GET /api/chart.php?range=month +[Thu Jul 30 18:40:08 2026] 127.0.0.1:55366 Closing +[Thu Jul 30 18:40:09 2026] 127.0.0.1:55368 Accepted +[Thu Jul 30 18:40:09 2026] 127.0.0.1:55368 [200]: GET /api/chart.php?range=day +[Thu Jul 30 18:40:09 2026] 127.0.0.1:55368 Closing +[Thu Jul 30 18:40:10 2026] 127.0.0.1:55374 Accepted +[Thu Jul 30 18:40:10 2026] 127.0.0.1:55374 [200]: GET /api/chart.php?range=hour +[Thu Jul 30 18:40:10 2026] 127.0.0.1:55374 Closing +[Thu Jul 30 18:40:11 2026] 127.0.0.1:55388 Accepted +[Thu Jul 30 18:40:11 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 18:40:11 2026] 127.0.0.1:55388 [200]: GET /api/stats.php +[Thu Jul 30 18:40:11 2026] 127.0.0.1:55388 Closing +[Thu Jul 30 18:40:11 2026] 127.0.0.1:55400 Accepted +[Thu Jul 30 18:40:12 2026] 127.0.0.1:55400 [200]: GET /api/chart.php?range=hour +[Thu Jul 30 18:40:12 2026] 127.0.0.1:55400 Closing +[Thu Jul 30 18:40:13 2026] 127.0.0.1:55406 Accepted +[Thu Jul 30 18:40:13 2026] 127.0.0.1:55406 [200]: GET /api/chart.php?range=day +[Thu Jul 30 18:40:13 2026] 127.0.0.1:55406 Closing +[Thu Jul 30 18:40:14 2026] 127.0.0.1:55410 Accepted +[Thu Jul 30 18:40:14 2026] 127.0.0.1:55410 [200]: GET /api/chart.php?range=month +[Thu Jul 30 18:40:14 2026] 127.0.0.1:55410 Closing +[Thu Jul 30 18:40:15 2026] 127.0.0.1:55426 Accepted +[Thu Jul 30 18:40:15 2026] 127.0.0.1:55426 [200]: GET /api/chart.php?range=year +[Thu Jul 30 18:40:15 2026] 127.0.0.1:55426 Closing +[Thu Jul 30 18:40:21 2026] 127.0.0.1:54046 Accepted +[Thu Jul 30 18:40:21 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 18:40:21 2026] 127.0.0.1:54046 [200]: GET /api/stats.php +[Thu Jul 30 18:40:21 2026] 127.0.0.1:54046 Closing +[Thu Jul 30 18:40:21 2026] 127.0.0.1:54062 Accepted +[Thu Jul 30 18:40:21 2026] 127.0.0.1:54062 [200]: GET /api/chart.php?range=year +[Thu Jul 30 18:40:21 2026] 127.0.0.1:54062 Closing +[Thu Jul 30 18:40:31 2026] 127.0.0.1:41238 Accepted +[Thu Jul 30 18:40:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 18:40:31 2026] 127.0.0.1:41238 [200]: GET /api/stats.php +[Thu Jul 30 18:40:31 2026] 127.0.0.1:41238 Closing +[Thu Jul 30 18:40:31 2026] 127.0.0.1:41250 Accepted +[Thu Jul 30 18:40:31 2026] 127.0.0.1:41250 [200]: GET /api/chart.php?range=year +[Thu Jul 30 18:40:31 2026] 127.0.0.1:41250 Closing +[Thu Jul 30 18:40:41 2026] 127.0.0.1:54792 Accepted +[Thu Jul 30 18:40:41 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 18:40:41 2026] 127.0.0.1:54792 [200]: GET /api/stats.php +[Thu Jul 30 18:40:41 2026] 127.0.0.1:54792 Closing +[Thu Jul 30 18:40:41 2026] 127.0.0.1:54794 Accepted +[Thu Jul 30 18:40:41 2026] 127.0.0.1:54794 [200]: GET /api/chart.php?range=year +[Thu Jul 30 18:40:41 2026] 127.0.0.1:54794 Closing +[Thu Jul 30 18:40:51 2026] 127.0.0.1:37532 Accepted +[Thu Jul 30 18:40:51 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 18:40:51 2026] 127.0.0.1:37532 [200]: GET /api/stats.php +[Thu Jul 30 18:40:51 2026] 127.0.0.1:37532 Closing +[Thu Jul 30 18:40:51 2026] 127.0.0.1:37548 Accepted +[Thu Jul 30 18:40:51 2026] 127.0.0.1:37548 [200]: GET /api/chart.php?range=year +[Thu Jul 30 18:40:51 2026] 127.0.0.1:37548 Closing +[Thu Jul 30 18:41:01 2026] 127.0.0.1:41054 Accepted +[Thu Jul 30 18:41:01 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 18:41:02 2026] 127.0.0.1:41054 [200]: GET /api/stats.php +[Thu Jul 30 18:41:02 2026] 127.0.0.1:41054 Closing +[Thu Jul 30 18:41:02 2026] 127.0.0.1:41066 Accepted +[Thu Jul 30 18:41:02 2026] 127.0.0.1:41066 [200]: GET /api/chart.php?range=year +[Thu Jul 30 18:41:02 2026] 127.0.0.1:41066 Closing +[Thu Jul 30 18:41:11 2026] 127.0.0.1:51786 Accepted +[Thu Jul 30 18:41:11 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 18:41:11 2026] 127.0.0.1:51786 [200]: GET /api/stats.php +[Thu Jul 30 18:41:11 2026] 127.0.0.1:51786 Closing +[Thu Jul 30 18:41:11 2026] 127.0.0.1:51798 Accepted +[Thu Jul 30 18:41:11 2026] 127.0.0.1:51798 [200]: GET /api/chart.php?range=year +[Thu Jul 30 18:41:11 2026] 127.0.0.1:51798 Closing +[Thu Jul 30 18:41:21 2026] 127.0.0.1:50828 Accepted +[Thu Jul 30 18:41:21 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 18:41:22 2026] 127.0.0.1:50828 [200]: GET /api/stats.php +[Thu Jul 30 18:41:22 2026] 127.0.0.1:50828 Closing +[Thu Jul 30 18:41:22 2026] 127.0.0.1:50832 Accepted +[Thu Jul 30 18:41:22 2026] 127.0.0.1:50832 [200]: GET /api/chart.php?range=year +[Thu Jul 30 18:41:22 2026] 127.0.0.1:50832 Closing +[Thu Jul 30 18:41:31 2026] 127.0.0.1:44220 Accepted +[Thu Jul 30 18:41:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 18:41:32 2026] 127.0.0.1:44220 [200]: GET /api/stats.php +[Thu Jul 30 18:41:32 2026] 127.0.0.1:44220 Closing +[Thu Jul 30 18:41:32 2026] 127.0.0.1:44222 Accepted +[Thu Jul 30 18:41:32 2026] 127.0.0.1:44222 [200]: GET /api/chart.php?range=year +[Thu Jul 30 18:41:32 2026] 127.0.0.1:44222 Closing +[Thu Jul 30 18:41:41 2026] 127.0.0.1:59136 Accepted +[Thu Jul 30 18:41:41 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 18:41:41 2026] 127.0.0.1:59136 [200]: GET /api/stats.php +[Thu Jul 30 18:41:41 2026] 127.0.0.1:59136 Closing +[Thu Jul 30 18:41:41 2026] 127.0.0.1:59142 Accepted +[Thu Jul 30 18:41:41 2026] 127.0.0.1:59142 [200]: GET /api/chart.php?range=year +[Thu Jul 30 18:41:41 2026] 127.0.0.1:59142 Closing +[Thu Jul 30 18:41:51 2026] 127.0.0.1:34988 Accepted +[Thu Jul 30 18:41:51 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 18:41:51 2026] 127.0.0.1:34988 [200]: GET /api/stats.php +[Thu Jul 30 18:41:51 2026] 127.0.0.1:34988 Closing +[Thu Jul 30 18:41:51 2026] 127.0.0.1:34994 Accepted +[Thu Jul 30 18:41:51 2026] 127.0.0.1:34994 [200]: GET /api/chart.php?range=year +[Thu Jul 30 18:41:51 2026] 127.0.0.1:34994 Closing +[Thu Jul 30 18:42:01 2026] 127.0.0.1:56370 Accepted +[Thu Jul 30 18:42:01 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 18:42:01 2026] 127.0.0.1:56370 [200]: GET /api/stats.php +[Thu Jul 30 18:42:01 2026] 127.0.0.1:56370 Closing +[Thu Jul 30 18:42:02 2026] 127.0.0.1:56378 Accepted +[Thu Jul 30 18:42:02 2026] 127.0.0.1:56378 [200]: GET /api/chart.php?range=year +[Thu Jul 30 18:42:02 2026] 127.0.0.1:56378 Closing +[Thu Jul 30 18:42:11 2026] 127.0.0.1:55796 Accepted +[Thu Jul 30 18:42:11 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 18:42:11 2026] 127.0.0.1:55796 [200]: GET /api/stats.php +[Thu Jul 30 18:42:11 2026] 127.0.0.1:55796 Closing +[Thu Jul 30 18:42:11 2026] 127.0.0.1:55812 Accepted +[Thu Jul 30 18:42:11 2026] 127.0.0.1:55812 [200]: GET /api/chart.php?range=year +[Thu Jul 30 18:42:11 2026] 127.0.0.1:55812 Closing +[Thu Jul 30 18:42:21 2026] 127.0.0.1:47696 Accepted +[Thu Jul 30 18:42:21 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 18:42:21 2026] 127.0.0.1:47696 [200]: GET /api/stats.php +[Thu Jul 30 18:42:21 2026] 127.0.0.1:47696 Closing +[Thu Jul 30 18:42:22 2026] 127.0.0.1:47706 Accepted +[Thu Jul 30 18:42:22 2026] 127.0.0.1:47706 [200]: GET /api/chart.php?range=year +[Thu Jul 30 18:42:22 2026] 127.0.0.1:47706 Closing +[Thu Jul 30 18:42:31 2026] 127.0.0.1:38428 Accepted +[Thu Jul 30 18:42:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 18:42:31 2026] 127.0.0.1:38428 [200]: GET /api/stats.php +[Thu Jul 30 18:42:31 2026] 127.0.0.1:38428 Closing +[Thu Jul 30 18:42:31 2026] 127.0.0.1:38442 Accepted +[Thu Jul 30 18:42:31 2026] 127.0.0.1:38442 [200]: GET /api/chart.php?range=year +[Thu Jul 30 18:42:31 2026] 127.0.0.1:38442 Closing +[Thu Jul 30 18:42:41 2026] 127.0.0.1:33438 Accepted +[Thu Jul 30 18:42:41 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 18:42:41 2026] 127.0.0.1:33438 [200]: GET /api/stats.php +[Thu Jul 30 18:42:41 2026] 127.0.0.1:33438 Closing +[Thu Jul 30 18:42:41 2026] 127.0.0.1:33442 Accepted +[Thu Jul 30 18:42:41 2026] 127.0.0.1:33442 [200]: GET /api/chart.php?range=year +[Thu Jul 30 18:42:41 2026] 127.0.0.1:33442 Closing +[Thu Jul 30 18:42:51 2026] 127.0.0.1:42230 Accepted +[Thu Jul 30 18:42:51 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 18:42:51 2026] 127.0.0.1:42230 [200]: GET /api/stats.php +[Thu Jul 30 18:42:51 2026] 127.0.0.1:42230 Closing +[Thu Jul 30 18:42:51 2026] 127.0.0.1:42246 Accepted +[Thu Jul 30 18:42:51 2026] 127.0.0.1:42246 [200]: GET /api/chart.php?range=year +[Thu Jul 30 18:42:51 2026] 127.0.0.1:42246 Closing +[Thu Jul 30 18:43:01 2026] 127.0.0.1:40020 Accepted +[Thu Jul 30 18:43:01 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 18:43:01 2026] 127.0.0.1:40020 [200]: GET /api/stats.php +[Thu Jul 30 18:43:01 2026] 127.0.0.1:40020 Closing +[Thu Jul 30 18:43:01 2026] 127.0.0.1:40028 Accepted +[Thu Jul 30 18:43:01 2026] 127.0.0.1:40028 [200]: GET /api/chart.php?range=year +[Thu Jul 30 18:43:01 2026] 127.0.0.1:40028 Closing +[Thu Jul 30 18:43:11 2026] 127.0.0.1:53108 Accepted +[Thu Jul 30 18:43:11 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 18:43:11 2026] 127.0.0.1:53108 [200]: GET /api/stats.php +[Thu Jul 30 18:43:11 2026] 127.0.0.1:53108 Closing +[Thu Jul 30 18:43:11 2026] 127.0.0.1:53124 Accepted +[Thu Jul 30 18:43:11 2026] 127.0.0.1:53124 [200]: GET /api/chart.php?range=year +[Thu Jul 30 18:43:11 2026] 127.0.0.1:53124 Closing +[Thu Jul 30 18:43:21 2026] 127.0.0.1:51652 Accepted +[Thu Jul 30 18:43:22 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 18:43:22 2026] 127.0.0.1:51652 [200]: GET /api/stats.php +[Thu Jul 30 18:43:22 2026] 127.0.0.1:51652 Closing +[Thu Jul 30 18:43:22 2026] 127.0.0.1:51662 Accepted +[Thu Jul 30 18:43:22 2026] 127.0.0.1:51662 [200]: GET /api/chart.php?range=year +[Thu Jul 30 18:43:22 2026] 127.0.0.1:51662 Closing +[Thu Jul 30 18:43:31 2026] 127.0.0.1:38778 Accepted +[Thu Jul 30 18:43:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 18:43:32 2026] 127.0.0.1:38778 [200]: GET /api/stats.php +[Thu Jul 30 18:43:32 2026] 127.0.0.1:38778 Closing +[Thu Jul 30 18:43:32 2026] 127.0.0.1:38780 Accepted +[Thu Jul 30 18:43:32 2026] 127.0.0.1:38780 [200]: GET /api/chart.php?range=year +[Thu Jul 30 18:43:32 2026] 127.0.0.1:38780 Closing +[Thu Jul 30 18:43:41 2026] 127.0.0.1:45972 Accepted +[Thu Jul 30 18:43:42 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 18:43:42 2026] 127.0.0.1:45972 [200]: GET /api/stats.php +[Thu Jul 30 18:43:42 2026] 127.0.0.1:45972 Closing +[Thu Jul 30 18:43:42 2026] 127.0.0.1:45982 Accepted +[Thu Jul 30 18:43:42 2026] 127.0.0.1:45982 [200]: GET /api/chart.php?range=year +[Thu Jul 30 18:43:42 2026] 127.0.0.1:45982 Closing +[Thu Jul 30 18:43:51 2026] 127.0.0.1:56454 Accepted +[Thu Jul 30 18:43:51 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 18:43:51 2026] 127.0.0.1:56454 [200]: GET /api/stats.php +[Thu Jul 30 18:43:51 2026] 127.0.0.1:56454 Closing +[Thu Jul 30 18:43:51 2026] 127.0.0.1:56468 Accepted +[Thu Jul 30 18:43:51 2026] 127.0.0.1:56468 [200]: GET /api/chart.php?range=year +[Thu Jul 30 18:43:51 2026] 127.0.0.1:56468 Closing +[Thu Jul 30 18:44:01 2026] 127.0.0.1:43470 Accepted +[Thu Jul 30 18:44:01 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 18:44:01 2026] 127.0.0.1:43470 [200]: GET /api/stats.php +[Thu Jul 30 18:44:01 2026] 127.0.0.1:43470 Closing +[Thu Jul 30 18:44:01 2026] 127.0.0.1:43478 Accepted +[Thu Jul 30 18:44:01 2026] 127.0.0.1:43478 [200]: GET /api/chart.php?range=year +[Thu Jul 30 18:44:01 2026] 127.0.0.1:43478 Closing +[Thu Jul 30 18:44:11 2026] 127.0.0.1:44572 Accepted +[Thu Jul 30 18:44:11 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 18:44:11 2026] 127.0.0.1:44572 [200]: GET /api/stats.php +[Thu Jul 30 18:44:11 2026] 127.0.0.1:44572 Closing +[Thu Jul 30 18:44:11 2026] 127.0.0.1:44586 Accepted +[Thu Jul 30 18:44:11 2026] 127.0.0.1:44586 [200]: GET /api/chart.php?range=year +[Thu Jul 30 18:44:11 2026] 127.0.0.1:44586 Closing +[Thu Jul 30 18:44:21 2026] 127.0.0.1:34204 Accepted +[Thu Jul 30 18:44:21 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 18:44:22 2026] 127.0.0.1:34204 [200]: GET /api/stats.php +[Thu Jul 30 18:44:22 2026] 127.0.0.1:34204 Closing +[Thu Jul 30 18:44:22 2026] 127.0.0.1:34216 Accepted +[Thu Jul 30 18:44:22 2026] 127.0.0.1:34216 [200]: GET /api/chart.php?range=year +[Thu Jul 30 18:44:22 2026] 127.0.0.1:34216 Closing +[Thu Jul 30 18:44:31 2026] 127.0.0.1:48722 Accepted +[Thu Jul 30 18:44:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 18:44:31 2026] 127.0.0.1:48722 [200]: GET /api/stats.php +[Thu Jul 30 18:44:31 2026] 127.0.0.1:48722 Closing +[Thu Jul 30 18:44:31 2026] 127.0.0.1:48726 Accepted +[Thu Jul 30 18:44:31 2026] 127.0.0.1:48726 [200]: GET /api/chart.php?range=year +[Thu Jul 30 18:44:31 2026] 127.0.0.1:48726 Closing +[Thu Jul 30 18:44:41 2026] 127.0.0.1:51434 Accepted +[Thu Jul 30 18:44:41 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 18:44:41 2026] 127.0.0.1:51434 [200]: GET /api/stats.php +[Thu Jul 30 18:44:41 2026] 127.0.0.1:51434 Closing +[Thu Jul 30 18:44:41 2026] 127.0.0.1:51440 Accepted +[Thu Jul 30 18:44:41 2026] 127.0.0.1:51440 [200]: GET /api/chart.php?range=year +[Thu Jul 30 18:44:41 2026] 127.0.0.1:51440 Closing +[Thu Jul 30 18:44:51 2026] 127.0.0.1:37408 Accepted +[Thu Jul 30 18:44:51 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 18:44:51 2026] 127.0.0.1:37408 [200]: GET /api/stats.php +[Thu Jul 30 18:44:51 2026] 127.0.0.1:37408 Closing +[Thu Jul 30 18:44:51 2026] 127.0.0.1:37414 Accepted +[Thu Jul 30 18:44:52 2026] 127.0.0.1:37414 [200]: GET /api/chart.php?range=year +[Thu Jul 30 18:44:52 2026] 127.0.0.1:37414 Closing +[Thu Jul 30 18:45:01 2026] 127.0.0.1:40334 Accepted +[Thu Jul 30 18:45:01 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 18:45:01 2026] 127.0.0.1:40334 [200]: GET /api/stats.php +[Thu Jul 30 18:45:01 2026] 127.0.0.1:40334 Closing +[Thu Jul 30 18:45:01 2026] 127.0.0.1:40338 Accepted +[Thu Jul 30 18:45:01 2026] 127.0.0.1:40338 [200]: GET /api/chart.php?range=year +[Thu Jul 30 18:45:01 2026] 127.0.0.1:40338 Closing +[Thu Jul 30 18:45:11 2026] 127.0.0.1:49306 Accepted +[Thu Jul 30 18:45:11 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 18:45:11 2026] 127.0.0.1:49306 [200]: GET /api/stats.php +[Thu Jul 30 18:45:11 2026] 127.0.0.1:49306 Closing +[Thu Jul 30 18:45:11 2026] 127.0.0.1:49312 Accepted +[Thu Jul 30 18:45:11 2026] 127.0.0.1:49312 [200]: GET /api/chart.php?range=year +[Thu Jul 30 18:45:11 2026] 127.0.0.1:49312 Closing +[Thu Jul 30 18:45:21 2026] 127.0.0.1:36724 Accepted +[Thu Jul 30 18:45:21 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 18:45:21 2026] 127.0.0.1:36724 [200]: GET /api/stats.php +[Thu Jul 30 18:45:21 2026] 127.0.0.1:36724 Closing +[Thu Jul 30 18:45:21 2026] 127.0.0.1:36730 Accepted +[Thu Jul 30 18:45:21 2026] 127.0.0.1:36730 [200]: GET /api/chart.php?range=year +[Thu Jul 30 18:45:21 2026] 127.0.0.1:36730 Closing +[Thu Jul 30 18:45:31 2026] 127.0.0.1:43398 Accepted +[Thu Jul 30 18:45:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 18:45:31 2026] 127.0.0.1:43398 [200]: GET /api/stats.php +[Thu Jul 30 18:45:31 2026] 127.0.0.1:43398 Closing +[Thu Jul 30 18:45:31 2026] 127.0.0.1:43404 Accepted +[Thu Jul 30 18:45:31 2026] 127.0.0.1:43404 [200]: GET /api/chart.php?range=year +[Thu Jul 30 18:45:31 2026] 127.0.0.1:43404 Closing +[Thu Jul 30 18:45:41 2026] 127.0.0.1:33184 Accepted +[Thu Jul 30 18:45:41 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 18:45:41 2026] 127.0.0.1:33184 [200]: GET /api/stats.php +[Thu Jul 30 18:45:41 2026] 127.0.0.1:33184 Closing +[Thu Jul 30 18:45:41 2026] 127.0.0.1:33198 Accepted +[Thu Jul 30 18:45:41 2026] 127.0.0.1:33198 [200]: GET /api/chart.php?range=year +[Thu Jul 30 18:45:41 2026] 127.0.0.1:33198 Closing +[Thu Jul 30 18:45:51 2026] 127.0.0.1:51144 Accepted +[Thu Jul 30 18:45:51 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 18:45:51 2026] 127.0.0.1:51144 [200]: GET /api/stats.php +[Thu Jul 30 18:45:51 2026] 127.0.0.1:51144 Closing +[Thu Jul 30 18:45:51 2026] 127.0.0.1:51156 Accepted +[Thu Jul 30 18:45:51 2026] 127.0.0.1:51156 [200]: GET /api/chart.php?range=year +[Thu Jul 30 18:45:51 2026] 127.0.0.1:51156 Closing +[Thu Jul 30 18:46:01 2026] 127.0.0.1:50016 Accepted +[Thu Jul 30 18:46:01 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 18:46:01 2026] 127.0.0.1:50016 [200]: GET /api/stats.php +[Thu Jul 30 18:46:01 2026] 127.0.0.1:50016 Closing +[Thu Jul 30 18:46:01 2026] 127.0.0.1:50026 Accepted +[Thu Jul 30 18:46:01 2026] 127.0.0.1:50026 [200]: GET /api/chart.php?range=year +[Thu Jul 30 18:46:01 2026] 127.0.0.1:50026 Closing +[Thu Jul 30 18:46:11 2026] 127.0.0.1:54588 Accepted +[Thu Jul 30 18:46:11 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 18:46:11 2026] 127.0.0.1:54588 [200]: GET /api/stats.php +[Thu Jul 30 18:46:11 2026] 127.0.0.1:54588 Closing +[Thu Jul 30 18:46:11 2026] 127.0.0.1:54598 Accepted +[Thu Jul 30 18:46:11 2026] 127.0.0.1:54598 [200]: GET /api/chart.php?range=year +[Thu Jul 30 18:46:11 2026] 127.0.0.1:54598 Closing +[Thu Jul 30 18:46:21 2026] 127.0.0.1:49346 Accepted +[Thu Jul 30 18:46:21 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 18:46:21 2026] 127.0.0.1:49346 [200]: GET /api/stats.php +[Thu Jul 30 18:46:21 2026] 127.0.0.1:49346 Closing +[Thu Jul 30 18:46:21 2026] 127.0.0.1:49352 Accepted +[Thu Jul 30 18:46:21 2026] 127.0.0.1:49352 [200]: GET /api/chart.php?range=year +[Thu Jul 30 18:46:21 2026] 127.0.0.1:49352 Closing +[Thu Jul 30 18:46:31 2026] 127.0.0.1:58350 Accepted +[Thu Jul 30 18:46:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 18:46:32 2026] 127.0.0.1:58350 [200]: GET /api/stats.php +[Thu Jul 30 18:46:32 2026] 127.0.0.1:58350 Closing +[Thu Jul 30 18:46:32 2026] 127.0.0.1:58364 Accepted +[Thu Jul 30 18:46:32 2026] 127.0.0.1:58364 [200]: GET /api/chart.php?range=year +[Thu Jul 30 18:46:32 2026] 127.0.0.1:58364 Closing +[Thu Jul 30 18:46:41 2026] 127.0.0.1:52290 Accepted +[Thu Jul 30 18:46:41 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 18:46:41 2026] 127.0.0.1:52290 [200]: GET /api/stats.php +[Thu Jul 30 18:46:41 2026] 127.0.0.1:52290 Closing +[Thu Jul 30 18:46:41 2026] 127.0.0.1:52294 Accepted +[Thu Jul 30 18:46:41 2026] 127.0.0.1:52294 [200]: GET /api/chart.php?range=year +[Thu Jul 30 18:46:41 2026] 127.0.0.1:52294 Closing +[Thu Jul 30 18:46:51 2026] 127.0.0.1:58836 Accepted +[Thu Jul 30 18:46:51 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 18:46:51 2026] 127.0.0.1:58836 [200]: GET /api/stats.php +[Thu Jul 30 18:46:51 2026] 127.0.0.1:58836 Closing +[Thu Jul 30 18:46:51 2026] 127.0.0.1:58840 Accepted +[Thu Jul 30 18:46:51 2026] 127.0.0.1:58840 [200]: GET /api/chart.php?range=year +[Thu Jul 30 18:46:51 2026] 127.0.0.1:58840 Closing +[Thu Jul 30 18:47:01 2026] 127.0.0.1:55740 Accepted +[Thu Jul 30 18:47:01 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 18:47:01 2026] 127.0.0.1:55740 [200]: GET /api/stats.php +[Thu Jul 30 18:47:01 2026] 127.0.0.1:55740 Closing +[Thu Jul 30 18:47:01 2026] 127.0.0.1:55748 Accepted +[Thu Jul 30 18:47:01 2026] 127.0.0.1:55748 [200]: GET /api/chart.php?range=year +[Thu Jul 30 18:47:01 2026] 127.0.0.1:55748 Closing +[Thu Jul 30 18:47:11 2026] 127.0.0.1:58080 Accepted +[Thu Jul 30 18:47:11 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 18:47:11 2026] 127.0.0.1:58080 [200]: GET /api/stats.php +[Thu Jul 30 18:47:11 2026] 127.0.0.1:58080 Closing +[Thu Jul 30 18:47:12 2026] 127.0.0.1:58094 Accepted +[Thu Jul 30 18:47:12 2026] 127.0.0.1:58094 [200]: GET /api/chart.php?range=year +[Thu Jul 30 18:47:12 2026] 127.0.0.1:58094 Closing +[Thu Jul 30 18:47:21 2026] 127.0.0.1:34654 Accepted +[Thu Jul 30 18:47:21 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 18:47:21 2026] 127.0.0.1:34654 [200]: GET /api/stats.php +[Thu Jul 30 18:47:21 2026] 127.0.0.1:34654 Closing +[Thu Jul 30 18:47:21 2026] 127.0.0.1:34660 Accepted +[Thu Jul 30 18:47:21 2026] 127.0.0.1:34660 [200]: GET /api/chart.php?range=year +[Thu Jul 30 18:47:21 2026] 127.0.0.1:34660 Closing +[Thu Jul 30 18:47:31 2026] 127.0.0.1:34732 Accepted +[Thu Jul 30 18:47:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 18:47:31 2026] 127.0.0.1:34732 [200]: GET /api/stats.php +[Thu Jul 30 18:47:31 2026] 127.0.0.1:34732 Closing +[Thu Jul 30 18:47:31 2026] 127.0.0.1:34742 Accepted +[Thu Jul 30 18:47:31 2026] 127.0.0.1:34742 [200]: GET /api/chart.php?range=year +[Thu Jul 30 18:47:31 2026] 127.0.0.1:34742 Closing +[Thu Jul 30 18:47:41 2026] 127.0.0.1:59658 Accepted +[Thu Jul 30 18:47:41 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 18:47:41 2026] 127.0.0.1:59658 [200]: GET /api/stats.php +[Thu Jul 30 18:47:41 2026] 127.0.0.1:59658 Closing +[Thu Jul 30 18:47:41 2026] 127.0.0.1:59672 Accepted +[Thu Jul 30 18:47:41 2026] 127.0.0.1:59672 [200]: GET /api/chart.php?range=year +[Thu Jul 30 18:47:41 2026] 127.0.0.1:59672 Closing +[Thu Jul 30 18:47:51 2026] 127.0.0.1:48122 Accepted +[Thu Jul 30 18:47:51 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 18:47:51 2026] 127.0.0.1:48122 [200]: GET /api/stats.php +[Thu Jul 30 18:47:51 2026] 127.0.0.1:48122 Closing +[Thu Jul 30 18:47:51 2026] 127.0.0.1:48132 Accepted +[Thu Jul 30 18:47:51 2026] 127.0.0.1:48132 [200]: GET /api/chart.php?range=year +[Thu Jul 30 18:47:51 2026] 127.0.0.1:48132 Closing +[Thu Jul 30 18:48:01 2026] 127.0.0.1:38856 Accepted +[Thu Jul 30 18:48:01 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 18:48:01 2026] 127.0.0.1:38856 [200]: GET /api/stats.php +[Thu Jul 30 18:48:01 2026] 127.0.0.1:38856 Closing +[Thu Jul 30 18:48:01 2026] 127.0.0.1:38864 Accepted +[Thu Jul 30 18:48:01 2026] 127.0.0.1:38864 [200]: GET /api/chart.php?range=year +[Thu Jul 30 18:48:01 2026] 127.0.0.1:38864 Closing +[Thu Jul 30 18:48:11 2026] 127.0.0.1:55130 Accepted +[Thu Jul 30 18:48:11 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 18:48:11 2026] 127.0.0.1:55130 [200]: GET /api/stats.php +[Thu Jul 30 18:48:11 2026] 127.0.0.1:55130 Closing +[Thu Jul 30 18:48:11 2026] 127.0.0.1:55140 Accepted +[Thu Jul 30 18:48:11 2026] 127.0.0.1:55140 [200]: GET /api/chart.php?range=year +[Thu Jul 30 18:48:11 2026] 127.0.0.1:55140 Closing +[Thu Jul 30 18:48:21 2026] 127.0.0.1:41192 Accepted +[Thu Jul 30 18:48:21 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 18:48:21 2026] 127.0.0.1:41192 [200]: GET /api/stats.php +[Thu Jul 30 18:48:21 2026] 127.0.0.1:41192 Closing +[Thu Jul 30 18:48:21 2026] 127.0.0.1:41196 Accepted +[Thu Jul 30 18:48:21 2026] 127.0.0.1:41196 [200]: GET /api/chart.php?range=year +[Thu Jul 30 18:48:21 2026] 127.0.0.1:41196 Closing +[Thu Jul 30 18:48:31 2026] 127.0.0.1:60614 Accepted +[Thu Jul 30 18:48:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 18:48:31 2026] 127.0.0.1:60614 [200]: GET /api/stats.php +[Thu Jul 30 18:48:31 2026] 127.0.0.1:60614 Closing +[Thu Jul 30 18:48:31 2026] 127.0.0.1:60622 Accepted +[Thu Jul 30 18:48:31 2026] 127.0.0.1:60622 [200]: GET /api/chart.php?range=year +[Thu Jul 30 18:48:31 2026] 127.0.0.1:60622 Closing +[Thu Jul 30 18:48:41 2026] 127.0.0.1:58476 Accepted +[Thu Jul 30 18:48:41 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 18:48:41 2026] 127.0.0.1:58476 [200]: GET /api/stats.php +[Thu Jul 30 18:48:41 2026] 127.0.0.1:58476 Closing +[Thu Jul 30 18:48:41 2026] 127.0.0.1:58478 Accepted +[Thu Jul 30 18:48:41 2026] 127.0.0.1:58478 [200]: GET /api/chart.php?range=year +[Thu Jul 30 18:48:41 2026] 127.0.0.1:58478 Closing +[Thu Jul 30 18:48:51 2026] 127.0.0.1:57514 Accepted +[Thu Jul 30 18:48:51 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 18:48:51 2026] 127.0.0.1:57514 [200]: GET /api/stats.php +[Thu Jul 30 18:48:51 2026] 127.0.0.1:57514 Closing +[Thu Jul 30 18:48:51 2026] 127.0.0.1:57522 Accepted +[Thu Jul 30 18:48:51 2026] 127.0.0.1:57522 [200]: GET /api/chart.php?range=year +[Thu Jul 30 18:48:51 2026] 127.0.0.1:57522 Closing +[Thu Jul 30 18:49:01 2026] 127.0.0.1:58998 Accepted +[Thu Jul 30 18:49:01 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 18:49:01 2026] 127.0.0.1:58998 [200]: GET /api/stats.php +[Thu Jul 30 18:49:01 2026] 127.0.0.1:58998 Closing +[Thu Jul 30 18:49:01 2026] 127.0.0.1:59002 Accepted +[Thu Jul 30 18:49:01 2026] 127.0.0.1:59002 [200]: GET /api/chart.php?range=year +[Thu Jul 30 18:49:01 2026] 127.0.0.1:59002 Closing +[Thu Jul 30 18:49:11 2026] 127.0.0.1:53050 Accepted +[Thu Jul 30 18:49:11 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 18:49:12 2026] 127.0.0.1:53050 [200]: GET /api/stats.php +[Thu Jul 30 18:49:12 2026] 127.0.0.1:53050 Closing +[Thu Jul 30 18:49:12 2026] 127.0.0.1:53054 Accepted +[Thu Jul 30 18:49:12 2026] 127.0.0.1:53054 [200]: GET /api/chart.php?range=year +[Thu Jul 30 18:49:12 2026] 127.0.0.1:53054 Closing +[Thu Jul 30 18:49:21 2026] 127.0.0.1:52608 Accepted +[Thu Jul 30 18:49:21 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 18:49:21 2026] 127.0.0.1:52608 [200]: GET /api/stats.php +[Thu Jul 30 18:49:21 2026] 127.0.0.1:52608 Closing +[Thu Jul 30 18:49:21 2026] 127.0.0.1:52614 Accepted +[Thu Jul 30 18:49:21 2026] 127.0.0.1:52614 [200]: GET /api/chart.php?range=year +[Thu Jul 30 18:49:21 2026] 127.0.0.1:52614 Closing +[Thu Jul 30 18:49:31 2026] 127.0.0.1:57124 Accepted +[Thu Jul 30 18:49:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 18:49:31 2026] 127.0.0.1:57124 [200]: GET /api/stats.php +[Thu Jul 30 18:49:31 2026] 127.0.0.1:57124 Closing +[Thu Jul 30 18:49:31 2026] 127.0.0.1:57132 Accepted +[Thu Jul 30 18:49:31 2026] 127.0.0.1:57132 [200]: GET /api/chart.php?range=year +[Thu Jul 30 18:49:31 2026] 127.0.0.1:57132 Closing +[Thu Jul 30 18:49:41 2026] 127.0.0.1:48588 Accepted +[Thu Jul 30 18:49:41 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 18:49:41 2026] 127.0.0.1:48588 [200]: GET /api/stats.php +[Thu Jul 30 18:49:41 2026] 127.0.0.1:48588 Closing +[Thu Jul 30 18:49:41 2026] 127.0.0.1:48600 Accepted +[Thu Jul 30 18:49:41 2026] 127.0.0.1:48600 [200]: GET /api/chart.php?range=year +[Thu Jul 30 18:49:41 2026] 127.0.0.1:48600 Closing +[Thu Jul 30 18:49:51 2026] 127.0.0.1:53150 Accepted +[Thu Jul 30 18:49:51 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 18:49:51 2026] 127.0.0.1:53150 [200]: GET /api/stats.php +[Thu Jul 30 18:49:51 2026] 127.0.0.1:53150 Closing +[Thu Jul 30 18:49:51 2026] 127.0.0.1:53156 Accepted +[Thu Jul 30 18:49:51 2026] 127.0.0.1:53156 [200]: GET /api/chart.php?range=year +[Thu Jul 30 18:49:51 2026] 127.0.0.1:53156 Closing +[Thu Jul 30 18:50:01 2026] 127.0.0.1:39338 Accepted +[Thu Jul 30 18:50:01 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 18:50:01 2026] 127.0.0.1:39338 [200]: GET /api/stats.php +[Thu Jul 30 18:50:01 2026] 127.0.0.1:39338 Closing +[Thu Jul 30 18:50:01 2026] 127.0.0.1:39354 Accepted +[Thu Jul 30 18:50:01 2026] 127.0.0.1:39354 [200]: GET /api/chart.php?range=year +[Thu Jul 30 18:50:01 2026] 127.0.0.1:39354 Closing +[Thu Jul 30 18:50:11 2026] 127.0.0.1:55046 Accepted +[Thu Jul 30 18:50:11 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 18:50:11 2026] 127.0.0.1:55046 [200]: GET /api/stats.php +[Thu Jul 30 18:50:11 2026] 127.0.0.1:55046 Closing +[Thu Jul 30 18:50:11 2026] 127.0.0.1:55058 Accepted +[Thu Jul 30 18:50:11 2026] 127.0.0.1:55058 [200]: GET /api/chart.php?range=year +[Thu Jul 30 18:50:11 2026] 127.0.0.1:55058 Closing +[Thu Jul 30 18:50:21 2026] 127.0.0.1:56254 Accepted +[Thu Jul 30 18:50:21 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 18:50:21 2026] 127.0.0.1:56254 [200]: GET /api/stats.php +[Thu Jul 30 18:50:21 2026] 127.0.0.1:56254 Closing +[Thu Jul 30 18:50:21 2026] 127.0.0.1:56262 Accepted +[Thu Jul 30 18:50:21 2026] 127.0.0.1:56262 [200]: GET /api/chart.php?range=year +[Thu Jul 30 18:50:21 2026] 127.0.0.1:56262 Closing +[Thu Jul 30 18:50:31 2026] 127.0.0.1:49494 Accepted +[Thu Jul 30 18:50:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 18:50:31 2026] 127.0.0.1:49494 [200]: GET /api/stats.php +[Thu Jul 30 18:50:31 2026] 127.0.0.1:49494 Closing +[Thu Jul 30 18:50:31 2026] 127.0.0.1:49510 Accepted +[Thu Jul 30 18:50:31 2026] 127.0.0.1:49510 [200]: GET /api/chart.php?range=year +[Thu Jul 30 18:50:31 2026] 127.0.0.1:49510 Closing +[Thu Jul 30 18:50:41 2026] 127.0.0.1:44642 Accepted +[Thu Jul 30 18:50:41 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 18:50:41 2026] 127.0.0.1:44642 [200]: GET /api/stats.php +[Thu Jul 30 18:50:41 2026] 127.0.0.1:44642 Closing +[Thu Jul 30 18:50:41 2026] 127.0.0.1:44644 Accepted +[Thu Jul 30 18:50:41 2026] 127.0.0.1:44644 [200]: GET /api/chart.php?range=year +[Thu Jul 30 18:50:41 2026] 127.0.0.1:44644 Closing +[Thu Jul 30 18:50:51 2026] 127.0.0.1:47744 Accepted +[Thu Jul 30 18:50:51 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 18:50:51 2026] 127.0.0.1:47744 [200]: GET /api/stats.php +[Thu Jul 30 18:50:51 2026] 127.0.0.1:47744 Closing +[Thu Jul 30 18:50:51 2026] 127.0.0.1:47754 Accepted +[Thu Jul 30 18:50:51 2026] 127.0.0.1:47754 [200]: GET /api/chart.php?range=year +[Thu Jul 30 18:50:51 2026] 127.0.0.1:47754 Closing +[Thu Jul 30 18:51:01 2026] 127.0.0.1:55230 Accepted +[Thu Jul 30 18:51:01 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 18:51:01 2026] 127.0.0.1:55230 [200]: GET /api/stats.php +[Thu Jul 30 18:51:01 2026] 127.0.0.1:55230 Closing +[Thu Jul 30 18:51:01 2026] 127.0.0.1:55246 Accepted +[Thu Jul 30 18:51:01 2026] 127.0.0.1:55246 [200]: GET /api/chart.php?range=year +[Thu Jul 30 18:51:01 2026] 127.0.0.1:55246 Closing +[Thu Jul 30 18:51:11 2026] 127.0.0.1:59182 Accepted +[Thu Jul 30 18:51:11 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 18:51:11 2026] 127.0.0.1:59182 [200]: GET /api/stats.php +[Thu Jul 30 18:51:11 2026] 127.0.0.1:59182 Closing +[Thu Jul 30 18:51:11 2026] 127.0.0.1:59192 Accepted +[Thu Jul 30 18:51:11 2026] 127.0.0.1:59192 [200]: GET /api/chart.php?range=year +[Thu Jul 30 18:51:11 2026] 127.0.0.1:59192 Closing +[Thu Jul 30 18:51:21 2026] 127.0.0.1:34526 Accepted +[Thu Jul 30 18:51:21 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 18:51:21 2026] 127.0.0.1:34526 [200]: GET /api/stats.php +[Thu Jul 30 18:51:21 2026] 127.0.0.1:34526 Closing +[Thu Jul 30 18:51:21 2026] 127.0.0.1:34542 Accepted +[Thu Jul 30 18:51:21 2026] 127.0.0.1:34542 [200]: GET /api/chart.php?range=year +[Thu Jul 30 18:51:21 2026] 127.0.0.1:34542 Closing +[Thu Jul 30 18:51:31 2026] 127.0.0.1:45464 Accepted +[Thu Jul 30 18:51:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 18:51:31 2026] 127.0.0.1:45464 [200]: GET /api/stats.php +[Thu Jul 30 18:51:31 2026] 127.0.0.1:45464 Closing +[Thu Jul 30 18:51:31 2026] 127.0.0.1:45476 Accepted +[Thu Jul 30 18:51:31 2026] 127.0.0.1:45476 [200]: GET /api/chart.php?range=year +[Thu Jul 30 18:51:31 2026] 127.0.0.1:45476 Closing +[Thu Jul 30 18:51:41 2026] 127.0.0.1:46854 Accepted +[Thu Jul 30 18:51:41 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 18:51:41 2026] 127.0.0.1:46854 [200]: GET /api/stats.php +[Thu Jul 30 18:51:41 2026] 127.0.0.1:46854 Closing +[Thu Jul 30 18:51:41 2026] 127.0.0.1:46864 Accepted +[Thu Jul 30 18:51:41 2026] 127.0.0.1:46864 [200]: GET /api/chart.php?range=year +[Thu Jul 30 18:51:41 2026] 127.0.0.1:46864 Closing +[Thu Jul 30 18:51:51 2026] 127.0.0.1:45530 Accepted +[Thu Jul 30 18:51:51 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 18:51:51 2026] 127.0.0.1:45530 [200]: GET /api/stats.php +[Thu Jul 30 18:51:51 2026] 127.0.0.1:45530 Closing +[Thu Jul 30 18:51:51 2026] 127.0.0.1:45546 Accepted +[Thu Jul 30 18:51:51 2026] 127.0.0.1:45546 [200]: GET /api/chart.php?range=year +[Thu Jul 30 18:51:51 2026] 127.0.0.1:45546 Closing +[Thu Jul 30 18:52:01 2026] 127.0.0.1:39154 Accepted +[Thu Jul 30 18:52:01 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 18:52:01 2026] 127.0.0.1:39154 [200]: GET /api/stats.php +[Thu Jul 30 18:52:01 2026] 127.0.0.1:39154 Closing +[Thu Jul 30 18:52:01 2026] 127.0.0.1:39168 Accepted +[Thu Jul 30 18:52:01 2026] 127.0.0.1:39168 [200]: GET /api/chart.php?range=year +[Thu Jul 30 18:52:01 2026] 127.0.0.1:39168 Closing +[Thu Jul 30 18:52:11 2026] 127.0.0.1:49376 Accepted +[Thu Jul 30 18:52:11 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 18:52:11 2026] 127.0.0.1:49376 [200]: GET /api/stats.php +[Thu Jul 30 18:52:11 2026] 127.0.0.1:49376 Closing +[Thu Jul 30 18:52:11 2026] 127.0.0.1:49378 Accepted +[Thu Jul 30 18:52:11 2026] 127.0.0.1:49378 [200]: GET /api/chart.php?range=year +[Thu Jul 30 18:52:11 2026] 127.0.0.1:49378 Closing +[Thu Jul 30 18:52:21 2026] 127.0.0.1:45806 Accepted +[Thu Jul 30 18:52:21 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 18:52:21 2026] 127.0.0.1:45806 [200]: GET /api/stats.php +[Thu Jul 30 18:52:21 2026] 127.0.0.1:45806 Closing +[Thu Jul 30 18:52:21 2026] 127.0.0.1:45814 Accepted +[Thu Jul 30 18:52:21 2026] 127.0.0.1:45814 [200]: GET /api/chart.php?range=year +[Thu Jul 30 18:52:21 2026] 127.0.0.1:45814 Closing +[Thu Jul 30 18:52:31 2026] 127.0.0.1:57308 Accepted +[Thu Jul 30 18:52:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 18:52:31 2026] 127.0.0.1:57308 [200]: GET /api/stats.php +[Thu Jul 30 18:52:31 2026] 127.0.0.1:57308 Closing +[Thu Jul 30 18:52:31 2026] 127.0.0.1:57320 Accepted +[Thu Jul 30 18:52:31 2026] 127.0.0.1:57320 [200]: GET /api/chart.php?range=year +[Thu Jul 30 18:52:31 2026] 127.0.0.1:57320 Closing +[Thu Jul 30 18:52:41 2026] 127.0.0.1:48272 Accepted +[Thu Jul 30 18:52:41 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 18:52:42 2026] 127.0.0.1:48272 [200]: GET /api/stats.php +[Thu Jul 30 18:52:42 2026] 127.0.0.1:48272 Closing +[Thu Jul 30 18:52:42 2026] 127.0.0.1:48284 Accepted +[Thu Jul 30 18:52:42 2026] 127.0.0.1:48284 [200]: GET /api/chart.php?range=year +[Thu Jul 30 18:52:42 2026] 127.0.0.1:48284 Closing +[Thu Jul 30 18:52:51 2026] 127.0.0.1:46210 Accepted +[Thu Jul 30 18:52:51 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 18:52:51 2026] 127.0.0.1:46210 [200]: GET /api/stats.php +[Thu Jul 30 18:52:51 2026] 127.0.0.1:46210 Closing +[Thu Jul 30 18:52:51 2026] 127.0.0.1:46226 Accepted +[Thu Jul 30 18:52:51 2026] 127.0.0.1:46226 [200]: GET /api/chart.php?range=year +[Thu Jul 30 18:52:51 2026] 127.0.0.1:46226 Closing +[Thu Jul 30 18:53:01 2026] 127.0.0.1:42748 Accepted +[Thu Jul 30 18:53:01 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 18:53:01 2026] 127.0.0.1:42748 [200]: GET /api/stats.php +[Thu Jul 30 18:53:01 2026] 127.0.0.1:42748 Closing +[Thu Jul 30 18:53:01 2026] 127.0.0.1:42752 Accepted +[Thu Jul 30 18:53:01 2026] 127.0.0.1:42752 [200]: GET /api/chart.php?range=year +[Thu Jul 30 18:53:01 2026] 127.0.0.1:42752 Closing +[Thu Jul 30 18:53:11 2026] 127.0.0.1:33678 Accepted +[Thu Jul 30 18:53:11 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 18:53:11 2026] 127.0.0.1:33678 [200]: GET /api/stats.php +[Thu Jul 30 18:53:11 2026] 127.0.0.1:33678 Closing +[Thu Jul 30 18:53:11 2026] 127.0.0.1:33684 Accepted +[Thu Jul 30 18:53:11 2026] 127.0.0.1:33684 [200]: GET /api/chart.php?range=year +[Thu Jul 30 18:53:11 2026] 127.0.0.1:33684 Closing +[Thu Jul 30 18:53:21 2026] 127.0.0.1:40868 Accepted +[Thu Jul 30 18:53:21 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 18:53:21 2026] 127.0.0.1:40868 [200]: GET /api/stats.php +[Thu Jul 30 18:53:21 2026] 127.0.0.1:40868 Closing +[Thu Jul 30 18:53:21 2026] 127.0.0.1:40876 Accepted +[Thu Jul 30 18:53:21 2026] 127.0.0.1:40876 [200]: GET /api/chart.php?range=year +[Thu Jul 30 18:53:21 2026] 127.0.0.1:40876 Closing +[Thu Jul 30 18:53:32 2026] 127.0.0.1:32934 Accepted +[Thu Jul 30 18:53:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 18:53:32 2026] 127.0.0.1:32934 [200]: GET /api/stats.php +[Thu Jul 30 18:53:32 2026] 127.0.0.1:32934 Closing +[Thu Jul 30 18:53:32 2026] 127.0.0.1:32940 Accepted +[Thu Jul 30 18:53:32 2026] 127.0.0.1:32940 [200]: GET /api/chart.php?range=year +[Thu Jul 30 18:53:32 2026] 127.0.0.1:32940 Closing +[Thu Jul 30 18:53:42 2026] 127.0.0.1:58008 Accepted +[Thu Jul 30 18:53:42 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 18:53:42 2026] 127.0.0.1:58008 [200]: GET /api/stats.php +[Thu Jul 30 18:53:42 2026] 127.0.0.1:58008 Closing +[Thu Jul 30 18:53:42 2026] 127.0.0.1:58012 Accepted +[Thu Jul 30 18:53:42 2026] 127.0.0.1:58012 [200]: GET /api/chart.php?range=year +[Thu Jul 30 18:53:42 2026] 127.0.0.1:58012 Closing +[Thu Jul 30 18:53:52 2026] 127.0.0.1:52012 Accepted +[Thu Jul 30 18:53:52 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 18:53:52 2026] 127.0.0.1:52012 [200]: GET /api/stats.php +[Thu Jul 30 18:53:52 2026] 127.0.0.1:52012 Closing +[Thu Jul 30 18:53:52 2026] 127.0.0.1:52016 Accepted +[Thu Jul 30 18:53:52 2026] 127.0.0.1:52016 [200]: GET /api/chart.php?range=year +[Thu Jul 30 18:53:52 2026] 127.0.0.1:52016 Closing +[Thu Jul 30 18:54:02 2026] 127.0.0.1:33674 Accepted +[Thu Jul 30 18:54:02 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 18:54:02 2026] 127.0.0.1:33674 [200]: GET /api/stats.php +[Thu Jul 30 18:54:02 2026] 127.0.0.1:33674 Closing +[Thu Jul 30 18:54:02 2026] 127.0.0.1:33688 Accepted +[Thu Jul 30 18:54:02 2026] 127.0.0.1:33688 [200]: GET /api/chart.php?range=year +[Thu Jul 30 18:54:02 2026] 127.0.0.1:33688 Closing +[Thu Jul 30 18:54:12 2026] 127.0.0.1:53352 Accepted +[Thu Jul 30 18:54:12 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 18:54:12 2026] 127.0.0.1:53352 [200]: GET /api/stats.php +[Thu Jul 30 18:54:12 2026] 127.0.0.1:53352 Closing +[Thu Jul 30 18:54:12 2026] 127.0.0.1:53360 Accepted +[Thu Jul 30 18:54:12 2026] 127.0.0.1:53360 [200]: GET /api/chart.php?range=year +[Thu Jul 30 18:54:12 2026] 127.0.0.1:53360 Closing +[Thu Jul 30 18:54:22 2026] 127.0.0.1:48814 Accepted +[Thu Jul 30 18:54:22 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 18:54:22 2026] 127.0.0.1:48814 [200]: GET /api/stats.php +[Thu Jul 30 18:54:22 2026] 127.0.0.1:48814 Closing +[Thu Jul 30 18:54:22 2026] 127.0.0.1:48820 Accepted +[Thu Jul 30 18:54:22 2026] 127.0.0.1:48820 [200]: GET /api/chart.php?range=year +[Thu Jul 30 18:54:22 2026] 127.0.0.1:48820 Closing +[Thu Jul 30 18:54:32 2026] 127.0.0.1:51256 Accepted +[Thu Jul 30 18:54:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 18:54:32 2026] 127.0.0.1:51256 [200]: GET /api/stats.php +[Thu Jul 30 18:54:32 2026] 127.0.0.1:51256 Closing +[Thu Jul 30 18:54:32 2026] 127.0.0.1:51258 Accepted +[Thu Jul 30 18:54:32 2026] 127.0.0.1:51258 [200]: GET /api/chart.php?range=year +[Thu Jul 30 18:54:32 2026] 127.0.0.1:51258 Closing +[Thu Jul 30 18:55:32 2026] 127.0.0.1:46994 Accepted +[Thu Jul 30 18:55:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 18:55:32 2026] 127.0.0.1:46994 [200]: GET /api/stats.php +[Thu Jul 30 18:55:32 2026] 127.0.0.1:46994 Closing +[Thu Jul 30 18:55:32 2026] 127.0.0.1:47006 Accepted +[Thu Jul 30 18:55:32 2026] 127.0.0.1:47006 [200]: GET /api/chart.php?range=year +[Thu Jul 30 18:55:32 2026] 127.0.0.1:47006 Closing +[Thu Jul 30 18:56:32 2026] 127.0.0.1:40128 Accepted +[Thu Jul 30 18:56:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 18:56:32 2026] 127.0.0.1:40128 [200]: GET /api/stats.php +[Thu Jul 30 18:56:32 2026] 127.0.0.1:40128 Closing +[Thu Jul 30 18:56:32 2026] 127.0.0.1:40140 Accepted +[Thu Jul 30 18:56:32 2026] 127.0.0.1:40140 [200]: GET /api/chart.php?range=year +[Thu Jul 30 18:56:32 2026] 127.0.0.1:40140 Closing +[Thu Jul 30 18:57:32 2026] 127.0.0.1:34982 Accepted +[Thu Jul 30 18:57:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 18:57:32 2026] 127.0.0.1:34982 [200]: GET /api/stats.php +[Thu Jul 30 18:57:32 2026] 127.0.0.1:34982 Closing +[Thu Jul 30 18:57:32 2026] 127.0.0.1:34992 Accepted +[Thu Jul 30 18:57:32 2026] 127.0.0.1:34992 [200]: GET /api/chart.php?range=year +[Thu Jul 30 18:57:32 2026] 127.0.0.1:34992 Closing +[Thu Jul 30 18:58:32 2026] 127.0.0.1:40340 Accepted +[Thu Jul 30 18:58:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 18:58:32 2026] 127.0.0.1:40340 [200]: GET /api/stats.php +[Thu Jul 30 18:58:32 2026] 127.0.0.1:40340 Closing +[Thu Jul 30 18:58:32 2026] 127.0.0.1:40356 Accepted +[Thu Jul 30 18:58:32 2026] 127.0.0.1:40356 [200]: GET /api/chart.php?range=year +[Thu Jul 30 18:58:32 2026] 127.0.0.1:40356 Closing +[Thu Jul 30 18:59:32 2026] 127.0.0.1:45724 Accepted +[Thu Jul 30 18:59:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 18:59:32 2026] 127.0.0.1:45724 [200]: GET /api/stats.php +[Thu Jul 30 18:59:32 2026] 127.0.0.1:45724 Closing +[Thu Jul 30 18:59:32 2026] 127.0.0.1:45730 Accepted +[Thu Jul 30 18:59:32 2026] 127.0.0.1:45730 [200]: GET /api/chart.php?range=year +[Thu Jul 30 18:59:32 2026] 127.0.0.1:45730 Closing +[Thu Jul 30 19:00:32 2026] 127.0.0.1:47778 Accepted +[Thu Jul 30 19:00:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 19:00:32 2026] 127.0.0.1:47778 [200]: GET /api/stats.php +[Thu Jul 30 19:00:32 2026] 127.0.0.1:47778 Closing +[Thu Jul 30 19:00:32 2026] 127.0.0.1:47788 Accepted +[Thu Jul 30 19:00:32 2026] 127.0.0.1:47788 [200]: GET /api/chart.php?range=year +[Thu Jul 30 19:00:32 2026] 127.0.0.1:47788 Closing +[Thu Jul 30 19:01:32 2026] 127.0.0.1:50706 Accepted +[Thu Jul 30 19:01:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 19:01:32 2026] 127.0.0.1:50706 [200]: GET /api/stats.php +[Thu Jul 30 19:01:32 2026] 127.0.0.1:50706 Closing +[Thu Jul 30 19:01:32 2026] 127.0.0.1:50716 Accepted +[Thu Jul 30 19:01:32 2026] 127.0.0.1:50716 [200]: GET /api/chart.php?range=year +[Thu Jul 30 19:01:32 2026] 127.0.0.1:50716 Closing +[Thu Jul 30 19:02:32 2026] 127.0.0.1:48880 Accepted +[Thu Jul 30 19:02:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 19:02:32 2026] 127.0.0.1:48880 [200]: GET /api/stats.php +[Thu Jul 30 19:02:32 2026] 127.0.0.1:48880 Closing +[Thu Jul 30 19:02:32 2026] 127.0.0.1:48892 Accepted +[Thu Jul 30 19:02:32 2026] 127.0.0.1:48892 [200]: GET /api/chart.php?range=year +[Thu Jul 30 19:02:32 2026] 127.0.0.1:48892 Closing +[Thu Jul 30 19:03:32 2026] 127.0.0.1:36442 Accepted +[Thu Jul 30 19:03:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 19:03:32 2026] 127.0.0.1:36442 [200]: GET /api/stats.php +[Thu Jul 30 19:03:32 2026] 127.0.0.1:36442 Closing +[Thu Jul 30 19:03:32 2026] 127.0.0.1:36450 Accepted +[Thu Jul 30 19:03:32 2026] 127.0.0.1:36450 [200]: GET /api/chart.php?range=year +[Thu Jul 30 19:03:32 2026] 127.0.0.1:36450 Closing +[Thu Jul 30 19:04:32 2026] 127.0.0.1:44888 Accepted +[Thu Jul 30 19:04:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 19:04:32 2026] 127.0.0.1:44888 [200]: GET /api/stats.php +[Thu Jul 30 19:04:32 2026] 127.0.0.1:44888 Closing +[Thu Jul 30 19:04:32 2026] 127.0.0.1:44894 Accepted +[Thu Jul 30 19:04:32 2026] 127.0.0.1:44894 [200]: GET /api/chart.php?range=year +[Thu Jul 30 19:04:32 2026] 127.0.0.1:44894 Closing +[Thu Jul 30 19:05:32 2026] 127.0.0.1:56092 Accepted +[Thu Jul 30 19:05:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 19:05:32 2026] 127.0.0.1:56092 [200]: GET /api/stats.php +[Thu Jul 30 19:05:32 2026] 127.0.0.1:56092 Closing +[Thu Jul 30 19:05:32 2026] 127.0.0.1:56100 Accepted +[Thu Jul 30 19:05:32 2026] 127.0.0.1:56100 [200]: GET /api/chart.php?range=year +[Thu Jul 30 19:05:32 2026] 127.0.0.1:56100 Closing +[Thu Jul 30 19:06:32 2026] 127.0.0.1:47870 Accepted +[Thu Jul 30 19:06:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 19:06:32 2026] 127.0.0.1:47870 [200]: GET /api/stats.php +[Thu Jul 30 19:06:32 2026] 127.0.0.1:47870 Closing +[Thu Jul 30 19:06:32 2026] 127.0.0.1:47886 Accepted +[Thu Jul 30 19:06:32 2026] 127.0.0.1:47886 [200]: GET /api/chart.php?range=year +[Thu Jul 30 19:06:32 2026] 127.0.0.1:47886 Closing +[Thu Jul 30 19:07:32 2026] 127.0.0.1:54370 Accepted +[Thu Jul 30 19:07:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 19:07:32 2026] 127.0.0.1:54370 [200]: GET /api/stats.php +[Thu Jul 30 19:07:32 2026] 127.0.0.1:54370 Closing +[Thu Jul 30 19:07:32 2026] 127.0.0.1:54372 Accepted +[Thu Jul 30 19:07:32 2026] 127.0.0.1:54372 [200]: GET /api/chart.php?range=year +[Thu Jul 30 19:07:32 2026] 127.0.0.1:54372 Closing +[Thu Jul 30 19:08:32 2026] 127.0.0.1:46176 Accepted +[Thu Jul 30 19:08:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 19:08:32 2026] 127.0.0.1:46176 [200]: GET /api/stats.php +[Thu Jul 30 19:08:32 2026] 127.0.0.1:46176 Closing +[Thu Jul 30 19:08:32 2026] 127.0.0.1:46180 Accepted +[Thu Jul 30 19:08:32 2026] 127.0.0.1:46180 [200]: GET /api/chart.php?range=year +[Thu Jul 30 19:08:32 2026] 127.0.0.1:46180 Closing +[Thu Jul 30 19:09:32 2026] 127.0.0.1:39224 Accepted +[Thu Jul 30 19:09:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 19:09:32 2026] 127.0.0.1:39224 [200]: GET /api/stats.php +[Thu Jul 30 19:09:32 2026] 127.0.0.1:39224 Closing +[Thu Jul 30 19:09:32 2026] 127.0.0.1:39226 Accepted +[Thu Jul 30 19:09:32 2026] 127.0.0.1:39226 [200]: GET /api/chart.php?range=year +[Thu Jul 30 19:09:32 2026] 127.0.0.1:39226 Closing +[Thu Jul 30 19:10:32 2026] 127.0.0.1:54870 Accepted +[Thu Jul 30 19:10:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 19:10:32 2026] 127.0.0.1:54870 [200]: GET /api/stats.php +[Thu Jul 30 19:10:32 2026] 127.0.0.1:54870 Closing +[Thu Jul 30 19:10:32 2026] 127.0.0.1:54886 Accepted +[Thu Jul 30 19:10:32 2026] 127.0.0.1:54886 [200]: GET /api/chart.php?range=year +[Thu Jul 30 19:10:32 2026] 127.0.0.1:54886 Closing +[Thu Jul 30 19:11:32 2026] 127.0.0.1:43926 Accepted +[Thu Jul 30 19:11:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 19:11:32 2026] 127.0.0.1:43926 [200]: GET /api/stats.php +[Thu Jul 30 19:11:32 2026] 127.0.0.1:43926 Closing +[Thu Jul 30 19:11:32 2026] 127.0.0.1:43940 Accepted +[Thu Jul 30 19:11:32 2026] 127.0.0.1:43940 [200]: GET /api/chart.php?range=year +[Thu Jul 30 19:11:32 2026] 127.0.0.1:43940 Closing +[Thu Jul 30 19:11:41 2026] 127.0.0.1:46102 Accepted +[Thu Jul 30 19:11:42 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 19:11:42 2026] 127.0.0.1:46102 [200]: GET /api/stats.php +[Thu Jul 30 19:11:42 2026] 127.0.0.1:46102 Closing +[Thu Jul 30 19:11:42 2026] 127.0.0.1:46118 Accepted +[Thu Jul 30 19:11:42 2026] 127.0.0.1:46118 [200]: GET /api/chart.php?range=year +[Thu Jul 30 19:11:42 2026] 127.0.0.1:46118 Closing +[Thu Jul 30 19:11:51 2026] 127.0.0.1:43370 Accepted +[Thu Jul 30 19:11:51 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 19:11:51 2026] 127.0.0.1:43370 [200]: GET /api/stats.php +[Thu Jul 30 19:11:51 2026] 127.0.0.1:43370 Closing +[Thu Jul 30 19:11:51 2026] 127.0.0.1:43382 Accepted +[Thu Jul 30 19:11:51 2026] 127.0.0.1:43382 [200]: GET /api/chart.php?range=year +[Thu Jul 30 19:11:51 2026] 127.0.0.1:43382 Closing +[Thu Jul 30 19:11:56 2026] 127.0.0.1:60948 Accepted +[Thu Jul 30 19:11:56 2026] 127.0.0.1:60948 [200]: GET /api/chart.php?range=day +[Thu Jul 30 19:11:56 2026] 127.0.0.1:60948 Closing +[Thu Jul 30 19:12:01 2026] 127.0.0.1:60964 Accepted +[Thu Jul 30 19:12:01 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 19:12:01 2026] 127.0.0.1:60964 [200]: GET /api/stats.php +[Thu Jul 30 19:12:01 2026] 127.0.0.1:60964 Closing +[Thu Jul 30 19:12:01 2026] 127.0.0.1:60980 Accepted +[Thu Jul 30 19:12:01 2026] 127.0.0.1:60980 [200]: GET /api/chart.php?range=year +[Thu Jul 30 19:12:01 2026] 127.0.0.1:60980 Closing +[Thu Jul 30 19:12:11 2026] 127.0.0.1:42056 Accepted +[Thu Jul 30 19:12:11 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 19:12:11 2026] 127.0.0.1:42056 [200]: GET /api/stats.php +[Thu Jul 30 19:12:11 2026] 127.0.0.1:42056 Closing +[Thu Jul 30 19:12:11 2026] 127.0.0.1:42072 Accepted +[Thu Jul 30 19:12:11 2026] 127.0.0.1:42072 [200]: GET /api/chart.php?range=year +[Thu Jul 30 19:12:11 2026] 127.0.0.1:42072 Closing +[Thu Jul 30 19:12:22 2026] 127.0.0.1:58178 Accepted +[Thu Jul 30 19:12:22 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 19:12:22 2026] 127.0.0.1:58178 [200]: GET /api/stats.php +[Thu Jul 30 19:12:22 2026] 127.0.0.1:58178 Closing +[Thu Jul 30 19:12:22 2026] 127.0.0.1:58184 Accepted +[Thu Jul 30 19:12:22 2026] 127.0.0.1:58184 [200]: GET /api/chart.php?range=year +[Thu Jul 30 19:12:22 2026] 127.0.0.1:58184 Closing +[Thu Jul 30 19:12:32 2026] 127.0.0.1:55904 Accepted +[Thu Jul 30 19:12:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 19:12:32 2026] 127.0.0.1:55904 [200]: GET /api/stats.php +[Thu Jul 30 19:12:32 2026] 127.0.0.1:55904 Closing +[Thu Jul 30 19:12:32 2026] 127.0.0.1:55914 Accepted +[Thu Jul 30 19:12:32 2026] 127.0.0.1:55914 [200]: GET /api/chart.php?range=year +[Thu Jul 30 19:12:32 2026] 127.0.0.1:55914 Closing +[Thu Jul 30 19:12:42 2026] 127.0.0.1:44092 Accepted +[Thu Jul 30 19:12:42 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 19:12:42 2026] 127.0.0.1:44092 [200]: GET /api/stats.php +[Thu Jul 30 19:12:42 2026] 127.0.0.1:44092 Closing +[Thu Jul 30 19:12:42 2026] 127.0.0.1:44106 Accepted +[Thu Jul 30 19:12:42 2026] 127.0.0.1:44106 [200]: GET /api/chart.php?range=year +[Thu Jul 30 19:12:42 2026] 127.0.0.1:44106 Closing +[Thu Jul 30 19:12:52 2026] 127.0.0.1:58546 Accepted +[Thu Jul 30 19:12:52 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 19:12:52 2026] 127.0.0.1:58546 [200]: GET /api/stats.php +[Thu Jul 30 19:12:52 2026] 127.0.0.1:58546 Closing +[Thu Jul 30 19:12:52 2026] 127.0.0.1:58558 Accepted +[Thu Jul 30 19:12:52 2026] 127.0.0.1:58558 [200]: GET /api/chart.php?range=year +[Thu Jul 30 19:12:52 2026] 127.0.0.1:58558 Closing +[Thu Jul 30 19:13:02 2026] 127.0.0.1:49272 Accepted +[Thu Jul 30 19:13:02 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 19:13:02 2026] 127.0.0.1:49272 [200]: GET /api/stats.php +[Thu Jul 30 19:13:02 2026] 127.0.0.1:49272 Closing +[Thu Jul 30 19:13:02 2026] 127.0.0.1:49280 Accepted +[Thu Jul 30 19:13:02 2026] 127.0.0.1:49280 [200]: GET /api/chart.php?range=year +[Thu Jul 30 19:13:02 2026] 127.0.0.1:49280 Closing +[Thu Jul 30 19:13:12 2026] 127.0.0.1:35098 Accepted +[Thu Jul 30 19:13:12 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 19:13:12 2026] 127.0.0.1:35098 [200]: GET /api/stats.php +[Thu Jul 30 19:13:12 2026] 127.0.0.1:35098 Closing +[Thu Jul 30 19:13:12 2026] 127.0.0.1:35110 Accepted +[Thu Jul 30 19:13:12 2026] 127.0.0.1:35110 [200]: GET /api/chart.php?range=year +[Thu Jul 30 19:13:12 2026] 127.0.0.1:35110 Closing +[Thu Jul 30 19:13:32 2026] 127.0.0.1:59598 Accepted +[Thu Jul 30 19:13:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 19:13:32 2026] 127.0.0.1:59598 [200]: GET /api/stats.php +[Thu Jul 30 19:13:32 2026] 127.0.0.1:59598 Closing +[Thu Jul 30 19:13:32 2026] 127.0.0.1:59600 Accepted +[Thu Jul 30 19:13:32 2026] 127.0.0.1:59600 [200]: GET /api/chart.php?range=year +[Thu Jul 30 19:13:32 2026] 127.0.0.1:59600 Closing +[Thu Jul 30 19:14:32 2026] 127.0.0.1:45782 Accepted +[Thu Jul 30 19:14:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 19:14:32 2026] 127.0.0.1:45782 [200]: GET /api/stats.php +[Thu Jul 30 19:14:32 2026] 127.0.0.1:45782 Closing +[Thu Jul 30 19:14:32 2026] 127.0.0.1:45796 Accepted +[Thu Jul 30 19:14:32 2026] 127.0.0.1:45796 [200]: GET /api/chart.php?range=year +[Thu Jul 30 19:14:32 2026] 127.0.0.1:45796 Closing +[Thu Jul 30 19:15:32 2026] 127.0.0.1:44790 Accepted +[Thu Jul 30 19:15:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 19:15:32 2026] 127.0.0.1:44790 [200]: GET /api/stats.php +[Thu Jul 30 19:15:32 2026] 127.0.0.1:44790 Closing +[Thu Jul 30 19:15:32 2026] 127.0.0.1:44796 Accepted +[Thu Jul 30 19:15:32 2026] 127.0.0.1:44796 [200]: GET /api/chart.php?range=year +[Thu Jul 30 19:15:32 2026] 127.0.0.1:44796 Closing +[Thu Jul 30 19:16:32 2026] 127.0.0.1:43548 Accepted +[Thu Jul 30 19:16:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 19:16:32 2026] 127.0.0.1:43548 [200]: GET /api/stats.php +[Thu Jul 30 19:16:32 2026] 127.0.0.1:43548 Closing +[Thu Jul 30 19:16:32 2026] 127.0.0.1:43562 Accepted +[Thu Jul 30 19:16:32 2026] 127.0.0.1:43562 [200]: GET /api/chart.php?range=year +[Thu Jul 30 19:16:32 2026] 127.0.0.1:43562 Closing +[Thu Jul 30 19:17:32 2026] 127.0.0.1:42794 Accepted +[Thu Jul 30 19:17:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 19:17:32 2026] 127.0.0.1:42794 [200]: GET /api/stats.php +[Thu Jul 30 19:17:32 2026] 127.0.0.1:42794 Closing +[Thu Jul 30 19:17:32 2026] 127.0.0.1:42808 Accepted +[Thu Jul 30 19:17:32 2026] 127.0.0.1:42808 [200]: GET /api/chart.php?range=year +[Thu Jul 30 19:17:32 2026] 127.0.0.1:42808 Closing +[Thu Jul 30 19:18:32 2026] 127.0.0.1:52414 Accepted +[Thu Jul 30 19:18:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 19:18:32 2026] 127.0.0.1:52414 [200]: GET /api/stats.php +[Thu Jul 30 19:18:32 2026] 127.0.0.1:52414 Closing +[Thu Jul 30 19:18:32 2026] 127.0.0.1:52418 Accepted +[Thu Jul 30 19:18:32 2026] 127.0.0.1:52418 [200]: GET /api/chart.php?range=year +[Thu Jul 30 19:18:32 2026] 127.0.0.1:52418 Closing +[Thu Jul 30 19:19:32 2026] 127.0.0.1:40510 Accepted +[Thu Jul 30 19:19:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 19:19:32 2026] 127.0.0.1:40510 [200]: GET /api/stats.php +[Thu Jul 30 19:19:32 2026] 127.0.0.1:40510 Closing +[Thu Jul 30 19:19:33 2026] 127.0.0.1:40516 Accepted +[Thu Jul 30 19:19:33 2026] 127.0.0.1:40516 [200]: GET /api/chart.php?range=year +[Thu Jul 30 19:19:33 2026] 127.0.0.1:40516 Closing +[Thu Jul 30 19:20:32 2026] 127.0.0.1:48384 Accepted +[Thu Jul 30 19:20:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 19:20:32 2026] 127.0.0.1:48384 [200]: GET /api/stats.php +[Thu Jul 30 19:20:32 2026] 127.0.0.1:48384 Closing +[Thu Jul 30 19:20:32 2026] 127.0.0.1:48400 Accepted +[Thu Jul 30 19:20:32 2026] 127.0.0.1:48400 [200]: GET /api/chart.php?range=year +[Thu Jul 30 19:20:32 2026] 127.0.0.1:48400 Closing +[Thu Jul 30 19:21:31 2026] 127.0.0.1:40390 Accepted +[Thu Jul 30 19:21:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 19:21:32 2026] 127.0.0.1:40390 [200]: GET /api/stats.php +[Thu Jul 30 19:21:32 2026] 127.0.0.1:40390 Closing +[Thu Jul 30 19:21:32 2026] 127.0.0.1:40394 Accepted +[Thu Jul 30 19:21:32 2026] 127.0.0.1:40394 [200]: GET /api/chart.php?range=year +[Thu Jul 30 19:21:32 2026] 127.0.0.1:40394 Closing +[Thu Jul 30 19:22:31 2026] 127.0.0.1:42774 Accepted +[Thu Jul 30 19:22:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 19:22:32 2026] 127.0.0.1:42774 [200]: GET /api/stats.php +[Thu Jul 30 19:22:32 2026] 127.0.0.1:42774 Closing +[Thu Jul 30 19:22:32 2026] 127.0.0.1:42784 Accepted +[Thu Jul 30 19:22:32 2026] 127.0.0.1:42784 [200]: GET /api/chart.php?range=year +[Thu Jul 30 19:22:32 2026] 127.0.0.1:42784 Closing +[Thu Jul 30 19:23:31 2026] 127.0.0.1:58852 Accepted +[Thu Jul 30 19:23:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 19:23:32 2026] 127.0.0.1:58852 [200]: GET /api/stats.php +[Thu Jul 30 19:23:32 2026] 127.0.0.1:58852 Closing +[Thu Jul 30 19:23:32 2026] 127.0.0.1:58860 Accepted +[Thu Jul 30 19:23:32 2026] 127.0.0.1:58860 [200]: GET /api/chart.php?range=year +[Thu Jul 30 19:23:32 2026] 127.0.0.1:58860 Closing +[Thu Jul 30 19:24:31 2026] 127.0.0.1:42238 Accepted +[Thu Jul 30 19:24:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 19:24:32 2026] 127.0.0.1:42238 [200]: GET /api/stats.php +[Thu Jul 30 19:24:32 2026] 127.0.0.1:42238 Closing +[Thu Jul 30 19:24:32 2026] 127.0.0.1:42250 Accepted +[Thu Jul 30 19:24:32 2026] 127.0.0.1:42250 [200]: GET /api/chart.php?range=year +[Thu Jul 30 19:24:32 2026] 127.0.0.1:42250 Closing +[Thu Jul 30 19:25:31 2026] 127.0.0.1:59956 Accepted +[Thu Jul 30 19:25:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 19:25:32 2026] 127.0.0.1:59956 [200]: GET /api/stats.php +[Thu Jul 30 19:25:32 2026] 127.0.0.1:59956 Closing +[Thu Jul 30 19:25:32 2026] 127.0.0.1:59968 Accepted +[Thu Jul 30 19:25:32 2026] 127.0.0.1:59968 [200]: GET /api/chart.php?range=year +[Thu Jul 30 19:25:32 2026] 127.0.0.1:59968 Closing +[Thu Jul 30 19:26:31 2026] 127.0.0.1:56084 Accepted +[Thu Jul 30 19:26:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 19:26:32 2026] 127.0.0.1:56084 [200]: GET /api/stats.php +[Thu Jul 30 19:26:32 2026] 127.0.0.1:56084 Closing +[Thu Jul 30 19:26:32 2026] 127.0.0.1:56098 Accepted +[Thu Jul 30 19:26:32 2026] 127.0.0.1:56098 [200]: GET /api/chart.php?range=year +[Thu Jul 30 19:26:32 2026] 127.0.0.1:56098 Closing +[Thu Jul 30 19:27:31 2026] 127.0.0.1:37308 Accepted +[Thu Jul 30 19:27:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 19:27:32 2026] 127.0.0.1:37308 [200]: GET /api/stats.php +[Thu Jul 30 19:27:32 2026] 127.0.0.1:37308 Closing +[Thu Jul 30 19:27:32 2026] 127.0.0.1:37310 Accepted +[Thu Jul 30 19:27:32 2026] 127.0.0.1:37310 [200]: GET /api/chart.php?range=year +[Thu Jul 30 19:27:32 2026] 127.0.0.1:37310 Closing +[Thu Jul 30 19:28:31 2026] 127.0.0.1:47300 Accepted +[Thu Jul 30 19:28:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 19:28:32 2026] 127.0.0.1:47300 [200]: GET /api/stats.php +[Thu Jul 30 19:28:32 2026] 127.0.0.1:47300 Closing +[Thu Jul 30 19:28:32 2026] 127.0.0.1:47316 Accepted +[Thu Jul 30 19:28:32 2026] 127.0.0.1:47316 [200]: GET /api/chart.php?range=year +[Thu Jul 30 19:28:32 2026] 127.0.0.1:47316 Closing +[Thu Jul 30 19:29:31 2026] 127.0.0.1:39866 Accepted +[Thu Jul 30 19:29:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 19:29:32 2026] 127.0.0.1:39866 [200]: GET /api/stats.php +[Thu Jul 30 19:29:32 2026] 127.0.0.1:39866 Closing +[Thu Jul 30 19:29:32 2026] 127.0.0.1:39872 Accepted +[Thu Jul 30 19:29:32 2026] 127.0.0.1:39872 [200]: GET /api/chart.php?range=year +[Thu Jul 30 19:29:32 2026] 127.0.0.1:39872 Closing +[Thu Jul 30 19:30:31 2026] 127.0.0.1:50920 Accepted +[Thu Jul 30 19:30:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 19:30:32 2026] 127.0.0.1:50920 [200]: GET /api/stats.php +[Thu Jul 30 19:30:32 2026] 127.0.0.1:50920 Closing +[Thu Jul 30 19:30:32 2026] 127.0.0.1:50922 Accepted +[Thu Jul 30 19:30:32 2026] 127.0.0.1:50922 [200]: GET /api/chart.php?range=year +[Thu Jul 30 19:30:32 2026] 127.0.0.1:50922 Closing +[Thu Jul 30 19:31:31 2026] 127.0.0.1:47956 Accepted +[Thu Jul 30 19:31:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 19:31:32 2026] 127.0.0.1:47956 [200]: GET /api/stats.php +[Thu Jul 30 19:31:32 2026] 127.0.0.1:47956 Closing +[Thu Jul 30 19:31:32 2026] 127.0.0.1:47966 Accepted +[Thu Jul 30 19:31:32 2026] 127.0.0.1:47966 [200]: GET /api/chart.php?range=year +[Thu Jul 30 19:31:32 2026] 127.0.0.1:47966 Closing +[Thu Jul 30 19:32:31 2026] 127.0.0.1:58468 Accepted +[Thu Jul 30 19:32:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 19:32:32 2026] 127.0.0.1:58468 [200]: GET /api/stats.php +[Thu Jul 30 19:32:32 2026] 127.0.0.1:58468 Closing +[Thu Jul 30 19:32:32 2026] 127.0.0.1:58474 Accepted +[Thu Jul 30 19:32:32 2026] 127.0.0.1:58474 [200]: GET /api/chart.php?range=year +[Thu Jul 30 19:32:32 2026] 127.0.0.1:58474 Closing +[Thu Jul 30 19:33:31 2026] 127.0.0.1:52032 Accepted +[Thu Jul 30 19:33:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 19:33:32 2026] 127.0.0.1:52032 [200]: GET /api/stats.php +[Thu Jul 30 19:33:32 2026] 127.0.0.1:52032 Closing +[Thu Jul 30 19:33:32 2026] 127.0.0.1:52040 Accepted +[Thu Jul 30 19:33:32 2026] 127.0.0.1:52040 [200]: GET /api/chart.php?range=year +[Thu Jul 30 19:33:32 2026] 127.0.0.1:52040 Closing +[Thu Jul 30 19:34:31 2026] 127.0.0.1:50232 Accepted +[Thu Jul 30 19:34:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 19:34:32 2026] 127.0.0.1:50232 [200]: GET /api/stats.php +[Thu Jul 30 19:34:32 2026] 127.0.0.1:50232 Closing +[Thu Jul 30 19:34:32 2026] 127.0.0.1:50234 Accepted +[Thu Jul 30 19:34:32 2026] 127.0.0.1:50234 [200]: GET /api/chart.php?range=year +[Thu Jul 30 19:34:32 2026] 127.0.0.1:50234 Closing +[Thu Jul 30 19:35:31 2026] 127.0.0.1:47148 Accepted +[Thu Jul 30 19:35:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 19:35:32 2026] 127.0.0.1:47148 [200]: GET /api/stats.php +[Thu Jul 30 19:35:32 2026] 127.0.0.1:47148 Closing +[Thu Jul 30 19:35:32 2026] 127.0.0.1:47156 Accepted +[Thu Jul 30 19:35:32 2026] 127.0.0.1:47156 [200]: GET /api/chart.php?range=year +[Thu Jul 30 19:35:32 2026] 127.0.0.1:47156 Closing +[Thu Jul 30 19:36:31 2026] 127.0.0.1:51068 Accepted +[Thu Jul 30 19:36:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 19:36:32 2026] 127.0.0.1:51068 [200]: GET /api/stats.php +[Thu Jul 30 19:36:32 2026] 127.0.0.1:51068 Closing +[Thu Jul 30 19:36:32 2026] 127.0.0.1:51076 Accepted +[Thu Jul 30 19:36:32 2026] 127.0.0.1:51076 [200]: GET /api/chart.php?range=year +[Thu Jul 30 19:36:32 2026] 127.0.0.1:51076 Closing +[Thu Jul 30 19:37:31 2026] 127.0.0.1:53708 Accepted +[Thu Jul 30 19:37:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 19:37:32 2026] 127.0.0.1:53708 [200]: GET /api/stats.php +[Thu Jul 30 19:37:32 2026] 127.0.0.1:53708 Closing +[Thu Jul 30 19:37:32 2026] 127.0.0.1:53720 Accepted +[Thu Jul 30 19:37:32 2026] 127.0.0.1:53720 [200]: GET /api/chart.php?range=year +[Thu Jul 30 19:37:32 2026] 127.0.0.1:53720 Closing +[Thu Jul 30 19:38:31 2026] 127.0.0.1:51148 Accepted +[Thu Jul 30 19:38:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 19:38:32 2026] 127.0.0.1:51148 [200]: GET /api/stats.php +[Thu Jul 30 19:38:32 2026] 127.0.0.1:51148 Closing +[Thu Jul 30 19:38:32 2026] 127.0.0.1:51162 Accepted +[Thu Jul 30 19:38:32 2026] 127.0.0.1:51162 [200]: GET /api/chart.php?range=year +[Thu Jul 30 19:38:32 2026] 127.0.0.1:51162 Closing +[Thu Jul 30 19:39:31 2026] 127.0.0.1:34756 Accepted +[Thu Jul 30 19:39:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 19:39:32 2026] 127.0.0.1:34756 [200]: GET /api/stats.php +[Thu Jul 30 19:39:32 2026] 127.0.0.1:34756 Closing +[Thu Jul 30 19:39:32 2026] 127.0.0.1:34764 Accepted +[Thu Jul 30 19:39:32 2026] 127.0.0.1:34764 [200]: GET /api/chart.php?range=year +[Thu Jul 30 19:39:32 2026] 127.0.0.1:34764 Closing +[Thu Jul 30 19:40:31 2026] 127.0.0.1:57396 Accepted +[Thu Jul 30 19:40:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 19:40:32 2026] 127.0.0.1:57396 [200]: GET /api/stats.php +[Thu Jul 30 19:40:32 2026] 127.0.0.1:57396 Closing +[Thu Jul 30 19:40:32 2026] 127.0.0.1:57412 Accepted +[Thu Jul 30 19:40:32 2026] 127.0.0.1:57412 [200]: GET /api/chart.php?range=year +[Thu Jul 30 19:40:32 2026] 127.0.0.1:57412 Closing +[Thu Jul 30 19:41:31 2026] 127.0.0.1:60176 Accepted +[Thu Jul 30 19:41:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 19:41:32 2026] 127.0.0.1:60176 [200]: GET /api/stats.php +[Thu Jul 30 19:41:32 2026] 127.0.0.1:60176 Closing +[Thu Jul 30 19:41:32 2026] 127.0.0.1:60178 Accepted +[Thu Jul 30 19:41:32 2026] 127.0.0.1:60178 [200]: GET /api/chart.php?range=year +[Thu Jul 30 19:41:32 2026] 127.0.0.1:60178 Closing +[Thu Jul 30 19:42:31 2026] 127.0.0.1:54222 Accepted +[Thu Jul 30 19:42:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 19:42:32 2026] 127.0.0.1:54222 [200]: GET /api/stats.php +[Thu Jul 30 19:42:32 2026] 127.0.0.1:54222 Closing +[Thu Jul 30 19:42:32 2026] 127.0.0.1:54238 Accepted +[Thu Jul 30 19:42:32 2026] 127.0.0.1:54238 [200]: GET /api/chart.php?range=year +[Thu Jul 30 19:42:32 2026] 127.0.0.1:54238 Closing +[Thu Jul 30 19:43:31 2026] 127.0.0.1:46878 Accepted +[Thu Jul 30 19:43:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 19:43:32 2026] 127.0.0.1:46878 [200]: GET /api/stats.php +[Thu Jul 30 19:43:32 2026] 127.0.0.1:46878 Closing +[Thu Jul 30 19:43:32 2026] 127.0.0.1:46894 Accepted +[Thu Jul 30 19:43:32 2026] 127.0.0.1:46894 [200]: GET /api/chart.php?range=year +[Thu Jul 30 19:43:32 2026] 127.0.0.1:46894 Closing +[Thu Jul 30 19:44:31 2026] 127.0.0.1:50112 Accepted +[Thu Jul 30 19:44:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 19:44:32 2026] 127.0.0.1:50112 [200]: GET /api/stats.php +[Thu Jul 30 19:44:32 2026] 127.0.0.1:50112 Closing +[Thu Jul 30 19:44:32 2026] 127.0.0.1:50118 Accepted +[Thu Jul 30 19:44:32 2026] 127.0.0.1:50118 [200]: GET /api/chart.php?range=year +[Thu Jul 30 19:44:32 2026] 127.0.0.1:50118 Closing +[Thu Jul 30 19:45:31 2026] 127.0.0.1:37956 Accepted +[Thu Jul 30 19:45:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 19:45:32 2026] 127.0.0.1:37956 [200]: GET /api/stats.php +[Thu Jul 30 19:45:32 2026] 127.0.0.1:37956 Closing +[Thu Jul 30 19:45:32 2026] 127.0.0.1:37966 Accepted +[Thu Jul 30 19:45:32 2026] 127.0.0.1:37966 [200]: GET /api/chart.php?range=year +[Thu Jul 30 19:45:32 2026] 127.0.0.1:37966 Closing +[Thu Jul 30 19:46:31 2026] 127.0.0.1:57894 Accepted +[Thu Jul 30 19:46:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 19:46:32 2026] 127.0.0.1:57894 [200]: GET /api/stats.php +[Thu Jul 30 19:46:32 2026] 127.0.0.1:57894 Closing +[Thu Jul 30 19:46:32 2026] 127.0.0.1:57910 Accepted +[Thu Jul 30 19:46:32 2026] 127.0.0.1:57910 [200]: GET /api/chart.php?range=year +[Thu Jul 30 19:46:32 2026] 127.0.0.1:57910 Closing +[Thu Jul 30 19:47:31 2026] 127.0.0.1:36238 Accepted +[Thu Jul 30 19:47:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 19:47:32 2026] 127.0.0.1:36238 [200]: GET /api/stats.php +[Thu Jul 30 19:47:32 2026] 127.0.0.1:36238 Closing +[Thu Jul 30 19:47:32 2026] 127.0.0.1:36250 Accepted +[Thu Jul 30 19:47:32 2026] 127.0.0.1:36250 [200]: GET /api/chart.php?range=year +[Thu Jul 30 19:47:32 2026] 127.0.0.1:36250 Closing +[Thu Jul 30 19:48:31 2026] 127.0.0.1:44226 Accepted +[Thu Jul 30 19:48:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 19:48:32 2026] 127.0.0.1:44226 [200]: GET /api/stats.php +[Thu Jul 30 19:48:32 2026] 127.0.0.1:44226 Closing +[Thu Jul 30 19:48:32 2026] 127.0.0.1:44234 Accepted +[Thu Jul 30 19:48:32 2026] 127.0.0.1:44234 [200]: GET /api/chart.php?range=year +[Thu Jul 30 19:48:32 2026] 127.0.0.1:44234 Closing +[Thu Jul 30 19:49:31 2026] 127.0.0.1:57082 Accepted +[Thu Jul 30 19:49:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 19:49:32 2026] 127.0.0.1:57082 [200]: GET /api/stats.php +[Thu Jul 30 19:49:32 2026] 127.0.0.1:57082 Closing +[Thu Jul 30 19:49:32 2026] 127.0.0.1:57096 Accepted +[Thu Jul 30 19:49:32 2026] 127.0.0.1:57096 [200]: GET /api/chart.php?range=year +[Thu Jul 30 19:49:32 2026] 127.0.0.1:57096 Closing +[Thu Jul 30 19:50:31 2026] 127.0.0.1:33728 Accepted +[Thu Jul 30 19:50:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 19:50:32 2026] 127.0.0.1:33728 [200]: GET /api/stats.php +[Thu Jul 30 19:50:32 2026] 127.0.0.1:33728 Closing +[Thu Jul 30 19:50:32 2026] 127.0.0.1:33742 Accepted +[Thu Jul 30 19:50:32 2026] 127.0.0.1:33742 [200]: GET /api/chart.php?range=year +[Thu Jul 30 19:50:32 2026] 127.0.0.1:33742 Closing +[Thu Jul 30 19:51:31 2026] 127.0.0.1:57090 Accepted +[Thu Jul 30 19:51:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 19:51:32 2026] 127.0.0.1:57090 [200]: GET /api/stats.php +[Thu Jul 30 19:51:32 2026] 127.0.0.1:57090 Closing +[Thu Jul 30 19:51:32 2026] 127.0.0.1:57096 Accepted +[Thu Jul 30 19:51:32 2026] 127.0.0.1:57096 [200]: GET /api/chart.php?range=year +[Thu Jul 30 19:51:32 2026] 127.0.0.1:57096 Closing +[Thu Jul 30 19:52:31 2026] 127.0.0.1:55712 Accepted +[Thu Jul 30 19:52:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 19:52:32 2026] 127.0.0.1:55712 [200]: GET /api/stats.php +[Thu Jul 30 19:52:32 2026] 127.0.0.1:55712 Closing +[Thu Jul 30 19:52:32 2026] 127.0.0.1:55720 Accepted +[Thu Jul 30 19:52:32 2026] 127.0.0.1:55720 [200]: GET /api/chart.php?range=year +[Thu Jul 30 19:52:32 2026] 127.0.0.1:55720 Closing +[Thu Jul 30 19:53:31 2026] 127.0.0.1:39344 Accepted +[Thu Jul 30 19:53:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 19:53:32 2026] 127.0.0.1:39344 [200]: GET /api/stats.php +[Thu Jul 30 19:53:32 2026] 127.0.0.1:39344 Closing +[Thu Jul 30 19:53:32 2026] 127.0.0.1:39356 Accepted +[Thu Jul 30 19:53:32 2026] 127.0.0.1:39356 [200]: GET /api/chart.php?range=year +[Thu Jul 30 19:53:32 2026] 127.0.0.1:39356 Closing +[Thu Jul 30 19:54:31 2026] 127.0.0.1:47462 Accepted +[Thu Jul 30 19:54:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 19:54:32 2026] 127.0.0.1:47462 [200]: GET /api/stats.php +[Thu Jul 30 19:54:32 2026] 127.0.0.1:47462 Closing +[Thu Jul 30 19:54:32 2026] 127.0.0.1:47478 Accepted +[Thu Jul 30 19:54:32 2026] 127.0.0.1:47478 [200]: GET /api/chart.php?range=year +[Thu Jul 30 19:54:32 2026] 127.0.0.1:47478 Closing +[Thu Jul 30 19:55:31 2026] 127.0.0.1:36456 Accepted +[Thu Jul 30 19:55:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 19:55:32 2026] 127.0.0.1:36456 [200]: GET /api/stats.php +[Thu Jul 30 19:55:32 2026] 127.0.0.1:36456 Closing +[Thu Jul 30 19:55:32 2026] 127.0.0.1:36458 Accepted +[Thu Jul 30 19:55:32 2026] 127.0.0.1:36458 [200]: GET /api/chart.php?range=year +[Thu Jul 30 19:55:32 2026] 127.0.0.1:36458 Closing +[Thu Jul 30 19:56:32 2026] 127.0.0.1:49184 Accepted +[Thu Jul 30 19:56:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 19:56:32 2026] 127.0.0.1:49184 [200]: GET /api/stats.php +[Thu Jul 30 19:56:32 2026] 127.0.0.1:49184 Closing +[Thu Jul 30 19:56:32 2026] 127.0.0.1:49186 Accepted +[Thu Jul 30 19:56:32 2026] 127.0.0.1:49186 [200]: GET /api/chart.php?range=year +[Thu Jul 30 19:56:32 2026] 127.0.0.1:49186 Closing +[Thu Jul 30 19:57:31 2026] 127.0.0.1:44028 Accepted +[Thu Jul 30 19:57:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 19:57:32 2026] 127.0.0.1:44028 [200]: GET /api/stats.php +[Thu Jul 30 19:57:32 2026] 127.0.0.1:44028 Closing +[Thu Jul 30 19:57:32 2026] 127.0.0.1:44030 Accepted +[Thu Jul 30 19:57:32 2026] 127.0.0.1:44030 [200]: GET /api/chart.php?range=year +[Thu Jul 30 19:57:32 2026] 127.0.0.1:44030 Closing +[Thu Jul 30 19:58:31 2026] 127.0.0.1:47702 Accepted +[Thu Jul 30 19:58:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 19:58:32 2026] 127.0.0.1:47702 [200]: GET /api/stats.php +[Thu Jul 30 19:58:32 2026] 127.0.0.1:47702 Closing +[Thu Jul 30 19:58:32 2026] 127.0.0.1:47704 Accepted +[Thu Jul 30 19:58:32 2026] 127.0.0.1:47704 [200]: GET /api/chart.php?range=year +[Thu Jul 30 19:58:32 2026] 127.0.0.1:47704 Closing +[Thu Jul 30 19:59:31 2026] 127.0.0.1:36288 Accepted +[Thu Jul 30 19:59:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 19:59:32 2026] 127.0.0.1:36288 [200]: GET /api/stats.php +[Thu Jul 30 19:59:32 2026] 127.0.0.1:36288 Closing +[Thu Jul 30 19:59:32 2026] 127.0.0.1:36302 Accepted +[Thu Jul 30 19:59:32 2026] 127.0.0.1:36302 [200]: GET /api/chart.php?range=year +[Thu Jul 30 19:59:32 2026] 127.0.0.1:36302 Closing +[Thu Jul 30 20:00:31 2026] 127.0.0.1:38312 Accepted +[Thu Jul 30 20:00:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 20:00:32 2026] 127.0.0.1:38312 [200]: GET /api/stats.php +[Thu Jul 30 20:00:32 2026] 127.0.0.1:38312 Closing +[Thu Jul 30 20:00:32 2026] 127.0.0.1:38326 Accepted +[Thu Jul 30 20:00:32 2026] 127.0.0.1:38326 [200]: GET /api/chart.php?range=year +[Thu Jul 30 20:00:32 2026] 127.0.0.1:38326 Closing +[Thu Jul 30 20:01:31 2026] 127.0.0.1:32934 Accepted +[Thu Jul 30 20:01:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 20:01:32 2026] 127.0.0.1:32934 [200]: GET /api/stats.php +[Thu Jul 30 20:01:32 2026] 127.0.0.1:32934 Closing +[Thu Jul 30 20:01:32 2026] 127.0.0.1:32940 Accepted +[Thu Jul 30 20:01:32 2026] 127.0.0.1:32940 [200]: GET /api/chart.php?range=year +[Thu Jul 30 20:01:32 2026] 127.0.0.1:32940 Closing +[Thu Jul 30 20:02:31 2026] 127.0.0.1:42866 Accepted +[Thu Jul 30 20:02:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 20:02:32 2026] 127.0.0.1:42866 [200]: GET /api/stats.php +[Thu Jul 30 20:02:32 2026] 127.0.0.1:42866 Closing +[Thu Jul 30 20:02:32 2026] 127.0.0.1:42874 Accepted +[Thu Jul 30 20:02:32 2026] 127.0.0.1:42874 [200]: GET /api/chart.php?range=year +[Thu Jul 30 20:02:32 2026] 127.0.0.1:42874 Closing +[Thu Jul 30 20:03:31 2026] 127.0.0.1:36892 Accepted +[Thu Jul 30 20:03:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 20:03:32 2026] 127.0.0.1:36892 [200]: GET /api/stats.php +[Thu Jul 30 20:03:32 2026] 127.0.0.1:36892 Closing +[Thu Jul 30 20:03:32 2026] 127.0.0.1:36908 Accepted +[Thu Jul 30 20:03:32 2026] 127.0.0.1:36908 [200]: GET /api/chart.php?range=year +[Thu Jul 30 20:03:32 2026] 127.0.0.1:36908 Closing +[Thu Jul 30 20:04:31 2026] 127.0.0.1:36542 Accepted +[Thu Jul 30 20:04:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 20:04:32 2026] 127.0.0.1:36542 [200]: GET /api/stats.php +[Thu Jul 30 20:04:32 2026] 127.0.0.1:36542 Closing +[Thu Jul 30 20:04:32 2026] 127.0.0.1:36546 Accepted +[Thu Jul 30 20:04:32 2026] 127.0.0.1:36546 [200]: GET /api/chart.php?range=year +[Thu Jul 30 20:04:32 2026] 127.0.0.1:36546 Closing +[Thu Jul 30 20:05:31 2026] 127.0.0.1:39150 Accepted +[Thu Jul 30 20:05:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 20:05:32 2026] 127.0.0.1:39150 [200]: GET /api/stats.php +[Thu Jul 30 20:05:32 2026] 127.0.0.1:39150 Closing +[Thu Jul 30 20:05:32 2026] 127.0.0.1:39152 Accepted +[Thu Jul 30 20:05:32 2026] 127.0.0.1:39152 [200]: GET /api/chart.php?range=year +[Thu Jul 30 20:05:32 2026] 127.0.0.1:39152 Closing +[Thu Jul 30 20:06:31 2026] 127.0.0.1:60044 Accepted +[Thu Jul 30 20:06:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 20:06:32 2026] 127.0.0.1:60044 [200]: GET /api/stats.php +[Thu Jul 30 20:06:32 2026] 127.0.0.1:60044 Closing +[Thu Jul 30 20:06:32 2026] 127.0.0.1:60052 Accepted +[Thu Jul 30 20:06:32 2026] 127.0.0.1:60052 [200]: GET /api/chart.php?range=year +[Thu Jul 30 20:06:32 2026] 127.0.0.1:60052 Closing +[Thu Jul 30 20:07:31 2026] 127.0.0.1:38310 Accepted +[Thu Jul 30 20:07:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 20:07:32 2026] 127.0.0.1:38310 [200]: GET /api/stats.php +[Thu Jul 30 20:07:32 2026] 127.0.0.1:38310 Closing +[Thu Jul 30 20:07:32 2026] 127.0.0.1:38318 Accepted +[Thu Jul 30 20:07:32 2026] 127.0.0.1:38318 [200]: GET /api/chart.php?range=year +[Thu Jul 30 20:07:32 2026] 127.0.0.1:38318 Closing +[Thu Jul 30 20:08:31 2026] 127.0.0.1:55460 Accepted +[Thu Jul 30 20:08:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 20:08:32 2026] 127.0.0.1:55460 [200]: GET /api/stats.php +[Thu Jul 30 20:08:32 2026] 127.0.0.1:55460 Closing +[Thu Jul 30 20:08:32 2026] 127.0.0.1:55470 Accepted +[Thu Jul 30 20:08:32 2026] 127.0.0.1:55470 [200]: GET /api/chart.php?range=year +[Thu Jul 30 20:08:32 2026] 127.0.0.1:55470 Closing +[Thu Jul 30 20:09:31 2026] 127.0.0.1:41028 Accepted +[Thu Jul 30 20:09:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 20:09:32 2026] 127.0.0.1:41028 [200]: GET /api/stats.php +[Thu Jul 30 20:09:32 2026] 127.0.0.1:41028 Closing +[Thu Jul 30 20:09:32 2026] 127.0.0.1:41044 Accepted +[Thu Jul 30 20:09:32 2026] 127.0.0.1:41044 [200]: GET /api/chart.php?range=year +[Thu Jul 30 20:09:32 2026] 127.0.0.1:41044 Closing +[Thu Jul 30 20:10:31 2026] 127.0.0.1:33358 Accepted +[Thu Jul 30 20:10:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 20:10:32 2026] 127.0.0.1:33358 [200]: GET /api/stats.php +[Thu Jul 30 20:10:32 2026] 127.0.0.1:33358 Closing +[Thu Jul 30 20:10:32 2026] 127.0.0.1:33374 Accepted +[Thu Jul 30 20:10:32 2026] 127.0.0.1:33374 [200]: GET /api/chart.php?range=year +[Thu Jul 30 20:10:32 2026] 127.0.0.1:33374 Closing +[Thu Jul 30 20:11:31 2026] 127.0.0.1:59944 Accepted +[Thu Jul 30 20:11:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 20:11:32 2026] 127.0.0.1:59944 [200]: GET /api/stats.php +[Thu Jul 30 20:11:32 2026] 127.0.0.1:59944 Closing +[Thu Jul 30 20:11:32 2026] 127.0.0.1:59948 Accepted +[Thu Jul 30 20:11:32 2026] 127.0.0.1:59948 [200]: GET /api/chart.php?range=year +[Thu Jul 30 20:11:32 2026] 127.0.0.1:59948 Closing +[Thu Jul 30 20:12:31 2026] 127.0.0.1:46876 Accepted +[Thu Jul 30 20:12:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 20:12:32 2026] 127.0.0.1:46876 [200]: GET /api/stats.php +[Thu Jul 30 20:12:32 2026] 127.0.0.1:46876 Closing +[Thu Jul 30 20:12:32 2026] 127.0.0.1:46882 Accepted +[Thu Jul 30 20:12:32 2026] 127.0.0.1:46882 [200]: GET /api/chart.php?range=year +[Thu Jul 30 20:12:32 2026] 127.0.0.1:46882 Closing +[Thu Jul 30 20:13:31 2026] 127.0.0.1:39924 Accepted +[Thu Jul 30 20:13:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 20:13:32 2026] 127.0.0.1:39924 [200]: GET /api/stats.php +[Thu Jul 30 20:13:32 2026] 127.0.0.1:39924 Closing +[Thu Jul 30 20:13:32 2026] 127.0.0.1:39940 Accepted +[Thu Jul 30 20:13:32 2026] 127.0.0.1:39940 [200]: GET /api/chart.php?range=year +[Thu Jul 30 20:13:32 2026] 127.0.0.1:39940 Closing +[Thu Jul 30 20:14:31 2026] 127.0.0.1:60320 Accepted +[Thu Jul 30 20:14:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 20:14:32 2026] 127.0.0.1:60320 [200]: GET /api/stats.php +[Thu Jul 30 20:14:32 2026] 127.0.0.1:60320 Closing +[Thu Jul 30 20:14:32 2026] 127.0.0.1:60328 Accepted +[Thu Jul 30 20:14:32 2026] 127.0.0.1:60328 [200]: GET /api/chart.php?range=year +[Thu Jul 30 20:14:32 2026] 127.0.0.1:60328 Closing +[Thu Jul 30 20:15:31 2026] 127.0.0.1:36896 Accepted +[Thu Jul 30 20:15:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 20:15:32 2026] 127.0.0.1:36896 [200]: GET /api/stats.php +[Thu Jul 30 20:15:32 2026] 127.0.0.1:36896 Closing +[Thu Jul 30 20:15:32 2026] 127.0.0.1:36906 Accepted +[Thu Jul 30 20:15:32 2026] 127.0.0.1:36906 [200]: GET /api/chart.php?range=year +[Thu Jul 30 20:15:32 2026] 127.0.0.1:36906 Closing +[Thu Jul 30 20:16:31 2026] 127.0.0.1:47790 Accepted +[Thu Jul 30 20:16:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 20:16:32 2026] 127.0.0.1:47790 [200]: GET /api/stats.php +[Thu Jul 30 20:16:32 2026] 127.0.0.1:47790 Closing +[Thu Jul 30 20:16:32 2026] 127.0.0.1:47798 Accepted +[Thu Jul 30 20:16:32 2026] 127.0.0.1:47798 [200]: GET /api/chart.php?range=year +[Thu Jul 30 20:16:32 2026] 127.0.0.1:47798 Closing +[Thu Jul 30 20:17:31 2026] 127.0.0.1:59534 Accepted +[Thu Jul 30 20:17:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 20:17:32 2026] 127.0.0.1:59534 [200]: GET /api/stats.php +[Thu Jul 30 20:17:32 2026] 127.0.0.1:59534 Closing +[Thu Jul 30 20:17:32 2026] 127.0.0.1:59540 Accepted +[Thu Jul 30 20:17:32 2026] 127.0.0.1:59540 [200]: GET /api/chart.php?range=year +[Thu Jul 30 20:17:32 2026] 127.0.0.1:59540 Closing +[Thu Jul 30 20:18:31 2026] 127.0.0.1:45408 Accepted +[Thu Jul 30 20:18:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 20:18:32 2026] 127.0.0.1:45408 [200]: GET /api/stats.php +[Thu Jul 30 20:18:32 2026] 127.0.0.1:45408 Closing +[Thu Jul 30 20:18:32 2026] 127.0.0.1:45412 Accepted +[Thu Jul 30 20:18:32 2026] 127.0.0.1:45412 [200]: GET /api/chart.php?range=year +[Thu Jul 30 20:18:32 2026] 127.0.0.1:45412 Closing +[Thu Jul 30 20:19:31 2026] 127.0.0.1:41242 Accepted +[Thu Jul 30 20:19:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 20:19:32 2026] 127.0.0.1:41242 [200]: GET /api/stats.php +[Thu Jul 30 20:19:32 2026] 127.0.0.1:41242 Closing +[Thu Jul 30 20:19:32 2026] 127.0.0.1:41244 Accepted +[Thu Jul 30 20:19:32 2026] 127.0.0.1:41244 [200]: GET /api/chart.php?range=year +[Thu Jul 30 20:19:32 2026] 127.0.0.1:41244 Closing +[Thu Jul 30 20:20:31 2026] 127.0.0.1:54402 Accepted +[Thu Jul 30 20:20:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 20:20:32 2026] 127.0.0.1:54402 [200]: GET /api/stats.php +[Thu Jul 30 20:20:32 2026] 127.0.0.1:54402 Closing +[Thu Jul 30 20:20:32 2026] 127.0.0.1:54404 Accepted +[Thu Jul 30 20:20:32 2026] 127.0.0.1:54404 [200]: GET /api/chart.php?range=year +[Thu Jul 30 20:20:32 2026] 127.0.0.1:54404 Closing +[Thu Jul 30 20:21:31 2026] 127.0.0.1:60576 Accepted +[Thu Jul 30 20:21:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 20:21:32 2026] 127.0.0.1:60576 [200]: GET /api/stats.php +[Thu Jul 30 20:21:32 2026] 127.0.0.1:60576 Closing +[Thu Jul 30 20:21:32 2026] 127.0.0.1:60584 Accepted +[Thu Jul 30 20:21:32 2026] 127.0.0.1:60584 [200]: GET /api/chart.php?range=year +[Thu Jul 30 20:21:32 2026] 127.0.0.1:60584 Closing +[Thu Jul 30 20:22:31 2026] 127.0.0.1:57806 Accepted +[Thu Jul 30 20:22:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 20:22:32 2026] 127.0.0.1:57806 [200]: GET /api/stats.php +[Thu Jul 30 20:22:32 2026] 127.0.0.1:57806 Closing +[Thu Jul 30 20:22:32 2026] 127.0.0.1:57810 Accepted +[Thu Jul 30 20:22:32 2026] 127.0.0.1:57810 [200]: GET /api/chart.php?range=year +[Thu Jul 30 20:22:32 2026] 127.0.0.1:57810 Closing +[Thu Jul 30 20:23:31 2026] 127.0.0.1:53718 Accepted +[Thu Jul 30 20:23:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 20:23:32 2026] 127.0.0.1:53718 [200]: GET /api/stats.php +[Thu Jul 30 20:23:32 2026] 127.0.0.1:53718 Closing +[Thu Jul 30 20:23:32 2026] 127.0.0.1:53730 Accepted +[Thu Jul 30 20:23:32 2026] 127.0.0.1:53730 [200]: GET /api/chart.php?range=year +[Thu Jul 30 20:23:32 2026] 127.0.0.1:53730 Closing +[Thu Jul 30 20:24:31 2026] 127.0.0.1:45126 Accepted +[Thu Jul 30 20:24:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 20:24:32 2026] 127.0.0.1:45126 [200]: GET /api/stats.php +[Thu Jul 30 20:24:32 2026] 127.0.0.1:45126 Closing +[Thu Jul 30 20:24:32 2026] 127.0.0.1:45132 Accepted +[Thu Jul 30 20:24:32 2026] 127.0.0.1:45132 [200]: GET /api/chart.php?range=year +[Thu Jul 30 20:24:32 2026] 127.0.0.1:45132 Closing +[Thu Jul 30 20:25:31 2026] 127.0.0.1:42900 Accepted +[Thu Jul 30 20:25:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 20:25:32 2026] 127.0.0.1:42900 [200]: GET /api/stats.php +[Thu Jul 30 20:25:32 2026] 127.0.0.1:42900 Closing +[Thu Jul 30 20:25:32 2026] 127.0.0.1:42916 Accepted +[Thu Jul 30 20:25:32 2026] 127.0.0.1:42916 [200]: GET /api/chart.php?range=year +[Thu Jul 30 20:25:32 2026] 127.0.0.1:42916 Closing +[Thu Jul 30 20:26:31 2026] 127.0.0.1:50992 Accepted +[Thu Jul 30 20:26:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 20:26:32 2026] 127.0.0.1:50992 [200]: GET /api/stats.php +[Thu Jul 30 20:26:32 2026] 127.0.0.1:50992 Closing +[Thu Jul 30 20:26:32 2026] 127.0.0.1:51000 Accepted +[Thu Jul 30 20:26:32 2026] 127.0.0.1:51000 [200]: GET /api/chart.php?range=year +[Thu Jul 30 20:26:32 2026] 127.0.0.1:51000 Closing +[Thu Jul 30 20:27:31 2026] 127.0.0.1:47364 Accepted +[Thu Jul 30 20:27:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 20:27:32 2026] 127.0.0.1:47364 [200]: GET /api/stats.php +[Thu Jul 30 20:27:32 2026] 127.0.0.1:47364 Closing +[Thu Jul 30 20:27:32 2026] 127.0.0.1:47380 Accepted +[Thu Jul 30 20:27:32 2026] 127.0.0.1:47380 [200]: GET /api/chart.php?range=year +[Thu Jul 30 20:27:32 2026] 127.0.0.1:47380 Closing +[Thu Jul 30 20:28:31 2026] 127.0.0.1:51454 Accepted +[Thu Jul 30 20:28:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 20:28:32 2026] 127.0.0.1:51454 [200]: GET /api/stats.php +[Thu Jul 30 20:28:32 2026] 127.0.0.1:51454 Closing +[Thu Jul 30 20:28:32 2026] 127.0.0.1:51468 Accepted +[Thu Jul 30 20:28:32 2026] 127.0.0.1:51468 [200]: GET /api/chart.php?range=year +[Thu Jul 30 20:28:32 2026] 127.0.0.1:51468 Closing +[Thu Jul 30 20:29:31 2026] 127.0.0.1:50668 Accepted +[Thu Jul 30 20:29:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 20:29:32 2026] 127.0.0.1:50668 [200]: GET /api/stats.php +[Thu Jul 30 20:29:32 2026] 127.0.0.1:50668 Closing +[Thu Jul 30 20:29:32 2026] 127.0.0.1:50684 Accepted +[Thu Jul 30 20:29:32 2026] 127.0.0.1:50684 [200]: GET /api/chart.php?range=year +[Thu Jul 30 20:29:32 2026] 127.0.0.1:50684 Closing +[Thu Jul 30 20:30:31 2026] 127.0.0.1:40738 Accepted +[Thu Jul 30 20:30:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 20:30:32 2026] 127.0.0.1:40738 [200]: GET /api/stats.php +[Thu Jul 30 20:30:32 2026] 127.0.0.1:40738 Closing +[Thu Jul 30 20:30:32 2026] 127.0.0.1:40744 Accepted +[Thu Jul 30 20:30:32 2026] 127.0.0.1:40744 [200]: GET /api/chart.php?range=year +[Thu Jul 30 20:30:32 2026] 127.0.0.1:40744 Closing +[Thu Jul 30 20:31:31 2026] 127.0.0.1:37320 Accepted +[Thu Jul 30 20:31:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 20:31:32 2026] 127.0.0.1:37320 [200]: GET /api/stats.php +[Thu Jul 30 20:31:32 2026] 127.0.0.1:37320 Closing +[Thu Jul 30 20:31:32 2026] 127.0.0.1:37322 Accepted +[Thu Jul 30 20:31:32 2026] 127.0.0.1:37322 [200]: GET /api/chart.php?range=year +[Thu Jul 30 20:31:32 2026] 127.0.0.1:37322 Closing +[Thu Jul 30 20:32:31 2026] 127.0.0.1:55892 Accepted +[Thu Jul 30 20:32:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 20:32:32 2026] 127.0.0.1:55892 [200]: GET /api/stats.php +[Thu Jul 30 20:32:32 2026] 127.0.0.1:55892 Closing +[Thu Jul 30 20:32:32 2026] 127.0.0.1:55906 Accepted +[Thu Jul 30 20:32:32 2026] 127.0.0.1:55906 [200]: GET /api/chart.php?range=year +[Thu Jul 30 20:32:32 2026] 127.0.0.1:55906 Closing +[Thu Jul 30 20:33:31 2026] 127.0.0.1:46410 Accepted +[Thu Jul 30 20:33:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 20:33:32 2026] 127.0.0.1:46410 [200]: GET /api/stats.php +[Thu Jul 30 20:33:32 2026] 127.0.0.1:46410 Closing +[Thu Jul 30 20:33:32 2026] 127.0.0.1:46418 Accepted +[Thu Jul 30 20:33:32 2026] 127.0.0.1:46418 [200]: GET /api/chart.php?range=year +[Thu Jul 30 20:33:32 2026] 127.0.0.1:46418 Closing +[Thu Jul 30 20:34:31 2026] 127.0.0.1:60024 Accepted +[Thu Jul 30 20:34:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 20:34:32 2026] 127.0.0.1:60024 [200]: GET /api/stats.php +[Thu Jul 30 20:34:32 2026] 127.0.0.1:60024 Closing +[Thu Jul 30 20:34:32 2026] 127.0.0.1:60026 Accepted +[Thu Jul 30 20:34:32 2026] 127.0.0.1:60026 [200]: GET /api/chart.php?range=year +[Thu Jul 30 20:34:32 2026] 127.0.0.1:60026 Closing +[Thu Jul 30 20:35:31 2026] 127.0.0.1:44794 Accepted +[Thu Jul 30 20:35:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 20:35:32 2026] 127.0.0.1:44794 [200]: GET /api/stats.php +[Thu Jul 30 20:35:32 2026] 127.0.0.1:44794 Closing +[Thu Jul 30 20:35:32 2026] 127.0.0.1:44808 Accepted +[Thu Jul 30 20:35:32 2026] 127.0.0.1:44808 [200]: GET /api/chart.php?range=year +[Thu Jul 30 20:35:32 2026] 127.0.0.1:44808 Closing +[Thu Jul 30 20:36:31 2026] 127.0.0.1:38974 Accepted +[Thu Jul 30 20:36:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 20:36:32 2026] 127.0.0.1:38974 [200]: GET /api/stats.php +[Thu Jul 30 20:36:32 2026] 127.0.0.1:38974 Closing +[Thu Jul 30 20:36:32 2026] 127.0.0.1:38976 Accepted +[Thu Jul 30 20:36:32 2026] 127.0.0.1:38976 [200]: GET /api/chart.php?range=year +[Thu Jul 30 20:36:32 2026] 127.0.0.1:38976 Closing +[Thu Jul 30 20:37:31 2026] 127.0.0.1:34120 Accepted +[Thu Jul 30 20:37:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 20:37:32 2026] 127.0.0.1:34120 [200]: GET /api/stats.php +[Thu Jul 30 20:37:32 2026] 127.0.0.1:34120 Closing +[Thu Jul 30 20:37:32 2026] 127.0.0.1:34124 Accepted +[Thu Jul 30 20:37:32 2026] 127.0.0.1:34124 [200]: GET /api/chart.php?range=year +[Thu Jul 30 20:37:32 2026] 127.0.0.1:34124 Closing +[Thu Jul 30 20:38:31 2026] 127.0.0.1:45286 Accepted +[Thu Jul 30 20:38:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 20:38:32 2026] 127.0.0.1:45286 [200]: GET /api/stats.php +[Thu Jul 30 20:38:32 2026] 127.0.0.1:45286 Closing +[Thu Jul 30 20:38:32 2026] 127.0.0.1:45292 Accepted +[Thu Jul 30 20:38:32 2026] 127.0.0.1:45292 [200]: GET /api/chart.php?range=year +[Thu Jul 30 20:38:32 2026] 127.0.0.1:45292 Closing +[Thu Jul 30 20:39:31 2026] 127.0.0.1:37502 Accepted +[Thu Jul 30 20:39:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 20:39:32 2026] 127.0.0.1:37502 [200]: GET /api/stats.php +[Thu Jul 30 20:39:32 2026] 127.0.0.1:37502 Closing +[Thu Jul 30 20:39:32 2026] 127.0.0.1:37508 Accepted +[Thu Jul 30 20:39:32 2026] 127.0.0.1:37508 [200]: GET /api/chart.php?range=year +[Thu Jul 30 20:39:32 2026] 127.0.0.1:37508 Closing +[Thu Jul 30 20:40:31 2026] 127.0.0.1:56470 Accepted +[Thu Jul 30 20:40:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 20:40:32 2026] 127.0.0.1:56470 [200]: GET /api/stats.php +[Thu Jul 30 20:40:32 2026] 127.0.0.1:56470 Closing +[Thu Jul 30 20:40:32 2026] 127.0.0.1:56476 Accepted +[Thu Jul 30 20:40:32 2026] 127.0.0.1:56476 [200]: GET /api/chart.php?range=year +[Thu Jul 30 20:40:32 2026] 127.0.0.1:56476 Closing +[Thu Jul 30 20:41:31 2026] 127.0.0.1:33616 Accepted +[Thu Jul 30 20:41:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 20:41:32 2026] 127.0.0.1:33616 [200]: GET /api/stats.php +[Thu Jul 30 20:41:32 2026] 127.0.0.1:33616 Closing +[Thu Jul 30 20:41:32 2026] 127.0.0.1:33628 Accepted +[Thu Jul 30 20:41:32 2026] 127.0.0.1:33628 [200]: GET /api/chart.php?range=year +[Thu Jul 30 20:41:32 2026] 127.0.0.1:33628 Closing +[Thu Jul 30 20:42:31 2026] 127.0.0.1:49856 Accepted +[Thu Jul 30 20:42:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 20:42:32 2026] 127.0.0.1:49856 [200]: GET /api/stats.php +[Thu Jul 30 20:42:32 2026] 127.0.0.1:49856 Closing +[Thu Jul 30 20:42:32 2026] 127.0.0.1:49858 Accepted +[Thu Jul 30 20:42:32 2026] 127.0.0.1:49858 [200]: GET /api/chart.php?range=year +[Thu Jul 30 20:42:32 2026] 127.0.0.1:49858 Closing +[Thu Jul 30 20:43:31 2026] 127.0.0.1:33348 Accepted +[Thu Jul 30 20:43:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 20:43:32 2026] 127.0.0.1:33348 [200]: GET /api/stats.php +[Thu Jul 30 20:43:32 2026] 127.0.0.1:33348 Closing +[Thu Jul 30 20:43:32 2026] 127.0.0.1:33358 Accepted +[Thu Jul 30 20:43:32 2026] 127.0.0.1:33358 [200]: GET /api/chart.php?range=year +[Thu Jul 30 20:43:32 2026] 127.0.0.1:33358 Closing +[Thu Jul 30 20:44:31 2026] 127.0.0.1:51672 Accepted +[Thu Jul 30 20:44:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 20:44:32 2026] 127.0.0.1:51672 [200]: GET /api/stats.php +[Thu Jul 30 20:44:32 2026] 127.0.0.1:51672 Closing +[Thu Jul 30 20:44:32 2026] 127.0.0.1:51688 Accepted +[Thu Jul 30 20:44:32 2026] 127.0.0.1:51688 [200]: GET /api/chart.php?range=year +[Thu Jul 30 20:44:32 2026] 127.0.0.1:51688 Closing +[Thu Jul 30 20:45:31 2026] 127.0.0.1:35120 Accepted +[Thu Jul 30 20:45:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 20:45:32 2026] 127.0.0.1:35120 [200]: GET /api/stats.php +[Thu Jul 30 20:45:32 2026] 127.0.0.1:35120 Closing +[Thu Jul 30 20:45:32 2026] 127.0.0.1:35136 Accepted +[Thu Jul 30 20:45:32 2026] 127.0.0.1:35136 [200]: GET /api/chart.php?range=year +[Thu Jul 30 20:45:32 2026] 127.0.0.1:35136 Closing +[Thu Jul 30 20:46:31 2026] 127.0.0.1:36312 Accepted +[Thu Jul 30 20:46:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 20:46:32 2026] 127.0.0.1:36312 [200]: GET /api/stats.php +[Thu Jul 30 20:46:32 2026] 127.0.0.1:36312 Closing +[Thu Jul 30 20:46:32 2026] 127.0.0.1:36328 Accepted +[Thu Jul 30 20:46:32 2026] 127.0.0.1:36328 [200]: GET /api/chart.php?range=year +[Thu Jul 30 20:46:32 2026] 127.0.0.1:36328 Closing +[Thu Jul 30 20:47:31 2026] 127.0.0.1:40120 Accepted +[Thu Jul 30 20:47:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 20:47:32 2026] 127.0.0.1:40120 [200]: GET /api/stats.php +[Thu Jul 30 20:47:32 2026] 127.0.0.1:40120 Closing +[Thu Jul 30 20:47:32 2026] 127.0.0.1:40122 Accepted +[Thu Jul 30 20:47:32 2026] 127.0.0.1:40122 [200]: GET /api/chart.php?range=year +[Thu Jul 30 20:47:32 2026] 127.0.0.1:40122 Closing +[Thu Jul 30 20:48:31 2026] 127.0.0.1:56808 Accepted +[Thu Jul 30 20:48:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 20:48:32 2026] 127.0.0.1:56808 [200]: GET /api/stats.php +[Thu Jul 30 20:48:32 2026] 127.0.0.1:56808 Closing +[Thu Jul 30 20:48:32 2026] 127.0.0.1:56812 Accepted +[Thu Jul 30 20:48:32 2026] 127.0.0.1:56812 [200]: GET /api/chart.php?range=year +[Thu Jul 30 20:48:32 2026] 127.0.0.1:56812 Closing +[Thu Jul 30 20:49:31 2026] 127.0.0.1:50466 Accepted +[Thu Jul 30 20:49:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 20:49:32 2026] 127.0.0.1:50466 [200]: GET /api/stats.php +[Thu Jul 30 20:49:32 2026] 127.0.0.1:50466 Closing +[Thu Jul 30 20:49:32 2026] 127.0.0.1:50480 Accepted +[Thu Jul 30 20:49:32 2026] 127.0.0.1:50480 [200]: GET /api/chart.php?range=year +[Thu Jul 30 20:49:32 2026] 127.0.0.1:50480 Closing +[Thu Jul 30 20:50:31 2026] 127.0.0.1:41718 Accepted +[Thu Jul 30 20:50:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 20:50:32 2026] 127.0.0.1:41718 [200]: GET /api/stats.php +[Thu Jul 30 20:50:32 2026] 127.0.0.1:41718 Closing +[Thu Jul 30 20:50:32 2026] 127.0.0.1:41724 Accepted +[Thu Jul 30 20:50:32 2026] 127.0.0.1:41724 [200]: GET /api/chart.php?range=year +[Thu Jul 30 20:50:32 2026] 127.0.0.1:41724 Closing +[Thu Jul 30 20:51:31 2026] 127.0.0.1:33964 Accepted +[Thu Jul 30 20:51:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 20:51:32 2026] 127.0.0.1:33964 [200]: GET /api/stats.php +[Thu Jul 30 20:51:32 2026] 127.0.0.1:33964 Closing +[Thu Jul 30 20:51:32 2026] 127.0.0.1:33972 Accepted +[Thu Jul 30 20:51:32 2026] 127.0.0.1:33972 [200]: GET /api/chart.php?range=year +[Thu Jul 30 20:51:32 2026] 127.0.0.1:33972 Closing +[Thu Jul 30 20:52:31 2026] 127.0.0.1:33552 Accepted +[Thu Jul 30 20:52:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 20:52:32 2026] 127.0.0.1:33552 [200]: GET /api/stats.php +[Thu Jul 30 20:52:32 2026] 127.0.0.1:33552 Closing +[Thu Jul 30 20:52:32 2026] 127.0.0.1:33564 Accepted +[Thu Jul 30 20:52:32 2026] 127.0.0.1:33564 [200]: GET /api/chart.php?range=year +[Thu Jul 30 20:52:32 2026] 127.0.0.1:33564 Closing +[Thu Jul 30 20:53:31 2026] 127.0.0.1:34184 Accepted +[Thu Jul 30 20:53:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 20:53:32 2026] 127.0.0.1:34184 [200]: GET /api/stats.php +[Thu Jul 30 20:53:32 2026] 127.0.0.1:34184 Closing +[Thu Jul 30 20:53:32 2026] 127.0.0.1:34200 Accepted +[Thu Jul 30 20:53:32 2026] 127.0.0.1:34200 [200]: GET /api/chart.php?range=year +[Thu Jul 30 20:53:32 2026] 127.0.0.1:34200 Closing +[Thu Jul 30 20:54:31 2026] 127.0.0.1:45188 Accepted +[Thu Jul 30 20:54:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 20:54:32 2026] 127.0.0.1:45188 [200]: GET /api/stats.php +[Thu Jul 30 20:54:32 2026] 127.0.0.1:45188 Closing +[Thu Jul 30 20:54:32 2026] 127.0.0.1:45198 Accepted +[Thu Jul 30 20:54:32 2026] 127.0.0.1:45198 [200]: GET /api/chart.php?range=year +[Thu Jul 30 20:54:32 2026] 127.0.0.1:45198 Closing +[Thu Jul 30 20:55:31 2026] 127.0.0.1:59456 Accepted +[Thu Jul 30 20:55:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 20:55:32 2026] 127.0.0.1:59456 [200]: GET /api/stats.php +[Thu Jul 30 20:55:32 2026] 127.0.0.1:59456 Closing +[Thu Jul 30 20:55:32 2026] 127.0.0.1:59460 Accepted +[Thu Jul 30 20:55:32 2026] 127.0.0.1:59460 [200]: GET /api/chart.php?range=year +[Thu Jul 30 20:55:32 2026] 127.0.0.1:59460 Closing +[Thu Jul 30 20:56:31 2026] 127.0.0.1:60958 Accepted +[Thu Jul 30 20:56:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 20:56:32 2026] 127.0.0.1:60958 [200]: GET /api/stats.php +[Thu Jul 30 20:56:32 2026] 127.0.0.1:60958 Closing +[Thu Jul 30 20:56:32 2026] 127.0.0.1:60972 Accepted +[Thu Jul 30 20:56:32 2026] 127.0.0.1:60972 [200]: GET /api/chart.php?range=year +[Thu Jul 30 20:56:32 2026] 127.0.0.1:60972 Closing +[Thu Jul 30 20:57:31 2026] 127.0.0.1:37822 Accepted +[Thu Jul 30 20:57:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 20:57:32 2026] 127.0.0.1:37822 [200]: GET /api/stats.php +[Thu Jul 30 20:57:32 2026] 127.0.0.1:37822 Closing +[Thu Jul 30 20:57:32 2026] 127.0.0.1:37828 Accepted +[Thu Jul 30 20:57:32 2026] 127.0.0.1:37828 [200]: GET /api/chart.php?range=year +[Thu Jul 30 20:57:32 2026] 127.0.0.1:37828 Closing +[Thu Jul 30 20:58:31 2026] 127.0.0.1:51612 Accepted +[Thu Jul 30 20:58:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 20:58:32 2026] 127.0.0.1:51612 [200]: GET /api/stats.php +[Thu Jul 30 20:58:32 2026] 127.0.0.1:51612 Closing +[Thu Jul 30 20:58:32 2026] 127.0.0.1:51616 Accepted +[Thu Jul 30 20:58:32 2026] 127.0.0.1:51616 [200]: GET /api/chart.php?range=year +[Thu Jul 30 20:58:32 2026] 127.0.0.1:51616 Closing +[Thu Jul 30 20:59:31 2026] 127.0.0.1:41172 Accepted +[Thu Jul 30 20:59:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 20:59:32 2026] 127.0.0.1:41172 [200]: GET /api/stats.php +[Thu Jul 30 20:59:32 2026] 127.0.0.1:41172 Closing +[Thu Jul 30 20:59:32 2026] 127.0.0.1:41184 Accepted +[Thu Jul 30 20:59:32 2026] 127.0.0.1:41184 [200]: GET /api/chart.php?range=year +[Thu Jul 30 20:59:32 2026] 127.0.0.1:41184 Closing +[Thu Jul 30 21:00:31 2026] 127.0.0.1:47162 Accepted +[Thu Jul 30 21:00:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 21:00:32 2026] 127.0.0.1:47162 [200]: GET /api/stats.php +[Thu Jul 30 21:00:32 2026] 127.0.0.1:47162 Closing +[Thu Jul 30 21:00:32 2026] 127.0.0.1:47164 Accepted +[Thu Jul 30 21:00:32 2026] 127.0.0.1:47164 [200]: GET /api/chart.php?range=year +[Thu Jul 30 21:00:32 2026] 127.0.0.1:47164 Closing +[Thu Jul 30 21:01:31 2026] 127.0.0.1:40572 Accepted +[Thu Jul 30 21:01:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 21:01:32 2026] 127.0.0.1:40572 [200]: GET /api/stats.php +[Thu Jul 30 21:01:32 2026] 127.0.0.1:40572 Closing +[Thu Jul 30 21:01:32 2026] 127.0.0.1:40588 Accepted +[Thu Jul 30 21:01:32 2026] 127.0.0.1:40588 [200]: GET /api/chart.php?range=year +[Thu Jul 30 21:01:32 2026] 127.0.0.1:40588 Closing +[Thu Jul 30 21:02:31 2026] 127.0.0.1:49644 Accepted +[Thu Jul 30 21:02:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 21:02:32 2026] 127.0.0.1:49644 [200]: GET /api/stats.php +[Thu Jul 30 21:02:32 2026] 127.0.0.1:49644 Closing +[Thu Jul 30 21:02:32 2026] 127.0.0.1:49650 Accepted +[Thu Jul 30 21:02:32 2026] 127.0.0.1:49650 [200]: GET /api/chart.php?range=year +[Thu Jul 30 21:02:32 2026] 127.0.0.1:49650 Closing +[Thu Jul 30 21:03:31 2026] 127.0.0.1:56128 Accepted +[Thu Jul 30 21:03:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 21:03:32 2026] 127.0.0.1:56128 [200]: GET /api/stats.php +[Thu Jul 30 21:03:32 2026] 127.0.0.1:56128 Closing +[Thu Jul 30 21:03:32 2026] 127.0.0.1:56142 Accepted +[Thu Jul 30 21:03:32 2026] 127.0.0.1:56142 [200]: GET /api/chart.php?range=year +[Thu Jul 30 21:03:32 2026] 127.0.0.1:56142 Closing +[Thu Jul 30 21:04:31 2026] 127.0.0.1:35632 Accepted +[Thu Jul 30 21:04:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 21:04:32 2026] 127.0.0.1:35632 [200]: GET /api/stats.php +[Thu Jul 30 21:04:32 2026] 127.0.0.1:35632 Closing +[Thu Jul 30 21:04:32 2026] 127.0.0.1:35648 Accepted +[Thu Jul 30 21:04:32 2026] 127.0.0.1:35648 [200]: GET /api/chart.php?range=year +[Thu Jul 30 21:04:32 2026] 127.0.0.1:35648 Closing +[Thu Jul 30 21:05:31 2026] 127.0.0.1:42278 Accepted +[Thu Jul 30 21:05:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 21:05:32 2026] 127.0.0.1:42278 [200]: GET /api/stats.php +[Thu Jul 30 21:05:32 2026] 127.0.0.1:42278 Closing +[Thu Jul 30 21:05:32 2026] 127.0.0.1:42292 Accepted +[Thu Jul 30 21:05:32 2026] 127.0.0.1:42292 [200]: GET /api/chart.php?range=year +[Thu Jul 30 21:05:32 2026] 127.0.0.1:42292 Closing +[Thu Jul 30 21:06:31 2026] 127.0.0.1:45540 Accepted +[Thu Jul 30 21:06:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 21:06:32 2026] 127.0.0.1:45540 [200]: GET /api/stats.php +[Thu Jul 30 21:06:32 2026] 127.0.0.1:45540 Closing +[Thu Jul 30 21:06:32 2026] 127.0.0.1:45544 Accepted +[Thu Jul 30 21:06:32 2026] 127.0.0.1:45544 [200]: GET /api/chart.php?range=year +[Thu Jul 30 21:06:32 2026] 127.0.0.1:45544 Closing +[Thu Jul 30 21:07:31 2026] 127.0.0.1:59658 Accepted +[Thu Jul 30 21:07:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 21:07:32 2026] 127.0.0.1:59658 [200]: GET /api/stats.php +[Thu Jul 30 21:07:32 2026] 127.0.0.1:59658 Closing +[Thu Jul 30 21:07:32 2026] 127.0.0.1:59664 Accepted +[Thu Jul 30 21:07:32 2026] 127.0.0.1:59664 [200]: GET /api/chart.php?range=year +[Thu Jul 30 21:07:32 2026] 127.0.0.1:59664 Closing +[Thu Jul 30 21:08:31 2026] 127.0.0.1:40722 Accepted +[Thu Jul 30 21:08:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 21:08:32 2026] 127.0.0.1:40722 [200]: GET /api/stats.php +[Thu Jul 30 21:08:32 2026] 127.0.0.1:40722 Closing +[Thu Jul 30 21:08:32 2026] 127.0.0.1:40738 Accepted +[Thu Jul 30 21:08:32 2026] 127.0.0.1:40738 [200]: GET /api/chart.php?range=year +[Thu Jul 30 21:08:32 2026] 127.0.0.1:40738 Closing +[Thu Jul 30 21:09:31 2026] 127.0.0.1:44734 Accepted +[Thu Jul 30 21:09:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 21:09:32 2026] 127.0.0.1:44734 [200]: GET /api/stats.php +[Thu Jul 30 21:09:32 2026] 127.0.0.1:44734 Closing +[Thu Jul 30 21:09:32 2026] 127.0.0.1:44744 Accepted +[Thu Jul 30 21:09:32 2026] 127.0.0.1:44744 [200]: GET /api/chart.php?range=year +[Thu Jul 30 21:09:32 2026] 127.0.0.1:44744 Closing +[Thu Jul 30 21:10:31 2026] 127.0.0.1:52080 Accepted +[Thu Jul 30 21:10:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 21:10:32 2026] 127.0.0.1:52080 [200]: GET /api/stats.php +[Thu Jul 30 21:10:32 2026] 127.0.0.1:52080 Closing +[Thu Jul 30 21:10:32 2026] 127.0.0.1:52088 Accepted +[Thu Jul 30 21:10:32 2026] 127.0.0.1:52088 [200]: GET /api/chart.php?range=year +[Thu Jul 30 21:10:32 2026] 127.0.0.1:52088 Closing +[Thu Jul 30 21:11:31 2026] 127.0.0.1:55278 Accepted +[Thu Jul 30 21:11:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 21:11:32 2026] 127.0.0.1:55278 [200]: GET /api/stats.php +[Thu Jul 30 21:11:32 2026] 127.0.0.1:55278 Closing +[Thu Jul 30 21:11:32 2026] 127.0.0.1:55282 Accepted +[Thu Jul 30 21:11:32 2026] 127.0.0.1:55282 [200]: GET /api/chart.php?range=year +[Thu Jul 30 21:11:32 2026] 127.0.0.1:55282 Closing +[Thu Jul 30 21:12:31 2026] 127.0.0.1:44140 Accepted +[Thu Jul 30 21:12:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 21:12:32 2026] 127.0.0.1:44140 [200]: GET /api/stats.php +[Thu Jul 30 21:12:32 2026] 127.0.0.1:44140 Closing +[Thu Jul 30 21:12:32 2026] 127.0.0.1:44150 Accepted +[Thu Jul 30 21:12:32 2026] 127.0.0.1:44150 [200]: GET /api/chart.php?range=year +[Thu Jul 30 21:12:32 2026] 127.0.0.1:44150 Closing +[Thu Jul 30 21:13:31 2026] 127.0.0.1:54238 Accepted +[Thu Jul 30 21:13:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 21:13:32 2026] 127.0.0.1:54238 [200]: GET /api/stats.php +[Thu Jul 30 21:13:32 2026] 127.0.0.1:54238 Closing +[Thu Jul 30 21:13:32 2026] 127.0.0.1:54250 Accepted +[Thu Jul 30 21:13:32 2026] 127.0.0.1:54250 [200]: GET /api/chart.php?range=year +[Thu Jul 30 21:13:32 2026] 127.0.0.1:54250 Closing +[Thu Jul 30 21:14:31 2026] 127.0.0.1:53708 Accepted +[Thu Jul 30 21:14:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 21:14:32 2026] 127.0.0.1:53708 [200]: GET /api/stats.php +[Thu Jul 30 21:14:32 2026] 127.0.0.1:53708 Closing +[Thu Jul 30 21:14:32 2026] 127.0.0.1:53722 Accepted +[Thu Jul 30 21:14:32 2026] 127.0.0.1:53722 [200]: GET /api/chart.php?range=year +[Thu Jul 30 21:14:32 2026] 127.0.0.1:53722 Closing +[Thu Jul 30 21:15:31 2026] 127.0.0.1:46162 Accepted +[Thu Jul 30 21:15:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 21:15:32 2026] 127.0.0.1:46162 [200]: GET /api/stats.php +[Thu Jul 30 21:15:32 2026] 127.0.0.1:46162 Closing +[Thu Jul 30 21:15:32 2026] 127.0.0.1:46164 Accepted +[Thu Jul 30 21:15:32 2026] 127.0.0.1:46164 [200]: GET /api/chart.php?range=year +[Thu Jul 30 21:15:32 2026] 127.0.0.1:46164 Closing +[Thu Jul 30 21:16:31 2026] 127.0.0.1:47842 Accepted +[Thu Jul 30 21:16:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 21:16:32 2026] 127.0.0.1:47842 [200]: GET /api/stats.php +[Thu Jul 30 21:16:32 2026] 127.0.0.1:47842 Closing +[Thu Jul 30 21:16:32 2026] 127.0.0.1:47852 Accepted +[Thu Jul 30 21:16:32 2026] 127.0.0.1:47852 [200]: GET /api/chart.php?range=year +[Thu Jul 30 21:16:32 2026] 127.0.0.1:47852 Closing +[Thu Jul 30 21:17:31 2026] 127.0.0.1:53534 Accepted +[Thu Jul 30 21:17:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 21:17:32 2026] 127.0.0.1:53534 [200]: GET /api/stats.php +[Thu Jul 30 21:17:32 2026] 127.0.0.1:53534 Closing +[Thu Jul 30 21:17:32 2026] 127.0.0.1:53536 Accepted +[Thu Jul 30 21:17:32 2026] 127.0.0.1:53536 [200]: GET /api/chart.php?range=year +[Thu Jul 30 21:17:32 2026] 127.0.0.1:53536 Closing +[Thu Jul 30 21:18:31 2026] 127.0.0.1:41468 Accepted +[Thu Jul 30 21:18:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 21:18:32 2026] 127.0.0.1:41468 [200]: GET /api/stats.php +[Thu Jul 30 21:18:32 2026] 127.0.0.1:41468 Closing +[Thu Jul 30 21:18:32 2026] 127.0.0.1:41470 Accepted +[Thu Jul 30 21:18:32 2026] 127.0.0.1:41470 [200]: GET /api/chart.php?range=year +[Thu Jul 30 21:18:32 2026] 127.0.0.1:41470 Closing +[Thu Jul 30 21:19:31 2026] 127.0.0.1:58556 Accepted +[Thu Jul 30 21:19:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 21:19:32 2026] 127.0.0.1:58556 [200]: GET /api/stats.php +[Thu Jul 30 21:19:32 2026] 127.0.0.1:58556 Closing +[Thu Jul 30 21:19:32 2026] 127.0.0.1:58558 Accepted +[Thu Jul 30 21:19:32 2026] 127.0.0.1:58558 [200]: GET /api/chart.php?range=year +[Thu Jul 30 21:19:32 2026] 127.0.0.1:58558 Closing +[Thu Jul 30 21:20:31 2026] 127.0.0.1:40350 Accepted +[Thu Jul 30 21:20:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 21:20:32 2026] 127.0.0.1:40350 [200]: GET /api/stats.php +[Thu Jul 30 21:20:32 2026] 127.0.0.1:40350 Closing +[Thu Jul 30 21:20:32 2026] 127.0.0.1:40352 Accepted +[Thu Jul 30 21:20:32 2026] 127.0.0.1:40352 [200]: GET /api/chart.php?range=year +[Thu Jul 30 21:20:32 2026] 127.0.0.1:40352 Closing +[Thu Jul 30 21:21:31 2026] 127.0.0.1:41304 Accepted +[Thu Jul 30 21:21:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 21:21:32 2026] 127.0.0.1:41304 [200]: GET /api/stats.php +[Thu Jul 30 21:21:32 2026] 127.0.0.1:41304 Closing +[Thu Jul 30 21:21:32 2026] 127.0.0.1:41310 Accepted +[Thu Jul 30 21:21:32 2026] 127.0.0.1:41310 [200]: GET /api/chart.php?range=year +[Thu Jul 30 21:21:32 2026] 127.0.0.1:41310 Closing +[Thu Jul 30 21:22:31 2026] 127.0.0.1:58506 Accepted +[Thu Jul 30 21:22:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 21:22:32 2026] 127.0.0.1:58506 [200]: GET /api/stats.php +[Thu Jul 30 21:22:32 2026] 127.0.0.1:58506 Closing +[Thu Jul 30 21:22:32 2026] 127.0.0.1:58514 Accepted +[Thu Jul 30 21:22:32 2026] 127.0.0.1:58514 [200]: GET /api/chart.php?range=year +[Thu Jul 30 21:22:32 2026] 127.0.0.1:58514 Closing +[Thu Jul 30 21:23:31 2026] 127.0.0.1:40166 Accepted +[Thu Jul 30 21:23:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 21:23:32 2026] 127.0.0.1:40166 [200]: GET /api/stats.php +[Thu Jul 30 21:23:32 2026] 127.0.0.1:40166 Closing +[Thu Jul 30 21:23:32 2026] 127.0.0.1:40176 Accepted +[Thu Jul 30 21:23:32 2026] 127.0.0.1:40176 [200]: GET /api/chart.php?range=year +[Thu Jul 30 21:23:32 2026] 127.0.0.1:40176 Closing +[Thu Jul 30 21:24:31 2026] 127.0.0.1:46796 Accepted +[Thu Jul 30 21:24:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 21:24:32 2026] 127.0.0.1:46796 [200]: GET /api/stats.php +[Thu Jul 30 21:24:32 2026] 127.0.0.1:46796 Closing +[Thu Jul 30 21:24:32 2026] 127.0.0.1:46804 Accepted +[Thu Jul 30 21:24:32 2026] 127.0.0.1:46804 [200]: GET /api/chart.php?range=year +[Thu Jul 30 21:24:32 2026] 127.0.0.1:46804 Closing +[Thu Jul 30 21:25:31 2026] 127.0.0.1:40880 Accepted +[Thu Jul 30 21:25:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 21:25:32 2026] 127.0.0.1:40880 [200]: GET /api/stats.php +[Thu Jul 30 21:25:32 2026] 127.0.0.1:40880 Closing +[Thu Jul 30 21:25:32 2026] 127.0.0.1:40888 Accepted +[Thu Jul 30 21:25:32 2026] 127.0.0.1:40888 [200]: GET /api/chart.php?range=year +[Thu Jul 30 21:25:32 2026] 127.0.0.1:40888 Closing +[Thu Jul 30 21:26:31 2026] 127.0.0.1:44550 Accepted +[Thu Jul 30 21:26:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 21:26:32 2026] 127.0.0.1:44550 [200]: GET /api/stats.php +[Thu Jul 30 21:26:32 2026] 127.0.0.1:44550 Closing +[Thu Jul 30 21:26:32 2026] 127.0.0.1:44566 Accepted +[Thu Jul 30 21:26:32 2026] 127.0.0.1:44566 [200]: GET /api/chart.php?range=year +[Thu Jul 30 21:26:32 2026] 127.0.0.1:44566 Closing +[Thu Jul 30 21:27:31 2026] 127.0.0.1:46964 Accepted +[Thu Jul 30 21:27:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 21:27:32 2026] 127.0.0.1:46964 [200]: GET /api/stats.php +[Thu Jul 30 21:27:32 2026] 127.0.0.1:46964 Closing +[Thu Jul 30 21:27:32 2026] 127.0.0.1:46976 Accepted +[Thu Jul 30 21:27:32 2026] 127.0.0.1:46976 [200]: GET /api/chart.php?range=year +[Thu Jul 30 21:27:32 2026] 127.0.0.1:46976 Closing +[Thu Jul 30 21:28:31 2026] 127.0.0.1:52032 Accepted +[Thu Jul 30 21:28:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 21:28:32 2026] 127.0.0.1:52032 [200]: GET /api/stats.php +[Thu Jul 30 21:28:32 2026] 127.0.0.1:52032 Closing +[Thu Jul 30 21:28:32 2026] 127.0.0.1:52040 Accepted +[Thu Jul 30 21:28:32 2026] 127.0.0.1:52040 [200]: GET /api/chart.php?range=year +[Thu Jul 30 21:28:32 2026] 127.0.0.1:52040 Closing +[Thu Jul 30 21:29:31 2026] 127.0.0.1:46192 Accepted +[Thu Jul 30 21:29:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 21:29:32 2026] 127.0.0.1:46192 [200]: GET /api/stats.php +[Thu Jul 30 21:29:32 2026] 127.0.0.1:46192 Closing +[Thu Jul 30 21:29:32 2026] 127.0.0.1:46198 Accepted +[Thu Jul 30 21:29:32 2026] 127.0.0.1:46198 [200]: GET /api/chart.php?range=year +[Thu Jul 30 21:29:32 2026] 127.0.0.1:46198 Closing +[Thu Jul 30 21:30:31 2026] 127.0.0.1:40950 Accepted +[Thu Jul 30 21:30:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 21:30:32 2026] 127.0.0.1:40950 [200]: GET /api/stats.php +[Thu Jul 30 21:30:32 2026] 127.0.0.1:40950 Closing +[Thu Jul 30 21:30:32 2026] 127.0.0.1:40962 Accepted +[Thu Jul 30 21:30:32 2026] 127.0.0.1:40962 [200]: GET /api/chart.php?range=year +[Thu Jul 30 21:30:32 2026] 127.0.0.1:40962 Closing +[Thu Jul 30 21:31:31 2026] 127.0.0.1:55768 Accepted +[Thu Jul 30 21:31:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 21:31:32 2026] 127.0.0.1:55768 [200]: GET /api/stats.php +[Thu Jul 30 21:31:32 2026] 127.0.0.1:55768 Closing +[Thu Jul 30 21:31:32 2026] 127.0.0.1:55778 Accepted +[Thu Jul 30 21:31:32 2026] 127.0.0.1:55778 [200]: GET /api/chart.php?range=year +[Thu Jul 30 21:31:32 2026] 127.0.0.1:55778 Closing +[Thu Jul 30 21:32:31 2026] 127.0.0.1:33226 Accepted +[Thu Jul 30 21:32:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 21:32:32 2026] 127.0.0.1:33226 [200]: GET /api/stats.php +[Thu Jul 30 21:32:32 2026] 127.0.0.1:33226 Closing +[Thu Jul 30 21:32:32 2026] 127.0.0.1:33228 Accepted +[Thu Jul 30 21:32:32 2026] 127.0.0.1:33228 [200]: GET /api/chart.php?range=year +[Thu Jul 30 21:32:32 2026] 127.0.0.1:33228 Closing +[Thu Jul 30 21:33:31 2026] 127.0.0.1:35320 Accepted +[Thu Jul 30 21:33:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 21:33:32 2026] 127.0.0.1:35320 [200]: GET /api/stats.php +[Thu Jul 30 21:33:32 2026] 127.0.0.1:35320 Closing +[Thu Jul 30 21:33:32 2026] 127.0.0.1:35328 Accepted +[Thu Jul 30 21:33:32 2026] 127.0.0.1:35328 [200]: GET /api/chart.php?range=year +[Thu Jul 30 21:33:32 2026] 127.0.0.1:35328 Closing +[Thu Jul 30 21:34:31 2026] 127.0.0.1:60018 Accepted +[Thu Jul 30 21:34:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 21:34:32 2026] 127.0.0.1:60018 [200]: GET /api/stats.php +[Thu Jul 30 21:34:32 2026] 127.0.0.1:60018 Closing +[Thu Jul 30 21:34:32 2026] 127.0.0.1:60026 Accepted +[Thu Jul 30 21:34:32 2026] 127.0.0.1:60026 [200]: GET /api/chart.php?range=year +[Thu Jul 30 21:34:32 2026] 127.0.0.1:60026 Closing +[Thu Jul 30 21:35:31 2026] 127.0.0.1:43094 Accepted +[Thu Jul 30 21:35:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 21:35:32 2026] 127.0.0.1:43094 [200]: GET /api/stats.php +[Thu Jul 30 21:35:32 2026] 127.0.0.1:43094 Closing +[Thu Jul 30 21:35:32 2026] 127.0.0.1:43106 Accepted +[Thu Jul 30 21:35:32 2026] 127.0.0.1:43106 [200]: GET /api/chart.php?range=year +[Thu Jul 30 21:35:32 2026] 127.0.0.1:43106 Closing +[Thu Jul 30 21:36:31 2026] 127.0.0.1:60348 Accepted +[Thu Jul 30 21:36:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 21:36:32 2026] 127.0.0.1:60348 [200]: GET /api/stats.php +[Thu Jul 30 21:36:32 2026] 127.0.0.1:60348 Closing +[Thu Jul 30 21:36:32 2026] 127.0.0.1:60352 Accepted +[Thu Jul 30 21:36:32 2026] 127.0.0.1:60352 [200]: GET /api/chart.php?range=year +[Thu Jul 30 21:36:32 2026] 127.0.0.1:60352 Closing +[Thu Jul 30 21:37:31 2026] 127.0.0.1:54610 Accepted +[Thu Jul 30 21:37:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 21:37:32 2026] 127.0.0.1:54610 [200]: GET /api/stats.php +[Thu Jul 30 21:37:32 2026] 127.0.0.1:54610 Closing +[Thu Jul 30 21:37:32 2026] 127.0.0.1:54612 Accepted +[Thu Jul 30 21:37:32 2026] 127.0.0.1:54612 [200]: GET /api/chart.php?range=year +[Thu Jul 30 21:37:32 2026] 127.0.0.1:54612 Closing +[Thu Jul 30 21:38:31 2026] 127.0.0.1:44304 Accepted +[Thu Jul 30 21:38:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 21:38:32 2026] 127.0.0.1:44304 [200]: GET /api/stats.php +[Thu Jul 30 21:38:32 2026] 127.0.0.1:44304 Closing +[Thu Jul 30 21:38:32 2026] 127.0.0.1:44310 Accepted +[Thu Jul 30 21:38:32 2026] 127.0.0.1:44310 [200]: GET /api/chart.php?range=year +[Thu Jul 30 21:38:32 2026] 127.0.0.1:44310 Closing +[Thu Jul 30 21:39:31 2026] 127.0.0.1:59242 Accepted +[Thu Jul 30 21:39:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 21:39:32 2026] 127.0.0.1:59242 [200]: GET /api/stats.php +[Thu Jul 30 21:39:32 2026] 127.0.0.1:59242 Closing +[Thu Jul 30 21:39:32 2026] 127.0.0.1:59248 Accepted +[Thu Jul 30 21:39:32 2026] 127.0.0.1:59248 [200]: GET /api/chart.php?range=year +[Thu Jul 30 21:39:32 2026] 127.0.0.1:59248 Closing +[Thu Jul 30 21:40:31 2026] 127.0.0.1:33754 Accepted +[Thu Jul 30 21:40:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 21:40:32 2026] 127.0.0.1:33754 [200]: GET /api/stats.php +[Thu Jul 30 21:40:32 2026] 127.0.0.1:33754 Closing +[Thu Jul 30 21:40:32 2026] 127.0.0.1:33758 Accepted +[Thu Jul 30 21:40:32 2026] 127.0.0.1:33758 [200]: GET /api/chart.php?range=year +[Thu Jul 30 21:40:32 2026] 127.0.0.1:33758 Closing +[Thu Jul 30 21:41:31 2026] 127.0.0.1:34706 Accepted +[Thu Jul 30 21:41:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 21:41:32 2026] 127.0.0.1:34706 [200]: GET /api/stats.php +[Thu Jul 30 21:41:32 2026] 127.0.0.1:34706 Closing +[Thu Jul 30 21:41:32 2026] 127.0.0.1:34708 Accepted +[Thu Jul 30 21:41:32 2026] 127.0.0.1:34708 [200]: GET /api/chart.php?range=year +[Thu Jul 30 21:41:32 2026] 127.0.0.1:34708 Closing +[Thu Jul 30 21:42:31 2026] 127.0.0.1:35222 Accepted +[Thu Jul 30 21:42:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 21:42:32 2026] 127.0.0.1:35222 [200]: GET /api/stats.php +[Thu Jul 30 21:42:32 2026] 127.0.0.1:35222 Closing +[Thu Jul 30 21:42:32 2026] 127.0.0.1:35228 Accepted +[Thu Jul 30 21:42:32 2026] 127.0.0.1:35228 [200]: GET /api/chart.php?range=year +[Thu Jul 30 21:42:32 2026] 127.0.0.1:35228 Closing +[Thu Jul 30 21:43:31 2026] 127.0.0.1:43174 Accepted +[Thu Jul 30 21:43:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 21:43:32 2026] 127.0.0.1:43174 [200]: GET /api/stats.php +[Thu Jul 30 21:43:32 2026] 127.0.0.1:43174 Closing +[Thu Jul 30 21:43:32 2026] 127.0.0.1:43178 Accepted +[Thu Jul 30 21:43:32 2026] 127.0.0.1:43178 [200]: GET /api/chart.php?range=year +[Thu Jul 30 21:43:32 2026] 127.0.0.1:43178 Closing +[Thu Jul 30 21:44:31 2026] 127.0.0.1:59450 Accepted +[Thu Jul 30 21:44:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 21:44:32 2026] 127.0.0.1:59450 [200]: GET /api/stats.php +[Thu Jul 30 21:44:32 2026] 127.0.0.1:59450 Closing +[Thu Jul 30 21:44:32 2026] 127.0.0.1:59458 Accepted +[Thu Jul 30 21:44:32 2026] 127.0.0.1:59458 [200]: GET /api/chart.php?range=year +[Thu Jul 30 21:44:32 2026] 127.0.0.1:59458 Closing +[Thu Jul 30 21:45:31 2026] 127.0.0.1:44480 Accepted +[Thu Jul 30 21:45:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 21:45:32 2026] 127.0.0.1:44480 [200]: GET /api/stats.php +[Thu Jul 30 21:45:32 2026] 127.0.0.1:44480 Closing +[Thu Jul 30 21:45:32 2026] 127.0.0.1:44484 Accepted +[Thu Jul 30 21:45:32 2026] 127.0.0.1:44484 [200]: GET /api/chart.php?range=year +[Thu Jul 30 21:45:32 2026] 127.0.0.1:44484 Closing +[Thu Jul 30 21:46:31 2026] 127.0.0.1:60572 Accepted +[Thu Jul 30 21:46:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 21:46:32 2026] 127.0.0.1:60572 [200]: GET /api/stats.php +[Thu Jul 30 21:46:32 2026] 127.0.0.1:60572 Closing +[Thu Jul 30 21:46:32 2026] 127.0.0.1:60584 Accepted +[Thu Jul 30 21:46:32 2026] 127.0.0.1:60584 [200]: GET /api/chart.php?range=year +[Thu Jul 30 21:46:32 2026] 127.0.0.1:60584 Closing +[Thu Jul 30 21:47:31 2026] 127.0.0.1:48916 Accepted +[Thu Jul 30 21:47:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 21:47:32 2026] 127.0.0.1:48916 [200]: GET /api/stats.php +[Thu Jul 30 21:47:32 2026] 127.0.0.1:48916 Closing +[Thu Jul 30 21:47:32 2026] 127.0.0.1:48932 Accepted +[Thu Jul 30 21:47:32 2026] 127.0.0.1:48932 [200]: GET /api/chart.php?range=year +[Thu Jul 30 21:47:32 2026] 127.0.0.1:48932 Closing +[Thu Jul 30 21:48:31 2026] 127.0.0.1:35704 Accepted +[Thu Jul 30 21:48:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 21:48:32 2026] 127.0.0.1:35704 [200]: GET /api/stats.php +[Thu Jul 30 21:48:32 2026] 127.0.0.1:35704 Closing +[Thu Jul 30 21:48:32 2026] 127.0.0.1:35706 Accepted +[Thu Jul 30 21:48:32 2026] 127.0.0.1:35706 [200]: GET /api/chart.php?range=year +[Thu Jul 30 21:48:32 2026] 127.0.0.1:35706 Closing +[Thu Jul 30 21:49:31 2026] 127.0.0.1:60172 Accepted +[Thu Jul 30 21:49:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 21:49:32 2026] 127.0.0.1:60172 [200]: GET /api/stats.php +[Thu Jul 30 21:49:32 2026] 127.0.0.1:60172 Closing +[Thu Jul 30 21:49:32 2026] 127.0.0.1:60186 Accepted +[Thu Jul 30 21:49:32 2026] 127.0.0.1:60186 [200]: GET /api/chart.php?range=year +[Thu Jul 30 21:49:32 2026] 127.0.0.1:60186 Closing +[Thu Jul 30 21:50:31 2026] 127.0.0.1:37590 Accepted +[Thu Jul 30 21:50:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 21:50:32 2026] 127.0.0.1:37590 [200]: GET /api/stats.php +[Thu Jul 30 21:50:32 2026] 127.0.0.1:37590 Closing +[Thu Jul 30 21:50:32 2026] 127.0.0.1:37596 Accepted +[Thu Jul 30 21:50:32 2026] 127.0.0.1:37596 [200]: GET /api/chart.php?range=year +[Thu Jul 30 21:50:32 2026] 127.0.0.1:37596 Closing +[Thu Jul 30 21:51:31 2026] 127.0.0.1:47580 Accepted +[Thu Jul 30 21:51:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 21:51:32 2026] 127.0.0.1:47580 [200]: GET /api/stats.php +[Thu Jul 30 21:51:32 2026] 127.0.0.1:47580 Closing +[Thu Jul 30 21:51:32 2026] 127.0.0.1:47592 Accepted +[Thu Jul 30 21:51:32 2026] 127.0.0.1:47592 [200]: GET /api/chart.php?range=year +[Thu Jul 30 21:51:32 2026] 127.0.0.1:47592 Closing +[Thu Jul 30 21:52:31 2026] 127.0.0.1:51126 Accepted +[Thu Jul 30 21:52:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 21:52:32 2026] 127.0.0.1:51126 [200]: GET /api/stats.php +[Thu Jul 30 21:52:32 2026] 127.0.0.1:51126 Closing +[Thu Jul 30 21:52:32 2026] 127.0.0.1:51134 Accepted +[Thu Jul 30 21:52:32 2026] 127.0.0.1:51134 [200]: GET /api/chart.php?range=year +[Thu Jul 30 21:52:32 2026] 127.0.0.1:51134 Closing +[Thu Jul 30 21:53:31 2026] 127.0.0.1:37338 Accepted +[Thu Jul 30 21:53:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 21:53:32 2026] 127.0.0.1:37338 [200]: GET /api/stats.php +[Thu Jul 30 21:53:32 2026] 127.0.0.1:37338 Closing +[Thu Jul 30 21:53:32 2026] 127.0.0.1:37352 Accepted +[Thu Jul 30 21:53:32 2026] 127.0.0.1:37352 [200]: GET /api/chart.php?range=year +[Thu Jul 30 21:53:32 2026] 127.0.0.1:37352 Closing +[Thu Jul 30 21:54:31 2026] 127.0.0.1:56298 Accepted +[Thu Jul 30 21:54:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 21:54:32 2026] 127.0.0.1:56298 [200]: GET /api/stats.php +[Thu Jul 30 21:54:32 2026] 127.0.0.1:56298 Closing +[Thu Jul 30 21:54:32 2026] 127.0.0.1:56310 Accepted +[Thu Jul 30 21:54:32 2026] 127.0.0.1:56310 [200]: GET /api/chart.php?range=year +[Thu Jul 30 21:54:32 2026] 127.0.0.1:56310 Closing +[Thu Jul 30 21:55:31 2026] 127.0.0.1:49730 Accepted +[Thu Jul 30 21:55:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 21:55:32 2026] 127.0.0.1:49730 [200]: GET /api/stats.php +[Thu Jul 30 21:55:32 2026] 127.0.0.1:49730 Closing +[Thu Jul 30 21:55:32 2026] 127.0.0.1:49738 Accepted +[Thu Jul 30 21:55:32 2026] 127.0.0.1:49738 [200]: GET /api/chart.php?range=year +[Thu Jul 30 21:55:32 2026] 127.0.0.1:49738 Closing +[Thu Jul 30 21:56:31 2026] 127.0.0.1:58420 Accepted +[Thu Jul 30 21:56:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 21:56:32 2026] 127.0.0.1:58420 [200]: GET /api/stats.php +[Thu Jul 30 21:56:32 2026] 127.0.0.1:58420 Closing +[Thu Jul 30 21:56:32 2026] 127.0.0.1:58428 Accepted +[Thu Jul 30 21:56:32 2026] 127.0.0.1:58428 [200]: GET /api/chart.php?range=year +[Thu Jul 30 21:56:32 2026] 127.0.0.1:58428 Closing +[Thu Jul 30 21:57:31 2026] 127.0.0.1:38284 Accepted +[Thu Jul 30 21:57:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 21:57:32 2026] 127.0.0.1:38284 [200]: GET /api/stats.php +[Thu Jul 30 21:57:32 2026] 127.0.0.1:38284 Closing +[Thu Jul 30 21:57:32 2026] 127.0.0.1:38298 Accepted +[Thu Jul 30 21:57:32 2026] 127.0.0.1:38298 [200]: GET /api/chart.php?range=year +[Thu Jul 30 21:57:32 2026] 127.0.0.1:38298 Closing +[Thu Jul 30 21:58:31 2026] 127.0.0.1:52182 Accepted +[Thu Jul 30 21:58:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 21:58:32 2026] 127.0.0.1:52182 [200]: GET /api/stats.php +[Thu Jul 30 21:58:32 2026] 127.0.0.1:52182 Closing +[Thu Jul 30 21:58:32 2026] 127.0.0.1:52184 Accepted +[Thu Jul 30 21:58:32 2026] 127.0.0.1:52184 [200]: GET /api/chart.php?range=year +[Thu Jul 30 21:58:32 2026] 127.0.0.1:52184 Closing +[Thu Jul 30 21:59:31 2026] 127.0.0.1:55432 Accepted +[Thu Jul 30 21:59:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 21:59:32 2026] 127.0.0.1:55432 [200]: GET /api/stats.php +[Thu Jul 30 21:59:32 2026] 127.0.0.1:55432 Closing +[Thu Jul 30 21:59:32 2026] 127.0.0.1:55440 Accepted +[Thu Jul 30 21:59:32 2026] 127.0.0.1:55440 [200]: GET /api/chart.php?range=year +[Thu Jul 30 21:59:32 2026] 127.0.0.1:55440 Closing +[Thu Jul 30 22:00:31 2026] 127.0.0.1:60158 Accepted +[Thu Jul 30 22:00:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 22:00:32 2026] 127.0.0.1:60158 [200]: GET /api/stats.php +[Thu Jul 30 22:00:32 2026] 127.0.0.1:60158 Closing +[Thu Jul 30 22:00:32 2026] 127.0.0.1:60160 Accepted +[Thu Jul 30 22:00:32 2026] 127.0.0.1:60160 [200]: GET /api/chart.php?range=year +[Thu Jul 30 22:00:32 2026] 127.0.0.1:60160 Closing +[Thu Jul 30 22:01:31 2026] 127.0.0.1:54052 Accepted +[Thu Jul 30 22:01:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 22:01:32 2026] 127.0.0.1:54052 [200]: GET /api/stats.php +[Thu Jul 30 22:01:32 2026] 127.0.0.1:54052 Closing +[Thu Jul 30 22:01:32 2026] 127.0.0.1:54062 Accepted +[Thu Jul 30 22:01:32 2026] 127.0.0.1:54062 [200]: GET /api/chart.php?range=year +[Thu Jul 30 22:01:32 2026] 127.0.0.1:54062 Closing +[Thu Jul 30 22:02:31 2026] 127.0.0.1:36844 Accepted +[Thu Jul 30 22:02:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 22:02:32 2026] 127.0.0.1:36844 [200]: GET /api/stats.php +[Thu Jul 30 22:02:32 2026] 127.0.0.1:36844 Closing +[Thu Jul 30 22:02:32 2026] 127.0.0.1:36858 Accepted +[Thu Jul 30 22:02:32 2026] 127.0.0.1:36858 [200]: GET /api/chart.php?range=year +[Thu Jul 30 22:02:32 2026] 127.0.0.1:36858 Closing +[Thu Jul 30 22:03:31 2026] 127.0.0.1:43484 Accepted +[Thu Jul 30 22:03:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 22:03:32 2026] 127.0.0.1:43484 [200]: GET /api/stats.php +[Thu Jul 30 22:03:32 2026] 127.0.0.1:43484 Closing +[Thu Jul 30 22:03:32 2026] 127.0.0.1:43488 Accepted +[Thu Jul 30 22:03:32 2026] 127.0.0.1:43488 [200]: GET /api/chart.php?range=year +[Thu Jul 30 22:03:32 2026] 127.0.0.1:43488 Closing +[Thu Jul 30 22:04:31 2026] 127.0.0.1:47206 Accepted +[Thu Jul 30 22:04:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 22:04:32 2026] 127.0.0.1:47206 [200]: GET /api/stats.php +[Thu Jul 30 22:04:32 2026] 127.0.0.1:47206 Closing +[Thu Jul 30 22:04:32 2026] 127.0.0.1:47210 Accepted +[Thu Jul 30 22:04:32 2026] 127.0.0.1:47210 [200]: GET /api/chart.php?range=year +[Thu Jul 30 22:04:32 2026] 127.0.0.1:47210 Closing +[Thu Jul 30 22:05:31 2026] 127.0.0.1:40806 Accepted +[Thu Jul 30 22:05:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 22:05:32 2026] 127.0.0.1:40806 [200]: GET /api/stats.php +[Thu Jul 30 22:05:32 2026] 127.0.0.1:40806 Closing +[Thu Jul 30 22:05:32 2026] 127.0.0.1:40814 Accepted +[Thu Jul 30 22:05:32 2026] 127.0.0.1:40814 [200]: GET /api/chart.php?range=year +[Thu Jul 30 22:05:32 2026] 127.0.0.1:40814 Closing +[Thu Jul 30 22:06:31 2026] 127.0.0.1:54234 Accepted +[Thu Jul 30 22:06:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 22:06:32 2026] 127.0.0.1:54234 [200]: GET /api/stats.php +[Thu Jul 30 22:06:32 2026] 127.0.0.1:54234 Closing +[Thu Jul 30 22:06:32 2026] 127.0.0.1:54244 Accepted +[Thu Jul 30 22:06:32 2026] 127.0.0.1:54244 [200]: GET /api/chart.php?range=year +[Thu Jul 30 22:06:32 2026] 127.0.0.1:54244 Closing +[Thu Jul 30 22:07:31 2026] 127.0.0.1:57904 Accepted +[Thu Jul 30 22:07:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 22:07:32 2026] 127.0.0.1:57904 [200]: GET /api/stats.php +[Thu Jul 30 22:07:32 2026] 127.0.0.1:57904 Closing +[Thu Jul 30 22:07:32 2026] 127.0.0.1:57920 Accepted +[Thu Jul 30 22:07:32 2026] 127.0.0.1:57920 [200]: GET /api/chart.php?range=year +[Thu Jul 30 22:07:32 2026] 127.0.0.1:57920 Closing +[Thu Jul 30 22:08:31 2026] 127.0.0.1:53730 Accepted +[Thu Jul 30 22:08:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 22:08:32 2026] 127.0.0.1:53730 [200]: GET /api/stats.php +[Thu Jul 30 22:08:32 2026] 127.0.0.1:53730 Closing +[Thu Jul 30 22:08:32 2026] 127.0.0.1:53738 Accepted +[Thu Jul 30 22:08:32 2026] 127.0.0.1:53738 [200]: GET /api/chart.php?range=year +[Thu Jul 30 22:08:32 2026] 127.0.0.1:53738 Closing +[Thu Jul 30 22:09:31 2026] 127.0.0.1:37764 Accepted +[Thu Jul 30 22:09:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 22:09:32 2026] 127.0.0.1:37764 [200]: GET /api/stats.php +[Thu Jul 30 22:09:32 2026] 127.0.0.1:37764 Closing +[Thu Jul 30 22:09:32 2026] 127.0.0.1:37774 Accepted +[Thu Jul 30 22:09:32 2026] 127.0.0.1:37774 [200]: GET /api/chart.php?range=year +[Thu Jul 30 22:09:32 2026] 127.0.0.1:37774 Closing +[Thu Jul 30 22:10:31 2026] 127.0.0.1:43902 Accepted +[Thu Jul 30 22:10:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 22:10:32 2026] 127.0.0.1:43902 [200]: GET /api/stats.php +[Thu Jul 30 22:10:32 2026] 127.0.0.1:43902 Closing +[Thu Jul 30 22:10:32 2026] 127.0.0.1:43904 Accepted +[Thu Jul 30 22:10:32 2026] 127.0.0.1:43904 [200]: GET /api/chart.php?range=year +[Thu Jul 30 22:10:32 2026] 127.0.0.1:43904 Closing +[Thu Jul 30 22:11:31 2026] 127.0.0.1:42232 Accepted +[Thu Jul 30 22:11:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 22:11:32 2026] 127.0.0.1:42232 [200]: GET /api/stats.php +[Thu Jul 30 22:11:32 2026] 127.0.0.1:42232 Closing +[Thu Jul 30 22:11:32 2026] 127.0.0.1:42244 Accepted +[Thu Jul 30 22:11:32 2026] 127.0.0.1:42244 [200]: GET /api/chart.php?range=year +[Thu Jul 30 22:11:32 2026] 127.0.0.1:42244 Closing +[Thu Jul 30 22:12:31 2026] 127.0.0.1:56308 Accepted +[Thu Jul 30 22:12:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 22:12:32 2026] 127.0.0.1:56308 [200]: GET /api/stats.php +[Thu Jul 30 22:12:32 2026] 127.0.0.1:56308 Closing +[Thu Jul 30 22:12:32 2026] 127.0.0.1:56310 Accepted +[Thu Jul 30 22:12:32 2026] 127.0.0.1:56310 [200]: GET /api/chart.php?range=year +[Thu Jul 30 22:12:32 2026] 127.0.0.1:56310 Closing +[Thu Jul 30 22:13:31 2026] 127.0.0.1:55774 Accepted +[Thu Jul 30 22:13:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 22:13:32 2026] 127.0.0.1:55774 [200]: GET /api/stats.php +[Thu Jul 30 22:13:32 2026] 127.0.0.1:55774 Closing +[Thu Jul 30 22:13:32 2026] 127.0.0.1:55776 Accepted +[Thu Jul 30 22:13:32 2026] 127.0.0.1:55776 [200]: GET /api/chart.php?range=year +[Thu Jul 30 22:13:32 2026] 127.0.0.1:55776 Closing +[Thu Jul 30 22:14:31 2026] 127.0.0.1:55008 Accepted +[Thu Jul 30 22:14:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 22:14:32 2026] 127.0.0.1:55008 [200]: GET /api/stats.php +[Thu Jul 30 22:14:32 2026] 127.0.0.1:55008 Closing +[Thu Jul 30 22:14:32 2026] 127.0.0.1:55020 Accepted +[Thu Jul 30 22:14:32 2026] 127.0.0.1:55020 [200]: GET /api/chart.php?range=year +[Thu Jul 30 22:14:32 2026] 127.0.0.1:55020 Closing +[Thu Jul 30 22:15:31 2026] 127.0.0.1:43078 Accepted +[Thu Jul 30 22:15:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 22:15:32 2026] 127.0.0.1:43078 [200]: GET /api/stats.php +[Thu Jul 30 22:15:32 2026] 127.0.0.1:43078 Closing +[Thu Jul 30 22:15:32 2026] 127.0.0.1:43088 Accepted +[Thu Jul 30 22:15:32 2026] 127.0.0.1:43088 [200]: GET /api/chart.php?range=year +[Thu Jul 30 22:15:32 2026] 127.0.0.1:43088 Closing +[Thu Jul 30 22:16:31 2026] 127.0.0.1:43234 Accepted +[Thu Jul 30 22:16:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 22:16:32 2026] 127.0.0.1:43234 [200]: GET /api/stats.php +[Thu Jul 30 22:16:32 2026] 127.0.0.1:43234 Closing +[Thu Jul 30 22:16:32 2026] 127.0.0.1:43238 Accepted +[Thu Jul 30 22:16:32 2026] 127.0.0.1:43238 [200]: GET /api/chart.php?range=year +[Thu Jul 30 22:16:32 2026] 127.0.0.1:43238 Closing +[Thu Jul 30 22:17:31 2026] 127.0.0.1:49256 Accepted +[Thu Jul 30 22:17:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 22:17:32 2026] 127.0.0.1:49256 [200]: GET /api/stats.php +[Thu Jul 30 22:17:32 2026] 127.0.0.1:49256 Closing +[Thu Jul 30 22:17:32 2026] 127.0.0.1:49264 Accepted +[Thu Jul 30 22:17:32 2026] 127.0.0.1:49264 [200]: GET /api/chart.php?range=year +[Thu Jul 30 22:17:32 2026] 127.0.0.1:49264 Closing +[Thu Jul 30 22:18:31 2026] 127.0.0.1:58172 Accepted +[Thu Jul 30 22:18:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 22:18:32 2026] 127.0.0.1:58172 [200]: GET /api/stats.php +[Thu Jul 30 22:18:32 2026] 127.0.0.1:58172 Closing +[Thu Jul 30 22:18:32 2026] 127.0.0.1:58176 Accepted +[Thu Jul 30 22:18:32 2026] 127.0.0.1:58176 [200]: GET /api/chart.php?range=year +[Thu Jul 30 22:18:32 2026] 127.0.0.1:58176 Closing +[Thu Jul 30 22:19:31 2026] 127.0.0.1:36824 Accepted +[Thu Jul 30 22:19:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 22:19:32 2026] 127.0.0.1:36824 [200]: GET /api/stats.php +[Thu Jul 30 22:19:32 2026] 127.0.0.1:36824 Closing +[Thu Jul 30 22:19:32 2026] 127.0.0.1:36836 Accepted +[Thu Jul 30 22:19:32 2026] 127.0.0.1:36836 [200]: GET /api/chart.php?range=year +[Thu Jul 30 22:19:32 2026] 127.0.0.1:36836 Closing +[Thu Jul 30 22:20:31 2026] 127.0.0.1:48650 Accepted +[Thu Jul 30 22:20:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 22:20:32 2026] 127.0.0.1:48650 [200]: GET /api/stats.php +[Thu Jul 30 22:20:32 2026] 127.0.0.1:48650 Closing +[Thu Jul 30 22:20:32 2026] 127.0.0.1:48654 Accepted +[Thu Jul 30 22:20:32 2026] 127.0.0.1:48654 [200]: GET /api/chart.php?range=year +[Thu Jul 30 22:20:32 2026] 127.0.0.1:48654 Closing +[Thu Jul 30 22:21:31 2026] 127.0.0.1:60088 Accepted +[Thu Jul 30 22:21:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 22:21:32 2026] 127.0.0.1:60088 [200]: GET /api/stats.php +[Thu Jul 30 22:21:32 2026] 127.0.0.1:60088 Closing +[Thu Jul 30 22:21:32 2026] 127.0.0.1:60096 Accepted +[Thu Jul 30 22:21:32 2026] 127.0.0.1:60096 [200]: GET /api/chart.php?range=year +[Thu Jul 30 22:21:32 2026] 127.0.0.1:60096 Closing +[Thu Jul 30 22:22:31 2026] 127.0.0.1:58584 Accepted +[Thu Jul 30 22:22:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 22:22:32 2026] 127.0.0.1:58584 [200]: GET /api/stats.php +[Thu Jul 30 22:22:32 2026] 127.0.0.1:58584 Closing +[Thu Jul 30 22:22:32 2026] 127.0.0.1:58588 Accepted +[Thu Jul 30 22:22:32 2026] 127.0.0.1:58588 [200]: GET /api/chart.php?range=year +[Thu Jul 30 22:22:32 2026] 127.0.0.1:58588 Closing +[Thu Jul 30 22:23:31 2026] 127.0.0.1:41662 Accepted +[Thu Jul 30 22:23:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 22:23:32 2026] 127.0.0.1:41662 [200]: GET /api/stats.php +[Thu Jul 30 22:23:32 2026] 127.0.0.1:41662 Closing +[Thu Jul 30 22:23:32 2026] 127.0.0.1:41678 Accepted +[Thu Jul 30 22:23:32 2026] 127.0.0.1:41678 [200]: GET /api/chart.php?range=year +[Thu Jul 30 22:23:32 2026] 127.0.0.1:41678 Closing +[Thu Jul 30 22:24:31 2026] 127.0.0.1:59782 Accepted +[Thu Jul 30 22:24:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 22:24:32 2026] 127.0.0.1:59782 [200]: GET /api/stats.php +[Thu Jul 30 22:24:32 2026] 127.0.0.1:59782 Closing +[Thu Jul 30 22:24:32 2026] 127.0.0.1:59792 Accepted +[Thu Jul 30 22:24:32 2026] 127.0.0.1:59792 [200]: GET /api/chart.php?range=year +[Thu Jul 30 22:24:32 2026] 127.0.0.1:59792 Closing +[Thu Jul 30 22:25:31 2026] 127.0.0.1:37528 Accepted +[Thu Jul 30 22:25:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 22:25:32 2026] 127.0.0.1:37528 [200]: GET /api/stats.php +[Thu Jul 30 22:25:32 2026] 127.0.0.1:37528 Closing +[Thu Jul 30 22:25:32 2026] 127.0.0.1:37540 Accepted +[Thu Jul 30 22:25:32 2026] 127.0.0.1:37540 [200]: GET /api/chart.php?range=year +[Thu Jul 30 22:25:32 2026] 127.0.0.1:37540 Closing +[Thu Jul 30 22:26:31 2026] 127.0.0.1:45480 Accepted +[Thu Jul 30 22:26:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 22:26:32 2026] 127.0.0.1:45480 [200]: GET /api/stats.php +[Thu Jul 30 22:26:32 2026] 127.0.0.1:45480 Closing +[Thu Jul 30 22:26:32 2026] 127.0.0.1:45482 Accepted +[Thu Jul 30 22:26:32 2026] 127.0.0.1:45482 [200]: GET /api/chart.php?range=year +[Thu Jul 30 22:26:32 2026] 127.0.0.1:45482 Closing +[Thu Jul 30 22:27:31 2026] 127.0.0.1:48730 Accepted +[Thu Jul 30 22:27:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 22:27:32 2026] 127.0.0.1:48730 [200]: GET /api/stats.php +[Thu Jul 30 22:27:32 2026] 127.0.0.1:48730 Closing +[Thu Jul 30 22:27:32 2026] 127.0.0.1:48742 Accepted +[Thu Jul 30 22:27:32 2026] 127.0.0.1:48742 [200]: GET /api/chart.php?range=year +[Thu Jul 30 22:27:32 2026] 127.0.0.1:48742 Closing +[Thu Jul 30 22:28:31 2026] 127.0.0.1:57364 Accepted +[Thu Jul 30 22:28:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 22:28:32 2026] 127.0.0.1:57364 [200]: GET /api/stats.php +[Thu Jul 30 22:28:32 2026] 127.0.0.1:57364 Closing +[Thu Jul 30 22:28:32 2026] 127.0.0.1:57378 Accepted +[Thu Jul 30 22:28:32 2026] 127.0.0.1:57378 [200]: GET /api/chart.php?range=year +[Thu Jul 30 22:28:32 2026] 127.0.0.1:57378 Closing +[Thu Jul 30 22:29:31 2026] 127.0.0.1:41230 Accepted +[Thu Jul 30 22:29:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 22:29:32 2026] 127.0.0.1:41230 [200]: GET /api/stats.php +[Thu Jul 30 22:29:32 2026] 127.0.0.1:41230 Closing +[Thu Jul 30 22:29:32 2026] 127.0.0.1:41246 Accepted +[Thu Jul 30 22:29:32 2026] 127.0.0.1:41246 [200]: GET /api/chart.php?range=year +[Thu Jul 30 22:29:32 2026] 127.0.0.1:41246 Closing +[Thu Jul 30 22:30:31 2026] 127.0.0.1:57878 Accepted +[Thu Jul 30 22:30:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 22:30:32 2026] 127.0.0.1:57878 [200]: GET /api/stats.php +[Thu Jul 30 22:30:32 2026] 127.0.0.1:57878 Closing +[Thu Jul 30 22:30:32 2026] 127.0.0.1:57894 Accepted +[Thu Jul 30 22:30:32 2026] 127.0.0.1:57894 [200]: GET /api/chart.php?range=year +[Thu Jul 30 22:30:32 2026] 127.0.0.1:57894 Closing +[Thu Jul 30 22:31:31 2026] 127.0.0.1:55314 Accepted +[Thu Jul 30 22:31:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 22:31:32 2026] 127.0.0.1:55314 [200]: GET /api/stats.php +[Thu Jul 30 22:31:32 2026] 127.0.0.1:55314 Closing +[Thu Jul 30 22:31:32 2026] 127.0.0.1:55318 Accepted +[Thu Jul 30 22:31:32 2026] 127.0.0.1:55318 [200]: GET /api/chart.php?range=year +[Thu Jul 30 22:31:32 2026] 127.0.0.1:55318 Closing +[Thu Jul 30 22:32:31 2026] 127.0.0.1:39034 Accepted +[Thu Jul 30 22:32:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 22:32:32 2026] 127.0.0.1:39034 [200]: GET /api/stats.php +[Thu Jul 30 22:32:32 2026] 127.0.0.1:39034 Closing +[Thu Jul 30 22:32:32 2026] 127.0.0.1:39048 Accepted +[Thu Jul 30 22:32:32 2026] 127.0.0.1:39048 [200]: GET /api/chart.php?range=year +[Thu Jul 30 22:32:32 2026] 127.0.0.1:39048 Closing +[Thu Jul 30 22:33:31 2026] 127.0.0.1:39936 Accepted +[Thu Jul 30 22:33:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 22:33:32 2026] 127.0.0.1:39936 [200]: GET /api/stats.php +[Thu Jul 30 22:33:32 2026] 127.0.0.1:39936 Closing +[Thu Jul 30 22:33:32 2026] 127.0.0.1:39938 Accepted +[Thu Jul 30 22:33:32 2026] 127.0.0.1:39938 [200]: GET /api/chart.php?range=year +[Thu Jul 30 22:33:32 2026] 127.0.0.1:39938 Closing +[Thu Jul 30 22:34:31 2026] 127.0.0.1:34354 Accepted +[Thu Jul 30 22:34:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 22:34:32 2026] 127.0.0.1:34354 [200]: GET /api/stats.php +[Thu Jul 30 22:34:32 2026] 127.0.0.1:34354 Closing +[Thu Jul 30 22:34:32 2026] 127.0.0.1:34370 Accepted +[Thu Jul 30 22:34:32 2026] 127.0.0.1:34370 [200]: GET /api/chart.php?range=year +[Thu Jul 30 22:34:32 2026] 127.0.0.1:34370 Closing +[Thu Jul 30 22:35:31 2026] 127.0.0.1:34922 Accepted +[Thu Jul 30 22:35:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 22:35:32 2026] 127.0.0.1:34922 [200]: GET /api/stats.php +[Thu Jul 30 22:35:32 2026] 127.0.0.1:34922 Closing +[Thu Jul 30 22:35:32 2026] 127.0.0.1:34932 Accepted +[Thu Jul 30 22:35:32 2026] 127.0.0.1:34932 [200]: GET /api/chart.php?range=year +[Thu Jul 30 22:35:32 2026] 127.0.0.1:34932 Closing +[Thu Jul 30 22:36:31 2026] 127.0.0.1:42066 Accepted +[Thu Jul 30 22:36:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 22:36:32 2026] 127.0.0.1:42066 [200]: GET /api/stats.php +[Thu Jul 30 22:36:32 2026] 127.0.0.1:42066 Closing +[Thu Jul 30 22:36:32 2026] 127.0.0.1:42072 Accepted +[Thu Jul 30 22:36:32 2026] 127.0.0.1:42072 [200]: GET /api/chart.php?range=year +[Thu Jul 30 22:36:32 2026] 127.0.0.1:42072 Closing +[Thu Jul 30 22:37:31 2026] 127.0.0.1:53414 Accepted +[Thu Jul 30 22:37:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 22:37:32 2026] 127.0.0.1:53414 [200]: GET /api/stats.php +[Thu Jul 30 22:37:32 2026] 127.0.0.1:53414 Closing +[Thu Jul 30 22:37:32 2026] 127.0.0.1:53418 Accepted +[Thu Jul 30 22:37:32 2026] 127.0.0.1:53418 [200]: GET /api/chart.php?range=year +[Thu Jul 30 22:37:32 2026] 127.0.0.1:53418 Closing +[Thu Jul 30 22:38:31 2026] 127.0.0.1:41046 Accepted +[Thu Jul 30 22:38:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 22:38:32 2026] 127.0.0.1:41046 [200]: GET /api/stats.php +[Thu Jul 30 22:38:32 2026] 127.0.0.1:41046 Closing +[Thu Jul 30 22:38:32 2026] 127.0.0.1:41056 Accepted +[Thu Jul 30 22:38:32 2026] 127.0.0.1:41056 [200]: GET /api/chart.php?range=year +[Thu Jul 30 22:38:32 2026] 127.0.0.1:41056 Closing +[Thu Jul 30 22:39:31 2026] 127.0.0.1:49096 Accepted +[Thu Jul 30 22:39:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 22:39:32 2026] 127.0.0.1:49096 [200]: GET /api/stats.php +[Thu Jul 30 22:39:32 2026] 127.0.0.1:49096 Closing +[Thu Jul 30 22:39:32 2026] 127.0.0.1:49106 Accepted +[Thu Jul 30 22:39:32 2026] 127.0.0.1:49106 [200]: GET /api/chart.php?range=year +[Thu Jul 30 22:39:32 2026] 127.0.0.1:49106 Closing +[Thu Jul 30 22:40:31 2026] 127.0.0.1:58720 Accepted +[Thu Jul 30 22:40:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 22:40:32 2026] 127.0.0.1:58720 [200]: GET /api/stats.php +[Thu Jul 30 22:40:32 2026] 127.0.0.1:58720 Closing +[Thu Jul 30 22:40:32 2026] 127.0.0.1:58734 Accepted +[Thu Jul 30 22:40:32 2026] 127.0.0.1:58734 [200]: GET /api/chart.php?range=year +[Thu Jul 30 22:40:32 2026] 127.0.0.1:58734 Closing +[Thu Jul 30 22:41:31 2026] 127.0.0.1:43574 Accepted +[Thu Jul 30 22:41:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 22:41:32 2026] 127.0.0.1:43574 [200]: GET /api/stats.php +[Thu Jul 30 22:41:32 2026] 127.0.0.1:43574 Closing +[Thu Jul 30 22:41:32 2026] 127.0.0.1:43578 Accepted +[Thu Jul 30 22:41:32 2026] 127.0.0.1:43578 [200]: GET /api/chart.php?range=year +[Thu Jul 30 22:41:32 2026] 127.0.0.1:43578 Closing +[Thu Jul 30 22:42:31 2026] 127.0.0.1:42076 Accepted +[Thu Jul 30 22:42:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 22:42:32 2026] 127.0.0.1:42076 [200]: GET /api/stats.php +[Thu Jul 30 22:42:32 2026] 127.0.0.1:42076 Closing +[Thu Jul 30 22:42:32 2026] 127.0.0.1:42086 Accepted +[Thu Jul 30 22:42:32 2026] 127.0.0.1:42086 [200]: GET /api/chart.php?range=year +[Thu Jul 30 22:42:32 2026] 127.0.0.1:42086 Closing +[Thu Jul 30 22:43:31 2026] 127.0.0.1:37978 Accepted +[Thu Jul 30 22:43:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 22:43:32 2026] 127.0.0.1:37978 [200]: GET /api/stats.php +[Thu Jul 30 22:43:32 2026] 127.0.0.1:37978 Closing +[Thu Jul 30 22:43:32 2026] 127.0.0.1:37994 Accepted +[Thu Jul 30 22:43:32 2026] 127.0.0.1:37994 [200]: GET /api/chart.php?range=year +[Thu Jul 30 22:43:32 2026] 127.0.0.1:37994 Closing +[Thu Jul 30 22:44:31 2026] 127.0.0.1:56064 Accepted +[Thu Jul 30 22:44:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 22:44:32 2026] 127.0.0.1:56064 [200]: GET /api/stats.php +[Thu Jul 30 22:44:32 2026] 127.0.0.1:56064 Closing +[Thu Jul 30 22:44:32 2026] 127.0.0.1:56076 Accepted +[Thu Jul 30 22:44:32 2026] 127.0.0.1:56076 [200]: GET /api/chart.php?range=year +[Thu Jul 30 22:44:32 2026] 127.0.0.1:56076 Closing +[Thu Jul 30 22:45:31 2026] 127.0.0.1:33268 Accepted +[Thu Jul 30 22:45:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 22:45:32 2026] 127.0.0.1:33268 [200]: GET /api/stats.php +[Thu Jul 30 22:45:32 2026] 127.0.0.1:33268 Closing +[Thu Jul 30 22:45:32 2026] 127.0.0.1:33284 Accepted +[Thu Jul 30 22:45:32 2026] 127.0.0.1:33284 [200]: GET /api/chart.php?range=year +[Thu Jul 30 22:45:32 2026] 127.0.0.1:33284 Closing +[Thu Jul 30 22:46:31 2026] 127.0.0.1:39472 Accepted +[Thu Jul 30 22:46:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 22:46:32 2026] 127.0.0.1:39472 [200]: GET /api/stats.php +[Thu Jul 30 22:46:32 2026] 127.0.0.1:39472 Closing +[Thu Jul 30 22:46:32 2026] 127.0.0.1:39480 Accepted +[Thu Jul 30 22:46:32 2026] 127.0.0.1:39480 [200]: GET /api/chart.php?range=year +[Thu Jul 30 22:46:32 2026] 127.0.0.1:39480 Closing +[Thu Jul 30 22:47:31 2026] 127.0.0.1:54746 Accepted +[Thu Jul 30 22:47:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 22:47:32 2026] 127.0.0.1:54746 [200]: GET /api/stats.php +[Thu Jul 30 22:47:32 2026] 127.0.0.1:54746 Closing +[Thu Jul 30 22:47:32 2026] 127.0.0.1:54748 Accepted +[Thu Jul 30 22:47:32 2026] 127.0.0.1:54748 [200]: GET /api/chart.php?range=year +[Thu Jul 30 22:47:32 2026] 127.0.0.1:54748 Closing +[Thu Jul 30 22:48:31 2026] 127.0.0.1:54134 Accepted +[Thu Jul 30 22:48:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 22:48:32 2026] 127.0.0.1:54134 [200]: GET /api/stats.php +[Thu Jul 30 22:48:32 2026] 127.0.0.1:54134 Closing +[Thu Jul 30 22:48:32 2026] 127.0.0.1:54136 Accepted +[Thu Jul 30 22:48:32 2026] 127.0.0.1:54136 [200]: GET /api/chart.php?range=year +[Thu Jul 30 22:48:32 2026] 127.0.0.1:54136 Closing +[Thu Jul 30 22:49:31 2026] 127.0.0.1:53080 Accepted +[Thu Jul 30 22:49:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 22:49:32 2026] 127.0.0.1:53080 [200]: GET /api/stats.php +[Thu Jul 30 22:49:32 2026] 127.0.0.1:53080 Closing +[Thu Jul 30 22:49:32 2026] 127.0.0.1:53084 Accepted +[Thu Jul 30 22:49:32 2026] 127.0.0.1:53084 [200]: GET /api/chart.php?range=year +[Thu Jul 30 22:49:32 2026] 127.0.0.1:53084 Closing +[Thu Jul 30 22:50:31 2026] 127.0.0.1:40096 Accepted +[Thu Jul 30 22:50:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 22:50:32 2026] 127.0.0.1:40096 [200]: GET /api/stats.php +[Thu Jul 30 22:50:32 2026] 127.0.0.1:40096 Closing +[Thu Jul 30 22:50:32 2026] 127.0.0.1:40106 Accepted +[Thu Jul 30 22:50:32 2026] 127.0.0.1:40106 [200]: GET /api/chart.php?range=year +[Thu Jul 30 22:50:32 2026] 127.0.0.1:40106 Closing +[Thu Jul 30 22:51:31 2026] 127.0.0.1:41442 Accepted +[Thu Jul 30 22:51:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 22:51:32 2026] 127.0.0.1:41442 [200]: GET /api/stats.php +[Thu Jul 30 22:51:32 2026] 127.0.0.1:41442 Closing +[Thu Jul 30 22:51:32 2026] 127.0.0.1:41448 Accepted +[Thu Jul 30 22:51:32 2026] 127.0.0.1:41448 [200]: GET /api/chart.php?range=year +[Thu Jul 30 22:51:32 2026] 127.0.0.1:41448 Closing +[Thu Jul 30 22:52:31 2026] 127.0.0.1:36720 Accepted +[Thu Jul 30 22:52:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 22:52:32 2026] 127.0.0.1:36720 [200]: GET /api/stats.php +[Thu Jul 30 22:52:32 2026] 127.0.0.1:36720 Closing +[Thu Jul 30 22:52:32 2026] 127.0.0.1:36732 Accepted +[Thu Jul 30 22:52:32 2026] 127.0.0.1:36732 [200]: GET /api/chart.php?range=year +[Thu Jul 30 22:52:32 2026] 127.0.0.1:36732 Closing +[Thu Jul 30 22:53:31 2026] 127.0.0.1:46794 Accepted +[Thu Jul 30 22:53:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 22:53:32 2026] 127.0.0.1:46794 [200]: GET /api/stats.php +[Thu Jul 30 22:53:32 2026] 127.0.0.1:46794 Closing +[Thu Jul 30 22:53:32 2026] 127.0.0.1:46796 Accepted +[Thu Jul 30 22:53:32 2026] 127.0.0.1:46796 [200]: GET /api/chart.php?range=year +[Thu Jul 30 22:53:32 2026] 127.0.0.1:46796 Closing +[Thu Jul 30 22:54:31 2026] 127.0.0.1:33064 Accepted +[Thu Jul 30 22:54:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 22:54:32 2026] 127.0.0.1:33064 [200]: GET /api/stats.php +[Thu Jul 30 22:54:32 2026] 127.0.0.1:33064 Closing +[Thu Jul 30 22:54:32 2026] 127.0.0.1:33066 Accepted +[Thu Jul 30 22:54:32 2026] 127.0.0.1:33066 [200]: GET /api/chart.php?range=year +[Thu Jul 30 22:54:32 2026] 127.0.0.1:33066 Closing +[Thu Jul 30 22:55:31 2026] 127.0.0.1:60282 Accepted +[Thu Jul 30 22:55:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 22:55:32 2026] 127.0.0.1:60282 [200]: GET /api/stats.php +[Thu Jul 30 22:55:32 2026] 127.0.0.1:60282 Closing +[Thu Jul 30 22:55:32 2026] 127.0.0.1:60298 Accepted +[Thu Jul 30 22:55:32 2026] 127.0.0.1:60298 [200]: GET /api/chart.php?range=year +[Thu Jul 30 22:55:32 2026] 127.0.0.1:60298 Closing +[Thu Jul 30 22:56:31 2026] 127.0.0.1:33742 Accepted +[Thu Jul 30 22:56:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 22:56:32 2026] 127.0.0.1:33742 [200]: GET /api/stats.php +[Thu Jul 30 22:56:32 2026] 127.0.0.1:33742 Closing +[Thu Jul 30 22:56:32 2026] 127.0.0.1:33750 Accepted +[Thu Jul 30 22:56:32 2026] 127.0.0.1:33750 [200]: GET /api/chart.php?range=year +[Thu Jul 30 22:56:32 2026] 127.0.0.1:33750 Closing +[Thu Jul 30 22:57:31 2026] 127.0.0.1:38680 Accepted +[Thu Jul 30 22:57:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 22:57:32 2026] 127.0.0.1:38680 [200]: GET /api/stats.php +[Thu Jul 30 22:57:32 2026] 127.0.0.1:38680 Closing +[Thu Jul 30 22:57:32 2026] 127.0.0.1:38686 Accepted +[Thu Jul 30 22:57:32 2026] 127.0.0.1:38686 [200]: GET /api/chart.php?range=year +[Thu Jul 30 22:57:32 2026] 127.0.0.1:38686 Closing +[Thu Jul 30 22:58:31 2026] 127.0.0.1:40552 Accepted +[Thu Jul 30 22:58:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 22:58:32 2026] 127.0.0.1:40552 [200]: GET /api/stats.php +[Thu Jul 30 22:58:32 2026] 127.0.0.1:40552 Closing +[Thu Jul 30 22:58:32 2026] 127.0.0.1:40564 Accepted +[Thu Jul 30 22:58:32 2026] 127.0.0.1:40564 [200]: GET /api/chart.php?range=year +[Thu Jul 30 22:58:32 2026] 127.0.0.1:40564 Closing +[Thu Jul 30 22:59:31 2026] 127.0.0.1:33958 Accepted +[Thu Jul 30 22:59:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 22:59:32 2026] 127.0.0.1:33958 [200]: GET /api/stats.php +[Thu Jul 30 22:59:32 2026] 127.0.0.1:33958 Closing +[Thu Jul 30 22:59:32 2026] 127.0.0.1:33966 Accepted +[Thu Jul 30 22:59:32 2026] 127.0.0.1:33966 [200]: GET /api/chart.php?range=year +[Thu Jul 30 22:59:32 2026] 127.0.0.1:33966 Closing +[Thu Jul 30 23:00:31 2026] 127.0.0.1:47574 Accepted +[Thu Jul 30 23:00:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 23:00:32 2026] 127.0.0.1:47574 [200]: GET /api/stats.php +[Thu Jul 30 23:00:32 2026] 127.0.0.1:47574 Closing +[Thu Jul 30 23:00:32 2026] 127.0.0.1:47588 Accepted +[Thu Jul 30 23:00:32 2026] 127.0.0.1:47588 [200]: GET /api/chart.php?range=year +[Thu Jul 30 23:00:32 2026] 127.0.0.1:47588 Closing +[Thu Jul 30 23:01:31 2026] 127.0.0.1:54516 Accepted +[Thu Jul 30 23:01:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 23:01:32 2026] 127.0.0.1:54516 [200]: GET /api/stats.php +[Thu Jul 30 23:01:32 2026] 127.0.0.1:54516 Closing +[Thu Jul 30 23:01:32 2026] 127.0.0.1:54524 Accepted +[Thu Jul 30 23:01:32 2026] 127.0.0.1:54524 [200]: GET /api/chart.php?range=year +[Thu Jul 30 23:01:32 2026] 127.0.0.1:54524 Closing +[Thu Jul 30 23:02:31 2026] 127.0.0.1:56918 Accepted +[Thu Jul 30 23:02:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 23:02:32 2026] 127.0.0.1:56918 [200]: GET /api/stats.php +[Thu Jul 30 23:02:32 2026] 127.0.0.1:56918 Closing +[Thu Jul 30 23:02:32 2026] 127.0.0.1:56920 Accepted +[Thu Jul 30 23:02:32 2026] 127.0.0.1:56920 [200]: GET /api/chart.php?range=year +[Thu Jul 30 23:02:32 2026] 127.0.0.1:56920 Closing +[Thu Jul 30 23:03:31 2026] 127.0.0.1:40412 Accepted +[Thu Jul 30 23:03:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 23:03:32 2026] 127.0.0.1:40412 [200]: GET /api/stats.php +[Thu Jul 30 23:03:32 2026] 127.0.0.1:40412 Closing +[Thu Jul 30 23:03:32 2026] 127.0.0.1:40428 Accepted +[Thu Jul 30 23:03:32 2026] 127.0.0.1:40428 [200]: GET /api/chart.php?range=year +[Thu Jul 30 23:03:32 2026] 127.0.0.1:40428 Closing +[Thu Jul 30 23:04:31 2026] 127.0.0.1:58112 Accepted +[Thu Jul 30 23:04:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 23:04:32 2026] 127.0.0.1:58112 [200]: GET /api/stats.php +[Thu Jul 30 23:04:32 2026] 127.0.0.1:58112 Closing +[Thu Jul 30 23:04:32 2026] 127.0.0.1:58126 Accepted +[Thu Jul 30 23:04:32 2026] 127.0.0.1:58126 [200]: GET /api/chart.php?range=year +[Thu Jul 30 23:04:32 2026] 127.0.0.1:58126 Closing +[Thu Jul 30 23:05:31 2026] 127.0.0.1:36368 Accepted +[Thu Jul 30 23:05:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 23:05:32 2026] 127.0.0.1:36368 [200]: GET /api/stats.php +[Thu Jul 30 23:05:32 2026] 127.0.0.1:36368 Closing +[Thu Jul 30 23:05:32 2026] 127.0.0.1:36374 Accepted +[Thu Jul 30 23:05:32 2026] 127.0.0.1:36374 [200]: GET /api/chart.php?range=year +[Thu Jul 30 23:05:32 2026] 127.0.0.1:36374 Closing +[Thu Jul 30 23:06:31 2026] 127.0.0.1:39052 Accepted +[Thu Jul 30 23:06:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 23:06:32 2026] 127.0.0.1:39052 [200]: GET /api/stats.php +[Thu Jul 30 23:06:32 2026] 127.0.0.1:39052 Closing +[Thu Jul 30 23:06:32 2026] 127.0.0.1:39060 Accepted +[Thu Jul 30 23:06:32 2026] 127.0.0.1:39060 [200]: GET /api/chart.php?range=year +[Thu Jul 30 23:06:32 2026] 127.0.0.1:39060 Closing +[Thu Jul 30 23:07:31 2026] 127.0.0.1:39280 Accepted +[Thu Jul 30 23:07:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 23:07:32 2026] 127.0.0.1:39280 [200]: GET /api/stats.php +[Thu Jul 30 23:07:32 2026] 127.0.0.1:39280 Closing +[Thu Jul 30 23:07:32 2026] 127.0.0.1:39282 Accepted +[Thu Jul 30 23:07:32 2026] 127.0.0.1:39282 [200]: GET /api/chart.php?range=year +[Thu Jul 30 23:07:32 2026] 127.0.0.1:39282 Closing +[Thu Jul 30 23:08:31 2026] 127.0.0.1:36622 Accepted +[Thu Jul 30 23:08:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 23:08:32 2026] 127.0.0.1:36622 [200]: GET /api/stats.php +[Thu Jul 30 23:08:32 2026] 127.0.0.1:36622 Closing +[Thu Jul 30 23:08:32 2026] 127.0.0.1:36634 Accepted +[Thu Jul 30 23:08:32 2026] 127.0.0.1:36634 [200]: GET /api/chart.php?range=year +[Thu Jul 30 23:08:32 2026] 127.0.0.1:36634 Closing +[Thu Jul 30 23:09:32 2026] 127.0.0.1:36122 Accepted +[Thu Jul 30 23:09:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 23:09:32 2026] 127.0.0.1:36122 [200]: GET /api/stats.php +[Thu Jul 30 23:09:32 2026] 127.0.0.1:36122 Closing +[Thu Jul 30 23:09:32 2026] 127.0.0.1:36132 Accepted +[Thu Jul 30 23:09:32 2026] 127.0.0.1:36132 [200]: GET /api/chart.php?range=year +[Thu Jul 30 23:09:32 2026] 127.0.0.1:36132 Closing +[Thu Jul 30 23:10:31 2026] 127.0.0.1:34872 Accepted +[Thu Jul 30 23:10:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 23:10:32 2026] 127.0.0.1:34872 [200]: GET /api/stats.php +[Thu Jul 30 23:10:32 2026] 127.0.0.1:34872 Closing +[Thu Jul 30 23:10:32 2026] 127.0.0.1:34888 Accepted +[Thu Jul 30 23:10:32 2026] 127.0.0.1:34888 [200]: GET /api/chart.php?range=year +[Thu Jul 30 23:10:32 2026] 127.0.0.1:34888 Closing +[Thu Jul 30 23:11:31 2026] 127.0.0.1:33056 Accepted +[Thu Jul 30 23:11:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 23:11:32 2026] 127.0.0.1:33056 [200]: GET /api/stats.php +[Thu Jul 30 23:11:32 2026] 127.0.0.1:33056 Closing +[Thu Jul 30 23:11:32 2026] 127.0.0.1:33072 Accepted +[Thu Jul 30 23:11:32 2026] 127.0.0.1:33072 [200]: GET /api/chart.php?range=year +[Thu Jul 30 23:11:32 2026] 127.0.0.1:33072 Closing +[Thu Jul 30 23:12:31 2026] 127.0.0.1:58786 Accepted +[Thu Jul 30 23:12:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 23:12:32 2026] 127.0.0.1:58786 [200]: GET /api/stats.php +[Thu Jul 30 23:12:32 2026] 127.0.0.1:58786 Closing +[Thu Jul 30 23:12:32 2026] 127.0.0.1:58798 Accepted +[Thu Jul 30 23:12:32 2026] 127.0.0.1:58798 [200]: GET /api/chart.php?range=year +[Thu Jul 30 23:12:32 2026] 127.0.0.1:58798 Closing +[Thu Jul 30 23:13:31 2026] 127.0.0.1:60964 Accepted +[Thu Jul 30 23:13:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 23:13:32 2026] 127.0.0.1:60964 [200]: GET /api/stats.php +[Thu Jul 30 23:13:32 2026] 127.0.0.1:60964 Closing +[Thu Jul 30 23:13:32 2026] 127.0.0.1:60968 Accepted +[Thu Jul 30 23:13:32 2026] 127.0.0.1:60968 [200]: GET /api/chart.php?range=year +[Thu Jul 30 23:13:32 2026] 127.0.0.1:60968 Closing +[Thu Jul 30 23:14:31 2026] 127.0.0.1:54980 Accepted +[Thu Jul 30 23:14:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 23:14:32 2026] 127.0.0.1:54980 [200]: GET /api/stats.php +[Thu Jul 30 23:14:32 2026] 127.0.0.1:54980 Closing +[Thu Jul 30 23:14:32 2026] 127.0.0.1:54982 Accepted +[Thu Jul 30 23:14:32 2026] 127.0.0.1:54982 [200]: GET /api/chart.php?range=year +[Thu Jul 30 23:14:32 2026] 127.0.0.1:54982 Closing +[Thu Jul 30 23:15:31 2026] 127.0.0.1:59580 Accepted +[Thu Jul 30 23:15:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 23:15:32 2026] 127.0.0.1:59580 [200]: GET /api/stats.php +[Thu Jul 30 23:15:32 2026] 127.0.0.1:59580 Closing +[Thu Jul 30 23:15:32 2026] 127.0.0.1:59594 Accepted +[Thu Jul 30 23:15:32 2026] 127.0.0.1:59594 [200]: GET /api/chart.php?range=year +[Thu Jul 30 23:15:32 2026] 127.0.0.1:59594 Closing +[Thu Jul 30 23:16:31 2026] 127.0.0.1:36456 Accepted +[Thu Jul 30 23:16:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 23:16:32 2026] 127.0.0.1:36456 [200]: GET /api/stats.php +[Thu Jul 30 23:16:32 2026] 127.0.0.1:36456 Closing +[Thu Jul 30 23:16:32 2026] 127.0.0.1:36458 Accepted +[Thu Jul 30 23:16:32 2026] 127.0.0.1:36458 [200]: GET /api/chart.php?range=year +[Thu Jul 30 23:16:32 2026] 127.0.0.1:36458 Closing +[Thu Jul 30 23:17:31 2026] 127.0.0.1:53916 Accepted +[Thu Jul 30 23:17:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 23:17:32 2026] 127.0.0.1:53916 [200]: GET /api/stats.php +[Thu Jul 30 23:17:32 2026] 127.0.0.1:53916 Closing +[Thu Jul 30 23:17:32 2026] 127.0.0.1:53922 Accepted +[Thu Jul 30 23:17:32 2026] 127.0.0.1:53922 [200]: GET /api/chart.php?range=year +[Thu Jul 30 23:17:32 2026] 127.0.0.1:53922 Closing +[Thu Jul 30 23:18:31 2026] 127.0.0.1:49834 Accepted +[Thu Jul 30 23:18:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 23:18:32 2026] 127.0.0.1:49834 [200]: GET /api/stats.php +[Thu Jul 30 23:18:32 2026] 127.0.0.1:49834 Closing +[Thu Jul 30 23:18:32 2026] 127.0.0.1:49850 Accepted +[Thu Jul 30 23:18:32 2026] 127.0.0.1:49850 [200]: GET /api/chart.php?range=year +[Thu Jul 30 23:18:32 2026] 127.0.0.1:49850 Closing +[Thu Jul 30 23:19:31 2026] 127.0.0.1:56322 Accepted +[Thu Jul 30 23:19:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 23:19:32 2026] 127.0.0.1:56322 [200]: GET /api/stats.php +[Thu Jul 30 23:19:32 2026] 127.0.0.1:56322 Closing +[Thu Jul 30 23:19:32 2026] 127.0.0.1:56330 Accepted +[Thu Jul 30 23:19:32 2026] 127.0.0.1:56330 [200]: GET /api/chart.php?range=year +[Thu Jul 30 23:19:32 2026] 127.0.0.1:56330 Closing +[Thu Jul 30 23:20:31 2026] 127.0.0.1:53614 Accepted +[Thu Jul 30 23:20:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 23:20:32 2026] 127.0.0.1:53614 [200]: GET /api/stats.php +[Thu Jul 30 23:20:32 2026] 127.0.0.1:53614 Closing +[Thu Jul 30 23:20:32 2026] 127.0.0.1:53618 Accepted +[Thu Jul 30 23:20:32 2026] 127.0.0.1:53618 [200]: GET /api/chart.php?range=year +[Thu Jul 30 23:20:32 2026] 127.0.0.1:53618 Closing +[Thu Jul 30 23:21:31 2026] 127.0.0.1:60976 Accepted +[Thu Jul 30 23:21:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 23:21:32 2026] 127.0.0.1:60976 [200]: GET /api/stats.php +[Thu Jul 30 23:21:32 2026] 127.0.0.1:60976 Closing +[Thu Jul 30 23:21:32 2026] 127.0.0.1:60990 Accepted +[Thu Jul 30 23:21:32 2026] 127.0.0.1:60990 [200]: GET /api/chart.php?range=year +[Thu Jul 30 23:21:32 2026] 127.0.0.1:60990 Closing +[Thu Jul 30 23:22:31 2026] 127.0.0.1:56474 Accepted +[Thu Jul 30 23:22:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 23:22:32 2026] 127.0.0.1:56474 [200]: GET /api/stats.php +[Thu Jul 30 23:22:32 2026] 127.0.0.1:56474 Closing +[Thu Jul 30 23:22:32 2026] 127.0.0.1:56480 Accepted +[Thu Jul 30 23:22:32 2026] 127.0.0.1:56480 [200]: GET /api/chart.php?range=year +[Thu Jul 30 23:22:32 2026] 127.0.0.1:56480 Closing +[Thu Jul 30 23:23:31 2026] 127.0.0.1:37452 Accepted +[Thu Jul 30 23:23:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 23:23:32 2026] 127.0.0.1:37452 [200]: GET /api/stats.php +[Thu Jul 30 23:23:32 2026] 127.0.0.1:37452 Closing +[Thu Jul 30 23:23:32 2026] 127.0.0.1:37460 Accepted +[Thu Jul 30 23:23:32 2026] 127.0.0.1:37460 [200]: GET /api/chart.php?range=year +[Thu Jul 30 23:23:32 2026] 127.0.0.1:37460 Closing +[Thu Jul 30 23:24:31 2026] 127.0.0.1:52434 Accepted +[Thu Jul 30 23:24:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 23:24:32 2026] 127.0.0.1:52434 [200]: GET /api/stats.php +[Thu Jul 30 23:24:32 2026] 127.0.0.1:52434 Closing +[Thu Jul 30 23:24:32 2026] 127.0.0.1:52440 Accepted +[Thu Jul 30 23:24:32 2026] 127.0.0.1:52440 [200]: GET /api/chart.php?range=year +[Thu Jul 30 23:24:32 2026] 127.0.0.1:52440 Closing +[Thu Jul 30 23:25:31 2026] 127.0.0.1:49736 Accepted +[Thu Jul 30 23:25:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 23:25:32 2026] 127.0.0.1:49736 [200]: GET /api/stats.php +[Thu Jul 30 23:25:32 2026] 127.0.0.1:49736 Closing +[Thu Jul 30 23:25:32 2026] 127.0.0.1:49746 Accepted +[Thu Jul 30 23:25:32 2026] 127.0.0.1:49746 [200]: GET /api/chart.php?range=year +[Thu Jul 30 23:25:32 2026] 127.0.0.1:49746 Closing +[Thu Jul 30 23:26:31 2026] 127.0.0.1:41086 Accepted +[Thu Jul 30 23:26:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 23:26:32 2026] 127.0.0.1:41086 [200]: GET /api/stats.php +[Thu Jul 30 23:26:32 2026] 127.0.0.1:41086 Closing +[Thu Jul 30 23:26:32 2026] 127.0.0.1:41096 Accepted +[Thu Jul 30 23:26:32 2026] 127.0.0.1:41096 [200]: GET /api/chart.php?range=year +[Thu Jul 30 23:26:32 2026] 127.0.0.1:41096 Closing +[Thu Jul 30 23:27:31 2026] 127.0.0.1:59842 Accepted +[Thu Jul 30 23:27:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 23:27:32 2026] 127.0.0.1:59842 [200]: GET /api/stats.php +[Thu Jul 30 23:27:32 2026] 127.0.0.1:59842 Closing +[Thu Jul 30 23:27:32 2026] 127.0.0.1:59852 Accepted +[Thu Jul 30 23:27:32 2026] 127.0.0.1:59852 [200]: GET /api/chart.php?range=year +[Thu Jul 30 23:27:32 2026] 127.0.0.1:59852 Closing +[Thu Jul 30 23:28:31 2026] 127.0.0.1:54746 Accepted +[Thu Jul 30 23:28:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 23:28:32 2026] 127.0.0.1:54746 [200]: GET /api/stats.php +[Thu Jul 30 23:28:32 2026] 127.0.0.1:54746 Closing +[Thu Jul 30 23:28:32 2026] 127.0.0.1:54760 Accepted +[Thu Jul 30 23:28:32 2026] 127.0.0.1:54760 [200]: GET /api/chart.php?range=year +[Thu Jul 30 23:28:32 2026] 127.0.0.1:54760 Closing +[Thu Jul 30 23:29:31 2026] 127.0.0.1:42516 Accepted +[Thu Jul 30 23:29:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 23:29:32 2026] 127.0.0.1:42516 [200]: GET /api/stats.php +[Thu Jul 30 23:29:32 2026] 127.0.0.1:42516 Closing +[Thu Jul 30 23:29:32 2026] 127.0.0.1:42530 Accepted +[Thu Jul 30 23:29:32 2026] 127.0.0.1:42530 [200]: GET /api/chart.php?range=year +[Thu Jul 30 23:29:32 2026] 127.0.0.1:42530 Closing +[Thu Jul 30 23:30:31 2026] 127.0.0.1:34862 Accepted +[Thu Jul 30 23:30:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 23:30:32 2026] 127.0.0.1:34862 [200]: GET /api/stats.php +[Thu Jul 30 23:30:32 2026] 127.0.0.1:34862 Closing +[Thu Jul 30 23:30:32 2026] 127.0.0.1:34870 Accepted +[Thu Jul 30 23:30:32 2026] 127.0.0.1:34870 [200]: GET /api/chart.php?range=year +[Thu Jul 30 23:30:32 2026] 127.0.0.1:34870 Closing +[Thu Jul 30 23:31:31 2026] 127.0.0.1:49136 Accepted +[Thu Jul 30 23:31:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 23:31:32 2026] 127.0.0.1:49136 [200]: GET /api/stats.php +[Thu Jul 30 23:31:32 2026] 127.0.0.1:49136 Closing +[Thu Jul 30 23:31:32 2026] 127.0.0.1:49138 Accepted +[Thu Jul 30 23:31:32 2026] 127.0.0.1:49138 [200]: GET /api/chart.php?range=year +[Thu Jul 30 23:31:32 2026] 127.0.0.1:49138 Closing +[Thu Jul 30 23:32:31 2026] 127.0.0.1:46172 Accepted +[Thu Jul 30 23:32:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 23:32:32 2026] 127.0.0.1:46172 [200]: GET /api/stats.php +[Thu Jul 30 23:32:32 2026] 127.0.0.1:46172 Closing +[Thu Jul 30 23:32:32 2026] 127.0.0.1:46186 Accepted +[Thu Jul 30 23:32:32 2026] 127.0.0.1:46186 [200]: GET /api/chart.php?range=year +[Thu Jul 30 23:32:32 2026] 127.0.0.1:46186 Closing +[Thu Jul 30 23:33:31 2026] 127.0.0.1:51702 Accepted +[Thu Jul 30 23:33:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 23:33:32 2026] 127.0.0.1:51702 [200]: GET /api/stats.php +[Thu Jul 30 23:33:32 2026] 127.0.0.1:51702 Closing +[Thu Jul 30 23:33:32 2026] 127.0.0.1:51710 Accepted +[Thu Jul 30 23:33:32 2026] 127.0.0.1:51710 [200]: GET /api/chart.php?range=year +[Thu Jul 30 23:33:32 2026] 127.0.0.1:51710 Closing +[Thu Jul 30 23:34:31 2026] 127.0.0.1:48780 Accepted +[Thu Jul 30 23:34:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 23:34:32 2026] 127.0.0.1:48780 [200]: GET /api/stats.php +[Thu Jul 30 23:34:32 2026] 127.0.0.1:48780 Closing +[Thu Jul 30 23:34:32 2026] 127.0.0.1:48792 Accepted +[Thu Jul 30 23:34:32 2026] 127.0.0.1:48792 [200]: GET /api/chart.php?range=year +[Thu Jul 30 23:34:32 2026] 127.0.0.1:48792 Closing +[Thu Jul 30 23:35:31 2026] 127.0.0.1:59066 Accepted +[Thu Jul 30 23:35:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 23:35:32 2026] 127.0.0.1:59066 [200]: GET /api/stats.php +[Thu Jul 30 23:35:32 2026] 127.0.0.1:59066 Closing +[Thu Jul 30 23:35:32 2026] 127.0.0.1:59080 Accepted +[Thu Jul 30 23:35:32 2026] 127.0.0.1:59080 [200]: GET /api/chart.php?range=year +[Thu Jul 30 23:35:32 2026] 127.0.0.1:59080 Closing +[Thu Jul 30 23:36:31 2026] 127.0.0.1:35560 Accepted +[Thu Jul 30 23:36:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 23:36:32 2026] 127.0.0.1:35560 [200]: GET /api/stats.php +[Thu Jul 30 23:36:32 2026] 127.0.0.1:35560 Closing +[Thu Jul 30 23:36:32 2026] 127.0.0.1:35572 Accepted +[Thu Jul 30 23:36:32 2026] 127.0.0.1:35572 [200]: GET /api/chart.php?range=year +[Thu Jul 30 23:36:32 2026] 127.0.0.1:35572 Closing +[Thu Jul 30 23:37:31 2026] 127.0.0.1:35826 Accepted +[Thu Jul 30 23:37:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 23:37:32 2026] 127.0.0.1:35826 [200]: GET /api/stats.php +[Thu Jul 30 23:37:32 2026] 127.0.0.1:35826 Closing +[Thu Jul 30 23:37:32 2026] 127.0.0.1:35838 Accepted +[Thu Jul 30 23:37:32 2026] 127.0.0.1:35838 [200]: GET /api/chart.php?range=year +[Thu Jul 30 23:37:32 2026] 127.0.0.1:35838 Closing +[Thu Jul 30 23:38:31 2026] 127.0.0.1:55602 Accepted +[Thu Jul 30 23:38:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 23:38:32 2026] 127.0.0.1:55602 [200]: GET /api/stats.php +[Thu Jul 30 23:38:32 2026] 127.0.0.1:55602 Closing +[Thu Jul 30 23:38:32 2026] 127.0.0.1:55608 Accepted +[Thu Jul 30 23:38:32 2026] 127.0.0.1:55608 [200]: GET /api/chart.php?range=year +[Thu Jul 30 23:38:32 2026] 127.0.0.1:55608 Closing +[Thu Jul 30 23:39:31 2026] 127.0.0.1:57368 Accepted +[Thu Jul 30 23:39:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 23:39:32 2026] 127.0.0.1:57368 [200]: GET /api/stats.php +[Thu Jul 30 23:39:32 2026] 127.0.0.1:57368 Closing +[Thu Jul 30 23:39:32 2026] 127.0.0.1:57382 Accepted +[Thu Jul 30 23:39:32 2026] 127.0.0.1:57382 [200]: GET /api/chart.php?range=year +[Thu Jul 30 23:39:32 2026] 127.0.0.1:57382 Closing +[Thu Jul 30 23:40:31 2026] 127.0.0.1:40082 Accepted +[Thu Jul 30 23:40:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 23:40:32 2026] 127.0.0.1:40082 [200]: GET /api/stats.php +[Thu Jul 30 23:40:32 2026] 127.0.0.1:40082 Closing +[Thu Jul 30 23:40:32 2026] 127.0.0.1:40098 Accepted +[Thu Jul 30 23:40:32 2026] 127.0.0.1:40098 [200]: GET /api/chart.php?range=year +[Thu Jul 30 23:40:32 2026] 127.0.0.1:40098 Closing +[Thu Jul 30 23:41:31 2026] 127.0.0.1:54466 Accepted +[Thu Jul 30 23:41:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 23:41:32 2026] 127.0.0.1:54466 [200]: GET /api/stats.php +[Thu Jul 30 23:41:32 2026] 127.0.0.1:54466 Closing +[Thu Jul 30 23:41:32 2026] 127.0.0.1:54468 Accepted +[Thu Jul 30 23:41:32 2026] 127.0.0.1:54468 [200]: GET /api/chart.php?range=year +[Thu Jul 30 23:41:32 2026] 127.0.0.1:54468 Closing +[Thu Jul 30 23:42:31 2026] 127.0.0.1:49156 Accepted +[Thu Jul 30 23:42:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 23:42:32 2026] 127.0.0.1:49156 [200]: GET /api/stats.php +[Thu Jul 30 23:42:32 2026] 127.0.0.1:49156 Closing +[Thu Jul 30 23:42:32 2026] 127.0.0.1:49172 Accepted +[Thu Jul 30 23:42:32 2026] 127.0.0.1:49172 [200]: GET /api/chart.php?range=year +[Thu Jul 30 23:42:32 2026] 127.0.0.1:49172 Closing +[Thu Jul 30 23:43:31 2026] 127.0.0.1:56398 Accepted +[Thu Jul 30 23:43:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 23:43:32 2026] 127.0.0.1:56398 [200]: GET /api/stats.php +[Thu Jul 30 23:43:32 2026] 127.0.0.1:56398 Closing +[Thu Jul 30 23:43:32 2026] 127.0.0.1:56400 Accepted +[Thu Jul 30 23:43:32 2026] 127.0.0.1:56400 [200]: GET /api/chart.php?range=year +[Thu Jul 30 23:43:32 2026] 127.0.0.1:56400 Closing +[Thu Jul 30 23:44:31 2026] 127.0.0.1:52568 Accepted +[Thu Jul 30 23:44:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 23:44:32 2026] 127.0.0.1:52568 [200]: GET /api/stats.php +[Thu Jul 30 23:44:32 2026] 127.0.0.1:52568 Closing +[Thu Jul 30 23:44:32 2026] 127.0.0.1:52582 Accepted +[Thu Jul 30 23:44:32 2026] 127.0.0.1:52582 [200]: GET /api/chart.php?range=year +[Thu Jul 30 23:44:32 2026] 127.0.0.1:52582 Closing +[Thu Jul 30 23:45:31 2026] 127.0.0.1:47992 Accepted +[Thu Jul 30 23:45:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 23:45:32 2026] 127.0.0.1:47992 [200]: GET /api/stats.php +[Thu Jul 30 23:45:32 2026] 127.0.0.1:47992 Closing +[Thu Jul 30 23:45:32 2026] 127.0.0.1:47998 Accepted +[Thu Jul 30 23:45:32 2026] 127.0.0.1:47998 [200]: GET /api/chart.php?range=year +[Thu Jul 30 23:45:32 2026] 127.0.0.1:47998 Closing +[Thu Jul 30 23:46:31 2026] 127.0.0.1:32850 Accepted +[Thu Jul 30 23:46:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 23:46:32 2026] 127.0.0.1:32850 [200]: GET /api/stats.php +[Thu Jul 30 23:46:32 2026] 127.0.0.1:32850 Closing +[Thu Jul 30 23:46:32 2026] 127.0.0.1:32852 Accepted +[Thu Jul 30 23:46:32 2026] 127.0.0.1:32852 [200]: GET /api/chart.php?range=year +[Thu Jul 30 23:46:32 2026] 127.0.0.1:32852 Closing +[Thu Jul 30 23:47:31 2026] 127.0.0.1:40462 Accepted +[Thu Jul 30 23:47:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 23:47:32 2026] 127.0.0.1:40462 [200]: GET /api/stats.php +[Thu Jul 30 23:47:32 2026] 127.0.0.1:40462 Closing +[Thu Jul 30 23:47:32 2026] 127.0.0.1:40478 Accepted +[Thu Jul 30 23:47:32 2026] 127.0.0.1:40478 [200]: GET /api/chart.php?range=year +[Thu Jul 30 23:47:32 2026] 127.0.0.1:40478 Closing +[Thu Jul 30 23:48:31 2026] 127.0.0.1:40238 Accepted +[Thu Jul 30 23:48:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 23:48:32 2026] 127.0.0.1:40238 [200]: GET /api/stats.php +[Thu Jul 30 23:48:32 2026] 127.0.0.1:40238 Closing +[Thu Jul 30 23:48:32 2026] 127.0.0.1:40242 Accepted +[Thu Jul 30 23:48:32 2026] 127.0.0.1:40242 [200]: GET /api/chart.php?range=year +[Thu Jul 30 23:48:32 2026] 127.0.0.1:40242 Closing +[Thu Jul 30 23:49:31 2026] 127.0.0.1:33944 Accepted +[Thu Jul 30 23:49:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 23:49:32 2026] 127.0.0.1:33944 [200]: GET /api/stats.php +[Thu Jul 30 23:49:32 2026] 127.0.0.1:33944 Closing +[Thu Jul 30 23:49:32 2026] 127.0.0.1:33954 Accepted +[Thu Jul 30 23:49:32 2026] 127.0.0.1:33954 [200]: GET /api/chart.php?range=year +[Thu Jul 30 23:49:32 2026] 127.0.0.1:33954 Closing +[Thu Jul 30 23:50:31 2026] 127.0.0.1:45676 Accepted +[Thu Jul 30 23:50:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 23:50:32 2026] 127.0.0.1:45676 [200]: GET /api/stats.php +[Thu Jul 30 23:50:32 2026] 127.0.0.1:45676 Closing +[Thu Jul 30 23:50:32 2026] 127.0.0.1:45678 Accepted +[Thu Jul 30 23:50:32 2026] 127.0.0.1:45678 [200]: GET /api/chart.php?range=year +[Thu Jul 30 23:50:32 2026] 127.0.0.1:45678 Closing +[Thu Jul 30 23:51:31 2026] 127.0.0.1:40164 Accepted +[Thu Jul 30 23:51:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 23:51:32 2026] 127.0.0.1:40164 [200]: GET /api/stats.php +[Thu Jul 30 23:51:32 2026] 127.0.0.1:40164 Closing +[Thu Jul 30 23:51:32 2026] 127.0.0.1:40180 Accepted +[Thu Jul 30 23:51:32 2026] 127.0.0.1:40180 [200]: GET /api/chart.php?range=year +[Thu Jul 30 23:51:32 2026] 127.0.0.1:40180 Closing +[Thu Jul 30 23:52:31 2026] 127.0.0.1:59446 Accepted +[Thu Jul 30 23:52:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 23:52:32 2026] 127.0.0.1:59446 [200]: GET /api/stats.php +[Thu Jul 30 23:52:32 2026] 127.0.0.1:59446 Closing +[Thu Jul 30 23:52:32 2026] 127.0.0.1:59458 Accepted +[Thu Jul 30 23:52:32 2026] 127.0.0.1:59458 [200]: GET /api/chart.php?range=year +[Thu Jul 30 23:52:32 2026] 127.0.0.1:59458 Closing +[Thu Jul 30 23:53:31 2026] 127.0.0.1:56040 Accepted +[Thu Jul 30 23:53:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 23:53:32 2026] 127.0.0.1:56040 [200]: GET /api/stats.php +[Thu Jul 30 23:53:32 2026] 127.0.0.1:56040 Closing +[Thu Jul 30 23:53:32 2026] 127.0.0.1:56046 Accepted +[Thu Jul 30 23:53:32 2026] 127.0.0.1:56046 [200]: GET /api/chart.php?range=year +[Thu Jul 30 23:53:32 2026] 127.0.0.1:56046 Closing +[Thu Jul 30 23:54:31 2026] 127.0.0.1:53690 Accepted +[Thu Jul 30 23:54:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 23:54:32 2026] 127.0.0.1:53690 [200]: GET /api/stats.php +[Thu Jul 30 23:54:32 2026] 127.0.0.1:53690 Closing +[Thu Jul 30 23:54:32 2026] 127.0.0.1:53694 Accepted +[Thu Jul 30 23:54:32 2026] 127.0.0.1:53694 [200]: GET /api/chart.php?range=year +[Thu Jul 30 23:54:32 2026] 127.0.0.1:53694 Closing +[Thu Jul 30 23:55:31 2026] 127.0.0.1:54524 Accepted +[Thu Jul 30 23:55:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 23:55:32 2026] 127.0.0.1:54524 [200]: GET /api/stats.php +[Thu Jul 30 23:55:32 2026] 127.0.0.1:54524 Closing +[Thu Jul 30 23:55:32 2026] 127.0.0.1:54530 Accepted +[Thu Jul 30 23:55:32 2026] 127.0.0.1:54530 [200]: GET /api/chart.php?range=year +[Thu Jul 30 23:55:32 2026] 127.0.0.1:54530 Closing +[Thu Jul 30 23:56:31 2026] 127.0.0.1:40290 Accepted +[Thu Jul 30 23:56:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 23:56:32 2026] 127.0.0.1:40290 [200]: GET /api/stats.php +[Thu Jul 30 23:56:32 2026] 127.0.0.1:40290 Closing +[Thu Jul 30 23:56:32 2026] 127.0.0.1:40306 Accepted +[Thu Jul 30 23:56:32 2026] 127.0.0.1:40306 [200]: GET /api/chart.php?range=year +[Thu Jul 30 23:56:32 2026] 127.0.0.1:40306 Closing +[Thu Jul 30 23:57:31 2026] 127.0.0.1:52868 Accepted +[Thu Jul 30 23:57:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 23:57:32 2026] 127.0.0.1:52868 [200]: GET /api/stats.php +[Thu Jul 30 23:57:32 2026] 127.0.0.1:52868 Closing +[Thu Jul 30 23:57:32 2026] 127.0.0.1:52878 Accepted +[Thu Jul 30 23:57:32 2026] 127.0.0.1:52878 [200]: GET /api/chart.php?range=year +[Thu Jul 30 23:57:32 2026] 127.0.0.1:52878 Closing +[Thu Jul 30 23:58:31 2026] 127.0.0.1:48538 Accepted +[Thu Jul 30 23:58:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 23:58:32 2026] 127.0.0.1:48538 [200]: GET /api/stats.php +[Thu Jul 30 23:58:32 2026] 127.0.0.1:48538 Closing +[Thu Jul 30 23:58:32 2026] 127.0.0.1:48554 Accepted +[Thu Jul 30 23:58:32 2026] 127.0.0.1:48554 [200]: GET /api/chart.php?range=year +[Thu Jul 30 23:58:32 2026] 127.0.0.1:48554 Closing +[Thu Jul 30 23:59:31 2026] 127.0.0.1:57284 Accepted +[Thu Jul 30 23:59:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Thu Jul 30 23:59:32 2026] 127.0.0.1:57284 [200]: GET /api/stats.php +[Thu Jul 30 23:59:32 2026] 127.0.0.1:57284 Closing +[Thu Jul 30 23:59:32 2026] 127.0.0.1:57290 Accepted +[Thu Jul 30 23:59:32 2026] 127.0.0.1:57290 [200]: GET /api/chart.php?range=year +[Thu Jul 30 23:59:32 2026] 127.0.0.1:57290 Closing +[Fri Jul 31 00:00:31 2026] 127.0.0.1:33416 Accepted +[Fri Jul 31 00:00:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 00:00:32 2026] 127.0.0.1:33416 [200]: GET /api/stats.php +[Fri Jul 31 00:00:32 2026] 127.0.0.1:33416 Closing +[Fri Jul 31 00:00:32 2026] 127.0.0.1:33424 Accepted +[Fri Jul 31 00:00:32 2026] 127.0.0.1:33424 [200]: GET /api/chart.php?range=year +[Fri Jul 31 00:00:32 2026] 127.0.0.1:33424 Closing +[Fri Jul 31 00:01:31 2026] 127.0.0.1:47404 Accepted +[Fri Jul 31 00:01:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 00:01:32 2026] 127.0.0.1:47404 [200]: GET /api/stats.php +[Fri Jul 31 00:01:32 2026] 127.0.0.1:47404 Closing +[Fri Jul 31 00:01:32 2026] 127.0.0.1:47410 Accepted +[Fri Jul 31 00:01:32 2026] 127.0.0.1:47410 [200]: GET /api/chart.php?range=year +[Fri Jul 31 00:01:32 2026] 127.0.0.1:47410 Closing +[Fri Jul 31 00:02:31 2026] 127.0.0.1:53076 Accepted +[Fri Jul 31 00:02:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 00:02:32 2026] 127.0.0.1:53076 [200]: GET /api/stats.php +[Fri Jul 31 00:02:32 2026] 127.0.0.1:53076 Closing +[Fri Jul 31 00:02:32 2026] 127.0.0.1:53080 Accepted +[Fri Jul 31 00:02:32 2026] 127.0.0.1:53080 [200]: GET /api/chart.php?range=year +[Fri Jul 31 00:02:32 2026] 127.0.0.1:53080 Closing +[Fri Jul 31 00:03:31 2026] 127.0.0.1:48072 Accepted +[Fri Jul 31 00:03:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 00:03:32 2026] 127.0.0.1:48072 [200]: GET /api/stats.php +[Fri Jul 31 00:03:32 2026] 127.0.0.1:48072 Closing +[Fri Jul 31 00:03:32 2026] 127.0.0.1:48088 Accepted +[Fri Jul 31 00:03:32 2026] 127.0.0.1:48088 [200]: GET /api/chart.php?range=year +[Fri Jul 31 00:03:32 2026] 127.0.0.1:48088 Closing +[Fri Jul 31 00:04:31 2026] 127.0.0.1:58908 Accepted +[Fri Jul 31 00:04:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 00:04:32 2026] 127.0.0.1:58908 [200]: GET /api/stats.php +[Fri Jul 31 00:04:32 2026] 127.0.0.1:58908 Closing +[Fri Jul 31 00:04:32 2026] 127.0.0.1:58922 Accepted +[Fri Jul 31 00:04:32 2026] 127.0.0.1:58922 [200]: GET /api/chart.php?range=year +[Fri Jul 31 00:04:32 2026] 127.0.0.1:58922 Closing +[Fri Jul 31 00:05:31 2026] 127.0.0.1:56476 Accepted +[Fri Jul 31 00:05:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 00:05:32 2026] 127.0.0.1:56476 [200]: GET /api/stats.php +[Fri Jul 31 00:05:32 2026] 127.0.0.1:56476 Closing +[Fri Jul 31 00:05:32 2026] 127.0.0.1:56478 Accepted +[Fri Jul 31 00:05:32 2026] 127.0.0.1:56478 [200]: GET /api/chart.php?range=year +[Fri Jul 31 00:05:32 2026] 127.0.0.1:56478 Closing +[Fri Jul 31 00:06:31 2026] 127.0.0.1:42916 Accepted +[Fri Jul 31 00:06:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 00:06:32 2026] 127.0.0.1:42916 [200]: GET /api/stats.php +[Fri Jul 31 00:06:32 2026] 127.0.0.1:42916 Closing +[Fri Jul 31 00:06:32 2026] 127.0.0.1:42922 Accepted +[Fri Jul 31 00:06:32 2026] 127.0.0.1:42922 [200]: GET /api/chart.php?range=year +[Fri Jul 31 00:06:32 2026] 127.0.0.1:42922 Closing +[Fri Jul 31 00:07:31 2026] 127.0.0.1:34384 Accepted +[Fri Jul 31 00:07:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 00:07:32 2026] 127.0.0.1:34384 [200]: GET /api/stats.php +[Fri Jul 31 00:07:32 2026] 127.0.0.1:34384 Closing +[Fri Jul 31 00:07:32 2026] 127.0.0.1:34388 Accepted +[Fri Jul 31 00:07:32 2026] 127.0.0.1:34388 [200]: GET /api/chart.php?range=year +[Fri Jul 31 00:07:32 2026] 127.0.0.1:34388 Closing +[Fri Jul 31 00:08:31 2026] 127.0.0.1:38402 Accepted +[Fri Jul 31 00:08:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 00:08:32 2026] 127.0.0.1:38402 [200]: GET /api/stats.php +[Fri Jul 31 00:08:32 2026] 127.0.0.1:38402 Closing +[Fri Jul 31 00:08:32 2026] 127.0.0.1:38416 Accepted +[Fri Jul 31 00:08:32 2026] 127.0.0.1:38416 [200]: GET /api/chart.php?range=year +[Fri Jul 31 00:08:32 2026] 127.0.0.1:38416 Closing +[Fri Jul 31 00:09:31 2026] 127.0.0.1:41392 Accepted +[Fri Jul 31 00:09:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 00:09:32 2026] 127.0.0.1:41392 [200]: GET /api/stats.php +[Fri Jul 31 00:09:32 2026] 127.0.0.1:41392 Closing +[Fri Jul 31 00:09:32 2026] 127.0.0.1:41404 Accepted +[Fri Jul 31 00:09:32 2026] 127.0.0.1:41404 [200]: GET /api/chart.php?range=year +[Fri Jul 31 00:09:32 2026] 127.0.0.1:41404 Closing +[Fri Jul 31 00:10:31 2026] 127.0.0.1:40982 Accepted +[Fri Jul 31 00:10:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 00:10:32 2026] 127.0.0.1:40982 [200]: GET /api/stats.php +[Fri Jul 31 00:10:32 2026] 127.0.0.1:40982 Closing +[Fri Jul 31 00:10:32 2026] 127.0.0.1:40992 Accepted +[Fri Jul 31 00:10:32 2026] 127.0.0.1:40992 [200]: GET /api/chart.php?range=year +[Fri Jul 31 00:10:32 2026] 127.0.0.1:40992 Closing +[Fri Jul 31 00:11:31 2026] 127.0.0.1:39760 Accepted +[Fri Jul 31 00:11:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 00:11:32 2026] 127.0.0.1:39760 [200]: GET /api/stats.php +[Fri Jul 31 00:11:32 2026] 127.0.0.1:39760 Closing +[Fri Jul 31 00:11:32 2026] 127.0.0.1:39764 Accepted +[Fri Jul 31 00:11:32 2026] 127.0.0.1:39764 [200]: GET /api/chart.php?range=year +[Fri Jul 31 00:11:32 2026] 127.0.0.1:39764 Closing +[Fri Jul 31 00:12:31 2026] 127.0.0.1:59976 Accepted +[Fri Jul 31 00:12:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 00:12:32 2026] 127.0.0.1:59976 [200]: GET /api/stats.php +[Fri Jul 31 00:12:32 2026] 127.0.0.1:59976 Closing +[Fri Jul 31 00:12:32 2026] 127.0.0.1:59984 Accepted +[Fri Jul 31 00:12:32 2026] 127.0.0.1:59984 [200]: GET /api/chart.php?range=year +[Fri Jul 31 00:12:32 2026] 127.0.0.1:59984 Closing +[Fri Jul 31 00:13:31 2026] 127.0.0.1:41610 Accepted +[Fri Jul 31 00:13:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 00:13:32 2026] 127.0.0.1:41610 [200]: GET /api/stats.php +[Fri Jul 31 00:13:32 2026] 127.0.0.1:41610 Closing +[Fri Jul 31 00:13:32 2026] 127.0.0.1:41618 Accepted +[Fri Jul 31 00:13:32 2026] 127.0.0.1:41618 [200]: GET /api/chart.php?range=year +[Fri Jul 31 00:13:32 2026] 127.0.0.1:41618 Closing +[Fri Jul 31 00:14:31 2026] 127.0.0.1:58088 Accepted +[Fri Jul 31 00:14:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 00:14:32 2026] 127.0.0.1:58088 [200]: GET /api/stats.php +[Fri Jul 31 00:14:32 2026] 127.0.0.1:58088 Closing +[Fri Jul 31 00:14:32 2026] 127.0.0.1:58104 Accepted +[Fri Jul 31 00:14:32 2026] 127.0.0.1:58104 [200]: GET /api/chart.php?range=year +[Fri Jul 31 00:14:32 2026] 127.0.0.1:58104 Closing +[Fri Jul 31 00:15:31 2026] 127.0.0.1:32976 Accepted +[Fri Jul 31 00:15:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 00:15:32 2026] 127.0.0.1:32976 [200]: GET /api/stats.php +[Fri Jul 31 00:15:32 2026] 127.0.0.1:32976 Closing +[Fri Jul 31 00:15:32 2026] 127.0.0.1:32992 Accepted +[Fri Jul 31 00:15:32 2026] 127.0.0.1:32992 [200]: GET /api/chart.php?range=year +[Fri Jul 31 00:15:32 2026] 127.0.0.1:32992 Closing +[Fri Jul 31 00:16:31 2026] 127.0.0.1:33398 Accepted +[Fri Jul 31 00:16:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 00:16:32 2026] 127.0.0.1:33398 [200]: GET /api/stats.php +[Fri Jul 31 00:16:32 2026] 127.0.0.1:33398 Closing +[Fri Jul 31 00:16:32 2026] 127.0.0.1:33404 Accepted +[Fri Jul 31 00:16:32 2026] 127.0.0.1:33404 [200]: GET /api/chart.php?range=year +[Fri Jul 31 00:16:32 2026] 127.0.0.1:33404 Closing +[Fri Jul 31 00:17:31 2026] 127.0.0.1:46532 Accepted +[Fri Jul 31 00:17:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 00:17:32 2026] 127.0.0.1:46532 [200]: GET /api/stats.php +[Fri Jul 31 00:17:32 2026] 127.0.0.1:46532 Closing +[Fri Jul 31 00:17:32 2026] 127.0.0.1:46538 Accepted +[Fri Jul 31 00:17:32 2026] 127.0.0.1:46538 [200]: GET /api/chart.php?range=year +[Fri Jul 31 00:17:32 2026] 127.0.0.1:46538 Closing +[Fri Jul 31 00:18:31 2026] 127.0.0.1:59426 Accepted +[Fri Jul 31 00:18:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 00:18:32 2026] 127.0.0.1:59426 [200]: GET /api/stats.php +[Fri Jul 31 00:18:32 2026] 127.0.0.1:59426 Closing +[Fri Jul 31 00:18:32 2026] 127.0.0.1:59442 Accepted +[Fri Jul 31 00:18:32 2026] 127.0.0.1:59442 [200]: GET /api/chart.php?range=year +[Fri Jul 31 00:18:32 2026] 127.0.0.1:59442 Closing +[Fri Jul 31 00:19:31 2026] 127.0.0.1:58340 Accepted +[Fri Jul 31 00:19:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 00:19:32 2026] 127.0.0.1:58340 [200]: GET /api/stats.php +[Fri Jul 31 00:19:32 2026] 127.0.0.1:58340 Closing +[Fri Jul 31 00:19:32 2026] 127.0.0.1:58350 Accepted +[Fri Jul 31 00:19:32 2026] 127.0.0.1:58350 [200]: GET /api/chart.php?range=year +[Fri Jul 31 00:19:32 2026] 127.0.0.1:58350 Closing +[Fri Jul 31 00:20:31 2026] 127.0.0.1:38530 Accepted +[Fri Jul 31 00:20:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 00:20:32 2026] 127.0.0.1:38530 [200]: GET /api/stats.php +[Fri Jul 31 00:20:32 2026] 127.0.0.1:38530 Closing +[Fri Jul 31 00:20:32 2026] 127.0.0.1:38538 Accepted +[Fri Jul 31 00:20:32 2026] 127.0.0.1:38538 [200]: GET /api/chart.php?range=year +[Fri Jul 31 00:20:32 2026] 127.0.0.1:38538 Closing +[Fri Jul 31 00:21:31 2026] 127.0.0.1:34546 Accepted +[Fri Jul 31 00:21:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 00:21:32 2026] 127.0.0.1:34546 [200]: GET /api/stats.php +[Fri Jul 31 00:21:32 2026] 127.0.0.1:34546 Closing +[Fri Jul 31 00:21:32 2026] 127.0.0.1:34556 Accepted +[Fri Jul 31 00:21:32 2026] 127.0.0.1:34556 [200]: GET /api/chart.php?range=year +[Fri Jul 31 00:21:32 2026] 127.0.0.1:34556 Closing +[Fri Jul 31 00:22:31 2026] 127.0.0.1:37260 Accepted +[Fri Jul 31 00:22:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 00:22:32 2026] 127.0.0.1:37260 [200]: GET /api/stats.php +[Fri Jul 31 00:22:32 2026] 127.0.0.1:37260 Closing +[Fri Jul 31 00:22:32 2026] 127.0.0.1:37270 Accepted +[Fri Jul 31 00:22:32 2026] 127.0.0.1:37270 [200]: GET /api/chart.php?range=year +[Fri Jul 31 00:22:32 2026] 127.0.0.1:37270 Closing +[Fri Jul 31 00:23:31 2026] 127.0.0.1:33440 Accepted +[Fri Jul 31 00:23:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 00:23:32 2026] 127.0.0.1:33440 [200]: GET /api/stats.php +[Fri Jul 31 00:23:32 2026] 127.0.0.1:33440 Closing +[Fri Jul 31 00:23:32 2026] 127.0.0.1:33456 Accepted +[Fri Jul 31 00:23:32 2026] 127.0.0.1:33456 [200]: GET /api/chart.php?range=year +[Fri Jul 31 00:23:32 2026] 127.0.0.1:33456 Closing +[Fri Jul 31 00:24:31 2026] 127.0.0.1:41980 Accepted +[Fri Jul 31 00:24:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 00:24:32 2026] 127.0.0.1:41980 [200]: GET /api/stats.php +[Fri Jul 31 00:24:32 2026] 127.0.0.1:41980 Closing +[Fri Jul 31 00:24:32 2026] 127.0.0.1:41986 Accepted +[Fri Jul 31 00:24:32 2026] 127.0.0.1:41986 [200]: GET /api/chart.php?range=year +[Fri Jul 31 00:24:32 2026] 127.0.0.1:41986 Closing +[Fri Jul 31 00:25:31 2026] 127.0.0.1:52812 Accepted +[Fri Jul 31 00:25:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 00:25:32 2026] 127.0.0.1:52812 [200]: GET /api/stats.php +[Fri Jul 31 00:25:32 2026] 127.0.0.1:52812 Closing +[Fri Jul 31 00:25:32 2026] 127.0.0.1:52824 Accepted +[Fri Jul 31 00:25:32 2026] 127.0.0.1:52824 [200]: GET /api/chart.php?range=year +[Fri Jul 31 00:25:32 2026] 127.0.0.1:52824 Closing +[Fri Jul 31 00:26:31 2026] 127.0.0.1:37802 Accepted +[Fri Jul 31 00:26:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 00:26:32 2026] 127.0.0.1:37802 [200]: GET /api/stats.php +[Fri Jul 31 00:26:32 2026] 127.0.0.1:37802 Closing +[Fri Jul 31 00:26:32 2026] 127.0.0.1:37806 Accepted +[Fri Jul 31 00:26:32 2026] 127.0.0.1:37806 [200]: GET /api/chart.php?range=year +[Fri Jul 31 00:26:32 2026] 127.0.0.1:37806 Closing +[Fri Jul 31 00:27:31 2026] 127.0.0.1:36516 Accepted +[Fri Jul 31 00:27:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 00:27:32 2026] 127.0.0.1:36516 [200]: GET /api/stats.php +[Fri Jul 31 00:27:32 2026] 127.0.0.1:36516 Closing +[Fri Jul 31 00:27:32 2026] 127.0.0.1:36528 Accepted +[Fri Jul 31 00:27:32 2026] 127.0.0.1:36528 [200]: GET /api/chart.php?range=year +[Fri Jul 31 00:27:32 2026] 127.0.0.1:36528 Closing +[Fri Jul 31 00:28:31 2026] 127.0.0.1:53820 Accepted +[Fri Jul 31 00:28:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 00:28:32 2026] 127.0.0.1:53820 [200]: GET /api/stats.php +[Fri Jul 31 00:28:32 2026] 127.0.0.1:53820 Closing +[Fri Jul 31 00:28:32 2026] 127.0.0.1:53834 Accepted +[Fri Jul 31 00:28:32 2026] 127.0.0.1:53834 [200]: GET /api/chart.php?range=year +[Fri Jul 31 00:28:32 2026] 127.0.0.1:53834 Closing +[Fri Jul 31 00:29:31 2026] 127.0.0.1:46054 Accepted +[Fri Jul 31 00:29:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 00:29:32 2026] 127.0.0.1:46054 [200]: GET /api/stats.php +[Fri Jul 31 00:29:32 2026] 127.0.0.1:46054 Closing +[Fri Jul 31 00:29:32 2026] 127.0.0.1:46064 Accepted +[Fri Jul 31 00:29:32 2026] 127.0.0.1:46064 [200]: GET /api/chart.php?range=year +[Fri Jul 31 00:29:32 2026] 127.0.0.1:46064 Closing +[Fri Jul 31 00:30:31 2026] 127.0.0.1:50068 Accepted +[Fri Jul 31 00:30:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 00:30:32 2026] 127.0.0.1:50068 [200]: GET /api/stats.php +[Fri Jul 31 00:30:32 2026] 127.0.0.1:50068 Closing +[Fri Jul 31 00:30:32 2026] 127.0.0.1:50070 Accepted +[Fri Jul 31 00:30:32 2026] 127.0.0.1:50070 [200]: GET /api/chart.php?range=year +[Fri Jul 31 00:30:32 2026] 127.0.0.1:50070 Closing +[Fri Jul 31 00:31:31 2026] 127.0.0.1:51078 Accepted +[Fri Jul 31 00:31:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 00:31:32 2026] 127.0.0.1:51078 [200]: GET /api/stats.php +[Fri Jul 31 00:31:32 2026] 127.0.0.1:51078 Closing +[Fri Jul 31 00:31:32 2026] 127.0.0.1:51082 Accepted +[Fri Jul 31 00:31:32 2026] 127.0.0.1:51082 [200]: GET /api/chart.php?range=year +[Fri Jul 31 00:31:32 2026] 127.0.0.1:51082 Closing +[Fri Jul 31 00:32:31 2026] 127.0.0.1:42608 Accepted +[Fri Jul 31 00:32:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 00:32:32 2026] 127.0.0.1:42608 [200]: GET /api/stats.php +[Fri Jul 31 00:32:32 2026] 127.0.0.1:42608 Closing +[Fri Jul 31 00:32:32 2026] 127.0.0.1:42624 Accepted +[Fri Jul 31 00:32:32 2026] 127.0.0.1:42624 [200]: GET /api/chart.php?range=year +[Fri Jul 31 00:32:32 2026] 127.0.0.1:42624 Closing +[Fri Jul 31 00:33:31 2026] 127.0.0.1:37354 Accepted +[Fri Jul 31 00:33:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 00:33:32 2026] 127.0.0.1:37354 [200]: GET /api/stats.php +[Fri Jul 31 00:33:32 2026] 127.0.0.1:37354 Closing +[Fri Jul 31 00:33:32 2026] 127.0.0.1:37366 Accepted +[Fri Jul 31 00:33:32 2026] 127.0.0.1:37366 [200]: GET /api/chart.php?range=year +[Fri Jul 31 00:33:32 2026] 127.0.0.1:37366 Closing +[Fri Jul 31 00:34:31 2026] 127.0.0.1:43648 Accepted +[Fri Jul 31 00:34:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 00:34:32 2026] 127.0.0.1:43648 [200]: GET /api/stats.php +[Fri Jul 31 00:34:32 2026] 127.0.0.1:43648 Closing +[Fri Jul 31 00:34:32 2026] 127.0.0.1:43664 Accepted +[Fri Jul 31 00:34:32 2026] 127.0.0.1:43664 [200]: GET /api/chart.php?range=year +[Fri Jul 31 00:34:32 2026] 127.0.0.1:43664 Closing +[Fri Jul 31 00:35:31 2026] 127.0.0.1:38900 Accepted +[Fri Jul 31 00:35:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 00:35:32 2026] 127.0.0.1:38900 [200]: GET /api/stats.php +[Fri Jul 31 00:35:32 2026] 127.0.0.1:38900 Closing +[Fri Jul 31 00:35:32 2026] 127.0.0.1:38916 Accepted +[Fri Jul 31 00:35:32 2026] 127.0.0.1:38916 [200]: GET /api/chart.php?range=year +[Fri Jul 31 00:35:32 2026] 127.0.0.1:38916 Closing +[Fri Jul 31 00:36:31 2026] 127.0.0.1:47788 Accepted +[Fri Jul 31 00:36:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 00:36:32 2026] 127.0.0.1:47788 [200]: GET /api/stats.php +[Fri Jul 31 00:36:32 2026] 127.0.0.1:47788 Closing +[Fri Jul 31 00:36:32 2026] 127.0.0.1:47790 Accepted +[Fri Jul 31 00:36:32 2026] 127.0.0.1:47790 [200]: GET /api/chart.php?range=year +[Fri Jul 31 00:36:32 2026] 127.0.0.1:47790 Closing +[Fri Jul 31 00:37:31 2026] 127.0.0.1:39186 Accepted +[Fri Jul 31 00:37:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 00:37:32 2026] 127.0.0.1:39186 [200]: GET /api/stats.php +[Fri Jul 31 00:37:32 2026] 127.0.0.1:39186 Closing +[Fri Jul 31 00:37:32 2026] 127.0.0.1:39198 Accepted +[Fri Jul 31 00:37:32 2026] 127.0.0.1:39198 [200]: GET /api/chart.php?range=year +[Fri Jul 31 00:37:32 2026] 127.0.0.1:39198 Closing +[Fri Jul 31 00:38:31 2026] 127.0.0.1:55946 Accepted +[Fri Jul 31 00:38:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 00:38:32 2026] 127.0.0.1:55946 [200]: GET /api/stats.php +[Fri Jul 31 00:38:32 2026] 127.0.0.1:55946 Closing +[Fri Jul 31 00:38:32 2026] 127.0.0.1:55954 Accepted +[Fri Jul 31 00:38:32 2026] 127.0.0.1:55954 [200]: GET /api/chart.php?range=year +[Fri Jul 31 00:38:32 2026] 127.0.0.1:55954 Closing +[Fri Jul 31 00:39:31 2026] 127.0.0.1:55694 Accepted +[Fri Jul 31 00:39:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 00:39:32 2026] 127.0.0.1:55694 [200]: GET /api/stats.php +[Fri Jul 31 00:39:32 2026] 127.0.0.1:55694 Closing +[Fri Jul 31 00:39:32 2026] 127.0.0.1:55698 Accepted +[Fri Jul 31 00:39:32 2026] 127.0.0.1:55698 [200]: GET /api/chart.php?range=year +[Fri Jul 31 00:39:32 2026] 127.0.0.1:55698 Closing +[Fri Jul 31 00:40:31 2026] 127.0.0.1:48296 Accepted +[Fri Jul 31 00:40:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 00:40:32 2026] 127.0.0.1:48296 [200]: GET /api/stats.php +[Fri Jul 31 00:40:32 2026] 127.0.0.1:48296 Closing +[Fri Jul 31 00:40:32 2026] 127.0.0.1:48298 Accepted +[Fri Jul 31 00:40:32 2026] 127.0.0.1:48298 [200]: GET /api/chart.php?range=year +[Fri Jul 31 00:40:32 2026] 127.0.0.1:48298 Closing +[Fri Jul 31 00:41:31 2026] 127.0.0.1:52996 Accepted +[Fri Jul 31 00:41:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 00:41:32 2026] 127.0.0.1:52996 [200]: GET /api/stats.php +[Fri Jul 31 00:41:32 2026] 127.0.0.1:52996 Closing +[Fri Jul 31 00:41:32 2026] 127.0.0.1:53006 Accepted +[Fri Jul 31 00:41:32 2026] 127.0.0.1:53006 [200]: GET /api/chart.php?range=year +[Fri Jul 31 00:41:32 2026] 127.0.0.1:53006 Closing +[Fri Jul 31 00:42:31 2026] 127.0.0.1:56106 Accepted +[Fri Jul 31 00:42:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 00:42:32 2026] 127.0.0.1:56106 [200]: GET /api/stats.php +[Fri Jul 31 00:42:32 2026] 127.0.0.1:56106 Closing +[Fri Jul 31 00:42:32 2026] 127.0.0.1:56112 Accepted +[Fri Jul 31 00:42:32 2026] 127.0.0.1:56112 [200]: GET /api/chart.php?range=year +[Fri Jul 31 00:42:32 2026] 127.0.0.1:56112 Closing +[Fri Jul 31 00:43:31 2026] 127.0.0.1:51224 Accepted +[Fri Jul 31 00:43:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 00:43:32 2026] 127.0.0.1:51224 [200]: GET /api/stats.php +[Fri Jul 31 00:43:32 2026] 127.0.0.1:51224 Closing +[Fri Jul 31 00:43:32 2026] 127.0.0.1:51228 Accepted +[Fri Jul 31 00:43:32 2026] 127.0.0.1:51228 [200]: GET /api/chart.php?range=year +[Fri Jul 31 00:43:32 2026] 127.0.0.1:51228 Closing +[Fri Jul 31 00:44:31 2026] 127.0.0.1:52152 Accepted +[Fri Jul 31 00:44:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 00:44:32 2026] 127.0.0.1:52152 [200]: GET /api/stats.php +[Fri Jul 31 00:44:32 2026] 127.0.0.1:52152 Closing +[Fri Jul 31 00:44:32 2026] 127.0.0.1:52168 Accepted +[Fri Jul 31 00:44:32 2026] 127.0.0.1:52168 [200]: GET /api/chart.php?range=year +[Fri Jul 31 00:44:32 2026] 127.0.0.1:52168 Closing +[Fri Jul 31 00:45:31 2026] 127.0.0.1:50032 Accepted +[Fri Jul 31 00:45:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 00:45:32 2026] 127.0.0.1:50032 [200]: GET /api/stats.php +[Fri Jul 31 00:45:32 2026] 127.0.0.1:50032 Closing +[Fri Jul 31 00:45:32 2026] 127.0.0.1:50038 Accepted +[Fri Jul 31 00:45:32 2026] 127.0.0.1:50038 [200]: GET /api/chart.php?range=year +[Fri Jul 31 00:45:32 2026] 127.0.0.1:50038 Closing +[Fri Jul 31 00:46:31 2026] 127.0.0.1:41130 Accepted +[Fri Jul 31 00:46:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 00:46:32 2026] 127.0.0.1:41130 [200]: GET /api/stats.php +[Fri Jul 31 00:46:32 2026] 127.0.0.1:41130 Closing +[Fri Jul 31 00:46:32 2026] 127.0.0.1:41142 Accepted +[Fri Jul 31 00:46:32 2026] 127.0.0.1:41142 [200]: GET /api/chart.php?range=year +[Fri Jul 31 00:46:32 2026] 127.0.0.1:41142 Closing +[Fri Jul 31 00:47:31 2026] 127.0.0.1:35098 Accepted +[Fri Jul 31 00:47:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 00:47:32 2026] 127.0.0.1:35098 [200]: GET /api/stats.php +[Fri Jul 31 00:47:32 2026] 127.0.0.1:35098 Closing +[Fri Jul 31 00:47:32 2026] 127.0.0.1:35114 Accepted +[Fri Jul 31 00:47:32 2026] 127.0.0.1:35114 [200]: GET /api/chart.php?range=year +[Fri Jul 31 00:47:32 2026] 127.0.0.1:35114 Closing +[Fri Jul 31 00:48:31 2026] 127.0.0.1:42010 Accepted +[Fri Jul 31 00:48:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 00:48:32 2026] 127.0.0.1:42010 [200]: GET /api/stats.php +[Fri Jul 31 00:48:32 2026] 127.0.0.1:42010 Closing +[Fri Jul 31 00:48:32 2026] 127.0.0.1:42012 Accepted +[Fri Jul 31 00:48:32 2026] 127.0.0.1:42012 [200]: GET /api/chart.php?range=year +[Fri Jul 31 00:48:32 2026] 127.0.0.1:42012 Closing +[Fri Jul 31 00:49:31 2026] 127.0.0.1:42896 Accepted +[Fri Jul 31 00:49:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 00:49:32 2026] 127.0.0.1:42896 [200]: GET /api/stats.php +[Fri Jul 31 00:49:32 2026] 127.0.0.1:42896 Closing +[Fri Jul 31 00:49:32 2026] 127.0.0.1:42910 Accepted +[Fri Jul 31 00:49:32 2026] 127.0.0.1:42910 [200]: GET /api/chart.php?range=year +[Fri Jul 31 00:49:32 2026] 127.0.0.1:42910 Closing +[Fri Jul 31 00:50:31 2026] 127.0.0.1:41750 Accepted +[Fri Jul 31 00:50:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 00:50:32 2026] 127.0.0.1:41750 [200]: GET /api/stats.php +[Fri Jul 31 00:50:32 2026] 127.0.0.1:41750 Closing +[Fri Jul 31 00:50:32 2026] 127.0.0.1:41758 Accepted +[Fri Jul 31 00:50:32 2026] 127.0.0.1:41758 [200]: GET /api/chart.php?range=year +[Fri Jul 31 00:50:32 2026] 127.0.0.1:41758 Closing +[Fri Jul 31 00:51:31 2026] 127.0.0.1:50508 Accepted +[Fri Jul 31 00:51:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 00:51:32 2026] 127.0.0.1:50508 [200]: GET /api/stats.php +[Fri Jul 31 00:51:32 2026] 127.0.0.1:50508 Closing +[Fri Jul 31 00:51:32 2026] 127.0.0.1:50520 Accepted +[Fri Jul 31 00:51:32 2026] 127.0.0.1:50520 [200]: GET /api/chart.php?range=year +[Fri Jul 31 00:51:32 2026] 127.0.0.1:50520 Closing +[Fri Jul 31 00:52:31 2026] 127.0.0.1:56036 Accepted +[Fri Jul 31 00:52:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 00:52:32 2026] 127.0.0.1:56036 [200]: GET /api/stats.php +[Fri Jul 31 00:52:32 2026] 127.0.0.1:56036 Closing +[Fri Jul 31 00:52:32 2026] 127.0.0.1:56044 Accepted +[Fri Jul 31 00:52:32 2026] 127.0.0.1:56044 [200]: GET /api/chart.php?range=year +[Fri Jul 31 00:52:32 2026] 127.0.0.1:56044 Closing +[Fri Jul 31 00:53:31 2026] 127.0.0.1:52966 Accepted +[Fri Jul 31 00:53:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 00:53:32 2026] 127.0.0.1:52966 [200]: GET /api/stats.php +[Fri Jul 31 00:53:32 2026] 127.0.0.1:52966 Closing +[Fri Jul 31 00:53:32 2026] 127.0.0.1:52976 Accepted +[Fri Jul 31 00:53:32 2026] 127.0.0.1:52976 [200]: GET /api/chart.php?range=year +[Fri Jul 31 00:53:32 2026] 127.0.0.1:52976 Closing +[Fri Jul 31 00:54:31 2026] 127.0.0.1:46328 Accepted +[Fri Jul 31 00:54:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 00:54:32 2026] 127.0.0.1:46328 [200]: GET /api/stats.php +[Fri Jul 31 00:54:32 2026] 127.0.0.1:46328 Closing +[Fri Jul 31 00:54:32 2026] 127.0.0.1:46340 Accepted +[Fri Jul 31 00:54:32 2026] 127.0.0.1:46340 [200]: GET /api/chart.php?range=year +[Fri Jul 31 00:54:32 2026] 127.0.0.1:46340 Closing +[Fri Jul 31 00:55:31 2026] 127.0.0.1:46076 Accepted +[Fri Jul 31 00:55:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 00:55:32 2026] 127.0.0.1:46076 [200]: GET /api/stats.php +[Fri Jul 31 00:55:32 2026] 127.0.0.1:46076 Closing +[Fri Jul 31 00:55:32 2026] 127.0.0.1:46092 Accepted +[Fri Jul 31 00:55:32 2026] 127.0.0.1:46092 [200]: GET /api/chart.php?range=year +[Fri Jul 31 00:55:32 2026] 127.0.0.1:46092 Closing +[Fri Jul 31 00:56:31 2026] 127.0.0.1:60806 Accepted +[Fri Jul 31 00:56:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 00:56:32 2026] 127.0.0.1:60806 [200]: GET /api/stats.php +[Fri Jul 31 00:56:32 2026] 127.0.0.1:60806 Closing +[Fri Jul 31 00:56:32 2026] 127.0.0.1:60822 Accepted +[Fri Jul 31 00:56:32 2026] 127.0.0.1:60822 [200]: GET /api/chart.php?range=year +[Fri Jul 31 00:56:32 2026] 127.0.0.1:60822 Closing +[Fri Jul 31 00:57:31 2026] 127.0.0.1:57662 Accepted +[Fri Jul 31 00:57:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 00:57:32 2026] 127.0.0.1:57662 [200]: GET /api/stats.php +[Fri Jul 31 00:57:32 2026] 127.0.0.1:57662 Closing +[Fri Jul 31 00:57:32 2026] 127.0.0.1:57676 Accepted +[Fri Jul 31 00:57:32 2026] 127.0.0.1:57676 [200]: GET /api/chart.php?range=year +[Fri Jul 31 00:57:32 2026] 127.0.0.1:57676 Closing +[Fri Jul 31 00:58:31 2026] 127.0.0.1:57304 Accepted +[Fri Jul 31 00:58:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 00:58:32 2026] 127.0.0.1:57304 [200]: GET /api/stats.php +[Fri Jul 31 00:58:32 2026] 127.0.0.1:57304 Closing +[Fri Jul 31 00:58:32 2026] 127.0.0.1:57316 Accepted +[Fri Jul 31 00:58:32 2026] 127.0.0.1:57316 [200]: GET /api/chart.php?range=year +[Fri Jul 31 00:58:32 2026] 127.0.0.1:57316 Closing +[Fri Jul 31 00:59:31 2026] 127.0.0.1:40804 Accepted +[Fri Jul 31 00:59:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 00:59:32 2026] 127.0.0.1:40804 [200]: GET /api/stats.php +[Fri Jul 31 00:59:32 2026] 127.0.0.1:40804 Closing +[Fri Jul 31 00:59:32 2026] 127.0.0.1:40816 Accepted +[Fri Jul 31 00:59:32 2026] 127.0.0.1:40816 [200]: GET /api/chart.php?range=year +[Fri Jul 31 00:59:32 2026] 127.0.0.1:40816 Closing +[Fri Jul 31 01:00:31 2026] 127.0.0.1:58474 Accepted +[Fri Jul 31 01:00:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 01:00:32 2026] 127.0.0.1:58474 [200]: GET /api/stats.php +[Fri Jul 31 01:00:32 2026] 127.0.0.1:58474 Closing +[Fri Jul 31 01:00:32 2026] 127.0.0.1:58478 Accepted +[Fri Jul 31 01:00:32 2026] 127.0.0.1:58478 [200]: GET /api/chart.php?range=year +[Fri Jul 31 01:00:32 2026] 127.0.0.1:58478 Closing +[Fri Jul 31 01:01:31 2026] 127.0.0.1:41288 Accepted +[Fri Jul 31 01:01:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 01:01:32 2026] 127.0.0.1:41288 [200]: GET /api/stats.php +[Fri Jul 31 01:01:32 2026] 127.0.0.1:41288 Closing +[Fri Jul 31 01:01:32 2026] 127.0.0.1:41298 Accepted +[Fri Jul 31 01:01:32 2026] 127.0.0.1:41298 [200]: GET /api/chart.php?range=year +[Fri Jul 31 01:01:32 2026] 127.0.0.1:41298 Closing +[Fri Jul 31 01:02:31 2026] 127.0.0.1:37016 Accepted +[Fri Jul 31 01:02:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 01:02:32 2026] 127.0.0.1:37016 [200]: GET /api/stats.php +[Fri Jul 31 01:02:32 2026] 127.0.0.1:37016 Closing +[Fri Jul 31 01:02:32 2026] 127.0.0.1:37028 Accepted +[Fri Jul 31 01:02:32 2026] 127.0.0.1:37028 [200]: GET /api/chart.php?range=year +[Fri Jul 31 01:02:32 2026] 127.0.0.1:37028 Closing +[Fri Jul 31 01:03:31 2026] 127.0.0.1:42792 Accepted +[Fri Jul 31 01:03:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 01:03:32 2026] 127.0.0.1:42792 [200]: GET /api/stats.php +[Fri Jul 31 01:03:32 2026] 127.0.0.1:42792 Closing +[Fri Jul 31 01:03:32 2026] 127.0.0.1:42798 Accepted +[Fri Jul 31 01:03:32 2026] 127.0.0.1:42798 [200]: GET /api/chart.php?range=year +[Fri Jul 31 01:03:32 2026] 127.0.0.1:42798 Closing +[Fri Jul 31 01:04:31 2026] 127.0.0.1:52942 Accepted +[Fri Jul 31 01:04:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 01:04:32 2026] 127.0.0.1:52942 [200]: GET /api/stats.php +[Fri Jul 31 01:04:32 2026] 127.0.0.1:52942 Closing +[Fri Jul 31 01:04:32 2026] 127.0.0.1:52958 Accepted +[Fri Jul 31 01:04:32 2026] 127.0.0.1:52958 [200]: GET /api/chart.php?range=year +[Fri Jul 31 01:04:32 2026] 127.0.0.1:52958 Closing +[Fri Jul 31 01:05:31 2026] 127.0.0.1:45182 Accepted +[Fri Jul 31 01:05:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 01:05:32 2026] 127.0.0.1:45182 [200]: GET /api/stats.php +[Fri Jul 31 01:05:32 2026] 127.0.0.1:45182 Closing +[Fri Jul 31 01:05:32 2026] 127.0.0.1:45192 Accepted +[Fri Jul 31 01:05:32 2026] 127.0.0.1:45192 [200]: GET /api/chart.php?range=year +[Fri Jul 31 01:05:32 2026] 127.0.0.1:45192 Closing +[Fri Jul 31 01:06:31 2026] 127.0.0.1:56088 Accepted +[Fri Jul 31 01:06:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 01:06:32 2026] 127.0.0.1:56088 [200]: GET /api/stats.php +[Fri Jul 31 01:06:32 2026] 127.0.0.1:56088 Closing +[Fri Jul 31 01:06:32 2026] 127.0.0.1:56092 Accepted +[Fri Jul 31 01:06:32 2026] 127.0.0.1:56092 [200]: GET /api/chart.php?range=year +[Fri Jul 31 01:06:32 2026] 127.0.0.1:56092 Closing +[Fri Jul 31 01:07:31 2026] 127.0.0.1:35864 Accepted +[Fri Jul 31 01:07:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 01:07:32 2026] 127.0.0.1:35864 [200]: GET /api/stats.php +[Fri Jul 31 01:07:32 2026] 127.0.0.1:35864 Closing +[Fri Jul 31 01:07:32 2026] 127.0.0.1:35866 Accepted +[Fri Jul 31 01:07:32 2026] 127.0.0.1:35866 [200]: GET /api/chart.php?range=year +[Fri Jul 31 01:07:32 2026] 127.0.0.1:35866 Closing +[Fri Jul 31 01:08:31 2026] 127.0.0.1:50450 Accepted +[Fri Jul 31 01:08:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 01:08:32 2026] 127.0.0.1:50450 [200]: GET /api/stats.php +[Fri Jul 31 01:08:32 2026] 127.0.0.1:50450 Closing +[Fri Jul 31 01:08:32 2026] 127.0.0.1:50464 Accepted +[Fri Jul 31 01:08:32 2026] 127.0.0.1:50464 [200]: GET /api/chart.php?range=year +[Fri Jul 31 01:08:32 2026] 127.0.0.1:50464 Closing +[Fri Jul 31 01:09:31 2026] 127.0.0.1:43680 Accepted +[Fri Jul 31 01:09:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 01:09:32 2026] 127.0.0.1:43680 [200]: GET /api/stats.php +[Fri Jul 31 01:09:32 2026] 127.0.0.1:43680 Closing +[Fri Jul 31 01:09:32 2026] 127.0.0.1:43682 Accepted +[Fri Jul 31 01:09:32 2026] 127.0.0.1:43682 [200]: GET /api/chart.php?range=year +[Fri Jul 31 01:09:32 2026] 127.0.0.1:43682 Closing +[Fri Jul 31 01:10:31 2026] 127.0.0.1:34048 Accepted +[Fri Jul 31 01:10:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 01:10:32 2026] 127.0.0.1:34048 [200]: GET /api/stats.php +[Fri Jul 31 01:10:32 2026] 127.0.0.1:34048 Closing +[Fri Jul 31 01:10:32 2026] 127.0.0.1:34054 Accepted +[Fri Jul 31 01:10:32 2026] 127.0.0.1:34054 [200]: GET /api/chart.php?range=year +[Fri Jul 31 01:10:32 2026] 127.0.0.1:34054 Closing +[Fri Jul 31 01:11:31 2026] 127.0.0.1:53610 Accepted +[Fri Jul 31 01:11:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 01:11:32 2026] 127.0.0.1:53610 [200]: GET /api/stats.php +[Fri Jul 31 01:11:32 2026] 127.0.0.1:53610 Closing +[Fri Jul 31 01:11:32 2026] 127.0.0.1:53620 Accepted +[Fri Jul 31 01:11:32 2026] 127.0.0.1:53620 [200]: GET /api/chart.php?range=year +[Fri Jul 31 01:11:32 2026] 127.0.0.1:53620 Closing +[Fri Jul 31 01:12:31 2026] 127.0.0.1:48400 Accepted +[Fri Jul 31 01:12:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 01:12:32 2026] 127.0.0.1:48400 [200]: GET /api/stats.php +[Fri Jul 31 01:12:32 2026] 127.0.0.1:48400 Closing +[Fri Jul 31 01:12:32 2026] 127.0.0.1:48410 Accepted +[Fri Jul 31 01:12:32 2026] 127.0.0.1:48410 [200]: GET /api/chart.php?range=year +[Fri Jul 31 01:12:32 2026] 127.0.0.1:48410 Closing +[Fri Jul 31 01:13:31 2026] 127.0.0.1:33936 Accepted +[Fri Jul 31 01:13:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 01:13:32 2026] 127.0.0.1:33936 [200]: GET /api/stats.php +[Fri Jul 31 01:13:32 2026] 127.0.0.1:33936 Closing +[Fri Jul 31 01:13:32 2026] 127.0.0.1:33946 Accepted +[Fri Jul 31 01:13:32 2026] 127.0.0.1:33946 [200]: GET /api/chart.php?range=year +[Fri Jul 31 01:13:32 2026] 127.0.0.1:33946 Closing +[Fri Jul 31 01:14:31 2026] 127.0.0.1:55404 Accepted +[Fri Jul 31 01:14:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 01:14:32 2026] 127.0.0.1:55404 [200]: GET /api/stats.php +[Fri Jul 31 01:14:32 2026] 127.0.0.1:55404 Closing +[Fri Jul 31 01:14:32 2026] 127.0.0.1:55412 Accepted +[Fri Jul 31 01:14:32 2026] 127.0.0.1:55412 [200]: GET /api/chart.php?range=year +[Fri Jul 31 01:14:32 2026] 127.0.0.1:55412 Closing +[Fri Jul 31 01:15:31 2026] 127.0.0.1:59070 Accepted +[Fri Jul 31 01:15:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 01:15:32 2026] 127.0.0.1:59070 [200]: GET /api/stats.php +[Fri Jul 31 01:15:32 2026] 127.0.0.1:59070 Closing +[Fri Jul 31 01:15:32 2026] 127.0.0.1:59080 Accepted +[Fri Jul 31 01:15:32 2026] 127.0.0.1:59080 [200]: GET /api/chart.php?range=year +[Fri Jul 31 01:15:32 2026] 127.0.0.1:59080 Closing +[Fri Jul 31 01:16:31 2026] 127.0.0.1:35222 Accepted +[Fri Jul 31 01:16:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 01:16:32 2026] 127.0.0.1:35222 [200]: GET /api/stats.php +[Fri Jul 31 01:16:32 2026] 127.0.0.1:35222 Closing +[Fri Jul 31 01:16:32 2026] 127.0.0.1:35232 Accepted +[Fri Jul 31 01:16:32 2026] 127.0.0.1:35232 [200]: GET /api/chart.php?range=year +[Fri Jul 31 01:16:32 2026] 127.0.0.1:35232 Closing +[Fri Jul 31 01:17:31 2026] 127.0.0.1:38208 Accepted +[Fri Jul 31 01:17:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 01:17:32 2026] 127.0.0.1:38208 [200]: GET /api/stats.php +[Fri Jul 31 01:17:32 2026] 127.0.0.1:38208 Closing +[Fri Jul 31 01:17:32 2026] 127.0.0.1:38224 Accepted +[Fri Jul 31 01:17:32 2026] 127.0.0.1:38224 [200]: GET /api/chart.php?range=year +[Fri Jul 31 01:17:32 2026] 127.0.0.1:38224 Closing +[Fri Jul 31 01:18:31 2026] 127.0.0.1:34158 Accepted +[Fri Jul 31 01:18:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 01:18:32 2026] 127.0.0.1:34158 [200]: GET /api/stats.php +[Fri Jul 31 01:18:32 2026] 127.0.0.1:34158 Closing +[Fri Jul 31 01:18:32 2026] 127.0.0.1:34162 Accepted +[Fri Jul 31 01:18:32 2026] 127.0.0.1:34162 [200]: GET /api/chart.php?range=year +[Fri Jul 31 01:18:32 2026] 127.0.0.1:34162 Closing +[Fri Jul 31 01:19:31 2026] 127.0.0.1:52842 Accepted +[Fri Jul 31 01:19:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 01:19:32 2026] 127.0.0.1:52842 [200]: GET /api/stats.php +[Fri Jul 31 01:19:32 2026] 127.0.0.1:52842 Closing +[Fri Jul 31 01:19:32 2026] 127.0.0.1:52852 Accepted +[Fri Jul 31 01:19:32 2026] 127.0.0.1:52852 [200]: GET /api/chart.php?range=year +[Fri Jul 31 01:19:32 2026] 127.0.0.1:52852 Closing +[Fri Jul 31 01:20:31 2026] 127.0.0.1:46862 Accepted +[Fri Jul 31 01:20:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 01:20:32 2026] 127.0.0.1:46862 [200]: GET /api/stats.php +[Fri Jul 31 01:20:32 2026] 127.0.0.1:46862 Closing +[Fri Jul 31 01:20:32 2026] 127.0.0.1:46876 Accepted +[Fri Jul 31 01:20:32 2026] 127.0.0.1:46876 [200]: GET /api/chart.php?range=year +[Fri Jul 31 01:20:32 2026] 127.0.0.1:46876 Closing +[Fri Jul 31 01:21:31 2026] 127.0.0.1:35578 Accepted +[Fri Jul 31 01:21:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 01:21:31 2026] 127.0.0.1:35578 [200]: GET /api/stats.php +[Fri Jul 31 01:21:31 2026] 127.0.0.1:35578 Closing +[Fri Jul 31 01:21:31 2026] 127.0.0.1:35580 Accepted +[Fri Jul 31 01:21:31 2026] 127.0.0.1:35580 [200]: GET /api/chart.php?range=year +[Fri Jul 31 01:21:31 2026] 127.0.0.1:35580 Closing +[Fri Jul 31 01:22:31 2026] 127.0.0.1:45950 Accepted +[Fri Jul 31 01:22:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 01:22:31 2026] 127.0.0.1:45950 [200]: GET /api/stats.php +[Fri Jul 31 01:22:31 2026] 127.0.0.1:45950 Closing +[Fri Jul 31 01:22:31 2026] 127.0.0.1:45960 Accepted +[Fri Jul 31 01:22:31 2026] 127.0.0.1:45960 [200]: GET /api/chart.php?range=year +[Fri Jul 31 01:22:31 2026] 127.0.0.1:45960 Closing +[Fri Jul 31 01:23:31 2026] 127.0.0.1:50424 Accepted +[Fri Jul 31 01:23:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 01:23:31 2026] 127.0.0.1:50424 [200]: GET /api/stats.php +[Fri Jul 31 01:23:31 2026] 127.0.0.1:50424 Closing +[Fri Jul 31 01:23:31 2026] 127.0.0.1:50426 Accepted +[Fri Jul 31 01:23:31 2026] 127.0.0.1:50426 [200]: GET /api/chart.php?range=year +[Fri Jul 31 01:23:31 2026] 127.0.0.1:50426 Closing +[Fri Jul 31 01:24:31 2026] 127.0.0.1:54746 Accepted +[Fri Jul 31 01:24:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 01:24:31 2026] 127.0.0.1:54746 [200]: GET /api/stats.php +[Fri Jul 31 01:24:31 2026] 127.0.0.1:54746 Closing +[Fri Jul 31 01:24:31 2026] 127.0.0.1:54752 Accepted +[Fri Jul 31 01:24:31 2026] 127.0.0.1:54752 [200]: GET /api/chart.php?range=year +[Fri Jul 31 01:24:31 2026] 127.0.0.1:54752 Closing +[Fri Jul 31 01:25:31 2026] 127.0.0.1:41076 Accepted +[Fri Jul 31 01:25:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 01:25:31 2026] 127.0.0.1:41076 [200]: GET /api/stats.php +[Fri Jul 31 01:25:31 2026] 127.0.0.1:41076 Closing +[Fri Jul 31 01:25:31 2026] 127.0.0.1:41080 Accepted +[Fri Jul 31 01:25:31 2026] 127.0.0.1:41080 [200]: GET /api/chart.php?range=year +[Fri Jul 31 01:25:31 2026] 127.0.0.1:41080 Closing +[Fri Jul 31 01:26:31 2026] 127.0.0.1:33462 Accepted +[Fri Jul 31 01:26:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 01:26:31 2026] 127.0.0.1:33462 [200]: GET /api/stats.php +[Fri Jul 31 01:26:31 2026] 127.0.0.1:33462 Closing +[Fri Jul 31 01:26:31 2026] 127.0.0.1:33474 Accepted +[Fri Jul 31 01:26:31 2026] 127.0.0.1:33474 [200]: GET /api/chart.php?range=year +[Fri Jul 31 01:26:31 2026] 127.0.0.1:33474 Closing +[Fri Jul 31 01:27:31 2026] 127.0.0.1:51644 Accepted +[Fri Jul 31 01:27:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 01:27:31 2026] 127.0.0.1:51644 [200]: GET /api/stats.php +[Fri Jul 31 01:27:31 2026] 127.0.0.1:51644 Closing +[Fri Jul 31 01:27:31 2026] 127.0.0.1:51650 Accepted +[Fri Jul 31 01:27:31 2026] 127.0.0.1:51650 [200]: GET /api/chart.php?range=year +[Fri Jul 31 01:27:31 2026] 127.0.0.1:51650 Closing +[Fri Jul 31 01:28:31 2026] 127.0.0.1:33274 Accepted +[Fri Jul 31 01:28:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 01:28:31 2026] 127.0.0.1:33274 [200]: GET /api/stats.php +[Fri Jul 31 01:28:31 2026] 127.0.0.1:33274 Closing +[Fri Jul 31 01:28:31 2026] 127.0.0.1:33290 Accepted +[Fri Jul 31 01:28:31 2026] 127.0.0.1:33290 [200]: GET /api/chart.php?range=year +[Fri Jul 31 01:28:31 2026] 127.0.0.1:33290 Closing +[Fri Jul 31 01:29:31 2026] 127.0.0.1:56506 Accepted +[Fri Jul 31 01:29:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 01:29:31 2026] 127.0.0.1:56506 [200]: GET /api/stats.php +[Fri Jul 31 01:29:31 2026] 127.0.0.1:56506 Closing +[Fri Jul 31 01:29:31 2026] 127.0.0.1:56510 Accepted +[Fri Jul 31 01:29:31 2026] 127.0.0.1:56510 [200]: GET /api/chart.php?range=year +[Fri Jul 31 01:29:31 2026] 127.0.0.1:56510 Closing +[Fri Jul 31 01:30:31 2026] 127.0.0.1:50848 Accepted +[Fri Jul 31 01:30:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 01:30:31 2026] 127.0.0.1:50848 [200]: GET /api/stats.php +[Fri Jul 31 01:30:31 2026] 127.0.0.1:50848 Closing +[Fri Jul 31 01:30:31 2026] 127.0.0.1:50862 Accepted +[Fri Jul 31 01:30:31 2026] 127.0.0.1:50862 [200]: GET /api/chart.php?range=year +[Fri Jul 31 01:30:31 2026] 127.0.0.1:50862 Closing +[Fri Jul 31 01:31:31 2026] 127.0.0.1:54676 Accepted +[Fri Jul 31 01:31:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 01:31:31 2026] 127.0.0.1:54676 [200]: GET /api/stats.php +[Fri Jul 31 01:31:31 2026] 127.0.0.1:54676 Closing +[Fri Jul 31 01:31:31 2026] 127.0.0.1:54692 Accepted +[Fri Jul 31 01:31:31 2026] 127.0.0.1:54692 [200]: GET /api/chart.php?range=year +[Fri Jul 31 01:31:31 2026] 127.0.0.1:54692 Closing +[Fri Jul 31 01:32:31 2026] 127.0.0.1:56790 Accepted +[Fri Jul 31 01:32:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 01:32:31 2026] 127.0.0.1:56790 [200]: GET /api/stats.php +[Fri Jul 31 01:32:31 2026] 127.0.0.1:56790 Closing +[Fri Jul 31 01:32:31 2026] 127.0.0.1:56804 Accepted +[Fri Jul 31 01:32:31 2026] 127.0.0.1:56804 [200]: GET /api/chart.php?range=year +[Fri Jul 31 01:32:31 2026] 127.0.0.1:56804 Closing +[Fri Jul 31 01:33:31 2026] 127.0.0.1:48624 Accepted +[Fri Jul 31 01:33:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 01:33:31 2026] 127.0.0.1:48624 [200]: GET /api/stats.php +[Fri Jul 31 01:33:31 2026] 127.0.0.1:48624 Closing +[Fri Jul 31 01:33:31 2026] 127.0.0.1:48628 Accepted +[Fri Jul 31 01:33:31 2026] 127.0.0.1:48628 [200]: GET /api/chart.php?range=year +[Fri Jul 31 01:33:31 2026] 127.0.0.1:48628 Closing +[Fri Jul 31 01:34:31 2026] 127.0.0.1:51196 Accepted +[Fri Jul 31 01:34:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 01:34:31 2026] 127.0.0.1:51196 [200]: GET /api/stats.php +[Fri Jul 31 01:34:31 2026] 127.0.0.1:51196 Closing +[Fri Jul 31 01:34:31 2026] 127.0.0.1:51208 Accepted +[Fri Jul 31 01:34:31 2026] 127.0.0.1:51208 [200]: GET /api/chart.php?range=year +[Fri Jul 31 01:34:31 2026] 127.0.0.1:51208 Closing +[Fri Jul 31 01:35:31 2026] 127.0.0.1:34354 Accepted +[Fri Jul 31 01:35:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 01:35:31 2026] 127.0.0.1:34354 [200]: GET /api/stats.php +[Fri Jul 31 01:35:31 2026] 127.0.0.1:34354 Closing +[Fri Jul 31 01:35:31 2026] 127.0.0.1:34358 Accepted +[Fri Jul 31 01:35:31 2026] 127.0.0.1:34358 [200]: GET /api/chart.php?range=year +[Fri Jul 31 01:35:31 2026] 127.0.0.1:34358 Closing +[Fri Jul 31 01:36:31 2026] 127.0.0.1:34116 Accepted +[Fri Jul 31 01:36:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 01:36:31 2026] 127.0.0.1:34116 [200]: GET /api/stats.php +[Fri Jul 31 01:36:31 2026] 127.0.0.1:34116 Closing +[Fri Jul 31 01:36:31 2026] 127.0.0.1:34122 Accepted +[Fri Jul 31 01:36:31 2026] 127.0.0.1:34122 [200]: GET /api/chart.php?range=year +[Fri Jul 31 01:36:31 2026] 127.0.0.1:34122 Closing +[Fri Jul 31 01:37:31 2026] 127.0.0.1:49972 Accepted +[Fri Jul 31 01:37:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 01:37:31 2026] 127.0.0.1:49972 [200]: GET /api/stats.php +[Fri Jul 31 01:37:31 2026] 127.0.0.1:49972 Closing +[Fri Jul 31 01:37:31 2026] 127.0.0.1:49974 Accepted +[Fri Jul 31 01:37:31 2026] 127.0.0.1:49974 [200]: GET /api/chart.php?range=year +[Fri Jul 31 01:37:31 2026] 127.0.0.1:49974 Closing +[Fri Jul 31 01:38:31 2026] 127.0.0.1:59262 Accepted +[Fri Jul 31 01:38:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 01:38:31 2026] 127.0.0.1:59262 [200]: GET /api/stats.php +[Fri Jul 31 01:38:31 2026] 127.0.0.1:59262 Closing +[Fri Jul 31 01:38:31 2026] 127.0.0.1:59266 Accepted +[Fri Jul 31 01:38:31 2026] 127.0.0.1:59266 [200]: GET /api/chart.php?range=year +[Fri Jul 31 01:38:31 2026] 127.0.0.1:59266 Closing +[Fri Jul 31 01:39:31 2026] 127.0.0.1:47426 Accepted +[Fri Jul 31 01:39:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 01:39:31 2026] 127.0.0.1:47426 [200]: GET /api/stats.php +[Fri Jul 31 01:39:31 2026] 127.0.0.1:47426 Closing +[Fri Jul 31 01:39:31 2026] 127.0.0.1:47430 Accepted +[Fri Jul 31 01:39:31 2026] 127.0.0.1:47430 [200]: GET /api/chart.php?range=year +[Fri Jul 31 01:39:31 2026] 127.0.0.1:47430 Closing +[Fri Jul 31 01:40:31 2026] 127.0.0.1:32984 Accepted +[Fri Jul 31 01:40:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 01:40:31 2026] 127.0.0.1:32984 [200]: GET /api/stats.php +[Fri Jul 31 01:40:31 2026] 127.0.0.1:32984 Closing +[Fri Jul 31 01:40:31 2026] 127.0.0.1:32990 Accepted +[Fri Jul 31 01:40:31 2026] 127.0.0.1:32990 [200]: GET /api/chart.php?range=year +[Fri Jul 31 01:40:31 2026] 127.0.0.1:32990 Closing +[Fri Jul 31 01:41:31 2026] 127.0.0.1:60410 Accepted +[Fri Jul 31 01:41:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 01:41:31 2026] 127.0.0.1:60410 [200]: GET /api/stats.php +[Fri Jul 31 01:41:31 2026] 127.0.0.1:60410 Closing +[Fri Jul 31 01:41:31 2026] 127.0.0.1:60412 Accepted +[Fri Jul 31 01:41:31 2026] 127.0.0.1:60412 [200]: GET /api/chart.php?range=year +[Fri Jul 31 01:41:31 2026] 127.0.0.1:60412 Closing +[Fri Jul 31 01:42:31 2026] 127.0.0.1:33286 Accepted +[Fri Jul 31 01:42:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 01:42:31 2026] 127.0.0.1:33286 [200]: GET /api/stats.php +[Fri Jul 31 01:42:31 2026] 127.0.0.1:33286 Closing +[Fri Jul 31 01:42:31 2026] 127.0.0.1:33288 Accepted +[Fri Jul 31 01:42:31 2026] 127.0.0.1:33288 [200]: GET /api/chart.php?range=year +[Fri Jul 31 01:42:31 2026] 127.0.0.1:33288 Closing +[Fri Jul 31 01:43:31 2026] 127.0.0.1:34122 Accepted +[Fri Jul 31 01:43:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 01:43:31 2026] 127.0.0.1:34122 [200]: GET /api/stats.php +[Fri Jul 31 01:43:31 2026] 127.0.0.1:34122 Closing +[Fri Jul 31 01:43:31 2026] 127.0.0.1:34136 Accepted +[Fri Jul 31 01:43:31 2026] 127.0.0.1:34136 [200]: GET /api/chart.php?range=year +[Fri Jul 31 01:43:31 2026] 127.0.0.1:34136 Closing +[Fri Jul 31 01:44:31 2026] 127.0.0.1:42598 Accepted +[Fri Jul 31 01:44:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 01:44:31 2026] 127.0.0.1:42598 [200]: GET /api/stats.php +[Fri Jul 31 01:44:31 2026] 127.0.0.1:42598 Closing +[Fri Jul 31 01:44:31 2026] 127.0.0.1:42610 Accepted +[Fri Jul 31 01:44:31 2026] 127.0.0.1:42610 [200]: GET /api/chart.php?range=year +[Fri Jul 31 01:44:31 2026] 127.0.0.1:42610 Closing +[Fri Jul 31 01:45:31 2026] 127.0.0.1:56694 Accepted +[Fri Jul 31 01:45:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 01:45:31 2026] 127.0.0.1:56694 [200]: GET /api/stats.php +[Fri Jul 31 01:45:31 2026] 127.0.0.1:56694 Closing +[Fri Jul 31 01:45:31 2026] 127.0.0.1:56702 Accepted +[Fri Jul 31 01:45:31 2026] 127.0.0.1:56702 [200]: GET /api/chart.php?range=year +[Fri Jul 31 01:45:31 2026] 127.0.0.1:56702 Closing +[Fri Jul 31 01:46:31 2026] 127.0.0.1:52910 Accepted +[Fri Jul 31 01:46:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 01:46:31 2026] 127.0.0.1:52910 [200]: GET /api/stats.php +[Fri Jul 31 01:46:31 2026] 127.0.0.1:52910 Closing +[Fri Jul 31 01:46:31 2026] 127.0.0.1:52924 Accepted +[Fri Jul 31 01:46:31 2026] 127.0.0.1:52924 [200]: GET /api/chart.php?range=year +[Fri Jul 31 01:46:31 2026] 127.0.0.1:52924 Closing +[Fri Jul 31 01:47:31 2026] 127.0.0.1:40288 Accepted +[Fri Jul 31 01:47:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 01:47:31 2026] 127.0.0.1:40288 [200]: GET /api/stats.php +[Fri Jul 31 01:47:31 2026] 127.0.0.1:40288 Closing +[Fri Jul 31 01:47:31 2026] 127.0.0.1:40300 Accepted +[Fri Jul 31 01:47:31 2026] 127.0.0.1:40300 [200]: GET /api/chart.php?range=year +[Fri Jul 31 01:47:31 2026] 127.0.0.1:40300 Closing +[Fri Jul 31 01:48:31 2026] 127.0.0.1:53694 Accepted +[Fri Jul 31 01:48:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 01:48:31 2026] 127.0.0.1:53694 [200]: GET /api/stats.php +[Fri Jul 31 01:48:31 2026] 127.0.0.1:53694 Closing +[Fri Jul 31 01:48:31 2026] 127.0.0.1:53698 Accepted +[Fri Jul 31 01:48:31 2026] 127.0.0.1:53698 [200]: GET /api/chart.php?range=year +[Fri Jul 31 01:48:31 2026] 127.0.0.1:53698 Closing +[Fri Jul 31 01:49:31 2026] 127.0.0.1:54366 Accepted +[Fri Jul 31 01:49:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 01:49:31 2026] 127.0.0.1:54366 [200]: GET /api/stats.php +[Fri Jul 31 01:49:31 2026] 127.0.0.1:54366 Closing +[Fri Jul 31 01:49:31 2026] 127.0.0.1:54382 Accepted +[Fri Jul 31 01:49:31 2026] 127.0.0.1:54382 [200]: GET /api/chart.php?range=year +[Fri Jul 31 01:49:31 2026] 127.0.0.1:54382 Closing +[Fri Jul 31 01:50:31 2026] 127.0.0.1:37122 Accepted +[Fri Jul 31 01:50:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 01:50:31 2026] 127.0.0.1:37122 [200]: GET /api/stats.php +[Fri Jul 31 01:50:31 2026] 127.0.0.1:37122 Closing +[Fri Jul 31 01:50:31 2026] 127.0.0.1:37130 Accepted +[Fri Jul 31 01:50:31 2026] 127.0.0.1:37130 [200]: GET /api/chart.php?range=year +[Fri Jul 31 01:50:31 2026] 127.0.0.1:37130 Closing +[Fri Jul 31 01:51:31 2026] 127.0.0.1:47438 Accepted +[Fri Jul 31 01:51:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 01:51:31 2026] 127.0.0.1:47438 [200]: GET /api/stats.php +[Fri Jul 31 01:51:31 2026] 127.0.0.1:47438 Closing +[Fri Jul 31 01:51:31 2026] 127.0.0.1:47452 Accepted +[Fri Jul 31 01:51:31 2026] 127.0.0.1:47452 [200]: GET /api/chart.php?range=year +[Fri Jul 31 01:51:31 2026] 127.0.0.1:47452 Closing +[Fri Jul 31 01:52:31 2026] 127.0.0.1:49452 Accepted +[Fri Jul 31 01:52:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 01:52:31 2026] 127.0.0.1:49452 [200]: GET /api/stats.php +[Fri Jul 31 01:52:31 2026] 127.0.0.1:49452 Closing +[Fri Jul 31 01:52:31 2026] 127.0.0.1:49468 Accepted +[Fri Jul 31 01:52:31 2026] 127.0.0.1:49468 [200]: GET /api/chart.php?range=year +[Fri Jul 31 01:52:31 2026] 127.0.0.1:49468 Closing +[Fri Jul 31 01:53:31 2026] 127.0.0.1:39262 Accepted +[Fri Jul 31 01:53:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 01:53:31 2026] 127.0.0.1:39262 [200]: GET /api/stats.php +[Fri Jul 31 01:53:31 2026] 127.0.0.1:39262 Closing +[Fri Jul 31 01:53:31 2026] 127.0.0.1:39266 Accepted +[Fri Jul 31 01:53:31 2026] 127.0.0.1:39266 [200]: GET /api/chart.php?range=year +[Fri Jul 31 01:53:31 2026] 127.0.0.1:39266 Closing +[Fri Jul 31 01:54:31 2026] 127.0.0.1:38912 Accepted +[Fri Jul 31 01:54:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 01:54:31 2026] 127.0.0.1:38912 [200]: GET /api/stats.php +[Fri Jul 31 01:54:31 2026] 127.0.0.1:38912 Closing +[Fri Jul 31 01:54:31 2026] 127.0.0.1:38918 Accepted +[Fri Jul 31 01:54:31 2026] 127.0.0.1:38918 [200]: GET /api/chart.php?range=year +[Fri Jul 31 01:54:31 2026] 127.0.0.1:38918 Closing +[Fri Jul 31 01:55:31 2026] 127.0.0.1:40540 Accepted +[Fri Jul 31 01:55:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 01:55:31 2026] 127.0.0.1:40540 [200]: GET /api/stats.php +[Fri Jul 31 01:55:31 2026] 127.0.0.1:40540 Closing +[Fri Jul 31 01:55:31 2026] 127.0.0.1:40548 Accepted +[Fri Jul 31 01:55:31 2026] 127.0.0.1:40548 [200]: GET /api/chart.php?range=year +[Fri Jul 31 01:55:31 2026] 127.0.0.1:40548 Closing +[Fri Jul 31 01:56:31 2026] 127.0.0.1:43520 Accepted +[Fri Jul 31 01:56:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 01:56:31 2026] 127.0.0.1:43520 [200]: GET /api/stats.php +[Fri Jul 31 01:56:31 2026] 127.0.0.1:43520 Closing +[Fri Jul 31 01:56:31 2026] 127.0.0.1:43532 Accepted +[Fri Jul 31 01:56:31 2026] 127.0.0.1:43532 [200]: GET /api/chart.php?range=year +[Fri Jul 31 01:56:31 2026] 127.0.0.1:43532 Closing +[Fri Jul 31 01:57:31 2026] 127.0.0.1:59598 Accepted +[Fri Jul 31 01:57:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 01:57:31 2026] 127.0.0.1:59598 [200]: GET /api/stats.php +[Fri Jul 31 01:57:31 2026] 127.0.0.1:59598 Closing +[Fri Jul 31 01:57:31 2026] 127.0.0.1:59610 Accepted +[Fri Jul 31 01:57:31 2026] 127.0.0.1:59610 [200]: GET /api/chart.php?range=year +[Fri Jul 31 01:57:31 2026] 127.0.0.1:59610 Closing +[Fri Jul 31 01:58:31 2026] 127.0.0.1:59636 Accepted +[Fri Jul 31 01:58:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 01:58:31 2026] 127.0.0.1:59636 [200]: GET /api/stats.php +[Fri Jul 31 01:58:31 2026] 127.0.0.1:59636 Closing +[Fri Jul 31 01:58:31 2026] 127.0.0.1:59640 Accepted +[Fri Jul 31 01:58:31 2026] 127.0.0.1:59640 [200]: GET /api/chart.php?range=year +[Fri Jul 31 01:58:31 2026] 127.0.0.1:59640 Closing +[Fri Jul 31 01:59:31 2026] 127.0.0.1:41892 Accepted +[Fri Jul 31 01:59:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 01:59:31 2026] 127.0.0.1:41892 [200]: GET /api/stats.php +[Fri Jul 31 01:59:31 2026] 127.0.0.1:41892 Closing +[Fri Jul 31 01:59:31 2026] 127.0.0.1:41902 Accepted +[Fri Jul 31 01:59:31 2026] 127.0.0.1:41902 [200]: GET /api/chart.php?range=year +[Fri Jul 31 01:59:31 2026] 127.0.0.1:41902 Closing +[Fri Jul 31 02:00:31 2026] 127.0.0.1:50492 Accepted +[Fri Jul 31 02:00:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 02:00:31 2026] 127.0.0.1:50492 [200]: GET /api/stats.php +[Fri Jul 31 02:00:31 2026] 127.0.0.1:50492 Closing +[Fri Jul 31 02:00:31 2026] 127.0.0.1:50502 Accepted +[Fri Jul 31 02:00:31 2026] 127.0.0.1:50502 [200]: GET /api/chart.php?range=year +[Fri Jul 31 02:00:31 2026] 127.0.0.1:50502 Closing +[Fri Jul 31 02:01:31 2026] 127.0.0.1:45456 Accepted +[Fri Jul 31 02:01:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 02:01:31 2026] 127.0.0.1:45456 [200]: GET /api/stats.php +[Fri Jul 31 02:01:31 2026] 127.0.0.1:45456 Closing +[Fri Jul 31 02:01:31 2026] 127.0.0.1:45472 Accepted +[Fri Jul 31 02:01:31 2026] 127.0.0.1:45472 [200]: GET /api/chart.php?range=year +[Fri Jul 31 02:01:31 2026] 127.0.0.1:45472 Closing +[Fri Jul 31 02:02:31 2026] 127.0.0.1:51222 Accepted +[Fri Jul 31 02:02:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 02:02:31 2026] 127.0.0.1:51222 [200]: GET /api/stats.php +[Fri Jul 31 02:02:31 2026] 127.0.0.1:51222 Closing +[Fri Jul 31 02:02:31 2026] 127.0.0.1:51236 Accepted +[Fri Jul 31 02:02:31 2026] 127.0.0.1:51236 [200]: GET /api/chart.php?range=year +[Fri Jul 31 02:02:31 2026] 127.0.0.1:51236 Closing +[Fri Jul 31 02:03:31 2026] 127.0.0.1:51180 Accepted +[Fri Jul 31 02:03:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 02:03:31 2026] 127.0.0.1:51180 [200]: GET /api/stats.php +[Fri Jul 31 02:03:31 2026] 127.0.0.1:51180 Closing +[Fri Jul 31 02:03:31 2026] 127.0.0.1:51196 Accepted +[Fri Jul 31 02:03:31 2026] 127.0.0.1:51196 [200]: GET /api/chart.php?range=year +[Fri Jul 31 02:03:31 2026] 127.0.0.1:51196 Closing +[Fri Jul 31 02:04:31 2026] 127.0.0.1:50280 Accepted +[Fri Jul 31 02:04:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 02:04:31 2026] 127.0.0.1:50280 [200]: GET /api/stats.php +[Fri Jul 31 02:04:31 2026] 127.0.0.1:50280 Closing +[Fri Jul 31 02:04:31 2026] 127.0.0.1:50284 Accepted +[Fri Jul 31 02:04:31 2026] 127.0.0.1:50284 [200]: GET /api/chart.php?range=year +[Fri Jul 31 02:04:31 2026] 127.0.0.1:50284 Closing +[Fri Jul 31 02:05:31 2026] 127.0.0.1:36058 Accepted +[Fri Jul 31 02:05:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 02:05:31 2026] 127.0.0.1:36058 [200]: GET /api/stats.php +[Fri Jul 31 02:05:31 2026] 127.0.0.1:36058 Closing +[Fri Jul 31 02:05:31 2026] 127.0.0.1:36068 Accepted +[Fri Jul 31 02:05:31 2026] 127.0.0.1:36068 [200]: GET /api/chart.php?range=year +[Fri Jul 31 02:05:31 2026] 127.0.0.1:36068 Closing +[Fri Jul 31 02:06:31 2026] 127.0.0.1:47942 Accepted +[Fri Jul 31 02:06:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 02:06:31 2026] 127.0.0.1:47942 [200]: GET /api/stats.php +[Fri Jul 31 02:06:31 2026] 127.0.0.1:47942 Closing +[Fri Jul 31 02:06:31 2026] 127.0.0.1:47954 Accepted +[Fri Jul 31 02:06:31 2026] 127.0.0.1:47954 [200]: GET /api/chart.php?range=year +[Fri Jul 31 02:06:31 2026] 127.0.0.1:47954 Closing +[Fri Jul 31 02:07:31 2026] 127.0.0.1:34420 Accepted +[Fri Jul 31 02:07:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 02:07:31 2026] 127.0.0.1:34420 [200]: GET /api/stats.php +[Fri Jul 31 02:07:31 2026] 127.0.0.1:34420 Closing +[Fri Jul 31 02:07:31 2026] 127.0.0.1:34430 Accepted +[Fri Jul 31 02:07:31 2026] 127.0.0.1:34430 [200]: GET /api/chart.php?range=year +[Fri Jul 31 02:07:31 2026] 127.0.0.1:34430 Closing +[Fri Jul 31 02:08:31 2026] 127.0.0.1:54650 Accepted +[Fri Jul 31 02:08:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 02:08:31 2026] 127.0.0.1:54650 [200]: GET /api/stats.php +[Fri Jul 31 02:08:31 2026] 127.0.0.1:54650 Closing +[Fri Jul 31 02:08:31 2026] 127.0.0.1:54658 Accepted +[Fri Jul 31 02:08:31 2026] 127.0.0.1:54658 [200]: GET /api/chart.php?range=year +[Fri Jul 31 02:08:31 2026] 127.0.0.1:54658 Closing +[Fri Jul 31 02:09:31 2026] 127.0.0.1:52146 Accepted +[Fri Jul 31 02:09:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 02:09:31 2026] 127.0.0.1:52146 [200]: GET /api/stats.php +[Fri Jul 31 02:09:31 2026] 127.0.0.1:52146 Closing +[Fri Jul 31 02:09:31 2026] 127.0.0.1:52148 Accepted +[Fri Jul 31 02:09:31 2026] 127.0.0.1:52148 [200]: GET /api/chart.php?range=year +[Fri Jul 31 02:09:31 2026] 127.0.0.1:52148 Closing +[Fri Jul 31 02:10:31 2026] 127.0.0.1:48252 Accepted +[Fri Jul 31 02:10:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 02:10:31 2026] 127.0.0.1:48252 [200]: GET /api/stats.php +[Fri Jul 31 02:10:31 2026] 127.0.0.1:48252 Closing +[Fri Jul 31 02:10:31 2026] 127.0.0.1:48256 Accepted +[Fri Jul 31 02:10:31 2026] 127.0.0.1:48256 [200]: GET /api/chart.php?range=year +[Fri Jul 31 02:10:31 2026] 127.0.0.1:48256 Closing +[Fri Jul 31 02:11:31 2026] 127.0.0.1:58528 Accepted +[Fri Jul 31 02:11:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 02:11:31 2026] 127.0.0.1:58528 [200]: GET /api/stats.php +[Fri Jul 31 02:11:31 2026] 127.0.0.1:58528 Closing +[Fri Jul 31 02:11:31 2026] 127.0.0.1:58534 Accepted +[Fri Jul 31 02:11:31 2026] 127.0.0.1:58534 [200]: GET /api/chart.php?range=year +[Fri Jul 31 02:11:31 2026] 127.0.0.1:58534 Closing +[Fri Jul 31 02:12:31 2026] 127.0.0.1:49790 Accepted +[Fri Jul 31 02:12:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 02:12:31 2026] 127.0.0.1:49790 [200]: GET /api/stats.php +[Fri Jul 31 02:12:31 2026] 127.0.0.1:49790 Closing +[Fri Jul 31 02:12:31 2026] 127.0.0.1:49792 Accepted +[Fri Jul 31 02:12:31 2026] 127.0.0.1:49792 [200]: GET /api/chart.php?range=year +[Fri Jul 31 02:12:31 2026] 127.0.0.1:49792 Closing +[Fri Jul 31 02:13:31 2026] 127.0.0.1:47604 Accepted +[Fri Jul 31 02:13:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 02:13:31 2026] 127.0.0.1:47604 [200]: GET /api/stats.php +[Fri Jul 31 02:13:31 2026] 127.0.0.1:47604 Closing +[Fri Jul 31 02:13:31 2026] 127.0.0.1:47614 Accepted +[Fri Jul 31 02:13:31 2026] 127.0.0.1:47614 [200]: GET /api/chart.php?range=year +[Fri Jul 31 02:13:31 2026] 127.0.0.1:47614 Closing +[Fri Jul 31 02:14:31 2026] 127.0.0.1:58600 Accepted +[Fri Jul 31 02:14:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 02:14:31 2026] 127.0.0.1:58600 [200]: GET /api/stats.php +[Fri Jul 31 02:14:31 2026] 127.0.0.1:58600 Closing +[Fri Jul 31 02:14:31 2026] 127.0.0.1:58614 Accepted +[Fri Jul 31 02:14:31 2026] 127.0.0.1:58614 [200]: GET /api/chart.php?range=year +[Fri Jul 31 02:14:31 2026] 127.0.0.1:58614 Closing +[Fri Jul 31 02:15:31 2026] 127.0.0.1:57886 Accepted +[Fri Jul 31 02:15:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 02:15:31 2026] 127.0.0.1:57886 [200]: GET /api/stats.php +[Fri Jul 31 02:15:31 2026] 127.0.0.1:57886 Closing +[Fri Jul 31 02:15:31 2026] 127.0.0.1:57900 Accepted +[Fri Jul 31 02:15:31 2026] 127.0.0.1:57900 [200]: GET /api/chart.php?range=year +[Fri Jul 31 02:15:31 2026] 127.0.0.1:57900 Closing +[Fri Jul 31 02:16:31 2026] 127.0.0.1:52710 Accepted +[Fri Jul 31 02:16:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 02:16:31 2026] 127.0.0.1:52710 [200]: GET /api/stats.php +[Fri Jul 31 02:16:31 2026] 127.0.0.1:52710 Closing +[Fri Jul 31 02:16:31 2026] 127.0.0.1:52718 Accepted +[Fri Jul 31 02:16:31 2026] 127.0.0.1:52718 [200]: GET /api/chart.php?range=year +[Fri Jul 31 02:16:31 2026] 127.0.0.1:52718 Closing +[Fri Jul 31 02:17:31 2026] 127.0.0.1:52708 Accepted +[Fri Jul 31 02:17:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 02:17:31 2026] 127.0.0.1:52708 [200]: GET /api/stats.php +[Fri Jul 31 02:17:31 2026] 127.0.0.1:52708 Closing +[Fri Jul 31 02:17:31 2026] 127.0.0.1:52716 Accepted +[Fri Jul 31 02:17:31 2026] 127.0.0.1:52716 [200]: GET /api/chart.php?range=year +[Fri Jul 31 02:17:31 2026] 127.0.0.1:52716 Closing +[Fri Jul 31 02:18:31 2026] 127.0.0.1:37162 Accepted +[Fri Jul 31 02:18:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 02:18:31 2026] 127.0.0.1:37162 [200]: GET /api/stats.php +[Fri Jul 31 02:18:31 2026] 127.0.0.1:37162 Closing +[Fri Jul 31 02:18:31 2026] 127.0.0.1:37174 Accepted +[Fri Jul 31 02:18:31 2026] 127.0.0.1:37174 [200]: GET /api/chart.php?range=year +[Fri Jul 31 02:18:31 2026] 127.0.0.1:37174 Closing +[Fri Jul 31 02:19:31 2026] 127.0.0.1:49340 Accepted +[Fri Jul 31 02:19:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 02:19:31 2026] 127.0.0.1:49340 [200]: GET /api/stats.php +[Fri Jul 31 02:19:31 2026] 127.0.0.1:49340 Closing +[Fri Jul 31 02:19:31 2026] 127.0.0.1:49356 Accepted +[Fri Jul 31 02:19:31 2026] 127.0.0.1:49356 [200]: GET /api/chart.php?range=year +[Fri Jul 31 02:19:31 2026] 127.0.0.1:49356 Closing +[Fri Jul 31 02:20:31 2026] 127.0.0.1:58370 Accepted +[Fri Jul 31 02:20:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 02:20:31 2026] 127.0.0.1:58370 [200]: GET /api/stats.php +[Fri Jul 31 02:20:31 2026] 127.0.0.1:58370 Closing +[Fri Jul 31 02:20:31 2026] 127.0.0.1:58374 Accepted +[Fri Jul 31 02:20:31 2026] 127.0.0.1:58374 [200]: GET /api/chart.php?range=year +[Fri Jul 31 02:20:31 2026] 127.0.0.1:58374 Closing +[Fri Jul 31 02:21:31 2026] 127.0.0.1:41878 Accepted +[Fri Jul 31 02:21:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 02:21:31 2026] 127.0.0.1:41878 [200]: GET /api/stats.php +[Fri Jul 31 02:21:31 2026] 127.0.0.1:41878 Closing +[Fri Jul 31 02:21:31 2026] 127.0.0.1:41890 Accepted +[Fri Jul 31 02:21:31 2026] 127.0.0.1:41890 [200]: GET /api/chart.php?range=year +[Fri Jul 31 02:21:31 2026] 127.0.0.1:41890 Closing +[Fri Jul 31 02:22:31 2026] 127.0.0.1:57602 Accepted +[Fri Jul 31 02:22:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 02:22:31 2026] 127.0.0.1:57602 [200]: GET /api/stats.php +[Fri Jul 31 02:22:31 2026] 127.0.0.1:57602 Closing +[Fri Jul 31 02:22:31 2026] 127.0.0.1:57614 Accepted +[Fri Jul 31 02:22:31 2026] 127.0.0.1:57614 [200]: GET /api/chart.php?range=year +[Fri Jul 31 02:22:31 2026] 127.0.0.1:57614 Closing +[Fri Jul 31 02:23:31 2026] 127.0.0.1:35872 Accepted +[Fri Jul 31 02:23:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 02:23:31 2026] 127.0.0.1:35872 [200]: GET /api/stats.php +[Fri Jul 31 02:23:31 2026] 127.0.0.1:35872 Closing +[Fri Jul 31 02:23:31 2026] 127.0.0.1:35878 Accepted +[Fri Jul 31 02:23:31 2026] 127.0.0.1:35878 [200]: GET /api/chart.php?range=year +[Fri Jul 31 02:23:31 2026] 127.0.0.1:35878 Closing +[Fri Jul 31 02:24:31 2026] 127.0.0.1:42426 Accepted +[Fri Jul 31 02:24:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 02:24:31 2026] 127.0.0.1:42426 [200]: GET /api/stats.php +[Fri Jul 31 02:24:31 2026] 127.0.0.1:42426 Closing +[Fri Jul 31 02:24:31 2026] 127.0.0.1:42428 Accepted +[Fri Jul 31 02:24:31 2026] 127.0.0.1:42428 [200]: GET /api/chart.php?range=year +[Fri Jul 31 02:24:31 2026] 127.0.0.1:42428 Closing +[Fri Jul 31 02:25:31 2026] 127.0.0.1:56330 Accepted +[Fri Jul 31 02:25:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 02:25:31 2026] 127.0.0.1:56330 [200]: GET /api/stats.php +[Fri Jul 31 02:25:31 2026] 127.0.0.1:56330 Closing +[Fri Jul 31 02:25:31 2026] 127.0.0.1:56344 Accepted +[Fri Jul 31 02:25:31 2026] 127.0.0.1:56344 [200]: GET /api/chart.php?range=year +[Fri Jul 31 02:25:31 2026] 127.0.0.1:56344 Closing +[Fri Jul 31 02:26:31 2026] 127.0.0.1:35906 Accepted +[Fri Jul 31 02:26:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 02:26:31 2026] 127.0.0.1:35906 [200]: GET /api/stats.php +[Fri Jul 31 02:26:31 2026] 127.0.0.1:35906 Closing +[Fri Jul 31 02:26:31 2026] 127.0.0.1:35912 Accepted +[Fri Jul 31 02:26:31 2026] 127.0.0.1:35912 [200]: GET /api/chart.php?range=year +[Fri Jul 31 02:26:31 2026] 127.0.0.1:35912 Closing +[Fri Jul 31 02:27:31 2026] 127.0.0.1:51838 Accepted +[Fri Jul 31 02:27:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 02:27:31 2026] 127.0.0.1:51838 [200]: GET /api/stats.php +[Fri Jul 31 02:27:31 2026] 127.0.0.1:51838 Closing +[Fri Jul 31 02:27:31 2026] 127.0.0.1:51854 Accepted +[Fri Jul 31 02:27:31 2026] 127.0.0.1:51854 [200]: GET /api/chart.php?range=year +[Fri Jul 31 02:27:31 2026] 127.0.0.1:51854 Closing +[Fri Jul 31 02:28:31 2026] 127.0.0.1:48418 Accepted +[Fri Jul 31 02:28:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 02:28:31 2026] 127.0.0.1:48418 [200]: GET /api/stats.php +[Fri Jul 31 02:28:31 2026] 127.0.0.1:48418 Closing +[Fri Jul 31 02:28:31 2026] 127.0.0.1:48434 Accepted +[Fri Jul 31 02:28:31 2026] 127.0.0.1:48434 [200]: GET /api/chart.php?range=year +[Fri Jul 31 02:28:31 2026] 127.0.0.1:48434 Closing +[Fri Jul 31 02:29:31 2026] 127.0.0.1:52510 Accepted +[Fri Jul 31 02:29:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 02:29:31 2026] 127.0.0.1:52510 [200]: GET /api/stats.php +[Fri Jul 31 02:29:31 2026] 127.0.0.1:52510 Closing +[Fri Jul 31 02:29:31 2026] 127.0.0.1:52516 Accepted +[Fri Jul 31 02:29:31 2026] 127.0.0.1:52516 [200]: GET /api/chart.php?range=year +[Fri Jul 31 02:29:31 2026] 127.0.0.1:52516 Closing +[Fri Jul 31 02:30:31 2026] 127.0.0.1:56460 Accepted +[Fri Jul 31 02:30:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 02:30:31 2026] 127.0.0.1:56460 [200]: GET /api/stats.php +[Fri Jul 31 02:30:31 2026] 127.0.0.1:56460 Closing +[Fri Jul 31 02:30:31 2026] 127.0.0.1:56474 Accepted +[Fri Jul 31 02:30:31 2026] 127.0.0.1:56474 [200]: GET /api/chart.php?range=year +[Fri Jul 31 02:30:31 2026] 127.0.0.1:56474 Closing +[Fri Jul 31 02:31:31 2026] 127.0.0.1:52182 Accepted +[Fri Jul 31 02:31:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 02:31:31 2026] 127.0.0.1:52182 [200]: GET /api/stats.php +[Fri Jul 31 02:31:31 2026] 127.0.0.1:52182 Closing +[Fri Jul 31 02:31:31 2026] 127.0.0.1:52194 Accepted +[Fri Jul 31 02:31:31 2026] 127.0.0.1:52194 [200]: GET /api/chart.php?range=year +[Fri Jul 31 02:31:31 2026] 127.0.0.1:52194 Closing +[Fri Jul 31 02:32:31 2026] 127.0.0.1:44210 Accepted +[Fri Jul 31 02:32:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 02:32:31 2026] 127.0.0.1:44210 [200]: GET /api/stats.php +[Fri Jul 31 02:32:31 2026] 127.0.0.1:44210 Closing +[Fri Jul 31 02:32:31 2026] 127.0.0.1:44212 Accepted +[Fri Jul 31 02:32:31 2026] 127.0.0.1:44212 [200]: GET /api/chart.php?range=year +[Fri Jul 31 02:32:31 2026] 127.0.0.1:44212 Closing +[Fri Jul 31 02:33:31 2026] 127.0.0.1:59956 Accepted +[Fri Jul 31 02:33:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 02:33:31 2026] 127.0.0.1:59956 [200]: GET /api/stats.php +[Fri Jul 31 02:33:31 2026] 127.0.0.1:59956 Closing +[Fri Jul 31 02:33:31 2026] 127.0.0.1:59968 Accepted +[Fri Jul 31 02:33:31 2026] 127.0.0.1:59968 [200]: GET /api/chart.php?range=year +[Fri Jul 31 02:33:31 2026] 127.0.0.1:59968 Closing +[Fri Jul 31 02:34:31 2026] 127.0.0.1:38538 Accepted +[Fri Jul 31 02:34:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 02:34:31 2026] 127.0.0.1:38538 [200]: GET /api/stats.php +[Fri Jul 31 02:34:31 2026] 127.0.0.1:38538 Closing +[Fri Jul 31 02:34:31 2026] 127.0.0.1:38546 Accepted +[Fri Jul 31 02:34:31 2026] 127.0.0.1:38546 [200]: GET /api/chart.php?range=year +[Fri Jul 31 02:34:31 2026] 127.0.0.1:38546 Closing +[Fri Jul 31 02:35:31 2026] 127.0.0.1:41908 Accepted +[Fri Jul 31 02:35:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 02:35:31 2026] 127.0.0.1:41908 [200]: GET /api/stats.php +[Fri Jul 31 02:35:31 2026] 127.0.0.1:41908 Closing +[Fri Jul 31 02:35:31 2026] 127.0.0.1:41914 Accepted +[Fri Jul 31 02:35:31 2026] 127.0.0.1:41914 [200]: GET /api/chart.php?range=year +[Fri Jul 31 02:35:31 2026] 127.0.0.1:41914 Closing +[Fri Jul 31 02:36:31 2026] 127.0.0.1:56260 Accepted +[Fri Jul 31 02:36:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 02:36:31 2026] 127.0.0.1:56260 [200]: GET /api/stats.php +[Fri Jul 31 02:36:31 2026] 127.0.0.1:56260 Closing +[Fri Jul 31 02:36:31 2026] 127.0.0.1:56264 Accepted +[Fri Jul 31 02:36:31 2026] 127.0.0.1:56264 [200]: GET /api/chart.php?range=year +[Fri Jul 31 02:36:31 2026] 127.0.0.1:56264 Closing +[Fri Jul 31 02:37:31 2026] 127.0.0.1:41914 Accepted +[Fri Jul 31 02:37:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 02:37:31 2026] 127.0.0.1:41914 [200]: GET /api/stats.php +[Fri Jul 31 02:37:31 2026] 127.0.0.1:41914 Closing +[Fri Jul 31 02:37:31 2026] 127.0.0.1:41922 Accepted +[Fri Jul 31 02:37:31 2026] 127.0.0.1:41922 [200]: GET /api/chart.php?range=year +[Fri Jul 31 02:37:31 2026] 127.0.0.1:41922 Closing +[Fri Jul 31 02:38:31 2026] 127.0.0.1:55298 Accepted +[Fri Jul 31 02:38:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 02:38:31 2026] 127.0.0.1:55298 [200]: GET /api/stats.php +[Fri Jul 31 02:38:31 2026] 127.0.0.1:55298 Closing +[Fri Jul 31 02:38:31 2026] 127.0.0.1:55302 Accepted +[Fri Jul 31 02:38:31 2026] 127.0.0.1:55302 [200]: GET /api/chart.php?range=year +[Fri Jul 31 02:38:31 2026] 127.0.0.1:55302 Closing +[Fri Jul 31 02:39:31 2026] 127.0.0.1:55794 Accepted +[Fri Jul 31 02:39:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 02:39:31 2026] 127.0.0.1:55794 [200]: GET /api/stats.php +[Fri Jul 31 02:39:31 2026] 127.0.0.1:55794 Closing +[Fri Jul 31 02:39:31 2026] 127.0.0.1:55796 Accepted +[Fri Jul 31 02:39:31 2026] 127.0.0.1:55796 [200]: GET /api/chart.php?range=year +[Fri Jul 31 02:39:31 2026] 127.0.0.1:55796 Closing +[Fri Jul 31 02:40:31 2026] 127.0.0.1:36010 Accepted +[Fri Jul 31 02:40:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 02:40:31 2026] 127.0.0.1:36010 [200]: GET /api/stats.php +[Fri Jul 31 02:40:31 2026] 127.0.0.1:36010 Closing +[Fri Jul 31 02:40:31 2026] 127.0.0.1:36020 Accepted +[Fri Jul 31 02:40:31 2026] 127.0.0.1:36020 [200]: GET /api/chart.php?range=year +[Fri Jul 31 02:40:31 2026] 127.0.0.1:36020 Closing +[Fri Jul 31 02:41:31 2026] 127.0.0.1:53728 Accepted +[Fri Jul 31 02:41:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 02:41:31 2026] 127.0.0.1:53728 [200]: GET /api/stats.php +[Fri Jul 31 02:41:31 2026] 127.0.0.1:53728 Closing +[Fri Jul 31 02:41:31 2026] 127.0.0.1:53730 Accepted +[Fri Jul 31 02:41:31 2026] 127.0.0.1:53730 [200]: GET /api/chart.php?range=year +[Fri Jul 31 02:41:31 2026] 127.0.0.1:53730 Closing +[Fri Jul 31 02:42:31 2026] 127.0.0.1:49882 Accepted +[Fri Jul 31 02:42:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 02:42:31 2026] 127.0.0.1:49882 [200]: GET /api/stats.php +[Fri Jul 31 02:42:31 2026] 127.0.0.1:49882 Closing +[Fri Jul 31 02:42:31 2026] 127.0.0.1:49892 Accepted +[Fri Jul 31 02:42:31 2026] 127.0.0.1:49892 [200]: GET /api/chart.php?range=year +[Fri Jul 31 02:42:31 2026] 127.0.0.1:49892 Closing +[Fri Jul 31 02:43:31 2026] 127.0.0.1:58240 Accepted +[Fri Jul 31 02:43:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 02:43:31 2026] 127.0.0.1:58240 [200]: GET /api/stats.php +[Fri Jul 31 02:43:31 2026] 127.0.0.1:58240 Closing +[Fri Jul 31 02:43:31 2026] 127.0.0.1:58248 Accepted +[Fri Jul 31 02:43:31 2026] 127.0.0.1:58248 [200]: GET /api/chart.php?range=year +[Fri Jul 31 02:43:31 2026] 127.0.0.1:58248 Closing +[Fri Jul 31 02:44:31 2026] 127.0.0.1:45310 Accepted +[Fri Jul 31 02:44:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 02:44:31 2026] 127.0.0.1:45310 [200]: GET /api/stats.php +[Fri Jul 31 02:44:31 2026] 127.0.0.1:45310 Closing +[Fri Jul 31 02:44:31 2026] 127.0.0.1:45316 Accepted +[Fri Jul 31 02:44:31 2026] 127.0.0.1:45316 [200]: GET /api/chart.php?range=year +[Fri Jul 31 02:44:31 2026] 127.0.0.1:45316 Closing +[Fri Jul 31 02:45:31 2026] 127.0.0.1:40952 Accepted +[Fri Jul 31 02:45:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 02:45:31 2026] 127.0.0.1:40952 [200]: GET /api/stats.php +[Fri Jul 31 02:45:31 2026] 127.0.0.1:40952 Closing +[Fri Jul 31 02:45:31 2026] 127.0.0.1:40960 Accepted +[Fri Jul 31 02:45:31 2026] 127.0.0.1:40960 [200]: GET /api/chart.php?range=year +[Fri Jul 31 02:45:31 2026] 127.0.0.1:40960 Closing +[Fri Jul 31 02:46:31 2026] 127.0.0.1:40476 Accepted +[Fri Jul 31 02:46:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 02:46:31 2026] 127.0.0.1:40476 [200]: GET /api/stats.php +[Fri Jul 31 02:46:31 2026] 127.0.0.1:40476 Closing +[Fri Jul 31 02:46:31 2026] 127.0.0.1:40482 Accepted +[Fri Jul 31 02:46:31 2026] 127.0.0.1:40482 [200]: GET /api/chart.php?range=year +[Fri Jul 31 02:46:31 2026] 127.0.0.1:40482 Closing +[Fri Jul 31 02:47:31 2026] 127.0.0.1:52516 Accepted +[Fri Jul 31 02:47:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 02:47:31 2026] 127.0.0.1:52516 [200]: GET /api/stats.php +[Fri Jul 31 02:47:31 2026] 127.0.0.1:52516 Closing +[Fri Jul 31 02:47:31 2026] 127.0.0.1:52518 Accepted +[Fri Jul 31 02:47:31 2026] 127.0.0.1:52518 [200]: GET /api/chart.php?range=year +[Fri Jul 31 02:47:31 2026] 127.0.0.1:52518 Closing +[Fri Jul 31 02:48:31 2026] 127.0.0.1:45498 Accepted +[Fri Jul 31 02:48:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 02:48:31 2026] 127.0.0.1:45498 [200]: GET /api/stats.php +[Fri Jul 31 02:48:31 2026] 127.0.0.1:45498 Closing +[Fri Jul 31 02:48:31 2026] 127.0.0.1:45512 Accepted +[Fri Jul 31 02:48:31 2026] 127.0.0.1:45512 [200]: GET /api/chart.php?range=year +[Fri Jul 31 02:48:31 2026] 127.0.0.1:45512 Closing +[Fri Jul 31 02:49:31 2026] 127.0.0.1:57400 Accepted +[Fri Jul 31 02:49:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 02:49:31 2026] 127.0.0.1:57400 [200]: GET /api/stats.php +[Fri Jul 31 02:49:31 2026] 127.0.0.1:57400 Closing +[Fri Jul 31 02:49:31 2026] 127.0.0.1:57404 Accepted +[Fri Jul 31 02:49:31 2026] 127.0.0.1:57404 [200]: GET /api/chart.php?range=year +[Fri Jul 31 02:49:31 2026] 127.0.0.1:57404 Closing +[Fri Jul 31 02:50:31 2026] 127.0.0.1:56468 Accepted +[Fri Jul 31 02:50:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 02:50:31 2026] 127.0.0.1:56468 [200]: GET /api/stats.php +[Fri Jul 31 02:50:31 2026] 127.0.0.1:56468 Closing +[Fri Jul 31 02:50:31 2026] 127.0.0.1:56480 Accepted +[Fri Jul 31 02:50:31 2026] 127.0.0.1:56480 [200]: GET /api/chart.php?range=year +[Fri Jul 31 02:50:31 2026] 127.0.0.1:56480 Closing +[Fri Jul 31 02:51:31 2026] 127.0.0.1:43692 Accepted +[Fri Jul 31 02:51:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 02:51:31 2026] 127.0.0.1:43692 [200]: GET /api/stats.php +[Fri Jul 31 02:51:31 2026] 127.0.0.1:43692 Closing +[Fri Jul 31 02:51:31 2026] 127.0.0.1:43694 Accepted +[Fri Jul 31 02:51:31 2026] 127.0.0.1:43694 [200]: GET /api/chart.php?range=year +[Fri Jul 31 02:51:31 2026] 127.0.0.1:43694 Closing +[Fri Jul 31 02:52:31 2026] 127.0.0.1:49580 Accepted +[Fri Jul 31 02:52:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 02:52:31 2026] 127.0.0.1:49580 [200]: GET /api/stats.php +[Fri Jul 31 02:52:31 2026] 127.0.0.1:49580 Closing +[Fri Jul 31 02:52:31 2026] 127.0.0.1:49584 Accepted +[Fri Jul 31 02:52:31 2026] 127.0.0.1:49584 [200]: GET /api/chart.php?range=year +[Fri Jul 31 02:52:31 2026] 127.0.0.1:49584 Closing +[Fri Jul 31 02:53:31 2026] 127.0.0.1:36696 Accepted +[Fri Jul 31 02:53:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 02:53:31 2026] 127.0.0.1:36696 [200]: GET /api/stats.php +[Fri Jul 31 02:53:31 2026] 127.0.0.1:36696 Closing +[Fri Jul 31 02:53:31 2026] 127.0.0.1:36712 Accepted +[Fri Jul 31 02:53:31 2026] 127.0.0.1:36712 [200]: GET /api/chart.php?range=year +[Fri Jul 31 02:53:31 2026] 127.0.0.1:36712 Closing +[Fri Jul 31 02:54:31 2026] 127.0.0.1:35132 Accepted +[Fri Jul 31 02:54:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 02:54:31 2026] 127.0.0.1:35132 [200]: GET /api/stats.php +[Fri Jul 31 02:54:31 2026] 127.0.0.1:35132 Closing +[Fri Jul 31 02:54:31 2026] 127.0.0.1:35144 Accepted +[Fri Jul 31 02:54:31 2026] 127.0.0.1:35144 [200]: GET /api/chart.php?range=year +[Fri Jul 31 02:54:31 2026] 127.0.0.1:35144 Closing +[Fri Jul 31 02:55:31 2026] 127.0.0.1:59834 Accepted +[Fri Jul 31 02:55:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 02:55:31 2026] 127.0.0.1:59834 [200]: GET /api/stats.php +[Fri Jul 31 02:55:31 2026] 127.0.0.1:59834 Closing +[Fri Jul 31 02:55:31 2026] 127.0.0.1:59846 Accepted +[Fri Jul 31 02:55:31 2026] 127.0.0.1:59846 [200]: GET /api/chart.php?range=year +[Fri Jul 31 02:55:31 2026] 127.0.0.1:59846 Closing +[Fri Jul 31 02:56:31 2026] 127.0.0.1:51600 Accepted +[Fri Jul 31 02:56:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 02:56:31 2026] 127.0.0.1:51600 [200]: GET /api/stats.php +[Fri Jul 31 02:56:31 2026] 127.0.0.1:51600 Closing +[Fri Jul 31 02:56:31 2026] 127.0.0.1:51606 Accepted +[Fri Jul 31 02:56:31 2026] 127.0.0.1:51606 [200]: GET /api/chart.php?range=year +[Fri Jul 31 02:56:31 2026] 127.0.0.1:51606 Closing +[Fri Jul 31 02:57:31 2026] 127.0.0.1:56954 Accepted +[Fri Jul 31 02:57:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 02:57:31 2026] 127.0.0.1:56954 [200]: GET /api/stats.php +[Fri Jul 31 02:57:31 2026] 127.0.0.1:56954 Closing +[Fri Jul 31 02:57:31 2026] 127.0.0.1:56960 Accepted +[Fri Jul 31 02:57:31 2026] 127.0.0.1:56960 [200]: GET /api/chart.php?range=year +[Fri Jul 31 02:57:31 2026] 127.0.0.1:56960 Closing +[Fri Jul 31 02:58:31 2026] 127.0.0.1:57296 Accepted +[Fri Jul 31 02:58:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 02:58:31 2026] 127.0.0.1:57296 [200]: GET /api/stats.php +[Fri Jul 31 02:58:31 2026] 127.0.0.1:57296 Closing +[Fri Jul 31 02:58:31 2026] 127.0.0.1:57308 Accepted +[Fri Jul 31 02:58:31 2026] 127.0.0.1:57308 [200]: GET /api/chart.php?range=year +[Fri Jul 31 02:58:31 2026] 127.0.0.1:57308 Closing +[Fri Jul 31 02:59:31 2026] 127.0.0.1:56566 Accepted +[Fri Jul 31 02:59:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 02:59:31 2026] 127.0.0.1:56566 [200]: GET /api/stats.php +[Fri Jul 31 02:59:31 2026] 127.0.0.1:56566 Closing +[Fri Jul 31 02:59:31 2026] 127.0.0.1:56572 Accepted +[Fri Jul 31 02:59:31 2026] 127.0.0.1:56572 [200]: GET /api/chart.php?range=year +[Fri Jul 31 02:59:31 2026] 127.0.0.1:56572 Closing +[Fri Jul 31 03:00:31 2026] 127.0.0.1:39188 Accepted +[Fri Jul 31 03:00:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 03:00:31 2026] 127.0.0.1:39188 [200]: GET /api/stats.php +[Fri Jul 31 03:00:31 2026] 127.0.0.1:39188 Closing +[Fri Jul 31 03:00:31 2026] 127.0.0.1:39194 Accepted +[Fri Jul 31 03:00:31 2026] 127.0.0.1:39194 [200]: GET /api/chart.php?range=year +[Fri Jul 31 03:00:31 2026] 127.0.0.1:39194 Closing +[Fri Jul 31 03:01:31 2026] 127.0.0.1:43486 Accepted +[Fri Jul 31 03:01:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 03:01:31 2026] 127.0.0.1:43486 [200]: GET /api/stats.php +[Fri Jul 31 03:01:31 2026] 127.0.0.1:43486 Closing +[Fri Jul 31 03:01:31 2026] 127.0.0.1:43500 Accepted +[Fri Jul 31 03:01:31 2026] 127.0.0.1:43500 [200]: GET /api/chart.php?range=year +[Fri Jul 31 03:01:31 2026] 127.0.0.1:43500 Closing +[Fri Jul 31 03:02:31 2026] 127.0.0.1:40384 Accepted +[Fri Jul 31 03:02:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 03:02:31 2026] 127.0.0.1:40384 [200]: GET /api/stats.php +[Fri Jul 31 03:02:31 2026] 127.0.0.1:40384 Closing +[Fri Jul 31 03:02:31 2026] 127.0.0.1:40386 Accepted +[Fri Jul 31 03:02:31 2026] 127.0.0.1:40386 [200]: GET /api/chart.php?range=year +[Fri Jul 31 03:02:31 2026] 127.0.0.1:40386 Closing +[Fri Jul 31 03:03:31 2026] 127.0.0.1:48122 Accepted +[Fri Jul 31 03:03:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 03:03:31 2026] 127.0.0.1:48122 [200]: GET /api/stats.php +[Fri Jul 31 03:03:31 2026] 127.0.0.1:48122 Closing +[Fri Jul 31 03:03:31 2026] 127.0.0.1:48126 Accepted +[Fri Jul 31 03:03:31 2026] 127.0.0.1:48126 [200]: GET /api/chart.php?range=year +[Fri Jul 31 03:03:31 2026] 127.0.0.1:48126 Closing +[Fri Jul 31 03:04:31 2026] 127.0.0.1:49732 Accepted +[Fri Jul 31 03:04:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 03:04:31 2026] 127.0.0.1:49732 [200]: GET /api/stats.php +[Fri Jul 31 03:04:31 2026] 127.0.0.1:49732 Closing +[Fri Jul 31 03:04:31 2026] 127.0.0.1:49744 Accepted +[Fri Jul 31 03:04:31 2026] 127.0.0.1:49744 [200]: GET /api/chart.php?range=year +[Fri Jul 31 03:04:31 2026] 127.0.0.1:49744 Closing +[Fri Jul 31 03:05:31 2026] 127.0.0.1:50742 Accepted +[Fri Jul 31 03:05:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 03:05:31 2026] 127.0.0.1:50742 [200]: GET /api/stats.php +[Fri Jul 31 03:05:31 2026] 127.0.0.1:50742 Closing +[Fri Jul 31 03:05:31 2026] 127.0.0.1:50754 Accepted +[Fri Jul 31 03:05:31 2026] 127.0.0.1:50754 [200]: GET /api/chart.php?range=year +[Fri Jul 31 03:05:31 2026] 127.0.0.1:50754 Closing +[Fri Jul 31 03:06:31 2026] 127.0.0.1:60982 Accepted +[Fri Jul 31 03:06:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 03:06:31 2026] 127.0.0.1:60982 [200]: GET /api/stats.php +[Fri Jul 31 03:06:31 2026] 127.0.0.1:60982 Closing +[Fri Jul 31 03:06:31 2026] 127.0.0.1:60996 Accepted +[Fri Jul 31 03:06:31 2026] 127.0.0.1:60996 [200]: GET /api/chart.php?range=year +[Fri Jul 31 03:06:31 2026] 127.0.0.1:60996 Closing +[Fri Jul 31 03:07:31 2026] 127.0.0.1:37616 Accepted +[Fri Jul 31 03:07:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 03:07:31 2026] 127.0.0.1:37616 [200]: GET /api/stats.php +[Fri Jul 31 03:07:31 2026] 127.0.0.1:37616 Closing +[Fri Jul 31 03:07:31 2026] 127.0.0.1:37624 Accepted +[Fri Jul 31 03:07:31 2026] 127.0.0.1:37624 [200]: GET /api/chart.php?range=year +[Fri Jul 31 03:07:31 2026] 127.0.0.1:37624 Closing +[Fri Jul 31 03:08:31 2026] 127.0.0.1:39602 Accepted +[Fri Jul 31 03:08:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 03:08:31 2026] 127.0.0.1:39602 [200]: GET /api/stats.php +[Fri Jul 31 03:08:31 2026] 127.0.0.1:39602 Closing +[Fri Jul 31 03:08:31 2026] 127.0.0.1:39608 Accepted +[Fri Jul 31 03:08:31 2026] 127.0.0.1:39608 [200]: GET /api/chart.php?range=year +[Fri Jul 31 03:08:31 2026] 127.0.0.1:39608 Closing +[Fri Jul 31 03:09:31 2026] 127.0.0.1:43756 Accepted +[Fri Jul 31 03:09:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 03:09:31 2026] 127.0.0.1:43756 [200]: GET /api/stats.php +[Fri Jul 31 03:09:31 2026] 127.0.0.1:43756 Closing +[Fri Jul 31 03:09:31 2026] 127.0.0.1:43760 Accepted +[Fri Jul 31 03:09:31 2026] 127.0.0.1:43760 [200]: GET /api/chart.php?range=year +[Fri Jul 31 03:09:31 2026] 127.0.0.1:43760 Closing +[Fri Jul 31 03:10:31 2026] 127.0.0.1:37472 Accepted +[Fri Jul 31 03:10:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 03:10:31 2026] 127.0.0.1:37472 [200]: GET /api/stats.php +[Fri Jul 31 03:10:31 2026] 127.0.0.1:37472 Closing +[Fri Jul 31 03:10:31 2026] 127.0.0.1:37474 Accepted +[Fri Jul 31 03:10:31 2026] 127.0.0.1:37474 [200]: GET /api/chart.php?range=year +[Fri Jul 31 03:10:31 2026] 127.0.0.1:37474 Closing +[Fri Jul 31 03:11:31 2026] 127.0.0.1:39662 Accepted +[Fri Jul 31 03:11:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 03:11:31 2026] 127.0.0.1:39662 [200]: GET /api/stats.php +[Fri Jul 31 03:11:31 2026] 127.0.0.1:39662 Closing +[Fri Jul 31 03:11:31 2026] 127.0.0.1:39672 Accepted +[Fri Jul 31 03:11:31 2026] 127.0.0.1:39672 [200]: GET /api/chart.php?range=year +[Fri Jul 31 03:11:31 2026] 127.0.0.1:39672 Closing +[Fri Jul 31 03:12:31 2026] 127.0.0.1:37042 Accepted +[Fri Jul 31 03:12:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 03:12:31 2026] 127.0.0.1:37042 [200]: GET /api/stats.php +[Fri Jul 31 03:12:31 2026] 127.0.0.1:37042 Closing +[Fri Jul 31 03:12:31 2026] 127.0.0.1:37050 Accepted +[Fri Jul 31 03:12:31 2026] 127.0.0.1:37050 [200]: GET /api/chart.php?range=year +[Fri Jul 31 03:12:31 2026] 127.0.0.1:37050 Closing +[Fri Jul 31 03:13:31 2026] 127.0.0.1:58990 Accepted +[Fri Jul 31 03:13:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 03:13:31 2026] 127.0.0.1:58990 [200]: GET /api/stats.php +[Fri Jul 31 03:13:31 2026] 127.0.0.1:58990 Closing +[Fri Jul 31 03:13:31 2026] 127.0.0.1:59000 Accepted +[Fri Jul 31 03:13:31 2026] 127.0.0.1:59000 [200]: GET /api/chart.php?range=year +[Fri Jul 31 03:13:31 2026] 127.0.0.1:59000 Closing +[Fri Jul 31 03:14:31 2026] 127.0.0.1:49398 Accepted +[Fri Jul 31 03:14:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 03:14:31 2026] 127.0.0.1:49398 [200]: GET /api/stats.php +[Fri Jul 31 03:14:31 2026] 127.0.0.1:49398 Closing +[Fri Jul 31 03:14:31 2026] 127.0.0.1:49412 Accepted +[Fri Jul 31 03:14:31 2026] 127.0.0.1:49412 [200]: GET /api/chart.php?range=year +[Fri Jul 31 03:14:31 2026] 127.0.0.1:49412 Closing +[Fri Jul 31 03:15:31 2026] 127.0.0.1:56128 Accepted +[Fri Jul 31 03:15:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 03:15:31 2026] 127.0.0.1:56128 [200]: GET /api/stats.php +[Fri Jul 31 03:15:31 2026] 127.0.0.1:56128 Closing +[Fri Jul 31 03:15:31 2026] 127.0.0.1:56136 Accepted +[Fri Jul 31 03:15:31 2026] 127.0.0.1:56136 [200]: GET /api/chart.php?range=year +[Fri Jul 31 03:15:31 2026] 127.0.0.1:56136 Closing +[Fri Jul 31 03:16:31 2026] 127.0.0.1:58702 Accepted +[Fri Jul 31 03:16:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 03:16:31 2026] 127.0.0.1:58702 [200]: GET /api/stats.php +[Fri Jul 31 03:16:31 2026] 127.0.0.1:58702 Closing +[Fri Jul 31 03:16:31 2026] 127.0.0.1:58704 Accepted +[Fri Jul 31 03:16:31 2026] 127.0.0.1:58704 [200]: GET /api/chart.php?range=year +[Fri Jul 31 03:16:31 2026] 127.0.0.1:58704 Closing +[Fri Jul 31 03:17:31 2026] 127.0.0.1:54426 Accepted +[Fri Jul 31 03:17:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 03:17:31 2026] 127.0.0.1:54426 [200]: GET /api/stats.php +[Fri Jul 31 03:17:31 2026] 127.0.0.1:54426 Closing +[Fri Jul 31 03:17:31 2026] 127.0.0.1:54430 Accepted +[Fri Jul 31 03:17:31 2026] 127.0.0.1:54430 [200]: GET /api/chart.php?range=year +[Fri Jul 31 03:17:31 2026] 127.0.0.1:54430 Closing +[Fri Jul 31 03:18:31 2026] 127.0.0.1:40438 Accepted +[Fri Jul 31 03:18:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 03:18:31 2026] 127.0.0.1:40438 [200]: GET /api/stats.php +[Fri Jul 31 03:18:31 2026] 127.0.0.1:40438 Closing +[Fri Jul 31 03:18:31 2026] 127.0.0.1:40448 Accepted +[Fri Jul 31 03:18:31 2026] 127.0.0.1:40448 [200]: GET /api/chart.php?range=year +[Fri Jul 31 03:18:31 2026] 127.0.0.1:40448 Closing +[Fri Jul 31 03:19:31 2026] 127.0.0.1:57758 Accepted +[Fri Jul 31 03:19:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 03:19:31 2026] 127.0.0.1:57758 [200]: GET /api/stats.php +[Fri Jul 31 03:19:31 2026] 127.0.0.1:57758 Closing +[Fri Jul 31 03:19:31 2026] 127.0.0.1:57762 Accepted +[Fri Jul 31 03:19:31 2026] 127.0.0.1:57762 [200]: GET /api/chart.php?range=year +[Fri Jul 31 03:19:31 2026] 127.0.0.1:57762 Closing +[Fri Jul 31 03:20:31 2026] 127.0.0.1:52454 Accepted +[Fri Jul 31 03:20:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 03:20:31 2026] 127.0.0.1:52454 [200]: GET /api/stats.php +[Fri Jul 31 03:20:31 2026] 127.0.0.1:52454 Closing +[Fri Jul 31 03:20:31 2026] 127.0.0.1:52456 Accepted +[Fri Jul 31 03:20:31 2026] 127.0.0.1:52456 [200]: GET /api/chart.php?range=year +[Fri Jul 31 03:20:31 2026] 127.0.0.1:52456 Closing +[Fri Jul 31 03:21:31 2026] 127.0.0.1:48364 Accepted +[Fri Jul 31 03:21:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 03:21:31 2026] 127.0.0.1:48364 [200]: GET /api/stats.php +[Fri Jul 31 03:21:31 2026] 127.0.0.1:48364 Closing +[Fri Jul 31 03:21:31 2026] 127.0.0.1:48374 Accepted +[Fri Jul 31 03:21:31 2026] 127.0.0.1:48374 [200]: GET /api/chart.php?range=year +[Fri Jul 31 03:21:31 2026] 127.0.0.1:48374 Closing +[Fri Jul 31 03:22:31 2026] 127.0.0.1:55302 Accepted +[Fri Jul 31 03:22:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 03:22:31 2026] 127.0.0.1:55302 [200]: GET /api/stats.php +[Fri Jul 31 03:22:31 2026] 127.0.0.1:55302 Closing +[Fri Jul 31 03:22:31 2026] 127.0.0.1:55314 Accepted +[Fri Jul 31 03:22:31 2026] 127.0.0.1:55314 [200]: GET /api/chart.php?range=year +[Fri Jul 31 03:22:31 2026] 127.0.0.1:55314 Closing +[Fri Jul 31 03:23:31 2026] 127.0.0.1:60118 Accepted +[Fri Jul 31 03:23:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 03:23:31 2026] 127.0.0.1:60118 [200]: GET /api/stats.php +[Fri Jul 31 03:23:31 2026] 127.0.0.1:60118 Closing +[Fri Jul 31 03:23:31 2026] 127.0.0.1:60122 Accepted +[Fri Jul 31 03:23:31 2026] 127.0.0.1:60122 [200]: GET /api/chart.php?range=year +[Fri Jul 31 03:23:31 2026] 127.0.0.1:60122 Closing +[Fri Jul 31 03:24:31 2026] 127.0.0.1:39594 Accepted +[Fri Jul 31 03:24:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 03:24:31 2026] 127.0.0.1:39594 [200]: GET /api/stats.php +[Fri Jul 31 03:24:31 2026] 127.0.0.1:39594 Closing +[Fri Jul 31 03:24:31 2026] 127.0.0.1:39610 Accepted +[Fri Jul 31 03:24:31 2026] 127.0.0.1:39610 [200]: GET /api/chart.php?range=year +[Fri Jul 31 03:24:31 2026] 127.0.0.1:39610 Closing +[Fri Jul 31 03:25:31 2026] 127.0.0.1:47080 Accepted +[Fri Jul 31 03:25:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 03:25:31 2026] 127.0.0.1:47080 [200]: GET /api/stats.php +[Fri Jul 31 03:25:31 2026] 127.0.0.1:47080 Closing +[Fri Jul 31 03:25:31 2026] 127.0.0.1:47084 Accepted +[Fri Jul 31 03:25:31 2026] 127.0.0.1:47084 [200]: GET /api/chart.php?range=year +[Fri Jul 31 03:25:31 2026] 127.0.0.1:47084 Closing +[Fri Jul 31 03:26:31 2026] 127.0.0.1:57246 Accepted +[Fri Jul 31 03:26:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 03:26:31 2026] 127.0.0.1:57246 [200]: GET /api/stats.php +[Fri Jul 31 03:26:31 2026] 127.0.0.1:57246 Closing +[Fri Jul 31 03:26:31 2026] 127.0.0.1:57262 Accepted +[Fri Jul 31 03:26:31 2026] 127.0.0.1:57262 [200]: GET /api/chart.php?range=year +[Fri Jul 31 03:26:31 2026] 127.0.0.1:57262 Closing +[Fri Jul 31 03:27:31 2026] 127.0.0.1:48334 Accepted +[Fri Jul 31 03:27:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 03:27:31 2026] 127.0.0.1:48334 [200]: GET /api/stats.php +[Fri Jul 31 03:27:31 2026] 127.0.0.1:48334 Closing +[Fri Jul 31 03:27:31 2026] 127.0.0.1:48344 Accepted +[Fri Jul 31 03:27:31 2026] 127.0.0.1:48344 [200]: GET /api/chart.php?range=year +[Fri Jul 31 03:27:31 2026] 127.0.0.1:48344 Closing +[Fri Jul 31 03:28:31 2026] 127.0.0.1:32780 Accepted +[Fri Jul 31 03:28:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 03:28:31 2026] 127.0.0.1:32780 [200]: GET /api/stats.php +[Fri Jul 31 03:28:31 2026] 127.0.0.1:32780 Closing +[Fri Jul 31 03:28:31 2026] 127.0.0.1:32792 Accepted +[Fri Jul 31 03:28:31 2026] 127.0.0.1:32792 [200]: GET /api/chart.php?range=year +[Fri Jul 31 03:28:31 2026] 127.0.0.1:32792 Closing +[Fri Jul 31 03:29:31 2026] 127.0.0.1:60498 Accepted +[Fri Jul 31 03:29:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 03:29:31 2026] 127.0.0.1:60498 [200]: GET /api/stats.php +[Fri Jul 31 03:29:31 2026] 127.0.0.1:60498 Closing +[Fri Jul 31 03:29:31 2026] 127.0.0.1:60512 Accepted +[Fri Jul 31 03:29:31 2026] 127.0.0.1:60512 [200]: GET /api/chart.php?range=year +[Fri Jul 31 03:29:31 2026] 127.0.0.1:60512 Closing +[Fri Jul 31 03:30:31 2026] 127.0.0.1:52678 Accepted +[Fri Jul 31 03:30:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 03:30:31 2026] 127.0.0.1:52678 [200]: GET /api/stats.php +[Fri Jul 31 03:30:31 2026] 127.0.0.1:52678 Closing +[Fri Jul 31 03:30:31 2026] 127.0.0.1:52694 Accepted +[Fri Jul 31 03:30:31 2026] 127.0.0.1:52694 [200]: GET /api/chart.php?range=year +[Fri Jul 31 03:30:31 2026] 127.0.0.1:52694 Closing +[Fri Jul 31 03:31:31 2026] 127.0.0.1:34548 Accepted +[Fri Jul 31 03:31:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 03:31:31 2026] 127.0.0.1:34548 [200]: GET /api/stats.php +[Fri Jul 31 03:31:31 2026] 127.0.0.1:34548 Closing +[Fri Jul 31 03:31:31 2026] 127.0.0.1:34562 Accepted +[Fri Jul 31 03:31:31 2026] 127.0.0.1:34562 [200]: GET /api/chart.php?range=year +[Fri Jul 31 03:31:31 2026] 127.0.0.1:34562 Closing +[Fri Jul 31 03:32:31 2026] 127.0.0.1:34652 Accepted +[Fri Jul 31 03:32:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 03:32:31 2026] 127.0.0.1:34652 [200]: GET /api/stats.php +[Fri Jul 31 03:32:31 2026] 127.0.0.1:34652 Closing +[Fri Jul 31 03:32:31 2026] 127.0.0.1:34662 Accepted +[Fri Jul 31 03:32:31 2026] 127.0.0.1:34662 [200]: GET /api/chart.php?range=year +[Fri Jul 31 03:32:31 2026] 127.0.0.1:34662 Closing +[Fri Jul 31 03:33:31 2026] 127.0.0.1:55656 Accepted +[Fri Jul 31 03:33:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 03:33:31 2026] 127.0.0.1:55656 [200]: GET /api/stats.php +[Fri Jul 31 03:33:31 2026] 127.0.0.1:55656 Closing +[Fri Jul 31 03:33:31 2026] 127.0.0.1:55670 Accepted +[Fri Jul 31 03:33:31 2026] 127.0.0.1:55670 [200]: GET /api/chart.php?range=year +[Fri Jul 31 03:33:31 2026] 127.0.0.1:55670 Closing +[Fri Jul 31 03:34:31 2026] 127.0.0.1:46976 Accepted +[Fri Jul 31 03:34:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 03:34:31 2026] 127.0.0.1:46976 [200]: GET /api/stats.php +[Fri Jul 31 03:34:31 2026] 127.0.0.1:46976 Closing +[Fri Jul 31 03:34:31 2026] 127.0.0.1:46992 Accepted +[Fri Jul 31 03:34:31 2026] 127.0.0.1:46992 [200]: GET /api/chart.php?range=year +[Fri Jul 31 03:34:31 2026] 127.0.0.1:46992 Closing +[Fri Jul 31 03:35:31 2026] 127.0.0.1:58954 Accepted +[Fri Jul 31 03:35:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 03:35:31 2026] 127.0.0.1:58954 [200]: GET /api/stats.php +[Fri Jul 31 03:35:31 2026] 127.0.0.1:58954 Closing +[Fri Jul 31 03:35:31 2026] 127.0.0.1:58958 Accepted +[Fri Jul 31 03:35:31 2026] 127.0.0.1:58958 [200]: GET /api/chart.php?range=year +[Fri Jul 31 03:35:31 2026] 127.0.0.1:58958 Closing +[Fri Jul 31 03:36:31 2026] 127.0.0.1:42204 Accepted +[Fri Jul 31 03:36:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 03:36:31 2026] 127.0.0.1:42204 [200]: GET /api/stats.php +[Fri Jul 31 03:36:31 2026] 127.0.0.1:42204 Closing +[Fri Jul 31 03:36:31 2026] 127.0.0.1:42210 Accepted +[Fri Jul 31 03:36:31 2026] 127.0.0.1:42210 [200]: GET /api/chart.php?range=year +[Fri Jul 31 03:36:31 2026] 127.0.0.1:42210 Closing +[Fri Jul 31 03:37:31 2026] 127.0.0.1:41366 Accepted +[Fri Jul 31 03:37:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 03:37:31 2026] 127.0.0.1:41366 [200]: GET /api/stats.php +[Fri Jul 31 03:37:31 2026] 127.0.0.1:41366 Closing +[Fri Jul 31 03:37:31 2026] 127.0.0.1:41378 Accepted +[Fri Jul 31 03:37:31 2026] 127.0.0.1:41378 [200]: GET /api/chart.php?range=year +[Fri Jul 31 03:37:31 2026] 127.0.0.1:41378 Closing +[Fri Jul 31 03:38:31 2026] 127.0.0.1:48386 Accepted +[Fri Jul 31 03:38:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 03:38:31 2026] 127.0.0.1:48386 [200]: GET /api/stats.php +[Fri Jul 31 03:38:31 2026] 127.0.0.1:48386 Closing +[Fri Jul 31 03:38:31 2026] 127.0.0.1:48390 Accepted +[Fri Jul 31 03:38:31 2026] 127.0.0.1:48390 [200]: GET /api/chart.php?range=year +[Fri Jul 31 03:38:31 2026] 127.0.0.1:48390 Closing +[Fri Jul 31 03:39:31 2026] 127.0.0.1:56478 Accepted +[Fri Jul 31 03:39:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 03:39:31 2026] 127.0.0.1:56478 [200]: GET /api/stats.php +[Fri Jul 31 03:39:31 2026] 127.0.0.1:56478 Closing +[Fri Jul 31 03:39:31 2026] 127.0.0.1:56482 Accepted +[Fri Jul 31 03:39:31 2026] 127.0.0.1:56482 [200]: GET /api/chart.php?range=year +[Fri Jul 31 03:39:31 2026] 127.0.0.1:56482 Closing +[Fri Jul 31 03:40:31 2026] 127.0.0.1:53834 Accepted +[Fri Jul 31 03:40:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 03:40:31 2026] 127.0.0.1:53834 [200]: GET /api/stats.php +[Fri Jul 31 03:40:31 2026] 127.0.0.1:53834 Closing +[Fri Jul 31 03:40:31 2026] 127.0.0.1:53846 Accepted +[Fri Jul 31 03:40:31 2026] 127.0.0.1:53846 [200]: GET /api/chart.php?range=year +[Fri Jul 31 03:40:31 2026] 127.0.0.1:53846 Closing +[Fri Jul 31 03:41:31 2026] 127.0.0.1:40992 Accepted +[Fri Jul 31 03:41:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 03:41:31 2026] 127.0.0.1:40992 [200]: GET /api/stats.php +[Fri Jul 31 03:41:31 2026] 127.0.0.1:40992 Closing +[Fri Jul 31 03:41:31 2026] 127.0.0.1:41008 Accepted +[Fri Jul 31 03:41:31 2026] 127.0.0.1:41008 [200]: GET /api/chart.php?range=year +[Fri Jul 31 03:41:31 2026] 127.0.0.1:41008 Closing +[Fri Jul 31 03:42:31 2026] 127.0.0.1:39022 Accepted +[Fri Jul 31 03:42:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 03:42:31 2026] 127.0.0.1:39022 [200]: GET /api/stats.php +[Fri Jul 31 03:42:31 2026] 127.0.0.1:39022 Closing +[Fri Jul 31 03:42:31 2026] 127.0.0.1:39026 Accepted +[Fri Jul 31 03:42:31 2026] 127.0.0.1:39026 [200]: GET /api/chart.php?range=year +[Fri Jul 31 03:42:31 2026] 127.0.0.1:39026 Closing +[Fri Jul 31 03:43:31 2026] 127.0.0.1:55856 Accepted +[Fri Jul 31 03:43:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 03:43:31 2026] 127.0.0.1:55856 [200]: GET /api/stats.php +[Fri Jul 31 03:43:31 2026] 127.0.0.1:55856 Closing +[Fri Jul 31 03:43:31 2026] 127.0.0.1:55872 Accepted +[Fri Jul 31 03:43:31 2026] 127.0.0.1:55872 [200]: GET /api/chart.php?range=year +[Fri Jul 31 03:43:31 2026] 127.0.0.1:55872 Closing +[Fri Jul 31 03:44:31 2026] 127.0.0.1:44690 Accepted +[Fri Jul 31 03:44:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 03:44:31 2026] 127.0.0.1:44690 [200]: GET /api/stats.php +[Fri Jul 31 03:44:31 2026] 127.0.0.1:44690 Closing +[Fri Jul 31 03:44:31 2026] 127.0.0.1:44702 Accepted +[Fri Jul 31 03:44:31 2026] 127.0.0.1:44702 [200]: GET /api/chart.php?range=year +[Fri Jul 31 03:44:31 2026] 127.0.0.1:44702 Closing +[Fri Jul 31 03:45:31 2026] 127.0.0.1:46586 Accepted +[Fri Jul 31 03:45:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 03:45:31 2026] 127.0.0.1:46586 [200]: GET /api/stats.php +[Fri Jul 31 03:45:31 2026] 127.0.0.1:46586 Closing +[Fri Jul 31 03:45:31 2026] 127.0.0.1:46600 Accepted +[Fri Jul 31 03:45:31 2026] 127.0.0.1:46600 [200]: GET /api/chart.php?range=year +[Fri Jul 31 03:45:31 2026] 127.0.0.1:46600 Closing +[Fri Jul 31 03:46:31 2026] 127.0.0.1:44264 Accepted +[Fri Jul 31 03:46:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 03:46:31 2026] 127.0.0.1:44264 [200]: GET /api/stats.php +[Fri Jul 31 03:46:31 2026] 127.0.0.1:44264 Closing +[Fri Jul 31 03:46:31 2026] 127.0.0.1:44272 Accepted +[Fri Jul 31 03:46:31 2026] 127.0.0.1:44272 [200]: GET /api/chart.php?range=year +[Fri Jul 31 03:46:31 2026] 127.0.0.1:44272 Closing +[Fri Jul 31 03:47:31 2026] 127.0.0.1:44750 Accepted +[Fri Jul 31 03:47:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 03:47:31 2026] 127.0.0.1:44750 [200]: GET /api/stats.php +[Fri Jul 31 03:47:31 2026] 127.0.0.1:44750 Closing +[Fri Jul 31 03:47:31 2026] 127.0.0.1:44764 Accepted +[Fri Jul 31 03:47:31 2026] 127.0.0.1:44764 [200]: GET /api/chart.php?range=year +[Fri Jul 31 03:47:31 2026] 127.0.0.1:44764 Closing +[Fri Jul 31 03:48:31 2026] 127.0.0.1:35108 Accepted +[Fri Jul 31 03:48:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 03:48:31 2026] 127.0.0.1:35108 [200]: GET /api/stats.php +[Fri Jul 31 03:48:31 2026] 127.0.0.1:35108 Closing +[Fri Jul 31 03:48:31 2026] 127.0.0.1:35120 Accepted +[Fri Jul 31 03:48:31 2026] 127.0.0.1:35120 [200]: GET /api/chart.php?range=year +[Fri Jul 31 03:48:31 2026] 127.0.0.1:35120 Closing +[Fri Jul 31 03:49:31 2026] 127.0.0.1:53678 Accepted +[Fri Jul 31 03:49:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 03:49:31 2026] 127.0.0.1:53678 [200]: GET /api/stats.php +[Fri Jul 31 03:49:31 2026] 127.0.0.1:53678 Closing +[Fri Jul 31 03:49:31 2026] 127.0.0.1:53684 Accepted +[Fri Jul 31 03:49:31 2026] 127.0.0.1:53684 [200]: GET /api/chart.php?range=year +[Fri Jul 31 03:49:31 2026] 127.0.0.1:53684 Closing +[Fri Jul 31 03:50:31 2026] 127.0.0.1:55728 Accepted +[Fri Jul 31 03:50:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 03:50:31 2026] 127.0.0.1:55728 [200]: GET /api/stats.php +[Fri Jul 31 03:50:31 2026] 127.0.0.1:55728 Closing +[Fri Jul 31 03:50:31 2026] 127.0.0.1:55730 Accepted +[Fri Jul 31 03:50:31 2026] 127.0.0.1:55730 [200]: GET /api/chart.php?range=year +[Fri Jul 31 03:50:31 2026] 127.0.0.1:55730 Closing +[Fri Jul 31 03:51:31 2026] 127.0.0.1:50230 Accepted +[Fri Jul 31 03:51:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 03:51:31 2026] 127.0.0.1:50230 [200]: GET /api/stats.php +[Fri Jul 31 03:51:31 2026] 127.0.0.1:50230 Closing +[Fri Jul 31 03:51:31 2026] 127.0.0.1:50238 Accepted +[Fri Jul 31 03:51:31 2026] 127.0.0.1:50238 [200]: GET /api/chart.php?range=year +[Fri Jul 31 03:51:31 2026] 127.0.0.1:50238 Closing +[Fri Jul 31 03:52:31 2026] 127.0.0.1:43140 Accepted +[Fri Jul 31 03:52:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 03:52:31 2026] 127.0.0.1:43140 [200]: GET /api/stats.php +[Fri Jul 31 03:52:31 2026] 127.0.0.1:43140 Closing +[Fri Jul 31 03:52:31 2026] 127.0.0.1:43144 Accepted +[Fri Jul 31 03:52:31 2026] 127.0.0.1:43144 [200]: GET /api/chart.php?range=year +[Fri Jul 31 03:52:31 2026] 127.0.0.1:43144 Closing +[Fri Jul 31 03:53:31 2026] 127.0.0.1:32906 Accepted +[Fri Jul 31 03:53:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 03:53:31 2026] 127.0.0.1:32906 [200]: GET /api/stats.php +[Fri Jul 31 03:53:31 2026] 127.0.0.1:32906 Closing +[Fri Jul 31 03:53:31 2026] 127.0.0.1:32916 Accepted +[Fri Jul 31 03:53:31 2026] 127.0.0.1:32916 [200]: GET /api/chart.php?range=year +[Fri Jul 31 03:53:31 2026] 127.0.0.1:32916 Closing +[Fri Jul 31 03:54:31 2026] 127.0.0.1:36170 Accepted +[Fri Jul 31 03:54:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 03:54:31 2026] 127.0.0.1:36170 [200]: GET /api/stats.php +[Fri Jul 31 03:54:31 2026] 127.0.0.1:36170 Closing +[Fri Jul 31 03:54:31 2026] 127.0.0.1:36176 Accepted +[Fri Jul 31 03:54:31 2026] 127.0.0.1:36176 [200]: GET /api/chart.php?range=year +[Fri Jul 31 03:54:31 2026] 127.0.0.1:36176 Closing +[Fri Jul 31 03:55:31 2026] 127.0.0.1:50714 Accepted +[Fri Jul 31 03:55:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 03:55:31 2026] 127.0.0.1:50714 [200]: GET /api/stats.php +[Fri Jul 31 03:55:31 2026] 127.0.0.1:50714 Closing +[Fri Jul 31 03:55:31 2026] 127.0.0.1:50728 Accepted +[Fri Jul 31 03:55:31 2026] 127.0.0.1:50728 [200]: GET /api/chart.php?range=year +[Fri Jul 31 03:55:31 2026] 127.0.0.1:50728 Closing +[Fri Jul 31 03:56:31 2026] 127.0.0.1:60120 Accepted +[Fri Jul 31 03:56:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 03:56:31 2026] 127.0.0.1:60120 [200]: GET /api/stats.php +[Fri Jul 31 03:56:31 2026] 127.0.0.1:60120 Closing +[Fri Jul 31 03:56:31 2026] 127.0.0.1:60128 Accepted +[Fri Jul 31 03:56:31 2026] 127.0.0.1:60128 [200]: GET /api/chart.php?range=year +[Fri Jul 31 03:56:31 2026] 127.0.0.1:60128 Closing +[Fri Jul 31 03:57:31 2026] 127.0.0.1:56976 Accepted +[Fri Jul 31 03:57:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 03:57:31 2026] 127.0.0.1:56976 [200]: GET /api/stats.php +[Fri Jul 31 03:57:31 2026] 127.0.0.1:56976 Closing +[Fri Jul 31 03:57:31 2026] 127.0.0.1:56990 Accepted +[Fri Jul 31 03:57:31 2026] 127.0.0.1:56990 [200]: GET /api/chart.php?range=year +[Fri Jul 31 03:57:31 2026] 127.0.0.1:56990 Closing +[Fri Jul 31 03:58:31 2026] 127.0.0.1:50968 Accepted +[Fri Jul 31 03:58:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 03:58:31 2026] 127.0.0.1:50968 [200]: GET /api/stats.php +[Fri Jul 31 03:58:31 2026] 127.0.0.1:50968 Closing +[Fri Jul 31 03:58:31 2026] 127.0.0.1:50974 Accepted +[Fri Jul 31 03:58:31 2026] 127.0.0.1:50974 [200]: GET /api/chart.php?range=year +[Fri Jul 31 03:58:31 2026] 127.0.0.1:50974 Closing +[Fri Jul 31 03:59:31 2026] 127.0.0.1:44976 Accepted +[Fri Jul 31 03:59:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 03:59:31 2026] 127.0.0.1:44976 [200]: GET /api/stats.php +[Fri Jul 31 03:59:31 2026] 127.0.0.1:44976 Closing +[Fri Jul 31 03:59:31 2026] 127.0.0.1:44986 Accepted +[Fri Jul 31 03:59:31 2026] 127.0.0.1:44986 [200]: GET /api/chart.php?range=year +[Fri Jul 31 03:59:31 2026] 127.0.0.1:44986 Closing +[Fri Jul 31 04:00:31 2026] 127.0.0.1:51094 Accepted +[Fri Jul 31 04:00:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 04:00:31 2026] 127.0.0.1:51094 [200]: GET /api/stats.php +[Fri Jul 31 04:00:31 2026] 127.0.0.1:51094 Closing +[Fri Jul 31 04:00:31 2026] 127.0.0.1:51104 Accepted +[Fri Jul 31 04:00:31 2026] 127.0.0.1:51104 [200]: GET /api/chart.php?range=year +[Fri Jul 31 04:00:31 2026] 127.0.0.1:51104 Closing +[Fri Jul 31 04:01:31 2026] 127.0.0.1:44798 Accepted +[Fri Jul 31 04:01:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 04:01:31 2026] 127.0.0.1:44798 [200]: GET /api/stats.php +[Fri Jul 31 04:01:31 2026] 127.0.0.1:44798 Closing +[Fri Jul 31 04:01:31 2026] 127.0.0.1:44802 Accepted +[Fri Jul 31 04:01:31 2026] 127.0.0.1:44802 [200]: GET /api/chart.php?range=year +[Fri Jul 31 04:01:31 2026] 127.0.0.1:44802 Closing +[Fri Jul 31 04:02:31 2026] 127.0.0.1:60184 Accepted +[Fri Jul 31 04:02:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 04:02:31 2026] 127.0.0.1:60184 [200]: GET /api/stats.php +[Fri Jul 31 04:02:31 2026] 127.0.0.1:60184 Closing +[Fri Jul 31 04:02:31 2026] 127.0.0.1:60188 Accepted +[Fri Jul 31 04:02:31 2026] 127.0.0.1:60188 [200]: GET /api/chart.php?range=year +[Fri Jul 31 04:02:31 2026] 127.0.0.1:60188 Closing +[Fri Jul 31 04:03:31 2026] 127.0.0.1:58178 Accepted +[Fri Jul 31 04:03:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 04:03:31 2026] 127.0.0.1:58178 [200]: GET /api/stats.php +[Fri Jul 31 04:03:31 2026] 127.0.0.1:58178 Closing +[Fri Jul 31 04:03:31 2026] 127.0.0.1:58184 Accepted +[Fri Jul 31 04:03:31 2026] 127.0.0.1:58184 [200]: GET /api/chart.php?range=year +[Fri Jul 31 04:03:31 2026] 127.0.0.1:58184 Closing +[Fri Jul 31 04:04:31 2026] 127.0.0.1:45734 Accepted +[Fri Jul 31 04:04:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 04:04:31 2026] 127.0.0.1:45734 [200]: GET /api/stats.php +[Fri Jul 31 04:04:31 2026] 127.0.0.1:45734 Closing +[Fri Jul 31 04:04:31 2026] 127.0.0.1:45742 Accepted +[Fri Jul 31 04:04:31 2026] 127.0.0.1:45742 [200]: GET /api/chart.php?range=year +[Fri Jul 31 04:04:31 2026] 127.0.0.1:45742 Closing +[Fri Jul 31 04:05:31 2026] 127.0.0.1:55520 Accepted +[Fri Jul 31 04:05:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 04:05:31 2026] 127.0.0.1:55520 [200]: GET /api/stats.php +[Fri Jul 31 04:05:31 2026] 127.0.0.1:55520 Closing +[Fri Jul 31 04:05:31 2026] 127.0.0.1:55526 Accepted +[Fri Jul 31 04:05:31 2026] 127.0.0.1:55526 [200]: GET /api/chart.php?range=year +[Fri Jul 31 04:05:31 2026] 127.0.0.1:55526 Closing +[Fri Jul 31 04:06:31 2026] 127.0.0.1:53862 Accepted +[Fri Jul 31 04:06:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 04:06:31 2026] 127.0.0.1:53862 [200]: GET /api/stats.php +[Fri Jul 31 04:06:31 2026] 127.0.0.1:53862 Closing +[Fri Jul 31 04:06:31 2026] 127.0.0.1:53864 Accepted +[Fri Jul 31 04:06:31 2026] 127.0.0.1:53864 [200]: GET /api/chart.php?range=year +[Fri Jul 31 04:06:31 2026] 127.0.0.1:53864 Closing +[Fri Jul 31 04:07:31 2026] 127.0.0.1:37754 Accepted +[Fri Jul 31 04:07:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 04:07:31 2026] 127.0.0.1:37754 [200]: GET /api/stats.php +[Fri Jul 31 04:07:31 2026] 127.0.0.1:37754 Closing +[Fri Jul 31 04:07:31 2026] 127.0.0.1:37766 Accepted +[Fri Jul 31 04:07:31 2026] 127.0.0.1:37766 [200]: GET /api/chart.php?range=year +[Fri Jul 31 04:07:31 2026] 127.0.0.1:37766 Closing +[Fri Jul 31 04:08:31 2026] 127.0.0.1:41236 Accepted +[Fri Jul 31 04:08:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 04:08:31 2026] 127.0.0.1:41236 [200]: GET /api/stats.php +[Fri Jul 31 04:08:31 2026] 127.0.0.1:41236 Closing +[Fri Jul 31 04:08:31 2026] 127.0.0.1:41240 Accepted +[Fri Jul 31 04:08:31 2026] 127.0.0.1:41240 [200]: GET /api/chart.php?range=year +[Fri Jul 31 04:08:31 2026] 127.0.0.1:41240 Closing +[Fri Jul 31 04:09:31 2026] 127.0.0.1:39112 Accepted +[Fri Jul 31 04:09:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 04:09:31 2026] 127.0.0.1:39112 [200]: GET /api/stats.php +[Fri Jul 31 04:09:31 2026] 127.0.0.1:39112 Closing +[Fri Jul 31 04:09:31 2026] 127.0.0.1:39128 Accepted +[Fri Jul 31 04:09:31 2026] 127.0.0.1:39128 [200]: GET /api/chart.php?range=year +[Fri Jul 31 04:09:31 2026] 127.0.0.1:39128 Closing +[Fri Jul 31 04:10:31 2026] 127.0.0.1:38932 Accepted +[Fri Jul 31 04:10:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 04:10:31 2026] 127.0.0.1:38932 [200]: GET /api/stats.php +[Fri Jul 31 04:10:31 2026] 127.0.0.1:38932 Closing +[Fri Jul 31 04:10:31 2026] 127.0.0.1:38942 Accepted +[Fri Jul 31 04:10:31 2026] 127.0.0.1:38942 [200]: GET /api/chart.php?range=year +[Fri Jul 31 04:10:31 2026] 127.0.0.1:38942 Closing +[Fri Jul 31 04:11:31 2026] 127.0.0.1:45036 Accepted +[Fri Jul 31 04:11:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 04:11:31 2026] 127.0.0.1:45036 [200]: GET /api/stats.php +[Fri Jul 31 04:11:31 2026] 127.0.0.1:45036 Closing +[Fri Jul 31 04:11:31 2026] 127.0.0.1:45048 Accepted +[Fri Jul 31 04:11:31 2026] 127.0.0.1:45048 [200]: GET /api/chart.php?range=year +[Fri Jul 31 04:11:31 2026] 127.0.0.1:45048 Closing +[Fri Jul 31 04:12:31 2026] 127.0.0.1:56638 Accepted +[Fri Jul 31 04:12:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 04:12:31 2026] 127.0.0.1:56638 [200]: GET /api/stats.php +[Fri Jul 31 04:12:31 2026] 127.0.0.1:56638 Closing +[Fri Jul 31 04:12:31 2026] 127.0.0.1:56642 Accepted +[Fri Jul 31 04:12:31 2026] 127.0.0.1:56642 [200]: GET /api/chart.php?range=year +[Fri Jul 31 04:12:31 2026] 127.0.0.1:56642 Closing +[Fri Jul 31 04:13:31 2026] 127.0.0.1:52806 Accepted +[Fri Jul 31 04:13:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 04:13:31 2026] 127.0.0.1:52806 [200]: GET /api/stats.php +[Fri Jul 31 04:13:31 2026] 127.0.0.1:52806 Closing +[Fri Jul 31 04:13:31 2026] 127.0.0.1:52816 Accepted +[Fri Jul 31 04:13:31 2026] 127.0.0.1:52816 [200]: GET /api/chart.php?range=year +[Fri Jul 31 04:13:31 2026] 127.0.0.1:52816 Closing +[Fri Jul 31 04:14:31 2026] 127.0.0.1:42452 Accepted +[Fri Jul 31 04:14:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 04:14:31 2026] 127.0.0.1:42452 [200]: GET /api/stats.php +[Fri Jul 31 04:14:31 2026] 127.0.0.1:42452 Closing +[Fri Jul 31 04:14:31 2026] 127.0.0.1:42462 Accepted +[Fri Jul 31 04:14:31 2026] 127.0.0.1:42462 [200]: GET /api/chart.php?range=year +[Fri Jul 31 04:14:31 2026] 127.0.0.1:42462 Closing +[Fri Jul 31 04:15:31 2026] 127.0.0.1:35354 Accepted +[Fri Jul 31 04:15:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 04:15:31 2026] 127.0.0.1:35354 [200]: GET /api/stats.php +[Fri Jul 31 04:15:31 2026] 127.0.0.1:35354 Closing +[Fri Jul 31 04:15:31 2026] 127.0.0.1:35368 Accepted +[Fri Jul 31 04:15:31 2026] 127.0.0.1:35368 [200]: GET /api/chart.php?range=year +[Fri Jul 31 04:15:31 2026] 127.0.0.1:35368 Closing +[Fri Jul 31 04:16:31 2026] 127.0.0.1:56876 Accepted +[Fri Jul 31 04:16:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 04:16:31 2026] 127.0.0.1:56876 [200]: GET /api/stats.php +[Fri Jul 31 04:16:31 2026] 127.0.0.1:56876 Closing +[Fri Jul 31 04:16:31 2026] 127.0.0.1:56880 Accepted +[Fri Jul 31 04:16:31 2026] 127.0.0.1:56880 [200]: GET /api/chart.php?range=year +[Fri Jul 31 04:16:31 2026] 127.0.0.1:56880 Closing +[Fri Jul 31 04:17:31 2026] 127.0.0.1:34268 Accepted +[Fri Jul 31 04:17:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 04:17:31 2026] 127.0.0.1:34268 [200]: GET /api/stats.php +[Fri Jul 31 04:17:31 2026] 127.0.0.1:34268 Closing +[Fri Jul 31 04:17:31 2026] 127.0.0.1:34278 Accepted +[Fri Jul 31 04:17:31 2026] 127.0.0.1:34278 [200]: GET /api/chart.php?range=year +[Fri Jul 31 04:17:31 2026] 127.0.0.1:34278 Closing +[Fri Jul 31 04:18:31 2026] 127.0.0.1:57754 Accepted +[Fri Jul 31 04:18:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 04:18:31 2026] 127.0.0.1:57754 [200]: GET /api/stats.php +[Fri Jul 31 04:18:31 2026] 127.0.0.1:57754 Closing +[Fri Jul 31 04:18:31 2026] 127.0.0.1:57764 Accepted +[Fri Jul 31 04:18:31 2026] 127.0.0.1:57764 [200]: GET /api/chart.php?range=year +[Fri Jul 31 04:18:31 2026] 127.0.0.1:57764 Closing +[Fri Jul 31 04:19:31 2026] 127.0.0.1:33220 Accepted +[Fri Jul 31 04:19:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 04:19:31 2026] 127.0.0.1:33220 [200]: GET /api/stats.php +[Fri Jul 31 04:19:31 2026] 127.0.0.1:33220 Closing +[Fri Jul 31 04:19:31 2026] 127.0.0.1:33224 Accepted +[Fri Jul 31 04:19:31 2026] 127.0.0.1:33224 [200]: GET /api/chart.php?range=year +[Fri Jul 31 04:19:31 2026] 127.0.0.1:33224 Closing +[Fri Jul 31 04:20:31 2026] 127.0.0.1:33424 Accepted +[Fri Jul 31 04:20:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 04:20:31 2026] 127.0.0.1:33424 [200]: GET /api/stats.php +[Fri Jul 31 04:20:31 2026] 127.0.0.1:33424 Closing +[Fri Jul 31 04:20:31 2026] 127.0.0.1:33434 Accepted +[Fri Jul 31 04:20:31 2026] 127.0.0.1:33434 [200]: GET /api/chart.php?range=year +[Fri Jul 31 04:20:31 2026] 127.0.0.1:33434 Closing +[Fri Jul 31 04:21:31 2026] 127.0.0.1:55104 Accepted +[Fri Jul 31 04:21:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 04:21:31 2026] 127.0.0.1:55104 [200]: GET /api/stats.php +[Fri Jul 31 04:21:31 2026] 127.0.0.1:55104 Closing +[Fri Jul 31 04:21:31 2026] 127.0.0.1:55106 Accepted +[Fri Jul 31 04:21:31 2026] 127.0.0.1:55106 [200]: GET /api/chart.php?range=year +[Fri Jul 31 04:21:31 2026] 127.0.0.1:55106 Closing +[Fri Jul 31 04:22:31 2026] 127.0.0.1:35102 Accepted +[Fri Jul 31 04:22:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 04:22:31 2026] 127.0.0.1:35102 [200]: GET /api/stats.php +[Fri Jul 31 04:22:31 2026] 127.0.0.1:35102 Closing +[Fri Jul 31 04:22:31 2026] 127.0.0.1:35116 Accepted +[Fri Jul 31 04:22:31 2026] 127.0.0.1:35116 [200]: GET /api/chart.php?range=year +[Fri Jul 31 04:22:31 2026] 127.0.0.1:35116 Closing +[Fri Jul 31 04:23:31 2026] 127.0.0.1:48318 Accepted +[Fri Jul 31 04:23:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 04:23:31 2026] 127.0.0.1:48318 [200]: GET /api/stats.php +[Fri Jul 31 04:23:31 2026] 127.0.0.1:48318 Closing +[Fri Jul 31 04:23:31 2026] 127.0.0.1:48324 Accepted +[Fri Jul 31 04:23:31 2026] 127.0.0.1:48324 [200]: GET /api/chart.php?range=year +[Fri Jul 31 04:23:31 2026] 127.0.0.1:48324 Closing +[Fri Jul 31 04:24:31 2026] 127.0.0.1:59602 Accepted +[Fri Jul 31 04:24:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 04:24:31 2026] 127.0.0.1:59602 [200]: GET /api/stats.php +[Fri Jul 31 04:24:31 2026] 127.0.0.1:59602 Closing +[Fri Jul 31 04:24:31 2026] 127.0.0.1:59612 Accepted +[Fri Jul 31 04:24:31 2026] 127.0.0.1:59612 [200]: GET /api/chart.php?range=year +[Fri Jul 31 04:24:31 2026] 127.0.0.1:59612 Closing +[Fri Jul 31 04:25:31 2026] 127.0.0.1:57786 Accepted +[Fri Jul 31 04:25:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 04:25:31 2026] 127.0.0.1:57786 [200]: GET /api/stats.php +[Fri Jul 31 04:25:31 2026] 127.0.0.1:57786 Closing +[Fri Jul 31 04:25:31 2026] 127.0.0.1:57796 Accepted +[Fri Jul 31 04:25:31 2026] 127.0.0.1:57796 [200]: GET /api/chart.php?range=year +[Fri Jul 31 04:25:31 2026] 127.0.0.1:57796 Closing +[Fri Jul 31 04:26:31 2026] 127.0.0.1:59074 Accepted +[Fri Jul 31 04:26:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 04:26:31 2026] 127.0.0.1:59074 [200]: GET /api/stats.php +[Fri Jul 31 04:26:31 2026] 127.0.0.1:59074 Closing +[Fri Jul 31 04:26:31 2026] 127.0.0.1:59082 Accepted +[Fri Jul 31 04:26:31 2026] 127.0.0.1:59082 [200]: GET /api/chart.php?range=year +[Fri Jul 31 04:26:31 2026] 127.0.0.1:59082 Closing +[Fri Jul 31 04:27:31 2026] 127.0.0.1:32882 Accepted +[Fri Jul 31 04:27:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 04:27:31 2026] 127.0.0.1:32882 [200]: GET /api/stats.php +[Fri Jul 31 04:27:31 2026] 127.0.0.1:32882 Closing +[Fri Jul 31 04:27:31 2026] 127.0.0.1:32890 Accepted +[Fri Jul 31 04:27:31 2026] 127.0.0.1:32890 [200]: GET /api/chart.php?range=year +[Fri Jul 31 04:27:31 2026] 127.0.0.1:32890 Closing +[Fri Jul 31 04:28:31 2026] 127.0.0.1:58692 Accepted +[Fri Jul 31 04:28:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 04:28:31 2026] 127.0.0.1:58692 [200]: GET /api/stats.php +[Fri Jul 31 04:28:31 2026] 127.0.0.1:58692 Closing +[Fri Jul 31 04:28:31 2026] 127.0.0.1:58696 Accepted +[Fri Jul 31 04:28:31 2026] 127.0.0.1:58696 [200]: GET /api/chart.php?range=year +[Fri Jul 31 04:28:31 2026] 127.0.0.1:58696 Closing +[Fri Jul 31 04:29:31 2026] 127.0.0.1:49314 Accepted +[Fri Jul 31 04:29:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 04:29:31 2026] 127.0.0.1:49314 [200]: GET /api/stats.php +[Fri Jul 31 04:29:31 2026] 127.0.0.1:49314 Closing +[Fri Jul 31 04:29:31 2026] 127.0.0.1:49316 Accepted +[Fri Jul 31 04:29:31 2026] 127.0.0.1:49316 [200]: GET /api/chart.php?range=year +[Fri Jul 31 04:29:31 2026] 127.0.0.1:49316 Closing +[Fri Jul 31 04:30:31 2026] 127.0.0.1:55128 Accepted +[Fri Jul 31 04:30:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 04:30:31 2026] 127.0.0.1:55128 [200]: GET /api/stats.php +[Fri Jul 31 04:30:31 2026] 127.0.0.1:55128 Closing +[Fri Jul 31 04:30:31 2026] 127.0.0.1:55136 Accepted +[Fri Jul 31 04:30:31 2026] 127.0.0.1:55136 [200]: GET /api/chart.php?range=year +[Fri Jul 31 04:30:31 2026] 127.0.0.1:55136 Closing +[Fri Jul 31 04:31:31 2026] 127.0.0.1:48522 Accepted +[Fri Jul 31 04:31:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 04:31:31 2026] 127.0.0.1:48522 [200]: GET /api/stats.php +[Fri Jul 31 04:31:31 2026] 127.0.0.1:48522 Closing +[Fri Jul 31 04:31:31 2026] 127.0.0.1:48536 Accepted +[Fri Jul 31 04:31:31 2026] 127.0.0.1:48536 [200]: GET /api/chart.php?range=year +[Fri Jul 31 04:31:31 2026] 127.0.0.1:48536 Closing +[Fri Jul 31 04:32:31 2026] 127.0.0.1:33474 Accepted +[Fri Jul 31 04:32:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 04:32:31 2026] 127.0.0.1:33474 [200]: GET /api/stats.php +[Fri Jul 31 04:32:31 2026] 127.0.0.1:33474 Closing +[Fri Jul 31 04:32:31 2026] 127.0.0.1:33490 Accepted +[Fri Jul 31 04:32:31 2026] 127.0.0.1:33490 [200]: GET /api/chart.php?range=year +[Fri Jul 31 04:32:31 2026] 127.0.0.1:33490 Closing +[Fri Jul 31 04:33:31 2026] 127.0.0.1:48456 Accepted +[Fri Jul 31 04:33:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 04:33:31 2026] 127.0.0.1:48456 [200]: GET /api/stats.php +[Fri Jul 31 04:33:31 2026] 127.0.0.1:48456 Closing +[Fri Jul 31 04:33:31 2026] 127.0.0.1:48462 Accepted +[Fri Jul 31 04:33:31 2026] 127.0.0.1:48462 [200]: GET /api/chart.php?range=year +[Fri Jul 31 04:33:31 2026] 127.0.0.1:48462 Closing +[Fri Jul 31 04:34:31 2026] 127.0.0.1:34234 Accepted +[Fri Jul 31 04:34:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 04:34:31 2026] 127.0.0.1:34234 [200]: GET /api/stats.php +[Fri Jul 31 04:34:31 2026] 127.0.0.1:34234 Closing +[Fri Jul 31 04:34:31 2026] 127.0.0.1:34242 Accepted +[Fri Jul 31 04:34:31 2026] 127.0.0.1:34242 [200]: GET /api/chart.php?range=year +[Fri Jul 31 04:34:31 2026] 127.0.0.1:34242 Closing +[Fri Jul 31 04:35:31 2026] 127.0.0.1:47046 Accepted +[Fri Jul 31 04:35:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 04:35:31 2026] 127.0.0.1:47046 [200]: GET /api/stats.php +[Fri Jul 31 04:35:31 2026] 127.0.0.1:47046 Closing +[Fri Jul 31 04:35:31 2026] 127.0.0.1:47052 Accepted +[Fri Jul 31 04:35:31 2026] 127.0.0.1:47052 [200]: GET /api/chart.php?range=year +[Fri Jul 31 04:35:31 2026] 127.0.0.1:47052 Closing +[Fri Jul 31 04:36:31 2026] 127.0.0.1:46016 Accepted +[Fri Jul 31 04:36:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 04:36:31 2026] 127.0.0.1:46016 [200]: GET /api/stats.php +[Fri Jul 31 04:36:31 2026] 127.0.0.1:46016 Closing +[Fri Jul 31 04:36:31 2026] 127.0.0.1:46026 Accepted +[Fri Jul 31 04:36:31 2026] 127.0.0.1:46026 [200]: GET /api/chart.php?range=year +[Fri Jul 31 04:36:31 2026] 127.0.0.1:46026 Closing +[Fri Jul 31 04:37:31 2026] 127.0.0.1:39706 Accepted +[Fri Jul 31 04:37:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 04:37:31 2026] 127.0.0.1:39706 [200]: GET /api/stats.php +[Fri Jul 31 04:37:31 2026] 127.0.0.1:39706 Closing +[Fri Jul 31 04:37:31 2026] 127.0.0.1:39720 Accepted +[Fri Jul 31 04:37:31 2026] 127.0.0.1:39720 [200]: GET /api/chart.php?range=year +[Fri Jul 31 04:37:31 2026] 127.0.0.1:39720 Closing +[Fri Jul 31 04:38:31 2026] 127.0.0.1:49978 Accepted +[Fri Jul 31 04:38:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 04:38:31 2026] 127.0.0.1:49978 [200]: GET /api/stats.php +[Fri Jul 31 04:38:31 2026] 127.0.0.1:49978 Closing +[Fri Jul 31 04:38:31 2026] 127.0.0.1:49994 Accepted +[Fri Jul 31 04:38:31 2026] 127.0.0.1:49994 [200]: GET /api/chart.php?range=year +[Fri Jul 31 04:38:31 2026] 127.0.0.1:49994 Closing +[Fri Jul 31 04:39:31 2026] 127.0.0.1:52832 Accepted +[Fri Jul 31 04:39:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 04:39:31 2026] 127.0.0.1:52832 [200]: GET /api/stats.php +[Fri Jul 31 04:39:31 2026] 127.0.0.1:52832 Closing +[Fri Jul 31 04:39:31 2026] 127.0.0.1:52846 Accepted +[Fri Jul 31 04:39:31 2026] 127.0.0.1:52846 [200]: GET /api/chart.php?range=year +[Fri Jul 31 04:39:31 2026] 127.0.0.1:52846 Closing +[Fri Jul 31 04:40:31 2026] 127.0.0.1:59674 Accepted +[Fri Jul 31 04:40:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 04:40:31 2026] 127.0.0.1:59674 [200]: GET /api/stats.php +[Fri Jul 31 04:40:31 2026] 127.0.0.1:59674 Closing +[Fri Jul 31 04:40:31 2026] 127.0.0.1:59686 Accepted +[Fri Jul 31 04:40:31 2026] 127.0.0.1:59686 [200]: GET /api/chart.php?range=year +[Fri Jul 31 04:40:31 2026] 127.0.0.1:59686 Closing +[Fri Jul 31 04:41:31 2026] 127.0.0.1:58172 Accepted +[Fri Jul 31 04:41:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 04:41:31 2026] 127.0.0.1:58172 [200]: GET /api/stats.php +[Fri Jul 31 04:41:31 2026] 127.0.0.1:58172 Closing +[Fri Jul 31 04:41:31 2026] 127.0.0.1:58186 Accepted +[Fri Jul 31 04:41:31 2026] 127.0.0.1:58186 [200]: GET /api/chart.php?range=year +[Fri Jul 31 04:41:31 2026] 127.0.0.1:58186 Closing +[Fri Jul 31 04:42:31 2026] 127.0.0.1:53242 Accepted +[Fri Jul 31 04:42:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 04:42:31 2026] 127.0.0.1:53242 [200]: GET /api/stats.php +[Fri Jul 31 04:42:31 2026] 127.0.0.1:53242 Closing +[Fri Jul 31 04:42:31 2026] 127.0.0.1:53250 Accepted +[Fri Jul 31 04:42:31 2026] 127.0.0.1:53250 [200]: GET /api/chart.php?range=year +[Fri Jul 31 04:42:31 2026] 127.0.0.1:53250 Closing +[Fri Jul 31 04:43:31 2026] 127.0.0.1:42808 Accepted +[Fri Jul 31 04:43:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 04:43:31 2026] 127.0.0.1:42808 [200]: GET /api/stats.php +[Fri Jul 31 04:43:31 2026] 127.0.0.1:42808 Closing +[Fri Jul 31 04:43:31 2026] 127.0.0.1:42816 Accepted +[Fri Jul 31 04:43:31 2026] 127.0.0.1:42816 [200]: GET /api/chart.php?range=year +[Fri Jul 31 04:43:31 2026] 127.0.0.1:42816 Closing +[Fri Jul 31 04:44:31 2026] 127.0.0.1:48484 Accepted +[Fri Jul 31 04:44:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 04:44:31 2026] 127.0.0.1:48484 [200]: GET /api/stats.php +[Fri Jul 31 04:44:31 2026] 127.0.0.1:48484 Closing +[Fri Jul 31 04:44:31 2026] 127.0.0.1:48494 Accepted +[Fri Jul 31 04:44:31 2026] 127.0.0.1:48494 [200]: GET /api/chart.php?range=year +[Fri Jul 31 04:44:31 2026] 127.0.0.1:48494 Closing +[Fri Jul 31 04:45:31 2026] 127.0.0.1:34986 Accepted +[Fri Jul 31 04:45:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 04:45:31 2026] 127.0.0.1:34986 [200]: GET /api/stats.php +[Fri Jul 31 04:45:31 2026] 127.0.0.1:34986 Closing +[Fri Jul 31 04:45:31 2026] 127.0.0.1:34990 Accepted +[Fri Jul 31 04:45:31 2026] 127.0.0.1:34990 [200]: GET /api/chart.php?range=year +[Fri Jul 31 04:45:31 2026] 127.0.0.1:34990 Closing +[Fri Jul 31 04:46:31 2026] 127.0.0.1:55056 Accepted +[Fri Jul 31 04:46:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 04:46:31 2026] 127.0.0.1:55056 [200]: GET /api/stats.php +[Fri Jul 31 04:46:31 2026] 127.0.0.1:55056 Closing +[Fri Jul 31 04:46:31 2026] 127.0.0.1:55068 Accepted +[Fri Jul 31 04:46:31 2026] 127.0.0.1:55068 [200]: GET /api/chart.php?range=year +[Fri Jul 31 04:46:31 2026] 127.0.0.1:55068 Closing +[Fri Jul 31 04:47:31 2026] 127.0.0.1:37656 Accepted +[Fri Jul 31 04:47:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 04:47:31 2026] 127.0.0.1:37656 [200]: GET /api/stats.php +[Fri Jul 31 04:47:31 2026] 127.0.0.1:37656 Closing +[Fri Jul 31 04:47:31 2026] 127.0.0.1:37666 Accepted +[Fri Jul 31 04:47:31 2026] 127.0.0.1:37666 [200]: GET /api/chart.php?range=year +[Fri Jul 31 04:47:31 2026] 127.0.0.1:37666 Closing +[Fri Jul 31 04:48:31 2026] 127.0.0.1:49970 Accepted +[Fri Jul 31 04:48:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 04:48:31 2026] 127.0.0.1:49970 [200]: GET /api/stats.php +[Fri Jul 31 04:48:31 2026] 127.0.0.1:49970 Closing +[Fri Jul 31 04:48:31 2026] 127.0.0.1:49972 Accepted +[Fri Jul 31 04:48:31 2026] 127.0.0.1:49972 [200]: GET /api/chart.php?range=year +[Fri Jul 31 04:48:31 2026] 127.0.0.1:49972 Closing +[Fri Jul 31 04:49:31 2026] 127.0.0.1:41234 Accepted +[Fri Jul 31 04:49:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 04:49:31 2026] 127.0.0.1:41234 [200]: GET /api/stats.php +[Fri Jul 31 04:49:31 2026] 127.0.0.1:41234 Closing +[Fri Jul 31 04:49:31 2026] 127.0.0.1:41250 Accepted +[Fri Jul 31 04:49:31 2026] 127.0.0.1:41250 [200]: GET /api/chart.php?range=year +[Fri Jul 31 04:49:31 2026] 127.0.0.1:41250 Closing +[Fri Jul 31 04:50:31 2026] 127.0.0.1:54806 Accepted +[Fri Jul 31 04:50:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 04:50:31 2026] 127.0.0.1:54806 [200]: GET /api/stats.php +[Fri Jul 31 04:50:31 2026] 127.0.0.1:54806 Closing +[Fri Jul 31 04:50:31 2026] 127.0.0.1:54810 Accepted +[Fri Jul 31 04:50:31 2026] 127.0.0.1:54810 [200]: GET /api/chart.php?range=year +[Fri Jul 31 04:50:31 2026] 127.0.0.1:54810 Closing +[Fri Jul 31 04:51:31 2026] 127.0.0.1:53308 Accepted +[Fri Jul 31 04:51:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 04:51:31 2026] 127.0.0.1:53308 [200]: GET /api/stats.php +[Fri Jul 31 04:51:31 2026] 127.0.0.1:53308 Closing +[Fri Jul 31 04:51:31 2026] 127.0.0.1:53318 Accepted +[Fri Jul 31 04:51:31 2026] 127.0.0.1:53318 [200]: GET /api/chart.php?range=year +[Fri Jul 31 04:51:31 2026] 127.0.0.1:53318 Closing +[Fri Jul 31 04:52:31 2026] 127.0.0.1:53734 Accepted +[Fri Jul 31 04:52:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 04:52:31 2026] 127.0.0.1:53734 [200]: GET /api/stats.php +[Fri Jul 31 04:52:31 2026] 127.0.0.1:53734 Closing +[Fri Jul 31 04:52:31 2026] 127.0.0.1:53748 Accepted +[Fri Jul 31 04:52:31 2026] 127.0.0.1:53748 [200]: GET /api/chart.php?range=year +[Fri Jul 31 04:52:31 2026] 127.0.0.1:53748 Closing +[Fri Jul 31 04:53:31 2026] 127.0.0.1:59088 Accepted +[Fri Jul 31 04:53:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 04:53:31 2026] 127.0.0.1:59088 [200]: GET /api/stats.php +[Fri Jul 31 04:53:31 2026] 127.0.0.1:59088 Closing +[Fri Jul 31 04:53:31 2026] 127.0.0.1:59094 Accepted +[Fri Jul 31 04:53:31 2026] 127.0.0.1:59094 [200]: GET /api/chart.php?range=year +[Fri Jul 31 04:53:31 2026] 127.0.0.1:59094 Closing +[Fri Jul 31 04:54:31 2026] 127.0.0.1:59542 Accepted +[Fri Jul 31 04:54:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 04:54:31 2026] 127.0.0.1:59542 [200]: GET /api/stats.php +[Fri Jul 31 04:54:31 2026] 127.0.0.1:59542 Closing +[Fri Jul 31 04:54:31 2026] 127.0.0.1:59546 Accepted +[Fri Jul 31 04:54:31 2026] 127.0.0.1:59546 [200]: GET /api/chart.php?range=year +[Fri Jul 31 04:54:31 2026] 127.0.0.1:59546 Closing +[Fri Jul 31 04:55:31 2026] 127.0.0.1:56122 Accepted +[Fri Jul 31 04:55:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 04:55:31 2026] 127.0.0.1:56122 [200]: GET /api/stats.php +[Fri Jul 31 04:55:31 2026] 127.0.0.1:56122 Closing +[Fri Jul 31 04:55:31 2026] 127.0.0.1:56126 Accepted +[Fri Jul 31 04:55:31 2026] 127.0.0.1:56126 [200]: GET /api/chart.php?range=year +[Fri Jul 31 04:55:31 2026] 127.0.0.1:56126 Closing +[Fri Jul 31 04:56:31 2026] 127.0.0.1:37156 Accepted +[Fri Jul 31 04:56:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 04:56:31 2026] 127.0.0.1:37156 [200]: GET /api/stats.php +[Fri Jul 31 04:56:31 2026] 127.0.0.1:37156 Closing +[Fri Jul 31 04:56:31 2026] 127.0.0.1:37168 Accepted +[Fri Jul 31 04:56:31 2026] 127.0.0.1:37168 [200]: GET /api/chart.php?range=year +[Fri Jul 31 04:56:31 2026] 127.0.0.1:37168 Closing +[Fri Jul 31 04:57:31 2026] 127.0.0.1:49130 Accepted +[Fri Jul 31 04:57:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 04:57:31 2026] 127.0.0.1:49130 [200]: GET /api/stats.php +[Fri Jul 31 04:57:31 2026] 127.0.0.1:49130 Closing +[Fri Jul 31 04:57:31 2026] 127.0.0.1:49132 Accepted +[Fri Jul 31 04:57:31 2026] 127.0.0.1:49132 [200]: GET /api/chart.php?range=year +[Fri Jul 31 04:57:31 2026] 127.0.0.1:49132 Closing +[Fri Jul 31 04:58:31 2026] 127.0.0.1:39818 Accepted +[Fri Jul 31 04:58:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 04:58:31 2026] 127.0.0.1:39818 [200]: GET /api/stats.php +[Fri Jul 31 04:58:31 2026] 127.0.0.1:39818 Closing +[Fri Jul 31 04:58:31 2026] 127.0.0.1:39832 Accepted +[Fri Jul 31 04:58:31 2026] 127.0.0.1:39832 [200]: GET /api/chart.php?range=year +[Fri Jul 31 04:58:31 2026] 127.0.0.1:39832 Closing +[Fri Jul 31 04:59:31 2026] 127.0.0.1:48810 Accepted +[Fri Jul 31 04:59:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 04:59:31 2026] 127.0.0.1:48810 [200]: GET /api/stats.php +[Fri Jul 31 04:59:31 2026] 127.0.0.1:48810 Closing +[Fri Jul 31 04:59:31 2026] 127.0.0.1:48826 Accepted +[Fri Jul 31 04:59:31 2026] 127.0.0.1:48826 [200]: GET /api/chart.php?range=year +[Fri Jul 31 04:59:31 2026] 127.0.0.1:48826 Closing +[Fri Jul 31 05:00:31 2026] 127.0.0.1:33738 Accepted +[Fri Jul 31 05:00:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 05:00:31 2026] 127.0.0.1:33738 [200]: GET /api/stats.php +[Fri Jul 31 05:00:31 2026] 127.0.0.1:33738 Closing +[Fri Jul 31 05:00:31 2026] 127.0.0.1:33744 Accepted +[Fri Jul 31 05:00:31 2026] 127.0.0.1:33744 [200]: GET /api/chart.php?range=year +[Fri Jul 31 05:00:31 2026] 127.0.0.1:33744 Closing +[Fri Jul 31 05:01:31 2026] 127.0.0.1:60080 Accepted +[Fri Jul 31 05:01:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 05:01:31 2026] 127.0.0.1:60080 [200]: GET /api/stats.php +[Fri Jul 31 05:01:31 2026] 127.0.0.1:60080 Closing +[Fri Jul 31 05:01:31 2026] 127.0.0.1:60084 Accepted +[Fri Jul 31 05:01:31 2026] 127.0.0.1:60084 [200]: GET /api/chart.php?range=year +[Fri Jul 31 05:01:31 2026] 127.0.0.1:60084 Closing +[Fri Jul 31 05:02:31 2026] 127.0.0.1:60048 Accepted +[Fri Jul 31 05:02:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 05:02:31 2026] 127.0.0.1:60048 [200]: GET /api/stats.php +[Fri Jul 31 05:02:31 2026] 127.0.0.1:60048 Closing +[Fri Jul 31 05:02:31 2026] 127.0.0.1:60064 Accepted +[Fri Jul 31 05:02:31 2026] 127.0.0.1:60064 [200]: GET /api/chart.php?range=year +[Fri Jul 31 05:02:31 2026] 127.0.0.1:60064 Closing +[Fri Jul 31 05:03:31 2026] 127.0.0.1:53284 Accepted +[Fri Jul 31 05:03:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 05:03:31 2026] 127.0.0.1:53284 [200]: GET /api/stats.php +[Fri Jul 31 05:03:31 2026] 127.0.0.1:53284 Closing +[Fri Jul 31 05:03:31 2026] 127.0.0.1:53298 Accepted +[Fri Jul 31 05:03:31 2026] 127.0.0.1:53298 [200]: GET /api/chart.php?range=year +[Fri Jul 31 05:03:31 2026] 127.0.0.1:53298 Closing +[Fri Jul 31 05:04:31 2026] 127.0.0.1:47248 Accepted +[Fri Jul 31 05:04:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 05:04:31 2026] 127.0.0.1:47248 [200]: GET /api/stats.php +[Fri Jul 31 05:04:31 2026] 127.0.0.1:47248 Closing +[Fri Jul 31 05:04:31 2026] 127.0.0.1:47264 Accepted +[Fri Jul 31 05:04:31 2026] 127.0.0.1:47264 [200]: GET /api/chart.php?range=year +[Fri Jul 31 05:04:31 2026] 127.0.0.1:47264 Closing +[Fri Jul 31 05:05:31 2026] 127.0.0.1:35490 Accepted +[Fri Jul 31 05:05:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 05:05:31 2026] 127.0.0.1:35490 [200]: GET /api/stats.php +[Fri Jul 31 05:05:31 2026] 127.0.0.1:35490 Closing +[Fri Jul 31 05:05:31 2026] 127.0.0.1:35502 Accepted +[Fri Jul 31 05:05:31 2026] 127.0.0.1:35502 [200]: GET /api/chart.php?range=year +[Fri Jul 31 05:05:31 2026] 127.0.0.1:35502 Closing +[Fri Jul 31 05:06:31 2026] 127.0.0.1:48632 Accepted +[Fri Jul 31 05:06:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 05:06:31 2026] 127.0.0.1:48632 [200]: GET /api/stats.php +[Fri Jul 31 05:06:31 2026] 127.0.0.1:48632 Closing +[Fri Jul 31 05:06:31 2026] 127.0.0.1:48642 Accepted +[Fri Jul 31 05:06:31 2026] 127.0.0.1:48642 [200]: GET /api/chart.php?range=year +[Fri Jul 31 05:06:31 2026] 127.0.0.1:48642 Closing +[Fri Jul 31 05:07:31 2026] 127.0.0.1:45190 Accepted +[Fri Jul 31 05:07:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 05:07:31 2026] 127.0.0.1:45190 [200]: GET /api/stats.php +[Fri Jul 31 05:07:31 2026] 127.0.0.1:45190 Closing +[Fri Jul 31 05:07:31 2026] 127.0.0.1:45194 Accepted +[Fri Jul 31 05:07:31 2026] 127.0.0.1:45194 [200]: GET /api/chart.php?range=year +[Fri Jul 31 05:07:31 2026] 127.0.0.1:45194 Closing +[Fri Jul 31 05:08:31 2026] 127.0.0.1:58516 Accepted +[Fri Jul 31 05:08:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 05:08:31 2026] 127.0.0.1:58516 [200]: GET /api/stats.php +[Fri Jul 31 05:08:31 2026] 127.0.0.1:58516 Closing +[Fri Jul 31 05:08:31 2026] 127.0.0.1:58532 Accepted +[Fri Jul 31 05:08:31 2026] 127.0.0.1:58532 [200]: GET /api/chart.php?range=year +[Fri Jul 31 05:08:31 2026] 127.0.0.1:58532 Closing +[Fri Jul 31 05:09:31 2026] 127.0.0.1:53028 Accepted +[Fri Jul 31 05:09:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 05:09:31 2026] 127.0.0.1:53028 [200]: GET /api/stats.php +[Fri Jul 31 05:09:31 2026] 127.0.0.1:53028 Closing +[Fri Jul 31 05:09:31 2026] 127.0.0.1:53038 Accepted +[Fri Jul 31 05:09:31 2026] 127.0.0.1:53038 [200]: GET /api/chart.php?range=year +[Fri Jul 31 05:09:31 2026] 127.0.0.1:53038 Closing +[Fri Jul 31 05:10:31 2026] 127.0.0.1:36634 Accepted +[Fri Jul 31 05:10:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 05:10:31 2026] 127.0.0.1:36634 [200]: GET /api/stats.php +[Fri Jul 31 05:10:31 2026] 127.0.0.1:36634 Closing +[Fri Jul 31 05:10:31 2026] 127.0.0.1:36642 Accepted +[Fri Jul 31 05:10:31 2026] 127.0.0.1:36642 [200]: GET /api/chart.php?range=year +[Fri Jul 31 05:10:31 2026] 127.0.0.1:36642 Closing +[Fri Jul 31 05:11:31 2026] 127.0.0.1:43188 Accepted +[Fri Jul 31 05:11:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 05:11:31 2026] 127.0.0.1:43188 [200]: GET /api/stats.php +[Fri Jul 31 05:11:31 2026] 127.0.0.1:43188 Closing +[Fri Jul 31 05:11:31 2026] 127.0.0.1:43204 Accepted +[Fri Jul 31 05:11:31 2026] 127.0.0.1:43204 [200]: GET /api/chart.php?range=year +[Fri Jul 31 05:11:31 2026] 127.0.0.1:43204 Closing +[Fri Jul 31 05:12:31 2026] 127.0.0.1:58012 Accepted +[Fri Jul 31 05:12:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 05:12:31 2026] 127.0.0.1:58012 [200]: GET /api/stats.php +[Fri Jul 31 05:12:31 2026] 127.0.0.1:58012 Closing +[Fri Jul 31 05:12:31 2026] 127.0.0.1:58020 Accepted +[Fri Jul 31 05:12:31 2026] 127.0.0.1:58020 [200]: GET /api/chart.php?range=year +[Fri Jul 31 05:12:31 2026] 127.0.0.1:58020 Closing +[Fri Jul 31 05:13:31 2026] 127.0.0.1:48762 Accepted +[Fri Jul 31 05:13:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 05:13:31 2026] 127.0.0.1:48762 [200]: GET /api/stats.php +[Fri Jul 31 05:13:31 2026] 127.0.0.1:48762 Closing +[Fri Jul 31 05:13:31 2026] 127.0.0.1:48778 Accepted +[Fri Jul 31 05:13:31 2026] 127.0.0.1:48778 [200]: GET /api/chart.php?range=year +[Fri Jul 31 05:13:31 2026] 127.0.0.1:48778 Closing +[Fri Jul 31 05:14:31 2026] 127.0.0.1:53990 Accepted +[Fri Jul 31 05:14:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 05:14:31 2026] 127.0.0.1:53990 [200]: GET /api/stats.php +[Fri Jul 31 05:14:31 2026] 127.0.0.1:53990 Closing +[Fri Jul 31 05:14:31 2026] 127.0.0.1:54004 Accepted +[Fri Jul 31 05:14:31 2026] 127.0.0.1:54004 [200]: GET /api/chart.php?range=year +[Fri Jul 31 05:14:31 2026] 127.0.0.1:54004 Closing +[Fri Jul 31 05:15:31 2026] 127.0.0.1:44434 Accepted +[Fri Jul 31 05:15:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 05:15:31 2026] 127.0.0.1:44434 [200]: GET /api/stats.php +[Fri Jul 31 05:15:31 2026] 127.0.0.1:44434 Closing +[Fri Jul 31 05:15:31 2026] 127.0.0.1:44442 Accepted +[Fri Jul 31 05:15:31 2026] 127.0.0.1:44442 [200]: GET /api/chart.php?range=year +[Fri Jul 31 05:15:31 2026] 127.0.0.1:44442 Closing +[Fri Jul 31 05:16:31 2026] 127.0.0.1:49684 Accepted +[Fri Jul 31 05:16:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 05:16:31 2026] 127.0.0.1:49684 [200]: GET /api/stats.php +[Fri Jul 31 05:16:31 2026] 127.0.0.1:49684 Closing +[Fri Jul 31 05:16:31 2026] 127.0.0.1:49694 Accepted +[Fri Jul 31 05:16:31 2026] 127.0.0.1:49694 [200]: GET /api/chart.php?range=year +[Fri Jul 31 05:16:31 2026] 127.0.0.1:49694 Closing +[Fri Jul 31 05:17:31 2026] 127.0.0.1:44076 Accepted +[Fri Jul 31 05:17:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 05:17:31 2026] 127.0.0.1:44076 [200]: GET /api/stats.php +[Fri Jul 31 05:17:31 2026] 127.0.0.1:44076 Closing +[Fri Jul 31 05:17:31 2026] 127.0.0.1:44086 Accepted +[Fri Jul 31 05:17:31 2026] 127.0.0.1:44086 [200]: GET /api/chart.php?range=year +[Fri Jul 31 05:17:31 2026] 127.0.0.1:44086 Closing +[Fri Jul 31 05:18:31 2026] 127.0.0.1:33346 Accepted +[Fri Jul 31 05:18:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 05:18:31 2026] 127.0.0.1:33346 [200]: GET /api/stats.php +[Fri Jul 31 05:18:31 2026] 127.0.0.1:33346 Closing +[Fri Jul 31 05:18:31 2026] 127.0.0.1:33350 Accepted +[Fri Jul 31 05:18:31 2026] 127.0.0.1:33350 [200]: GET /api/chart.php?range=year +[Fri Jul 31 05:18:31 2026] 127.0.0.1:33350 Closing +[Fri Jul 31 05:19:31 2026] 127.0.0.1:44610 Accepted +[Fri Jul 31 05:19:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 05:19:31 2026] 127.0.0.1:44610 [200]: GET /api/stats.php +[Fri Jul 31 05:19:31 2026] 127.0.0.1:44610 Closing +[Fri Jul 31 05:19:31 2026] 127.0.0.1:44622 Accepted +[Fri Jul 31 05:19:31 2026] 127.0.0.1:44622 [200]: GET /api/chart.php?range=year +[Fri Jul 31 05:19:31 2026] 127.0.0.1:44622 Closing +[Fri Jul 31 05:20:31 2026] 127.0.0.1:35580 Accepted +[Fri Jul 31 05:20:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 05:20:31 2026] 127.0.0.1:35580 [200]: GET /api/stats.php +[Fri Jul 31 05:20:31 2026] 127.0.0.1:35580 Closing +[Fri Jul 31 05:20:31 2026] 127.0.0.1:35590 Accepted +[Fri Jul 31 05:20:31 2026] 127.0.0.1:35590 [200]: GET /api/chart.php?range=year +[Fri Jul 31 05:20:31 2026] 127.0.0.1:35590 Closing +[Fri Jul 31 05:21:31 2026] 127.0.0.1:42300 Accepted +[Fri Jul 31 05:21:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 05:21:31 2026] 127.0.0.1:42300 [200]: GET /api/stats.php +[Fri Jul 31 05:21:31 2026] 127.0.0.1:42300 Closing +[Fri Jul 31 05:21:31 2026] 127.0.0.1:42312 Accepted +[Fri Jul 31 05:21:31 2026] 127.0.0.1:42312 [200]: GET /api/chart.php?range=year +[Fri Jul 31 05:21:31 2026] 127.0.0.1:42312 Closing +[Fri Jul 31 05:22:31 2026] 127.0.0.1:54222 Accepted +[Fri Jul 31 05:22:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 05:22:31 2026] 127.0.0.1:54222 [200]: GET /api/stats.php +[Fri Jul 31 05:22:31 2026] 127.0.0.1:54222 Closing +[Fri Jul 31 05:22:31 2026] 127.0.0.1:54228 Accepted +[Fri Jul 31 05:22:31 2026] 127.0.0.1:54228 [200]: GET /api/chart.php?range=year +[Fri Jul 31 05:22:31 2026] 127.0.0.1:54228 Closing +[Fri Jul 31 05:23:31 2026] 127.0.0.1:40586 Accepted +[Fri Jul 31 05:23:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 05:23:31 2026] 127.0.0.1:40586 [200]: GET /api/stats.php +[Fri Jul 31 05:23:31 2026] 127.0.0.1:40586 Closing +[Fri Jul 31 05:23:31 2026] 127.0.0.1:40594 Accepted +[Fri Jul 31 05:23:31 2026] 127.0.0.1:40594 [200]: GET /api/chart.php?range=year +[Fri Jul 31 05:23:31 2026] 127.0.0.1:40594 Closing +[Fri Jul 31 05:24:31 2026] 127.0.0.1:40942 Accepted +[Fri Jul 31 05:24:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 05:24:31 2026] 127.0.0.1:40942 [200]: GET /api/stats.php +[Fri Jul 31 05:24:31 2026] 127.0.0.1:40942 Closing +[Fri Jul 31 05:24:31 2026] 127.0.0.1:40952 Accepted +[Fri Jul 31 05:24:31 2026] 127.0.0.1:40952 [200]: GET /api/chart.php?range=year +[Fri Jul 31 05:24:31 2026] 127.0.0.1:40952 Closing +[Fri Jul 31 05:25:31 2026] 127.0.0.1:55210 Accepted +[Fri Jul 31 05:25:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 05:25:31 2026] 127.0.0.1:55210 [200]: GET /api/stats.php +[Fri Jul 31 05:25:31 2026] 127.0.0.1:55210 Closing +[Fri Jul 31 05:25:31 2026] 127.0.0.1:55214 Accepted +[Fri Jul 31 05:25:31 2026] 127.0.0.1:55214 [200]: GET /api/chart.php?range=year +[Fri Jul 31 05:25:31 2026] 127.0.0.1:55214 Closing +[Fri Jul 31 05:26:31 2026] 127.0.0.1:45990 Accepted +[Fri Jul 31 05:26:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 05:26:31 2026] 127.0.0.1:45990 [200]: GET /api/stats.php +[Fri Jul 31 05:26:31 2026] 127.0.0.1:45990 Closing +[Fri Jul 31 05:26:31 2026] 127.0.0.1:46002 Accepted +[Fri Jul 31 05:26:31 2026] 127.0.0.1:46002 [200]: GET /api/chart.php?range=year +[Fri Jul 31 05:26:31 2026] 127.0.0.1:46002 Closing +[Fri Jul 31 05:27:31 2026] 127.0.0.1:53766 Accepted +[Fri Jul 31 05:27:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 05:27:31 2026] 127.0.0.1:53766 [200]: GET /api/stats.php +[Fri Jul 31 05:27:31 2026] 127.0.0.1:53766 Closing +[Fri Jul 31 05:27:31 2026] 127.0.0.1:53782 Accepted +[Fri Jul 31 05:27:31 2026] 127.0.0.1:53782 [200]: GET /api/chart.php?range=year +[Fri Jul 31 05:27:31 2026] 127.0.0.1:53782 Closing +[Fri Jul 31 05:28:31 2026] 127.0.0.1:33684 Accepted +[Fri Jul 31 05:28:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 05:28:31 2026] 127.0.0.1:33684 [200]: GET /api/stats.php +[Fri Jul 31 05:28:31 2026] 127.0.0.1:33684 Closing +[Fri Jul 31 05:28:31 2026] 127.0.0.1:33698 Accepted +[Fri Jul 31 05:28:31 2026] 127.0.0.1:33698 [200]: GET /api/chart.php?range=year +[Fri Jul 31 05:28:31 2026] 127.0.0.1:33698 Closing +[Fri Jul 31 05:29:31 2026] 127.0.0.1:60648 Accepted +[Fri Jul 31 05:29:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 05:29:31 2026] 127.0.0.1:60648 [200]: GET /api/stats.php +[Fri Jul 31 05:29:31 2026] 127.0.0.1:60648 Closing +[Fri Jul 31 05:29:31 2026] 127.0.0.1:60660 Accepted +[Fri Jul 31 05:29:31 2026] 127.0.0.1:60660 [200]: GET /api/chart.php?range=year +[Fri Jul 31 05:29:31 2026] 127.0.0.1:60660 Closing +[Fri Jul 31 05:30:31 2026] 127.0.0.1:43388 Accepted +[Fri Jul 31 05:30:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 05:30:31 2026] 127.0.0.1:43388 [200]: GET /api/stats.php +[Fri Jul 31 05:30:31 2026] 127.0.0.1:43388 Closing +[Fri Jul 31 05:30:31 2026] 127.0.0.1:43400 Accepted +[Fri Jul 31 05:30:31 2026] 127.0.0.1:43400 [200]: GET /api/chart.php?range=year +[Fri Jul 31 05:30:31 2026] 127.0.0.1:43400 Closing +[Fri Jul 31 05:31:31 2026] 127.0.0.1:45732 Accepted +[Fri Jul 31 05:31:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 05:31:31 2026] 127.0.0.1:45732 [200]: GET /api/stats.php +[Fri Jul 31 05:31:31 2026] 127.0.0.1:45732 Closing +[Fri Jul 31 05:31:31 2026] 127.0.0.1:45748 Accepted +[Fri Jul 31 05:31:31 2026] 127.0.0.1:45748 [200]: GET /api/chart.php?range=year +[Fri Jul 31 05:31:31 2026] 127.0.0.1:45748 Closing +[Fri Jul 31 05:32:31 2026] 127.0.0.1:58726 Accepted +[Fri Jul 31 05:32:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 05:32:31 2026] 127.0.0.1:58726 [200]: GET /api/stats.php +[Fri Jul 31 05:32:31 2026] 127.0.0.1:58726 Closing +[Fri Jul 31 05:32:31 2026] 127.0.0.1:58732 Accepted +[Fri Jul 31 05:32:31 2026] 127.0.0.1:58732 [200]: GET /api/chart.php?range=year +[Fri Jul 31 05:32:31 2026] 127.0.0.1:58732 Closing +[Fri Jul 31 05:33:31 2026] 127.0.0.1:49020 Accepted +[Fri Jul 31 05:33:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 05:33:31 2026] 127.0.0.1:49020 [200]: GET /api/stats.php +[Fri Jul 31 05:33:31 2026] 127.0.0.1:49020 Closing +[Fri Jul 31 05:33:31 2026] 127.0.0.1:49028 Accepted +[Fri Jul 31 05:33:31 2026] 127.0.0.1:49028 [200]: GET /api/chart.php?range=year +[Fri Jul 31 05:33:31 2026] 127.0.0.1:49028 Closing +[Fri Jul 31 05:34:31 2026] 127.0.0.1:50674 Accepted +[Fri Jul 31 05:34:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 05:34:31 2026] 127.0.0.1:50674 [200]: GET /api/stats.php +[Fri Jul 31 05:34:31 2026] 127.0.0.1:50674 Closing +[Fri Jul 31 05:34:31 2026] 127.0.0.1:50682 Accepted +[Fri Jul 31 05:34:31 2026] 127.0.0.1:50682 [200]: GET /api/chart.php?range=year +[Fri Jul 31 05:34:31 2026] 127.0.0.1:50682 Closing +[Fri Jul 31 05:35:31 2026] 127.0.0.1:50428 Accepted +[Fri Jul 31 05:35:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 05:35:31 2026] 127.0.0.1:50428 [200]: GET /api/stats.php +[Fri Jul 31 05:35:31 2026] 127.0.0.1:50428 Closing +[Fri Jul 31 05:35:31 2026] 127.0.0.1:50442 Accepted +[Fri Jul 31 05:35:31 2026] 127.0.0.1:50442 [200]: GET /api/chart.php?range=year +[Fri Jul 31 05:35:31 2026] 127.0.0.1:50442 Closing +[Fri Jul 31 05:36:31 2026] 127.0.0.1:58464 Accepted +[Fri Jul 31 05:36:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 05:36:31 2026] 127.0.0.1:58464 [200]: GET /api/stats.php +[Fri Jul 31 05:36:31 2026] 127.0.0.1:58464 Closing +[Fri Jul 31 05:36:31 2026] 127.0.0.1:58470 Accepted +[Fri Jul 31 05:36:31 2026] 127.0.0.1:58470 [200]: GET /api/chart.php?range=year +[Fri Jul 31 05:36:31 2026] 127.0.0.1:58470 Closing +[Fri Jul 31 05:37:31 2026] 127.0.0.1:53340 Accepted +[Fri Jul 31 05:37:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 05:37:31 2026] 127.0.0.1:53340 [200]: GET /api/stats.php +[Fri Jul 31 05:37:31 2026] 127.0.0.1:53340 Closing +[Fri Jul 31 05:37:31 2026] 127.0.0.1:53344 Accepted +[Fri Jul 31 05:37:31 2026] 127.0.0.1:53344 [200]: GET /api/chart.php?range=year +[Fri Jul 31 05:37:31 2026] 127.0.0.1:53344 Closing +[Fri Jul 31 05:38:31 2026] 127.0.0.1:49274 Accepted +[Fri Jul 31 05:38:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 05:38:31 2026] 127.0.0.1:49274 [200]: GET /api/stats.php +[Fri Jul 31 05:38:31 2026] 127.0.0.1:49274 Closing +[Fri Jul 31 05:38:31 2026] 127.0.0.1:49280 Accepted +[Fri Jul 31 05:38:31 2026] 127.0.0.1:49280 [200]: GET /api/chart.php?range=year +[Fri Jul 31 05:38:31 2026] 127.0.0.1:49280 Closing +[Fri Jul 31 05:39:31 2026] 127.0.0.1:44982 Accepted +[Fri Jul 31 05:39:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 05:39:31 2026] 127.0.0.1:44982 [200]: GET /api/stats.php +[Fri Jul 31 05:39:31 2026] 127.0.0.1:44982 Closing +[Fri Jul 31 05:39:31 2026] 127.0.0.1:44990 Accepted +[Fri Jul 31 05:39:31 2026] 127.0.0.1:44990 [200]: GET /api/chart.php?range=year +[Fri Jul 31 05:39:31 2026] 127.0.0.1:44990 Closing +[Fri Jul 31 05:40:31 2026] 127.0.0.1:54940 Accepted +[Fri Jul 31 05:40:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 05:40:31 2026] 127.0.0.1:54940 [200]: GET /api/stats.php +[Fri Jul 31 05:40:31 2026] 127.0.0.1:54940 Closing +[Fri Jul 31 05:40:31 2026] 127.0.0.1:54946 Accepted +[Fri Jul 31 05:40:31 2026] 127.0.0.1:54946 [200]: GET /api/chart.php?range=year +[Fri Jul 31 05:40:31 2026] 127.0.0.1:54946 Closing +[Fri Jul 31 05:41:31 2026] 127.0.0.1:55120 Accepted +[Fri Jul 31 05:41:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 05:41:31 2026] 127.0.0.1:55120 [200]: GET /api/stats.php +[Fri Jul 31 05:41:31 2026] 127.0.0.1:55120 Closing +[Fri Jul 31 05:41:31 2026] 127.0.0.1:55128 Accepted +[Fri Jul 31 05:41:31 2026] 127.0.0.1:55128 [200]: GET /api/chart.php?range=year +[Fri Jul 31 05:41:31 2026] 127.0.0.1:55128 Closing +[Fri Jul 31 05:42:31 2026] 127.0.0.1:54370 Accepted +[Fri Jul 31 05:42:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 05:42:31 2026] 127.0.0.1:54370 [200]: GET /api/stats.php +[Fri Jul 31 05:42:31 2026] 127.0.0.1:54370 Closing +[Fri Jul 31 05:42:31 2026] 127.0.0.1:54372 Accepted +[Fri Jul 31 05:42:31 2026] 127.0.0.1:54372 [200]: GET /api/chart.php?range=year +[Fri Jul 31 05:42:31 2026] 127.0.0.1:54372 Closing +[Fri Jul 31 05:43:31 2026] 127.0.0.1:45434 Accepted +[Fri Jul 31 05:43:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 05:43:31 2026] 127.0.0.1:45434 [200]: GET /api/stats.php +[Fri Jul 31 05:43:31 2026] 127.0.0.1:45434 Closing +[Fri Jul 31 05:43:31 2026] 127.0.0.1:45446 Accepted +[Fri Jul 31 05:43:31 2026] 127.0.0.1:45446 [200]: GET /api/chart.php?range=year +[Fri Jul 31 05:43:31 2026] 127.0.0.1:45446 Closing +[Fri Jul 31 05:44:31 2026] 127.0.0.1:40944 Accepted +[Fri Jul 31 05:44:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 05:44:31 2026] 127.0.0.1:40944 [200]: GET /api/stats.php +[Fri Jul 31 05:44:31 2026] 127.0.0.1:40944 Closing +[Fri Jul 31 05:44:31 2026] 127.0.0.1:40946 Accepted +[Fri Jul 31 05:44:31 2026] 127.0.0.1:40946 [200]: GET /api/chart.php?range=year +[Fri Jul 31 05:44:31 2026] 127.0.0.1:40946 Closing +[Fri Jul 31 05:45:31 2026] 127.0.0.1:52374 Accepted +[Fri Jul 31 05:45:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 05:45:31 2026] 127.0.0.1:52374 [200]: GET /api/stats.php +[Fri Jul 31 05:45:31 2026] 127.0.0.1:52374 Closing +[Fri Jul 31 05:45:31 2026] 127.0.0.1:52388 Accepted +[Fri Jul 31 05:45:31 2026] 127.0.0.1:52388 [200]: GET /api/chart.php?range=year +[Fri Jul 31 05:45:31 2026] 127.0.0.1:52388 Closing +[Fri Jul 31 05:46:31 2026] 127.0.0.1:34234 Accepted +[Fri Jul 31 05:46:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 05:46:31 2026] 127.0.0.1:34234 [200]: GET /api/stats.php +[Fri Jul 31 05:46:31 2026] 127.0.0.1:34234 Closing +[Fri Jul 31 05:46:31 2026] 127.0.0.1:34240 Accepted +[Fri Jul 31 05:46:31 2026] 127.0.0.1:34240 [200]: GET /api/chart.php?range=year +[Fri Jul 31 05:46:31 2026] 127.0.0.1:34240 Closing +[Fri Jul 31 05:47:31 2026] 127.0.0.1:42260 Accepted +[Fri Jul 31 05:47:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 05:47:31 2026] 127.0.0.1:42260 [200]: GET /api/stats.php +[Fri Jul 31 05:47:31 2026] 127.0.0.1:42260 Closing +[Fri Jul 31 05:47:31 2026] 127.0.0.1:42274 Accepted +[Fri Jul 31 05:47:31 2026] 127.0.0.1:42274 [200]: GET /api/chart.php?range=year +[Fri Jul 31 05:47:31 2026] 127.0.0.1:42274 Closing +[Fri Jul 31 05:48:31 2026] 127.0.0.1:55802 Accepted +[Fri Jul 31 05:48:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 05:48:31 2026] 127.0.0.1:55802 [200]: GET /api/stats.php +[Fri Jul 31 05:48:31 2026] 127.0.0.1:55802 Closing +[Fri Jul 31 05:48:31 2026] 127.0.0.1:55808 Accepted +[Fri Jul 31 05:48:31 2026] 127.0.0.1:55808 [200]: GET /api/chart.php?range=year +[Fri Jul 31 05:48:31 2026] 127.0.0.1:55808 Closing +[Fri Jul 31 05:49:31 2026] 127.0.0.1:39522 Accepted +[Fri Jul 31 05:49:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 05:49:32 2026] 127.0.0.1:39522 [200]: GET /api/stats.php +[Fri Jul 31 05:49:32 2026] 127.0.0.1:39522 Closing +[Fri Jul 31 05:49:32 2026] 127.0.0.1:39526 Accepted +[Fri Jul 31 05:49:32 2026] 127.0.0.1:39526 [200]: GET /api/chart.php?range=year +[Fri Jul 31 05:49:32 2026] 127.0.0.1:39526 Closing +[Fri Jul 31 05:50:31 2026] 127.0.0.1:57086 Accepted +[Fri Jul 31 05:50:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 05:50:31 2026] 127.0.0.1:57086 [200]: GET /api/stats.php +[Fri Jul 31 05:50:31 2026] 127.0.0.1:57086 Closing +[Fri Jul 31 05:50:31 2026] 127.0.0.1:57096 Accepted +[Fri Jul 31 05:50:31 2026] 127.0.0.1:57096 [200]: GET /api/chart.php?range=year +[Fri Jul 31 05:50:31 2026] 127.0.0.1:57096 Closing +[Fri Jul 31 05:51:31 2026] 127.0.0.1:33556 Accepted +[Fri Jul 31 05:51:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 05:51:32 2026] 127.0.0.1:33556 [200]: GET /api/stats.php +[Fri Jul 31 05:51:32 2026] 127.0.0.1:33556 Closing +[Fri Jul 31 05:51:32 2026] 127.0.0.1:33560 Accepted +[Fri Jul 31 05:51:32 2026] 127.0.0.1:33560 [200]: GET /api/chart.php?range=year +[Fri Jul 31 05:51:32 2026] 127.0.0.1:33560 Closing +[Fri Jul 31 05:52:31 2026] 127.0.0.1:36388 Accepted +[Fri Jul 31 05:52:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 05:52:31 2026] 127.0.0.1:36388 [200]: GET /api/stats.php +[Fri Jul 31 05:52:31 2026] 127.0.0.1:36388 Closing +[Fri Jul 31 05:52:31 2026] 127.0.0.1:36402 Accepted +[Fri Jul 31 05:52:31 2026] 127.0.0.1:36402 [200]: GET /api/chart.php?range=year +[Fri Jul 31 05:52:31 2026] 127.0.0.1:36402 Closing +[Fri Jul 31 05:53:31 2026] 127.0.0.1:50428 Accepted +[Fri Jul 31 05:53:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 05:53:31 2026] 127.0.0.1:50428 [200]: GET /api/stats.php +[Fri Jul 31 05:53:31 2026] 127.0.0.1:50428 Closing +[Fri Jul 31 05:53:31 2026] 127.0.0.1:50440 Accepted +[Fri Jul 31 05:53:31 2026] 127.0.0.1:50440 [200]: GET /api/chart.php?range=year +[Fri Jul 31 05:53:31 2026] 127.0.0.1:50440 Closing +[Fri Jul 31 05:54:31 2026] 127.0.0.1:47682 Accepted +[Fri Jul 31 05:54:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 05:54:31 2026] 127.0.0.1:47682 [200]: GET /api/stats.php +[Fri Jul 31 05:54:31 2026] 127.0.0.1:47682 Closing +[Fri Jul 31 05:54:31 2026] 127.0.0.1:47696 Accepted +[Fri Jul 31 05:54:31 2026] 127.0.0.1:47696 [200]: GET /api/chart.php?range=year +[Fri Jul 31 05:54:31 2026] 127.0.0.1:47696 Closing +[Fri Jul 31 05:55:31 2026] 127.0.0.1:52456 Accepted +[Fri Jul 31 05:55:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 05:55:31 2026] 127.0.0.1:52456 [200]: GET /api/stats.php +[Fri Jul 31 05:55:31 2026] 127.0.0.1:52456 Closing +[Fri Jul 31 05:55:31 2026] 127.0.0.1:52470 Accepted +[Fri Jul 31 05:55:31 2026] 127.0.0.1:52470 [200]: GET /api/chart.php?range=year +[Fri Jul 31 05:55:31 2026] 127.0.0.1:52470 Closing +[Fri Jul 31 05:56:31 2026] 127.0.0.1:38950 Accepted +[Fri Jul 31 05:56:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 05:56:31 2026] 127.0.0.1:38950 [200]: GET /api/stats.php +[Fri Jul 31 05:56:31 2026] 127.0.0.1:38950 Closing +[Fri Jul 31 05:56:31 2026] 127.0.0.1:38966 Accepted +[Fri Jul 31 05:56:31 2026] 127.0.0.1:38966 [200]: GET /api/chart.php?range=year +[Fri Jul 31 05:56:31 2026] 127.0.0.1:38966 Closing +[Fri Jul 31 05:57:31 2026] 127.0.0.1:54162 Accepted +[Fri Jul 31 05:57:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 05:57:31 2026] 127.0.0.1:54162 [200]: GET /api/stats.php +[Fri Jul 31 05:57:31 2026] 127.0.0.1:54162 Closing +[Fri Jul 31 05:57:31 2026] 127.0.0.1:54178 Accepted +[Fri Jul 31 05:57:31 2026] 127.0.0.1:54178 [200]: GET /api/chart.php?range=year +[Fri Jul 31 05:57:31 2026] 127.0.0.1:54178 Closing +[Fri Jul 31 05:58:31 2026] 127.0.0.1:39850 Accepted +[Fri Jul 31 05:58:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 05:58:31 2026] 127.0.0.1:39850 [200]: GET /api/stats.php +[Fri Jul 31 05:58:31 2026] 127.0.0.1:39850 Closing +[Fri Jul 31 05:58:31 2026] 127.0.0.1:39860 Accepted +[Fri Jul 31 05:58:31 2026] 127.0.0.1:39860 [200]: GET /api/chart.php?range=year +[Fri Jul 31 05:58:31 2026] 127.0.0.1:39860 Closing +[Fri Jul 31 05:59:31 2026] 127.0.0.1:40308 Accepted +[Fri Jul 31 05:59:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 05:59:31 2026] 127.0.0.1:40308 [200]: GET /api/stats.php +[Fri Jul 31 05:59:31 2026] 127.0.0.1:40308 Closing +[Fri Jul 31 05:59:31 2026] 127.0.0.1:40318 Accepted +[Fri Jul 31 05:59:31 2026] 127.0.0.1:40318 [200]: GET /api/chart.php?range=year +[Fri Jul 31 05:59:31 2026] 127.0.0.1:40318 Closing +[Fri Jul 31 06:00:31 2026] 127.0.0.1:45114 Accepted +[Fri Jul 31 06:00:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 06:00:31 2026] 127.0.0.1:45114 [200]: GET /api/stats.php +[Fri Jul 31 06:00:31 2026] 127.0.0.1:45114 Closing +[Fri Jul 31 06:00:31 2026] 127.0.0.1:45130 Accepted +[Fri Jul 31 06:00:31 2026] 127.0.0.1:45130 [200]: GET /api/chart.php?range=year +[Fri Jul 31 06:00:31 2026] 127.0.0.1:45130 Closing +[Fri Jul 31 06:01:31 2026] 127.0.0.1:56938 Accepted +[Fri Jul 31 06:01:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 06:01:31 2026] 127.0.0.1:56938 [200]: GET /api/stats.php +[Fri Jul 31 06:01:31 2026] 127.0.0.1:56938 Closing +[Fri Jul 31 06:01:31 2026] 127.0.0.1:56948 Accepted +[Fri Jul 31 06:01:31 2026] 127.0.0.1:56948 [200]: GET /api/chart.php?range=year +[Fri Jul 31 06:01:31 2026] 127.0.0.1:56948 Closing +[Fri Jul 31 06:02:31 2026] 127.0.0.1:46454 Accepted +[Fri Jul 31 06:02:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 06:02:31 2026] 127.0.0.1:46454 [200]: GET /api/stats.php +[Fri Jul 31 06:02:31 2026] 127.0.0.1:46454 Closing +[Fri Jul 31 06:02:31 2026] 127.0.0.1:46464 Accepted +[Fri Jul 31 06:02:31 2026] 127.0.0.1:46464 [200]: GET /api/chart.php?range=year +[Fri Jul 31 06:02:31 2026] 127.0.0.1:46464 Closing +[Fri Jul 31 06:03:31 2026] 127.0.0.1:49222 Accepted +[Fri Jul 31 06:03:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 06:03:31 2026] 127.0.0.1:49222 [200]: GET /api/stats.php +[Fri Jul 31 06:03:31 2026] 127.0.0.1:49222 Closing +[Fri Jul 31 06:03:31 2026] 127.0.0.1:49224 Accepted +[Fri Jul 31 06:03:31 2026] 127.0.0.1:49224 [200]: GET /api/chart.php?range=year +[Fri Jul 31 06:03:31 2026] 127.0.0.1:49224 Closing +[Fri Jul 31 06:04:31 2026] 127.0.0.1:40166 Accepted +[Fri Jul 31 06:04:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 06:04:31 2026] 127.0.0.1:40166 [200]: GET /api/stats.php +[Fri Jul 31 06:04:31 2026] 127.0.0.1:40166 Closing +[Fri Jul 31 06:04:31 2026] 127.0.0.1:40180 Accepted +[Fri Jul 31 06:04:31 2026] 127.0.0.1:40180 [200]: GET /api/chart.php?range=year +[Fri Jul 31 06:04:31 2026] 127.0.0.1:40180 Closing +[Fri Jul 31 06:05:31 2026] 127.0.0.1:38796 Accepted +[Fri Jul 31 06:05:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 06:05:31 2026] 127.0.0.1:38796 [200]: GET /api/stats.php +[Fri Jul 31 06:05:31 2026] 127.0.0.1:38796 Closing +[Fri Jul 31 06:05:31 2026] 127.0.0.1:38800 Accepted +[Fri Jul 31 06:05:31 2026] 127.0.0.1:38800 [200]: GET /api/chart.php?range=year +[Fri Jul 31 06:05:31 2026] 127.0.0.1:38800 Closing +[Fri Jul 31 06:06:31 2026] 127.0.0.1:42282 Accepted +[Fri Jul 31 06:06:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 06:06:31 2026] 127.0.0.1:42282 [200]: GET /api/stats.php +[Fri Jul 31 06:06:31 2026] 127.0.0.1:42282 Closing +[Fri Jul 31 06:06:31 2026] 127.0.0.1:42290 Accepted +[Fri Jul 31 06:06:31 2026] 127.0.0.1:42290 [200]: GET /api/chart.php?range=year +[Fri Jul 31 06:06:31 2026] 127.0.0.1:42290 Closing +[Fri Jul 31 06:07:31 2026] 127.0.0.1:44836 Accepted +[Fri Jul 31 06:07:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 06:07:31 2026] 127.0.0.1:44836 [200]: GET /api/stats.php +[Fri Jul 31 06:07:31 2026] 127.0.0.1:44836 Closing +[Fri Jul 31 06:07:31 2026] 127.0.0.1:44844 Accepted +[Fri Jul 31 06:07:31 2026] 127.0.0.1:44844 [200]: GET /api/chart.php?range=year +[Fri Jul 31 06:07:31 2026] 127.0.0.1:44844 Closing +[Fri Jul 31 06:08:31 2026] 127.0.0.1:39618 Accepted +[Fri Jul 31 06:08:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 06:08:31 2026] 127.0.0.1:39618 [200]: GET /api/stats.php +[Fri Jul 31 06:08:31 2026] 127.0.0.1:39618 Closing +[Fri Jul 31 06:08:31 2026] 127.0.0.1:39620 Accepted +[Fri Jul 31 06:08:31 2026] 127.0.0.1:39620 [200]: GET /api/chart.php?range=year +[Fri Jul 31 06:08:31 2026] 127.0.0.1:39620 Closing +[Fri Jul 31 06:09:31 2026] 127.0.0.1:46682 Accepted +[Fri Jul 31 06:09:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 06:09:31 2026] 127.0.0.1:46682 [200]: GET /api/stats.php +[Fri Jul 31 06:09:31 2026] 127.0.0.1:46682 Closing +[Fri Jul 31 06:09:31 2026] 127.0.0.1:46694 Accepted +[Fri Jul 31 06:09:31 2026] 127.0.0.1:46694 [200]: GET /api/chart.php?range=year +[Fri Jul 31 06:09:31 2026] 127.0.0.1:46694 Closing +[Fri Jul 31 06:10:31 2026] 127.0.0.1:60862 Accepted +[Fri Jul 31 06:10:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 06:10:31 2026] 127.0.0.1:60862 [200]: GET /api/stats.php +[Fri Jul 31 06:10:31 2026] 127.0.0.1:60862 Closing +[Fri Jul 31 06:10:31 2026] 127.0.0.1:60864 Accepted +[Fri Jul 31 06:10:31 2026] 127.0.0.1:60864 [200]: GET /api/chart.php?range=year +[Fri Jul 31 06:10:31 2026] 127.0.0.1:60864 Closing +[Fri Jul 31 06:11:31 2026] 127.0.0.1:53124 Accepted +[Fri Jul 31 06:11:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 06:11:31 2026] 127.0.0.1:53124 [200]: GET /api/stats.php +[Fri Jul 31 06:11:31 2026] 127.0.0.1:53124 Closing +[Fri Jul 31 06:11:31 2026] 127.0.0.1:53134 Accepted +[Fri Jul 31 06:11:31 2026] 127.0.0.1:53134 [200]: GET /api/chart.php?range=year +[Fri Jul 31 06:11:31 2026] 127.0.0.1:53134 Closing +[Fri Jul 31 06:12:31 2026] 127.0.0.1:46200 Accepted +[Fri Jul 31 06:12:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 06:12:31 2026] 127.0.0.1:46200 [200]: GET /api/stats.php +[Fri Jul 31 06:12:31 2026] 127.0.0.1:46200 Closing +[Fri Jul 31 06:12:31 2026] 127.0.0.1:46212 Accepted +[Fri Jul 31 06:12:31 2026] 127.0.0.1:46212 [200]: GET /api/chart.php?range=year +[Fri Jul 31 06:12:31 2026] 127.0.0.1:46212 Closing +[Fri Jul 31 06:13:31 2026] 127.0.0.1:43166 Accepted +[Fri Jul 31 06:13:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 06:13:31 2026] 127.0.0.1:43166 [200]: GET /api/stats.php +[Fri Jul 31 06:13:31 2026] 127.0.0.1:43166 Closing +[Fri Jul 31 06:13:31 2026] 127.0.0.1:43174 Accepted +[Fri Jul 31 06:13:31 2026] 127.0.0.1:43174 [200]: GET /api/chart.php?range=year +[Fri Jul 31 06:13:31 2026] 127.0.0.1:43174 Closing +[Fri Jul 31 06:14:31 2026] 127.0.0.1:55522 Accepted +[Fri Jul 31 06:14:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 06:14:31 2026] 127.0.0.1:55522 [200]: GET /api/stats.php +[Fri Jul 31 06:14:31 2026] 127.0.0.1:55522 Closing +[Fri Jul 31 06:14:31 2026] 127.0.0.1:55524 Accepted +[Fri Jul 31 06:14:31 2026] 127.0.0.1:55524 [200]: GET /api/chart.php?range=year +[Fri Jul 31 06:14:31 2026] 127.0.0.1:55524 Closing +[Fri Jul 31 06:15:31 2026] 127.0.0.1:41800 Accepted +[Fri Jul 31 06:15:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 06:15:31 2026] 127.0.0.1:41800 [200]: GET /api/stats.php +[Fri Jul 31 06:15:31 2026] 127.0.0.1:41800 Closing +[Fri Jul 31 06:15:31 2026] 127.0.0.1:41808 Accepted +[Fri Jul 31 06:15:31 2026] 127.0.0.1:41808 [200]: GET /api/chart.php?range=year +[Fri Jul 31 06:15:31 2026] 127.0.0.1:41808 Closing +[Fri Jul 31 06:16:31 2026] 127.0.0.1:55474 Accepted +[Fri Jul 31 06:16:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 06:16:31 2026] 127.0.0.1:55474 [200]: GET /api/stats.php +[Fri Jul 31 06:16:31 2026] 127.0.0.1:55474 Closing +[Fri Jul 31 06:16:31 2026] 127.0.0.1:55488 Accepted +[Fri Jul 31 06:16:31 2026] 127.0.0.1:55488 [200]: GET /api/chart.php?range=year +[Fri Jul 31 06:16:31 2026] 127.0.0.1:55488 Closing +[Fri Jul 31 06:17:31 2026] 127.0.0.1:47672 Accepted +[Fri Jul 31 06:17:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 06:17:31 2026] 127.0.0.1:47672 [200]: GET /api/stats.php +[Fri Jul 31 06:17:31 2026] 127.0.0.1:47672 Closing +[Fri Jul 31 06:17:31 2026] 127.0.0.1:47678 Accepted +[Fri Jul 31 06:17:31 2026] 127.0.0.1:47678 [200]: GET /api/chart.php?range=year +[Fri Jul 31 06:17:31 2026] 127.0.0.1:47678 Closing +[Fri Jul 31 06:18:31 2026] 127.0.0.1:45736 Accepted +[Fri Jul 31 06:18:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 06:18:31 2026] 127.0.0.1:45736 [200]: GET /api/stats.php +[Fri Jul 31 06:18:31 2026] 127.0.0.1:45736 Closing +[Fri Jul 31 06:18:31 2026] 127.0.0.1:45740 Accepted +[Fri Jul 31 06:18:31 2026] 127.0.0.1:45740 [200]: GET /api/chart.php?range=year +[Fri Jul 31 06:18:31 2026] 127.0.0.1:45740 Closing +[Fri Jul 31 06:19:31 2026] 127.0.0.1:48040 Accepted +[Fri Jul 31 06:19:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 06:19:31 2026] 127.0.0.1:48040 [200]: GET /api/stats.php +[Fri Jul 31 06:19:31 2026] 127.0.0.1:48040 Closing +[Fri Jul 31 06:19:31 2026] 127.0.0.1:48054 Accepted +[Fri Jul 31 06:19:31 2026] 127.0.0.1:48054 [200]: GET /api/chart.php?range=year +[Fri Jul 31 06:19:31 2026] 127.0.0.1:48054 Closing +[Fri Jul 31 06:20:31 2026] 127.0.0.1:44734 Accepted +[Fri Jul 31 06:20:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 06:20:31 2026] 127.0.0.1:44734 [200]: GET /api/stats.php +[Fri Jul 31 06:20:31 2026] 127.0.0.1:44734 Closing +[Fri Jul 31 06:20:31 2026] 127.0.0.1:44740 Accepted +[Fri Jul 31 06:20:31 2026] 127.0.0.1:44740 [200]: GET /api/chart.php?range=year +[Fri Jul 31 06:20:31 2026] 127.0.0.1:44740 Closing +[Fri Jul 31 06:21:31 2026] 127.0.0.1:53694 Accepted +[Fri Jul 31 06:21:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 06:21:31 2026] 127.0.0.1:53694 [200]: GET /api/stats.php +[Fri Jul 31 06:21:31 2026] 127.0.0.1:53694 Closing +[Fri Jul 31 06:21:31 2026] 127.0.0.1:53706 Accepted +[Fri Jul 31 06:21:31 2026] 127.0.0.1:53706 [200]: GET /api/chart.php?range=year +[Fri Jul 31 06:21:31 2026] 127.0.0.1:53706 Closing +[Fri Jul 31 06:22:31 2026] 127.0.0.1:57450 Accepted +[Fri Jul 31 06:22:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 06:22:31 2026] 127.0.0.1:57450 [200]: GET /api/stats.php +[Fri Jul 31 06:22:31 2026] 127.0.0.1:57450 Closing +[Fri Jul 31 06:22:31 2026] 127.0.0.1:57462 Accepted +[Fri Jul 31 06:22:31 2026] 127.0.0.1:57462 [200]: GET /api/chart.php?range=year +[Fri Jul 31 06:22:31 2026] 127.0.0.1:57462 Closing +[Fri Jul 31 06:23:31 2026] 127.0.0.1:60462 Accepted +[Fri Jul 31 06:23:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 06:23:31 2026] 127.0.0.1:60462 [200]: GET /api/stats.php +[Fri Jul 31 06:23:31 2026] 127.0.0.1:60462 Closing +[Fri Jul 31 06:23:31 2026] 127.0.0.1:60470 Accepted +[Fri Jul 31 06:23:31 2026] 127.0.0.1:60470 [200]: GET /api/chart.php?range=year +[Fri Jul 31 06:23:31 2026] 127.0.0.1:60470 Closing +[Fri Jul 31 06:24:31 2026] 127.0.0.1:55318 Accepted +[Fri Jul 31 06:24:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 06:24:32 2026] 127.0.0.1:55318 [200]: GET /api/stats.php +[Fri Jul 31 06:24:32 2026] 127.0.0.1:55318 Closing +[Fri Jul 31 06:24:32 2026] 127.0.0.1:55324 Accepted +[Fri Jul 31 06:24:32 2026] 127.0.0.1:55324 [200]: GET /api/chart.php?range=year +[Fri Jul 31 06:24:32 2026] 127.0.0.1:55324 Closing +[Fri Jul 31 06:25:31 2026] 127.0.0.1:53288 Accepted +[Fri Jul 31 06:25:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 06:25:31 2026] 127.0.0.1:53288 [200]: GET /api/stats.php +[Fri Jul 31 06:25:31 2026] 127.0.0.1:53288 Closing +[Fri Jul 31 06:25:31 2026] 127.0.0.1:53296 Accepted +[Fri Jul 31 06:25:31 2026] 127.0.0.1:53296 [200]: GET /api/chart.php?range=year +[Fri Jul 31 06:25:31 2026] 127.0.0.1:53296 Closing +[Fri Jul 31 06:26:31 2026] 127.0.0.1:44018 Accepted +[Fri Jul 31 06:26:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 06:26:31 2026] 127.0.0.1:44018 [200]: GET /api/stats.php +[Fri Jul 31 06:26:31 2026] 127.0.0.1:44018 Closing +[Fri Jul 31 06:26:31 2026] 127.0.0.1:44022 Accepted +[Fri Jul 31 06:26:31 2026] 127.0.0.1:44022 [200]: GET /api/chart.php?range=year +[Fri Jul 31 06:26:31 2026] 127.0.0.1:44022 Closing +[Fri Jul 31 06:27:31 2026] 127.0.0.1:51172 Accepted +[Fri Jul 31 06:27:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 06:27:31 2026] 127.0.0.1:51172 [200]: GET /api/stats.php +[Fri Jul 31 06:27:31 2026] 127.0.0.1:51172 Closing +[Fri Jul 31 06:27:31 2026] 127.0.0.1:51184 Accepted +[Fri Jul 31 06:27:31 2026] 127.0.0.1:51184 [200]: GET /api/chart.php?range=year +[Fri Jul 31 06:27:31 2026] 127.0.0.1:51184 Closing +[Fri Jul 31 06:28:31 2026] 127.0.0.1:50724 Accepted +[Fri Jul 31 06:28:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 06:28:31 2026] 127.0.0.1:50724 [200]: GET /api/stats.php +[Fri Jul 31 06:28:31 2026] 127.0.0.1:50724 Closing +[Fri Jul 31 06:28:31 2026] 127.0.0.1:50726 Accepted +[Fri Jul 31 06:28:31 2026] 127.0.0.1:50726 [200]: GET /api/chart.php?range=year +[Fri Jul 31 06:28:31 2026] 127.0.0.1:50726 Closing +[Fri Jul 31 06:29:31 2026] 127.0.0.1:47802 Accepted +[Fri Jul 31 06:29:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 06:29:31 2026] 127.0.0.1:47802 [200]: GET /api/stats.php +[Fri Jul 31 06:29:31 2026] 127.0.0.1:47802 Closing +[Fri Jul 31 06:29:31 2026] 127.0.0.1:47814 Accepted +[Fri Jul 31 06:29:31 2026] 127.0.0.1:47814 [200]: GET /api/chart.php?range=year +[Fri Jul 31 06:29:31 2026] 127.0.0.1:47814 Closing +[Fri Jul 31 06:30:31 2026] 127.0.0.1:32994 Accepted +[Fri Jul 31 06:30:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 06:30:31 2026] 127.0.0.1:32994 [200]: GET /api/stats.php +[Fri Jul 31 06:30:31 2026] 127.0.0.1:32994 Closing +[Fri Jul 31 06:30:31 2026] 127.0.0.1:33002 Accepted +[Fri Jul 31 06:30:31 2026] 127.0.0.1:33002 [200]: GET /api/chart.php?range=year +[Fri Jul 31 06:30:31 2026] 127.0.0.1:33002 Closing +[Fri Jul 31 06:31:31 2026] 127.0.0.1:46084 Accepted +[Fri Jul 31 06:31:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 06:31:31 2026] 127.0.0.1:46084 [200]: GET /api/stats.php +[Fri Jul 31 06:31:31 2026] 127.0.0.1:46084 Closing +[Fri Jul 31 06:31:31 2026] 127.0.0.1:46092 Accepted +[Fri Jul 31 06:31:31 2026] 127.0.0.1:46092 [200]: GET /api/chart.php?range=year +[Fri Jul 31 06:31:31 2026] 127.0.0.1:46092 Closing +[Fri Jul 31 06:32:31 2026] 127.0.0.1:44712 Accepted +[Fri Jul 31 06:32:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 06:32:31 2026] 127.0.0.1:44712 [200]: GET /api/stats.php +[Fri Jul 31 06:32:31 2026] 127.0.0.1:44712 Closing +[Fri Jul 31 06:32:31 2026] 127.0.0.1:44716 Accepted +[Fri Jul 31 06:32:31 2026] 127.0.0.1:44716 [200]: GET /api/chart.php?range=year +[Fri Jul 31 06:32:31 2026] 127.0.0.1:44716 Closing +[Fri Jul 31 06:33:31 2026] 127.0.0.1:39796 Accepted +[Fri Jul 31 06:33:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 06:33:31 2026] 127.0.0.1:39796 [200]: GET /api/stats.php +[Fri Jul 31 06:33:31 2026] 127.0.0.1:39796 Closing +[Fri Jul 31 06:33:31 2026] 127.0.0.1:39812 Accepted +[Fri Jul 31 06:33:31 2026] 127.0.0.1:39812 [200]: GET /api/chart.php?range=year +[Fri Jul 31 06:33:31 2026] 127.0.0.1:39812 Closing +[Fri Jul 31 06:34:31 2026] 127.0.0.1:37864 Accepted +[Fri Jul 31 06:34:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 06:34:31 2026] 127.0.0.1:37864 [200]: GET /api/stats.php +[Fri Jul 31 06:34:31 2026] 127.0.0.1:37864 Closing +[Fri Jul 31 06:34:31 2026] 127.0.0.1:37870 Accepted +[Fri Jul 31 06:34:31 2026] 127.0.0.1:37870 [200]: GET /api/chart.php?range=year +[Fri Jul 31 06:34:31 2026] 127.0.0.1:37870 Closing +[Fri Jul 31 06:35:31 2026] 127.0.0.1:58260 Accepted +[Fri Jul 31 06:35:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 06:35:31 2026] 127.0.0.1:58260 [200]: GET /api/stats.php +[Fri Jul 31 06:35:31 2026] 127.0.0.1:58260 Closing +[Fri Jul 31 06:35:31 2026] 127.0.0.1:58266 Accepted +[Fri Jul 31 06:35:31 2026] 127.0.0.1:58266 [200]: GET /api/chart.php?range=year +[Fri Jul 31 06:35:31 2026] 127.0.0.1:58266 Closing +[Fri Jul 31 06:36:31 2026] 127.0.0.1:43054 Accepted +[Fri Jul 31 06:36:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 06:36:31 2026] 127.0.0.1:43054 [200]: GET /api/stats.php +[Fri Jul 31 06:36:31 2026] 127.0.0.1:43054 Closing +[Fri Jul 31 06:36:31 2026] 127.0.0.1:43070 Accepted +[Fri Jul 31 06:36:31 2026] 127.0.0.1:43070 [200]: GET /api/chart.php?range=year +[Fri Jul 31 06:36:31 2026] 127.0.0.1:43070 Closing +[Fri Jul 31 06:37:31 2026] 127.0.0.1:40804 Accepted +[Fri Jul 31 06:37:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 06:37:31 2026] 127.0.0.1:40804 [200]: GET /api/stats.php +[Fri Jul 31 06:37:31 2026] 127.0.0.1:40804 Closing +[Fri Jul 31 06:37:31 2026] 127.0.0.1:40820 Accepted +[Fri Jul 31 06:37:31 2026] 127.0.0.1:40820 [200]: GET /api/chart.php?range=year +[Fri Jul 31 06:37:31 2026] 127.0.0.1:40820 Closing +[Fri Jul 31 06:38:31 2026] 127.0.0.1:47148 Accepted +[Fri Jul 31 06:38:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 06:38:31 2026] 127.0.0.1:47148 [200]: GET /api/stats.php +[Fri Jul 31 06:38:31 2026] 127.0.0.1:47148 Closing +[Fri Jul 31 06:38:31 2026] 127.0.0.1:47154 Accepted +[Fri Jul 31 06:38:31 2026] 127.0.0.1:47154 [200]: GET /api/chart.php?range=year +[Fri Jul 31 06:38:31 2026] 127.0.0.1:47154 Closing +[Fri Jul 31 06:39:31 2026] 127.0.0.1:45730 Accepted +[Fri Jul 31 06:39:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 06:39:31 2026] 127.0.0.1:45730 [200]: GET /api/stats.php +[Fri Jul 31 06:39:31 2026] 127.0.0.1:45730 Closing +[Fri Jul 31 06:39:31 2026] 127.0.0.1:45746 Accepted +[Fri Jul 31 06:39:31 2026] 127.0.0.1:45746 [200]: GET /api/chart.php?range=year +[Fri Jul 31 06:39:31 2026] 127.0.0.1:45746 Closing +[Fri Jul 31 06:40:31 2026] 127.0.0.1:39428 Accepted +[Fri Jul 31 06:40:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 06:40:31 2026] 127.0.0.1:39428 [200]: GET /api/stats.php +[Fri Jul 31 06:40:31 2026] 127.0.0.1:39428 Closing +[Fri Jul 31 06:40:31 2026] 127.0.0.1:39436 Accepted +[Fri Jul 31 06:40:31 2026] 127.0.0.1:39436 [200]: GET /api/chart.php?range=year +[Fri Jul 31 06:40:31 2026] 127.0.0.1:39436 Closing +[Fri Jul 31 06:41:31 2026] 127.0.0.1:48588 Accepted +[Fri Jul 31 06:41:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 06:41:31 2026] 127.0.0.1:48588 [200]: GET /api/stats.php +[Fri Jul 31 06:41:31 2026] 127.0.0.1:48588 Closing +[Fri Jul 31 06:41:31 2026] 127.0.0.1:48602 Accepted +[Fri Jul 31 06:41:31 2026] 127.0.0.1:48602 [200]: GET /api/chart.php?range=year +[Fri Jul 31 06:41:31 2026] 127.0.0.1:48602 Closing +[Fri Jul 31 06:42:31 2026] 127.0.0.1:50170 Accepted +[Fri Jul 31 06:42:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 06:42:31 2026] 127.0.0.1:50170 [200]: GET /api/stats.php +[Fri Jul 31 06:42:31 2026] 127.0.0.1:50170 Closing +[Fri Jul 31 06:42:31 2026] 127.0.0.1:50174 Accepted +[Fri Jul 31 06:42:31 2026] 127.0.0.1:50174 [200]: GET /api/chart.php?range=year +[Fri Jul 31 06:42:31 2026] 127.0.0.1:50174 Closing +[Fri Jul 31 06:43:31 2026] 127.0.0.1:37326 Accepted +[Fri Jul 31 06:43:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 06:43:31 2026] 127.0.0.1:37326 [200]: GET /api/stats.php +[Fri Jul 31 06:43:31 2026] 127.0.0.1:37326 Closing +[Fri Jul 31 06:43:31 2026] 127.0.0.1:37336 Accepted +[Fri Jul 31 06:43:31 2026] 127.0.0.1:37336 [200]: GET /api/chart.php?range=year +[Fri Jul 31 06:43:31 2026] 127.0.0.1:37336 Closing +[Fri Jul 31 06:44:31 2026] 127.0.0.1:54738 Accepted +[Fri Jul 31 06:44:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 06:44:31 2026] 127.0.0.1:54738 [200]: GET /api/stats.php +[Fri Jul 31 06:44:31 2026] 127.0.0.1:54738 Closing +[Fri Jul 31 06:44:31 2026] 127.0.0.1:54750 Accepted +[Fri Jul 31 06:44:31 2026] 127.0.0.1:54750 [200]: GET /api/chart.php?range=year +[Fri Jul 31 06:44:31 2026] 127.0.0.1:54750 Closing +[Fri Jul 31 06:45:31 2026] 127.0.0.1:35736 Accepted +[Fri Jul 31 06:45:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 06:45:31 2026] 127.0.0.1:35736 [200]: GET /api/stats.php +[Fri Jul 31 06:45:31 2026] 127.0.0.1:35736 Closing +[Fri Jul 31 06:45:31 2026] 127.0.0.1:35738 Accepted +[Fri Jul 31 06:45:31 2026] 127.0.0.1:35738 [200]: GET /api/chart.php?range=year +[Fri Jul 31 06:45:31 2026] 127.0.0.1:35738 Closing +[Fri Jul 31 06:46:31 2026] 127.0.0.1:39146 Accepted +[Fri Jul 31 06:46:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 06:46:31 2026] 127.0.0.1:39146 [200]: GET /api/stats.php +[Fri Jul 31 06:46:31 2026] 127.0.0.1:39146 Closing +[Fri Jul 31 06:46:31 2026] 127.0.0.1:39162 Accepted +[Fri Jul 31 06:46:31 2026] 127.0.0.1:39162 [200]: GET /api/chart.php?range=year +[Fri Jul 31 06:46:31 2026] 127.0.0.1:39162 Closing +[Fri Jul 31 06:47:31 2026] 127.0.0.1:34832 Accepted +[Fri Jul 31 06:47:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 06:47:31 2026] 127.0.0.1:34832 [200]: GET /api/stats.php +[Fri Jul 31 06:47:31 2026] 127.0.0.1:34832 Closing +[Fri Jul 31 06:47:31 2026] 127.0.0.1:34838 Accepted +[Fri Jul 31 06:47:31 2026] 127.0.0.1:34838 [200]: GET /api/chart.php?range=year +[Fri Jul 31 06:47:31 2026] 127.0.0.1:34838 Closing +[Fri Jul 31 06:48:31 2026] 127.0.0.1:48090 Accepted +[Fri Jul 31 06:48:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 06:48:31 2026] 127.0.0.1:48090 [200]: GET /api/stats.php +[Fri Jul 31 06:48:31 2026] 127.0.0.1:48090 Closing +[Fri Jul 31 06:48:31 2026] 127.0.0.1:48106 Accepted +[Fri Jul 31 06:48:31 2026] 127.0.0.1:48106 [200]: GET /api/chart.php?range=year +[Fri Jul 31 06:48:31 2026] 127.0.0.1:48106 Closing +[Fri Jul 31 06:49:31 2026] 127.0.0.1:42072 Accepted +[Fri Jul 31 06:49:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 06:49:31 2026] 127.0.0.1:42072 [200]: GET /api/stats.php +[Fri Jul 31 06:49:31 2026] 127.0.0.1:42072 Closing +[Fri Jul 31 06:49:31 2026] 127.0.0.1:42084 Accepted +[Fri Jul 31 06:49:31 2026] 127.0.0.1:42084 [200]: GET /api/chart.php?range=year +[Fri Jul 31 06:49:31 2026] 127.0.0.1:42084 Closing +[Fri Jul 31 06:50:31 2026] 127.0.0.1:44246 Accepted +[Fri Jul 31 06:50:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 06:50:31 2026] 127.0.0.1:44246 [200]: GET /api/stats.php +[Fri Jul 31 06:50:31 2026] 127.0.0.1:44246 Closing +[Fri Jul 31 06:50:31 2026] 127.0.0.1:44248 Accepted +[Fri Jul 31 06:50:31 2026] 127.0.0.1:44248 [200]: GET /api/chart.php?range=year +[Fri Jul 31 06:50:31 2026] 127.0.0.1:44248 Closing +[Fri Jul 31 06:51:31 2026] 127.0.0.1:38754 Accepted +[Fri Jul 31 06:51:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 06:51:31 2026] 127.0.0.1:38754 [200]: GET /api/stats.php +[Fri Jul 31 06:51:31 2026] 127.0.0.1:38754 Closing +[Fri Jul 31 06:51:31 2026] 127.0.0.1:38766 Accepted +[Fri Jul 31 06:51:31 2026] 127.0.0.1:38766 [200]: GET /api/chart.php?range=year +[Fri Jul 31 06:51:31 2026] 127.0.0.1:38766 Closing +[Fri Jul 31 06:52:31 2026] 127.0.0.1:44880 Accepted +[Fri Jul 31 06:52:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 06:52:31 2026] 127.0.0.1:44880 [200]: GET /api/stats.php +[Fri Jul 31 06:52:31 2026] 127.0.0.1:44880 Closing +[Fri Jul 31 06:52:31 2026] 127.0.0.1:44886 Accepted +[Fri Jul 31 06:52:31 2026] 127.0.0.1:44886 [200]: GET /api/chart.php?range=year +[Fri Jul 31 06:52:31 2026] 127.0.0.1:44886 Closing +[Fri Jul 31 06:53:31 2026] 127.0.0.1:37674 Accepted +[Fri Jul 31 06:53:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 06:53:31 2026] 127.0.0.1:37674 [200]: GET /api/stats.php +[Fri Jul 31 06:53:31 2026] 127.0.0.1:37674 Closing +[Fri Jul 31 06:53:31 2026] 127.0.0.1:37686 Accepted +[Fri Jul 31 06:53:31 2026] 127.0.0.1:37686 [200]: GET /api/chart.php?range=year +[Fri Jul 31 06:53:31 2026] 127.0.0.1:37686 Closing +[Fri Jul 31 06:54:31 2026] 127.0.0.1:59606 Accepted +[Fri Jul 31 06:54:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 06:54:31 2026] 127.0.0.1:59606 [200]: GET /api/stats.php +[Fri Jul 31 06:54:31 2026] 127.0.0.1:59606 Closing +[Fri Jul 31 06:54:31 2026] 127.0.0.1:59610 Accepted +[Fri Jul 31 06:54:31 2026] 127.0.0.1:59610 [200]: GET /api/chart.php?range=year +[Fri Jul 31 06:54:31 2026] 127.0.0.1:59610 Closing +[Fri Jul 31 06:55:31 2026] 127.0.0.1:53642 Accepted +[Fri Jul 31 06:55:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 06:55:31 2026] 127.0.0.1:53642 [200]: GET /api/stats.php +[Fri Jul 31 06:55:31 2026] 127.0.0.1:53642 Closing +[Fri Jul 31 06:55:31 2026] 127.0.0.1:53648 Accepted +[Fri Jul 31 06:55:31 2026] 127.0.0.1:53648 [200]: GET /api/chart.php?range=year +[Fri Jul 31 06:55:31 2026] 127.0.0.1:53648 Closing +[Fri Jul 31 06:56:31 2026] 127.0.0.1:50518 Accepted +[Fri Jul 31 06:56:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 06:56:31 2026] 127.0.0.1:50518 [200]: GET /api/stats.php +[Fri Jul 31 06:56:31 2026] 127.0.0.1:50518 Closing +[Fri Jul 31 06:56:31 2026] 127.0.0.1:50526 Accepted +[Fri Jul 31 06:56:31 2026] 127.0.0.1:50526 [200]: GET /api/chart.php?range=year +[Fri Jul 31 06:56:31 2026] 127.0.0.1:50526 Closing +[Fri Jul 31 06:57:31 2026] 127.0.0.1:49152 Accepted +[Fri Jul 31 06:57:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 06:57:31 2026] 127.0.0.1:49152 [200]: GET /api/stats.php +[Fri Jul 31 06:57:31 2026] 127.0.0.1:49152 Closing +[Fri Jul 31 06:57:31 2026] 127.0.0.1:49164 Accepted +[Fri Jul 31 06:57:31 2026] 127.0.0.1:49164 [200]: GET /api/chart.php?range=year +[Fri Jul 31 06:57:31 2026] 127.0.0.1:49164 Closing +[Fri Jul 31 06:58:31 2026] 127.0.0.1:41878 Accepted +[Fri Jul 31 06:58:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 06:58:31 2026] 127.0.0.1:41878 [200]: GET /api/stats.php +[Fri Jul 31 06:58:31 2026] 127.0.0.1:41878 Closing +[Fri Jul 31 06:58:31 2026] 127.0.0.1:41894 Accepted +[Fri Jul 31 06:58:31 2026] 127.0.0.1:41894 [200]: GET /api/chart.php?range=year +[Fri Jul 31 06:58:31 2026] 127.0.0.1:41894 Closing +[Fri Jul 31 06:59:31 2026] 127.0.0.1:36980 Accepted +[Fri Jul 31 06:59:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 06:59:31 2026] 127.0.0.1:36980 [200]: GET /api/stats.php +[Fri Jul 31 06:59:31 2026] 127.0.0.1:36980 Closing +[Fri Jul 31 06:59:31 2026] 127.0.0.1:36996 Accepted +[Fri Jul 31 06:59:31 2026] 127.0.0.1:36996 [200]: GET /api/chart.php?range=year +[Fri Jul 31 06:59:31 2026] 127.0.0.1:36996 Closing +[Fri Jul 31 07:00:31 2026] 127.0.0.1:60602 Accepted +[Fri Jul 31 07:00:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 07:00:31 2026] 127.0.0.1:60602 [200]: GET /api/stats.php +[Fri Jul 31 07:00:31 2026] 127.0.0.1:60602 Closing +[Fri Jul 31 07:00:31 2026] 127.0.0.1:60618 Accepted +[Fri Jul 31 07:00:31 2026] 127.0.0.1:60618 [200]: GET /api/chart.php?range=year +[Fri Jul 31 07:00:31 2026] 127.0.0.1:60618 Closing +[Fri Jul 31 07:01:31 2026] 127.0.0.1:35804 Accepted +[Fri Jul 31 07:01:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 07:01:31 2026] 127.0.0.1:35804 [200]: GET /api/stats.php +[Fri Jul 31 07:01:31 2026] 127.0.0.1:35804 Closing +[Fri Jul 31 07:01:31 2026] 127.0.0.1:35812 Accepted +[Fri Jul 31 07:01:31 2026] 127.0.0.1:35812 [200]: GET /api/chart.php?range=year +[Fri Jul 31 07:01:31 2026] 127.0.0.1:35812 Closing +[Fri Jul 31 07:02:31 2026] 127.0.0.1:55148 Accepted +[Fri Jul 31 07:02:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 07:02:31 2026] 127.0.0.1:55148 [200]: GET /api/stats.php +[Fri Jul 31 07:02:31 2026] 127.0.0.1:55148 Closing +[Fri Jul 31 07:02:31 2026] 127.0.0.1:55154 Accepted +[Fri Jul 31 07:02:31 2026] 127.0.0.1:55154 [200]: GET /api/chart.php?range=year +[Fri Jul 31 07:02:31 2026] 127.0.0.1:55154 Closing +[Fri Jul 31 07:03:31 2026] 127.0.0.1:52830 Accepted +[Fri Jul 31 07:03:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 07:03:31 2026] 127.0.0.1:52830 [200]: GET /api/stats.php +[Fri Jul 31 07:03:31 2026] 127.0.0.1:52830 Closing +[Fri Jul 31 07:03:31 2026] 127.0.0.1:52840 Accepted +[Fri Jul 31 07:03:31 2026] 127.0.0.1:52840 [200]: GET /api/chart.php?range=year +[Fri Jul 31 07:03:31 2026] 127.0.0.1:52840 Closing +[Fri Jul 31 07:04:31 2026] 127.0.0.1:38374 Accepted +[Fri Jul 31 07:04:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 07:04:31 2026] 127.0.0.1:38374 [200]: GET /api/stats.php +[Fri Jul 31 07:04:31 2026] 127.0.0.1:38374 Closing +[Fri Jul 31 07:04:31 2026] 127.0.0.1:38384 Accepted +[Fri Jul 31 07:04:31 2026] 127.0.0.1:38384 [200]: GET /api/chart.php?range=year +[Fri Jul 31 07:04:31 2026] 127.0.0.1:38384 Closing +[Fri Jul 31 07:05:31 2026] 127.0.0.1:35136 Accepted +[Fri Jul 31 07:05:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 07:05:31 2026] 127.0.0.1:35136 [200]: GET /api/stats.php +[Fri Jul 31 07:05:31 2026] 127.0.0.1:35136 Closing +[Fri Jul 31 07:05:31 2026] 127.0.0.1:35148 Accepted +[Fri Jul 31 07:05:31 2026] 127.0.0.1:35148 [200]: GET /api/chart.php?range=year +[Fri Jul 31 07:05:31 2026] 127.0.0.1:35148 Closing +[Fri Jul 31 07:06:31 2026] 127.0.0.1:52876 Accepted +[Fri Jul 31 07:06:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 07:06:31 2026] 127.0.0.1:52876 [200]: GET /api/stats.php +[Fri Jul 31 07:06:31 2026] 127.0.0.1:52876 Closing +[Fri Jul 31 07:06:31 2026] 127.0.0.1:52886 Accepted +[Fri Jul 31 07:06:31 2026] 127.0.0.1:52886 [200]: GET /api/chart.php?range=year +[Fri Jul 31 07:06:31 2026] 127.0.0.1:52886 Closing +[Fri Jul 31 07:07:31 2026] 127.0.0.1:38704 Accepted +[Fri Jul 31 07:07:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 07:07:31 2026] 127.0.0.1:38704 [200]: GET /api/stats.php +[Fri Jul 31 07:07:31 2026] 127.0.0.1:38704 Closing +[Fri Jul 31 07:07:31 2026] 127.0.0.1:38706 Accepted +[Fri Jul 31 07:07:31 2026] 127.0.0.1:38706 [200]: GET /api/chart.php?range=year +[Fri Jul 31 07:07:31 2026] 127.0.0.1:38706 Closing +[Fri Jul 31 07:08:31 2026] 127.0.0.1:43450 Accepted +[Fri Jul 31 07:08:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 07:08:31 2026] 127.0.0.1:43450 [200]: GET /api/stats.php +[Fri Jul 31 07:08:31 2026] 127.0.0.1:43450 Closing +[Fri Jul 31 07:08:31 2026] 127.0.0.1:43456 Accepted +[Fri Jul 31 07:08:31 2026] 127.0.0.1:43456 [200]: GET /api/chart.php?range=year +[Fri Jul 31 07:08:31 2026] 127.0.0.1:43456 Closing +[Fri Jul 31 07:09:31 2026] 127.0.0.1:41610 Accepted +[Fri Jul 31 07:09:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 07:09:31 2026] 127.0.0.1:41610 [200]: GET /api/stats.php +[Fri Jul 31 07:09:31 2026] 127.0.0.1:41610 Closing +[Fri Jul 31 07:09:31 2026] 127.0.0.1:41620 Accepted +[Fri Jul 31 07:09:31 2026] 127.0.0.1:41620 [200]: GET /api/chart.php?range=year +[Fri Jul 31 07:09:31 2026] 127.0.0.1:41620 Closing +[Fri Jul 31 07:10:31 2026] 127.0.0.1:35892 Accepted +[Fri Jul 31 07:10:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 07:10:31 2026] 127.0.0.1:35892 [200]: GET /api/stats.php +[Fri Jul 31 07:10:31 2026] 127.0.0.1:35892 Closing +[Fri Jul 31 07:10:31 2026] 127.0.0.1:35908 Accepted +[Fri Jul 31 07:10:31 2026] 127.0.0.1:35908 [200]: GET /api/chart.php?range=year +[Fri Jul 31 07:10:31 2026] 127.0.0.1:35908 Closing +[Fri Jul 31 07:11:31 2026] 127.0.0.1:52240 Accepted +[Fri Jul 31 07:11:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 07:11:31 2026] 127.0.0.1:52240 [200]: GET /api/stats.php +[Fri Jul 31 07:11:31 2026] 127.0.0.1:52240 Closing +[Fri Jul 31 07:11:31 2026] 127.0.0.1:52248 Accepted +[Fri Jul 31 07:11:31 2026] 127.0.0.1:52248 [200]: GET /api/chart.php?range=year +[Fri Jul 31 07:11:31 2026] 127.0.0.1:52248 Closing +[Fri Jul 31 07:12:31 2026] 127.0.0.1:47752 Accepted +[Fri Jul 31 07:12:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 07:12:31 2026] 127.0.0.1:47752 [200]: GET /api/stats.php +[Fri Jul 31 07:12:31 2026] 127.0.0.1:47752 Closing +[Fri Jul 31 07:12:31 2026] 127.0.0.1:47764 Accepted +[Fri Jul 31 07:12:31 2026] 127.0.0.1:47764 [200]: GET /api/chart.php?range=year +[Fri Jul 31 07:12:31 2026] 127.0.0.1:47764 Closing +[Fri Jul 31 07:13:31 2026] 127.0.0.1:37098 Accepted +[Fri Jul 31 07:13:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 07:13:32 2026] 127.0.0.1:37098 [200]: GET /api/stats.php +[Fri Jul 31 07:13:32 2026] 127.0.0.1:37098 Closing +[Fri Jul 31 07:13:32 2026] 127.0.0.1:37100 Accepted +[Fri Jul 31 07:13:32 2026] 127.0.0.1:37100 [200]: GET /api/chart.php?range=year +[Fri Jul 31 07:13:32 2026] 127.0.0.1:37100 Closing +[Fri Jul 31 07:14:31 2026] 127.0.0.1:59328 Accepted +[Fri Jul 31 07:14:32 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 07:14:32 2026] 127.0.0.1:59328 [200]: GET /api/stats.php +[Fri Jul 31 07:14:32 2026] 127.0.0.1:59328 Closing +[Fri Jul 31 07:14:32 2026] 127.0.0.1:59336 Accepted +[Fri Jul 31 07:14:32 2026] 127.0.0.1:59336 [200]: GET /api/chart.php?range=year +[Fri Jul 31 07:14:32 2026] 127.0.0.1:59336 Closing +[Fri Jul 31 07:15:31 2026] 127.0.0.1:39814 Accepted +[Fri Jul 31 07:15:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 07:15:31 2026] 127.0.0.1:39814 [200]: GET /api/stats.php +[Fri Jul 31 07:15:31 2026] 127.0.0.1:39814 Closing +[Fri Jul 31 07:15:31 2026] 127.0.0.1:39824 Accepted +[Fri Jul 31 07:15:31 2026] 127.0.0.1:39824 [200]: GET /api/chart.php?range=year +[Fri Jul 31 07:15:31 2026] 127.0.0.1:39824 Closing +[Fri Jul 31 07:16:31 2026] 127.0.0.1:33830 Accepted +[Fri Jul 31 07:16:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 07:16:31 2026] 127.0.0.1:33830 [200]: GET /api/stats.php +[Fri Jul 31 07:16:31 2026] 127.0.0.1:33830 Closing +[Fri Jul 31 07:16:31 2026] 127.0.0.1:33844 Accepted +[Fri Jul 31 07:16:31 2026] 127.0.0.1:33844 [200]: GET /api/chart.php?range=year +[Fri Jul 31 07:16:31 2026] 127.0.0.1:33844 Closing +[Fri Jul 31 07:17:31 2026] 127.0.0.1:55292 Accepted +[Fri Jul 31 07:17:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 07:17:31 2026] 127.0.0.1:55292 [200]: GET /api/stats.php +[Fri Jul 31 07:17:31 2026] 127.0.0.1:55292 Closing +[Fri Jul 31 07:17:31 2026] 127.0.0.1:55300 Accepted +[Fri Jul 31 07:17:31 2026] 127.0.0.1:55300 [200]: GET /api/chart.php?range=year +[Fri Jul 31 07:17:31 2026] 127.0.0.1:55300 Closing +[Fri Jul 31 07:18:31 2026] 127.0.0.1:42152 Accepted +[Fri Jul 31 07:18:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 07:18:31 2026] 127.0.0.1:42152 [200]: GET /api/stats.php +[Fri Jul 31 07:18:31 2026] 127.0.0.1:42152 Closing +[Fri Jul 31 07:18:31 2026] 127.0.0.1:42156 Accepted +[Fri Jul 31 07:18:31 2026] 127.0.0.1:42156 [200]: GET /api/chart.php?range=year +[Fri Jul 31 07:18:31 2026] 127.0.0.1:42156 Closing +[Fri Jul 31 07:19:31 2026] 127.0.0.1:46152 Accepted +[Fri Jul 31 07:19:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 07:19:31 2026] 127.0.0.1:46152 [200]: GET /api/stats.php +[Fri Jul 31 07:19:31 2026] 127.0.0.1:46152 Closing +[Fri Jul 31 07:19:31 2026] 127.0.0.1:46158 Accepted +[Fri Jul 31 07:19:31 2026] 127.0.0.1:46158 [200]: GET /api/chart.php?range=year +[Fri Jul 31 07:19:31 2026] 127.0.0.1:46158 Closing +[Fri Jul 31 07:20:31 2026] 127.0.0.1:39780 Accepted +[Fri Jul 31 07:20:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 07:20:31 2026] 127.0.0.1:39780 [200]: GET /api/stats.php +[Fri Jul 31 07:20:31 2026] 127.0.0.1:39780 Closing +[Fri Jul 31 07:20:31 2026] 127.0.0.1:39784 Accepted +[Fri Jul 31 07:20:31 2026] 127.0.0.1:39784 [200]: GET /api/chart.php?range=year +[Fri Jul 31 07:20:31 2026] 127.0.0.1:39784 Closing +[Fri Jul 31 07:21:31 2026] 127.0.0.1:57494 Accepted +[Fri Jul 31 07:21:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 07:21:31 2026] 127.0.0.1:57494 [200]: GET /api/stats.php +[Fri Jul 31 07:21:31 2026] 127.0.0.1:57494 Closing +[Fri Jul 31 07:21:31 2026] 127.0.0.1:57502 Accepted +[Fri Jul 31 07:21:31 2026] 127.0.0.1:57502 [200]: GET /api/chart.php?range=year +[Fri Jul 31 07:21:31 2026] 127.0.0.1:57502 Closing +[Fri Jul 31 07:22:31 2026] 127.0.0.1:33450 Accepted +[Fri Jul 31 07:22:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 07:22:31 2026] 127.0.0.1:33450 [200]: GET /api/stats.php +[Fri Jul 31 07:22:31 2026] 127.0.0.1:33450 Closing +[Fri Jul 31 07:22:31 2026] 127.0.0.1:33456 Accepted +[Fri Jul 31 07:22:31 2026] 127.0.0.1:33456 [200]: GET /api/chart.php?range=year +[Fri Jul 31 07:22:31 2026] 127.0.0.1:33456 Closing +[Fri Jul 31 07:23:31 2026] 127.0.0.1:42494 Accepted +[Fri Jul 31 07:23:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 07:23:31 2026] 127.0.0.1:42494 [200]: GET /api/stats.php +[Fri Jul 31 07:23:31 2026] 127.0.0.1:42494 Closing +[Fri Jul 31 07:23:31 2026] 127.0.0.1:42502 Accepted +[Fri Jul 31 07:23:31 2026] 127.0.0.1:42502 [200]: GET /api/chart.php?range=year +[Fri Jul 31 07:23:31 2026] 127.0.0.1:42502 Closing +[Fri Jul 31 07:24:31 2026] 127.0.0.1:54982 Accepted +[Fri Jul 31 07:24:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 07:24:31 2026] 127.0.0.1:54982 [200]: GET /api/stats.php +[Fri Jul 31 07:24:31 2026] 127.0.0.1:54982 Closing +[Fri Jul 31 07:24:31 2026] 127.0.0.1:54992 Accepted +[Fri Jul 31 07:24:31 2026] 127.0.0.1:54992 [200]: GET /api/chart.php?range=year +[Fri Jul 31 07:24:31 2026] 127.0.0.1:54992 Closing +[Fri Jul 31 07:25:31 2026] 127.0.0.1:40792 Accepted +[Fri Jul 31 07:25:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 07:25:31 2026] 127.0.0.1:40792 [200]: GET /api/stats.php +[Fri Jul 31 07:25:31 2026] 127.0.0.1:40792 Closing +[Fri Jul 31 07:25:31 2026] 127.0.0.1:40808 Accepted +[Fri Jul 31 07:25:31 2026] 127.0.0.1:40808 [200]: GET /api/chart.php?range=year +[Fri Jul 31 07:25:31 2026] 127.0.0.1:40808 Closing +[Fri Jul 31 07:26:31 2026] 127.0.0.1:52088 Accepted +[Fri Jul 31 07:26:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 07:26:31 2026] 127.0.0.1:52088 [200]: GET /api/stats.php +[Fri Jul 31 07:26:31 2026] 127.0.0.1:52088 Closing +[Fri Jul 31 07:26:31 2026] 127.0.0.1:52094 Accepted +[Fri Jul 31 07:26:31 2026] 127.0.0.1:52094 [200]: GET /api/chart.php?range=year +[Fri Jul 31 07:26:31 2026] 127.0.0.1:52094 Closing +[Fri Jul 31 07:27:31 2026] 127.0.0.1:35152 Accepted +[Fri Jul 31 07:27:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 07:27:31 2026] 127.0.0.1:35152 [200]: GET /api/stats.php +[Fri Jul 31 07:27:31 2026] 127.0.0.1:35152 Closing +[Fri Jul 31 07:27:31 2026] 127.0.0.1:35166 Accepted +[Fri Jul 31 07:27:31 2026] 127.0.0.1:35166 [200]: GET /api/chart.php?range=year +[Fri Jul 31 07:27:31 2026] 127.0.0.1:35166 Closing +[Fri Jul 31 07:28:31 2026] 127.0.0.1:36298 Accepted +[Fri Jul 31 07:28:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 07:28:31 2026] 127.0.0.1:36298 [200]: GET /api/stats.php +[Fri Jul 31 07:28:31 2026] 127.0.0.1:36298 Closing +[Fri Jul 31 07:28:31 2026] 127.0.0.1:36308 Accepted +[Fri Jul 31 07:28:31 2026] 127.0.0.1:36308 [200]: GET /api/chart.php?range=year +[Fri Jul 31 07:28:31 2026] 127.0.0.1:36308 Closing +[Fri Jul 31 07:29:31 2026] 127.0.0.1:53614 Accepted +[Fri Jul 31 07:29:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 07:29:31 2026] 127.0.0.1:53614 [200]: GET /api/stats.php +[Fri Jul 31 07:29:31 2026] 127.0.0.1:53614 Closing +[Fri Jul 31 07:29:31 2026] 127.0.0.1:53626 Accepted +[Fri Jul 31 07:29:31 2026] 127.0.0.1:53626 [200]: GET /api/chart.php?range=year +[Fri Jul 31 07:29:31 2026] 127.0.0.1:53626 Closing +[Fri Jul 31 07:30:31 2026] 127.0.0.1:42010 Accepted +[Fri Jul 31 07:30:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 07:30:31 2026] 127.0.0.1:42010 [200]: GET /api/stats.php +[Fri Jul 31 07:30:31 2026] 127.0.0.1:42010 Closing +[Fri Jul 31 07:30:31 2026] 127.0.0.1:42024 Accepted +[Fri Jul 31 07:30:31 2026] 127.0.0.1:42024 [200]: GET /api/chart.php?range=year +[Fri Jul 31 07:30:31 2026] 127.0.0.1:42024 Closing +[Fri Jul 31 07:31:31 2026] 127.0.0.1:59192 Accepted +[Fri Jul 31 07:31:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 07:31:31 2026] 127.0.0.1:59192 [200]: GET /api/stats.php +[Fri Jul 31 07:31:31 2026] 127.0.0.1:59192 Closing +[Fri Jul 31 07:31:31 2026] 127.0.0.1:59208 Accepted +[Fri Jul 31 07:31:31 2026] 127.0.0.1:59208 [200]: GET /api/chart.php?range=year +[Fri Jul 31 07:31:31 2026] 127.0.0.1:59208 Closing +[Fri Jul 31 07:32:31 2026] 127.0.0.1:58754 Accepted +[Fri Jul 31 07:32:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 07:32:31 2026] 127.0.0.1:58754 [200]: GET /api/stats.php +[Fri Jul 31 07:32:31 2026] 127.0.0.1:58754 Closing +[Fri Jul 31 07:32:31 2026] 127.0.0.1:58760 Accepted +[Fri Jul 31 07:32:31 2026] 127.0.0.1:58760 [200]: GET /api/chart.php?range=year +[Fri Jul 31 07:32:31 2026] 127.0.0.1:58760 Closing +[Fri Jul 31 07:33:31 2026] 127.0.0.1:42626 Accepted +[Fri Jul 31 07:33:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 07:33:31 2026] 127.0.0.1:42626 [200]: GET /api/stats.php +[Fri Jul 31 07:33:31 2026] 127.0.0.1:42626 Closing +[Fri Jul 31 07:33:31 2026] 127.0.0.1:42632 Accepted +[Fri Jul 31 07:33:31 2026] 127.0.0.1:42632 [200]: GET /api/chart.php?range=year +[Fri Jul 31 07:33:31 2026] 127.0.0.1:42632 Closing +[Fri Jul 31 07:34:31 2026] 127.0.0.1:36186 Accepted +[Fri Jul 31 07:34:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 07:34:31 2026] 127.0.0.1:36186 [200]: GET /api/stats.php +[Fri Jul 31 07:34:31 2026] 127.0.0.1:36186 Closing +[Fri Jul 31 07:34:31 2026] 127.0.0.1:36188 Accepted +[Fri Jul 31 07:34:31 2026] 127.0.0.1:36188 [200]: GET /api/chart.php?range=year +[Fri Jul 31 07:34:31 2026] 127.0.0.1:36188 Closing +[Fri Jul 31 07:35:31 2026] 127.0.0.1:34264 Accepted +[Fri Jul 31 07:35:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 07:35:31 2026] 127.0.0.1:34264 [200]: GET /api/stats.php +[Fri Jul 31 07:35:31 2026] 127.0.0.1:34264 Closing +[Fri Jul 31 07:35:31 2026] 127.0.0.1:34274 Accepted +[Fri Jul 31 07:35:31 2026] 127.0.0.1:34274 [200]: GET /api/chart.php?range=year +[Fri Jul 31 07:35:31 2026] 127.0.0.1:34274 Closing +[Fri Jul 31 07:36:31 2026] 127.0.0.1:47346 Accepted +[Fri Jul 31 07:36:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 07:36:31 2026] 127.0.0.1:47346 [200]: GET /api/stats.php +[Fri Jul 31 07:36:31 2026] 127.0.0.1:47346 Closing +[Fri Jul 31 07:36:31 2026] 127.0.0.1:47350 Accepted +[Fri Jul 31 07:36:31 2026] 127.0.0.1:47350 [200]: GET /api/chart.php?range=year +[Fri Jul 31 07:36:31 2026] 127.0.0.1:47350 Closing +[Fri Jul 31 07:37:31 2026] 127.0.0.1:53428 Accepted +[Fri Jul 31 07:37:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 07:37:31 2026] 127.0.0.1:53428 [200]: GET /api/stats.php +[Fri Jul 31 07:37:31 2026] 127.0.0.1:53428 Closing +[Fri Jul 31 07:37:31 2026] 127.0.0.1:53436 Accepted +[Fri Jul 31 07:37:31 2026] 127.0.0.1:53436 [200]: GET /api/chart.php?range=year +[Fri Jul 31 07:37:31 2026] 127.0.0.1:53436 Closing +[Fri Jul 31 07:38:31 2026] 127.0.0.1:53382 Accepted +[Fri Jul 31 07:38:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 07:38:31 2026] 127.0.0.1:53382 [200]: GET /api/stats.php +[Fri Jul 31 07:38:31 2026] 127.0.0.1:53382 Closing +[Fri Jul 31 07:38:31 2026] 127.0.0.1:53390 Accepted +[Fri Jul 31 07:38:31 2026] 127.0.0.1:53390 [200]: GET /api/chart.php?range=year +[Fri Jul 31 07:38:31 2026] 127.0.0.1:53390 Closing +[Fri Jul 31 07:39:31 2026] 127.0.0.1:42630 Accepted +[Fri Jul 31 07:39:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 07:39:31 2026] 127.0.0.1:42630 [200]: GET /api/stats.php +[Fri Jul 31 07:39:31 2026] 127.0.0.1:42630 Closing +[Fri Jul 31 07:39:31 2026] 127.0.0.1:42642 Accepted +[Fri Jul 31 07:39:31 2026] 127.0.0.1:42642 [200]: GET /api/chart.php?range=year +[Fri Jul 31 07:39:31 2026] 127.0.0.1:42642 Closing +[Fri Jul 31 07:40:31 2026] 127.0.0.1:44980 Accepted +[Fri Jul 31 07:40:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 07:40:31 2026] 127.0.0.1:44980 [200]: GET /api/stats.php +[Fri Jul 31 07:40:31 2026] 127.0.0.1:44980 Closing +[Fri Jul 31 07:40:31 2026] 127.0.0.1:44986 Accepted +[Fri Jul 31 07:40:31 2026] 127.0.0.1:44986 [200]: GET /api/chart.php?range=year +[Fri Jul 31 07:40:31 2026] 127.0.0.1:44986 Closing +[Fri Jul 31 07:41:31 2026] 127.0.0.1:35490 Accepted +[Fri Jul 31 07:41:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 07:41:31 2026] 127.0.0.1:35490 [200]: GET /api/stats.php +[Fri Jul 31 07:41:31 2026] 127.0.0.1:35490 Closing +[Fri Jul 31 07:41:31 2026] 127.0.0.1:35506 Accepted +[Fri Jul 31 07:41:31 2026] 127.0.0.1:35506 [200]: GET /api/chart.php?range=year +[Fri Jul 31 07:41:31 2026] 127.0.0.1:35506 Closing +[Fri Jul 31 07:42:31 2026] 127.0.0.1:49948 Accepted +[Fri Jul 31 07:42:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 07:42:31 2026] 127.0.0.1:49948 [200]: GET /api/stats.php +[Fri Jul 31 07:42:31 2026] 127.0.0.1:49948 Closing +[Fri Jul 31 07:42:31 2026] 127.0.0.1:49956 Accepted +[Fri Jul 31 07:42:31 2026] 127.0.0.1:49956 [200]: GET /api/chart.php?range=year +[Fri Jul 31 07:42:31 2026] 127.0.0.1:49956 Closing +[Fri Jul 31 07:43:31 2026] 127.0.0.1:34852 Accepted +[Fri Jul 31 07:43:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 07:43:31 2026] 127.0.0.1:34852 [200]: GET /api/stats.php +[Fri Jul 31 07:43:31 2026] 127.0.0.1:34852 Closing +[Fri Jul 31 07:43:31 2026] 127.0.0.1:34860 Accepted +[Fri Jul 31 07:43:31 2026] 127.0.0.1:34860 [200]: GET /api/chart.php?range=year +[Fri Jul 31 07:43:31 2026] 127.0.0.1:34860 Closing +[Fri Jul 31 07:44:31 2026] 127.0.0.1:51464 Accepted +[Fri Jul 31 07:44:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 07:44:31 2026] 127.0.0.1:51464 [200]: GET /api/stats.php +[Fri Jul 31 07:44:31 2026] 127.0.0.1:51464 Closing +[Fri Jul 31 07:44:31 2026] 127.0.0.1:51470 Accepted +[Fri Jul 31 07:44:31 2026] 127.0.0.1:51470 [200]: GET /api/chart.php?range=year +[Fri Jul 31 07:44:31 2026] 127.0.0.1:51470 Closing +[Fri Jul 31 07:45:31 2026] 127.0.0.1:43732 Accepted +[Fri Jul 31 07:45:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 07:45:31 2026] 127.0.0.1:43732 [200]: GET /api/stats.php +[Fri Jul 31 07:45:31 2026] 127.0.0.1:43732 Closing +[Fri Jul 31 07:45:31 2026] 127.0.0.1:43744 Accepted +[Fri Jul 31 07:45:31 2026] 127.0.0.1:43744 [200]: GET /api/chart.php?range=year +[Fri Jul 31 07:45:31 2026] 127.0.0.1:43744 Closing +[Fri Jul 31 07:46:31 2026] 127.0.0.1:42686 Accepted +[Fri Jul 31 07:46:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 07:46:31 2026] 127.0.0.1:42686 [200]: GET /api/stats.php +[Fri Jul 31 07:46:31 2026] 127.0.0.1:42686 Closing +[Fri Jul 31 07:46:31 2026] 127.0.0.1:42696 Accepted +[Fri Jul 31 07:46:31 2026] 127.0.0.1:42696 [200]: GET /api/chart.php?range=year +[Fri Jul 31 07:46:31 2026] 127.0.0.1:42696 Closing +[Fri Jul 31 07:47:31 2026] 127.0.0.1:46908 Accepted +[Fri Jul 31 07:47:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 07:47:31 2026] 127.0.0.1:46908 [200]: GET /api/stats.php +[Fri Jul 31 07:47:31 2026] 127.0.0.1:46908 Closing +[Fri Jul 31 07:47:31 2026] 127.0.0.1:46914 Accepted +[Fri Jul 31 07:47:31 2026] 127.0.0.1:46914 [200]: GET /api/chart.php?range=year +[Fri Jul 31 07:47:31 2026] 127.0.0.1:46914 Closing +[Fri Jul 31 07:48:31 2026] 127.0.0.1:59356 Accepted +[Fri Jul 31 07:48:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 07:48:31 2026] 127.0.0.1:59356 [200]: GET /api/stats.php +[Fri Jul 31 07:48:31 2026] 127.0.0.1:59356 Closing +[Fri Jul 31 07:48:31 2026] 127.0.0.1:59358 Accepted +[Fri Jul 31 07:48:31 2026] 127.0.0.1:59358 [200]: GET /api/chart.php?range=year +[Fri Jul 31 07:48:31 2026] 127.0.0.1:59358 Closing +[Fri Jul 31 07:49:31 2026] 127.0.0.1:48138 Accepted +[Fri Jul 31 07:49:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 07:49:31 2026] 127.0.0.1:48138 [200]: GET /api/stats.php +[Fri Jul 31 07:49:31 2026] 127.0.0.1:48138 Closing +[Fri Jul 31 07:49:31 2026] 127.0.0.1:48154 Accepted +[Fri Jul 31 07:49:31 2026] 127.0.0.1:48154 [200]: GET /api/chart.php?range=year +[Fri Jul 31 07:49:31 2026] 127.0.0.1:48154 Closing +[Fri Jul 31 07:50:31 2026] 127.0.0.1:35348 Accepted +[Fri Jul 31 07:50:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 07:50:31 2026] 127.0.0.1:35348 [200]: GET /api/stats.php +[Fri Jul 31 07:50:31 2026] 127.0.0.1:35348 Closing +[Fri Jul 31 07:50:31 2026] 127.0.0.1:35360 Accepted +[Fri Jul 31 07:50:31 2026] 127.0.0.1:35360 [200]: GET /api/chart.php?range=year +[Fri Jul 31 07:50:31 2026] 127.0.0.1:35360 Closing +[Fri Jul 31 07:51:31 2026] 127.0.0.1:46298 Accepted +[Fri Jul 31 07:51:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 07:51:31 2026] 127.0.0.1:46298 [200]: GET /api/stats.php +[Fri Jul 31 07:51:31 2026] 127.0.0.1:46298 Closing +[Fri Jul 31 07:51:31 2026] 127.0.0.1:46314 Accepted +[Fri Jul 31 07:51:31 2026] 127.0.0.1:46314 [200]: GET /api/chart.php?range=year +[Fri Jul 31 07:51:31 2026] 127.0.0.1:46314 Closing +[Fri Jul 31 07:52:31 2026] 127.0.0.1:45096 Accepted +[Fri Jul 31 07:52:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 07:52:31 2026] 127.0.0.1:45096 [200]: GET /api/stats.php +[Fri Jul 31 07:52:31 2026] 127.0.0.1:45096 Closing +[Fri Jul 31 07:52:31 2026] 127.0.0.1:45104 Accepted +[Fri Jul 31 07:52:31 2026] 127.0.0.1:45104 [200]: GET /api/chart.php?range=year +[Fri Jul 31 07:52:31 2026] 127.0.0.1:45104 Closing +[Fri Jul 31 07:53:31 2026] 127.0.0.1:53792 Accepted +[Fri Jul 31 07:53:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 07:53:31 2026] 127.0.0.1:53792 [200]: GET /api/stats.php +[Fri Jul 31 07:53:31 2026] 127.0.0.1:53792 Closing +[Fri Jul 31 07:53:31 2026] 127.0.0.1:53808 Accepted +[Fri Jul 31 07:53:31 2026] 127.0.0.1:53808 [200]: GET /api/chart.php?range=year +[Fri Jul 31 07:53:31 2026] 127.0.0.1:53808 Closing +[Fri Jul 31 07:54:31 2026] 127.0.0.1:39502 Accepted +[Fri Jul 31 07:54:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 07:54:31 2026] 127.0.0.1:39502 [200]: GET /api/stats.php +[Fri Jul 31 07:54:31 2026] 127.0.0.1:39502 Closing +[Fri Jul 31 07:54:31 2026] 127.0.0.1:39504 Accepted +[Fri Jul 31 07:54:31 2026] 127.0.0.1:39504 [200]: GET /api/chart.php?range=year +[Fri Jul 31 07:54:31 2026] 127.0.0.1:39504 Closing +[Fri Jul 31 07:55:31 2026] 127.0.0.1:53160 Accepted +[Fri Jul 31 07:55:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 07:55:31 2026] 127.0.0.1:53160 [200]: GET /api/stats.php +[Fri Jul 31 07:55:31 2026] 127.0.0.1:53160 Closing +[Fri Jul 31 07:55:31 2026] 127.0.0.1:53162 Accepted +[Fri Jul 31 07:55:31 2026] 127.0.0.1:53162 [200]: GET /api/chart.php?range=year +[Fri Jul 31 07:55:31 2026] 127.0.0.1:53162 Closing +[Fri Jul 31 07:56:31 2026] 127.0.0.1:37258 Accepted +[Fri Jul 31 07:56:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 07:56:31 2026] 127.0.0.1:37258 [200]: GET /api/stats.php +[Fri Jul 31 07:56:31 2026] 127.0.0.1:37258 Closing +[Fri Jul 31 07:56:31 2026] 127.0.0.1:37274 Accepted +[Fri Jul 31 07:56:31 2026] 127.0.0.1:37274 [200]: GET /api/chart.php?range=year +[Fri Jul 31 07:56:31 2026] 127.0.0.1:37274 Closing +[Fri Jul 31 07:57:31 2026] 127.0.0.1:43956 Accepted +[Fri Jul 31 07:57:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 07:57:31 2026] 127.0.0.1:43956 [200]: GET /api/stats.php +[Fri Jul 31 07:57:31 2026] 127.0.0.1:43956 Closing +[Fri Jul 31 07:57:31 2026] 127.0.0.1:43968 Accepted +[Fri Jul 31 07:57:31 2026] 127.0.0.1:43968 [200]: GET /api/chart.php?range=year +[Fri Jul 31 07:57:31 2026] 127.0.0.1:43968 Closing +[Fri Jul 31 07:58:31 2026] 127.0.0.1:39712 Accepted +[Fri Jul 31 07:58:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 07:58:31 2026] 127.0.0.1:39712 [200]: GET /api/stats.php +[Fri Jul 31 07:58:31 2026] 127.0.0.1:39712 Closing +[Fri Jul 31 07:58:31 2026] 127.0.0.1:39726 Accepted +[Fri Jul 31 07:58:31 2026] 127.0.0.1:39726 [200]: GET /api/chart.php?range=year +[Fri Jul 31 07:58:31 2026] 127.0.0.1:39726 Closing +[Fri Jul 31 07:59:31 2026] 127.0.0.1:34258 Accepted +[Fri Jul 31 07:59:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 07:59:31 2026] 127.0.0.1:34258 [200]: GET /api/stats.php +[Fri Jul 31 07:59:31 2026] 127.0.0.1:34258 Closing +[Fri Jul 31 07:59:31 2026] 127.0.0.1:34264 Accepted +[Fri Jul 31 07:59:31 2026] 127.0.0.1:34264 [200]: GET /api/chart.php?range=year +[Fri Jul 31 07:59:31 2026] 127.0.0.1:34264 Closing +[Fri Jul 31 08:00:31 2026] 127.0.0.1:40328 Accepted +[Fri Jul 31 08:00:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 08:00:31 2026] 127.0.0.1:40328 [200]: GET /api/stats.php +[Fri Jul 31 08:00:31 2026] 127.0.0.1:40328 Closing +[Fri Jul 31 08:00:31 2026] 127.0.0.1:40336 Accepted +[Fri Jul 31 08:00:31 2026] 127.0.0.1:40336 [200]: GET /api/chart.php?range=year +[Fri Jul 31 08:00:31 2026] 127.0.0.1:40336 Closing +[Fri Jul 31 08:01:31 2026] 127.0.0.1:44940 Accepted +[Fri Jul 31 08:01:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 08:01:31 2026] 127.0.0.1:44940 [200]: GET /api/stats.php +[Fri Jul 31 08:01:31 2026] 127.0.0.1:44940 Closing +[Fri Jul 31 08:01:31 2026] 127.0.0.1:44948 Accepted +[Fri Jul 31 08:01:31 2026] 127.0.0.1:44948 [200]: GET /api/chart.php?range=year +[Fri Jul 31 08:01:31 2026] 127.0.0.1:44948 Closing +[Fri Jul 31 08:02:31 2026] 127.0.0.1:45588 Accepted +[Fri Jul 31 08:02:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 08:02:31 2026] 127.0.0.1:45588 [200]: GET /api/stats.php +[Fri Jul 31 08:02:31 2026] 127.0.0.1:45588 Closing +[Fri Jul 31 08:02:31 2026] 127.0.0.1:45592 Accepted +[Fri Jul 31 08:02:31 2026] 127.0.0.1:45592 [200]: GET /api/chart.php?range=year +[Fri Jul 31 08:02:31 2026] 127.0.0.1:45592 Closing +[Fri Jul 31 08:03:31 2026] 127.0.0.1:59462 Accepted +[Fri Jul 31 08:03:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 08:03:31 2026] 127.0.0.1:59462 [200]: GET /api/stats.php +[Fri Jul 31 08:03:31 2026] 127.0.0.1:59462 Closing +[Fri Jul 31 08:03:31 2026] 127.0.0.1:59478 Accepted +[Fri Jul 31 08:03:31 2026] 127.0.0.1:59478 [200]: GET /api/chart.php?range=year +[Fri Jul 31 08:03:31 2026] 127.0.0.1:59478 Closing +[Fri Jul 31 08:04:31 2026] 127.0.0.1:55778 Accepted +[Fri Jul 31 08:04:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 08:04:31 2026] 127.0.0.1:55778 [200]: GET /api/stats.php +[Fri Jul 31 08:04:31 2026] 127.0.0.1:55778 Closing +[Fri Jul 31 08:04:31 2026] 127.0.0.1:55780 Accepted +[Fri Jul 31 08:04:31 2026] 127.0.0.1:55780 [200]: GET /api/chart.php?range=year +[Fri Jul 31 08:04:31 2026] 127.0.0.1:55780 Closing +[Fri Jul 31 08:05:31 2026] 127.0.0.1:55720 Accepted +[Fri Jul 31 08:05:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 08:05:31 2026] 127.0.0.1:55720 [200]: GET /api/stats.php +[Fri Jul 31 08:05:31 2026] 127.0.0.1:55720 Closing +[Fri Jul 31 08:05:31 2026] 127.0.0.1:55730 Accepted +[Fri Jul 31 08:05:31 2026] 127.0.0.1:55730 [200]: GET /api/chart.php?range=year +[Fri Jul 31 08:05:31 2026] 127.0.0.1:55730 Closing +[Fri Jul 31 08:06:31 2026] 127.0.0.1:40922 Accepted +[Fri Jul 31 08:06:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 08:06:31 2026] 127.0.0.1:40922 [200]: GET /api/stats.php +[Fri Jul 31 08:06:31 2026] 127.0.0.1:40922 Closing +[Fri Jul 31 08:06:31 2026] 127.0.0.1:40926 Accepted +[Fri Jul 31 08:06:31 2026] 127.0.0.1:40926 [200]: GET /api/chart.php?range=year +[Fri Jul 31 08:06:31 2026] 127.0.0.1:40926 Closing +[Fri Jul 31 08:07:31 2026] 127.0.0.1:53550 Accepted +[Fri Jul 31 08:07:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 08:07:31 2026] 127.0.0.1:53550 [200]: GET /api/stats.php +[Fri Jul 31 08:07:31 2026] 127.0.0.1:53550 Closing +[Fri Jul 31 08:07:31 2026] 127.0.0.1:53562 Accepted +[Fri Jul 31 08:07:31 2026] 127.0.0.1:53562 [200]: GET /api/chart.php?range=year +[Fri Jul 31 08:07:31 2026] 127.0.0.1:53562 Closing +[Fri Jul 31 08:08:31 2026] 127.0.0.1:57290 Accepted +[Fri Jul 31 08:08:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 08:08:31 2026] 127.0.0.1:57290 [200]: GET /api/stats.php +[Fri Jul 31 08:08:31 2026] 127.0.0.1:57290 Closing +[Fri Jul 31 08:08:31 2026] 127.0.0.1:57306 Accepted +[Fri Jul 31 08:08:31 2026] 127.0.0.1:57306 [200]: GET /api/chart.php?range=year +[Fri Jul 31 08:08:31 2026] 127.0.0.1:57306 Closing +[Fri Jul 31 08:09:31 2026] 127.0.0.1:48280 Accepted +[Fri Jul 31 08:09:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 08:09:31 2026] 127.0.0.1:48280 [200]: GET /api/stats.php +[Fri Jul 31 08:09:31 2026] 127.0.0.1:48280 Closing +[Fri Jul 31 08:09:31 2026] 127.0.0.1:48284 Accepted +[Fri Jul 31 08:09:31 2026] 127.0.0.1:48284 [200]: GET /api/chart.php?range=year +[Fri Jul 31 08:09:31 2026] 127.0.0.1:48284 Closing +[Fri Jul 31 08:10:31 2026] 127.0.0.1:57290 Accepted +[Fri Jul 31 08:10:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 08:10:31 2026] 127.0.0.1:57290 [200]: GET /api/stats.php +[Fri Jul 31 08:10:31 2026] 127.0.0.1:57290 Closing +[Fri Jul 31 08:10:31 2026] 127.0.0.1:57300 Accepted +[Fri Jul 31 08:10:31 2026] 127.0.0.1:57300 [200]: GET /api/chart.php?range=year +[Fri Jul 31 08:10:31 2026] 127.0.0.1:57300 Closing +[Fri Jul 31 08:11:31 2026] 127.0.0.1:45020 Accepted +[Fri Jul 31 08:11:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 08:11:31 2026] 127.0.0.1:45020 [200]: GET /api/stats.php +[Fri Jul 31 08:11:31 2026] 127.0.0.1:45020 Closing +[Fri Jul 31 08:11:31 2026] 127.0.0.1:45034 Accepted +[Fri Jul 31 08:11:31 2026] 127.0.0.1:45034 [200]: GET /api/chart.php?range=year +[Fri Jul 31 08:11:31 2026] 127.0.0.1:45034 Closing +[Fri Jul 31 08:12:31 2026] 127.0.0.1:43638 Accepted +[Fri Jul 31 08:12:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 08:12:31 2026] 127.0.0.1:43638 [200]: GET /api/stats.php +[Fri Jul 31 08:12:31 2026] 127.0.0.1:43638 Closing +[Fri Jul 31 08:12:31 2026] 127.0.0.1:43652 Accepted +[Fri Jul 31 08:12:31 2026] 127.0.0.1:43652 [200]: GET /api/chart.php?range=year +[Fri Jul 31 08:12:31 2026] 127.0.0.1:43652 Closing +[Fri Jul 31 08:13:31 2026] 127.0.0.1:60410 Accepted +[Fri Jul 31 08:13:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 08:13:31 2026] 127.0.0.1:60410 [200]: GET /api/stats.php +[Fri Jul 31 08:13:31 2026] 127.0.0.1:60410 Closing +[Fri Jul 31 08:13:31 2026] 127.0.0.1:60412 Accepted +[Fri Jul 31 08:13:31 2026] 127.0.0.1:60412 [200]: GET /api/chart.php?range=year +[Fri Jul 31 08:13:31 2026] 127.0.0.1:60412 Closing +[Fri Jul 31 08:14:31 2026] 127.0.0.1:35036 Accepted +[Fri Jul 31 08:14:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 08:14:31 2026] 127.0.0.1:35036 [200]: GET /api/stats.php +[Fri Jul 31 08:14:31 2026] 127.0.0.1:35036 Closing +[Fri Jul 31 08:14:31 2026] 127.0.0.1:35040 Accepted +[Fri Jul 31 08:14:31 2026] 127.0.0.1:35040 [200]: GET /api/chart.php?range=year +[Fri Jul 31 08:14:31 2026] 127.0.0.1:35040 Closing +[Fri Jul 31 08:15:31 2026] 127.0.0.1:48558 Accepted +[Fri Jul 31 08:15:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 08:15:31 2026] 127.0.0.1:48558 [200]: GET /api/stats.php +[Fri Jul 31 08:15:31 2026] 127.0.0.1:48558 Closing +[Fri Jul 31 08:15:31 2026] 127.0.0.1:48570 Accepted +[Fri Jul 31 08:15:31 2026] 127.0.0.1:48570 [200]: GET /api/chart.php?range=year +[Fri Jul 31 08:15:31 2026] 127.0.0.1:48570 Closing +[Fri Jul 31 08:16:31 2026] 127.0.0.1:52082 Accepted +[Fri Jul 31 08:16:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 08:16:31 2026] 127.0.0.1:52082 [200]: GET /api/stats.php +[Fri Jul 31 08:16:31 2026] 127.0.0.1:52082 Closing +[Fri Jul 31 08:16:31 2026] 127.0.0.1:52088 Accepted +[Fri Jul 31 08:16:31 2026] 127.0.0.1:52088 [200]: GET /api/chart.php?range=year +[Fri Jul 31 08:16:31 2026] 127.0.0.1:52088 Closing +[Fri Jul 31 08:17:31 2026] 127.0.0.1:34198 Accepted +[Fri Jul 31 08:17:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 08:17:31 2026] 127.0.0.1:34198 [200]: GET /api/stats.php +[Fri Jul 31 08:17:31 2026] 127.0.0.1:34198 Closing +[Fri Jul 31 08:17:31 2026] 127.0.0.1:34200 Accepted +[Fri Jul 31 08:17:31 2026] 127.0.0.1:34200 [200]: GET /api/chart.php?range=year +[Fri Jul 31 08:17:31 2026] 127.0.0.1:34200 Closing +[Fri Jul 31 08:18:31 2026] 127.0.0.1:57138 Accepted +[Fri Jul 31 08:18:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 08:18:31 2026] 127.0.0.1:57138 [200]: GET /api/stats.php +[Fri Jul 31 08:18:31 2026] 127.0.0.1:57138 Closing +[Fri Jul 31 08:18:31 2026] 127.0.0.1:57146 Accepted +[Fri Jul 31 08:18:31 2026] 127.0.0.1:57146 [200]: GET /api/chart.php?range=year +[Fri Jul 31 08:18:31 2026] 127.0.0.1:57146 Closing +[Fri Jul 31 08:19:31 2026] 127.0.0.1:46020 Accepted +[Fri Jul 31 08:19:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 08:19:31 2026] 127.0.0.1:46020 [200]: GET /api/stats.php +[Fri Jul 31 08:19:31 2026] 127.0.0.1:46020 Closing +[Fri Jul 31 08:19:31 2026] 127.0.0.1:46036 Accepted +[Fri Jul 31 08:19:31 2026] 127.0.0.1:46036 [200]: GET /api/chart.php?range=year +[Fri Jul 31 08:19:31 2026] 127.0.0.1:46036 Closing +[Fri Jul 31 08:20:31 2026] 127.0.0.1:58628 Accepted +[Fri Jul 31 08:20:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 08:20:31 2026] 127.0.0.1:58628 [200]: GET /api/stats.php +[Fri Jul 31 08:20:31 2026] 127.0.0.1:58628 Closing +[Fri Jul 31 08:20:31 2026] 127.0.0.1:58640 Accepted +[Fri Jul 31 08:20:31 2026] 127.0.0.1:58640 [200]: GET /api/chart.php?range=year +[Fri Jul 31 08:20:31 2026] 127.0.0.1:58640 Closing +[Fri Jul 31 08:21:31 2026] 127.0.0.1:46794 Accepted +[Fri Jul 31 08:21:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 08:21:31 2026] 127.0.0.1:46794 [200]: GET /api/stats.php +[Fri Jul 31 08:21:31 2026] 127.0.0.1:46794 Closing +[Fri Jul 31 08:21:31 2026] 127.0.0.1:46806 Accepted +[Fri Jul 31 08:21:31 2026] 127.0.0.1:46806 [200]: GET /api/chart.php?range=year +[Fri Jul 31 08:21:31 2026] 127.0.0.1:46806 Closing +[Fri Jul 31 08:22:31 2026] 127.0.0.1:58544 Accepted +[Fri Jul 31 08:22:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 08:22:31 2026] 127.0.0.1:58544 [200]: GET /api/stats.php +[Fri Jul 31 08:22:31 2026] 127.0.0.1:58544 Closing +[Fri Jul 31 08:22:31 2026] 127.0.0.1:58558 Accepted +[Fri Jul 31 08:22:31 2026] 127.0.0.1:58558 [200]: GET /api/chart.php?range=year +[Fri Jul 31 08:22:31 2026] 127.0.0.1:58558 Closing +[Fri Jul 31 08:23:31 2026] 127.0.0.1:46598 Accepted +[Fri Jul 31 08:23:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 08:23:31 2026] 127.0.0.1:46598 [200]: GET /api/stats.php +[Fri Jul 31 08:23:31 2026] 127.0.0.1:46598 Closing +[Fri Jul 31 08:23:31 2026] 127.0.0.1:46614 Accepted +[Fri Jul 31 08:23:31 2026] 127.0.0.1:46614 [200]: GET /api/chart.php?range=year +[Fri Jul 31 08:23:31 2026] 127.0.0.1:46614 Closing +[Fri Jul 31 08:24:31 2026] 127.0.0.1:54308 Accepted +[Fri Jul 31 08:24:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 08:24:31 2026] 127.0.0.1:54308 [200]: GET /api/stats.php +[Fri Jul 31 08:24:31 2026] 127.0.0.1:54308 Closing +[Fri Jul 31 08:24:31 2026] 127.0.0.1:54324 Accepted +[Fri Jul 31 08:24:31 2026] 127.0.0.1:54324 [200]: GET /api/chart.php?range=year +[Fri Jul 31 08:24:31 2026] 127.0.0.1:54324 Closing +[Fri Jul 31 08:25:31 2026] 127.0.0.1:40858 Accepted +[Fri Jul 31 08:25:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 08:25:31 2026] 127.0.0.1:40858 [200]: GET /api/stats.php +[Fri Jul 31 08:25:31 2026] 127.0.0.1:40858 Closing +[Fri Jul 31 08:25:31 2026] 127.0.0.1:40864 Accepted +[Fri Jul 31 08:25:31 2026] 127.0.0.1:40864 [200]: GET /api/chart.php?range=year +[Fri Jul 31 08:25:31 2026] 127.0.0.1:40864 Closing +[Fri Jul 31 08:26:31 2026] 127.0.0.1:56086 Accepted +[Fri Jul 31 08:26:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 08:26:31 2026] 127.0.0.1:56086 [200]: GET /api/stats.php +[Fri Jul 31 08:26:31 2026] 127.0.0.1:56086 Closing +[Fri Jul 31 08:26:31 2026] 127.0.0.1:56100 Accepted +[Fri Jul 31 08:26:31 2026] 127.0.0.1:56100 [200]: GET /api/chart.php?range=year +[Fri Jul 31 08:26:31 2026] 127.0.0.1:56100 Closing +[Fri Jul 31 08:27:31 2026] 127.0.0.1:44360 Accepted +[Fri Jul 31 08:27:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 08:27:31 2026] 127.0.0.1:44360 [200]: GET /api/stats.php +[Fri Jul 31 08:27:31 2026] 127.0.0.1:44360 Closing +[Fri Jul 31 08:27:31 2026] 127.0.0.1:44362 Accepted +[Fri Jul 31 08:27:31 2026] 127.0.0.1:44362 [200]: GET /api/chart.php?range=year +[Fri Jul 31 08:27:31 2026] 127.0.0.1:44362 Closing +[Fri Jul 31 08:28:31 2026] 127.0.0.1:59070 Accepted +[Fri Jul 31 08:28:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 08:28:31 2026] 127.0.0.1:59070 [200]: GET /api/stats.php +[Fri Jul 31 08:28:31 2026] 127.0.0.1:59070 Closing +[Fri Jul 31 08:28:31 2026] 127.0.0.1:59072 Accepted +[Fri Jul 31 08:28:31 2026] 127.0.0.1:59072 [200]: GET /api/chart.php?range=year +[Fri Jul 31 08:28:31 2026] 127.0.0.1:59072 Closing +[Fri Jul 31 08:29:31 2026] 127.0.0.1:34250 Accepted +[Fri Jul 31 08:29:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 08:29:31 2026] 127.0.0.1:34250 [200]: GET /api/stats.php +[Fri Jul 31 08:29:31 2026] 127.0.0.1:34250 Closing +[Fri Jul 31 08:29:31 2026] 127.0.0.1:34266 Accepted +[Fri Jul 31 08:29:31 2026] 127.0.0.1:34266 [200]: GET /api/chart.php?range=year +[Fri Jul 31 08:29:31 2026] 127.0.0.1:34266 Closing +[Fri Jul 31 08:30:31 2026] 127.0.0.1:42796 Accepted +[Fri Jul 31 08:30:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 08:30:31 2026] 127.0.0.1:42796 [200]: GET /api/stats.php +[Fri Jul 31 08:30:31 2026] 127.0.0.1:42796 Closing +[Fri Jul 31 08:30:31 2026] 127.0.0.1:42808 Accepted +[Fri Jul 31 08:30:31 2026] 127.0.0.1:42808 [200]: GET /api/chart.php?range=year +[Fri Jul 31 08:30:31 2026] 127.0.0.1:42808 Closing +[Fri Jul 31 08:31:31 2026] 127.0.0.1:56928 Accepted +[Fri Jul 31 08:31:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 08:31:31 2026] 127.0.0.1:56928 [200]: GET /api/stats.php +[Fri Jul 31 08:31:31 2026] 127.0.0.1:56928 Closing +[Fri Jul 31 08:31:31 2026] 127.0.0.1:56930 Accepted +[Fri Jul 31 08:31:31 2026] 127.0.0.1:56930 [200]: GET /api/chart.php?range=year +[Fri Jul 31 08:31:31 2026] 127.0.0.1:56930 Closing +[Fri Jul 31 08:32:31 2026] 127.0.0.1:51990 Accepted +[Fri Jul 31 08:32:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 08:32:31 2026] 127.0.0.1:51990 [200]: GET /api/stats.php +[Fri Jul 31 08:32:31 2026] 127.0.0.1:51990 Closing +[Fri Jul 31 08:32:31 2026] 127.0.0.1:52000 Accepted +[Fri Jul 31 08:32:31 2026] 127.0.0.1:52000 [200]: GET /api/chart.php?range=year +[Fri Jul 31 08:32:31 2026] 127.0.0.1:52000 Closing +[Fri Jul 31 08:33:31 2026] 127.0.0.1:38836 Accepted +[Fri Jul 31 08:33:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 08:33:31 2026] 127.0.0.1:38836 [200]: GET /api/stats.php +[Fri Jul 31 08:33:31 2026] 127.0.0.1:38836 Closing +[Fri Jul 31 08:33:31 2026] 127.0.0.1:38850 Accepted +[Fri Jul 31 08:33:31 2026] 127.0.0.1:38850 [200]: GET /api/chart.php?range=year +[Fri Jul 31 08:33:31 2026] 127.0.0.1:38850 Closing +[Fri Jul 31 08:34:31 2026] 127.0.0.1:42584 Accepted +[Fri Jul 31 08:34:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 08:34:31 2026] 127.0.0.1:42584 [200]: GET /api/stats.php +[Fri Jul 31 08:34:31 2026] 127.0.0.1:42584 Closing +[Fri Jul 31 08:34:31 2026] 127.0.0.1:42586 Accepted +[Fri Jul 31 08:34:31 2026] 127.0.0.1:42586 [200]: GET /api/chart.php?range=year +[Fri Jul 31 08:34:31 2026] 127.0.0.1:42586 Closing +[Fri Jul 31 08:35:31 2026] 127.0.0.1:37554 Accepted +[Fri Jul 31 08:35:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 08:35:31 2026] 127.0.0.1:37554 [200]: GET /api/stats.php +[Fri Jul 31 08:35:31 2026] 127.0.0.1:37554 Closing +[Fri Jul 31 08:35:31 2026] 127.0.0.1:37568 Accepted +[Fri Jul 31 08:35:31 2026] 127.0.0.1:37568 [200]: GET /api/chart.php?range=year +[Fri Jul 31 08:35:31 2026] 127.0.0.1:37568 Closing +[Fri Jul 31 08:36:31 2026] 127.0.0.1:41372 Accepted +[Fri Jul 31 08:36:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 08:36:31 2026] 127.0.0.1:41372 [200]: GET /api/stats.php +[Fri Jul 31 08:36:31 2026] 127.0.0.1:41372 Closing +[Fri Jul 31 08:36:31 2026] 127.0.0.1:41382 Accepted +[Fri Jul 31 08:36:31 2026] 127.0.0.1:41382 [200]: GET /api/chart.php?range=year +[Fri Jul 31 08:36:31 2026] 127.0.0.1:41382 Closing +[Fri Jul 31 08:37:31 2026] 127.0.0.1:33528 Accepted +[Fri Jul 31 08:37:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 08:37:31 2026] 127.0.0.1:33528 [200]: GET /api/stats.php +[Fri Jul 31 08:37:31 2026] 127.0.0.1:33528 Closing +[Fri Jul 31 08:37:31 2026] 127.0.0.1:33538 Accepted +[Fri Jul 31 08:37:31 2026] 127.0.0.1:33538 [200]: GET /api/chart.php?range=year +[Fri Jul 31 08:37:31 2026] 127.0.0.1:33538 Closing +[Fri Jul 31 08:38:31 2026] 127.0.0.1:58010 Accepted +[Fri Jul 31 08:38:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 08:38:31 2026] 127.0.0.1:58010 [200]: GET /api/stats.php +[Fri Jul 31 08:38:31 2026] 127.0.0.1:58010 Closing +[Fri Jul 31 08:38:31 2026] 127.0.0.1:58024 Accepted +[Fri Jul 31 08:38:31 2026] 127.0.0.1:58024 [200]: GET /api/chart.php?range=year +[Fri Jul 31 08:38:31 2026] 127.0.0.1:58024 Closing +[Fri Jul 31 08:39:31 2026] 127.0.0.1:57172 Accepted +[Fri Jul 31 08:39:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 08:39:31 2026] 127.0.0.1:57172 [200]: GET /api/stats.php +[Fri Jul 31 08:39:31 2026] 127.0.0.1:57172 Closing +[Fri Jul 31 08:39:31 2026] 127.0.0.1:57182 Accepted +[Fri Jul 31 08:39:31 2026] 127.0.0.1:57182 [200]: GET /api/chart.php?range=year +[Fri Jul 31 08:39:31 2026] 127.0.0.1:57182 Closing +[Fri Jul 31 08:40:31 2026] 127.0.0.1:55452 Accepted +[Fri Jul 31 08:40:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 08:40:31 2026] 127.0.0.1:55452 [200]: GET /api/stats.php +[Fri Jul 31 08:40:31 2026] 127.0.0.1:55452 Closing +[Fri Jul 31 08:40:31 2026] 127.0.0.1:55464 Accepted +[Fri Jul 31 08:40:31 2026] 127.0.0.1:55464 [200]: GET /api/chart.php?range=year +[Fri Jul 31 08:40:31 2026] 127.0.0.1:55464 Closing +[Fri Jul 31 08:41:31 2026] 127.0.0.1:57122 Accepted +[Fri Jul 31 08:41:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 08:41:31 2026] 127.0.0.1:57122 [200]: GET /api/stats.php +[Fri Jul 31 08:41:31 2026] 127.0.0.1:57122 Closing +[Fri Jul 31 08:41:31 2026] 127.0.0.1:57128 Accepted +[Fri Jul 31 08:41:31 2026] 127.0.0.1:57128 [200]: GET /api/chart.php?range=year +[Fri Jul 31 08:41:31 2026] 127.0.0.1:57128 Closing +[Fri Jul 31 08:42:31 2026] 127.0.0.1:58280 Accepted +[Fri Jul 31 08:42:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 08:42:31 2026] 127.0.0.1:58280 [200]: GET /api/stats.php +[Fri Jul 31 08:42:31 2026] 127.0.0.1:58280 Closing +[Fri Jul 31 08:42:31 2026] 127.0.0.1:58292 Accepted +[Fri Jul 31 08:42:31 2026] 127.0.0.1:58292 [200]: GET /api/chart.php?range=year +[Fri Jul 31 08:42:31 2026] 127.0.0.1:58292 Closing +[Fri Jul 31 08:43:31 2026] 127.0.0.1:52696 Accepted +[Fri Jul 31 08:43:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 08:43:31 2026] 127.0.0.1:52696 [200]: GET /api/stats.php +[Fri Jul 31 08:43:31 2026] 127.0.0.1:52696 Closing +[Fri Jul 31 08:43:31 2026] 127.0.0.1:52698 Accepted +[Fri Jul 31 08:43:31 2026] 127.0.0.1:52698 [200]: GET /api/chart.php?range=year +[Fri Jul 31 08:43:31 2026] 127.0.0.1:52698 Closing +[Fri Jul 31 08:44:31 2026] 127.0.0.1:39800 Accepted +[Fri Jul 31 08:44:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 08:44:31 2026] 127.0.0.1:39800 [200]: GET /api/stats.php +[Fri Jul 31 08:44:31 2026] 127.0.0.1:39800 Closing +[Fri Jul 31 08:44:31 2026] 127.0.0.1:39812 Accepted +[Fri Jul 31 08:44:31 2026] 127.0.0.1:39812 [200]: GET /api/chart.php?range=year +[Fri Jul 31 08:44:31 2026] 127.0.0.1:39812 Closing +[Fri Jul 31 08:45:31 2026] 127.0.0.1:35890 Accepted +[Fri Jul 31 08:45:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 08:45:31 2026] 127.0.0.1:35890 [200]: GET /api/stats.php +[Fri Jul 31 08:45:31 2026] 127.0.0.1:35890 Closing +[Fri Jul 31 08:45:31 2026] 127.0.0.1:35898 Accepted +[Fri Jul 31 08:45:31 2026] 127.0.0.1:35898 [200]: GET /api/chart.php?range=year +[Fri Jul 31 08:45:31 2026] 127.0.0.1:35898 Closing +[Fri Jul 31 08:46:31 2026] 127.0.0.1:38126 Accepted +[Fri Jul 31 08:46:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 08:46:31 2026] 127.0.0.1:38126 [200]: GET /api/stats.php +[Fri Jul 31 08:46:31 2026] 127.0.0.1:38126 Closing +[Fri Jul 31 08:46:31 2026] 127.0.0.1:38130 Accepted +[Fri Jul 31 08:46:31 2026] 127.0.0.1:38130 [200]: GET /api/chart.php?range=year +[Fri Jul 31 08:46:31 2026] 127.0.0.1:38130 Closing +[Fri Jul 31 08:47:31 2026] 127.0.0.1:50204 Accepted +[Fri Jul 31 08:47:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 08:47:31 2026] 127.0.0.1:50204 [200]: GET /api/stats.php +[Fri Jul 31 08:47:31 2026] 127.0.0.1:50204 Closing +[Fri Jul 31 08:47:31 2026] 127.0.0.1:50210 Accepted +[Fri Jul 31 08:47:31 2026] 127.0.0.1:50210 [200]: GET /api/chart.php?range=year +[Fri Jul 31 08:47:31 2026] 127.0.0.1:50210 Closing +[Fri Jul 31 08:48:31 2026] 127.0.0.1:33522 Accepted +[Fri Jul 31 08:48:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 08:48:31 2026] 127.0.0.1:33522 [200]: GET /api/stats.php +[Fri Jul 31 08:48:31 2026] 127.0.0.1:33522 Closing +[Fri Jul 31 08:48:31 2026] 127.0.0.1:33538 Accepted +[Fri Jul 31 08:48:31 2026] 127.0.0.1:33538 [200]: GET /api/chart.php?range=year +[Fri Jul 31 08:48:31 2026] 127.0.0.1:33538 Closing +[Fri Jul 31 08:49:31 2026] 127.0.0.1:55328 Accepted +[Fri Jul 31 08:49:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 08:49:31 2026] 127.0.0.1:55328 [200]: GET /api/stats.php +[Fri Jul 31 08:49:31 2026] 127.0.0.1:55328 Closing +[Fri Jul 31 08:49:31 2026] 127.0.0.1:55334 Accepted +[Fri Jul 31 08:49:31 2026] 127.0.0.1:55334 [200]: GET /api/chart.php?range=year +[Fri Jul 31 08:49:31 2026] 127.0.0.1:55334 Closing +[Fri Jul 31 08:50:31 2026] 127.0.0.1:34442 Accepted +[Fri Jul 31 08:50:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 08:50:31 2026] 127.0.0.1:34442 [200]: GET /api/stats.php +[Fri Jul 31 08:50:31 2026] 127.0.0.1:34442 Closing +[Fri Jul 31 08:50:31 2026] 127.0.0.1:34452 Accepted +[Fri Jul 31 08:50:31 2026] 127.0.0.1:34452 [200]: GET /api/chart.php?range=year +[Fri Jul 31 08:50:31 2026] 127.0.0.1:34452 Closing +[Fri Jul 31 08:51:31 2026] 127.0.0.1:59908 Accepted +[Fri Jul 31 08:51:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 08:51:31 2026] 127.0.0.1:59908 [200]: GET /api/stats.php +[Fri Jul 31 08:51:31 2026] 127.0.0.1:59908 Closing +[Fri Jul 31 08:51:31 2026] 127.0.0.1:59920 Accepted +[Fri Jul 31 08:51:31 2026] 127.0.0.1:59920 [200]: GET /api/chart.php?range=year +[Fri Jul 31 08:51:31 2026] 127.0.0.1:59920 Closing +[Fri Jul 31 08:52:31 2026] 127.0.0.1:48262 Accepted +[Fri Jul 31 08:52:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 08:52:31 2026] 127.0.0.1:48262 [200]: GET /api/stats.php +[Fri Jul 31 08:52:31 2026] 127.0.0.1:48262 Closing +[Fri Jul 31 08:52:31 2026] 127.0.0.1:48276 Accepted +[Fri Jul 31 08:52:31 2026] 127.0.0.1:48276 [200]: GET /api/chart.php?range=year +[Fri Jul 31 08:52:31 2026] 127.0.0.1:48276 Closing +[Fri Jul 31 08:53:31 2026] 127.0.0.1:48868 Accepted +[Fri Jul 31 08:53:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 08:53:31 2026] 127.0.0.1:48868 [200]: GET /api/stats.php +[Fri Jul 31 08:53:31 2026] 127.0.0.1:48868 Closing +[Fri Jul 31 08:53:31 2026] 127.0.0.1:48876 Accepted +[Fri Jul 31 08:53:31 2026] 127.0.0.1:48876 [200]: GET /api/chart.php?range=year +[Fri Jul 31 08:53:31 2026] 127.0.0.1:48876 Closing +[Fri Jul 31 08:54:31 2026] 127.0.0.1:44830 Accepted +[Fri Jul 31 08:54:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 08:54:31 2026] 127.0.0.1:44830 [200]: GET /api/stats.php +[Fri Jul 31 08:54:31 2026] 127.0.0.1:44830 Closing +[Fri Jul 31 08:54:31 2026] 127.0.0.1:44836 Accepted +[Fri Jul 31 08:54:31 2026] 127.0.0.1:44836 [200]: GET /api/chart.php?range=year +[Fri Jul 31 08:54:31 2026] 127.0.0.1:44836 Closing +[Fri Jul 31 08:55:31 2026] 127.0.0.1:34194 Accepted +[Fri Jul 31 08:55:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 08:55:31 2026] 127.0.0.1:34194 [200]: GET /api/stats.php +[Fri Jul 31 08:55:31 2026] 127.0.0.1:34194 Closing +[Fri Jul 31 08:55:31 2026] 127.0.0.1:34202 Accepted +[Fri Jul 31 08:55:31 2026] 127.0.0.1:34202 [200]: GET /api/chart.php?range=year +[Fri Jul 31 08:55:31 2026] 127.0.0.1:34202 Closing +[Fri Jul 31 08:56:31 2026] 127.0.0.1:59566 Accepted +[Fri Jul 31 08:56:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 08:56:31 2026] 127.0.0.1:59566 [200]: GET /api/stats.php +[Fri Jul 31 08:56:31 2026] 127.0.0.1:59566 Closing +[Fri Jul 31 08:56:31 2026] 127.0.0.1:59570 Accepted +[Fri Jul 31 08:56:31 2026] 127.0.0.1:59570 [200]: GET /api/chart.php?range=year +[Fri Jul 31 08:56:31 2026] 127.0.0.1:59570 Closing +[Fri Jul 31 08:57:31 2026] 127.0.0.1:47384 Accepted +[Fri Jul 31 08:57:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 08:57:31 2026] 127.0.0.1:47384 [200]: GET /api/stats.php +[Fri Jul 31 08:57:31 2026] 127.0.0.1:47384 Closing +[Fri Jul 31 08:57:31 2026] 127.0.0.1:47398 Accepted +[Fri Jul 31 08:57:31 2026] 127.0.0.1:47398 [200]: GET /api/chart.php?range=year +[Fri Jul 31 08:57:31 2026] 127.0.0.1:47398 Closing +[Fri Jul 31 08:58:31 2026] 127.0.0.1:41058 Accepted +[Fri Jul 31 08:58:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 08:58:31 2026] 127.0.0.1:41058 [200]: GET /api/stats.php +[Fri Jul 31 08:58:31 2026] 127.0.0.1:41058 Closing +[Fri Jul 31 08:58:31 2026] 127.0.0.1:41072 Accepted +[Fri Jul 31 08:58:31 2026] 127.0.0.1:41072 [200]: GET /api/chart.php?range=year +[Fri Jul 31 08:58:31 2026] 127.0.0.1:41072 Closing +[Fri Jul 31 08:59:31 2026] 127.0.0.1:43990 Accepted +[Fri Jul 31 08:59:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 08:59:31 2026] 127.0.0.1:43990 [200]: GET /api/stats.php +[Fri Jul 31 08:59:31 2026] 127.0.0.1:43990 Closing +[Fri Jul 31 08:59:31 2026] 127.0.0.1:43994 Accepted +[Fri Jul 31 08:59:31 2026] 127.0.0.1:43994 [200]: GET /api/chart.php?range=year +[Fri Jul 31 08:59:31 2026] 127.0.0.1:43994 Closing +[Fri Jul 31 09:00:31 2026] 127.0.0.1:36628 Accepted +[Fri Jul 31 09:00:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 09:00:31 2026] 127.0.0.1:36628 [200]: GET /api/stats.php +[Fri Jul 31 09:00:31 2026] 127.0.0.1:36628 Closing +[Fri Jul 31 09:00:31 2026] 127.0.0.1:36640 Accepted +[Fri Jul 31 09:00:31 2026] 127.0.0.1:36640 [200]: GET /api/chart.php?range=year +[Fri Jul 31 09:00:31 2026] 127.0.0.1:36640 Closing +[Fri Jul 31 09:01:31 2026] 127.0.0.1:44818 Accepted +[Fri Jul 31 09:01:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 09:01:31 2026] 127.0.0.1:44818 [200]: GET /api/stats.php +[Fri Jul 31 09:01:31 2026] 127.0.0.1:44818 Closing +[Fri Jul 31 09:01:31 2026] 127.0.0.1:44834 Accepted +[Fri Jul 31 09:01:31 2026] 127.0.0.1:44834 [200]: GET /api/chart.php?range=year +[Fri Jul 31 09:01:31 2026] 127.0.0.1:44834 Closing +[Fri Jul 31 09:02:31 2026] 127.0.0.1:33138 Accepted +[Fri Jul 31 09:02:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 09:02:31 2026] 127.0.0.1:33138 [200]: GET /api/stats.php +[Fri Jul 31 09:02:31 2026] 127.0.0.1:33138 Closing +[Fri Jul 31 09:02:31 2026] 127.0.0.1:33154 Accepted +[Fri Jul 31 09:02:31 2026] 127.0.0.1:33154 [200]: GET /api/chart.php?range=year +[Fri Jul 31 09:02:31 2026] 127.0.0.1:33154 Closing +[Fri Jul 31 09:03:31 2026] 127.0.0.1:42756 Accepted +[Fri Jul 31 09:03:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 09:03:31 2026] 127.0.0.1:42756 [200]: GET /api/stats.php +[Fri Jul 31 09:03:31 2026] 127.0.0.1:42756 Closing +[Fri Jul 31 09:03:31 2026] 127.0.0.1:42770 Accepted +[Fri Jul 31 09:03:31 2026] 127.0.0.1:42770 [200]: GET /api/chart.php?range=year +[Fri Jul 31 09:03:31 2026] 127.0.0.1:42770 Closing +[Fri Jul 31 09:04:31 2026] 127.0.0.1:43708 Accepted +[Fri Jul 31 09:04:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 09:04:31 2026] 127.0.0.1:43708 [200]: GET /api/stats.php +[Fri Jul 31 09:04:31 2026] 127.0.0.1:43708 Closing +[Fri Jul 31 09:04:31 2026] 127.0.0.1:43722 Accepted +[Fri Jul 31 09:04:31 2026] 127.0.0.1:43722 [200]: GET /api/chart.php?range=year +[Fri Jul 31 09:04:31 2026] 127.0.0.1:43722 Closing +[Fri Jul 31 09:05:31 2026] 127.0.0.1:51754 Accepted +[Fri Jul 31 09:05:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 09:05:31 2026] 127.0.0.1:51754 [200]: GET /api/stats.php +[Fri Jul 31 09:05:31 2026] 127.0.0.1:51754 Closing +[Fri Jul 31 09:05:31 2026] 127.0.0.1:51764 Accepted +[Fri Jul 31 09:05:31 2026] 127.0.0.1:51764 [200]: GET /api/chart.php?range=year +[Fri Jul 31 09:05:31 2026] 127.0.0.1:51764 Closing +[Fri Jul 31 09:06:31 2026] 127.0.0.1:34482 Accepted +[Fri Jul 31 09:06:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 09:06:31 2026] 127.0.0.1:34482 [200]: GET /api/stats.php +[Fri Jul 31 09:06:31 2026] 127.0.0.1:34482 Closing +[Fri Jul 31 09:06:31 2026] 127.0.0.1:34494 Accepted +[Fri Jul 31 09:06:31 2026] 127.0.0.1:34494 [200]: GET /api/chart.php?range=year +[Fri Jul 31 09:06:31 2026] 127.0.0.1:34494 Closing +[Fri Jul 31 09:07:31 2026] 127.0.0.1:33288 Accepted +[Fri Jul 31 09:07:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 09:07:31 2026] 127.0.0.1:33288 [200]: GET /api/stats.php +[Fri Jul 31 09:07:31 2026] 127.0.0.1:33288 Closing +[Fri Jul 31 09:07:31 2026] 127.0.0.1:33300 Accepted +[Fri Jul 31 09:07:31 2026] 127.0.0.1:33300 [200]: GET /api/chart.php?range=year +[Fri Jul 31 09:07:31 2026] 127.0.0.1:33300 Closing +[Fri Jul 31 09:08:31 2026] 127.0.0.1:42550 Accepted +[Fri Jul 31 09:08:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 09:08:31 2026] 127.0.0.1:42550 [200]: GET /api/stats.php +[Fri Jul 31 09:08:31 2026] 127.0.0.1:42550 Closing +[Fri Jul 31 09:08:31 2026] 127.0.0.1:42554 Accepted +[Fri Jul 31 09:08:31 2026] 127.0.0.1:42554 [200]: GET /api/chart.php?range=year +[Fri Jul 31 09:08:31 2026] 127.0.0.1:42554 Closing +[Fri Jul 31 09:09:31 2026] 127.0.0.1:48012 Accepted +[Fri Jul 31 09:09:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 09:09:31 2026] 127.0.0.1:48012 [200]: GET /api/stats.php +[Fri Jul 31 09:09:31 2026] 127.0.0.1:48012 Closing +[Fri Jul 31 09:09:31 2026] 127.0.0.1:48028 Accepted +[Fri Jul 31 09:09:31 2026] 127.0.0.1:48028 [200]: GET /api/chart.php?range=year +[Fri Jul 31 09:09:31 2026] 127.0.0.1:48028 Closing +[Fri Jul 31 09:10:31 2026] 127.0.0.1:60854 Accepted +[Fri Jul 31 09:10:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 09:10:31 2026] 127.0.0.1:60854 [200]: GET /api/stats.php +[Fri Jul 31 09:10:31 2026] 127.0.0.1:60854 Closing +[Fri Jul 31 09:10:31 2026] 127.0.0.1:60860 Accepted +[Fri Jul 31 09:10:31 2026] 127.0.0.1:60860 [200]: GET /api/chart.php?range=year +[Fri Jul 31 09:10:31 2026] 127.0.0.1:60860 Closing +[Fri Jul 31 09:11:31 2026] 127.0.0.1:58988 Accepted +[Fri Jul 31 09:11:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 09:11:31 2026] 127.0.0.1:58988 [200]: GET /api/stats.php +[Fri Jul 31 09:11:31 2026] 127.0.0.1:58988 Closing +[Fri Jul 31 09:11:31 2026] 127.0.0.1:58992 Accepted +[Fri Jul 31 09:11:31 2026] 127.0.0.1:58992 [200]: GET /api/chart.php?range=year +[Fri Jul 31 09:11:31 2026] 127.0.0.1:58992 Closing +[Fri Jul 31 09:12:31 2026] 127.0.0.1:48662 Accepted +[Fri Jul 31 09:12:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 09:12:31 2026] 127.0.0.1:48662 [200]: GET /api/stats.php +[Fri Jul 31 09:12:31 2026] 127.0.0.1:48662 Closing +[Fri Jul 31 09:12:31 2026] 127.0.0.1:48668 Accepted +[Fri Jul 31 09:12:31 2026] 127.0.0.1:48668 [200]: GET /api/chart.php?range=year +[Fri Jul 31 09:12:31 2026] 127.0.0.1:48668 Closing +[Fri Jul 31 09:13:31 2026] 127.0.0.1:53058 Accepted +[Fri Jul 31 09:13:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 09:13:31 2026] 127.0.0.1:53058 [200]: GET /api/stats.php +[Fri Jul 31 09:13:31 2026] 127.0.0.1:53058 Closing +[Fri Jul 31 09:13:31 2026] 127.0.0.1:53070 Accepted +[Fri Jul 31 09:13:31 2026] 127.0.0.1:53070 [200]: GET /api/chart.php?range=year +[Fri Jul 31 09:13:31 2026] 127.0.0.1:53070 Closing +[Fri Jul 31 09:14:31 2026] 127.0.0.1:49906 Accepted +[Fri Jul 31 09:14:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 09:14:31 2026] 127.0.0.1:49906 [200]: GET /api/stats.php +[Fri Jul 31 09:14:31 2026] 127.0.0.1:49906 Closing +[Fri Jul 31 09:14:31 2026] 127.0.0.1:49922 Accepted +[Fri Jul 31 09:14:31 2026] 127.0.0.1:49922 [200]: GET /api/chart.php?range=year +[Fri Jul 31 09:14:31 2026] 127.0.0.1:49922 Closing +[Fri Jul 31 09:15:31 2026] 127.0.0.1:60850 Accepted +[Fri Jul 31 09:15:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 09:15:31 2026] 127.0.0.1:60850 [200]: GET /api/stats.php +[Fri Jul 31 09:15:31 2026] 127.0.0.1:60850 Closing +[Fri Jul 31 09:15:31 2026] 127.0.0.1:60866 Accepted +[Fri Jul 31 09:15:31 2026] 127.0.0.1:60866 [200]: GET /api/chart.php?range=year +[Fri Jul 31 09:15:31 2026] 127.0.0.1:60866 Closing +[Fri Jul 31 09:16:31 2026] 127.0.0.1:54182 Accepted +[Fri Jul 31 09:16:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 09:16:31 2026] 127.0.0.1:54182 [200]: GET /api/stats.php +[Fri Jul 31 09:16:31 2026] 127.0.0.1:54182 Closing +[Fri Jul 31 09:16:31 2026] 127.0.0.1:54186 Accepted +[Fri Jul 31 09:16:31 2026] 127.0.0.1:54186 [200]: GET /api/chart.php?range=year +[Fri Jul 31 09:16:31 2026] 127.0.0.1:54186 Closing +[Fri Jul 31 09:17:31 2026] 127.0.0.1:56804 Accepted +[Fri Jul 31 09:17:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 09:17:31 2026] 127.0.0.1:56804 [200]: GET /api/stats.php +[Fri Jul 31 09:17:31 2026] 127.0.0.1:56804 Closing +[Fri Jul 31 09:17:31 2026] 127.0.0.1:56812 Accepted +[Fri Jul 31 09:17:31 2026] 127.0.0.1:56812 [200]: GET /api/chart.php?range=year +[Fri Jul 31 09:17:31 2026] 127.0.0.1:56812 Closing +[Fri Jul 31 09:18:31 2026] 127.0.0.1:60524 Accepted +[Fri Jul 31 09:18:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 09:18:31 2026] 127.0.0.1:60524 [200]: GET /api/stats.php +[Fri Jul 31 09:18:31 2026] 127.0.0.1:60524 Closing +[Fri Jul 31 09:18:31 2026] 127.0.0.1:60532 Accepted +[Fri Jul 31 09:18:31 2026] 127.0.0.1:60532 [200]: GET /api/chart.php?range=year +[Fri Jul 31 09:18:31 2026] 127.0.0.1:60532 Closing +[Fri Jul 31 09:19:31 2026] 127.0.0.1:34944 Accepted +[Fri Jul 31 09:19:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 09:19:31 2026] 127.0.0.1:34944 [200]: GET /api/stats.php +[Fri Jul 31 09:19:31 2026] 127.0.0.1:34944 Closing +[Fri Jul 31 09:19:31 2026] 127.0.0.1:34954 Accepted +[Fri Jul 31 09:19:31 2026] 127.0.0.1:34954 [200]: GET /api/chart.php?range=year +[Fri Jul 31 09:19:31 2026] 127.0.0.1:34954 Closing +[Fri Jul 31 09:20:31 2026] 127.0.0.1:57292 Accepted +[Fri Jul 31 09:20:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 09:20:31 2026] 127.0.0.1:57292 [200]: GET /api/stats.php +[Fri Jul 31 09:20:31 2026] 127.0.0.1:57292 Closing +[Fri Jul 31 09:20:31 2026] 127.0.0.1:57308 Accepted +[Fri Jul 31 09:20:31 2026] 127.0.0.1:57308 [200]: GET /api/chart.php?range=year +[Fri Jul 31 09:20:31 2026] 127.0.0.1:57308 Closing +[Fri Jul 31 09:21:31 2026] 127.0.0.1:53084 Accepted +[Fri Jul 31 09:21:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 09:21:31 2026] 127.0.0.1:53084 [200]: GET /api/stats.php +[Fri Jul 31 09:21:31 2026] 127.0.0.1:53084 Closing +[Fri Jul 31 09:21:31 2026] 127.0.0.1:53092 Accepted +[Fri Jul 31 09:21:31 2026] 127.0.0.1:53092 [200]: GET /api/chart.php?range=year +[Fri Jul 31 09:21:31 2026] 127.0.0.1:53092 Closing +[Fri Jul 31 09:22:31 2026] 127.0.0.1:50270 Accepted +[Fri Jul 31 09:22:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 09:22:31 2026] 127.0.0.1:50270 [200]: GET /api/stats.php +[Fri Jul 31 09:22:31 2026] 127.0.0.1:50270 Closing +[Fri Jul 31 09:22:31 2026] 127.0.0.1:50278 Accepted +[Fri Jul 31 09:22:31 2026] 127.0.0.1:50278 [200]: GET /api/chart.php?range=year +[Fri Jul 31 09:22:31 2026] 127.0.0.1:50278 Closing +[Fri Jul 31 09:23:31 2026] 127.0.0.1:50570 Accepted +[Fri Jul 31 09:23:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 09:23:31 2026] 127.0.0.1:50570 [200]: GET /api/stats.php +[Fri Jul 31 09:23:31 2026] 127.0.0.1:50570 Closing +[Fri Jul 31 09:23:31 2026] 127.0.0.1:50582 Accepted +[Fri Jul 31 09:23:31 2026] 127.0.0.1:50582 [200]: GET /api/chart.php?range=year +[Fri Jul 31 09:23:31 2026] 127.0.0.1:50582 Closing +[Fri Jul 31 09:24:31 2026] 127.0.0.1:37494 Accepted +[Fri Jul 31 09:24:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 09:24:31 2026] 127.0.0.1:37494 [200]: GET /api/stats.php +[Fri Jul 31 09:24:31 2026] 127.0.0.1:37494 Closing +[Fri Jul 31 09:24:31 2026] 127.0.0.1:37510 Accepted +[Fri Jul 31 09:24:31 2026] 127.0.0.1:37510 [200]: GET /api/chart.php?range=year +[Fri Jul 31 09:24:31 2026] 127.0.0.1:37510 Closing +[Fri Jul 31 09:25:31 2026] 127.0.0.1:36746 Accepted +[Fri Jul 31 09:25:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 09:25:31 2026] 127.0.0.1:36746 [200]: GET /api/stats.php +[Fri Jul 31 09:25:31 2026] 127.0.0.1:36746 Closing +[Fri Jul 31 09:25:31 2026] 127.0.0.1:36758 Accepted +[Fri Jul 31 09:25:31 2026] 127.0.0.1:36758 [200]: GET /api/chart.php?range=year +[Fri Jul 31 09:25:31 2026] 127.0.0.1:36758 Closing +[Fri Jul 31 09:26:31 2026] 127.0.0.1:40998 Accepted +[Fri Jul 31 09:26:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 09:26:31 2026] 127.0.0.1:40998 [200]: GET /api/stats.php +[Fri Jul 31 09:26:31 2026] 127.0.0.1:40998 Closing +[Fri Jul 31 09:26:31 2026] 127.0.0.1:41010 Accepted +[Fri Jul 31 09:26:31 2026] 127.0.0.1:41010 [200]: GET /api/chart.php?range=year +[Fri Jul 31 09:26:31 2026] 127.0.0.1:41010 Closing +[Fri Jul 31 09:27:31 2026] 127.0.0.1:56788 Accepted +[Fri Jul 31 09:27:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 09:27:31 2026] 127.0.0.1:56788 [200]: GET /api/stats.php +[Fri Jul 31 09:27:31 2026] 127.0.0.1:56788 Closing +[Fri Jul 31 09:27:31 2026] 127.0.0.1:56800 Accepted +[Fri Jul 31 09:27:31 2026] 127.0.0.1:56800 [200]: GET /api/chart.php?range=year +[Fri Jul 31 09:27:31 2026] 127.0.0.1:56800 Closing +[Fri Jul 31 09:28:31 2026] 127.0.0.1:45876 Accepted +[Fri Jul 31 09:28:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 09:28:31 2026] 127.0.0.1:45876 [200]: GET /api/stats.php +[Fri Jul 31 09:28:31 2026] 127.0.0.1:45876 Closing +[Fri Jul 31 09:28:31 2026] 127.0.0.1:45880 Accepted +[Fri Jul 31 09:28:31 2026] 127.0.0.1:45880 [200]: GET /api/chart.php?range=year +[Fri Jul 31 09:28:31 2026] 127.0.0.1:45880 Closing +[Fri Jul 31 09:29:31 2026] 127.0.0.1:34066 Accepted +[Fri Jul 31 09:29:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 09:29:31 2026] 127.0.0.1:34066 [200]: GET /api/stats.php +[Fri Jul 31 09:29:31 2026] 127.0.0.1:34066 Closing +[Fri Jul 31 09:29:31 2026] 127.0.0.1:34070 Accepted +[Fri Jul 31 09:29:31 2026] 127.0.0.1:34070 [200]: GET /api/chart.php?range=year +[Fri Jul 31 09:29:31 2026] 127.0.0.1:34070 Closing +[Fri Jul 31 09:30:31 2026] 127.0.0.1:38216 Accepted +[Fri Jul 31 09:30:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 09:30:31 2026] 127.0.0.1:38216 [200]: GET /api/stats.php +[Fri Jul 31 09:30:31 2026] 127.0.0.1:38216 Closing +[Fri Jul 31 09:30:31 2026] 127.0.0.1:38222 Accepted +[Fri Jul 31 09:30:31 2026] 127.0.0.1:38222 [200]: GET /api/chart.php?range=year +[Fri Jul 31 09:30:31 2026] 127.0.0.1:38222 Closing +[Fri Jul 31 09:31:31 2026] 127.0.0.1:46234 Accepted +[Fri Jul 31 09:31:31 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 09:31:31 2026] 127.0.0.1:46234 [200]: GET /api/stats.php +[Fri Jul 31 09:31:31 2026] 127.0.0.1:46234 Closing +[Fri Jul 31 09:31:31 2026] 127.0.0.1:46250 Accepted +[Fri Jul 31 09:31:31 2026] 127.0.0.1:46250 [200]: GET /api/chart.php?range=year +[Fri Jul 31 09:31:31 2026] 127.0.0.1:46250 Closing +[Fri Jul 31 09:31:45 2026] 127.0.0.1:55392 Accepted +[Fri Jul 31 09:31:45 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 09:31:45 2026] 127.0.0.1:55392 [200]: GET /api/stats.php +[Fri Jul 31 09:31:45 2026] 127.0.0.1:55392 Closing +[Fri Jul 31 09:31:45 2026] 127.0.0.1:55400 Accepted +[Fri Jul 31 09:31:45 2026] 127.0.0.1:55400 [200]: GET /api/chart.php?range=year +[Fri Jul 31 09:31:45 2026] 127.0.0.1:55400 Closing +[Fri Jul 31 09:31:50 2026] 127.0.0.1:55414 Accepted +[Fri Jul 31 09:31:50 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 09:31:50 2026] 127.0.0.1:55414 [200]: GET /api/stats.php +[Fri Jul 31 09:31:50 2026] 127.0.0.1:55414 Closing +[Fri Jul 31 09:31:50 2026] 127.0.0.1:55420 Accepted +[Fri Jul 31 09:31:50 2026] 127.0.0.1:55420 [200]: GET /api/chart.php?range=year +[Fri Jul 31 09:31:50 2026] 127.0.0.1:55420 Closing +[Fri Jul 31 09:31:58 2026] 127.0.0.1:43562 Accepted +[Fri Jul 31 09:31:58 2026] 127.0.0.1:43562 [200]: GET / +[Fri Jul 31 09:31:58 2026] 127.0.0.1:43562 Closing +[Fri Jul 31 09:31:58 2026] 127.0.0.1:43570 Accepted +[Fri Jul 31 09:31:58 2026] 127.0.0.1:43570 [200]: GET /assets/index.css +[Fri Jul 31 09:31:58 2026] 127.0.0.1:43570 Closing +[Fri Jul 31 09:31:58 2026] 127.0.0.1:43582 Accepted +[Fri Jul 31 09:31:58 2026] 127.0.0.1:43582 [200]: GET /assets/nostr.bundle.js +[Fri Jul 31 09:31:58 2026] 127.0.0.1:43590 Accepted +[Fri Jul 31 09:31:58 2026] 127.0.0.1:43594 Accepted +[Fri Jul 31 09:31:58 2026] 127.0.0.1:43582 Closing +[Fri Jul 31 09:31:58 2026] 127.0.0.1:43590 [200]: GET /assets/nostr-lite.js +[Fri Jul 31 09:31:58 2026] 127.0.0.1:43594 [200]: GET /assets/app.js +[Fri Jul 31 09:31:58 2026] 127.0.0.1:43590 Closing +[Fri Jul 31 09:31:58 2026] 127.0.0.1:43594 Closing +[Fri Jul 31 09:31:58 2026] 127.0.0.1:43602 Accepted +[Fri Jul 31 09:31:58 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 09:31:58 2026] 127.0.0.1:43602 [200]: GET /api/stats.php +[Fri Jul 31 09:31:58 2026] 127.0.0.1:43602 Closing +[Fri Jul 31 09:31:58 2026] 127.0.0.1:43618 Accepted +[Fri Jul 31 09:31:58 2026] 127.0.0.1:43632 Accepted +[Fri Jul 31 09:31:58 2026] 127.0.0.1:43618 [200]: GET /api/chart.php?range=hour +[Fri Jul 31 09:31:58 2026] 127.0.0.1:43618 Closing +[Fri Jul 31 09:31:58 2026] 127.0.0.1:43636 Accepted +[Fri Jul 31 09:31:58 2026] 127.0.0.1:43632 [200]: GET /favicon.ico +[Fri Jul 31 09:31:58 2026] 127.0.0.1:43632 Closing +[Fri Jul 31 09:31:58 2026] 127.0.0.1:43644 Accepted +[Fri Jul 31 09:31:58 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 09:31:58 2026] 127.0.0.1:43636 [200]: GET /api/stats.php +[Fri Jul 31 09:31:58 2026] 127.0.0.1:43636 Closing +[Fri Jul 31 09:31:58 2026] 127.0.0.1:43644 [200]: GET /api/chart.php?range=hour +[Fri Jul 31 09:31:58 2026] 127.0.0.1:43644 Closing +[Fri Jul 31 09:31:58 2026] 127.0.0.1:43652 Accepted +[Fri Jul 31 09:31:58 2026] 127.0.0.1:43652 [200]: GET /api/chart.php?range=hour +[Fri Jul 31 09:31:58 2026] 127.0.0.1:43652 Closing +[Fri Jul 31 09:32:00 2026] 127.0.0.1:43656 Accepted +[Fri Jul 31 09:32:00 2026] 127.0.0.1:43656 [200]: GET /api/profile.php?pubkey=8ff74724ed641b3c28e5a86d7c5cbc49c37638ace8c6c38935860e7a5eedde0e +[Fri Jul 31 09:32:00 2026] 127.0.0.1:43656 Closing +[Fri Jul 31 09:32:03 2026] 127.0.0.1:43658 Accepted +[Fri Jul 31 09:32:03 2026] 127.0.0.1:43658 [200]: GET /api/chart.php?range=day +[Fri Jul 31 09:32:03 2026] 127.0.0.1:43658 Closing +[Fri Jul 31 09:32:05 2026] 127.0.0.1:49930 Accepted +[Fri Jul 31 09:32:05 2026] 127.0.0.1:49930 [200]: GET /api/chart.php?range=month +[Fri Jul 31 09:32:05 2026] 127.0.0.1:49930 Closing +[Fri Jul 31 09:32:06 2026] 127.0.0.1:49934 Accepted +[Fri Jul 31 09:32:06 2026] 127.0.0.1:49934 [200]: GET /api/chart.php?range=year +[Fri Jul 31 09:32:06 2026] 127.0.0.1:49934 Closing +[Fri Jul 31 09:32:07 2026] 127.0.0.1:49948 Accepted +[Fri Jul 31 09:32:07 2026] 127.0.0.1:49948 [200]: GET /api/chart.php?range=hour +[Fri Jul 31 09:32:07 2026] 127.0.0.1:49948 Closing +[Fri Jul 31 09:32:08 2026] 127.0.0.1:49962 Accepted +[Fri Jul 31 09:32:08 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 09:32:08 2026] 127.0.0.1:49962 [200]: GET /api/stats.php +[Fri Jul 31 09:32:08 2026] 127.0.0.1:49962 Closing +[Fri Jul 31 09:32:08 2026] 127.0.0.1:49970 Accepted +[Fri Jul 31 09:32:08 2026] 127.0.0.1:49970 [200]: GET /api/chart.php?range=hour +[Fri Jul 31 09:32:08 2026] 127.0.0.1:49970 Closing +[Fri Jul 31 09:32:18 2026] 127.0.0.1:53498 Accepted +[Fri Jul 31 09:32:18 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 09:32:18 2026] 127.0.0.1:53498 [200]: GET /api/stats.php +[Fri Jul 31 09:32:18 2026] 127.0.0.1:53498 Closing +[Fri Jul 31 09:32:18 2026] 127.0.0.1:53504 Accepted +[Fri Jul 31 09:32:18 2026] 127.0.0.1:53504 [200]: GET /api/chart.php?range=hour +[Fri Jul 31 09:32:18 2026] 127.0.0.1:53504 Closing +[Fri Jul 31 09:32:28 2026] 127.0.0.1:32998 Accepted +[Fri Jul 31 09:32:28 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 09:32:28 2026] 127.0.0.1:32998 [200]: GET /api/stats.php +[Fri Jul 31 09:32:28 2026] 127.0.0.1:32998 Closing +[Fri Jul 31 09:32:28 2026] 127.0.0.1:33008 Accepted +[Fri Jul 31 09:32:28 2026] 127.0.0.1:33008 [200]: GET /api/chart.php?range=hour +[Fri Jul 31 09:32:28 2026] 127.0.0.1:33008 Closing +[Fri Jul 31 09:32:38 2026] 127.0.0.1:37244 Accepted +[Fri Jul 31 09:32:38 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 09:32:38 2026] 127.0.0.1:37244 [200]: GET /api/stats.php +[Fri Jul 31 09:32:38 2026] 127.0.0.1:37244 Closing +[Fri Jul 31 09:32:38 2026] 127.0.0.1:37258 Accepted +[Fri Jul 31 09:32:38 2026] 127.0.0.1:37258 [200]: GET /api/chart.php?range=hour +[Fri Jul 31 09:32:38 2026] 127.0.0.1:37258 Closing +[Fri Jul 31 09:32:48 2026] 127.0.0.1:52138 Accepted +[Fri Jul 31 09:32:48 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 09:32:48 2026] 127.0.0.1:52138 [200]: GET /api/stats.php +[Fri Jul 31 09:32:48 2026] 127.0.0.1:52138 Closing +[Fri Jul 31 09:32:48 2026] 127.0.0.1:52152 Accepted +[Fri Jul 31 09:32:48 2026] 127.0.0.1:52152 [200]: GET /api/chart.php?range=hour +[Fri Jul 31 09:32:48 2026] 127.0.0.1:52152 Closing +[Fri Jul 31 09:32:58 2026] 127.0.0.1:57398 Accepted +[Fri Jul 31 09:32:58 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 09:32:58 2026] 127.0.0.1:57398 [200]: GET /api/stats.php +[Fri Jul 31 09:32:58 2026] 127.0.0.1:57398 Closing +[Fri Jul 31 09:32:58 2026] 127.0.0.1:57406 Accepted +[Fri Jul 31 09:32:58 2026] 127.0.0.1:57406 [200]: GET /api/chart.php?range=hour +[Fri Jul 31 09:32:58 2026] 127.0.0.1:57406 Closing +[Fri Jul 31 09:33:08 2026] 127.0.0.1:36900 Accepted +[Fri Jul 31 09:33:08 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 09:33:08 2026] 127.0.0.1:36900 [200]: GET /api/stats.php +[Fri Jul 31 09:33:08 2026] 127.0.0.1:36900 Closing +[Fri Jul 31 09:33:08 2026] 127.0.0.1:36910 Accepted +[Fri Jul 31 09:33:08 2026] 127.0.0.1:36910 [200]: GET /api/chart.php?range=hour +[Fri Jul 31 09:33:08 2026] 127.0.0.1:36910 Closing +[Fri Jul 31 09:33:18 2026] 127.0.0.1:59592 Accepted +[Fri Jul 31 09:33:18 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 09:33:18 2026] 127.0.0.1:59592 [200]: GET /api/stats.php +[Fri Jul 31 09:33:18 2026] 127.0.0.1:59592 Closing +[Fri Jul 31 09:33:18 2026] 127.0.0.1:59594 Accepted +[Fri Jul 31 09:33:18 2026] 127.0.0.1:59594 [200]: GET /api/chart.php?range=hour +[Fri Jul 31 09:33:18 2026] 127.0.0.1:59594 Closing +[Fri Jul 31 09:33:28 2026] 127.0.0.1:55564 Accepted +[Fri Jul 31 09:33:28 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 09:33:28 2026] 127.0.0.1:55564 [200]: GET /api/stats.php +[Fri Jul 31 09:33:28 2026] 127.0.0.1:55564 Closing +[Fri Jul 31 09:33:28 2026] 127.0.0.1:55566 Accepted +[Fri Jul 31 09:33:28 2026] 127.0.0.1:55566 [200]: GET /api/chart.php?range=hour +[Fri Jul 31 09:33:28 2026] 127.0.0.1:55566 Closing +[Fri Jul 31 09:33:38 2026] 127.0.0.1:57120 Accepted +[Fri Jul 31 09:33:38 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 09:33:38 2026] 127.0.0.1:57120 [200]: GET /api/stats.php +[Fri Jul 31 09:33:38 2026] 127.0.0.1:57120 Closing +[Fri Jul 31 09:33:38 2026] 127.0.0.1:57134 Accepted +[Fri Jul 31 09:33:38 2026] 127.0.0.1:57134 [200]: GET /api/chart.php?range=hour +[Fri Jul 31 09:33:38 2026] 127.0.0.1:57134 Closing +[Fri Jul 31 09:33:48 2026] 127.0.0.1:34610 Accepted +[Fri Jul 31 09:33:48 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 09:33:48 2026] 127.0.0.1:34610 [200]: GET /api/stats.php +[Fri Jul 31 09:33:48 2026] 127.0.0.1:34610 Closing +[Fri Jul 31 09:33:48 2026] 127.0.0.1:34618 Accepted +[Fri Jul 31 09:33:48 2026] 127.0.0.1:34618 [200]: GET /api/chart.php?range=hour +[Fri Jul 31 09:33:48 2026] 127.0.0.1:34618 Closing +[Fri Jul 31 09:33:58 2026] 127.0.0.1:40586 Accepted +[Fri Jul 31 09:33:58 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 09:33:58 2026] 127.0.0.1:40586 [200]: GET /api/stats.php +[Fri Jul 31 09:33:58 2026] 127.0.0.1:40586 Closing +[Fri Jul 31 09:33:58 2026] 127.0.0.1:40588 Accepted +[Fri Jul 31 09:33:58 2026] 127.0.0.1:40588 [200]: GET /api/chart.php?range=hour +[Fri Jul 31 09:33:58 2026] 127.0.0.1:40588 Closing +[Fri Jul 31 09:34:08 2026] 127.0.0.1:41390 Accepted +[Fri Jul 31 09:34:08 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 09:34:08 2026] 127.0.0.1:41390 [200]: GET /api/stats.php +[Fri Jul 31 09:34:08 2026] 127.0.0.1:41390 Closing +[Fri Jul 31 09:34:08 2026] 127.0.0.1:41404 Accepted +[Fri Jul 31 09:34:08 2026] 127.0.0.1:41404 [200]: GET /api/chart.php?range=hour +[Fri Jul 31 09:34:08 2026] 127.0.0.1:41404 Closing +[Fri Jul 31 09:34:18 2026] 127.0.0.1:54932 Accepted +[Fri Jul 31 09:34:18 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 09:34:18 2026] 127.0.0.1:54932 [200]: GET /api/stats.php +[Fri Jul 31 09:34:18 2026] 127.0.0.1:54932 Closing +[Fri Jul 31 09:34:18 2026] 127.0.0.1:54936 Accepted +[Fri Jul 31 09:34:18 2026] 127.0.0.1:54936 [200]: GET /api/chart.php?range=hour +[Fri Jul 31 09:34:18 2026] 127.0.0.1:54936 Closing +[Fri Jul 31 09:34:28 2026] 127.0.0.1:55842 Accepted +[Fri Jul 31 09:34:28 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 09:34:28 2026] 127.0.0.1:55842 [200]: GET /api/stats.php +[Fri Jul 31 09:34:28 2026] 127.0.0.1:55842 Closing +[Fri Jul 31 09:34:28 2026] 127.0.0.1:55856 Accepted +[Fri Jul 31 09:34:28 2026] 127.0.0.1:55856 [200]: GET /api/chart.php?range=hour +[Fri Jul 31 09:34:28 2026] 127.0.0.1:55856 Closing +[Fri Jul 31 09:34:38 2026] 127.0.0.1:36202 Accepted +[Fri Jul 31 09:34:38 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 09:34:38 2026] 127.0.0.1:36202 [200]: GET /api/stats.php +[Fri Jul 31 09:34:38 2026] 127.0.0.1:36202 Closing +[Fri Jul 31 09:34:38 2026] 127.0.0.1:36216 Accepted +[Fri Jul 31 09:34:38 2026] 127.0.0.1:36216 [200]: GET /api/chart.php?range=hour +[Fri Jul 31 09:34:38 2026] 127.0.0.1:36216 Closing +[Fri Jul 31 09:34:48 2026] 127.0.0.1:44478 Accepted +[Fri Jul 31 09:34:48 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 09:34:48 2026] 127.0.0.1:44478 [200]: GET /api/stats.php +[Fri Jul 31 09:34:48 2026] 127.0.0.1:44478 Closing +[Fri Jul 31 09:34:48 2026] 127.0.0.1:44484 Accepted +[Fri Jul 31 09:34:48 2026] 127.0.0.1:44484 [200]: GET /api/chart.php?range=hour +[Fri Jul 31 09:34:48 2026] 127.0.0.1:44484 Closing +[Fri Jul 31 09:34:58 2026] 127.0.0.1:47268 Accepted +[Fri Jul 31 09:34:58 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 09:34:58 2026] 127.0.0.1:47268 [200]: GET /api/stats.php +[Fri Jul 31 09:34:58 2026] 127.0.0.1:47268 Closing +[Fri Jul 31 09:34:58 2026] 127.0.0.1:47284 Accepted +[Fri Jul 31 09:34:58 2026] 127.0.0.1:47284 [200]: GET /api/chart.php?range=hour +[Fri Jul 31 09:34:58 2026] 127.0.0.1:47284 Closing +[Fri Jul 31 09:35:00 2026] 127.0.0.1:47298 Accepted +[Fri Jul 31 09:35:00 2026] 127.0.0.1:47298 [200]: GET / +[Fri Jul 31 09:35:00 2026] 127.0.0.1:47298 Closing +[Fri Jul 31 09:35:00 2026] 127.0.0.1:47304 Accepted +[Fri Jul 31 09:35:00 2026] 127.0.0.1:47318 Accepted +[Fri Jul 31 09:35:00 2026] 127.0.0.1:47304 [200]: GET /assets/index.css +[Fri Jul 31 09:35:00 2026] 127.0.0.1:47326 Accepted +[Fri Jul 31 09:35:00 2026] 127.0.0.1:47304 Closing +[Fri Jul 31 09:35:00 2026] 127.0.0.1:47330 Accepted +[Fri Jul 31 09:35:00 2026] 127.0.0.1:47318 [200]: GET /assets/nostr.bundle.js +[Fri Jul 31 09:35:00 2026] 127.0.0.1:47326 [200]: GET /assets/nostr-lite.js +[Fri Jul 31 09:35:00 2026] 127.0.0.1:47330 [200]: GET /assets/app.js +[Fri Jul 31 09:35:00 2026] 127.0.0.1:47330 Closing +[Fri Jul 31 09:35:00 2026] 127.0.0.1:47318 Closing +[Fri Jul 31 09:35:00 2026] 127.0.0.1:47326 Closing +[Fri Jul 31 09:35:00 2026] 127.0.0.1:47340 Accepted +[Fri Jul 31 09:35:00 2026] 127.0.0.1:47344 Accepted +[Fri Jul 31 09:35:00 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 09:35:00 2026] 127.0.0.1:47340 [200]: GET /api/stats.php +[Fri Jul 31 09:35:00 2026] 127.0.0.1:47340 Closing +[Fri Jul 31 09:35:00 2026] 127.0.0.1:47344 [200]: GET /api/chart.php?range=hour +[Fri Jul 31 09:35:00 2026] 127.0.0.1:47344 Closing +[Fri Jul 31 09:35:00 2026] 127.0.0.1:47356 Accepted +[Fri Jul 31 09:35:00 2026] 127.0.0.1:47372 Accepted +[Fri Jul 31 09:35:00 2026] 127.0.0.1:47356 [200]: GET /favicon.ico +[Fri Jul 31 09:35:00 2026] 127.0.0.1:47356 Closing +[Fri Jul 31 09:35:00 2026] 127.0.0.1:47380 Accepted +[Fri Jul 31 09:35:00 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 09:35:00 2026] 127.0.0.1:47372 [200]: GET /api/stats.php +[Fri Jul 31 09:35:00 2026] 127.0.0.1:47372 Closing +[Fri Jul 31 09:35:00 2026] 127.0.0.1:47380 [200]: GET /api/chart.php?range=hour +[Fri Jul 31 09:35:00 2026] 127.0.0.1:47380 Closing +[Fri Jul 31 09:35:00 2026] 127.0.0.1:47388 Accepted +[Fri Jul 31 09:35:00 2026] 127.0.0.1:47388 [200]: GET /api/chart.php?range=hour +[Fri Jul 31 09:35:00 2026] 127.0.0.1:47388 Closing +[Fri Jul 31 09:35:00 2026] 127.0.0.1:47396 Accepted +[Fri Jul 31 09:35:00 2026] 127.0.0.1:47396 [200]: GET /api/profile.php?pubkey=8ff74724ed641b3c28e5a86d7c5cbc49c37638ace8c6c38935860e7a5eedde0e +[Fri Jul 31 09:35:00 2026] 127.0.0.1:47396 Closing +[Fri Jul 31 09:35:10 2026] 127.0.0.1:36514 Accepted +[Fri Jul 31 09:35:10 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 09:35:10 2026] 127.0.0.1:36514 [200]: GET /api/stats.php +[Fri Jul 31 09:35:10 2026] 127.0.0.1:36514 Closing +[Fri Jul 31 09:35:10 2026] 127.0.0.1:36526 Accepted +[Fri Jul 31 09:35:10 2026] 127.0.0.1:36526 [200]: GET /api/chart.php?range=hour +[Fri Jul 31 09:35:10 2026] 127.0.0.1:36526 Closing +[Fri Jul 31 09:35:20 2026] 127.0.0.1:55696 Accepted +[Fri Jul 31 09:35:20 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 09:35:20 2026] 127.0.0.1:55696 [200]: GET /api/stats.php +[Fri Jul 31 09:35:20 2026] 127.0.0.1:55696 Closing +[Fri Jul 31 09:35:20 2026] 127.0.0.1:55708 Accepted +[Fri Jul 31 09:35:20 2026] 127.0.0.1:55708 [200]: GET /api/chart.php?range=hour +[Fri Jul 31 09:35:20 2026] 127.0.0.1:55708 Closing +[Fri Jul 31 09:35:30 2026] 127.0.0.1:44562 Accepted +[Fri Jul 31 09:35:30 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 09:35:30 2026] 127.0.0.1:44562 [200]: GET /api/stats.php +[Fri Jul 31 09:35:30 2026] 127.0.0.1:44562 Closing +[Fri Jul 31 09:35:30 2026] 127.0.0.1:44564 Accepted +[Fri Jul 31 09:35:30 2026] 127.0.0.1:44564 [200]: GET /api/chart.php?range=hour +[Fri Jul 31 09:35:30 2026] 127.0.0.1:44564 Closing +[Fri Jul 31 09:35:40 2026] 127.0.0.1:60422 Accepted +[Fri Jul 31 09:35:40 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 09:35:40 2026] 127.0.0.1:60422 [200]: GET /api/stats.php +[Fri Jul 31 09:35:40 2026] 127.0.0.1:60422 Closing +[Fri Jul 31 09:35:40 2026] 127.0.0.1:60434 Accepted +[Fri Jul 31 09:35:40 2026] 127.0.0.1:60434 [200]: GET /api/chart.php?range=hour +[Fri Jul 31 09:35:40 2026] 127.0.0.1:60434 Closing +[Fri Jul 31 09:35:50 2026] 127.0.0.1:58448 Accepted +[Fri Jul 31 09:35:50 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 09:35:50 2026] 127.0.0.1:58448 [200]: GET /api/stats.php +[Fri Jul 31 09:35:50 2026] 127.0.0.1:58448 Closing +[Fri Jul 31 09:35:50 2026] 127.0.0.1:58454 Accepted +[Fri Jul 31 09:35:50 2026] 127.0.0.1:58454 [200]: GET /api/chart.php?range=hour +[Fri Jul 31 09:35:50 2026] 127.0.0.1:58454 Closing +[Fri Jul 31 09:36:00 2026] 127.0.0.1:46774 Accepted +[Fri Jul 31 09:36:00 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 09:36:00 2026] 127.0.0.1:46774 [200]: GET /api/stats.php +[Fri Jul 31 09:36:00 2026] 127.0.0.1:46774 Closing +[Fri Jul 31 09:36:00 2026] 127.0.0.1:46778 Accepted +[Fri Jul 31 09:36:00 2026] 127.0.0.1:46778 [200]: GET /api/chart.php?range=hour +[Fri Jul 31 09:36:00 2026] 127.0.0.1:46778 Closing +[Fri Jul 31 09:36:10 2026] 127.0.0.1:40158 Accepted +[Fri Jul 31 09:36:10 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 09:36:10 2026] 127.0.0.1:40158 [200]: GET /api/stats.php +[Fri Jul 31 09:36:10 2026] 127.0.0.1:40158 Closing +[Fri Jul 31 09:36:10 2026] 127.0.0.1:40162 Accepted +[Fri Jul 31 09:36:10 2026] 127.0.0.1:40162 [200]: GET /api/chart.php?range=hour +[Fri Jul 31 09:36:10 2026] 127.0.0.1:40162 Closing +[Fri Jul 31 09:36:20 2026] 127.0.0.1:50762 Accepted +[Fri Jul 31 09:36:20 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 09:36:20 2026] 127.0.0.1:50762 [200]: GET /api/stats.php +[Fri Jul 31 09:36:20 2026] 127.0.0.1:50762 Closing +[Fri Jul 31 09:36:20 2026] 127.0.0.1:50764 Accepted +[Fri Jul 31 09:36:20 2026] 127.0.0.1:50764 [200]: GET /api/chart.php?range=hour +[Fri Jul 31 09:36:20 2026] 127.0.0.1:50764 Closing +[Fri Jul 31 09:36:30 2026] 127.0.0.1:42246 Accepted +[Fri Jul 31 09:36:30 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 09:36:30 2026] 127.0.0.1:42246 [200]: GET /api/stats.php +[Fri Jul 31 09:36:30 2026] 127.0.0.1:42246 Closing +[Fri Jul 31 09:36:30 2026] 127.0.0.1:42260 Accepted +[Fri Jul 31 09:36:30 2026] 127.0.0.1:42260 [200]: GET /api/chart.php?range=hour +[Fri Jul 31 09:36:30 2026] 127.0.0.1:42260 Closing +[Fri Jul 31 09:36:31 2026] 127.0.0.1:42266 Accepted +[Fri Jul 31 09:36:31 2026] 127.0.0.1:42266 [200]: GET /api/chart.php?range=day +[Fri Jul 31 09:36:31 2026] 127.0.0.1:42266 Closing +[Fri Jul 31 09:36:32 2026] 127.0.0.1:42270 Accepted +[Fri Jul 31 09:36:33 2026] 127.0.0.1:42270 [200]: GET /api/chart.php?range=hour +[Fri Jul 31 09:36:33 2026] 127.0.0.1:42270 Closing +[Fri Jul 31 09:36:40 2026] 127.0.0.1:46100 Accepted +[Fri Jul 31 09:36:40 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 09:36:40 2026] 127.0.0.1:46100 [200]: GET /api/stats.php +[Fri Jul 31 09:36:40 2026] 127.0.0.1:46100 Closing +[Fri Jul 31 09:36:40 2026] 127.0.0.1:46114 Accepted +[Fri Jul 31 09:36:40 2026] 127.0.0.1:46114 [200]: GET /api/chart.php?range=hour +[Fri Jul 31 09:36:40 2026] 127.0.0.1:46114 Closing +[Fri Jul 31 09:36:50 2026] 127.0.0.1:53598 Accepted +[Fri Jul 31 09:36:50 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 09:36:50 2026] 127.0.0.1:53598 [200]: GET /api/stats.php +[Fri Jul 31 09:36:50 2026] 127.0.0.1:53598 Closing +[Fri Jul 31 09:36:50 2026] 127.0.0.1:53600 Accepted +[Fri Jul 31 09:36:50 2026] 127.0.0.1:53600 [200]: GET /api/chart.php?range=hour +[Fri Jul 31 09:36:50 2026] 127.0.0.1:53600 Closing +[Fri Jul 31 09:36:57 2026] 127.0.0.1:35532 Accepted +[Fri Jul 31 09:36:57 2026] 127.0.0.1:35532 [200]: GET /api/caching.php +[Fri Jul 31 09:36:57 2026] 127.0.0.1:35532 Closing +[Fri Jul 31 09:37:05 2026] 127.0.0.1:59884 Accepted +[Fri Jul 31 09:37:05 2026] 127.0.0.1:59884 [200]: GET /api/caching.php +[Fri Jul 31 09:37:05 2026] 127.0.0.1:59884 Closing +[Fri Jul 31 09:37:05 2026] 127.0.0.1:59888 Accepted +[Fri Jul 31 09:37:05 2026] 127.0.0.1:59888 [200]: POST /api/config.php +[Fri Jul 31 09:37:05 2026] 127.0.0.1:59888 Closing +[Fri Jul 31 09:37:05 2026] 127.0.0.1:59892 Accepted +[Fri Jul 31 09:37:05 2026] 127.0.0.1:59892 [200]: GET /api/caching.php +[Fri Jul 31 09:37:05 2026] 127.0.0.1:59892 Closing +[Fri Jul 31 09:37:27 2026] 127.0.0.1:50106 Accepted +[Fri Jul 31 09:37:27 2026] 127.0.0.1:50106 [200]: GET /api/events.php?limit=50 +[Fri Jul 31 09:37:27 2026] 127.0.0.1:50106 Closing +[Fri Jul 31 09:37:34 2026] 127.0.0.1:50110 Accepted +[Fri Jul 31 09:37:34 2026] 127.0.0.1:50110 [200]: GET /api/caching.php +[Fri Jul 31 09:37:34 2026] 127.0.0.1:50110 Closing +[Fri Jul 31 09:37:43 2026] 127.0.0.1:38120 Accepted +[Fri Jul 31 09:37:43 2026] 127.0.0.1:38120 [200]: GET /api/caching.php +[Fri Jul 31 09:37:43 2026] 127.0.0.1:38120 Closing +[Fri Jul 31 09:38:32 2026] 127.0.0.1:42488 Accepted +[Fri Jul 31 09:38:32 2026] 127.0.0.1:42488 [200]: GET /api/caching.php +[Fri Jul 31 09:38:32 2026] 127.0.0.1:42488 Closing +[Fri Jul 31 09:38:40 2026] 127.0.0.1:41006 Accepted +[Fri Jul 31 09:38:40 2026] 127.0.0.1:41006 [200]: GET /assets/index.css +[Fri Jul 31 09:38:40 2026] 127.0.0.1:41006 Closing +[Fri Jul 31 09:38:40 2026] 127.0.0.1:41016 Accepted +[Fri Jul 31 09:38:40 2026] 127.0.0.1:41016 [200]: GET /.well-known/appspecific/com.chrome.devtools.json +[Fri Jul 31 09:38:40 2026] 127.0.0.1:41016 Closing +[Fri Jul 31 09:41:49 2026] 127.0.0.1:58182 Accepted +[Fri Jul 31 09:41:49 2026] 127.0.0.1:58182 [200]: GET / +[Fri Jul 31 09:41:49 2026] 127.0.0.1:58182 Closing +[Fri Jul 31 09:41:49 2026] 127.0.0.1:58194 Accepted +[Fri Jul 31 09:41:49 2026] 127.0.0.1:58208 Accepted +[Fri Jul 31 09:41:49 2026] 127.0.0.1:58194 [200]: GET /assets/index.css +[Fri Jul 31 09:41:49 2026] 127.0.0.1:58218 Accepted +[Fri Jul 31 09:41:49 2026] 127.0.0.1:58194 Closing +[Fri Jul 31 09:41:49 2026] 127.0.0.1:58228 Accepted +[Fri Jul 31 09:41:49 2026] 127.0.0.1:58208 [200]: GET /assets/nostr.bundle.js +[Fri Jul 31 09:41:49 2026] 127.0.0.1:58208 Closing +[Fri Jul 31 09:41:49 2026] 127.0.0.1:58218 [200]: GET /assets/nostr-lite.js +[Fri Jul 31 09:41:49 2026] 127.0.0.1:58218 Closing +[Fri Jul 31 09:41:49 2026] 127.0.0.1:58228 [200]: GET /assets/app.js +[Fri Jul 31 09:41:49 2026] 127.0.0.1:58228 Closing +[Fri Jul 31 09:41:49 2026] 127.0.0.1:58240 Accepted +[Fri Jul 31 09:41:49 2026] 127.0.0.1:58240 [200]: GET /.well-known/appspecific/com.chrome.devtools.json +[Fri Jul 31 09:41:49 2026] 127.0.0.1:58240 Closing +[Fri Jul 31 09:41:49 2026] 127.0.0.1:58256 Accepted +[Fri Jul 31 09:41:49 2026] 127.0.0.1:58260 Accepted +[Fri Jul 31 09:41:49 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 09:41:49 2026] 127.0.0.1:58256 [200]: GET /api/stats.php +[Fri Jul 31 09:41:49 2026] 127.0.0.1:58256 Closing +[Fri Jul 31 09:41:49 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 09:41:49 2026] 127.0.0.1:58260 [200]: GET /api/stats.php +[Fri Jul 31 09:41:49 2026] 127.0.0.1:58260 Closing +[Fri Jul 31 09:41:49 2026] 127.0.0.1:58274 Accepted +[Fri Jul 31 09:41:49 2026] 127.0.0.1:58282 Accepted +[Fri Jul 31 09:41:49 2026] 127.0.0.1:58274 [200]: GET /api/chart.php?range=hour +[Fri Jul 31 09:41:49 2026] 127.0.0.1:58274 Closing +[Fri Jul 31 09:41:49 2026] 127.0.0.1:58282 [200]: GET /favicon.ico +[Fri Jul 31 09:41:49 2026] 127.0.0.1:58282 Closing +[Fri Jul 31 09:41:49 2026] 127.0.0.1:58294 Accepted +[Fri Jul 31 09:41:49 2026] 127.0.0.1:58294 [200]: GET /api/chart.php?range=hour +[Fri Jul 31 09:41:49 2026] 127.0.0.1:58294 Closing +[Fri Jul 31 09:41:49 2026] 127.0.0.1:58302 Accepted +[Fri Jul 31 09:41:49 2026] 127.0.0.1:58302 [200]: GET /api/chart.php?range=hour +[Fri Jul 31 09:41:49 2026] 127.0.0.1:58302 Closing +[Fri Jul 31 09:41:49 2026] 127.0.0.1:58318 Accepted +[Fri Jul 31 09:41:49 2026] 127.0.0.1:58318 [200]: GET /api/profile.php?pubkey=8ff74724ed641b3c28e5a86d7c5cbc49c37638ace8c6c38935860e7a5eedde0e +[Fri Jul 31 09:41:49 2026] 127.0.0.1:58318 Closing +[Fri Jul 31 09:41:54 2026] 127.0.0.1:58330 Accepted +[Fri Jul 31 09:41:54 2026] 127.0.0.1:58330 [200]: GET /api/caching.php +[Fri Jul 31 09:41:54 2026] 127.0.0.1:58330 Closing +[Fri Jul 31 09:42:38 2026] 127.0.0.1:43738 Accepted +[Fri Jul 31 09:42:38 2026] 127.0.0.1:43738 [200]: GET / +[Fri Jul 31 09:42:38 2026] 127.0.0.1:43738 Closing +[Fri Jul 31 09:42:38 2026] 127.0.0.1:43754 Accepted +[Fri Jul 31 09:42:38 2026] 127.0.0.1:43760 Accepted +[Fri Jul 31 09:42:38 2026] 127.0.0.1:43754 [200]: GET /assets/index.css +[Fri Jul 31 09:42:38 2026] 127.0.0.1:43776 Accepted +[Fri Jul 31 09:42:38 2026] 127.0.0.1:43760 [200]: GET /assets/nostr.bundle.js +[Fri Jul 31 09:42:38 2026] 127.0.0.1:43782 Accepted +[Fri Jul 31 09:42:38 2026] 127.0.0.1:43776 [200]: GET /assets/nostr-lite.js +[Fri Jul 31 09:42:38 2026] 127.0.0.1:43754 Closing +[Fri Jul 31 09:42:38 2026] 127.0.0.1:43782 [200]: GET /assets/app.js +[Fri Jul 31 09:42:38 2026] 127.0.0.1:43760 Closing +[Fri Jul 31 09:42:38 2026] 127.0.0.1:43776 Closing +[Fri Jul 31 09:42:38 2026] 127.0.0.1:43782 Closing +[Fri Jul 31 09:42:38 2026] 127.0.0.1:43786 Accepted +[Fri Jul 31 09:42:38 2026] 127.0.0.1:43786 [200]: GET /.well-known/appspecific/com.chrome.devtools.json +[Fri Jul 31 09:42:38 2026] 127.0.0.1:43786 Closing +[Fri Jul 31 09:42:38 2026] 127.0.0.1:43800 Accepted +[Fri Jul 31 09:42:38 2026] 127.0.0.1:43804 Accepted +[Fri Jul 31 09:42:38 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 09:42:38 2026] 127.0.0.1:43800 [200]: GET /api/stats.php +[Fri Jul 31 09:42:38 2026] 127.0.0.1:43800 Closing +[Fri Jul 31 09:42:38 2026] 127.0.0.1:43814 Accepted +[Fri Jul 31 09:42:38 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 09:42:38 2026] 127.0.0.1:43804 [200]: GET /api/stats.php +[Fri Jul 31 09:42:38 2026] 127.0.0.1:43804 Closing +[Fri Jul 31 09:42:38 2026] 127.0.0.1:43828 Accepted +[Fri Jul 31 09:42:38 2026] 127.0.0.1:43814 [200]: GET /api/chart.php?range=hour +[Fri Jul 31 09:42:38 2026] 127.0.0.1:43814 Closing +[Fri Jul 31 09:42:38 2026] 127.0.0.1:43828 [200]: GET /favicon.ico +[Fri Jul 31 09:42:38 2026] 127.0.0.1:43828 Closing +[Fri Jul 31 09:42:38 2026] 127.0.0.1:43842 Accepted +[Fri Jul 31 09:42:38 2026] 127.0.0.1:43842 [200]: GET /api/chart.php?range=hour +[Fri Jul 31 09:42:38 2026] 127.0.0.1:43842 Closing +[Fri Jul 31 09:42:38 2026] 127.0.0.1:43858 Accepted +[Fri Jul 31 09:42:38 2026] 127.0.0.1:43858 [200]: GET /api/chart.php?range=hour +[Fri Jul 31 09:42:38 2026] 127.0.0.1:43858 Closing +[Fri Jul 31 09:42:38 2026] 127.0.0.1:43868 Accepted +[Fri Jul 31 09:42:38 2026] 127.0.0.1:43868 [200]: GET /api/profile.php?pubkey=8ff74724ed641b3c28e5a86d7c5cbc49c37638ace8c6c38935860e7a5eedde0e +[Fri Jul 31 09:42:38 2026] 127.0.0.1:43868 Closing +[Fri Jul 31 09:42:43 2026] 127.0.0.1:43884 Accepted +[Fri Jul 31 09:42:43 2026] 127.0.0.1:43884 [200]: GET /api/caching.php +[Fri Jul 31 09:42:43 2026] 127.0.0.1:43884 Closing +[Fri Jul 31 09:44:23 2026] 127.0.0.1:44536 Accepted +[Fri Jul 31 09:44:23 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 09:44:23 2026] 127.0.0.1:44536 [200]: GET /api/stats.php +[Fri Jul 31 09:44:23 2026] 127.0.0.1:44536 Closing +[Fri Jul 31 09:44:23 2026] 127.0.0.1:44552 Accepted +[Fri Jul 31 09:44:23 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 09:44:23 2026] 127.0.0.1:44552 [200]: GET /api/stats.php +[Fri Jul 31 09:44:23 2026] 127.0.0.1:44552 Closing +[Fri Jul 31 09:44:23 2026] 127.0.0.1:44562 Accepted +[Fri Jul 31 09:44:23 2026] 127.0.0.1:44562 [200]: GET /api/chart.php?range=hour +[Fri Jul 31 09:44:23 2026] 127.0.0.1:44562 Closing +[Fri Jul 31 09:44:23 2026] 127.0.0.1:44566 Accepted +[Fri Jul 31 09:44:23 2026] 127.0.0.1:44566 [200]: GET /api/chart.php?range=hour +[Fri Jul 31 09:44:23 2026] 127.0.0.1:44566 Closing +[Fri Jul 31 09:44:33 2026] 127.0.0.1:58404 Accepted +[Fri Jul 31 09:44:33 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 09:44:33 2026] 127.0.0.1:58404 [200]: GET /api/stats.php +[Fri Jul 31 09:44:33 2026] 127.0.0.1:58404 Closing +[Fri Jul 31 09:44:33 2026] 127.0.0.1:58420 Accepted +[Fri Jul 31 09:44:33 2026] 127.0.0.1:58420 [200]: GET /api/chart.php?range=hour +[Fri Jul 31 09:44:33 2026] 127.0.0.1:58420 Closing +[Fri Jul 31 09:44:43 2026] 127.0.0.1:35644 Accepted +[Fri Jul 31 09:44:43 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 09:44:43 2026] 127.0.0.1:35644 [200]: GET /api/stats.php +[Fri Jul 31 09:44:43 2026] 127.0.0.1:35644 Closing +[Fri Jul 31 09:44:43 2026] 127.0.0.1:35646 Accepted +[Fri Jul 31 09:44:43 2026] 127.0.0.1:35646 [200]: GET /api/chart.php?range=hour +[Fri Jul 31 09:44:43 2026] 127.0.0.1:35646 Closing +[Fri Jul 31 09:44:53 2026] 127.0.0.1:60230 Accepted +[Fri Jul 31 09:44:53 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 09:44:53 2026] 127.0.0.1:60230 [200]: GET /api/stats.php +[Fri Jul 31 09:44:53 2026] 127.0.0.1:60230 Closing +[Fri Jul 31 09:44:53 2026] 127.0.0.1:60236 Accepted +[Fri Jul 31 09:44:53 2026] 127.0.0.1:60236 [200]: GET /api/chart.php?range=hour +[Fri Jul 31 09:44:53 2026] 127.0.0.1:60236 Closing +[Fri Jul 31 09:45:01 2026] 127.0.0.1:43410 Accepted +[Fri Jul 31 09:45:01 2026] 127.0.0.1:43410 [200]: GET /api/caching.php +[Fri Jul 31 09:45:01 2026] 127.0.0.1:43410 Closing +[Fri Jul 31 09:45:46 2026] 127.0.0.1:36570 Accepted +[Fri Jul 31 09:45:46 2026] 127.0.0.1:36570 [200]: GET /api/caching.php +[Fri Jul 31 09:45:46 2026] 127.0.0.1:36570 Closing +[Fri Jul 31 09:45:51 2026] 127.0.0.1:36582 Accepted +[Fri Jul 31 09:45:51 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 09:45:51 2026] 127.0.0.1:36582 [200]: GET /api/stats.php +[Fri Jul 31 09:45:51 2026] 127.0.0.1:36582 Closing +[Fri Jul 31 09:45:51 2026] 127.0.0.1:36598 Accepted +[Fri Jul 31 09:45:51 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 09:45:51 2026] 127.0.0.1:36598 [200]: GET /api/stats.php +[Fri Jul 31 09:45:51 2026] 127.0.0.1:36598 Closing +[Fri Jul 31 09:45:51 2026] 127.0.0.1:36612 Accepted +[Fri Jul 31 09:45:51 2026] 127.0.0.1:36612 [200]: GET /api/chart.php?range=hour +[Fri Jul 31 09:45:51 2026] 127.0.0.1:36612 Closing +[Fri Jul 31 09:45:51 2026] 127.0.0.1:36614 Accepted +[Fri Jul 31 09:45:51 2026] 127.0.0.1:36614 [200]: GET /api/chart.php?range=hour +[Fri Jul 31 09:45:51 2026] 127.0.0.1:36614 Closing +[Fri Jul 31 09:46:01 2026] 127.0.0.1:37848 Accepted +[Fri Jul 31 09:46:01 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 09:46:01 2026] 127.0.0.1:37848 [200]: GET /api/stats.php +[Fri Jul 31 09:46:01 2026] 127.0.0.1:37848 Closing +[Fri Jul 31 09:46:01 2026] 127.0.0.1:37850 Accepted +[Fri Jul 31 09:46:01 2026] 127.0.0.1:37850 [200]: GET /api/chart.php?range=hour +[Fri Jul 31 09:46:01 2026] 127.0.0.1:37850 Closing +[Fri Jul 31 09:46:10 2026] 127.0.0.1:57520 Accepted +[Fri Jul 31 09:46:10 2026] 127.0.0.1:57520 [200]: GET /api/caching.php +[Fri Jul 31 09:46:10 2026] 127.0.0.1:57520 Closing +[Fri Jul 31 10:01:55 2026] 127.0.0.1:40744 Accepted +[Fri Jul 31 10:01:55 2026] 127.0.0.1:40744 [200]: POST /api/caching.php +[Fri Jul 31 10:01:55 2026] 127.0.0.1:40744 Closing +[Fri Jul 31 10:02:49 2026] 127.0.0.1:47800 Accepted +[Fri Jul 31 10:02:49 2026] 127.0.0.1:47800 [200]: GET /api/caching.php +[Fri Jul 31 10:02:49 2026] 127.0.0.1:47800 Closing +[Fri Jul 31 10:04:58 2026] 127.0.0.1:38430 Accepted +[Fri Jul 31 10:04:58 2026] 127.0.0.1:38430 [200]: GET / +[Fri Jul 31 10:04:58 2026] 127.0.0.1:38430 Closing +[Fri Jul 31 10:04:58 2026] 127.0.0.1:38434 Accepted +[Fri Jul 31 10:04:58 2026] 127.0.0.1:38434 [200]: GET /assets/index.css +[Fri Jul 31 10:04:58 2026] 127.0.0.1:38434 Closing +[Fri Jul 31 10:04:58 2026] 127.0.0.1:38448 Accepted +[Fri Jul 31 10:04:58 2026] 127.0.0.1:38464 Accepted +[Fri Jul 31 10:04:58 2026] 127.0.0.1:38474 Accepted +[Fri Jul 31 10:04:58 2026] 127.0.0.1:38448 [200]: GET /assets/nostr.bundle.js +[Fri Jul 31 10:04:58 2026] 127.0.0.1:38464 [200]: GET /assets/nostr-lite.js +[Fri Jul 31 10:04:58 2026] 127.0.0.1:38474 [200]: GET /assets/app.js +[Fri Jul 31 10:04:58 2026] 127.0.0.1:38448 Closing +[Fri Jul 31 10:04:58 2026] 127.0.0.1:38464 Closing +[Fri Jul 31 10:04:58 2026] 127.0.0.1:38474 Closing +[Fri Jul 31 10:04:58 2026] 127.0.0.1:38476 Accepted +[Fri Jul 31 10:04:58 2026] 127.0.0.1:38478 Accepted +[Fri Jul 31 10:04:58 2026] 127.0.0.1:38486 Accepted +[Fri Jul 31 10:04:59 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 10:04:59 2026] 127.0.0.1:38476 [200]: GET /api/stats.php +[Fri Jul 31 10:04:59 2026] 127.0.0.1:38476 Closing +[Fri Jul 31 10:04:59 2026] 127.0.0.1:38490 Accepted +[Fri Jul 31 10:04:59 2026] PHP Warning: syntax error, unexpected '(' in /proc/meminfo on line 9 + in /home/user/lt/c-relay-pg/admin/api/stats.php on line 47 +[Fri Jul 31 10:04:59 2026] 127.0.0.1:38478 [200]: GET /api/stats.php +[Fri Jul 31 10:04:59 2026] 127.0.0.1:38478 Closing +[Fri Jul 31 10:04:59 2026] 127.0.0.1:38486 [200]: GET /api/chart.php?range=hour +[Fri Jul 31 10:04:59 2026] 127.0.0.1:38486 Closing +[Fri Jul 31 10:04:59 2026] 127.0.0.1:38490 [200]: GET /favicon.ico +[Fri Jul 31 10:04:59 2026] 127.0.0.1:38490 Closing +[Fri Jul 31 10:04:59 2026] 127.0.0.1:38500 Accepted +[Fri Jul 31 10:04:59 2026] 127.0.0.1:38502 Accepted +[Fri Jul 31 10:04:59 2026] 127.0.0.1:38500 [200]: GET /api/chart.php?range=hour +[Fri Jul 31 10:04:59 2026] 127.0.0.1:38500 Closing +[Fri Jul 31 10:04:59 2026] 127.0.0.1:38502 [200]: GET /api/profile.php?pubkey=8ff74724ed641b3c28e5a86d7c5cbc49c37638ace8c6c38935860e7a5eedde0e +[Fri Jul 31 10:04:59 2026] 127.0.0.1:38502 Closing +[Fri Jul 31 10:04:59 2026] 127.0.0.1:38506 Accepted +[Fri Jul 31 10:04:59 2026] 127.0.0.1:38506 [200]: GET /api/chart.php?range=hour +[Fri Jul 31 10:04:59 2026] 127.0.0.1:38506 Closing +[Fri Jul 31 10:05:03 2026] 127.0.0.1:38522 Accepted +[Fri Jul 31 10:05:03 2026] 127.0.0.1:38522 [200]: GET /api/caching.php +[Fri Jul 31 10:05:03 2026] 127.0.0.1:38522 Closing +[Fri Jul 31 10:05:21 2026] 127.0.0.1:56336 Accepted +[Fri Jul 31 10:05:21 2026] 127.0.0.1:56336 [200]: POST /api/caching.php +[Fri Jul 31 10:05:21 2026] 127.0.0.1:56336 Closing +[Fri Jul 31 10:05:21 2026] 127.0.0.1:56348 Accepted +[Fri Jul 31 10:05:21 2026] 127.0.0.1:56348 [200]: GET /api/caching.php +[Fri Jul 31 10:05:21 2026] 127.0.0.1:56348 Closing +[Fri Jul 31 10:07:01 2026] 127.0.0.1:33980 Accepted +[Fri Jul 31 10:07:01 2026] 127.0.0.1:33980 [200]: GET /api/caching.php +[Fri Jul 31 10:07:01 2026] 127.0.0.1:33980 Closing diff --git a/admin/relays.php b/admin/relays.php deleted file mode 100644 index 033cc71..0000000 --- a/admin/relays.php +++ /dev/null @@ -1,132 +0,0 @@ -prepare("SELECT COUNT(*) FROM caching_backfill_relay_progress rp $where_sql"); - $stmt->execute($params); - $total = intval($stmt->fetchColumn()); - - $sql = " - SELECT rp.author_pubkey, rp.relay_url, rp.until_cursor, rp.complete, - rp.events_fetched, - COALESCE(rp.consecutive_errors, 0) AS consecutive_errors, - rp.last_status, rp.updated_at, - e.content::json->>'name' AS name, - e.content::json->>'display_name' AS display_name - FROM caching_backfill_relay_progress rp - LEFT JOIN LATERAL (SELECT content FROM events WHERE pubkey = rp.author_pubkey AND kind = 0 ORDER BY created_at DESC LIMIT 1) e ON true - $where_sql - ORDER BY rp.complete ASC, COALESCE(rp.consecutive_errors, 0) DESC, rp.updated_at DESC - LIMIT $per OFFSET $offset - "; - $stmt = $pdo->prepare($sql); - $stmt->execute($params); - $relays = $stmt->fetchAll(); -} catch (PDOException $ex) {} - -function status_badge(string $status): string { - if ($status === 'eose') return 'eose'; - if ($status === 'timeout') return 'timeout'; - if (str_starts_with($status, 'error')) return '' . e($status) . ''; - if (str_starts_with($status, 'NOTICE')) return '' . e($status) . ''; - if (str_starts_with($status, 'CLOSED')) return '' . e($status) . ''; - if ($status === '') return ''; - return '' . e($status) . ''; -} - -admin_header('relays', 'C-Relay-PG Admin — Relay Progress'); -?> - -
-
PER-RELAY BACKFILL PROGRESS ( total)
- -
- - - - Filtered by: - Clear - -
- -
- - - - - - - - - - - - - - - = 3 ? 'style="background:rgba(255,0,0,0.05)"' : '' ?>> - - - - - - - - - - - - - -
AuthorRelay URLCompleteEventsErrorsLast StatusUpdated
- - - - unknown - -
-
✓' : '' ?> 0 - ? '' . intval($r['consecutive_errors']) . '' - : '0' ?>
No relay progress rows found.
-
- - -
- - diff --git a/admin/serve.sh b/admin/serve.sh new file mode 100755 index 0000000..b96d4d1 --- /dev/null +++ b/admin/serve.sh @@ -0,0 +1,27 @@ +#!/bin/bash +# Launch the admin2 PHP built-in server, fully detached from the calling shell. +# Usage: ./admin2/serve.sh [port] (default port 8088) +PORT="${1:-8088}" +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" + +# Kill any existing instance on this port. +pkill -f "php -S 127.0.0.1:$PORT" 2>/dev/null +sleep 1 + +# Start fully detached in its own session so SIGTERM to the launcher +# does not propagate to the PHP server. +setsid php -S 127.0.0.1:$PORT -t "$SCRIPT_DIR" > "$SCRIPT_DIR/php_server.log" 2>&1 < /dev/null & +PHP_PID=$! +disown $PHP_PID 2>/dev/null + +# Give it a moment to bind, then report. +sleep 1 +if kill -0 "$PHP_PID" 2>/dev/null; then + echo "admin PHP server started on http://127.0.0.1:$PORT (PID $PHP_PID)" + echo "Serving from: $SCRIPT_DIR" + echo "Log: $SCRIPT_DIR/php_server.log" +else + echo "ERROR: PHP server failed to start. Log:" + cat "$SCRIPT_DIR/php_server.log" 2>/dev/null + exit 1 +fi diff --git a/caching/Makefile b/caching/Makefile index 566f37c..c792378 100644 --- a/caching/Makefile +++ b/caching/Makefile @@ -22,7 +22,7 @@ LIBS = -lwebsockets -lssl -lcrypto -lsecp256k1 -lcurl -lz -ldl -lpthread -lm -lp MAIN_SRC = src/main.c src/debug.c src/jsonc_strip.c src/config.c src/state.c \ src/follow_graph.c src/relay_sink.c src/live_subscriber.c \ - src/backfill.c src/relay_discovery.c \ + src/backfill.c src/forward_catchup.c src/relay_discovery.c \ src/pg_inbox.c src/pg_config.c # Architecture detection diff --git a/caching/src/backfill.c b/caching/src/backfill.c index 92043b6..198b241 100644 --- a/caching/src/backfill.c +++ b/caching/src/backfill.c @@ -134,6 +134,24 @@ static int find_oldest_created_at(cJSON **events, int count, long *out_oldest) { return found; } +/* Find the newest (maximum) created_at among an array of event JSON objects. + * Returns 1 and sets *out_newest, or 0 if no events / no valid created_at. */ +static int find_newest_created_at(cJSON **events, int count, long *out_newest) { + long newest = 0; + int found = 0; + for (int i = 0; i < count; i++) { + cJSON *ca = cJSON_GetObjectItem(events[i], "created_at"); + if (!ca || !cJSON_IsNumber(ca)) continue; + long ts = (long)ca->valuedouble; + if (!found || ts > newest) { + newest = ts; + found = 1; + } + } + if (found && out_newest) *out_newest = newest; + return found; +} + /* Build the kinds array for a given pubkey (admin vs regular). * Returns NULL if no kinds filter should be applied (admin_all_kinds). */ static cJSON *build_kinds(cr_config_t *cfg, const char *pk) { @@ -370,9 +388,11 @@ int cr_backfill_tick(cr_backfill_t *bf, cr_config_t *cfg, continue; } - /* Find oldest timestamp, then publish every event. */ + /* Find oldest and newest timestamps, then publish every event. */ long oldest_ts = 0; + long newest_ts = 0; find_oldest_created_at(events, ev_count, &oldest_ts); + find_newest_created_at(events, ev_count, &newest_ts); for (int k = 0; k < ev_count; k++) { cr_sink_publish(sink, events[k]); @@ -381,6 +401,11 @@ int cr_backfill_tick(cr_backfill_t *bf, cr_config_t *cfg, free(events); bf->events_total += ev_count; + /* Update last_event_at for forward catch-up gap tracking. */ + if (newest_ts > 0) { + pg_inbox_update_last_event_at(pk, newest_ts); + } + DEBUG_LOG("backfill: %s @ %s -> %d events (until=%ld, oldest=%ld, eose=%d)", pk, relay_url, ev_count, until_cursor, oldest_ts, qctx.got_eose); diff --git a/caching/src/forward_catchup.c b/caching/src/forward_catchup.c new file mode 100644 index 0000000..f03605d --- /dev/null +++ b/caching/src/forward_catchup.c @@ -0,0 +1,199 @@ +/* + * caching_relay - forward catch-up implementation. + * + * See forward_catchup.h for design. + */ +#include "forward_catchup.h" +#include "pg_inbox.h" +#include "config.h" +#include "relay_sink.h" +#include "debug.h" + +#include +#include +#include +#include + +/* Find the newest (maximum) created_at among an array of event JSON objects. + * Returns 1 and sets *out_newest, or 0 if no events / no valid created_at. */ +static int find_newest_created_at(cJSON **events, int count, long *out_newest) { + long newest = 0; + int found = 0; + for (int i = 0; i < count; i++) { + cJSON *ca = cJSON_GetObjectItem(events[i], "created_at"); + if (!ca || !cJSON_IsNumber(ca)) continue; + long ts = (long)ca->valuedouble; + if (!found || ts > newest) { + newest = ts; + found = 1; + } + } + if (found && out_newest) *out_newest = newest; + return found; +} + +/* Build the kinds array for a given pubkey (admin vs regular). + * Returns NULL if no kinds filter should be applied (admin_all_kinds). */ +static cJSON *build_kinds(cr_config_t *cfg, const char *pk) { + int is_admin = cr_follow_is_root(cfg, pk); + if (is_admin && cfg->admin_all_kinds) { + return NULL; + } + cJSON *kinds = cJSON_CreateArray(); + if (is_admin && cfg->admin_kind_count > 0) { + for (int i = 0; i < cfg->admin_kind_count; i++) + cJSON_AddItemToArray(kinds, cJSON_CreateNumber(cfg->admin_kinds[i])); + } else { + for (int i = 0; i < cfg->kind_count; i++) + cJSON_AddItemToArray(kinds, cJSON_CreateNumber(cfg->kinds[i])); + } + return kinds; +} + +/* Get relay URLs for an author from the relay progress table. + * Returns a cJSON array of relay_url strings. Caller must cJSON_Delete(). + * Returns NULL on error or if no relays found. */ +static cJSON *get_author_relays(const char *pk) { + /* Use pg_inbox_get_incomplete_relays for incomplete authors. + * For completed authors, we need all relays — query directly. */ + cJSON *incomplete = pg_inbox_get_incomplete_relays(pk); + if (incomplete && cJSON_GetArraySize(incomplete) > 0) { + /* Extract just the relay_url strings. */ + cJSON *urls = cJSON_CreateArray(); + int n = cJSON_GetArraySize(incomplete); + for (int i = 0; i < n; i++) { + cJSON *entry = cJSON_GetArrayItem(incomplete, i); + cJSON *url = cJSON_GetObjectItemCaseSensitive(entry, "relay_url"); + if (url && cJSON_IsString(url) && url->valuestring[0]) { + cJSON_AddItemToArray(urls, cJSON_CreateString(url->valuestring)); + } + } + cJSON_Delete(incomplete); + if (cJSON_GetArraySize(urls) > 0) return urls; + cJSON_Delete(urls); + } + if (incomplete) cJSON_Delete(incomplete); + + /* For completed authors, fall back to the upstream pool's connected + * relays. The caller will use the pool directly. */ + return NULL; +} + +int cr_forward_catchup(cr_config_t *cfg, + nostr_relay_pool_t *upstream, + cr_sink_t *sink) { + if (!cfg || !upstream || !sink) return -1; + + cJSON *authors = pg_inbox_get_authors_for_catchup(); + if (!authors) { + DEBUG_INFO("forward_catchup: no authors with last_event_at > 0"); + return 0; + } + + int author_count = cJSON_GetArraySize(authors); + if (author_count == 0) { + cJSON_Delete(authors); + DEBUG_INFO("forward_catchup: no authors need catch-up"); + return 0; + } + + DEBUG_INFO("forward_catchup: checking %d authors for missed events", author_count); + + long now = (long)time(NULL); + int page_size = cfg->backfill.events_per_tick; + if (page_size < 1) page_size = 500; + + cr_sink_set_source_class(sink, CR_SINK_CLASS_BACKFILL); + + int total_events_published = 0; + int authors_caught_up = 0; + + for (int i = 0; i < author_count; i++) { + cJSON *entry = cJSON_GetArrayItem(authors, i); + if (!entry) continue; + + cJSON *pk_node = cJSON_GetObjectItemCaseSensitive(entry, "pubkey"); + cJSON *lea_node = cJSON_GetObjectItemCaseSensitive(entry, "last_event_at"); + if (!pk_node || !cJSON_IsString(pk_node) || !lea_node || !cJSON_IsNumber(lea_node)) + continue; + + const char *pk = pk_node->valuestring; + long last_event_at = (long)lea_node->valuedouble; + + if (last_event_at <= 0 || last_event_at >= now) continue; + + /* Build filter: since = last_event_at + 1, until = now. */ + cJSON *filter = cJSON_CreateObject(); + cJSON *authors_arr = cJSON_CreateArray(); + cJSON_AddItemToArray(authors_arr, cJSON_CreateString(pk)); + cJSON_AddItemToObject(filter, "authors", authors_arr); + cJSON *kinds = build_kinds(cfg, pk); + if (kinds) cJSON_AddItemToObject(filter, "kinds", kinds); + cJSON_AddItemToObject(filter, "since", cJSON_CreateNumber((double)(last_event_at + 1))); + cJSON_AddItemToObject(filter, "until", cJSON_CreateNumber((double)now)); + cJSON_AddItemToObject(filter, "limit", cJSON_CreateNumber((double)page_size)); + + /* Try to get author-specific relays first; fall back to upstream pool. */ + cJSON *author_relays = get_author_relays(pk); + + int ev_count = 0; + cJSON **events = NULL; + + if (author_relays && cJSON_GetArraySize(author_relays) > 0) { + /* Query using the author's outbox relays. */ + int n_relays = cJSON_GetArraySize(author_relays); + const char **urls = malloc(sizeof(char *) * n_relays); + for (int r = 0; r < n_relays; r++) { + cJSON *u = cJSON_GetArrayItem(author_relays, r); + urls[r] = cJSON_IsString(u) ? u->valuestring : ""; + } + events = synchronous_query_relays_with_progress( + urls, n_relays, filter, RELAY_QUERY_ALL_RESULTS, + &ev_count, 30, NULL, NULL, 0, NULL); + free(urls); + } else { + /* Fall back: query all connected upstream relays. + * Use the pool's relay list. We pass NULL for urls to let + * the pool use all connected relays. */ + events = synchronous_query_relays_with_progress( + NULL, 0, filter, RELAY_QUERY_ALL_RESULTS, + &ev_count, 30, NULL, NULL, 0, NULL); + } + cJSON_Delete(author_relays); + cJSON_Delete(filter); + + if (events && ev_count > 0) { + /* Publish all events. */ + long newest = 0; + find_newest_created_at(events, ev_count, &newest); + + for (int k = 0; k < ev_count; k++) { + cr_sink_publish(sink, events[k]); + cJSON_Delete(events[k]); + } + free(events); + total_events_published += ev_count; + authors_caught_up++; + + /* Update last_event_at to the newest event we saw. */ + if (newest > 0) { + pg_inbox_update_last_event_at(pk, newest); + } + + DEBUG_LOG("forward_catchup: %s -> %d events (since=%ld, until=%ld)", + pk, ev_count, last_event_at + 1, now); + } else { + /* No events in the gap — update last_event_at to now so we + * don't re-query the same empty window next time. */ + pg_inbox_update_last_event_at(pk, now); + if (events) free(events); + } + } + + cJSON_Delete(authors); + + DEBUG_INFO("forward_catchup: %d authors checked, %d had events, %d total events published", + author_count, authors_caught_up, total_events_published); + + return 0; +} diff --git a/caching/src/forward_catchup.h b/caching/src/forward_catchup.h new file mode 100644 index 0000000..ae9cfd0 --- /dev/null +++ b/caching/src/forward_catchup.h @@ -0,0 +1,30 @@ +/* + * caching_relay - forward catch-up for gap bridging. + * + * When the caching service starts (or caching is re-enabled after being + * off), events posted by followed authors during the downtime are missed + * by the backward-drain backfill (which walks toward the beginning of + * time) and by the live subscriber (which starts at `since = now`). + * + * The forward catch-up queries `since = last_event_at + 1, until = now` + * for each followed author to bridge that gap. `last_event_at` is the + * `created_at` of the most recent event we've ever seen for the author, + * maintained by the backfill and live subscriber. + */ +#ifndef CACHING_RELAY_FORWARD_CATCHUP_H +#define CACHING_RELAY_FORWARD_CATCHUP_H + +#include "config.h" +#include "relay_sink.h" +#include "../nostr_core_lib/nostr_core/nostr_core.h" + +/* Run forward catch-up for all followed authors with last_event_at > 0. + * For each author, queries events from last_event_at + 1 to now on one + * outbox relay and publishes them to the sink. + * + * Returns 0 on success, -1 on error. */ +int cr_forward_catchup(cr_config_t *cfg, + nostr_relay_pool_t *upstream, + cr_sink_t *sink); + +#endif /* CACHING_RELAY_FORWARD_CATCHUP_H */ diff --git a/caching/src/live_subscriber.c b/caching/src/live_subscriber.c index 16b7568..7e57849 100644 --- a/caching/src/live_subscriber.c +++ b/caching/src/live_subscriber.c @@ -4,6 +4,7 @@ #define _GNU_SOURCE #include "live_subscriber.h" #include "follow_graph.h" +#include "pg_inbox.h" #include "debug.h" #include @@ -25,6 +26,15 @@ static void live_on_event(cJSON *event, const char *relay_url, void *user_data) ctx->live->events_received++; cr_sink_publish(ctx->sink, event); + /* Update last_event_at for forward catch-up gap tracking. */ + cJSON *ev_pubkey = cJSON_GetObjectItem(event, "pubkey"); + cJSON *ev_created = cJSON_GetObjectItem(event, "created_at"); + if (ev_pubkey && cJSON_IsString(ev_pubkey) && + ev_created && cJSON_IsNumber(ev_created)) { + pg_inbox_update_last_event_at(ev_pubkey->valuestring, + (long)ev_created->valuedouble); + } + /* Detect admin kind-3 (contact list) changes from a root pubkey and * signal the main loop to refresh the follow graph immediately. */ if (ctx->cfg) { diff --git a/caching/src/main.c b/caching/src/main.c index 0034cb3..6cb7641 100644 --- a/caching/src/main.c +++ b/caching/src/main.c @@ -17,6 +17,7 @@ #include "relay_sink.h" #include "live_subscriber.h" #include "backfill.h" +#include "forward_catchup.h" #include "relay_discovery.h" #include "pg_inbox.h" #include "pg_config.h" @@ -367,6 +368,15 @@ int main(int argc, char **argv) { init_relay_progress_for_all(&cfg, &relay_map, &followed); } + /* Forward catch-up: bridge the gap for events posted while caching + * was off. Runs once at startup (not on --restart, which does a full + * re-drain from now). For each followed author with last_event_at > 0, + * queries since = last_event_at + 1, until = now. */ + if (pg_conn && !restart && cfg.backfill.enabled) { + DEBUG_INFO("forward catch-up: bridging gap for followed authors"); + cr_forward_catchup(&cfg, upstream, &sink); + } + /* Open live subscription. */ cr_live_t live; if (cfg.live.enabled) { diff --git a/caching/src/pg_inbox.c b/caching/src/pg_inbox.c index 596470d..81d0cb3 100644 --- a/caching/src/pg_inbox.c +++ b/caching/src/pg_inbox.c @@ -1100,3 +1100,89 @@ int pg_inbox_get_active_target(char *out_pubkey, int pk_len, PQclear(res); return 0; } + +/* ------------------------------------------------------------------ */ +/* Forward catch-up support (last_event_at tracking) */ +/* ------------------------------------------------------------------ */ + +cJSON* pg_inbox_get_authors_for_catchup(void) { + if (!g_pg) { + DEBUG_ERROR("pg_inbox: get_authors_for_catchup: not initialized"); + return NULL; + } + + const char *sql = + "SELECT pubkey, last_event_at " + " FROM caching_followed_pubkeys " + " WHERE last_event_at > 0 " + " ORDER BY last_event_at ASC"; + + PGresult *res = PQexec(g_pg, sql); + if (!res) { + DEBUG_ERROR("pg_inbox: get_authors_for_catchup: NULL result"); + return NULL; + } + ExecStatusType st = PQresultStatus(res); + if (st != PGRES_TUPLES_OK) { + DEBUG_ERROR("pg_inbox: get_authors_for_catchup failed: %s", + PQresultErrorMessage(res)); + PQclear(res); + return NULL; + } + + cJSON *arr = cJSON_CreateArray(); + if (!arr) { + PQclear(res); + return NULL; + } + + int n = PQntuples(res); + for (int i = 0; i < n; i++) { + const char *pk = PQgetvalue(res, i, 0); + long last_event_at = strtol(PQgetvalue(res, i, 1), NULL, 10); + if (!pk || pk[0] == '\0') continue; + + cJSON *obj = cJSON_CreateObject(); + cJSON_AddStringToObject(obj, "pubkey", pk); + cJSON_AddNumberToObject(obj, "last_event_at", (double)last_event_at); + cJSON_AddItemToArray(arr, obj); + } + + PQclear(res); + return arr; +} + +int pg_inbox_update_last_event_at(const char *pk, long event_created_at) { + if (!g_pg) { + DEBUG_ERROR("pg_inbox: update_last_event_at: not initialized"); + return -1; + } + if (!pk || pk[0] == '\0' || event_created_at <= 0) return -1; + + char ea_buf[32]; + snprintf(ea_buf, sizeof(ea_buf), "%ld", event_created_at); + + const char *vals[2] = {pk, ea_buf}; + int lens[2] = {(int)strlen(pk), (int)strlen(ea_buf)}; + int fmts[2] = {0, 0}; + + const char *sql = + "UPDATE caching_followed_pubkeys " + " SET last_event_at = GREATEST(last_event_at, $2::BIGINT) " + " WHERE pubkey = $1"; + + PGresult *res = PQexecParams(g_pg, sql, 2, NULL, vals, lens, fmts, 0); + if (!res) { + DEBUG_ERROR("pg_inbox: update_last_event_at: NULL result"); + return -1; + } + ExecStatusType st = PQresultStatus(res); + if (st != PGRES_COMMAND_OK) { + DEBUG_ERROR("pg_inbox: update_last_event_at failed: %s", + PQresultErrorMessage(res)); + PQclear(res); + return -1; + } + PQclear(res); + return 0; +} diff --git a/caching/src/pg_inbox.h b/caching/src/pg_inbox.h index 20bbb20..cca9745 100644 --- a/caching/src/pg_inbox.h +++ b/caching/src/pg_inbox.h @@ -149,4 +149,17 @@ int pg_inbox_set_active_target(const char *pubkey, const char *relay_url); int pg_inbox_get_active_target(char *out_pubkey, int pk_len, char *out_relay, int relay_len); +/* ------------------------------------------------------------------ */ +/* Forward catch-up support (last_event_at tracking) */ +/* ------------------------------------------------------------------ */ + +/* Returns a cJSON array of {pubkey, last_event_at} objects for all + * followed authors where last_event_at > 0. Caller must cJSON_Delete(). + * Returns NULL on error. */ +cJSON* pg_inbox_get_authors_for_catchup(void); + +/* Update last_event_at for a pubkey to the GREATEST of current and + * the given value. Returns 0 on success, -1 on error. */ +int pg_inbox_update_last_event_at(const char *pk, long event_created_at); + #endif /* CACHING_RELAY_PG_INBOX_H */ diff --git a/plans/admin2_php_full_admin_plan.md b/plans/admin2_php_full_admin_plan.md new file mode 100644 index 0000000..3bcb9c8 --- /dev/null +++ b/plans/admin2_php_full_admin_plan.md @@ -0,0 +1,206 @@ +# admin2: Full PHP Admin for C-Relay-PG + +## Goal + +Recreate the entire c-relay-pg admin interface as a PHP application in a new +`admin2/` directory, starting from the existing `api/` HTML/CSS/JS files and +replacing the Nostr admin command backend with direct PostgreSQL queries via +PHP PDO. This covers ALL admin sections, not just caching. + +## Architecture + +Same as `admin/` (PHP + nginx + PDO + 10s polling), but with the full +section set from the original `api/index.html`: + +```mermaid +flowchart LR + Browser -->|HTTPS /admin2/| Nginx + Nginx -->|*.php| PHP_FPM + Nginx -->|/relay/| Relay[C-Relay-PG] + PHP_FPM -->|PDO| PostgreSQL + Relay -->|libpq| PostgreSQL +``` + +## Sections (9 pages, matching original nav) + +| # | Nav Label | Section ID | Data Source | PHP API Endpoint | +|---|-----------|------------|-------------|------------------| +| 1 | Statistics | databaseStatisticsSection | `pg_database_size()`, `events` count, `pg_stat_activity`, process stats | `api/stats.php` | +| 2 | Subscriptions | subscriptionDetailsSection | `subscriptions` + `subscription_metrics` tables | `api/subscriptions.php` | +| 3 | Configuration | div_config | `config` table (read/edit all keys) | `api/config.php` | +| 4 | Authorization | authRulesSection + wotSection | `auth_rules` table | `api/auth.php` | +| 5 | IP BAN | ipBansSection | `ip_bans` table | `api/ipbans.php` | +| 6 | Relay Events | relayEventsSection | `events` table (recent events, kind filter) | `api/events.php` | +| 7 | Caching | cachingSection | `caching_*` tables (already built in `admin/`) | `api/caching.php` | +| 8 | DM | nip17DMSection | `events` table (kind 4/14/15 DMs) | `api/dm.php` | +| 9 | Database Query | sqlQuerySection | Direct SQL execution (admin only) | `api/query.php` | + +## Graph on Statistics Page + +The original has an event-rate chart. For the PHP version: +- **X-axis:** one tick = 10 seconds (the refresh interval) +- **Y-axis:** events per interval +- **Data source:** `api/stats.php` returns `events_delta` (count of new events since last poll) +- **JS:** maintains a rolling array of the last 60 data points (10 minutes of history), appends a new point on each 10s refresh, renders as a simple canvas/SVG line chart +- **No external chart library** — use a lightweight inline canvas renderer to keep it dependency-free + +## File Structure + +``` +admin2/ +├── index.php ← Single-page app (all 9 sections in one page, show/hide via JS) +├── assets/ +│ ├── index.css ← Copied from api/index.css (unchanged) +│ └── app.js ← Adapted from api/index.js (replace Nostr commands with fetch() to PHP APIs) +├── lib/ +│ ├── config.php ← DB connection config (same as admin/) +│ ├── db.php ← PDO helper (same as admin/) +│ └── helpers.php ← Shared helpers (same as admin/) +├── api/ +│ ├── stats.php ← Statistics: DB size, event counts, process info, event-rate delta +│ ├── subscriptions.php ← Subscription details + metrics +│ ├── config.php ← Config table read/edit (all keys, not just caching) +│ ├── auth.php ← Auth rules + WoT status +│ ├── ipbans.php ← IP ban list (read/add/remove) +│ ├── events.php ← Recent relay events (paginated, kind filter) +│ ├── caching.php ← Caching status (reuses admin/api/status.php logic) +│ ├── dm.php ← DM list (kind 4/14/15 events) +│ └── query.php ← Direct SQL query execution (admin only, read-only by default) +└── README.md +``` + +## Implementation Plan + +### Step 1 — Scaffold admin2/ directory +- Create `admin2/` with `lib/` (copy from `admin/`), `assets/`, `api/` +- Copy `api/index.css` → `admin2/assets/index.css` (unchanged) +- Copy `api/index.html` → `admin2/index.php` (will be adapted) + +### Step 2 — Adapt index.php from api/index.html +- Remove Nostr login/auth (NIP-07 extension, kind-23456 admin commands) +- Remove WebSocket connection logic (replaced by PHP AJAX polling) +- Keep all 9 section HTML structures exactly as-is +- Keep the side-nav, header, section show/hide JS +- Replace `sendAdminCommand()` calls with `fetch('api/*.php')` calls +- Add 10s auto-refresh via `setInterval` for statistics page +- Add event-rate chart canvas renderer + +### Step 3 — Adapt app.js from api/index.js +- Keep: `switchPage()`, nav handling, section show/hide, config table rendering +- Remove: WebSocket connection, NIP-07 login, NIP-44 encryption, kind-23456 event sending +- Replace: each `sendAdminCommand(['system_command', '...'])` with `fetch('api/....php')` +- Add: `refreshStats()` function that polls `api/stats.php` every 10s +- Add: event-rate chart rendering on canvas (rolling 60-point window) + +### Step 4 — Build PHP API endpoints (9 files) +Each endpoint returns JSON, queried directly from PostgreSQL via PDO: + +**api/stats.php** — Statistics page data: +```sql +SELECT pg_database_size(current_database()) AS db_size; +SELECT COUNT(*) FROM events; +SELECT COUNT(*) FROM pg_stat_activity WHERE state = 'active'; +-- Event rate: count events with first_seen in last 10s +SELECT COUNT(*) FROM events WHERE first_seen >= EXTRACT(EPOCH FROM NOW())::BIGINT - 10; +-- Kind distribution +SELECT kind, COUNT(*) FROM events GROUP BY kind ORDER BY count DESC; +``` + +**api/config.php** — Configuration (all config keys, not just caching): +```sql +SELECT key, value FROM config ORDER BY key; +-- POST: UPDATE config SET value = ? WHERE key = ? +``` + +**api/subscriptions.php** — Subscription details: +```sql +SELECT * FROM subscriptions ORDER BY created_at DESC LIMIT 100; +SELECT * FROM subscription_metrics ORDER BY id DESC LIMIT 100; +``` + +**api/auth.php** — Auth rules: +```sql +SELECT * FROM auth_rules ORDER BY id; +``` + +**api/ipbans.php** — IP bans: +```sql +SELECT * FROM ip_bans ORDER BY banned_at DESC; +-- POST: INSERT/DELETE +``` + +**api/events.php** — Recent relay events (paginated): +```sql +SELECT id, pubkey, kind, created_at, content, tags +FROM events ORDER BY created_at DESC LIMIT 50 OFFSET ?; +-- Filter by kind, pubkey +``` + +**api/caching.php** — Caching status (reuse from admin/): +```sql +SELECT * FROM caching_service_state; +SELECT * FROM caching_followed_pubkeys LIMIT 50 OFFSET ?; +SELECT * FROM caching_backfill_relay_progress LIMIT 50 OFFSET ?; +``` + +**api/dm.php** — Direct messages: +```sql +SELECT id, pubkey, kind, created_at, content +FROM events WHERE kind IN (4, 14, 15) ORDER BY created_at DESC LIMIT 50; +``` + +**api/query.php** — SQL query (admin only): +```sql +-- Execute arbitrary SELECT, return JSON +-- Read-only by default; write mode behind a flag +``` + +### Step 5 — Event-rate chart +- Canvas element in the statistics section +- JS maintains `eventRateHistory = []` (max 60 points) +- On each 10s refresh, push new event count, shift if > 60 +- Render as line chart on canvas (no external library) +- X-axis labels: time (mm:ss), one tick per 10s +- Y-axis labels: event count per interval + +### Step 6 — nginx config +Add `/admin2/` location block (same pattern as `/admin/`): +```nginx +location ^~ /admin2/ { + alias /opt/c-relay-pg/admin2/; + index index.php; + auth_basic "Relay Admin"; + auth_basic_user_file /opt/c-relay-pg/admin/.htpasswd; + location ~ \.php$ { + fastcgi_pass unix:/run/php/php8.3-fpm.sock; + include fastcgi_params; + fastcgi_param SCRIPT_FILENAME $request_filename; + } + location ^~ /admin2/lib/ { deny all; } +} +``` + +### Step 7 — Deploy and test +- Copy `admin2/` to server +- Add nginx location block, reload +- Test all 9 sections +- Verify 10s auto-refresh on statistics page +- Verify event-rate chart updates + +## Key Differences from Original api/ + +| Aspect | Original (api/) | New (admin2/) | +|--------|-----------------|---------------| +| Auth | NIP-07 Nostr extension login | HTTP Basic Auth (nginx) | +| Data fetch | WebSocket + kind-23456 encrypted admin commands | PHP AJAX `fetch()` to `api/*.php` | +| Encryption | NIP-44 (64KB limit) | None (direct DB, no limit) | +| Real-time | WebSocket push | 10s polling | +| Backend | C relay binary (embedded JS) | PHP-FPM + PostgreSQL PDO | +| Sections | 9 (same) | 9 (same HTML, different data source) | + +## Out of Scope + +- NIP-07 Nostr login (use HTTP Basic Auth) +- WebSocket push (use 10s polling) +- Write operations that require relay-level logic (event publishing, NIP-42 auth) — those stay on the Nostr admin API +- The original `api/` page remains unchanged and functional diff --git a/plans/forward_catchup_plan.md b/plans/forward_catchup_plan.md new file mode 100644 index 0000000..4ac6877 --- /dev/null +++ b/plans/forward_catchup_plan.md @@ -0,0 +1,306 @@ +# Forward Catch-Up Plan: Bridging the Gap When Caching Resumes + +## Problem + +When caching is turned off (or the caching service stops), events posted by +followed authors during the downtime are missed. The current backfill walks +**backward** from `until_cursor` toward the beginning of time — it does not +cover events **newer** than the cursor. The live subscriber uses +`since = time(NULL)`, so it only catches events from the moment it connects. +Events in the gap between "last event we know about" and "caching resumed" +are lost. + +## Schema Change: `last_event_at` column + +Add a `last_event_at BIGINT NOT NULL DEFAULT 0` column to +`caching_followed_pubkeys`. This records the `created_at` of the most +recent event we've ever seen for this author — not a proxy like +`updated_at` (which records when we last *touched* the row, which could +be a zero-event progress write or a follow-graph refresh). + +`since = last_event_at + 1, until = now` is exact: it catches every +event the relay doesn't yet have, with no assumptions about when the +last event occurred relative to when we last checked. + +### Population + +- **Backfill**: when publishing a page of events, compute + `max(created_at)` across the page (we already compute + `min(created_at)` for the cursor advance — add a parallel max). + Update `last_event_at = GREATEST(last_event_at, page_max_created_at)`. +- **Live subscriber**: when an event is received and published, update + `last_event_at = GREATEST(last_event_at, event.created_at)`. +- **One-time seed from `events` table**: on schema upgrade, set + `last_event_at = COALESCE((SELECT MAX(created_at) FROM events WHERE + pubkey = caching_followed_pubkeys.pubkey), 0)` for all existing rows. + This seeds the column from the relay's own data. + +### Migration + +Added to `src/pg_schema.sql` and `src/pg_schema.h`: + +```sql +ALTER TABLE caching_followed_pubkeys + ADD COLUMN IF NOT EXISTS last_event_at BIGINT NOT NULL DEFAULT 0; + +-- One-time seed from the events table. +UPDATE caching_followed_pubkeys fp + SET last_event_at = COALESCE( + (SELECT MAX(e.created_at) FROM events e WHERE e.pubkey = fp.pubkey), + 0 + ) + WHERE fp.last_event_at = 0; +``` + +No schema version bump needed — `ALTER TABLE ADD COLUMN IF NOT EXISTS` +is idempotent and the seed `UPDATE` is guarded by `WHERE last_event_at = 0`. + +## Current Architecture + +### Tables + +**`caching_followed_pubkeys`** (per-author state): +| Column | Purpose | +|---|---| +| `pubkey` | PK | +| `until_cursor` | Unix timestamp; backfill queries `until = this`, walks backward | +| `backfill_complete` | TRUE when drained to the beginning of time | +| `events_fetched` | Cumulative count | +| `last_seen` | Updated on follow-graph refresh | +| `updated_at` | Updated on every backfill progress write and completion mark | +| `last_event_at` | **NEW**: `created_at` of the most recent event we've seen for this author | + +**`caching_backfill_relay_progress`** (per-author-per-relay state): +| Column | Purpose | +|---|---| +| `author_pubkey, relay_url` | Composite PK | +| `until_cursor` | Per-relay backward-walk cursor | +| `complete` | TRUE when this relay is drained for this author | +| `updated_at` | Updated on every relay progress write | + +### Backfill flow ([`caching/src/backfill.c`](../caching/src/backfill.c:256)) + +1. Pick next incomplete author (round-robin) +2. For each incomplete relay for that author: + - Query `authors=[pk], until=until_cursor, limit=page_size` + - Publish events to the relay via the sink + - Advance `until_cursor` to `oldest_event_created_at - 1` + - If < page_size events + EOSE: mark relay `complete = TRUE` +3. If all relays complete: mark author `backfill_complete = TRUE` + +### Restart behavior + +- **Normal restart** (no `--restart`): cursor and completion state preserved. + Backfill resumes the backward walk from stored cursors. **Gap not covered.** +- **`--restart`**: all cursors reset to 0, all completion flags cleared. Full + re-drain from `now` backward. **Re-fetches everything** but covers the gap + incidentally (since it starts from `now`). + +### Live subscriber ([`caching/src/live_subscriber.c`](../caching/src/live_subscriber.c:86)) + +Uses `since = time(NULL)` — only catches events from the moment it connects. +No gap-bridging. + +## The Gap + +``` +Time ──────────────────────────────────────────────────────► + │ │ │ + last_event_at caching now + (most recent event turned (caching + we know about) off resumed) + │ + └── events posted here are missed +``` + +For **completed authors** (`backfill_complete = TRUE`): the backward walk is +done. `last_event_at` tells us the most recent event we have. Events posted +after `last_event_at` are in the gap. + +For **incomplete authors**: the backward walk is still in progress. The cursor +is somewhere in the past, walking backward. Events newer than the cursor are +not fetched by backfill. The live subscriber covers events from `now` forward. +The gap is between `last_event_at` and `now`. + +## Solution: Forward Catch-Up Phase + +Add a **forward catch-up** phase that runs once when the caching service +starts (or when backfill is re-enabled), before the normal backward-drain +backfill loop begins. + +### Logic + +For **every** followed author (both complete and incomplete): +1. Read `last_event_at` from `caching_followed_pubkeys`. +2. If `last_event_at = 0`, skip (no events known yet — the backward drain + will handle it). +3. Query one or two outbox relays: + `authors=[pk], since=last_event_at + 1, until=now, limit=page_size` +4. Publish all returned events to the relay via the sink. +5. Update `last_event_at` to the max `created_at` seen (or `now` if no + events were returned, to avoid re-querying the same empty window next + time). + +This is safe for both complete and incomplete authors: +- **Complete authors**: the backward drain is done, so the forward catch-up + is the only thing needed. +- **Incomplete authors**: the backward drain walks *below* `until_cursor`, + so events above `until_cursor` up to `last_event_at` were already fetched + during the initial drain (when `until_cursor` started at `now`). The + forward catch-up fills from `last_event_at + 1` to `now` — the gap that + formed while caching was off. + +### When to run + +- **On caching service startup** (not `--restart`, which does a full reset). +- The caching service process starts when `caching_enabled` is turned on, + so this covers the "caching was off, now it's on" case. + +### Implementation + +#### 1. Schema: add `last_event_at` column + +In `src/pg_schema.sql` and `src/pg_schema.h`: + +```sql +ALTER TABLE caching_followed_pubkeys + ADD COLUMN IF NOT EXISTS last_event_at BIGINT NOT NULL DEFAULT 0; + +UPDATE caching_followed_pubkeys fp + SET last_event_at = COALESCE( + (SELECT MAX(e.created_at) FROM events e WHERE e.pubkey = fp.pubkey), + 0 + ) + WHERE fp.last_event_at = 0; +``` + +#### 2. New function: `pg_inbox_get_authors_for_catchup()` + +In `caching/src/pg_inbox.c`: + +```c +/* Returns a cJSON array of {pubkey, last_event_at} objects for all + * followed authors where last_event_at > 0. Caller must cJSON_Delete(). + * Returns NULL on error. */ +cJSON* pg_inbox_get_authors_for_catchup(void); +``` + +SQL: +```sql +SELECT pubkey, last_event_at + FROM caching_followed_pubkeys + WHERE last_event_at > 0 + ORDER BY last_event_at ASC +``` + +#### 3. New function: `pg_inbox_update_last_event_at()` + +```c +/* Update last_event_at for a pubkey to the max of current and new value. */ +int pg_inbox_update_last_event_at(const char *pk, long event_created_at); +``` + +SQL: +```sql +UPDATE caching_followed_pubkeys + SET last_event_at = GREATEST(last_event_at, $2::BIGINT) + WHERE pubkey = $1 +``` + +#### 4. New function: `cr_forward_catchup()` + +In a new file `caching/src/forward_catchup.c`: + +```c +/* Run forward catch-up for all followed authors. + * For each author with last_event_at > 0, query events from + * last_event_at + 1 to now and publish them to the sink. + * Returns 0 on success, -1 on error. */ +int cr_forward_catchup(cr_config_t *cfg, + nostr_relay_pool_t *upstream, + cr_sink_t *sink); +``` + +Flow: +1. Call `pg_inbox_get_authors_for_catchup()` to get the list. +2. For each author: + a. Get the author's outbox relays from `caching_backfill_relay_progress` + (any relay, since we just need one good source). + b. Query `authors=[pk], since=last_event_at + 1, until=now, + limit=page_size` on one relay. + c. Publish all returned events to the sink. + d. If events were returned, update `last_event_at` to the max + `created_at` in the batch. If no events, update `last_event_at` + to `now` (so we don't re-query the same empty window). +3. Log: "forward catch-up: N authors checked, M events published". + +#### 5. Update backfill to maintain `last_event_at` + +In `caching/src/backfill.c`, in the page-publishing loop (around line 375): +- Add a `find_newest_created_at()` helper (parallel to the existing + `find_oldest_created_at()`). +- After publishing a page, call + `pg_inbox_update_last_event_at(pk, newest_created_at)`. + +#### 6. Update live subscriber to maintain `last_event_at` + +In `caching/src/live_subscriber.c`, in the event-received callback: +- Extract `created_at` from the event. +- Call `pg_inbox_update_last_event_at(pubkey, created_at)`. + +#### 7. Call from `main.c` + +In `caching/src/main.c`, after relay discovery and followed-set sync, +before the main loop: + +```c +/* Forward catch-up: bridge the gap for all followed authors. */ +if (cfg->backfill.enabled && pg_conn && !restart) { + DEBUG_INFO("forward catch-up: checking for missed events"); + cr_forward_catchup(&cfg, upstream, &sink); +} +``` + +This runs once at startup. It's not throttled — it's a one-time pass. + +### Edge cases + +- **`--restart` flag**: full reset already starts from `now`, so forward + catch-up is skipped. The `last_event_at` seed from the `events` table + will set it to the most recent known event, and the backward drain from + `now` will cover everything. +- **`last_event_at = 0`**: author has no known events. Skip — the backward + drain handles it. +- **Very large gap** (caching off for months): the forward catch-up query + may return many events. Use `limit = page_size` and paginate if needed. + The relay's own dedup (unique index on event ID) handles duplicates. +- **Relay doesn't support `since`**: most Nostr relays support `since`/ + `until` (NIP-01). If ignored, the relay returns all events — dedup + handles it. + +### Files to change + +| File | Change | +|---|---| +| `src/pg_schema.sql` | `ALTER TABLE` add `last_event_at` + seed from `events` | +| `src/pg_schema.h` | Mirror the above | +| `caching/src/forward_catchup.c` | New: `cr_forward_catchup()` | +| `caching/src/forward_catchup.h` | New: declaration | +| `caching/src/pg_inbox.c` | New: `pg_inbox_get_authors_for_catchup()`, `pg_inbox_update_last_event_at()` | +| `caching/src/pg_inbox.h` | New: declarations | +| `caching/src/backfill.c` | Add `find_newest_created_at()`, call `pg_inbox_update_last_event_at()` after each page | +| `caching/src/live_subscriber.c` | Call `pg_inbox_update_last_event_at()` on event receipt | +| `caching/src/main.c` | Call `cr_forward_catchup()` at startup | +| `caching/Makefile` | Add `forward_catchup.c` to sources | + +### Sequencing + +```mermaid +graph TD + A[Caching service starts] --> B{Is --restart?} + B -- Yes --> C[Reset all progress, full re-drain from now] + B -- No --> D[Forward catch-up: all authors with last_event_at > 0] + D --> E[Normal backward-drain backfill loop] + E --> F[Live subscriber: since = now, ongoing] + F --> G[Live subscriber updates last_event_at on each event] + E --> H[Backfill updates last_event_at on each page] diff --git a/plans/profile_cache_plan.md b/plans/profile_cache_plan.md new file mode 100644 index 0000000..99a03a6 --- /dev/null +++ b/plans/profile_cache_plan.md @@ -0,0 +1,708 @@ +# Profile (kind-0) Cache Plan + +Make username/profile resolution a first-class c-relay-pg feature backed by a +dedicated `profiles` table, replacing the three independent ad-hoc +implementations that exist today. Phase 1 (name/metadata cache) is scoped for +implementation now; Phase 2 (image caching) is designed here but deferred. + +## 0. Scope Boundary + +**In scope:** `src/` (schema + C data layer) and `admin/` (the PHP admin). + +**Out of scope:** the top-level [`api/`](../api/index.js) directory — the legacy +embedded JS admin compiled into the binary via +[`src/embedded_web_content.h`](../src/embedded_web_content.h) and served by +[`handle_embedded_file_request()`](../src/api.c:1006). It is being replaced by +`admin/` and is deliberately left untouched. + +Two consequences worth being explicit about: + +1. **Do not "fix" the duplicated logic in `api/index.js`.** It carries its own + copies of the profile-name preference ([`api/index.js:962`](../api/index.js:962)) + and profile-picture handling ([`api/index.js:986`](../api/index.js:986)), plus + the same class of unescaped-`innerHTML` issue described in §2A.2. These are + knowingly left as-is because the whole tree is slated for removal. Note this + means the XSS exposure persists for as long as the embedded UI remains + reachable on the relay's HTTP port — a reason to prioritize retiring `api/`, + tracked separately from this plan. +2. **The C-side changes still matter to both.** [`src/api.c`](../src/api.c) serves + the JSON that the embedded UI consumes, so the batching work in §2.5 benefits + `api/` incidentally. The C API must therefore stay backward-compatible: keep + emitting the existing `name` field (now the resolved value) alongside the new + `display_name` / `best_name` fields, so the legacy frontend keeps working + unchanged until it is deleted. + +--- + +## 1. Current State + +Profile display-name resolution was introduced alongside the caching service and +never generalized. There are **three separate implementations**, none cached: + +### 1.1 C backend — per-pubkey query inside a loop + +[`postgres_db_get_profile_metadata()`](../src/db_ops_postgres.c:2523) runs: + +```sql +SELECT content FROM events WHERE pubkey = $1 AND kind = 0 +ORDER BY created_at DESC LIMIT 1 +``` + +then `cJSON_Parse`es `content` and copies out eight known fields +(`name`, `display_name`, `picture`, `about`, `nip05`, `website`, `lud16`, `lud06`). + +Dispatched through [`db_get_profile_metadata()`](../src/db_ops.c:189); the SQLite +backend is a `NULL` stub ([`src/db_ops.c:389`](../src/db_ops.c:389)). + +Called from three places, **always inside a row loop** — a classic N+1: + +| Call site | Loop over | Queries per response | +|---|---|---| +| [`query_top_pubkeys()`](../src/api.c:503) | top 10 pubkeys | 10 | +| [`src/api.c:1646`](../src/api.c:1646) | top pubkeys (2nd copy) | 10 | +| caching follows status [`src/config.c:4298`](../src/config.c:4298) | every followed pubkey | 1 per follow (unbounded) | + +The `config.c` loop additionally issues a per-pubkey kind-count query +([`src/config.c:4326`](../src/config.c:4326)), an outbox lookup +([`src/config.c:4346`](../src/config.c:4346)) and a relay-progress query +([`src/config.c:4356`](../src/config.c:4356)) — so a relay following 500 authors +performs ~2000 queries to render one admin panel. + +The `display_name || name` preference logic is **duplicated verbatim** at all +three call sites. + +### 1.2 PHP admin — repeated LATERAL joins + +[`admin/api/stats.php:90`](../admin/api/stats.php:90) and +[`admin/api/caching.php:23`](../admin/api/caching.php:23) each hand-roll: + +```sql +LEFT JOIN LATERAL ( + SELECT content FROM events WHERE pubkey = e.pubkey AND kind = 0 + ORDER BY created_at DESC LIMIT 1 +) p ON true +... p.content::json->>'name', p.content::json->>'display_name' +``` + +with the same `$display_name ?: $name` fallback repeated in PHP. `content::json` +re-parses the JSON text on every single admin page poll. The cast is also +fragile: a malformed kind-0 `content` raises a PostgreSQL error that aborts the +whole query (the `try/catch` then silently returns an empty result set). + +### 1.3 Browser JS — fetches from public relays + +[`loadUserProfile()`](../admin/assets/app.js:626) opens WebSocket connections to +**third-party public relays** to fetch the logged-in admin's own kind-0, even +though the relay's own database very likely has it. A third variant of the +name-preference logic lives at [`admin/assets/app.js:650`](../admin/assets/app.js:650) +(`profile.name || profile.display_name || profile.displayName`) — note this one +prefers `name` over `display_name`, the **opposite** of the C and PHP versions, +so the same user can render under two different names in one UI. + +Profile images are hotlinked straight to whatever URL the kind-0 contains +([`admin/assets/app.js:653`](../admin/assets/app.js:653)), which leaks the admin's +IP to arbitrary hosts and breaks silently on dead links. + +### 1.4 Conclusion + +A cache table is clearly warranted: + +- Kind 0 is **replaceable** — the unique index + [`uq_events_replaceable_pubkey_kind`](../src/pg_schema.sql:82) guarantees at + most one kind-0 row per pubkey. A `profiles` table is therefore a strict 1:1 + projection of existing data and can be rebuilt from scratch at any time. No + risk of divergence-by-design. +- Profiles change rarely but are read constantly. +- Parsing JSON at write time (once per profile update) instead of read time + (every page poll × every row) is a large, cheap win. +- One canonical name-preference rule fixes the inconsistency across the three + layers. + +--- + +## 2. Phase 1 — `profiles` Table + +### 2.1 Schema + +Added to [`src/pg_schema.sql`](../src/pg_schema.sql) before the `COMMIT;` at +[line 405](../src/pg_schema.sql:405), and mirrored into +[`src/pg_schema.h`](../src/pg_schema.h) as escaped C string literals. + +```sql +CREATE TABLE IF NOT EXISTS profiles ( + pubkey TEXT PRIMARY KEY, + event_id TEXT NOT NULL, + created_at BIGINT NOT NULL, + name TEXT NOT NULL DEFAULT '', + display_name TEXT NOT NULL DEFAULT '', + about TEXT NOT NULL DEFAULT '', + picture TEXT NOT NULL DEFAULT '', + banner TEXT NOT NULL DEFAULT '', + nip05 TEXT NOT NULL DEFAULT '', + website TEXT NOT NULL DEFAULT '', + lud16 TEXT NOT NULL DEFAULT '', + lud06 TEXT NOT NULL DEFAULT '', + raw_content TEXT NOT NULL DEFAULT '', + parse_ok BOOLEAN NOT NULL DEFAULT TRUE, + updated_at BIGINT NOT NULL DEFAULT EXTRACT(EPOCH FROM NOW())::BIGINT +); + +CREATE INDEX IF NOT EXISTS idx_profiles_name ON profiles(name) + WHERE name <> ''; +CREATE INDEX IF NOT EXISTS idx_profiles_display_name ON profiles(display_name) + WHERE display_name <> ''; +CREATE INDEX IF NOT EXISTS idx_profiles_nip05 ON profiles(nip05) + WHERE nip05 <> ''; +``` + +Notes: +- **`name` and `display_name` are both stored verbatim, always.** Storing both + is free (they are short strings on a table with one row per pubkey), and it + means the question "which field do Nostr clients actually populate?" can be + answered from real data later rather than guessed at now — see + [§2.9](#29-which-field-do-people-actually-use). Neither field is ever + discarded, overwritten by the other, or collapsed into a single value at write + time. +- There is deliberately **no generated `best_name` column.** An earlier draft + had one; it was wrong. A `STORED` generated column freezes the preference rule + into the schema, so changing which field is displayed would require a schema + migration and a full-table rewrite. Display preference is a presentation + decision and belongs at read time. +- `raw_content` keeps the original JSON so non-standard fields (including + `displayName`, the camelCase variant some clients emit — see + [`admin/assets/app.js:650`](../admin/assets/app.js:650)) remain reachable + without re-querying `events`. +- `parse_ok = FALSE` records "we saw a kind-0 but its content was not valid + JSON" — distinct from "no profile at all" (row absent). This makes the + malformed-JSON case explicit instead of an aborted query. +- Empty-string defaults rather than `NULL` keep the C accessors branch-free. + +### 2.1.1 Display preference as configuration + +The preference rule lives in the existing `config` table +([`src/pg_schema.sql:192`](../src/pg_schema.sql:192)) so it can be changed at +runtime through the normal admin config path, with no migration: + +```sql +INSERT INTO config (key, value, data_type, description, category, requires_restart) +VALUES ('profile_name_preference', 'display_name', + 'string', 'Which kind-0 field to prefer for display: display_name or name', + 'display', 0) +ON CONFLICT (key) DO NOTHING; +``` + +Valid values: `display_name` (prefer `display_name`, fall back to `name`) or +`name` (the reverse). Default `display_name`, matching the current C and PHP +behaviour so nothing visibly changes on upgrade. + +Each layer gets **one** resolver that reads this key — replacing the four +scattered inline copies with one function per layer, while keeping the choice +adjustable: + +```c +// Applies profile_name_preference; falls back to the other field when the +// preferred one is empty. Returns "" when neither is set (never NULL). +const char* profile_display_name(const cJSON* profile); +``` + +Every profile object returned to a UI carries `name`, `display_name`, **and** the +resolved `best_name`, so a consumer can render the resolved label while still +having both raw values available. + +### 2.2 Population — PostgreSQL trigger + +A trigger keeps the table correct regardless of which process writes the event +(relay ingest, the caching inbox poller, or a manual `psql` insert), so no +writer can bypass it. + +```sql +CREATE OR REPLACE FUNCTION sync_profile_from_event() RETURNS TRIGGER AS $$ +DECLARE + j JSONB; +BEGIN + IF NEW.kind <> 0 THEN + RETURN NEW; + END IF; + + BEGIN + j := NEW.content::jsonb; + IF jsonb_typeof(j) <> 'object' THEN + j := NULL; + END IF; + EXCEPTION WHEN others THEN + j := NULL; + END; + + INSERT INTO profiles ( + pubkey, event_id, created_at, + name, display_name, about, picture, banner, + nip05, website, lud16, lud06, + raw_content, parse_ok, updated_at + ) VALUES ( + NEW.pubkey, NEW.id, NEW.created_at, + COALESCE(j->>'name',''), + COALESCE(j->>'display_name',''), + COALESCE(j->>'about',''), + COALESCE(j->>'picture',''), + COALESCE(j->>'banner',''), + COALESCE(j->>'nip05',''), + COALESCE(j->>'website',''), + COALESCE(j->>'lud16',''), + COALESCE(j->>'lud06',''), + NEW.content, (j IS NOT NULL), + EXTRACT(EPOCH FROM NOW())::BIGINT + ) + ON CONFLICT (pubkey) DO UPDATE SET + event_id = EXCLUDED.event_id, + created_at = EXCLUDED.created_at, + name = EXCLUDED.name, + display_name = EXCLUDED.display_name, + about = EXCLUDED.about, + picture = EXCLUDED.picture, + banner = EXCLUDED.banner, + nip05 = EXCLUDED.nip05, + website = EXCLUDED.website, + lud16 = EXCLUDED.lud16, + lud06 = EXCLUDED.lud06, + raw_content = EXCLUDED.raw_content, + parse_ok = EXCLUDED.parse_ok, + updated_at = EXCLUDED.updated_at + -- Never let an older kind-0 overwrite a newer one. + WHERE EXCLUDED.created_at >= profiles.created_at; + + RETURN NEW; +END; +$$ LANGUAGE plpgsql; + +DROP TRIGGER IF EXISTS trg_events_sync_profile ON events; +CREATE TRIGGER trg_events_sync_profile +AFTER INSERT OR UPDATE OF content ON events +FOR EACH ROW EXECUTE FUNCTION sync_profile_from_event(); +``` + +The `NEW.kind <> 0` early return means the cost for the 99.9% of events that are +not profiles is one integer comparison — negligible next to the two triggers +already firing on every insert +([`trg_events_set_derived_fields`](../src/pg_schema.sql:160), +[`trg_events_sync_event_tags`](../src/pg_schema.sql:166), +[`trg_notify_event_stored`](../src/pg_schema.sql:283)). + +**Deletion:** add a companion `AFTER DELETE` trigger removing the `profiles` row +when its backing kind-0 is deleted (NIP-09 via [`src/nip009.c`](../src/nip009.c)), +guarded on `OLD.kind = 0 AND profiles.event_id = OLD.id` so a delete of a +superseded event does not drop a current profile. + +### 2.3 One-time backfill + +Existing databases already hold kind-0 events. Following the established +guarded-migration pattern used for `d_tag_value` +([`src/pg_schema.sql:57`](../src/pg_schema.sql:57)), the backfill runs only on +the version transition, not on every boot: + +```sql +DO $$ +BEGIN + IF COALESCE((SELECT value FROM schema_info WHERE key = 'version'), '0') < '6' THEN + INSERT INTO profiles (pubkey, event_id, created_at, name, display_name, + about, picture, banner, nip05, website, lud16, lud06, + raw_content, parse_ok) + SELECT e.pubkey, e.id, e.created_at, + COALESCE(c.j->>'name',''), COALESCE(c.j->>'display_name',''), + COALESCE(c.j->>'about',''), COALESCE(c.j->>'picture',''), + COALESCE(c.j->>'banner',''), COALESCE(c.j->>'nip05',''), + COALESCE(c.j->>'website',''), COALESCE(c.j->>'lud16',''), + COALESCE(c.j->>'lud06',''), + e.content, (c.j IS NOT NULL) + FROM events e + LEFT JOIN LATERAL ( + SELECT CASE WHEN e.content ~ '^\s*\{' THEN + (SELECT x FROM jsonb(e.content::jsonb) AS x) + END AS j + ) c ON true + WHERE e.kind = 0 + ON CONFLICT (pubkey) DO NOTHING; + END IF; +END +$$; +``` + +The `::jsonb` cast can still raise on malformed content. Implementation should +use a small `PL/pgSQL` loop with a per-row `EXCEPTION` block, or a +`safe_jsonb(text)` helper function marked `IMMUTABLE` that returns `NULL` on +parse failure — cleaner and reusable by the trigger too. Prefer the +`safe_jsonb()` helper and use it in both the trigger and the backfill. + +Bump `EMBEDDED_PG_SCHEMA_VERSION` from `"5"` to `"6"` in +[`src/pg_schema.h:4`](../src/pg_schema.h:4) and the `schema_info` insert at +[`src/pg_schema.sql:260`](../src/pg_schema.sql:260). + +`postgres_db_apply_schema()` ([`src/db_ops_postgres.c:138`](../src/db_ops_postgres.c:138)) +runs the whole embedded script at startup, so existing deployments upgrade +automatically. There is no generator script for `pg_schema.h` — it is a +hand-maintained mirror, so **both files must be edited and kept identical**. + +### 2.4 C API + +Replace the single-row helper with a batch-capable pair in +[`src/db_ops.h`](../src/db_ops.h:144): + +```c +// Single profile from the profiles cache. NULL if no profile is cached. +// Result object always contains "name", "display_name" (each possibly "") +// and the resolved "best_name". Caller must cJSON_Delete(). +cJSON* db_get_profile(const char* pubkey); + +// Batch lookup: one query for many pubkeys. Returns an object keyed by +// pubkey hex -> profile object. Pubkeys with no cached profile are absent. +// Caller must cJSON_Delete(). +cJSON* db_get_profiles(const char** pubkeys, int count); +``` + +`db_get_profiles()` issues a single `WHERE pubkey = ANY($1::text[])` query, +collapsing the N+1 loops into one round trip. + +`db_get_profile_metadata()` is retained as a deprecated thin wrapper over +`db_get_profile()` so nothing breaks mid-refactor, then removed once all call +sites are migrated. + +SQLite stubs in [`src/db_ops.c:389`](../src/db_ops.c:389) continue returning +`NULL` — the `profiles` table is PostgreSQL-only, consistent with how the +caching tables are handled. + +### 2.5 C call-site migration + +| File | Change | +|---|---| +| [`src/api.c:502`](../src/api.c:502) | Collect the 10 pubkeys, one `db_get_profiles()` call, then attach `name`/`display_name`/`best_name`/`picture` from the map. Replace the inline preference logic with `profile_display_name()`. | +| [`src/api.c:1645`](../src/api.c:1645) | Same. Consider factoring the two near-identical blocks into one shared `api_attach_profile_fields()` helper. | +| [`src/config.c:4297`](../src/config.c:4297) | Batch all followed pubkeys up front (they are already fully enumerated by the outer query) and look them up from the returned map inside the loop. | + +The `config.c` loop's other per-row queries (kind counts, relay progress) are +out of scope here but are noted as the next optimization target — they can +become two `GROUP BY` queries executed once. + +### 2.6 PHP migration + +Add one helper to [`admin/lib/helpers.php`](../admin/lib/helpers.php): + +```php +/** + * Batch-resolve profiles from the cache. + * Returns [pubkey_hex => ['name'=>..., 'display_name'=>..., + * 'best_name'=>..., 'picture'=>..., 'nip05'=>...]]. + */ +function profile_map(array $pubkeys): array + +/** Applies the profile_name_preference config key. Never returns null. */ +function profile_display_name(array $profile): string +``` + +`profile_map()` is a single parameterized `WHERE pubkey = ANY(...)` query against +`profiles`, returning both raw name fields plus the resolved label. Then: + +- [`admin/api/stats.php:90`](../admin/api/stats.php:90) — drop the + `LEFT JOIN LATERAL` and the `content::json` casts; the top-pubkeys query + becomes a plain `GROUP BY e.pubkey`, and names come from `profile_map()`. + This also removes the `GROUP BY e.pubkey, p.content` grouping-by-a-JSON-blob + wart. +- [`admin/api/caching.php:23`](../admin/api/caching.php:23) — same; or simply + `LEFT JOIN profiles p ON p.pubkey = fp.pubkey` and select `p.name, + p.display_name`, which is a cheap indexed join now that no subquery or parsing + is involved. +- Replace both copies of the `$display_name ?: $name` fallback with + `profile_display_name()`. + +### 2.7 JS migration + +- Add a read-only admin endpoint (`admin/api/profile.php?pubkey=...`) returning + the cached profile. +- [`loadUserProfile()`](../admin/assets/app.js:626) tries that endpoint first and + only falls back to public relays if the relay has no cached kind-0 for the + logged-in admin (a real possibility for a fresh relay), then keeps the existing + render path. +- Consume the server-provided `best_name` instead of re-deriving a preference in + the browser, so all three layers finally agree and the JS copy at + [`admin/assets/app.js:650`](../admin/assets/app.js:650) — which currently + prefers `name`, the opposite of C and PHP — stops disagreeing. Keep + `displayName` (camelCase) handling only in the public-relay fallback path, + where raw client JSON is parsed directly. + +--- + +## 2A. Hostile Characters in Names + +Nostr names are attacker-controlled free-form UTF-8. The guiding principle: + +> **Store bytes verbatim. Neutralize at the point of rendering.** + +Sanitizing at write time would be wrong — it is lossy, irreversible, and the +"correct" transformation differs per output context (HTML body vs. attribute vs. +JSON vs. CSV vs. terminal log). A name mangled on the way into the cache can +never be recovered, and the cache would no longer faithfully mirror the kind-0 +event. So the cache table stores exactly what the user published. + +**But "it's a frontend issue" is only ~90% true.** There is one true storage-layer +concern, and one place where the current frontend is actively unsafe. + +### 2A.1 Storage-layer concern: NUL bytes (must handle at write time) + +PostgreSQL `TEXT` **cannot** store `U+0000`. A kind-0 containing `\u0000` in its +JSON string makes `->>` yield a value that PostgreSQL refuses to store, raising +`ERROR: unsupported Unicode escape sequence` — which would abort the trigger and +therefore **reject the whole event insert**. That turns a cosmetic nuisance into +a denial-of-service on event ingestion. + +This is not a presentation problem and must be handled in the trigger: + +```sql +-- Strip NUL only; everything else is preserved byte-for-byte. +replace(COALESCE(j->>'name',''), E'\\u0000', '') +``` + +Implement as a small `sanitize_pg_text(text)` helper used for every extracted +string column. It removes **only** characters PostgreSQL structurally cannot +store — not "weird" characters generally. Invalid UTF-8 byte sequences are +already rejected earlier by `cJSON` parsing and by the `safe_jsonb()` helper +(the row lands with `parse_ok = FALSE`), so no additional handling is needed. + +A defensive `byte_size` guard is also worth adding: cap stored name fields at a +sane length (e.g. 1 KB) so a megabyte-long "name" cannot bloat the table or the +admin JSON payloads. Truncation is recorded in `raw_content`, which keeps the +full original. + +### 2A.2 Live vulnerability: stored XSS in the admin UI + +This must be fixed as part of this work, because the whole point of the change is +to route more user-controlled names into more admin pages. + +[`admin/assets/app.js:142`](../admin/assets/app.js:142) interpolates the name +directly into `innerHTML`: + +```js +tbody.innerHTML = d.top_pubkeys.map((p, i) => + `${i+1}${p.name || 'unknown'}...` +``` + +and [`admin/assets/app.js:411`](../admin/assets/app.js:411) does the same for the +caching-follows table. A user who sets their kind-0 `name` to +`` achieves **script execution in the relay +administrator's authenticated browser session** merely by posting enough events +to appear in the top-pubkeys list. No privileged access is required. + +The codebase is already inconsistent about this: the header name at +[`app.js:652`](../admin/assets/app.js:652) correctly uses `textContent` and is +safe. The table renderers are not. + +**Fix:** add an escaping helper and apply it to every interpolated +user-controlled value in `innerHTML` template strings: + +```js +const esc = (s) => String(s ?? '').replace(/[&<>"']/g, + c => ({'&':'&','<':'<','>':'>','"':'"',"'":'''}[c])); +``` + +Auditing the surrounding rows shows the same pattern applied to other +user-controlled fields — event `content` ([`app.js:380`](../admin/assets/app.js:380)), +DM content ([`app.js:441`](../admin/assets/app.js:441)), config values +([`app.js:219`](../admin/assets/app.js:219)), and auth-rule `pattern_value` +([`app.js:251`](../admin/assets/app.js:251)) — so the sweep should cover all of +them, not just names. Preferring `textContent` / `createElement` over `innerHTML` +in these renderers is the more durable fix where it is not too invasive. + +Note the PHP side is already correct: [`e()`](../admin/lib/helpers.php:9) wraps +`htmlspecialchars(..., ENT_QUOTES, 'UTF-8')` and is used for server-rendered +output. The gap is purely in the JS-built tables. + +### 2A.3 Presentation-layer nuisances (frontend, cosmetic) + +These stay unsanitized in the database and are handled with CSS/formatting: + +| Issue | Effect | Mitigation | +|---|---|---| +| Bidi overrides (`U+202E` RTL) | Reverses surrounding text, spoofs other names | Render names in a `` element — purpose-built for exactly this, isolates bidi without altering the value | +| Zalgo / stacked combining marks | Vertical overflow past row bounds | `overflow: hidden` + fixed line-height on the name cell | +| Zero-width chars (`U+200B`, `U+FEFF`) | Invisible; two names look identical | Optional: reveal-on-hover indicator; do not strip | +| Newlines / tabs | Break single-line table layout | CSS `white-space: nowrap` + `text-overflow: ellipsis` | +| Very long names | Blow out column width | CSS `max-width` + ellipsis (value stays intact in a `title` tooltip) | +| Emoji / astral-plane chars | None — legitimate usage | Nothing; ensure JS length math uses code points, not UTF-16 units, when truncating | + +Truncation in JS deserves care: `substring()` on a UTF-16 string can split a +surrogate pair and emit a replacement glyph. Use `Array.from(str).slice(0, n)` or +CSS-based ellipsis (preferred — no string surgery at all). + +### 2A.4 Terminal/log safety + +Names flow into `DEBUG_*` output. ANSI escape sequences in a name can manipulate +a maintainer's terminal. Log rendering should escape non-printable bytes, or +simply avoid logging profile names at all — the pubkey is the useful identifier +in logs anyway. + +### 2.9 Which field do people actually use? + +Storing both fields turns this into an empirical question rather than a guess. +Once the table is populated, one aggregate query answers it against real data +from your relay's own corpus: + +```sql +SELECT count(*) FILTER (WHERE name <> '' AND display_name <> '') AS both, + count(*) FILTER (WHERE name <> '' AND display_name = '') AS name_only, + count(*) FILTER (WHERE name = '' AND display_name <> '') AS display_only, + count(*) FILTER (WHERE name = '' AND display_name = '') AS neither, + count(*) FILTER (WHERE name <> '' AND display_name <> '' + AND name <> display_name) AS both_differ, + count(*) AS total + FROM profiles; +``` + +`both_differ` is the number that matters: it counts profiles where the preference +setting actually changes what gets rendered. If it is near zero, the setting is +academic and either default is fine. If it is large, the setting earns its keep. + +Worth surfacing as a small panel on the admin stats page — it is one cheap +aggregate over a table with one row per pubkey, and it makes +`profile_name_preference` self-documenting: you can see the impact of the choice +before making it. Add it once the table has accumulated real data. + +### 2.8 Verification + +- Fresh database: relay starts, `profiles` exists, posting a kind-0 populates + exactly one row with `name` and `display_name` both preserved verbatim. +- Upgrade path: start against a database with pre-existing kind-0 events, confirm + the backfill fills every row once and does **not** re-run on the next restart. +- Replaceable-update: publish a newer kind-0, confirm the row updates; replay an + older one, confirm the row does **not** regress. +- Malformed content: store a kind-0 whose content is not JSON; confirm the insert + still succeeds, `parse_ok = FALSE`, and the admin pages render without error. +- **NUL byte:** publish a kind-0 whose `name` contains `\u0000`; confirm the + event is still accepted, the profile row is created, and the relay does not + error. This is the regression test for the ingest-DoS path in §2A.1. +- **XSS:** publish a kind-0 with `name` set to + ``, load the stats and caching pages, and + confirm the markup is rendered as visible text and `window.__xss` is + undefined. +- **Bidi/Zalgo:** publish names containing `U+202E` and stacked combining marks; + confirm table layout and neighbouring rows are unaffected. +- Consistency: the same pubkey shows an identical name in the stats table, the + caching follows table, and the header. +- Query-count check: confirm the top-pubkeys API response issues one profile + query rather than ten. +- Both-fields check: query `profiles` for a pubkey whose kind-0 sets `name` and + `display_name` to different values; confirm both are stored distinctly. + +--- + +## 3. Phase 2 — Image Caching (design only, deferred) + +Recorded here so Phase 1's schema does not need reworking later. + +### 3.1 Motivation + +Today the admin UI hotlinks `picture` URLs directly +([`admin/assets/app.js:653`](../admin/assets/app.js:653)). Problems: the admin's +browser reveals its IP to arbitrary third-party hosts on every page load; dead +or slow hosts degrade the UI; images can be arbitrarily large; there is no way to +show avatars offline. + +### 3.2 Proposed schema + +```sql +CREATE TABLE IF NOT EXISTS profile_images ( + pubkey TEXT PRIMARY KEY, + source_url TEXT NOT NULL, + mime_type TEXT NOT NULL DEFAULT '', + byte_size INTEGER NOT NULL DEFAULT 0, + sha256 TEXT NOT NULL DEFAULT '', + etag TEXT NOT NULL DEFAULT '', + image_data BYTEA, + fetch_state TEXT NOT NULL DEFAULT 'pending', + fetch_attempts INTEGER NOT NULL DEFAULT 0, + last_error TEXT, + fetched_at BIGINT NOT NULL DEFAULT 0, + updated_at BIGINT NOT NULL DEFAULT EXTRACT(EPOCH FROM NOW())::BIGINT, + CHECK (fetch_state IN ('pending','ok','failed','skipped','too_large')) +); +CREATE INDEX IF NOT EXISTS idx_profile_images_pending + ON profile_images(fetch_state, fetch_attempts) WHERE fetch_state = 'pending'; +``` + +`BYTEA` in PostgreSQL rather than the filesystem keeps backup/restore and the +container story single-artifact, matching how everything else in this project is +stored. Avatars are small; a cap keeps total size bounded. + +### 3.3 Fetch worker + +`libcurl` is already linked ([`Makefile:6`](../Makefile:6)) but currently unused +in `src/`. A worker modeled on +[`caching_inbox_poller.c`](../src/caching_inbox_poller.c) — two-state +idle/active polling, config-gated, off the main libwebsockets thread — would: + +1. Enqueue `pending` rows when `profiles.picture` changes (trigger or poll). +2. Fetch with a hard timeout, a max-bytes ceiling (~256 KB), redirect limit, + and `Content-Type` allow-list (`image/png|jpeg|webp|gif`). +3. Send `If-None-Match` on refresh, honour `304`. +4. Exponential backoff, capped `fetch_attempts`, terminal `failed`. + +New config keys following existing naming: `profile_image_cache_enabled` +(default **off**), `profile_image_max_bytes`, `profile_image_refresh_days`, +`profile_image_fetch_concurrency`. + +### 3.4 Serving + +A relay HTTP route `/avatar/` handled in +[`handle_embedded_file_request()`](../src/api.c:1006) (called from +[`src/websockets.c:1261`](../src/websockets.c:1261)), returning the bytes with a +long `Cache-Control` and an `ETag`, falling back to a generated identicon or +`404` when uncached. The UI then only ever loads images from the relay's own +origin. + +### 3.5 Risks to weigh before committing + +- **Outbound HTTP from the relay** is a new capability and a real SSRF surface — + needs a private-IP/localhost block-list and scheme restriction. This is the + main reason to keep it default-off and deferred. +- Database growth: bounded by `max_bytes × profile count`; needs a documented + ceiling and a prune path. +- Content risk: the relay would be re-serving arbitrary third-party bytes under + its own origin. Strict `Content-Type` enforcement plus + `Content-Security-Policy` / `X-Content-Type-Options: nosniff` on the route. + +--- + +## 4. Files Touched (Phase 1) + +| File | Change | +|---|---| +| [`src/pg_schema.sql`](../src/pg_schema.sql) | `profiles` table (both name fields, no generated column), `safe_jsonb()`, `sanitize_pg_text()`, sync + delete triggers, guarded backfill, `profile_name_preference` config default, version → 6 | +| [`src/pg_schema.h`](../src/pg_schema.h) | Mirror the above as C string literals; bump `EMBEDDED_PG_SCHEMA_VERSION` | +| [`src/db_ops.h`](../src/db_ops.h) | Declare `db_get_profile()` / `db_get_profiles()` | +| [`src/db_ops_postgres.h`](../src/db_ops_postgres.h) | Declare the postgres implementations | +| [`src/db_ops_postgres.c`](../src/db_ops_postgres.c) | Implement both against `profiles`; retire the events-table query | +| [`src/db_ops.c`](../src/db_ops.c) | Dispatch entries + SQLite stubs | +| [`src/config.h`](../src/config.h) / [`src/config.c`](../src/config.c) | `profile_display_name()` resolver; batch profile lookup in the caching follows loop | +| [`src/api.c`](../src/api.c) | Batch both top-pubkeys loops; shared attach helper emitting `name` + `display_name` + `best_name` | +| [`admin/lib/helpers.php`](../admin/lib/helpers.php) | `profile_map()` + `profile_display_name()` | +| [`admin/api/stats.php`](../admin/api/stats.php) | Use `profile_map()`; drop LATERAL + JSON casts | +| [`admin/api/caching.php`](../admin/api/caching.php) | Join `profiles`; drop LATERAL + JSON casts | +| `admin/api/profile.php` | New: single-profile lookup endpoint | +| [`admin/assets/app.js`](../admin/assets/app.js) | **`esc()` helper + XSS sweep of all `innerHTML` renderers (§2A.2)**; local-first profile load; consume server `best_name` | +| [`admin/assets/index.css`](../admin/assets/index.css) | `nowrap` / `overflow` / `max-width` + ellipsis on name cells (§2A.3) | +| `tests/` | New script covering populate / upgrade / replace / malformed / NUL / XSS / bidi cases | + +--- + +## 5. Sequencing + +```mermaid +graph TD + A[Add profiles table + safe_jsonb + sanitize_pg_text + triggers to pg_schema.sql] --> B[Mirror into pg_schema.h and bump version to 6] + B --> C[Guarded one-time backfill + profile_name_preference config default] + C --> D[Implement db_get_profile and db_get_profiles] + D --> E[Migrate api.c and config.c to batch lookups] + E --> F[Add profile_map helper and migrate PHP endpoints] + F --> X[Fix stored XSS: esc helper and innerHTML sweep in app.js] + X --> G[Add profile.php endpoint and update app.js profile load] + G --> Y[CSS hardening for hostile name rendering] + Y --> Z[Add name-field usage panel to stats page] + G --> H[Tests: populate, upgrade, replace, malformed, consistency] + H --> I[Phase 2 image caching - deferred] +``` diff --git a/plans/server_side_ascii_chart_plan.md b/plans/server_side_ascii_chart_plan.md new file mode 100644 index 0000000..a621270 --- /dev/null +++ b/plans/server_side_ascii_chart_plan.md @@ -0,0 +1,233 @@ +# Server-Side ASCII Chart Plan + +## Goal + +Replace the client-side `text_graph.js` ASCII chart with a **server-side PHP renderer** that produces the ASCII X-bar chart string. The chart is served from a **dedicated plain-text endpoint** (`api/chart.php`) that works both in the browser (injected into a `
`) and in the terminal via `curl` — the ASCII art renders correctly either way. + +Four time ranges, each with its own bin size and refresh/caching strategy: + +| Range | Span | Bin size | Bins | Refresh | Cache TTL | +|--------|-------------|------------|------|------------------|------------| +| Hour | last 1h | 10 seconds | 360 | every 10s (live) | none | +| Day | last 24h | 5 minutes | 288 | every 10s* | 1 hour | +| Month | last 30d | 1 hour | 720 | every 10s* | 1 day | +| Year | last 365d | 1 day | 365 | every 10s* | 1 month | + +\* The client polls every 10s, but the server only re-runs the expensive query when the cache expires. Between cache expirations, the cached ASCII string is returned instantly. + +## Architecture + +```mermaid +flowchart TD + subgraph Clients + T[Terminal — curl] + W[Web UI — app.js] + end + + T -->|GET chart.php?range=hour| EP[chart.php] + W -->|GET chart.php?range=hour| EP + T -->|GET chart.php?range=day| EP + W -->|GET chart.php?range=day| EP + + EP --> C{Cache valid?} + C -->|Yes| Return[Return cached ASCII string] + C -->|No| Query[Run GROUP BY binning query] + Query --> Render[render_ascii_chart in lib/ascii_chart.php] + Render --> CacheWrite[Write to cache file] + CacheWrite --> Return + + Return -->|text/plain; charset=utf-8| T + Return -->|text/plain; charset=utf-8| W + + subgraph "Cache files (admin2/cache/)" + H[chart_hour.txt — never cached] + D[chart_day.txt — TTL 1h] + M[chart_month.txt — TTL 1d] + Y[chart_year.txt — TTL 1mo] + end +``` + +## Components + +### 1. PHP ASCII Chart Renderer — `admin2/lib/ascii_chart.php` + +A pure function that takes an array of bin counts and produces the ASCII X-bar chart string. Mirrors the layout of the original `text_graph.js`: + +``` + New Events + + 11 | X + 10 | X X + 9 | X X X X + 8 | X X X X X X X + 7 | X X X X X X X X X X + 6 | X X X X X X X X X X X X X + 5 | X X X X X X X X X X X X X X X + 4 | X X X X X X X X X X X X X X X X X + 3 |X X X X X X X X X X X X X X X X X X X + 2 |X X X X X X X X X X X X X X X X X X X + 1 |X X X X X X X X X X X X X X X X X X X + +---------------------------------------- + 0s 50s 100s 150s 200s 250s 300s +``` + +**Function signature:** +```php +function render_ascii_chart(array $bins, array $options = []): string +``` + +**Options:** +- `title` (string, default `'New Events'`) +- `max_height` (int, default `11`) — chart height in rows +- `x_axis_label` (string, default `''`) +- `bin_duration` (int, seconds) — for X-axis elapsed-time labels +- `label_interval` (int, default `5`) — label every N bins + +**Algorithm** (same as `text_graph.js` render method): +1. `max_count = max($bins)`; `scale_factor = max(1, ceil(max_count / max_height))` +2. For each row from `max_height` down to `1`: + - Y-axis label = `(row - 1) * scale_factor + 1`, right-padded to 3 chars + - For each bin: if `ceil(count / scale_factor) >= row` → `X`, else space +3. X-axis: `+` followed by dashes (one per bin) +4. X-axis labels: elapsed time every `label_interval` bins, formatted as `Ns` / `Nm` / `Hh` / `Dd` depending on magnitude + +### 2. Binning SQL Queries — in `stats.php` + +Each range uses a `FLOOR((created_at - epoch) / bin_size)` GROUP BY query. The `idx_events_created_at` index makes these fast. + +**Hour (live, no cache):** +```sql +SELECT FLOOR((created_at - :epoch) / 10)::INT AS bin, COUNT(*) AS cnt +FROM events +WHERE created_at >= :epoch +GROUP BY bin +ORDER BY bin; +``` +- `epoch = now - 3600`, `bin_size = 10s`, produces up to 360 bins +- Runs on every 10s poll (cheap: only scans last hour, indexed) + +**Day (cache TTL 1h):** +```sql +SELECT FLOOR((created_at - :epoch) / 300)::INT AS bin, COUNT(*) AS cnt +FROM events +WHERE created_at >= :epoch +GROUP BY bin +ORDER BY bin; +``` +- `epoch = now - 86400`, `bin_size = 300s` (5 min), produces up to 288 bins + +**Month (cache TTL 1d):** +```sql +SELECT FLOOR((created_at - :epoch) / 3600)::INT AS bin, COUNT(*) AS cnt +FROM events +WHERE created_at >= :epoch +GROUP BY bin +ORDER BY bin; +``` +- `epoch = now - 2592000`, `bin_size = 3600s` (1h), produces up to 720 bins + +**Year (cache TTL 1 month):** +```sql +SELECT FLOOR((created_at - :epoch) / 86400)::INT AS bin, COUNT(*) AS cnt +FROM events +WHERE created_at >= :epoch +GROUP BY bin +ORDER BY bin; +``` +- `epoch = now - 31536000`, `bin_size = 86400s` (1 day), produces up to 365 bins + +**Bin array assembly:** Query returns only non-empty bins. PHP fills a fixed-length array (all zeros) and overlays the counts at the correct positions, so empty time slots show as blank columns — the chart always advances in time. + +### 3. File-Based Cache — `admin2/cache/` + +Simple file cache with TTL. No APCu/Redis dependency. + +```php +function get_cached_chart(string $range): ?string +function set_cached_chart(string $range, string $ascii): void +``` + +- Cache files: `admin2/cache/chart_{range}.txt` +- TTLs: `hour` = 0 (never cache), `day` = 3600, `month` = 86400, `year` = 2592000 +- Check: `filemtime($file) > time() - $ttl` +- Directory `admin2/cache/` created automatically with `mkdir(..., 0775, true)` + +### 4. Standalone Chart Endpoint — `admin2/api/chart.php` + +A dedicated plain-text endpoint that returns the raw ASCII chart string. Works in both the browser and the terminal. + +**Request:** `GET api/chart.php?range=hour|day|month|year` + +**Response:** `Content-Type: text/plain; charset=utf-8` — just the ASCII chart string, no JSON wrapper. + +**Terminal usage:** +```bash +curl http://localhost:8088/api/chart.php?range=hour +curl http://localhost:8088/api/chart.php?range=day +curl http://localhost:8088/api/chart.php?range=month +curl http://localhost:8088/api/chart.php?range=year +``` + +**Logic:** +1. Read `range` query param (default: `hour`) +2. Validate against allowed ranges (`hour`, `day`, `month`, `year`) +3. Check cache: if valid, return cached string immediately +4. If cache miss/expired: run the binning SQL query, fill the bin array, call `render_ascii_chart()`, write to cache, return the string +5. Set `Content-Type: text/plain; charset=utf-8` header + +**`stats.php` is unchanged** — it continues to return the existing JSON stats (numbers only). The chart is a completely separate endpoint, keeping concerns cleanly separated. + +### 5. Frontend Changes + +#### `admin2/index.php` +- Replace the single chart div with a chart container + range selector tabs: + ```html +
+ + + + +
+
Loading chart...
+ ``` +- Remove `