Найти тему
Advent of Code 2023: Day 1: Trebuchet?! Снова AoC — и снова начат с опозданием. Дуплет! Основная идея прежняя – решать в jshell, пока это не станет слишком многословным. Экономия на буковках, в общем. Обвязка для загрузки условий задачи – та же, что для AoC-2022. Тег #adventofcode_2023, или страница на сайте. Для первой части загадки получилось достаточно простое и короткое решение, но для второй оно практически никак не подошло. Часть вторая и универсальное решение Совсем бесполезным решение для первой части назвать нельзя – легло в основу универсального. static void day1(String puzzleInputUri) throws IOException, InterruptedException { Map<String, String> digits = Map.of( "1", "one", "2", "two", "3", "three", "4", "four", "5", "five", "6", "six", "7", "seven", "8", "eight", "9", "nine" ); TreeMap<Integer, String> firstLast = new TreeMap<>(); var result = client.send(request.uri((URI.create(puzzleInputUri))).build(), HttpResponse.BodyHandlers.ofLines()).body() .map(string -> { firstLast.clear(); digits.forEach((digit, numeric) -> { firstLast.put(string.indexOf(digit), digit); firstLast.put(string.lastIndexOf(digit), digit); firstLast.put(string.indexOf(numeric), digit); firstLast.put(string.lastIndexOf(numeric), digit); } ); firstLast.remove(-1); // not matched substrings index return firstLast.firstEntry().getValue() + firstLast.lastEntry().getValue(); }) .mapToInt(Integer::parseInt) .sum(); System.out.println(result); } Жаль, что — для экономии буковок — не удалось отыскать где-нибудь в недрах стандартной библиотеки (Locale etc) готовых привязок цифр к числительным. Хотя и ожидаемо. Загадка первого дня была не слишком сложной, но поначалу пошла туговато на фоне повседневного “перекладывания жысонов“. Тем полезней переключаться! Участвуй! #adventofcode #adventofcode_2023 @panykey | Искусство реализации идей
1 год назад
Git хук для запуска тестов Есть у меня такой pre-push хук - автоматом прогоняет тесты локально, через maven. Подключается по необходимости через отдельные git конфиги для проектов. #!/bin/env bash set -eu # https://gist.github.com/arnobroekhof/9454645 # save the file as <git_directory>/.git/hooks/pre-<commit|push> and chmod +x # modified: dimio, 2022-09-21 echo "Running mvn clean test for errors" # retrieving current working directory CWD=$(pwd) # find dir with parent pom.xml (a top-level depth) - run tests for all modules PROJ_DIR="$(git rev-parse --show-toplevel)$(dirname $(find -type f -name 'pom.xml' -printf '%d %p\n' | sort | tr -d '[:digit:]') | tr -d . | head -n 1)" cd "${PROJ_DIR}" MVN_RESULT=$(mvn clean test 2>&1) if [ $? -ne 0 ]; then echo echo "${MVN_RESULT}" | ((tee /dev/fd/5 | grep -A 10 -B 2 "Summary:" > /dev/fd/4) 5>&1 | sed -n -e '/^Failed tests:/,/Tests run:.*$/ p' ) 4>&1 echo echo "Error while testing the code" cd "${CWD}" exit 1 fi cd "${CWD}" Стащил его, судя по всему, отсюда: https://gist.github.com/arnobroekhof/9454645. Потом допиливал немного - чтобы он с многомодульными проектами работал корректно. Может, ещё что-то по мелочи причёсывал. И он отлично работает (разве что можно через sed попробовать результаты по всем модулям агрегировать). Но вот проблема - на текущем проекте везде gradle, а под него я что-то не могу найти похожего простого решения 😕 Есть ли оно? #git #maven #bash dimio.org
1 год назад
Калькулятор здорового человека Привычно запустил хоткеем SpeedCrunch калькулятор и поймал себя на мысли - насколько же он офигенен! Пожалуй, мой идеал калькулятора, не меньше. В сравнении с чем он познавался, чтобы не быть голословным: 👉 Win калькулятор. Он просто есть, на нём можно считать, но зачастую проще на телефоне открыть эмулятор научного. Дальше Win10 я не заглядывал, что там в свежих - без понятия. 👉 Gnome калькулятор - аналогично. Нечего вспомнить про него, а ведь года четыре на Гноме просидел. 👉 Qalculate! - такой мощный комбайн. Стоял на Винде и запускал я его редко - слишком заморочный какой-то, запускался с заметной задержкой (понятно, что из-за неродной ОС). Легче в виндовом и посчитать сразу. Может, стоит его сравнить в параллели с SpeedCrunch 🤔 👉 SpeedCrunch - пока самый оптимум по шкале простота/фичи. Если всё поотключать - будет такой "Win калькулятор с удобствами". Повключать - уже похоже на Qalculate. Можно выбрать серединку 💯 Что он умеет - на картинке видно в целом. Простые пользовательские функции довольно удобны. Прям топ - автосохранение результата вычисления в ans и автоподстановка оттуда - обратно в строку ввода. Импорт/экспорт сеансов, скины, форы представления результатов - это всё есть. Разделитель десятичный можно поставить - одновременно и точку, и запятую 🔥 Не помню, где я про него вычитал, года полтора уже пользуюсь. Доволен, что это произошло! #софт @dimio | dimio.org
1 год назад
Низкоуровневое форматирование flash/SD/microSD под Linux Несколько раз приходилось форматировать флешки (к которым относятся и различные SD и microSD карточки), а поскольку происходит это довольно редко – вынужден был лезть в гугл. Конспективная памятка по форматированию флешек под Linux: Проверить подключение flash fdisk -l Выведет список подключенных дисков и их разделов. Обычно флешка – /dev/sdb, но нужно обязательно проверить, так ли это! Проверить, примонтирована ли флешка df -h Если флешка примонтирована – покажет это и точку монтирования. Перед форматированием – отмонтировать: umount /dev/sdb. Проверить защиту от записи и геометрию При желании – можно проверить защиту от записи и геометрию (защита от записи в линуксе не важна): hdparm /dev/sdb Если нужно низкоуровневое форматирование – забить нулями dd if=/dev/zero of=/dev/sdb В выводе покажет объем флешки (должен соответствовать заявленному), скорость и время записи. Также покажет, сколько было записано байт на флешку, что полезно при проверке флешки на физические ошибки (см. ниже). Проверить на физические ошибки head -c N /dev/sdb | md5sum head -c N /dev/zero | md5sum где N равно числу байт, записанных на флешку при помощи dd. Если контрольные суммы не совпадают – флешка “битая” или были ошибки записи (в реальности сталкивался с форматированием microSD через плохой кард-ридер – даже когда не выскакивали ошибки ввода-вывода при операциях – контрольные суммы не совпадали, с заменой кард-ридера проблема ушла). Пример: dimio@ibm $ dd if=/dev/zero of=/dev/sdb dd: запись в «/dev/sdb»: На устройстве кончилось место 3932161+0 записей считано 3932160+0 записей написано скопировано 2013265920 байт (2,0 GB), 1010,99 c, 2,0 MB/c dimio@ibm $ head -c 2013265920 /dev/zero | md5sum 5d0fd6273bed1c500c6fc22d86a59630 - dimio@ibm $ head -c 2013265920 /dev/sdb | md5sum 5d0fd6273bed1c500c6fc22d86a59630 - Ну и для полного счастья при желании: dimio@ibm… #linux #notes --- Ссылка на запись --- https://dimio.org/nizkourovnevoe-formatirovanie-flash-pod-linux.html
283 читали · 1 год назад
Получение класса “Enum с параметром” по значению параметра Частенько в коде встречаются перечисления, дополнительно хранящие некие значения (в виде private final поля обычно). Чтобы в дальнейшем можно было, например, при сериализации в json это значение подставлять автоматом (@JsonValue у Jackson). Тогда возникает обычно и обратная задача – десериализовать (распарсить) значение обратно в Enum (@JsonCreator у Jackson). Вот мне и надоело копипастить туда-сюда все эти методы (сериализации/десериализации) между классами Enum. Решил сделать один раз утилитный метод и в проекте им пользоваться. Благо, время позволило. В принципе, подобный метод есть в недрах Apache Commons EnumUtils, но он работает только со строковым параметром String enumName, плюс выкидывает стандартное исключение. А обычно надо выкинуть некое кастомное, принятое на проекте. Так и родился свой костылёчек, как оно зачастую и бывает. Получить класс Enum по значению Импорты копировать не буду, полагаю, IDE предложит их подставить по выбору, если автоматически не сможет этого сделать. Сам утилитный метод примитивен: public final class EnumUtil { private EnumUtil() {} public static <T extends ValuedEnum<V>, V> T fromValue(Class<T> enumType, V value) { return Arrays.stream(enumType.getEnumConstants()) .filter(it -> it.getValue().equals(value)) .findAny() .orElseThrow(() -> new IllegalArgumentException(String.format( "Wrong value [%s] for enum type [%s]", value, enumType.getSimpleName()) )); } } ValuedEnum – это интерфейс, который реализуют все Enum со значением. Вот он: public sealed interface ValuedEnum<V> permits ComplexValue, NumberValue, StringValue { V getValue(); ValuedEnum<V> fromValue(V value); } Сделан sealed, чтобы при имплементации (методом копипасты) – был дополнительный “маячок”, заставляющий обратить внимание – это именно Enum со значением. Пример работы и тесты - на сайте, в запись ТГ не влезают. #java #программинг #Памятки
1 год назад
LibreOffice Calc – трюки работы с таблицей Накопилось ещё некоторое количество “приёмчиков” работы с Open/Libre Office. Если предыдущая заметка на эту тему была посвящена LO Writer, то на сей раз – “подопытным” выступает пакет Calc (электронные таблицы). Для затравки – простое, но часто нужное действие – перемещение строк и столбцов таблицы. Перемещение столбцов / строк 1. Выделить нужный диапазон при помощи выделения всего столбца/строки (для этого можно щелкнуть ЛКМ на заголовок столбца/строки). 2. Кликнуть и зажать ЛКМ внутри выделенного диапазона (на самих выделенных ячейках с данными, не на заголовке). 3. Тащить мышью диапазон, затем при отпускании: ◦ Перезапишет тот диапазон ячеек, на который был перетащен ◦ При зажатом Alt – поменяет диапазоны ячеек местами LibreOffice Calc: поменять местами столбцы (запуск анимации по клику) Изменение типа данных ячеек 1. Выделить нужный диапазон ячеек (или весь столбец/строку целиком по клику на заголовок). 2. Верхнее меню: Данные -> Текст по столбцам. 3. ЛКМ на столбец в нижней области открывшегося окошка (для выделения диапазона, в котором требуется преобразование). 4. Выбрать тип столбца – Ок. Эту операцию удобно проиллюстрировать примером: есть столбец с датами, которые хранятся, как текст (т.е. тип данных внутри офиса у них – текстовый, такое часто встречается при работе с кривыми выгрузками для Экселя). Использование меню Формат – Формат чисел – Дата не поможет в данном случае, т.к. дата хранится в виде строки '2023-06-16. Вот здесь и пригодится изменение типа данных ячеек, после которого их уже можно будет отформатировать, как даты (чтобы изменить отображение, если надо). LibreOffice Calc: преобразовать текст в дату (запуск анимации по клику) Автоматическое вычисление промежуточных итогов Ещё одна отличная функция Calc – можно получить итоговые значения для заданного набора данных (агрегировать). Буквально – в несколько кликов! Что отдельно приятно – функция работает с фильтрами. 1. Ctrl +… #office #libreoffice #notes #трюки --- Ссылка на запись --- https://dimio.org/libreoffice-calc-tryuki-raboty-s-tabliczej.html
1 год назад
LeetCode 2278. Percentage of Letter in String Ещё одна простая задачка – определение процентного содержания целевого символа в исходной строке. Пара решений: - через стримы (примитивно, без кастомной свёртки, да и помедленней) - и через цикл for. Стримы public int percentageLetter(String s, char letter) { long cnt = s.chars().filter(it -> it == (int) letter).count(); return (int) (100 * cnt / s.length()); } Success: Runtime:2 ms, faster than 12.22% of Java online submissions. Memory Usage:40.6 MB, less than 45.95% of Java online submissions. Цикл public int percentageLetter(String s, char letter) { int cnt = 0; for (char c : s.toCharArray()) { cnt += c == letter ? 1 : 0; } return 100 * cnt / s.length(); } Success: Runtime:0 ms, faster than 100.00% of Java online submissions. Memory Usage:40.1 MB, less than 88.72% of Java online submissions. Решение на гитхабе. Given a string s and a character letter, return the percentage of characters in s that equal letter rounded down to the nearest whole percent. https://leetcode.com/problems/percentage-of-letter-in-string/ #algorithms #java #leetcode --- Ссылка на запись --- https://dimio.org/leetcode-2278-percentage-of-letter-in-string.html
1 год назад
LeetCode 1935. Maximum Number of Words You Can Type Тоже забавная задачка со “сломанной клавиатурой”. Решил в ней Arrays.binarySearch использовать для поиска буквы слова в наборе “сломанных клавишей”, да и чтобы не забыть о его (метода) существовании в целом. Судя по статистике – нормально получилось, в общем-то. class Solution { public int canBeTypedWords(String text, String brokenLetters) { var brL = brokenLetters.toCharArray(); Arrays.sort(brL); var words = text.split(" "); int canTypeCnt = 0; for (var word : words) { boolean canType = true; for (int i = 0; i = 0) { canType = false; break; } } if (canType) { canTypeCnt++; } } return canTypeCnt; } } Success: Runtime:2 ms, faster than 91.93% of Java online submissions. Memory Usage:42.7 MB, less than 23.23% of Java online submissions. То же решение на гитхабе. There is a malfunctioning keyboard where some letter keys do not work. All other keys on the keyboard work properly. Given a string text of words separated by a single space (no leading or trailing spaces) and a string brokenLetters of all distinct letter keys that are broken, return the number of words in text you can fully type using this keyboard. https://leetcode.com/problems/maximum-number-of-words-you-can-type/ #algorithms #java #leetcode --- Ссылка на запись --- https://dimio.org/leetcode-1935-maximum-number-of-words-you-can-type.html
1 год назад
Git config с разделением по проектам Возникла потребность настраивать по-разному конфиги гита для разных проектов (email контактный поменять, хотя бы, или хук на прогон тестов повесить). Ну и понятно, что как-то эти конфиги подкладывать туда-сюда – не слишком увлекательно. К счастью, в свежих версиях гита – есть инклюды. В том числе – по условию – includeIf. Вот ими и стоит воспользоваться. Основной конфиг git Общая концепция такова – в основном конфиге ~/.gitconfig – перечислить (под условиями) конфиги “зависимые”, а все специфичные настройки прописать уже в них. Ничего экстраординарного, в общем. Примерно вот так у меня это выглядит, по условию включается конфиг из файла gitconfig-project-1: [user] name = Dmitry email = dimio@dimio.org [includeIf "gitdir:~/project-1/repos/"] path = ~/.config/git/gitconfig-project-1 Важный момент – директорию после gitdir: нужно указывать без отделения пробелом. Вложенный конфиг git А вот так – выглядит сам файл ~/.config/git/gitconfig-project-1 [user] email = dmitry@dimio.org [core] hooksPath = ~/.config/git/hooks/ autocrlf = input sshCommand = "ssh -F ${HOME}/.ssh/config-project-1" Тут уже как раз и переопределены email, хуки (для этого проекта активирован автопрогон тестов в pre-push хуке) и конфиг ssh (там специфические настройки для доступа к репозиторию по ключу). Разделение credentials Раз уж зашла речь о разделении конфигов и о доступе – можно сразу настройки доступа по http(s) разбить немного. Включаются они так: git config --global credential.helper store. И после этого лежат в ~/.git-credentials в открытом виде! Разделить их для разных репозиториев внутри одного хоста – можно так (на примере github): git config --global credential.github.com.useHttpPath true И тогда в .git-credentials будут отдельные записи лежать: https://:@github.com/path/to/repo1.git https://:@github.com/path/to/repo2.git Но, безусловно, удобней (да и безопасней, пожалуй) – пользоваться доступом с ssh ключами. #rc #git #notes --- Ссылка на запись --- https://dimio.org/git-config-s-razdeleniem-po-proektam.html
2 года назад
CloudFlare WARP + WireGuard на роутере Keenetic По аналогии с настройкой доступа к Cloudflare WARP через WireGuard в Linux – решил, заодно уж, поднять VPN и на роутере. В наличии – Keenetic Omni KN-1410 с KeeneticOS версии 3.7.4 (WireGuard есть и в более ранних версиях). Насколько я понимаю, политика Keenetic такова, что функциональность прошивок у них идентична для разных моделей роутеров (не зависит от “класса” устройства). Так что – должно работать не только на Omni. Конфиг WireGuard для WARP В основном – процесс проходит аналогичным образом. Для начала надо сгенерировать конфиг и подправить его, прописав Endpoint, DNS, маску сети. У меня такой файл получился: [Interface] PrivateKey = {автоматически сгенерированный ключ} Address = {сгенирированный IPv4 адрес}/32 Address = {сгенирированный IPv6 адрес} # DNS OpenNIC + Google DNS = 94.16.114.254, 51.77.149.139, 185.181.61.24, 8.8.8.8 [Peer] PublicKey = {автоматически сгенерированный ключ} Endpoint = 162.159.193.10:2408 AllowedIPs = 0.0.0.0/0 AllowedIPs = ::/0 Здесь добавлены (помимо Google) адреса DNS OpenNIC – через них, дополнительно, будут работать домены lib и coin. Там есть зеркала у некоторых заблокированных популярных ресурсов. Настройка WARP на роутере Через веб-интерфейс надо импортировать конфиг для WARP: Интернет – Другие подключения – Загрузить из файла. Нажать на автоматически созданное соединение и поставить галку Использовать для выхода в интернет. Ну и активировать само подключение ползунком. Доступ в интернет через WireGuard на Keenetic Omni Далее – там же, в веб-интерфейсе, задать приоритет подключению через VPN: Интернет – Приоритеты подключений – перетащить WARP подключение на самый верх. Приоритет подключений Всё, работает. Устройства из внутренней сети – ходят в интернет через WARP. Дополнительную информацию можно найти в справке Keenetic, если что-то пошло не так. Мне хватило действий, описанных в заметке. Надеюсь, и у вас проблем не возникнет! #notes #vpn #Интернет --- Ссылка на запись --- https://dimio.org/cloudflare-warp-wireguard-na-routere-keenetic.html
1397 читали · 2 года назад
Leetcode 1920. Build Array from Permutation После долгих праздничных выходных — приходится «разогревать» голову задачками с высоким Acceptance. И даже они — не сразу заходят. Со скрипом. class Solution { public static int[] buildArray(int[] nums) { int[] ans = new int[nums.length]; for (int i = 0; i Given a zero-based permutation nums (0-indexed), build an array ans of the same length where ans[i] = nums[nums[i]] for each 0 <= i < nums.length and return it. A zero-based permutation nums is an array of distinct integers from 0 to nums.length - 1 (inclusive). https://leetcode.com/problems/build-array-from-permutation/description/ #algorithms #array #java #leetcode --- Ссылка на запись --- https://dimio.org/leetcode-1920-build-array-from-permutation.html
2 года назад
CloudFlare WARP + WireGuard = простой способ разблокировки Долгое время пользовался ssh-туннелем для «разблокировки» некоторых сетевых ресурсов, доступ к которым был ограничен для IP Российского диапазона (ну, драйверы там скачать с сайта производителя, и т.п.). Но — всему приходит конец. Моему терпению — тоже. Надоело постоянно переключать потребителей на работу через прокси (privoxy), чтобы завернуть трафик в socks-прокси туннеля. TOR стали прикручивать, что привело к очень долгому поиску мостов. И лень моя победила (в очередной раз). Очевидно — нужен был способ попроще, да ещё — без особых затрат. Ставить VPN сервер (в том или ином виде) на VPS — хотелось ещё меньше, чем кидать туннель. Всякие платные прокси (типа Mullvad) — они удобны, позволяют выбрать «точку выхода», но — надо изыскивать возможность их оплатить. Бесплатные — обычно, работают так себе. Тут я вспомнил, что есть же CloudFlare и его WARP, причем — в бесплатной версии, да со всей мощью клаудфлэровских серверов, да без ограничений скорости, да ещё и — должен, теоретически, работать через нативный клиент WireGuard. «Надо попробовать» — подумал Штирлиц. Настройка WARP в Linux В целом, процесс достаточно понятный, на современных системах — проблем быть не должно (на современных — это где Network Manager поддерживает Wire Guard, иначе — можно и через консоль поднимать/гасить интерфейс VPN, но это менее удобно). - Сгенерировать конфиг для WARP — консольной утилитой или онлайн-генератором на её базе. Ещё есть неофициальный CLI, мне он не пригодился. - Полученный конфиг можно сунуть в /etc/wireguard/ и попробовать поднять через systemctl start wg-quick@название-конфига.conf. Но вряд ли это заработает, конфиг придется править. Конфиг WireGuard для WARP А чтобы не править его, передергивая интерфейс вручную из консоли, — проще сразу добавить в Network Manager. Подобрать рабочие настройки там, затем — перенести в конфиг. И получить основной (через графический интерфейс) и резервный (из… #linux #vpn #Интернет #памятка --- Ссылка на запись --- https://dimio.org/cloudflare-warp-wireguard-prostoj-sposob-razblokirovki.html
196 читали · 2 года назад