Commit graph

172 commits

Author SHA1 Message Date
Mario Zechner
de8952d34a feat: highlight session cards with orange border when 'esc to interrupt' is detected
- Add checkForEscPrompt() method to scan buffer content on each update
- Emit 'esc-prompt-change' event when prompt presence changes
- Apply orange border to session card when prompt is detected
- Case-insensitive search for 'esc to interrupt' text

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-06-20 05:07:56 +02:00
Mario Zechner
3ec549344b fix: improve terminal buffer fitting algorithm
- Properly measure character width at 14px and scale proportionally
- Calculate visible rows based on container height
- Show bottom N lines that fit in the viewport
- Remove overly conservative character width estimates

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-06-20 04:54:06 +02:00
Mario Zechner
89982e9bdf feat: implement WebSocket-based real-time buffer updates
- Add /buffers WebSocket endpoint with binary protocol
- Replace polling with push-based updates in vibe-terminal-buffer
- Add buffer change notifications to TerminalManager
- Remove pollInterval property from components
- Optimize network traffic by only sending updates on changes

Binary protocol: [0xBF magic][4 bytes: session ID length][session ID][buffer data]

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-06-20 04:36:23 +02:00
Mario Zechner
deb3935172 Implement optimized binary format for terminal buffer transmission
- Switch from JSON to binary format for buffer data transfer
- Optimize encoding with run-length encoding for empty rows
- Reduce data size with efficient cell encoding (1 byte for spaces, variable for complex cells)
- Support both palette and RGB colors with minimal overhead
- Pre-calculate exact buffer sizes to avoid allocations

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-06-20 03:56:00 +02:00
Mario Zechner
35755d8376 fix: remove debug logging from vibe-terminal-buffer
🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-06-20 03:49:02 +02:00
Mario Zechner
faba4b1407 refactor: simplify vibe-terminal-buffer to always fit horizontally
- Remove fontSize and fitHorizontally properties as they're no longer needed
- Always auto-scale font size to fit terminal width in container
- Simplify dimension calculation logic
- Remove unused props from session-card component
- Maintain bottom-aligned terminal view with proper scaling

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-06-20 03:48:08 +02:00
Mario Zechner
dbbaaa8442 fix: remove viewportY=0 to show bottom portion of terminal
- Let server decide which portion of buffer to return
- Server defaults to showing bottom portion with prompt
- Only request the number of lines that fit in viewport

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-06-20 03:25:50 +02:00
Mario Zechner
fb7d1b2dc0 feat: ensure last non-empty line is always visible in terminal buffer
- Show bottom portion of buffer when content exceeds viewport
- Keep all content visible when it fits within viewport
- Maintain fitHorizontally mode to show all content scaled
- Calculate proper start index to show the most relevant content

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-06-20 03:24:25 +02:00
Mario Zechner
6479168ca5 fix: change terminal buffer background to black
- Replace dark gray (#1e1e1e) with pure black background
- Match the expected terminal appearance

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-06-20 03:21:47 +02:00
Mario Zechner
3bf543e694 fix: resolve terminal rendering issues in vibe-terminal-buffer
- Move terminal color definitions to shared CSS in input.css
- Use bright color palette for dark backgrounds
- Switch from Lit template rendering to direct innerHTML for terminal content
- Add display: inline-block to terminal-char for proper rendering
- Remove redundant style definitions from terminal.ts
- Fix issue where Lit's template system was interfering with terminal output

The key fix was using innerHTML directly instead of Lit's template system for
the terminal content, matching the approach used in terminal.ts.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-06-20 03:21:16 +02:00
Mario Zechner
01df54c63b fix: add terminal styles to vibe-terminal-buffer component
- Add explicit terminal character styles to ensure proper rendering
- Include style definitions for bold, italic, underline, dim, strikethrough
- Ensure CSS variables are properly inherited from parent scope
- Fix text rendering issues where colors appeared gray

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-06-20 02:58:44 +02:00
Mario Zechner
c738ec0f57 feat: trim blank cells from end of each line
- Reduce data transfer by omitting trailing blank cells
- Keep at least one cell per line to maintain structure
- Handle empty lines efficiently with single space cell
- Add fallback rendering for completely empty lines

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-06-20 02:47:14 +02:00
Mario Zechner
4a9ee48427 feat: implement fitHorizontally mode and buffer trimming
- Add fitHorizontally mode to vibe-terminal-buffer component
- Scale font size to fit entire terminal width when enabled
- Trim blank lines from bottom of buffer to reduce data transfer
- Always show content from top down (not centered on cursor)
- Match behavior of terminal.ts fitTerminal implementation

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-06-20 02:45:13 +02:00
Mario Zechner
aa0658acc7 Fetch at least one full terminal screen in buffer component
The component was only fetching as many lines as could fit in its container,
which could miss important context. Now it fetches at least one full terminal
screen worth of lines (stats.rows) to ensure we capture the complete visible
terminal state.

Also improved rendering to show the bottom portion when we have more lines
than can fit in the display area.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-06-20 02:33:23 +02:00
Mario Zechner
ef7a679c2b Fix binary buffer encoding to support large terminals
The binary encoding was using 16-bit unsigned integers which failed when:
- Terminal has many rows (>65k)
- Cursor is above the viewport (negative relative position)

Changes:
- Upgrade to version 2 of the binary format
- Use 32-bit integers for dimensions and positions
- Use signed integers for viewport/cursor positions
- Update header size from 16 to 32 bytes
- Update documentation to reflect new format

This fixes the issue where cursorY could be negative when the cursor
is above the visible viewport (e.g., cursorY=0, viewportY=46 results
in relative cursorY=-46).

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-06-20 02:31:15 +02:00
Mario Zechner
b041743287 Add vibe-terminal-buffer component for efficient session previews
Replace terminal.ts in session-card with new buffer-based component that:
- Fetches terminal buffer snapshots via JSON API
- Polls every second only when content changes (checks lastModified)
- Automatically calculates lines needed based on container height
- Reuses terminal rendering styles and logic

Changes:
- Create terminal-renderer.ts with shared rendering logic for both components
- Add vibe-terminal-buffer component that works with buffer API
- Update session-card to use vibe-terminal-buffer instead of vibe-terminal
- Add terminal-line CSS for proper styling
- Fix color handling in terminal-manager (-1 means default color)
- Add debug logging to help diagnose rendering issues

The new approach is more efficient - no cast file parsing, just direct
buffer snapshots from the server.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-06-20 02:19:09 +02:00
Mario Zechner
00602e3218 Implement server-side terminal buffer management with xterm.js headless
Major architectural change: replaced tail -f streaming with direct file watching
and server-side terminal state management for better performance and efficiency.

Key changes:
- Add StreamWatcher class using fs.watch() instead of tail -f process
  - Benchmarks showed fs.watch() is faster and more efficient
  - Handles multiple SSE clients per session without duplicate processes
  - Streams existing content then watches for new data

- Add TerminalManager class for server-side xterm.js instances
  - Maintains headless terminal state per session
  - Watches stream files and feeds data into terminals
  - Provides binary buffer snapshots on demand

- Add new /api/sessions/{id}/buffer endpoint
  - Returns efficient binary terminal buffer snapshots
  - Supports viewportY and lines parameters for partial updates
  - Uses run-length encoding for compression

- Create comprehensive binary format documentation (snapshot-format.md)
  - 16-byte header with dimensions and cursor position
  - Variable-length cell encoding with UTF-8 and RGB support
  - ~75% size reduction compared to JSON

- Fix cmdline.join() error with defensive programming
  - Handle cases where cmdline might not be an array

This enables session-list.ts to efficiently show terminal states without
overwhelming client/server resources.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-06-20 01:56:20 +02:00
Mario Zechner
6391605267 Reorder ctrl key dialog buttons for better UX
- Move CANCEL button to the left (renamed from CLOSE)
- Keep CLEAR button in the middle when sequence exists
- Move SEND button to the right when sequence exists
- Follows standard UI convention with cancel actions on left, primary actions on right

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-06-19 22:55:37 +02:00
Mario Zechner
3c081f90f4 Less stream logging in Node. 2025-06-19 22:51:38 +02:00
Mario Zechner
17f46c84c8 Fix terminal paste functionality and standardize resize endpoint field names
- Made terminal container focusable to receive paste events without clipboard API
- Added tabindex="0" and paste event handling to terminal component
- Terminal now dispatches custom 'terminal-paste' events with clipboard text
- Session view listens for paste events and sends text to terminal session
- Standardized resize endpoint field names across all servers (Rust, Go, Node.js)
- Changed from width/height to cols/rows for consistency
- Removed custom clipboard handling code that required permissions
- Standard Ctrl+V/Cmd+V paste now works without permission prompts
- Maintained PID copying functionality in session cards

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-06-19 22:28:19 +02:00
Mario Zechner
bbd079c052 Fix terminal keyboard event handling to allow browser shortcuts
The terminal component was aggressively preventing default on ALL keyboard events, blocking important browser shortcuts like F12 (DevTools), Ctrl+C/Ctrl+V (copy/paste), and Ctrl+F (find).

Updated the keyboard handler to:
- Allow F12 and Ctrl+Shift+I/Cmd+Alt+I for DevTools
- Allow common browser shortcuts like Ctrl+A, Ctrl+F, Ctrl+R, etc.
- Allow Alt+Tab and Cmd+Tab for window switching
- Only preventDefault on keys that are actually handled by the terminal

This preserves terminal functionality while restoring essential browser shortcuts.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-06-19 22:06:23 +02:00
Mario Zechner
5ce76f828f No more artifiial waiting, just start streaming. 2025-06-19 21:26:09 +02:00
Mario Zechner
2040e6e7b4 Removed expand toggle in session-view header. 2025-06-19 21:25:49 +02:00
Mario Zechner
607090a1d3 Pty improvements 2025-06-19 14:07:59 +02:00
Mario Zechner
812e0615cc Force fwd.ts to always use node-pty, never tty-fwd fallback
- Set implementation to 'node-pty' and disable fallback to tty-fwd
- Remove conditional logic since we always have direct PTY access
- Simplify input handling to always use direct PTY write
- Remove fallback session status monitoring
- fwd.ts is the Node.js replacement for tty-fwd, should never use tty-fwd itself

This makes fwd.ts behavior consistent and eliminates complexity from fallback paths.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-06-19 07:09:01 +02:00
Mario Zechner
a068d64ebc Improve fwd.ts exit detection using direct PTY process events
- Use PTY process onExit handler for immediate exit detection instead of asciinema stream monitoring
- Remove redundant asciinema exit event parsing - that's output format, not process state
- Make session status polling a fallback only when direct PTY access isn't available
- This provides faster, more reliable exit detection at the source (PTY process)

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-06-19 07:06:41 +02:00
Mario Zechner
dc562f5f9e Fix fwd.ts hanging on process exit and remove redundant control pipe creation
- Add proper cleanup of all intervals and FIFO streams on exit
- Detect exit events directly from asciinema stream for faster response
- Reduce session monitoring polling from 1000ms to 500ms
- Remove redundant createControlPipeForExternalSession function
- fwd.ts now creates its own control pipe, PtyManager no longer needs to create them

This should eliminate the hanging issue when exiting processes wrapped with fwd.ts.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-06-19 07:01:36 +02:00
Mario Zechner
69e3a6d47e Fix critical input performance bottlenecks causing 1-2 second delays
- Replace blocking spawnSync calls with direct stdin pipe writes
- Change from 100ms polling to fs.watchFile for immediate file notifications
- Use appendFileSync instead of writeFileSync for better performance
- Add platform-specific key mapping for tty-fwd input path
- Reduce polling interval from 100ms to 50ms for watchFile

This eliminates the 5-second timeout blocking and improves input responsiveness from 1-2 seconds to near-instantaneous.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-06-19 06:42:03 +02:00
Mario Zechner
1c52ed79d8 Fix Windows enter key mapping to use carriage return
- Change enter key from \n (line feed) to \r (carriage return) on Windows
- Maintains \n for Unix/macOS compatibility
- Fixes enter key behavior in Windows terminals

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-06-19 06:38:10 +02:00
Mario Zechner
64e55147e5 Implement cross-platform control pipe and direct PTY access for fwd.ts
- Add platform detection for Windows vs Unix FIFO handling
- Implement polling fallback for Windows control pipes
- Add direct PTY process access for faster keyboard input
- Fix duplicate cleanup handlers and formatting issues

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-06-19 06:35:33 +02:00
Mario Zechner
eaf161706c Fix TypeScript type errors in control and stdin stream handling
- Add proper type guards for control message fields (cols, rows, signal)
- Handle string | Buffer types for stream data events correctly
- Fix null assignment issue in control pipe creation
- Add type conversion for chunk data in FIFO streams

All TypeScript errors resolved.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-06-19 06:28:53 +02:00
Mario Zechner
c86c514030 Fix control pipe to use FIFO streaming and rename to 'control'
- Create control as FIFO instead of regular file using mkfifo
- Use same read+write streaming approach as stdin FIFO
- Rename 'control-pipe' to 'control' for consistency
- Replace polling mechanism with continuous FIFO streaming
- Update session type to use 'control' field name
- Fix PtyManager to reference correct control field

This should fix the issue where resize only worked once due to
control pipe closing after first write.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-06-19 06:25:25 +02:00
Mario Zechner
7a37f7a231 Fix FIFO stdin handling by opening for read+write like tty-fwd
- Open stdin FIFO with 'r+' mode to keep it open continuously
- Use fs.openSync + createReadStream for proper FIFO handling
- Prevent FIFO from closing when external writers disconnect
- Follow tty-fwd pattern of opening FIFO for both read and write
- Remove problematic spawn('cat') approach that was exiting

This should fix the issue where stdin FIFO closes after first input.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-06-19 06:17:44 +02:00
Mario Zechner
a2b0ba77da Fix enter key mapping for proper command execution
- Change enter key from '\r' to '\n' for correct shell behavior
- Swap enter and ctrl_enter mappings to match terminal expectations
- Most shells expect newline (\n) to execute commands, not carriage return (\r)

This fixes the issue where commands typed in frontend would hang
after pressing enter instead of executing properly.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-06-19 06:06:27 +02:00
Mario Zechner
83011381c2 Fix external session input handling via stdin FIFO monitoring
- Add stdin FIFO monitoring to fwd.ts for web server input forwarding
- Create ReadStream to continuously read from stdin pipe
- Forward web server input to PTY process in real-time
- Prevent hanging when web server sends input to external sessions
- Maintain dual input sources: terminal keyboard + web frontend

This fixes the issue where fwd.ts would hang when receiving
input from the web server via the stdin FIFO pipe.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-06-19 06:02:50 +02:00
Mario Zechner
a4077fbac6 Add control pipe migration and SIGWINCH fallback for external sessions
- Add automatic control pipe creation for existing external sessions
- Update session.json retroactively when control pipe is created
- Implement SIGWINCH fallback when control pipe is not available
- Support resize operations for legacy external sessions

This enables resize functionality for sessions created before
the control pipe feature was implemented.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-06-19 06:00:26 +02:00
Mario Zechner
6c055013af Implement control pipe for external PTY session communication
- Add control-pipe field to session types for external command communication
- Create ResizeControlMessage and KillControlMessage interfaces
- Update PtyManager to send control messages via pipe for external sessions
- Enhance fwd.ts to create and monitor control pipe for resize/kill commands
- Support real-time resize operations for external sessions via IPC
- Add proper cleanup of control pipes on session exit

This enables full PTY control (resize, kill) for sessions created by
external tools like fwd.ts through a file-based IPC mechanism.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-06-19 05:57:13 +02:00
Mario Zechner
0fcddd2194 Fix PTY session operations to support external sessions
- Modify sendInput to write to stdin pipe for external sessions
- Update resizeSession to handle external sessions gracefully
- Fix killSession to work with sessions created by fwd.ts
- Check filesystem for session info when not in memory map
- Support both in-memory and disk-only session management

This fixes frontend operations failing with "Session not found"
when interacting with sessions created by external tools.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-06-19 05:51:00 +02:00
Mario Zechner
a229a7f360 Add interactive PTY forwarding tool with real-time I/O
- Create fwd.ts command-line tool for spawning PTY sessions
- Support both interactive and monitor-only modes
- Real-time bidirectional terminal communication
- Parse asciinema output format for clean terminal display
- Handle terminal raw mode and graceful cleanup
- Auto-detect PTY implementation (node-pty vs tty-fwd)

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-06-19 05:42:55 +02:00
Mario Zechner
7cb80ec708 Center loading animation in viewport when no session selected
- Change from w-full h-full to fixed inset-0 for proper viewport centering
- Ensures loading spinner is centered relative to entire viewport
- Provides better visual positioning regardless of container constraints

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-06-19 05:29:31 +02:00
Mario Zechner
85a4811b65 Show loading animation when no session is selected
- Replace static "No session selected" text with animated loading spinner
- Use same loading animation style as session connection state
- Shows "Waiting for session..." message with spinning indicator
- Provides better visual feedback when waiting for session selection

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-06-19 05:27:19 +02:00
Mario Zechner
b054a57fe3 Add ResizeObserver back in, fix rows/cols calc in terminal. 2025-06-19 05:22:07 +02:00
Mario Zechner
585a593ecc Fix mobile onscreen keyboard scroll position issue
- Add refreshTerminalAfterMobileInput() method to recalculate scroll position
- Call refresh after closing mobile input overlay (cancel, send, send+enter)
- Wait 300ms for viewport to settle before forcing scrollToBottom()
- Fixes issue where terminal scroll position gets confused after keyboard disappears

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-06-19 04:41:39 +02:00
Mario Zechner
89e2dfe356 Remove mobile browser bar hiding code that was cutting off terminal
- Remove hideAddressBar() method and calls that were interfering with viewport
- Remove adjustTerminalForMobileButtons() method that was causing layout issues
- Terminal should now display properly on mobile without being cut off

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-06-19 04:23:18 +02:00
Mario Zechner
6711b3b721 Update project configuration and API documentation
- Update API.md with corrected server analysis and critical compatibility issues
- Update Xcode project configuration with version 104 and development settings
- Maintain comprehensive stream logging for debugging session exit issues

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-06-19 04:00:39 +02:00
Mario Zechner
62f0579d07 Implement cross-platform ProcessUtils for reliable process checking
- Add ProcessUtils class with Windows/Unix process detection methods
- Replace raw process.kill(pid, 0) calls with ProcessUtils.isProcessRunning()
- Support Windows tasklist and Unix kill signal 0 approaches
- Add process killing and waiting utilities for better process management
- Update SessionManager, PtyManager, and PtyService to use ProcessUtils
- Improves reliability of cmd.exe session detection on Windows

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-06-19 03:56:05 +02:00
Mario Zechner
addd0fcd71 Add comprehensive stream endpoint logging for debugging
- Enhanced stream endpoint with detailed [STREAM] logging
- Log client connections, tail process creation, and data flow
- Track exit event detection and stream cleanup
- Log connection events (close, abort, error) for debugging
- Helps diagnose Windows cmd.exe session exit issues

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-06-19 03:17:43 +02:00
Mario Zechner
240153b405 Optional session ID for PtyManager.createSession. 2025-06-19 03:17:43 +02:00
Peter Steinberger
10598a1305 Fix race condition in session creation
The server now waits for tty-fwd to fully register the session before
returning the response. This prevents the frontend from querying for a
session that doesn't exist yet in the session list.

Also removed the problematic frontend fallback that would select the
"most recent" session when the exact ID wasn't found, which was causing
it to open the previous session.
2025-06-19 02:47:50 +02:00
Peter Steinberger
83a4bf0f75
fix: apply formatters to pass CI checks (#19) 2025-06-19 01:39:27 +02:00