Продолжаем разговор об исключениях
Please open Telegram to view this post
VIEW IN TELEGRAM
qa.log
Ассерты
🔼 Если условие не выполняется, тест считается неуспешным, и фреймворк (например, JUnit) выбрасывает
Это часть соглашения фреймворков тестирования (например, JUnit, TestNG):
- они распознают
- и корректно отображают его в отчётах: с сообщением, строкой кода, и разницей между
Виды ассертов:
🟢
🟢
🟢
🟢
🟢
Assertions - это утверждения, которые проверяют, что определённое условие выполняется:
assertEquals(200, response.statusCode)
AssertionError.AssertionError — это потомок класса Error, а не Exception, и он не должен обрабатываться приложением. То есть в случае NullPointerException, например, приложение выплюнет исключение вне зависимости от того, обработает ли его разработчик. Это часть соглашения фреймворков тестирования (например, JUnit, TestNG):
- они распознают
AssertionError как падение теста;- и корректно отображают его в отчётах: с сообщением, строкой кода, и разницей между
expected/actual.Виды ассертов:
assertEquals = утвердить идентичность
fun <T> assertEquals(expected: T, actual: T, message: String? = null) {
if (expected != actual) {
val errorMsg = message ?: "Assertion failed: expected <$expected>, but was <$actual>"
throw AssertionError(errorMsg)
}
}
// Применение
val expectedStatus = 200
val actualStatus = apiResponse.statusCode
assertEquals(expectedStatus, actualStatus, "Некорректный статус ответа")
assertTrue = утвердить истинность
fun assertTrue(condition: Boolean, message: String? = null) {
if (!condition) {
throw AssertionError(message ?: "Assertion failed: expected true, but was false")
}
}
// Применение:
val petCreated = apiResponse.statusCode == 200
assertTrue(petCreated, "Питомец не был создан")
assertFalse = утвердить ложность
fun assertFalse(condition: Boolean, message: String? = null) {
if (condition) {
throw AssertionError(message ?: "Assertion failed: expected false, but was true")
}
}
// Использование:
val isError = apiResponse.statusCode >= 400
assertFalse(isError, "Ответ содержит ошибку: ${apiResponse.statusCode}")
assertNotNull = утвердить наличие
fun assertNotNull(value: Any?, message: String? = null) {
if (value == null) {
throw AssertionError(message ?: "Assertion failed: value was null")
}
}
// Использование:
val createdPetId = apiResponse.data?.id
assertNotNull(createdPetId, "ID созданного питомца не должен быть null")
assertNull = утвердить отсутствие
fun assertNull(value: Any?, message: String? = null) {
if (value != null) {
throw AssertionError(message ?: "Assertion failed: expected null, but was $value")
}
}
// Использование:
val deletedPet = apiClient.getPetById(999)
assertNull(deletedPet, "Удалённый питомец должен быть null")
Please open Telegram to view this post
VIEW IN TELEGRAM
Forbes: Крупные IT-компании обяжут поддерживать вузы для сохранения аккредитации
Наличие аккредитации позволят IT-компаниям “экономить” на налоговых отчислениях, что в свою очередь оставляет в бюджете неутилизированное пространство для занятости выгодоприобретателей-коммерсантов.
Для сохранения льготы предлагается принять участие в “поддержке образовательного сектора” по IT-специальностям путем организации стажировок, а так же проведения занятий в вузах для учащихся.
Ситуация win-win:
🔼 Для государства - прикладная актуализация образовательной базы по критически важному направлению и оптимизация расходов бюджета;
🔼 Для компаний - возможность сохранения налоговых льгот и, как следствие, большого процента бюджета, даже с учетом оплат стажировок и преподавания/менторства сотрудниками;
🔼 Для рядовых сотрудников компании - шанс на реализацию в сфере преподавания и некоторая прибавка к доходу.
Стажерские вакансии на всех площадках найма через 3..2..1..
Наличие аккредитации позволят IT-компаниям “экономить” на налоговых отчислениях, что в свою очередь оставляет в бюджете неутилизированное пространство для занятости выгодоприобретателей-коммерсантов.
Для сохранения льготы предлагается принять участие в “поддержке образовательного сектора” по IT-специальностям путем организации стажировок, а так же проведения занятий в вузах для учащихся.
Ситуация win-win:
Стажерские вакансии на всех площадках найма через 3..2..1..
Please open Telegram to view this post
VIEW IN TELEGRAM
This media is not supported in your browser
VIEW IN TELEGRAM
Кроме прочего, AI-ассистентом так же предлагается функциональность по поиску потенциальных проблем сверх требований. Удобно в качестве дополнительного фильтра для самопроверки.
Please open Telegram to view this post
VIEW IN TELEGRAM
This media is not supported in your browser
VIEW IN TELEGRAM
Теперь можно вызывать действия прямо из окна автодополнения.
Вводим одинарную (.), чтобы увидеть предложения по автодополнению кода, и двойную (..), чтобы отфильтровать результаты только по действиям.
Отсматриваем предварительный результат и применяем при его эффективности.
Такое дополнение позволяет редактировать наработки из одного места.
Полный список обновлений - What’s New in IntelliJ IDEA 2025.3
Please open Telegram to view this post
VIEW IN TELEGRAM
Разомнемся после праздников
🖥 Новая задача Best Time to Buy and Sell Stock
ОПИСАНИЕ:
ПРИМЕРЫ🔽 :
ОПИСАНИЕ:
Вам дан массив цен, где prices[i] — цена данной акции в i-й день.
Вы хотите максимизировать свою прибыль, выбрав один день для покупки одной акции и другой день в будущем для ее продажи.
Верните максимальную прибыль, которую вы можете получить от этой сделки. Если вы не можете получить никакой прибыли, верните 0.
ПРИМЕРЫ
Input: prices = [7,1,5,3,6,4]
Output: 5
Explanation: Buy on day 2 (price = 1) and sell on day 5 (price = 6), profit = 6-1 = 5.
Note that buying on day 2 and selling on day 1 is not allowed because you must buy before you sell.
Input: prices = [7,6,4,3,1]
Output: 0
Explanation: In this case, no transactions are done and the max profit = 0.
Please open Telegram to view this post
VIEW IN TELEGRAM
LeetCode
Best Time to Buy and Sell Stock - LeetCode
Can you solve this real interview question? Best Time to Buy and Sell Stock - You are given an array prices where prices[i] is the price of a given stock on the ith day.
You want to maximize your profit by choosing a single day to buy one stock and choosing…
You want to maximize your profit by choosing a single day to buy one stock and choosing…
Продолжаем разговор об исключениях
Please open Telegram to view this post
VIEW IN TELEGRAM
qa.log
Кастомные ассерты
Создадим вспомогательный класс, в котором опишем интересующие нас проверки с использованием
Добавляем компаньона, который приводит тип получаемых данных к типу класса:
Проверяем полученный ответ и возвращаем значение в нужном типе:
🔽 Для стандартных проверок составление кастомных ассертов не требуется, так как большинство необходимых методов уже имеется в общедоступных библиотеках.
🔼 Однако иногда появляются точечно случаи, под которые таких проверок нет.
Custom Assert - ассерты, позволяющие выполнять проверки на своих условиях в дополнение к возможностям стандартной библиотеки.
ResponseAssert.assertThat(response)
.hasStatusCode200()
Создадим вспомогательный класс, в котором опишем интересующие нас проверки с использованием
AbstractAssert (из библиотеки assertj) типа данных самого класса и принимаемого значения:
class ResponseAssert(
actual: Response
) : AbstractAssert<ResponseAssert, Response>(
actual, ResponseAssert::class.java) {}
Добавляем компаньона, который приводит тип получаемых данных к типу класса:
companion object {
fun assertThat(actual: Response): ResponseAssert {
return ResponseAssert(actual)
}
}
Проверяем полученный ответ и возвращаем значение в нужном типе:
fun hasStatusCode200(): ResponseAssert {
if (actual.status() != 200) {
failWithMessage("Expected status code 200 but was ${actual.status()}")
}
return this
}
Please open Telegram to view this post
VIEW IN TELEGRAM
This media is not supported in your browser
VIEW IN TELEGRAM
Помимо генераций, AI-ассистентами так же предлагается функционал по объяснению фрагментов кода.
Please open Telegram to view this post
VIEW IN TELEGRAM
Использовать Codex возможно с подпиской JetBrains AI и своей учетной записью ChatGPT (или ключом API OpenAI). Никаких дополнительных приседаний - доступ прямо из чата AI-ассистента.
Представлены 3 режима работы:
• ридонли
• рв
• фул аксес (полностью автономный помощник с допуском к редактированию внешних файлов)
Дополнительно доступны последние версии моделей от OpenAI, а так же несколько опций глубины “мышления”:
• низкий
• средний
• высокий
• ультравысокий
Если подписки нет, то доступна пробная беслпатная версия на ограниченный срок, пока не будут исчерпаны промо-кредиты.
JetBrains так же сохранил для своих пользователей возможности мультимодельной работы: список доступных достаточно часто обновляемых LLM от других “поставщиков” размещается на своем прежнем месте - так же в окне чата с асситентом.
Что это меняет?
Небольшой демо-прокат по возможностям кодекса показал доступность к сразу несольким уровням настройки проектов, гибкость в предложении вариантов, более глубокое понимание витиеватого и в то же время абстрактного запроса, ну, и самое интересное - возможность сравнения с инструментами конкурентов!
Please open Telegram to view this post
VIEW IN TELEGRAM
qa.log
Commit contains problemsПри открытии вкладки
Code Analysis для изучения проблем коммита бегущей строкой возникает потребность в предложении AI-ассистентом моментальных in-place правок. Видим проблему на строке 10: “Переменная нигде не используется” и мгновенно по кнопке с предложением стереть такую переменную избавляемся от неисправностей коммита.
Please open Telegram to view this post
VIEW IN TELEGRAM
ОПИСАНИЕ:
Фраза является палиндромом, если после преобразования всех заглавных букв в строчные и удаления всех неалфавитно-цифровых символов она читается одинаково в прямом и обратном направлении. Алфавитно-цифровые символы включают буквы и цифры.
Для заданной строки s верните true, если она является палиндромом, или false в противном случае.
ПРИМЕРЫ
Input: s = "A man, a plan, a canal: Panama"
Output: true
Explanation: "amanaplanacanalpanama" is a palindrome.
Input: s = "race a car"
Output: false
Explanation: "raceacar" is not a palindrome.
Input: s = " "
Output: true
Explanation: s is an empty string "" after removing non-alphanumeric characters.
Since an empty string reads the same forward and backward, it is a palindrome.
Please open Telegram to view this post
VIEW IN TELEGRAM
LeetCode
Valid Palindrome - LeetCode
Can you solve this real interview question? Valid Palindrome - A phrase is a palindrome if, after converting all uppercase letters into lowercase letters and removing all non-alphanumeric characters, it reads the same forward and backward. Alphanumeric characters…
В рейтинге опенсорсных проектов github набирает популярность новый инструмент - openclaw
👍 400к звезд на независимом бесплатном проекте, 65к ответвлений и более 5к мр-ов в репозиторий.
На деле openclaw - это карманный ai-ассистент, который не просто дает ответы на вопросы, заданные в чате, а решает вполне интеграционные задачи взаимодействия с большим количеством сервисов.
Теперь, чтобы, к примеру, создать встречу с коллегами с текстовым и визуальным сопровождением, отправить приглашение на почтовые ящики и уведомить о ней в публичном рабочем канале достаточно “входа” через одну из предлагаемых точек: мессенджер, веб-клиент или ios-приложение и короткой команды, выражающей суть.
Далее инструмент самостотельно проведет многоступенчатую интеграцию и уведомит о результате.
Подробное описание фичей тут.
Независимо от выбранного пути, при первоначальной настройке конфигурируются:
Варианты подключений описаны тут в разделе
OpenClaw — это шлюз для самостоятельной установки, который связывает ваши любимые мессенджеры — WhatsApp, Telegram, Discord, iMessage и другие — с ИИ-агентами для программирования, такими как Pi. Вы запускаете один процесс шлюза на своем компьютере (или сервере), и он становится мостом между вашими мессенджерами и всегда доступным ИИ-помощником.
На деле openclaw - это карманный ai-ассистент, который не просто дает ответы на вопросы, заданные в чате, а решает вполне интеграционные задачи взаимодействия с большим количеством сервисов.
Теперь, чтобы, к примеру, создать встречу с коллегами с текстовым и визуальным сопровождением, отправить приглашение на почтовые ящики и уведомить о ней в публичном рабочем канале достаточно “входа” через одну из предлагаемых точек: мессенджер, веб-клиент или ios-приложение и короткой команды, выражающей суть.
Далее инструмент самостотельно проведет многоступенчатую интеграцию и уведомит о результате.
Подробное описание фичей тут.
Независимо от выбранного пути, при первоначальной настройке конфигурируются:
• Поставщик модели и аутентификация — ключ API, OAuth или токен настройки для выбранного поставщика
• Рабочая область — каталог для файлов агента, шаблонов начальной настройки и памяти
• Шлюз — порт, адрес привязки, режим аутентификации
• Каналы (опционально) — WhatsApp, Telegram, Discord и другие
• Демон (опционально) — фоновый сервис, благодаря которому шлюз запускается автоматически
Варианты подключений описаны тут в разделе
Quick Start через one-liner/nmp и напрямую macOS установочник.Please open Telegram to view this post
VIEW IN TELEGRAM
RE-usable Claude Code Skills для автотестирования
Чаты уходят в прошлое, и на замену им приходят полноценные агенты со скиллами. Это вызвано в первую очередь возможностью экономии ресурсов на поддержание контекста.
Создаем агента под генерацию данных для автотестов, наполняем контекст короткой понятной паттерн-инструкцией и на выходе получаем структурировано обработанные тестовые объекты, генерация которых не затребовала обработку всего контекста проекта, а работала в рамках предоставленных шаблонов.
Далее создаем скилл с инструкцией по сборке таких данных в паттернизированные тестовые сценарии с соблюдением иерархии. Далее - скилл под рефакторинг. Далее - обработка ошибок. И так далее.
Теперь работа с кодом может выглядеть, как короткий императив к агентам, который, используя экономичный контекст инструкций, соберет подходящее решение, не затратив на это много ресурсов и времени.
Шаблоны скилов могут быть универсальными и дополняемыми в соответствии с потребностями.
Клонируем к себе базовый набор инструментов (в моем случае под Kotlin & JUnit5) из моего репозитория на github и адаптируем под свои нужды.
Чаты уходят в прошлое, и на замену им приходят полноценные агенты со скиллами. Это вызвано в первую очередь возможностью экономии ресурсов на поддержание контекста.
Создаем агента под генерацию данных для автотестов, наполняем контекст короткой понятной паттерн-инструкцией и на выходе получаем структурировано обработанные тестовые объекты, генерация которых не затребовала обработку всего контекста проекта, а работала в рамках предоставленных шаблонов.
Далее создаем скилл с инструкцией по сборке таких данных в паттернизированные тестовые сценарии с соблюдением иерархии. Далее - скилл под рефакторинг. Далее - обработка ошибок. И так далее.
Теперь работа с кодом может выглядеть, как короткий императив к агентам, который, используя экономичный контекст инструкций, соберет подходящее решение, не затратив на это много ресурсов и времени.
Шаблоны скилов могут быть универсальными и дополняемыми в соответствии с потребностями.
Клонируем к себе базовый набор инструментов (в моем случае под Kotlin & JUnit5) из моего репозитория на github и адаптируем под свои нужды.
👍1
qa.log
RE-usable Claude Code Skills для автотестирования Чаты уходят в прошлое, и на замену им приходят полноценные агенты со скиллами. Это вызвано в первую очередь возможностью экономии ресурсов на поддержание контекста. Создаем агента под генерацию данных для…
upd:
Добавлена логика по работе с распределенными системами и асинхронным получением данных от брокеров.
Хочется не просто вызывать метод и проверять ответ, а убедиться, что нужное событие появилось в брокере с правильными данными в правильный момент. Это retry-логика, сравнение с допуском по времени, отдельная обработка генерируемых полей.
Скилл задаёт универсальную архитектуру слоями Test → Steps → Manager → Client, паттерн checkEvent прямо в тест-классе, шаблоны createExpectedEvent и compareEvents с готовой логикой сравнения. Секции [НАСТРОИТЬ] под брокер, доменную модель, статусы.
Работает с любым стеком на JVM: Kafka, RabbitMQ, любой другой брокер. Проект на Kotlin + JUnit5, но паттерны переносятся на Java без изменений.
Доработка в репо https://github.com/wlasadd/claude-autotest-skills
git commit -m "Add event-streaming skill”Добавлена логика по работе с распределенными системами и асинхронным получением данных от брокеров.
Хочется не просто вызывать метод и проверять ответ, а убедиться, что нужное событие появилось в брокере с правильными данными в правильный момент. Это retry-логика, сравнение с допуском по времени, отдельная обработка генерируемых полей.
Скилл задаёт универсальную архитектуру слоями Test → Steps → Manager → Client, паттерн checkEvent прямо в тест-классе, шаблоны createExpectedEvent и compareEvents с готовой логикой сравнения. Секции [НАСТРОИТЬ] под брокер, доменную модель, статусы.
Работает с любым стеком на JVM: Kafka, RabbitMQ, любой другой брокер. Проект на Kotlin + JUnit5, но паттерны переносятся на Java без изменений.
Доработка в репо https://github.com/wlasadd/claude-autotest-skills
GitHub
GitHub - wlasadd/claude-autotest-skills: Base Claude Code skills for test automation (Kotlin + JUnit5)
Base Claude Code skills for test automation (Kotlin + JUnit5) - wlasadd/claude-autotest-skills
👍1
Claude skills с инструкциями по прикладной работе с автоматизацией могут быть так же дополнены шаблонами по непосредственной экономии памяти.
- решает проблему лимитов токенов на лету.
Храним отдельные инструкции по шаблонизированию проекта + caveman скилл по оптимизации наполнения контекста. На выходе получаем агента, который не только структурировано, но и дешево воспроизводит и дополняет логику проекта.
GitHub - JuliusBrussee/caveman
- решает проблему лимитов токенов на лету.
Храним отдельные инструкции по шаблонизированию проекта + caveman скилл по оптимизации наполнения контекста. На выходе получаем агента, который не только структурировано, но и дешево воспроизводит и дополняет логику проекта.
Новая задача Valid Palindrome
ОПИСАНИЕ:
ПРИМЕРЫ:
ОПИСАНИЕ:
Фраза является палиндромом, если после преобразования всех заглавных букв в строчные и удаления всех неалфавитно-цифровых символов она читается одинаково как в прямом, так и в обратном направлении. К алфавитно-цифровым символам относятся буквы и цифры.
Для заданной строки s верните true, если она является палиндромом, иначе верните false.
ПРИМЕРЫ:
Input: s = "A man, a plan, a canal: Panama"
Output: true
Explanation: "amanaplanacanalpanama" is a palindrome.
Input: s = "race a car"
Output: false
Explanation: "raceacar" is not a palindrome.
Input: s = " "
Output: true
Explanation: s is an empty string "" after removing non-alphanumeric characters.
Since an empty string reads the same forward and backward, it is a palindrome.
LeetCode
Valid Palindrome - LeetCode
Can you solve this real interview question? Valid Palindrome - A phrase is a palindrome if, after converting all uppercase letters into lowercase letters and removing all non-alphanumeric characters, it reads the same forward and backward. Alphanumeric characters…
СОБЕСЕДОВАНИЕ:
Раздел: Сериализация, десериализация
Вопрос: Популярные библиотеки и причины их выбора.
Раздел: Сериализация, десериализация
Вопрос: Популярные библиотеки и причины их выбора.
Jackson - библиотека, по умолчанию интегрированная во многие HTTP-клиенты, популярна для работы с JSON в Kotlin.• Умеет автоматически сериализовать и десериализовать data class по именам полей
• Поддерживается в большинстве API-клиентов (Feign, RestTemplate и др.)
• Позволяет кастомизировать процесс через аннотации
Аннотации Jackson:
@JsonProperty - задаёт явное имя ключа в JSON:
data class Product(
val productId: UUID,
@JsonProperty("brandInfo")
val brand: Brand?
)
// JSON: { "brandInfo": "Nike" }
@JsonIgnore - исключает поле из сериализации и десериализации. Поле присутствует в объекте, но не попадает в JSON:
data class Product(
val productId: UUID,
@JsonIgnore
val brand: Brand?
)
// brand не попадёт в JSON
@JsonInclude - указывает какие поля включать в JSON. Удобно для отправки «чистых» запросов без лишних полей:
@JsonInclude(JsonInclude.Include.NON_NULL)
data class Pet(
val name: String,
val description: String? = null
)
// если description == null — поле не попадёт в JSON
@JsonProperty на enum - переименовывает конкретные константы в JSON:
enum class Status {
@JsonProperty("available") AVAILABLE,
@JsonProperty("pending") PENDING,
@JsonProperty("sold") SOLD
}
// JSON вернёт "available" вместо "AVAILABLE"
@JsonValue - говорит Jackson использовать значение конкретного поля для сериализации всего объекта. В отличие от @JsonProperty на константах, здесь значение берётся из поля, переданного в конструктор:
enum class Status(@JsonValue val value: String) {
AVAILABLE("available"),
PENDING("pending"),
SOLD("sold")
}
// Jackson сериализует enum как строку "available", беря значение из поля value
К популярным библиотекам относятся так же:
Kotlinx Serialization, Moshi, Gson.Вектор разработки все больше смещается с написания кода в сторону умения работать с настройками конфигов агентов.
Claude Code, Codex, Cursor и тп - успешные коммерческие продукты, которые уже успели себя зарекомендовать.
Попробуем разобраться с мультимодельными опенсорсными провайдерами, например, opencode (установка описана внутри), и настроить конфиг для него.
Что обещано:
Минимальные требования:
-
-
Далее разберем каждый из файлов подробно и достаточно для первого запуска.
Claude Code, Codex, Cursor и тп - успешные коммерческие продукты, которые уже успели себя зарекомендовать.
Попробуем разобраться с мультимодельными опенсорсными провайдерами, например, opencode (установка описана внутри), и настроить конфиг для него.
Что обещано:
Что такое OpenCode?
OpenCode — это агент с открытым исходным кодом, который помогает писать код в терминале, IDE или на рабочем столе.
[*] Поддержка LSP Автоматическая загрузка подходящих LSP для LLM
[*] Многосессионность Параллельный запуск нескольких агентов в рамках одного проекта
[*] Поделиться ссылкой Поделитесь ссылкой на любую сессию для справки или отладки
[*] GitHub Copilot Войдите через GitHub, чтобы использовать свою учетную запись Copilot
[*] ChatGPT Plus/Pro Войдите через OpenAI, чтобы использовать свою учетную запись ChatGPT Plus или Pro
[*] Любая модель Более 75 поставщиков LLM через Models.dev, включая локальные модели
[*] Любой редактор Доступно в виде интерфейса терминала, настольного приложения и расширения IDE
Минимальные требования:
-
opencode.json - машинная конфигурация инструмента. Здесь: какие модели использовать, какие MCP-серверы подключить, какие права давать агенту, какие под-агенты создать. Это аналог settings.json в Claude Code.-
AGENTS.md - текстовые инструкции для модели на естественном языке. Это системный промпт проекта: правила кодстайла, поведение, формат ответов. Аналог CLAUDE.md.Далее разберем каждый из файлов подробно и достаточно для первого запуска.
opencode.ai
OpenCode | The open source AI coding agent
OpenCode - The open source coding agent.
Блок 1.
По ссылке расположен универсальный конфиг-шаблон, предоставляемый самим провайдером для более гибкой настройки.
Это поля на корневом уровне объекта, которые задают общее поведение инструмента до того, как дело дойдёт до моделей и агентов.
opencode.json: верхнеуровневые параметрыПо ссылке расположен универсальный конфиг-шаблон, предоставляемый самим провайдером для более гибкой настройки.
Это поля на корневом уровне объекта, которые задают общее поведение инструмента до того, как дело дойдёт до моделей и агентов.
"$schema": "https://opencode.ai/config.json", // схема конфигурации
"lsp": true, // включает Language Server Protocol. opencode поднимает языковые серверы (для Kotlin/Java и т.д.) и за счёт этого «видит» ошибки компиляции, типы, определения символов.
"formatter": true, // разрешает авто-форматирование изменённых файлов через настроенные форматтеры
"default_agent": "plan", // какой из под-агентов запускается по умолчанию при старте сессии. plan - это read-only агент без права менять файлы и запускать команды.
"shell": "/bin/zsh", // какой shell использовать для bash-команд
"logLevel": "INFO", // уровень логирования самого opencode. INFO - стандартный
"share": "disabled", // запрещает шаринг сессий (выгрузку диалога в облако opencode по ссылке)
"autoupdate": "notify", // при выходе новой версии opencode только уведомляет, но не обновляется сам
"snapshot": true, // включает снапшоты состояния файлов перед изменениями, чтобы можно было откатить правки агента