diff --git a/internal/ui/web/demo/fixtures/presets.json b/internal/ui/web/demo/fixtures/presets.json index b5f60187..25fedd10 100644 --- a/internal/ui/web/demo/fixtures/presets.json +++ b/internal/ui/web/demo/fixtures/presets.json @@ -1,21 +1,21 @@ -[{"name": "beanstalkd", "description": "Beanstalkd work queue", "image": "docker.io/schickling/beanstalkd:latest"} -, {"name": "elasticsearch", "description": "Elasticsearch single-node search and analytics engine", "image": "docker.elastic.co/elasticsearch/elasticsearch:8.13.4"} -, {"name": "elasticvue", "description": "Elasticvue web UI for the lerd Elasticsearch service", "image": "docker.io/cars10/elasticvue:latest", "dashboard": "http://localhost:8083", "depends_on": ["elasticsearch"], "missing_deps": ["elasticsearch"]} -, {"name": "gotenberg", "description": "Gotenberg API for PDF generation and document conversion", "image": "docker.io/gotenberg/gotenberg:8", "installed": true} -, {"name": "mariadb", "description": "MariaDB (MySQL-compatible) versions", "versions": [{"tag": "12", "label": "12 (latest)"}, {"tag": "12.3", "label": "12.3 LTS"}, {"tag": "11.8", "label": "11.8 LTS"}, {"tag": "11.4", "label": "11.4 LTS"}, {"tag": "11", "label": "11 (legacy)"}, {"tag": "10.11", "label": "10.11 LTS"}], "default_version": "11.8", "installed": true, "installed_tags": ["11"]} -, {"name": "memcached", "description": "Memcached in-memory key/value cache", "image": "docker.io/library/memcached:1.6-alpine"} -, {"name": "mongo", "description": "MongoDB document database", "image": "docker.io/library/mongo:7"} -, {"name": "mongo-express", "description": "Mongo Express web UI for the lerd MongoDB service", "image": "docker.io/library/mongo-express:latest", "dashboard": "http://localhost:8082", "depends_on": ["mongo"], "missing_deps": ["mongo"]} -, {"name": "opensearch", "description": "OpenSearch single-node search and analytics engine", "image": "docker.io/opensearchproject/opensearch:2.19.5"} -, {"name": "pgadmin", "description": "pgAdmin web UI for the lerd Postgres service", "image": "docker.io/dpage/pgadmin4:latest", "dashboard": "http://localhost:8081", "depends_on": ["postgres"]} -, {"name": "phpmyadmin", "description": "phpMyAdmin web UI for every installed lerd MySQL service", "image": "docker.io/library/phpmyadmin:latest", "dashboard": "http://localhost:8080", "depends_on": ["mysql"], "installed": true} -, {"name": "postgres-pgvector", "description": "PostgreSQL with pgvector (vector embeddings, no PostGIS)", "versions": [{"tag": "18", "label": "18 (default)"}, {"tag": "17", "label": "17"}, {"tag": "16", "label": "16"}], "default_version": "18"} -, {"name": "postgres-timescaledb", "description": "PostgreSQL with TimescaleDB (time-series extension)", "versions": [{"tag": "17", "label": "17 (default)"}, {"tag": "16", "label": "16"}], "default_version": "17"} -, {"name": "rabbitmq", "description": "RabbitMQ message broker with management UI", "image": "docker.io/library/rabbitmq:3-management-alpine", "dashboard": "http://localhost:15672"} -, {"name": "redisinsight", "description": "RedisInsight web UI for the lerd Redis service", "image": "docker.io/redis/redisinsight:latest", "dashboard": "http://localhost:8085", "depends_on": ["redis"]} -, {"name": "selenium", "description": "Selenium + Chromium for browser testing (Laravel Dusk, Symfony Panther, etc.)", "image": "docker.io/selenium/standalone-chromium:latest", "dashboard": "http://localhost:7900/?autoconnect=1&resize=scale", "installed": true} -, {"name": "soketi", "description": "Soketi realtime WebSocket server (Pusher-compatible)", "image": "quay.io/soketi/soketi:1.6-16-alpine"} -, {"name": "stripe-mock", "description": "Local Stripe API mock for Cashier and webhook testing", "image": "docker.io/stripemock/stripe-mock:latest"} -, {"name": "typesense", "description": "Typesense search engine", "image": "docker.io/typesense/typesense:30.2"} -, {"name": "typesense-dashboard", "description": "Typesense Dashboard web UI for the lerd Typesense service", "image": "docker.io/bfritscher/typesense-dashboard:latest", "dashboard": "http://localhost:8084", "depends_on": ["typesense"], "missing_deps": ["typesense"]} -, {"name": "valkey", "description": "Valkey in-memory store (Redis-compatible)", "image": "docker.io/valkey/valkey:9-alpine"}] +[{"name": "beanstalkd", "description": "Beanstalkd work queue", "image": "docker.io/schickling/beanstalkd:latest", "category": "messaging", "icon": "queue"} +, {"name": "elasticsearch", "description": "Elasticsearch single-node search and analytics engine", "image": "docker.elastic.co/elasticsearch/elasticsearch:8.13.4", "category": "search", "icon": "search"} +, {"name": "elasticvue", "description": "Elasticvue web UI for the lerd Elasticsearch service", "image": "docker.io/cars10/elasticvue:latest", "dashboard": "http://localhost:8083", "depends_on": ["elasticsearch"], "missing_deps": ["elasticsearch"], "category": "admin", "icon": "search"} +, {"name": "gotenberg", "description": "Gotenberg API for PDF generation and document conversion", "image": "docker.io/gotenberg/gotenberg:8", "installed": true, "category": "mail", "icon": "mail"} +, {"name": "mariadb", "description": "MariaDB (MySQL-compatible) versions", "versions": [{"tag": "12", "label": "12 (latest)"}, {"tag": "12.3", "label": "12.3 LTS"}, {"tag": "11.8", "label": "11.8 LTS"}, {"tag": "11.4", "label": "11.4 LTS"}, {"tag": "11", "label": "11 (legacy)"}, {"tag": "10.11", "label": "10.11 LTS"}], "default_version": "11.8", "installed": true, "installed_tags": ["11"], "category": "databases", "icon": "database"} +, {"name": "memcached", "description": "Memcached in-memory key/value cache", "image": "docker.io/library/memcached:1.6-alpine", "category": "cache", "icon": "bolt"} +, {"name": "mongo", "description": "MongoDB document database", "image": "docker.io/library/mongo:7", "category": "databases", "icon": "leaf"} +, {"name": "mongo-express", "description": "Mongo Express web UI for the lerd MongoDB service", "image": "docker.io/library/mongo-express:latest", "dashboard": "http://localhost:8082", "depends_on": ["mongo"], "missing_deps": ["mongo"], "category": "admin", "icon": "leaf"} +, {"name": "opensearch", "description": "OpenSearch single-node search and analytics engine", "image": "docker.io/opensearchproject/opensearch:2.19.5", "category": "search", "icon": "search"} +, {"name": "pgadmin", "description": "pgAdmin web UI for the lerd Postgres service", "image": "docker.io/dpage/pgadmin4:latest", "dashboard": "http://localhost:8081", "depends_on": ["postgres"], "category": "admin", "icon": "elephant"} +, {"name": "phpmyadmin", "description": "phpMyAdmin web UI for every installed lerd MySQL service", "image": "docker.io/library/phpmyadmin:latest", "dashboard": "http://localhost:8080", "depends_on": ["mysql"], "installed": true, "category": "admin", "icon": "database"} +, {"name": "postgres-pgvector", "description": "PostgreSQL with pgvector (vector embeddings, no PostGIS)", "versions": [{"tag": "18", "label": "18 (default)"}, {"tag": "17", "label": "17"}, {"tag": "16", "label": "16"}], "default_version": "18", "category": "databases", "icon": "elephant"} +, {"name": "postgres-timescaledb", "description": "PostgreSQL with TimescaleDB (time-series extension)", "versions": [{"tag": "17", "label": "17 (default)"}, {"tag": "16", "label": "16"}], "default_version": "17", "category": "databases", "icon": "elephant"} +, {"name": "rabbitmq", "description": "RabbitMQ message broker with management UI", "image": "docker.io/library/rabbitmq:3-management-alpine", "dashboard": "http://localhost:15672", "category": "messaging", "icon": "queue"} +, {"name": "redisinsight", "description": "RedisInsight web UI for the lerd Redis service", "image": "docker.io/redis/redisinsight:latest", "dashboard": "http://localhost:8085", "depends_on": ["redis"], "category": "admin", "icon": "database"} +, {"name": "selenium", "description": "Selenium + Chromium for browser testing (Laravel Dusk, Symfony Panther, etc.)", "image": "docker.io/selenium/standalone-chromium:latest", "dashboard": "http://localhost:7900/?autoconnect=1&resize=scale", "installed": true, "category": "testing", "icon": "browserPlay"} +, {"name": "soketi", "description": "Soketi realtime WebSocket server (Pusher-compatible)", "image": "quay.io/soketi/soketi:1.6-16-alpine", "category": "messaging", "icon": "broadcast"} +, {"name": "stripe-mock", "description": "Local Stripe API mock for Cashier and webhook testing", "image": "docker.io/stripemock/stripe-mock:latest", "category": "testing", "icon": "card"} +, {"name": "typesense", "description": "Typesense search engine", "image": "docker.io/typesense/typesense:30.2", "category": "search", "icon": "search"} +, {"name": "typesense-dashboard", "description": "Typesense Dashboard web UI for the lerd Typesense service", "image": "docker.io/bfritscher/typesense-dashboard:latest", "dashboard": "http://localhost:8084", "depends_on": ["typesense"], "missing_deps": ["typesense"], "category": "admin", "icon": "search"} +, {"name": "valkey", "description": "Valkey in-memory store (Redis-compatible)", "image": "docker.io/valkey/valkey:9-alpine", "category": "cache", "icon": "bolt"}] diff --git a/internal/ui/web/demo/fixtures/services.json b/internal/ui/web/demo/fixtures/services.json index 7f73e74b..e6c23407 100644 --- a/internal/ui/web/demo/fixtures/services.json +++ b/internal/ui/web/demo/fixtures/services.json @@ -1 +1 @@ -[{"name": "mailpit", "status": "active", "version": "latest", "env_vars": {"MAIL_ENCRYPTION": "null", "MAIL_HOST": "lerd-mailpit", "MAIL_MAILER": "smtp", "MAIL_PASSWORD": "null", "MAIL_PORT": "1025", "MAIL_USERNAME": "null"}, "port": 1025, "published_port": 1025, "default_port": 1025, "preset_owned": true, "secondary_ports": [{"container": 8025, "default": 8025}], "is_default": true, "site_count": 5, "site_domains": ["acme.test", "shopfront.test", "checkout.test", "orbit.test", "admin.orbit.test"], "pinned": false, "update_strategy": "rolling", "migration_supported": false, "can_rollback": false}, {"name": "meilisearch", "status": "active", "version": "v1.41", "env_vars": {"MEILISEARCH_HOST": "http://lerd-meilisearch:7700", "SCOUT_DRIVER": "meilisearch"}, "port": 7700, "published_port": 7700, "default_port": 7700, "preset_owned": true, "is_default": true, "site_count": 2, "site_domains": ["orbit.test", "admin.orbit.test"], "pinned": false, "update_strategy": "patch", "previous_version": "docker.io/getmeili/meilisearch:v1.7", "migration_supported": false, "can_rollback": true}, {"name": "mysql", "status": "active", "version": "v8.4.10", "env_vars": {"DB_CONNECTION": "mysql", "DB_DATABASE": "lerd", "DB_HOST": "lerd-mysql", "DB_PASSWORD": "lerd", "DB_PORT": "3306", "DB_USERNAME": "root"}, "connection_url": "mysql://root:lerd@127.0.0.1:3306/lerd", "port": 3306, "published_port": 3306, "default_port": 3306, "preset_owned": true, "client_shims": [{"tool": "mysql", "host_has": true, "enabled": true, "decided": true}, {"tool": "mysqldump", "host_has": false, "enabled": true, "decided": true}], "is_default": true, "tunable": true, "site_count": 4, "site_domains": ["checkout.test", "orbit.test", "admin.orbit.test", "blog.orbit.test"], "pinned": false, "update_strategy": "minor", "previous_version": "docker.io/library/mysql:8.4.9", "migration_supported": true, "can_rollback": true}, {"name": "postgres", "status": "active", "version": "v18", "env_vars": {"DB_CONNECTION": "pgsql", "DB_DATABASE": "lerd", "DB_HOST": "lerd-postgres", "DB_PASSWORD": "lerd", "DB_PORT": "5432", "DB_USERNAME": "postgres"}, "connection_url": "postgresql://postgres:lerd@127.0.0.1:5432/lerd", "port": 5432, "published_port": 5432, "default_port": 5432, "preset_owned": true, "client_shims": [{"tool": "psql", "host_has": true, "enabled": true, "decided": true}, {"tool": "pg_dump", "host_has": true, "enabled": false, "decided": false}], "is_default": true, "tunable": true, "site_count": 2, "site_domains": ["acme.test", "shopfront.test"], "pinned": false, "update_strategy": "minor", "previous_version": "docker.io/postgis/postgis:16-3.5-alpine", "migration_supported": true, "can_rollback": false}, {"name": "redis", "status": "active", "version": "v7.4.9", "env_vars": {"CACHE_STORE": "redis", "QUEUE_CONNECTION": "redis", "REDIS_HOST": "lerd-redis", "REDIS_PASSWORD": "null", "REDIS_PORT": "6379", "SESSION_DRIVER": "redis"}, "connection_url": "redis://127.0.0.1:6379", "port": 6379, "published_port": 6379, "default_port": 6379, "preset_owned": true, "client_shims": [{"tool": "redis-cli", "host_has": false, "enabled": true, "decided": true}], "is_default": true, "tunable": true, "site_count": 5, "site_domains": ["acme.test", "shopfront.test", "checkout.test", "orbit.test", "admin.orbit.test"], "pinned": false, "update_strategy": "minor", "previous_version": "docker.io/library/redis:7.4.8-alpine", "migration_supported": false, "can_rollback": true}, {"name": "rustfs", "status": "active", "version": "latest", "env_vars": {"AWS_ACCESS_KEY_ID": "lerd", "AWS_BUCKET": "lerd", "AWS_DEFAULT_REGION": "us-east-1", "AWS_ENDPOINT": "http://lerd-rustfs:9000", "AWS_SECRET_ACCESS_KEY": "lerdpassword", "AWS_URL": "http://localhost:9000", "AWS_USE_PATH_STYLE_ENDPOINT": "true", "FILESYSTEM_DISK": "s3"}, "port": 9000, "published_port": 9000, "default_port": 9000, "preset_owned": true, "secondary_ports": [{"container": 9001, "default": 9001}], "is_default": true, "site_count": 5, "site_domains": ["acme.test", "shopfront.test", "checkout.test", "orbit.test", "admin.orbit.test"], "pinned": false, "update_strategy": "rolling", "migration_supported": false, "can_rollback": false}, {"name": "gotenberg", "status": "active", "version": "v8", "env_vars": {"GOTENBERG_URL": "http://lerd-gotenberg:3000"}, "custom": true, "site_count": 2, "site_domains": ["orbit.test", "admin.orbit.test"], "pinned": false, "migration_supported": false, "can_rollback": false}, {"name": "mariadb-11", "status": "active", "version": "v11", "env_vars": {"DB_CONNECTION": "mysql", "DB_DATABASE": "lerd", "DB_HOST": "lerd-mariadb-11", "DB_PASSWORD": "lerd", "DB_PORT": "3306", "DB_USERNAME": "root"}, "connection_url": "mysql://root:lerd@127.0.0.1:3411/lerd", "port": 3411, "published_port": 3411, "default_port": 3306, "preset_owned": true, "custom": true, "tunable": true, "site_count": 0, "pinned": false, "migration_supported": false, "can_rollback": false}, {"name": "phpmyadmin", "status": "active", "version": "latest", "env_vars": {}, "custom": true, "site_count": 0, "pinned": false, "depends_on": ["mysql"], "migration_supported": false, "can_rollback": false}, {"name": "selenium", "status": "active", "version": "latest", "env_vars": {"DUSK_DRIVER_URL": "http://lerd-selenium:4444"}, "custom": true, "site_count": 1, "site_domains": ["orbit.test"], "pinned": false, "migration_supported": false, "can_rollback": false}, {"name": "queue-acme", "status": "active", "env_vars": {}, "site_count": 0, "pinned": false, "queue_site": "acme", "migration_supported": false, "can_rollback": false}, {"name": "stripe-acme", "status": "active", "env_vars": {}, "site_count": 0, "pinned": false, "stripe_listener_site": "acme", "migration_supported": false, "can_rollback": false}, {"name": "schedule-acme", "status": "active", "env_vars": {}, "site_count": 0, "pinned": false, "schedule_worker_site": "acme", "migration_supported": false, "can_rollback": false}, {"name": "reverb-acme", "status": "active", "env_vars": {}, "site_count": 0, "pinned": false, "reverb_site": "acme", "migration_supported": false, "can_rollback": false}, {"name": "vite-acme", "status": "active", "env_vars": {}, "site_count": 0, "pinned": false, "worker_site": "acme", "worker_name": "vite", "worker_label": "Vite", "migration_supported": false, "can_rollback": false}] \ No newline at end of file +[{"name": "mailpit", "status": "active", "version": "latest", "env_vars": {"MAIL_ENCRYPTION": "null", "MAIL_HOST": "lerd-mailpit", "MAIL_MAILER": "smtp", "MAIL_PASSWORD": "null", "MAIL_PORT": "1025", "MAIL_USERNAME": "null"}, "port": 1025, "published_port": 1025, "default_port": 1025, "preset_owned": true, "secondary_ports": [{"container": 8025, "default": 8025}], "is_default": true, "site_count": 5, "site_domains": ["acme.test", "shopfront.test", "checkout.test", "orbit.test", "admin.orbit.test"], "pinned": false, "update_strategy": "rolling", "migration_supported": false, "can_rollback": false, "category": "mail", "icon": "mail"}, {"name": "meilisearch", "status": "active", "version": "v1.41", "env_vars": {"MEILISEARCH_HOST": "http://lerd-meilisearch:7700", "SCOUT_DRIVER": "meilisearch"}, "port": 7700, "published_port": 7700, "default_port": 7700, "preset_owned": true, "is_default": true, "site_count": 2, "site_domains": ["orbit.test", "admin.orbit.test"], "pinned": false, "update_strategy": "patch", "previous_version": "docker.io/getmeili/meilisearch:v1.7", "migration_supported": false, "can_rollback": true, "category": "search", "icon": "search"}, {"name": "mysql", "status": "active", "version": "v8.4.10", "env_vars": {"DB_CONNECTION": "mysql", "DB_DATABASE": "lerd", "DB_HOST": "lerd-mysql", "DB_PASSWORD": "lerd", "DB_PORT": "3306", "DB_USERNAME": "root"}, "connection_url": "mysql://root:lerd@127.0.0.1:3306/lerd", "port": 3306, "published_port": 3306, "default_port": 3306, "preset_owned": true, "client_shims": [{"tool": "mysql", "host_has": true, "enabled": true, "decided": true}, {"tool": "mysqldump", "host_has": false, "enabled": true, "decided": true}], "is_default": true, "tunable": true, "site_count": 4, "site_domains": ["checkout.test", "orbit.test", "admin.orbit.test", "blog.orbit.test"], "pinned": false, "update_strategy": "minor", "previous_version": "docker.io/library/mysql:8.4.9", "migration_supported": true, "can_rollback": true, "category": "databases", "icon": "database", "is_database": true}, {"name": "postgres", "status": "active", "version": "v18", "env_vars": {"DB_CONNECTION": "pgsql", "DB_DATABASE": "lerd", "DB_HOST": "lerd-postgres", "DB_PASSWORD": "lerd", "DB_PORT": "5432", "DB_USERNAME": "postgres"}, "connection_url": "postgresql://postgres:lerd@127.0.0.1:5432/lerd", "port": 5432, "published_port": 5432, "default_port": 5432, "preset_owned": true, "client_shims": [{"tool": "psql", "host_has": true, "enabled": true, "decided": true}, {"tool": "pg_dump", "host_has": true, "enabled": false, "decided": false}], "is_default": true, "tunable": true, "site_count": 2, "site_domains": ["acme.test", "shopfront.test"], "pinned": false, "update_strategy": "minor", "previous_version": "docker.io/postgis/postgis:16-3.5-alpine", "migration_supported": true, "can_rollback": false, "category": "databases", "icon": "elephant", "is_database": true}, {"name": "redis", "status": "active", "version": "v7.4.9", "env_vars": {"CACHE_STORE": "redis", "QUEUE_CONNECTION": "redis", "REDIS_HOST": "lerd-redis", "REDIS_PASSWORD": "null", "REDIS_PORT": "6379", "SESSION_DRIVER": "redis"}, "connection_url": "redis://127.0.0.1:6379", "port": 6379, "published_port": 6379, "default_port": 6379, "preset_owned": true, "client_shims": [{"tool": "redis-cli", "host_has": false, "enabled": true, "decided": true}], "is_default": true, "tunable": true, "site_count": 5, "site_domains": ["acme.test", "shopfront.test", "checkout.test", "orbit.test", "admin.orbit.test"], "pinned": false, "update_strategy": "minor", "previous_version": "docker.io/library/redis:7.4.8-alpine", "migration_supported": false, "can_rollback": true, "category": "cache", "icon": "bolt"}, {"name": "rustfs", "status": "active", "version": "latest", "env_vars": {"AWS_ACCESS_KEY_ID": "lerd", "AWS_BUCKET": "lerd", "AWS_DEFAULT_REGION": "us-east-1", "AWS_ENDPOINT": "http://lerd-rustfs:9000", "AWS_SECRET_ACCESS_KEY": "lerdpassword", "AWS_URL": "http://localhost:9000", "AWS_USE_PATH_STYLE_ENDPOINT": "true", "FILESYSTEM_DISK": "s3"}, "port": 9000, "published_port": 9000, "default_port": 9000, "preset_owned": true, "secondary_ports": [{"container": 9001, "default": 9001}], "is_default": true, "site_count": 5, "site_domains": ["acme.test", "shopfront.test", "checkout.test", "orbit.test", "admin.orbit.test"], "pinned": false, "update_strategy": "rolling", "migration_supported": false, "can_rollback": false, "category": "storage", "icon": "storage"}, {"name": "gotenberg", "status": "active", "version": "v8", "env_vars": {"GOTENBERG_URL": "http://lerd-gotenberg:3000"}, "custom": true, "site_count": 2, "site_domains": ["orbit.test", "admin.orbit.test"], "pinned": false, "migration_supported": false, "can_rollback": false, "category": "mail", "icon": "mail"}, {"name": "mariadb-11", "status": "active", "version": "v11", "env_vars": {"DB_CONNECTION": "mysql", "DB_DATABASE": "lerd", "DB_HOST": "lerd-mariadb-11", "DB_PASSWORD": "lerd", "DB_PORT": "3306", "DB_USERNAME": "root"}, "connection_url": "mysql://root:lerd@127.0.0.1:3411/lerd", "port": 3411, "published_port": 3411, "default_port": 3306, "preset_owned": true, "custom": true, "tunable": true, "site_count": 0, "pinned": false, "migration_supported": false, "can_rollback": false, "category": "databases", "icon": "database", "is_database": true}, {"name": "phpmyadmin", "status": "active", "version": "latest", "env_vars": {}, "custom": true, "site_count": 0, "pinned": false, "depends_on": ["mysql"], "migration_supported": false, "can_rollback": false, "category": "admin", "icon": "database"}, {"name": "selenium", "status": "active", "version": "latest", "env_vars": {"DUSK_DRIVER_URL": "http://lerd-selenium:4444"}, "custom": true, "site_count": 1, "site_domains": ["orbit.test"], "pinned": false, "migration_supported": false, "can_rollback": false, "category": "testing", "icon": "browserPlay"}, {"name": "queue-acme", "status": "active", "env_vars": {}, "site_count": 0, "pinned": false, "queue_site": "acme", "migration_supported": false, "can_rollback": false}, {"name": "stripe-acme", "status": "active", "env_vars": {}, "site_count": 0, "pinned": false, "stripe_listener_site": "acme", "migration_supported": false, "can_rollback": false}, {"name": "schedule-acme", "status": "active", "env_vars": {}, "site_count": 0, "pinned": false, "schedule_worker_site": "acme", "migration_supported": false, "can_rollback": false}, {"name": "reverb-acme", "status": "active", "env_vars": {}, "site_count": 0, "pinned": false, "reverb_site": "acme", "migration_supported": false, "can_rollback": false}, {"name": "vite-acme", "status": "active", "env_vars": {}, "site_count": 0, "pinned": false, "worker_site": "acme", "worker_name": "vite", "worker_label": "Vite", "migration_supported": false, "can_rollback": false}] \ No newline at end of file