diff --git a/.dockerignore b/.dockerignore index 650dea2..6da289f 100644 --- a/.dockerignore +++ b/.dockerignore @@ -5,10 +5,10 @@ # Node.js node_modules +bun.lockb npm-debug.log yarn-debug.log yarn-error.log -pnpm-debug.log # Build outputs dist @@ -62,4 +62,3 @@ logs # Cache .cache .npm -.pnpm-store diff --git a/.github/workflows/README.md b/.github/workflows/README.md index d78b898..aba0aa2 100644 --- a/.github/workflows/README.md +++ b/.github/workflows/README.md @@ -24,8 +24,7 @@ This workflow runs on all branches and pull requests. It: - On push to any branch (except changes to README.md and docs) - On pull requests to any branch (except changes to README.md and docs) -**Key features:** -- Uses pnpm for faster dependency installation +- Uses Bun for dependency installation - Caches dependencies to speed up builds - Uploads build artifacts for 7 days diff --git a/.github/workflows/astro-build-test.yml b/.github/workflows/astro-build-test.yml index 448190f..d7e23f3 100644 --- a/.github/workflows/astro-build-test.yml +++ b/.github/workflows/astro-build-test.yml @@ -21,26 +21,20 @@ jobs: - name: Checkout repository uses: actions/checkout@v4 - - name: Install pnpm - uses: pnpm/action-setup@v3 + - name: Setup Bun + uses: oven-sh/setup-bun@v1 with: - version: 10 - run_install: false - - - name: Setup Node.js - uses: actions/setup-node@v4 - with: - node-version: 'lts/*' - cache: 'pnpm' + bun-version: '1.2.9' + cache: true - name: Install dependencies - run: pnpm install + run: bun install - name: Run tests - run: pnpm test + run: bunx vitest run - name: Build Astro project - run: pnpm build + run: bunx astro build - name: Upload build artifacts uses: actions/upload-artifact@v4 diff --git a/.github/workflows/docker-scan.yml b/.github/workflows/docker-scan.yml index 005e612..5265cd4 100644 --- a/.github/workflows/docker-scan.yml +++ b/.github/workflows/docker-scan.yml @@ -7,14 +7,14 @@ on: - 'Dockerfile' - '.dockerignore' - 'package.json' - - 'pnpm-lock.yaml' + - 'bun.lockb' pull_request: branches: [ main ] paths: - 'Dockerfile' - '.dockerignore' - 'package.json' - - 'pnpm-lock.yaml' + - 'bun.lockb' schedule: - cron: '0 0 * * 0' # Run weekly on Sunday at midnight diff --git a/README.md b/README.md index dabdc28..64b63da 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ ```bash docker compose --profile production up -d # or -pnpm setup && pnpm dev +bun run setup && bun run dev ```
@@ -63,9 +63,9 @@ Easily configure your GitHub and Gitea connections, set up automatic mirroring s
See the [Quick Start Guide](docs/quickstart.md) for detailed instructions on getting up and running quickly.
-### Prerequisites
+-### Prerequisites
-- Node.js 22 or later
+- Bun 1.2.9 or later
- A GitHub account with a personal access token
- A Gitea instance with an access token
@@ -92,7 +92,7 @@ Before running the application in production mode for the first time, you need t
```bash
# Initialize the database for production mode
-pnpm setup
+bun run setup
```
This will create the necessary tables. On first launch, you'll be guided through creating your admin account with a secure password.
@@ -110,7 +110,7 @@ Gitea Mirror provides multi-architecture Docker images that work on both ARM64 (
docker compose --profile production up -d
# For development mode (requires configuration)
-# Ensure you have run pnpm setup first
+# Ensure you have run bun run setup first
docker compose -f docker-compose.dev.yml up -d
```
@@ -206,40 +206,40 @@ git clone https://github.com/arunavo4/gitea-mirror.git
cd gitea-mirror
# Quick setup (installs dependencies and initializes the database)
-pnpm setup
+bun run setup
# Development Mode Options
# Run in development mode
-pnpm dev
+bun run dev
# Run in development mode with clean database (removes existing DB first)
-pnpm dev:clean
+bun run dev:clean
# Production Mode Options
# Build the application
-pnpm build
+bun run build
# Preview the production build
-pnpm preview
+bun run preview
# Start the production server (default)
-pnpm start
+bun run start
# Start the production server with a clean setup
-pnpm start:fresh
+bun run start:fresh
# Database Management
# Initialize the database
-pnpm init-db
+bun run init-db
# Reset users for testing first-time signup
-pnpm reset-users
+bun run reset-users
# Check database status
-pnpm check-db
+bun run check-db
```
### Configuration
@@ -262,10 +262,10 @@ Key configuration options include:
```bash
# Install dependencies
-pnpm setup
+bun run setup
# Start the development server
-pnpm dev
+bun run dev
```
@@ -359,7 +359,7 @@ docker compose -f docker-compose.dev.yml up -d
## Technologies Used
- **Frontend**: Astro, React, Shadcn UI, Tailwind CSS v4
-- **Backend**: Node.js
+ - **Backend**: Bun
- **Database**: SQLite (default) or PostgreSQL
- **Caching/Queue**: Redis
- **API Integration**: GitHub API (Octokit), Gitea API
@@ -467,33 +467,19 @@ Try the following steps:
> For better Redis connection handling, you can modify the `src/lib/redis.ts` file to include retry logic and better error handling:
```typescript
-import Redis from "ioredis";
+import { RedisClient } from "bun";
// Connect to Redis using REDIS_URL environment variable or default to redis://redis:6379
-const redisUrl = process.env.REDIS_URL ?? 'redis://redis:6379';
+const redisUrl = process.env.REDIS_URL ?? "redis://redis:6379";
console.log(`Connecting to Redis at: ${redisUrl}`);
-// Configure Redis client with connection options
-const redisOptions = {
- retryStrategy: (times) => {
- // Retry with exponential backoff up to 30 seconds
- const delay = Math.min(times * 100, 3000);
- console.log(`Redis connection attempt ${times} failed. Retrying in ${delay}ms...`);
- return delay;
- },
- maxRetriesPerRequest: 5,
- enableReadyCheck: true,
- connectTimeout: 10000,
+const redis = new RedisClient(redisUrl, { autoReconnect: true });
+
+redis.onconnect = () => console.log("Redis client connected");
+redis.onclose = err => {
+ if (err) console.error("Redis client error:", err);
};
-
-export const redis = new Redis(redisUrl, redisOptions);
-export const redisPublisher = new Redis(redisUrl, redisOptions);
-export const redisSubscriber = new Redis(redisUrl, redisOptions);
-
-// Log connection events
-redis.on('connect', () => console.log('Redis client connected'));
-redis.on('error', (err) => console.error('Redis client error:', err));
```
diff --git a/docker-entrypoint.sh b/docker-entrypoint.sh
index 2065dc1..c746662 100644
--- a/docker-entrypoint.sh
+++ b/docker-entrypoint.sh
@@ -5,19 +5,19 @@ set -e
# Ensure data directory exists
mkdir -p /app/data
-# If pnpm is available, run setup (for dev images), else run node init directly
-if command -v pnpm >/dev/null 2>&1; then
- echo "Running pnpm setup (if needed)..."
- pnpm setup || true
+# If bun is available, run setup (for dev images)
+if command -v bun >/dev/null 2>&1; then
+ echo "Running bun setup (if needed)..."
+ bun run setup || true
fi
# Initialize the database if it doesn't exist
if [ ! -f "/app/data/gitea-mirror.db" ]; then
echo "Initializing database..."
if [ -f "dist/scripts/init-db.js" ]; then
- node dist/scripts/init-db.js
+ bun dist/scripts/init-db.js
elif [ -f "dist/scripts/manage-db.js" ]; then
- node dist/scripts/manage-db.js init
+ bun dist/scripts/manage-db.js init
else
echo "Warning: Could not find database initialization scripts in dist/scripts."
echo "Creating and initializing database manually..."
@@ -119,9 +119,9 @@ EOF
else
echo "Database already exists, checking for issues..."
if [ -f "dist/scripts/fix-db-issues.js" ]; then
- node dist/scripts/fix-db-issues.js
+ bun dist/scripts/fix-db-issues.js
elif [ -f "dist/scripts/manage-db.js" ]; then
- node dist/scripts/manage-db.js fix
+ bun dist/scripts/manage-db.js fix
fi
# Since the application is not used by anyone yet, we've removed the schema updates and migrations
@@ -130,4 +130,4 @@ fi
# Start the application
echo "Starting Gitea Mirror..."
-exec node ./dist/server/entry.mjs
+exec bun ./dist/server/entry.mjs
diff --git a/package.json b/package.json
index 9e206c4..3acfe17 100644
--- a/package.json
+++ b/package.json
@@ -3,31 +3,30 @@
"type": "module",
"version": "1.0.0",
"engines": {
- "node": ">=22.0.0"
+ "bun": ">=1.2.9"
},
"scripts": {
- "setup": "pnpm install && pnpm manage-db init",
- "dev": "astro dev",
- "dev:clean": "pnpm cleanup-db && pnpm manage-db init && astro dev",
- "build": "astro build",
+ "setup": "bun install && bun run manage-db init",
+ "dev": "bunx astro dev",
+ "dev:clean": "bun run cleanup-db && bun run manage-db init && bunx astro dev",
+ "build": "bunx astro build",
"cleanup-db": "rm -f gitea-mirror.db data/gitea-mirror.db",
- "manage-db": "tsx scripts/manage-db.ts",
- "init-db": "tsx scripts/manage-db.ts init",
- "check-db": "tsx scripts/manage-db.ts check",
- "fix-db": "tsx scripts/manage-db.ts fix",
- "reset-users": "tsx scripts/manage-db.ts reset-users",
- "preview": "astro preview",
- "start": "node dist/server/entry.mjs",
- "start:fresh": "pnpm cleanup-db && pnpm manage-db init && node dist/server/entry.mjs",
- "test": "vitest run",
- "test:watch": "vitest",
- "astro": "astro"
+ "manage-db": "bun scripts/manage-db.ts",
+ "init-db": "bun scripts/manage-db.ts init",
+ "check-db": "bun scripts/manage-db.ts check",
+ "fix-db": "bun scripts/manage-db.ts fix",
+ "reset-users": "bun scripts/manage-db.ts reset-users",
+ "preview": "bunx astro preview",
+ "start": "bun dist/server/entry.mjs",
+ "start:fresh": "bun run cleanup-db && bun run manage-db init && bun dist/server/entry.mjs",
+ "test": "bunx vitest run",
+ "test:watch": "bunx vitest",
+ "astro": "bunx astro"
},
"dependencies": {
"@astrojs/mdx": "^4.2.6",
"@astrojs/node": "^9.2.1",
"@astrojs/react": "^4.2.7",
- "@libsql/client": "^0.15.4",
"@octokit/rest": "^21.1.1",
"@radix-ui/react-avatar": "^1.1.4",
"@radix-ui/react-checkbox": "^1.1.5",
@@ -54,7 +53,6 @@
"cmdk": "^1.1.1",
"drizzle-orm": "^0.41.0",
"fuse.js": "^7.1.0",
- "ioredis": "^5.6.1",
"jsonwebtoken": "^9.0.2",
"lucide-react": "^0.488.0",
"next-themes": "^0.4.6",
@@ -73,15 +71,13 @@
"@testing-library/jest-dom": "^6.6.3",
"@testing-library/react": "^16.3.0",
"@types/bcryptjs": "^3.0.0",
- "@types/better-sqlite3": "^7.6.13",
"@types/jsonwebtoken": "^9.0.9",
"@types/superagent": "^8.1.9",
"@types/uuid": "^10.0.0",
"@vitejs/plugin-react": "^4.4.0",
- "better-sqlite3": "^9.6.0",
"jsdom": "^26.1.0",
"tsx": "^4.19.3",
"vitest": "^3.1.1"
},
- "packageManager": "pnpm@10.10.0"
+ "packageManager": "bun@1.2.9"
}
diff --git a/scripts/README-docker.md b/scripts/README-docker.md
index 952a4a8..02216fc 100644
--- a/scripts/README-docker.md
+++ b/scripts/README-docker.md
@@ -43,7 +43,7 @@ The script uses environment variables from the `.env` file in the project root:
3. Using with docker-compose:
```bash
# Ensure dependencies are installed and database is initialized
- pnpm setup
+ bun run setup
# First build the image
./scripts/build-docker.sh --load
diff --git a/scripts/README.md b/scripts/README.md
index 94e3f12..3dcae9e 100644
--- a/scripts/README.md
+++ b/scripts/README.md
@@ -19,38 +19,38 @@ This is a consolidated database management tool that handles all database-relate
You can execute the database management tool using your package manager with various commands:
```bash
-# Checks database status (default action if no command is specified, equivalent to 'pnpm check-db')
-pnpm manage-db
+# Checks database status (default action if no command is specified, equivalent to 'bun run check-db')
+bun run manage-db
# Check database status
-pnpm check-db
+bun run check-db
# Initialize the database (only if it doesn't exist)
-pnpm init-db
+bun run init-db
# Fix database location issues
-pnpm fix-db
+bun run fix-db
# Automatic check, fix, and initialize if needed
-pnpm db-auto
+bun run db-auto
# Reset all users (for testing signup flow)
-pnpm reset-users
+bun run reset-users
# Update the database schema to the latest version
-pnpm update-schema
+bun run update-schema
# Remove database files completely
-pnpm cleanup-db
+bun run cleanup-db
# Complete setup (install dependencies and initialize database)
-pnpm setup
+bun run setup
# Start development server with a fresh database
-pnpm dev:clean
+bun run dev:clean
# Start production server with a fresh database
-pnpm start:fresh
+bun run start:fresh
```
## Database File Location
diff --git a/scripts/docker-diagnostics.sh b/scripts/docker-diagnostics.sh
old mode 100755
new mode 100644
index 77ca842..3972a91
--- a/scripts/docker-diagnostics.sh
+++ b/scripts/docker-diagnostics.sh
@@ -105,12 +105,12 @@ echo -e "${BLUE} Recommendations ${NC}"
echo -e "${BLUE}=====================================================${NC}"
echo -e "\n${YELLOW}For local development:${NC}"
-echo -e "1. ${GREEN}pnpm setup${NC} (initialize database and install dependencies)"
+echo -e "1. ${GREEN}bun run setup${NC} (initialize database and install dependencies)"
echo -e "2. ${GREEN}./scripts/build-docker.sh --load${NC} (build and load into Docker)"
echo -e "3. ${GREEN}docker-compose -f docker-compose.dev.yml up -d${NC} (start the development container)"
echo -e "\n${YELLOW}For production deployment (using Docker Compose):${NC}"
-echo -e "1. ${GREEN}pnpm setup${NC} (if not already done, to ensure database schema is ready)"
+echo -e "1. ${GREEN}bun run setup${NC} (if not already done, to ensure database schema is ready)"
echo -e "2. ${GREEN}docker-compose --profile production up -d${NC} (start the production container)"
echo -e "\n${YELLOW}For CI/CD builds:${NC}"
diff --git a/scripts/manage-db.ts b/scripts/manage-db.ts
index eb84bf4..4827773 100644
--- a/scripts/manage-db.ts
+++ b/scripts/manage-db.ts
@@ -168,7 +168,7 @@ async function checkDatabase() {
);
console.warn("This file should be in the data directory.");
console.warn(
- 'Run "pnpm manage-db fix" to fix this issue or "pnpm cleanup-db" to remove it.'
+ 'Run "bun run manage-db fix" to fix this issue or "bun run cleanup-db" to remove it.'
);
}
@@ -215,12 +215,12 @@ async function checkDatabase() {
} catch (error) {
console.error("❌ Error connecting to the database:", error);
console.warn(
- 'The database file might be corrupted. Consider running "pnpm manage-db init" to recreate it.'
+ 'The database file might be corrupted. Consider running "bun run manage-db init" to recreate it.'
);
}
} else {
console.warn("⚠️ WARNING: Database file not found in data directory.");
- console.warn('Run "pnpm manage-db init" to create it.');
+ console.warn('Run "bun run manage-db init" to create it.');
}
}
@@ -235,10 +235,10 @@ async function initializeDatabase() {
if (fs.existsSync(dataDbFile)) {
console.log("⚠️ Database already exists at data/gitea-mirror.db");
console.log(
- 'If you want to recreate the database, run "pnpm cleanup-db" first.'
+ 'If you want to recreate the database, run "bun run cleanup-db" first.'
);
console.log(
- 'Or use "pnpm manage-db reset-users" to just remove users without recreating tables.'
+ 'Or use "bun run manage-db reset-users" to just remove users without recreating tables.'
);
// Check if we can connect to it
@@ -457,7 +457,7 @@ async function resetUsers() {
if (!doesDbExist) {
console.log(
- "❌ Database file doesn't exist. Run 'pnpm manage-db init' first to create it."
+ "❌ Database file doesn't exist. Run 'bun run manage-db init' first to create it."
);
return;
}
@@ -629,7 +629,7 @@ async function fixDatabaseIssues() {
console.warn(
"⚠️ WARNING: Production database file not found in data directory."
);
- console.warn('Run "pnpm manage-db init" to create it.');
+ console.warn('Run "bun run manage-db init" to create it.');
} else {
console.log("✅ Production database file found in data directory.");
@@ -641,7 +641,7 @@ async function fixDatabaseIssues() {
} catch (error) {
console.error("❌ Error connecting to the database:", error);
console.warn(
- 'The database file might be corrupted. Consider running "pnpm manage-db init" to recreate it.'
+ 'The database file might be corrupted. Consider running "bun run manage-db init" to recreate it.'
);
}
}
@@ -692,7 +692,7 @@ Available commands:
reset-users - Remove all users and their data
auto - Automatic mode: check, fix, and initialize if needed
-Usage: pnpm manage-db [command]
+Usage: bun run manage-db [command]
`);
}
}
diff --git a/src/content/docs/architecture.md b/src/content/docs/architecture.md
index 7b8b7a9..4045f4b 100644
--- a/src/content/docs/architecture.md
+++ b/src/content/docs/architecture.md
@@ -22,7 +22,7 @@ The application is built using:
- React: Component library for interactive UI elements
- Shadcn UI: UI component library built on Tailwind CSS
- SQLite: Database for storing configuration and state
-- Node.js: Runtime environment for the backend
+- Bun: Runtime environment for the backend
## Architecture Diagram
@@ -30,7 +30,7 @@ The application is built using:
graph TD
subgraph "Gitea Mirror"
Frontend["Frontend
(Astro)"]
- Backend["Backend
(Node.js)"]
+ Backend["Backend
(Bun)"]
Database["Database
(SQLite)"]
Frontend <--> Backend
@@ -60,9 +60,9 @@ Key frontend components:
- **Configuration**: Settings for GitHub and Gitea connections
- **Activity Log**: Detailed log of mirroring operations
-### Backend (Node.js)
+### Backend (Bun)
-The backend is built with Node.js and provides API endpoints for the frontend to interact with. It handles:
+The backend is built with Bun and provides API endpoints for the frontend to interact with. It handles:
- Authentication and user management
- GitHub API integration
diff --git a/src/content/docs/configuration.md b/src/content/docs/configuration.md
index 381ff41..ce4c713 100644
--- a/src/content/docs/configuration.md
+++ b/src/content/docs/configuration.md
@@ -23,7 +23,7 @@ The following environment variables can be used to configure Gitea Mirror:
| Variable | Description | Default Value | Example |
|----------|-------------|---------------|---------|
-| `NODE_ENV` | Node environment (development, production, test) | `development` | `production` |
+| `NODE_ENV` | Runtime environment (development, production, test) | `development` | `production` |
| `DATABASE_URL` | SQLite database URL | `sqlite://data/gitea-mirror.db` | `sqlite://path/to/your/database.db` |
| `JWT_SECRET` | Secret key for JWT authentication | `your-secret-key-change-this-in-production` | `your-secure-random-string` |
| `HOST` | Server host | `localhost` | `0.0.0.0` |
diff --git a/src/content/docs/quickstart.md b/src/content/docs/quickstart.md
index 8efa109..2e75493 100644
--- a/src/content/docs/quickstart.md
+++ b/src/content/docs/quickstart.md
@@ -16,7 +16,7 @@ Before you begin, make sure you have:
1. A GitHub account with a personal access token
2. A Gitea instance with an access token
-3. Docker and docker-compose (recommended) or Node.js 18+ installed
+3. Docker and docker-compose (recommended) or Bun 1.2.9+ installed
## Installation Options
@@ -51,7 +51,7 @@ If you prefer to run the application directly on your system:
2. Run the quick setup script:
```bash
- pnpm setup
+ bun run setup
```
This installs dependencies and initializes the database.
@@ -59,13 +59,13 @@ If you prefer to run the application directly on your system:
**Development Mode:**
```bash
- pnpm dev
+ bun run dev
```
**Production Mode:**
```bash
- pnpm build
- pnpm start
+ bun run build
+ bun run start
```
4. Access the application at [http://localhost:4321](http://localhost:4321)
diff --git a/src/lib/config.ts b/src/lib/config.ts
index 8583353..8968830 100644
--- a/src/lib/config.ts
+++ b/src/lib/config.ts
@@ -4,7 +4,7 @@
// Environment variables
export const ENV = {
- // Node environment (development, production, test)
+ // Runtime environment (development, production, test)
NODE_ENV: process.env.NODE_ENV || "development",
// Database URL - use SQLite by default
diff --git a/src/lib/db/index.ts b/src/lib/db/index.ts
index 0ae592a..bb9307f 100644
--- a/src/lib/db/index.ts
+++ b/src/lib/db/index.ts
@@ -1,6 +1,6 @@
import { z } from "zod";
-import { createClient } from "@libsql/client";
-import { drizzle } from "drizzle-orm/libsql";
+import { Database } from "bun:sqlite";
+import { drizzle } from "drizzle-orm/bun-sqlite";
import { sqliteTable, text, integer } from "drizzle-orm/sqlite-core";
import path from "path";
@@ -11,11 +11,24 @@ const dataDir = path.join(process.cwd(), "data");
const dbUrl =
process.env.DATABASE_URL || `file:${path.join(dataDir, "gitea-mirror.db")}`;
-// Create a client connection to the database
-export const client = createClient({ url: dbUrl });
+// Create a SQLite database instance using Bun's native driver
+export const sqlite = new Database(dbUrl);
+
+// Simple async wrapper around Bun's SQLite API for compatibility
+export const client = {
+ async execute(sql: string, params?: any[]) {
+ const stmt = sqlite.query(sql);
+ if (/^\s*select/i.test(sql)) {
+ const rows = stmt.all(params ?? []);
+ return { rows } as { rows: any[] };
+ }
+ stmt.run(params ?? []);
+ return { rows: [] } as { rows: any[] };
+ },
+};
// Create a drizzle instance
-export const db = drizzle(client);
+export const db = drizzle(sqlite);
// Define the tables
export const users = sqliteTable("users", {
diff --git a/src/lib/redis.ts b/src/lib/redis.ts
index 6c59d9d..a5686e7 100644
--- a/src/lib/redis.ts
+++ b/src/lib/redis.ts
@@ -1,30 +1,23 @@
-import Redis from "ioredis";
+import { RedisClient } from "bun";
// Connect to Redis using REDIS_URL environment variable or default to redis://redis:6379
// This ensures we have a fallback URL when running with Docker Compose
-const redisUrl = process.env.REDIS_URL ?? 'redis://redis:6379';
+const redisUrl = process.env.REDIS_URL ?? "redis://redis:6379";
console.log(`Connecting to Redis at: ${redisUrl}`);
// Configure Redis client with connection options
-const redisOptions = {
- retryStrategy: (times: number) => {
- // Retry with exponential backoff up to 30 seconds
- const delay = Math.min(times * 100, 3000);
- console.log(`Redis connection attempt ${times} failed. Retrying in ${delay}ms...`);
- return delay;
- },
- maxRetriesPerRequest: 5,
- enableReadyCheck: true,
- connectTimeout: 10000,
+function createClient() {
+ return new RedisClient(redisUrl, {
+ autoReconnect: true,
+ });
+}
+
+export const redis = createClient();
+export const redisPublisher = createClient();
+export const redisSubscriber = createClient();
+
+redis.onconnect = () => console.log("Connected to Redis server");
+redis.onclose = (err) => {
+ if (err) console.error("Disconnected from Redis server:", err);
};
-
-export const redis = new Redis(redisUrl, redisOptions);
-export const redisPublisher = new Redis(redisUrl, redisOptions); // For publishing
-export const redisSubscriber = new Redis(redisUrl, redisOptions); // For subscribing
-
-// Log connection events
-redis.on('connect', () => console.log('Redis client connected'));
-redis.on('error', (err) => console.error('Redis client error:', err));
-redis.on('ready', () => console.log('Redis client ready'));
-redis.on('reconnecting', () => console.log('Redis client reconnecting...'));