{"id":51710119,"url":"https://github.com/oae/sensorpanel","last_synced_at":"2026-07-16T20:02:48.138Z","repository":{"id":367782365,"uuid":"1146130213","full_name":"oae/sensorpanel","owner":"oae","description":"Turn cheap USB LCD panels into pro-grade hardware monitors. Real sensors, custom themes, one binary.","archived":false,"fork":false,"pushed_at":"2026-06-27T15:34:05.000Z","size":802,"stargazers_count":5,"open_issues_count":2,"forks_count":0,"subscribers_count":0,"default_branch":"master","last_synced_at":"2026-06-27T17:17:29.866Z","etag":null,"topics":["cli","cpu-monitor","cross-platform","dashboard","golang","gpu-monitor","hardware-monitor","lcd-display","linux","macos","nixos","react","real-time","sensors","system-monitor","temperature-monitor","typescript","usb-lcd","windows"],"latest_commit_sha":null,"homepage":null,"language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/oae.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-01-30T16:59:24.000Z","updated_at":"2026-06-27T15:33:54.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/oae/sensorpanel","commit_stats":null,"previous_names":["oae/sensorpanel"],"tags_count":4,"template":false,"template_full_name":null,"purl":"pkg:github/oae/sensorpanel","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/oae%2Fsensorpanel","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/oae%2Fsensorpanel/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/oae%2Fsensorpanel/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/oae%2Fsensorpanel/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/oae","download_url":"https://codeload.github.com/oae/sensorpanel/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/oae%2Fsensorpanel/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35557060,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-07-16T02:00:06.687Z","response_time":83,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cli","cpu-monitor","cross-platform","dashboard","golang","gpu-monitor","hardware-monitor","lcd-display","linux","macos","nixos","react","real-time","sensors","system-monitor","temperature-monitor","typescript","usb-lcd","windows"],"created_at":"2026-07-16T20:02:47.411Z","updated_at":"2026-07-16T20:02:48.124Z","avatar_url":"https://github.com/oae.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# SensorPanel\n\n[![CI](https://github.com/oae/sensorpanel/actions/workflows/ci.yml/badge.svg)](https://github.com/oae/sensorpanel/actions/workflows/ci.yml)\n[![Go Report Card](https://goreportcard.com/badge/github.com/oae/sensorpanel)](https://goreportcard.com/report/github.com/oae/sensorpanel)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\nA cross-platform CLI tool for driving USB LCD displays as real-time system monitoring dashboards.\n\n![Dashboard Example](docs/dashboard-preview.png)\n\n## Features\n\n- **Multi-device support** - Modular device profiles for different USB displays\n- **Easy device contribution** - Interactive wizard to add support for new panels\n- **Real-time monitoring** - CPU, GPU (NVIDIA/AMD), RAM, disk, and network stats\n- **Media display modes** - Static images, animated GIFs, and a now-playing dashboard\n- **Music dashboard** - Cover art, song metadata, progress waveform, and synchronized lyrics\n- **Regional USB updates** - Sends only changed rectangles when the panel protocol supports it\n- **Dynamic sensor config** - Enable/disable sensors and configure options at runtime\n- **Web-based themes** - Create custom themes using React + TypeScript\n- **TypeScript SDK** - React hooks for easy theme development with hot reload\n- **Single-command dev** - One command starts everything for theme development\n- **Headless rendering** - Auto-downloads Chrome for Testing to render themes\n- **Cross-platform** - Works on Linux, macOS, and Windows\n- **Autostart service** - Install as system service on all platforms\n- **NixOS support** - Flake with module, udev rules, and systemd service\n\n## Quick Start\n\n### 1. Build\n\n```bash\n# Install Mage (recommended build tool)\ngo install github.com/magefile/mage@latest\n\n# Build with Mage\nmage build\n\n# Or directly with Go\ngo build .\n\n# Or with Nix\nnix build\n```\n\n### 2. Select your display\n\n```bash\n./sensorpanel device list     # See available devices\n./sensorpanel device select   # Interactive selection\n```\n\n### 3. Run the dashboard\n\n```bash\n# With built-in renderer\n./sensorpanel run\n\n# Play an animated GIF instead of sensor data\n./sensorpanel run --gif /path/to/animation.gif\n\n# URLs are also supported\n./sensorpanel run --gif https://media.tenor.com/j8dwT9wdyc8AAAAi/evernight-anime.gif\n\n# Display a static PNG, JPEG, or GIF from a file or URL\n./sensorpanel run --image /path/to/wallpaper.png\n\n# Display the active song with artwork, progress waveform, and synchronized lyrics\n./sensorpanel run --music\n\n# With sensor options\n./sensorpanel run --opt disk.mounts=/,/home --opt network.interface=eth*\n\n# Or create and use a custom theme\n./sensorpanel theme create my-theme\n./sensorpanel theme select my-theme\n./sensorpanel run\n```\n\n### 4. (Optional) Install as autostart service\n\n```bash\n# Install to start on login\n./sensorpanel service install --opt disk.mounts=/\n\n# Start now\n./sensorpanel service start\n\n# Check status\n./sensorpanel service status\n```\n\n## Supported Devices\n\nSensorPanel uses a modular device profile system. Currently supported:\n\n| Device | Resolution | Color Format | Notes |\n|--------|------------|--------------|-------|\n| QTKeJi/AIDA64 USB Display | 480x320 | RGB565 BE | VID 0x1908 |\n| Generic AX206-based frames | Various | RGB565 | GEMBIRD, Pearl, Coby, etc. |\n\n**Don't see your device?** Run `sensorpanel device create` to add support for it!\n\n## Commands\n\n### Run Dashboard\n\n```bash\nsensorpanel run [flags]\n\nFlags:\n  -i, --interval float    Update interval in seconds (default 1.0)\n  -b, --brightness int    Backlight brightness 0-7 (default 7)\n  -s, --sensors strings   Sensors to enable (e.g., cpu,memory,disk). Default: all\n  -x, --exclude strings   Sensors to exclude (e.g., network,nvidia_gpu)\n  -o, --opt strings       Sensor options (e.g., disk.mounts=/,/home)\n      --gif string        Play an animated GIF file or URL instead of sensor data\n      --image string      Display a PNG, JPEG, or GIF file or URL instead of sensor data\n      --music             Show now-playing music dashboard instead of sensor data\n```\n\nThe music dashboard currently supports Linux MPRIS players such as Spotify,\nVLC, and compatible browser players. It requires `playerctl`. Synchronized\nlyrics are loaded from LRCLIB when available.\nLyrics are cached locally for faster reuse and fewer network requests.\n\nSee [Media and Music Modes](docs/media-modes.md) for format support, layout\nbehavior, requirements, lyrics behavior, and service setup.\n\n### Sensor Options\n\nConfigure sensor behavior with `--opt` flags or in config.json:\n\n```bash\n# Show available sensor options\nsensorpanel sensor opts\n\n# Examples\nsensorpanel run --opt disk.mounts=/,/home --opt network.interface=eth*\n```\n\n| Option | Type | Description |\n|--------|------|-------------|\n| `disk.mounts` | `[]string` | Disk mount points to monitor |\n| `network.interface` | `string` | Network interface filter (supports `*` wildcard) |\n| `nvidia_gpu.smi_path` | `string` | Custom path to nvidia-smi binary |\n\n### Device Management\n\n```bash\nsensorpanel device list      # List connected USB displays\nsensorpanel device select    # Interactive device selection\nsensorpanel device info      # Show current device and profile info\nsensorpanel device create    # Generate code for new device support\nsensorpanel device reset     # Reset to defaults\n```\n\n### Theme Management\n\n```bash\nsensorpanel theme list              # List installed themes\nsensorpanel theme create \u003cname\u003e     # Create from React+TypeScript template\nsensorpanel theme select \u003cname\u003e     # Set active theme\nsensorpanel theme dev [name]        # Start dev server with hot reload\nsensorpanel theme build [name]      # Build theme for production\nsensorpanel theme preview [name]    # Open in browser\nsensorpanel theme delete \u003cname\u003e     # Remove theme\nsensorpanel theme path              # Show themes directory\nsensorpanel theme sdk update [name] # Update SDK in existing theme\nsensorpanel theme browser install   # Download Chrome for Testing\nsensorpanel theme browser status    # Check browser availability\nsensorpanel theme browser remove    # Remove cached browser\n```\n\n### Panel Control\n\n```bash\nsensorpanel panel status       # Check if panel is connected\nsensorpanel panel test         # Display test pattern\nsensorpanel panel on           # Turn backlight on\nsensorpanel panel off          # Turn backlight off\nsensorpanel panel brightness 5 # Set brightness (0-7)\n```\n\n### Sensor Management\n\n```bash\nsensorpanel sensor list              # List all registered sensors\nsensorpanel sensor list -a           # List only available sensors on this system\nsensorpanel sensor opts              # List available sensor options\nsensorpanel sensor types             # Generate TypeScript types for all sensors\nsensorpanel sensor types -o types.ts # Output to file\nsensorpanel sensor create            # Interactive wizard to create a new sensor\n```\n\n### Service Management (Autostart)\n\n```bash\nsensorpanel service install          # Install as autostart service\nsensorpanel service install --opt disk.mounts=/  # With sensor options\nsensorpanel service install --music  # Start in now-playing mode\nsensorpanel service install --gif https://example.com/animation.gif\nsensorpanel service install --image /path/to/wallpaper.png\nsensorpanel service uninstall        # Remove autostart service\nsensorpanel service start            # Start the service now\nsensorpanel service stop             # Stop the service\nsensorpanel service status           # Show service status\nsensorpanel service logs             # View service logs\nsensorpanel service logs -f          # Follow logs in real-time\n```\n\nCross-platform support:\n- **Linux**: systemd user service (`~/.config/systemd/user/`)\n- **macOS**: launchd LaunchAgent (`~/Library/LaunchAgents/`)\n- **Windows**: Startup folder + Registry\n\nRe-running `service install` updates the existing service definition. Stop and\nstart the service afterward to apply the new command line.\n\n### Other Commands\n\n```bash\nsensorpanel benchmark                                      # Measure full-frame FPS\nsensorpanel benchmark --region-width 64 --region-height 32 # Measure regional FPS\nsensorpanel benchmark --animation --target-fps 60          # Test moving regional updates\nsensorpanel prune              # Remove config and cache (keeps themes)\nsensorpanel prune --all        # Also remove themes\n```\n\n### Rendering performance\n\nSensorPanel automatically uses regional updates for run modes when the selected\nUSB display supports rectangular writes. The first frame is sent as a full\nframe. Later frames are compared against the previous RGB565 buffer, unchanged\nframes are skipped, and changed pixels are grouped into cost-aware rectangular\nupdates. If a regional write fails, SensorPanel falls back to full-frame writes.\n\nRegional updates help most when the layout is mostly static and only small\nareas change, such as numeric sensor values, playback progress, or a clock.\nThey help least when large parts of the screen change every frame, such as\nfull-screen GIF/video-style animation, large gradients, or moving backgrounds.\n\nThe benchmark command can measure the real device instead of relying on theory:\n\n```bash\n# Full-frame transfer speed\nsensorpanel benchmark\n\n# Raw rectangular write speed for a centered 64x32 area\nsensorpanel benchmark --region-width 64 --region-height 32 --frames 100\n\n# End-to-end dirty-region animation test\nsensorpanel benchmark --animation --region-width 64 --region-height 32 --target-fps 60\n```\n\nOn USB full-speed panels such as the QTKeJi/AIDA64 480×320 display, small\nregions can update much faster than full frames, but large full-screen changes\nare still limited by USB bandwidth and the panel's update behavior.\n\n## Adding Device Support\n\nGot a USB display that isn't supported yet? Adding support is easy:\n\n```bash\n# Run the interactive wizard\n./sensorpanel device create\n```\n\nThis prompts you for:\n- Device name and ID\n- USB Vendor ID and Product ID\n- Display resolution\n- Color format (RGB565/RGB888) and byte order\n- Backlight levels\n\nIt generates a skeleton Go file in `pkg/device/` that you can customize.\n\nSee [docs/adding-devices.md](docs/adding-devices.md) for detailed protocol research tips.\n\n## Adding Custom Sensors\n\nSensorPanel uses a modular sensor provider system. Each sensor is a Go provider that implements the `sensors.Provider` interface.\n\n### Built-in Sensors\n\n| Sensor | Platforms | Description |\n|--------|-----------|-------------|\n| `cpu` | Linux | CPU load, temperature, frequency |\n| `memory` | Linux | RAM usage |\n| `disk` | Linux, macOS, Windows | Disk usage per mount point |\n| `network` | Linux | Network interface statistics |\n| `nvidia_gpu` | Linux | NVIDIA GPU via nvidia-smi |\n| `amd_gpu` | Linux | AMD GPU via sysfs |\n\n### Create a Custom Sensor\n\n```bash\n# Run the interactive wizard\n./sensorpanel sensor create\n```\n\nThis prompts you for:\n- Sensor ID and name\n- Target platform (Linux, macOS, Windows, or all)\n- Category (system, gpu, storage, network, power)\n- Field definitions with types and units\n\nIt generates a skeleton Go file in `pkg/sensors/` that you can customize.\n\n### Adding Platform-Specific Implementations\n\nIf a sensor already exists but only for certain platforms, running `sensor create` with the same ID will prompt you to add an implementation for a different platform:\n\n```bash\n./sensorpanel sensor create\nSensor ID: cpu\nSensor 'cpu' already exists for platforms: linux\nWhich platform would you like to add?\n  1. linux\n  2. darwin (macOS)\n  3. windows\n```\n\n### Update TypeScript Types\n\nAfter adding or modifying sensors, regenerate the TypeScript types for themes:\n\n```bash\n./sensorpanel sensor types -o path/to/theme/lib/sensorpanel/types.ts\n```\n\n## Theme Development\n\nThemes are React + TypeScript applications that receive sensor data via WebSocket. A bundled SDK provides React hooks for easy integration.\n\n### Create a theme\n\n```bash\nsensorpanel theme create my-theme\n```\n\n### Development workflow (single command!)\n\n```bash\n# Start everything with one command:\nsensorpanel theme dev my-theme\n\n# With sensor options:\nsensorpanel theme dev my-theme --opt disk.mounts=/ --opt network.interface=eth*\n\n# This automatically:\n# - Detects your package manager (npm/yarn/pnpm/bun)\n# - Installs dependencies if needed\n# - Starts WebSocket sensor server (port 19847)\n# - Starts Vite dev server with HMR (port 15173)\n# - Opens your browser\n```\n\n### Using the SDK\n\n```tsx\nimport { useSensorData, useConnectionStatus, formatRate } from \"../lib/sensorpanel\";\n\nfunction App() {\n  const data = useSensorData();\n  const status = useConnectionStatus();\n\n  if (status !== \"connected\" || !data) {\n    return \u003cdiv\u003eConnecting...\u003c/div\u003e;\n  }\n\n  return (\n    \u003cdiv\u003e\n      \u003cp\u003eCPU: {data.cpu.load.toFixed(0)}%\u003c/p\u003e\n      \u003cp\u003eGPU: {data.gpu.temperature?.toFixed(0) ?? \"--\"}°C\u003c/p\u003e\n      \u003cp\u003eRAM: {data.memory.percent.toFixed(0)}%\u003c/p\u003e\n    \u003c/div\u003e\n  );\n}\n```\n\n### Build and use\n\n```bash\nsensorpanel theme build my-theme\nsensorpanel theme select my-theme\nsensorpanel run\n```\n\nSee [docs/creating-themes.md](docs/creating-themes.md) for the full guide.\n\n## NixOS Installation\n\n### Add to your flake.nix\n\n```nix\n{\n  inputs = {\n    nixpkgs.url = \"github:NixOS/nixpkgs/nixos-unstable\";\n    sensorpanel.url = \"github:alperen/sensorpanel\";\n  };\n\n  outputs = { self, nixpkgs, sensorpanel, ... }: {\n    nixosConfigurations.yourhostname = nixpkgs.lib.nixosSystem {\n      system = \"x86_64-linux\";\n      modules = [\n        ./configuration.nix\n        sensorpanel.nixosModules.default\n        {\n          services.sensorpanel = {\n            enable = true;\n            interval = 1.0;\n            brightness = 7;\n            theme = \"my-theme\";  # or null for built-in renderer\n          };\n        }\n      ];\n    };\n  };\n}\n```\n\n### Module options\n\n```nix\nservices.sensorpanel = {\n  enable = true;\n  interval = 1.0;        # Update interval in seconds\n  brightness = 7;        # Backlight brightness (0-7)\n  theme = null;          # Theme name or null for built-in\n  sensorOptions = {      # Sensor-specific options\n    \"disk.mounts\" = [ \"/\" \"/home\" ];\n    \"network.interface\" = \"eth*\";\n  };\n  user = \"sensorpanel\";  # Service user\n  group = \"sensorpanel\"; # Service group (for USB access)\n};\n```\n\n## File Locations\n\n| Type | Path |\n|------|------|\n| Config | `~/.config/sensorpanel/config.json` |\n| Themes | `~/.local/share/sensorpanel/themes/` |\n| Browser cache | `~/.cache/sensorpanel/browser/` |\n\n## Architecture\n\n### Device Profiles\n\nEach USB display is supported via a device profile that implements:\n\n```go\ntype DeviceProfile interface {\n    ID() string                           // \"qtkeji\", \"my-device\"\n    Name() string                         // Human-readable name\n    Matches(vid, pid uint16) bool         // USB device matching\n    Width() int                           // Display width\n    Height() int                          // Display height\n    ColorFormat() ColorFormat             // RGB565 or RGB888\n    ByteOrder() ByteOrder                 // BigEndian or LittleEndian\n    BlitCommand(x, y, w, h, len int) []byte  // Build display command\n    BacklightCommand(level int) []byte    // Build backlight command\n    ConvertImage(img image.Image) []byte  // Convert to device format\n}\n```\n\n### Sensor Sources (Linux)\n\n| Metric | Source |\n|--------|--------|\n| CPU Load | `/proc/stat` |\n| CPU Temp | `/sys/class/hwmon/*/temp*_input` |\n| CPU Freq | `/sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq` |\n| GPU (NVIDIA) | `nvidia-smi` |\n| GPU (AMD) | `/sys/class/drm/card*/device/` |\n| RAM | `/proc/meminfo` |\n| Disk | `syscall.Statfs` |\n| Network | `/proc/net/dev` |\n\n## Troubleshooting\n\n### Device not found\n\n```bash\n# List USB devices\nlsusb\n\n# Check if sensorpanel detects it\n./sensorpanel device list\n```\n\nIf your device shows in `lsusb` but not in sensorpanel, it may need a new device profile. Run `sensorpanel device create` to add support.\n\n### Permission denied\n\nCreate a udev rule for your device:\n\n```bash\n# Replace XXXX and YYYY with your device's VID and PID\nsudo tee /etc/udev/rules.d/99-sensorpanel.rules \u003c\u003c EOF\nSUBSYSTEM==\"usb\", ATTR{idVendor}==\"XXXX\", ATTR{idProduct}==\"YYYY\", MODE=\"0666\"\nEOF\n\nsudo udevadm control --reload-rules\nsudo udevadm trigger\n```\n\nOn NixOS with the module, udev rules are set up automatically for known devices.\n\n### Theme not rendering\n\n```bash\n# Check if browser is installed\nsensorpanel theme browser status\n\n# Install browser if needed\nsensorpanel theme browser install\n\n# Check theme is built\nls ~/.local/share/sensorpanel/themes/my-theme/dist/\n```\n\n### No GPU stats\n\n```bash\n# NVIDIA: Check nvidia-smi works\nnvidia-smi\n\n# AMD: Check sysfs\nls /sys/class/drm/card*/device/gpu_busy_percent\n```\n\n## Development with Mage\n\nSensorPanel uses [Mage](https://magefile.org/) as its build tool. Install it with:\n\n```bash\ngo install github.com/magefile/mage@latest\n```\n\n### Available Targets\n\n```bash\nmage -l              # List all targets\n\nmage build           # Build for current platform (default)\nmage install         # Build and install to GOPATH/bin\nmage test            # Run all tests\nmage vet             # Run go vet\nmage lint            # Run golangci-lint\nmage check           # Run all checks (vet, test, lint)\nmage clean           # Remove build artifacts\nmage release         # Cross-compile for all platforms (dist/)\nmage dev             # Build and run the dashboard\nmage devTheme        # Build and start theme dev mode\n```\n\n## Testing\n\nSensorPanel has comprehensive unit tests with good coverage across all core packages.\n\n### Running Tests\n\n```bash\n# Run all tests\ngo test ./...\n\n# Run with verbose output\ngo test -v ./...\n\n# Run with race detector\ngo test -race ./...\n\n# Run with coverage\ngo test -coverprofile=coverage.out ./...\ngo tool cover -func=coverage.out    # Summary by function\ngo tool cover -html=coverage.out    # Interactive HTML report\n```\n\n### Coverage by Package\n\n| Package | Coverage | Description |\n|---------|----------|-------------|\n| `pkg/device` | ~99% | Device profiles and registry |\n| `pkg/server` | ~95% | WebSocket server for themes |\n| `pkg/paths` | ~77% | XDG directory handling |\n| `pkg/sensors` | ~57% | System sensor collection |\n| `pkg/panel` | ~50% | USB panel protocol (hardware-dependent) |\n| `pkg/config` | ~40% | Configuration and device discovery |\n| `pkg/theme` | ~34% | Theme management and building |\n\nSome packages have lower coverage because they interact with hardware (USB devices), external processes (Chromium), or the filesystem in ways that are difficult to test in isolation.\n\n## Contributing\n\nContributions are welcome! See [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.\n\n### Ways to contribute\n\n- **Add device support** - Run `sensorpanel device create` and submit a PR\n- **Create themes** - Share your themes with the community\n- **Improve docs** - Help others get started\n- **Fix bugs** - Check the issue tracker\n\n## License\n\nMIT License - See LICENSE file for details.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Foae%2Fsensorpanel","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Foae%2Fsensorpanel","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Foae%2Fsensorpanel/lists"}