сделай возможность по api получать sql запросы и обрабатывать их вот мой код // app.js
const express = require('express');
const bodyParser = require('body-parser');
const fs = require('fs');
const path = require('path');
const { GPU } = require('gpu.js');
const session = require('express-session'); // Added for session management
const bcrypt = require('bcrypt'); // Added for password hashing
const { v4: uuidv4 } = require('uuid'); // Added for token generation

// Инициализация GPU.js
const gpu = new GPU();

// Константы для путей и параметров
const PORT = 3000;
const BD_DIR = path.join(__dirname, 'BD');
const USERS_FILE = path.join(BD_DIR, 'users.json');
const SALT_ROUNDS = 10;

// Убедимся, что папка BD существует
if (!fs.existsSync(BD_DIR)) {
  fs.mkdirSync(BD_DIR);
}

// Убедимся, что файл users.json существует
if (!fs.existsSync(USERS_FILE)) {
  fs.writeFileSync(USERS_FILE, JSON.stringify([]), 'utf8');
}

// Чтение пользователей из файла
let users = JSON.parse(fs.readFileSync(USERS_FILE, 'utf8'));

// Класс Table для управления таблицами
class Table {
  constructor(name, schema, autoIncrement = false) {
    this.name = name;
    this.schema = schema; // Объект с типами, например: { id: 'number', name: 'string' }
    this.autoIncrement = autoIncrement; // Флаг автоинкремента для 'id'
    this.autoIncrementValue = 1; // Начальное значение для автоинкремента

    // Инициализация колонок
    this.columns = {};
    for (let field in schema) {
      if (schema[field] === 'number') {
        this.columns[field] = []; // Массив чисел
      } else {
        this.columns[field] = []; // Массив строк
      }
    }
  }

  // Метод для вставки записи
  insert(record) {
    // Если автоинкремент включен, генерируем id
    if (this.autoIncrement) {
      record.id = this.autoIncrementValue++;
    } else {
      if (record.id === undefined || record.id === null) {
        throw new Error('Поле "id" обязательно для вставки записи.');
      }
      const id = record.id;
      const ids = this.columns['id'];
      if (ids.includes(id)) {
        throw new Error(`Запись с id=${id} уже существует.`);
      }
    }

    for (let field in this.schema) {
      if (this.autoIncrement && field === 'id') {
        // Уже установили значение id
        this.columns[field].push(record[field]);
      } else {
        this.columns[field].push(
          record[field] !== undefined ? record[field] : (this.schema[field] === 'number' ? 0 : '')
        );
      }
    }
  }

  // Метод для удаления записи по id
  deleteRecord(id) {
    const ids = this.columns['id'];
    const index = ids.indexOf(id);
    if (index !== -1) {
      for (let field in this.columns) {
        this.columns[field].splice(index, 1);
      }
      return true;
    }
    return false;
  }

  // Метод для обновления записи по id
  updateRecord(id, newRecord) {
    const ids = this.columns['id'];
    const index = ids.indexOf(id);
    if (index !== -1) {
      for (let field in newRecord) {
        if (this.schema[field]) {
          if (field === 'id' && this.autoIncrement) {
            // Не разрешаем изменять auto-increment id вручную
            continue;
          }
          this.columns[field][index] = newRecord[field];
        }
      }
      return true;
    }
    return false;
  }

  // Метод для получения записи по id с использованием GPU
  getGPU(id) {
    // Преобразуем колонки в массивы чисел или строк
    const recordLength = this.columns['id'].length;
    const ids = this.columns['id'];

    // Создаем TypedArray для id, если они числа
    let idArray;
    if (this.schema['id'] === 'number') {
      idArray = new Float32Array(ids);
    } else {
      // Для строк GPU.js не поддерживает, поэтому ограничимся числовым id.
      throw new Error('GPU-поиск поддерживается только для числовых id.');
    }

    // Создаем GPU Kernel для поиска индекса
    const findIndexGPU = gpu.createKernel(function(idArray, targetId) {
      let index = -1;
      for (let i = 0; i < this.constants.size; i++) {
        if (idArray[i] === targetId) {
          index = i;
          break;
        }
      }
      return index;
    })
      .setOutput([1])
      .setConstants({ size: recordLength });

    const index = findIndexGPU(idArray, id)[0];

    if (index === -1) return null;

    // Получение всей записи
    const record = {};
    for (let field in this.columns) {
      record[field] = this.columns[field][index];
    }
    return record;
  }

  getRecord(id) {
    return this.getGPU(id);
    // Или использовать CPU метод:
    // return this.getCPU(id);
  }

  getAll() {
    // Преобразование колонночного хранения в массив записей
    const recordLength = this.columns['id'].length;
    const records = [];
    for (let i = 0; i < recordLength; i++) {
      const record = {};
      for (let field in this.columns) {
        record[field] = this.columns[field][i];
      }
      records.push(record);
    }
    return records;
  }

  // Использование CPU для получения записи по id
  getCPU(id) {
    const index = this.columns['id'].indexOf(id);
    if (index === -1) return null;
    const record = {};
    for (let field in this.columns) {
      record[field] = this.columns[field][index];
    }
    return record;
  }

  // Добавление новой колонки
  addColumn(columnName, columnType) {
    if (this.schema[columnName]) {
      throw new Error(`Колонка "${columnName}" уже существует.`);
    }
    if (!['number', 'string'].includes(columnType.toLowerCase())) {
      throw new Error('Поддерживаются только типы "number" и "string".');
    }
    this.schema[columnName] = columnType.toLowerCase();
    // Инициализация новой колонки
    this.columns[columnName] = this.columns['id'].map(() => (columnType.toLowerCase() === 'number' ? 0 : ''));
  }

  // Удаление колонки
  deleteColumn(columnName) {
    if (!this.schema[columnName]) {
      throw new Error(`Колонка "${columnName}" не найдена.`);
    }
    if (columnName === 'id') {
      throw new Error('Невозможно удалить обязательную колонку "id".');
    }
    delete this.schema[columnName];
    delete this.columns[columnName];
  }
}

// Класс Database с автоматическим сохранением после каждой модификации
class Database {
  constructor(filePath) {
    this.tables = new Map();
    this.filePath = filePath; // Сохраняем путь к файлу
  }

  createTable(tableName, schema, autoIncrement = false) {
    if (this.tables.has(tableName)) {
      throw new Error(`Таблица "${tableName}" уже существует.`);
    }
    const table = new Table(tableName, schema, autoIncrement);
    // Если автоинкремент включен, устанавливаем начальное значение
    if (autoIncrement) {
      const ids = table.columns['id'];
      if (ids.length > 0) {
        table.autoIncrementValue = Math.max(...ids) + 1;
      } else {
        table.autoIncrementValue = 1;
      }
    }
    this.tables.set(tableName, table);
    this.saveToFile(); // Сохранение после создания таблицы
  }

  dropTable(tableName) {
    if (this.tables.delete(tableName)) {
      this.saveToFile(); // Сохранение после удаления таблицы
      return true;
    }
    return false;
  }

  insert(tableName, record) {
    const table = this.tables.get(tableName);
    if (!table) {
      throw new Error(`Таблица "${tableName}" не найдена.`);
    }
    table.insert(record);
    this.saveToFile(); // Сохранение после вставки записи
  }

  deleteRecord(tableName, id) {
    const table = this.tables.get(tableName);
    if (!table) {
      throw new Error(`Таблица "${tableName}" не найдена.`);
    }
    const result = table.deleteRecord(id);
    if (result) {
      this.saveToFile(); // Сохранение после удаления записи
    }
    return result;
  }

  updateRecord(tableName, id, newRecord) {
    const table = this.tables.get(tableName);
    if (!table) {
      throw new Error(`Таблица "${tableName}" не найдена.`);
    }
    const result = table.updateRecord(id, newRecord);
    if (result) {
      this.saveToFile(); // Сохранение после обновления записи
    }
    return result;
  }

  getRecord(tableName, id) {
    const table = this.tables.get(tableName);
    if (!table) {
      throw new Error(`Таблица "${tableName}" не найдена.`);
    }
    return table.getRecord(id);
  }

  getAll(tableName) {
    const table = this.tables.get(tableName);
    if (!table) {
      throw new Error(`Таблица "${tableName}" не найдена.`);
    }
    return table.getAll();
  }

  getTables() {
    return Array.from(this.tables.keys());
  }

  getTableSchema(tableName) {
    const table = this.tables.get(tableName);
    if (!table) {
      throw new Error(`Таблица "${tableName}" не найдена.`);
    }
    return table.schema;
  }

  getTableAutoIncrement(tableName) {
    const table = this.tables.get(tableName);
    if (!table) {
      throw new Error(`Таблица "${tableName}" не найдена.`);
    }
    return table.autoIncrement;
  }

  addColumn(tableName, columnName, columnType) {
    const table = this.tables.get(tableName);
    if (!table) {
      throw new Error(`Таблица "${tableName}" не найдена.`);
    }
    table.addColumn(columnName, columnType);
    this.saveToFile(); // Сохранение после добавления колонки
  }

  deleteColumn(tableName, columnName) {
    const table = this.tables.get(tableName);
    if (!table) {
      throw new Error(`Таблица "${tableName}" не найдена.`);
    }
    table.deleteColumn(columnName);
    this.saveToFile(); // Сохранение после удаления колонки
  }

  // Сохранение базы данных в файл
  saveToFile() {
    const data = {};
    this.tables.forEach((table, name) => {
      data[name] = {
        schema: table.schema,
        columns: table.columns,
        autoIncrement: table.autoIncrement,
        autoIncrementValue: table.autoIncrementValue
      };
    });
    fs.writeFileSync(this.filePath, JSON.stringify(data, null, 2), 'utf8');
    console.log(`Данные сохранены в ${this.filePath}`);
  }

  // Загрузка базы данных из файла
  loadFromFile() {
    if (fs.existsSync(this.filePath)) {
      const rawData = fs.readFileSync(this.filePath, 'utf8');
      const data = JSON.parse(rawData);
      for (const tableName in data) {
        const tableData = data[tableName];
        const table = new Table(tableName, tableData.schema, tableData.autoIncrement);
        for (let field in tableData.columns) {
          table.columns[field] = tableData.columns[field];
        }
        table.autoIncrementValue = tableData.autoIncrementValue || 1;
        this.tables.set(tableName, table);
      }
      console.log(`Данные загружены из ${this.filePath}`);
    } else {
      console.log(`Файл ${this.filePath} не найден. Начинается с пустой базы данных.`);
    }
  }

  // Метод для выполнения SQL-подобной команды
  executeSQLCommand(command) {
    const parsed = parseSQL(command);
    if (!parsed) {
      throw new Error('Некорректная команда.');
    }

    const { type } = parsed;

    switch (type.toUpperCase()) {
      case 'SELECT':
        if (parsed.type === 'JOIN') { // Изменено
          return this.selectQuery(parsed.table1, parsed.fields, parsed.where, parsed.order, parsed); // Изменено
        }
        return this.selectQuery(parsed.tableName, parsed.fields, parsed.where, parsed.order);
      case 'INSERT':
        return this.insertQuery(parsed.tableName, parsed.values);
      case 'UPDATE':
        return this.updateQuery(parsed.tableName, parsed.fields, parsed.where);
      case 'DELETE':
        return this.deleteQuery(parsed.tableName, parsed.where);
      default:
        throw new Error(`Неизвестный тип команды "${type}".`);
    }
  }

  // Методы для поддержки SQL-команд

  selectQuery(tableName, selectedFields = ['*'], where = null, order = null, join = null) { // Изменено
    const table = this.tables.get(tableName);
    if (!table) {
      throw new Error(`Таблица "${tableName}" не найдена.`);
    }

    let records = table.getAll();

    // Если есть JOIN
    if (join) { // Добавлено
      const joinTable = this.tables.get(join.table2);
      if (!joinTable) {
        throw new Error(`Таблица для JOIN "${join.table2}" не найдена.`);
      }

      const [leftTableName, leftField] = join.joinCondition.left.split('.');
      const [rightTableName, rightField] = join.joinCondition.right.split('.');

      if (leftTableName !== tableName || rightTableName !== join.table2) {
        throw new Error('Некорректные условия JOIN.');
      }

      const joinRecords = joinTable.getAll();

      // Выполнение INNER JOIN
      records = records.flatMap(record1 => {
        return joinRecords.filter(record2 => record1[leftField] === record2[rightField])
                          .map(record2 => ({ ...record1, ...record2 }));
      });
    }

    // Применение WHERE
    if (where) {
      records = records.filter(record => evaluateWhere(record, where));
    }

    // Применение ORDER BY
    if (order) {
      const { field, direction } = order;
      if (!Object.keys(records[0] || {}).includes(field)) {
        throw new Error(`Поле "${field}" не найдено в результирующем наборе данных.`);
      }
      records.sort((a, b) => {
        if (a[field] < b[field]) return direction === 'ASC' ? -1 : 1;
        if (a[field] > b[field]) return direction === 'ASC' ? 1 : -1;
        return 0;
      });
    }

    // Выбор полей
    if (!(selectedFields.length === 1 && selectedFields[0] === '*')) {
      records = records.map(record => {
        const selected = {};
        selectedFields.forEach(field => {
          if (!(field in record)) {
            throw new Error(`Поле "${field}" не найдено в таблицах.`);
          }
          selected[field] = record[field];
        });
        return selected;
      });
    }

    return records;
  }

  // Остальные методы остаются без изменений
}

// Функции для парсинга и оценки WHERE

function parseSQL(command) {
  const selectRegex = /^SELECT\s+(.+)\s+FROM\s+(\w+)(?:\s+WHERE\s+(.+?))?(?:\s+ORDER\s+BY\s+(\w+)\s+(ASC|DESC))?;?$/i;
  const insertRegex = /^INSERT\s+INTO\s+(\w+)\s*\(([^)]+)\)\s+VALUES\s*\(([^)]+)\);?$/i;
  const updateRegex = /^UPDATE\s+(\w+)\s+SET\s+([^;]+?)(?:\s+WHERE\s+(.+))?;?$/i;
  const deleteRegex = /^DELETE\s+FROM\s+(\w+)(?:\s+WHERE\s+(.+))?;?$/i;

  // Новое регулярное выражение для JOIN
  const joinRegex = /^SELECT\s+(.+)\s+FROM\s+(\w+)\s+JOIN\s+(\w+)\s+ON\s+(\w+\.\w+)\s*=\s*(\w+\.\w+)(?:\s+WHERE\s+(.+?))?(?:\s+ORDER\s+BY\s+(\w+)\s+(ASC|DESC))?;?$/i;

  let match = command.match(joinRegex);
  if (match) {
    const fields = match[1].split(',').map(f => f.trim());
    const table1 = match[2];
    const table2 = match[3];
    const joinConditionLeft = match[4];
    const joinConditionRight = match[5];
    const where = match[6] ? parseWhere(match[6]) : null;
    const orderField = match[7];
    const orderDirection = match[8] ? match[8].toUpperCase() : 'ASC';
    const order = orderField ? { field: orderField, direction: orderDirection } : null;
    return { 
      type: 'JOIN', // Обновлено
      fields, 
      table1, 
      table2, 
      joinCondition: { left: joinConditionLeft, right: joinConditionRight }, // Добавлено
      where, 
      order 
    };
  }

  let matchSelect = command.match(selectRegex);
  if (matchSelect) {
    const fields = matchSelect[1].split(',').map(f => f.trim());
    const tableName = matchSelect[2];
    const where = matchSelect[3] ? parseWhere(matchSelect[3]) : null;
    const orderField = matchSelect[4];
    const orderDirection = matchSelect[5] ? matchSelect[5].toUpperCase() : 'ASC';
    const order = orderField ? { field: orderField, direction: orderDirection } : null;
    return { type: 'SELECT', tableName, fields, where, order };
  }

  let matchInsert = command.match(insertRegex);
  if (matchInsert) {
    const tableName = matchInsert[1];
    const fields = matchInsert[2].split(',').map(f => f.trim());
    const values = matchInsert[3].split(',').map(v => {
      v = v.trim();
      if (v.startsWith('"') && v.endsWith('"')) {
        return v.slice(1, -1);
      }
      if (v.startsWith("'") && v.endsWith("'")) {
        return v.slice(1, -1);
      }
      return Number(v);
    });
    const record = {};
    fields.forEach((field, index) => {
      record[field] = values[index];
    });
    return { type: 'INSERT', tableName, values: record };
  }

  let matchUpdate = command.match(updateRegex);
  if (matchUpdate) {
    const tableName = matchUpdate[1];
    const setClauses = matchUpdate[2].split(',').map(c => c.trim());
    const fields = {};
    setClauses.forEach(clause => {
      const [field, value] = clause.split('=').map(s => s.trim());
      let processedValue = value;
      if (value.startsWith('"') && value.endsWith('"')) {
        processedValue = value.slice(1, -1);
      }
      if (value.startsWith("'") && value.endsWith("'")) {
        processedValue = value.slice(1, -1);
      }
      if (!isNaN(Number(processedValue))) {
        processedValue = Number(processedValue);
      }
      fields[field] = processedValue;
    });
    const where = matchUpdate[3] ? parseWhere(matchUpdate[3]) : null;
    return { type: 'UPDATE', tableName, fields, where };
  }

  let matchDelete = command.match(deleteRegex);
  if (matchDelete) {
    const tableName = matchDelete[1];
    const where = matchDelete[2] ? parseWhere(matchDelete[2]) : null;
    return { type: 'DELETE', tableName, where };
  }

  return null;
}

function parseWhere(whereClause) {
  // Поддержка простых условий вида "field operator value"
  const operators = ['>=', '<=', '!=', '=', '>', '<'];
  for (let op of operators) {
    const parts = whereClause.split(op);
    if (parts.length === 2) {
      const field = parts[0].trim();
      let value = parts[1].trim();
      if (value.startsWith('"') && value.endsWith('"')) {
        value = value.slice(1, -1);
      }
      if (value.startsWith("'") && value.endsWith("'")) {
        value = value.slice(1, -1);
      }
      if (!isNaN(Number(value))) {
        value = Number(value);
      }
      return { field, operator: op, value };
    }
  }
  return null;
}

function evaluateWhere(record, where) {
  const { field, operator, value } = where;
  const recordValue = record[field];
  switch (operator) {
    case '=':
      return recordValue === value;
    case '!=':
      return recordValue !== value;
    case '>':
      return recordValue > value;
    case '<':
      return recordValue < value;
    case '>=':
      return recordValue >= value;
    case '<=':
      return recordValue <= value;
    default:
      return false;
  }
}

// Инициализация приложения
const app = express();

// Настройка промежуточного ПО
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json()); // Для обработки JSON тел запросов
app.use(express.static(path.join(__dirname, 'public')));

// Настройка сессий
app.use(session({
  secret: 'your-secret-key', // Замените на ваш секрет
  resave: false,
  saveUninitialized: false
}));

// Функция для рендеринга HTML страниц с добавлением стилей и анимаций
function renderPage(res, title, content) {
  const html = `
  <!DOCTYPE html>
  <html lang="ru">
  <head>
    <meta charset="UTF-8">
    <title>${title}</title>
    <!-- Bootstrap CSS -->
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
    <!-- Animate.css for animations -->
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.1.1/animate.min.css"/>
    <!-- Highlight.js for syntax highlighting -->
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.7.0/styles/default.min.css">
    <style>
      body {
        padding-top: 70px;
        background-color: #f0f2f5;
        font-family: 'Roboto', sans-serif;
      }
      .table-actions {
        display: flex;
        gap: 5px;
      }
      /* Стиль для консоли */
      #command-console {
        width: 100%;
        height: 200px;
      }
      #command-result {
        white-space: pre-wrap;
        background-color: #ffffff;
        padding: 15px;
        border: 1px solid #ced4da;
        border-radius: 4px;
        height: 200px;
        overflow-y: scroll;
        box-shadow: inset 0 1px 3px rgba(0,0,0,0.1);
      }
      /* Кастомные стили */
      .navbar-brand {
        font-weight: bold;
        font-size: 1.5rem;
        animation: fadeInDown 1s;
      }
      table {
        animation: fadeIn 1s;
      }
      .btn-primary {
        transition: background-color 0.3s, transform 0.3s;
      }
      .btn-primary:hover {
        background-color: #0056b3;
        transform: scale(1.05);
      }
      .btn-success, .btn-danger, .btn-secondary {
        transition: transform 0.3s;
      }
      .btn-success:hover, .btn-danger:hover, .btn-secondary:hover {
        transform: scale(1.05);
      }
      /* Анимации для содержимого контейнера */
      .container {
        animation: fadeInUp 1s;
      }
      /* Ховеры для строк таблицы */
      table tbody tr:hover {
        background-color: #f1f1f1;
        transition: background-color 0.3s;
      }
      /* Дополнительные стили для документации */
      .documentation {
        margin-top: 30px;
      }
      .documentation pre {
        background-color: #f8f9fa;
        padding: 15px;
        border-radius: 5px;
      }
    </style>
  </head>
  <body>
    <nav class="navbar navbar-expand-lg navbar-dark bg-dark fixed-top animate__animated animate__fadeInDown">
      <a class="navbar-brand" href="/">Custom DB Manager</a>
      <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNav" 
              aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
        <span class="navbar-toggler-icon"></span>
      </button>
      ${title !== 'Вход' && title !== 'Регистрация' ? `
      <div class="collapse navbar-collapse" id="navbarNav">
        <ul class="navbar-nav mr-auto">
          <li class="nav-item ${title === 'Список Таблиц' ? 'active' : ''}">
            <a class="nav-link" href="/">Таблицы</a>
          </li>
          <li class="nav-item ${title === 'Создать Таблицу' ? 'active' : ''}">
            <a class="nav-link" href="/create-table">Создать Таблицу</a>
          </li>
          <li class="nav-item ${title === 'Выполнить Команду' ? 'active' : ''}">
            <a class="nav-link" href="/execute-command">Выполнить Команду</a>
          </li>
        </ul>
        <span class="navbar-text mr-3">
          Привет, ${app.locals.currentUser || 'Гость'}!
        </span>
        <a href="/logout" class="btn btn-outline-light">Выйти</a>
      </div>
      ` : ''}
    </nav>
    <div class="container mt-4 animate__animated animate__fadeInUp">
      ${content}
    </div>
    <!-- Bootstrap JS и зависимости -->
    <script src="https://code.jquery.com/jquery-3.5.1.slim.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.1/dist/umd/popper.min.js"></script>
    <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"></script>
    <!-- Highlight.js -->
    <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.7.0/highlight.min.js"></script>
    <script>hljs.highlightAll();</script>
    <!-- Дополнительные скрипты для анимаций -->
    <script>
      // Пример анимации при загрузке страницы
      document.addEventListener('DOMContentLoaded', () => {
        const elements = document.querySelectorAll('.animate-on-load');
        elements.forEach(el => {
          el.classList.add('animate__animated', 'animate__fadeIn');
        });
      });
    </script>
  </body>
  </html>
  `;
  res.send(html);
}

// -----------------------------------------------------------------------------------
// Функции управления пользователями
// -----------------------------------------------------------------------------------

// Функция сохранения пользователей в файл
function saveUsers() {
  fs.writeFileSync(USERS_FILE, JSON.stringify(users, null, 2), 'utf8');
  console.log(`Пользователи сохранены в ${USERS_FILE}`);
}

// Функция для поиска пользователя по имени
function findUser(username) {
  return users.find(user => user.username === username);
}

// Функция для поиска пользователя по токену
function findUserByToken(token) {
  return users.find(user => user.token === token);
}

// -----------------------------------------------------------------------------------
// Маршруты аутентификации
// -----------------------------------------------------------------------------------

// Страница регистрации
app.get('/register', (req, res) => {
  const content = `
    <h1 class="animate__animated animate__fadeInDown">Регистрация</h1>
    <form action="/register" method="POST" class="animate__animated animate__fadeIn">
      <div class="form-group">
        <label for="username">Имя пользователя</label>
        <input type="text" class="form-control" id="username" name="username" placeholder="Введите имя пользователя" required>
      </div>
      <div class="form-group">
        <label for="password">Пароль</label>
        <input type="password" class="form-control" id="password" name="password" placeholder="Введите пароль" required>
      </div>
      <button type="submit" class="btn btn-primary animate__animated animate__fadeIn">Зарегистрироваться</button>
      <a href="/login" class="btn btn-secondary animate__animated animate__fadeIn">Войти</a>
    </form>
  `;
  renderPage(res, 'Регистрация', content);
});

// Обработка регистрации
app.post('/register', async (req, res) => {
  const { username, password } = req.body;
  try {
    // Проверка наличия пользователя
    if (findUser(username)) {
      throw new Error('Имя пользователя уже занято.');
    }

    // Хеширование пароля
    const passwordHash = await bcrypt.hash(password, SALT_ROUNDS);

    // Генерация уникального токена
    const token = uuidv4();

    // Создание пользователя
    const newUser = { username, passwordHash, token };
    users.push(newUser);
    saveUsers();

    // Создание папки пользователя
    const userDir = path.join(BD_DIR, username);
    if (!fs.existsSync(userDir)) {
      fs.mkdirSync(userDir);
    }

    // Инициализация базы данных пользователя
    const userDBPath = path.join(userDir, 'database.json');
    if (!fs.existsSync(userDBPath)) {
      const emptyDB = { tables: {} };
      fs.writeFileSync(userDBPath, JSON.stringify(emptyDB, null, 2), 'utf8');
    }

    // Перенаправление на страницу входа
    res.redirect('/login');
  } catch (error) {
    const content = `
      <div class="alert alert-danger animate__animated animate__fadeIn" role="alert">
        <h4 class="alert-heading">Ошибка регистрации</h4>
        <p>${escapeHTML(error.message)}</p>
        <hr>
        <a href="/register" class="btn btn-primary animate__animated animate__fadeIn">Попробовать снова</a>
      </div>
    `;
    renderPage(res, 'Ошибка регистрации', content);
  }
});

// Страница входа
app.get('/login', (req, res) => {
  const content = `
    <h1 class="animate__animated animate__fadeInDown">Вход</h1>
    <form action="/login" method="POST" class="animate__animated animate__fadeIn">
      <div class="form-group">
        <label for="username">Имя пользователя</label>
        <input type="text" class="form-control" id="username" name="username" placeholder="Введите имя пользователя" required>
      </div>
      <div class="form-group">
        <label for="password">Пароль</label>
        <input type="password" class="form-control" id="password" name="password" placeholder="Введите пароль" required>
      </div>
      <button type="submit" class="btn btn-primary animate__animated animate__fadeIn">Войти</button>
      <a href="/register" class="btn btn-secondary animate__animated animate__fadeIn">Регистрация</a>
    </form>
  `;
  renderPage(res, 'Вход', content);
});

// Обработка входа
app.post('/login', async (req, res) => {
  const { username, password } = req.body;
  try {
    const user = findUser(username);
    if (!user) {
      throw new Error('Неверное имя пользователя или пароль.');
    }

    const passwordMatch = await bcrypt.compare(password, user.passwordHash);
    if (!passwordMatch) {
      throw new Error('Неверное имя пользователя или пароль.');
    }

    // Установка сессии
    req.session.username = username;
    res.redirect('/');
  } catch (error) {
    const content = `
      <div class="alert alert-danger animate__animated animate__fadeIn" role="alert">
        <h4 class="alert-heading">Ошибка входа</h4>
        <p>${escapeHTML(error.message)}</p>
        <hr>
        <a href="/login" class="btn btn-primary animate__animated animate__fadeIn">Попробовать снова</a>
      </div>
    `;
    renderPage(res, 'Ошибка входа', content);
  }
});

// Обработка выхода
app.get('/logout', (req, res) => {
  req.session.destroy(() => {
    res.redirect('/login');
  });
});

// -----------------------------------------------------------------------------------
// Middleware для защиты маршрутов
// -----------------------------------------------------------------------------------
function isAuthenticated(req, res, next) {
  if (req.session.username) {
    app.locals.currentUser = req.session.username; // Для отображения в навбаре
    return next();
  }
  res.redirect('/login');
}

// -----------------------------------------------------------------------------------
// Веб-интерфейс (существующий код, теперь защищенный аутентификацией)
// -----------------------------------------------------------------------------------

// Главная страница - список таблиц
app.get('/', isAuthenticated, (req, res) => {
  const username = req.session.username;
  const userDBPath = path.join(BD_DIR, username, 'database.json');

  // Инициализация базы данных пользователя
  const db = new Database(userDBPath);
  db.loadFromFile();

  const tables = db.getTables();
  let content = `<h1 class="animate__animated animate__fadeInDown">Список Таблиц</h1>`;

  // Добавление раздела для отображения и управления токеном
  const user = findUser(username);
  content += `
    <script>
      function copyToken() {
        const tokenInput = document.querySelector('input[readonly]');
        tokenInput.select();
        tokenInput.setSelectionRange(0, 99999); // Для мобильных устройств
        document.execCommand('copy');
        alert('Токен скопирован в буфер обмена.');
      }

      function regenerateToken() {
        if (confirm('Вы уверены, что хотите сгенерировать новый токен? Старый токен станет недействительным.')) {
          fetch('/regenerate-token', { method: 'POST' })
            .then(response => response.json())
            .then(data => {
              if (data.success) {
                alert('Новый токен сгенерирован.');
                location.reload();
              } else {
                alert('Ошибка: ' + data.message);
              }
            })
            .catch(err => {
              alert('Произошла ошибка.');
            });
        }
      }
    </script>
  `;

  if (tables.length === 0) {
    content += `<div class="alert alert-info animate__animated animate__fadeIn">Нет созданных таблиц. Создайте первую таблицу <a href="/create-table">здесь</a>.</div>`;
  } else {
    content += `
    <table class="table table-bordered table-hover">
      <thead class="thead-dark">
        <tr>
          <th>Название Таблицы</th>
          <th>Действия</th>
        </tr>
      </thead>
      <tbody>
    `;
    tables.forEach(table => {
      content += `
        <tr>
          <td><a href="/table/${encodeURIComponent(table)}" class="animate__animated animate__fadeInUp">${table}</a></td>
          <td>
            <div class="table-actions">
              <a href="/table/${encodeURIComponent(table)}/manage-schema" class="btn btn-secondary btn-sm animate__animated animate__fadeIn">Управление Структурой</a>
              <form action="/drop-table/${encodeURIComponent(table)}" method="POST" onsubmit="return confirm('Вы уверены, что хотите удалить таблицу ${table}?');" class="mb-0">
                <button type="submit" class="btn btn-danger btn-sm animate__animated animate__fadeIn">Удалить</button>
              </form>
            </div>
          </td>
        </tr>
      `;
    });
    content += `
      </tbody>
    </table>
    `;
  }
  renderPage(res, 'Список Таблиц', content);
});

// Обработка запроса на регенерацию токена
app.post('/regenerate-token', isAuthenticated, (req, res) => {
  const username = req.session.username;
  const user = findUser(username);
  if (!user) {
    return res.status(400).json({ success: false, message: 'Пользователь не найден.' });
  }
  user.token = uuidv4();
  saveUsers();
  res.json({ success: true });
});

// Страница регистрации новой таблицы
app.get('/create-table', isAuthenticated, (req, res) => {
  const content = `
    <h1 class="animate__animated animate__fadeInDown">Создать Новую Таблицу</h1>
    <form action="/create-table" method="POST" class="animate__animated animate__fadeIn">
      <div class="form-group">
        <label for="tableName">Название Таблицы</label>
        <input type="text" class="form-control" id="tableName" name="tableName" placeholder="Введите название таблицы" required>
      </div>
      <div class="form-group">
        <label for="columns">Поля таблицы</label>
        <div id="columns-container">
          <div class="form-row mb-2 animate__animated animate__fadeIn">
            <div class="col-md-4">
              <input type="text" class="form-control" name="columnNames" placeholder="Имя колонки" required>
            </div>
            <div class="col-md-4">
              <select class="form-control" name="columnTypes" required>
                <option value="" disabled selected>Выберите тип</option>
                <option value="number">Number</option>
                <option value="string">String</option>
              </select>
            </div>
            <div class="col-md-4">
              <button type="button" class="btn btn-outline-danger remove-column animate__animated animate__fadeIn">&times;</button>
            </div>
          </div>
        </div>
        <button type="button" class="btn btn-outline-primary" id="add-column">Добавить Колонку</button>
        <small class="form-text text-muted">Минимум одно поле должно быть "id: number".</small>
      </div>
      <div class="form-group form-check">
        <input type="checkbox" class="form-check-input" id="autoIncrement" name="autoIncrement">
        <label class="form-check-label" for="autoIncrement">Автоинкремент для поля "id"</label>
      </div>
      <button type="submit" class="btn btn-primary animate__animated animate__fadeIn">Создать Таблицу</button>
      <a href="/" class="btn btn-secondary animate__animated animate__fadeIn">Отмена</a>
    </form>

    <script>
      document.addEventListener('DOMContentLoaded', function() {
        const addColumnButton = document.getElementById('add-column');
        const columnsContainer = document.getElementById('columns-container');

        addColumnButton.addEventListener('click', function() {
          const newColumn = document.createElement('div');
          newColumn.className = 'form-row mb-2 animate__animated animate__fadeIn';
          newColumn.innerHTML = \`
            <div class="col-md-4">
              <input type="text" class="form-control" name="columnNames" placeholder="Имя колонки" required>
            </div>
            <div class="col-md-4">
              <select class="form-control" name="columnTypes" required>
                <option value="" disabled selected>Выберите тип</option>
                <option value="number">Number</option>
                <option value="string">String</option>
              </select>
            </div>
            <div class="col-md-4">
              <button type="button" class="btn btn-outline-danger remove-column animate__animated animate__fadeIn">&times;</button>
            </div>
          \`;
          columnsContainer.appendChild(newColumn);
        });

        columnsContainer.addEventListener('click', function(e) {
          if (e.target && e.target.classList.contains('remove-column')) {
            const row = e.target.closest('.form-row');
            row.classList.add('animate__animated', 'animate__fadeOut');
            row.addEventListener('animationend', function() {
              row.remove();
            });
          }
        });
      });
    </script>
  `;
  renderPage(res, 'Создать Таблицу', content);
});

// Обработка создания новой таблицы
app.post('/create-table', isAuthenticated, (req, res) => {
  const username = req.session.username;
  const userDBPath = path.join(BD_DIR, username, 'database.json');
  const { tableName, autoIncrement } = req.body;
  // Получение массивов имен и типов колонок
  let columnNames = req.body.columnNames;
  let columnTypes = req.body.columnTypes;

  // Обеспечение того, что columnNames и columnTypes являются массивами
  if (!Array.isArray(columnNames)) {
    columnNames = [columnNames];
  }
  if (!Array.isArray(columnTypes)) {
    columnTypes = [columnTypes];
  }

  try {
    // Парсинг колонок
    const schema = {};
    for (let i = 0; i < columnNames.length; i++) {
      const name = columnNames[i].trim();
      const type = columnTypes[i].trim().toLowerCase();

      if (!name) {
        throw new Error(`Имя колонки в строке ${i + 1} не может быть пустым.`);
      }

      if (!['number', 'string'].includes(type)) {
        throw new Error(`Некорректный тип колонки "${name}" в строке ${i + 1}. Допустимые типы: number, string.`);
      }

      if (schema[name]) {
        throw new Error(`Дублирующееся имя колонки: "${name}" в строке ${i + 1}.`);
      }

      schema[name] = type;
    }

    // Проверка наличия обязательной колонки 'id'
    if (!schema.id) {
      throw new Error('Необходимо указать колонку "id: number" в качестве уникального идентификатора.');
    }

    if (schema.id !== 'number') {
      throw new Error('Колонка "id" должна быть типа "number".');
    }

    // Проверка на уникальность имен колонок
    const uniqueColumns = new Set(Object.keys(schema));
    if (uniqueColumns.size !== Object.keys(schema).length) {
      throw new Error('Имена колонок должны быть уникальными.');
    }

    // Проверка автоинкремента: если включен, убедимся, что 'id' присутствует и числовой
    const isAutoIncrement = autoIncrement === 'on';

    // Инициализация базы данных пользователя
    const db = new Database(userDBPath);
    db.loadFromFile();

    db.createTable(tableName, schema, isAutoIncrement);
    res.redirect('/');
  } catch (error) {
    const content = `
      <div class="alert alert-danger animate__animated animate__fadeIn" role="alert">
        <h4 class="alert-heading">Ошибка</h4>
        <p>${escapeHTML(error.message)}</p>
        <hr>
        <a href="/create-table" class="btn btn-primary animate__animated animate__fadeIn">Назад</a>
      </div>
    `;
    renderPage(res, 'Ошибка', content);
  }
});

// Страница управления структурой таблицы
app.get('/table/:tableName/manage-schema', isAuthenticated, (req, res) => {
  const username = req.session.username;
  const tableName = req.params.tableName;
  const userDBPath = path.join(BD_DIR, username, 'database.json');

  try {
    const db = new Database(userDBPath);
    db.loadFromFile();

    const schema = db.getTableSchema(tableName);
    const autoIncrement = db.getTableAutoIncrement(tableName);
    let content = `<h1 class="animate__animated animate__fadeInDown">Управление Структурой Таблицы: ${tableName}</h1>`;

    // Форма добавления новой колонки
    content += `
      <h3 class="animate__animated animate__fadeInUp">Добавить Новую Колонку</h3>
      <form action="/table/${encodeURIComponent(tableName)}/add-column" method="POST" class="animate__animated animate__fadeIn">
        <div class="form-row">
          <div class="col-md-5 mb-3">
            <label for="columnName">Название Колонки</label>
            <input type="text" class="form-control" id="columnName" name="columnName" placeholder="Например: email" required>
          </div>
          <div class="col-md-5 mb-3">
            <label for="columnType">Тип Колонки</label>
            <select class="form-control" id="columnType" name="columnType" required>
              <option value="" disabled selected>Выберите тип</option>
              <option value="number">Number</option>
              <option value="string">String</option>
            </select>
          </div>
          <div class="col-md-2 mb-3 align-self-end">
            <button type="submit" class="btn btn-success animate__animated animate__fadeIn">Добавить</button>
          </div>
        </div>
      </form>
    `;

    // Таблица текущей схемы
    content += `
      <h3 class="animate__animated animate__fadeInUp">Текущая Структура Таблицы</h3>
      <table class="table table-bordered table-hover">
        <thead class="thead-light">
          <tr>
            <th>Название Колонки</th>
            <th>Тип</th>
            <th>Действия</th>
          </tr>
        </thead>
        <tbody>
    `;
    for (let field in schema) {
      content += `
        <tr>
          <td>${field}</td>
          <td>${schema[field]}</td>
          <td>
            ${field !== 'id' ? `
            <form action="/table/${encodeURIComponent(tableName)}/delete-column" method="POST" onsubmit="return confirm('Вы уверены, что хотите удалить колонку "${field}"? Это приведет к потере всех данных в этой колонке.');" class="mb-0 animate__animated animate__fadeIn">
              <input type="hidden" name="columnName" value="${field}">
              <button type="submit" class="btn btn-danger btn-sm">Удалить</button>
            </form>
            ` : `
            <span class="text-muted">Обязательная колонка ${autoIncrement ? '(Автоинкремент)' : ''}</span>
            `}
          </td>
        </tr>
      `;
    }
    content += `
        </tbody>
      </table>
      <a href="/table/${encodeURIComponent(tableName)}" class="btn btn-secondary animate__animated animate__fadeIn">Назад</a>
    `;
    renderPage(res, `Управление Структурой ${tableName}`, content);
  } catch (error) {
    const content = `
      <div class="alert alert-danger animate__animated animate__fadeIn" role="alert">
        <h4 class="alert-heading">Ошибка</h4>
        <p>${escapeHTML(error.message)}</p>
        <hr>
        <a href="/" class="btn btn-primary animate__animated animate__fadeIn">Назад</a>
      </div>
    `;
    renderPage(res, 'Ошибка', content);
  }
});

// Обработка добавления новой колонки
app.post('/table/:tableName/add-column', isAuthenticated, (req, res) => {
  const username = req.session.username;
  const tableName = req.params.tableName;
  const { columnName, columnType } = req.body;
  const userDBPath = path.join(BD_DIR, username, 'database.json');

  try {
    if (columnName.toLowerCase() === 'id') {
      throw new Error('Невозможно добавить колонку с именем "id". Оно зарезервировано.');
    }
    const db = new Database(userDBPath);
    db.loadFromFile();
    db.addColumn(tableName, columnName, columnType);
    res.redirect(`/table/${encodeURIComponent(tableName)}/manage-schema`);
  } catch (error) {
    const content = `
      <div class="alert alert-danger animate__animated animate__fadeIn" role="alert">
        <h4 class="alert-heading">Ошибка</h4>
        <p>${escapeHTML(error.message)}</p>
        <hr>
        <a href="/table/${encodeURIComponent(tableName)}/manage-schema" class="btn btn-primary animate__animated animate__fadeIn">Назад</a>
      </div>
    `;
    renderPage(res, 'Ошибка', content);
  }
});

// Обработка удаления колонки
app.post('/table/:tableName/delete-column', isAuthenticated, (req, res) => {
  const username = req.session.username;
  const tableName = req.params.tableName;
  const { columnName } = req.body;
  const userDBPath = path.join(BD_DIR, username, 'database.json');

  try {
    const db = new Database(userDBPath);
    db.loadFromFile();
    db.deleteColumn(tableName, columnName);
    res.redirect(`/table/${encodeURIComponent(tableName)}/manage-schema`);
  } catch (error) {
    const content = `
      <div class="alert alert-danger animate__animated animate__fadeIn" role="alert">
        <h4 class="alert-heading">Ошибка</h4>
        <p>${escapeHTML(error.message)}</p>
        <hr>
        <a href="/table/${encodeURIComponent(tableName)}/manage-schema" class="btn btn-primary animate__animated animate__fadeIn">Назад</a>
      </div>
    `;
    renderPage(res, 'Ошибка', content);
  }
});

// Страница отображения таблицы и ее записей
app.get('/table/:tableName', isAuthenticated, (req, res) => {
  const username = req.session.username;
  const tableName = req.params.tableName;
  const userDBPath = path.join(BD_DIR, username, 'database.json');

  try {
    const db = new Database(userDBPath);
    db.loadFromFile();

    const records = db.getAll(tableName);
    const schema = db.getTableSchema(tableName);
    const autoIncrement = db.getTableAutoIncrement(tableName);
    let content = `<h1 class="animate__animated animate__fadeInDown">Таблица: ${tableName}</h1>`;
    content += `
      <div class="mb-3">
        <a href="/table/${encodeURIComponent(tableName)}/add" class="btn btn-success animate__animated animate__fadeIn">Добавить Запись</a>
        <a href="/table/${encodeURIComponent(tableName)}/manage-schema" class="btn btn-secondary animate__animated animate__fadeIn">Управление Структурой</a>
      </div>
    `;
    content += `
      <div class="table-responsive">
        <table class="table table-bordered table-hover">
          <thead class="thead-dark">
            <tr>
    `;
    for (let field in schema) {
      content += `<th>${field}</th>`;
    }
    content += `<th>Действия</th></tr></thead><tbody>`;
    if (records.length === 0) {
      content += `
        <tr>
          <td colspan="${Object.keys(schema).length + 1}" class="text-center">Нет записей.</td>
        </tr>
      `;
    } else {
      records.forEach(record => {
        content += `<tr class="animate__animated animate__fadeInUp">`;
        for (let field in schema) {
          content += `<td>${record[field]}</td>`;
        }
        content += `
          <td>
            <div class="table-actions">
              <a href="/table/${encodeURIComponent(tableName)}/edit/${encodeURIComponent(record.id)}" class="btn btn-primary btn-sm animate__animated animate__fadeIn">Редактировать</a>
              <form action="/table/${encodeURIComponent(tableName)}/delete/${encodeURIComponent(record.id)}" method="POST" onsubmit="return confirm('Вы уверены, что хотите удалить запись с id=${record.id}?');" class="mb-0 animate__animated animate__fadeIn">
                <button type="submit" class="btn btn-danger btn-sm">Удалить</button>
              </form>
            </div>
          </td>
        `;
        content += `</tr>`;
      });
    }
    content += `</tbody></table></div>`;
    content += `<a href="/" class="btn btn-secondary animate__animated animate__fadeIn">Назад</a>`;
    renderPage(res, `Таблица: ${tableName}`, content);
  } catch (error) {
    const content = `
      <div class="alert alert-danger animate__animated animate__fadeIn" role="alert">
        <h4 class="alert-heading">Ошибка</h4>
        <p>${escapeHTML(error.message)}</p>
        <hr>
        <a href="/" class="btn btn-primary animate__animated animate__fadeIn">Назад</a>
      </div>
    `;
    renderPage(res, 'Ошибка', content);
  }
});

// Страница добавления новой записи
app.get('/table/:tableName/add', isAuthenticated, (req, res) => {
  const username = req.session.username;
  const tableName = req.params.tableName;
  const userDBPath = path.join(BD_DIR, username, 'database.json');

  try {
    const db = new Database(userDBPath);
    db.loadFromFile();

    const schema = db.getTableSchema(tableName);
    const autoIncrement = db.getTableAutoIncrement(tableName);
    let formFields = '';
    for (let field in schema) {
      if (field === 'id' && autoIncrement) {
        // Если автоинкремент, не отображаем поле id
        continue;
      }
      formFields += `
        <div class="form-group animate__animated animate__fadeIn">
          <label for="${field}">${field} (${schema[field]})</label>
          ${schema[field] === 'number' ? `
            <input type="number" class="form-control" id="${field}" name="${field}" required>
          ` : `
            <input type="text" class="form-control" id="${field}" name="${field}" required>
          `}
        </div>
      `;
    }
    const content = `
      <h1 class="animate__animated animate__fadeInDown">Добавить Запись в Таблицу: ${tableName}</h1>
      <form action="/table/${encodeURIComponent(tableName)}/add" method="POST" class="animate__animated animate__fadeIn">
        ${formFields}
        <button type="submit" class="btn btn-primary animate__animated animate__fadeIn">Добавить Запись</button>
        <a href="/table/${encodeURIComponent(tableName)}" class="btn btn-secondary animate__animated animate__fadeIn">Отмена</a>
      </form>
    `;
    renderPage(res, `Добавить Запись в ${tableName}`, content);
  } catch (error) {
    const content = `
      <div class="alert alert-danger animate__animated animate__fadeIn" role="alert">
        <h4 class="alert-heading">Ошибка</h4>
        <p>${escapeHTML(error.message)}</p>
        <hr>
        <a href="/" class="btn btn-primary animate__animated animate__fadeIn">Назад</a>
      </div>
    `;
    renderPage(res, 'Ошибка', content);
  }
});

// Обработка добавления новой записи
app.post('/table/:tableName/add', isAuthenticated, (req, res) => {
  const username = req.session.username;
  const tableName = req.params.tableName;
  const record = req.body;
  const userDBPath = path.join(BD_DIR, username, 'database.json');

  try {
    const db = new Database(userDBPath);
    db.loadFromFile();

    const schema = db.getTableSchema(tableName);
    const autoIncrement = db.getTableAutoIncrement(tableName);

    // Если автоинкремент для 'id', удаляем ручной ввод 'id' (если он был)
    if (autoIncrement && record.id !== undefined) {
      delete record.id;
    }

    // Преобразование типов полей
    for (const field in record) {
      if (schema[field] === 'number') {
        record[field] = Number(record[field]);
        if (isNaN(record[field])) {
          throw new Error(`Поле "${field}" должно быть числом.`);
        }
      }
    }

    db.insert(tableName, record);
    res.redirect(`/table/${encodeURIComponent(tableName)}`);
  } catch (error) {
    const content = `
      <div class="alert alert-danger animate__animated animate__fadeIn" role="alert">
        <h4 class="alert-heading">Ошибка</h4>
        <p>${escapeHTML(error.message)}</p>
        <hr>
        <a href="/table/${encodeURIComponent(tableName)}/add" class="btn btn-primary animate__animated animate__fadeIn">Назад</a>
      </div>
    `;
    renderPage(res, 'Ошибка', content);
  }
});

// Страница редактирования записи
app.get('/table/:tableName/edit/:id', isAuthenticated, (req, res) => {
  const username = req.session.username;
  const tableName = req.params.tableName;
  const id = req.params.id;
  const userDBPath = path.join(BD_DIR, username, 'database.json');

  try {
    const db = new Database(userDBPath);
    db.loadFromFile();

    const record = db.getRecord(tableName, Number(id));
    if (!record) {
      throw new Error(`Запись с id=${id} не найдена.`);
    }
    const schema = db.getTableSchema(tableName);
    const autoIncrement = db.getTableAutoIncrement(tableName);
    let formFields = '';
    for (let field in schema) {
      if (field === 'id' && autoIncrement) {
        // Если автоинкремент, не редактируем поле id
        continue;
      }
      formFields += `
        <div class="form-group animate__animated animate__fadeIn">
          <label for="${field}">${field} (${schema[field]})</label>
          ${schema[field] === 'number' ? `
            <input type="number" class="form-control" id="${field}" name="${field}" value="${record[field]}" required>
          ` : `
            <input type="text" class="form-control" id="${field}" name="${field}" value="${record[field]}" required>
          `}
        </div>
      `;
    }
    const content = `
      <h1 class="animate__animated animate__fadeInDown">Редактировать Запись в Таблице: ${tableName}</h1>
      <form action="/table/${encodeURIComponent(tableName)}/edit/${encodeURIComponent(id)}" method="POST" class="animate__animated animate__fadeIn">
        ${formFields}
        <button type="submit" class="btn btn-primary animate__animated animate__fadeIn">Сохранить Изменения</button>
        <a href="/table/${encodeURIComponent(tableName)}" class="btn btn-secondary animate__animated animate__fadeIn">Отмена</a>
      </form>
    `;
    renderPage(res, `Редактировать Запись в ${tableName}`, content);
  } catch (error) {
    const content = `
      <div class="alert alert-danger animate__animated animate__fadeIn" role="alert">
        <h4 class="alert-heading">Ошибка</h4>
        <p>${escapeHTML(error.message)}</p>
        <hr>
        <a href="/" class="btn btn-primary animate__animated animate__fadeIn">Назад</a>
      </div>
    `;
    renderPage(res, 'Ошибка', content);
  }
});

// Обработка редактирования записи
app.post('/table/:tableName/edit/:id', isAuthenticated, (req, res) => {
  const username = req.session.username;
  const tableName = req.params.tableName;
  const id = req.params.id;
  const newRecord = req.body;
  const userDBPath = path.join(BD_DIR, username, 'database.json');

  try {
    const db = new Database(userDBPath);
    db.loadFromFile();

    const schema = db.getTableSchema(tableName);
    const autoIncrement = db.getTableAutoIncrement(tableName);

    // Если автоинкремент для 'id', удаляем ручной ввод 'id' (если он был)
    if (autoIncrement && newRecord.id !== undefined) {
      delete newRecord.id;
    }

    // Преобразование типов полей
    for (const field in newRecord) {
      if (schema[field] === 'number') {
        newRecord[field] = Number(newRecord[field]);
        if (isNaN(newRecord[field])) {
          throw new Error(`Поле "${field}" должно быть числом.`);
        }
      }
    }

    const success = db.updateRecord(tableName, Number(id), newRecord);
    if (!success) {
      throw new Error(`Запись с id=${id} не найдена.`);
    }
    res.redirect(`/table/${encodeURIComponent(tableName)}`);
  } catch (error) {
    const content = `
      <div class="alert alert-danger animate__animated animate__fadeIn" role="alert">
        <h4 class="alert-heading">Ошибка</h4>
        <p>${escapeHTML(error.message)}</p>
        <hr>
        <a href="/table/${encodeURIComponent(tableName)}/edit/${encodeURIComponent(id)}" class="btn btn-primary animate__animated animate__fadeIn">Назад</a>
      </div>
    `;
    renderPage(res, 'Ошибка', content);
  }
});

// Обработка удаления записи
app.post('/table/:tableName/delete/:id', isAuthenticated, (req, res) => {
  const username = req.session.username;
  const tableName = req.params.tableName;
  const id = req.params.id;
  const userDBPath = path.join(BD_DIR, username, 'database.json');

  try {
    const db = new Database(userDBPath);
    db.loadFromFile();

    const success = db.deleteRecord(tableName, Number(id));
    if (!success) {
      throw new Error(`Запись с id=${id} не найдена.`);
    }
    res.redirect(`/table/${encodeURIComponent(tableName)}`);
  } catch (error) {
    const content = `
      <div class="alert alert-danger animate__animated animate__fadeIn" role="alert">
        <h4 class="alert-heading">Ошибка</h4>
        <p>${escapeHTML(error.message)}</p>
        <hr>
        <a href="/table/${encodeURIComponent(tableName)}" class="btn btn-primary animate__animated animate__fadeIn">Назад</a>
      </div>
    `;
    renderPage(res, 'Ошибка', content);
  }
});

// Обработка удаления таблицы
app.post('/drop-table/:tableName', isAuthenticated, (req, res) => {
  const username = req.session.username;
  const tableName = req.params.tableName;
  const userDBPath = path.join(BD_DIR, username, 'database.json');

  try {
    const db = new Database(userDBPath);
    db.loadFromFile();

    db.dropTable(tableName);
    res.redirect('/');
  } catch (error) {
    const content = `
      <div class="alert alert-danger animate__animated animate__fadeIn" role="alert">
        <h4 class="alert-heading">Ошибка</h4>
        <p>${escapeHTML(error.message)}</p>
        <hr>
        <a href="/" class="btn btn-primary animate__animated animate__fadeIn">Назад</a>
      </div>
    `;
    renderPage(res, 'Ошибка', content);
  }
});

// -----------------------------------------------------------------------------------
// Новая функция: Вкладка "Выполнить Команду" с описанием операторов и API
// -----------------------------------------------------------------------------------

// Страница выполнения команды
app.get('/execute-command', isAuthenticated, (req, res) => {
  const username = req.session.username;
  const userDBPath = path.join(BD_DIR, username, 'database.json');

  const exampleQueries = `
    <div class="accordion" id="exampleAccordion">
      <div class="card">
        <div class="card-header" id="headingOne">
          <h2 class="mb-0">
            <button class="btn btn-link btn-block text-left" type="button" data-toggle="collapse" data-target="#collapseOne" aria-expanded="true" aria-controls="collapseOne">
              Пример 1: Простый SELECT
            </button>
          </h2>
        </div>

        <div id="collapseOne" class="collapse show" aria-labelledby="headingOne" data-parent="#exampleAccordion">
          <div class="card-body">
            <pre><code class="sql">SELECT * FROM users;</code></pre>
          </div>
        </div>
      </div>
      
      <div class="card">
        <div class="card-header" id="headingTwo">
          <h2 class="mb-0">
            <button class="btn btn-link btn-block text-left collapsed" type="button" data-toggle="collapse" data-target="#collapseTwo" aria-expanded="false" aria-controls="collapseTwo">
              Пример 2: SELECT с WHERE и ORDER BY
            </button>
          </h2>
        </div>
        <div id="collapseTwo" class="collapse" aria-labelledby="headingTwo" data-parent="#exampleAccordion">
          <div class="card-body">
            <pre><code class="sql">SELECT id, name FROM users WHERE age &gt;= 18 ORDER BY name ASC;</code></pre>
          </div>
        </div>
      </div>
      
      <div class="card">
        <div class="card-header" id="headingThree">
          <h2 class="mb-0">
            <button class="btn btn-link btn-block text-left collapsed" type="button" data-toggle="collapse" data-target="#collapseThree" aria-expanded="false" aria-controls="collapseThree">
              Пример 3: SELECT с JOIN
            </button>
          </h2>
        </div>
        <div id="collapseThree" class="collapse" aria-labelledby="headingThree" data-parent="#exampleAccordion">
          <div class="card-body">
            <pre><code class="sql">SELECT users.name, orders.id FROM users JOIN orders ON users.id = orders.user_id WHERE users.age &gt; 25;</code></pre>
          </div>
        </div>
      </div>
      
      <!-- Добавьте дополнительные примеры по необходимости -->
    </div>
  `;

  const documentation = `
    <div class="documentation">
      <h2>Описание Доступных Операторов и Команд</h2>
      
      <h4>SELECT</h4>
      <p>Используется для выборки данных из одной или нескольких таблиц.</p>
      <pre><code class="sql">SELECT field1, field2 FROM table_name WHERE condition ORDER BY field ASC|DESC;</code></pre>
      
      <h4>INSERT</h4>
      <p>Используется для вставки новых записей в таблицу.</p>
      <pre><code class="sql">INSERT INTO table_name (field1, field2) VALUES (value1, value2);</code></pre>
      
      <h4>UPDATE</h4>
      <p>Используется для обновления существующих записей в таблице.</p>
      <pre><code class="sql">UPDATE table_name SET field1 = new_value1 WHERE condition;</code></pre>
      
      <h4>DELETE</h4>
      <p>Используется для удаления записей из таблицы.</p>
      <pre><code class="sql">DELETE FROM table_name WHERE condition;</code></pre>
      
      <h4>JOIN</h4>
      <p>Используется для объединения строк из двух или более таблиц на основе связанного столбца между ними.</p>
      <pre><code class="sql">SELECT fields FROM table1 JOIN table2 ON table1.field = table2.field;</code></pre>
      
      <h3>Операторы Сравнения</h3>
      <ul>
        <li><strong>=</strong>: Равно</li>
        <li><strong>!=</strong> или <strong>&lt;&gt;</strong>: Не равно</li>
        <li><strong>&gt;</strong>: Больше</li>
        <li><strong>&lt;</strong>: Меньше</li>
        <li><strong>&gt;=</strong>: Больше или равно</li>
        <li><strong>&lt;=</strong>: Меньше или равно</li>
      </ul>

      <h3>Логические Операторы</h3>
      <ul>
        <li><strong>AND</strong>: И</li>
        <li><strong>OR</strong>: Или</li>
        <li><strong>NOT</strong>: Не</li>
      </ul>

      <h2>API Доступные Маршруты</h2>
      <p>Все API маршруты требуют отправки токена в заголовке <code>Authorization: Bearer &lt;token&gt;</code>.</p>

      <h4>Получение Списка Таблиц</h4>
      <pre><code class="bash">GET /api/tables</code></pre>
      <p>Возвращает список всех таблиц пользователя.</p>

      <h4>Создание Таблицы</h4>
      <pre><code class="bash">POST /api/create-table</code></pre>
      <p>Создает новую таблицу.</p>
      <pre><code class="json">
{
  "tableName": "users",
  "schema": {
    "id": "number",
    "name": "string",
    "age": "number"
  },
  "autoIncrement": true
}
      </code></pre>

      <h4>Вставка Записи</h4>
      <pre><code class="bash">POST /api/insert</code></pre>
      <p>Вставляет новую запись в таблицу.</p>
      <pre><code class="json">
{
  "tableName": "users",
  "record": {
    "name": "Иван Иванов",
    "age": 30
  }
}
      </code></pre>

      <h4>Получение Записи по ID</h4>
      <pre><code class="bash">GET /api/record/&lt;tableName&gt;/&lt;id&gt;</code></pre>
      <p>Возвращает запись из таблицы по указанному ID.</p>

      <h4>Обновление Записи по ID</h4>
      <pre><code class="bash">PUT /api/update/&lt;tableName&gt;/&lt;id&gt;</code></pre>
      <p>Обновляет запись в таблице по указанному ID.</p>
      <pre><code class="json">
{
  "name": "Иван Петров",
  "age": 31
}
      </code></pre>

      <h4>Удаление Записи по ID</h4>
      <pre><code class="bash">DELETE /api/delete/&lt;tableName&gt;/&lt;id&gt;</code></pre>
      <p>Удаляет запись из таблицы по указанному ID.</p>
    </div>
  `;

  const exampleSection = `
    <hr>
    <h3>Примеры SQL-подобных команд:</h3>
    ${exampleQueries}
  `;

  const user = findUser(username); // Получаем информацию о пользователе

  const content = `
    <h1 class="animate__animated animate__fadeInDown">Выполнить Команду</h1>
    <div class="mb-4">
      <h3>Ваш API Токен</h3>
      <p>Используйте этот токен для API-запросов:</p>
      <div class="input-group mb-3">
        <input type="text" class="form-control" value="${user.token}" readonly>
        <div class="input-group-append">
          <button class="btn btn-outline-secondary" type="button" onclick="copyToken()">Копировать</button>
        </div>
      </div>
      <button class="btn btn-warning" onclick="regenerateToken()">Сгенерировать новый токен</button>
    </div>
    <form action="/execute-command" method="POST" class="animate__animated animate__fadeIn">
      <div class="form-group">
        <label for="command">Введите вашу SQL-подобную команду:</label>
        <textarea class="form-control" id="command" name="command" rows="4" placeholder="Например: SELECT * FROM users ORDER BY name ASC;" required></textarea>
      </div>
      <button type="submit" class="btn btn-primary animate__animated animate__fadeIn">Выполнить</button>
      <a href="/" class="btn btn-secondary animate__animated animate__fadeIn">Отмена</a>
    </form>
    <hr>
    <h3>Документация и Примеры:</h3>
    ${documentation}
    ${exampleSection}
    <script>
      function copyToken() {
        const tokenInput = document.querySelector('input[readonly]');
        tokenInput.select();
        tokenInput.setSelectionRange(0, 99999); // Для мобильных устройств
        document.execCommand('copy');
        alert('Токен скопирован в буфер обмена.');
      }

      function regenerateToken() {
        if (confirm('Вы уверены, что хотите сгенерировать новый токен? Старый токен станет недействительным.')) {
          fetch('/regenerate-token', { method: 'POST' })
            .then(response => response.json())
            .then(data => {
              if (data.success) {
                alert('Новый токен сгенерирован.');
                location.reload();
              } else {
                alert('Ошибка: ' + data.message);
              }
            })
            .catch(err => {
              alert('Произошла ошибка.');
            });
        }
      }
    </script>
  `;
  renderPage(res, 'Выполнить Команду', content);
});

// Обработка выполнения команды
app.post('/execute-command', isAuthenticated, (req, res) => {
  const username = req.session.username;
  const { command } = req.body;
  const userDBPath = path.join(BD_DIR, username, 'database.json');

  try {
    const db = new Database(userDBPath);
    db.loadFromFile();

    const result = db.executeSQLCommand(command);
    // Форматирование результата для отображения
    let displayResult;
    if (Array.isArray(result)) {
      displayResult = result;
    } else if (result.updated !== undefined) {
      displayResult = { updated: result.updated };
    } else if (result.deleted !== undefined) {
      displayResult = { deleted: result.deleted };
    } else {
      displayResult = result;
    }

    const documentation = `
      <div class="documentation">
        <h2>Описание Доступных Операторов и Команд</h2>
        
        <h4>SELECT</h4>
        <p>Используется для выборки данных из одной или нескольких таблиц.</p>
        <pre><code class="sql">SELECT field1, field2 FROM table_name WHERE condition ORDER BY field ASC|DESC;</code></pre>
        
        <h4>INSERT</h4>
        <p>Используется для вставки новых записей в таблицу.</p>
        <pre><code class="sql">INSERT INTO table_name (field1, field2) VALUES (value1, value2);</code></pre>
        
        <h4>UPDATE</h4>
        <p>Используется для обновления существующих записей в таблице.</p>
        <pre><code class="sql">UPDATE table_name SET field1 = new_value1 WHERE condition;</code></pre>
        
        <h4>DELETE</h4>
        <p>Используется для удаления записей из таблицы.</p>
        <pre><code class="sql">DELETE FROM table_name WHERE condition;</code></pre>
        
        <h4>JOIN</h4>
        <p>Используется для объединения строк из двух или более таблиц на основе связанного столбца между ними.</p>
        <pre><code class="sql">SELECT fields FROM table1 JOIN table2 ON table1.field = table2.field;</code></pre>
        
        <h3>Операторы Сравнения</h3>
        <ul>
          <li><strong>=</strong>: Равно</li>
          <li><strong>!=</strong> или <strong>&lt;&gt;</strong>: Не равно</li>
          <li><strong>&gt;</strong>: Больше</li>
          <li><strong>&lt;</strong>: Меньше</li>
          <li><strong>&gt;=</strong>: Больше или равно</li>
          <li><strong>&lt;=</strong>: Меньше или равно</li>
        </ul>

        <h3>Логические Операторы</h3>
        <ul>
          <li><strong>AND</strong>: И</li>
          <li><strong>OR</strong>: Или</li>
          <li><strong>NOT</strong>: Не</li>
        </ul>

        <h2>API Доступные Маршруты</h2>
        <p>Все API маршруты требуют отправки токена в заголовке <code>Authorization: Bearer &lt;token&gt;</code>.</p>

        <h4>Получение Списка Таблиц</h4>
        <pre><code class="bash">GET /api/tables</code></pre>
        <p>Возвращает список всех таблиц пользователя.</p>

        <h4>Создание Таблицы</h4>
        <pre><code class="bash">POST /api/create-table</code></pre>
        <p>Создает новую таблицу.</p>
        <pre><code class="json">
{
  "tableName": "users",
  "schema": {
    "id": "number",
    "name": "string",
    "age": "number"
  },
  "autoIncrement": true
}
        </code></pre>

        <h4>Вставка Записи</h4>
        <pre><code class="bash">POST /api/insert</code></pre>
        <p>Вставляет новую запись в таблицу.</p>
        <pre><code class="json">
{
  "tableName": "users",
  "record": {
    "name": "Иван Иванов",
    "age": 30
  }
}
        </code></pre>

        <h4>Получение Записи по ID</h4>
        <pre><code class="bash">GET /api/record/&lt;tableName&gt;/&lt;id&gt;</code></pre>
        <p>Возвращает запись из таблицы по указанному ID.</p>

        <h4>Обновление Записи по ID</h4>
        <pre><code class="bash">PUT /api/update/&lt;tableName&gt;/&lt;id&gt;</code></pre>
        <p>Обновляет запись в таблице по указанному ID.</p>
        <pre><code class="json">
{
  "name": "Иван Петров",
  "age": 31
}
        </code></pre>

        <h4>Удаление Записи по ID</h4>
        <pre><code class="bash">DELETE /api/delete/&lt;tableName&gt;/&lt;id&gt;</code></pre>
        <p>Удаляет запись из таблицы по указанному ID.</p>
      </div>
    `;

    const content = `
      <h1 class="animate__animated animate__fadeInDown">Выполнить Команду</h1>
      <form action="/execute-command" method="POST" class="animate__animated animate__fadeIn">
        <div class="form-group">
          <label for="command">Введите вашу SQL-подобную команду:</label>
          <textarea class="form-control" id="command" name="command" rows="4" placeholder="Например: SELECT * FROM users ORDER BY name ASC;" required>${escapeHTML(command)}</textarea>
        </div>
        <button type="submit" class="btn btn-primary animate__animated animate__fadeIn">Выполнить</button>
        <a href="/" class="btn btn-secondary animate__animated animate__fadeIn">Отмена</a>
      </form>
      <hr>
      <h3 class="animate__animated animate__fadeInUp">Результат:</h3>
      <pre id="command-result" class="animate__animated animate__fadeInUp">${JSON.stringify(displayResult, null, 2)}</pre>
      <hr>
      ${documentation}
      <h3 class="animate__animated animate__fadeInUp">Примеры Запросов:</h3>
      ${exampleQueries}
      <a href="/execute-command" class="btn btn-secondary mt-3 animate__animated animate__fadeIn">Выполнить другую команду</a>
    `;
    renderPage(res, 'Выполнить Команду', content);
  } catch (error) {
    const content = `
      <h1 class="animate__animated animate__fadeInDown">Выполнить Команду</h1>
      <form action="/execute-command" method="POST" class="animate__animated animate__fadeIn">
        <div class="form-group">
          <label for="command">Введите вашу SQL-подобную команду:</label>
          <textarea class="form-control" id="command" name="command" rows="4" required>${escapeHTML(command)}</textarea>
        </div>
        <button type="submit" class="btn btn-primary animate__animated animate__fadeIn">Выполнить</button>
        <a href="/" class="btn btn-secondary animate__animated animate__fadeIn">Отмена</a>
      </form>
      <hr>
      <div class="alert alert-danger animate__animated animate__fadeIn" role="alert">
        <h4 class="alert-heading">Ошибка</h4>
        <p>${escapeHTML(error.message)}</p>
      </div>
      <a href="/execute-command" class="btn btn-secondary animate__animated animate__fadeIn">Попробовать снова</a>
    `;
    renderPage(res, 'Ошибка', content);
  }
});

// -----------------------------------------------------------------------------------
// API-интерфейс с токен-аутентификацией
// -----------------------------------------------------------------------------------

// Маршруты API начинаются с /api
// Все API маршруты требуют передать токен в заголовке Authorization: Bearer <token>

// Middleware для проверки токена
function authenticateToken(req, res, next) {
  const authHeader = req.headers['authorization'];
  if (!authHeader) return res.status(401).json({ error: 'Нет заголовка авторизации.' });

  const tokenParts = authHeader.split(' ');
  if (tokenParts.length !== 2 || tokenParts[0] !== 'Bearer') {
    return res.status(401).json({ error: 'Неверный формат заголовка авторизации.' });
  }

  const token = tokenParts[1];
  const user = findUserByToken(token);
  if (!user) {
    return res.status(403).json({ error: 'Неверный токен.' });
  }

  // При успешной аутентификации добавляем пользователя в объект запроса
  req.user = user;
  next();
}

// Пример API маршрута: Получение списка таблиц
app.get('/api/tables', authenticateToken, (req, res) => {
  const username = req.user.username;
  const userDBPath = path.join(BD_DIR, username, 'database.json');

  try {
    const db = new Database(userDBPath);
    db.loadFromFile();
    const tables = db.getTables();
    res.json({ tables });
  } catch (error) {
    res.status(500).json({ error: error.message });
  }
});

// Пример API маршрута: Создание таблицы
app.post('/api/create-table', authenticateToken, (req, res) => {
  const username = req.user.username;
  const { tableName, schema, autoIncrement } = req.body;
  const userDBPath = path.join(BD_DIR, username, 'database.json');

  try {
    if (!tableName || !schema || typeof schema !== 'object') {
      throw new Error('Необходимо указать tableName и схемы таблицы.');
    }

    const db = new Database(userDBPath);
    db.loadFromFile();

    db.createTable(tableName, schema, autoIncrement);
    res.json({ success: true, message: `Таблица "${tableName}" создана.` });
  } catch (error) {
    res.status(400).json({ error: error.message });
  }
});

// Пример API маршрута: Вставка записи
app.post('/api/insert', authenticateToken, (req, res) => {
  const username = req.user.username;
  const { tableName, record } = req.body;
  const userDBPath = path.join(BD_DIR, username, 'database.json');

  try {
    if (!tableName || !record || typeof record !== 'object') {
      throw new Error('Необходимо указать tableName и запись.');
    }

    const db = new Database(userDBPath);
    db.loadFromFile();

    db.insert(tableName, record);
    res.json({ success: true, message: 'Запись вставлена успешно.' });
  } catch (error) {
    res.status(400).json({ error: error.message });
  }
});

// Пример API маршрута: Получение записи по id
app.get('/api/record/:tableName/:id', authenticateToken, (req, res) => {
  const username = req.user.username;
  const { tableName, id } = req.params;
  const userDBPath = path.join(BD_DIR, username, 'database.json');

  try {
    const db = new Database(userDBPath);
    db.loadFromFile();

    const record = db.getRecord(tableName, Number(id));
    if (!record) {
      throw new Error(`Запись с id=${id} не найдена.`);
    }
    res.json({ record });
  } catch (error) {
    res.status(404).json({ error: error.message });
  }
});

// Пример API маршрута: Обновление записи по id
app.put('/api/update/:tableName/:id', authenticateToken, (req, res) => {
  const username = req.user.username;
  const { tableName, id } = req.params;
  const newRecord = req.body;
  const userDBPath = path.join(BD_DIR, username, 'database.json');

  try {
    if (!newRecord || typeof newRecord !== 'object') {
      throw new Error('Необходимо предоставить новые данные для записи.');
    }

    const db = new Database(userDBPath);
    db.loadFromFile();

    const success = db.updateRecord(tableName, Number(id), newRecord);
    if (!success) {
      throw new Error(`Запись с id=${id} не найдена.`);
    }
    res.json({ success: true, message: `Запись с id=${id} обновлена.` });
  } catch (error) {
    res.status(400).json({ error: error.message });
  }
});

// Пример API маршрута: Удаление записи по id
app.delete('/api/delete/:tableName/:id', authenticateToken, (req, res) => {
  const username = req.user.username;
  const { tableName, id } = req.params;
  const userDBPath = path.join(BD_DIR, username, 'database.json');

  try {
    const db = new Database(userDBPath);
    db.loadFromFile();

    const success = db.deleteRecord(tableName, Number(id));
    if (!success) {
      throw new Error(`Запись с id=${id} не найдена.`);
    }
    res.json({ success: true, message: `Запись с id=${id} удалена.` });
  } catch (error) {
    res.status(404).json({ error: error.message });
  }
});

// -----------------------------------------------------------------------------------
// Завершение работы и сохранение данных
// -----------------------------------------------------------------------------------

// Запуск сервера
const server = app.listen(PORT, () => {
  console.log(`Сервер запущен на http://localhost:${PORT}`);
});

// Обработка завершения работы для дополнительного сохранения данных (опционально)
process.on('SIGINT', () => {
  console.log('\nЗавершение работы...');
  saveUsers();
  server.close(() => {
    console.log('Сервер остановлен.');
    process.exit(0);
  });
});

// -----------------------------------------------------------------------------------
// Вспомогательная функция для экранирования HTML
// -----------------------------------------------------------------------------------
function escapeHTML(str) {
  if (typeof str !== 'string') return str;
  return str.replace(/&/g, '&amp;')
            .replace(/</g, '&lt;')
            .replace(/>/g, '&gt;')
            .replace(/"/g, '&quot;')
            .replace(/'/g, '&#039;');
}