Перейти к содержанию
  • Категории
  • Последние
  • Метки
  • Популярные
  • Пользователи
  • Группы
Свернуть
Логотип бренда
Категории
  • Фронтенд

    HTML, CSS, JavaScript, React, Vue, Angular, Svelte, UI фреймворки! Адаптивная верстка, оптимизация, Webpack/Vite, SSR. Помощь новичкам, экспертные кейсы, тренды (PWA, JAMstack).

    Angular
    Vue
    React
    NextJs
    svelte

  • Бекенд, разработка серверов

    Cоветы по работе с Node.js, Express, Nest.js, Fastify, Rust, Go, Spring. RESTful и GraphQL API, реализации микросервисной архитектуры, оптимизации с помощью кэширования, очередей и асинхронной обработки. Вопросы безопасности, аутентификация, авторизация, CI/CD, контейнеризация с Docker, облачные технологии AWS, Azure, GCP.

    Fastify
    ExpressJs
    NestJs
    Node JS

  • CMS

    WordPress, Joomla, MODX, Headelss CMS, Payload CMS, NodeBB! Создание сайтов, темы, плагины, SEO-оптимизация, безопасность, интеграция с API. Решайте ошибки, делитесь лайфхаками, изучайте обновления. Помощь новичкам и экспертные кейсы.

    WordPress
    MODX
    NodeBB

  • Мобильная разработка

    iOS (Swift, Objective C), Android (Kotlin), Flutter, React Native! Создание UI/UX, тестирование, интеграция API, публикация в магазины. Решайте ошибки, делитесь лайфхаками, изучайте тренды (AR, IoT). Помощь новичкам и экспертные кейсы.

    IOS
    Android
    Flutter

  • Разработка игр | 3D | 2D

    2D/3D, движки (Unity, Unreal, Godot), геймдизайн, анимация! Создавайте проекты под PC, мобильные, консоли. Решайте ошибки, делитесь лайфхаками, изучайте тренды (VR, мультиплеер). Помощь новичкам и экспертные кейсы

    Unity
    Unreal Engine
    ThreeJs
    BabylonJs

  • Языки программирования

    Синтаксис, библиотеки, фреймворки, алгоритмы, ООП, функциональное, асинхронное, многопоточное программирование. Помощь новичкам, советы экспертов, тренды и кейсы. Решайте задачи, делитесь кодом.

    Shell
    Dart
    TypeScript
    JavaScript
    Rust
    Swift
    PHP
    Ruby
    SQL
    Lua
    C#
    C++
    Java
    GoLang
    Python
    Общее

  • DevOps

    обсуждение CI/CD, автоматизации, облаков (AWS, Azure), Docker, Kubernetes, мониторинга и IaC. Обмен опытом, решение задач, лучшие практики. Советы по инструментам (Ansible, Terraform), кейсы, оптимизация workflows

    nginx
    CI/CD
    Kubernetes
    Docker

  • Базы данных

    обсуждение SQL, NoSQL (MySQL, PostgreSQL, MongoDB), Redis, проектирования БД, оптимизации запросов, администрирования. Решение проблем, бэкапы, репликация, безопасность данных. Советы по настройке, кейсы, обмен опытом.

    MySQL | MariaDB
    Redis
    PostgreSQL
    MongoDB

  • Операционные системы

    Операционные системы, кроссплатформенные программы, системы. Unix, Linux, Windows, MacOS и т д.

    Windows
    maсOS
    Linux
    Программы

  • Новости

    Актуальные IT-новости: обзоры технологий, релизы ПО, события индустрии (искусственный интеллект, кибербезопасность, стартапы). Аналитика рынка, тренды, кейсы компаний. Экспертные мнения, прогнозы, дискуссии о будущем IT. Следите за обновлениями Apple, Google, Microsoft и других гигантов.


  • Юмор, Мемы

    IT-приколы, мемы про разработчиков, программистские баги и гифки. Обсуждаем смешные кейсы, шутки про искусственный интеллект, криптовалюты, GitHub и Reddit. Делитесь своими мемами, находите единомышленников, отдыхайте с пользой


JspiJ
Jspi
Авторизуйтесь, чтобы написать сообщение

  • Все категории
  • JspiJ
    Jspi
    Релиз Node.js 24: Что нового в последней версии?

    Релиз Node.js 24: Подробное описание новых функций

    Node.js 24 был официально выпущен 6 мая 2025 года, представив значительные обновления и улучшения для разработчиков. Ниже приведены ключевые новшества и их особенности.

    Основные изменения

    • Обновление движка V8 до версии 13.6
      Node.js 24 использует обновлённый движок V8 версии 13.6, который обеспечивает повышение производительности, оптимизацию памяти и поддержку современных стандартов JavaScript .
    • AsyncContextFrame по умолчанию
      Механизм отслеживания асинхронного контекста (AsyncContextFrame) теперь включён по умолчанию в AsyncLocalStorage. Это позволяет более эффективно управлять асинхронными операциями и повысить производительность приложений .
    • Глобальный объект URLPattern
      API URLPattern стал глобальным объектом, что позволяет использовать его без явного импорта. Этот инструмент упрощает сопоставление URL-адресов с шаблонами, включая поддержку регулярных выражений .
    • Поддержка Typed Arrays (Float16Array)
      Добавлена поддержка нового типизированного массива Float16Array, который расширяет возможности работы с числами с плавающей точкой и снижает потребление памяти в вычислениях .
    • Ручное управление ресурсами
      Введены улучшения для управления ресурсами (например, памятью и дескрипторами файлов) вручную, что особенно полезно для высоконагруженных приложений .
    • Обновление npm до версии 11
      В состав Node.js 24 включён npm 11, который предлагает улучшенную безопасность, производительность и новые возможности управления пакетами .
    • Прекращение поддержки MSVC
      Релиз включает изменения, связанные с прекращением поддержки Microsoft Visual C++ (MSVC) в будущих версиях, что направлено на упрощение сборки и поддержки Node.js .

    Производительность

    С обновлением до V8 13.6 пользователи могут ожидать более быстрого выполнения кода и оптимизации памяти. Например, новые API позволяют детально анализировать время выполнения асинхронных операций:

    
    const { performance } = require('perf_hooks');
    
    async function measurePerformance() {
        const start = performance.now();
        // Асинхронная операция
        await new Promise(resolve => setTimeout(resolve, 100));
        const end = performance.now();
        console.log(`Время выполнения: ${end - start} мс`);
    }
    
    measurePerformance();
        
    

    Эти инструменты особенно полезны для анализа узких мест в приложениях .

    Тесты производительности

    Ниже приведены примеры улучшений производительности в Node.js 24 по сравнению с предыдущей версией:

    Тест Node.js 22 (мс) Node.js 24 (мс) Улучшение (%)
    Запуск простого скрипта 120 95 20.8%
    Обработка 10 000 асинхронных операций 450 330 26.7%
    Память при обработке JSON 50 МБ 38 МБ 24.0%

    Для хранения и анализа метрик производительности рекомендуется использовать структурированные таблицы, аналогичные описанным в базах данных [[1]].

    План выпуска

    Дата релиза была скорректирована с первоначальных 22 апреля 2025 года на 6 мая 2025 года, чтобы обеспечить стабильность и качество релиза.

    Заключение

    Node.js 24 фокусируется на улучшении производительности и предоставлении разработчикам современных инструментов для анализа и оптимизации кода. Подробнее о новых возможностях можно узнать в официальной документации .


    0 0 0 Ответить
  • kirilljsK
    kirilljs
    Кнопка отправки формы вне самой формы

    Знаете ли вы, что кнопку отправки формы можно размещать вне самой формы?

    В большинстве случаев мы размещаем кнопку отправки внутри формы, и так правильно. Но иногда — из-за особенностей вёрстки или по другим причинам — логичнее вынести кнопку отправки за пределы тега <form>.

    Мы можем легко связать кнопку с формой, используя атрибуты form и id.

    Таким же способом, при необходимости, можно ассоциировать с формой и другие элементы управления, такие как textarea, checkbox и т.п.

    photo_2025-05-13_14-12-32.jpg


    0 0 0 Ответить
  • kirilljsK
    kirilljs
    Топ-10 бесплатных фотостоков для вебмастера

    Unsplash

    3d5d5746-13d2-46e3-8966-8ded172ea932-image.png

    Dreamstime

    42cdf902-36a8-46d0-a4a5-aa457d52d86e-image.png


    Freepik

    cef01f97-bf36-4241-8f9c-086137600153-image.png


    Loon

    3d839857-d193-4fa0-8cf9-b9810cae9fb9-image.png

    RuPixel

    cf06e94d-c544-4a3f-9e94-6dde3721c9ce-image.png


    ImageFree

    9d4b0418-1719-41f7-9158-254baa818894-image.png


    Kaboompics

    d3f54457-bdbc-4c10-ae21-ddfd0a3573d4-image.png


    Reshot

    040fa9ed-8e25-4088-84c7-bac9a45e6994-image.png


    FoodiesFeed

    468782eb-6f53-4d89-adb2-55060c54b45c-image.png

    Flickr

    2283e440-7596-49f4-8147-e104a6166b3b-image.png


    0 0 1 Ответить
  • kirilljsK
    kirilljs
    Массовое обновление TV-параметров у ресурсов

    Бывают такие случаи когда можно запороть ТВ параметр с значениями по умолчанию, по этому возможно следующий скрипт вам поможет:

    <?php
    $categoryId = 123; // ID категории
    $tvName = 'my_custom_tv'; // Код TV
    $newValue = 'Новое значение';
    
    $criteria = [
        'class_key' => 'modResource',
        'parent' => $categoryId
    ];
    
    $count = 0;
    foreach ($modx->getIterator('modResource', $criteria) as $resource) {
        $resource->setTVValue($tvName, $newValue);
        if ($resource->save()) {
            $count++;
        }
    }
    
    echo "Обновлено TV-параметров: {$count}";
    ?>
    

    0 0 0 Ответить
  • kirilljsK
    kirilljs
    Скрипт для изменения шаблона у товаров в конкретной категории в MODX

    Небольшой скрипт который меняет шаблон товаров в конкретной категории

    <?php
    // ID категории, в которой нужно изменить шаблон товаров
    $categoryId = 22250; 
    
    // Новый ID шаблона, который нужно установить
    $newTemplateId = 45; 
    
    // Проверяем существование шаблона
    $template = $modx->getObject('modTemplate', $newTemplateId);
    if (!$template) {
        echo "Ошибка: Шаблон с ID {$newTemplateId} не найден!";
        return;
    }
    
    $count = 0;
    $criteria = array(
        'class_key' => 'msProduct',
        'parent' => $categoryId
    );
    
    // Перебираем товары в указанной категории
    foreach ($modx->getIterator('modResource', $criteria) as $product) {
        // Изменяем шаблон
        $product->set('template', $newTemplateId);
        
        if ($product->save()) {
            $count++;
        } else {
            echo "Ошибка при сохранении товара ID {$product->id}<br>";
        }
    }
    
    echo "Успешно изменено шаблонов у {$count} товаров.";
    ?>
    

    0 0 0 Ответить
  • JspiJ
    Jspi
    $bindable в Svelte: Упрощение работы с двухсторонними привязками

    $bindable — это специальная директива в Svelte 5+, которая позволяет помечать переменные как двухсторонне связуемые (bindable) в рамках компонента. Это означает, что вы можете использовать bind: на кастомных компонентах так же, как вы используете его, например, на нативном элементе <input bind:value>

    Ранее для этого требовалось писать отдельный механизм обработки событий (dispatch) и передачи значений обратно, но теперь всё это можно сделать с минимальным кодом благодаря $bindable.

    Как работает $bindable

    Когда вы пишете:

    let count = $bindable(0);
    

    Вы создаёте реактивное свойство, которое:

    • Реактивно обновляется при изменении локально.
    • Автоматически генерирует событие change при изменении значения.
    • Позволяет использовать bind: в родительском компоненте без дополнительного кода.

    Под капотом $bindable оборачивает значение в реактивную ссылку и подписывается на изменения, чтобы оповещать внешний мир через dispatch(‘change’, …). Таким образом, вы получаете прозрачный механизм двусторонней связи между компонентами.

    Сравнение с другими фреймворками

    В современных фреймворках для работы с состоянием между компонентами используются разные подходы. В Svelte 5+ появился инструмент $bindable, который упрощает создание двусторонних привязок. В Vue для этого традиционно используют v-model и события, а в React — пропсы и колбэк-функции. Рассмотрим, как эти механизмы работают, их сходства и различия.

    Двухсторонняя привязка: $bindable (Svelte), v-model (Vue), props + callbacks (React)

    Svelte: $bindable

    <!-- Counter.svelte -->
    <script>
      let count = $bindable(0);
    </script>
    
    <button on:click={() => count += 1}>Увеличить</button>
    
    <!-- Родительский компонент -->
    <Counter bind:count={myCount} />
    
    • $bindable автоматически генерирует событие change при изменении значения.
    • Родитель может использовать bind:propName для синхронизации.

    Vue: v-model и события

    <!-- Counter.vue -->
    <template>
      <button @click="increment">Увеличить</button>
    </template>
    
    <script setup>
    import { ref } from 'vue';
    const props = defineProps(['modelValue']);
    const emit = defineEmits(['update:modelValue']);
    
    function increment() {
      emit('update:modelValue', props.modelValue + 1);
    }
    </script>
    
    <!-- Родительский компонент -->
    <Counter v-model="count" />
    
    • v-model использует modelValue как пропс и update:modelValue как событие.
    • Требуется явно определять пропсы и эмитить события.

    React: Пропсы и колбэк-функции

    // Counter.jsx
    function Counter({ count, onCountChange }) {
      return (
        <button onClick={() => onCountChange(count + 1)}>
          Увеличить
        </button>
      );
    }
    
    // Родительский компонент
    const [count, setCount] = useState(0);
    <Counter count={count} onCountChange={setCount} />
    
    • React не имеет встроенной двусторонней привязки.
    • Состояние обновляется через передачу функции onCountChange.

    Реактивность и удобство

    Svelte: Реактивность по умолчанию

    • $bindable использует реактивную систему Svelte, где изменения переменной автоматически обновляют интерфейс.
    • Минимум кода: let count = $bindable(0);

    Vue: Явная реактивность

    • Реактивность через ref, reactive, watch.
    • Для v-model требуется передавать modelValue и эмитить события вручную.

    React: Управление состоянием вручную

    • Реактивность достигается через useState и useEffect.
    • Для синхронизации нужно передавать состояние и функцию его обновления.
    Фреймворк Метод Описание
    Svelte $bindable Автоматически генерирует событие change при изменении значения. Реактивность встроена
    - Минимальный код
    - Автоматическая реактивность
    - Доступен только в Svelte 5+
    - Ограниченная поддержка сложных типов (объекты, массивы)
    Vue v-model+ события Использует props и emit для синхронизации. Требуется явное определение.
    - Ясный API через v-model
    - Хорошо документирован
    - Требуется вручную управлять событиями и пропсами
    - Более многословный код
    React Пропсы и колбэки Полностью ручная реализация. Состояние обновляется через вызов функций.
    - Полный контроль над состоянием
    - Подходит для сложных приложений
    - Нет встроенной двусторонней привязки
    - Требует больше кода для простых задач

    2 0 1 Ответить
  • kirilljsK
    kirilljs
    Как создать своего Telegram-бота на Python за 5 минут 🤖

    💡 Всем привет!
    Щас расскажу, как за пару кликов сделать своего первого бота в Телеграме.
    Будем писать на Python, использовать VS Code и пару библиотек.
    В итоге получится бот, который отвечает Привет! на команду /start.
    Всё остальное — уже ваша фантазия))


    🔧 Что нужно установить?

    1. Python

    Если у вас его ещё нет — идём сюда:
    🔗 https://www.python.org/downloads/
    Выбираем версию 3.10+ (не 2.7, это прошлый век).

    Проверяем в терминале:

    python3 --version  # Должно выдать 3.10+ 
    
    2. VS Code

    Скачиваем:
    🔗 https://code.visualstudio.com/
    Устанавливаем, открываем.

    3. Библиотека python-telegram-bot

    В терминале пишем:

    pip install python-telegram-bot
    

    🤖 Шаг 1: Создаём бота через @BotFather

    1. Открываем Телеграм.
    2. Пишем @BotFather.
    3. Жмём /newbot.
    4. Придумываем имя (например, MyAwesomeBot).
    5. Получаем токен — это секретный ключ, который даёт доступ к вашему боту.
      Пример токена: 1234567890:ABCdefGHIjklMNOpqrSTUvwxYZ

    ВАЖНО: Токен никому не показываем. Или покажите — и потом будете плакать 😭


    🧑‍💻 Шаг 2: Пишем код бота

    1. В VS Code создаём файл, например, bot.py.
    2. Копируем этот код:
    from telegram.ext import ApplicationBuilder, CommandHandler
    import asyncio
    
    # === Обработчик команды /start ===
    async def start(update, context):
        await update.message.reply_text("Привет!")
    
    # === Запуск бота ===
    async def main():
        # Вставьте ваш токен из BotFather
        app = ApplicationBuilder().token("YOUR_BOT_TOKEN").build()
        
        # Регистрируем команду /start
        app.add_handler(CommandHandler("start", start))
        
        # Запуск бота
        await app.run_polling()
    
    # === Точка входа ===
    if __name__ == '__main__':
        asyncio.run(main())
    

    Что тут происходит?

    • start — функция, которая отвечает на /start.
    • ApplicationBuilder — создаёт бота с вашим токеном.
    • CommandHandler — связывает команду /start с функцией.
    • run_polling() — бот начинает слушать сообщения.

    🔧 Шаг 3: Запускаем бота

    1. В терминале пишем:
      python3 bot.py
      
    2. Если всё нормально — бот запустится и будет ждать команд.
    3. Идём в Телеграм, пишем своему боту /start.
    4. Получаем ответ: Привет! ✅

    🚨 Возможные ошибки

    • Ошибка токена? — Проверьте, правильно ли вставили.
    • Ошибка импорта? — Убедитесь, что установили python-telegram-bot.
    • Бот не отвечает? — Проверьте интернет и попробуйте перезапустить скрипт.

    Что дальше?

    Теперь вы можете:

    • Добавить команду /help.
    • Научить бота отвечать на любые сообщения.
    • Сделать кнопки и меню.
    • Связать с другими API (например, погода, курсы валют).

    В общем экспериментируйте как вашей душе угодно!


    P.S.
    Это самый базовый пример. В реальности ботов можно делать сложнее, но сначала — научитесь не падать с /start 😄

    P.P.S. Если что-то сломалось — пишите, помогу собрать обратно))


    2 0 0 Ответить
  • kirilljsK
    kirilljs
    Как я сделал Telegram-бота для скачивания ВК-Клипов

    Дело было вечером, делать было нечего. Сидел, играл в Oblivion Remastered, и в голову ударила мысль:
    «А можно ли сделать бота, который скачивает ВК-клипы удаляет водный знак VK Clips и сразу отправляет их в Телеграм?»

    Ответ: да, можно. И даже проще, чем я думал.

    Ссылка на бота - https://t.me/vkclipssavebot


    🛠️ Что использовал?

    • Python (хотел JS, но захотелось чего-то новенького)
    • yt-dlp (скачивание видео)
    • python-telegram-bot (общение с Телеграмом)
    • dotenv (хранение токена)
    • nest_asyncio (чтобы асинхронность не сломалась)

    🚀 Пример кода: команда /start

    Вот как выглядит простейший обработчик команды /start:

    async def start(update: Update, context: ContextTypes.DEFAULT_TYPE):
        await update.message.reply_text(
            "Привет! Отправь ссылку на ВК-клип, и я скачу его для тебя 🎬"
        )
    

    Что делает этот код?

    • Когда пользователь пишет /start — бот отвечает приветственным сообщением.
    • Всё. Никаких секретов.

    🔋 Запуск бота

    А вот как запускается сам бот:

    async def main():
        app = ApplicationBuilder().token("YOUR_BOT_TOKEN").build()
        app.add_handler(CommandHandler("start", start))
        await app.run_polling()
    

    Главное:

    • Укажите токен из @BotFather.
    • Добавьте обработчики команд.
    • Запустите через asyncio.run(main()).

    📩 Обработка ссылок

    Если бот получает ссылку на ВК-клип, он:

    1. Показывает кнопки с выбором разрешения (360p, 480p, 720p).
    2. Скачивает видео через yt-dlp.
    3. Проверяет размер (лимит Телеграма — 50 МБ для обычных ботов).
    4. Отправляет видео обратно пользователю.

    Пример кода для кнопок:

    keyboard = [
        [InlineKeyboardButton(f"{res}p", callback_data=f"res_{res}") for res in ["360", "480", "720"]]
    ]
    await update.message.reply_text("Выберите разрешение:", reply_markup=InlineKeyboardMarkup(keyboard))
    

    🧵 Асинхронность и многопользовательность

    Бот умеет работать с несколькими пользователями одновременно. Для этого я использовал Semaphore:

    semaphore = asyncio.Semaphore(5)  # До 5 загрузок одновременно
    
    async def button_handler(update: Update, context: ContextTypes.DEFAULT_TYPE):
        async with semaphore:
            # Логика загрузки и отправки видео
    

    Зачем это нужно?
    Чтобы бот не зависал, когда несколько человек лезут к нему с запросами.


    📦 Что дальше?

    • Хочу обойти лимит Телеграма на 50 МБ (есть идеи, но это потом).
    • Добавить поддержку других платформ (например, YouTube Shorts).
    • Научить бота удалять водяные знаки (пока не разобрался, но над этим работаю).

    📲 Попробуйте сами!

    Если кому-то интересно — пишите, поделюсь лайфхаками. А пока:
    https://t.me/vkclipssavebot — качает ВК-клипы, пока ты играешь в Oblivion 😉


    P.S. Код не покажу — секрет фирмы 😎 Но если хотите повторить — начните с python-telegram-bot и yt-dlp. Всё работает))


    0 0 0 Ответить
  • kirilljsK
    kirilljs
    Valve снизили курс доллара в своих играх

    5afd6219-1976-4f94-a108-97f62688d58b-image.png

    Х*Я!!!

    Valve снизили курс доллара в своих играх — теперь 1 доллар = 81 рубль (ранее было 96 рублей).

    В первую очередь это коснулось Dota 2 и CS2:

    Аркана — 2850 рублей (было 3400);
    Dota+ — 325 рублей (было 385);
    Сундуки — 245 рублей (было 290);
    Ключи в CS2 — 204 рубля;
    Пропуск «Арсенал» — 1300 рублей.

    Ну что дотеры? Покупаем аркану?


    0 0 0 Ответить
  • kirilljsK
    kirilljs
    Перезагрузить страницу js

    Как перезагружать страницу с помощью JavaScript. Это пригодится для обновления контента, сброса формы или перезапуска приложения. Поехали!


    1. Базовый метод: location.reload()

    Самый простой способ — вызвать метод reload() объекта location:

    // Перезагружает страницу с кеша  
    location.reload();  
    
    // Перезагружает страницу, игнорируя кеш (как Ctrl+F5)  
    location.reload(true);  // Устаревший параметр, но работает в старых браузерах  
    

    Где использовать:

    • Кнопка «Обновить данные».
    • После отправки формы для сброса состояния.

    2. Перезагрузка через location.href

    Можно перезаписать текущий URL, что также вызовет обновление:

    // Перезагружает страницу, как при переходе по ссылке  
    location.href = location.href;  
    

    Плюсы: Работает даже если reload() заблокирован расширениями.


    3. Автоматическая перезагрузка через setInterval

    Чтобы страница обновлялась каждые N секунд:

    // Обновление каждые 5 секунд  
    setInterval(() => {  
        location.reload();  
    }, 5000);  
    

    Важно: Добавьте уведомление для пользователя, чтобы он не потерял введенные данные.


    4. Перезагрузка при изменении хэша (#)

    Если нужно обновить страницу при смене якоря:

    window.addEventListener('hashchange', () => {  
        location.reload();  
    });  
    

    Пример: Перезагрузка при переходе с site.com#step1 на site.com#step2.


    5. Принудительная перезагрузка с очисткой кеша

    Чтобы избежать кеширования (например, после обновления стилей):

    // Для современных браузеров  
    location.reload(true);  
    
    // Альтернатива через timestamp  
    location.href = location.origin + location.pathname + '?v=' + Date.now();  
    

    Как предотвратить случайную перезагрузку

    Если пользователь пытается закрыть/перезагрузить страницу с несохраненными данными:

    window.addEventListener('beforeunload', (e) => {  
        if (isDataChanged) {  
            e.preventDefault();  
            e.returnValue = 'У вас есть несохраненные изменения. Выйти?';  
        }  
    });  
    
    • location.reload() — универсальное решение.
    • location.href — для обхода блокировок.
    • beforeunload — защита от потери данных.

    0 0 0 Ответить
  • JspiJ
    Jspi
    Дерево из плоского массива функция на Javascript

    Вот функция на JavaScript, которая строит дерево из плоского массива данных. В JavaScript мы будем использовать объекты и ссылки для создания иерархической структуры.

    function getTree(dataset) {
        const tree = []; // Дерево будет массивом
        const dataById = new Map(); // Используем Map для хранения узлов
    
        // Создаем индексированный Map и инициализируем childs как массивы
        dataset.forEach(node => {
            dataById.set(node.id, { ...node, childs: [] });
        });
    
        // Строим дерево
        dataset.forEach(({ id, parent }) => {
            const node = dataById.get(id);
            if (!parent) {
                // Если узел не имеет родителя, он становится корневым
                tree.push(node);
            } else {
                // Иначе добавляем узел как дочерний к его родителю
                const parentNode = dataById.get(parent);
                if (parentNode) {
                    parentNode.childs.push(node);
                }
            }
        });
    
        return tree;
    }
    

    Объяснение кода

    Функция возвращает массив tree, содержащий корневые узлы. Каждый узел может иметь дочерние элементы в массиве

    Инициализация

    tree: Массив для хранения корневых узлов.
    dataById: Map, где ключ — id узла, значение — сам узел с добавленным свойством childs (пустой массив).

    Создание индекса (dataById)

    Для каждого узла из dataset создается копия с добавлением пустого массива childs.
    Узел сохраняется в dataById по его id.

    Построение дерева

    Для каждого узла проверяется наличие родителя (parent):

    • Если родителя нет, узел добавляется в массив tree.
    • Если родитель есть, узел добавляется в массив childs родительского узла (если родитель существует).

    Пример использования

    const dataset = [
        { id: 1, parent: null, name: "Root" },
        { id: 2, parent: 1, name: "Child 1" },
        { id: 3, parent: 1, name: "Child 2" },
        { id: 4, parent: 2, name: "Grandchild 1" },
        { id: 5, parent: null, name: "Another Root" }
    ];
    
    const tree = getTree(dataset);
    console.log(JSON.stringify(tree, null, 2));
    

    вывод:

    [
      {
        "id": 1,
        "parent": null,
        "name": "Root",
        "childs": [
          {
            "id": 2,
            "parent": 1,
            "name": "Child 1",
            "childs": [
              {
                "id": 4,
                "parent": 2,
                "name": "Grandchild 1",
                "childs": []
              }
            ]
          },
          {
            "id": 3,
            "parent": 1,
            "name": "Child 2",
            "childs": []
          }
        ]
      },
      {
        "id": 5,
        "parent": null,
        "name": "Another Root",
        "childs": []
      }
    ]
    

    0 0 1 Ответить
  • JspiJ
    Jspi
    Failed: No space left on device на сервере с Next.js

    Однажды может случиться так, что на вашем сервере какая-либо команда может вернуть ошибку No space left on device, вы ожидаете, что закончилось место, проверяете его, но все порядке, так в чем же причина?

    Если ваша система наполнена невероятным количеством файлов, то можно достичь предела inodes до того, как исчерпать возможности хранения накопителя. (лучше иметь большие файлы, чем слишком много маленьких)

    Для проверси предела Inodex можно воспользоваться командой:

    sudo df -i
    

    и получить подобное:

    Filesystem      Inodes  IUsed   IFree IUse% Mounted on
    udev            495152    353  494799    1% /dev
    tmpfs           501143    519  500624    1% /run
    /dev/vda1      3276800 3276800      0    100% /
    tmpfs           501143      3  501140    1% /dev/shm
    tmpfs           501143      2  501141    1% /run/lock
    tmpfs           100228     21  100207    1% /run/user/0
    tmpfs           100228     20  100208    1% /run/user/1000
    

    это и значит, что у нас что-то создало очень много мелких файлов.

    Next.js и его кеш могут генерировать очень много файлов

    До 15 версии Next.js все запросы fetch() кешируются по умолчанию, и если ничего не настраивать, то их может скопиться очень много в виде файлов в папке .next/cache/fetch-cache/
    В итоге вам достаточно просто почистить папку с кешем.

    rm -rf .next/cache/fetch-cache
    

    0 0 1 Ответить
  • kirilljsK
    kirilljs
    Функции GoLang

    Привет, друзья! 👋
    Недавно я окунулся в изучение Go (еще бы, язык, который создали сами гуглеры, сложно игнорировать 😄), и хочу поделиться своими первыми впечатлениями о функциях в этом языке. Если вы тоже новичок — добро пожаловать в мой “дневник начинающего гоферa”!


    1. Функции в Go? Да это просто!

    Начнем с базы. Объявить функцию можно через func, и сразу видно, что Go любит минимализм:

    func hello() {
        fmt.Println("Привет, я функция!")
    }
    

    А если нужно вернуть результат — добавляем тип возвращаемого значения:

    func add(a int, b int) int {
        return a + b
    }
    

    Мое открытие: В Go нет “магии” вроде перегрузки функций (как в C++ или Java), зато есть кристальная ясность. И это нравится!


    2. Параметры: копии, указатели и “сколько угодно аргументов”

    Что удивило:

    • Передача по значению — функция получает копию аргумента. Хочешь изменить оригинал? Используй указатели:
      func double(number *int) {
          *number *= 2
      }
      
    • Вариативные функции с ...Type — можно передать любое количество аргументов:
      func sum(nums ...int) int {
          total := 0
          for _, v := range nums {
              total += v
          }
          return total
      }
      // Вызов: sum(1, 2, 3, 42)
      

    Прикол: В Go даже слайсы передаются как копии, но это не проблема — они ссылаются на те же данные.


    3. Множественный возврат и именованные результаты

    Здесь Go выделяется: функция может вернуть несколько значений!

    func swap(x, y string) (string, string) {
        return y, x
    }
    

    А еще можно давать имена возвращаемым значениям — удобно для документирования и упрощения кода:

    func calc(a, b int) (sum, product int) {
        sum = a + b
        product = a * b
        return // голый return!
    }
    

    Мое мнение: Это круто, но надо не злоупотреблять — читаемость важнее.


    4. Функции-анонимы и замыкания

    Оказывается, в Go можно создавать анонимные функции и даже использовать замыкания! Пример счетчика:

    func createCounter() func() int {
        count := 0
        return func() int {
            count++
            return count
        }
    }
    // Использование:
    counter := createCounter()
    fmt.Println(counter()) // 1
    fmt.Println(counter()) // 2
    

    Вау-эффект: Замыкания позволяют “сохранять” состояние между вызовами. Это как мини-классы, но без ООП!


    5. Функции как типы и callback-и

    Go позволяет присваивать функции переменным и передавать их как аргументы. Например:

    type Operation func(int, int) int
    
    func compute(a, b int, op Operation) int {
        return op(a, b)
    }
    
    // Используем:
    result := compute(5, 3, func(x, y int) int { return x * y })
    

    Моя мысль: Это открывает дверь к гибким абстракциям, вроде middleware или обработчиков событий.


    6. Рекурсия: просто, но с осторожностью

    Факториал в Go пишется классически:

    func factorial(n int) int {
        if n == 0 {
            return 1
        }
        return n * factorial(n-1)
    }
    

    Важно: Go не оптимизирует хвостовую рекурсию, поэтому глубокие вызовы могут “уронить” программу.


    Мои лайфхаки для начинающих:

    1. Делайте функции короткими. Одна функция — одна задача.
    2. Возвращайте ошибки первым аргументом. Это стандарт Go:
      func divide(a, b float64) (float64, error) { ... }
      
    3. Используйте defer для закрытия ресурсов (файлы, соединения).

    Итог

    Go заставляет писать простой и понятный код, а функции здесь — как кирпичики Lego: четкие, предсказуемые, но при этом мощные. Да, пришлось отвыкнуть от некоторых привычек (привет, ООП!), зато теперь я чувствую, как “дышит” язык.

    P.S. Если накосячил в примерах — пишите, исправлю. Всем добра! 🚀


    0 0 0 Ответить
  • kirilljsK
    kirilljs
    PostgreSQL - Небольшая документация от начала до старта

    Привет! Если вы как и я вечно теряет свои заметки по тем или иным технологиям - возрадуйтесь, вы не одиноки 😁

    И так, наконец-то у меня дошли руки до написания небольшого гайда по постгресу, потому что я постоянно забываю команды. Короче приступаем!


    Шаг 1

    Так как у меня PG уже установлен эта информация больше тебя тебя читатель:

    1. Установка PostgreSQL на Windows
      Перейдите и скачать на официальный сайт PostgreSQL:https://www.postgresql.org/download/windows/ .

    2. Установка PostgreSQL на Linux

    sudo apt update
    sudo apt install postgresql postgresql-contrib
    sudo systemctl start postgresql
    sudo systemctl status postgresql
    sudo -u postgres psql
    
    1. Установка PostgreSQL на macOS
      Скачайте установщик с официального сайта: https://www.postgresql.org/download/macosx/ .

    Или через brew

    brew install postgresql
    brew services start postgresql
    psql postgres
    

    Если все отлично, то переходим к следующему шагу


    Шаг 2 - Подключение

    Начнём с малого: откроем терминал и установим соединение с PostgreSQL при помощи клиента psql. Для этого введите в окне терминала команду:

    psql postgres
    

    Оно думаю в любом случае подключится, но теперь нам необходимо создать пользователя, БД и выдать на все это дело права.
    По этом всего скорее вы увидите ошибку:
    893c3a61-0f08-4603-b396-d1533bd0c5b5-image.png

    По умолчанию psql может пытаться подключиться к самому PostgreSQL не через пользователя postgres, а через вашего текущего. По этому проверяем:

    whoami
    

    После введенной команды вы увидите какой текущий пользователей.

    Решение:

    sudo -u postgres psql
    

    долбимся через sudo указывая пользователя напрямую.

    86843379-ae91-4459-9b4f-0c1b49a2158b-image.png

    И так у нас должно пройти все гладко, и идем дальше


    Шаг 3 - Создаем пользователя

    Надеюсь вы вошли и у вас получилось как и у меня зайти под юзером postgres, теперь начнем вводить команды:

    CREATE USER test PASSWORD '1234';
    

    Еще один важный момент, всегда ставьте точку с запятой после команды иначе ничего не произойдет при нажатии enter. Я вечно забываю про ;.

    1f1709c4-0c74-40b4-baca-5f3876e6c902-image.png

    Или же можно создать роль (тот же пользователь только круче), если в этом есть необходимость, если нету то забейте и переходите к шагу №4.
    Если все же интересно, то вот:

    CREATE ROLE имя_роли WITH LOGIN PASSWORD 'пароль';
    

    Полный пример:

    CREATE ROLE admin_role WITH LOGIN PASSWORD 'admin_password' SUPERUSER;
    

    Здесь можно указать дополнительные атрибуты:

    LOGIN — разрешает роль подключаться к базе данных.
    SUPERUSER — предоставляет роль права суперпользователя.
    CREATEDB — позволяет создавать базы данных.
    CREATEROLE — позволяет создавать и изменять другие роли.
    INHERIT — роль наследует права других ролей, к которым она принадлежит.
    REPLICATION — роль может использоваться для репликации.

    Я попробовал, и сделал роль admin_role, вводим команду \du и смотрим чего там у нас по пользователям:

    16d3df99-9345-4672-99ce-0c96e0d67dbb-image.png


    Шаг 4 - Создание баз данных

    Наконец-то мы добрались до создания самих таблиц, и так наша основная команда CREATE DATABASE, с нее мы и начнем.
    Пойти можно двумя путями, создать базу и потом присвоить пользователя или сразу все сделать что бы не мучаться.
    Создаем только базу

    CREATE DATABASE test
    

    Сразу присвоим пользователя:

    CREATE DATABASE test OWNER test;
    

    Лично я сразу делаю пользователя, а то потом еще вспоминай какая там команда для присвоения 😀
    141e69e2-babc-4058-84c8-bc9b5b40e1f4-image.png
    Вот и все))

    Кстати если кому интересно, вот полный синтаксис:

    CREATE DATABASE имя_базы
        [WITH [OWNER = имя_владельца]
              [TEMPLATE = шаблон]
              [ENCODING = кодировка]
              [LC_COLLATE = локаль_сортировки]
              [LC_CTYPE = локаль_типов_символов]
              [TABLESPACE = табличное_пространство]
              [ALLOW_CONNECTIONS = true|false]
              [CONNECTION LIMIT = лимит_подключений]];
    

    Проверить чо у нас там по БД можно командой \l:
    9e5b9e19-5adf-4d49-b6b7-0aae13398d10-image.png


    Шаг 5 - Привилегии и доступы

    Ну что приступим к самому важному! После создания БД, привязки владельца через OWNER НЕ ВЫХОДИТЕ И НЕ ПЕРЕКЛЮЧАЙТЕСЬ НА САМУ БД, так как права можно выдать только через супер-пупер пользователя.
    И так, вот наша первая команда:

    -- 1. Предоставляем права на базу данных
    GRANT ALL PRIVILEGES ON DATABASE test TO test;
    
    -- 2. Переходим в базу данных
    \c test
    
    -- 3. Предоставляем право использования схемы public
    GRANT USAGE ON SCHEMA public TO test;
    
    -- 4. Предоставляем права на существующие таблицы
    GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO test;
    
    -- 5. Предоставляем права на существующие последовательности
    GRANT ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA public TO test;
    
    -- 6. Предоставляем права на существующие функции
    GRANT ALL PRIVILEGES ON ALL FUNCTIONS IN SCHEMA public TO test;
    
    -- 7. Назначаем права на будущие таблицы
    ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL PRIVILEGES ON TABLES TO test;
    
    -- 8. Назначаем права на будущие последовательности
    ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL PRIVILEGES ON SEQUENCES TO test;
    
    -- 9. Назначаем права на будущие функции
    ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL PRIVILEGES ON FUNCTIONS TO test;
    
    -- 10. Делаем пользователя владельцем базы данных
    ALTER DATABASE test OWNER TO test;
    

    8fcecc2d-a829-473f-808b-f45ebd6cccab-image.png

    Вот и все, все права выданы, можно приступать к работе с БД.

    Ну и для проверки закрепим, выйдем из psql и попробуем подключиться к базе при помощи команды:

    psql -d test -U test -h localhost -W
    

    Если все прошло успешно, увидим следующее:
    0dc0cd0a-f8c7-4a3e-8910-2e5da28c4d59-image.png

    И еще для закрепления! Давайте попробуем создать таблицу (Мы в базе под нужным пользователем)

    dde0a37b-07dd-44fe-b504-0493c5bf1c30-image.png

    Все работает, красотища то какая! Можно наконец-то брать node или go и бежать писать сервак!
    Всем спасибо за внимание, если есть вопросы - пишите в комменты.


    0 0 0 Ответить
  • kirilljsK
    kirilljs
    Исправление ошибки `makeUrl()` в MODX Revo: '`0` is not a valid integer'

    При работе с MODX Revolution вы можете столкнуться с ошибкой в консоли админки: 0 is not a valid integer and may not be passed to makeUrl().
    Разберемся, как её исправить.


    Причины возникновения ошибки

    Ошибка возникает, когда в ссылке указан некорректный ID ресурса.
    Примеры проблемных вызовов:

    1. Ссылка с пустым/нулевым плейсхолдером:
       <a href="[[~[[+id]]]]">Ссылка</a>
    

    Если [[+id]] равен 0 или не определен, MODX не может сгенерировать URL.

    1. Прямая ссылка на ID 0:
       <a href="[[+0]]">Ссылка</a>
    

    Ресурс с ID 0 не существует, что вызывает ошибку.


    Решение: диагностика через модификацию ядра

    Если проблемный код не удается найти вручную, выполните следующие шаги:

    1. Резервная копия
    Создайте бэкап файла core/model/modx/modx.class.php — мы будем его модифицировать.

    2. Добавление трейса ошибки
    Найдите в файле блок:

    } else {
        $this->log(modX::LOG_LEVEL_ERROR, '`' . $id . '` is not a valid integer and may not be passed to makeUrl()');
    }
    return $url;
    

    Замените его на:

    } else {
        $this->log(modX::LOG_LEVEL_ERROR, '`' . $id . '` is not a valid integer and may not be passed to makeUrl()');
        try {
            throw new Exception('Trace error');
        } catch (Exception $e) {
            $this->log(modX::LOG_LEVEL_ERROR, $e->getTraceAsString());
        }
    }
    return $url;
    

    3. Провоцируем ошибку
    Перейдите на страницы сайта, где может возникать ошибка.
    Затем проверьте логи MODX (Управление → Логи ошибок).


    Анализ логов

    В логах появится трейс ошибки, например:

    [2023-10-05 14:30:00] (ERROR @ /index.php) `[[+id]]` is not a valid integer and may not be passed to makeUrl()
    [2023-10-05 14:30:00] (ERROR @ /index.php)
    #0 /site/core/model/modx/modparser.class.php(765): modX->makeUrl('[[+id]]', '', '', -1)
    #1 /site/core/model/modx/modparser.class.php(385): modLinkTag->process(NULL)
    #2 /site/core/model/modx/modparser.class.php(164): modParser->processTag(Array, false)
    #3 /site/core/model/modx/modchunk.class.php(92): modParser->processElementTags('[[$tpl.news]]', '<div>...', false, false, '[[', ']]', Array, 10)
    #4 /site/core/model/modx/modx.class.php(1558): modChunk->process(Array)
    #5 /site/assets/components/mypackage/snippet.php(20): modX->getChunk('tpl.news', Array)
    

    Важные строки:

    • #3 — указывает на чанк tpl.news, где используется проблемная ссылка.
    • #5 — ссылается на сниппет или компонент, вызвавший ошибку.

    Исправление кода

    1. Откройте указанный в логах чанк/шаблон.
    2. Замените некорректные ссылки, например:
       <!-- Было -->
       <a href="[[~[[+id]]]]">Подробнее</a>
       
       <!-- Стало (проверка на существование ID) -->
       <a href="[[~[[+id:notempty=`[[+id]]`]]]]">Подробнее</a>
    

    Или убедитесь, что плейсхолдер [[+id]] передается корректно.


    Важно!

    После исправления ошибок верните исходный код файла modx.class.php, чтобы избежать проблем с обновлениями и производительностью.


    Если проблема осталась — проверьте все вызовы [[~...]] и работу с ID ресурсов в шаблонах и сниппетах.


    0 0 0 Ответить
  • kirilljsK
    kirilljs
    ModX как поменять всем товарам шаблон

    Раз уже в предидущей теме я разобрал как переносить товары массово из одной категории в другую, то наверное продолжу делиться своими наработками по скриптам.

    И так задача - как поменять товарам шаблон, вот небольшой, но рабочий скрипт:

    <?php
    foreach ($modx->getIterator('modResource', array('class_key' => 'msProduct')) as $resource) {
      $resource->set('template', ID нового шаблона);
        $resource->save();
    }
    

    Вот и всё, простенький, но эффективный скрипт.


    0 0 0 Ответить
  • kirilljsK
    kirilljs
    Modx | MiniShop — Скрипт переноса всех товаров из одной категории в другую

    Встрял кароче с задачей как перенести все товары из одной категории в другую, вообще нашел платное решение на modstore.pro, но зачем платить мы же погромисты)))))

    Вообщем написал небольшой скрипт который работает через консоль прямо в админке:

    <?php
    $oldCategoryId = 21951; // ID исходной категории
    $newCategoryId = 21953; // ID целевой категории
    
    // Проверяем существование новой категории
    $newCategory = $modx->getObject('modResource', $newCategoryId);
    if (!$newCategory) {
        echo "Ошибка: Категория с ID {$newCategoryId} не найдена!";
        return;
    }
    
    $count = 0;
    $criteria = array(
        'class_key' => 'msProduct',
        'parent' => $oldCategoryId
    );
    
    foreach ($modx->getIterator('modResource', $criteria) as $product) {
        $product->set('parent', $newCategoryId);
        
        if ($product->save()) {
            $count++;
        } else {
            echo "Ошибка при сохранении товара ID {$product->id}<br>";
        }
    }
    
    echo "Успешно перемещено {$count} товаров.";
    ?>
    

    Вауля - и ой как хорошо, наши товары перенеслись в другую категорию!
    Не забудьте только почистить кэш и скинуть url в настройках.


    0 0 0 Ответить
  • kirilljsK
    kirilljs
    Как написать первую программу на Lua для Roblox - Роблокс

    qwe.webp

    Roblox — одна из самых популярных платформ для создания игр, где Lua используется для написания игровой логики. В этой статье мы разберем, как создать вашу первую программу: от настройки среды до написания скрипта, который оживит объект в игре.

    Почему Lua в Roblox?

    Roblox Studio использует Lua как основной язык для скриптов по нескольким причинам:

    • Простота: Минималистичный синтаксис Lua идеален для новичков.
    • Интеграция: Lua-скрипты управляют объектами, физикой, событиями и интерфейсами в Roblox.
    • Кроссплатформенность: Код работает одинаково на всех устройствах, поддерживаемых Roblox.

    Шаг 1: Установка Roblox Studio

    1. Перейдите на официальный сайт Roblox и зарегистрируйтесь.
    2. Скачайте Roblox Studio (бесплатно).
    3. Запустите программу и создайте новое место (Create → New Place).

    Шаг 2: Создание первого скрипта

    1. В Roblox Studio добавьте объект:

      • Нажмите + в панели Workspace.
      • Выберите Part (куб) или Model (например, персонажа).
    2. Добавьте скрипт:

      • Щелкните правой кнопкой мыши на объекте в Explorer (окно слева).
      • Выберите Insert Object → Script.

    Шаг 3: Напишите код на Lua

    Вставьте в скрипт следующий код:

    local part = script.Parent  -- Ссылка на объект, к которому прикреплен скрипт  
    
    part.Touched:Connect(function(hit)  
        local player = game.Players:GetPlayerFromCharacter(hit.Parent)  
        if player then  
            part.BrickColor = BrickColor.Random()  -- Изменение цвета при касании  
            print(player.Name .. " коснулся объекта!")  
        end  
    end)  
    

    Что делает этот код?

    • При касании объекта (Touched) проверяет, принадлежит ли касание игроку.
    • Меняет цвет объекта на случайный.
    • Выводит сообщение в консоль.

    Шаг 4: Тестирование скрипта

    1. Нажмите Play (зеленая кнопка) в Roblox Studio.
    2. Перейдите в режим тестирования и подойдите к объекту.
    3. Убедитесь, что цвет изменился, а в консоли (Output ) появилось сообщение.

    Основы Roblox API: что нужно знать

    Чтобы писать сложные скрипты, изучите ключевые компоненты:

    1. Объекты и свойства
    • Workspace: Корневая папка для всех объектов в игре.
    • Players: Управление игроками и их данными.
    • Properties: Например, Part.Position, Part.Size.
    1. События (Events)
    • Touched — срабатывает при касании объекта.
    • MouseButton1Click — клик по GUI-элементу.
    • PlayerAdded — когда игрок заходит в игру.
    1. Службы (Services)
    • RunService: Управление игровым циклом (рендеринг, физика).
    • MarketplaceService: Работа с покупками внутри игры.

    Пример: Движущийся объект

    Добавьте скрипт, который заставит объект перемещаться:

    local part = script.Parent  
    
    while true do  
        part.Position = part.Position + Vector3.new(0, 0.5, 0)  -- Движение вверх  
        wait(0.1)  -- Пауза в 0.1 секунды  
    end  
    

    Важно:

    • wait() — обязательная функция для задержки, иначе цикл перегрузит игру.
    • Vector3.new(x, y, z) — задает координаты в 3D-пространстве.

    Советы для новичков

    • Используйте документацию: Roblox Developer Hub содержит примеры и описание API.
    • Изучайте чужой код: Загляните в скрипты популярных игр Roblox.
    • Пробуйте шаблоны: Roblox Studio предоставляет готовые шаблоны для изучения.

    Что дальше?

    Создайте простую игру: лабиринт, кликер или платформер.
    Добавьте GUI-интерфейс с помощью ScreenGui и TextButton.
    Изучите работу с DataStore для сохранения прогресса игроков.


    Первая программа на Lua в Roblox — это всегда эксперимент. Начните с простых скриптов, постепенно осваивая события, физику и многопользовательские функции. Помните: даже популярные игры вроде Adopt Me! или Brookhaven начинались с малого. Удачи в создании вашей первой игры!


    0 0 0 Ответить
  • kirilljsK
    kirilljs
    Lua для начинающих: основы программирования, примеры кода и применение

    lua.jpg

    Разберем основы языка Lua, его особенности, синтаксис и примеры кода для новичков. Вы узнаете, чем Lua отличается от Python или JavaScript, где его применяют (от разработки игр до IoT) и как быстро начать программировать на этом легковесном языке.

    Почему Lua идеален для начинающих?

    Lua — это минималистичный скриптовый язык, который ценят за:

    • Простой синтаксис: меньше правил, больше практики.
    • Высокую скорость выполнения: Lua компилируется в байт-код, что делает его быстрым даже в ресурсоемких проектах.
    • Интеграцию с другими языками: Lua легко встраивается в C/C++, что расширяет его возможности.

    Например, в Roblox или World of Warcraft аддоны пишут именно на Lua из-за его гибкости и низких требований к ресурсам.

    Основы синтаксиса Lua: с чего начать?

    Lua славится минималистичным и интуитивным синтаксисом, который позволяет новичкам быстро перейти от теории к практике. Чтобы освоить базу, достаточно понять несколько ключевых концепций. Разберем их по порядку.


    Переменные: динамическая типизация и области видимости

    В Lua переменные не требуют явного указания типа — он определяется автоматически. Для объявления используется ключевое слово local (рекомендуется) или присваивание без него (глобальная переменная).

    local message = "Привет, Lua!"  -- Локальная переменная  
    count = 10                      -- Глобальная переменная (лучше избегать)  
    

    Важно:

    • Локальные переменные видны только в блоке, где объявлены (например, внутри функции).
    • Глобальные переменные доступны везде, но их использование может привести к ошибкам в больших проектах.

    Типы данных: от чисел до таблиц

    Lua поддерживает 8 базовых типов данных. Наиболее часто используются:

    • number: целые и дробные числа (3, 3.14).
    • string: строки в одинарных или двойных кавычках ("текст", 'Lua').
    • boolean: true или false.
    • nil: отсутствие значения (аналог null в других языках).
    • table: универсальная структура для хранения данных (аналог массивов и объектов).

    Пример работы с таблицами:

    local user = {name = "Alice", age = 25}  
    print(user.name)  -- Выведет "Alice"  
    

    Условные операторы: if-then-else

    Условные конструкции в Lua пишутся с помощью if, then, else и elseif. Блок закрывается ключевым словом end.

    Пример:

    local temperature = 20  
    if temperature > 30 then  
        print("Жарко!")  
    elseif temperature > 15 then  
        print("Тепло")  
    else  
        print("Прохладно")  
    end  
    

    Циклы: for, while и repeat-until

    Lua предлагает три типа циклов:

    1. Числовой цикл for:
    for i = 1, 5 do  
        print("Итерация " .. i)  -- Выведет числа от 1 до 5  
    end  
    
    1. Цикл while:
    local x = 1  
    while x <= 3 do  
        print(x)  
        x = x + 1  
    end  
    
    1. Цикл repeat-until (аналог do-while):
    repeat  
        print("Попытка")  
    until false  -- Бесконечный цикл (на примере)  
    

    Функции: объявление и аргументы

    Функции в Lua объявляются через function и могут возвращать несколько значений.

    Пример функции с аргументами:

    local function sum(a, b)  
        return a + b  
    end  
    print(sum(2, 3))  -- Выведет 5  
    

    Особенности:
    Функции можно сохранять в переменные или таблицы.
    Поддерживается vararg (переменное число аргументов) через ...


    Таблицы: основа структур данных

    Таблицы в Lua — это ассоциативные массивы, которые могут хранить любые типы данных. Они используются для создания объектов, списков и даже классов.

    Пример сложной таблицы:

    local person = {  
        name = "Bob",  
        age = 30,  
        hobbies = {"games", "reading"},  
        greet = function(self)  
            print("Hello, " .. self.name)  
        end  
    }  
    person:greet()  -- Вызов метода таблицы  
    

    Совет: Используйте метатаблицы для реализации ООП-концепций, например, наследования.


    Обработка ошибок: assert и pcall

    Для управления ошибками Lua предоставляет функции assert() и pcall() (protected call).

    Пример с pcall:

    local status, result = pcall(function()  
        error("Что-то пошло не так")  
    end)  
    if not status then  
        print("Ошибка: " .. result)  
    end  
    

    Где используется Lua? Примеры проектов

    Lua — язык-невидимка, который часто работает «под капотом». Вот где его можно встретить:

    1. Игровая индустрия
    • Roblox: Вся логика игр пишется на Lua.
    • World of Warcraft: Аддоны и модификации создаются с помощью Lua.
    • Love2D: Популярный фреймворк для 2D-игр.
    1. Веб-сервисы
    • OpenResty: Платформа на основе Nginx + Lua для обработки миллионов запросов в секунду.
    • Tarantool: NoSQL-база данных с поддержкой Lua для написания хранимых процедур.
    1. IoT и встраиваемые системы
    • NodeMCU: Платформа для IoT-устройств, где Lua управляет микроконтроллерами.
    • ESP8266/ESP32: Lua используется для программирования Wi-Fi модулей.
    1. Прочее
    • Adobe Photoshop: Некоторые скрипты для автоматизации.
    • Wireshark: Анализ сетевого трафика через Lua-скрипты.

    Как начать изучать Lua: шаги для новичка

    Если вы уже разобрались с основами синтаксиса (переменные, циклы, таблицы), переходите к практике. Вот пошаговый план:

    Шаг 1: Установка инструментов

    • Интерпретатор Lua: Скачайте с официального сайта.
    • Редактор кода: VS Code с расширением Lua Language Server или ZeroBrane Studio.
    • Онлайн-песочница: replit.com для быстрого старта.

    Шаг 2: Пишите мини-проекты
    Применяйте изученные таблицы и функции в реальных задачах:

    • Калькулятор с графическим интерфейсом (используйте библиотеку IUP ).
    • Текстовая RPG-игра с использованием циклов и условий.
    • Парсер CSV-файла (работа со строками и таблицами).

    Шаг 3: Изучите продвинутые темы

    • Метатаблицы: Реализуйте ООП через __index и __newindex.
    • Модули: Организуйте код в файлы с помощью require().
    • Работа с API: Подключите Lua к C/C++ или используйте библиотеку LuaSocket для HTTP-запросов.

    Шаг 4: Участвуйте в сообществах

    • Форумы: Lua Users и Reddit r/lua и конечно же на нашем форуме - RosDesk!
    • GitHub: Изучайте исходники популярных проектов на Lua (например, фреймворк LÖVE ).

    Шаг 5: Создайте портфолио

    • Реализуйте проекты, которые покажут ваши навыки:

    • Игра на Love2D с публикацией на itch.io.

    • Утилита для автоматизации задач на ESP32.

    • Скрипт для анализа данных (используйте LuaCSV ).


    Итого 😊

    Lua — язык, который дает свободу выбора: от игр до промышленного IoT. Его минималистичный синтаксис позволяет быстро начать, а интеграция с C/C++ открывает двери в высоконагруженные проекты. Следуя шагам из этой статьи, вы не только освоите Lua, но и сможете применять его в коммерческих задачах. Не забывайте экспериментировать — именно это превращает новичков в профессионалов.


    0 0 0 Ответить
  • kirilljsK
    kirilljs
    Использование классов для анимации | Класс Animator в действии

    Зачем использовать классы для анимации?

    1. Чистота кода
      Анимации, описанные через CSS, проще читать и поддерживать, чем JavaScript-анимации.

    2. Производительность
      CSS-анимации часто работают быстрее за счёт использования GPU для обработки трансформаций и переходов.

    3. Гибкость
      Вы можете легко управлять анимациями через добавление или удаление классов, не переписывая логику.

    4. Повторное использование
      Один класс анимации можно применять к разным элементам.


    Пример реализации класса Animator

    Класс Animator может быть полезен для управления анимациями через добавление и удаление CSS-классов. Вот пример его реализации:

    class Animator {
      constructor() {
        this.animations = {};
      }
    
      /**
       * Добавляет класс анимации элементу.
       * @param {HTMLElement} element - Элемент для анимации.
       * @param {string} animationClass - Название класса анимации.
       */
      addAnimation(element, animationClass) {
        element.classList.add(animationClass);
        return new Promise((resolve) => {
          const onAnimationEnd = () => {
            element.classList.remove(animationClass);
            element.removeEventListener('animationend', onAnimationEnd);
            resolve();
          };
          element.addEventListener('animationend', onAnimationEnd);
        });
      }
    
      /**
       * Удаляет класс анимации элемента.
       * @param {HTMLElement} element - Элемент для анимации.
       * @param {string} animationClass - Название класса анимации.
       */
      removeAnimation(element, animationClass) {
        element.classList.remove(animationClass);
      }
    }
    
    // Пример использования:
    const animator = new Animator();
    
    const box = document.querySelector('.box');
    animator.addAnimation(box, 'fade-in').then(() => {
      console.log('Анимация завершена!');
    });
    

    Как это работает?

    1. Добавление класса
      Метод addAnimation добавляет класс анимации к элементу и возвращает Promise, который разрешается после завершения анимации (событие animationend).
    2. Удаление класса
      После завершения анимации класс автоматически удаляется, чтобы элемент вернулся к исходному состоянию.
    3. CSS для анимации
      Для работы анимации нужно определить соответствующие стили в CSS:
    /* Пример CSS для анимации */
    .fade-in {
      animation: fadeInAnimation 1s ease-in-out;
    }
    
    @keyframes fadeInAnimation {
      from {
        opacity: 0;
      }
      to {
        opacity: 1;
      }
    }
    

    Преимущества класса Animator

    1. Автоматизация
      Вам не нужно вручную отслеживать завершение анимации — это делает Animator.
    2. Масштабируемость
      Можно легко расширить функциональность, например, добавить поддержку последовательных анимаций или цепочек.
    3. Удобство
      Работа с анимациями становится более декларативной и понятной.

    Пример использования в реальном проекте

    Представьте, что у вас есть карточки товаров, которые должны появляться на странице с анимацией “выезда” при загрузке. Вот как это можно реализовать:

    const cards = document.querySelectorAll('.product-card');
    const animator = new Animator();
    
    cards.forEach((card, index) => {
      setTimeout(() => {
        animator.addAnimation(card, 'slide-in');
      }, index * 200); // Добавляем задержку для эффекта последовательности
    });
    
    /* CSS для анимации */
    .slide-in {
      animation: slideInAnimation 0.5s ease-out;
    }
    
    @keyframes slideInAnimation {
      from {
        transform: translateY(20px);
        opacity: 0;
      }
      to {
        transform: translateY(0);
        opacity: 1;
      }
    }
    

    Сравнение подходов к анимации

    Подход Преимущества Недостатки
    CSS-классы - Простота реализации
    - Высокая производительность
    - Легко переиспользовать
    - Чистый и декларативный код
    - Ограниченная гибкость для сложных анимаций
    - Зависимость от браузерной поддержки
    JavaScript-анимации - Полный контроль над процессом анимации
    - Возможность динамически изменять параметры
    - Подходит для сложных задач
    - Сложнее в реализации и поддержке
    - Может быть менее производительным
    - Больше кода
    Библиотеки (например, GSAP) - Мощные инструменты для создания сложных анимаций
    - Кроссбраузерность
    - Встроенные функции для работы с таймингом и эффектами
    - Избыточность для простых задач
    - Дополнительная зависимость
    - Увеличение размера проекта

    Можно разобрать примеры создания более сложных анимаций с использованием requestAnimationFrame или библиотек, таких как GSAP.


    0 0 0 Ответить
  • Войти

  • Нет учётной записи? Зарегистрироваться

  • Войдите или зарегистрируйтесь для поиска.
  • Первое сообщение
    Последнее сообщение
0
  • Категории
  • Последние
  • Метки
  • Популярные
  • Пользователи
  • Группы