Пост №5: SMS-шлюз, Telegram-бот, нейромодули и мобильная версия
Продолжаю цикл постов о создании системы онлайн-записи для автосервиса. Сегодня расскажу про SMS-уведомления, интеграцию с Telegram, про все нейромодули, которые я использую в программе, и про то, как я адаптировал сайт для телефонов.
SMS-шлюз: как я подключил уведомления по SMS
Когда я начинал проект, я планировал отправлять уведомления только по email и в Telegram. Но потом понял: не все клиенты читают email, а Telegram есть не у всех. SMS — самый надежный канал, потому что он доходит всегда.
Я решил использовать платформу SMS-шлюза. Выбрал "...." — у них есть API и нормальная документация. Подключение заняло пару часов.
Как это работает
У меня уже была функция send_client_email(). Я добавил рядом функцию send_client_sms(). Она проверяет, есть ли у клиента телефон, формирует короткое сообщение с деталями записи и отправляет через API SMS-центра.
В сообщении я указываю название услуги, адрес мастерской, дату, время, стоимость и контактный телефон для вопросов. Все в одном сообщении, чтобы клиенту не приходилось ничего искать.
Триггеры для отправки
SMS отправляются не всегда, а в трех случаях:
1. Подтверждение записи — клиент получает SMS сразу после создания записи. Это дает ему уверенность, что запись действительно создана.
2. Напоминание за день — я добавил планировщик, который раз в день проверяет, у кого запись на завтра, и отправляет SMS-напоминание. Это снизило количество неявок примерно на 30 процентов.
3. Отмена записи — если оператор отменяет запись, клиент получает SMS с уведомлением, чтобы не приехал зря.
Это перекрывает все основные сценарии. Клиент всегда знает, что происходит.
Сколько это стоит
SMS-шлюз берет около 0.5 рубля за сообщение. В месяц я отправляю около 200-300 SMS, это примерно 100-150 рублей. За эти деньги я получаю:
- Минимум пропущенных записей (клиенты не забывают)
- Минимум недовольных клиентов (все знают, что делать)
- Экономию времени менеджера (не нужно обзванивать всех накануне)
Окупается с лихвой.
Telegram-бот для записи
У меня есть отдельный примитивный Telegram-бот, который принимает записи. Это удобно для клиентов, которые не хотят заходить на сайт, а привыкли все делать в мессенджере.
Как он работает
1. Клиент пишет боту команду /start
2. Бот показывает кнопки: "Записаться", "Мои записи", "Контакты"
3. При выборе "Записаться" бот запрашивает мастерскую, услугу, дату и время
4. Проверяет свободные слоты через API системы
5. Подтверждает запись и отправляет уведомление оператору
Бот написан на библиотеке python-telegram-bot. Это очень гибкая библиотека, которая поддерживает и команды, и кнопки, и обработку callback-запросов.
Сейчас через бот приходит около 20 процентов всех записей. Это неплохо, учитывая, что я не рекламирую его специально.
Нейромодули: как я использую DeepSeek в программе
DeepSeek используется в нескольких местах системы. Я не просто вызываю API один раз — у меня есть четыре отдельных нейромодуля, каждый со своей задачей.
1. Модуль анализа отзывов (review_analyzer.py)
Самый первый модуль, который я написал. Он принимает на вход список отзывов о конкретном сервисе (до 500 штук) и возвращает структурированное резюме: 5 самых частых жалоб, 5 самых частых похвал, средний рейтинг, основные услуги, которые упоминаются. Это помогает быстро понять, что у конкурента хорошо, а что плохо, не читая сотни отзывов вручную.
2. Модуль нормализации цен (price_normalizer.py)
Этот модуль решает проблему неструктурированных цен. На входе — текст из объявления на Авито или с сайта конкурента, например "замена масла от 2500 рублей" или "комплексная диагностика 3000-5000 руб". На выходе — нормализованная цена в рублях (одно число). Модуль использует DeepSeek для понимания контекста: если написано "от 2500", нейросеть понимает, что это минимальная цена, и возвращает 2500. Если указан диапазон, возвращает среднее. Это решило проблему, которую я не мог решить регулярными выражениями.
3. Модуль классификации услуг (service_classifier.py)
Самый сложный модуль. На входе — список услуг, которые предлагает конкурент (из объявлений, сайта, отзывов). На выходе — нормализованный список услуг из моей базы. Например, если у конкурента написано "замена масла в двигателе", модуль понимает, что это услуга "замена масла". Если написано "профилактика тормозной системы", это может быть "замена колодок", "замена тормозной жидкости" или "ремонт тормозной системы" — нейросеть определяет наиболее вероятный вариант. Без этого модуля я бы не смог сопоставлять услуги разных сервисов, потому что каждый пишет их по-разному.
4. Модуль валидации рыночных расчетов (market_validator.py)
Этот модуль используется для проверки расчетов долей рынка. Я загружаю в него список сервисов с их параметрами (количество отзывов, рейтинг, услуги, цены) и прошу проверить, насколько логично распределение. Нейросеть указывает на аномалии: например, если у сервиса мало отзывов, но высокая доля рынка, или если цена сильно отличается от среднего по рынку. Это помогает выявлять ошибки в алгоритме и корректировать коэффициенты.
Все модули работают через единый API-интерфейс DeepSeek, но с разными промптами. Я вынес их в отдельные файлы, чтобы можно было обновлять или заменять каждый независимо.
Мобильная версия: адаптивность с первого дня
Еще на этапе проектирования я решил, что сайт будет адаптивным. Сейчас 60 процентов клиентов заходят с телефона, и если сайт неудобный на мобилке — они уйдут.
Я использовал Bootstrap 5 с его grid-системой и готовыми компонентами. Все блоки корректно перестраиваются на мобильных экранах, кнопки увеличены для пальцев, шрифты читабельные.
Что я сделал специально для мобильной версии
1. Датапикер с Flatpickr. На мобильных устройствах системный календарь часто работает некорректно. Я использовал Flatpickr — легкий плагин для выбора даты, который работает и на десктопе, и на телефонах.
2. Опрос при неактивности. Если клиент начал запись, но не завершил (например, закрыл вкладку), через 60 секунд появляется опрос "Почему вы не записались?". Это помогло собрать много полезной обратной связи.
3. Сохранение данных в sessionStorage. Если клиент прервал запись, его данные (номер телефона, выбранная услуга) сохраняются в браузере. При повторном заходе он может продолжить с того же места, а не заполнять все заново.
Это особенно актуально для мобильных пользователей, которые часто переключаются между приложениями и могут случайно закрыть вкладку.
Итог
SMS-уведомления, Telegram-бот и мобильная версия сделали систему максимально доступной для клиентов. Нейромодули сделали анализ данных полностью автоматическим и значительно более точным, чем ручная обработка. Все вместе это увеличило конверсию примерно на 20 процентов.
В следующем посте расскажу про систему лояльности и как я удерживаю клиентов без классических кешбэков. Если есть вопросы — пишите в комментарии.
Рассказ инженера Big Data
Мы решили ускорить NameNode.
Сначала увеличили количество потоков.
Сервер посмотрел на нас и сказал: “Спасибо, теперь мне плохо быстрее”.
Потому что очередь — это не когда мало людей у окошка.
Очередь — это когда окошко одно, а люди уже начали жить в очереди.
И вот стоит запрос getFileInfo.
Он ничего не хочет.
Он просто спросить.
Но таких “просто спросить” — девять тысяч.
И каждый с выражением лица: “я на секундочку”.
А система в этот момент думает:
“Если все на секундочку, почему у меня уже среда?”
И тут приходит администратор.
Не человек — профессия.
У него в глазах не усталость.
У него в глазах jstack.
Он говорит:
“Сейчас мы посмотрим, кто держит lock”.
Это очень сильная фраза.
В обычной жизни так не говорят.
В обычной жизни говорят: “Кто последний?”
А тут: “Кто держит lock?”
И сразу понятно — люди давно не отдыхают.
Сделали jstack -l.
И NameNode завис.
То есть мы хотели узнать, почему он зависает.
И для этого дали ему команду зависнуть окончательно.
Это называется диагностика.
В медицине так нельзя, а в IT — пожалуйста.
Потом решили:
“Больше -l не делать”.
Это тоже важный этап зрелости инженера.
Когда ты не знаешь, что делать, но уже знаешь, чего делать нельзя.
На этом держится половина промышленной эксплуатации.
Потоки стоят.
Очередь RPC растёт.
CallQueueLength смотрит на тебя как очередь в поликлинике в понедельник утром.
Там уже не запросы.
Там судьбы.
Один запрос пришёл открыть файл.
Второй — узнать информацию о файле.
Третий — удалить файл.
Четвёртый — просто посмотреть список.
И каждый считает, что он главный.
open говорит:
“Без меня вообще ничего не начнётся”.
getFileInfo говорит:
“Я маленький, я быстро”.
delete говорит:
“Я сейчас освобожу место”.
А NameNode говорит:
“Вы все говорите одновременно. Я один”.
И где-то рядом DataNode.
У него вообще своя жизнь.
Он пишет:
“Block token verification failed”.
Что это значит?
Это значит: “Я помню блок, но не помню пароль от воспоминаний”.
Блок есть.
Токен есть.
Ключа нет.
Как в жизни: человек есть, пропуск есть, база сказала — не знаю такого.
Потом появляется Hive Metastore.
Это уже не сервис.
Это посредник между болью и базой данных.
Цепочка красивая:
Trino идёт в Metastore.
Metastore идёт в HAProxy.
HAProxy идёт в PgBouncer.
PgBouncer идёт в PostgreSQL.
PostgreSQL смотрит на Patroni.
Patroni смотрит в вечность.
И где-то посередине возникает timeout.
Все говорят:
“Это не у меня”.
Trino говорит:
“Я просто спросил”.
Hive говорит:
“Я передал”.
HAProxy говорит:
“Я балансировал”.
PgBouncer говорит:
“Я пулил”.
PostgreSQL говорит:
“Я вообще живой благодаря Patroni”.
Patroni говорит:
“Я лидер, но не крайний”.
И вот в логе появляется прекрасное:
Connection is not available.
Очень человеческая фраза.
Не “ошибка”.
Не “сбой”.
А именно — “соединение недоступно”.
Как хороший специалист в отпуске.
Он есть.
Он где-то числится.
Но сейчас недоступен.
Тогда мы увеличиваем pool.
Потому что если не хватает соединений, надо дать больше соединений.
Это логично до первой тысячи.
Потом выясняется, что больше соединений — это не решение, а способ быстрее узнать, где следующая проблема.
Сначала не хватало соединений.
Потом не хватает потоков.
Потом не хватает памяти.
Потом не хватает терпения.
Потом не хватает людей, которые помнят, зачем это всё было построено.
А Trino тем временем живёт отдельно.
У него 185 нод.
Потом уже 275.
Два координатора.
Большой кластер.
Очень большой.
Такой большой, что когда запрос не выполняется, это уже не ошибка, а коллективное мероприятие.
И он пишет:
No nodes available to run query.
Вот это особенно красиво.
Двести семьдесят пять нод.
И ни одной свободной.
Как парковка у торгового центра перед Новым годом.
Ты смотришь на кластер и говоришь:
“Но вот же они. Стоят”.
А Trino отвечает:
“Физически — да. Духовно — нет”.
Потом Trino находит утечку памяти.
Он пишет:
“Memory leak detected”.
И перечисляет query id.
Длинные такие, солидные.
Как номера уголовных дел.
Запрос уже завершился.
Но память держит.
Он ушёл, но вещи оставил.
Как родственник после праздников:
“Я только куртку заберу потом”.
И память ждёт.
День ждёт.
Ночь ждёт.
ZGC ходит рядом, тихий, интеллигентный.
Говорит:
“Я бы убрал, но оно формально занято”.
ZGC вообще похож на хорошего уборщика в музее.
Всё видит, всё понимает, но экспонаты трогать нельзя.
Потом начинается Kafka.
Kafka — это когда ты решил, что логов много, но всё равно хочешь их сохранить.
Потому что вдруг пригодятся.
Что именно пригодится — неизвестно.
Но удалять нельзя.
Вдруг потом спросят: “А кто удалил?”
И вот HDFS audit летит в Kafka.
Ranger audit летит в Kafka.
Spark читает Kafka.
Пишет ORC.
Trino читает ORC.
Человек читает Trino.
И в конце человек всё равно делает grep.
Потому что сколько бы мы ни строили платформу данных, настоящий BI начинается с:
cat log | grep ERROR
А потом awk.
awk — это такой маленький Hadoop для одного человека.
Если человек злой и выспался — он заменяет половину enterprise-стека.
Потом Spark Streaming.
Он должен читать поток, парсить, складывать.
Очень просто.
Пока не появляется offset.
Offset — это память о том, где ты остановился.
В жизни этого очень не хватает.
Spark говорит:
“Я помню”.
Kafka говорит:
“А я помню, что ты помнишь”.
YARN говорит:
“Подожди, у меня ресурсов нет”.
И всё стоит, потому что кто-то где-то попросил executor, а YARN отвечает:
“Ваш запрос очень важен для нас. Оставайтесь на линии”.
Executor ждёт.
Driver ждёт.
Kafka ждёт.
Пользователь ждёт.
Только данные не ждут.
Данные приходят.
И это главная особенность Big Data.
Маленькие данные можно отложить.
Большие — нельзя.
Они идут.
Как отопительный сезон.
Как отчётность.
Как родственники на дачу.
Потом мы смотрим Grafana.
Grafana — это когда всё плохо, но красиво.
Линии бегут.
CPU прыгает.
Network падает.
Heatmap светится.
И ты уже не решаешь проблему, а любуешься её динамикой.
Особенно приятно, когда график показывает, что проблема была ночью.
В три часа.
Когда ты спал.
То есть теоретически спал.
Потому что в 03:17 пришло сообщение:
“NameNode опять залип”.
И ты смотришь на телефон.
На мир.
На потолок.
И думаешь:
“Когда я был маленький, я хотел заниматься компьютерами”.
Вот оно.
Занимаешься.
Потом появляется PostgreSQL.
Мы смотрим самые тяжёлые таблицы.
SDS.
DBS.
SEQ_SCAN большой.
Очень обидно, когда таблица называется из трёх букв, а проблем создаёт на весь день.
Делаем ANALYZE.
И сразу вопрос:
“А он не заблокирует?”
Потому что в промышленной базе любая команда звучит как угроза.
Даже ANALYZE.
Хотя по названию вроде культурная вещь.
А всё равно страшно.
Потом индексы.
Индексы — это как полки в гараже.
Пока их нет, всё лежит на полу, но все знают, где что.
Потом ставишь полки — и сначала становится хуже.
Потому что теперь надо понять, на какую полку ты положил то, что раньше просто пинал ногой.
Но без индексов нельзя.
С индексами тоже нельзя просто так.
В этом и состоит архитектура.
А ещё есть HAProxy.
У него параметры.
Много параметров.
maxconn, timeout, backlog, nbthread.
Ты смотришь на них и понимаешь:
люди не настраивают HAProxy.
Люди ведут с ним переговоры.
“Сколько соединений ты выдержишь?”
“Смотря как попросите”.
“А если увеличить?”
“А если я упаду?”
И ты такой:
“Давай аккуратно”.
В Big Data слово “аккуратно” означает:
сначала на одной ноде, потом на всех, потом откат, потом опять на всех, но уже с другим значением.
Потом Ansible.
Ansible — это способ ошибиться сразу на 185 серверах, но с чувством порядка.
Одна команда — и везде одинаково.
Если правильно — праздник.
Если неправильно — тоже везде одинаково.
Красота стандартизации.
Особенно хорош site.retry.
Это файл, где записаны те, кто не смог.
У людей тоже должен быть life.retry.
Список задач, на которых мы отвалились, но потом вернёмся.
А пока возвращаемся к NameNode.
NameNode сидит.
У него 500 гигабайт heap.
ZGC.
Метрики.
JMX.
Очереди.
Потоки.
Handlers.
И всё равно он иногда смотрит в одну точку.
Потому что размер памяти не отменяет смысла происходящего.
Можно дать человеку большой кабинет.
Можно дать ему три секретаря.
Можно дать ему кофемашину.
Но если к нему каждую секунду забегают тысячи людей с вопросом:
“А этот файл есть?”
— рано или поздно он начнёт отвечать глазами.
И вот мы сидим ночью.
Смотрим на логи.
Там Java.
Thrift.
SocketTimeoutException.
Read timed out.
Очень честная ошибка:
“Я читал, читал — и устал”.
И в этот момент приходит мысль:
Big Data — это не про большие данные.
Это про большую ответственность за маленькие настройки.
Один timeout.
Один pool.
Один индекс.
Один handler count.
Одна очередь.
Один jstack -l.
И всё.
У тебя уже не кластер.
У тебя роман.
Роман о человеке, который хотел просто хранить файлы.
Потом просто читать таблицы.
Потом просто ускорить запросы.
Потом просто понять, почему оно висит.
Потом просто дожить до утра.
И самое смешное — утром оно заработает.
Само.
Ты придёшь, а графики ровные.
Очередь ноль.
CPU нормальный.
Metastore отвечает.
Trino выполняет.
Kafka пишет.
Spark читает.
И все скажут:
“Ну вот, видишь, прошло”.
А ты знаешь:
оно не прошло.
Оно просто ждёт следующего релиза.
Ответ на пост «Внезапная Фура Курей»1
Ещё до ФИДО была история про заводы, с численностью работников от нескольких десятков тысяч. Зарплаты им всем рассчитывались тогда на ЕС ЭВМ с точностью до копейки, — ни малейших отклонений, никогда. Всё идеально точно. Суть в том, что -при вычислениях- точность была существенно выше. Были десятые, сотые и даже тысячные доли от одной копейки. Они все -официально- обнулялись (ну как можно заплатить 0,975 копейки?), а на практике — суммировались к зарплате сисадмина. ))
Внезапная Фура Курей1
Сразу отмечу: не моё, попячено в сети.
Есть в Магните огромная логистическая система: десятки крупных складов, тысячи промежуточных, десятки тысяч магазинов самого разного размера и времени работы. И всё это обслуживает огромный автопарк самой разной грузовой техники, для которой есть свои хабы, свои заправки, свои мастерские и вот это всё. Каждый день в каждый из магазинов по всей стране нужно привезти продукты, которых там не хватает, но не больше, чем нужно, и ничего лишнего, в машине определённого размера и с определёнными свойствами.Чтобы как-то этим управлять в недрах Магнита родилась огромная ML-модель на базе бигдаты про все эти нюансы с историей, обогащенная всякими периферийными знаниями вроде погоды, пробок и т.д., и т.п. Система каждый день (ну ладно, не совсем ежедневно, раз в неделю) успешно вычисляла оптимальные маршруты для машин с минимальным перепробегом и доставкой правильных продуктов в нужные места в определённое время с некоторыми корректировками от кожаных. Выглядело это реально впечатляюще.
Но, как водится, были нюансы. Несколько лет кряду разработчики боролись с таким событием, как Внезапная Фура Курей.
Суть в чём. Раз в год, ближе к декабрю, когда логистика предельно усложняется, в каком-то случайном городке за Уралом перед разгрузочной рампой местного магазина появляется ОН: двадцатитонный рефрижератор, полностью гружёный замороженными куриными тушками. Которые по расчётам бигдаты нужно доставить именно сюда.
Как правило, магазин чисто физически не способен принять все 20 тонн, а водитель ехать назад отказывается, потому что у него маршрут на неделю вперёд расписан и там жёсткий тайминг. Поэтому в городке объявляется неделя почти бесплатной курятины, которую нужно срочно реализовать с максимальным дисконтом, а остаток утилизировать.
Баг пытались поймать года 3. Каждый раз отчитывались, что вот теперь-то точно пофикшено. И все равно под Новый год где-то появлялся ОН.
Хочешь большой, но чистой любви?
Какими качествами должны обладать партнёры, чтоб создать долгие и счастливые отношения?
Какие качества человека — настоящий зелёный флаг?
На что обращать внимание, а что можно игнорировать?
К ответам на эти вопросы нас приблизило исследование канадской учёной Саманты Джоэл и её товарищей. Особенность данного исследования в том, что это первая в науке об отношениях работа, собравшая беспрецедентный для этого поля массив данных о парах.
Другая не менее важная деталь: в отличие от большинства работ в психологии, где выводы объясняются задним числом, здесь использовали метод, способный предсказывать, какие критерии человека повлияют на качество отношений, а какие нет
Дисклеймер:
Сильные, независимые, состоявшиеся, гражданки с 4 дипломами и деньгами, ищущие высокого, с зарплатой от 500к в месяц, готового взять ответственность за вас, ваших детей и котов, могут смело не читать. Вам результаты исследования придутся не по душе.
Итак, у учёных было сорок три продольных датасета, восемьдесят шесть исследователей, двадцать девять лабораторий, одиннадцать тысяч сто девяносто шесть пар, двадцать две тысячи сто шестьдесят три участника на baseline, две тысячи четыреста три self-report переменные, несколько сотен шкал удовлетворённости, обязательств, привязанности, конфликтов, депрессии, тревожности, нейротизма и ещё бог знает чего, аккуратно разложенного по codebook'ам.
Не то чтобы всё это было абсолютно необходимо для исследования качества отношений, но, если уж начали собирать данные для обучения модели, становится трудно остановиться.
Особенно когда где-то в папке лежат ещё шесть неопубликованных longitudinal datasets, а random forest уже заведён и тихо гудит в углу.
Собрав всё это, они обучили модель и спросили её:
— Что является ответом на главный вопрос человечества о любви, семье, привязанности, совместимости, стабильности отношений и том, почему одни пары остаются вместе, а другие рассыпаются после покупки икеевского шкафа?
Модель думала семь с половиной миллионов миллисекунд, пережевала сорок три датасета, одиннадцать тысяч сто девяносто шесть пар, две тысячи четыреста три переменные, сотни шкал удовлетворённости, тревожности, нейротизма, обязательств и конфликтов, после чего наконец выдала ответ:
— Зависит.
В лаборатории наступила тишина.
— "Зависит" от чего?
Модель моргнула всеми деревьями random forest'а и сказала:
— От того, насколько хорошо вы задали вопрос.
И так что же все-таки удалось узнать?
Не влияет на шансы на совместное счастье:
внешность, рост, доход, профессия, статус, происхождение,
прошлые браки — и даже то, насколько партнёр похож на вас.
Всё, из чего обычно собирают чек-лист, предсказывает счастье в паре крайне слабо.
А счастье в паре предсказывает совсем другое.
Вы чувствуете, что партнёр вкладывается и ценит вас, а он чувствует то же от вас.
Конфликтов в паре мало. Оба довольны своей жизнью ещё до начала отношений и спокойны в близости, не цепляются от тревоги и не сбегают от неё.
Важен не цвет лексуса, то, как он ухаживает за ним.
Ветеранам диванных войск посвящается
Интернет на заре своего появления был только средством обмена информацией. А когда он стал дешёвым, быстрым и общедоступным, - на первый план вышли совсем другие функции. И на первом месте по важности для "хозяев мира", как думаете, какая?
Средство донесения пропаганды? Ну, в топ-5 наверное входит, но далеко не на первом месте.
Средство мониторинга? Люди ведь сами о себе выкладывают почти всё. Ценнейшие данные. Но и они не на первом месте по значимости.
А на первом месте функция...
Спускать. Пар. Народного. Гнева.
Вот вознегодовал Гена Залупкин из Булкодрищенска по какому-то жизненно важному вопросу, закону или событию. Зашёл в свою любимую соцсеть на выбор, навалил кучу гневных комментариев, получил одобрение от единомышленников, поспорил с оппонентами, и мозг уже подуспокоился. Вот и не нужно никуда идти на баррикады, вот и славненько. Мозг смакует сладость победы, и ему пофиг, что в реальном мире решение проблемы не стало ближе ни на миллиметр.
Именно так это и работает.
Моему дальнему знакомому из Африки во сне однажды приснился загадочный человек в белом, с посохом и длинной бородой. Он сказал ему: "Мой тебе совет - не оставляй цифровых следов своей жизнедеятельности. Нигде и никогда. Риска много - толку ноль. Один поступок важнее тысячи слов. Вот приняли, например, закон, запрещающий охоту на ультрамариновых ебозавриков. А оные расплодились, обнаглели, всюду лезут, жить стало невыносимо, не жизнь, а зоопарк. От них уже явный вред, видный невооружённым глазом.
А закон-то работает, и никто его не отменяет. Что делать? Писать и призывать? Сядешь. Охотиться в открытую? Тоже сядешь.
Выиграть у шулера по его правилам с его колодой невозможно. Выход один - по-тихому брать контрафактные ионные плазмаганы, ехать в глухие дебри, вылавливать по одному и щёлкать ультрамариновых супостатов, а когда они опомнятся, вопрос уже будет решён".
Но я так делать ни в коем случае не буду, и вам не советую. Вот видите, я веду себя законопослушно: залез в соцсеть и написал гневный пост. А дальше пусть оно как-нибудь само.
В конце концов, ну какая только хрень не приснится знакомому из Африки.
Статистика по юзерам
Оказывается, есть прям левый сайт, где кто-то собирает и выкладывает статистику юзеров Пикбу.
Название писать Пикабу не разрешает.
Вбиваешь любой ник и смотришь, какие лучшие и худшие посты, комментарии, их количество и дофига всякого прочего.