<?xml version="1.0" encoding="UTF-8"?><feed
	xmlns="http://www.w3.org/2005/Atom"
	xmlns:thr="http://purl.org/syndication/thread/1.0"
	xml:lang="ru-RU"
	>
	<title type="text">dimio.org</title>
	<subtitle type="text">Perl, Linux, программирование, настройка и что-нибудь ещё...</subtitle>

	<updated>2024-12-23T14:24:45Z</updated>

	<link rel="alternate" type="text/html" href="https://dimio.org" />
	<id>https://dimio.org/feed/atom</id>
	<link rel="self" type="application/atom+xml" href="https://dimio.org/feed/atom" />

	<generator uri="https://wordpress.org/" version="6.9.4">WordPress</generator>
	<entry>
		<author>
			<name>dimio</name>
							<uri>http://dimio.org</uri>
						</author>

		<title type="html"><![CDATA[Путеводитель по базам данных (Владимир Комаров)]]></title>
		<link rel="alternate" type="text/html" href="https://dimio.org/putevoditel-po-bazam-dannyh-vladimir-komarov.html" />

		<id>https://dimio.org/?p=2061</id>
		<updated>2024-12-23T14:24:45Z</updated>
		<published>2024-12-23T14:24:43Z</published>
		<category scheme="https://dimio.org" term="Полезности" /><category scheme="https://dimio.org" term="notes" /><category scheme="https://dimio.org" term="sql" />
		<summary type="html"><![CDATA[Отличное дополнение к &#171;PostgreSQL изнутри&#187; &#8212; ещё одна годная и бесплатная книга по СУБД на сайте PostgresPro &#8212; Путеводитель по базам данных. Хороший учебник/справочник по базе баз с примерами на актуальных системах. И, сверх того, ещё и с указанием конкретных вендорских названий для реализаций тех или иных аспектов СУБД. Есть отличный предметный указатель, с которого можно и &#8230; <a href="https://dimio.org/putevoditel-po-bazam-dannyh-vladimir-komarov.html" class="more-link">Читать далее <span class="screen-reader-text">Путеводитель по базам данных (Владимир Комаров)</span> <span class="meta-nav">&#8594;</span></a>]]></summary>

					<content type="html" xml:base="https://dimio.org/putevoditel-po-bazam-dannyh-vladimir-komarov.html"><![CDATA[
<p>Отличное дополнение к &#171;<a href="https://t.me/panykey/133" target="_blank" rel="noreferrer noopener">PostgreSQL изнутри</a>&#187; &#8212; ещё одна годная и бесплатная книга по СУБД на сайте PostgresPro &#8212; <a href="https://postgrespro.ru/education/books/dbguide" target="_blank" rel="noreferrer noopener">Путеводитель по базам данных</a>.</p>



<p>Хороший учебник/справочник по <em>базе баз</em> с примерами на актуальных системах. И, сверх того, ещё и с указанием конкретных вендорских названий для реализаций тех или иных аспектов СУБД.</p>



<p>Есть отличный предметный указатель, с которого можно и начать &#8212; по нему хорошо прослеживаются релевантные темы и термины, т.е. можно прям &#171;укрупнённо&#187; быстро охватить некую предметную область.</p>



<span id="more-2061"></span>



<p>Нет заныривания в глубины глубин и погружения в детали, не влияющие на практическое использование, но уж по приведённым примерам &#8212; будет дано и сравнение, и описание альтернатив.</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p>Книга рассказывает об архитектурных принципах, на которых базируются все современные системы управления базами данных, а также об алгоритмах и структурах данных, которые в них используются. Особое внимание уделено сравнению реализаций одних и тех же подходов в близких по функциональности платформах.</p>
</blockquote>



<div class="wp-block-buttons has-custom-font-size has-small-font-size is-content-justification-center is-nowrap is-layout-flex wp-container-core-buttons-is-layout-1fb9aab6 wp-block-buttons-is-layout-flex">
<div class="wp-block-button has-custom-width wp-block-button__width-100 is-style-outline is-style-outline--1"><a class="wp-block-button__link has-dark-gray-color has-text-color has-link-color wp-element-button" href="https://t.me/panykey/153">Комментировать в TELEGRAM</a></div>
</div>
]]></content>
		
			</entry>
		<entry>
		<author>
			<name>dimio</name>
							<uri>http://dimio.org</uri>
						</author>

		<title type="html"><![CDATA[План &#8212; закон!]]></title>
		<link rel="alternate" type="text/html" href="https://dimio.org/plan-zakon.html" />

		<id>https://dimio.org/?p=2046</id>
		<updated>2024-09-01T20:48:33Z</updated>
		<published>2024-09-01T20:48:31Z</published>
		<category scheme="https://dimio.org" term="Кодинг" /><category scheme="https://dimio.org" term="Полезности" /><category scheme="https://dimio.org" term="scheduler" /><category scheme="https://dimio.org" term="программирование" />
		<summary type="html"><![CDATA[Выбирал тут планировщик для периодических заданий по обслуживанию приложения.С Quartz что-то все устали возиться, ленились отдельную схему под его таблички выделять и кончили тем, что возжелали свежих проблем нового, неизведанного. И, в том числе: Конечно &#8212; open source с подходящей лицензией. И spring-boot-starter в комплекте &#8212; для максимального удовольствия. Первым в гонку влезает Quartz &#8212; &#8230; <a href="https://dimio.org/plan-zakon.html" class="more-link">Читать далее <span class="screen-reader-text">План &#8212; закон!</span> <span class="meta-nav">&#8594;</span></a>]]></summary>

					<content type="html" xml:base="https://dimio.org/plan-zakon.html"><![CDATA[
<p>Выбирал тут планировщик для периодических заданий по обслуживанию приложения.<br />С <em>Quartz</em> что-то все устали возиться, ленились отдельную схему под его таблички выделять и кончили тем, что возжелали <s>свежих проблем</s> нового, неизведанного.</p>



<p>И, в том числе:</p>



<ul class="wp-block-list">
<li>Поддержки работы со множеством узлов в кластере;</li>



<li>Поддержки персистентности заданий;</li>



<li>Простоты использования;</li>



<li>Простоты развертывания.</li>
</ul>



<p>Конечно &#8212; <em>open source</em> с подходящей лицензией. И <em>spring-boot-starter</em> в комплекте &#8212; для максимального удовольствия.</p>


<div class="wp-block-image">
<figure data-wp-context="{&quot;imageId&quot;:&quot;69db9f05d82d0&quot;}" data-wp-interactive="core/image" data-wp-key="69db9f05d82d0" class="aligncenter size-large wp-lightbox-container"><img fetchpriority="high" decoding="async" width="510" height="185" data-wp-class--hide="state.isContentHidden" data-wp-class--show="state.isContentVisible" data-wp-init="callbacks.setButtonStyles" data-wp-on--click="actions.showLightbox" data-wp-on--load="callbacks.setButtonStyles" data-wp-on-window--resize="callbacks.setButtonStyles" src="https://dimio.org/wp-content/uploads/2024/09/image-3-510x185.png" alt="" class="wp-image-2050" srcset="https://dimio.org/wp-content/uploads/2024/09/image-3-510x185.png 510w, https://dimio.org/wp-content/uploads/2024/09/image-3-400x145.png 400w, https://dimio.org/wp-content/uploads/2024/09/image-3-200x73.png 200w, https://dimio.org/wp-content/uploads/2024/09/image-3-768x279.png 768w, https://dimio.org/wp-content/uploads/2024/09/image-3.png 1280w" sizes="(max-width: 510px) 100vw, 510px" /><button
			class="lightbox-trigger"
			type="button"
			aria-haspopup="dialog"
			aria-label="Увеличить"
			data-wp-init="callbacks.initTriggerButton"
			data-wp-on--click="actions.showLightbox"
			data-wp-style--right="state.imageButtonRight"
			data-wp-style--top="state.imageButtonTop"
		>
			<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="none" viewBox="0 0 12 12">
				<path fill="#fff" d="M2 0a2 2 0 0 0-2 2v2h1.5V2a.5.5 0 0 1 .5-.5h2V0H2Zm2 10.5H2a.5.5 0 0 1-.5-.5V8H0v2a2 2 0 0 0 2 2h2v-1.5ZM8 12v-1.5h2a.5.5 0 0 0 .5-.5V8H12v2a2 2 0 0 1-2 2H8Zm2-12a2 2 0 0 1 2 2v2h-1.5V2a.5.5 0 0 0-.5-.5H8V0h2Z" />
			</svg>
		</button></figure>
</div>


<span id="more-2046"></span>



<p>Первым в гонку влезает <a href="https://github.com/quartz-scheduler/quartz" target="_blank" rel="noreferrer noopener">Quartz</a> &#8212; он здесь ужé и у́же применяться не желает!</p>



<p>Вторым идёт истинно <s>безликий</s> средний <a href="https://github.com/jobrunr/jobrunr" target="_blank" rel="noreferrer noopener">JobRunr</a> &#8212; откуда-то вынырнул и смылся куда-то.</p>



<p>А против всего недостаточно хорошего у нас, как пелось, есть третий путь: молодёжный и свежий, только из-под клавиатуры &#8212; <a href="https://github.com/kagkarlsson/db-scheduler" target="_blank" rel="noreferrer noopener">db-scheduler</a>!<br />(Если не заглядывать в <code>git log</code>, а мы и не будем).</p>



<p>Таблички все же любят? Кто нет &#8212; можно без любви, она суха и беспристрастна при любом отношении (но ориентацию предпочитает альбомную):</p>



<figure class="wp-block-table aligncenter"><table class="has-fixed-layout"><thead><tr><th>Критерий</th><th class="has-text-align-center" data-align="center">Quartz</th><th class="has-text-align-center" data-align="center">JobRunr</th><th class="has-text-align-center" data-align="center">db-scheduler</th></tr></thead><tbody><tr><td>Cluster-friendly</td><td class="has-text-align-center" data-align="center">+</td><td class="has-text-align-center" data-align="center">+</td><td class="has-text-align-center" data-align="center">+</td></tr><tr><td>Персистентные задачи</td><td class="has-text-align-center" data-align="center">+</td><td class="has-text-align-center" data-align="center">+</td><td class="has-text-align-center" data-align="center">+</td></tr><tr><td>История запусков</td><td class="has-text-align-center" data-align="center">+</td><td class="has-text-align-center" data-align="center">+</td><td class="has-text-align-center" data-align="center">+/-</td></tr><tr><td>Простота использования</td><td class="has-text-align-center" data-align="center">+/-</td><td class="has-text-align-center" data-align="center">+/-</td><td class="has-text-align-center" data-align="center">+</td></tr><tr><td>Простота развертывания</td><td class="has-text-align-center" data-align="center">+/-</td><td class="has-text-align-center" data-align="center">+</td><td class="has-text-align-center" data-align="center">+</td></tr><tr><td>Служебных таблиц в БД</td><td class="has-text-align-center" data-align="center">11 (-)</td><td class="has-text-align-center" data-align="center">5 (+/-)</td><td class="has-text-align-center" data-align="center">1 (+)</td></tr><tr><td>Ретраи</td><td class="has-text-align-center" data-align="center">Вручную (-)</td><td class="has-text-align-center" data-align="center">Поставка (+)</td><td class="has-text-align-center" data-align="center">Поставка (+)</td></tr><tr><td>Звёзд в GitHub</td><td class="has-text-align-center" data-align="center">6,2k</td><td class="has-text-align-center" data-align="center">2,3k</td><td class="has-text-align-center" data-align="center">1,2k</td></tr><tr><td>Дата последнего релиза</td><td class="has-text-align-center" data-align="center">Окт 2019 (-)</td><td class="has-text-align-center" data-align="center">Июл 2024 (+)</td><td class="has-text-align-center" data-align="center">Июл 2024 (+)</td></tr><tr><td>Лицензия</td><td class="has-text-align-center" data-align="center">Apache 2.0</td><td class="has-text-align-center" data-align="center">LGPL v3</td><td class="has-text-align-center" data-align="center">Apache 2.0</td></tr></tbody></table><figcaption class="wp-element-caption">Сравнение шедулеров: Quartz vs JobRunr vs db-scheduler</figcaption></figure>



<h2 class="wp-block-heading">Quartz</h2>



<p>По <em>Кварцу</em> понятно &#8212; он остановился в развитии (Достиг нирваны? Ждёт тепловой смерти вселенной?).<br />Делает много табличек &#8212; делает больно глазкам (да-да, можно и исправить, но лень же). В поставке нет ретраев.<br />Создание заданий смотрится очень энтерпрайзно, если вы в Индии &#8212; хватайте Кварц!</p>



<h2 class="wp-block-heading">JobRunr</h2>



<p>У <em>JobRunr</em> есть UI-панелька, Healthcheck из коробки, API-шка для работы с задачами, поддержка NoSQL хранилищ &#8212; и совсем нет совести!</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p>Нет и не было…</p>
</blockquote>



<p>Хочет много денег за такие пустячки, как:</p>



<ul class="wp-block-list">
<li>автоматический рестарт собственного служебного сервера при падениях;</li>



<li>использование открытой Spring-транзакции в заданиях;</li>



<li>интервал опроса задач менее 5 секунд.</li>
</ul>



<p>Всё это решается усердной ручной работой, но &#8212; без приятных ощущений.</p>



<p>А ещё у него тяжелые запросы во вьюшке для дашборда и построения метрик. И умирание сервера вместе с liveness пробами при потере коннекта к БД, после чего отстреливается под. И название &#8212; из семи символов! И… Ладно, не буду придираться.</p>



<h2 class="wp-block-heading">db-scheduler</h2>



<p>О, от <em>db-scheduler</em> веет ветром перемен! Самим свои существованием он, как будто, подбивает впасть<br />в грех починки исправного! Соблазняет, как в истории про змею и яблоко.<br />Ну и кое-что полезное имеет и умеет тоже: мало (очень) сторонних зависимостей, код понятный и простой, Healthcheck в поставке, метрики &#8212; тоже, <a href="https://github.com/kagkarlsson/db-scheduler?tab=readme-ov-file#performance" target="_blank" rel="noreferrer noopener">заявляет высокую производительность</a>, умеет создавать задания в одном сервисе и выполнять в другом, создает впечатление просты перехода на него.</p>



<p>При этом &#8212; из коробки в нём нет истории выполнений задания (есть плагин) и UI-панели (тоже плагин).<br />И id-шник заданию при запуске надо вручную создавать. Не выглядит особо опасным занятием, если честно.</p>



<h2 class="wp-block-heading">Что делать?</h2>



<p>Простыня выше <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/261d.png" alt="☝" class="wp-smiley" style="height: 1em; max-height: 1em;" /> совершенно точно не является индивидуальной инвестиционной рекомендацией, если только вы не инвестируете в таблицы БД и строчки в редакторе (снова поприветствуем Индию!). Никакой другой рекомендацией она не является тоже.<br />Личный выбор каждого &#8212; <code>TITS or GTFO</code>, а подбор планировщика &#8212; не так уж, в сущности, важен <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f642.png" alt="🙂" class="wp-smiley" style="height: 1em; max-height: 1em;" /></p>



<div class="wp-block-buttons has-custom-font-size has-small-font-size is-content-justification-center is-nowrap is-layout-flex wp-container-core-buttons-is-layout-1fb9aab6 wp-block-buttons-is-layout-flex">
<div class="wp-block-button has-custom-width wp-block-button__width-100 is-style-outline is-style-outline--2"><a class="wp-block-button__link has-black-color has-white-background-color has-text-color has-background has-link-color wp-element-button" href="https://t.me/panykey/150" target="_blank" rel="noreferrer noopener">Комментировать в TELEGRAM</a></div>
</div>
]]></content>
		
			</entry>
		<entry>
		<author>
			<name>dimio</name>
							<uri>http://dimio.org</uri>
						</author>

		<title type="html"><![CDATA[Advent of Code 2023: Day 4: Scratchcards]]></title>
		<link rel="alternate" type="text/html" href="https://dimio.org/advent-of-code-2023-day-4-scratchcards.html" />

		<id>https://dimio.org/?p=2015</id>
		<updated>2023-12-19T15:54:06Z</updated>
		<published>2023-12-19T15:41:52Z</published>
		<category scheme="https://dimio.org" term="Problem solving" /><category scheme="https://dimio.org" term="Кодинг" /><category scheme="https://dimio.org" term="adventofcode" /><category scheme="https://dimio.org" term="adventofcode-2023" /><category scheme="https://dimio.org" term="программирование" />
		<summary type="html"><![CDATA[Про задачу четвертого дня сказать особенно нечего. По условию &#8212; проще третей. По парсингу ввода &#8212; проще второй. Решается быстро. Сразу прикинул, что с использованием примитивов или оборачиванием в типы из стандартной библиотеки &#8212; будет портяночно. Поэтому &#8212; отдельный класс с логикой: И короткое решение с его помощью: https://adventofcode.com/2023/day/4]]></summary>

					<content type="html" xml:base="https://dimio.org/advent-of-code-2023-day-4-scratchcards.html"><![CDATA[
<p>Про задачу четвертого дня сказать особенно нечего. По условию &#8212; проще <a href="https://dimio.org/advent-of-code-2023-day-3-gear-ratios.html">третей</a>. По парсингу ввода &#8212; проще <a href="https://dimio.org/advent-of-code-2023-day-2-cube-conundrum.html">второй</a>. Решается быстро.</p>



<p>Сразу прикинул, что с использованием примитивов или оборачиванием в типы из стандартной библиотеки &#8212; будет портяночно. Поэтому &#8212; отдельный класс с логикой:</p>



<pre title="AoC 2023 Day 4 solution" class="wp-block-code"><code lang="java" class="language-java">public class Card {
    private static final Predicate&lt;String&gt; EMPTY = s -&gt; " ".equals(s) || "".equals(s);
    Integer cardN, winCnt;
    Set&lt;Integer&gt; win, have;
    List&lt;Card&gt; nextCards = new ArrayList&lt;&gt;(); // 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 -&gt; this.win.contains(h)).count();
    }
    void addNext(List&lt;Card&gt; nextCards) { // added for part 2
        this.nextCards.addAll(nextCards);
    }
    Stream&lt;Card&gt; flat() { // added for part 2
        return Stream.concat(Stream.of(this),
                this.nextCards.stream().flatMap(Card::flat));
    }
    private static Set&lt;Integer&gt; parseNums(String[] nums) {
        return Arrays.stream(nums).filter(not(EMPTY)).map(Integer::parseInt)
                .collect(Collectors.toSet());
    }
};</code></pre>



<span id="more-2015"></span>



<p>И короткое решение с его помощью:</p>



<pre title="AoC 2023 Day 4 solution" class="wp-block-code"><code lang="java" class="language-java">static void day4(String puzzleInputUri) throws IOException, InterruptedException {
    var cards = client.send(request.uri((URI.create(puzzleInputUri))).build(),
                    HttpResponse.BodyHandlers.ofLines()).body()
            .map(it -&gt; it.split(":", 2))
            .map(it -&gt; Map.entry(it[0], it[1].split("\\|", 2)))
            .map(it -&gt; new Card(it.getKey(), it.getValue()[0].split(" "),
                    it.getValue()[1].split(" ")))
            .toList();

    var answer1 = cards.stream()
            .filter(card -&gt; card.winCnt &gt; 0)
            .mapToInt(card -&gt; card.winCnt)
            .mapToDouble(win -&gt; Math.pow(2, (win - 1)))
            .reduce(Double::sum).orElseThrow();
    System.out.println(answer1); // 20117

    var answer2 = IntStream.iterate(cards.size() - 1, i -&gt; i &gt;= 0, i -&gt; i - 1)
            .mapToObj(cards::get)
            .peek(card -&gt; card.addNext(cards.subList(card.cardN, card.cardN + card.winCnt)))
            .flatMap(card -&gt; card.flat())
            .count();
    System.out.println(answer2); // 13768818
}</code></pre>



<pre class="wp-block-preformatted">https://adventofcode.com/2023/day/4</pre>



<div class="wp-block-buttons has-custom-font-size has-small-font-size is-content-justification-center is-nowrap is-layout-flex wp-container-core-buttons-is-layout-1fb9aab6 wp-block-buttons-is-layout-flex">
<div class="wp-block-button has-custom-width wp-block-button__width-100 is-style-outline is-style-outline--3"><a class="wp-block-button__link wp-element-button" href="https://t.me/panykey/141" target="_blank" rel="noreferrer noopener">Комментировать в TELEGRAM</a></div>
</div>
]]></content>
		
			</entry>
		<entry>
		<author>
			<name>dimio</name>
							<uri>http://dimio.org</uri>
						</author>

		<title type="html"><![CDATA[Advent of Code 2023: Day 3: Gear Ratios]]></title>
		<link rel="alternate" type="text/html" href="https://dimio.org/advent-of-code-2023-day-3-gear-ratios.html" />

		<id>https://dimio.org/?p=2012</id>
		<updated>2023-12-13T20:16:33Z</updated>
		<published>2023-12-13T19:52:07Z</published>
		<category scheme="https://dimio.org" term="Problem solving" /><category scheme="https://dimio.org" term="Кодинг" /><category scheme="https://dimio.org" term="adventofcode" /><category scheme="https://dimio.org" term="adventofcode-2023" /><category scheme="https://dimio.org" term="программирование" />
		<summary type="html"><![CDATA[В начале была лень&#8230; Стойкое нежелание возиться с границами массивов. Оно, и только оно толкнуло меня на скользкую дорожку замены матрицы примитивов на List&#60;List&#60;>>. Следующим шагом на пути окунания в пучины многословия &#8212; стало создание контейнеров для упаковки данных со &#171;схемы двигателя&#187;. Вот они: У меня было три штуки рекордов, несколько методов с регулярно вычисляющей &#8230; <a href="https://dimio.org/advent-of-code-2023-day-3-gear-ratios.html" class="more-link">Читать далее <span class="screen-reader-text">Advent of Code 2023: Day 3: Gear Ratios</span> <span class="meta-nav">&#8594;</span></a>]]></summary>

					<content type="html" xml:base="https://dimio.org/advent-of-code-2023-day-3-gear-ratios.html"><![CDATA[
<p>В начале была лень&#8230; Стойкое нежелание возиться с границами массивов. Оно, и только оно толкнуло меня на скользкую дорожку замены матрицы примитивов на <code>List&lt;List&lt;>></code>.</p>



<p>Следующим шагом на пути окунания в пучины многословия &#8212; стало создание контейнеров для упаковки данных со &#171;схемы двигателя&#187;. Вот они:</p>



<pre title="AoC 2023 Day 3 solution" id="data-containers" class="wp-block-code"><code lang="java" class="language-java">public record Coord(Integer row, Integer column){};
public record Cell(Coord coord, Integer codePoint){
    Set&lt;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&lt;Cell> cells){
    public Part {
        cells = List.copyOf(cells);
    }
    Set&lt;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()));
    }
};</code></pre>



<span id="more-2012"></span>



<p>У меня было три штуки рекордов, несколько методов с регулярно вычисляющей одно и то же логикой внутри них и россыпь операций по упаковке простого содержимого в сложные формы. Не то, чтобы всё это было нужно в решении задачи, но раз начал <em>коллекционировать</em> объекты, то иди в своём увлечении до конца.</p>



<pre title="AoC 2023 Day 3 solution" class="wp-block-code"><code lang="java" class="language-java">static void day3(String puzzleInputUri) throws IOException, InterruptedException {
    Integer emptyCell = (int) '.';
    Integer gearCell = (int) '*';
    List&lt;List&lt;Integer>> scheme = client.send(request.uri((URI.create(puzzleInputUri))).build(),
                    HttpResponse.BodyHandlers.ofLines()).body()
            .map(line -> line.chars().boxed().collect(Collectors.toCollection(ArrayList::new)))
            .peek(chars -> chars.addFirst(emptyCell))
            .peek(chars -> chars.addLast(emptyCell))
            .collect(Collectors.toCollection(ArrayList::new));
    scheme.addFirst(Collections.nCopies(scheme.getFirst().size(), emptyCell));
    scheme.addLast(Collections.nCopies(scheme.getFirst().size(), emptyCell));

    List&lt;Part> parts = new ArrayList&lt;>();
    List&lt;Cell> gears = new ArrayList&lt;>();
    List&lt;Cell> partDigit = new ArrayList&lt;>();
    boolean prevIsDigit = false;
    for (int row = 1; row &lt; scheme.size() - 1; row++) {
        for (int column = 1; column &lt; scheme.get(row).size() - 1; column++) {
            Integer cellValue = scheme.get(row).get(column);
            if (Character.isDigit(cellValue)) {
                partDigit.add(new Cell(new Coord(row, column), cellValue));
                prevIsDigit = true;
            } else if (prevIsDigit) {
                parts.add(new Part(partDigit));
                partDigit.clear();
                prevIsDigit = false;
            }
            if (gearCell.equals(cellValue)) {
                gears.add(new Cell(new Coord(row, column), cellValue));
            }
        }
    }
    var validParts = parts.stream()
            .filter(part -> part.border().stream().anyMatch(
                    c -> !emptyCell.equals(scheme.get(c.row()).get(c.column()))
            )).toList();

    var answer1 = validParts.stream()
            .mapToInt(part -> part.value())
            .sum();
    System.out.println(answer1);

    var answer2 = gears.stream()
            .map(gear -> Map.entry(gear,
                validParts.stream().filter(part -> part.border().contains(gear.coord())).toList()
            ))
            .filter(gearParts -> gearParts.getValue().size() == 2)
            .map(Map.Entry::getValue)
            .mapToInt(gearParts -> gearParts.getFirst().value() * gearParts.getLast().value())
            .sum();
    System.out.println(answer2);
}</code></pre>



<p>Это очень опасное предприятие закончилось благополучно! Длинная подготовка вылилась в достаточно короткие решения. Пришло удивительное, вселенское ощущение правильности всего того, что я делал.</p>



<pre title="Визуализация схемы" class="wp-block-code"><code lang="java" class="language-java">static void printScheme(List&lt;List&lt;Integer>> scheme) {
    scheme.forEach(row -> {
        StringBuilder sb = new StringBuilder();
        row.forEach(sb::appendCodePoint);
        System.out.println(sb);
    });
}</code></pre>



<pre class="wp-block-preformatted">https://adventofcode.com/2023/day/3</pre>



<div class="wp-block-buttons has-custom-font-size has-small-font-size is-content-justification-center is-nowrap is-layout-flex wp-container-core-buttons-is-layout-1fb9aab6 wp-block-buttons-is-layout-flex">
<div class="wp-block-button has-custom-width wp-block-button__width-100 is-style-outline is-style-outline--4"><a class="wp-block-button__link wp-element-button" href="https://t.me/panykey/140" target="_blank" rel="noreferrer noopener">Комментировать в TELEGRAM</a></div>
</div>
]]></content>
		
					<link rel="replies" type="text/html" href="https://dimio.org/advent-of-code-2023-day-3-gear-ratios.html#comments" thr:count="0" />
			<link rel="replies" type="application/atom+xml" href="https://dimio.org/advent-of-code-2023-day-3-gear-ratios.html/feed/atom" thr:count="0" />
			<thr:total>0</thr:total>
			</entry>
		<entry>
		<author>
			<name>dimio</name>
							<uri>http://dimio.org</uri>
						</author>

		<title type="html"><![CDATA[Advent of Code 2023: Day 2: Cube Conundrum]]></title>
		<link rel="alternate" type="text/html" href="https://dimio.org/advent-of-code-2023-day-2-cube-conundrum.html" />

		<id>https://dimio.org/?p=2010</id>
		<updated>2023-12-10T14:26:48Z</updated>
		<published>2023-12-10T14:26:48Z</published>
		<category scheme="https://dimio.org" term="Problem solving" /><category scheme="https://dimio.org" term="Кодинг" /><category scheme="https://dimio.org" term="adventofcode" /><category scheme="https://dimio.org" term="adventofcode-2023" /><category scheme="https://dimio.org" term="программирование" />
		<summary type="html"><![CDATA[Страшный, длинный, мучительный парсинг ввода&#8230;Хотелось бы, конечно, иметь возможность сделать по-перловому, что-то типа: 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" &#124; perl -wlne '@matches = $_ =~ /(?:\G(?!\A)&#124;^Game) (\S+)/g; print join("=",@matches)'. &#8230; <a href="https://dimio.org/advent-of-code-2023-day-2-cube-conundrum.html" class="more-link">Читать далее <span class="screen-reader-text">Advent of Code 2023: Day 2: Cube Conundrum</span> <span class="meta-nav">&#8594;</span></a>]]></summary>

					<content type="html" xml:base="https://dimio.org/advent-of-code-2023-day-2-cube-conundrum.html"><![CDATA[
<p>Страшный, длинный, мучительный парсинг ввода&#8230;<br />Хотелось бы, конечно, иметь возможность сделать по-перловому, что-то типа: <code>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)'</code>.</p>



<p>Немного почистить после, или сразу докрутить регулярку, чтобы не захватывала разделители. Сложить в хэш. И закончить кучей циклов в итоге <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f641.png" alt="🙁" class="wp-smiley" style="height: 1em; max-height: 1em;" /></p>



<p>С другой стороны &#8212; и возня с <code>java Matcher</code> не вдохновляла, и описывать структуру в виде POJO &#8212; для чисто скриптового решения &#8212; зачем.</p>



<p><code>split</code> &#8212; дёшево и сердито, <em>fastpath</em> бонусом. К счастью &#8212; ввод был одинаков для обеих частей загадки.</p>



<span id="more-2010"></span>



<pre title="AoC 2023 Day 2 solution" id="part-1-2-solution" class="wp-block-code"><code lang="java" class="language-java">// Game 1: 3 blue, 4 red; 1 red, 2 green, 6 blue; 2 green
static void day2(String puzzleInputUri) throws IOException, InterruptedException {
    Map&lt;String, Integer> bagOfCubes = Map.of("red", 12, "green", 13, "blue", 14);
    var games = client.send(request.uri((URI.create(puzzleInputUri))).build(),
                    HttpResponse.BodyHandlers.ofLines()).body()
            .map(game -> game.split(":", 2))
            .map(idAndResults -> Map.entry(
                    idAndResults[0].split(" ", 2)[1], // game id
                    idAndResults[1] // results string
            ))
            .map(idAndResults -> Map.entry(idAndResults.getKey(), idAndResults.getValue().split(";")))
            .map(idAndResults -> {
                List&lt;Map&lt;String, Integer>> parsedResults = new ArrayList&lt;>();
                for (String s : idAndResults.getValue()) {
                    Map&lt;String, Integer> cubesCount = new HashMap&lt;>();
                    for (String s1 : s.split(",")) {
                        String[] cubeCount = s1.trim().split(" ", 2);
                        cubesCount.put(cubeCount[1].trim(), Integer.parseInt(cubeCount[0].trim()));
                    }
                    parsedResults.add(cubesCount);
                }
                return Map.entry(idAndResults.getKey(), parsedResults);
            })
            .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));

    var answer1 = games.entrySet().stream()
            .filter(idAndResults -> idAndResults.getValue().stream()
                .flatMap(it -> it.entrySet().stream())
                .noneMatch(result -> result.getValue() > bagOfCubes.get(result.getKey()))
            )
            .mapToInt(idAndResults -> Integer.parseInt(idAndResults.getKey()))
            .sum();

    var answer2 = games.entrySet().stream()
            .map(idAndResults -> Map.entry(
                idAndResults.getKey(),
                idAndResults.getValue().stream()
                    .reduce((m1, m2) -> {
                        Map&lt;String, Integer> minRequired = new HashMap&lt;>();
                        bagOfCubes.keySet().forEach(cube -> minRequired.put(cube,
                            Math.max(m1.getOrDefault(cube, 0),
                                    m2.getOrDefault(cube, 0))
                        ));
                        return minRequired;
                    }).orElseThrow()
                )
            )
            .mapToInt(idAndMinRequired -> idAndMinRequired.getValue().values().stream()
                    .reduce((v1, v2) -> v1 * v2).orElseThrow() // v != 0 ? v : 1
            )
            .sum();

    System.out.println(answer1);
    System.out.println(answer2);
}</code></pre>



<p>Вид этой портянки мне не особо мил, особенно <code>for</code> внутри (<code>mapMulti</code> взамен?). Но и как-то значимо &#171;облагородить&#187; её не удалось с ходу &#8212; получалась куча менее понятных <code>map</code>, происходящее в которых сложно осознать уже через пару десятков минут.<br />А часики тикают, задачи требуют решений &#8212; и пора двигаться дальше!</p>



<pre class="wp-block-preformatted">https://adventofcode.com/2023/day/2</pre>



<div class="wp-block-buttons has-custom-font-size has-small-font-size is-content-justification-center is-nowrap is-layout-flex wp-container-core-buttons-is-layout-1fb9aab6 wp-block-buttons-is-layout-flex">
<div class="wp-block-button has-custom-width wp-block-button__width-100 is-style-outline is-style-outline--5"><a class="wp-block-button__link wp-element-button" href="https://t.me/panykey/139" target="_blank" rel="noreferrer noopener">Комментировать в TELEGRAM</a></div>
</div>
]]></content>
		
			</entry>
		<entry>
		<author>
			<name>dimio</name>
							<uri>http://dimio.org</uri>
						</author>

		<title type="html"><![CDATA[Advent of Code 2023: Day 1: Trebuchet?!]]></title>
		<link rel="alternate" type="text/html" href="https://dimio.org/advent-of-code-2023-day-1-trebuchet.html" />

		<id>https://dimio.org/?p=1996</id>
		<updated>2023-12-08T20:29:24Z</updated>
		<published>2023-12-08T10:12:59Z</published>
		<category scheme="https://dimio.org" term="Problem solving" /><category scheme="https://dimio.org" term="Кодинг" /><category scheme="https://dimio.org" term="adventofcode" /><category scheme="https://dimio.org" term="adventofcode-2023" /><category scheme="https://dimio.org" term="программирование" />
		<summary type="html"><![CDATA[Снова AoC &#8212; и снова начат с опозданием. Дуплет! Основная идея прежняя &#8212; решать в jshell, пока это не станет слишком многословным. Экономия на буковках, в общем. Обвязка для загрузки условий задачи &#8212; та же, что для AoC-2022. Тег для задачек 2023 года &#8212; adventofcode-2023 (или раздел Problem Solving). Первая часть загадки первого дня Достаточно &#8230; <a href="https://dimio.org/advent-of-code-2023-day-1-trebuchet.html" class="more-link">Читать далее <span class="screen-reader-text">Advent of Code 2023: Day 1: Trebuchet?!</span> <span class="meta-nav">&#8594;</span></a>]]></summary>

					<content type="html" xml:base="https://dimio.org/advent-of-code-2023-day-1-trebuchet.html"><![CDATA[
<p>Снова <a href="https://adventofcode.com/">AoC</a> &#8212; и снова начат с опозданием. Дуплет! Основная идея прежняя &#8212; решать в <code>jshell</code>, пока это не станет слишком многословным. Экономия на буковках, в общем.</p>



<p>Обвязка для загрузки условий задачи &#8212; <a href="https://dimio.org/advent-of-code-2022.html#aoc-jshell-helper">та же, что для AoC-2022</a>. Тег для задачек 2023 года &#8212; <a href="https://dimio.org/tag/adventofcode-2023">adventofcode-2023</a> (или раздел <a href="https://dimio.org/problem-solving">Problem Solving</a>).</p>



<span id="more-1996"></span>



<h2 class="wp-block-heading" id="day-1-part-1">Первая часть загадки первого дня</h2>



<p>Достаточно простое и короткое получилось решение, отлично сработало для первой части пазла &#8212; и практически никак не подошло для второй. Оставляю &#171;для истории&#187;.</p>



<pre title="AoC 2023 Day 1 Part 1 solution" id="part-1-solution" class="wp-block-code"><code lang="java" class="language-java">// Only part 1 solution
static void day1(String puzzleInputUri) throws IOException, InterruptedException {
    var result = client.send(request.uri((URI.create(puzzleInputUri))).build(), HttpResponse.BodyHandlers.ofLines()).body()
            .map(String::chars)
            .map(IntStream::boxed)
            .map(codePoints -&gt; {
                List&lt;String&gt; digits = codePoints
                        .filter(Character::isDigit)
                        .map(Character::toString)
                        .toList();
                return digits.getFirst() + digits.getLast();
            })
            .mapToInt(Integer::parseInt)
            .sum();
    System.out.println(result);
}</code></pre>



<h2 class="wp-block-heading">Часть вторая и универсальное решение</h2>



<p>Но совсем бесполезным решение для первой части назвать нельзя &#8212; оно легло в основу универсального решения.</p>



<pre title="AoC 2023 Day 1 universal solution" class="wp-block-code"><code lang="java" class="language-java">// Universal solution
static void day1(String puzzleInputUri) throws IOException, InterruptedException {
    Map&lt;String, String&gt; digits = Map.of(
            "1", "one",
            "2", "two",
            "3", "three",
            "4", "four",
            "5", "five",
            "6", "six",
            "7", "seven",
            "8", "eight",
            "9", "nine"
    );
    TreeMap&lt;Integer, String&gt; firstLast = new TreeMap&lt;&gt;();
    var result = client.send(request.uri((URI.create(puzzleInputUri))).build(), HttpResponse.BodyHandlers.ofLines()).body()
            .map(string -&gt; {
                firstLast.clear();
                digits.forEach((digit, numeric) -&gt; {
                        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);
}</code></pre>



<p>Жаль, что (для экономии буковок) &#8212; не удалось отыскать где-нибудь в недрах стандартной библиотеки готовых привязок цифр к числительным. Хотя и ожидаемо.</p>



<p>Загадка первого дня была не слишком сложной, но поначалу пошла туговато на фоне повседневного &#171;<a href="https://dimio.org/perekladyvaesh-zhysony-pssst-drug-smotri-syuda.html">перекладывания жысонов</a>&#171;.</p>



<p>Тем полезней переключаться! Участвуй!</p>



<pre class="wp-block-preformatted">https://adventofcode.com/2023/day/1</pre>



<div class="wp-block-buttons has-custom-font-size has-small-font-size is-content-justification-center is-nowrap is-layout-flex wp-container-core-buttons-is-layout-1fb9aab6 wp-block-buttons-is-layout-flex">
<div class="wp-block-button has-custom-width wp-block-button__width-100 is-style-outline is-style-outline--6"><a class="wp-block-button__link wp-element-button" href="https://t.me/panykey/138" target="_blank" rel="noreferrer noopener">Комментировать в TELEGRAM <img decoding="async" width="24" height="24" class="wp-image-1960" style="width: 24px;" src="https://dimio.org/wp-content/uploads/2023/07/telegram-svgrepo-com.png" alt="" srcset="https://dimio.org/wp-content/uploads/2023/07/telegram-svgrepo-com.png 256w, https://dimio.org/wp-content/uploads/2023/07/telegram-svgrepo-com-200x200.png 200w" sizes="(max-width: 24px) 100vw, 24px" /></a></div>
</div>
]]></content>
		
			</entry>
		<entry>
		<author>
			<name>dimio</name>
							<uri>http://dimio.org</uri>
						</author>

		<title type="html"><![CDATA[Spring: TLS/SSL подключение к RabbitMQ]]></title>
		<link rel="alternate" type="text/html" href="https://dimio.org/spring-tls-ssl-podklyuchenie-k-rabbitmq.html" />

		<id>https://dimio.org/?p=1987</id>
		<updated>2024-08-01T09:31:13Z</updated>
		<published>2023-11-22T13:53:36Z</published>
		<category scheme="https://dimio.org" term="Кодинг" /><category scheme="https://dimio.org" term="Памятки" /><category scheme="https://dimio.org" term="amqp" /><category scheme="https://dimio.org" term="java" /><category scheme="https://dimio.org" term="rabbitmq" /><category scheme="https://dimio.org" term="tls/ssl" />
		<summary type="html"><![CDATA[Возникла потребность подключаться из Java приложения к брокеру RabbitMQ с использованием защищенного соединения. Приложение на Spring Boot, живёт в контейнере Docker и должно слушать два узла Rabbit параллельно. Команды для создания KeyStore и TrustStore Настройки вынесены в переменные в начале списка команд, можно заполнить значения и скопировать всё в консоль целиком. Это создаст хранилища с &#8230; <a href="https://dimio.org/spring-tls-ssl-podklyuchenie-k-rabbitmq.html" class="more-link">Читать далее <span class="screen-reader-text">Spring: TLS/SSL подключение к RabbitMQ</span> <span class="meta-nav">&#8594;</span></a>]]></summary>

					<content type="html" xml:base="https://dimio.org/spring-tls-ssl-podklyuchenie-k-rabbitmq.html"><![CDATA[
<p>Возникла потребность подключаться из Java приложения к брокеру RabbitMQ с использованием защищенного соединения. Приложение на Spring Boot, живёт в контейнере Docker и должно слушать два узла Rabbit параллельно.</p>



<ul class="wp-block-list">
<li>На входе: сертификат клиентского узла &#8212; контейнер <em>client-cert.pfx</em>, корневой сертификат для него <em>root-cert.crt</em></li>



<li>Открытый серверный сертификат шлюза Rabbit: выкачивается автоматически (можно подложить вручную)</li>



<li>Используемая версия java поддерживает форматы хранилищ и JKS, и PKCS12</li>



<li>Требуется: создать и положить сертификаты в Key Store (сертификаты приложения &#171;клиентские&#187;) и Trust Store (доверенные &#171;серверные&#187; сертификаты). <a href="https://www.baeldung.com/java-keystore-truststore-difference">В чём разница.</a></li>
</ul>



<span id="more-1987"></span>



<h2 class="wp-block-heading">Команды для создания KeyStore и TrustStore</h2>



<p>Настройки вынесены в переменные в начале списка команд, можно заполнить значения и скопировать всё в консоль целиком.</p>



<pre class="wp-block-code"><code lang="bash" class="language-bash">export CLIENT_APP_CRT_NAME=client-cert;
# Пароль, заданный при выпуске клиентского сертификата
# Он же используется в кач-ве пароля для хранилищ
export CRT_STORAGES_PASSWORD='changeit';
export RABBIT_GATEWAY_CRT_NAME=rabbit-gw-dev;
export RABBIT_GATEWAY_URL=rabbit-gw-dev.url;
export RABBIT_GATEWAY_PORT=1234;
export ROOT_CRT_NAME=root-cert;

# Извлечь ключ pem и сертификат crt из pfx
openssl pkcs12 -in "${CLIENT_APP_CRT_NAME}".pfx -passin pass:"${CRT_STORAGES_PASSWORD}" -nocerts -nodes -out "${CLIENT_APP_CRT_NAME}".pem;
openssl pkcs12 -in "${CLIENT_APP_CRT_NAME}".pfx -passin pass:"${CRT_STORAGES_PASSWORD}" -clcerts -nokeys -out "${CLIENT_APP_CRT_NAME}".crt;

# Key Store (сертификат приложения)
openssl pkcs12 -export -in "${CLIENT_APP_CRT_NAME}".crt -inkey "${CLIENT_APP_CRT_NAME}".pem \
 -out "${RABBIT_GATEWAY_CRT_NAME}"_key_store.p12 -name "${RABBIT_GATEWAY_CRT_NAME}" -passout pass:"${CRT_STORAGES_PASSWORD}" \
 -CAfile "${ROOT_CRT_NAME}".crt -caname root;

# Trust Store (сертификат шлюза)
keytool -import -alias "${RABBIT_GATEWAY_URL}"_client -file "${CLIENT_APP_CRT_NAME}".crt -keystore "${RABBIT_GATEWAY_CRT_NAME}"_trust_store.jks \
 -noprompt -deststorepass "${CRT_STORAGES_PASSWORD}";
openssl s_client -showcerts -connect "${RABBIT_GATEWAY_URL}":"${RABBIT_GATEWAY_PORT}" -prexit 2&gt;/dev/null | sed -n -e '/BEGIN\ CERTIFICATE/,/END\ CERTIFICATE/ p' \
 | tee "${RABBIT_GATEWAY_URL}".cert \
&amp;&amp; keytool -import -alias "${RABBIT_GATEWAY_URL}"_server -file "${RABBIT_GATEWAY_URL}".cert -keystore "${RABBIT_GATEWAY_CRT_NAME}"_trust_store.jks \
 -noprompt -deststorepass "${CRT_STORAGES_PASSWORD}";

unset CLIENT_APP_CRT_NAME;
unset CRT_STORAGES_PASSWORD;
unset RABBIT_GATEWAY_CRT_NAME;
unset RABBIT_GATEWAY_URL;
unset RABBIT_GATEWAY_PORT;
unset ROOT_CRT_NAME;</code></pre>



<p>Это создаст хранилища с сертификатами KeyStore и TrustStore: <code>rabbit-gw-dev_key_store.p12</code> и <code>rabbit-gw-dev_trust_store.jks</code></p>



<h2 class="wp-block-heading">Копирование хранилищ в образ Docker</h2>



<p>Хранилища лежат в репозитории, в каталоге <code>keystore</code>, и копируются в контейнер &#8212; также в каталог <code>keystore</code>, расположенный в папке приложения.</p>



<pre class="wp-block-code"><code lang="docker" class="language-docker">ADD app-repository/keystore/rabbit-gw-dev_key_store.p12 /app-in-container/keystore/rabbit-gw-dev_key_store.p12
ADD app-repository/keystore/rabbit-gw-dev_trust_store.jks /app-in-container/keystore/rabbit-gw-dev_trust_store.jks
ENV SSL_KEYSTORE=/app-in-container/keystore/</code></pre>



<p>Через переменную <code>SSL_KEYSTORE</code> можно сослаться на каталог с хранилищами ключей, расположенный в контейнере, из настроек приложения.</p>



<h2 class="wp-block-heading">Включение TLS для RabbitMQ в Spring Boot</h2>



<p>Выдержка из <em>application.yml</em> с настройками, отвечающими за TLS/SSL:</p>



<pre title="Spring Boot RabbitMQ TLS/SSL config" class="wp-block-code"><code lang="yaml" class="language-yaml">spring:
  rabbitmq:
    # &lt;-- host, port, username, password
    ssl:
      enabled: true
      keyStore: file:${SSL_KEYSTORE}${RABBIT_SSL_KEY_STORE}
      key-store-password: ${RABBIT_SSL_KEY_STORE_PASSWORD}
      trust-store: file:${SSL_KEYSTORE}${RABBIT_SSL_TRUST_STORE}
      trust-store-password: ${RABBIT_SSL_TRUST_STORE_PASSWORD}
  multirabbitmq:
    enabled: true
    connections:
      reserve-gateway:
        # &lt;-- host, port, username, password
        ssl:
          enabled: ${spring.rabbitmq.ssl.enabled}
          keyStore: ${spring.rabbitmq.ssl.keyStore}
          key-store-password: ${spring.rabbitmq.ssl.key-store-password}
          trust-store: ${spring.rabbitmq.ssl.trust-store}
          trust-store-password: ${spring.rabbitmq.ssl.trust-store-password}</code></pre>



<p>Дополнительно здесь используется <a href="https://mvnrepository.com/artifact/com.free-now.multirabbit/spring-multirabbit">Spring MultiRabbit Library</a> для одновременного подключения к нескольким узлам RabbitMQ. Чтобы вручную <code>СontainerFactory</code>/<code>RabbitTemplate</code> для слушателей не создавать/настраивать.</p>



<p>Ранее <a href="https://dimio.org/rabbitmq-container-wrapper.html">писал про обертку для Testcontainers</a>, в которой тоже используется эта библиотека.</p>



<p>Дополнительно &#8212; в документации RabbitMQ <a href="https://www.rabbitmq.com/ssl.html#java-client">описано TLS подключение &#171;голого&#187; java client из кода</a>, без использования Spring.</p>



<h2 class="wp-block-heading">Итог и дополнительные ссылки</h2>



<p>В целом &#8212; всё оказалось несложно (когда один раз проделаешь этот путь). Основная &#171;проблема&#187; &#8212; правильно создать KeyStore и TrustStore с сертификатами. Ну и базово понять разницу межу типами хранилищ KeyStore / TrustStore.</p>



<p><em>Ссылки по теме (глубже в теорию):</em></p>



<ul class="wp-block-list">
<li><a href="https://docs.oracle.com/en/java/javase/11/security/java-secure-socket-extension-jsse-reference-guide.html#GUID-93DEEE16-0B70-40E5-BBE7-55C3FD432345">Java Secure Socket Extension (JSSE) Reference Guide</a></li>



<li><a href="https://www.rfc-editor.org/rfc/rfc5246">The Transport Layer Security (TLS) Protocol RFC</a></li>
</ul>



<div class="wp-block-buttons has-custom-font-size has-small-font-size is-content-justification-center is-nowrap is-layout-flex wp-container-core-buttons-is-layout-1fb9aab6 wp-block-buttons-is-layout-flex">
<div class="wp-block-button has-custom-width wp-block-button__width-100 has-custom-font-size is-style-outline has-small-font-size is-style-outline--7"><a class="wp-block-button__link has-black-color has-green-background-color has-text-color has-background has-link-color wp-element-button" href="https://t.me/panykey/137" target="_blank" rel="noreferrer noopener">Комментировать в TELEGRAM</a></div>
</div>
]]></content>
		
					<link rel="replies" type="text/html" href="https://dimio.org/spring-tls-ssl-podklyuchenie-k-rabbitmq.html#comments" thr:count="0" />
			<link rel="replies" type="application/atom+xml" href="https://dimio.org/spring-tls-ssl-podklyuchenie-k-rabbitmq.html/feed/atom" thr:count="0" />
			<thr:total>0</thr:total>
			</entry>
		<entry>
		<author>
			<name>dimio</name>
							<uri>http://dimio.org</uri>
						</author>

		<title type="html"><![CDATA[Перекладываешь жысоны? Пссст, друг, смотри сюда!]]></title>
		<link rel="alternate" type="text/html" href="https://dimio.org/perekladyvaesh-zhysony-pssst-drug-smotri-syuda.html" />

		<id>https://dimio.org/?p=1951</id>
		<updated>2024-08-01T09:29:51Z</updated>
		<published>2023-07-18T06:29:18Z</published>
		<category scheme="https://dimio.org" term="Кодинг" /><category scheme="https://dimio.org" term="Полезности" /><category scheme="https://dimio.org" term="idea" /><category scheme="https://dimio.org" term="java" /><category scheme="https://dimio.org" term="json" />
		<summary type="html"><![CDATA[Не знаю, как я раньше жил без этих плагинов… Да нормально жил, но утомлялся точно больше. Не скажу даже вот так сразу, какой из них полезней. Остановлюсь на каждом чуть подробней. RoboPOJOGenerator Пожалуй, всё же &#8212; генератор классов POJO из JSON. Копипастишь прямо из документации &#8212; ВЖУХ! И ни фига! Сначала надо засунуть в insomnia &#8230; <a href="https://dimio.org/perekladyvaesh-zhysony-pssst-drug-smotri-syuda.html" class="more-link">Читать далее <span class="screen-reader-text">Перекладываешь жысоны? Пссст, друг, смотри сюда!</span> <span class="meta-nav">&#8594;</span></a>]]></summary>

					<content type="html" xml:base="https://dimio.org/perekladyvaesh-zhysony-pssst-drug-smotri-syuda.html"><![CDATA[
<p>Не знаю, как я раньше жил без этих плагинов…</p>


<div class="wp-block-image">
<figure class="aligncenter size-large"><img decoding="async" width="510" height="186" src="https://dimio.org/wp-content/uploads/2023/07/izobrazhenie-510x186.png" alt="" class="wp-image-1955" srcset="https://dimio.org/wp-content/uploads/2023/07/izobrazhenie-510x186.png 510w, https://dimio.org/wp-content/uploads/2023/07/izobrazhenie-400x146.png 400w, https://dimio.org/wp-content/uploads/2023/07/izobrazhenie-200x73.png 200w, https://dimio.org/wp-content/uploads/2023/07/izobrazhenie.png 737w" sizes="(max-width: 510px) 100vw, 510px" /></figure>
</div>


<p>Да нормально жил, но утомлялся точно больше. Не скажу даже вот так сразу, какой из них полезней. Остановлюсь на каждом чуть подробней.</p>



<span id="more-1951"></span>



<h2 class="wp-block-heading">RoboPOJOGenerator</h2>



<p>Пожалуй, всё же &#8212; генератор классов POJO из JSON.</p>


<div class="wp-block-image">
<figure class="aligncenter size-large"><img loading="lazy" decoding="async" width="510" height="215" src="https://dimio.org/wp-content/uploads/2023/07/izobrazhenie-1-510x215.png" alt="" class="wp-image-1956" srcset="https://dimio.org/wp-content/uploads/2023/07/izobrazhenie-1-510x215.png 510w, https://dimio.org/wp-content/uploads/2023/07/izobrazhenie-1-400x169.png 400w, https://dimio.org/wp-content/uploads/2023/07/izobrazhenie-1-200x84.png 200w, https://dimio.org/wp-content/uploads/2023/07/izobrazhenie-1-768x324.png 768w, https://dimio.org/wp-content/uploads/2023/07/izobrazhenie-1.png 839w" sizes="auto, (max-width: 510px) 100vw, 510px" /></figure>
</div>


<p>Копипастишь прямо из документации &#8212; ВЖУХ! И ни фига! Сначала надо засунуть в insomnia (ну или postman, или http клиент в идее &#8212; кому что привычней) и проверить, что json не кривой. Зато потом &#8212; магия срабатывает в полный рост.</p>



<p>Все эти тысячи полей, вложенных структур &#8212; уже не надо сидеть, уныло создавая и перенося руками. Чуть подправить там да сям разные мелочи в конце.</p>



<h2 class="wp-block-heading">POJO to JSON</h2>



<p><br />Обратный генератор POJO в JSON пригождается реже, но когда пригождается &#8212; очень удобен.</p>


<div class="wp-block-image">
<figure class="aligncenter size-large"><img loading="lazy" decoding="async" width="430" height="510" src="https://dimio.org/wp-content/uploads/2023/07/izobrazhenie-2-430x510.png" alt="" class="wp-image-1957" srcset="https://dimio.org/wp-content/uploads/2023/07/izobrazhenie-2-430x510.png 430w, https://dimio.org/wp-content/uploads/2023/07/izobrazhenie-2-337x400.png 337w, https://dimio.org/wp-content/uploads/2023/07/izobrazhenie-2-169x200.png 169w, https://dimio.org/wp-content/uploads/2023/07/izobrazhenie-2.png 604w" sizes="auto, (max-width: 430px) 100vw, 430px" /></figure>
</div>


<p>Он может набить json случайными данными с нужными типами. Дальше можно сразу сунуть готовый json в запрос, или скинуть на обсуждение.</p>



<h2 class="wp-block-heading">Теперь это в прошлом &#8212;</h2>



<p> копирование полей по одному из документации в DTO и сочинение примеров запросов.</p>



<p>Слава роботам!</p>



<div class="wp-block-buttons has-custom-font-size has-small-font-size is-content-justification-center is-nowrap is-layout-flex wp-container-core-buttons-is-layout-1fb9aab6 wp-block-buttons-is-layout-flex">
<div class="wp-block-button has-custom-width wp-block-button__width-100 has-custom-font-size is-style-fill has-small-font-size"><a class="wp-block-button__link has-black-color has-green-background-color has-text-color has-background has-link-color wp-element-button" href="https://t.me/panykey/110" target="_blank" rel="noreferrer noopener">Комментировать в телеге <img loading="lazy" decoding="async" width="24" height="24" class="wp-image-1960" style="width: 24px;" src="https://dimio.org/wp-content/uploads/2023/07/telegram-svgrepo-com.png" alt="" srcset="https://dimio.org/wp-content/uploads/2023/07/telegram-svgrepo-com.png 256w, https://dimio.org/wp-content/uploads/2023/07/telegram-svgrepo-com-200x200.png 200w" sizes="auto, (max-width: 24px) 100vw, 24px" /></a></div>
</div>
]]></content>
		
			</entry>
		<entry>
		<author>
			<name>dimio</name>
							<uri>http://dimio.org</uri>
						</author>

		<title type="html"><![CDATA[Git хук для запуска тестов]]></title>
		<link rel="alternate" type="text/html" href="https://dimio.org/git-huk-dlya-zapuska-testov.html" />

		<id>https://dimio.org/?p=1932</id>
		<updated>2023-07-18T09:49:03Z</updated>
		<published>2023-07-03T17:02:15Z</published>
		<category scheme="https://dimio.org" term="Кодинг" /><category scheme="https://dimio.org" term="Полезности" /><category scheme="https://dimio.org" term="bash" /><category scheme="https://dimio.org" term="git" /><category scheme="https://dimio.org" term="java" /><category scheme="https://dimio.org" term="notes" />
		<summary type="html"><![CDATA[Есть у меня такой pre-push хук &#8212; автоматом прогоняет тесты локально, через maven. Подключается по необходимости через отдельные git конфиги для проектов. Стащил его, судя по всему, отсюда: https://gist.github.com/arnobroekhof/9454645. Потом допиливал немного &#8212; чтобы он с многомодульными проектами работал корректно. Может, ещё что-то по мелочи причёсывал. И он отлично работает (разве что можно через sed &#8230; <a href="https://dimio.org/git-huk-dlya-zapuska-testov.html" class="more-link">Читать далее <span class="screen-reader-text">Git хук для запуска тестов</span> <span class="meta-nav">&#8594;</span></a>]]></summary>

					<content type="html" xml:base="https://dimio.org/git-huk-dlya-zapuska-testov.html"><![CDATA[
<div class="wp-block-media-text alignwide is-stacked-on-mobile"><figure class="wp-block-media-text__media"><a href="https://dimio.org/wp-content/uploads/2023/07/image.png"><img loading="lazy" decoding="async" width="510" height="384" src="https://dimio.org/wp-content/uploads/2023/07/image-510x384.png" alt="" class="wp-image-1935 size-full" srcset="https://dimio.org/wp-content/uploads/2023/07/image-510x384.png 510w, https://dimio.org/wp-content/uploads/2023/07/image-400x301.png 400w, https://dimio.org/wp-content/uploads/2023/07/image-200x150.png 200w, https://dimio.org/wp-content/uploads/2023/07/image-768x578.png 768w, https://dimio.org/wp-content/uploads/2023/07/image.png 1020w" sizes="auto, (max-width: 510px) 100vw, 510px" /></a></figure><div class="wp-block-media-text__content">
<p>Есть у меня такой <code>pre-push</code> хук &#8212; автоматом прогоняет тесты локально, через <code>maven</code>. Подключается по необходимости <a href="https://t.me/panykey/68">через отдельные git конфиги для проектов</a>.</p>
</div></div>



<span id="more-1932"></span>



<pre class="wp-block-code"><code lang="bash" class="language-bash">#!/bin/env bash
set -eu

# https://gist.github.com/arnobroekhof/9454645
# save the file as &lt;git_directory&gt;/.git/hooks/pre-&lt;commit|push&gt; 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&gt;&amp;1)
if [ $? -ne 0 ]; then
  echo
  echo "${MVN_RESULT}" | ((tee /dev/fd/5 | grep -A 10 -B 2 "Summary:" &gt; /dev/fd/4) 5&gt;&amp;1 | sed -n -e '/^Failed tests:/,/Tests run:.*$/ p' ) 4&gt;&amp;1
  echo
  echo "Error while testing the code"
  cd "${CWD}"
  exit 1
fi
cd "${CWD}"</code></pre>



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



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



<p>Но вот проблема &#8212; на текущем проекте везде <code>gradle</code>, а под него я что-то не могу найти похожего простого решения <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f641.png" alt="🙁" class="wp-smiley" style="height: 1em; max-height: 1em;" /></p>



<p><mark>Есть ли оно?</mark></p>



<div class="wp-block-buttons has-custom-font-size has-small-font-size is-content-justification-center is-nowrap is-layout-flex wp-container-core-buttons-is-layout-1fb9aab6 wp-block-buttons-is-layout-flex">
<div class="wp-block-button has-custom-width wp-block-button__width-100 is-style-outline is-style-outline--8"><a class="wp-block-button__link wp-element-button" href="https://t.me/panykey/99" target="_blank" rel="noreferrer noopener">Комментировать в телеге <img loading="lazy" decoding="async" width="24" height="24" class="wp-image-1960" style="width: 24px;" src="https://dimio.org/wp-content/uploads/2023/07/telegram-svgrepo-com.png" alt="" srcset="https://dimio.org/wp-content/uploads/2023/07/telegram-svgrepo-com.png 256w, https://dimio.org/wp-content/uploads/2023/07/telegram-svgrepo-com-200x200.png 200w" sizes="auto, (max-width: 24px) 100vw, 24px" /></a></div>
</div>
]]></content>
		
			</entry>
		<entry>
		<author>
			<name>dimio</name>
							<uri>http://dimio.org</uri>
						</author>

		<title type="html"><![CDATA[Как связать контейнеры Docker в одну сеть]]></title>
		<link rel="alternate" type="text/html" href="https://dimio.org/kak-sviazat-konteyneri-docker-v-odnu-set.html" />

		<id>https://dimio.org/?p=1924</id>
		<updated>2023-06-29T16:00:47Z</updated>
		<published>2023-06-29T11:10:52Z</published>
		<category scheme="https://dimio.org" term="Кодинг" /><category scheme="https://dimio.org" term="Памятки" /><category scheme="https://dimio.org" term="docker" /><category scheme="https://dimio.org" term="huginn" /><category scheme="https://dimio.org" term="notes" /><category scheme="https://dimio.org" term="программирование" />
		<summary type="html"><![CDATA[Очень легко и удобно оказалось в Докере (compose) связывать сети. Раньше сервисы обычно пихал в один compose-файл (или, точнее, лень было разделять специально &#8212; как шли &#171;из коробки&#187; &#8212; так и запускались). Но стало неудобно. Совсем неудобно стало, что каждый норовит себе отдельную БД поднять соседним контейнером. И всё равно приходится лезть, и монтирование данных &#8230; <a href="https://dimio.org/kak-sviazat-konteyneri-docker-v-odnu-set.html" class="more-link">Читать далее <span class="screen-reader-text">Как связать контейнеры Docker в одну сеть</span> <span class="meta-nav">&#8594;</span></a>]]></summary>

					<content type="html" xml:base="https://dimio.org/kak-sviazat-konteyneri-docker-v-odnu-set.html"><![CDATA[
<p>Очень легко и удобно оказалось в Докере (<em>compose</em>) связывать сети. Раньше сервисы обычно пихал в один <em>compose</em>-файл (или, точнее, лень было разделять специально &#8212; как шли &#171;из коробки&#187; &#8212; так и запускались).</p>


<div class="wp-block-image">
<figure class="aligncenter size-large"><a href="https://dimio.org/wp-content/uploads/2023/06/photo_2023-06-28_08-42-53.jpg"><img loading="lazy" decoding="async" width="510" height="223" src="https://dimio.org/wp-content/uploads/2023/06/photo_2023-06-28_08-42-53-510x223.jpg" alt="" class="wp-image-1929" srcset="https://dimio.org/wp-content/uploads/2023/06/photo_2023-06-28_08-42-53-510x223.jpg 510w, https://dimio.org/wp-content/uploads/2023/06/photo_2023-06-28_08-42-53-400x175.jpg 400w, https://dimio.org/wp-content/uploads/2023/06/photo_2023-06-28_08-42-53-200x87.jpg 200w, https://dimio.org/wp-content/uploads/2023/06/photo_2023-06-28_08-42-53-768x336.jpg 768w, https://dimio.org/wp-content/uploads/2023/06/photo_2023-06-28_08-42-53.jpg 908w" sizes="auto, (max-width: 510px) 100vw, 510px" /></a></figure>
</div>


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



<span id="more-1924"></span>



<h2 class="wp-block-heading">Первый сервис (у меня &#8212; БД), в docker-compose:</h2>



<pre class="wp-block-code"><code lang="yaml" class="language-yaml">version: "3.5"
services:
  postgres:
    container_name: pglocal
    # лишнее пропущено
    networks:
      - postgres
networks:
  postgres:
    driver: bridge
    name: postgres_net</code></pre>



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



<h2 class="wp-block-heading">Второй сервис (<a href="https://dimio.org/huginn-yahoo-pipes-habr-i-fid-lenty-kommentariev.html">автоматизация huginn</a>):</h2>



<pre class="wp-block-code"><code lang="yaml" class="language-yaml">version: "2"
services:
  huginn:
    container_name: huginn
    environment:
      - POSTGRES_PORT_5432_TCP_ADDR=pglocal
    # лишнее пропущено
    networks:
      - huginn
networks:
  huginn:
    external:
      name: postgres_net</code></pre>



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


<div class="wp-block-image">
<figure class="aligncenter size-large"><a href="https://dimio.org/wp-content/uploads/2023/06/photo_2023-06-28_08-42-53-2.jpg"><img loading="lazy" decoding="async" width="510" height="136" src="https://dimio.org/wp-content/uploads/2023/06/photo_2023-06-28_08-42-53-2-510x136.jpg" alt="" class="wp-image-1930" srcset="https://dimio.org/wp-content/uploads/2023/06/photo_2023-06-28_08-42-53-2-510x136.jpg 510w, https://dimio.org/wp-content/uploads/2023/06/photo_2023-06-28_08-42-53-2-400x107.jpg 400w, https://dimio.org/wp-content/uploads/2023/06/photo_2023-06-28_08-42-53-2-200x53.jpg 200w, https://dimio.org/wp-content/uploads/2023/06/photo_2023-06-28_08-42-53-2-768x205.jpg 768w, https://dimio.org/wp-content/uploads/2023/06/photo_2023-06-28_08-42-53-2.jpg 1280w" sizes="auto, (max-width: 510px) 100vw, 510px" /></a></figure>
</div>


<p>Минус вижу &#8212; порядок ожидания нужных служб сделать посложней, чем с <code>depends_on</code> и службами в одном файле.</p>



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



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



<p><a href="https://t.me/panykey/92">Читать в телеграм</a>.</p>
]]></content>
		
					<link rel="replies" type="text/html" href="https://dimio.org/kak-sviazat-konteyneri-docker-v-odnu-set.html#comments" thr:count="0" />
			<link rel="replies" type="application/atom+xml" href="https://dimio.org/kak-sviazat-konteyneri-docker-v-odnu-set.html/feed/atom" thr:count="0" />
			<thr:total>0</thr:total>
			</entry>
		<entry>
		<author>
			<name>dimio</name>
							<uri>http://dimio.org</uri>
						</author>

		<title type="html"><![CDATA[Преданье старины глубокой]]></title>
		<link rel="alternate" type="text/html" href="https://dimio.org/predane-stariny-glubokoj.html" />

		<id>https://dimio.org/?p=1918</id>
		<updated>2023-06-23T07:37:24Z</updated>
		<published>2023-06-23T07:37:23Z</published>
		<category scheme="https://dimio.org" term="Отдых" /><category scheme="https://dimio.org" term="жизненное" /><category scheme="https://dimio.org" term="отдых" /><category scheme="https://dimio.org" term="путешествия" /><category scheme="https://dimio.org" term="театр" />
		<summary type="html"><![CDATA[Довелось недавно, оказавшись на задворках Москвы, сходить в любопытный театр (Этнотеатр) на не менее любопытный спектакль &#8212; Комедия о Фроле Скобееве. Современная постановка сделана по пьесе конца XIX века, а та, в свою очередь, написана по произведению века XVII (или начала XVIII, тут мнения расходятся). Чтобы грамотно написать цифры веков &#8212; весьма кстати пришлась задачка &#8230; <a href="https://dimio.org/predane-stariny-glubokoj.html" class="more-link">Читать далее <span class="screen-reader-text">Преданье старины глубокой</span> <span class="meta-nav">&#8594;</span></a>]]></summary>

					<content type="html" xml:base="https://dimio.org/predane-stariny-glubokoj.html"><![CDATA[
<p>Довелось недавно, оказавшись на задворках Москвы, сходить в любопытный театр (Этнотеатр) на не менее любопытный спектакль &#8212; <a rel="noreferrer noopener" href="https://etnoteatr.ru/shows/12" target="_blank">Комедия о Фроле Скобееве</a>.</p>


<div class="wp-block-image">
<figure class="aligncenter size-large"><a href="https://dimio.org/wp-content/uploads/2023/06/izobrazhenie-1.png"><img loading="lazy" decoding="async" width="510" height="319" src="https://dimio.org/wp-content/uploads/2023/06/izobrazhenie-1-510x319.png" alt="" class="wp-image-1919" srcset="https://dimio.org/wp-content/uploads/2023/06/izobrazhenie-1-510x319.png 510w, https://dimio.org/wp-content/uploads/2023/06/izobrazhenie-1-400x250.png 400w, https://dimio.org/wp-content/uploads/2023/06/izobrazhenie-1-200x125.png 200w, https://dimio.org/wp-content/uploads/2023/06/izobrazhenie-1-768x480.png 768w, https://dimio.org/wp-content/uploads/2023/06/izobrazhenie-1.png 1280w" sizes="auto, (max-width: 510px) 100vw, 510px" /></a><figcaption class="wp-element-caption">Фото с etnoteatr.ru</figcaption></figure>
</div>


<p>Современная постановка сделана по <a href="http://az.lib.ru/a/awerkiew_d_w/text_0090.shtml" target="_blank" rel="noreferrer noopener">пьесе</a> конца <em>XIX</em> века, а та, в свою очередь, написана по <a rel="noreferrer noopener" href="https://www.krugosvet.ru/enc/kultura_i_obrazovanie/literatura/POVEST_O_FROLE_SKOBEEVE.html" target="_blank">произведению</a> века <em>XVII</em> (или начала <em>XVIII</em>, тут мнения расходятся).</p>



<span id="more-1918"></span>



<figure class="wp-block-pullquote" style="font-size:12px;font-style:normal;font-weight:100"><blockquote><p>Чтобы грамотно написать цифры веков &#8212; весьма кстати пришлась <a href="https://dimio.org/leetcode-13-roman-to-integer.html">задачка Roman to Integer</a>  &#8212; подсмотрел в ней префиксы для записи <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f600.png" alt="😀" class="wp-smiley" style="height: 1em; max-height: 1em;" /></p></blockquote></figure>



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



<ul class="wp-block-list">
<li>И факт старинности основы спектакля (русский театр, всё же, в массе известен века с двадцатого).</li>



<li>И подход, который нашёл постановщик к  подаче действа &#8212; сцена в виде этакой балаганной карусели &#8212; здорово добавляет антуража.</li>



<li>И костюмы проработаны, и игра цепляет, и &#171;осовремененено&#187; совсем каплю и в меру &#8212; &#171;виной&#187; тому, видимо, этнографичность и историчность театра <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f642.png" alt="🙂" class="wp-smiley" style="height: 1em; max-height: 1em;" /></li>
</ul>



<p>Тем более, что у себя, в Питере, я подобного сочетания не обнаружил, да и в принципе постановок по этой пьесе не встретил. <strong>Рекомендую!</strong></p>
]]></content>
		
					<link rel="replies" type="text/html" href="https://dimio.org/predane-stariny-glubokoj.html#comments" thr:count="0" />
			<link rel="replies" type="application/atom+xml" href="https://dimio.org/predane-stariny-glubokoj.html/feed/atom" thr:count="0" />
			<thr:total>0</thr:total>
			</entry>
		<entry>
		<author>
			<name>dimio</name>
							<uri>http://dimio.org</uri>
						</author>

		<title type="html"><![CDATA[LibreOffice Calc &#8212; трюки работы с таблицей]]></title>
		<link rel="alternate" type="text/html" href="https://dimio.org/libreoffice-calc-tryuki-raboty-s-tabliczej.html" />

		<id>https://dimio.org/?p=1897</id>
		<updated>2023-06-21T06:57:41Z</updated>
		<published>2023-06-16T18:53:47Z</published>
		<category scheme="https://dimio.org" term="Памятки" /><category scheme="https://dimio.org" term="Полезности" /><category scheme="https://dimio.org" term="*office" /><category scheme="https://dimio.org" term="libreoffice" /><category scheme="https://dimio.org" term="notes" /><category scheme="https://dimio.org" term="трюки" />
		<summary type="html"><![CDATA[Накопилось ещё некоторое количество &#171;приёмчиков&#187; работы с Open/Libre Office. Если предыдущая заметка на эту тему была посвящена LO Writer, то на сей раз &#8212; &#171;подопытным&#187; выступает пакет Calc (электронные таблицы). Для затравки &#8212; простое, но часто нужное действие &#8212; перемещение строк и столбцов таблицы. Перемещение столбцов / строк Изменение типа данных ячеек Эту операцию удобно &#8230; <a href="https://dimio.org/libreoffice-calc-tryuki-raboty-s-tabliczej.html" class="more-link">Читать далее <span class="screen-reader-text">LibreOffice Calc &#8212; трюки работы с таблицей</span> <span class="meta-nav">&#8594;</span></a>]]></summary>

					<content type="html" xml:base="https://dimio.org/libreoffice-calc-tryuki-raboty-s-tabliczej.html"><![CDATA[
<p>Накопилось ещё некоторое количество &#171;приёмчиков&#187; работы с <a href="https://dimio.org/libreoffice-udobstvo-i-prostota.html">Open/Libre Office</a>. Если предыдущая заметка на эту тему <a href="https://dimio.org/avtonumeraciya-strok-tablicy-v-libreoffice-writer.html">была посвящена LO Writer</a>, то на сей раз &#8212; &#171;подопытным&#187; выступает пакет <em>Calc</em> (электронные таблицы).</p>



<p>Для затравки &#8212; простое, но часто нужное действие &#8212; перемещение строк и столбцов таблицы.</p>



<span id="more-1897"></span>



<h2 class="wp-block-heading">Перемещение столбцов / строк</h2>



<ol class="wp-block-list">
<li>Выделить нужный диапазон при помощи выделения всего столбца/строки (для этого можно щелкнуть ЛКМ на заголовок столбца/строки).</li>



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



<li>Тащить мышью диапазон, затем при отпускании:
<ul class="wp-block-list">
<li>Перезапишет тот диапазон ячеек, на который был перетащен</li>



<li>При зажатом <code>Alt</code> &#8212; поменяет диапазоны ячеек местами</li>
</ul>
</li>
</ol>


<div class="wp-block-image">
<figure class="aligncenter size-large"><a href="https://dimio.org/wp-content/uploads/2023/06/libreoffice-calc-swap-columns.gif"><img loading="lazy" decoding="async" width="510" height="286" src="https://dimio.org/wp-content/uploads/2023/06/libreoffice-calc-swap-columns-510x286.gif" alt="" class="wp-image-1899" srcset="https://dimio.org/wp-content/uploads/2023/06/libreoffice-calc-swap-columns-510x286.gif 510w, https://dimio.org/wp-content/uploads/2023/06/libreoffice-calc-swap-columns-400x224.gif 400w" sizes="auto, (max-width: 510px) 100vw, 510px" /></a><figcaption class="wp-element-caption">LibreOffice Calc: поменять местами столбцы (запуск анимации по клику)</figcaption></figure>
</div>


<h2 class="wp-block-heading">Изменение типа данных ячеек</h2>



<ol class="wp-block-list">
<li>Выделить нужный диапазон ячеек (или весь столбец/строку целиком по клику на заголовок).</li>



<li>Верхнее меню: <em>Данные -&gt; Текст по столбцам</em>.</li>



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



<li>Выбрать тип столбца &#8212; Ок.</li>
</ol>



<p>Эту операцию удобно проиллюстрировать примером: есть столбец с датами, которые хранятся, как текст (т.е. тип данных внутри офиса у них &#8212; текстовый, такое часто встречается при работе с кривыми выгрузками для Экселя). Использование меню <em>Формат &#8212; Формат чисел &#8212; Дата</em> не поможет в данном случае, т.к. дата хранится в виде строки <code><mark>'2023-06-16</mark></code>.</p>


<div class="wp-block-image">
<figure class="aligncenter size-full"><a href="https://dimio.org/wp-content/uploads/2023/06/izobrazhenie.png"><img loading="lazy" decoding="async" width="346" height="117" src="https://dimio.org/wp-content/uploads/2023/06/izobrazhenie.png" alt="" class="wp-image-1900"/></a></figure>
</div>


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


<div class="wp-block-image">
<figure class="aligncenter size-large"><a href="https://dimio.org/wp-content/uploads/2023/06/libreoffice-calc-change-data-type-parse-text-to-date.gif"><img loading="lazy" decoding="async" width="510" height="399" src="https://dimio.org/wp-content/uploads/2023/06/libreoffice-calc-change-data-type-parse-text-to-date-510x399.gif" alt="" class="wp-image-1901" srcset="https://dimio.org/wp-content/uploads/2023/06/libreoffice-calc-change-data-type-parse-text-to-date-510x399.gif 510w, https://dimio.org/wp-content/uploads/2023/06/libreoffice-calc-change-data-type-parse-text-to-date-400x313.gif 400w, https://dimio.org/wp-content/uploads/2023/06/libreoffice-calc-change-data-type-parse-text-to-date-200x156.gif 200w, https://dimio.org/wp-content/uploads/2023/06/libreoffice-calc-change-data-type-parse-text-to-date-768x601.gif 768w" sizes="auto, (max-width: 510px) 100vw, 510px" /></a><figcaption class="wp-element-caption">LibreOffice Calc: преобразовать текст в дату (запуск анимации по клику)</figcaption></figure>
</div>


<h2 class="wp-block-heading">Автоматическое вычисление промежуточных итогов</h2>



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



<ol class="wp-block-list">
<li><code>Ctrl + *</code> &#8212; выделить все данные на листе. Можно выбирать и не весь диапазон, естественно.</li>



<li><em>Данные -&gt; Промежуточные итоги</em>.</li>



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



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



<li>Выбрать агрегатную функцию.</li>



<li>Кнопками слева вверху (<code>1-2-3</code> и <code>+/-</code>) можно переключать вид (свернуть-развернуть).</li>
</ol>



<p>Проще всего продемонстрировать этот процесс на примере прошлого файла, в котором текст парсился в даты.</p>


<div class="wp-block-image">
<figure class="aligncenter size-large"><a href="https://dimio.org/wp-content/uploads/2023/06/libreoffice-calc-subtotals.gif"><img loading="lazy" decoding="async" width="510" height="429" src="https://dimio.org/wp-content/uploads/2023/06/libreoffice-calc-subtotals-510x429.gif" alt="" class="wp-image-1902" srcset="https://dimio.org/wp-content/uploads/2023/06/libreoffice-calc-subtotals-510x429.gif 510w, https://dimio.org/wp-content/uploads/2023/06/libreoffice-calc-subtotals-400x337.gif 400w, https://dimio.org/wp-content/uploads/2023/06/libreoffice-calc-subtotals-200x168.gif 200w, https://dimio.org/wp-content/uploads/2023/06/libreoffice-calc-subtotals-768x647.gif 768w" sizes="auto, (max-width: 510px) 100vw, 510px" /></a><figcaption class="wp-element-caption">LibreOffice Calc: промежуточные итоги (запуск анимации по клику)</figcaption></figure>
</div>


<h2 class="wp-block-heading">Выводы</h2>



<p>Вывод, в общем-то, простой: если поискать, поинтересоваться и немного глубже узнать возможности электронных таблиц <em>Calc</em> &#8212; с их помощью можно достаточно широкий круг рутинных задач решить быстро и просто. Пользуйтесь с удовольствием!</p>



<p><strong>Бонус:</strong> Автонумерацию строк в Calc <a href="https://dimio.org/avtonumeraciya-strok-tablicy-v-libreoffice-writer.html">можно сделать формулой, как и во Writer</a>. Растягивать формулу удобно, выделив нужные строки (включая ячейку с формулой), и нажав <code>Ctrl+D</code>.</p>
]]></content>
		
					<link rel="replies" type="text/html" href="https://dimio.org/libreoffice-calc-tryuki-raboty-s-tabliczej.html#comments" thr:count="0" />
			<link rel="replies" type="application/atom+xml" href="https://dimio.org/libreoffice-calc-tryuki-raboty-s-tabliczej.html/feed/atom" thr:count="0" />
			<thr:total>0</thr:total>
			</entry>
		<entry>
		<author>
			<name>dimio</name>
							<uri>http://dimio.org</uri>
						</author>

		<title type="html"><![CDATA[Git: извлечение первого и последнего коммита по автору]]></title>
		<link rel="alternate" type="text/html" href="https://dimio.org/git-izvlechenie-pervogo-i-poslednego-komita-po-avtoru.html" />

		<id>https://dimio.org/?p=1877</id>
		<updated>2023-05-05T05:48:05Z</updated>
		<published>2023-05-04T11:43:15Z</published>
		<category scheme="https://dimio.org" term="Кодинг" /><category scheme="https://dimio.org" term="Памятки" /><category scheme="https://dimio.org" term="git" /><category scheme="https://dimio.org" term="linux" /><category scheme="https://dimio.org" term="notes" />
		<summary type="html"><![CDATA[В силу определённых обстоятельств &#8212; периодически стал возникать вопрос, в каких временных рамках я занимался тем или иным проектом. И готового ответа на него у меня не было &#8212; как-то не приходило в голову фиксировать подобную информацию. Но есть же git &#8212; ведь он поможет? Ведь поможет, да? Git поможет! Возникла тривиальная идея &#8212; вытащить &#8230; <a href="https://dimio.org/git-izvlechenie-pervogo-i-poslednego-komita-po-avtoru.html" class="more-link">Читать далее <span class="screen-reader-text">Git: извлечение первого и последнего коммита по автору</span> <span class="meta-nav">&#8594;</span></a>]]></summary>

					<content type="html" xml:base="https://dimio.org/git-izvlechenie-pervogo-i-poslednego-komita-po-avtoru.html"><![CDATA[
<p>В силу определённых обстоятельств &#8212; периодически стал возникать вопрос, в каких временных рамках я занимался тем или иным проектом. И готового ответа на него у меня не было &#8212; как-то не приходило в голову фиксировать подобную информацию.</p>



<div class="wp-block-media-text alignwide is-stacked-on-mobile is-vertically-aligned-top is-style-default" style="grid-template-columns:30% auto"><figure class="wp-block-media-text__media"><img loading="lazy" decoding="async" width="200" height="200" src="https://dimio.org/wp-content/uploads/2023/05/padme-i-enakin-shablon-mema-200x200.png?v=1683192386" alt="" class="wp-image-1879 size-thumbnail"/></figure><div class="wp-block-media-text__content">
<p>Но есть же <code>git</code> &#8212; ведь он поможет? Ведь поможет, да?</p>
</div></div>



<span id="more-1877"></span>



<h2 class="wp-block-heading">Git поможет!</h2>



<p>Возникла тривиальная идея &#8212; вытащить эту информацию из гит-лога. Первый и последний коммиты &#8212; плюс-минус дадут требуемые рамки. Достаточно найти все коммиты определённого автора (в данном случае &#8212; себя) и взять первый+последний.</p>



<h3 class="wp-block-heading" id="git-alias-find-commits-by-author">Git alias для поиска по автору</h3>



<p>Чтобы не запоминать (или не искать в истории) довольно длинную команду &#8212; её удобно запихать в пользовательский alias (именно гита, не оболочки). Например &#8212; в <code>~/.gitconfig</code> прописать (в секции <mark><code>[alias]</code></mark>):</p>



<pre class="wp-block-code"><code lang="bash" class="language-bash">[alias]
	first-last-by-author = "!f() { \
	 LOG=$(git log --pretty=format:\"%h%x09%an%x09%ad%x09%s\" --date=short --author=\"${1}\"); \
	 FIRST=$(echo \"${LOG}\" | head --lines=1); \
	 LAST=$(echo \"${LOG}\" | tail --lines=1); \
	 echo \"${FIRST}\"; echo \"${LAST}\"; \
	}; f"</code></pre>



<p>В частном случае &#8212; это уже работает достаточно удобно и выглядит примерно так:</p>



<pre class="wp-block-preformatted">user@host:~/single-repo$ git first-last-by-author dmitry

f887e8aa55      Dmitry        2022-06-26
6f7a97ded7      Dmitry        2021-04-08</pre>



<p>Когда репозиторий для поиска &#8212; один. Или парочка. Или&#8230; Нет, когда их парочка сотен &#8212; становится грустно. Идея явно требует развития!</p>



<h3 class="wp-block-heading">One Function to find them all</h3>



<p>Для решения задачи поиска по набору репозиториев &#8212; пришлось воспользоваться функциями оболочки. Они у меня сложены в отдельном файле <code>~/.config/bash/<a href="https://dimio.org/bash-born-again-shell-obolochka-komandnoj-stroki.html#bash_functions">bash_functions</a></code>.</p>



<p>На базе <a href="/gitlab-sklonirovat-spisok-repozitoriev.html#git-update-repository-collection" data-type="URL" data-id="/gitlab-sklonirovat-spisok-repozitoriev.html#git-update-repository-collection">команды для обновления репозиториев</a> и приведённого выше <a href="#git-alias-find-commits-by-author" data-type="internal" data-id="#git-alias-find-commits-by-author">гит-алиаса для поиска по автору</a> &#8212; сделал такую вот bash-функцию:</p>



<pre class="wp-block-code"><code lang="bash" class="language-bash">git-first-last-commit-by-author() {
	export GIT_SEARCH_AUTHOR_NAME="${1}"
	LOG=$(find . -type d -name '.git' | xargs -n1 -- \
	 sh -c 'cd "${0}/.." &amp;&amp; git first-last-by-author "${GIT_SEARCH_AUTHOR_NAME}" | sed "/^[[:space:]]*$/d"' \
	 | sort --key=4,4 \
	)
	unset GIT_SEARCH_AUTHOR_NAME
	echo "${LOG}" | head --lines=1
	echo "${LOG}" | tail --lines=1
}</code></pre>



<p>Теперь поиск работает и в общем случае (в каталоге <code>multi-repo</code> лежит куча git-репозиториев):</p>



<pre class="wp-block-preformatted">user@host:~/multi-repo$ git-first-last-commit-by-author dmitry

8f1d4ae         Dmitry        2022-08-16
83a8f89c        Dmitry        2023-02-15</pre>



<p>Видно, что здесь порядок сортировки по датам &#8212; прямой. Мне так удобней, но всегда можно использовать ключ <code><mark>--reverse</mark></code> для <code>sort</code> внутри <code>git-first-last-commit-by-author()</code>.</p>
]]></content>
		
					<link rel="replies" type="text/html" href="https://dimio.org/git-izvlechenie-pervogo-i-poslednego-komita-po-avtoru.html#comments" thr:count="0" />
			<link rel="replies" type="application/atom+xml" href="https://dimio.org/git-izvlechenie-pervogo-i-poslednego-komita-po-avtoru.html/feed/atom" thr:count="0" />
			<thr:total>0</thr:total>
			</entry>
		<entry>
		<author>
			<name>dimio</name>
							<uri>http://dimio.org</uri>
						</author>

		<title type="html"><![CDATA[HackerRank Bit Manipulation: Counter game]]></title>
		<link rel="alternate" type="text/html" href="https://dimio.org/hackerrank-bit-manipulation-counter-game.html" />

		<id>https://dimio.org/?p=1871</id>
		<updated>2023-04-25T13:28:08Z</updated>
		<published>2023-04-25T13:28:08Z</published>
		<category scheme="https://dimio.org" term="Problem solving" /><category scheme="https://dimio.org" term="Алгосы" /><category scheme="https://dimio.org" term="algorithms" /><category scheme="https://dimio.org" term="hackerrank" /><category scheme="https://dimio.org" term="java" />
		<summary type="html"><![CDATA[Вторая из ранее сохранённых и ныне обретённых задачек с HackerRank. Как понятно из заголовка &#8212; решается через битовые операции. Хотя &#8212; теоретическим можно было бы помучиться с BigInteger и арифметикой&#8230; И посмотреть, какое время займёт поиск решения. Традиционно &#8212; решение на Гитхабе. https://www.hackerrank.com/challenges/counter-game/problem]]></summary>

					<content type="html" xml:base="https://dimio.org/hackerrank-bit-manipulation-counter-game.html"><![CDATA[
<p>Вторая из ранее сохранённых и ныне обретённых задачек с HackerRank. Как понятно из заголовка &#8212; решается через битовые операции.</p>



<p>Хотя &#8212; теоретическим можно было бы помучиться с <code>BigInteger</code> и арифметикой&#8230; И посмотреть, какое время займёт поиск решения.</p>



<pre class="wp-block-code"><code lang="java" class="language-java">import java.util.Scanner;

public class Solution {

    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        int t = in.nextInt();
        for (int a0 = 0; a0 &lt; t; a0++) {
            long n = in.nextLong();
            String result = counterGame(n - 1);
            System.out.println(result);
        }
        in.close();
    }

    private static String counterGame(long n) {
        //long mask = 0x8000000000000000L; //2^63 in hex //W
        //eq:
        //long mask = -9223372036854775808L; //2^63 //W
        long mask;
        int step = 0;
        for (int i = 63; i >= 0; i--) {
            mask = 1L &lt;&lt; i;
            //compare with 2 power i
            if ((n &amp; mask) != 0) {
                //we max 2^i
                //step++;
                step = step ^ 1;
            }
            n -= mask;
            //mask >>>= 1;
        }

        return ((step &amp; 1) != 0) ? "Louise" : "Richard";
    }

}</code></pre>



<p>Традиционно &#8212; <a href="https://github.com/dimio/problem-solving/blob/b3122eae1b11e5c3cd980485a9343274b464154f/hackerrank/src/org/dimio/problem/hacker/rank/algorithms/bit_manipulation/counter_game/Solution.java">решение на Гитхабе</a>.</p>



<pre class="wp-block-preformatted">https://www.hackerrank.com/challenges/counter-game/problem</pre>
]]></content>
		
					<link rel="replies" type="text/html" href="https://dimio.org/hackerrank-bit-manipulation-counter-game.html#comments" thr:count="0" />
			<link rel="replies" type="application/atom+xml" href="https://dimio.org/hackerrank-bit-manipulation-counter-game.html/feed/atom" thr:count="0" />
			<thr:total>0</thr:total>
			</entry>
		<entry>
		<author>
			<name>dimio</name>
							<uri>http://dimio.org</uri>
						</author>

		<title type="html"><![CDATA[HackerRank 30 Days of Code: Day 11: 2D Arrays]]></title>
		<link rel="alternate" type="text/html" href="https://dimio.org/hackerrank-30-days-of-code-day-11-2d-arrays.html" />

		<id>https://dimio.org/?p=1861</id>
		<updated>2023-12-08T06:16:16Z</updated>
		<published>2023-04-24T19:44:25Z</published>
		<category scheme="https://dimio.org" term="Problem solving" /><category scheme="https://dimio.org" term="Алгосы" /><category scheme="https://dimio.org" term="30 days of code" /><category scheme="https://dimio.org" term="hackerrank" /><category scheme="https://dimio.org" term="java" /><category scheme="https://dimio.org" term="perl" />
		<summary type="html"><![CDATA[Не Литкодом единым, как говорится! Нашёл на диске пару задачек с HackerRank &#8212; видимо, показались тогда особо любопытными, и были сохранены. Впрочем, и сейчас они выглядят интересно. Эта, например (первая из них) &#8212; перемещение паттерна в виде &#171;песочных часов&#187; по &#171;игровому полю&#187;, представленному матрицей, с целью найти такой паттерн, сумма цифр в котором будет максимальной. &#8230; <a href="https://dimio.org/hackerrank-30-days-of-code-day-11-2d-arrays.html" class="more-link">Читать далее <span class="screen-reader-text">HackerRank 30 Days of Code: Day 11: 2D Arrays</span> <span class="meta-nav">&#8594;</span></a>]]></summary>

					<content type="html" xml:base="https://dimio.org/hackerrank-30-days-of-code-day-11-2d-arrays.html"><![CDATA[
<p>Не <a href="https://dimio.org/tag/leetcode">Литкодом</a> единым, как говорится! Нашёл на диске пару задачек с HackerRank &#8212; видимо, показались тогда особо любопытными, и были сохранены.</p>



<p>Впрочем, и сейчас они выглядят интересно. Эта, например (первая из них) &#8212; перемещение паттерна в виде &#171;песочных часов&#187; по &#171;игровому полю&#187;, представленному матрицей, с целью найти такой паттерн, сумма цифр в котором будет максимальной.</p>



<p>Здесь у меня получилось два решения &#8212; частное (на <a href="https://dimio.org/tag/java">Java</a>) и общее (на <a href="https://dimio.org/tag/perl">Perl</a>).</p>



<span id="more-1861"></span>



<h2 class="wp-block-heading">Java-решение</h2>



<p>Решение для паттерна и поля, указанных в задаче. Т.е. поле размером <code>6х6</code> и часики с внешним габаритом <code>3х3</code>.</p>



<pre class="wp-block-code"><code lang="java" class="language-java">import java.util.Arrays;
import java.util.Scanner;

public class Solution {

    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        int[][] arr = new int[6][6];
        for (int i = 0; i &lt; 6; i++) {
            for (int j = 0; j &lt; 6; j++) {
                arr[i][j] = in.nextInt();
            }
        }
        System.out.println(solve(arr));
    }

    private static int solve(int[][] arr) {
        int[] sum = new int[16];
        int h = 0;

        for (int i = 0; i &lt; 4; i++) {
            for (int j = 0; j &lt; 4; j++) {
                sum[h] = arr[i][j] + arr[i][j + 1] + arr[i][j + 2]
                    + arr[i + 1][j + 1]
                    + arr[i + 2][j] + arr[i + 2][j + 1] + arr[i + 2][j + 2];
                h++;
            }
        }

        Arrays.sort(sum);
        return sum[sum.length - 1];
    }

}</code></pre>



<h2 class="wp-block-heading">Perl-решение</h2>



<p>Здесь уже можно задать в скрипте габариты паттерна &#171;часов&#187; и подать на вход матрицу произвольного размера (конечно, с учётом того, что паттерн должен в ней помещаться).</p>



<pre class="wp-block-code"><code lang="perl" class="language-perl">#!/usr/bin/env perl
require 5.008_008;
use warnings;
use strict;
use utf8;

# hourglass dimensions, min 3x3
my $hg_dim = {
    'x' =&gt; 3, # width, must be odd
    'y' =&gt; 3, # height
};

$hg_dim-&gt;{wdht} = $hg_dim-&gt;{x} - 1; #i
$hg_dim-&gt;{hght} = $hg_dim-&gt;{y} - 1; #j
$hg_dim-&gt;{cntr} = sprintf("%u", $hg_dim-&gt;{x} / 2);

my $arr = [];
while (&lt;STDIN&gt;) {
    chomp;
    push @{$arr}, [ split(' ', $_) ];
}

# ...or $#{$arr-$hg_dim-1&gt;[0]}+1 - $hg_dim-1
my $max_x = (scalar @{$arr-&gt;[0]}) - ($hg_dim-&gt;{wdht});
my $max_y = (scalar @{$arr}) - ($hg_dim-&gt;{hght});

# for neg nums, or add $sum on array and sort it
my $max_sum = -1000;

for (my $y = 0; $y &lt; $max_y; $y++) {
    for (my $x = 0; $x &lt; $max_x; $x++) {
        my $sum = 0;
        for (my $i = $x; $i &lt;= $x + $hg_dim-&gt;{wdht}; $i++) {
            $sum += $arr-&gt;[$y]-&gt;[$i];                   # upper row
            $sum += $arr-&gt;[$y + $hg_dim-&gt;{hght}]-&gt;[$i]; # lowest row
        }
        for (my $j = $y + 1; $j &lt; $y + $hg_dim-&gt;{hght}; $j++) {
            $sum += $arr-&gt;[$j]-&gt;[$x + $hg_dim-&gt;{cntr}]; # column
        }
        $max_sum = ($sum &gt; $max_sum) ? $sum : $max_sum;
    }
}

print $max_sum, $/;</code></pre>



<h2 class="wp-block-heading">Что в итоге?</h2>



<p>В итоге &#8212; оба приведённых решения работают, причём &#8212; по сию пору. Это отрадно <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f642.png" alt="🙂" class="wp-smiley" style="height: 1em; max-height: 1em;" /> По традиции &#8212; они же <a href="https://github.com/dimio/problem-solving/tree/master/hackerrank/src/org/dimio/problem/hacker/rank/thirty_days_of_code/d11_2d_arrays">выложены на GitHub.</a></p>



<pre class="wp-block-preformatted">https://www.hackerrank.com/challenges/30-2d-arrays/problem</pre>



<div class="wp-block-buttons has-custom-font-size has-small-font-size is-content-justification-center is-nowrap is-layout-flex wp-container-core-buttons-is-layout-1fb9aab6 wp-block-buttons-is-layout-flex">
<div class="wp-block-button has-custom-width wp-block-button__width-100 is-style-outline is-style-outline--9"><a class="wp-block-button__link wp-element-button" href="https://t.me/panykey/76" target="_blank" rel="noreferrer noopener">Комментировать в TELEGRAM <img loading="lazy" decoding="async" width="24" height="24" class="wp-image-1960" style="width: 24px;" src="https://dimio.org/wp-content/uploads/2023/07/telegram-svgrepo-com.png" alt="" srcset="https://dimio.org/wp-content/uploads/2023/07/telegram-svgrepo-com.png 256w, https://dimio.org/wp-content/uploads/2023/07/telegram-svgrepo-com-200x200.png 200w" sizes="auto, (max-width: 24px) 100vw, 24px" /></a></div>
</div>
]]></content>
		
			</entry>
	</feed>
