Обновить

Бэкенд

Сначала показывать
Порог рейтинга

Слышу уже от второго человека, что язык Rust не дает нормально работать с указателями в связанных списках, деревьях и графах (в моей вселенной ЯП без этого - это как свадьба без невесты). Взял ChatGPT, задал промпт: "write a code to insert a node into a doubly linked list in rust". Оно сгенерило нечто с кучей дополнительных слов, которых не было ни в Си, ни в Паскале 40 лет назад: borrow, as_ref, and_then, upgrade, map, downgrade, Some, clone, borrow_mut. Это все реально нужно или они там совсем озверели?

Теги:
+9
Комментарии36

StingrayTV Alice получил свою первую бета-версию.

Теперь интеграция ресивера Триколора и Алисы стало реальностью.

Демо-видео 1
Демо-видео 2
Демо-видео 3

Теги:
0
Комментарии0

StingrayTV Alice стал ещё лучше - теперь оно уже почти production-ready, с кучей фиксов и улучшений.

В частности:

  1. Пофиксил пару специфичных моментов, связанные с получением информации о текущем телеканале (они идут как SSE, поэтому пришлось воспользоваться WebClient для работы с SSE-запросами) - это позволило наконец-то избавиться от торможения запросов к ресиверу, что в свою очередь позволило наконец-то довести приложение до полностью работоспособного состояния.

  2. Теперь StingrayTV Alice использует bridge-сеть Docker'а, а для работы с mDNS теперь используется ретранслятор, соединяющий контейнер и mDNS-сеть вместе через выделенный контейнер. Это позволило окончательно разграничить сетевой стек в контейнерах, и улучшить общую безопасность.

Приложение уже окончательно протестировано на моём ресивере, осталось только совсем чуть-чуть, и скоро выйдет первая бета.

Теги:
+1
Комментарии0

Как автоматизировать Photoshop через кодинг

Когда говорят об автоматизации, чаще всего имеют в виду Python. Но важно понимать: Photoshop не выполняет Python-код напрямую.

Зато у него есть встроенная поддержка скриптов — Photoshop умеет исполнять код на JavaScript (ExtendScript).

Это не «JS как в браузере» и не замена Python. Это родной язык автоматизации Photoshop, с прямым доступом к:

  • слоям

  • тексту

  • смарт-объектам

  • экспорту файлов

  • истории документа

Если задача — управлять самим Photoshop, то скрипты внутри Photoshop — самый надёжный путь.

Что это даёт на практике

Через код можно:

  • массово менять текст в PSD

  • генерировать сотни изображений из одного шаблона

  • автоматизировать экспорт

  • исключить Actions и Variables с их ограничениями

По сути, мы описываем действия, которые дизайнер делает руками, но в виде кода.

Пример задачи

Есть:

  • один PSD

  • текстовый слой

  • значения 1 м → 100 м

Нужно:

  • автоматически подставить значения

  • сохранить 100 PNG-файлов

  • вернуть PSD в исходное состояние

Пример скрипта для Photoshop (JSX)

#target photoshop

var doc = app.activeDocument;
var layerName = "1 м"; // имя текстового слоя
var outputFolder = Folder.selectDialog("Выбери папку для сохранения");

if (!outputFolder) {
    alert("Папка не выбрана");
    exit();
}

function findTextLayer(layerSet) {
    for (var i = 0; i < layerSet.layers.length; i++) {
        var layer = layerSet.layers[i];
        if (layer.kind == LayerKind.TEXT && layer.name == layerName) {
            return layer;
        }
        if (layer.typename == "LayerSet") {
            var found = findTextLayer(layer);
            if (found) return found;
        }
    }
    return null;
}

var textLayer = findTextLayer(doc);
if (!textLayer) {
    alert("Текстовый слой не найден");
    exit();
}

for (var i = 1; i <= 100; i++) {
    textLayer.textItem.contents = i + " м";

    var file = new File(outputFolder + "/pkabel_4x2_5_" + i + "m.png");

    var opts = new PNGSaveOptions();
    opts.compression = 9;

    doc.saveAs(file, opts, true, Extension.LOWERCASE);
}

// откат без сохранения
doc.activeHistoryState = doc.historyStates[0];

alert("Готово!");
Теги:
+4
Комментарии0

Звёзды разработки и практикующие инженеры разбирают горячие темы — от FAIL до GOD. Встречайте tech-шоу «АйТир Лист» от МойОфис.

В нашем шоу мы берём одну область в разработке, выбираем самые обсуждаемые технологии, практики и подходы — и раскладываем их по шкале от FAIL до GOD.
Формат простой: эксперты защищают свои позиции, спорят, соглашаются и не соглашаются. 14 табличек, 14 поводов для споров и честный экспертный рейтинг без попытки всем понравиться.

Первый выпуск — опенсорс для фронтенда

Дебютный эпизод мы посвятили популярным опенсорс-решениям для фронтенда: от инструментов, которые давно пора отпускать, до стандартов индустрии.

В выпуске:

  • Александр Коротаев — эксперт по фронтенду и креативному кодингу

  • Алексей Золотых — тимлид команды веб-редакторов МойОфис

  • Ведущий — Эдгар Акопян

Обсуждаем инструменты, которые формируют повседневную фронтенд-разработку, и честно отвечаем на вопрос: что сегодня выглядит как GOD-tier, а что застряло на уровне MVP или FAIL.

Смотрите выпуск: YouTube | RuTube | VK

Второй выпуск — фичи и идиомы C++

Во втором эпизоде «АйТир Листа» — уже не инструменты, а язык.
Мы устроили полноценную битву мнений вокруг фич и идиом C++: 14 табличек превращаются в 14 поводов для дебатов, где каждая возможность языка проходит через экспертную оценку.

В выпуске:

  • Данил Черепанов — архитектор редакторов МойОфис

  • Антон Полухин — эксперт-разработчик C++ техплатформы городских сервисов Яндекс

  • Ведущий — Эдгар Акопян

Получилось много споров, неожиданных аргументов и ситуаций, где «привычно» не значит «хорошо».

Смотрите и делитесь мнением: YouTube | RuTube | VK

В следующих выпусках продолжим разбирать технологии без скидок на хайп и «так исторически сложилось». Предлагайте темы, а если готовы к жарким спорам – становитесь участниками нашего шоу) А как стать? Пишите в комменты с какой темой бы хотели поспорить!


Теги:
+12
Комментарии0

Мне навеяло темой: "Что должно быть на каждой PCB с микроконтроллером":

В чем счастье эмбеддед программиста.

Больше 20 лет назад мы с товарищем, специалистом по схемотехнике — цифровой, аналоговой, любой, и конструкции плат, должны были прикрутить маленький экранчик (10х10 сантиметров примерно) для визуализации ввода к нашему секретному девайсу. И все было как обычно, он принес(прислал) мне описание контроллера экрана, я проверил схему подключения к атмеге (какая-то 8-ми битная микруха АТ серии там была), которую он нарисовал, на предмет программной управляемости (необходимости, достаточности и удобства конструкции). Он развел, вытравил, спаял, скрутил, собрал, проверил цепи,... я всего не знаю что там надо делать, я преклоняюсь перед талантом людей, которые все это знают и грамотно делают, иначе мне бы было не на чем работать! И в один прекрасный день мы собрались вдвоем (для меня это была как бы халтурка) чтобы включить, запрограммировать и окончательно проверить что схема и все необходимые функции программного управления работают и можно снять характеристики, все проверить для того чтобы написать уже пользовательскую программу. Я сначала всегда пишу программу, которая проверяет возможности железа: схемотехнику обвязки и возможности аппаратных модулей встроенных в контроллер-процессор, тайминги, какие-то взаимные ограничения на использование ног, периферийных юнитов, кросстайминги, просто свое понимание работы периферии полученное из теоретического описания. Все требует проверки на практике, на работающей железке с работающей программой.

Я скомпилировал подготовленную программу, основной целью которой было вывести несколько символов на экран, чтобы подтвердить что я все правильно понял и ничего не напутал по описанию контроллера экрана, по протоколу управления, мы ничего не напутали по схемотехнике, последовательный порт SPI по которому управляется экран правильно проинициализирован и правильно используется в микроконтроллере.

Мы подключили программатор и загрузили прошивку! Ожидая что на экране что-то появится. Дисплей имел и графический режим управления, в котором можно было зажигать любые пиксели по координатам, но нас вполне устраивал символьный режим с курсором, в котором у нас было где-то 8 строк по 10 символов. И, как это обычно бывает, ничего не произошло, экран остался безжизненным. Первым делом надо проверить что прошивка работает - поморгать светодиодом, если нет светодиодов просто посмотреть запрограммированный сигнал на каком то выводе процессора осциллографом - все было в порядке, все сигналы на месте. Я начал строить предположения о том, что я мог неправильно понять и, соответственно неправильно настроить-сконфигурировать-передать-принять-перепутать порядок посылок при инициализации дисплея. На это ушел может быть час или два - я дотошно перебирал варианты, вплоть до самых невероятных - ничего не помогало, экран оставался мертвым. Я рассказал напарнику, что называется на пальцах, последовательность операций, которые выполняет моя прошивка. Что-то мы дополнительно проконтролировали по тестовым пинам, нигде логика не была нарушена, все сомнительные варианты мы перепроверили под контролем напарника. Экран оставался мертвым...

И тут, как-то невзначай, мой товарищ, как будто из глубины своего сознания, начал доставать воспоминание, он говорит: "Слушай-ка там в доках схема регулировки яркости была нарисована... я где-то тут прикрутил регулировку, может надо ее покрутить?" И он начинает крутить какой-то неприметный металлический штырек и на экране чудесным образом начинают проявляться символы!

Сложно передать мои эмоции когда я сказал ему: "Какой же ты... молодец, что догадался прикрутить эту регулировку яркости! Без нее бы у нас так ничего и не получилось, сегодня, с этим экраном!". Прошло столько лет, а я не могу забыть эту историю.

Всем удачи в Новом Году. Пусть у вас всегда будут в наличии необходимые регулировки, особенно аналоговые.

Теги:
+9
Комментарии3

Вышла новая версия fq 0.16.0

fq - это инструмент, язык и декодер для работы с двоичными данными. Конечная цель проекта — объединить в одном инструменте функции jq, hexdump, dd и gdb.

Поддерживаем массу форматов, полный список: https://github.com/wader/fq/blob/master/doc/formats.md

Написан на Golang.

Демонстрация работы
Демонстрация работы

GitHub: https://github.com/wader/fq

ChangeLog: https://github.com/wader/fq/releases/tag/v0.16.0

Теги:
+2
Комментарии0

Философия IT-собеседований: взгляд разработчика и DevOps-инженера

Привет, Хабр! Мой пост носит дискуссионный характер. В веб-разработке, администрировании и DevOps я уже 17 лет. Долгое время работал «на себя», оказывая помощь клиентам, с которыми выстроены надёжные взаимоотношения, но текущие реалии рынка подтолкнули к поиску работы по ТК, об этом я и хочу поговорить.

Обо мне: 40 лет, из которых 17 лет в коммерческой разработке. Прошел долгий путь как в fullstack-разработке (web), так и в создании embedded-решений (каршеринг), администрировании и DevOps.

Раньше мой процесс найма редко выходил за рамки одного интервью. Сейчас же я регулярно сталкиваюсь с многоступенчатыми отказами, иногда даже на этапе HR-скрининга. Этот контраст заставил меня задуматься: что делает найм эффективным, а что превращает его в фарс? Решил систематизировать свои наблюдения и поделиться тем, что в современных собеседованиях кажется здравым, а что — откровенно лишним.

Описываю позитивные практики, с которыми сталкивался, практики за которые я уважаю потенциальных работодателей и команды. Это парадигма, в которой я вёл деятельность с начала карьеры.

  1. Диалог на равных.
    Мое лучшее интервью: техлид не мучил теорией, а предложил обсудить реальную дилемму, которую он решает в данный момент (внедрение NoSQL-хранилища ради одного специфичного сервиса, т.е. доп. точка отказа vs производительность). Без таймера и стресса мы искали решение. Итог — оффер и годы отличной работы.

  2. Проверка логики, а не памяти.
    Люблю кейсы в духе: «Вот дано А, почему происходит Б?». Из банального: может ли Вася из другого города достучаться до вашего локального IP? Это показывает понимание базы лучше любого теста.

  3. Ценность универсальных знаний.
    Универсальные знания долгое время позволяли быстро находить решение практически любой проблемы от хардверной, до нарушения самых элементарных паттернов проектирования в коде и эффективно их устранять. Мне нравятся задачи, где проблема может быть скрыта на любом уровне и нравятся клиенты, понимающие, как я могу снять их головную боль обеспечив работоспособность ПО в любой среде и условиях.

А теперь я хочу описать то, от чего меня бомбит. Это факторы которые будут отпугивать меня вплоть до момента, когда будет нечего кушать и я буду вынужден прогнуться под выгодное предложение.

  1. Лайвкодинг.
    В 40 лет написание кода для меня — процесс интимный... хотя я практикую парное программирование в реальной команде и это мне нравится, но в предвкушении собеседований иногда хочется "психануть" и на предложение выбрать время для лайвокдинга сказать — "предлагаю парное программирование с одним из ваших специалистов, ведь для меня тоже важно, с кем я буду вести разработку". (Не пробовал так отвечать, но попробую, как только выдастся случай).

  2. Вакансии-обманки.
    Зачем заманивать стеком DevOps (Linux, Nginx, Ansible, Terraform, Puppet, Docker, Kubernetes, MySQL, PostgreSQL, Elasticsearch, Logstash, Kibana, Zabbix), если по факту сообщаете, что ничего этого не будет, а ищите классического сисадмина 9-18? — Давайте адкеватный запрос, а не тратьте время.

  3. Терминологическая каша. Сложно отвечать экспертно, когда интервьюер путает CI и OCI или Redis и Rabbit. Если нет погружения в контекст, конструктивного диалога не выйдет. Готовиться к собеседованию должен не только соискатель, но и тот, кто нанимает.

  4. Отсутствие пунктуальности.
    Для меня было шоком, что фаундер может просто не явиться на собседование, или рекретер забывает о диалоге и назначенной встрече. У вас там всё нормально?) Хотя рекрутер мало чем отличается от агента недвижимости, но фаундер забывающий про собеседование для меня персонаж странный.

  5. Узкая специализация.
    Раньше, как мне кажется, ценилась универсальность, способность разработчика понимать инфраструктуру, а инженера/админа — код. Сегодня индустрия уходит в жесткую сегментацию, видимо, для более точного просчёта рисков. А я считаю, что именно универсальность — это страховка проекта от того, что решение будет принято в вакууме одного стека, без учета общей картины.

Теги:
+7
Комментарии2

Нагрузочное тестирование YMatrix

В партнерском материале расширяются результаты нагрузочного тестирования из статьи «Нагрузочное тестирование GP6 vs GP7 vs Cloudberry» и презентуются результаты тестирования YMatrix. Это дополнение к предыдущей статье, призванное сформировать понимание сравнимости результатов различных форков GreenPlum.

Теги:
0
Комментарии0

Если вы занимаетесь разработкой, не пропустите

У нас недавно выходили подборки полезных образовательных материалов для тех, кто хочет расти в ИТ. Заглядывайте:

Теги:
+1
Комментарии0

Приглашаем на бесплатный вебинар «За кулисами Java: Секреты памяти, которые разгонят ваше приложение».

🕓 Когда: 25 декабря, 16:00–17:00 (Мск)

👨‍🎓 Спикер: Прощаев Сергей — эксперт в области Java.

Содержание:

✔️ Архитектура памяти в JVM: тонкости работы стека и кучи (Java 8+).

✔️ Фундаментальные проблемы параллелизма: видимость, упорядоченность, атомарность.

✔️ Сравнительный анализ инструментов синхронизации: synchronized, volatile, атомарные классы из java.util.concurrent.atomic.

✔️ Практические рекомендации по выбору инструментов для оптимальной производительности и надёжности.

Вы узнаете:

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

➕ Как избегать распространённых ошибок, связанных с управлением памятью.

➕ Какие best practices применяют в отраслях с жёсткими требованиями к отказоустойчивости.

Для участия желательны базовые знания Java на уровне Middle и понимание основ многопоточности.

👉 Записаться

Теги:
0
Комментарии0

Успевайте поучаствовать в CodeRunWinterChallenge до 25 декабря!

Вечная зима… Лорд Нуль погрузил мир CodeRun в лёд. Только Кодерун с вашей помощью может бросить злодею вызов, покорить Пик Кода, остановить Ледниковый период и вернуть тепло... Впереди — 21 день восхождения…

Решайте задачи каждый день, помогайте Кодеруну и боритесь за призы:

  • Топ-20 получат умные колонки Яндекс Станция Лайт 2.

  • Топ-100 получат сертификаты, карьерные консультации и приоритет при отборе в Яндекс.

→ Подробности на странице челленджа

Теги:
0
Комментарии0

Выкладываем все карты на стол

Запустили IT Poker с K2 Cloud. Шоу, в котором сильнейшие девелоперы и техлиды показывают, на что способен их скиллсет.

Собрали 12 айтишников из ведущих компаний за столом для покера, но вместо обычной колоды приготовили технологии, сервисы и архитектурные решения. Представьте: в одной руке у игрока — API Gateway, в другой — брокер сообщений, а на флоп внезапно ложится Load Balancer.

Кто дойдёт до конца и сорвёт банк? Справятся ли инженеры без ИИ и техдоков?

Смотреть первые выпуски и болеть за своих уже можно в VK Видео и на YouTube.

Теги:
0
Комментарии0

Ближайшие события

Как написать свой линтер на Go?

Бэкенд-инженер AvitoTech Вячеслав Овчинников на стриме Go live-Coding разобрал механику линтеров и то, как работать с AST Go-проектов. Слава показал, что создание собственного правила — это не магия, а понятный и довольно увлекательный процесс. На стриме он:

  • написал простой, но полноценный линтер;

  • показал, как парсить AST и анализировать типы;

  • добавил своё правило и нашел проблемные конструкции в коде;

  • подключил линтер к golangci-lint.

Специально для вас мы сделали запись стрима, рекомендуем к просмотру всем, кому интересна тема линтеров на Go.

Запись стрима также есть на YouTube.

В ноябре Александр Кувакин, backend-инженер в команде Engineering Excellence AvitoTech, рассказывал в статье на Хабре о том, как backend-разработчикам выстраивать систему тестов на бэкенде. В тексте Саша разобрал основные проблемы и тесты, которые проверяют бизнес-логику. Почитать можно вот по этой ссылке.

А вот здесь вы найдете еще больше материалов по Go — статьи, видео, подкасты.

Теги:
+27
Комментарии0

Где учиться DevOps?

На Хабр Карьере мы собрали все полезные курсы в одном месте, чтобы вам не пришлось тратить свое время на поиски и сравнения.

А сегодня — подборка по одному из самых востребованных направлений в IT. Если хотите разобраться в DevOps с нуля или системно прокачать навыки — поглядите курсы по основным инструментам:

Kubernetes. Оркестрация контейнеров, масштабирование сервисов и управление сложной инфраструктурой.

Docker. Упаковка приложений в контейнеры для удобного запуска и переноса между средами.

CI/CD. Автоматизация сборки, тестирования и доставки кода в продакшн.

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

Linux. Основа серверной среды и ключевой навык для работы с инфраструктурой.

→ А еще у нас есть курсы на любой вкус и кошелек — посмотрите

Теги:
+1
Комментарии0

Метод registerListeners() в CMSPlugin в плагинах планируется удалить в Joomla 7.0.

Этот метод регистрирует устаревшие слушатели событий в диспетчере, имитируя работу плагинов Joomla! 3.x и ниже для Joomla 4+. По умолчанию этот метод ищет все общедоступные методы, название которых начинается с on. Он регистрирует лямбда-функции (замыкания), которые пытаются преобразовать аргументы отправленного события в аргументы вызова метода и вызвать ваш метод on<Нечто>. Результат передаётся обратно событию в его аргумент result.

Теперь этот слой совместимости с устаревшей Joomla 3 помечен к удалению в Joomla 7.0, которая должна выйти осенью 2027 года. Это означает, что те уникальные расширения от Joomla 2.5 / Joomla 3, которые ещё работали на Joomla 4-6 скорее всего окончательно перестанут работать на Joomla 7. Предполагается, что активные разработчики планомерно и постепенно избавляются от технического долга и обновляют свои расширения 😎

Чат русскоязычного Joomla-сообщества.

Теги:
+1
Комментарии0

Усыпальница Java

Java обычно воспринимают как "тихую гавань" стабильности и обратной совместимости. Но на самом деле внутри неё постоянно кипит жизнь: язык и платформа меняются, обрастают новыми API и возможностями, а старые решения постепенно отправляются на покой в виртуальную усыпальницу.

В новой статье мы разберёмся, чем именно наполняется эта усыпальница и почему. Поговорим о legacy-коллекциях Java, финализаторах, Nashorn, SecurityManager и легендарном Unsafe. Какие задачи они решали? Какие архитектурные и эксплуатационные проблемы породили? И, конечно, разберём, какие современные альтернативы пришли им на смену.

Теги:
+2
Комментарии4

Где учить английский язык?

Знание иностранного языка здорово расширяет горизонты — как на работе, так и в обычной жизни Этот навык открывает доступ к знаниям со всего мира, позволяет читать профессиональную литературу на языке оригинала и напрямую общаться с людьми со всего света.

Мы понимаем, что цели у всех разные: одни хотят прокачать разговорную речь, другие — освоить профессиональную лексику. Подумали и собрали подборку курсов по самым разным направлениям в изучении языка. Ловите:

Разговорный английский. Говорим уверенно без языкового барьера.

Письменный английский. Письма, сообщения, документы и четкие формулировки.

Английский с носителем языка. Практикуем свободную речь и произношение.

Деловой английский. Для встреч, переговоров, презентаций и рабочей переписки.

Английский для IT. Профильная лексика и упор на деловое общение.

→ На Хабр Карьере есть курсы под разные цели и уровни — заглядывайте к нам на витрину.

Теги:
+1
Комментарии0

Баги на всех языках мира. Проверка LanguageTool

Всем привет! Hello, everyone! Hallo zusammen! Hola a tothom! مرحباً بالجميع!

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

В новой статье заглянем в её код и посмотрим на интересные вещи, которые нашёл в нём статический анализатор кода PVS-Studio: от утечек ресурсов и логических противоречий в условиях до дублирующихся ключей в хеш-таблицах, избыточных проверок и мёртвого кода.

Теги:
+4
Комментарии0

vibe-learning как изучать алгоритмы, тренироваться на leetcode и вообще.

Сейчас, если есть желание разобраться, LLM вполне может заменить ментора, в том числе в тренировке решения задач на leetcode и других подобных сайтах. Я реально счастлив, что можно бесконечно мучить LLM, задавать разной тупости вопросы, просить объяснить — для самообразования почти идеально. Но, конечно же есть «но» — за вас оно думать не будет, цель — понять и запомнить, сформировать нужное мышление. Для запоминания, в случае с leetcode‑like задачами, можно применить активное вспоминание(1, 2) — это не когда повторяешь бездумно читая тоже самое или заучиваешь как стих, а при повторении пытаешься вспоминать + разбор задачи без кода. Алгоритм примерно такой:

  1. Сложная задача? Копируем условие в LLM и просим объяснить условие без кода.

  2. Если всё ещё не понятно — просим объяснить алгоритм словами, без кода.

  3. Если всё ещё не понятно — просим дать подсказку.

  4. ... — просим показать упрощённое решение.

  5. ... — просим показать полное эффективное по временной сложности решение.

  6. Смотрим, разбираем алгоритм по шагам, смотрим в дебагере в IDE, etc.

  7. Когда стало понятно — закрываем окно чата с LLM, уходим налить себе чай и повторяем решение уже в окне leetcode без подсказок.

Это лучше делать с однотипными задачами — решить несколько подряд для закрепления. Задачи можно искать по топикам, например Метод скользящего окна и другие, постепенно LLM станет не нужна.

На истину и гениальность не претендую, просто делюсь личным опытом.

Думаю, подобная «техника» применима к изучение любых вещей, главное — обратная связь, возможность самопроверки. Как это сделать, например, при чтении книг? Книги обычно разделены по темам и есть вопросы для самопроверки — это можно загрузить в LLM и попросить провести тестирование по этой теме или найти готовые онлайн тесты. Думаю и сам процесс этой возни тоже может быть полезен.

А вы как изучаете алгоритмы и другие сложные темы?

Теги:
+3
Комментарии1
1
23 ...