ChooChooLoco

ChooChooLoco

Дятл dimio.org Техноблевничок: https://t.me/+kSNYhy8GR5VhMDFi
На Пикабу
2392 рейтинг 15 подписчиков 19 подписок 68 постов 7 в горячем
Награды:
Пикабу 16 лет! За киноманство За киберзащиту За участие в Пикабу-Оскаре
4

Пейте, дети, молоко! Пользуйтесь стандартной библиотекой И будьте бдительны!

Забавную ситуацию вспомнил: как-то на ревью коллега стал меня убеждать в необходимости своих правок. Обосновывал тем, что "из теста вернули с комментарием — очень долго работает запрос, не можем дождаться ответа и обрубаем". Поэтому он решил изменить способ итерации, чтобы всё ускорилось 🚀

Краткая суть: был метод, возвращавший некие данные за период (12 месяцев с отмоткой назад, endDate = 12 месяцев назад, нижняя граница). Внутри себя - он итерировался по этим месяцам, дергал другой метод для получения помесячных наборов, и агрегировал их. Конструкция была такая:

LocalDate startDate = LocalDate.of(2022, 11, 1);

LocalDate endDate = startDate.minusMonths(12);

for (LocalDate date = endDate; date.isBefore(startDate); date = date.minusMonths(1))

Подобный метод-агрегатор был не один, и на ревью первого из них я коллеге посоветовал генерировать набор дат вызовом библиотечного АПИ datesUntil с шагом в месяц, и дальше сгенерированный набор использовать. Это дело благополучно забылось, даты продолжали создаваться внутри for и кочевали с копипастой, дожив до обсуждаемого момента 🤷🏻‍♂️

Я сильно засомневался, что в совершенно ненагруженном вызове, при итерации по 12 элементам — иной способ итерации даст какую-то заметную разницу. Сделал иллюстративные наброски в JShell (полноценные бенчмарки лень было, да и ни к чему) для сравнения разных способов с исходным. Типа таких:

Пейте, дети, молоко! Пользуйтесь стандартной библиотекой  И будьте бдительны!

(копипастабельный текст тут)

Внимательный читатель уже видит суть проблемы. 🕵🏻‍♂️ Самый внимательный - уверен, увидел уже на третьем абзаце!

Результаты, ожидаемо, отличались крайне незначительно:

Dates list for - i => 692

Dates in-place generated for each => 704

Dates list for - each => 708

Dates array for - i => 708

Dates list forEach => 712

Dates list while + iterator => 1060

Разумного объяснения не было 🤯 Стали закрадываться мысли - а не хлопнуть ли нам взяться ли нам за JMeter, профайлер, снять граф... Углубиться, так сказать, до дна.

Не пришлось - взглянул повнимательней и заметил разницу: date = date.minusMonths(1) vs date.plusMonths(1). Вот оно! 🥳 Банальный бесконечный цикл с отмоткой назад от нижней границы периода.

Будь я бдительней - раньше бы заметил, что при копипасте цикла между методами - поменялось назначение границ периода, а итерация осталась старой. В одном методе работало ожидаемо, в другом - 💥.

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

Молоко, говорят - просто полезно для здоровья. Его даже за вредность дают. Но не всем 🐱

Показать полностью 1
4

Midjourney без Дискорда (почти)

Продолжая развлекаться с нейросетями - поставил АПИшку к Midjourney (https://github.com/novicezk/midjourney-proxy).

Важно: это только АПИ, смысл её - в переадресации запросов к дискорд-боту Midjourney, адаптер, короче. Тестовый период и/или подписка - завязаны на дискорд-аккаунт. И похоже, что триала сейчас нет, или он крайне ограничен.

Ещё минусы:

  • Вся документация, примеры, встроенный "свагер" - на чистейшем... китайском? Иероглифами, короче.

  • Токен надо доставать через браузер, предварительно залогинившись в Дискорд.

Плюсы: она работает 🫡 И это удобней, чем листать ответы бота в дискорде, продираясь через тысячи сообщений.

Ставить как обычно - склонировать/скачать с гитхаба. Сделал docker-compose для удобства, собрать/обновить контейнер можно аналогично сборке freeGPT (docker-compose build).

Текстом можно скопипастить тут.

Где взять настройки

Токен (user-token): зайти на сервер Midjourney в Дискорде, в браузере в консоли разработчика (F12) - вкладка Сеть/Network. В заголовках запроса будет Authorization.

guild-id: Номер сервера (из адресной строки - первый набор цифр)

channel-id: Номер канала (из адресной строки - второй набор цифр)

Если регистрируется свежий аккаунт - предварительно через Дискорд нужно принять ToS Midjourney:

Время учить иероглифы?

Посмотреть свагер и подёргать запросы можно тут: localhost:1339/mj/doc.html#/home

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

Запрос генерации

Посмотреть очередь генерации

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

Показать полностью 4
11

Git хук для запуска тестов

Есть у меня такой pre-push хук - автоматом прогоняет тесты локально, через maven. Подключается по необходимости через отдельные git конфиги для проектов.

Git хук для запуска тестов

Стащил его, судя по всему, отсюда: https://gist.github.com/arnobroekhof/9454645. Потом допиливал немного – чтобы он с многомодульными проектами работал корректно. Может, ещё что-то по мелочи причёсывал.

И он отлично работает (разве что можно через sed попробовать результаты по всем модулям агрегировать).

Но вот проблема – на текущем проекте везде gradle, а под него я что-то не могу найти похожего простого решения

Есть ли оно?

Показать полностью
397

Легко связать контейнеры Docker в одну сеть

Очень легко и удобно оказалось в Докере (compose) связывать сети. Раньше сервисы обычно пихал в один compose-файл (или, точнее, лень было разделять специально – как шли “из коробки” – так и запускались).

Но стало неудобно. Совсем неудобно стало, что каждый норовит себе отдельную БД поднять соседним контейнером. И всё равно приходится лезть, и монтирование данных для БД на хостовой ФС прописывать. Ближе к делу:

Первый сервис (у меня – БД), в docker-compose:

Сеть с драйвером bridge по умолчанию создается, но пусть явно будет прописано.

Второй сервис (автоматизация huginn):

И всё. Оба сервиса живут внутри сети postgres_net, друг-друга видят по названиям, по ним же и пингуются. huginn использует pglocal в своём конфиге.

Минус вижу – порядок ожидания нужных служб сделать посложней, чем с depends_on и службами в одном файле.

Или через docker-compose -f service1.yml -f service2.yml up все нужные службы пускать (тогда depends_on сработает). Мне не удобно так.

Или через command и внешние скрипты ожидания приходится. Хорошо, что wait-for-it.sh уже придуман до нас!

Те же, там же.

Показать полностью 3
45

Из России с любовью

Такие вот удачные модельки-конструкторы у нас делают.

Вчера фланировал по центру и забрёл в винный подвальчик, где ими торгуют.

Всяких размеров есть, но мелкие прям хороши:

  • не надо резать, не надо клеить

  • симпатичные

  • собрать можно за час, а не за месяц/два/никогда

  • своё, родное ❤️

Годнота!

скопипячено из телеги

Показать полностью 2
2

Преданье старины глубокой

Оказавшись на задворках Москвы - с меня слетела шляпа довелось сходить в любопытный театр (Этнотеатр) на не менее любопытный спектакль – Комедия о Фроле Скобееве.

Преданье старины глубокой

Фото с etnoteatr.ru

Современная постановка сделана по пьесе конца XIX века, а та, в свою очередь, написана по произведению века XVII (или начала XVIII, тут мнения расходятся).

И вот прямо так интересно оказалось всё это вместе:

  • И факт старинности основы спектакля (русский театр, всё же, в массе известен века с двадцатого, если правильно помню).

  • И подход, который нашёл постановщик к подаче действа – сцена в виде этакой балаганной карусели – здорово добавляет антуража.

  • И костюмы проработаны, и игра цепляет, и “осовремененено” совсем каплю и в меру – “виной” тому, видимо, этнографичность и историчность театра 🙂

Тем более, что у себя, в Питере, я подобного сочетания не обнаружил, да и в принципе постановок по этой пьесе не встретил. Рекомендую!

Традиционно приготовлено из канала :(

Показать полностью
6

Достать “Enum с параметром” по значению параметра в джаве

Частенько встречаются перечисления, дополнительно хранящие некие значения.

Чтобы в дальнейшем можно было, например, при сериализации в json это самое значение подставлять автоматом. Тогда возникает обычно и обратная задача – десериализовать (распарсить) значение обратно в Enum.

Вот мне и надоело копипастить туда-сюда все эти методы (сериализации/десериализации) между классами Enum. Их прям очень много таких оказалось на нынешнем проекте. Решил сделать один раз утилитный метод и в проекте им пользоваться. Благо, время позволило.

В принципе, подобный метод есть в недрах Apache Commons EnumUtils, но он работает только со строковым параметром String enumName, плюс выкидывает стандартное исключение. А обычно надо выкинуть некое кастомное, принятое на проекте. Так и родился свой костылёчек, как оно зачастую и бывает.

Получить класс Enum по значению

Импорты копировать не буду, полагаю, IDE предложит их подставить по выбору, если автоматически не сможет этого сделать. Сам утилитный метод примитивен:

Разве что – в реальных условиях он выбрасывает не IllegalArgumentException, а кастомное исключение.

ValuedEnum – это интерфейс, который реализуют все Enum со значением. Вот он:

Сделан sealed, чтобы при имплементации (методом копипасты с опорой на "так сойдёт") – был дополнительный “маячок”, заставляющий обратить внимание – это именно Enum со значением.

Примеры реализаций и тесты картинками вставлять смысла не вижу - там уже достаточно много и проще скопировать-запустить с сайта или найти в говнотелеге.

Результаты тестов привожу:

Всяческого разумного порицания жду нетерпеливо, неразумного - со смирением :)

Показать полностью 3
32

LibreOffice Calc – трюки работы с таблицей

Накопилось ещё некоторое количество “приёмчиков” работы с Open/Libre Office. Если предыдущая заметка на эту тему была посвящена LO Writer, то на сей раз – “подопытным” выступает пакет Calc (электронные таблицы).

Для затравки – простое, но часто нужное действие – перемещение строк и столбцов таблицы.

Перемещение столбцов / строк

  1. Выделить нужный диапазон при помощи выделения всего столбца/строки (для этого можно щелкнуть ЛКМ на заголовок столбца/строки).

  2. Кликнуть и зажать ЛКМ внутри выделенного диапазона (на самих выделенных ячейках с данными, не на заголовке).

  3. Тащить мышью диапазон, затем при отпускании:

    • Перезапишет тот диапазон ячеек, на который был перетащен

    • При зажатом Alt – поменяет диапазоны ячеек местами

Изменение типа данных ячеек

  1. Выделить нужный диапазон ячеек (или весь столбец/строку целиком по клику на заголовок).

  2. Верхнее меню: Данные -> Текст по столбцам.

  3. ЛКМ на столбец в нижней области открывшегося окошка (для выделения диапазона, в котором требуется преобразование).

  4. Выбрать тип столбца – Ок.

Эту операцию удобно проиллюстрировать примером: есть столбец с датами, которые хранятся, как текст (т.е. тип данных внутри офиса у них – текстовый, такое часто встречается при работе с кривыми выгрузками для Экселя). Использование меню Формат – Формат чисел – Дата не поможет в данном случае, т.к. дата хранится в виде строки '2023-06-16.

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

Автоматическое вычисление промежуточных итогов

Ещё одна отличная функция Calc – можно получить итоговые значения для заданного набора данных (агрегировать). Буквально – в несколько кликов! Что отдельно приятно – функция работает с фильтрами.

  1. Ctrl + * – выделить все данные на листе. Можно выбирать и не весь диапазон, естественно.

  2. Данные -> Промежуточные итоги.

  3. Выбрать столбец, по которому агрегировать.

  4. Выбрать столбец для которого нужно получить агрегат.

  5. Выбрать агрегатную функцию.

  6. Кнопками слева от таблицы (1-2-3 и +/-) можно переключать вид (свернуть-развернуть).

Выводы

Вывод, в общем-то, простой: если поискать, поинтересоваться и немного глубже узнать возможности электронных таблиц Calc – с их помощью можно достаточно широкий круг рутинных задач решить быстро и просто. Пользуйтесь с удовольствием!

Источник (с гифками-примерам).

Показать полностью 2
Отличная работа, все прочитано!