Архив рубрики: Кодинг

«С рождения Бобби пай-мальчиком был»

Увлёкся азартной игрой с государством корпорацией.

Успел выиграть каплю знания — PostgreSQL умеет нативно оперировать множествами, в т.ч. — символов. И получается очень удобно, когда словарный запас иссяк:

select word
from public.nouns
where
char_length(word) = 5
and string_to_array(word, null) @> '{с,о}'
and not string_to_array(word, null) && '{а,к,ц,и,я}'
and word like '__ь'
Читать далее «С рождения Бобби пай-мальчиком был»

План — закон!

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

И, в том числе:

  • Поддержки работы со множеством узлов в кластере;
  • Поддержки персистентности заданий;
  • Простоты использования;
  • Простоты развертывания.

Конечно — open source с подходящей лицензией. И spring-boot-starter в комплекте — для максимального удовольствия.

Читать далее План — закон!

Java List split

Долго валялось в закладках на SO — и пригодилось, наконец. Обычно — или уже была «в коробке» Guava с Lists.partition(), или — Apache Commons и его ListUtils.partition().

Деление на подмножества (каплю доработано относительно исходника на SO):

// https://stackoverflow.com/a/30072617
public static <T> Stream<List<T>> listPartition(@NotNull List<T> source, @Positive int length) {
    requireNonNull(source, "Source list must not be null");
    if (length <= 0) {
        throw new IllegalArgumentException("Partitions length must be greater than zero");
    }
    int size = source.size();
    if (size == 0) {
        return Stream.empty();
    }
    if (size <= length) {
        return Stream.of(source);
    }
    int fullChunks = (size - 1) / length;
    return IntStream.range(0, fullChunks + 1)
        .mapToObj(n -> source.subList(n * length, n == fullChunks ? size : (n + 1) * length));
}
Читать далее Java List split

Advent of Code 2023: Day 4: Scratchcards

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

Сразу прикинул, что с использованием примитивов или оборачиванием в типы из стандартной библиотеки — будет портяночно. Поэтому — отдельный класс с логикой:

public class Card {
    private static final Predicate<String> EMPTY = s -> " ".equals(s) || "".equals(s);
    Integer cardN, winCnt;
    Set<Integer> win, have;
    List<Card> nextCards = new ArrayList<>(); // added for part 2
    public Card(String cardN, String[] win, String[] have) {
        this.cardN = Integer.parseInt(cardN.replaceAll("^Card\\s+", ""));
        this.win = parseNums(win);
        this.have = parseNums(have);
        this.winCnt = (int) this.have.stream().filter(h -> this.win.contains(h)).count();
    }
    void addNext(List<Card> nextCards) { // added for part 2
        this.nextCards.addAll(nextCards);
    }
    Stream<Card> flat() { // added for part 2
        return Stream.concat(Stream.of(this),
                this.nextCards.stream().flatMap(Card::flat));
    }
    private static Set<Integer> parseNums(String[] nums) {
        return Arrays.stream(nums).filter(not(EMPTY)).map(Integer::parseInt)
                .collect(Collectors.toSet());
    }
};
Читать далее Advent of Code 2023: Day 4: Scratchcards

Advent of Code 2023: Day 3: Gear Ratios

В начале была лень… Стойкое нежелание возиться с границами массивов. Оно, и только оно толкнуло меня на скользкую дорожку замены матрицы примитивов на List<List<>>.

Следующим шагом на пути окунания в пучины многословия — стало создание контейнеров для упаковки данных со «схемы двигателя». Вот они:

public record Coord(Integer row, Integer column){};
public record Cell(Coord coord, Integer codePoint){
    Set<Coord> border() {return Set.of(
            new Coord(coord.row(), coord.column() - 1), // left
            new Coord(coord.row() - 1, coord.column() - 1), // top-left
            new Coord(coord.row() - 1, coord.column()), // top
            new Coord(coord.row() - 1, coord.column() + 1), // top-right
            new Coord(coord.row(), coord.column() + 1), // right
            new Coord(coord.row() + 1, coord.column() + 1), // bot-right
            new Coord(coord.row() + 1, coord.column()), // bottom
            new Coord(coord.row() + 1, coord.column() - 1) // bot-left
    );}
};
public record Part(List<Cell> cells){
    public Part {
        cells = List.copyOf(cells);
    }
    Set<Coord> border() {
        return cells.stream()
            .flatMap(c -> c.border().stream())
            .filter(bCoord -> cells.stream()
                    .noneMatch(c -> bCoord.equals(c.coord())))
            .collect(Collectors.toSet());
    }
    Integer value() {
        return Integer.parseInt(cells.stream()
                .map(c -> Character.toChars(c.codePoint()))
                .map(String::new).collect(Collectors.joining()));
    }
};
Читать далее Advent of Code 2023: Day 3: Gear Ratios

Advent of Code 2023: Day 2: Cube Conundrum

Страшный, длинный, мучительный парсинг ввода…
Хотелось бы, конечно, иметь возможность сделать по-перловому, что-то типа: echo -e "Game 1: 3 blue, 4 red; 1 red, 2 green, 6 blue; 2 green\nGame 2: 1 blue, 2 green; 3 green, 4 blue, 1 red; 1 green, 1 blue" | perl -wlne '@matches = $_ =~ /(?:\G(?!\A)|^Game) (\S+)/g; print join("=",@matches)'.

Немного почистить после, или сразу докрутить регулярку, чтобы не захватывала разделители. Сложить в хэш. И закончить кучей циклов в итоге 🙁

С другой стороны — и возня с java Matcher не вдохновляла, и описывать структуру в виде POJO — для чисто скриптового решения — зачем.

split — дёшево и сердито, fastpath бонусом. К счастью — ввод был одинаков для обеих частей загадки.

Читать далее Advent of Code 2023: Day 2: Cube Conundrum

Advent of Code 2023: Day 1: Trebuchet?!

Снова AoC — и снова начат с опозданием. Дуплет! Основная идея прежняя — решать в jshell, пока это не станет слишком многословным. Экономия на буковках, в общем.

Обвязка для загрузки условий задачи — та же, что для AoC-2022. Тег для задачек 2023 года — adventofcode-2023 (или раздел Problem Solving).

Читать далее Advent of Code 2023: Day 1: Trebuchet?!

Spring: TLS/SSL подключение к RabbitMQ

Возникла потребность подключаться из Java приложения к брокеру RabbitMQ с использованием защищенного соединения. Приложение на Spring Boot, живёт в контейнере Docker и должно слушать два узла Rabbit параллельно.

  • На входе: сертификат клиентского узла — контейнер client-cert.pfx, корневой сертификат для него root-cert.crt
  • Открытый серверный сертификат шлюза Rabbit: выкачивается автоматически (можно подложить вручную)
  • Используемая версия java поддерживает форматы хранилищ и JKS, и PKCS12
  • Требуется: создать и положить сертификаты в Key Store (сертификаты приложения «клиентские») и Trust Store (доверенные «серверные» сертификаты). В чём разница.
Читать далее Spring: TLS/SSL подключение к RabbitMQ