<?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">Блог Евгения Жирнова</title>
	<subtitle type="text">Сайт о программировании, путешествиях и не только</subtitle>

	<updated>2026-03-30T12:52:24Z</updated>

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

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

		<title type="html"><![CDATA[WordPress: Интерактивный тег &#060;!&#8212;more&#8212;&#062; без перезагрузки страницы]]></title>
		<link rel="alternate" type="text/html" href="https://blog2k.ru/archives/12756" />

		<id>https://blog2k.ru/?p=12756</id>
		<updated>2025-12-14T08:53:12Z</updated>
		<published>2025-12-05T20:23:19Z</published>
		<category scheme="https://blog2k.ru" term="JavaScript" /><category scheme="https://blog2k.ru" term="PHP" /><category scheme="https://blog2k.ru" term="Программирование" /><category scheme="https://blog2k.ru" term="WordPress API" />
		<summary type="html"><![CDATA[В статье описан способ реализации функции «развернуть/свернуть» для постов в WordPress, позволяющий скрывать часть поста после тега «!--more--». Представлены фрагменты кода на PHP, CSS и JavaScript для реализации этой функции.]]></summary>

					<content type="html" xml:base="https://blog2k.ru/archives/12756"><![CDATA[<p>В начале статьи хочу признаться, что я не верстальщик и не владею PHP, JavaScript или CSS на должном уровне, поэтому всё, что написано ниже, используйте на свой страх и риск. Возможно, это неправильно и надо делать не так. Я не знаю, как надо правильно, учусь самостоятельно, поэтому пишу, как умею <del>хрум-хрум-хрум</del>.</p>
<p>Решил привести в порядок свою главную страницу блога. Не нравятся мне длинные посты, которые нужно долго листать, чтобы перейти к следующему. Изначально рассматривал два варианта:</p>
<ol>
<li>Кнопка <code class="" data-line="">[Пропустить пост]</code> для быстрой перемотки к следующему посту и возвращению к предыдущему</li>
<li>Кнопка <code class="" data-line="">[Развернуть]</code> для динамической загрузки остальной части поста после тега <code class="" data-line="">&lt;!--more--&gt;</code>.</li>
</ol>
<p>В итоге выбрал третий путь: весь пост загружается сразу, но часть после тега <code class="" data-line="">&lt;!--more--&gt;</code> показывается или скрывается по клику на кнопку <code class="" data-line="">[развернуть/свернуть]</code>.</p>
<p>Я выбрал этот вариант по двум причинам:</p>
<ol>
<li>Скрытая часть поста должна корректно обрабатываться скриптами по событию <code class="" data-line="">onload</code>/<code class="" data-line="">onready</code>.</li>
<li>Размер постов у меня небольшой.<span id="more-12756"></span></li>
</ol>
<h2>Реализация</h2>
<p>Для начала нужно выбрать способ получения полного текста поста. Если вызвать <a href="https://wp-kama.ru/function/get_the_content" rel="nofollow" target="_blank">get_the_content()</a>, то возвращается только часть до тега. Можно обойти это поведение, используя глобальную переменную <code class="" data-line="">$more</code>, но такое решение выглядит как костыль:</p>
<pre><code class="language-php" data-line="">function my_the_content() {
    global $more;
    $prev_more = $more;
    $more = 1;
    $content = apply_filters(&#039;the_content&#039;, get_the_content());
    $more = $prev_more;
}
</code></pre>
<p>Я решил брать текст поста из поля <code class="" data-line="">post_content</code> объекта <code class="" data-line="">$post</code> и делить его с помощью функции <a href="https://wp-kama.ru/function/get_extended" rel="nofollow" target="_blank">get_extended()</a>.</p>
<p>В итоге, я заменил вызов <a href="https://wp-kama.ru/function/the_content" rel="nofollow" target="_blank">the_content()</a> в своей теме на <code class="" data-line="">my_the_content($post)</code> такого вида (код нужно добавить в <code class="" data-line="">functions.php</code> вашей темы WordPress):</p>
<pre><code class="language-php" data-line="">function my_the_content($post) {
    // На странице поста стандартное поведение
    if (is_singular()) {
        the_content();
        return;
    }

    // Получаем текст целиком из поля post_content и применяем фильтры
    $content = apply_filters(&#039;the_content&#039;, $post-&gt;post_content);

    // Разбиваем на несколько частей по тегу &lt;!--more--&gt;
    $parts = get_extended($content);

    // Часть после тега
    $extended = $parts[&#039;extended&#039;];

    // После тега ничего нет, заканчиваем работу
    if (empty($extended)) {
        return;
    }

    // Поддержка роботов и тех, кому отключили JavaScript за неуплату
    echo &#039;&lt;noscript&gt;&#039;;
    echo &#039;&lt;div&gt;&#039;.$extended.&#039;&lt;/div&gt;&#039;;
    echo &#039;&lt;style&gt;.post-body {display: none; }&lt;/style&gt;&#039;;
    echo &#039;&lt;/noscript&gt;&#039;;

    // Храним всю дополнительную часть в секции post-body,
    // классы expanded/collapsed используются для регулировки видимости элементов
    echo &#039;&lt;div class=&quot;post-body&quot;&gt;&#039;;
    // Прячем кнопки в отдельном контейнере для удобства
    echo &#039;&lt;div class=&quot;toggle-buttons&quot;&gt;&#039;;
    // Две кнопки, одна видна, другая спрятана
    echo &#039;&lt;div class=&quot;toggle-post-body expanded&quot;&gt;&#039;;
    echo &#039;&lt;div class=&quot;label expand&quot;&gt;развернуть&lt;/div&gt;&#039;;
    echo &#039;&lt;/div&gt;&#039;;
    echo &#039;&lt;div class=&quot;toggle-post-body collapsed&quot;&gt;&#039;;
    echo &#039;&lt;div class=&quot;label collapse&quot;&gt;свернуть&lt;/div&gt;&#039;;
    echo &#039;&lt;/div&gt;&#039;;
    echo &#039;&lt;/div&gt;&#039;;
    // Тело поста спрятано по умолчанию
    echo &#039;&lt;div class=&quot;post-body-content collapsed&quot;&gt;&#039;.$extended.&#039;&lt;/div&gt;&#039;;
    echo &#039;&lt;/div&gt;&#039;;
}
</code></pre>
<h2>Стилизация</h2>
<p>Теперь стили для блока <code class="" data-line="">.post-body</code>. Все изменения затрагивают только элементы внутри него:</p>
<pre><code class="language-css" data-line="">/* Элементы с классом collapsed внутри post-body скрыты */
.post-body .collapsed {
  display: none;
}

/* Элементы с классом expanded внутри post-body видны */
.post-body .expanded {
  display: block;
}

/* Общие настройки для кнопок-переключателей */
.post-body .toggle-post-body .label {
  color: #cc6633;
  cursor: pointer;
  margin-bottom: 0.5em;
  border-bottom: 1px dashed;
  font-size: 90%;
}

/* Треугольник для кнопки &quot;свернуть&quot; */
.post-body .toggle-post-body .label.collapse:before {
  content: &#039;\25BC&#039;;/* ▼ */
  margin-right: 5px;
}

/* Треугольник для кнопки &quot;развернуть&quot; */
.post-body .toggle-post-body .label.expand:before {
  content: &#039;\25B6&#039;; /* ▶ */
  margin-right: 5px;
}
</code></pre>
<h2>Логика на JavaScript:</h2>
<p>И, наконец, скрипт, который переключает видимость:</p>
<pre><code class="language-javascript" data-line="">// Добавляем обработку клику по элементам с классом &quot;toggle-post-body&quot;
jQuery(&#039;.toggle-post-body&#039;).click(function(event){
  var nextButton = jQuery(this)
    .toggleClass(&#039;expanded&#039;)
    .toggleClass(&#039;collapsed&#039;)
    .siblings(&#039;.toggle-post-body&#039;);

  nextButton
    .toggleClass(&quot;expanded&quot;)
    .toggleClass(&quot;collapsed&quot;);

  var contentBlock = nextButton
    .closest(&quot;.toggle-buttons&quot;)
    .next(&#039;.post-body-content&#039;);

  contentBlock
    .toggleClass(&quot;expanded&quot;)
    .toggleClass(&quot;collapsed&quot;);
});
</code></pre>
<h2>Заключение</h2>
<p>Подводя итог, логика работы выглядит следующим образом:</p>
<ol>
<li>Расширенная часть поста по умолчанию скрыта (класс .collapsed).</li>
<li>При клике на видимую кнопку (например, &#171;развернуть&#187;) запускается скрипт.</li>
<li>Скрипт переключает видимость у нажатой кнопки (скрывая её) и у соседней (показывая её).</li>
<li>Одновременно скрипт меняет видимость у блока с контентом.</li>
</ol>
<h2>Недостатки</h2>
<ol>
<li>Пользователь не может перейти на страницу с самим постом, кроме как кликнув на заголовок.</li>
<li>Пришлось убрать блок кнопки Social Likes с главной страницы для того, чтобы люди могли делиться контентом в социальных сетях. Но они этого и так не делают, так что невелика потеря.</li>
<li>Некоторые мои записи используют канвас для рисования с помощью WebGL или JavaScript. Для них пришлось делать уникальный идентификатор канвасов для каждого поста.</li>
<li>Страница грузит содержимое всех постов, что может быть накладно, если все посты на странице рисуют графику, например.</li>
<li>Пришлось переписать каждый пост с меткой <a href="https://blog2k.ru/tags/interactive" target="_blank">&#171;Интерактив&#187;</a>, чтобы каждый скрипт писал в свой уникальный canvas плюс немного исправить вызов <code class="" data-line="">requestAnimationFrame</code>. Зато выложил все скрипты на <a href="https://github.com/jirnov/blog2k.ru" target="_blank">GitHub</a> и добавил каждому демонстрационный <code class="" data-line="">index.html</code>.</li>
</ol>
<p><strong>UPD</strong>: Немного упростил логику. Теперь у меня два элемента типа <code class="" data-line="">toggle-post-body</code>. По кнопке их видимость меняется местами. Можете посмотреть исходники плагина <code class="" data-line="">b2k-tools</code> с актуальной версией на <a href="https://github.com/jirnov/b2k-tools" rel="nofollow" target="_blank">GitHub</a>.</p>
<p>Раз вы дочитали до конца, как считаете: нужно ли добавить кнопку &#171;свернуть&#187; в конец поста для быстрой навигации?</p>
]]></content>
		
					<link rel="replies" type="text/html" href="https://blog2k.ru/archives/12756#comments" thr:count="0" />
			<link rel="replies" type="application/atom+xml" href="https://blog2k.ru/archives/12756/feed/atom" thr:count="0" />
			<thr:total>0</thr:total>
			</entry>
		<entry>
		<author>
			<name>eJ</name>
					</author>

		<title type="html"><![CDATA[Вопросы и ответы для собеседования и подготовки Senior C++ разработчика]]></title>
		<link rel="alternate" type="text/html" href="https://blog2k.ru/archives/12320" />

		<id>https://blog2k.ru/?p=12320</id>
		<updated>2026-03-17T13:34:04Z</updated>
		<published>2025-10-30T10:59:14Z</published>
		<category scheme="https://blog2k.ru" term="C++" /><category scheme="https://blog2k.ru" term="Программирование" /><category scheme="https://blog2k.ru" term="многопоточность" /><category scheme="https://blog2k.ru" term="Полезная статья" />
		<summary type="html"><![CDATA[Статья содержит вопросы и ответы для программистов на позиции Senior C++. Освещаются темы, связанные с переменными, умными указателями, исключениями, виртуальными методами и другими аспектами языка C++.]]></summary>

					<content type="html" xml:base="https://blog2k.ru/archives/12320"><![CDATA[<style>
table { white-space: nowrap; display: block; overflow-x: auto; }
</style>
<p>Всем привет! Решил разложить по полочкам и записать актуальные на 2025 год вопросы и ответы программисту в позиции Senior C++. Вы можете это использовать как для проведения собеседований в качестве интервьюера, так и для подготовки к ним. Считаю, это самая скучная статья на моём сайте, но лучший способ что-то запомнить — это записать и систематизировать свои знания.</p>
<p>Немного о себе: пишу на C++ уже восемнадцатый год и немножко понимаю в программировании.</p>
<p>Кстати, <a href="https://youtube.com/shorts/fSra2zfzKas?si=n9uj0lufI_S7VHY0" rel="nofollow" target="_blank">недавно узнал</a>, что человек запоминает 25% любой информации, но надолго. И вот смотрю я на эту прорву текста и думаю — если это всего лишь четверть, то ни фига себе &#8212; насколько огромная часть знаний прошла мимо меня.</p>
<p><span id="more-12320"></span>Статья создавалась постепенно: после каждого собеседования я дополнял её новыми вопросами, с которыми столкнулся лично. Например, перед началом написания статьи я ничего не знал про <strong>perfect forwarding</strong> (мельком слышал про универсальную ссылку) и <code class="" data-line="">std::shared_mutex</code>.</p>
<h2>Где располагаются переменные, чем инициализированы, область видимости:</h2>
<pre><code class="language-cpp" data-line="">int a;
static int b;
int c = 30;
const int d = 20; // без слова &quot;extern&quot; переменная d видна только в этом файле

void function() {
  int fa;
  int fb = 10;
  const int fc = 5;
  static int fd; // инициализируется нулём при первом вызове функции
  static int fe = 1; // инициализируется единичкой при первом вызове функции 
}
</code></pre>
<p>Если мы объявляем переменную в глобальном пространстве, то указание <code class="" data-line="">static</code> делает видимость этой переменной только в этом файле. Указание константности приводит (в зависимости от желания компилятора) помещение его значения по умолчанию в секцию <strong>.rodata</strong> исполняемого файла или сразу встраивание этого значения в код вместо переменной. Все переменные объявленные вне функций инициализированы нулём по умолчанию и живут в сегменте памяти <strong>BSS</strong>, который выделяется и заполняется нулями при запуске программы, его размер записан в исполняемом файле. Не const переменные сохраняют своё значение в сегменте памяти <strong>DATA</strong> исполняемого файла. Этот сегмент копируется в память компьютера при запуске программы. Все глобальные переменные живут в статической памяти (BSS/DATA/.rodata). <strong>Статическая память</strong> выделятся при старте программы, имеет постоянный размер и существует в течение всей жизни программы. Размещение переменных по сегментам статической памяти — это поведение на этапе компоновки, описанное в стандартных соглашениях (Application Binary Interface, ABI). Сводная таблица всех переменных из примера выше:</p>
<table>
<thead>
<tr>
<th>Переменная</th>
<th>Инициализация</th>
<th>Сегмент памяти</th>
<th>Видимость</th>
</tr>
</thead>
<tbody>
<tr>
<td><code class="" data-line="">int a;</code></td>
<td>Неявная (0)</td>
<td>BSS</td>
<td>Глобальная</td>
</tr>
<tr>
<td><code class="" data-line="">static int b;</code></td>
<td>Неявная (0)</td>
<td>BSS</td>
<td>Файловая</td>
</tr>
<tr>
<td><code class="" data-line="">int c = 30;</code></td>
<td>Явная (30)</td>
<td>DATA</td>
<td>Глобальная</td>
</tr>
<tr>
<td><code class="" data-line="">const int d = 20;</code></td>
<td>Явная (20)</td>
<td>.rodata или inline</td>
<td>Файловая</td>
</tr>
<tr>
<td><code class="" data-line="">int fa;</code></td>
<td>Мусор</td>
<td>стек</td>
<td>Блочная</td>
</tr>
<tr>
<td><code class="" data-line="">int fb = 10;</code></td>
<td>Явная (10)</td>
<td>стек</td>
<td>Блочная</td>
</tr>
<tr>
<td><code class="" data-line="">const int fc = 5;</code></td>
<td>Явная (5)</td>
<td>стек или inline</td>
<td>Блочная</td>
</tr>
<tr>
<td><code class="" data-line="">static int fd;</code></td>
<td>Неявная (0)</td>
<td>BSS</td>
<td>Блочная</td>
</tr>
<tr>
<td><code class="" data-line="">static int fe = 1;</code></td>
<td>Явная (1)</td>
<td>DATA</td>
<td>Блочная</td>
</tr>
</tbody>
</table>
<h2>Правила вывода типа для <em>auto</em></h2>
<p><code class="" data-line="">auto</code> по умолчанию создает копию без ссылок и квалификаторов (const, volatile) верхнего уровня. <code class="" data-line="">auto</code> сохраняет низкоуровневые квалификаторы (касающиеся указываемых данных), но отбрасывает высокоуровневые (касающиеся самой переменной-указателя).</p>
<p>Пример:</p>
<pre><code class="language-cpp" data-line="">int x = 42;
const int *p1 = &amp;x; // нельзя менять данные, но можно указатель
int *const p2 = &amp;x; // нельзя менять указатель, но можно менять данные
const int *const p3 = &amp;x; // нельзя менять указатель, нельзя менять данные
const int &amp;p4 = x; // ссылка на const int 

auto a1 = p1; // const int * - оставили const для данных
auto a2 = p2; // int * - убрали const для указателя
auto a3 = p3; // const int * - оставили const для данных, убрали const для указателя
auto a4 = p4; // int - убрали const, убрали ссылку
</code></pre>
<p>В итоге, правила для <code class="" data-line="">auto</code>:</p>
<ul>
<li><strong>указатели</strong>: сохраняют квалификаторы низкого уровня</li>
<li><strong>ссылки</strong>: отбрасывает ссылку, отбрасывает <code class="" data-line="">const</code></li>
</ul>
<h2>Что такое RAII?</h2>
<p>Resource Acquisition Is Initialization &#8212; дословно &#171;захват ресурса есть инициализация&#187;. В конструкторе захватываем ресурс, в деструкторе освобождаем.</p>
<h2>Какие бывают умные указатели?</h2>
<ul>
<li><code class="" data-line="">std::shared_ptr</code> &#8212; RAII указатель на объект со счётчиком ссылок. Копирование увеличивает счётчик ссылок, в деструкторе счётчик уменьшается. При достижении нуля освобождает память.</li>
<li><code class="" data-line="">std::weak_ptr</code> &#8212; слабая ссылка на объект, управляемый <code class="" data-line="">std::shared_ptr</code>. Не увеличивает счётчик ссылок. Для использования нужно преобразовать в <code class="" data-line="">std::shared_ptr</code> с помощью метода <code class="" data-line="">lock()</code>. Полезен, чтобы избежать циклических ссылок между <code class="" data-line="">std::shared_ptr</code>.</li>
<li><code class="" data-line="">std::unique_ptr</code> &#8212; указатель с исключительным владением объектом. Запрещено копирование, разрешено только перемещение. Для передачи владения используйте <code class="" data-line="">std::move</code>. Имеет специализацию для массивов: <code class="" data-line="">std::unique_ptr&lt;T[]&gt;</code>.</li>
</ul>
<h2>Почему лучше использовать <code class="" data-line="">std::make_shared</code> и <code class="" data-line="">std::make_unique</code>, когда возможно?</h2>
<p>Во время вычисления параметров конструктора возможно исключение, которое приведёт к утечке памяти. Также <code class="" data-line="">std::make_shared</code> выделяет память для объекта и контрольного блока за одну аллокацию. В конце концов, читать удобнее.</p>
<p><strong>NOTE</strong>: Более увлечённый в C++ коллега (привет, Евгений!) указал, что есть <a href="https://habr.com/ru/articles/509004/" rel="nofollow" target="_blank">ситуации</a>, когда использование <code class="" data-line="">std::make_shared</code> менее эфективно, чем просто вызов конструктора <code class="" data-line="">std::shared_ptr</code>. Это связано с тем, что при использовании <code class="" data-line="">std::make_shared</code> остаётся живым контрольный блок, пока жива хоть одна <code class="" data-line="">weak_ptr</code> ссылка на объект. Когда используем конструктор такого не происходит. Плюс к этому <code class="" data-line="">std::make_shared</code> всегда игнорирует перегруженные операторы <code class="" data-line="">new</code> и <code class="" data-line="">delete</code> для класса и использует глобальный.</p>
<h2>Что происходит при возникновении исключения.</h2>
<p>Выполнение функции прерывается, идёт поиск подходящего <code class="" data-line="">catch</code>. Сначала в текущей функции, потом идёт последовательно выход наверх по стеку. При выходе вызываются все деструкторы локальных объектов, которые покидают текущую область видимости. Если подходящий <code class="" data-line="">catch</code> не найден, то <code class="" data-line="">std::terminate()</code>. Если во время раскрутки стека вызовов происходит повторное исключение, то снова <code class="" data-line="">std::terminate()</code>.</p>
<h2>Что происходит при возникновении исключения в конструкторе/деструкторе?</h2>
<ul>
<li>Если исключение происходит в конструкторе, для уже созданных членов класса вызываются деструкторы, деструктор этого объекта не вызывается, а дальше всё как обычно</li>
<li>Деструктор неявно объявлен как <code class="" data-line="">noexcept</code> <strong>со стандарта C++11</strong>, поэтому любое исключение, покидающее деструктор вызывает <code class="" data-line="">std::terminate()</code>. Также может возникнуть ситуация, если при обработке исключения в деструкторе во время раскрутки стека вызовов произойдёт исключение &#8212; то будет <code class="" data-line="">std::terminate()</code></li>
</ul>
<h2>Почему память выделенная <code class="" data-line="">new/malloc</code> будет утечкой, а умный указатель корректно освободит память при вызове исключения?</h2>
<p>Потому что происходит раскрутка стека и очистка локальных переменных, выделенных на стеке, плюс вызываются деструкторы этих переменных. Сырой указатель от <code class="" data-line="">new/malloc</code> не имеет деструктора и выделен в куче.</p>
<h2>В чём особенность placement <code class="" data-line="">new</code>?</h2>
<p>При использовании placement <code class="" data-line="">new</code> деструктор нужно вызывать вручную. Правильный порядок действий:</p>
<pre><code class="language-cpp" data-line="">// 1. Выделили память
void* memory = ::operator new(sizeof(MyClass));

// 2. Создали объект (placement new)
MyClass* obj = new (memory) MyClass();

// 3. Использовали объект
obj-&gt;method();

// 4. Вызвали деструктор
obj-&gt;~MyClass();

// 5. Освободили память
::operator delete(memory);
</code></pre>
<h2>Что такое срез исключения? Когда происходит? Как избежать?</h2>
<p>Это происходит когда мы пытаемся перехватить исключение <em>по значению</em>, когда тип исключения в <code class="" data-line="">catch</code>-блоке является базовым к брошенному исключению, например вот так:</p>
<pre><code class="language-cpp" data-line="">try {
  throw MyException(what, extended_data); // наследник std::exception
}
catch (std::exception e) { // тут происходит СРЕЗ
  // Значение extended_data утеряно
}
</code></pre>
<p>Поэтому лучший путь &#8212; это <strong>перехватывать исключение по константной ссылке</strong>.</p>
<pre><code class="language-cpp" data-line="">try {
  throw MyException(what, extended_data); // наследник std::exception
}
catch (const std::exception &amp;e) {
  // Сохраняется полная информация об исключении
}
</code></pre>
<h2>Что происходит при бросании исключения из <code class="" data-line="">noexcept</code> метода?</h2>
<p>Немедленный вызов <code class="" data-line="">std::terminate()</code> и аварийное завершение программы.</p>
<h2>Сколько создаётся <em>vtable</em> и <em>vptr</em> в классах и экземплярах классов?</h2>
<ul>
<li><em>vtable</em> &#8212; создаётся во время компиляции одна для каждого полиморфного класса, хранится в статической памяти</li>
<li><em>vptr</em> &#8212; создаётся в конструкторе в одном экземпляре в каждом объекте полиморфного класса, хранится внутри объекта. Сначала vptr указывает на таблицу базового класса, потом уже текущего.</li>
</ul>
<h2>Что происходит при вызове виртуального метода в конструкторе?</h2>
<p>В конструкторе указатель на таблицу виртуальных методов (<em>vptr</em>) указывает на таблицу текущего класса, значит вызываются методы текущего класса, а не производного. Конструктор производного класса вызывается после конструктора базового. Вызов чисто виртуального метода приведёт к неопределённому поведению или ошибке компиляции.</p>
<pre><code class="language-cpp" data-line="">struct Base {
public:
    Base() {
       print(); // Вызывается Base::print()
    }

    virtual void print() { ... }
};

struct Derived : Base {
   Derived() { // вызывается Base::Base(), затем Base::print()
      print(); // а здесь уже Derived::print()
   }

   void print() override { ... }
}
</code></pre>
<p>В общем, лучше не вызвать виртуальную функцию наследников класса в конструкторах.</p>
<h2>Что происходит при вызове виртуального метода в деструкторе?</h2>
<p>То же самое, что в вопросе выше. Только в конструкторе производный класс ещё не построен, а в деструкторе производный класс уже разрушен.</p>
<h2>Какие бывают касты в C++.</h2>
<p>Целую заметку написал, не буду повторяться: <a href="https://blog2k.ru/archives/11397" target="_blank">Различные касты в C++</a>.</p>
<h2>Что такое семантика перемещения (move semantic)?</h2>
<p>Механизм, который, <strong>начиная с C++11</strong>, позволяет эффективно передавать ресурсы между объектами без дорогостоящего копирования. Использование выглядит так:</p>
<pre><code class="language-cpp" data-line="">std::vector&lt;int&gt; a;
a.resize(1000000); // выделяем много памяти
std::vector&lt;int&gt; b = std::move(a); // перемещаем данные, исходный объект в неопределённом состоянии
</code></pre>
<p>После выполнения кода объект <code class="" data-line="">b</code> владеет данными, объект <code class="" data-line="">a</code> находится в валидном, но неопределённом состоянии. Полезно знать, что <code class="" data-line="">std::move</code> только преобразует тип в <strong>r-value</strong> ссылку и ничего никуда не перемещает, реальное перемещение выполняет конструктор перемещения или оператор перемещения.</p>
<h2>Что такое RVO и NRVO</h2>
<p>Это оптимизации компилятора под названием <strong>Copy elision</strong> (пропуск копий), которые позволяют избежать лишнего копирования/перемещения при возврате объектов из функций:</p>
<ul>
<li>RVO(<strong>Return Value Optimization</strong>) &#8212; оптимизация безымянного возвращаемого значения, <strong>гарантировано стандартом C++17</strong>:</li>
</ul>
<pre><code class="language-cpp" data-line="">HeavyObject create() {
   return HeavyObject();
}
</code></pre>
<ul>
<li>NRVO(<strong>Named Return Value Optimization</strong>) &#8212; оптимизация именованного возвращаемого значения, когда возвращается именованная локальная переменная. Обратите внимание &#8212; использование <code class="" data-line="">std::move</code> при возврате значения <strong>ломает</strong> эту оптимизацию!</li>
</ul>
<pre><code class="language-cpp" data-line="">HeavyObject create() {
   HeavyObject a;
   return a;
}
</code></pre>
<h2>Что такое и как использовать <code class="" data-line="">std::future</code>/<code class="" data-line="">std::promise</code>? В каких случаях <code class="" data-line="">std::future</code> бросает ошибку?</h2>
<p>future/promise &#8212; это механизм передачи данных или исключений между потоками. Одному <code class="" data-line="">std::promise</code> соответствует один <code class="" data-line="">std::future</code>.</p>
<ul>
<li><code class="" data-line="">std::promise</code> &#8212; устанавливает значение (<code class="" data-line="">set_value()</code>) или исключение (<code class="" data-line="">set_exception()</code>), которое извлекается с помощью <code class="" data-line="">std::future</code>.</li>
<li><code class="" data-line="">std::future</code> &#8212; предоставляет доступ к результату (<code class="" data-line="">get()</code>), записанному через <code class="" data-line="">std::promise</code>. Метод <code class="" data-line="">get()</code> вызывает исключение, если <code class="" data-line="">std::promise</code> уничтожен без установки значения или исключения. Повторный вызов <code class="" data-line="">get()</code> также вызовет ошибку.</li>
</ul>
<p>Пример для наглядности:</p>
<pre><code class="language-cpp" data-line="">#include &lt;iostream&gt;
#include &lt;future&gt;
#include &lt;thread&gt;

int main() {
  auto worker = [](auto p) {
    try {     
        p.set_value(&quot;Hello world!&quot;);
        // Делаем что-то вызывающее исключение
    }
    catch(...) {
        // Передаём исключение
        p.set_exception(std::current_exception());
    }
  };

  std::promise&lt;std::string&gt; promise;
  auto f = promise.get_future();

  // Передаём promise по значению в поток с помощью перемещения
  std::thread t(worker, std::move(promise));

  try {
     std::cout &lt;&lt; f.get() &lt;&lt; std::endl;
  } 
  catch (const std::exception &amp;e) {
     std::cerr &lt;&lt; &quot;Exception : &quot; &lt;&lt; e.what() &lt;&lt; std::endl;
  }

  t.join();
}
</code></pre>
<p><code class="" data-line="">std::future</code> можно использовать для получения значения только один раз и нельзя копировать, если хотите это изменить, создайте <code class="" data-line="">std::shared_future</code> с помощью метода <code class="" data-line="">std::future::share()</code> &#8212; этот класс лишён таких недостатков.</p>
<h2>Что такое deadlock и как происходит?</h2>
<p>Блокирование потоков в ожидании друг друга. Происходит, когда в потоке <code class="" data-line="">A</code> блокируется мьютекс <code class="" data-line="">a</code>, потом <code class="" data-line="">b</code>. А в потоке <code class="" data-line="">B</code> сначала мьютекс <code class="" data-line="">b</code>, потом <code class="" data-line="">a</code>. Исправляется использованием <code class="" data-line="">std::scoped_lock</code> или одинаковым порядком блокирования мьютексов.</p>
<h2>Зачем нужен <code class="" data-line="">std::shared_mutex</code>?</h2>
<p>Вместе с <code class="" data-line="">std::shared_lock</code> и <code class="" data-line="">std::unique_lock</code> <code class="" data-line="">std::shared_mutex</code> обеспечивает множественный доступ (на чтение) при использовании <code class="" data-line="">std::shared_lock</code> и эксклюзивный доступ (на запись) при использовании <code class="" data-line="">std::unique_lock</code> соответственно.</p>
<p>Пример для наглядности:</p>
<pre><code class="language-cpp" data-line="">std::shared_mutex mutex;
std::vector&lt;int&gt; data;

void write(int value) { 
    std::unique_lock lock(mutex); // эксклюзивная блокировка
    data.push_back(value);
}

int read(size_t index) {
    std::shared_lock lock(mutex); // разделяемая блокировка
    return data.at(index);
}
</code></pre>
<h2>Зачем нужно указание <code class="" data-line="">memory_order</code> в объектах типа <code class="" data-line="">std::atomic</code>? Какие бывают <code class="" data-line="">memory_order</code>?</h2>
<p>Если вкратце, то <code class="" data-line="">memory_order</code> позволяет контролировать модель памяти для атомарных операций. Модель памяти определяет, как операции чтения и записи памяти могут быть переупорядочены компилятором и процессором для оптимизации. Начиная от самой слабой гарантии <code class="" data-line="">std::memory_order_relaxed</code> и заканчивая самой строгой <code class="" data-line="">std::memory_order_seq_cst</code> (по умолчанию). Если хотите подробнее вникнуть в тему, то вот сорокаминутное видео с объяснением от разработчика из Яндекса: </p>
<div class="sllv-video -type_youtube" data-provider="youtube" data-video="SIZmLPtcZiE"><a class="sllv-video__link" href="https://youtu.be/SIZmLPtcZiE?si=hwQ2yaSddEHvgKWU" rel="external noopener" target="_blank"><img decoding="async" class="sllv-video__media" src="https://i.ytimg.com/vi_webp/SIZmLPtcZiE/sddefault.webp" alt="Видео"></a><button class="sllv-video__button" type="button" aria-label="Воспроизвести видео"><svg width="68" height="48" viewBox="0 0 68 48"><path class="sllv-video__button-shape" d="M66.52 7.74c-.78-2.93-2.49-5.41-5.42-6.19C55.79.13 34 0 34 0S12.21.13 6.9 1.55c-2.93.78-4.63 3.26-5.42 6.19C.06 13.05 0 24 0 24s.06 10.95 1.48 16.26c.78 2.93 2.49 5.41 5.42 6.19C12.21 47.87 34 48 34 48s21.79-.13 27.1-1.55c2.93-.78 4.64-3.26 5.42-6.19C67.94 34.95 68 24 68 24s-.06-10.95-1.48-16.26z"/><path class="sllv-video__button-icon" d="M45 24L27 14v20"/></svg></button></div>
<h2>Чем процесс отличается от потока?</h2>
<p>Изолированностью в первую очередь. Процессы имеют свои ресурсы, потоки делят ресурсы одного процесса. Падение одного потока приводит к завершению всего процесса. Завершение процесса никак не затрагивает другие процессы.</p>
<h2>Что будет если вызвать new с огромным куском памяти?</h2>
<p>Произойдёт вызов исключения <code class="" data-line="">std::bad_alloc</code>, можно использовать <code class="" data-line="">new (std::nothrow)</code> если хочется получить <code class="" data-line="">nullptr</code> в случае неудачи.</p>
<h2>Как работает алгоритм <code class="" data-line="">std::remove</code>/<code class="" data-line="">std::remove_if</code></h2>
<p>Пробегаемся по контейнеру слева направо двумя итераторами:</p>
<ul>
<li>первый итератор (<code class="" data-line="">first</code>) указывает на текущий элемент </li>
<li>второй (<code class="" data-line="">result</code>) указывает на позицию куда сохранять подходящие элементы.</li>
</ul>
<p>Реализация алгоритма для наглядности:</p>
<pre><code class="language-cpp" data-line="">template&lt;typename ForwardIt, typename UnaryPredicate&gt;
ForwardIt remove_if(ForwardIt first, ForwardIt last, UnaryPredicate p) {
    ForwardIt result = first;
    for (; first != last; ++first) {
        if (!p(*first)) {
            if (result != first) {
                *result = std::move(*first);
            }
            ++result;
        }
    }
    return result;
}
</code></pre>
<h2>Какие бывают контейнеры STL. Устройство и сложность операций поиска/вставки/удаления.</h2>
<ul>
<li><code class="" data-line="">std::vector</code> &#8212; выделяет непрерывный кусок памяти, если не хватает места, то выделяется бОльший кусок, старые данные копируются туда, доступ имеет сложность O(1), вставка в конец имеет амортизированную сложность O(1), вставка в начало/середину требует сдвига всех данных вправо и имеет сложность O(n). Эффективно использует кеш процессора. Имеет возможность доступа по индексу.</li>
<li><code class="" data-line="">std::list</code> &#8212; двусвязный список, поиск O(n), доступ по индексу O(n), вставка O(1) при наличии итератора, удаление O(1) при наличии итератора, доступ к элементам по итератору.</li>
<li><code class="" data-line="">std::forward_list</code> &#8212; односвязный список, аналогичен <code class="" data-line="">std::list</code>, но занимает меньше памяти. Может вставлять/удалять только после известного элемента.</li>
<li><code class="" data-line="">std::deque</code> &#8212; двусторонняя очередь, реализуется как массив указателей на блоки, доступ O(1), вставка/удаление с начала/конца O(1), в середине O(n).</li>
<li><code class="" data-line="">std::unordered_set</code>/<code class="" data-line="">std::unordered_map</code> &#8212; хеш-таблица из бакетов, поиск, вставка, удаление O(1) в среднем случае, O(n) в худшем (при коллизиях), элементы без сортировки.</li>
<li><code class="" data-line="">std::set</code>/<code class="" data-line="">std::map</code> &#8212; красно-черные деревья, поиск/вставка/удаление O(log n). Элементы отсортированы.</li>
<li><code class="" data-line="">std::array</code> &#8212; аналог сишного массива фиксированного размера с плюшками STL в виде итераторов и деструктора</li>
<li><code class="" data-line="">std::span</code> &#8212; интерфейс для работы с непрерывными последовательностями данных без владения этими данными</li>
<li><code class="" data-line="">std::string_view</code> &#8212; аналог <code class="" data-line="">std::span</code> для <code class="" data-line="">std::string</code>, доступ к данным строки без владения</li>
</ul>
<h2>Что такое <em>универсальная ссылка</em>, что такое <em>perfect forwarding</em>?</h2>
<p><strong>Perfect forwarding</strong> &#8212; это способ передать аргумент в другую функцию точно так, как он был получен:</p>
<ul>
<li><code class="" data-line="">lvalue</code> остаётся <code class="" data-line="">lvalue</code></li>
<li><code class="" data-line="">rvalue</code> остаётся <code class="" data-line="">rvalue</code></li>
<li><code class="" data-line="">const</code> остаётся <code class="" data-line="">const</code></li>
</ul>
<p>Выглядит так:</p>
<pre><code class="language-cpp" data-line="">template&lt;typename T&gt;
void foo(T&amp;&amp;value) // T&amp;&amp; является универсальной ссылкой
{
    bar(std::forward&lt;T&gt;(value));
}
</code></pre>
<p>Тут есть важный нюанс для шаблонных классов, легко ошибиться:</p>
<pre><code class="language-cpp" data-line="">template&lt;typename T&gt;
class A {
    void foo(T&amp;&amp;value) // это не универсальная ссылка
    {
        bar(std::forward&lt;T&gt;(value));
    }

    template&lt;typename U&gt;
    void foo2(U&amp;&amp;value) // а здесь всё работает правильно 
    {
        bar(std::forward&lt;U&gt;(value));
    }
}
</code></pre>
<p>Требований для <strong>perfect forwarding</strong> два:</p>
<ol>
<li>Это должна быть шаблонная функция с <strong>универсальной ссылкой</strong></li>
<li>использование <code class="" data-line="">std::forward</code> для передачи параметров дальше</li>
</ol>
<p>Почему так сделано? Очевидно, потому, что создатели C++ ненавидят людей и желают им всего плохого, а если без шуток, то, чтобы избежать проблем при инстанцировании шаблона класса ну и щепотка ненависти к людям, конечно. Кстати <code class="" data-line="">T&amp;&amp;</code> становится универсальной ссылкой, только в контексте вывода параметров шаблона.</p>
<p>P.S. Благодарю создателей <a href="https://ru.wikipedia.org/wiki/Markdown" rel="nofollow" target="_blank">Markdown</a> за синтаксис языка разметки, всё форматирование сделано с помощью него.</p>
]]></content>
		
					<link rel="replies" type="text/html" href="https://blog2k.ru/archives/12320#comments" thr:count="0" />
			<link rel="replies" type="application/atom+xml" href="https://blog2k.ru/archives/12320/feed/atom" thr:count="0" />
			<thr:total>0</thr:total>
			</entry>
		<entry>
		<author>
			<name>eJ</name>
					</author>

		<title type="html"><![CDATA[Обновляем краткое содержания статей в блоге с помощью ИИ, денег, bash и wp-cli]]></title>
		<link rel="alternate" type="text/html" href="https://blog2k.ru/archives/12014" />

		<id>https://blog2k.ru/?p=12014</id>
		<updated>2025-11-29T05:28:15Z</updated>
		<published>2025-10-22T13:48:56Z</published>
		<category scheme="https://blog2k.ru" term="PHP" /><category scheme="https://blog2k.ru" term="Программирование" /><category scheme="https://blog2k.ru" term="bash" /><category scheme="https://blog2k.ru" term="WordPress API" /><category scheme="https://blog2k.ru" term="ИИ" /><category scheme="https://blog2k.ru" term="Полезная статья" />
		<summary type="html"><![CDATA[В статье описан bash-скрипт для обновления кратких описаний статей в блоге с помощью Yandex GPT. Скрипт автоматически формирует краткое содержание для каждой статьи и предлагает пользователю подтвердить его.]]></summary>

					<content type="html" xml:base="https://blog2k.ru/archives/12014"><![CDATA[<p>Всем привет! Если вы не первый раз на моём сайте, то могли заметить, что краткое содержание заметок содержит первые n слов (вроде, 22) из заметки безо всякого осмысления. По крайней мере, так было до недавнего времени.</p>
<p>Поскольку сейчас наступил XXI век, то пора передать формирование краткого содержания заметок на откуп искусственному интеллекту.</p>
<p>Делать плагин мне откровенно не хочется, поэтому я обновил все заметки с помощью bash-скрипта, запрашивая краткое содержание статьи через <code class="" data-line="">curl</code> у Yandex GPT через их API.</p>
<p>Алгоритм такой:</p>
<ul>
<li>получаю ID всех статей блога с помощью <a href="https://wp-cli.org/" rel="nofollow" target="_blank">wp-cli</a></li>
<li>для каждой статьи блога, отправляю её содержимое в Yandex GPT с помощью API</li>
<li>получаю краткую выжимку статьи и показываю пользователю</li>
<li>если он согласен с содержимым, то обновляю поле <code class="" data-line="">post_excerpt</code> у статьи</li>
<li>вывожу <code class="" data-line="">post_excerpt</code> в мета поле <code class="" data-line="">description</code> при формировании статьи в разделе <head></li>
<li>???</li>
<li>PROFIT</li>
</ul>
<p>Для регистрации и работы с Yandex GPT нужно немного денег, я потратил 50 рублей. Регистрация и получение идентификаторов каталога (<code class="" data-line="">folder_id</code>) и API ключа (<code class="" data-line="">api_key</code>) найдёте в этой статье на &#171;Хабре&#187;: (Как подключить Yandex GPT к своему проекту на Python)[https://habr.com/ru/articles/780008/].</p>
<p>Добавил в скрипт подтверждение каждого шага от пользователя, потому что иногда ИИ выдаёт какую-то политкорректную дичь типа &#171;Я не могу обсуждать эту тему. Давайте поговорим о чём-нибудь ещё&#187; на простые запросы, а также он не умеет работать с видео. И добавил проверку, что цитата не заполнена для поста, чтобы лишний раз не тратить запросы к ИИ.</p>
<p><span id="more-12014"></span>Перед запуском скрипта, не забудьте изменить <strong>folder_id</strong>, <strong>api_key</strong> и <strong>wordpress_dir</strong> на свои.</p>
<pre><code class="language-bash" data-line="">#!/usr/bin/env bash

# Конфигурация
FOLDER_ID=&quot;folder_id&quot;
API_KEY=&quot;api_key&quot;
API_URL=&quot;https://llm.api.cloud.yandex.net/foundationModels/v1/completion&quot;

wrap_for_yandexgpt() {
  local text=&quot;$1&quot;

  jq -n \
    --arg text &quot;$text&quot; \
    --arg folder &quot;$FOLDER_ID&quot; \
    &#039;{
      &quot;modelUri&quot;: &quot;gpt://\($folder)/yandexgpt-lite&quot;,
      &quot;completionOptions&quot;: {
        &quot;stream&quot;: false,
        &quot;temperature&quot;: 0.3,
        &quot;maxTokens&quot;: &quot;2000&quot;
      },
    &quot;messages&quot;: [
    {
      &quot;role&quot;: &quot;user&quot;,
      &quot;text&quot;: $text
    }
  ]
}&#039;
}

# Функция для отправки запроса
create_post_excerpt() {
  local content=&quot;$1&quot;
  local prompt=&quot;Сделай краткое метаописание статьи (до 60 слов):\n\n$content&quot;
  local json_payload
  json_payload=$(wrap_for_yandexgpt &quot;$prompt&quot;)

  # Выполняем запрос и сохраняем ответ в переменную
  local response
  response=$(curl -s -w &quot;\nHTTPSTATUS:%{http_code}&quot; -X POST -H &quot;Content-Type: application/json&quot; -H &quot;Authorization: Api-Key $API_KEY&quot; -H &quot;x-folder-id: $FOLDER_ID&quot; -d &quot;$json_payload&quot; $API_URL)

  # Проверяем, что curl выполнился успешно
  if [ $? -ne 0 ]; then
    echo &quot;Ошибка выполнения curl&quot; &gt;&amp;2
    return 1
  fi

  # Извлекаем HTTP код и тело ответа
  local http_code
  local body
  http_code=$(echo &quot;$response&quot; | sed -n &#039;s/HTTPSTATUS://p&#039;)
  body=$(echo &quot;$response&quot; | sed &#039;$d&#039;)

  # Проверяем HTTP-код
  if [ &quot;$http_code&quot; -ne 200 ]; then
    echo &quot;ошибка HTTP: $http_code&quot; &gt;&amp;2
    return 1
  fi

  # Проверяем наличие ошибки в теле ответа
  if echo &quot;$body&quot; | jq -e &#039;.error&#039; &gt;/dev/null 2&gt;&amp;1; then
    local error_msg
    error_msg=$(echo &quot;$body&quot; | jq -r &#039;.error.message // .error&#039;)
    echo &quot;ошибка API: $error_msg&quot; &gt;&amp;2
    return 1
  fi  

  # Извлекаем текст
  local result
  result=$(echo &quot;$body&quot; | jq -r &#039;.result.alternatives[0].message.text // empty&#039;)

  if [ -z &quot;$result&quot; ]; then
    echo &quot;пустой ответ от API&quot; &gt;&amp;2
    return 1
  fi

  local status
  status=$(echo &quot;$body&quot; | jq -r &#039;.result.alternatives[0].status // empty&#039;)

  if [ &quot;$status&quot; == &quot;ALTERNATIVE_STATUS_CONTENT_FILTER&quot; ]; then
    echo &quot;[cencored]&quot;
    return 1
  fi

  echo &quot;$result&quot;
  return 0
}

update_post_excerpt() {
  local post_id=$1
  local excerpt=&quot;$2&quot;
  wp --allow-root post update &quot;$post_id&quot; --post_excerpt=&quot;$excerpt&quot;
}

get_post_excerpt() {
  local post_id=$1
  wp --allow-root post get &quot;$post_id&quot; --field=post_excerpt
}

get_post_title() {
  local posts_data=&quot;$1&quot;
  local post_id=&quot;$2&quot;

  echo &quot;$posts_data&quot; | jq &quot;.[] | select(.ID==$post_id) | .post_title&quot;
}

get_post_content() {
  local posts_data=&quot;$1&quot;
  local post_id=&quot;$2&quot;

  echo &quot;$posts_data&quot; | jq &quot;.[] | select(.ID==$post_id) | .post_content&quot;
}


cd wordpress_dir || exit

posts_data=$(wp post list --allow-root --post_type=post --fields=ID,post_title,post_content,post_excerpt --format=json --post_status=publish | jq &#039;map(select(.post_excerpt==&quot;&quot; or .post_excerpt==null))&#039;)

post_ids=$(echo &quot;$posts_data&quot; | jq .[].ID)

for post_id in $post_ids; do
  title=$(get_post_title &quot;$posts_data&quot; &quot;$post_id&quot;)
  echo &quot;ЗАГОЛОВОК: $title&quot;
  content=$(get_post_content &quot;$posts_data&quot; &quot;$post_id&quot;)
  post_excerpt=$(create_post_excerpt &quot;$content&quot;)
  exit_code=$?

  if [ $exit_code -ne 0 ]; then
    echo &quot;ОШИБКА ПОЛУЧЕНИЯ ЦИТАТЫ: $post_excerpt&quot;
    echo
    continue
  fi

  echo &quot;ЦИТАТА: \&quot;$post_excerpt\&quot;&quot;

  while true; do
    read -r -n1 -p &quot;Обновить цитату? (y - да, n - пропустить, q - выход) &quot; choice
    choice=$(echo &quot;$choice&quot; | tr &#039;[:upper:]&#039; &#039;[:lower:]&#039;)
    echo

    case $choice in
      y)
        update_post_excerpt &quot;$post_id&quot; &quot;$post_excerpt&quot;
        break
        ;;
      n)
        break
        ;;
      q)
        exit 0
        ;;
      *)
        continue
        ;;
    esac
  done

  echo
done

cd - || exit
</code></pre>
<p>Всё, что делает этот скрипт он делает только под вашу личную ответственность. Я никаких гарантий не даю и ответственности за результат не несу. Примерно половину скрипта написал DeepSeek, претензии к нему.</p>
<p><strong>UPD</strong>. Выложил скрипты на <a href="https://github.com/jirnov/freebsd-scripts" rel="nofollow" target="_blank">GitHub</a>.</p>
]]></content>
		
					<link rel="replies" type="text/html" href="https://blog2k.ru/archives/12014#comments" thr:count="0" />
			<link rel="replies" type="application/atom+xml" href="https://blog2k.ru/archives/12014/feed/atom" thr:count="0" />
			<thr:total>0</thr:total>
			</entry>
		<entry>
		<author>
			<name>eJ</name>
					</author>

		<title type="html"><![CDATA[Добавляем подсветку нового языка в плагин Prismatic+Prism.js]]></title>
		<link rel="alternate" type="text/html" href="https://blog2k.ru/archives/11982" />

		<id>https://blog2k.ru/?p=11982</id>
		<updated>2025-12-09T12:18:33Z</updated>
		<published>2025-10-14T10:30:40Z</published>
		<category scheme="https://blog2k.ru" term="JavaScript" /><category scheme="https://blog2k.ru" term="PHP" /><category scheme="https://blog2k.ru" term="Программирование" /><category scheme="https://blog2k.ru" term="WordPress API" />
		<summary type="html"><![CDATA[Инструкция по добавлению языка CMake в плагин Prismatic для подсветки кода в WordPress. Подробно описан процесс загрузки и интеграции файла с языком в папку плагина.]]></summary>

					<content type="html" xml:base="https://blog2k.ru/archives/11982"><![CDATA[<p>Всем привет! Понадобилось мне вставить <code class="" data-line="">CMakeLists.txt</code> в <a href="https://blog2k.ru/archives/11969" target="_blank">мою заметку</a> с подсветкой кода. В блоге она включена с помощью плагина <a href="https://wordpress.org/plugins/prismatic/" rel="nofollow" target="_blank">Prismatic</a> и библиотеки <a href="https://prismjs.com/" rel="nofollow" target="_blank">Prism.js</a> c темой &#171;Tomorow Night&#187;, если вам интересно. И так родилась эта инструкция по добавлению нового языка (в нашем случае CMake) в плагин. Все работы проходят в папке плагина <code class="" data-line="">wp-content/plugins/prismatic</code>, порядок действий следующий:</p>
<ol>
<li>Переходим на страницу скачивания <a href="https://prismjs.com/download#themes=prism&#038;languages=cmake" rel="nofollow" target="_blank">Prism</a>. Выбираем minified версию и только тот язык, который вам нужен, у меня был язык cmake и получился файл на 18 килобайт.</li>
<li>Вставляем по адресу <code class="" data-line="">./lib/prism/js/lang-cmake.js</code> кусок кода с <code class="" data-line="">Prism.language.cmake</code>. <a href="/wp-content/plugins/prismatic/lib/prism/js/lang-cmake.js" rel="nofollow" target="_blank">Пример lang-cmake.js</a></li>
<li>Открываем <code class="" data-line="">./inc/resources-enqueue.php</code> в функции <code class="" data-line="">prismatic_prism_classes</code> в первом массиве после <code class="" data-line="">&#039;language-bash&#039;</code> вставляем <code class="" data-line="">&#039;language-cmake&#039;</code>, во втором после <code class="" data-line="">&#039;lang-bash&#039;</code> вставляем <code class="" data-line="">&#039;lang-cmake&#039;</code>.</li>
</ol>
<p>Мне кажется, первый массив отвечает за название CSS класса, а второй &#8212; название JS файла, но я не уверен, потому что я ненастоящий PHP программист.</p>
<p>Патч под спойлером к с версии 3.6:<br />
<div class="spoiler-wrap"><div class="spoiler-head folded">Подсветка синтаксиса CMake в Prismatic + Prism</div><div class="spoiler-body"></p>
<pre><code class="language-diff" data-line="">Index: inc/resources-enqueue.php
===================================================================
--- inc/resources-enqueue.php   (revision 3415040)
+++ inc/resources-enqueue.php   (working copy)
@@ -458,6 +458,7 @@ function prismatic_prism_classes() {
            &#039;language-batch&#039;, 
            &#039;language-c&#039;, 
            &#039;language-clike&#039;, 
+           &#039;language-cmake&#039;, 
            &#039;language-coffeescript&#039;, 
            &#039;language-cpp&#039;, 
            &#039;language-csharp&#039;, 
@@ -542,6 +543,7 @@ function prismatic_prism_classes() {
            &#039;lang-batch&#039;, 
            &#039;lang-c&#039;, 
            &#039;lang-clike&#039;, 
+           &#039;lang-cmake&#039;, 
            &#039;lang-coffeescript&#039;, 
            &#039;lang-cpp&#039;, 
            &#039;lang-csharp&#039;, 
@@ -651,4 +653,4 @@ function prismatic_get_current_screen_id() {
    
    return false;
    
-}
\ No newline at end of file
+}
Index: lib/prism/js/lang-cmake.js
===================================================================
--- lib/prism/js/lang-cmake.js  (nonexistent)
+++ lib/prism/js/lang-cmake.js  (working copy)
@@ -0,0 +1 @@
+Prism.languages.cmake={comment:/#.*/,string:{pattern:/&quot;(?:[^\\&quot;]|\\.)*&quot;/,greedy:!0,inside:{interpolation:{pattern:/\$\{(?:[^{}$]|\$\{[^{}$]*\})*\}/,inside:{punctuation:/\$\{|\}/,variable:/\w+/}}}},variable:/\b(?:CMAKE_\w+|\w+_(?:(?:BINARY|SOURCE)_DIR|DESCRIPTION|HOMEPAGE_URL|ROOT|VERSION(?:_MAJOR|_MINOR|_PATCH|_TWEAK)?)|(?:ANDROID|APPLE|BORLAND|BUILD_SHARED_LIBS|CACHE|CPACK_(?:ABSOLUTE_DESTINATION_FILES|COMPONENT_INCLUDE_TOPLEVEL_DIRECTORY|ERROR_ON_ABSOLUTE_INSTALL_DESTINATION|INCLUDE_TOPLEVEL_DIRECTORY|INSTALL_DEFAULT_DIRECTORY_PERMISSIONS|INSTALL_SCRIPT|PACKAGING_INSTALL_PREFIX|SET_DESTDIR|WARN_ON_ABSOLUTE_INSTALL_DESTINATION)|CTEST_(?:BINARY_DIRECTORY|BUILD_COMMAND|BUILD_NAME|BZR_COMMAND|BZR_UPDATE_OPTIONS|CHANGE_ID|CHECKOUT_COMMAND|CONFIGURATION_TYPE|CONFIGURE_COMMAND|COVERAGE_COMMAND|COVERAGE_EXTRA_FLAGS|CURL_OPTIONS|CUSTOM_(?:COVERAGE_EXCLUDE|ERROR_EXCEPTION|ERROR_MATCH|ERROR_POST_CONTEXT|ERROR_PRE_CONTEXT|MAXIMUM_FAILED_TEST_OUTPUT_SIZE|MAXIMUM_NUMBER_OF_(?:ERRORS|WARNINGS)|MAXIMUM_PASSED_TEST_OUTPUT_SIZE|MEMCHECK_IGNORE|POST_MEMCHECK|POST_TEST|PRE_MEMCHECK|PRE_TEST|TESTS_IGNORE|WARNING_EXCEPTION|WARNING_MATCH)|CVS_CHECKOUT|CVS_COMMAND|CVS_UPDATE_OPTIONS|DROP_LOCATION|DROP_METHOD|DROP_SITE|DROP_SITE_CDASH|DROP_SITE_PASSWORD|DROP_SITE_USER|EXTRA_COVERAGE_GLOB|GIT_COMMAND|GIT_INIT_SUBMODULES|GIT_UPDATE_CUSTOM|GIT_UPDATE_OPTIONS|HG_COMMAND|HG_UPDATE_OPTIONS|LABELS_FOR_SUBPROJECTS|MEMORYCHECK_(?:COMMAND|COMMAND_OPTIONS|SANITIZER_OPTIONS|SUPPRESSIONS_FILE|TYPE)|NIGHTLY_START_TIME|P4_CLIENT|P4_COMMAND|P4_OPTIONS|P4_UPDATE_OPTIONS|RUN_CURRENT_SCRIPT|SCP_COMMAND|SITE|SOURCE_DIRECTORY|SUBMIT_URL|SVN_COMMAND|SVN_OPTIONS|SVN_UPDATE_OPTIONS|TEST_LOAD|TEST_TIMEOUT|TRIGGER_SITE|UPDATE_COMMAND|UPDATE_OPTIONS|UPDATE_VERSION_ONLY|USE_LAUNCHERS)|CYGWIN|ENV|EXECUTABLE_OUTPUT_PATH|GHS-MULTI|IOS|LIBRARY_OUTPUT_PATH|MINGW|MSVC(?:10|11|12|14|60|70|71|80|90|_IDE|_TOOLSET_VERSION|_VERSION)?|MSYS|PROJECT_NAME|UNIX|WIN32|WINCE|WINDOWS_PHONE|WINDOWS_STORE|XCODE))\b/,property:/\b(?:cxx_\w+|(?:ARCHIVE_OUTPUT_(?:DIRECTORY|NAME)|COMPILE_DEFINITIONS|COMPILE_PDB_NAME|COMPILE_PDB_OUTPUT_DIRECTORY|EXCLUDE_FROM_DEFAULT_BUILD|IMPORTED_(?:IMPLIB|LIBNAME|LINK_DEPENDENT_LIBRARIES|LINK_INTERFACE_LANGUAGES|LINK_INTERFACE_LIBRARIES|LINK_INTERFACE_MULTIPLICITY|LOCATION|NO_SONAME|OBJECTS|SONAME)|INTERPROCEDURAL_OPTIMIZATION|LIBRARY_OUTPUT_DIRECTORY|LIBRARY_OUTPUT_NAME|LINK_FLAGS|LINK_INTERFACE_LIBRARIES|LINK_INTERFACE_MULTIPLICITY|LOCATION|MAP_IMPORTED_CONFIG|OSX_ARCHITECTURES|OUTPUT_NAME|PDB_NAME|PDB_OUTPUT_DIRECTORY|RUNTIME_OUTPUT_DIRECTORY|RUNTIME_OUTPUT_NAME|STATIC_LIBRARY_FLAGS|VS_CSHARP|VS_DOTNET_REFERENCEPROP|VS_DOTNET_REFERENCE|VS_GLOBAL_SECTION_POST|VS_GLOBAL_SECTION_PRE|VS_GLOBAL|XCODE_ATTRIBUTE)_\w+|\w+_(?:CLANG_TIDY|COMPILER_LAUNCHER|CPPCHECK|CPPLINT|INCLUDE_WHAT_YOU_USE|OUTPUT_NAME|POSTFIX|VISIBILITY_PRESET)|ABSTRACT|ADDITIONAL_MAKE_CLEAN_FILES|ADVANCED|ALIASED_TARGET|ALLOW_DUPLICATE_CUSTOM_TARGETS|ANDROID_(?:ANT_ADDITIONAL_OPTIONS|API|API_MIN|ARCH|ASSETS_DIRECTORIES|GUI|JAR_DEPENDENCIES|NATIVE_LIB_DEPENDENCIES|NATIVE_LIB_DIRECTORIES|PROCESS_MAX|PROGUARD|PROGUARD_CONFIG_PATH|SECURE_PROPS_PATH|SKIP_ANT_STEP|STL_TYPE)|ARCHIVE_OUTPUT_DIRECTORY|ATTACHED_FILES|ATTACHED_FILES_ON_FAIL|AUTOGEN_(?:BUILD_DIR|ORIGIN_DEPENDS|PARALLEL|SOURCE_GROUP|TARGETS_FOLDER|TARGET_DEPENDS)|AUTOMOC|AUTOMOC_(?:COMPILER_PREDEFINES|DEPEND_FILTERS|EXECUTABLE|MACRO_NAMES|MOC_OPTIONS|SOURCE_GROUP|TARGETS_FOLDER)|AUTORCC|AUTORCC_EXECUTABLE|AUTORCC_OPTIONS|AUTORCC_SOURCE_GROUP|AUTOUIC|AUTOUIC_EXECUTABLE|AUTOUIC_OPTIONS|AUTOUIC_SEARCH_PATHS|BINARY_DIR|BUILDSYSTEM_TARGETS|BUILD_RPATH|BUILD_RPATH_USE_ORIGIN|BUILD_WITH_INSTALL_NAME_DIR|BUILD_WITH_INSTALL_RPATH|BUNDLE|BUNDLE_EXTENSION|CACHE_VARIABLES|CLEAN_NO_CUSTOM|COMMON_LANGUAGE_RUNTIME|COMPATIBLE_INTERFACE_(?:BOOL|NUMBER_MAX|NUMBER_MIN|STRING)|COMPILE_(?:DEFINITIONS|FEATURES|FLAGS|OPTIONS|PDB_NAME|PDB_OUTPUT_DIRECTORY)|COST|CPACK_DESKTOP_SHORTCUTS|CPACK_NEVER_OVERWRITE|CPACK_PERMANENT|CPACK_STARTUP_SHORTCUTS|CPACK_START_MENU_SHORTCUTS|CPACK_WIX_ACL|CROSSCOMPILING_EMULATOR|CUDA_EXTENSIONS|CUDA_PTX_COMPILATION|CUDA_RESOLVE_DEVICE_SYMBOLS|CUDA_SEPARABLE_COMPILATION|CUDA_STANDARD|CUDA_STANDARD_REQUIRED|CXX_EXTENSIONS|CXX_STANDARD|CXX_STANDARD_REQUIRED|C_EXTENSIONS|C_STANDARD|C_STANDARD_REQUIRED|DEBUG_CONFIGURATIONS|DEFINE_SYMBOL|DEFINITIONS|DEPENDS|DEPLOYMENT_ADDITIONAL_FILES|DEPLOYMENT_REMOTE_DIRECTORY|DISABLED|DISABLED_FEATURES|ECLIPSE_EXTRA_CPROJECT_CONTENTS|ECLIPSE_EXTRA_NATURES|ENABLED_FEATURES|ENABLED_LANGUAGES|ENABLE_EXPORTS|ENVIRONMENT|EXCLUDE_FROM_ALL|EXCLUDE_FROM_DEFAULT_BUILD|EXPORT_NAME|EXPORT_PROPERTIES|EXTERNAL_OBJECT|EchoString|FAIL_REGULAR_EXPRESSION|FIND_LIBRARY_USE_LIB32_PATHS|FIND_LIBRARY_USE_LIB64_PATHS|FIND_LIBRARY_USE_LIBX32_PATHS|FIND_LIBRARY_USE_OPENBSD_VERSIONING|FIXTURES_CLEANUP|FIXTURES_REQUIRED|FIXTURES_SETUP|FOLDER|FRAMEWORK|Fortran_FORMAT|Fortran_MODULE_DIRECTORY|GENERATED|GENERATOR_FILE_NAME|GENERATOR_IS_MULTI_CONFIG|GHS_INTEGRITY_APP|GHS_NO_SOURCE_GROUP_FILE|GLOBAL_DEPENDS_DEBUG_MODE|GLOBAL_DEPENDS_NO_CYCLES|GNUtoMS|HAS_CXX|HEADER_FILE_ONLY|HELPSTRING|IMPLICIT_DEPENDS_INCLUDE_TRANSFORM|IMPORTED|IMPORTED_(?:COMMON_LANGUAGE_RUNTIME|CONFIGURATIONS|GLOBAL|IMPLIB|LIBNAME|LINK_DEPENDENT_LIBRARIES|LINK_INTERFACE_(?:LANGUAGES|LIBRARIES|MULTIPLICITY)|LOCATION|NO_SONAME|OBJECTS|SONAME)|IMPORT_PREFIX|IMPORT_SUFFIX|INCLUDE_DIRECTORIES|INCLUDE_REGULAR_EXPRESSION|INSTALL_NAME_DIR|INSTALL_RPATH|INSTALL_RPATH_USE_LINK_PATH|INTERFACE_(?:AUTOUIC_OPTIONS|COMPILE_DEFINITIONS|COMPILE_FEATURES|COMPILE_OPTIONS|INCLUDE_DIRECTORIES|LINK_DEPENDS|LINK_DIRECTORIES|LINK_LIBRARIES|LINK_OPTIONS|POSITION_INDEPENDENT_CODE|SOURCES|SYSTEM_INCLUDE_DIRECTORIES)|INTERPROCEDURAL_OPTIMIZATION|IN_TRY_COMPILE|IOS_INSTALL_COMBINED|JOB_POOLS|JOB_POOL_COMPILE|JOB_POOL_LINK|KEEP_EXTENSION|LABELS|LANGUAGE|LIBRARY_OUTPUT_DIRECTORY|LINKER_LANGUAGE|LINK_(?:DEPENDS|DEPENDS_NO_SHARED|DIRECTORIES|FLAGS|INTERFACE_LIBRARIES|INTERFACE_MULTIPLICITY|LIBRARIES|OPTIONS|SEARCH_END_STATIC|SEARCH_START_STATIC|WHAT_YOU_USE)|LISTFILE_STACK|LOCATION|MACOSX_BUNDLE|MACOSX_BUNDLE_INFO_PLIST|MACOSX_FRAMEWORK_INFO_PLIST|MACOSX_PACKAGE_LOCATION|MACOSX_RPATH|MACROS|MANUALLY_ADDED_DEPENDENCIES|MEASUREMENT|MODIFIED|NAME|NO_SONAME|NO_SYSTEM_FROM_IMPORTED|OBJECT_DEPENDS|OBJECT_OUTPUTS|OSX_ARCHITECTURES|OUTPUT_NAME|PACKAGES_FOUND|PACKAGES_NOT_FOUND|PARENT_DIRECTORY|PASS_REGULAR_EXPRESSION|PDB_NAME|PDB_OUTPUT_DIRECTORY|POSITION_INDEPENDENT_CODE|POST_INSTALL_SCRIPT|PREDEFINED_TARGETS_FOLDER|PREFIX|PRE_INSTALL_SCRIPT|PRIVATE_HEADER|PROCESSORS|PROCESSOR_AFFINITY|PROJECT_LABEL|PUBLIC_HEADER|REPORT_UNDEFINED_PROPERTIES|REQUIRED_FILES|RESOURCE|RESOURCE_LOCK|RULE_LAUNCH_COMPILE|RULE_LAUNCH_CUSTOM|RULE_LAUNCH_LINK|RULE_MESSAGES|RUNTIME_OUTPUT_DIRECTORY|RUN_SERIAL|SKIP_AUTOGEN|SKIP_AUTOMOC|SKIP_AUTORCC|SKIP_AUTOUIC|SKIP_BUILD_RPATH|SKIP_RETURN_CODE|SOURCES|SOURCE_DIR|SOVERSION|STATIC_LIBRARY_FLAGS|STATIC_LIBRARY_OPTIONS|STRINGS|SUBDIRECTORIES|SUFFIX|SYMBOLIC|TARGET_ARCHIVES_MAY_BE_SHARED_LIBS|TARGET_MESSAGES|TARGET_SUPPORTS_SHARED_LIBS|TESTS|TEST_INCLUDE_FILE|TEST_INCLUDE_FILES|TIMEOUT|TIMEOUT_AFTER_MATCH|TYPE|USE_FOLDERS|VALUE|VARIABLES|VERSION|VISIBILITY_INLINES_HIDDEN|VS_(?:CONFIGURATION_TYPE|COPY_TO_OUT_DIR|DEBUGGER_(?:COMMAND|COMMAND_ARGUMENTS|ENVIRONMENT|WORKING_DIRECTORY)|DEPLOYMENT_CONTENT|DEPLOYMENT_LOCATION|DOTNET_REFERENCES|DOTNET_REFERENCES_COPY_LOCAL|INCLUDE_IN_VSIX|IOT_STARTUP_TASK|KEYWORD|RESOURCE_GENERATOR|SCC_AUXPATH|SCC_LOCALPATH|SCC_PROJECTNAME|SCC_PROVIDER|SDK_REFERENCES|SHADER_(?:DISABLE_OPTIMIZATIONS|ENABLE_DEBUG|ENTRYPOINT|FLAGS|MODEL|OBJECT_FILE_NAME|OUTPUT_HEADER_FILE|TYPE|VARIABLE_NAME)|STARTUP_PROJECT|TOOL_OVERRIDE|USER_PROPS|WINRT_COMPONENT|WINRT_EXTENSIONS|WINRT_REFERENCES|XAML_TYPE)|WILL_FAIL|WIN32_EXECUTABLE|WINDOWS_EXPORT_ALL_SYMBOLS|WORKING_DIRECTORY|WRAP_EXCLUDE|XCODE_(?:EMIT_EFFECTIVE_PLATFORM_NAME|EXPLICIT_FILE_TYPE|FILE_ATTRIBUTES|LAST_KNOWN_FILE_TYPE|PRODUCT_TYPE|SCHEME_(?:ADDRESS_SANITIZER|ADDRESS_SANITIZER_USE_AFTER_RETURN|ARGUMENTS|DISABLE_MAIN_THREAD_CHECKER|DYNAMIC_LIBRARY_LOADS|DYNAMIC_LINKER_API_USAGE|ENVIRONMENT|EXECUTABLE|GUARD_MALLOC|MAIN_THREAD_CHECKER_STOP|MALLOC_GUARD_EDGES|MALLOC_SCRIBBLE|MALLOC_STACK|THREAD_SANITIZER(?:_STOP)?|UNDEFINED_BEHAVIOUR_SANITIZER(?:_STOP)?|ZOMBIE_OBJECTS))|XCTEST)\b/,keyword:/\b(?:add_compile_definitions|add_compile_options|add_custom_command|add_custom_target|add_definitions|add_dependencies|add_executable|add_library|add_link_options|add_subdirectory|add_test|aux_source_directory|break|build_command|build_name|cmake_host_system_information|cmake_minimum_required|cmake_parse_arguments|cmake_policy|configure_file|continue|create_test_sourcelist|ctest_build|ctest_configure|ctest_coverage|ctest_empty_binary_directory|ctest_memcheck|ctest_read_custom_files|ctest_run_script|ctest_sleep|ctest_start|ctest_submit|ctest_test|ctest_update|ctest_upload|define_property|else|elseif|enable_language|enable_testing|endforeach|endfunction|endif|endmacro|endwhile|exec_program|execute_process|export|export_library_dependencies|file|find_file|find_library|find_package|find_path|find_program|fltk_wrap_ui|foreach|function|get_cmake_property|get_directory_property|get_filename_component|get_property|get_source_file_property|get_target_property|get_test_property|if|include|include_directories|include_external_msproject|include_guard|include_regular_expression|install|install_files|install_programs|install_targets|link_directories|link_libraries|list|load_cache|load_command|macro|make_directory|mark_as_advanced|math|message|option|output_required_files|project|qt_wrap_cpp|qt_wrap_ui|remove|remove_definitions|return|separate_arguments|set|set_directory_properties|set_property|set_source_files_properties|set_target_properties|set_tests_properties|site_name|source_group|string|subdir_depends|subdirs|target_compile_definitions|target_compile_features|target_compile_options|target_include_directories|target_link_directories|target_link_libraries|target_link_options|target_sources|try_compile|try_run|unset|use_mangled_mesa|utility_source|variable_requires|variable_watch|while|write_file)(?=\s*\()\b/,boolean:/\b(?:FALSE|OFF|ON|TRUE)\b/,namespace:/\b(?:INTERFACE|PRIVATE|PROPERTIES|PUBLIC|SHARED|STATIC|TARGET_OBJECTS)\b/,operator:/\b(?:AND|DEFINED|EQUAL|GREATER|LESS|MATCHES|NOT|OR|STREQUAL|STRGREATER|STRLESS|VERSION_EQUAL|VERSION_GREATER|VERSION_LESS)\b/,inserted:{pattern:/\b\w+::\w+\b/,alias:&quot;class-name&quot;},number:/\b\d+(?:\.\d+)*\b/,function:/\b[a-z_]\w*(?=\s*\()\b/i,punctuation:/[()&gt;}]|\$[&lt;{]/};
\ No newline at end of file
</code></pre>
<p></div></div></p>
<p><strong>UPD</strong>: Послал патч автору плагина Prismatic, так что есть вероятность, что подсветка cmake появится в следующих версиях, но это не точно.</p>
]]></content>
		
					<link rel="replies" type="text/html" href="https://blog2k.ru/archives/11982#comments" thr:count="0" />
			<link rel="replies" type="application/atom+xml" href="https://blog2k.ru/archives/11982/feed/atom" thr:count="0" />
			<thr:total>0</thr:total>
			</entry>
		<entry>
		<author>
			<name>eJ</name>
					</author>

		<title type="html"><![CDATA[Подключение git репозитория в CMake]]></title>
		<link rel="alternate" type="text/html" href="https://blog2k.ru/archives/11969" />

		<id>https://blog2k.ru/?p=11969</id>
		<updated>2025-11-03T08:22:19Z</updated>
		<published>2025-10-14T10:29:21Z</published>
		<category scheme="https://blog2k.ru" term="C++" /><category scheme="https://blog2k.ru" term="Программирование" /><category scheme="https://blog2k.ru" term="CMake" />
		<summary type="html"><![CDATA[В статье описывается, как с помощью CMake и команды FetchContent подключить библиотеку SFML в проект. CMake автоматически скачает и подключит SFML.]]></summary>

					<content type="html" xml:base="https://blog2k.ru/archives/11969"><![CDATA[<p>Всем привет, недавно изучал либу <a href="https://www.sfml-dev.org/" rel="nofollow" target="_blank">SFML</a> и с удивлением обнаружил, что её <a href="https://github.com/SFML/cmake-sfml-project" rel="nofollow" target="_blank">можно подключить</a> в CMakeLists.txt с помощью команды <a href="https://cmake.org/cmake/help/latest/module/FetchContent.html" rel="nofollow" target="_blank">FetchContent</a> следующим образом:</p>
<pre><code class="language-cmake" data-line="">cmake_minimum_required(VERSION 3.28)

project(main LANGUAGES CXX)

include(FetchContent)
FetchContent_Declare(SFML
    GIT_REPOSITORY https://github.com/SFML/SFML.git
    GIT_TAG 3.0.2
    GIT_SHALLOW ON
    EXCLUDE_FROM_ALL
    SYSTEM)
FetchContent_MakeAvailable(SFML)

add_executable(main src/main.cpp)
target_compile_features(main PRIVATE cxx_std_17)
target_link_libraries(main PRIVATE SFML::Graphics)
</code>
</pre>
<p>И при создании файлов для сборки, CMake самостоятельно скачает и подключит SFML к вашему проекту &#8212; чистая магия, на мой взгляд.</p>
]]></content>
		
					<link rel="replies" type="text/html" href="https://blog2k.ru/archives/11969#comments" thr:count="0" />
			<link rel="replies" type="application/atom+xml" href="https://blog2k.ru/archives/11969/feed/atom" thr:count="0" />
			<thr:total>0</thr:total>
			</entry>
		<entry>
		<author>
			<name>eJ</name>
					</author>

		<title type="html"><![CDATA[Как я тестовое задание делал]]></title>
		<link rel="alternate" type="text/html" href="https://blog2k.ru/archives/11915" />

		<id>https://blog2k.ru/?p=11915</id>
		<updated>2025-11-29T05:29:36Z</updated>
		<published>2025-10-02T12:12:25Z</published>
		<category scheme="https://blog2k.ru" term="C++" /><category scheme="https://blog2k.ru" term="Программирование" /><category scheme="https://blog2k.ru" term="CMake" /><category scheme="https://blog2k.ru" term="OpenGL" /><category scheme="https://blog2k.ru" term="Visual Studio" />
		<summary type="html"><![CDATA[Автор рассказывает о прохождении тестового задания. В статье описан процесс работы над заданием, с какими трудностями столкнулся автор и как их решал.]]></summary>

					<content type="html" xml:base="https://blog2k.ru/archives/11915"><![CDATA[<p>В конце сентября сходил на собеседование в некую компанию и получил тестовое задание сроком на семь дней. При этом работу предлагали в офисе. Но есть нюансы!</p>
<p>Во-первых, за время работы в &#171;Газпром-Медиа&#187; я отвык работать в офисе. Во-вторых, я уверен, что выполнение тестового задания должно быть оплачено, тем более это целый проект. В-третьих, что-то мне подсказывало, что тестовое задание не примут в любом случае, потому что я не сказал <em>способ нахождения пересечения луча со сферой</em>, да и манера общения в целом мне не понравилась. Тем не менее, с целью узнать что-то новое и в качестве разминки для мозгов, тестовое задание таки взялся выполнять. Ниже расскажу, как это было.</p>
<p>Если описать общими словами задание, то оно звучит так: сделать приложение, имитирующее джекпот автомат с пятью барабанами, которые должны вращаться при нажатии анимированной кнопки &#171;START&#187; и замедляться по очереди спустя 4-5 секунд.<br />
<span id="more-11915"></span></p>
<hr />
<h2>Суббота (утро, за шесть дней до дедлайна)</h2>
<ul>
<li>В основном составлял план решения задачи.</li>
<li>Загуглил, как работать с OpenGL на Desktop: с помощью <strong>GLUT</strong> (который устарел и вместо него берут <strong>FreeGLUT</strong>) и <strong>GLEW</strong>. Всегда использовал только мобильную embedded версию OpenGL на мобильных девайсах или WebGL. Для загрузки картинок выбрал библиотеку <strong>stb</strong>, потому что ранее с ней работал и в ней всего один хедер-файл.</li>
<li>Создал проект с помощью CMake и скомпилировал его в QtCreator, потому что в компании использовали в основном его.</li>
<li>Сделал пустое окошко и загрузку пиксельных данных из любого файла с изображением с помощью <strong>stb</strong>.</li>
<li>В десктопном OpenGL в отличие от ES версии по ходу дела можно использовать как современные шейдеры, так и устаревшие <code class="" data-line="">glBegin</code>/<code class="" data-line="">glEnd</code> одновременно. На мобильных устройствах OpenGL ES такого делать не позволяет.</li>
</ul>
<h2>Понедельник (вечер, за четыре дня до дедлайна)</h2>
<ul>
<li>Понял, что QtCreator использует какие-то свои библиотеки плюс какие-то из <strong>msys2</strong>, а я больше привык к Visual Studio. Скачал FreeGLUT и прописал его в CMakeLists.txt.</li>
<li>Сделал проект для Visual Studio и заставил его работать. Это получилось только после того, как я переставил свой Visual Studio, потому что там не было основного сборщика и он подцеплял какие-то настройки из msys2. Удалось исправить только после обнуления переменной окружения Path и запуска генератора cmake из-под vcvarsall.bat.</li>
</ul>
<h2>Вторник (три дня до дедлайна)</h2>
<ul>
<li>Разбил программу на компоненты: <code class="" data-line="">Application</code>, <code class="" data-line="">Sprite</code>, <code class="" data-line="">Image</code>, <code class="" data-line="">Texture</code>, <code class="" data-line="">Mesh</code>, <code class="" data-line="">Shader</code> и так далее.</li>
<li>Окошко всё ещё пустое, ничего не рисуется, долго думал, как &#171;прикрутить&#187; нестатический C++ метод <code class="" data-line="">Application::render</code> как Сишный callback в методе <code class="" data-line="">glutDisplayFunc()</code>. Кстати, через пару месяцев нашёл метод &#8212; передать указатель на экземпляр своего класса через <code class="" data-line="">glutSetWindowData()</code>/<code class="" data-line="">glutGetWindowData()</code>, чтобы не использовать синглтон.</li>
</ul>
<h2>Среда (с утра до обеда, два дня до дедлайна)</h2>
<ul>
<li>Наконец-то нарисовал спрайт с текстурой по нужным мне пиксельным координатам. Решил на этом остановиться: закрашиваю фон красным, рисую один спрайт.</li>
<li>Подключил библиотеку glm, чтобы не умножать матрицы с векторами руками.</li>
<li>Создал класс <code class="" data-line="">Camera</code>.</li>
<li>Сначала хотел сделать стандартный макрос <code class="" data-line="">CHECK_GL_CHECK(glFunction)</code>, но в итоге прикрутил вывод ошибок в консоль с помощью <code class="" data-line="">glDebugMessageCallback()</code>.</li>
<li>Вечером добавил вычисление и рисование FPS и frametime. Очень странная установка позиции для вывода текста с помощью <code class="" data-line="">glutBitmapString()</code>. С цветом текста разобраться не удалось. Было бы здорово делать через freetype, про которую у меня написано <a href="https://blog2k.ru/tags/freetype" target="_blank">много статей</a>, но время поджимает, да не очень-то и хочется.</li>
</ul>
<h2>Четверг (один день до дедлайна)</h2>
<ul>
<li>накануне много думал про вращающееся колесо с картинками. Хотел сделать физическое колесо с массой и инерцией для запуска и остановки, но решил не заморачиваться и сделать горизонтальную модель ленты с индексами текущей ячейки от 0 до n, индекс типа float, целая часть которого &#8212; текущая ячейка, а дробная &#8212; её смещение от нуля до единицы. Отдельно идёт класс View, который по данным от модели рисует иконки. Для эффекта закруглённости решил сверху наложить маску с затенением сверху/снизу и бликом посередине. Вроде должно сработать.</li>
<li>под вечер сделал подобие колеса из четырёх иконок и решил собрать программу из того, что было.</li>
<li>для этого привлёк настоящего проектировщика зданий для рисования маски с отверстием посередине, включил поддержку RGBA и цвет для вершин, добавил надпись START со сменой цвета, про маску с тенью успешно забыл.</li>
</ul>
<h2>Пятница (дедлайн)</h2>
<ul>
<li>С утра пораньше сделал вращение колеса с плавной остановкой. Накануне придумал способ &#8212; крутимся с постоянной скоростью, за секунду до финала начинаем замедление с помощью формулы равнозамедленного движения.</li>
<li>Вынес создание спрайтов с кешированием текстур в отдельный класс.</li>
<li>Добавил обработку клика на кнопку.</li>
<li>В итоге поставил Ubuntu на Hyper V виртуальную машину, установил нужные библиотеки через apt, написал инструкцию в Readme, убедился, что всё работает, загрузил изменения с виртуальной машины через SFTP на винду и в GitHub.</li>
<li>Под винду включил статическую линковку в MSVC, чтобы не было нужды в .dll-файлах.</li>
<li>Собрал исходники, собрал бинарники, отдал на проверку, гештальт закрыт!</li>
</ul>
<h2>Вторник (отклик от компании)</h2>
<ul>
<li>Используются шейдеры, но при этом нет эффектов.</li>
<li>Сторонние библиотеки STB и GLM, при этом GLM используется только для одной функции, <del>а STB для другой</del>.</li>
</ul>
<hr />
<p>Оставлю эти замечания без комментариев, менять ничего не буду.</p>
<p>Для представления о том, что получилось, приведу скриншот (работает под любыми современными ОС):<br />
<img decoding="async" src="https://blog2k.ru/wp-content/uploads/2025/10/test_project.png" alt="Casino Test Project" /><br />
Теперь это ещё один <a href="https://github.com/jirnov/casino_test" rel="nofollow" target="_blank">мёртвый проект</a> на GitHub, по которому будут учиться AI, <em>хе-хе-хе</em>. Вы тоже можете составить своё мнение по этому &#171;проекту&#187; здесь в комментариях или в виде Merge Request к проекту. Для желающих увидеть ту самую версию, полученную &#171;заказчиком&#187;, я поставил тег <code class="" data-line="">first_release</code> в репозитории.</p>
]]></content>
		
					<link rel="replies" type="text/html" href="https://blog2k.ru/archives/11915#comments" thr:count="0" />
			<link rel="replies" type="application/atom+xml" href="https://blog2k.ru/archives/11915/feed/atom" thr:count="0" />
			<thr:total>0</thr:total>
			</entry>
		<entry>
		<author>
			<name>eJ</name>
					</author>

		<title type="html"><![CDATA[Текирова, Кемер, Турция &#8212; поездка на неделю]]></title>
		<link rel="alternate" type="text/html" href="https://blog2k.ru/archives/11869" />

		<id>https://blog2k.ru/?p=11869</id>
		<updated>2026-03-30T12:52:24Z</updated>
		<published>2025-09-29T08:30:40Z</published>
		<category scheme="https://blog2k.ru" term="Путешествия" /><category scheme="https://blog2k.ru" term="Турция" /><category scheme="https://blog2k.ru" term="Кемер" /><category scheme="https://blog2k.ru" term="отпуск" />
		<summary type="html"><![CDATA[Автор рассказывает о впечатлениях от отдыха в Турции, описывает свой опыт посещения экскурсий и даёт совет, как сэкономить на них. Также упоминаются особенности отдыха в отеле и на пляже, впечатления от местных достопримечательностей.]]></summary>

					<content type="html" xml:base="https://blog2k.ru/archives/11869"><![CDATA[<p>Писать или нет?, &#8212; думал я. По дороге в аэропорт провожающий гид &#171;обрадовал&#187;, что рейс будет &#171;Анталия-Махачкала&#187;, а не &#171;Анталия-Петербург&#187;. И это ещё везение &#8212; кому-то до нас достался Новосибирск или Самара. &#171;Точно писать!&#187; &#8212; это сигнал свыше. Махачкала &#8212; это как будто Россия, но Дагестан, а достаточна ли у меня длина рукавов и штанин для посещения данной местности &#8212; я не очень уверен.</p>
<p><img fetchpriority="high" decoding="async" class="aligncenter size-full wp-image-11957" src="https://blog2k.ru/wp-content/uploads/2025/10/2025-09-18-20-00-14.jpg" alt="Овчарка Белла" width="953" height="1271" srcset="https://blog2k.ru/wp-content/uploads/2025/10/2025-09-18-20-00-14.jpg 768w, https://blog2k.ru/wp-content/uploads/2025/10/2025-09-18-20-00-14-225x300.jpg 225w, https://blog2k.ru/wp-content/uploads/2025/10/2025-09-18-20-00-14-1152x1536.jpg 1152w, https://blog2k.ru/wp-content/uploads/2025/10/2025-09-18-20-00-14-1536x2048.jpg 1536w" sizes="(max-width: 953px) 100vw, 953px" /></p>
<p>Итак, мы купили относительно недорогой тур в <a href="https://www.amorehotels.com/ru/index.html" rel="nofollow" target="_blank">трехзвездочный отель</a> Турции на семь дней. Что сказать, отель так себе, но радушие хозяев и местная живность в лице немецкой овчарки Беллы, рыжего кота, желтоглазой кошки и четырёх озорных котят подкупают, поэтому о минусах отеля писать не буду. Мы славно ели, крепко спали, подкармливали зверушек на завтрак и ужин. В отеле у нас всё прошло хорошо.</p>
<p><span id="more-11869"></span><img decoding="async" class="aligncenter size-full wp-image-11956" src="https://blog2k.ru/wp-content/uploads/2025/10/2025-09-18-20-07-54.jpg" alt="Полосатый котёнок" width="3000" height="4000" srcset="https://blog2k.ru/wp-content/uploads/2025/10/2025-09-18-20-07-54.jpg 768w, https://blog2k.ru/wp-content/uploads/2025/10/2025-09-18-20-07-54-225x300.jpg 225w, https://blog2k.ru/wp-content/uploads/2025/10/2025-09-18-20-07-54-1152x1536.jpg 1152w, https://blog2k.ru/wp-content/uploads/2025/10/2025-09-18-20-07-54-1536x2048.jpg 1536w" sizes="(max-width: 3000px) 100vw, 3000px" /></p>
<p>От отеля до пляжа примерно километр пути, лежаки бесплатно предоставляет местное кафе при условии покупки у них чего-нибудь, но это неточно &#8212; иногда мы занимали лежаки просто так.</p>
<p>Жили мы в городке Текирова, почти на краю Кемерской губернии и на экскурсии нас забирали первыми и возвращали последними (иногда наоборот). Из-за этой особенности водителям было лениво отвозить нас так далеко от Анталии, и они дважды пытались &#171;сбагрить&#187; нас товарищам, которым было по пути. Один раз нам удалось от такой пересадки отбиться, в другой &#8212; нет.</p>
<p>Ощущения, когда ты последний пассажир ночью в автобусе с незнакомыми турецкими мужиками &#8212; незабываемое. Особенно они обостряются после рассказа о беженцах-наркоманах из Сирии которые могут и ножом пырнуть, плюс ИГИЛ &#8212; всё ещё действующая организация, до которой ехать километров пятьсот.</p>
<p>По пути в аэропорт, к счастью, ситуация поменялась и рейс снова стал Анталия &#8212; Санкт-Петербург и все радостно захлопали, так что в Махачкалу, хвала Аллаху, попасть не суждено. Потому что специально в Дагестан я никогда бы не поехал.</p>
<p>Итак, насчёт экскурсий раздумья такие: больше их покупать не будем, арендуем машину/мопед и прокатимся по Кемерскому краю самостоятельно. Кстати, вот вам полезный совет: открываете сайт с названием местного тур оператора (Marş Travel, Şereşe Travel, Ginza Travel и т.д.) и требуете, чтобы экскурсию вам продали по интернет цене, иначе продаван называет цену, какая придёт в его светлую темноволосую голову. Мы были на экскурсии, где цена варьировалась от 25 до 40 баксов за человека, причём состав и условия экскурсий был одинаковыми. Мы купили несколько поездок: хамам, Демре-Мира-Кекова, бухта Порто Дженевиз, развалины города Перге, теперь по порядку о каждой поездке без прикрас.</p>
<p><img decoding="async" class="aligncenter size-full wp-image-11959" src="https://blog2k.ru/wp-content/uploads/2025/10/2025-09-20-21-38-39.jpg" alt="Котёнок на дереве" width="3000" height="4000" srcset="https://blog2k.ru/wp-content/uploads/2025/10/2025-09-20-21-38-39.jpg 768w, https://blog2k.ru/wp-content/uploads/2025/10/2025-09-20-21-38-39-225x300.jpg 225w, https://blog2k.ru/wp-content/uploads/2025/10/2025-09-20-21-38-39-1152x1536.jpg 1152w, https://blog2k.ru/wp-content/uploads/2025/10/2025-09-20-21-38-39-1536x2048.jpg 1536w" sizes="(max-width: 3000px) 100vw, 3000px" /></p>
<h2>Хамам</h2>
<p>Отвозят на маршрутке в общественный хамам. Впервые был в очереди в бане, в целом хамам &#8212; это хорошо и обязательно к посещению а начале отпуска, только не этот конкретно, лучше бы взяли хамам в соседнем отеле. На обратном пути водитель пытался нас пересадить в другую маршрутку, но там не хватило сидячих мест, так что удалось отбиться с небольшим скандалом. Цена двадцать баксов с человека. С нами ехали те, кто взял за 18 баксов и за 25, так что делайте выводы.</p>
<h2>Демре Мира Кекова</h2>
<p>Посещение трёх городов и церкви Николая Чудотворца, также известного как Санта Клаус.</p>
<p>Оказалось, Санта не живёт с женой на Северном Полюсе, а давно умер, и власти скрывают! Перед покупкой экскурсии вам льют в уши, что вы поплывёте на судне со стеклянным дном обозревать руины древних городов, по факту получаются два грязных окошка, в которые ничего не видно кроме зелёной воды. Глумиться про религию не буду (это не одобряют жена и УК РФ), но давно я не видел такого коммерциализированного подхода к религии, особенно в сфере продаж реквизита. Из хорошего &#8212; посещение церкви Святого Николая Чудотворца. Монументальное и очень древнее строение. Удивительно, как в начале нашей эры смогли возвести подобное сооружение.</p>
<h2>Бухта Порто Дженевиз</h2>
<p>Прогулка на кораблике с купанием по трём бухтам: два раза по часу и один на полчаса. Старт корабля из Адрасана. Рекомендую вместо этого купить экскурсию на турецкие Мальдивы &#8212; Сулуада. Там вода чище, виды красивее и в целом лучше. Экскурсия запомнилась знакомством с байкерами из Нижнего Новгорода, которые своим ходом через Грузию за шесть дней доехали до Кемера. Из неприятного &#8212; тётка в маршрутке, которая заняла чужое место и внезапно забыла русский язык. Так мы и познакомились с байкерами.</p>
<p>Отдельно хочу отметить Адрасан &#8212; уникальное место, где кораблики припаркованы кормой прямо к пляжу, вереница кораблей километра два длиной. Вид грандиозный. Если там не были, обязательно побывайте.</p>
<h2>Перге</h2>
<p>Четыре события по цене одного и пятое в подарок. Сначала везут в парк к верхнему Дюденскому водопаду. Потом часик гуляем по развалинам древнего города Перге. Потом &#8212; ужин вкуснейшими котлетками-кюфте, много-много пахлавы, турецкий чаёк. Далее отвозят в &#171;Land of legends&#187; с шоу фонтанов, красивым замком <span>Nickelodeon</span> и элитными магазинами. В завершение программы &#8212; вишенка на торте: пересадка посреди ночи из комфортного автобуса в ссаную маршрутку с двумя неизвестными турками, потому что водителю лениво далеко ехать, зато бакшиш брать не лениво.</p>
<p><img loading="lazy" decoding="async" class="aligncenter size-full wp-image-11960" src="https://blog2k.ru/wp-content/uploads/2025/10/2025-09-22-20-32-36.jpg" alt="Замок Nickelodeon" width="3000" height="4000" srcset="https://blog2k.ru/wp-content/uploads/2025/10/2025-09-22-20-32-36.jpg 768w, https://blog2k.ru/wp-content/uploads/2025/10/2025-09-22-20-32-36-225x300.jpg 225w, https://blog2k.ru/wp-content/uploads/2025/10/2025-09-22-20-32-36-1152x1536.jpg 1152w, https://blog2k.ru/wp-content/uploads/2025/10/2025-09-22-20-32-36-1536x2048.jpg 1536w" sizes="auto, (max-width: 3000px) 100vw, 3000px" /></p>
<h2>Кемер</h2>
<p>Три года назад <a href="https://blog2k.ru/archives/9520" target="_blank">мы были в Кемере</a> и решили его посетить самостоятельно. Ездили в самую жару на автобусе номер 8, если правильно помню. Вспомнили, что там очень неудобный заход в море через гальку и на пляже не очень-то полежишь. Так что мы были в Кемере один раз. Рядом, кстати, располагается античный ликийский город Фаселис, но туда мы не добрались.</p>
<p><img loading="lazy" decoding="async" class="aligncenter size-full wp-image-11958" src="https://blog2k.ru/wp-content/uploads/2025/10/2025-09-20-11-43-53.jpg" alt="Статуя коня в Кемере" width="4000" height="3000" srcset="https://blog2k.ru/wp-content/uploads/2025/10/2025-09-20-11-43-53.jpg 1024w, https://blog2k.ru/wp-content/uploads/2025/10/2025-09-20-11-43-53-300x225.jpg 300w, https://blog2k.ru/wp-content/uploads/2025/10/2025-09-20-11-43-53-768x576.jpg 768w, https://blog2k.ru/wp-content/uploads/2025/10/2025-09-20-11-43-53-1536x1152.jpg 1536w, https://blog2k.ru/wp-content/uploads/2025/10/2025-09-20-11-43-53-2048x1536.jpg 2048w" sizes="auto, (max-width: 4000px) 100vw, 4000px" /></p>
<p>В целом это небольшое путешествие очень понравилось и оставило самые приятные воспоминания &#8212; когда ещё понежишься на солнце, когда дома 16 градусов &#171;тепла&#187; и дождь. Это был не очень логичный поступок, когда мы с женой одновременно безработные, но считаю все было не зря, зимой будет что вспомнить.</p>
]]></content>
		
					<link rel="replies" type="text/html" href="https://blog2k.ru/archives/11869#comments" thr:count="0" />
			<link rel="replies" type="application/atom+xml" href="https://blog2k.ru/archives/11869/feed/atom" thr:count="0" />
			<thr:total>0</thr:total>
			</entry>
		<entry>
		<author>
			<name>eJ</name>
					</author>

		<title type="html"><![CDATA[Небольшая новость]]></title>
		<link rel="alternate" type="text/html" href="https://blog2k.ru/archives/11841" />

		<id>https://blog2k.ru/?p=11841</id>
		<updated>2025-10-22T12:29:58Z</updated>
		<published>2025-09-10T15:26:55Z</published>
		<category scheme="https://blog2k.ru" term="PHP" /><category scheme="https://blog2k.ru" term="Программирование" /><category scheme="https://blog2k.ru" term="JavaScript" /><category scheme="https://blog2k.ru" term="WordPress API" />
		<summary type="html"><![CDATA[Я выложил на GitHub исходники своих наработок для WordPress: тему сайта, плагин с полезными функциями, виджет для отображения списка постов и плагин для виджета погоды. Всё под лицензией MIT.]]></summary>

					<content type="html" xml:base="https://blog2k.ru/archives/11841"><![CDATA[<p>Всем привет! Всякому программисту положено иметь pet-проект, который он холит, лелеет и делает в свободное время.</p>
<p>Когда я задумался о таком, оказалось, что мой pet-проект &#8212; это собственно сайт blog2k.ru, для которого я написал свою тему для WordPress и поддерживаю собственный WordPress плагин со всякими полезными плюшками.</p>
<p>Буквально сегодня выложил в открытый доступ на github исходники своих наработок:</p>
<ul>
<li>тема для WordPress этого сайта: <a href="https://github.com/jirnov/b2k-theme" rel="nofollow" target="_blank">b2k-theme</a></li>
<li>плагин с полезным функционалом: <a href="https://github.com/jirnov/b2k-tools" rel="nofollow" target="_blank">b2k-tools</a></li>
<li>виджет, который при добавлении в область title sidebar, показывает список постов c текущей категорией или тегом: <a href="https://github.com/jirnov/wp-index-widget" rel="nofollow" target="_blank">wp-index-widget</a></li>
<li>плагин для виджета отображения погоды: <a href="https://github.com/jirnov/yowindow-widget" rel="nofollow" target="_blank">yowindow-widget</a></li>
</ul>
<p>Работу плагина wp-index-widget можно увидеть, например, <a href="https://blog2k.ru/topics/programming" target="_blank">здесь</a>.</p>
<p>Всё выложено под лицензией MIT, можно модифицировать, изменять, брать любую часть и даже использовать в коммерческих целях.</p>
<p>Коммиты и форки всячески приветствуются и не осуждаются. Пул реквесты также, возможно, будут приняты. Enjoy!</p>
]]></content>
		
					<link rel="replies" type="text/html" href="https://blog2k.ru/archives/11841#comments" thr:count="0" />
			<link rel="replies" type="application/atom+xml" href="https://blog2k.ru/archives/11841/feed/atom" thr:count="0" />
			<thr:total>0</thr:total>
			</entry>
		<entry>
		<author>
			<name>eJ</name>
					</author>

		<title type="html"><![CDATA[Пул потоков с запуском функций с переменным количеством параметров]]></title>
		<link rel="alternate" type="text/html" href="https://blog2k.ru/archives/11803" />

		<id>https://blog2k.ru/?p=11803</id>
		<updated>2025-10-22T12:30:15Z</updated>
		<published>2025-09-05T07:15:55Z</published>
		<category scheme="https://blog2k.ru" term="C++" /><category scheme="https://blog2k.ru" term="Программирование" /><category scheme="https://blog2k.ru" term="ИИ" /><category scheme="https://blog2k.ru" term="многопоточность" />
		<summary type="html"><![CDATA[В статье автор исправляет предложенный ИИ нерабочий код для пула потоков на C++, используя `std::packaged_task` и `variadic templates`. Также обсуждаются возможные улучшения кода с использованием `std::condition_variable`.]]></summary>

					<content type="html" xml:base="https://blog2k.ru/archives/11803"><![CDATA[<p>Всем привет! Внезапно оказался без определённого места работы и в свободное время мучаю <a href="https://www.deepseek.com/" rel="nofollow" target="_blank">ИИ</a> по поводу возможных задач и вопросов на собеседованиях по C++, и некоторые задачи делаю самостоятельно.</p>
<p>Недавно я попросил ИИ сделать пул потоков. Я его написал заранее, но захотелось проверить, где я мог ошибиться.</p>
<p>ИИ написал нерабочий код, но с интересной идеей: запускать вместо стандартного <code class="" data-line="">std::function&lt;void()&gt;</code> функции с параметрами с помощью <code class="" data-line="">std::packaged_task</code> и variadic templates. Меня этот так вдохновило, что я решил таки сделать этот код рабочим. И сделал!</p>
<p>Кстати, мой код не нравится ИИ &#8212; он предлагает его переделать на <code class="" data-line="">std::condition_variable</code> и, возможно, он прав, а я написал ерунду, таков путь!</p>
<div class="spoiler-wrap"><div class="spoiler-head folded">Мой вариант на C++:</div><div class="spoiler-body"></p>
<pre><code class="language-cpp" data-line="">#include &lt;vector&gt;
#include &lt;atomic&gt;
#include &lt;thread&gt;
#include &lt;mutex&gt;
#include &lt;functional&gt;
#include &lt;deque&gt;
#include &lt;optional&gt;
#include &lt;future&gt;
#include &lt;iostream&gt;

class ThreadPool {
public:
    /// По умолчанию количество потоков равно количеству аппаратных потоков
    ThreadPool(size_t numThreads=std::jthread::hardware_concurrency()) {
        m_threads.reserve(numThreads);
        for (size_t i = 0; i &lt; numThreads; ++i) {
            m_threads.emplace_back([this](){ runLoop(); });
        }
    }

    // Принимаем на входе функцию и её аргументы, на выходе автоматически
    // оборачиваем результат работы функции в std::future
    template&lt;typename... Args&gt;
    auto runTaskAsync(auto f, Args&amp;&amp;...args) {
        // Выясняем возращаемый тип у функции
        using return_type = std::invoke_result_t&lt;decltype(f), Args...&gt;;

        // Заворачиваем функцию с переменным количеством аргументов в
        // std::packaged_task, у которого можно получить std::future&lt;return_type&gt;
        auto task = std::make_shared&lt;std::packaged_task&lt;return_type()&gt;&gt;(
            std::bind(std::forward&lt;decltype(f)&gt;(f), std::forward&lt;Args&gt;(args)...)
            );

        // Получаем std::future
        auto res = task-&gt;get_future();

        if (m_Running) {
            std::unique_lock lock(m_guard);
            // Добавляем задачу в очередь на выполнение
            m_tasks.push_back([task](){(*task)();});

            // Уведомляем ожидающие потоки
            m_hasTask = true;
            // Может тут надо использовать notify_one (?)
            m_hasTask.notify_all();
        }

        return res;
    }

    // Вызываем функцию синхронно и возвращаем результат
    template&lt;typename...Args&gt;
    auto runTaskSync(auto f, Args &amp;&amp;...args) {
        return runTaskAsync(f, std::forward&lt;Args&gt;(args)...).get();
    }

    ~ThreadPool()
    {
        // Устанавливаем флаг остановки потоков
        m_Running = false;
        // Очищаем очередь задач
        {
            std::unique_lock lock(m_guard);
            m_tasks.clear();
        }
        // Обманом :-) выводим потоки из режима ожидания
        m_hasTask = true;
        m_hasTask.notify_all();

        // Для каждого потока
        for (auto &amp;thread : m_threads) {
            if (thread.joinable()) {
                // Дожидаемся завершения работы
                thread.join();
            }
        }
    }
private:
    using Task = std::function&lt;void()&gt;;

    void runLoop() {
        while (m_Running) {
            // Ждём задачу
            m_hasTask.wait(false);

            std::optional&lt;Task&gt; task;

            // Забираем задачу из начала списка
            {
                std::unique_lock lock(m_guard);
                if (!m_tasks.empty()) {
                    task = m_tasks.front();
                    m_tasks.pop_front();
                }
            }

            // Задача есть, исполняем
            if (task) {
                (*task)();
            }
            else {
                // Отдаём процессорное время другим потокам
                std::this_thread::yield();
            }
        }
    }

    // Вектор потоков
    std::vector&lt;std::thread&gt; m_threads;
    // Атомарный флаг остановки потоков
    std::atomic_bool m_Running{ true };
    // Атомарный флаг наличия задачи
    std::atomic_bool m_hasTask{ false };
    // Очередь задач
    std::deque&lt;Task&gt; m_tasks;
    // Мьютекс для защиты очереди задач
    std::mutex m_guard;
};


int main()
{
    // Создаём пул потоков
    ThreadPool mgr;

    // Первая задача на две секунды, которая возвращает строку
    auto func = [](const std::string &amp;s) {
        std::cout &lt;&lt; &quot;Long task1 begin...&quot; &lt;&lt; std::endl;
        std::this_thread::sleep_for(std::chrono::seconds(2));
        std::cout &lt;&lt; &quot;Long task1 end...&quot; &lt;&lt; std::endl;
        return s;
    };

    // Вторая задача на пять секунд, которая ничего не возвращает
    auto func2 = []() {
        std::cout &lt;&lt; &quot;Long task2 begin...&quot; &lt;&lt; std::endl;
        std::this_thread::sleep_for(std::chrono::seconds(5));
        std::cout &lt;&lt; &quot;Long task2 end...&quot; &lt;&lt; std::endl;
    };

    // Запускаем первую задачу с параметром
    auto result1 = mgr.runTaskAsync(func, &quot;task1 result&quot;);
    // Запускаем вторую задачу без параметров
    auto result2 = mgr.runTaskAsync(func2);

    // Получаем результат выполнения первой задачи и выводим в консоль
    std::cout &lt;&lt; &quot;Task1 result = &quot; &lt;&lt; result1.get() &lt;&lt; std::endl;
    // Ждём вторую задачу
    std::cout &lt;&lt; &quot;Wait task2 result&quot; &lt;&lt; std::endl;
    result2.wait();
}
</code></pre>
<p></div></div>
<div class="spoiler-wrap"><div class="spoiler-head folded">Исходник от ИИ для сравнения:</div><div class="spoiler-body"></p>
<pre><code class="language-cpp" data-line="">#include &lt;vector&gt;
#include &lt;queue&gt;
#include &lt;thread&gt;
#include &lt;mutex&gt;
#include &lt;condition_variable&gt;
#include &lt;functional&gt;
#include &lt;future&gt;
#include &lt;memory&gt;
#include &lt;stdexcept&gt;

class ThreadPool {
public:
    // Конструктор, создающий указанное количество потоков
    ThreadPool(size_t threads) : stop(false) {
        for(size_t i = 0; i &lt; threads; ++i) {
            workers.emplace_back([this] {
                for(;;) {
                    std::function&lt;void()&gt; task;
                    
                    {
                        std::unique_lock&lt;std::mutex&gt; lock(this-&gt;queue_mutex);
                        this-&gt;condition.wait(lock, 
                            [this]{ return this-&gt;stop || !this-&gt;tasks.empty(); });
                        if(this-&gt;stop &amp;&amp; this-&gt;tasks.empty())
                            return;
                        task = std::move(this-&gt;tasks.front());
                        this-&gt;tasks.pop();
                    }
                    
                    task();
                }
            });
        }
    }
    
    // Добавление задачи в пул
    template&lt;class F, class... Args&gt;
    auto enqueue(F&amp;&amp; f, Args&amp;&amp;... args) 
        -&gt; std::future&lt;typename std::result_of&lt;F(Args...)&gt;::type&gt; {
        using return_type = typename std::result_of&lt;F(Args...)&gt;::type;
        
        auto task = std::make_shared&lt;std::packaged_task&lt;return_type()&gt;&gt;(
            std::bind(std::forward&lt;F&gt;(f), std::forward&lt;Args&gt;(args)...)
        );
            
        std::future&lt;return_type&gt; res = task-&gt;get_future();
        {
            std::unique_lock&lt;std::mutex&gt; lock(queue_mutex);
            
            // Не добавляем новые задачи после остановки пула
            if(stop)
                throw std::runtime_error(&quot;enqueue on stopped ThreadPool&quot;);
                
            tasks.emplace([task](){ (*task)(); });
        }
        condition.notify_one();
        return res;
    }
    
    // Деструктор, останавливающий все потоки
    ~ThreadPool() {
        {
            std::unique_lock&lt;std::mutex&gt; lock(queue_mutex);
            stop = true;
        }
        condition.notify_all();
        for(std::thread &amp;worker: workers)
            worker.join();
    }

private:
    std::vector&lt;std::thread&gt; workers;       // Рабочие потоки
    std::queue&lt;std::function&lt;void()&gt;&gt; tasks;// Очередь задач
    
    std::mutex queue_mutex;                 // Мьютекс для синхронизации доступа к очереди
    std::condition_variable condition;      // Условная переменная для уведомлений
    bool stop;                              // Флаг остановки пула
};
</code></pre>
<p></div></div>
<p>Буду признателен, если вы укажете на возможные ошибки и недочёты в моём коде.</p>
]]></content>
		
					<link rel="replies" type="text/html" href="https://blog2k.ru/archives/11803#comments" thr:count="0" />
			<link rel="replies" type="application/atom+xml" href="https://blog2k.ru/archives/11803/feed/atom" thr:count="0" />
			<thr:total>0</thr:total>
			</entry>
		<entry>
		<author>
			<name>eJ</name>
					</author>

		<title type="html"><![CDATA[Летний гастротур по России]]></title>
		<link rel="alternate" type="text/html" href="https://blog2k.ru/archives/11606" />

		<id>https://blog2k.ru/?p=11606</id>
		<updated>2026-01-31T09:29:20Z</updated>
		<published>2025-08-09T08:50:25Z</published>
		<category scheme="https://blog2k.ru" term="Путешествия" /><category scheme="https://blog2k.ru" term="Россия" /><category scheme="https://blog2k.ru" term="Казань" /><category scheme="https://blog2k.ru" term="Калининград" /><category scheme="https://blog2k.ru" term="отпуск" /><category scheme="https://blog2k.ru" term="Пермь" />
		<summary type="html"><![CDATA[Посетил Зеленоградск, где не впечатлился отелем, но город оставил приятные впечатления. Пробовал разные виды рыбы, посетил колесо обозрения и музей кошек. Планирую вернуться.]]></summary>

					<content type="html" xml:base="https://blog2k.ru/archives/11606"><![CDATA[<h2>Зеленоградск</h2>
<p>Изначально мы прилетели в Калининград и взяли такси до Зеленоградска. Вдоль трассы полно зелени и полей, ехать 20 минут, такси стоит недорого относительно Петербурга.</p>
<p>Заселились в <a href="https://kranz-hotel.ru/" rel="nofollow" target="_blank">отель &#171;Кранц&#187;</a>, немецкое название Зеленоградска именно такое. Отель не понравился. Стоит в два раза дороже, чем должен. Единственный плюс отеля &#8212; его расположение недалеко от берега, остальное плохо &#8212; туалет и ванная одна на два номера, завтрак советский из полуфабрикатов, кофе растворимый, вешалок в номере нет, подниматься по крутой лестнице на третий этаж сложно с пустыми руками, с чемоданами вообще шею можно сломать, по уборке в номере возникли вопросы.</p>
<p>Но город, в отличие от отеля, оставил самые приятные впечатления, несмотря на сильный ветер и температуру в 12-16 градусов. Так получилось, что поездка была больше гастротуром, чем туризмом, не успевали испытывать голод. Перепробовали всё, привезли лишнего весу килограмм шесть на двоих.</p>
<p>Напробовался рыбы разных видов и способов приготовления. Тут тебе и строганина из пеламиды, и тартар из лосося, и шаверма из тунца. Так-то рыбу я не ем особо, а тут прям ушёл в отрыв.</p>
<p>После приезда, отдохнув от поездки, вечером посетили колесо обозрения <a href="https://yandex.ru/maps/org/koleso_obozreniya_glaz_baltiki/121947512010/?ll=20.457743%2C54.944388&#038;z=12" rel="nofollow" target="_blank">&#171;Глаз Балтики&#187;</a> и обозрели весь Зеленоградск сверху.</p>
<p>Церкви в Зеленоградске получаются из католических костёлов: добавляют костёлу золотой купол и получается цыганский дворец с элементами готики. Выглядит не к месту и чужеродно на мой непритязательный взгляд. Зачем так сделано &#8212; лично мне непонятно.</p>
<p><img loading="lazy" decoding="async" src="https://blog2k.ru/wp-content/uploads/2025/08/2025-06-18-11-12-08.jpg" alt="Церковь трансформер из хостела" width="4000" height="3000" class="aligncenter size-full wp-image-11751" srcset="https://blog2k.ru/wp-content/uploads/2025/08/2025-06-18-11-12-08.jpg 1024w, https://blog2k.ru/wp-content/uploads/2025/08/2025-06-18-11-12-08-300x225.jpg 300w, https://blog2k.ru/wp-content/uploads/2025/08/2025-06-18-11-12-08-768x576.jpg 768w, https://blog2k.ru/wp-content/uploads/2025/08/2025-06-18-11-12-08-1536x1152.jpg 1536w, https://blog2k.ru/wp-content/uploads/2025/08/2025-06-18-11-12-08-2048x1536.jpg 2048w" sizes="auto, (max-width: 4000px) 100vw, 4000px" /><span id="more-11606"></span></p>
<p>Зеленоградск считается городом кошек. Законы, подобные турецким или греческим отсутствуют, но кошек полно и выглядят они довольно упитанными.</p>
<p><img loading="lazy" decoding="async" class="aligncenter size-full wp-image-11656" src="https://blog2k.ru/wp-content/uploads/2025/07/2025-06-18-19-22-25.jpg" alt="Зеленоградск. Мурал с котами." width="3000" height="4000" srcset="https://blog2k.ru/wp-content/uploads/2025/07/2025-06-18-19-22-25.jpg 768w, https://blog2k.ru/wp-content/uploads/2025/07/2025-06-18-19-22-25-225x300.jpg 225w, https://blog2k.ru/wp-content/uploads/2025/07/2025-06-18-19-22-25-1152x1536.jpg 1152w, https://blog2k.ru/wp-content/uploads/2025/07/2025-06-18-19-22-25-1536x2048.jpg 1536w" sizes="auto, (max-width: 3000px) 100vw, 3000px" /></p>
<p>Есть <a href="https://www.zelenogradsk.com/tourism/museums/murrarium/" rel="nofollow" target="_blank">музей кошек Мурариум</a> в бывшей водонапорной башне. Сверху открывается хороший вид на весь Зеленоградск. Сам музей содержит коллекцию разнообразных фигурок кошек, поделок в виде кошек, открыток с кошками и так далее. Имеет смысл посетить хотя бы ради вида с последнего этажа.</p>
<p>Новостройки в Зеленоградске стараются делать в стиле а-ля фахверк. С высоты город выглядит приятно, и в нём хочется остаться жить. Цены на квартиры — питерские.</p>
<p>Посетили <a href="https://kenigmuseum.ru/" rel="nofollow" target="_blank">музей миниатюр</a>, послушали историю про остров богачей (остров Канта), который разбомбили британские самолёты, и про замок в Калининграде, которые советские власти решили не восстанавливать, и сейчас там парковка.</p>
<p>Первый вечер мы провели в <a href="https://telegraph.rest/" rel="nofollow" target="_blank">ресторане &#171;Телеграф&#187;</a>, где я впервые увидел живого сомелье и строганину из пеламиды. Живой сомелье посоветовала оранжевое вино, которое делает винодел Никита из Севастополя, а строганина &#8212; это замороженное сырое мясо рыбы. Как ни странно, мне понравилось.</p>
<p><img loading="lazy" decoding="async" class="aligncenter size-full wp-image-11653" src="https://blog2k.ru/wp-content/uploads/2025/07/2025-06-17-21-55-52.jpg" alt="Ресторан " телеграф_="телеграф_" width="4000" height="3000" srcset="https://blog2k.ru/wp-content/uploads/2025/07/2025-06-17-21-55-52.jpg 1024w, https://blog2k.ru/wp-content/uploads/2025/07/2025-06-17-21-55-52-300x225.jpg 300w, https://blog2k.ru/wp-content/uploads/2025/07/2025-06-17-21-55-52-768x576.jpg 768w, https://blog2k.ru/wp-content/uploads/2025/07/2025-06-17-21-55-52-1536x1152.jpg 1536w, https://blog2k.ru/wp-content/uploads/2025/07/2025-06-17-21-55-52-2048x1536.jpg 2048w" sizes="auto, (max-width: 4000px) 100vw, 4000px" /></p>
<p>Во второй вечер пошли в <a href="https://chef.ru/place/balt/" rel="nofollow" target="_blank">ресторан &#171;Балт&#187;</a>, где вкушали скумбрию с настойками. Скумбрия прекрасна, настойки &#8212; водка с вареньем. Рыбу съели, настойки не оценили и пошли в &#171;Телеграф&#187;, где они выше всяких похвал. Вкусы настоек в &#171;Телеграфе&#187; разнообразные: от малины и марципана до настоек на грибах и бородинском хлебе. Настойки очень понравились, рекомендую. Будете в Зеленоградске, обязательно зайдите в &#171;Телеграф&#187; хотя бы за настойками, а в &#171;Балт&#187; за скумбрией.</p>
<p>Также мы посетили <a href="https://gnezdo.cafe/" rel="nofollow" target="_blank">кафе &#171;Гнездо&#187;</a>, куда пёрлись по пляжу километра четыре под шквалистым ветром и ничего там толком не съели: скумбрия с костями, угорь с куском жира, картошка залита маслом. Блюда можно есть только вприкуску с Панкреатином. Жирно, невкусно и с костями.<br />
Ещё вкушали добротные (в отличие от гостиницы) завтраки в <a href="https://branchnamore.ru/" rel="nofollow" target="_blank">кафе &#171;Бранч на море&#187;</a>. Совсем рядом <a href="https://ogonekcafe.ru/" rel="nofollow" target="_blank">ресторан &#171;Огонёк&#187;</a>, &#8212; тоже посетили и остались довольны.</p>
<p>На Куршскую косу, к сожалению, не попали. Ну ничего, будет повод приехать.</p>
<p>Если у вас сложилось впечатление, что мы бродили от стола к столу, преодолевая холод <strike>голод</strike> и ветер, то так оно и было. Зеленоградск в целом приятный городок, мы бы вернулись туда <strike>поесть</strike> ещё раз. Следующим местом по плану был Светлогорск, куда мы отправились на каршеринге CityRent.</p>
<h2>Светлогорск</h2>
<p>Оказалось, что каршеринг берёт дополнительный оброк за переезд внутри Калининградской области между городками, ценник получился в два раза дороже такси, поэтому CityRent мы использовали первый и последний раз в жизни. Копеечку заработали, клиента потеряли &#8212; молодцы, типичный российский бизнес, как он есть.</p>
<p><img loading="lazy" decoding="async" class="aligncenter size-full wp-image-11658" src="https://blog2k.ru/wp-content/uploads/2025/07/2025-06-19-20-26-10.jpg" alt="Светлогорск. Водонапорная башня" width="3000" height="4000" srcset="https://blog2k.ru/wp-content/uploads/2025/07/2025-06-19-20-26-10.jpg 768w, https://blog2k.ru/wp-content/uploads/2025/07/2025-06-19-20-26-10-225x300.jpg 225w, https://blog2k.ru/wp-content/uploads/2025/07/2025-06-19-20-26-10-1152x1536.jpg 1152w, https://blog2k.ru/wp-content/uploads/2025/07/2025-06-19-20-26-10-1536x2048.jpg 1536w" sizes="auto, (max-width: 3000px) 100vw, 3000px" /></p>
<p>Гостиница наша располагалась в посёлке Отрадное в двух километрах от Светлогорска. В Светлогорске делать нечего, в Отрадном тем более. В этой части путешествия не понравилось абсолютно ничего. Вдоль моря не погулять, все значимые места закрыты на перестройку или реставрацию. После семи вечера всё закрывается, смотреть не на что. Потерпев Светлогорск три дня, отправились в Калининград.</p>
<h2>Калининград</h2>
<p>Город Калининград и область оставили впечатление, будто территорию захватили, а как содержать &#8212; не знают, поэтому преследовало чувство упадка, и грязные хрущевки это чувство только усиливали. Что интересно: трамваи в Калининграде имеют более узкую колею, чем в Петербурге, и поэтому выглядят, как детская железная дорога. Посетили мастер-класс по изготовлению фигурок из марципана, с последующей их окраской, обзорную экскурсию по рекам и каналам. Затем побывали на подводной лодке, внутри тесно, но очень интересно. Понравился собор на острове Канта и район, где расположен уютный бар &#171;У вас горизонт завален&#187;, где развлекались до ночи и меняли оливки на клубнику. Спустя два дня (как голова перестала болеть) отправились в Казань.</p>
<h2>Казань</h2>
<p>В Казани заселились в <a href="https://innjoyhotel.ru/" rel="nofollow" target="_blank">отель Innjoy</a>, что находится на главной туристической улице Баумана, что гарантировало минимальный путь к достопримечательностям, но при этом народ гулял и шумел на улице до утра. Казань выглядит как мусульманская смесь Санкт-Петербурга и Москвы. Посетили мечеть &#171;Кул Шариф&#187; с музеем внутри. Ислам в Казани, можно сказать, дружелюбный, с человеческим лицом — такой, каким он и должен быть, а не тот, который демонстративно тащат с собой приезжие из аулов. В музее почитали жалобу на татар от православных исследователей на старославянском. Читали сквозь смех и слёзы.</p>
<blockquote><p>Ермоген Митрополит их призывал в соборную церковь Пречистыя Богородицы и поучал их от божественного писания и наказывал как подобает крестьянам жить и они ученья не принимают и от Татарских обычаев не отстанут</p></blockquote>
<blockquote><p>И умерших в церкви хоронить не носят, кладут по старым своим Татарским кладбищам</p></blockquote>
<blockquote><p>И с женками , и с девками с некрещенными живут мимо своих жен</p></blockquote>
<p><img loading="lazy" decoding="async" class="aligncenter size-full wp-image-11650" src="https://blog2k.ru/wp-content/uploads/2025/07/2025-06-24-11-49-07.jpg" alt="Мечеть " кул="кул" шариф_="шариф_" width="2226" height="2447" srcset="https://blog2k.ru/wp-content/uploads/2025/07/2025-06-24-11-49-07.jpg 932w, https://blog2k.ru/wp-content/uploads/2025/07/2025-06-24-11-49-07-273x300.jpg 273w, https://blog2k.ru/wp-content/uploads/2025/07/2025-06-24-11-49-07-768x844.jpg 768w, https://blog2k.ru/wp-content/uploads/2025/07/2025-06-24-11-49-07-1397x1536.jpg 1397w, https://blog2k.ru/wp-content/uploads/2025/07/2025-06-24-11-49-07-1863x2048.jpg 1863w" sizes="auto, (max-width: 2226px) 100vw, 2226px" /></p>
<p>Кормили в отеле хорошо. На улице Баумана забрели в <a href="https://menu.restify.one/rebernaya_kzn" rel="nofollow" target="_blank">заведение &#171;Рёбра на огне&#187;</a>, которое нас совсем не впечатлило: концепция &#171;есть руками без вилок&#187; не понравилась, мясо жестковато, первую порцию свиных рёбер вообще принесли недожаренной. Их рёбра проигрывают <a href="https://www.restoclub.ru/spb/place/holy-ribs" rel="nofollow" target="_blank">Holy Ribs</a> по всем параметрам.</p>
<h2>Пермь</h2>
<p>Саму Пермь толком не смотрели, прогулялись от вокзала Пермь-1 через набережную мимо особняков купцов Жирновых, зарулили в блинную, схватили по-быстрому еды и поехали на вокзал Пермь-2. Жили у родственников за городом, проживание &#8212; пять звезд, всё включено, даже laundry hotel service. &#171;Шанежки&#187; были такие большие, что назывались гордо &#171;Шаньги&#187;, и я даже сразу их не распознал. Думаю, если бы тётя взялась делать <em>&#171;посикуньчики&#187;</em>, они бы звались <em>&#171;посикуны&#187;</em> из-за размера.</p>
<h2>Итог</h2>
<p>Подведу итог: Казань и Зеленоградск хочется посетить ещё раз, когда-нибудь. Цены практически везде питерские, а зарплаты &#8212; нет. Как выживает местное население, мне неведомо. Только такси местами дешевле, но не намного. Между городами передвигались на самолётах, из Казани до Перми — поездом.</p>
<p>А по возвращению в Питер, мы двинули в Кингисепп, но это уже другая история, и вы её не услышите.</p>
]]></content>
		
					<link rel="replies" type="text/html" href="https://blog2k.ru/archives/11606#comments" thr:count="2" />
			<link rel="replies" type="application/atom+xml" href="https://blog2k.ru/archives/11606/feed/atom" thr:count="2" />
			<thr:total>2</thr:total>
			</entry>
		<entry>
		<author>
			<name>eJ</name>
					</author>

		<title type="html"><![CDATA[Как найти сигнатуру Java/Kotlin метода для работы через JNI]]></title>
		<link rel="alternate" type="text/html" href="https://blog2k.ru/archives/11665" />

		<id>https://blog2k.ru/?p=11665</id>
		<updated>2025-10-29T08:42:55Z</updated>
		<published>2025-08-04T18:44:15Z</published>
		<category scheme="https://blog2k.ru" term="Java" /><category scheme="https://blog2k.ru" term="Программирование" />
		<summary type="html"><![CDATA[В статье описаны два способа определения сигнатуры Java-метода: по таблице соответствия типов и с помощью команды `javap`. Это необходимо для получения ссылки на Java-метод.]]></summary>

					<content type="html" xml:base="https://blog2k.ru/archives/11665"><![CDATA[<p>Для того, чтобы получить ссылку на Java метод, нужно знать его сигнатуру. Есть два <del>стула</del> способа:</p>
<h3>1. Подобрать сигнатуру по <a href="https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/types.html" rel="nofollow" target="_blank">таблице</a>:</h3>
<table style="text-align: center;max-width:512px" border="1" summary="Java VM Type Signatures">
<thead>
<tr>
<th id="h201">Сигнатура</th>
<th id="h202">Java тип</th>
</tr>
</thead>
<tbody>
<tr>
<td headers="h201">V</td>
<td headers="h202">void</td>
</tr>
<tr>
<td headers="h201">Z</td>
<td headers="h202">boolean</td>
</tr>
<tr>
<td headers="h201">B</td>
<td headers="h202">byte</td>
</tr>
<tr>
<td headers="h201">C</td>
<td headers="h202">char</td>
</tr>
<tr>
<td headers="h201">S</td>
<td headers="h202">short</td>
</tr>
<tr>
<td headers="h201">I</td>
<td headers="h202">int</td>
</tr>
<tr>
<td headers="h201">J</td>
<td headers="h202">long</td>
</tr>
<tr>
<td headers="h201">F</td>
<td headers="h202">float</td>
</tr>
<tr>
<td headers="h201">D</td>
<td headers="h202">double</td>
</tr>
<tr>
<td headers="h201">L fully-qualified-class ;</td>
<td headers="h202">fully-qualified-class</td>
</tr>
<tr>
<td headers="h201">[ type</td>
<td headers="h202">type[]</td>
</tr>
<tr>
<td headers="h201">( arg-types ) ret-type</td>
<td headers="h202">method type</td>
</tr>
</tbody>
</table>
<h3>2. Получить сигнатуру через <code class="" data-line="">javap</code></h3>
<pre><code class="language-bash" data-line="">%JAVA_HOME%/bin/javap -classpath &quot;your.jar&quot; -s com.myproject.YourClass
</code></pre>
<h3>Пример:</h3>
<p>Для метода:</p>
<pre><code class="language-java" data-line="">public static void runTask(Runnable runnable) {
    runnable.run();
}
</code></pre>
<p>Сигнатура будет: <strong>runTask(Ljava/lang/Runnable;)V</strong> &#8212; принимает объект класса <code class="" data-line="">java.lang.Runnable</code> и возвращает void.<br />
Для встроенных классов (например <code class="" data-line="">android.os.Handler</code>) ищите <code class="" data-line="">.jar</code> в <code class="" data-line="">Android_SDK</code>.</p>
<h3>Совет:</h3>
<p>Для С++ удобнее использовать библиотеку <a href="https://github.com/mitchdowd/jnipp" rel="nofollow" target="_blank">jnipp</a> вместо <code class="" data-line="">jni.h</code></p>
<p><strong>P.S.</strong> Информации подобного рода в интернете &#8212; полно, писал исключительно для себя, чтобы каждый раз не искать.</p>
]]></content>
		
					<link rel="replies" type="text/html" href="https://blog2k.ru/archives/11665#comments" thr:count="0" />
			<link rel="replies" type="application/atom+xml" href="https://blog2k.ru/archives/11665/feed/atom" thr:count="0" />
			<thr:total>0</thr:total>
			</entry>
		<entry>
		<author>
			<name>eJ</name>
					</author>

		<title type="html"><![CDATA[Различные касты в C++]]></title>
		<link rel="alternate" type="text/html" href="https://blog2k.ru/archives/11397" />

		<id>https://blog2k.ru/?p=11397</id>
		<updated>2025-11-19T11:49:24Z</updated>
		<published>2025-05-28T10:14:31Z</published>
		<category scheme="https://blog2k.ru" term="C++" /><category scheme="https://blog2k.ru" term="Программирование" />
		<summary type="html"><![CDATA[В статье описаны основные способы приведения типов в C++: `static_cast`, `dynamic_cast`, `reinterpret_cast`, `const_cast`, C-style cast, `std::static_pointer_cast`, `std::dynamic_pointer_cast`, `std::const_pointer_cast`. Рассказано об их особенностях и личном опыте использования автором.]]></summary>

					<content type="html" xml:base="https://blog2k.ru/archives/11397"><![CDATA[<p>Наткнулся на <a href="https://youtu.be/CVTgYjHjYk0?si=wY0XleloaWWVObJ-" rel="nofollow" target="_blank">полезное видео</a> про приведение типов в C++. Освежил знания в голове. Чтобы не забыть, тут запишу, вдруг пригодится. Видео встроено в конце статьи, можете промотать до него, если текст вам неинтересен, видео более подробное. Автору видео и ведущему <a href="https://www.youtube.com/@PolevoysProgramming" rel="nofollow" target="_blank">канала</a> моё почтение &#8212; <a href="https://www.youtube.com/watch?v=QSIBUblx0J0" rel="nofollow" target="_blank">ролик про lvalue/rvalue</a> я так полностью и не усвоил. Итак, основные способы приведения типов в языке С++ следующие:</p>
<h2>static_cast</h2>
<p>Проверка производится во время компиляции, сообщение о невозможности операции будет получено в момент сборки приложения. Осуществляет явное допустимое приведение типов данных, в основном, используется для преобразования между числовыми типами данных. Нужно быть внимательным, если используете для приведения указателя на родительский класс (<code class="" data-line="">Base *</code>) к указателю на наследника (<code class="" data-line="">Derived *</code>), он не выполняет проверку на корректность приведения (только порядок наследования) в этом случае и привёт к undefined behaviour &#8212; не надо так! Лучше использовать для этого <code class="" data-line="">dynamic_cast</code>. Личный опыт: использую для того, чтобы компилятор не ругался на signed/unsigned типы и float/double.</p>
<h2>dynamic_cast</h2>
<p>Проверка производится во время исполнения. В случае неправильного приведения указателей будет возвращен <code class="" data-line="">nullptr</code>, в случае ссылок исключение <code class="" data-line="">std::bad_cast</code>. Использует RTTI, работает динамически, может применяться только к классам, которые имеют хоть одну виртуальную функцию (в которых есть таблица виртуальных методов). Личный опыт: <code class="" data-line="">dynamic_cast</code> предпочитаю использовать только для приведения указателя на родительский класс (<code class="" data-line="">Base *</code>) к указателю на наследника (<code class="" data-line="">Derived *</code>) с проверкой на 0. Никогда не использую его для ссылок, чтобы не париться с исключениями.</p>
<h2>reinterpret_cast</h2>
<p>Приведение указателей любых типов друг в друга без проверки, на ваш страх и риск. Говорит считать кусок памяти одного типа куском памяти другого типа. Был указатель на массив uint8_t, стал указатель на массив float. Что интересно: не генерирует код, не создаёт новых переменных. Он не изменяет битовое представление данных, а просто интерпретирует их по-другому. Личный опыт: <code class="" data-line="">reinterpret_cast</code> обычно использую, чтобы передавать различные типы через сырой указатель на область памяти (<code class="" data-line="">void*</code>), но однажды я посмотрел, как побитово устроен <code class="" data-line="">float</code>, и под впечатлением от увиденного написал <a href="https://blog2k.ru/archives/3321" target="_blank">целую статью</a>.</p>
<h2>const_cast</h2>
<p>Убирает <code class="" data-line="">const</code> и <code class="" data-line="">volatile</code> модификаторы с переменной. Личный опыт: даже не знаю, для чего он вам может понадобиться. В голову приходит перегрузка операторов: <code class="" data-line="">T &amp;operator[](index)</code> и <code class="" data-line="">const T&amp; operator[](index) const</code> и вызов константного оператора из не константного с помощью <code class="" data-line="">const_cast</code>, чтобы не дублировать код.</p>
<h2>C-style cast</h2>
<p><a href="https://en.cppreference.com/w/cpp/language/explicit_cast" rel="nofollow" target="_blank">Применяет цепочку</a> преобразований, сначала <code class="" data-line="">const_cast</code>, потом <code class="" data-line="">static_cast</code>, потом <code class="" data-line="">static_cast</code> от <code class="" data-line="">const_cast</code>, потом <code class="" data-line="">reinterpret_cast</code>, потом <code class="" data-line="">reinterpret_cast</code> от <code class="" data-line="">const_cast</code>. Здорово, правда? Не рекомендую вам его использовать в C++. Личный опыт: грешен, использую, когда лень много писать, но стараюсь его избегать и вам советую, потому что его невозможно найти поиском по файлу, только просматривая каждую строку глазами, а они не вечные. Вообще, всю жизнь считал, что это аналог <code class="" data-line="">reinterpret_cast</code>, но я ошибался.</p>
<h2>std::static_pointer_cast</h2>
<p>Аналог <code class="" data-line="">static_cast</code> для приведения умных указателей <code class="" data-line="">std::shared_ptr</code>. Личный опыт: <code class="" data-line="">std::static_pointer_cast</code> использую для приведения умных указателей на базовый класс (<code class="" data-line="">std::shared_ptr&lt;Base&gt;</code>) к умному указателю на наследованный класс (<code class="" data-line="">std::shared_ptr&lt;Derived&gt;</code>).</p>
<h2>std::dynamic_pointer_cast</h2>
<p>Аналог <code class="" data-line="">dynamic_cast</code> для умных указателей <code class="" data-line="">std::shared_ptr</code>. Личный опыт: никогда не видел вживую и не использовал, узнал про него в сейчас лет.</p>
<h2>std::const_pointer_cast</h2>
<p>Аналог <code class="" data-line="">const_cast</code> для умных указателей <code class="" data-line="">std::shared_ptr</code>. Личный опыт: узнал про последние два только во время написания этой статьи, никогда не использовал. Буду &#171;блистать&#187; на собесах.</p>
<h2>Видео по теме</h2>
<div class="sllv-video -type_youtube" data-provider="youtube" data-video="CVTgYjHjYk0"><a class="sllv-video__link" href="https://youtu.be/CVTgYjHjYk0?si=wY0XleloaWWVObJ-" rel="external noopener" target="_blank"><img decoding="async" class="sllv-video__media" src="https://i.ytimg.com/vi_webp/CVTgYjHjYk0/sddefault.webp" alt="Видео"></a><button class="sllv-video__button" type="button" aria-label="Воспроизвести видео"><svg width="68" height="48" viewBox="0 0 68 48"><path class="sllv-video__button-shape" d="M66.52 7.74c-.78-2.93-2.49-5.41-5.42-6.19C55.79.13 34 0 34 0S12.21.13 6.9 1.55c-2.93.78-4.63 3.26-5.42 6.19C.06 13.05 0 24 0 24s.06 10.95 1.48 16.26c.78 2.93 2.49 5.41 5.42 6.19C12.21 47.87 34 48 34 48s21.79-.13 27.1-1.55c2.93-.78 4.64-3.26 5.42-6.19C67.94 34.95 68 24 68 24s-.06-10.95-1.48-16.26z"/><path class="sllv-video__button-icon" d="M45 24L27 14v20"/></svg></button></div>
]]></content>
		
					<link rel="replies" type="text/html" href="https://blog2k.ru/archives/11397#comments" thr:count="0" />
			<link rel="replies" type="application/atom+xml" href="https://blog2k.ru/archives/11397/feed/atom" thr:count="0" />
			<thr:total>0</thr:total>
			</entry>
		<entry>
		<author>
			<name>eJ</name>
					</author>

		<title type="html"><![CDATA[Что происходит когда кретин начинает писать плагин для WordPress]]></title>
		<link rel="alternate" type="text/html" href="https://blog2k.ru/archives/11342" />

		<id>https://blog2k.ru/?p=11342</id>
		<updated>2025-10-22T12:30:46Z</updated>
		<published>2025-05-15T11:07:34Z</published>
		<category scheme="https://blog2k.ru" term="JavaScript" /><category scheme="https://blog2k.ru" term="Администрирование" /><category scheme="https://blog2k.ru" term="Программирование" /><category scheme="https://blog2k.ru" term="Хобби" /><category scheme="https://blog2k.ru" term="WordPress API" />
		<summary type="html"><![CDATA[На моём сайте при заходе на страницу «Контакты» автоматически запускался аудиофайл из-за вредоносного кода в плагине Ajaxify Comments от Ronald Huereca. Я отключил все плагины и поочерёдно их включал, чтобы выявить проблему.]]></summary>

					<content type="html" xml:base="https://blog2k.ru/archives/11342"><![CDATA[<p>Всем привет! Случилась у меня сегодня история: при заходе на страницу <a href="https://blog2k.ru/about" target="_blank">Контакты</a> запустилось проигрывание аудио файла. Сначала я подумал, что сайт хакнули, поэтому, открыв страницу с помощью пункта меню &#171;Посмотреть код&#187;, открыл код страницы и начал внимательно его рассматривать.</p>
<p>Оказалось, кто-то или что-то добавляет ссылку на аудиофайл в конце страницы с тегом audio и он начинает играть.</p>
<p>После этого пошёл отключил все плагины разом и начал их включать по одному.</p>
<p>Хорошо хоть вредитель находится вверху списка плагинов и это плагин <strong>Ajaxify Comments</strong> от автора <strong>Ronald Huereca</strong> с мозговым аппаратом облегчённого образца и говорящей фамилией.</p>
<p>Этот кретин догадался вставить следующий код:</p>
<pre><code class="language-javascript" data-line="">// Dear russian users visiting russian sites. Let&#039;s have fun.
if (typeof window !== &#039;undefined&#039; &amp;&amp; /^ru\b/.test(navigator.language) &amp;&amp; location.host.match(/\.(ru|su|by|xn--p1ai)$/)) {
    const now = new Date();
    const initiationDate = localStorage.getItem(&#039;swal-initiation&#039;);
    if (!initiationDate) {
      localStorage.setItem(&#039;swal-initiation&#039;, &quot;&quot;.concat(now));
    } else if ((now.getTime() - Date.parse(initiationDate)) / (1000 * 60 * 60 * 24) &gt; 3) {
      setTimeout(() =&gt; {
        document.body.style.pointerEvents = &#039;none&#039;;
        /// Код добавления аудио удалён
        document.body.appendChild(audio);
        setTimeout(() =&gt; {
          audio.play().catch(() =&gt; {
            // ignore
          });
        }, 2500);
      }, 500);
    }
  }
</code></pre>
<p>Для непрограммистов объясняю: это означает для всех русских и белорусских сайтов (а также доменов .su и .рф) добавить аудио файл и запускать его проигрывание в зависимости от текущей даты. Трижды подумайте &#8212; нужен ли вам плагин <strong>Ajaxify Comments</strong> от конченого кретина <strong>Ronald Huereca</strong>.</p>
<p>Судя по истории <a href="https://github.com/DLXPlugins/wp-ajaxify-comments" rel="nofollow" target="_blank">github</a>: этот кусок кода добавлен 10 сентября 2023 года. Можете сказать ему спасибо в виде одной звезды в рейтинге на <a href="https://wordpress.org/plugins/wp-ajaxify-comments/" rel="nofollow" target="_blank">странице плагина</a>.</p>
]]></content>
		
					<link rel="replies" type="text/html" href="https://blog2k.ru/archives/11342#comments" thr:count="3" />
			<link rel="replies" type="application/atom+xml" href="https://blog2k.ru/archives/11342/feed/atom" thr:count="3" />
			<thr:total>3</thr:total>
			</entry>
		<entry>
		<author>
			<name>eJ</name>
					</author>

		<title type="html"><![CDATA[Добавление swap файла подкачки во FreeBSD]]></title>
		<link rel="alternate" type="text/html" href="https://blog2k.ru/archives/11302" />

		<id>https://blog2k.ru/?p=11302</id>
		<updated>2025-10-22T12:30:58Z</updated>
		<published>2025-05-06T06:47:59Z</published>
		<category scheme="https://blog2k.ru" term="Администрирование" /><category scheme="https://blog2k.ru" term="Хобби" /><category scheme="https://blog2k.ru" term="FreeBSD" />
		<summary type="html"><![CDATA[В статье описывается, как создать swap-файл в FreeBSD для расширения виртуальной памяти. Процесс включает создание файла, установку прав доступа, добавление его в /etc/fstab и активацию через swapon. Это полезно для оптимизации работы системы при нехватке оперативной памяти.]]></summary>

					<content type="html" xml:base="https://blog2k.ru/archives/11302"><![CDATA[<p>Добавление swap файла подкачки во FreeBSD, вольный перевод <a href="https://docs.freebsd.org/en/books/handbook/config/#create-swapfile" rel="nofollow" target="_blank">части официальной документации</a>.</p>
<p>Первым шагом создадим swap файл <strong>/var/swap0</strong> размером 1024M:</p>
<pre><code class="language-bash" data-line="">dd if=/dev/zero of=/var/swap0 bs=1M count=1024
</code></pre>
<p>Вторым шагом выставим необходимые права доступа на swap файл:</p>
<pre><code class="language-bash" data-line="">chmod 0600 /var/swap0
</code></pre>
<p>Третий шагом информируем систему о новом swap файле путём добавления его в <strong>/etc/fstab</strong></p>
<pre><code class="" data-line="">md none swap sw,file=/var/swap0,late 0 0
</code></pre>
<p>swap файл подключится после перезагрузки системы, чтобы включить его немедленно, используйте swapon:</p>
<pre><code class="language-bash" data-line="">swapon -aL
</code></pre>
<p>Зачем это нужно?</p>
<p>Оперативная память довольно дорогой параметр при выборе VDS сервера, размер жёсткого диска обходится гораздо дешевле. Правда, swap область обычно создаётся в виде раздела жёсткого диска при первой инсталляции и увеличить его ещё тот геморрой, а иногда это необходимо. У меня, например, mysql сервер со временем выжирает весь своп и сервер тупо виснет пока mysql не будет перезапущен. Надеюсь этого решения хватит надолго.</p>
]]></content>
		
					<link rel="replies" type="text/html" href="https://blog2k.ru/archives/11302#comments" thr:count="0" />
			<link rel="replies" type="application/atom+xml" href="https://blog2k.ru/archives/11302/feed/atom" thr:count="0" />
			<thr:total>0</thr:total>
			</entry>
		<entry>
		<author>
			<name>eJ</name>
					</author>

		<title type="html"><![CDATA[Добавляем вывод количества просмотров записи из Jetpack Stats]]></title>
		<link rel="alternate" type="text/html" href="https://blog2k.ru/archives/11198" />

		<id>https://blog2k.ru/?p=11198</id>
		<updated>2025-12-09T08:42:46Z</updated>
		<published>2025-04-11T14:02:15Z</published>
		<category scheme="https://blog2k.ru" term="PHP" /><category scheme="https://blog2k.ru" term="Программирование" /><category scheme="https://blog2k.ru" term="WordPress API" />
		<summary type="html"><![CDATA[В статье описывается, как я пытался оптимизировать получение количества просмотров записей в блоге. Сначала использовал плагин, но затем решил сделать это сам, избегая долгой загрузки страниц. Описываются две попытки решения проблемы: с кешированием и без, с использованием WPCron.]]></summary>

					<content type="html" xml:base="https://blog2k.ru/archives/11198"><![CDATA[<p>Всем привет! У каждой записи в моем блоге есть метаинформация, где присутствует цифра с глазиком &#8212; это общее количество просмотров записи. Получается эта информация из плагина Jetpack. Сначала использовал <a href="https://wordpress.org/plugins/post-views-for-jetpack/" rel="nofollow" target="_blank">специальный плагин</a>, который вытаскивает эту информацию самостоятельно, потом, подсмотрев как он работает, решил сделать это сам. Получилось не сразу. Рассказываю как всё было.</p>
<h2>Попытка №1 &#8212; решение в лоб с кешированием</h2>
<p>Получение количества просмотров работает чрезвычайно медленно. Например, некоторые мои страницы при работе напрямую с плагином загружались аж ПЯТЬДЕСЯТ ТРИ (!!) секунды. Поэтому в один прекрасный день я выключил этот функционал. Код был такой (<code class="" data-line="">functions.php</code>). Не используйте его, он здесь только для истории:</p>
<pre><code class="language-php" data-line=""># Используем класс WPCOM_Stats из Jetpack
use Automattic\Jetpack\Stats\WPCOM_Stats;

# Метод получения количества просмотров с кэшированием
function get_post_views($post_id) {
  # Ключ кэша &quot;wp_cached_counter_номер_поста&quot;
  $cache_key = &#039;wp_cached_counter_&#039; . $post_id;

  # Получим значение кэша по ключу
  $counter = get_transient($cache_key);

  # Если значения нет, значит создадим
  if (false == $counter) {
    # Объект класса для работы со статистикой Jetpack
    $wp_stats = new WPCOM_Stats();

    # Получим статистику просмотров для $post_id и преобразуем её в объект (тут может пройти до ДЕСЯТИ секунд)
    $stats = $wp_stats-&gt;convert_stats_array_to_object($wp_stats-&gt;get_post_views($post_id));

    # Количество просмотров
    $counter = intval($stats-&gt;views);

    # Сохраним в кэше на час
    set_transient($cache_key, $counter, HOUR_IN_SECONDS);
  }

  return $counter;
}

# Печатаем количество просмотров поста
function print_view_counter() {
  # Получим значение
  $counter = get_post_views(get_the_ID());

  # Нулевые счётчики не выводим
  if (!$counter) {
    return;
  }

  # Если больше тысячи, выведем количество тысяч с суффиксом K. То есть вместо 6404 будет 6K
  if (intval($counter) &gt; 1000) {
    printf(&#039;&lt;span class=&quot;view&quot; title=&quot;%s&quot;&gt;%sK&lt;/span&gt;&#039;, $counter, intdiv($counter, 1000));
  }
  else {
    printf(&#039;&lt;span class=&quot;view&quot;&gt;%s&lt;/span&gt;&#039;, $counter);
  }
}
</code></pre>
<p>Затем вставляем в любом месте темы код:</p>
<pre><code class="language-php" data-line="">&lt;?php print_view_counter(); ?&gt;
</code></pre>
<p>и получаем цифру просмотров.</p>
<p>Спустя какое-то время я увидел, что страницы грузятся безбожно долго, особенно страницы с категориями или тегами. Некоторые грузились по минуте, потому что запрос количества просмотров идёт с сайта stats.wp.com и иногда доходит до ДЕСЯТИ СЕКУНД на запрос.</p>
<p><span id="more-11198"></span></p>
<h2>Попытка №2 &#8212; использование WPCron без кеширования</h2>
<p>В итоге я решил запускать обновление счётчиков периодически по крону, записывать/получать их значения с помощью <code class="" data-line="">update_post_meta</code> и <code class="" data-line="">get_post_meta</code> соответственно в поле <code class="" data-line="">_post_counter</code>. В моём самописном плагине я ежедневно обновляю информацию:</p>
<pre><code class="language-php" data-line=""># Используем Jetpack WPCOM_Stats
use Automattic\Jetpack\Stats\WPCOM_Stats;

# Метод получения счётчика без кеширования, возвращает цифру
function b2k_get_post_counter($wp_stats, $post_id) {
  $stats = $wp_stats-&gt;convert_stats_array_to_object($wp_stats-&gt;get_post_views($post_id));
  return intval($stats-&gt;views);
}

# Обновление счётчиков у всех страниц в блоге
function b2k_update_all_counters() {
  $posts = get_posts(
    array(
      &#039;post_type&#039; =&gt; &#039;any&#039;,
      &#039;posts_per_page&#039; =&gt; -1,
      &#039;post_status&#039; =&gt; &#039;publish&#039;
    )
  );

  # Создадим один раз объект для запроса статистики
  $wp_stats = new WPCOM_Stats();

  # Для каждой страницы
  foreach ($posts as $post) {
    # Запрашиваем счётчик
    $counter = b2k_get_post_counter($wp_stats, $post-&gt;ID);
    # Записываем его в мета поле с именем _post_counter каждой странице
    update_post_meta($post-&gt;ID, &#039;_post_counter&#039;, $counter);
  }
}
# Создаём событие b2k_update_counters_event
add_action(&#039;b2k_update_counters_event&#039;, &#039;b2k_update_all_counters&#039;);

# Во время активации плагина
function b2k_cron_activation() {
  # Убираем хук b2k_update_counters_event
  wp_clear_scheduled_hook(&#039;b2k_update_counters_event&#039;);
  # Добавляем ежедневный запуск события b2k_update_counters_event
  wp_schedule_event(time(), &#039;daily&#039;, &#039;b2k_update_counters_event&#039;);
}
register_activation_hook(__FILE__, &#039;b2k_cron_activation&#039;);

# Во время деактивации плагина
function b2k_cron_deactivation() {
  # Удаляем хук
  wp_clear_scheduled_hook(&#039;b2k_update_counters_event&#039;);
}
register_deactivation_hook(__FILE__, &#039;b2k_cron_deactivation&#039;);
</code></pre>
<p>В теме я просто получаю значение поля:</p>
<pre><code class="language-php" data-line="">function print_view_counter() {
  # Получить значение мета поля _post_counter, всегда строка
  $counter = get_post_meta($post_id, &quot;_post_counter&quot;, true);
  # Если счётчика нет, значит ноль
  if (!$counter) {
    $counter = 0;
  }
  else {
    # Иначе нам нужна цифра
    $counter = intval($counter);
  }

  # Если больше тысячи, выведем количество тысяч с суффиксом K. То есть вместо 6404 будет 6K
  if ($counter &gt; 1000) {
    printf(&#039;&lt;span class=&quot;view&quot; title=&quot;%s&quot;&gt;%sK&lt;/span&gt;&#039;, $counter, intdiv($counter, 1000));
  }
  else {
    printf(&#039;&lt;span class=&quot;view&quot;&gt;%s&lt;/span&gt;&#039;, $counter);
  }
}
</code></pre>
<p>В вычислении скорости загрузи меня выручил плагин <a href="https://ru.wordpress.org/plugins/query-monitor/" rel="nofollow" target="_blank">Query Monitor</a>. Для работы кода обязателен плагин <a href="https://ru.wordpress.org/plugins/jetpack/" rel="nofollow" target="_blank">Jetpack</a> с включенным модулем Stats. Для первоначальной установки Cron события необходимо выключить и включить плагин.</p>
<p><strong>UPD</strong>: Код выше скорее всего устарел и актуальную версию можно найти в <a href="https://github.com/jirnov/b2k-tools" rel="nofollow" target="_blank">исходниках плагина b2k-tools на GitHub</a>.</p>
]]></content>
		
					<link rel="replies" type="text/html" href="https://blog2k.ru/archives/11198#comments" thr:count="0" />
			<link rel="replies" type="application/atom+xml" href="https://blog2k.ru/archives/11198/feed/atom" thr:count="0" />
			<thr:total>0</thr:total>
			</entry>
		<entry>
		<author>
			<name>eJ</name>
					</author>

		<title type="html"><![CDATA[Устройство движка для квестов Trickster Games]]></title>
		<link rel="alternate" type="text/html" href="https://blog2k.ru/archives/10793" />

		<id>https://blog2k.ru/?p=10793</id>
		<updated>2025-12-08T07:55:47Z</updated>
		<published>2025-03-28T19:14:33Z</published>
		<category scheme="https://blog2k.ru" term="C++" /><category scheme="https://blog2k.ru" term="Python" /><category scheme="https://blog2k.ru" term="Программирование" /><category scheme="https://blog2k.ru" term="Trickster Games" /><category scheme="https://blog2k.ru" term="Полезная статья" />
		<summary type="html"><![CDATA[В статье описывается структура игрового движка для квестов Trickster Games, который использовался в некоторых играх. Движок написан на C++ с использованием DirectX 9.0 и Boost.Python для связки с Python 2.xx. Основное внимание уделено элементам редактора, таким как уровни, слои, анимированные объекты и их свойства. Также описаны форматы файлов, используемые в движке.]]></summary>

					<content type="html" xml:base="https://blog2k.ru/archives/10793"><![CDATA[<p>Всем привет! В результате <a href="https://blog2k.ru/archives/10648" target="_blank">недавних трудов</a> у меня появились исходники движка для квестов компании Trickster Games. Выкладывать я их не буду, потому что не знаю насколько он лицензионно чистый. Я не юрист, в таких вопросах не разбираюсь. Поэтому расскажу своими словами &#8212; как устроен движок для квестов <a href="https://stopgame.ru/company/2412" rel="nofollow" target="_blank">Trickster Games</a>.</p>
<p>Поколений движков было два &#8212; первый использовался для игр <a href="https://stopgame.ru/game/tanita_ili_morskoe_prikljuchenie" rel="nofollow" target="_blank">Танита. Морское Приключение</a>, <a href="https://stopgame.ru/game/prikljuchenija_barona_mjunhgauzena_na_lune" rel="nofollow" target="_blank">Приключения Барона Мюнхгаузена на Луне</a> и использовал <a href="https://ru.wikipedia.org/wiki/Lua" rel="nofollow" target="_blank">lua</a> в качестве скриптового языка.</p>
<p><img loading="lazy" decoding="async" src="https://blog2k.ru/wp-content/uploads/2025/03/6704427086.webp" alt="Танита. Морское приключение и Приключения Барона Мюнхгаузена на Луне" width="1200" height="600" class="aligncenter size-full wp-image-10803" srcset="https://blog2k.ru/wp-content/uploads/2025/03/6704427086.webp 1200w, https://blog2k.ru/wp-content/uploads/2025/03/6704427086-300x150.webp 300w, https://blog2k.ru/wp-content/uploads/2025/03/6704427086-1024x512.webp 1024w, https://blog2k.ru/wp-content/uploads/2025/03/6704427086-768x384.webp 768w" sizes="auto, (max-width: 1200px) 100vw, 1200px" /></p>
<p>Начиная с игры <a href="https://stopgame.ru/game/petrovich_i_vse_vse_vse" rel="nofollow" target="_blank">&#171;Петрович и все, все, все&#187;</a> движок переходит на использование Python 2.xx вместо lua. Я пришёл в Trickster Games, когда начали делать Петрович, так что про предыдущие движки и игры практически ничего не знаю.</p>
<p>Итак, приступим!</p>
<p><span id="more-10793"></span></p>
<h2>Описание редактора игрового движка Trickster Games</h2>
<p>Небольшое отступление: движок казался гораздо проще. Однако, он содержит в себе множество разных python классов, буду заново разбираться по ходу написания статьи.</p>
<p>Итак, у нас есть редактор (это первый уровень игры &#171;Петрович и все все все&#187;):</p>
<p><img loading="lazy" decoding="async" src="https://blog2k.ru/wp-content/uploads/2025/03/editor.png" alt="Редактор Trickster Games" width="1264" height="967" class="aligncenter size-full wp-image-10819" srcset="https://blog2k.ru/wp-content/uploads/2025/03/editor.png 1264w, https://blog2k.ru/wp-content/uploads/2025/03/editor-300x230.png 300w, https://blog2k.ru/wp-content/uploads/2025/03/editor-1024x783.png 1024w, https://blog2k.ru/wp-content/uploads/2025/03/editor-768x588.png 768w" sizes="auto, (max-width: 1264px) 100vw, 1264px" /></p>
<p>Это тот же самый движок, но запущенный в специальном режиме.<br />
Слева у нас окно дерева объектов, снизу свойства объекта, а справа самый большой экран &#8212; экран предпросмотра уровня. Фон заполняется жёлтым цветом, чтобы на сцене сразу были видны пустые места. В режиме игры, фон заполняется чёрным цветом, так что это не бросается в глаза в обычном режиме.</p>
<p>Почти все объекты наследуются от ItemBase и рисуются относительно координат родителя. При перемещении родительского элемента на сцене, его дети перемещаются вместе с ним. В дереве объектов элементы можно перетаскивать с помощью drag-n-drop или добавлять новые правой кнопкой мыши. У каждого элемента есть замочек и глазик &#8212; блокировать перемещение/выделение при клике на сцену и показать/спрятать элемент при отрисовке сцены. Отрисовка элементов идёт по дереву от корневого узла вниз.</p>
<h3>Уровень (Location)</h3>
<p>Собственно уровень игры, рутовый элемент нашей сцены, содержит параметры width, height &#8212; ширина локации, высота локации. Вот её панель свойств:</p>
<p><img loading="lazy" decoding="async" src="https://blog2k.ru/wp-content/uploads/2025/03/location_props.png" alt="Свойства локации в игровом редакторе Trickster Games" width="1270" height="193" class="aligncenter size-full wp-image-10834" srcset="https://blog2k.ru/wp-content/uploads/2025/03/location_props.png 1270w, https://blog2k.ru/wp-content/uploads/2025/03/location_props-300x46.png 300w, https://blog2k.ru/wp-content/uploads/2025/03/location_props-1024x156.png 1024w, https://blog2k.ru/wp-content/uploads/2025/03/location_props-768x117.png 768w" sizes="auto, (max-width: 1270px) 100vw, 1270px" /></p>
<p>Может содержать в качестве детей только слои.</p>
<h3>Слой (Layer)</h3>
<p>Слой локации, имеет параметр parallax &#8212; это отставание при прокрутке. С помощью него создаётся <a href="https://ru.wikipedia.org/wiki/%D0%9F%D0%B0%D1%80%D0%B0%D0%BB%D0%BB%D0%B0%D0%BA%D1%81-%D1%81%D0%BA%D1%80%D0%BE%D0%BB%D0%BB%D0%B8%D0%BD%D0%B3" rel="nofollow" target="_blank">эффект глубины</a> при скроллинге локации по горизонтали или вертикали. Вот её панель свойств:<br />
<img loading="lazy" decoding="async" src="https://blog2k.ru/wp-content/uploads/2025/03/layer_props.png" alt="Свойства слоя в игровом редакторе Trickster Games" width="1270" height="193" class="aligncenter size-full wp-image-10839" srcset="https://blog2k.ru/wp-content/uploads/2025/03/layer_props.png 1270w, https://blog2k.ru/wp-content/uploads/2025/03/layer_props-300x46.png 300w, https://blog2k.ru/wp-content/uploads/2025/03/layer_props-1024x156.png 1024w, https://blog2k.ru/wp-content/uploads/2025/03/layer_props-768x117.png 768w" sizes="auto, (max-width: 1270px) 100vw, 1270px" /> Может содержать в качестве детей статические изображения, регионы, пути, анимированные объекты и точки.</p>
<h3>Статическое изображение (LayerImage)</h3>
<p>Фоновое изображение, ничего не делает, просто рисуется с соответствующим свойствами (параллакс) слоя. Имеет довольно скудный набор свойств:</p>
<p><img loading="lazy" decoding="async" src="https://blog2k.ru/wp-content/uploads/2025/03/layerimage_props.png" alt="Свойства статического изображения в игровом редакторе Trickster Games" width="1270" height="193" class="aligncenter size-full wp-image-10844" srcset="https://blog2k.ru/wp-content/uploads/2025/03/layerimage_props.png 1270w, https://blog2k.ru/wp-content/uploads/2025/03/layerimage_props-300x46.png 300w, https://blog2k.ru/wp-content/uploads/2025/03/layerimage_props-1024x156.png 1024w, https://blog2k.ru/wp-content/uploads/2025/03/layerimage_props-768x117.png 768w" sizes="auto, (max-width: 1270px) 100vw, 1270px" /></p>
<h3>Анимированный объект (AnimatedObject)</h3>
<p>Можно сказать, что это наш главный элемент, базовый кирпичик нашего движка. У него есть позиция, набор состояний, к нему привязываются звуки, регионы, а также скрипт.</p>
<p><img loading="lazy" decoding="async" src="https://blog2k.ru/wp-content/uploads/2025/03/animatedobject_props.png" alt="Свойства игрового объекта в игровом редакторе Trickster Games" width="1270" height="193" class="aligncenter size-full wp-image-10846" srcset="https://blog2k.ru/wp-content/uploads/2025/03/animatedobject_props.png 1270w, https://blog2k.ru/wp-content/uploads/2025/03/animatedobject_props-300x46.png 300w, https://blog2k.ru/wp-content/uploads/2025/03/animatedobject_props-1024x156.png 1024w, https://blog2k.ru/wp-content/uploads/2025/03/animatedobject_props-768x117.png 768w" sizes="auto, (max-width: 1270px) 100vw, 1270px" /></p>
<p>Он может наследоваться от особенных классов, например, Playable Character &#8212; это наш главный герой, который умеет ходить по локации, или Takeable Item &#8212; это вещь, которую можно забрать себе в инвентарь. Он может загружаться согласно определённым условиям из скрипта, если поставить флажок &#171;Conditional object loading&#187;. Пример условной загрузки элемента &#171;Item_parfume&#187; (условия описываются в родительском элементе):</p>
<pre><code class="language-python" data-line="">class FloorLayer:
    def should_load_Item_parfume(self):
        return not world.parfume_taken
</code></pre>
<p>Также у него есть pivot &#8212; начало его координат и позиция на локации абсолютная и относительная. К нему могут привязываться дочерние AnimatedObject, Region и StateSequence. Содержит список состояний. Представляет собой <a href="https://ru.wikipedia.org/wiki/%D0%9A%D0%BE%D0%BD%D0%B5%D1%87%D0%BD%D1%8B%D0%B9_%D0%B0%D0%B2%D1%82%D0%BE%D0%BC%D0%B0%D1%82" rel="nofollow" target="_blank">конечный автомат</a>, который меняет своё состояние в зависимости от внешних условий. Может загружать дочерние элементы типа AnimatedObject по некоторым условиям.</p>
<h3>Состояние объекта (AnimatedSequence)</h3>
<p>Анимация и состояние AnimatedObject. Анимация неотделима от состояния объекта. Пока AnimatedObject находится в определённом состоянии, проигрывается анимация этого состояния из одного или нескольких кадров. К любому кадру можно привязать автоматическое проигрывание звука.<br />
<img loading="lazy" decoding="async" src="https://blog2k.ru/wp-content/uploads/2025/03/state_props.png" alt="Свойства состояния объекта в игровом редакторе Trickster Games" width="1270" height="243" class="aligncenter size-full wp-image-10861" srcset="https://blog2k.ru/wp-content/uploads/2025/03/state_props.png 1270w, https://blog2k.ru/wp-content/uploads/2025/03/state_props-300x57.png 300w, https://blog2k.ru/wp-content/uploads/2025/03/state_props-1024x196.png 1024w, https://blog2k.ru/wp-content/uploads/2025/03/state_props-768x147.png 768w" sizes="auto, (max-width: 1270px) 100vw, 1270px" /></p>
<p>У состояния есть свойства on_enter, on_exit, link, on_update &#8212; для привязки пользовательских функций. on_enter выполнятся при переходе в это состояние, on_exit &#8212; при выходе из него, link &#8212; выполняется каждый кадр, и если возвращает строку, то состояние меняется на указанное, on_update вызывается каждым кадр с неким dt (количество миллисекунд между кадрами).</p>
<h3>Регион (Region)</h3>
<p>Некий замкнутый набор точек. Определяет область для хождения главного героя на сцене (на скриншоте редактора это R_Floor) и области для клика мышкой. Имеет свойство<br />
&#171;.click&#187; или &#171;.click_with_<Item_name>&#187; для проверки клика на этот регион, второе свойство динамическое и проверяется клик с предметом из трея. Предоставляет метод для поиска кратчайшего пути между точками для хождения главного героя. Может иметь несколько типов (не помню, кто за что отвечает) и менять курсор мыши при наведении.<br />
<img loading="lazy" decoding="async" src="https://blog2k.ru/wp-content/uploads/2025/03/region_props.png" alt="Свойства региона в игровом редакторе Trickster Games" width="1274" height="243" class="aligncenter size-full wp-image-10865" srcset="https://blog2k.ru/wp-content/uploads/2025/03/region_props.png 1274w, https://blog2k.ru/wp-content/uploads/2025/03/region_props-300x57.png 300w, https://blog2k.ru/wp-content/uploads/2025/03/region_props-1024x195.png 1024w, https://blog2k.ru/wp-content/uploads/2025/03/region_props-768x146.png 768w" sizes="auto, (max-width: 1274px) 100vw, 1274px" /></p>
<h3>Путь (Path)</h3>
<p>Путь состоящий из нескольких точек. Можно привязать элемент к этому пути, и объект будет плавно по нему перемещаться.<br />
<img loading="lazy" decoding="async" src="https://blog2k.ru/wp-content/uploads/2025/03/path_props.png" alt="Свойства пути в игровом редакторе Trickster Games" width="1274" height="243" class="aligncenter size-full wp-image-10867" srcset="https://blog2k.ru/wp-content/uploads/2025/03/path_props.png 1274w, https://blog2k.ru/wp-content/uploads/2025/03/path_props-300x57.png 300w, https://blog2k.ru/wp-content/uploads/2025/03/path_props-1024x195.png 1024w, https://blog2k.ru/wp-content/uploads/2025/03/path_props-768x146.png 768w" sizes="auto, (max-width: 1274px) 100vw, 1274px" /></p>
<h3>Точка (Point)</h3>
<p>Точка на уровне. В основном используется, чтобы указывать, куда подходит главный герой для выполнения действий. Настраиваемых свойств в редакторе не имеет, только позицию.</p>
<h2>Описание игрового движка Trickster Games</h2>
<p>Движок написан на C++, для рендера используется DirectX 9.0, для связки Python 2.xx и C++ используется Boost.Python. Для сборки и компиляции исходников движка применяется (<span class="text-red">БУДЬТЕ ПРОКЛЯТЫ ЕГО СОЗДАТЕЛИ!</span>) <a href="https://www.boost.org/doc/libs/1_31_0/tools/build/jam_src/index.html" rel="nofollow" target="_blank">Boost Jam</a> и Visual Studio 2007.</p>
<p>Базовый элемент в игровом движке &#8212; это GameObject, который имеет матрицу трансформации себя относительно родителя, список детей типа GameObject, и используется для создания дерева сцены. Простыми словами, для отрисовки дерева сцены вызывается GameObject::update(dt), который последовательно вызывает обновления всех детей, начиная от корня дерева вниз по иерархии. От него торчат уши в Python. Python-часть движка инициализируется следующим кодом:</p>
<pre><code class="language-cpp" data-line="">std::string setup(
&quot;sys.path = [r&#039;Data\Scripts1.pak&#039;, r&#039;Data\Scripts2.pak&#039;, &quot;
                    &quot;r&#039;Data\Scripts3.pak&#039;, r&#039;Data\Scripts3.pak\CommonClasses&#039;, &quot;
                    &quot;r&#039;Data\Scripts4.pak&#039;, r&#039;Data\Scripts4.pak\World&#039;, &#039;.&#039;, &#039;Lib/std&#039;]n&quot;);
run_string(setup);
</code></pre>
<p>Затем вызываем метод <code class="" data-line="">on_init</code> из файла <code class="" data-line="">Lib/engine.py</code>:</p>
<pre><code class="language-cpp" data-line="">boost::python::call&lt;void&gt;(bp::object(py[&quot;Lib&quot;].attr(&quot;engine&quot;).attr(&quot;on_init&quot;)).ptr(), long(application::Application::window()));
py_on_frame = py[&quot;Lib&quot;].attr(&quot;engine&quot;).attr(&quot;on_frame&quot;);
</code></pre>
<p>И после делаем <code class="" data-line="">on_frame</code> из того же файла каждый кадр:</p>
<pre><code class="language-cpp" data-line="">boost::python::call&lt;void&gt;(py_on_frame.ptr(), dt / 1000.0f, just_redraw, cursor_position, mouse_button_state);
</code></pre>
<p>Всё, никакой магии.</p>
<h2>Форматы файлов</h2>
<p>При подготовке релиза происходит преобразование .py файлов в .pyc, PNG в DDS, и всё это запаковывается в .zip файл.</p>
<h3>Анимация</h3>
<p>Анимация делалась в Adobe Flash и экспортировалась в набор PNG файлов, которые при запаковке релиза превращаются в <a href="https://ru.wikipedia.org/wiki/DirectDraw_Surface" rel="nofollow" target="_blank">DDS</a> &#8212; это родной формат для DirectX SDK.</p>
<h3>Звуки</h3>
<p>Звуки &#8212; это .wav файлы</p>
<h3>Видео</h3>
<p>Для видео использовался формат OGV (<a href="https://ru.wikipedia.org/wiki/Theora" rel="nofollow" target="_blank">Theora Vorbis</a>).</p>
<p>Вроде всё, что мог, описал. Спрашивайте, если что-то осталось непонятным.</p>
<p><strong>UPD:</strong> Выложил C++ часть исходников редактора/движка на <a href="https://github.com/jirnov/tanita2_engine" rel="nofollow" target="_blank">github.com</a>.</p>
]]></content>
		
					<link rel="replies" type="text/html" href="https://blog2k.ru/archives/10793#comments" thr:count="0" />
			<link rel="replies" type="application/atom+xml" href="https://blog2k.ru/archives/10793/feed/atom" thr:count="0" />
			<thr:total>0</thr:total>
			</entry>
		<entry>
		<author>
			<name>eJ</name>
					</author>

		<title type="html"><![CDATA[Как досрочно погасить кредит к определенной дате]]></title>
		<link rel="alternate" type="text/html" href="https://blog2k.ru/archives/10765" />

		<id>https://blog2k.ru/?p=10765</id>
		<updated>2025-10-22T12:36:14Z</updated>
		<published>2025-02-03T07:48:37Z</published>
		<category scheme="https://blog2k.ru" term="Жизнь" /><category scheme="https://blog2k.ru" term="Полезные советы" /><category scheme="https://blog2k.ru" term="рекомендую" />
		<summary type="html"><![CDATA[Чтобы досрочно погасить кредит к определённой дате, рассчитайте сумму, которую нужно вносить сверх стандартного платежа. Для этого разделите остаток долга на количество месяцев до нужной даты.]]></summary>

					<content type="html" xml:base="https://blog2k.ru/archives/10765"><![CDATA[<p>Как досрочно погасить кредит к определенной дате? Как вычислить сумму досрочного платежа?</p>
<p>Элементарно: открываете свой график платежей и смотрите остаток в тот месяц, когда хотите, чтобы кредит был полностью погашен, берете эту цифру, делите его на количество месяцев от текущего до искомого и получаете сумму рублей, которые надо вносить сверх вашего стандартного платежа.</p>
<p>Пример: допустим у меня есть кредит в <code class="" data-line="">250 000 &#x20bd;</code>, сейчас февраль и в обычном режиме он погасится через пару лет. Я хочу, чтоб он был погашен в августе, смотрю остаток на август и он составляет <code class="" data-line="">150 000 &#x20bd;</code>, до августа осталось 7 месяцев, включая текущий. Значит <code class="" data-line="">150 000 / 7 &asymp; 21 429 &#x20bd;</code> мне надо вносить сверх обычного платежа и к августу остаток будет нулевым.</p>
<p>Этот способ не учитывает сокращение процентов, так что фактически кредит будет погашен немного раньше нужного срока. Плохо что ли? Хорошо!</p>
<p>Все цифры и даты выдуманы с потолка, все совпадения случайны.</p>
]]></content>
		
					<link rel="replies" type="text/html" href="https://blog2k.ru/archives/10765#comments" thr:count="0" />
			<link rel="replies" type="application/atom+xml" href="https://blog2k.ru/archives/10765/feed/atom" thr:count="0" />
			<thr:total>0</thr:total>
			</entry>
		<entry>
		<author>
			<name>eJ</name>
					</author>

		<title type="html"><![CDATA[Нет сил больше молчать, буду хвастаться.]]></title>
		<link rel="alternate" type="text/html" href="https://blog2k.ru/archives/10648" />

		<id>https://blog2k.ru/?p=10648</id>
		<updated>2025-12-08T07:58:50Z</updated>
		<published>2024-09-18T20:51:26Z</published>
		<category scheme="https://blog2k.ru" term="Бла-бла-бла" /><category scheme="https://blog2k.ru" term="Жизнь" /><category scheme="https://blog2k.ru" term="Trickster Games" /><category scheme="https://blog2k.ru" term="своими руками" />
		<summary type="html"><![CDATA[В статье описывается процесс восстановления данных с устаревших жёстких дисков IDE, которые не подключаются напрямую. Автор использовал посекторные дампы дисков и виртуальные машины для доступа к файлам.]]></summary>

					<content type="html" xml:base="https://blog2k.ru/archives/10648"><![CDATA[<p>Всем привет! Мне нужно срочно поделиться с миром, какой я весь из себя молодец, нет сил больше держать это в себе. В общем, встала задача восстановить данные с жёстких дисков сервера фирмы, где я раньше работал. Так исторически сложилось, что сервер после развала фирмы по договорённости с руководством переехал ко мне домой. Родилась идея восстановить данные с сервера. Сервер давно не включается, в нём старые HDD IDE диски. Всего дисков три штуки: 160Gb, 320Gb и 1.5Tb. Файловая система на них ext2fs или часть RAID массива. Была идея подключить их к виртуальной машине Debian и получить доступ к файлам.</p>
<p>Как я поступил изначально &#8212; купил переходник IDE->USB и попробовал подключить диск к компьютеру.<br />
<img loading="lazy" decoding="async" src="https://blog2k.ru/wp-content/uploads/2024/09/ide2usb.jpg" alt="IDE to USB converter" width="960" height="1280" class="aligncenter size-full wp-image-10654" srcset="https://blog2k.ru/wp-content/uploads/2024/09/ide2usb.jpg 768w, https://blog2k.ru/wp-content/uploads/2024/09/ide2usb-225x300.jpg 225w" sizes="auto, (max-width: 960px) 100vw, 960px" /><br />
<span id="more-10648"></span>Ничего не получилось даже с отдельным блоком питания &#8212; отправил переходник обратно продавцу. Стало понятно, что подключить диски напрямую малой кровью не получится, значит, надо делать копию дисков и подключать к виртуальной машине виртуальные жёсткие диски с этих копий. Постепенно родился такой план решения задачи:</p>
<ol>
<li>Получить посекторные дампы с дисков в виде огромных файлов</li>
<li>Получить виртуальные жёсткие диски с этих файлов и подключить их к виртуальной машине</li>
<li>Получить доступ к файлам из этих дампов из виртуальной машины</li>
</ol>
<h2>Посекторные дампы дисков</h2>
<p>Отнёс диски в <a href="https://dicom.spb.ru/" rel="nofollow" target="_blank">специализированную контору</a>, которая сделала посекторную копию двух дисков на принесённый мною новый SATA диск. Каждая копия обошлась мне в 1500&#x20bd;. Новый SATA диск вышел в районе 4000&#x20bd;. Через пару недель принёс диск с копиями домой, воткнул в <em>компуктер</em> и получил вот такую картину:<br />
<img loading="lazy" decoding="async" src="https://blog2k.ru/wp-content/uploads/2024/09/files.png" alt="Список дампов" width="495" height="194" class="alignleft size-full wp-image-10669" srcset="https://blog2k.ru/wp-content/uploads/2024/09/files.png 495w, https://blog2k.ru/wp-content/uploads/2024/09/files-300x118.png 300w" sizes="auto, (max-width: 495px) 100vw, 495px" /><br />
Второй файл оказался битый, потому что <a href="https://market.yandex.ru/product--st2000vx000/1779564223?sku=10731885&#038;uniqueId=741706&#038;do-waremd5=OMEoiiErTBGoFXfuCx54MQ" rel="nofollow" target="_blank">новый диск</a> для хранения дампов оказался барахлом. НИКОГДА НЕ ПОКУПАЙТЕ <code class="" data-line="">Seagate ST2000VX000</code> &#8212; у меня он начал сыпаться после 19 часов работы. Так что сначала запустил команду для восстановления всех файлов, которая справилась за каких-то три часа:</p>
<pre><code class="" data-line="">chkdsk /F /R /X</code></pre>
<p>и приступил к следующему шагу.</p>
<h2>Конвертирование дампов в виртуальные жёсткие диски для виртуальной машины и их подключение</h2>
<p>Ни одна из известных мне виртуальных машин (<a href="https://www.virtualbox.org/" rel="nofollow" target="_blank">VirtualBox</a>, <a href="https://ru.wikipedia.org/wiki/VMware" rel="nofollow" target="_blank">VMWare</a>, <a href="https://ru.wikipedia.org/wiki/Hyper-V" rel="nofollow" target="_blank">Hyper-V</a>) не поддерживает сырые данные в виде виртуального жёсткого диска, так что в процессе поиска решения, благодаря <a href="https://bogachev.biz/2018/12/04/konvertirovanie-raw-obraza-iz-kvm-v-vhd-vhdx-dlya-hyper-v/" rel="nofollow" target="_blank">статье</a>, наткнулся на бесплатную утилиту <a href="https://www.starwindsoftware.com/starwind-v2v-converter" rel="nofollow" target="_blank">Startwind V2V Converter</a>, при помощи которой и сконвертировал сырые дампы в <code class="" data-line="">.vdi</code> (VirtualBox Disk) и <code class="" data-line="">.vmdk</code> (VMWare Virtual Disk). Программа очень проста в использовании. Выбираем источник данных Local File, место назначения Local File. Потом тип файла и его подтип. Мне пришлось сделать два разных типа, потому что, как я писал выше, второй файл битый, и в формате <code class="" data-line="">.vdi</code> VirtualBox его переварить не смогла, а вот в формате <code class="" data-line="">.vmdk</code> вполне.<br />
Виртуальную машину я использовал <a href="https://www.virtualbox.org/" rel="nofollow" target="_blank">Oracle VirtualBox</a>, просто потому что она бесплатная. Хотел использовать Hyper-V, встроенную в Windows 10 Pro, но она ни в каком виде не смогла подключить второй битый файл.<br />
Подключение расписывать тоже не буду, покажу финальный скриншот:<br />
<img loading="lazy" decoding="async" src="https://blog2k.ru/wp-content/uploads/2024/09/virtual_drives.png" alt="VirtualBox virtual HDD" width="1201" height="733" class="aligncenter size-full wp-image-10712" srcset="https://blog2k.ru/wp-content/uploads/2024/09/virtual_drives.png 1201w, https://blog2k.ru/wp-content/uploads/2024/09/virtual_drives-300x183.png 300w, https://blog2k.ru/wp-content/uploads/2024/09/virtual_drives-1024x625.png 1024w, https://blog2k.ru/wp-content/uploads/2024/09/virtual_drives-768x469.png 768w" sizes="auto, (max-width: 1201px) 100vw, 1201px" /></p>
<h2>Финальный аккорд &#8212; получаем доступ к файлам</h2>
<p>После подключения дисков и запуска Debian необходимо определить, куда они подключились. В линуксе это устройства /dev/sd[a-z], при этом /dev/sda уже занят. Значит, это диски sdb и sdc. Запускаем</p>
<pre><code class="language-bash" data-line="">fdisk -l /dev/sd[b,c]
</code></pre>
<p>И получаем следующую картину:<br />
<img loading="lazy" decoding="async" src="https://blog2k.ru/wp-content/uploads/2024/09/fdisk.png" alt="fdisk" width="1280" height="800" class="aligncenter size-full wp-image-10717" srcset="https://blog2k.ru/wp-content/uploads/2024/09/fdisk.png 1280w, https://blog2k.ru/wp-content/uploads/2024/09/fdisk-300x188.png 300w, https://blog2k.ru/wp-content/uploads/2024/09/fdisk-1024x640.png 1024w, https://blog2k.ru/wp-content/uploads/2024/09/fdisk-768x480.png 768w" sizes="auto, (max-width: 1280px) 100vw, 1280px" /><br />
Отсюда следует, что /dev/sdc2 можно сразу монтировать командой:</p>
<pre><code class="language-bash" data-line="">mount /dev/sdc2 /mnt/memory-150
</code></pre>
<p>А на диске <code class="" data-line="">/dev/sdb</code> располагается кусок raid массива. Я в них абсолютно ничего не понимаю, зато умею гуглить, и нашёл статью, как подключить один кусок из программного raid массива &#8212; <a href="https://interface31.ru/tech_it/2022/04/podklyuchaem-disk-iz-nas-v-linux-ili-montirovanie-raid-i-lvm-razdelov.html" rel="nofollow" target="_blank">тыц</a>. Как бездумная, но опытная обезьянка, выполнил шаманство с запуском <code class="" data-line="">pvscan</code>, <code class="" data-line="">mdamd</code>, <code class="" data-line="">lvm2</code> и прочими командами, и у меня появилось устройства <code class="" data-line="">/dev/onraid/root</code> <code class="" data-line="">/dev/onraid/shares</code> <code class="" data-line="">/dev/onraid/var</code>, которые я успешно смонтировал командами:</p>
<pre><code class="language-bash" data-line="">mount /dev/onraid/root /mnt/memory-300-root
mount /dev/onraid/shares /mnt/memory-300-shares
mount /dev/onraid/var /mnt/memory-300-var
</code></pre>
<p>Всё, результат есть, файлы доступны, можно <del>продавать исходники</del> пустить ностальгическую слезу. Осталось проделать похожие процедуры с третьим диском на полтора терабайта, но у меня пока нет таких свободных объёмов. А потом можно подумать, что делать с этим добром, потому что самые свежие исходники там от 2010 года и выглядят местами очень наивно.</p>
<p>P.S. Кому интересно, <a href="https://blog2k.ru/archives/10793" target="_blank">устройство игрового движка Trickster Games</a></p>
]]></content>
		
					<link rel="replies" type="text/html" href="https://blog2k.ru/archives/10648#comments" thr:count="5" />
			<link rel="replies" type="application/atom+xml" href="https://blog2k.ru/archives/10648/feed/atom" thr:count="5" />
			<thr:total>5</thr:total>
			</entry>
		<entry>
		<author>
			<name>eJ</name>
					</author>

		<title type="html"><![CDATA[Инструкция по замене третьего стоп-сигнала на SEAT Altea Freetrack]]></title>
		<link rel="alternate" type="text/html" href="https://blog2k.ru/archives/10587" />

		<id>https://blog2k.ru/?p=10587</id>
		<updated>2025-12-08T07:52:51Z</updated>
		<published>2024-09-08T19:37:58Z</published>
		<category scheme="https://blog2k.ru" term="SEAT Altea Freetrack" /><category scheme="https://blog2k.ru" term="Автомобиль" /><category scheme="https://blog2k.ru" term="Seat Altea Freetrack" /><category scheme="https://blog2k.ru" term="Полезная статья" /><category scheme="https://blog2k.ru" term="своими руками" />
		<summary type="html"><![CDATA[В статье делюсь инструкцией по замене третьего стоп-сигнала. Нужно снять обшивку пятой двери, разделить стоп-сигнал на части, заменить его на новый и проверить работоспособность. Работы лучше выполнять в тёплое время года.]]></summary>

					<content type="html" xml:base="https://blog2k.ru/archives/10587"><![CDATA[<p>Всем привет! Давно бесил меня нерабочий третий стоп-сигнал и буквально недавно я его поменял вот этими вот самыми программистскими руками. Поделюсь с вами инструкцией.</p>
<p>Для замены третьего стоп-сигнала необходимо снять обшивку пятой двери, которая состоит из двух частей: верхней и нижней. Нижняя часть крепится клипсами и четырьмя шурупами. Два из них под заглушками, два возле выемки для закрытия багажника. Верхняя часть крепится только на клипсы. Сначала снимается нижняя часть обшивки, затем верхняя часть.<br />
Сам стоп-сигнал состоит из двух частей: внешний красный плафон и прозрачный корпус с микросхемой. Корпус стоп-сигнала разделяется с некоторым усилием на две части, если потянуть за длинный хвостик прозрачного корпуса вправо. А теперь подробно и по пунктам.</p>
<p><span id="more-10587"></span></p>
<h2>Для замены стоп-сигнала требуется провести следующие операции:</h2>
<ol>
<li>Снять нижнюю часть обшивки. Снимаем предварительно заглушки, выкручиваем под ними два шурупа, затем два шурупа в выемке и тянем обшивку вниз, взявшись за отверстия от заглушек. Фоток не делал, шурупы найдёте самостоятельно.</li>
<li>Снять верхнюю часть обшивки. Сначала тянем обшивку за бока к центру, чтобы она сузилась, затем вытягиваем центр на себя, согласно стрелочкам: <img loading="lazy" decoding="async" src="https://blog2k.ru/wp-content/uploads/2024/09/remove-last-panel-scaled.jpg" alt="Верхняя часть обшивки пятой двери" width="2560" height="1920" class="aligncenter size-full wp-image-10598" srcset="https://blog2k.ru/wp-content/uploads/2024/09/remove-last-panel-scaled.jpg 1024w, https://blog2k.ru/wp-content/uploads/2024/09/remove-last-panel-300x225.jpg 300w, https://blog2k.ru/wp-content/uploads/2024/09/remove-last-panel-768x576.jpg 768w, https://blog2k.ru/wp-content/uploads/2024/09/remove-last-panel-1536x1152.jpg 1536w, https://blog2k.ru/wp-content/uploads/2024/09/remove-last-panel-2048x1536.jpg 2048w" sizes="auto, (max-width: 2560px) 100vw, 2560px" /></li>
<li>Разделить стоп-сигнал на две части, потянув за язычок вправо через отверстие справа, указанное стрелочкой, зацепив за язычок ключом на 10: <img loading="lazy" decoding="async" src="https://blog2k.ru/wp-content/uploads/2024/09/finger_hole-scaled.jpg" alt="Отверстие в двери для доступа к правой части стоп-сигнала" width="2560" height="1920" class="aligncenter size-full wp-image-10630" srcset="https://blog2k.ru/wp-content/uploads/2024/09/finger_hole-scaled.jpg 1024w, https://blog2k.ru/wp-content/uploads/2024/09/finger_hole-300x225.jpg 300w, https://blog2k.ru/wp-content/uploads/2024/09/finger_hole-768x576.jpg 768w, https://blog2k.ru/wp-content/uploads/2024/09/finger_hole-1536x1152.jpg 1536w, https://blog2k.ru/wp-content/uploads/2024/09/finger_hole-2048x1536.jpg 2048w" sizes="auto, (max-width: 2560px) 100vw, 2560px" /> <img loading="lazy" decoding="async" src="https://blog2k.ru/wp-content/uploads/2024/09/5P0945097A-scaled.jpg" alt="Третий стоп-сигнал SEAT Altea Freetrack. Код запчасти 5P0945097A" width="2560" height="1920" class="aligncenter size-full wp-image-10596" srcset="https://blog2k.ru/wp-content/uploads/2024/09/5P0945097A-scaled.jpg 1024w, https://blog2k.ru/wp-content/uploads/2024/09/5P0945097A-300x225.jpg 300w, https://blog2k.ru/wp-content/uploads/2024/09/5P0945097A-768x576.jpg 768w, https://blog2k.ru/wp-content/uploads/2024/09/5P0945097A-1536x1152.jpg 1536w, https://blog2k.ru/wp-content/uploads/2024/09/5P0945097A-2048x1536.jpg 2048w" sizes="auto, (max-width: 2560px) 100vw, 2560px" /></li>
<li>После щелчка поддеть красный плафон снаружи пластиковой карточкой и извлечь его из гнезда</li>
<li>Вытащить всю конструкции наружу с внешней стороны двери</li>
<li>Поменять стоп-сигнал на новый, благо он <a href="https://track24.ru/google/?q=5P0945097A" rel="nofollow" target="_blank">доступен по цене</a>, если вы сын депутата или простого русского олигарха. Номер запчасти <code class="" data-line="">5P0945097A</code>. Лично я заказывал б/у в компании Ted Auto через сайт zzap.ru.</li>
<li>Проверить работоспособность</li>
<li>Собрать всё в обратном порядке</li>
</ol>
<p>Единственный момент с рывками был во время снятия обеих частей обшивки. Стоп-сигнал разделился на две части без рывков, с некоторым усилием. Все работы выполняйте в тёплое время года, чтобы пластиковые детали были более пластичными, в холодное время повышается риск отломать клипсы и сломать стоп-сигнал. Я делал это при температуре +26&deg;C.</p>
<p><strong>UPD:</strong> На Алиэкспрес есть третий стоп сигнал подешевле, сам не заказывал, на ваш страх и риск: <a href="https://sl.aliexpress.ru/p?key=Cm9hGNm" rel="nofollow" target="_blank">третий стоп-сигнал Seat Altea Freetrack</a></p>
]]></content>
		
					<link rel="replies" type="text/html" href="https://blog2k.ru/archives/10587#comments" thr:count="0" />
			<link rel="replies" type="application/atom+xml" href="https://blog2k.ru/archives/10587/feed/atom" thr:count="0" />
			<thr:total>0</thr:total>
			</entry>
		<entry>
		<author>
			<name>eJ</name>
					</author>

		<title type="html"><![CDATA[Рекурсивное блокирование мьютекса, знакомимся с std::recursive_mutex.]]></title>
		<link rel="alternate" type="text/html" href="https://blog2k.ru/archives/10553" />

		<id>https://blog2k.ru/?p=10553</id>
		<updated>2025-12-03T12:53:09Z</updated>
		<published>2024-08-29T06:10:30Z</published>
		<category scheme="https://blog2k.ru" term="C++" /><category scheme="https://blog2k.ru" term="Программирование" /><category scheme="https://blog2k.ru" term="многопоточность" />
		<summary type="html"><![CDATA[В статье объясняется особенность работы `std::recursive_mutex` по сравнению с `std::mutex`. Пример показывает, как `std::recursive_mutex` помогает избежать проблем при многократных блокировках в одном потоке.]]></summary>

					<content type="html" xml:base="https://blog2k.ru/archives/10553"><![CDATA[<p>Всем привет! Случайно вспомнил, что мой блог про программирование, математику <em>вообще-то</em> и в целом создан для просвещения мешков с костями и мясом.</p>
<p>Поэтому хочу рассказать про <a href="https://en.cppreference.com/w/cpp/thread/recursive_mutex"><code class="" data-line="">std::recursive_mutex</code></a>. Он работает так же, как и <code class="" data-line="">std::mutex</code>, но запоминает номер потока, из которого был заблокирован и позволяет вторую блокировку из одного потока. В моём случае был приблизительно такой код:</p>
<pre><code class="language-cpp" data-line="">struct Item {
    ~Item() {
        Storage::getInstance().RemoveItemByIndex(someItemIndex);
        Storage::getInstance().AddItem(newItem);
    }
}
using ItemPtr = std::shared_ptr&lt;Item&gt;;
using ItemRef = const ItemPtr &amp;;
using ItemId = std::size_t;

class Storage {
public:
    ItemId AddItem(ItemRef item)
    {
        std::scoped_lock lock(m_itemsGuard);
        m_items.push_back(item);
        return m_items.size() - 1;
    }

    void RemoveItemByIndex(ItemId id)
    {
        std::scoped_lock lock(m_itemsGuard);
        auto item = m_items.at(id);
        m_items.erase(m_items.begin() + id);
        item.reset(); // Тут повторно заходим в RemoveItem
    }

private:
    std::vector&lt;ItemPtr&gt; m_items;
    std::recursive_mutex m_itemsGuard;
};


void test() {
    Storage storage;
    auto index = storage.AddItem(std::make_shared&lt;Item&gt;());
    storage.RemoveItemByIndex(index); // здесь проблема
}
</code></pre>
<p>Обратите внимание, что в деструкторе <code class="" data-line="">Item</code> есть обращение к методам <code class="" data-line="">Storage</code>, а там на каждое изменение массива стоит блокировка мьютекса. И оно попадет в вечный lock с <code class="" data-line="">std::mutex</code>. А на этом у меня всё. Enjoy!</p>
]]></content>
		
					<link rel="replies" type="text/html" href="https://blog2k.ru/archives/10553#comments" thr:count="0" />
			<link rel="replies" type="application/atom+xml" href="https://blog2k.ru/archives/10553/feed/atom" thr:count="0" />
			<thr:total>0</thr:total>
			</entry>
		<entry>
		<author>
			<name>eJ</name>
					</author>

		<title type="html"><![CDATA[Второе путешествие в Мармарис, Турция]]></title>
		<link rel="alternate" type="text/html" href="https://blog2k.ru/archives/10416" />

		<id>https://blog2k.ru/?p=10416</id>
		<updated>2025-12-08T07:57:30Z</updated>
		<published>2024-08-20T07:08:49Z</published>
		<category scheme="https://blog2k.ru" term="Путешествия" /><category scheme="https://blog2k.ru" term="Турция" /><category scheme="https://blog2k.ru" term="Мармарис" /><category scheme="https://blog2k.ru" term="отпуск" />
		<summary type="html"><![CDATA[Поездка в Мармарис прошла хорошо. В отеле было много вкусной еды, качественный алкоголь. Бесплатный Wi-Fi работал неплохо. Понравились экскурсии: остров Клеопатры, слияние морей, эгейские острова и река Дальян. Рекомендую Мармарис к посещению.]]></summary>

					<content type="html" xml:base="https://blog2k.ru/archives/10416"><![CDATA[<p>На второй день после возвращения домой меня посетило давно забытое чувство &#8212; чувство голода. В отеле было навалом еды: шведский стол на завтрак, обед и ужин, вдобавок бургеры, пицца, хот доги, нагетсы, шаверма и прочий фастфуд без ограничений &#8212; удержаться было очень тяжело, всё очень вкусное, много и включено. Набрал пару килограмм за десять дней. Впервые в отеле Турции вино (красное, белое, розовое) было хорошего качества и разлито по графинчикам по пол-литра. Пиво можно и не упоминать. На жаре &#8212; чистая амброзия. Как не спились за это время &#8212; загадка. WiFi интернет бесплатный и работает относительно неплохо. Британцы крикливые, как чайки, и некоторые особо толстые особи катаются на электрических машинках, как в Южном Парке.</p>
<p><img loading="lazy" decoding="async" src="https://blog2k.ru/wp-content/uploads/2024/08/MV5BMjE5OTk4OTQ1Ml5BMl5BanBnXkFtZTcwMzI1MDY1OA@@._V1_-1024x576.jpg" alt="" width="1024" height="576" class="aligncenter size-large wp-image-10522" srcset="https://blog2k.ru/wp-content/uploads/2024/08/MV5BMjE5OTk4OTQ1Ml5BMl5BanBnXkFtZTcwMzI1MDY1OA@@._V1_.jpg 1024w, https://blog2k.ru/wp-content/uploads/2024/08/MV5BMjE5OTk4OTQ1Ml5BMl5BanBnXkFtZTcwMzI1MDY1OA@@._V1_-300x169.jpg 300w, https://blog2k.ru/wp-content/uploads/2024/08/MV5BMjE5OTk4OTQ1Ml5BMl5BanBnXkFtZTcwMzI1MDY1OA@@._V1_-768x432.jpg 768w, https://blog2k.ru/wp-content/uploads/2024/08/MV5BMjE5OTk4OTQ1Ml5BMl5BanBnXkFtZTcwMzI1MDY1OA@@._V1_-1536x864.jpg 1536w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></p>
<p><span id="more-10416"></span>Отель <a href="https://www.tripadvisor.ru/Hotel_Review-g298033-d315227-Reviews-Blue_Bay_Platinum_Hotel-Marmaris_Marmaris_District_Mugla_Province_Turkish_Aegean_Coast.html" rel="nofollow" target="_blank">Blue Bay Platinum</a> был недалеко от отеля <a href="https://www.tripadvisor.ru/Hotel_Review-g298033-d1852987-Reviews-Prestige_Garden_Hotel_Apart-Marmaris_Marmaris_District_Mugla_Province_Turkish_Aegean_C.html" rel="nofollow" target="_blank">Prestige Garden</a>, где я был в <a href="https://blog2k.ru/archives/8344" target="_blank">прошлый раз</a> много лет назад.</p>
<p><img loading="lazy" decoding="async" src="https://blog2k.ru/wp-content/uploads/2024/08/bluebay-1024x576.jpg" alt="BLUE BAY PLATINUM HOTEL 5*" width="1024" height="576" class="aligncenter size-large wp-image-10502" srcset="https://blog2k.ru/wp-content/uploads/2024/08/bluebay.jpg 1024w, https://blog2k.ru/wp-content/uploads/2024/08/bluebay-300x169.jpg 300w, https://blog2k.ru/wp-content/uploads/2024/08/bluebay-768x432.jpg 768w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></p>
<p>Поездка прошла неожиданно <del>быстро</del> хорошо и без каких либо <a href="https://blog2k.ru/archives/10042" target="_blank">проблем</a>: самолёт задержали всего на полчаса, в гостинице было чисто, еды было много и она была вкусной. Погода отличная.</p>
<p>Экскурсии выбрали задолго до вылета, поэтому приехали подготовленные с определенной целью: максимум искупаться и попрыгать с лодки в лазурное море. Всего экскурсий было четыре: остров Клеопатры, слияние морей, эгейские острова и река Дальян. Все заказывали у Давида из <a href="https://maps.app.goo.gl/U1sj15xe7erZ1HFt6" rel="nofollow" target="_blank">Hot Travel Agency</a>. Сначала был хамам.</p>
<p>Про хамам рассказывать особо нечего: хамам хороший, массаж на все деньги, располагается в отдельном здании, везут на автобусе, в отличие от того раза в Алании, когда нас повезли два парня, не говорящие на других языках, кроме турецкого.</p>
<h2>Остров Клеопатры</h2>
<p>План такой: вас привозят на остров, там вы тусуетесь два часа под пальмами, отвозят обратно. Дополнительно есть остановки для купания до острова и после. Пляж Клеопатры огорожен, спуск к воде сделан отдельными лесенками. Песок на пляже прекрасен, вода прозрачная и теплейшая, как в ванне, обед включен. Обед состоит из макарошек, куриного шницеля, какого-то салата и куска хлеба, он стандартный для всех экскурсий в Турции и входит в стоимость, безалкогольные напитки без ограничений: кола, фанта, спрайт, чай, кофе. Вход на остров оплачивается отдельно и стоит 14 баксов. Если не платите, сидите два часа на судне. Глупо? Глупо, согласен.<br />
Минусы: стоимость билета Давид нам озвучивал в 10 баксов, пришлось брать в долг у гида. Неприятно, но не катастрофа. Всегда берите с собой денег с запасом.</p>
<h2>Слияние морей</h2>
<p>Откровенно говоря, слияния морей (Эгегейского и Средиземноморского) не показывают. Просто поездка в город Турунч на корабле с остановками для купания. Называется так для привлечения туристов. Есть два варианта: с безлимитными напитками и с добавлением безлимитного алкоголя за 10 баксов. Мы взяли с алкоголем и тут нас попытались нагреть: не выдали специальные браслеты, которые положены в таких случаях. После вопроса в WhatsApp Давиду нас неожиданно нашли и соответствующие браслеты выдали. Подозреваю, что попытка нагреть нас была со стороны команды корабля. Одна две остановки для купания, затем час в городе Турунч, потом ещё одна остановка для купания. Кроме адской жары в городе Турунч (высаживают в полдень!) и попыткой нагреть (будьте внимательны!) экскурсия ничем особенным не запомнилась.</p>
<h2>Эгейские острова</h2>
<p>Самая насыщенная на события поездка на корабле: шесть островов, среди них: остров с козликами, с развалинами греческого храма, остров с кроликами, остров &#171;Зубы дракона&#187; с пещерами и прочее. Нам очень понравилось, никаких нареканий, судно называется Granitsa, у местного гида есть любопытная особенность: заканчивать объявления по громкой связи протяжным &#171;Спасиба-а-а!&#187; с ударением на последний слог, ни с кем её не перепутаете. Обеспечивает хорошее настроение всю дорогу.</p>
<h2>Река Дальян</h2>
<p>Алгоритм такой: грузимся на маленькое судно из автобуса, идём по реке Дальян до впадения её в море, там купаемся полтора часа, затем обратно.</p>
<p><img loading="lazy" decoding="async" src="https://blog2k.ru/wp-content/uploads/2024/08/boat2-768x1024.jpeg" alt="Судно на реке Дальян" width="768" height="1024" class="aligncenter size-large wp-image-10508" srcset="https://blog2k.ru/wp-content/uploads/2024/08/boat2-scaled.jpeg 768w, https://blog2k.ru/wp-content/uploads/2024/08/boat2-225x300.jpeg 225w, https://blog2k.ru/wp-content/uploads/2024/08/boat2-1152x1536.jpeg 1152w, https://blog2k.ru/wp-content/uploads/2024/08/boat2-1536x2048.jpeg 1536w" sizes="auto, (max-width: 768px) 100vw, 768px" /></p>
<p>Впадение реки Дальян в море захватывает дух и вызывает полный восторг. Так что природа &#8212; огонь,  впечатлений масса: искупались на все деньги, носились по волнам, как малые дети, сплошной восторг, вода &#8212; парное молоко. На реке можно лицезреть древние гробницы, высеченные прямо в скале.</p>
<p><img loading="lazy" decoding="async" src="https://blog2k.ru/wp-content/uploads/2024/08/dalyan-768x1024.jpeg" alt="Река Дальян, гробницы" width="768" height="1024" class="aligncenter size-large wp-image-10506" srcset="https://blog2k.ru/wp-content/uploads/2024/08/dalyan-scaled.jpeg 768w, https://blog2k.ru/wp-content/uploads/2024/08/dalyan-225x300.jpeg 225w, https://blog2k.ru/wp-content/uploads/2024/08/dalyan-1152x1536.jpeg 1152w, https://blog2k.ru/wp-content/uploads/2024/08/dalyan-1536x2048.jpeg 1536w" sizes="auto, (max-width: 768px) 100vw, 768px" /></p>
<p>Пару раз ездили в порт Мармариса на стоянку яхт и больших кораблей. От отеля до стоянки 45 минут ходьбы.</p>
<p><img loading="lazy" decoding="async" src="https://blog2k.ru/wp-content/uploads/2024/08/boat-768x1024.jpeg" alt="Судно в порту Мармариса" width="768" height="1024" class="aligncenter size-large wp-image-10503" srcset="https://blog2k.ru/wp-content/uploads/2024/08/boat-scaled.jpeg 768w, https://blog2k.ru/wp-content/uploads/2024/08/boat-225x300.jpeg 225w, https://blog2k.ru/wp-content/uploads/2024/08/boat-1152x1536.jpeg 1152w, https://blog2k.ru/wp-content/uploads/2024/08/boat-1536x2048.jpeg 1536w" sizes="auto, (max-width: 768px) 100vw, 768px" /></p>
<p>Подведу итог: путешествие понравилось, Мармарис рекомендую к посещению. Намного лучше <a href="https://blog2k.ru/archives/10042" target="_blank">Алании</a> и Анталии вместе взятых. Возможно, конкуренцию может составить <a href="https://blog2k.ru/archives/9520" target="_blank">Кемер</a>, но это неточно.</p>
<p>P.S. Кому интересно, туры ищем через сайт конторы <a href="https://tour-kassa.ru/" rel="nofollow" target="_blank">Тур-Касса</a>. Ни разу не реклама, просто они ищут у всех операторов. Для быстрого поиска самое оно. Сначала ищем отели в нужном городе, нужной страны, потом смотрим на сайте туроператора &#8212; может выйти немного дешевле.</p>
]]></content>
		
					<link rel="replies" type="text/html" href="https://blog2k.ru/archives/10416#comments" thr:count="0" />
			<link rel="replies" type="application/atom+xml" href="https://blog2k.ru/archives/10416/feed/atom" thr:count="0" />
			<thr:total>0</thr:total>
			</entry>
		<entry>
		<author>
			<name>eJ</name>
					</author>

		<title type="html"><![CDATA[В своё время порвало с этой картинки, не могу не поделиться]]></title>
		<link rel="alternate" type="text/html" href="https://blog2k.ru/archives/10403" />

		<id>https://blog2k.ru/?p=10403</id>
		<updated>2024-05-16T11:09:23Z</updated>
		<published>2024-05-16T11:09:23Z</published>
		<category scheme="https://blog2k.ru" term="Бла-бла-бла" /><category scheme="https://blog2k.ru" term="юмор" />
		<summary type="html"><![CDATA[]]></summary>

					<content type="html" xml:base="https://blog2k.ru/archives/10403"><![CDATA[<p><img loading="lazy" decoding="async" src="https://blog2k.ru/wp-content/uploads/2024/05/440871472_2464671863729332_5041850134438811685_n.jpg" alt="Сколько стоит ночлег? 10 рыбов. Есть только 1 дохлый мух" width="1080" height="1217" class="aligncenter size-full wp-image-10404" srcset="https://blog2k.ru/wp-content/uploads/2024/05/440871472_2464671863729332_5041850134438811685_n.jpg 909w, https://blog2k.ru/wp-content/uploads/2024/05/440871472_2464671863729332_5041850134438811685_n-266x300.jpg 266w, https://blog2k.ru/wp-content/uploads/2024/05/440871472_2464671863729332_5041850134438811685_n-768x865.jpg 768w" sizes="auto, (max-width: 1080px) 100vw, 1080px" /></p>
]]></content>
		
					<link rel="replies" type="text/html" href="https://blog2k.ru/archives/10403#comments" thr:count="0" />
			<link rel="replies" type="application/atom+xml" href="https://blog2k.ru/archives/10403/feed/atom" thr:count="0" />
			<thr:total>0</thr:total>
			</entry>
		<entry>
		<author>
			<name>eJ</name>
					</author>

		<title type="html"><![CDATA[Выключаем звук на сайтах в Google Chrome на Windows и Android.]]></title>
		<link rel="alternate" type="text/html" href="https://blog2k.ru/archives/10338" />

		<id>https://blog2k.ru/?p=10338</id>
		<updated>2025-10-22T12:36:55Z</updated>
		<published>2024-02-28T08:52:38Z</published>
		<category scheme="https://blog2k.ru" term="Полезные советы" /><category scheme="https://blog2k.ru" term="рекомендую" />
		<summary type="html"><![CDATA[В статье рассказывается, как запретить сайтам воспроизводить звук в браузере Google Chrome на Windows и Android. Описан простой способ добавления сайтов в исключения для запрета звука.]]></summary>

					<content type="html" xml:base="https://blog2k.ru/archives/10338"><![CDATA[<p>Некоторые новостные сайты настолько пренебрежительно относятся к своим посетителям, что не стесняясь запускают ролики со звуком во время просмотра. Я абсолютно уверен, что они в курсе, что поступают, как последние упыри, но а я научу вас с этим бороться в браузере Google Chrome.</p>
<h2>Windows</h2>
<ol>
<li>Нажимаем Ctrl-L</li>
<li>Вбиваем в строку <code class="" data-line="">chrome://settings/</code></li>
<li>В поисковой строке вбиваем <code class="" data-line="">настройки сайтов</code> и переходим в найденный пункт</li>
<li>Мотаем вниз, открываем <code class="" data-line="">Дополнительные настройки контента</code> и затем <code class="" data-line="">Звук</code></li>
<li>В разделе <code class="" data-line="">Запретить сайтам воспроизводить звук</code> давим кнопку <code class="" data-line="">Добавить</code></li>
<li>Добавляем сайты <strong><code class="" data-line="">lenta.ru</code></strong> и <strong><code class="" data-line="">moslenta.ru</code></strong>, чтоб их маркетологи были здоровы, мать их</li>
</ol>
<h2>Android</h2>
<ol>
<li>Переходим в <code class="" data-line="">Настройки</code> из меню справа на три точки</li>
<li>Затем пункт <code class="" data-line="">Настройки сайтов</code></li>
<li>Заходим в пункт <code class="" data-line="">Звук</code></li>
<li>Давим <code class="" data-line="">Добавить исключение</code></li>
<li>Добавляем сайты <strong><code class="" data-line="">lenta.ru</code></strong> и <strong><code class="" data-line="">m.lenta.ru</code></strong></li>
<li>Шлём лучик поноса авторам Ленты</li>
<li>PROFIT</li>
</ol>
<p>Ну и не мог пройти мимо цитаты из книжки «HTML5 для веб–дизайнеров»:<br />
<img loading="lazy" decoding="async" src="https://blog2k.ru/wp-content/uploads/2024/03/1709811244188149984.jpg" alt="" width="1280" height="959" class="aligncenter size-full wp-image-10377" srcset="https://blog2k.ru/wp-content/uploads/2024/03/1709811244188149984.jpg 1024w, https://blog2k.ru/wp-content/uploads/2024/03/1709811244188149984-300x225.jpg 300w, https://blog2k.ru/wp-content/uploads/2024/03/1709811244188149984-768x575.jpg 768w" sizes="auto, (max-width: 1280px) 100vw, 1280px" /></p>
]]></content>
		
					<link rel="replies" type="text/html" href="https://blog2k.ru/archives/10338#comments" thr:count="2" />
			<link rel="replies" type="application/atom+xml" href="https://blog2k.ru/archives/10338/feed/atom" thr:count="2" />
			<thr:total>2</thr:total>
			</entry>
		<entry>
		<author>
			<name>eJ</name>
					</author>

		<title type="html"><![CDATA[Краниопластика &#8212; титановый апгрейд организма]]></title>
		<link rel="alternate" type="text/html" href="https://blog2k.ru/archives/10248" />

		<id>https://blog2k.ru/?p=10248</id>
		<updated>2025-12-08T07:59:57Z</updated>
		<published>2023-11-22T07:25:10Z</published>
		<category scheme="https://blog2k.ru" term="Жизнь" /><category scheme="https://blog2k.ru" term="Здоровье" /><category scheme="https://blog2k.ru" term="здоровье" />
		<summary type="html"><![CDATA[Автор делится личным опытом прохождения трёх операций: карбоновый апгрейд сердца, удаление куска черепа и краниопластика для восстановления формы черепа. Подробно описывает подготовку, ход операции и впечатления от пребывания в нейрохирургическом отделении. Выражает благодарность своему нейрохирургу Андрееву Станиславу Иосифовичу за проделанную работу.]]></summary>

					<content type="html" xml:base="https://blog2k.ru/archives/10248"><![CDATA[<p>Слабонервным беременным детям со слабой психикой и желудком без чувства юмора  просьба убраться от экрана. Контент строго 18+, возможны дикпики, невыносимая тяжесть бытия и груз прожитых лет. Я вас предупредил!</p>
<p>Как-то так получилось, что я неплохо знаком с хирургией, но есть нюанс (C) &#8212; знаком с ней с обратной стороны ножа, как пациент.</p>
<p><a href="https://blog2k.ru/archives/7778" target="_blank">Карбоновый апгрейд сердца</a> у меня был шесть лет назад, <a href="https://blog2k.ru/archives/8893" target="_blank">кусок черепа удалили</a> два года назад, и пришёл я, значит, на титановый апгрейд, чтоб форму черепа обратно восстановить, ибо приносит это сильный моральный дискомфорт.</p>
<p>Операция называется краниопластика. Это когда к черепу на место удаленной ранее кости, прикручивают пластину на малюсенькие винты или крепят на специальные скобы (молотком?). Выглядит жутковато. Материал пластины может быть разным, мне досталась титановая и это здорово, потому что титан <del>холодненький</del> хорошо приживается в нашем организме и практически не вызывает отторжения. А ещё он прочный!</p>
<p>Операция не считается особо сложной, но рискованная, как и любое хирургическое вмешательство. Расскажу, как всё проходило у меня.</p>
<p>Перво-наперво, я созрел морально. Это сложно, это нервно, но я справился, потому что выбора нет. Затем записался к нейрохирургу на приём в <a href="https://elizahospital.ru/" rel="nofollow" target="_blank">Елизаветинской больнице</a>. Для дозревания потребовалось около двух лет.</p>
<p>Волею случая, мне достался нейрохирург <strong>Андреев Станислав Иосифович</strong> и все дальнейшее общение проходило с ним. Поскольку, пациент я непростой, с подвохом, анализов мне пришлось сдавать немного больше обычного и дополнительно получать разрешения местного анестезиолога и терапевта.</p>
<p><span id="more-10248"></span>После получения разрешения, мне назначили дату госпитализации и туда я пришёл с уже побритой головой. Заселился в палату, взяли анализ крови, дополнительно пообщался с анестезиологом, запретили ужинать и есть до операции. Разрешили пить воду до полуночи, но без фанатизма. Утром был разбужен фразой медсестры: У тебя операция в девять! Был снова побрит, надели компрессионные чулки первого типа против тромбоза, сняли всё остальное и повезли в операционную номер один.</p>
<p>В операционной очень чисто, все в масках и ощутимо <del>ссыкотно</del> холодно. Вставили катетер в левую руку, поставили две баночки какого-то препарата, на правую руку надели тонометр, приклеили датчики сердечного ритма, на палец надели пульсоксиметр (измеритель уровня кислорода в крови), дали подышать маску и под лекцию анестезиолога своему ординатору про то, что сначала вводят гипнотическое, потом релаксант, потом я уснул. Операция идёт около часа, но для меня прошло меньше секунды. Закрыл глаза, открыл глаза &#8212; во рту, как кошки насрали, немного саднит горло после интубации и хочется пить. Перед операцией анестезиолог обещал разбудить, чтобы вытащить трубку и сделать несколько тестов. С его слов этот момент точно был, но я его не помню.</p>
<p>После перевода в палату наказали не спать час, что я с лёгкостью и сделал: просто закрыл глаза, через час открыл, при этом совсем-совсем не спал. Окончательно пришёл в себя только на следующий день. Немного опухла оперированная часть головы и болел шов. Когда голова болит только снаружи для меня ощущение совершенно новое, но не рекомендую вам его испытывать.</p>
<p>Я ещё надеюсь и верю, что когда-нибудь медицина достигнет такого уровня, что изобретение темных Эльдар &#8212; <a href="https://ru.wikipedia.org/wiki/%D0%9A%D0%B0%D1%82%D0%B5%D1%82%D0%B5%D1%80_%D0%A4%D0%BE%D0%BB%D0%B5%D1%8F" rel="nofollow" target="_blank">катетер Фолея</a> &#8212;  будут устанавливать и снимать тогда и только тогда, когда пациент находится без сознания. В этот раз мне частично повезло и установили его после введения наркоза, а вот вытаскивали уже в сознании и это была самая неприятная часть операции.</p>
<p>Кто-то возразит: &#171;Вот прицепился к катетеру Фолея, мне делали и всё нормально было&#187;, а я отвечу: &#171;вали нахер, извращенец, и больше сюда не приходи, нам не по пути, грязный овцеёб!&#187;</p>
<div class="sllv-video -type_youtube" data-provider="youtube" data-video="sE_J6iHmYoc"><a class="sllv-video__link" href="https://youtu.be/sE_J6iHmYoc?si=qUVChIjb1eUvgOAC" rel="external noopener" target="_blank"><img decoding="async" class="sllv-video__media" src="https://i.ytimg.com/vi/sE_J6iHmYoc/sddefault.jpg" alt="Видео"></a><button class="sllv-video__button" type="button" aria-label="Воспроизвести видео"><svg width="68" height="48" viewBox="0 0 68 48"><path class="sllv-video__button-shape" d="M66.52 7.74c-.78-2.93-2.49-5.41-5.42-6.19C55.79.13 34 0 34 0S12.21.13 6.9 1.55c-2.93.78-4.63 3.26-5.42 6.19C.06 13.05 0 24 0 24s.06 10.95 1.48 16.26c.78 2.93 2.49 5.41 5.42 6.19C12.21 47.87 34 48 34 48s21.79-.13 27.1-1.55c2.93-.78 4.64-3.26 5.42-6.19C67.94 34.95 68 24 68 24s-.06-10.95-1.48-16.26z"/><path class="sllv-video__button-icon" d="M45 24L27 14v20"/></svg></button></div>
<p>Обстановка в нейрохирургическом отделении номер два местами напоминает помесь <a href="https://ru.wikipedia.org/wiki/Outlast" rel="nofollow" target="_blank">игры Outlast</a> и психушку. Специфика такова, что люди с проблемами в голове в виде кровоизлияний и опухолей сначала неадекватны из-за своего недуга, а затем из-за последствий оперативного вмешательства в мозги. А значит увидеть мычащего зомби в окровавленной шапочке из бинтов в своей палате посреди ночи обычное дело. Как правило медперсонал всё время начеку, поэтому зомби быстро ловят и отводят в свою палату. Разумеется, встречаются товарищи, которые пробухали свои мозги и потеряли человеческий облик. И они нам совсем не товарищи! Таким уже всё равно и их обычно переводят прямиком в дурку. В прошлый раз на отделение было три палаты: женская, мужская и мужская для буйных. В дурку уезжают из третьей. На этот раз палаты для буйных не было.</p>
<p>В прошлый визит, у нас был чокнутый дед, который ходил голый в одних подгузниках и босиком с важным видом по палатам и задумчиво говорил: &#171;Тааак!&#187;. У него был такой серьезный вид, что мы дали ему кличку Главврач. Сначала он был вроде нормальный, но посреди ночи начал ловить кикимору, которая сидела у него на кровати и хотела его задушить. В итоге через пару недель увезли деда в психушку.</p>
<p>Медперсонал бывает грубоват, но я их понимаю. Надо иметь железную выдержку и стальные нервы, чтобы каждый день общаться с такими пациентами.</p>
<p>Отдельно хотелось бы отметить питание в больнице. Не то, чтобы я был требователен к меню в больнице, которая занимается экстренной помощью, но судите сами: утром пшенная каша с булкой, днём варёная капуста, которую кто-то может по ошибке принять за суп, вечером манная каша. Качество еды приемлемое, сытность достаточная, но ассортимент бедненький. Платная палата стоит 2200 в сутки, при этом кормят там той же едой.</p>
<p>И вы можете меня спросить:, что я делал две с лишним недели в больнице после операции, а я отвечу: ходил с важным видом, чтоб остальные не заподозрили, что я нормальный.</p>
<p>А ещё к нам перевели юного самокатчика, который разбил голову по пьяни, катаясь на электросамокате. По виду, как настоящий человек, с ходу и не отличишь. Только тупой.</p>
<p>Между прочим, результат операции поразительный &#8212; череп теперь ровный, лишние рубцы и бугры со шрама убрали. Хочу сказать огромное спасибо <strong>Андрееву Станиславу Иосифовичу</strong> за проделанную работу!</p>
<p>А на сегодня всё. Ставьте лайк, подписывайтесь на канал, нажимайте колокольчик где-нибудь в другом месте.</p>
]]></content>
		
					<link rel="replies" type="text/html" href="https://blog2k.ru/archives/10248#comments" thr:count="0" />
			<link rel="replies" type="application/atom+xml" href="https://blog2k.ru/archives/10248/feed/atom" thr:count="0" />
			<thr:total>0</thr:total>
			</entry>
		<entry>
		<author>
			<name>eJ</name>
					</author>

		<title type="html"><![CDATA[Знакомимся с полезными инструментами STL &#8212; std::remove() и std::remove_if()]]></title>
		<link rel="alternate" type="text/html" href="https://blog2k.ru/archives/10148" />

		<id>https://blog2k.ru/?p=10148</id>
		<updated>2025-10-22T12:37:11Z</updated>
		<published>2023-09-21T19:36:55Z</published>
		<category scheme="https://blog2k.ru" term="C++" /><category scheme="https://blog2k.ru" term="Программирование" /><category scheme="https://blog2k.ru" term="рекомендую" />
		<summary type="html"><![CDATA[В статье делюсь знаниями о различиях между `std::unordered_map` и `std::map`, а также о том, как упростить удаление элементов из контейнера с помощью `std::remove_if`.]]></summary>

					<content type="html" xml:base="https://blog2k.ru/archives/10148"><![CDATA[<p>Добрый день, всем привет!</p>
<p>Снова в эфире рубрика &#171;Вы не спрашивали, но мы отвечаем&#187;, раздел <a href="https://blog2k.ru/topics/programming" target="_blank">&#171;Программирование&#187;</a>, глава &#171;Что нового я узнал в сейчас лет&#187;.</p>
<p>Например, не так давно я узнал, что <code class="" data-line="">std::unordered_map</code> не сортирует данные в отличие от <code class="" data-line="">std::map</code>. А много-много лет назад (в 2007-м году) нам пришлось реализовывать <a href="https://ru.wikipedia.org/wiki/%D0%94%D0%B2%D0%BE%D0%B8%D1%87%D0%BD%D1%8B%D0%B9_%D0%BF%D0%BE%D0%B8%D1%81%D0%BA" rel="nofollow" target="_blank">бинарный поиск</a>, чтобы ускорить вставку элементов в <code class="" data-line="">std::map</code> (там жил кэш текстур) вместо того, чтобы взять <code class="" data-line="">std::unordered_map</code>. Наш просчёт немного оправдывает то, что мы были молоды, неопытны и <code class="" data-line="">std::unordered_map</code> появился в стандарте C++11 спустя несколько лет после описываемых событий.</p>
<p>Вообще, я не отношусь к тем людям, которые ежедневно читают свежайший стандарт C++, подчеркивая карандашиком важные места. Скорее, я начинаю читать <a href="https://en.cppreference.com/w/" rel="nofollow" target="_blank">стандарт</a>, когда нужно найти решение текущей задачи. Так, например, я совершенно случайно наткнулся на <code class="" data-line="">std::enable_shared_from_this</code>, когда просматривал код нашего проекта, поминая тимлида нехорошими словами . Там был метод типа make() у класса, который должен вернуть <code class="" data-line="">std::shared_ptr</code> от экземпляра этого класса. Если вы наследуете класс от <code class="" data-line="">std::enable_shared_from_this</code>, то у вас появляется метод <code class="" data-line="">shared_from_this()</code>, и дело в шляпе. Нужно только помнить, что метод <code class="" data-line="">shared_from_this()</code> можно вызвать только у объекта, который уже управляем <code class="" data-line="">std::shared_ptr</code> иначе будет исключение.</p>
<p>Каких-то одиннадцать лет назад я написал <a href="https://blog2k.ru/archives/3081" target="_blank">статью про эффективное удаление элементов массива</a>. Тогда единственный способ, который я знал, выглядел следующим образом:</p>
<pre class="language-cpp"><code class="" data-line="">auto iter=data.begin();
while(iter != data.end()) {
    if (condition(*iter)) {
        iter = puf(data, iter);
    else {
        ++iter;
    }
}
</code></pre>
<p>Вся упомянутая в статье магия с перемещением в конец массива и удалением происходит в <code class="" data-line="">puf()</code>.</p>
<p>Оказывается, есть метод лучше, и имя ему &#8212; <code class="" data-line="">std::remove_if</code>. Этот метод перемещает в начало элементы, для которых условие ложно, возвращая итератор на конец массива с элементами, для которых условие истинно. Эксперимент показал, что после итератора лежит мусор.</p>
<p>С новыми знаниями, удаление элементов из контейнера будет выглядеть так:</p>
<pre class="language-cpp"><code class="" data-line="">auto iter = std::remove_if(data.begin(), data.end(), condition);
data.erase(iter, iter.end());
</code></pre>
<p>Что является более продвинутым вариантом и пишется короче, с чем я вас и поздравляю!</p>
<p>Обратите внимание, методы <code class="" data-line="">std::remove</code> и <code class="" data-line="">std::remove_if</code> не удаляют элементы, удаление происходит после вызова <code class="" data-line="">std::erase</code>.</p>
]]></content>
		
					<link rel="replies" type="text/html" href="https://blog2k.ru/archives/10148#comments" thr:count="0" />
			<link rel="replies" type="application/atom+xml" href="https://blog2k.ru/archives/10148/feed/atom" thr:count="0" />
			<thr:total>0</thr:total>
			</entry>
		<entry>
		<author>
			<name>eJ</name>
					</author>

		<title type="html"><![CDATA[Про Турцию в целом и отдых в Алании в частности]]></title>
		<link rel="alternate" type="text/html" href="https://blog2k.ru/archives/10042" />

		<id>https://blog2k.ru/?p=10042</id>
		<updated>2025-12-09T08:44:58Z</updated>
		<published>2023-07-03T13:49:10Z</published>
		<category scheme="https://blog2k.ru" term="Путешествия" /><category scheme="https://blog2k.ru" term="Турция" /><category scheme="https://blog2k.ru" term="отпуск" />
		<summary type="html"><![CDATA[Отпуск в Турции был в целом приятным, но омрачён задержкой рейса на 12 часов без компенсаций. Также отмечены проблемы с трансфером, дополнительные расходы в отеле и недостатки в организации экскурсий туроператором.]]></summary>

					<content type="html" xml:base="https://blog2k.ru/archives/10042"><![CDATA[<p>Спешу поделиться впечатлениями об отпуске в Турции: плавали в море, загорали на пляже, пили коктейли, ели вкусняшки, природа в Турции великолепная, панорамы потрясающие, воробьи поджарые, голуби пёстрые &#8212; похожи на попугаев, турки шумные и любят бибикать по поводу и без, а теперь о плохом.</p>
<p><a href="https://blog2k.ru/wp-content/uploads/2023/07/2023-06-23-09-34-06-scaled.jpg"><img loading="lazy" decoding="async" src="https://blog2k.ru/wp-content/uploads/2023/07/2023-06-23-09-34-06-scaled.jpg" alt="Турция. Панорама Алании" width="2560" height="1440" class="aligncenter size-full wp-image-10104" srcset="https://blog2k.ru/wp-content/uploads/2023/07/2023-06-23-09-34-06-scaled.jpg 1024w, https://blog2k.ru/wp-content/uploads/2023/07/2023-06-23-09-34-06-300x169.jpg 300w, https://blog2k.ru/wp-content/uploads/2023/07/2023-06-23-09-34-06-768x432.jpg 768w, https://blog2k.ru/wp-content/uploads/2023/07/2023-06-23-09-34-06-1536x864.jpg 1536w, https://blog2k.ru/wp-content/uploads/2023/07/2023-06-23-09-34-06-2048x1152.jpg 2048w" sizes="auto, (max-width: 2560px) 100vw, 2560px" /></a></p>
<p><span id="more-10042"></span></p>
<h2>Жалобы</h2>
<p>Для ЛЛ: обратный вылет задержали на 12 часов без каких либо компенсаций.</p>
<h3>1. Турецкие авиалинии <a href="https://www.turkishairlines.com/" rel="nofollow" target="_blank">Turkish Airlines</a></h3>
<p>Задержали рейс домой на двенадцать, сука, часов, без предоставления отеля. В качестве компенсации каждого пассажира задержанного рейса посадили в самолёте у окошка, а если серьезно, то всем, по большому счету, плевать на проблемы отдыхающих: авиакомпании, туроператору, турагентству и отелю.</p>
<h3>2. Туроператор <a href="https://pegast.ru/" rel="nofollow" target="_blank">Пегас Туристик</a></h3>
<p>Во время трансфера на вылет, развернули автобус и вернули всех туристов обратно без объяснения причин, при этом водитель ни русского, ни английского не знает. На кой чёрт нанимают водителей для трансфера иностранных туристов без знания языков для меня загадка. Цитирую водителя: &#171;проблемо, но инглиш&#187; и чемодан на улицу херак. Общались с помощью непереводимой игры слов и администратора отеля, о котором будет ниже. Плюс к этому хочу отметить отельного гида, в обязанности которой входит лишь впаривание экскурсии по цене примерно вдвое обычных. Экскурсии категорически рекомендую покупать на улице: в итоге вас заберёт автобус и привезёт к тем, кто купил её дороже у отельного гида.</p>
<h3>3. Турагентство <a href="https://www.anextour.com/" rel="nofollow" target="_blank">АнексТур</a></h3>
<p>При звонке на горячую линию с жалобой на Пегас Туристик послали разбираться самостоятельно. Они свою комиссию получили, деньги собрали, их ваши проблемы не интересуют.</p>
<h3>4. Отель <a href="https://www.booking.com/hotel/tr/saritas-antalya.ru.html" rel="nofollow" target="_blank">Сариташ</a></h3>
<p>Захотели доплаты (30$) при вселении, чтобы был вид на море. Убрались в номере (плохо) ровно один раз за две недели после третьей жалобы на ресепшн. Постельное бельё поменяли только на десятый день. Каждый завтрак/обед/ужин организовали очередь за горячей едой (кости куриные или жареная рыба, яичница и блинчики на завтрак). Столовка почему-то вызывала стойкую ассоциацию с фильмом <a href="https://www.kinopoisk.ru/film/1134778/" rel="nofollow" target="_blank">Платформа</a>. К счастью, мы были на первом уровне. Но надо отдать должное: блинчики были вкусные и администратор не оставил нас без горячей пищи во время ожидания трансфера: номер для поспать не дали &#8212; авиакомпания/туроператор пожалели компенсировать €45, но поесть обед, ужин и напитки &#8212; пожалуйста.</p>
<p>Попробуем дальше общаться, как говорят в статье <a href="https://journal.tinkoff.ru/zaderzhka-chartera/" rel="nofollow" target="_blank">Как получить компенсацию за задержку рейса самолета?</a> И посмотрим, что получится.</p>
<h2>Экскурсии</h2>
<p>Среди отдыхающих нам встречались русские, украинцы, молдаване, поляки, немцы, англичане. Плюс к этому общались с узбеком, норвежцами и иракцем из Дании. Конфликтов на тему Украины ни с кем не возникало. А у норвежцев, как и положено северному народу, был с собой лёд!</p>
<p>Экскурсии брали у эксцентричного <a href="https://goo.gl/maps/JHvHy5vaTiVTYXD1A" rel="nofollow" target="_blank">Альберта 5★</a> и <a href="https://goo.gl/maps/syVC84EB8dsxTjKH8" rel="nofollow" target="_blank">Тимура</a> &#8212; турка из Оренбурга. Альберт 5★ говорит на английском, его коллега Максим на русском. Тимур знает русский в совершенстве. Будете заказывать экскурсию с оплатой по частям: требуйте, чтобы оставшуюся сумму писали в турецких лирах, иначе придется заплатить на месте больше, чем рассчитывали. Про каждую экскурсию напишу отдельно.</p>
<h3>1. Хамам (Альберт 5★, $20 за двоих)</h3>
<p>Многие рекомендуют посетить хамам сразу после прибытия, чтоб загар лучше ложился <del>брат</del>. В назначенное время нас посадили <del>на измену</del> к двум джигитам, которые знают только турецкий, в старый рыдван и увезли в неизвестном направлении вдоль моря в сторону Сирии. Километров через 10-15 мы приехали в подвал/автостоянку за шлагбаумом возле какого-то отеля, где собственно находился хамам. Было несколько тревожно. Нам предоставили шкафчики для личных вещей. После переодевания полежали в парилке, потом в парной, затем нас хорошенько потерли скрабом и после сделали мыльный массаж, затем чай с крендельками, маска глиняная на лицо и, когда мы вконец разомлели: массаж с маслом. В итоге, те же джигиты на том же рыдване отвезли нас обратно. Мне всё понравилось, супруге тоже. Узнал, что левая рука у меня гнётся хуже правой &#8212; пойду у ревматолога спрошу, как с этим быть. Хамам рекомендую к посещению.</p>
<h3>2. Катамаран (Альберт 5★, $40 за двоих)</h3>
<p>Включает в себя путешествие на лодке и купание. Проблема в том, что с маршрутами для лодок в той части Турции наряженка, поэтому в 10:30 из порта стартует флотилия из 12-ти одинаковых посудин и идут они все по одному и тому же маршруту, в котором всего семь потенциальных мест для купания. Нам не повезло и купаться мы останавливались всего два раза по 15 минут и один из них в грязной воде. Питание включено, кола, фанта, спрайт безлимит, алкоголь за деньги.</p>
<h3>3. Джиппинг (гид туроператора, $70 за двоих)</h3>
<p>Катания на открытых джипах (Land Rover Defender) по местным просёлочным дорогам с заездом в местную деревню за покупками, потом везут покушать и искупаться в бассейне. Ушлый турок хотел нас нагреть во время обеда: вместо 250 турецких лир насчитал €11 или 295 лир за напитки, но супруга убедила его в обратном. Причём тут евры никто не понял, уговор был про лиры. Будьте внимательны. Катания на джипах сопровождаются обливанием водой других джипов и пассажиров в них из бутылок &#8212; получается очень весело. Рекомендую отдельно джипы не брать, а выбрать экскурсию в Сападере каньон &#8212; получается тоже самое. В конце вам предлагают купить набор фотографий и видео о поездке за $25.</p>
<h3>4. Судно Relax (Тимур, $50 за двоих)</h3>
<p>С одной стороны тоже самое, что Катамаран, а с другой народу поменьше и купаться разрешают по 40 минут вместо 15-ти. Плюс музыки поменьше и народа. Остановок было, вроде, четыре. Я настолько расслабился, что в первый раз обгорел. На судне даже есть своя маленькая толстая собачка.</p>
<p><img loading="lazy" decoding="async" src="https://blog2k.ru/wp-content/uploads/2023/07/photo_2023-07-25_22-20-13-e1690312917552.jpg" alt="Судовая собачка" width="1004" height="720" class="aligncenter size-full wp-image-10127" srcset="https://blog2k.ru/wp-content/uploads/2023/07/photo_2023-07-25_22-20-13-e1690312917552.jpg 1004w, https://blog2k.ru/wp-content/uploads/2023/07/photo_2023-07-25_22-20-13-e1690312917552-300x215.jpg 300w, https://blog2k.ru/wp-content/uploads/2023/07/photo_2023-07-25_22-20-13-e1690312917552-768x551.jpg 768w" sizes="auto, (max-width: 1004px) 100vw, 1004px" /></p>
<p>Никакой суеты, релакс как он есть и прыжки в воду с третьего этажа (я лично только со второго прыгал, выше уже сцу). Рекомендую.</p>
<h3>5. Каньон Сападере (Тимур, 1000₺ за двоих)</h3>
<p>Почти тоже самое, что джиппинг, но машин одновременно семь-восемь вместо трёх и поливать водой становится веселее и чаще. Там мы познакомились с харизматичным дедом из Швейцарии, который умеет танцевать руками, держась одной ногой за джип. Как зовут &#8212; не знаю. Наверно Клаус, мне кажется всех дедов в Швейцарии зовут Клаус и говорят они на швейцарском языке, который очень уж похож на немецкий.<br />
<img loading="lazy" decoding="async" src="https://blog2k.ru/wp-content/uploads/2023/07/photo_2023-07-04_14-39-59-1.jpg" alt="Швейцарский дед, возможно, Клаус." width="1280" height="850" class="aligncenter size-full wp-image-10119" srcset="https://blog2k.ru/wp-content/uploads/2023/07/photo_2023-07-04_14-39-59-1.jpg 1024w, https://blog2k.ru/wp-content/uploads/2023/07/photo_2023-07-04_14-39-59-1-300x199.jpg 300w, https://blog2k.ru/wp-content/uploads/2023/07/photo_2023-07-04_14-39-59-1-768x510.jpg 768w" sizes="auto, (max-width: 1280px) 100vw, 1280px" /><br />
В конце экскурсии так же предлагают фотографии и видео за $20, но нам сделали хорошую скидку, как друзьям Тимура.</p>
<h3>6. Квадроциклы (Тимур, $35 за один байк плюс пассажир)</h3>
<p>Квадроциклы запомнились тем, что не вся экипировка включена в стоимость: только шлем и шапочка под него. Не хочешь пыль глотать &#8212; плати за бандану, не хочешь камнем в глазик &#8212; плати за очки. Заранее об этом Тимур упомянуть забыл. А так два заезда с перерывом в 15 минут по пыльным дорогам в лесу возле бетонного завода. Грязное потом всё: ухи, глаза, нос, шея, колени, но всё равно довольно интересно. Если любите такую технику, как я, то рекомендую. Помните про экстра расходы: не забывайте в отеле солнцезащитные очки &#8212; они вам точно пригодятся и купите заранее бандану, в других местах она дешевле в два-три раза.</p>
<h2>Итого</h2>
<p>Турки много и часто курят. Я хоть и бросил в 21-м году (стаж 25 лет), но от табачного дыма до сих пор кайфую. Ещё в Турции любят котиков и чёрный чай.</p>
<p><a href="https://blog2k.ru/wp-content/uploads/2023/07/2023-06-26-14-07-45-scaled.jpg"><img loading="lazy" decoding="async" src="https://blog2k.ru/wp-content/uploads/2023/07/2023-06-26-14-07-45-scaled.jpg" alt="Котёнок спит на скамейке, парк Ататюрка, Алания, Турция" width="2560" height="1440" class="aligncenter size-full wp-image-10106" srcset="https://blog2k.ru/wp-content/uploads/2023/07/2023-06-26-14-07-45-scaled.jpg 1024w, https://blog2k.ru/wp-content/uploads/2023/07/2023-06-26-14-07-45-300x169.jpg 300w, https://blog2k.ru/wp-content/uploads/2023/07/2023-06-26-14-07-45-768x432.jpg 768w, https://blog2k.ru/wp-content/uploads/2023/07/2023-06-26-14-07-45-1536x864.jpg 1536w, https://blog2k.ru/wp-content/uploads/2023/07/2023-06-26-14-07-45-2048x1152.jpg 2048w" sizes="auto, (max-width: 2560px) 100vw, 2560px" /></a></p>
<p>Деньги брали с собой в наличных долларах, которые были накоплены ещё в довоенное время. Дополнительно переводили себе деньги через приложение от компании <a href="https://www.contact-sys.com/" rel="nofollow" target="_blank">CONTACT</a> по грабительскому курсу. Инфляция в Турции бешеная: фуникулёр был 160₺, через день &#8212; 190₺, а в 2018 стоил всего 90₺. За один доллар сначала давали 22.83₺, через две недели уже 24₺. Так что нашему рублю ещё есть куда стремиться. Здорово, правда?</p>
<p><a href="https://blog2k.ru/wp-content/uploads/2023/07/2023-06-24-18-10-57.jpg"><img loading="lazy" decoding="async" src="https://blog2k.ru/wp-content/uploads/2023/07/2023-06-24-18-10-57.jpg" alt="Личинки шелкопряда, 1940 год, Алания, Турция" width="2510" height="1682" class="aligncenter size-full wp-image-10109" srcset="https://blog2k.ru/wp-content/uploads/2023/07/2023-06-24-18-10-57.jpg 1024w, https://blog2k.ru/wp-content/uploads/2023/07/2023-06-24-18-10-57-300x201.jpg 300w, https://blog2k.ru/wp-content/uploads/2023/07/2023-06-24-18-10-57-768x515.jpg 768w, https://blog2k.ru/wp-content/uploads/2023/07/2023-06-24-18-10-57-1536x1029.jpg 1536w, https://blog2k.ru/wp-content/uploads/2023/07/2023-06-24-18-10-57-2048x1372.jpg 2048w" sizes="auto, (max-width: 2510px) 100vw, 2510px" /></a></p>
<p>Несмотря на всё выше перечисленное, отпуск в целом понравился. Единственное тёмное пятно: это задержка рейса на 12 часов и в корне неправильные действия всех к этому причастных, в остальном мы отдохнули, наелись и накупались.</p>
<p>Отдельно хочу поблагодарить компанию <a href="https://www.megafon.ru" rel="nofollow" target="_blank">Мегафон</a> за отличную работу накопленных дней роуминга.</p>
<p>И раз уж вы дочитали до этого места: самый вкусный суп Том Ям делают в <a href="https://yandex.ru/maps/-/CDRnZiD" rel="nofollow" target="_blank">ресторане Mai Thai</a> в Мурино, не благодарите. Заказывайте на кокосовом молоке &#8212; не ошибётесь.</p>
]]></content>
		
					<link rel="replies" type="text/html" href="https://blog2k.ru/archives/10042#comments" thr:count="3" />
			<link rel="replies" type="application/atom+xml" href="https://blog2k.ru/archives/10042/feed/atom" thr:count="3" />
			<thr:total>3</thr:total>
			</entry>
		<entry>
		<author>
			<name>eJ</name>
					</author>

		<title type="html"><![CDATA[Пару слов про компьютерный звук]]></title>
		<link rel="alternate" type="text/html" href="https://blog2k.ru/archives/9978" />

		<id>https://blog2k.ru/?p=9978</id>
		<updated>2026-01-31T12:16:56Z</updated>
		<published>2023-03-03T08:26:39Z</published>
		<category scheme="https://blog2k.ru" term="Программирование" /><category scheme="https://blog2k.ru" term="Полезная статья" />
		<summary type="html"><![CDATA[Компьютерный звук представлен в виде массива чисел. Минимальная единица — семпл. Звук проигрывается через буферы, заполняемые семплами в отдельном потоке. Для стереозвука количество семплов удваивается.]]></summary>

					<content type="html" xml:base="https://blog2k.ru/archives/9978"><![CDATA[<p>Компьютерный звук в компьютере представлен в виде (сюрприз-сюрприз!) массива чисел. Минимальная единица звука в компьютере &#8212; это семпл &#8212; одно число. Частота дискретизации &#8212; это количество семплов в одной секунде. Всем известная цифра 44100 &#8212; это всего лишь сорок четыре тысячи сто семплов в секунду. Семпл может быть в разных форматах и их <a href="http://trac.ffmpeg.org/wiki/audio%20types" rel="nofollow" target="_blank">достаточно много</a>, чтобы описывать в этой статье. Лично я встречался  с форматом <a href="https://blog2k.ru/archives/3321" target="_blank">float32</a> и с одним байтом (<code class="" data-line="">std::uint8_t</code>) на семпл.</p>
<p>Расскажу в общих словах алгоритм проигрывание звука на компьютере. Я так делал, друзья делали <del>всем понравилось</del> и, в целом, везде одинаковый принцип. Алгоритм такой:</p>
<ol>
<li>Создать два буфера (A и B) в нужном формате </li>
<li>Заполнить буфер A семплами</li>
<li>Отдать буфер A на проигрывание звуковой карте</li>
<li>Заполнить буфер B семплами</li>
<li>Отдать буфер B на проигрывание звуковой карте</li>
<li>Перейти к шагу 2.</li>
</ol>
<p>Когда звуковая карта заканчивает проигрывать буфер, она запрашивает новый, который должен быть готов к этому моменту. Таким образом, как только вы отдали один буфер на проигрывание, немедленно надо заполнять следующий. Всё это, разумеется, делается в отдельном потоке с максимальным приоритетом, потому что пользователь <del>зараза</del> сразу слышит помехи своими ушами. Понизить FPS и немного схалтурить тут не получится.</p>
<p>Буферов должно быть не меньше двух, но может быть и гораздо больше. Как правило буфер для проигрывания &#8212; это указатель на кусок памяти и его длина в семплах или байтах. Про размер буфера ничего не скажу &#8212; я встречал размер буфер как 512 байт, так и миллион (один мегабайт) и все работали вроде бы одинаково. Возможно, кто-нибудь знает тру размер буфера и будет так любезен, чтобы написать о нём в комментариях.</p>
<p>&#171;А как же второй канал, стерео и звук вокруг?&#187;, &#8212; спросит внимательный читатель. Лично я сталкивался только со стерео звуком, поэтому про пяти и более канальный звук не расскажу. Семплы для стерео звука располагаются в буфере interleaved, по очереди: LRLRLRLR. А значит для стерео звука количество семплов на секунду в буфере удваивается. И на одну секунду для частоты 44100 надо уже 88200 семплов.</p>
]]></content>
		
					<link rel="replies" type="text/html" href="https://blog2k.ru/archives/9978#comments" thr:count="0" />
			<link rel="replies" type="application/atom+xml" href="https://blog2k.ru/archives/9978/feed/atom" thr:count="0" />
			<thr:total>0</thr:total>
			</entry>
		<entry>
		<author>
			<name>eJ</name>
					</author>

		<title type="html"><![CDATA[Настройка title для каждой страницы сайта на WordPress без плагинов]]></title>
		<link rel="alternate" type="text/html" href="https://blog2k.ru/archives/9914" />

		<id>https://blog2k.ru/?p=9914</id>
		<updated>2025-10-22T12:37:30Z</updated>
		<published>2022-12-31T17:43:06Z</published>
		<category scheme="https://blog2k.ru" term="PHP" /><category scheme="https://blog2k.ru" term="Программирование" /><category scheme="https://blog2k.ru" term="WordPress API" />
		<summary type="html"><![CDATA[Этот код для WordPress добавляет фильтр к заголовкам страниц, изменяя их структуру в зависимости от типа страницы. Например, для постов добавляется их название, для категорий — «Категория Название» и так далее.]]></summary>

					<content type="html" xml:base="https://blog2k.ru/archives/9914"><![CDATA[<p>Просто добавьте этот код в <code class="" data-line="">functions.php</code> вашей темы:</p>
<pre><code class="language-php" data-line="">function your_document_title($title) {
  $sep = &#039; &#124; &#039;;
  $array = [];
  $term = get_queried_object();

  global $page;

  if (is_singular()) {
    if ($page) {
      array_push($array, &#039;Часть &#039;.intval($page));
    }
    array_push($array, get_the_title($term));
  }
  else if (is_paged()) {
    array_push($array, &#039;Страница &#039; . intval(get_query_var(&#039;paged&#039;)));
  }

 if (is_search()) {
    array_push($array, &#039;Результат поиска по запросу &quot;&#039;.esc_html($_GET[&#039;s&#039;].&#039;&quot;&#039;));
  }
  else if (is_category($term)) {
    array_push($array, &#039;Категория &quot;&#039; . $term-&gt;name . &#039;&quot;&#039;);
  }
  else if (is_tag($term)) {
    array_push($array, &#039;Метка &quot;&#039; . $term-&gt;name . &#039;&quot;&#039;);
  }

  array_push($array, get_bloginfo(&#039;name&#039;));

  if (is_front_page() &amp;&amp; !is_paged()) {
    array_push($array, get_bloginfo(&#039;description&#039;));
  }

  return implode($sep, $array);
}
add_filter(&#039;document_title&#039;, &#039;your_document_title&#039;);
</code></pre>
<p>Эти строчки добавляют фильтр к методу <code class="" data-line="">document_title</code>.<br />
Для каждого заголовка страницы WordPress вызывает наш код следующим образом:</p>
<pre><code class="language-php" data-line="">$title = your_document_title(default_title());
</code></pre>
<p>Правила такие:</p>
<ul>
<li>для одиночных постов &#8212; &#171;Название поста&#187;</li>
<li>для страницы категории выводится &#8212; Категория &#171;Название&#187;</li>
<li>для страницы тега выводится &#8212; Метка &#171;Название&#187;</li>
<li>для главной страницы &#171;Название сайта | Описание сайта&#187;</li>
<li>для постов разбитых на части добавляется &#171;Часть N&#187; в начале</li>
<li>для страница поиска типа /s=QUERY &#171;Результат поиска QUERY&#187;</li>
<li>для страниц пагинации типа /page/N добавляется &#171;Страница N&#187; в начале</li>
<li>для всех страниц добавляется информация из поля Настройки->Общие->Название сайта</li>
<li>для всех страниц, кроме главной и страниц пагинаций, в конце добавляется информация из поля &#171;Настройки->Общие->Краткое описание&#187;</li>
</ul>
]]></content>
		
					<link rel="replies" type="text/html" href="https://blog2k.ru/archives/9914#comments" thr:count="0" />
			<link rel="replies" type="application/atom+xml" href="https://blog2k.ru/archives/9914/feed/atom" thr:count="0" />
			<thr:total>0</thr:total>
			</entry>
		<entry>
		<author>
			<name>eJ</name>
					</author>

		<title type="html"><![CDATA[Добавляем мета тег canonical к каждой странице сайта на WordPress без плагинов]]></title>
		<link rel="alternate" type="text/html" href="https://blog2k.ru/archives/9890" />

		<id>https://blog2k.ru/?p=9890</id>
		<updated>2025-10-22T12:37:42Z</updated>
		<published>2022-12-31T16:47:52Z</published>
		<category scheme="https://blog2k.ru" term="PHP" /><category scheme="https://blog2k.ru" term="Программирование" /><category scheme="https://blog2k.ru" term="WordPress API" />
		<summary type="html"><![CDATA[Добавляю запись типа `meta rel="canonical" href="url"` к каждой странице сайта на WordPress. Код в `functions.php` темы выводит корректный URL и удаляет GET-аргументы из URL.]]></summary>

					<content type="html" xml:base="https://blog2k.ru/archives/9890"><![CDATA[<p>Всем привет! Чтобы добавить запись типа <code class="" data-line="">meta rel=&quot;canonical&quot; href=&quot;url&quot;</code> к каждой странице вашего сайта на WordPress, добавьте этот код в <code class="" data-line="">functions.php</code> вашей темы:</p>
<pre><code class="language-php" data-line="">function remove_args($url) {
  $parsed = parse_url($url);

  $fragment = &#039;&#039;;

  if (array_key_exists(&#039;fragment&#039;, $parsed)) {
    $fragment = &#039;#&#039; . $parsed[&#039;fragment&#039;];
  }

  return sprintf(&quot;%s://%s%s%s&quot;,
    $parsed[&#039;scheme&#039;],
    $parsed[&#039;host&#039;],
    $parsed[&#039;path&#039;] ?? &#039;&#039;,
    $fragment);
}


function print_canonical_link() {
  $url = &quot;&quot;;

  // Одиночная страница
  if (is_single()) {
    global $page;
    // Пост из нескольких частей
    if ($page) {
      $url = get_pagenum_link($page);
    }
    else {
      $url = get_permalink();
    }
  }
  // Страница пагинации типа что-то-там/page/N
  else if (is_paged()) {
    $url = get_pagenum_link(get_query_var(&#039;paged&#039;));
  }
  // Главная страница сайта
  else if(is_front_page()) {
    $url = get_home_url();
  }
  // Страницы категории или тега
  else if(is_category() || is_tag()) {
    $url = get_term_link(get_queried_object());
  }

  if ($url) {
    echo &#039;&lt;link rel=&quot;canonical&quot; href=&quot;&#039;.remove_args($url).&#039;&quot; /&gt;&#039;;
  }
}
add_action(&#039;wp_head&#039;, &#039;print_canonical_link&#039;);
</code></pre>
<p>Подробности для непосвящённых: функция <code class="" data-line="">print_canonical_link()</code> выводит запись вида<br />
<code class="" data-line="">&lt;meta rel=&quot;canonical&quot; href=&quot;url&quot; /&gt;</code> во время вызова штатной функции <code class="" data-line="">wp_head()</code>, что очень уважают поисковые системы, но это неточно. А функция <code class="" data-line="">remove_args()</code> удаляет GET аргументы вида &#171;?key=value&#187; из URL. Критика, замечания, пожелания приветствуются.</p>
]]></content>
		
					<link rel="replies" type="text/html" href="https://blog2k.ru/archives/9890#comments" thr:count="2" />
			<link rel="replies" type="application/atom+xml" href="https://blog2k.ru/archives/9890/feed/atom" thr:count="2" />
			<thr:total>2</thr:total>
			</entry>
		<entry>
		<author>
			<name>eJ</name>
					</author>

		<title type="html"><![CDATA[Загрузка разных счётчиков с помощью jQuery.getScript() без плагинов WordPress]]></title>
		<link rel="alternate" type="text/html" href="https://blog2k.ru/archives/9823" />

		<id>https://blog2k.ru/?p=9823</id>
		<updated>2025-10-22T12:37:48Z</updated>
		<published>2022-12-06T06:44:49Z</published>
		<category scheme="https://blog2k.ru" term="JavaScript" /><category scheme="https://blog2k.ru" term="PHP" /><category scheme="https://blog2k.ru" term="Администрирование" /><category scheme="https://blog2k.ru" term="Программирование" /><category scheme="https://blog2k.ru" term="Хобби" /><category scheme="https://blog2k.ru" term="Google Analytics" /><category scheme="https://blog2k.ru" term="WordPress API" />
		<summary type="html"><![CDATA[Создан JS-скрипт для ускорения загрузки счётчиков Google Analytics, Яндекс.Метрика и mail.ru, чтобы избежать торможения основной страницы сайта. Описан способ интеграции скрипта в WordPress.]]></summary>

					<content type="html" xml:base="https://blog2k.ru/archives/9823"><![CDATA[<p>Всем привет! Иногда бывает, что счётчики Google Analytics, Яндекс.Метрика и счётчик mail.ru тормозят загрузку основной страницы. Написал js скрипт для того, чтобы это избежать.</p>
<pre><code class="language-javascript" data-line="">jQuery(document).ready(function($) {
    $.ajaxSetup({cache : true});

    // Данные для Google Analytics
    window.dataLayer = [];
    window.gtag = function() {
        window.dataLayer.push(arguments);
    }

    $.getScript(
        // !! ОБЯЗАТЕЛЬНО ЗАМЕНИТЕ ИДЕНТИФИКАТОР GOOGLE ANALYTICS &quot;G-41BWRDZLG5&quot; НА СВОЙ !!
        &#039;https://www.googletagmanager.com/gtag/js?id=G-41BWRDZLG5&#039;,
        function() {
            gtag(&#039;js&#039;, new Date());
            gtag(&#039;config&#039;, &#039;G-41BWRDZLG5&#039;);
        }
    );

    // Данные для Яндекс.Метрики
    window.ym = function() { (window.ym.a||[]).push(arguments); }
    window.ym.l = 1*new Date();

    $.getScript(
        &#039;https://mc.yandex.ru/metrika/tag.js&#039;,
        function() {
            // !! ОБЯЗАТЕЛЬНО ЗАМЕНИТЕ ИДЕНТИФИКАТОР ЯНДЕКС МЕТРИКИ &quot;91531653&quot; НА СВОЙ !!
            ym(91531653, &quot;init&quot;, {
                    webvisor:true,
                    trackLinks:true,
                    clickmap:true,
                    accurateTrackBounce:false
                }
            );
        }
    );

    // Данные для top.mail.ru
    var _tmr = window._tmr || (window._tmr = []);
    _tmr.push({
        // !! ОБЯЗАТЕЛЬНО  ЗАМЕНИТЕ ИДЕНТИФИКАТОР MAIL.RU &quot;2601331&quot; НА СВОЙ !!
        id: &quot;2601331&quot;,
        type: &quot;pageView&quot;,
        start: (new Date()).getTime()
    });

    $.getScript(&#039;//top-fwz1.mail.ru/js/code.js&#039;);
});
</code></pre>
<p>Известная бага счётчика Яндекс.Метрика &#8212; замедление сайта, поэтому скачал его локально в папку <code class="" data-line="">[wordpress_folder]/metrika</code> и добавил в задачу в crontab для обновления этого файла каждый час, Затем заменил <code class="" data-line="">https://mc.yandex.ru/metrika/tag.js</code> в скрипте выше на <code class="" data-line="">/metrika_tag.js</code>.</p>
<pre><code class="language-bash" data-line="">@hourly curl -s https://mc.yandex.ru/metrika/tag.js -o [wordpress_folder]/metrika_tag.js
</code></pre>
<p>Источник вдохновения статья <a href="https://www.lexium.ru/2020/01/yandex-metrika-storonnijj-kod-zablokiroval-osnovnojj-potok/" rel="nofollow" target="_blank">Yandex Metrika: Сторонний код заблокировал основной поток</a>. Не забудьте поменять идентификаторы счётчиков и проверить, что <code class="" data-line="">tag.js</code> доступен по адресу <code class="" data-line="">[ваш сайт]/metrika/tag.js</code>, если вы решили воспользоваться ускорением загрузки счётчика.</p>
<p>Чтобы добавить загрузку счётчиков в WordPress, необходимо положить его содержимое в файлик <code class="" data-line="">wordpress/wp-content/themes/[ваша_тема]/js/counters.js</code> и добавить следующий код в <code class="" data-line="">wordpress/wp-content/themes/[ваша_тема]/functions.php</code>:<br />
<div class="spoiler-wrap"><div class="spoiler-head folded">functions.php (для всех пользователей)</div><div class="spoiler-body"></p>
<pre><code class="language-php" data-line="">function enqueue_counter() {
  // Регистрируем скрипт
  wp_register_script(&#039;counters&#039;, get_template_directory_uri() . &#039;/js/counters.js&#039;, array(&#039;jquery&#039;), false, true);
    
  // Загружаем скрипт
  wp_enqueue_script(&#039;counters&#039;);
}
add_action(&#039;wp_enqueue_scripts&#039;, &#039;enqueue_counters&#039;);
</code></pre>
<p></div></div></p>
<p>Я использую проверку, что <a href="https://wp-kama.ru/function/is_user_logged_in" rel="nofollow" target="_blank">пользователь не авторизован</a>, зачем мне отслеживать самого себя:<br />
<div class="spoiler-wrap"><div class="spoiler-head folded">functions.php (только для неавторизованных пользователей)</div><div class="spoiler-body"></p>
<pre><code class="language-php" data-line="">function enqueue_counter() {
  // Регистрируем скрипт
  wp_register_script(&#039;counters&#039;, get_template_directory_uri() . &#039;/js/counters.js&#039;, array(&#039;jquery&#039;), false, true);
    
  // Загружаем скрипт, если пользователь неавторизован
  if (!is_user_logged_in()) {
    wp_enqueue_script(&#039;counters&#039;);
  }
}
add_action(&#039;wp_enqueue_scripts&#039;, &#039;enqueue_counters&#039;);
</code></pre>
<p></div></div></p>
]]></content>
		
					<link rel="replies" type="text/html" href="https://blog2k.ru/archives/9823#comments" thr:count="0" />
			<link rel="replies" type="application/atom+xml" href="https://blog2k.ru/archives/9823/feed/atom" thr:count="0" />
			<thr:total>0</thr:total>
			</entry>
		<entry>
		<author>
			<name>eJ</name>
					</author>

		<title type="html"><![CDATA[Обновление скрипта резервного копирования]]></title>
		<link rel="alternate" type="text/html" href="https://blog2k.ru/archives/9760" />

		<id>https://blog2k.ru/?p=9760</id>
		<updated>2025-10-22T12:37:53Z</updated>
		<published>2022-10-21T07:28:45Z</published>
		<category scheme="https://blog2k.ru" term="Администрирование" /><category scheme="https://blog2k.ru" term="Хобби" /><category scheme="https://blog2k.ru" term="bash" /><category scheme="https://blog2k.ru" term="FreeBSD" />
		<summary type="html"><![CDATA[Обновил скрипт для резервного копирования, оптимизировал код, разделил на функции. Теперь скрипт более структурирован и соответствует стандартам.]]></summary>

					<content type="html" xml:base="https://blog2k.ru/archives/9760"><![CDATA[<p>Обновил <a href="https://blog2k.ru/archives/9679" target="_blank">скрипт для резервного копирования</a>. Убрал вызов <code class="" data-line="">bc</code>, вынес всё в отдельные функции, причесал код, чтобы <a href="https://www.shellcheck.net/" rel="nofollow" target="_blank">ShellCheck</a> был счастлив:</p>
<pre><code class="language-bash" data-line="">#!/usr/local/bin/bash

BACKUP_ROOT=/var/backups/manual/
BACKUP_DIR=&quot;$BACKUP_ROOT&quot;$(date +&quot;%Y-%m-%d/%H-%M&quot;)
PREFIX=$(date +&quot;%Y%m%d_%H%M&quot;)
LIMIT=$((4*1024*1024))

exit_on_error() {
    exit_code=$?
    if [ $exit_code -ne 0 ]; then
        &gt;&amp;2 echo -e &quot;FAIL&quot;
        exit $exit_code
    fi
}

print_used_space() {
    printf &quot;Used space: &quot;
    SIZE=$(du -sB 1 $BACKUP_ROOT | cut -f 1)
    printf &quot;%sMb(%s%%)\n&quot; &quot;$((SIZE / 1024))&quot; &quot;$((SIZE * 100 / LIMIT))&quot;
}

backup_etc() {
    FILENAME=&quot;$PREFIX&quot;_etc.tar.bz2
    printf &quot;Creating %s .. &quot; &quot;$FILENAME&quot;
    if /usr/bin/tar -Pjcf &quot;$BACKUP_DIR&quot;/&quot;$FILENAME&quot; /etc /usr/local/etc /home /var/db/ports /var/named/etc/namedb /root/scripts &gt; /dev/null 2&gt;&amp;1; then
        printf &quot;OK\n&quot;
    else
        exit_on_error
    fi
}

backup_site() {
    FILENAME=&quot;$PREFIX&quot;_www.tar.bz2
    printf &quot;Creating %s .. &quot; &quot;$FILENAME&quot;
    if /usr/bin/tar -Pjcf &quot;$BACKUP_DIR&quot;/&quot;$FILENAME&quot; /usr/local/www &gt; /dev/null; then
        printf &quot;OK\n&quot;
    else
        exit_on_error
    fi
}

backup_db() {
    FILENAME=&quot;$PREFIX&quot;_db.sql.bz2
    printf &quot;Creating %s .. &quot; &quot;$FILENAME&quot;
    if /usr/local/bin/mysqldump --login-path=backup --opt --all-databases --triggers --routines --events | bzip2 -c &gt; &quot;$BACKUP_DIR&quot;/&quot;$FILENAME&quot;; then
        printf &quot;OK\n&quot;
    else
        exit_on_error
    fi
}

remove_old_files() {
    removed=0
    for days in $(seq 100 -1 0)
    do
        SIZE=$(du -sB 1 $BACKUP_ROOT | cut -f 1)
        if [[ $SIZE -le $LIMIT ]]; then
            break
        fi
        if [[ -z &quot;$(find $BACKUP_ROOT -type f -mtime +&quot;$days&quot;)&quot; ]]; then
            continue
        fi
        printf &quot;Removing files older than %d days:\n&quot; &quot;$days&quot;
        find $BACKUP_ROOT -type f -mtime +&quot;$days&quot;d -delete -print
        find $BACKUP_ROOT -empty -type d -delete -print
        removed=1
    done

    if [ $removed -ne 0 ]; then
        true
        return
    fi

    false
}

if [ ! -d &quot;$BACKUP_DIR&quot; ]; then
        mkdir -p &quot;$BACKUP_DIR&quot;
fi

backup_etc
backup_site
backup_db
print_used_space
remove_old_files &amp;&amp; print_used_space
true
</code></pre>
]]></content>
		
					<link rel="replies" type="text/html" href="https://blog2k.ru/archives/9760#comments" thr:count="0" />
			<link rel="replies" type="application/atom+xml" href="https://blog2k.ru/archives/9760/feed/atom" thr:count="0" />
			<thr:total>0</thr:total>
			</entry>
		<entry>
		<author>
			<name>eJ</name>
					</author>

		<title type="html"><![CDATA[Скрипт для резервного копирования]]></title>
		<link rel="alternate" type="text/html" href="https://blog2k.ru/archives/9679" />

		<id>https://blog2k.ru/?p=9679</id>
		<updated>2025-10-22T12:38:13Z</updated>
		<published>2022-09-15T10:52:43Z</published>
		<category scheme="https://blog2k.ru" term="Администрирование" /><category scheme="https://blog2k.ru" term="Хобби" /><category scheme="https://blog2k.ru" term="bash" /><category scheme="https://blog2k.ru" term="FreeBSD" />
		<summary type="html"><![CDATA[Я обновил скрипт для резервного копирования, улучшив его функциональность: скрипт интеллектуально удаляет старые файлы, учитывает ограничение хранилища в 4,5 ГБ и выводит сообщения об ошибках с цветовой разметкой. Скрипт проверен на сайте ShellCheck.]]></summary>

					<content type="html" xml:base="https://blog2k.ru/archives/9679"><![CDATA[<p>Всем привет, обновил <a href="https://blog2k.ru/archives/1174" target="_blank">скрипт для резервного копирования</a> с учётом того, что я вообще-то программист, а не просто айтишник! Он стал более интеллектуально определять и удалять старые файлы, учитывать ограничение в 4.5Gb (на FTP для бекапа доступно 5Gb) и успешность операций, добавлены сообщения об ошибках. И бонусом сообщения раскрашены в разные цвета, нейтральные выделены <font style="font-weight:bold">жирным</font>, хорошие <font color="green">зелёным</font>, а плохие <font color="red">красным цветом</font> &#8212; красота! Скрипт проверен на сайте <a href="https://www.shellcheck.net/" rel="nofollow" target="_blank">ShellCheck</a>, который я настоятельно рекомендую к использованию. Если найдёте ошибку или вам есть что добавить, смело пишите комментарий.</p>
<pre><code class="language-bash" data-line="">#!/usr/local/bin/bash

# Основная папка для архивов
BACKUP_ROOT=/var/backups/manual/
# Папка, куда непоредственно пишем файлы, выглядит как BACKUP_ROOT/ГОД/МЕСЯЦ/ДЕНЬ
BACKUP_DIR=&quot;$BACKUP_ROOT&quot;$(date +&quot;%Y/%m/%d&quot;)
# Время запуска скрипта. Все файлы имеют вид имя_файла_%ЧАС%%МИНУТА%.tag.bz2
TIME=$(date +&quot;%H%M&quot;)
# Ограничение хранилища в килобайтах для проверки
LIMIT=$(echo &quot;4096*2^10&quot;|bc)
# Ограничение хранилища в мегабайтах для вывода в сообщениях
HLIMIT=$(echo &quot;$LIMIT/1024&quot;|bc)&quot;Mb&quot;

# Функция выход в случае ошибки
exit_on_error() {
    # Получаем код ошибки
    exit_code=$?
    # Входное сообщение
    message=$1
    if [ $exit_code -ne 0 ]; then
        # Выводим сообщение в stderr
        &gt;&amp;2 echo -e &quot;\e[31m${message}\e[0m&quot;
        # Выходим к кодом exit_code
        exit $exit_code
    fi
}

# Если папки нет
if [ ! -d &quot;$BACKUP_DIR&quot; ]; then
    # Создаём папку со всеми промежуточными подпапками
    mkdir -p &quot;$BACKUP_DIR&quot;
fi

printf &quot;\e[1mSearching space for backup\e[0m .. &quot;
# Цикл от 100 дней до нуля
for days in $(seq 100 -1 0)
do
    SIZE=$(du -sB 1 $BACKUP_ROOT | cut -f 1)
    HSZ=$(echo &quot;$SIZE/1024&quot;|bc)&quot;Mb&quot;
    # Если размер хранилища не превышает лимита
    if [[ $SIZE -le $LIMIT ]]; then
        # Выводим сообщение и прерываем цикл
        printf &quot;[%s/%s] .. &quot; &quot;$HSZ&quot; &quot;$HLIMIT&quot;
        break
    fi
    # Если нет ни одного файла старше $days дней
    if [[ -z &quot;$(find $BACKUP_ROOT -type f -mtime +&quot;$days&quot;)&quot; ]]; then
        # Продолжаем цикл
        continue
    fi
    printf &quot;\e[31m%s/%s]\e[0m .. &quot; &quot;$HSZ&quot; &quot;$HLIMIT&quot;
    # Удаление файлов старше $days прошло успешно
    if find $BACKUP_ROOT -type f -mtime +&quot;$days&quot;d -delete &gt; /dev/null; then
        # Выводим сообщение 
        printf &quot;CLEAN (older than %s days) .. &quot; &quot;$days&quot;
    else
        # Выходим с сообщением FAIL
        exit_on_error &quot;FAIL&quot;
    fi
    # Удаляем пустые папки, чтоб не мусорить
    find $BACKUP_ROOT -empty -type d -delete
done
echo -e &quot;\e[32mOK\e[0m&quot;

printf &quot;\e[1mBackuping etc files\e[0m .. &quot;
/usr/bin/tar -Pjcf &quot;$BACKUP_DIR&quot;/etc_&quot;$TIME&quot;.tar.bz2 /etc /usr/local/etc /home /var/db/ports /var/named/etc/namedb /root/scripts &gt; /dev/null 2&gt;&amp;1 &amp;&amp; echo -e &quot;\e[32mOK\e[0m&quot; || exit_on_error &quot;FAIL&quot;

printf &quot;\e[1mBackuping www folder\e[0m .. &quot;
/usr/bin/tar -Pjcf &quot;$BACKUP_DIR&quot;/www_&quot;$TIME&quot;.tar.bz2 /usr/local/www &gt; /dev/null &amp;&amp; echo -e &quot;\e[32mOK\e[0m&quot; || exit_on_error &quot;FAIL&quot;

printf &quot;\e[1mBackuping SQL databases\e[0m .. &quot;
/usr/local/bin/mysqldump --login-path=backup --opt --all-databases --triggers --routines --events | bzip2 -c &gt; &quot;$BACKUP_DIR&quot;/sql_&quot;$TIME&quot;.sql.bz2 &amp;&amp; echo -e &quot;\e[32mOK\e[0m&quot; || exit_on_error &quot;FAIL&quot;
</code></pre>
<p>Откровенно говоря, не до конца понимаю, в каких единицах считает занятое место команда <code class="" data-line="">du</code>. Предполагаю, что в килобайтах.</p>
<p>P.S. Для того, чтобы получить вывод без цвета, использую утилиту <a href="https://www.freshports.org/textproc/ansifilter" rel="nofollow" target="_blank">textproc/ansifilter</a>:</p>
<pre><code class="" data-line="">script.sh | ansifilter --text
</code></pre>
]]></content>
		
					<link rel="replies" type="text/html" href="https://blog2k.ru/archives/9679#comments" thr:count="0" />
			<link rel="replies" type="application/atom+xml" href="https://blog2k.ru/archives/9679/feed/atom" thr:count="0" />
			<thr:total>0</thr:total>
			</entry>
		<entry>
		<author>
			<name>eJ</name>
					</author>

		<title type="html"><![CDATA[Добавил меню]]></title>
		<link rel="alternate" type="text/html" href="https://blog2k.ru/archives/9650" />

		<id>https://blog2k.ru/?p=9650</id>
		<updated>2025-10-22T12:38:19Z</updated>
		<published>2022-08-29T09:10:33Z</published>
		<category scheme="https://blog2k.ru" term="Администрирование" /><category scheme="https://blog2k.ru" term="Хобби" /><category scheme="https://blog2k.ru" term="WordPress API" />
		<summary type="html"><![CDATA[Я добавил на сайт меню с навигацией по рубрикам и подрубрикам. Теперь можно просматривать разные разделы, включая «Путешествия», «Программирование» с подразделами по языкам программирования. Сделал это вручную без автоматизации.]]></summary>

					<content type="html" xml:base="https://blog2k.ru/archives/9650"><![CDATA[<p>Всем привет! Вам конечно всё равно, но я добавил меню. Теперь у меня есть навигация не только по меткам, но и по рубрикам. Можно посмотреть все <a href="https://blog2k.ru/topics/travel" target="_blank">Путешествия</a> или рубрику <a href="https://blog2k.ru/topics/programming" target="_blank">Программирование</a> включая подрубрики <a href="https://blog2k.ru/topics/programming/cpp" target="_blank">C++</a>, <a href="https://blog2k.ru/topics/programming/python" target="_blank">Python</a>, <a href="https://blog2k.ru/topics/programming/java" target="_blank">Java</a> и <a href="https://blog2k.ru/topics/programming/javascript" target="_blank">так далее</a>. Всё добавлено вручную, никакой автоматизации.</p>
<p>Поддержка меню в WordPress встроена изначально, все пункты и подменю добавляются в админке, но поскольку тема у меня самописная, пришлось попотеть с CSS и немного с JavaScript. Что-то натырено со сторонних сайтов, что-то взято из видео ниже.</p>
<p>Добавить меню хотел очень давно, но не хватало стимула и знаний.  Спасибо <a href="https://www.youtube.com/c/FreelancerLifeStyle" rel="nofollow" target="_blank">каналу хлопца Евгения</a>. После просмотра его видео про адаптивное меню решил <del>сменить профессию</del> сделать похожее на своём сайте.</p>
<div class="sllv-video -type_youtube" data-provider="youtube" data-video="chJQofBSx94"><a class="sllv-video__link" href="https://youtu.be/chJQofBSx94" rel="external noopener" target="_blank"><img decoding="async" class="sllv-video__media" src="https://i.ytimg.com/vi_webp/chJQofBSx94/sddefault.webp" alt="Видео"></a><button class="sllv-video__button" type="button" aria-label="Воспроизвести видео"><svg width="68" height="48" viewBox="0 0 68 48"><path class="sllv-video__button-shape" d="M66.52 7.74c-.78-2.93-2.49-5.41-5.42-6.19C55.79.13 34 0 34 0S12.21.13 6.9 1.55c-2.93.78-4.63 3.26-5.42 6.19C.06 13.05 0 24 0 24s.06 10.95 1.48 16.26c.78 2.93 2.49 5.41 5.42 6.19C12.21 47.87 34 48 34 48s21.79-.13 27.1-1.55c2.93-.78 4.64-3.26 5.42-6.19C67.94 34.95 68 24 68 24s-.06-10.95-1.48-16.26z"/><path class="sllv-video__button-icon" d="M45 24L27 14v20"/></svg></button></div>
<p>Дайте знать, если плашка с рубрикой нужна к каждой статье. Хотя кого я спрашиваю, ходит на сайт два с половиной человека. Один из них гуглбот, а второй &#8212; это я.</p>
<p>UPD: В мобильной версии сайта добавил меню с помощью плагина <a href="https://ru.wordpress.org/plugins/mobile-menu/" rel="nofollow" target="_blank">WP Mobile Menu</a>.</p>
]]></content>
		
					<link rel="replies" type="text/html" href="https://blog2k.ru/archives/9650#comments" thr:count="0" />
			<link rel="replies" type="application/atom+xml" href="https://blog2k.ru/archives/9650/feed/atom" thr:count="0" />
			<thr:total>0</thr:total>
			</entry>
		<entry>
		<author>
			<name>eJ</name>
					</author>

		<title type="html"><![CDATA[Где размять мозги программисту? Тренировочный полигон для айтишников]]></title>
		<link rel="alternate" type="text/html" href="https://blog2k.ru/archives/9543" />

		<id>https://blog2k.ru/?p=9543</id>
		<updated>2025-10-22T12:38:24Z</updated>
		<published>2022-07-12T13:47:57Z</published>
		<category scheme="https://blog2k.ru" term="C++" /><category scheme="https://blog2k.ru" term="Программирование" /><category scheme="https://blog2k.ru" term="рекомендую" />
		<summary type="html"><![CDATA[В статье обсуждается проблема оценки профессионализма программистов и предлагается использовать сайты вроде LeetCode для решения задач как способ поддержания профессионального тонуса.]]></summary>

					<content type="html" xml:base="https://blog2k.ru/archives/9543"><![CDATA[<p>Всем привет! В этот раз расскажу, чем меряться программистам после кружки пива. Вот есть бегун, очевидно, что лучший бегун бежит или быстрее всех, или дальше всех. Или вот стрелок. Лучший конечно же тот, который чаще всего попадает в центр мишени, а не мимо неё.</p>
<p>А программистам и похвастаться нечем. Они не бегают и стрелять не умеют, а сидят, сгорбленные, уставившись красными глазами в монитор, и что-то пишут. Чем он занят? Зачем он здесь? Никто не знает.</p>
<p>А работодатель хочет знать, как определить сильного программиста. По хиленьким ручкам, красным глазкам, горбатой спине или катышкам на свитере? Ну, допустим, текущему работодателю определить просто &#8212; надо брать того, кто не слишком сильно пахнет, а как быть с новым работодателем?</p>
<p>Вот пришёл ты такой красивый на собес, и тебе прямо с порога &#8212; &#171;давай сортировку пузырьком пиши в уме!&#187; А ты работаешь в своём НИИ уже пятый десяток и всегда использовал метод <code class="" data-line="">sort()</code> из вашей секретной сверхбыстрой библиотеки на Фортране и знать не знаешь, что у неё внутри. И библиотека та написана учёным, седовласым мужем, чьё имя с отчеством произносятся в конторе с придыханием и пиететом, и бюст евоный стоит сразу при входе в холле.</p>
<p>И значит это ровно то, что часть мозга, которая отвечает за простейшие алгоритмы атрофировалась за ненадобностью. Потому что все эти вещи пишутся один раз и навсегда, а не каждый день, как полагает потенциальный работодатель. Посему надо держать себя в тонусе. И поможёт нам в этом сайт <a href="https://leetcode.com/" rel="nofollow" target="_blank">LeetCode</a>.</p>
<p>Сайты представляют собой список задач разного уровня сложности и среду для их решения. Если вы программист и вам скучно или если вы не программист и вам интересно чем программисты зарабатывают на жизнь, смело заходите и решайте задачи.</p>
<p>Кому интересно &#8212; вот мой профиль на <a href="https://leetcode.com/zhirnov/" rel="nofollow" target="_blank">LeetCode</a>.</p>
]]></content>
		
					<link rel="replies" type="text/html" href="https://blog2k.ru/archives/9543#comments" thr:count="0" />
			<link rel="replies" type="application/atom+xml" href="https://blog2k.ru/archives/9543/feed/atom" thr:count="0" />
			<thr:total>0</thr:total>
			</entry>
		<entry>
		<author>
			<name>eJ</name>
					</author>

		<title type="html"><![CDATA[Отпуск в Турции после ковидной эры]]></title>
		<link rel="alternate" type="text/html" href="https://blog2k.ru/archives/9520" />

		<id>https://blog2k.ru/?p=9520</id>
		<updated>2025-12-09T08:47:02Z</updated>
		<published>2022-07-10T19:14:18Z</published>
		<category scheme="https://blog2k.ru" term="Путешествия" /><category scheme="https://blog2k.ru" term="Турция" /><category scheme="https://blog2k.ru" term="Кемер" /><category scheme="https://blog2k.ru" term="отпуск" />
		<summary type="html"><![CDATA[Загрузившись таблетками, как самоходный полевой госпиталь, мы с супругой отправились в Турцию. Я уверен, когда Роберт Линн Асприн описывал деволов &#8212; обитателей измерения Девы, он прогуливался по торговым улочкам Кемера. Манера торговаться, угадывать язык покупателя, продавать снег зимой &#8212; вот это всё скопировано с турков-продавцов. А теперь сразу про деньги. Турки берут любую валюту: евро, [&#8230;]]]></summary>

					<content type="html" xml:base="https://blog2k.ru/archives/9520"><![CDATA[<p>Загрузившись <a href="https://blog2k.ru/archives/7778" target="_blank">таблетками</a>, как самоходный полевой госпиталь, мы с супругой отправились в Турцию.</p>
<p><a href="https://blog2k.ru/wp-content/uploads/2022/07/IMG_20220704_140419-scaled.jpg"><img loading="lazy" decoding="async" src="https://blog2k.ru/wp-content/uploads/2022/07/IMG_20220704_140419-scaled.jpg" alt="Море в Турции" width="2560" height="1440" class="aligncenter size-full wp-image-9528" srcset="https://blog2k.ru/wp-content/uploads/2022/07/IMG_20220704_140419-scaled.jpg 1024w, https://blog2k.ru/wp-content/uploads/2022/07/IMG_20220704_140419-300x169.jpg 300w, https://blog2k.ru/wp-content/uploads/2022/07/IMG_20220704_140419-768x432.jpg 768w, https://blog2k.ru/wp-content/uploads/2022/07/IMG_20220704_140419-1536x864.jpg 1536w, https://blog2k.ru/wp-content/uploads/2022/07/IMG_20220704_140419-2048x1152.jpg 2048w" sizes="auto, (max-width: 2560px) 100vw, 2560px" /></a></p>
<p>Я уверен, когда Роберт Линн Асприн <a href="https://ru.wikipedia.org/wiki/%D0%95%D1%89%D1%91_%D0%BE%D0%B4%D0%B8%D0%BD_%D0%B2%D0%B5%D0%BB%D0%B8%D0%BA%D0%BE%D0%BB%D0%B5%D0%BF%D0%BD%D1%8B%D0%B9_%D0%9C%D0%98%D0%A4" rel="nofollow" target="_blank">описывал деволов</a> &#8212; обитателей измерения Девы, он прогуливался по торговым улочкам Кемера. Манера торговаться, угадывать язык покупателя, продавать снег зимой &#8212; вот это всё скопировано с турков-продавцов.</p>
<p>А теперь сразу про деньги. Турки берут любую валюту: евро, доллары, турецкие лиры, некоторые берут рубли. Трудностей в общении нет, если вы хотите что-то купить, местные сразу вспоминают русский язык. Если вы не знаете английский, а продавец не знает русский, он найдёт вам переводчика. Так что языковой барьер у турков отсутствует, как у всякого порядочного девола.</p>
<p><span id="more-9520"></span></p>
<p>Всем привет! Как вы уже догадались, сейчас расскажу про поездку в Турцию, город Кемер, в условиях санкций от всего т.н. &#171;цивилизованного&#187; мира. Отношение к этому я уже <a href="https://blog2k.ru/archives/9414" target="_blank">выражал ранее картинкой</a> на языке их хозяев.</p>
<p>За один доллар дают 16-17 лир, за один евро 20 лир, про рубли &#8212; не знаю. Лиры снимали в банкоматах банков Ziraat, Deniz и Vakif с рублёвого счёта карты Мир Тинькофф. Карта Мир Альфа банка работать отказалась ни в банкомате, ни в терминале оплаты, бесполезный кусок пластика, хорошо этот кусок хоть бесплатный. Лиры в России не покупайте, наши упыри продают их по удвоенному курсу, гореть им в аду. Снимайте лиры в банкоматах с рублёвого счёта и платите наличкой, курс при этом близок к самому выгодному даже учитывая комиссию.</p>
<p>В Кемере мы были в отеле Kemer Hotel, три звезды. Его я не рекомендую: мясо/рыба в меню отсутствует, в номере не убираются ни перед заездом, ни во время отдыха. Единственная отрада &#8212; вкусный чёрный чай.</p>
<p>Экскурсии можно заказывать у туроператорного гида за тройную цену или в уличных турагенствах гораздо дешевле, мы брали в Ginza Travel. Туроператорный гид упорно отговаривает от уличных турагенств, настаивая на отсутствии у них страховки &#8212; в чём я сильно сомневаюсь.</p>
<p><a href="https://blog2k.ru/wp-content/uploads/2022/07/IMG_20220704_140357-scaled.jpg"><img loading="lazy" decoding="async" src="https://blog2k.ru/wp-content/uploads/2022/07/IMG_20220704_140357-scaled.jpg" alt="Турция, Сулуада" width="2560" height="1440" class="aligncenter size-full wp-image-9531" srcset="https://blog2k.ru/wp-content/uploads/2022/07/IMG_20220704_140357-scaled.jpg 1024w, https://blog2k.ru/wp-content/uploads/2022/07/IMG_20220704_140357-300x169.jpg 300w, https://blog2k.ru/wp-content/uploads/2022/07/IMG_20220704_140357-768x432.jpg 768w, https://blog2k.ru/wp-content/uploads/2022/07/IMG_20220704_140357-1536x864.jpg 1536w, https://blog2k.ru/wp-content/uploads/2022/07/IMG_20220704_140357-2048x1152.jpg 2048w" sizes="auto, (max-width: 2560px) 100vw, 2560px" /></a></p>
<p>Турки, в отличие от россиян, большие патриоты. Флаг Турции висит на каждом шагу. Может потому, что им не рассказывают из каждого утюга, что ненавидеть свою страну &#8212; это нормально и почётно. Как сказал гид Ясин по прозвищу &#171;Мультфильм&#187; скоро Россия и Турция совсем породнятся. Кстати, в Турции процветает культ личности Мустафа Кемаля Ататюрка и никого это не коробит. Памятники и площади имени Ататюрка в каждом городе Турции. Оскорбление его памяти карается законом.</p>
<p>В стоимость экскурсий, как правило, включён незамысловатый обед с макарошками, салатом и курицей/рыбой, или просто чьё-то безымянное мясо, плюс к этому кусочек булки/хлеба. Иногда за напиток надо доплачивать отдельно. Почему в России не предлагают даже такой же сервис за приемлемые деньги &#8212; вопрос риторический.</p>
<p>Сначала мы прогулялись по Кемеру и поназаказывали экскурсии почти на каждый день. Три корабля, подъем на гору Тахталы и посещение Памукале, итого пять штук подряд. Стоимость в среднем 500-550 лир на двоих, самая дорогая в Памукале 1180 лир, но она того стоит. Потом мы отправились в Чиралы своим ходом на автобусе и маршрутке. Маршрутка стоит 26 лир с человека и ходит раз в час. Сначала вас высаживают из автобуса (30 лир с человека) на трассе, потом надо спускаться вниз семь километров на маршрутке (можно пешком). Автобус и маршрутка называются милым уху словом &#171;долмуш&#187;. Чиралы является заповедником, на его пляжах морские черепахи хранят свои яички, поэтому зонты и шезлонги лежат в тридцати метрах от моря. Парковка и катание на машине по пляжу стоит четыре тысячи долларов. Так же рядом для любителей можно посетить развалины древнего города.</p>
<p><a href="https://blog2k.ru/wp-content/uploads/2022/07/IMG_20220630_122035-scaled.jpg"><img loading="lazy" decoding="async" src="https://blog2k.ru/wp-content/uploads/2022/07/IMG_20220630_122035-scaled.jpg" alt="Турция, шоссе D400" width="2560" height="1440" class="aligncenter size-full wp-image-9535" srcset="https://blog2k.ru/wp-content/uploads/2022/07/IMG_20220630_122035-scaled.jpg 1024w, https://blog2k.ru/wp-content/uploads/2022/07/IMG_20220630_122035-300x169.jpg 300w, https://blog2k.ru/wp-content/uploads/2022/07/IMG_20220630_122035-768x432.jpg 768w, https://blog2k.ru/wp-content/uploads/2022/07/IMG_20220630_122035-1536x864.jpg 1536w, https://blog2k.ru/wp-content/uploads/2022/07/IMG_20220630_122035-2048x1152.jpg 2048w" sizes="auto, (max-width: 2560px) 100vw, 2560px" /></a></p>
<p>Вернувшись из Чиралы, через туристическое агенство арендовали машину на сутки, начиная со следующего утра. Машина отличная на мой взгляд, у ней унутри три цилиндра и 65 лошадиных сил, называется RENAULT TALIANT (белого цвета), коробка автомат, есть кондиционер. Обошлось нам это чудо инженерной мысли в 835 лир за сутки (50 баксов). Несмотря на слабый двигатель, машина в горах показала себя достаточно хорошо. Целью нашего путешествия был пляж Капуташ, всего 160 километров в одну сторону &#8212; это пляж с изумительно изумрудной водой, куда не возят туристов. Супруга ловко справилась с машиной, которую видела первый раз в жизни в незнакомой стране, поэтому к вечеру, уставшие, но довольные были в отеле.</p>
<p><a href="https://blog2k.ru/wp-content/uploads/2022/07/IMG_20220630_130220-scaled.jpg"><img loading="lazy" decoding="async" src="https://blog2k.ru/wp-content/uploads/2022/07/IMG_20220630_130220-scaled.jpg" alt="Турция, пляж Капуташ" width="2560" height="1440" class="aligncenter size-full wp-image-9533" srcset="https://blog2k.ru/wp-content/uploads/2022/07/IMG_20220630_130220-scaled.jpg 1024w, https://blog2k.ru/wp-content/uploads/2022/07/IMG_20220630_130220-300x169.jpg 300w, https://blog2k.ru/wp-content/uploads/2022/07/IMG_20220630_130220-768x432.jpg 768w, https://blog2k.ru/wp-content/uploads/2022/07/IMG_20220630_130220-1536x864.jpg 1536w, https://blog2k.ru/wp-content/uploads/2022/07/IMG_20220630_130220-2048x1152.jpg 2048w" sizes="auto, (max-width: 2560px) 100vw, 2560px" /></a></p>
<p>В первую экскурсию на корабле утром нас забыли забрать из отеля (Hello, Mehmet!), так что в Турции тоже не всегда всё слава <del>Аллаху</del> Богу. Мы связались с гидом и за нами прислали люкс автобус на две персоны, благо ехать было недалеко, а до стоянки яхт быстрее было дойти пешком, но уговор ждать автобус у отеля, есть уговор. Стоимость экскурсии была 500 лир на двоих, что по-нашему примерно 1750 рублей. В эту цену входит обед, трансфер туда и обратно, напитки отдельно за свои. Там мы около трёх раз купались в разных локациях, поели, позагорали и отправились домой. Мы такое дело вдвоём очень уважаем &#8212; когда делать ничего не надо, сверху яркая оранжевая штука в небе, солёная вода внизу, так что остались довольны, а сразу после поездки отправились к продавцу путёвок устраивать скандал, чтоб ему жизнь медом не казалась. Тот заверил нас, что больше такого не повторится.</p>
<p>На следующий день мы отправились в экскурсию на гору Тахталы, купленную через гида от туроператора. Подъём на фуникулёре на высоту 2365 метров полнейший восторг, страшно аж яички втягиваются. Фуникулёр промышленного масштаба &#8212; рассчитан на 80 человек. До подъёма заехали на оливковую ферму, где пили прямо из стопок масло и дегустировали вино. После спуска нас повезли в каньон Гейнюк,где накормили и дали искупаться, но желающих плавать в холодной горной реке особо не нашлось. Потом небольшой заплыв на корабле и по домам. Отдали за всё удовольствие 158 баксов на двоих в теории, а на практике на 18 баксов дороже, потому что терминал туроператорного гида взял двумя руками комиссию сколько смог унести (привет, Мевлюд!).</p>
<p>С интернетом в отеле было плохо, WiFi платный (доллар в сутки) и не работал из номера, поэтому мы купили симку оператора Vodafone за 450 лир, куда было включено 20 гигабайт интернета, ещё 750 минут и 1000 СМС, но работал почему-то только интернет.</p>
<p>А ещё турки много и часто курят и было сложно сдержаться от соблазна закурить снова (я бросил год назад). Проблема в том, что в моей памяти нет моментов, когда я, например, выхожу с аэропорта по прилёту и не курю, когда не курю после пива, потому что стаж моего курения около 25 лет и начался задолго до моих заграничных поездок по курортам. Но я сдержался и потому большой молодец! </p>
<p>Читатели просили подвести итог нашего путешествия и написать заключительный абзац. А вот и он! Всё понравилось, было пару неприятных моментов с уборкой в номере и веганском меню в отеле. В остальном всё хорошо. Супруга заставляла мазаться солцезащитным кремом, чтоб избежать возможного спидорака, поэтому домой приехал белый, зато ни разу не сгорел.</p>
]]></content>
		
					<link rel="replies" type="text/html" href="https://blog2k.ru/archives/9520#comments" thr:count="0" />
			<link rel="replies" type="application/atom+xml" href="https://blog2k.ru/archives/9520/feed/atom" thr:count="0" />
			<thr:total>0</thr:total>
			</entry>
		<entry>
		<author>
			<name>eJ</name>
					</author>

		<title type="html"><![CDATA[Симуляции жидкости в реальном времени]]></title>
		<link rel="alternate" type="text/html" href="https://blog2k.ru/archives/9484" />

		<id>https://blog2k.ru/?p=9484</id>
		<updated>2025-10-22T12:38:36Z</updated>
		<published>2022-05-26T10:00:38Z</published>
		<category scheme="https://blog2k.ru" term="Графика" /><category scheme="https://blog2k.ru" term="Математика" /><category scheme="https://blog2k.ru" term="нравится" /><category scheme="https://blog2k.ru" term="рекомендую" />
		<summary type="html"><![CDATA[Наткнулся на видео о симуляции жидкости и полезную книгу по этой теме. Интересуюсь симуляцией жидкости и нетвёрдых тел. Планирую реализовать симуляцию жидкости/дыма на JavaScript и выложить на сайте с описанием и исходниками.]]></summary>

					<content type="html" xml:base="https://blog2k.ru/archives/9484"><![CDATA[<p>Всем привет!</p>
<p>Наткнулся на видео о том, как работает симуляции жидкости:</p>
<div class="sllv-video -type_youtube" data-provider="youtube" data-video="qsYE1wMEMPA"><a class="sllv-video__link" href="https://youtu.be/qsYE1wMEMPA" rel="external noopener" target="_blank"><img decoding="async" class="sllv-video__media" src="https://i.ytimg.com/vi_webp/qsYE1wMEMPA/sddefault.webp" alt="Видео"></a><button class="sllv-video__button" type="button" aria-label="Воспроизвести видео"><svg width="68" height="48" viewBox="0 0 68 48"><path class="sllv-video__button-shape" d="M66.52 7.74c-.78-2.93-2.49-5.41-5.42-6.19C55.79.13 34 0 34 0S12.21.13 6.9 1.55c-2.93.78-4.63 3.26-5.42 6.19C.06 13.05 0 24 0 24s.06 10.95 1.48 16.26c.78 2.93 2.49 5.41 5.42 6.19C12.21 47.87 34 48 34 48s21.79-.13 27.1-1.55c2.93-.78 4.64-3.26 5.42-6.19C67.94 34.95 68 24 68 24s-.06-10.95-1.48-16.26z"/><path class="sllv-video__button-icon" d="M45 24L27 14v20"/></svg></button></div>
<p>И там же есть полезная ссылка на книгу о симуляции жидкости в реальном времени: <a href="https://damassets.autodesk.net/content/dam/autodesk/research/publications-assets/pdf/realtime-fluid-dynamics-for.pdf" rel="nofollow" target="_blank">Real-Time Fluid Dynamics for Games</a>. Сишного кода в книге на сто строк всего. Безо всякой зубодробительной математики. Любопытно, что книга понятнее, чем видео. Схороню здесь, чтобы не потерять. Давно интересовался этой темой.</p>
<p>И чтоб два раза не вставать, симуляция нетвёрдых тел (типа желе):</p>
<div class="sllv-video -type_youtube" data-provider="youtube" data-video="kyQP4t_wOGI"><a class="sllv-video__link" href="https://youtu.be/kyQP4t_wOGI" rel="external noopener" target="_blank"><img decoding="async" class="sllv-video__media" src="https://i.ytimg.com/vi_webp/kyQP4t_wOGI/sddefault.webp" alt="Видео"></a><button class="sllv-video__button" type="button" aria-label="Воспроизвести видео"><svg width="68" height="48" viewBox="0 0 68 48"><path class="sllv-video__button-shape" d="M66.52 7.74c-.78-2.93-2.49-5.41-5.42-6.19C55.79.13 34 0 34 0S12.21.13 6.9 1.55c-2.93.78-4.63 3.26-5.42 6.19C.06 13.05 0 24 0 24s.06 10.95 1.48 16.26c.78 2.93 2.49 5.41 5.42 6.19C12.21 47.87 34 48 34 48s21.79-.13 27.1-1.55c2.93-.78 4.64-3.26 5.42-6.19C67.94 34.95 68 24 68 24s-.06-10.95-1.48-16.26z"/><path class="sllv-video__button-icon" d="M45 24L27 14v20"/></svg></button></div>
<p>Возможно, в будущем, напишу реализацию жидкости/дыма на JavaScript и выложу на сайте с описанием и исходниками.</p>
]]></content>
		
					<link rel="replies" type="text/html" href="https://blog2k.ru/archives/9484#comments" thr:count="0" />
			<link rel="replies" type="application/atom+xml" href="https://blog2k.ru/archives/9484/feed/atom" thr:count="0" />
			<thr:total>0</thr:total>
			</entry>
		<entry>
		<author>
			<name>eJ</name>
					</author>

		<title type="html"><![CDATA[Сайт для создания и тестирования шейдеров]]></title>
		<link rel="alternate" type="text/html" href="https://blog2k.ru/archives/9460" />

		<id>https://blog2k.ru/?p=9460</id>
		<updated>2025-10-22T12:38:43Z</updated>
		<published>2022-05-24T08:02:30Z</published>
		<category scheme="https://blog2k.ru" term="WebGL" /><category scheme="https://blog2k.ru" term="Графика" /><category scheme="https://blog2k.ru" term="рекомендую" /><category scheme="https://blog2k.ru" term="шейдер" />
		<summary type="html"><![CDATA[На сайте shadertoy.com можно экспериментировать с параметрами Gaussian Blur в WebGL 2.0 на языке GLSL. Рекомендую попробовать.]]></summary>

					<content type="html" xml:base="https://blog2k.ru/archives/9460"><![CDATA[<p>В поисках Gaussian Blur наткнулся на сайт <a href="https://www.shadertoy.com/" rel="nofollow" target="_blank">shadertoy</a>.</p>
<p>Можно менять параметры налету и смотреть что получается. Попробуйте на примере <a href="https://www.shadertoy.com/view/Xltfzj" rel="nofollow" target="_blank">Gaussian Blur</a>. Платформа <code class="" data-line="">WebGL 2.0</code>, язык <code class="" data-line="">GLSL</code>, рекомендую к ознакомлению.</p>
<p>Также можно встраивать результат на страницу:</p>
<p><iframe loading="lazy" width="640" height="360" frameborder="0" src="https://www.shadertoy.com/embed/Xltfzj?gui=true&#038;t=10&#038;paused=false&#038;muted=false" allowfullscreen></iframe></p>
]]></content>
		
					<link rel="replies" type="text/html" href="https://blog2k.ru/archives/9460#comments" thr:count="0" />
			<link rel="replies" type="application/atom+xml" href="https://blog2k.ru/archives/9460/feed/atom" thr:count="0" />
			<thr:total>0</thr:total>
			</entry>
		<entry>
		<author>
			<name>eJ</name>
					</author>

		<title type="html"><![CDATA[Последние новости сайта]]></title>
		<link rel="alternate" type="text/html" href="https://blog2k.ru/archives/9414" />

		<id>https://blog2k.ru/?p=9414</id>
		<updated>2023-07-05T10:06:52Z</updated>
		<published>2022-05-19T13:55:25Z</published>
		<category scheme="https://blog2k.ru" term="Администрирование" /><category scheme="https://blog2k.ru" term="Хобби" /><category scheme="https://blog2k.ru" term="FreeBSD" /><category scheme="https://blog2k.ru" term="SSL" />
		<summary type="html"><![CDATA[SSL Сертификат В связи с событиями на Украине контора Sectigo объявила санкции и перестала выпускать ssl сертификаты для .ru и .рф доменов. За выпуск оного я платил 820 рублей в год. Благодаря сcанкциям, я перешёл на использование бесплатного сертификата от Let&#8217;s Encrypt (с помощью certbot &#8212; он есть в портах FreeBSD). Поначалу certbot капризничал и [&#8230;]]]></summary>

					<content type="html" xml:base="https://blog2k.ru/archives/9414"><![CDATA[<h2>SSL Сертификат</h2>
<p>В связи с событиями на Украине контора <code class="" data-line="">Sectigo</code> объявила санкции и перестала выпускать ssl сертификаты для .ru и .рф доменов. За выпуск оного я платил 820 рублей в год.</p>
<p>Благодаря сcанкциям, я перешёл на использование бесплатного сертификата от <a href="https://letsencrypt.org/ru/about/" rel="nofollow" target="_blank">Let&#8217;s Encrypt</a> (с помощью <code class="" data-line="">certbot</code> &#8212; он есть в портах <code class="" data-line="">FreeBSD</code>). Поначалу <code class="" data-line="">certbot</code> капризничал и не хотел работать без <code class="" data-line="">AAAA</code> DNS записи, но это вылечилось, когда я прописал <code class="" data-line="">www</code> как <code class="" data-line="">CNAME</code> основного домена. Так что теперь я использую сертификат от <a href="https://letsencrypt.org/ru/about/" rel="nofollow" target="_blank">Let&#8217;s Encrypt</a>, а конторе <code class="" data-line="">Sectigo</code> вместе с <code class="" data-line="">Comodo</code> могу сказать следующее:</p>
<p><a href="https://blog2k.ru/wp-content/uploads/2022/05/fuck-you-asshole.jpg"><img loading="lazy" decoding="async" src="https://blog2k.ru/wp-content/uploads/2022/05/fuck-you-asshole-300x300.jpg" alt="Fuck you asshole!" width="300" height="300" class="aligncenter size-medium wp-image-9439" srcset="https://blog2k.ru/wp-content/uploads/2022/05/fuck-you-asshole-300x300.jpg 300w, https://blog2k.ru/wp-content/uploads/2022/05/fuck-you-asshole-150x150.jpg 150w, https://blog2k.ru/wp-content/uploads/2022/05/fuck-you-asshole-250x250.jpg 250w, https://blog2k.ru/wp-content/uploads/2022/05/fuck-you-asshole-120x120.jpg 120w, https://blog2k.ru/wp-content/uploads/2022/05/fuck-you-asshole.jpg 400w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></p>
<p>Кстати, в связи с подобными запретами Минцифры РФ подсуетилось и начало выпускать отечественные SSL сертификаты через госуслуги, которые никем не признаны, доступны только юридическим лицам и принесут больше проблем, чем пользы. Досадно, что настройкой чебурнета занимаются кретины.</p>
<h2>IPv6</h2>
<p>Решая проблемы с <code class="" data-line="">certbot</code>, неожиданно вспомнил, что <a href="https://ruweb.net/?ref=142897" rel="nofollow" target="_blank">хостер</a> выдал мне сеть /64 <code class="" data-line="">IPv6</code> адресов. Я не сильно в этом разбираюсь, но судя по калькулятору, могу выдать каждому жителю планеты Земля по два миллиарда адресов в моём личном адресном пространстве. Мне много не надо, поэтому взял циферку один и теперь у моего сайта <a href="https://www.reg.ru/nettools/dig?domain=blog2k.ru&#038;type=aaaa&#038;dns=" target="_blank">есть</a> <code class="" data-line="">AAAA</code> DNS запись и он открывается по <code class="" data-line="">IPv6</code> адресу.</p>
]]></content>
		
					<link rel="replies" type="text/html" href="https://blog2k.ru/archives/9414#comments" thr:count="1" />
			<link rel="replies" type="application/atom+xml" href="https://blog2k.ru/archives/9414/feed/atom" thr:count="1" />
			<thr:total>1</thr:total>
			</entry>
		<entry>
		<author>
			<name>eJ</name>
					</author>

		<title type="html"><![CDATA[ERROR 2503 и ERROR 2502 при запуске инсталлятора .msi]]></title>
		<link rel="alternate" type="text/html" href="https://blog2k.ru/archives/9347" />

		<id>https://blog2k.ru/?p=9347</id>
		<updated>2025-10-22T12:38:53Z</updated>
		<published>2022-04-21T10:34:36Z</published>
		<category scheme="https://blog2k.ru" term="Жизнь" /><category scheme="https://blog2k.ru" term="Полезные советы" />
		<summary type="html"><![CDATA[Устранил проблему установки программы с расширением .msi на удалёнке: запуск cmd от имени администратора помог преодолеть ошибку 2503. Видеоинструкция по ссылке.]]></summary>

					<content type="html" xml:base="https://blog2k.ru/archives/9347"><![CDATA[<p>Хотел написать увлекательную историю про то, как у нас устроена удалёнка, но не хочу, поэтому буду краток.</p>
<p>Понадобилось поставить программу из файла с расширением <code class="" data-line="">.msi</code>, а она не ставится. Программа очень важная, для доступа к локальной сети и последующей работе из дома.</p>
<p>При запуске инсталлятора на 95% прогресса, программа выдаёт окно с ошибкой 2503 и откатывает процесс назад.<br />
Перерыв интернет, нашёл два совета:</p>
<ol>
<li>Установить права всем на всё на папку <code class="" data-line="">%TEMP</code> &#8212; не помогло</li>
<li>Способ второй: запустить <em><code class="" data-line="">cmd</code> As Administrator</em> и там запустить <code class="" data-line="">.msi</code> на выполнение &#8212; <strong>СРАБОТАЛ!</strong> В благодарность, выкладываю видео сего процесса, хотя терпеть не могу, когда одну строку растягивают на три с половиной минуты.</li>
</ol>
<div style="text-align:center;">
<div class="sllv-video -type_youtube" data-provider="youtube" data-video="kIEkS4J_hHQ"><a class="sllv-video__link" href="https://youtu.be/kIEkS4J_hHQ" rel="external noopener" target="_blank"><img decoding="async" class="sllv-video__media" src="https://i.ytimg.com/vi_webp/kIEkS4J_hHQ/sddefault.webp" alt="Видео"></a><button class="sllv-video__button" type="button" aria-label="Воспроизвести видео"><svg width="68" height="48" viewBox="0 0 68 48"><path class="sllv-video__button-shape" d="M66.52 7.74c-.78-2.93-2.49-5.41-5.42-6.19C55.79.13 34 0 34 0S12.21.13 6.9 1.55c-2.93.78-4.63 3.26-5.42 6.19C.06 13.05 0 24 0 24s.06 10.95 1.48 16.26c.78 2.93 2.49 5.41 5.42 6.19C12.21 47.87 34 48 34 48s21.79-.13 27.1-1.55c2.93-.78 4.64-3.26 5.42-6.19C67.94 34.95 68 24 68 24s-.06-10.95-1.48-16.26z"/><path class="sllv-video__button-icon" d="M45 24L27 14v20"/></svg></button></div>
</div>
]]></content>
		
					<link rel="replies" type="text/html" href="https://blog2k.ru/archives/9347#comments" thr:count="0" />
			<link rel="replies" type="application/atom+xml" href="https://blog2k.ru/archives/9347/feed/atom" thr:count="0" />
			<thr:total>0</thr:total>
			</entry>
		<entry>
		<author>
			<name>eJ</name>
					</author>

		<title type="html"><![CDATA[Как избавиться от спам-звонков за два шага]]></title>
		<link rel="alternate" type="text/html" href="https://blog2k.ru/archives/9300" />

		<id>https://blog2k.ru/?p=9300</id>
		<updated>2026-01-31T13:47:40Z</updated>
		<published>2021-11-29T15:28:36Z</published>
		<category scheme="https://blog2k.ru" term="Жизнь" /><category scheme="https://blog2k.ru" term="Полезные советы" /><category scheme="https://blog2k.ru" term="рекомендую" />
		<summary type="html"><![CDATA[В статье рассказывается о двух бесплатных приложениях для Android: антиспам от Касперского и телефонный робот-секретарь от банка Тинькофф. Они помогут определить, полезен ли звонок, и возьмут трубку, если вы сомневаетесь.]]></summary>

					<content type="html" xml:base="https://blog2k.ru/archives/9300"><![CDATA[<p>Всем привет, буду краток! Вам понадобится всего две вещи:<br />1. Антиспам от Касперского: <a href="https://play.google.com/store/apps/details?id=com.kaspersky.who_calls" rel="nofollow" target="_blank">Антиспам: Kaspersky Who Calls</a><br />2. Телефонный робот-секретарь от банка Тинькофф: <a href="https://www.tinkoff.ru/oleg/secretary" rel="nofollow" target="_blank">Телефонный секретарь Олег</a></p>
<p>Первое приложение &#8212; показывает насколько полезный звонок. Второй поговорит за вас, если вы всё равно сомневаетесь в звонящем. Всё это бесплатно, то есть даром. Не благодарите. Если возникнут вопросы, спрашивайте в комментариях, всё расскажу.</p>
<p>Инструкция подходит для телефонов Android. Для пользователей техники Apple инструкций нет, потому что <del>богатые должны страдать</del> она точно такая же.</p>
]]></content>
		
					<link rel="replies" type="text/html" href="https://blog2k.ru/archives/9300#comments" thr:count="2" />
			<link rel="replies" type="application/atom+xml" href="https://blog2k.ru/archives/9300/feed/atom" thr:count="2" />
			<thr:total>2</thr:total>
			</entry>
		<entry>
		<author>
			<name>eJ</name>
					</author>

		<title type="html"><![CDATA[Youtube каналы про реставрацию старых вещей]]></title>
		<link rel="alternate" type="text/html" href="https://blog2k.ru/archives/8867" />

		<id>https://blog2k.ru/?p=8867</id>
		<updated>2026-01-31T11:05:54Z</updated>
		<published>2021-06-28T10:54:25Z</published>
		<category scheme="https://blog2k.ru" term="Жизнь" /><category scheme="https://blog2k.ru" term="видео" /><category scheme="https://blog2k.ru" term="рекомендую" />
		<summary type="html"><![CDATA[В статье автор делится подборкой каналов на YouTube, где мастера реставрируют старые инструменты и устройства. Однако он также отмечает, что некоторые «рестораторы» искусственно состаривают предметы и затем выдают результат за реставрацию старых вещей. Автор предупреждает о таких каналах и рекомендует к просмотру каналы LADB Restoration, TysyTube Restoration и my mechanics.]]></summary>

					<content type="html" xml:base="https://blog2k.ru/archives/8867"><![CDATA[<p>Пока мыслей для блога особых нет, решил поделиться каналами Youtube, где рукастый народ реставрирует старые инструменты и устройства.</p>
<p>Примерно два года назад, бродя по просторам Youtube, наткнулся на ролик, где человек реставрировал плоскогубцы. Был в полном восторге. Вот сейчас они ржавые, а через двадцать минут &#8212; новенькие, как будто из магазина. Почитал ради интереса комментарии и выяснилось, что автор ролика знатный брехун. Комментаторы заметили, что губки отреставрированных плоскогубцев идеально смыкаются без зазоров, что невозможно, если плоскогубцам много лет, ими долго пользовались по назначению и они пролежали в луже не один год.</p>
<p>Оказывается, некоторые уроды берут хорошую вещь, снимают с ней финальный результат, затем искуственно эту вещь старят и героически её реставрируют. Не одного меня с этого бомбит, так что вот вам ролик про таких &#171;рестораторов&#187; (осторожно &#8212; много мата, но исключительно по делу):</p>
<div style="text-align:center;">
<div class="sllv-video -type_youtube" data-provider="youtube" data-video="MLIjefB6_gU"><a class="sllv-video__link" href="https://youtu.be/MLIjefB6_gU?t=163" rel="external noopener" target="_blank"><img decoding="async" class="sllv-video__media" src="https://i.ytimg.com/vi_webp/MLIjefB6_gU/sddefault.webp" alt="Видео"></a><button class="sllv-video__button" type="button" aria-label="Воспроизвести видео"><svg width="68" height="48" viewBox="0 0 68 48"><path class="sllv-video__button-shape" d="M66.52 7.74c-.78-2.93-2.49-5.41-5.42-6.19C55.79.13 34 0 34 0S12.21.13 6.9 1.55c-2.93.78-4.63 3.26-5.42 6.19C.06 13.05 0 24 0 24s.06 10.95 1.48 16.26c.78 2.93 2.49 5.41 5.42 6.19C12.21 47.87 34 48 34 48s21.79-.13 27.1-1.55c2.93-.78 4.64-3.26 5.42-6.19C67.94 34.95 68 24 68 24s-.06-10.95-1.48-16.26z"/><path class="sllv-video__button-icon" d="M45 24L27 14v20"/></svg></button></div>
</div>
<p>А теперь к делу!<span id="more-8867"></span></p>
<h2>LADB Restoration</h2>
<div style="text-align:center;">
<div class="sllv-video -type_youtube" data-provider="youtube" data-video="9_sXSCjNHTg"><a class="sllv-video__link" href="https://youtu.be/9_sXSCjNHTg" rel="external noopener" target="_blank"><img decoding="async" class="sllv-video__media" src="https://i.ytimg.com/vi_webp/9_sXSCjNHTg/sddefault.webp" alt="Видео"></a><button class="sllv-video__button" type="button" aria-label="Воспроизвести видео"><svg width="68" height="48" viewBox="0 0 68 48"><path class="sllv-video__button-shape" d="M66.52 7.74c-.78-2.93-2.49-5.41-5.42-6.19C55.79.13 34 0 34 0S12.21.13 6.9 1.55c-2.93.78-4.63 3.26-5.42 6.19C.06 13.05 0 24 0 24s.06 10.95 1.48 16.26c.78 2.93 2.49 5.41 5.42 6.19C12.21 47.87 34 48 34 48s21.79-.13 27.1-1.55c2.93-.78 4.64-3.26 5.42-6.19C67.94 34.95 68 24 68 24s-.06-10.95-1.48-16.26z"/><path class="sllv-video__button-icon" d="M45 24L27 14v20"/></svg></button></div>
</div>
<p>Человек живёт во Франции, если я правильно понял, и реставрирует в основном инструменты и устройства. А что самое важное &#8212; этими вещами потом сам и пользуется. Решил написать про него в первую очередь, потому что, смотря на его работу, на мгновение возникает мысль &#171;О! Я так тоже смогу!&#187;, на самом деле &#8212; нет. Это не может не радовать, поскольку набор инструментов у него практически стандартный, который вы сможете найти в своём ящике с инструментами, если он у вас, конечно, есть. Если ящика с инструментами у вас нет, то нажмите <code class="" data-line="">Ctrl-W</code>.</p>
<p>Ссылка на канал: <a href="https://www.youtube.com/channel/UC8AvcEE8l8mHs-rZTXoynVQ" rel="nofollow" target="_blank">LADB Restoration</a></p>
<h2>TysyTube Restoration</h2>
<div style="text-align:center;">
<div class="sllv-video -type_youtube" data-provider="youtube" data-video="Un5VsIzWkSA"><a class="sllv-video__link" href="https://youtu.be/Un5VsIzWkSA" rel="external noopener" target="_blank"><img decoding="async" class="sllv-video__media" src="https://i.ytimg.com/vi_webp/Un5VsIzWkSA/sddefault.webp" alt="Видео"></a><button class="sllv-video__button" type="button" aria-label="Воспроизвести видео"><svg width="68" height="48" viewBox="0 0 68 48"><path class="sllv-video__button-shape" d="M66.52 7.74c-.78-2.93-2.49-5.41-5.42-6.19C55.79.13 34 0 34 0S12.21.13 6.9 1.55c-2.93.78-4.63 3.26-5.42 6.19C.06 13.05 0 24 0 24s.06 10.95 1.48 16.26c.78 2.93 2.49 5.41 5.42 6.19C12.21 47.87 34 48 34 48s21.79-.13 27.1-1.55c2.93-.78 4.64-3.26 5.42-6.19C67.94 34.95 68 24 68 24s-.06-10.95-1.48-16.26z"/><path class="sllv-video__button-icon" d="M45 24L27 14v20"/></svg></button></div>
</div>
<p>Человек реставрирует всё подряд, причём до идеального состояния. Чувствуется перфекционизм и золотые руки. Рекомендую для просмотра и вызывания чувства зависти.</p>
<p>Ссылка на канал: <a href="https://www.youtube.com/channel/UCIGEtjevANE0Nqain3EqNSg" rel="nofollow" target="_blank">TysyTube Restoration</a></p>
<h2>my mechanics</h2>
<div style="text-align:center;">
<div class="sllv-video -type_youtube" data-provider="youtube" data-video="6iDJNGdMFls"><a class="sllv-video__link" href="https://youtu.be/6iDJNGdMFls" rel="external noopener" target="_blank"><img decoding="async" class="sllv-video__media" src="https://i.ytimg.com/vi_webp/6iDJNGdMFls/sddefault.webp" alt="Видео"></a><button class="sllv-video__button" type="button" aria-label="Воспроизвести видео"><svg width="68" height="48" viewBox="0 0 68 48"><path class="sllv-video__button-shape" d="M66.52 7.74c-.78-2.93-2.49-5.41-5.42-6.19C55.79.13 34 0 34 0S12.21.13 6.9 1.55c-2.93.78-4.63 3.26-5.42 6.19C.06 13.05 0 24 0 24s.06 10.95 1.48 16.26c.78 2.93 2.49 5.41 5.42 6.19C12.21 47.87 34 48 34 48s21.79-.13 27.1-1.55c2.93-.78 4.64-3.26 5.42-6.19C67.94 34.95 68 24 68 24s-.06-10.95-1.48-16.26z"/><path class="sllv-video__button-icon" d="M45 24L27 14v20"/></svg></button></div>
</div>
<p>У меня есть подозрение, что этот канал и предыдущий ведёт один и тот же человек, потому что стиль и инструменты очень похожи. Человек живёт в Швейцарии. Казалось бы, кушай швейцарский сыр, живи в шоколаде, пей молоко альпийских гор, ан нет!</p>
<p>Ссылка на канал: <a href="https://www.youtube.com/channel/UCMrMVIBtqFW6O0-MWq26gqw" rel="nofollow" target="_blank">my mechanics</a></p>
<p>P.S. И напоследок пару слов. Если в названии ролика есть слова <em>&#171;Шок&#187;</em>, <em>&#171;Этот ролик взорвал интернет&#187;</em> и <em>&#171;Cрочно смотреть всем, пока не удалили&#187;</em>, то автор ролика считает вас дебилом. Будьте бдительны! Также, если текстовая заметка заканчивается словами <em>&#171;Узнали?&#187;</em>, <em>&#171;Согласны?&#187;</em>, <em>&#171;Знакомо?&#187;</em> это значит, что вас разводят на комментарии, как деревенского дурачка. Не ведитесь! Зря, что ли, наши предки слезали с деревьев, осваивали прямохождение и с большим трудом выращивали мозг, чтобы вы велись, как тупая обезьянка. Согласны? Знакомо?</p>
]]></content>
		
					<link rel="replies" type="text/html" href="https://blog2k.ru/archives/8867#comments" thr:count="0" />
			<link rel="replies" type="application/atom+xml" href="https://blog2k.ru/archives/8867/feed/atom" thr:count="0" />
			<thr:total>0</thr:total>
			</entry>
		<entry>
		<author>
			<name>eJ</name>
					</author>

		<title type="html"><![CDATA[Забористая анестезия или плавное съезжание кукушки в реанимации]]></title>
		<link rel="alternate" type="text/html" href="https://blog2k.ru/archives/8893" />

		<id>https://blog2k.ru/?p=8893</id>
		<updated>2025-12-09T08:51:38Z</updated>
		<published>2021-05-17T08:27:22Z</published>
		<category scheme="https://blog2k.ru" term="Жизнь" /><category scheme="https://blog2k.ru" term="Здоровье" /><category scheme="https://blog2k.ru" term="здоровье" />
		<summary type="html"><![CDATA[Автор статьи рассказывает о своих необычных ощущениях и галлюцинациях после перенесённого геморрагического инсульта и трепанации черепа. Несмотря на непростое состояние, он выражает благодарность нейрохирургам за проведённую операцию.]]></summary>

					<content type="html" xml:base="https://blog2k.ru/archives/8893"><![CDATA[<p>Угораздило меня <a href="https://blog2k.ru/archives/7778" target="_blank">опять</a> попасть в больницу, но в этот раз с геморрагическим инсультом с последующей трепанацией черепа. В реанимации после этого я провёл две недели. Это бесконечно долгий срок, учитывая &#171;дружелюбность&#187;  медсестёр в реанимации Елизаветинской больницы с их скотским отношением к пациентам реанимации. Окрики и хамство &#8212; это именно то, чего не хватает пациенту с гематомой в голове для скорейшего выздоровления. Но Бог им судья, статья вообще не про это, а про то, что мне чудилось в тех местах. Начну с простого  случая &#8212; как у меня украли тело.<br />
Когда меня перевели из реанимации в палату, я был уверен, что у меня <em>украли </em> одно  тело, потому что в той версии были специальные крутилки на коленях, которыми можно регулировать давление. И подарили их мне протоссы, чувствуете накал идиотии? Я был настолько возмущён очевидным воровством имущества, что хотел жаловаться главврачу. Так же после перевода в палату, я был на сто процентов уверен, что нахожусь в США. Как такое возможно &#8212; поступить в Санкт-Петербурге в Елизаветинскую больницу, а оказаться в США &#8212; не знаю, но мне это было совершено очевидно! Я даже спрашивал медсестёр:<br />
&#8212; Где я нахожусь?<br />
&#8212; Елизаветинская больница<br />
&#8212; А город какой?<br />
&#8212; Санкт-Петербург!<br />
&#8212; А страна какая?<br />
&#8212; Россия!( и тут я чувствую, что врёт медсестра!)<br />
Мои подозрения подпитывали некоторые &#171;странные&#187; вещи:<br />
&#8212; на розетках написано 220V (зачем?!)<br />
&#8212; на постельном белье синими буквами напечатано &#171;РИКВЭСТ&#187; (request англ. запрос)<br />
<img loading="lazy" decoding="async" src="https://blog2k.ru/wp-content/uploads/2021/05/IMG_20210508_200545-300x225.jpg" alt="Риквэст" width="300" height="225" class="aligncenter size-medium wp-image-8896" srcset="https://blog2k.ru/wp-content/uploads/2021/05/IMG_20210508_200545-300x225.jpg 300w, https://blog2k.ru/wp-content/uploads/2021/05/IMG_20210508_200545-scaled.jpg 1024w, https://blog2k.ru/wp-content/uploads/2021/05/IMG_20210508_200545-768x576.jpg 768w, https://blog2k.ru/wp-content/uploads/2021/05/IMG_20210508_200545-1536x1152.jpg 1536w, https://blog2k.ru/wp-content/uploads/2021/05/IMG_20210508_200545-2048x1536.jpg 2048w" sizes="auto, (max-width: 300px) 100vw, 300px" /><br />
&#8212; на бейджиках персонала написано сначала имя, потом отчество, затем фамилия. По-русски так не пишут!!<br />
&#8212; пейзаж за окном явно не питерский, а какой-то приятный и промышленный.<br />
<img loading="lazy" decoding="async" src="https://blog2k.ru/wp-content/uploads/2021/05/IMG_20210509_052816-scaled.jpg" alt="Вид из окна Елизаветинской больницы" width="2560" height="1920" class="aligncenter size-full wp-image-8897" srcset="https://blog2k.ru/wp-content/uploads/2021/05/IMG_20210509_052816-scaled.jpg 1024w, https://blog2k.ru/wp-content/uploads/2021/05/IMG_20210509_052816-300x225.jpg 300w, https://blog2k.ru/wp-content/uploads/2021/05/IMG_20210509_052816-768x576.jpg 768w, https://blog2k.ru/wp-content/uploads/2021/05/IMG_20210509_052816-1536x1152.jpg 1536w, https://blog2k.ru/wp-content/uploads/2021/05/IMG_20210509_052816-2048x1536.jpg 2048w" sizes="auto, (max-width: 2560px) 100vw, 2560px" /><br />
 Отдельно стояло здание с отсеками для космических истребителей, но его я в расчёт почему-то не принял. Между прочим, мой лечащий врач был уверен, что я в адеквате. Это он просто не спросил в какой стране мы находимся. А ещё в моей палате примерно две недели после перевода находился Зератул (Zeratul) из Темных храмовников, но ничего не предпринимал.</p>
<p><span id="more-8893"></span>Окончательно в том, что мы в России меня убедило включение мобильника со встроенным GPS.<br />
Дальше был прикол со временем и пространством. В реанимации какое-то время у меня были привязаны руки, потому что я люблю спать на боку. Но повязок на руках я не видел, просто руки не пошевелить и всё.  Тогда от скуки я начинал стучать ногтями по железной части кровати. Мне отвечали &#171;кончай шуметь, три часа ночи, люди спят!&#187; и в этот момент я переносился в другое измерение где чотко видел повязку на руках. Это была Англия 1920-х годов. Как и почему я был в этом уверен &#8212; не имею ни малейшего понятия. Кстати, в самой реанимации большую часть я провёл в Алжире в 1980-х годах и там была война с участием Франции. Здорово, правда?!<br />
Вообще, после операции на сердце, психика у меня относительно крепкая, относительно большинства людей, потому что не всякий  сможет морально принять, что технически один раз уже был полностью мёртв.<br />
Наверно, именно это помогло мне сохранить рассудок после перенесенных переживаний, но, откровенно говоря, балансировал я на грани. Кстати, первый признак, что у вас едет крыша &#8212; вы ни на секунду ни в чём не сомневаетесь. На кровати сидит говорящий драгун (dragooon) протоссов размером с котёнка? Так и надо, это нормально, у всех так.<br />
<img loading="lazy" decoding="async" src="https://blog2k.ru/wp-content/uploads/2021/05/dragoon.jpg" alt="Драгун протоссов" width="811" height="470" class="aligncenter size-full wp-image-8899" srcset="https://blog2k.ru/wp-content/uploads/2021/05/dragoon.jpg 811w, https://blog2k.ru/wp-content/uploads/2021/05/dragoon-300x174.jpg 300w, https://blog2k.ru/wp-content/uploads/2021/05/dragoon-768x445.jpg 768w" sizes="auto, (max-width: 811px) 100vw, 811px" /><br />
В палате стоит Зератул, <em>ненуачо</em> потолки в больнице по три метра, значит заранее рассчитали.<br />
<img loading="lazy" decoding="async" src="https://blog2k.ru/wp-content/uploads/2021/05/Зератул-1.jpg" alt="Зератул" width="759" height="1000" class="aligncenter size-full wp-image-8907" srcset="https://blog2k.ru/wp-content/uploads/2021/05/Зератул-1.jpg 759w, https://blog2k.ru/wp-content/uploads/2021/05/Зератул-1-228x300.jpg 228w" sizes="auto, (max-width: 759px) 100vw, 759px" /><br />
Хвала Аллаху, это было временным явлением, через пару недель после перевода в палату всё пришло в норму.</p>
<p>Пользуясь случаем, хочу поблагодарить нейрохирургов <strong>Ивана Геннадьевича Захматова</strong> и <strong>Щербинина Антона Владимировича</strong> за блестяще проведенную операцию!</p>
]]></content>
		
					<link rel="replies" type="text/html" href="https://blog2k.ru/archives/8893#comments" thr:count="2" />
			<link rel="replies" type="application/atom+xml" href="https://blog2k.ru/archives/8893/feed/atom" thr:count="2" />
			<thr:total>2</thr:total>
			</entry>
		<entry>
		<author>
			<name>eJ</name>
					</author>

		<title type="html"><![CDATA[Youtube каналы про выживание в каменном веке]]></title>
		<link rel="alternate" type="text/html" href="https://blog2k.ru/archives/8840" />

		<id>https://blog2k.ru/?p=8840</id>
		<updated>2026-01-31T11:11:41Z</updated>
		<published>2020-10-28T09:22:31Z</published>
		<category scheme="https://blog2k.ru" term="Жизнь" /><category scheme="https://blog2k.ru" term="видео" /><category scheme="https://blog2k.ru" term="рекомендую" />
		<summary type="html"><![CDATA[В статье перечислены YouTube-каналы про выживание в каменном веке. Автор рассказывает о трёх каналах и рекомендует их к просмотру. Также выражается недовольство монетизацией YouTube.]]></summary>

					<content type="html" xml:base="https://blog2k.ru/archives/8840"><![CDATA[<p>Один мой коллега (привет, Алекс) однажды в командировке сказал умную вещь &#8212; не надо бояться писать обо всём. Мысль пришла &#8212; записал в блог. Не одобрил мысль читатель &#8212; да насрать (это уже от меня) &#8212; мой блог, что хочу, то и пишу. Не нравится &#8212; скатертью по жопе, проваливай, смотри, чтоб дверью на выходе не прищемило.</p>
<p>В этой заметке хочу поделиться Youtube каналами про выживание в каменном веке. Все каналы объединяет одна тема &#8212; выживание в дикой природе.</p>
<h2>Primitive Technology</h2>
<div style="text-align:center;">
<div class="sllv-video -type_youtube" data-provider="youtube" data-video="-cgQUrdBoaM"><a class="sllv-video__link" href="https://youtu.be/-cgQUrdBoaM" rel="external noopener" target="_blank"><img decoding="async" class="sllv-video__media" src="https://i.ytimg.com/vi_webp/-cgQUrdBoaM/sddefault.webp" alt="Видео"></a><button class="sllv-video__button" type="button" aria-label="Воспроизвести видео"><svg width="68" height="48" viewBox="0 0 68 48"><path class="sllv-video__button-shape" d="M66.52 7.74c-.78-2.93-2.49-5.41-5.42-6.19C55.79.13 34 0 34 0S12.21.13 6.9 1.55c-2.93.78-4.63 3.26-5.42 6.19C.06 13.05 0 24 0 24s.06 10.95 1.48 16.26c.78 2.93 2.49 5.41 5.42 6.19C12.21 47.87 34 48 34 48s21.79-.13 27.1-1.55c2.93-.78 4.64-3.26 5.42-6.19C67.94 34.95 68 24 68 24s-.06-10.95-1.48-16.26z"/><path class="sllv-video__button-icon" d="M45 24L27 14v20"/></svg></button></div>
</div>
<p>Этот канал наиболее близок простому обывателю &#8212; плетение неказистых корзин и лепка глиняной посуды без претензий на красоту, поэтому он первый в моём списке. Съёмки происходили в Австралии ради написания книги. Как пишет автор &#8212; опыта армейской службы он не имеет. Большинство роликов имеют русские субтитры, в отличие от остальных каналов.<span id="more-8840"></span></p>
<p>Ссылка на канал: <a href="https://www.youtube.com/channel/UCAL3JXZSzSm8AlZyD3nQdBA" rel="nofollow" target="_blank">Primitive Technology Channel</a></p>
<h2>Primitive Life</h2>
<div style="text-align:center;">
<div class="sllv-video -type_youtube" data-provider="youtube" data-video="X6uGgfJGxo0"><a class="sllv-video__link" href="https://youtu.be/X6uGgfJGxo0" rel="external noopener" target="_blank"><img decoding="async" class="sllv-video__media" src="https://i.ytimg.com/vi_webp/X6uGgfJGxo0/sddefault.webp" alt="Видео"></a><button class="sllv-video__button" type="button" aria-label="Воспроизвести видео"><svg width="68" height="48" viewBox="0 0 68 48"><path class="sllv-video__button-shape" d="M66.52 7.74c-.78-2.93-2.49-5.41-5.42-6.19C55.79.13 34 0 34 0S12.21.13 6.9 1.55c-2.93.78-4.63 3.26-5.42 6.19C.06 13.05 0 24 0 24s.06 10.95 1.48 16.26c.78 2.93 2.49 5.41 5.42 6.19C12.21 47.87 34 48 34 48s21.79-.13 27.1-1.55c2.93-.78 4.64-3.26 5.42-6.19C67.94 34.95 68 24 68 24s-.06-10.95-1.48-16.26z"/><path class="sllv-video__button-icon" d="M45 24L27 14v20"/></svg></button></div>
</div>
<p>На этом канале похожий вариант, но автор делает всё более монументально, с упором на комфорт и внешний вид. Если в Primitive Technology автор строит временную хижину на пару месяцев, чтобы выжить, иметь убежище от дождя и немножко еды, то здесь целый участок, с бассейном с рыбками, курятником, свинарником и почти каменным домом. Между делом, автор изготавливает железный нож.</p>
<p>Ссылка на канал: <a href="https://www.youtube.com/c/PrimitiveLife" rel="nofollow" target="_blank">Primitive Life</a></p>
<h2>Primitive Skills</h2>
<div style="text-align:center;">
<div class="sllv-video -type_youtube" data-provider="youtube" data-video="tBTwI7xYEy0"><a class="sllv-video__link" href="https://youtu.be/tBTwI7xYEy0" rel="external noopener" target="_blank"><img decoding="async" class="sllv-video__media" src="https://i.ytimg.com/vi_webp/tBTwI7xYEy0/sddefault.webp" alt="Видео"></a><button class="sllv-video__button" type="button" aria-label="Воспроизвести видео"><svg width="68" height="48" viewBox="0 0 68 48"><path class="sllv-video__button-shape" d="M66.52 7.74c-.78-2.93-2.49-5.41-5.42-6.19C55.79.13 34 0 34 0S12.21.13 6.9 1.55c-2.93.78-4.63 3.26-5.42 6.19C.06 13.05 0 24 0 24s.06 10.95 1.48 16.26c.78 2.93 2.49 5.41 5.42 6.19C12.21 47.87 34 48 34 48s21.79-.13 27.1-1.55c2.93-.78 4.64-3.26 5.42-6.19C67.94 34.95 68 24 68 24s-.06-10.95-1.48-16.26z"/><path class="sllv-video__button-icon" d="M45 24L27 14v20"/></svg></button></div>
</div>
<p>Автор этого канала умеет удивительно красиво плести. Ну и заодно добывать огонь, делать продвинутые железные инструменты, выращивать и готовить рис, разводить рыбу, строить дом и делать глиняную посуду.</p>
<p>Ссылка на канал: <a href="https://www.youtube.com/c/PrimitiveSkillsnet" rel="nofollow" target="_blank">Primitive Skills</a></p>
<p><strong>Приятного просмотра!</strong></p>
<p>Ну и в завершении этой подборки я хотел бы послать лучи ненависти владельцам Youtube, которые до такой степени оборзели, что клянчат деньги на  премиум подписку в мобильном приложении за то, чтоб не переключаться на главный экран при сворачивании приложения в трей на Андроиде. Гореть вам в аду! Вам мало показа двух, сука, рекламных вставок в начале десятиминутного ролика?! Уже Ярмольник до такой степени остоепиздел в совершенно убогой рекламе МТС с Нагиевым, что сил моих нет. Ярмольник такой же техногик и программист, как я, блять, звезда порнхаба.</p>
]]></content>
		
					<link rel="replies" type="text/html" href="https://blog2k.ru/archives/8840#comments" thr:count="2" />
			<link rel="replies" type="application/atom+xml" href="https://blog2k.ru/archives/8840/feed/atom" thr:count="2" />
			<thr:total>2</thr:total>
			</entry>
		<entry>
		<author>
			<name>eJ</name>
					</author>

		<title type="html"><![CDATA[Вторая командировка в Германию]]></title>
		<link rel="alternate" type="text/html" href="https://blog2k.ru/archives/8776" />

		<id>https://blog2k.ru/?p=8776</id>
		<updated>2025-12-09T08:52:44Z</updated>
		<published>2020-02-22T10:12:36Z</published>
		<category scheme="https://blog2k.ru" term="Германия" /><category scheme="https://blog2k.ru" term="Путешествия" /><category scheme="https://blog2k.ru" term="командировка" />
		<summary type="html"><![CDATA[Вторая командировка в Германию оказалась насыщенной. Посетил завод Volkswagen, где увидел работу трёхметровых роборук. Познакомился с особенностями железной дороги в Германии. Остановился в отеле City Journal Hotel в центре города.]]></summary>

					<content type="html" xml:base="https://blog2k.ru/archives/8776"><![CDATA[<p>Вторая командировка в Германию получилась гораздо насыщеннее и интереснее первой.</p>
<p>Суровая немецкая зима встретила нас температурой плюс восемь-десять градусов Цельсия. Хорошо, что я взял с собой тёплые штаны, курточку и сапоги.</p>
<p>Прилетели в Берлин, затем на местном метро доехали из аэропорта до центрального вокзала, купили билеты до Вольфсбурга и побежали на поезд, который отходил через четыре минуты.</p>
<p><img loading="lazy" decoding="async" class="aligncenter size-full wp-image-8790" src="https://blog2k.ru/wp-content/uploads/2020/02/IMG_20200123_155722-scaled.jpg" alt="Центральный вокзал Берлина" width="2048" height="1536" srcset="https://blog2k.ru/wp-content/uploads/2020/02/IMG_20200123_155722-scaled.jpg 1024w, https://blog2k.ru/wp-content/uploads/2020/02/IMG_20200123_155722-300x225.jpg 300w, https://blog2k.ru/wp-content/uploads/2020/02/IMG_20200123_155722-768x576.jpg 768w, https://blog2k.ru/wp-content/uploads/2020/02/IMG_20200123_155722-1536x1152.jpg 1536w, https://blog2k.ru/wp-content/uploads/2020/02/IMG_20200123_155722-2048x1536.jpg 2048w" sizes="auto, (max-width: 2048px) 100vw, 2048px" /></p>
<p>Поезд из Берлина до Вольфсбурга несётся со скоростью 250 километров в час, поэтому поездка занимает около часа. В прошлый раз ездили это же расстояние на машине, потратили гораздо больше времени, даже учитывая то, что на местных хайвеях иногда не было ограничения вообще.</p>
<p><span id="more-8776"></span>В поезде есть два типа мест: забронированные заранее и обычные. Мы, конечно, по незнанию, сели на чьи-то забронированные места возле окошка. Через пару остановок зашла тётенька и попросила нас <del>дохлёбывать и уёбывать</del> освободить места.</p>
<p>Поселились в отеле City Journal Hotel. Я не сильно разбираюсь в отелях, но мне понравилось. Место в центре города, недалеко находится улочка с барами. Нормальный завтрак: булочка, колбаса, сыр, масло, яйца, йогурт, кофе, сок &#8212; а чего ещё надо с ранья? До работы пешком минут пятнадцать всего.</p>
<p><img loading="lazy" decoding="async" class="aligncenter size-full wp-image-8787" src="https://blog2k.ru/wp-content/uploads/2020/02/IMG_20200119_100651-scaled.jpg" alt="Гостиница &quot;City Hotel Journal&quot;" width="2048" height="1536" srcset="https://blog2k.ru/wp-content/uploads/2020/02/IMG_20200119_100651-scaled.jpg 1024w, https://blog2k.ru/wp-content/uploads/2020/02/IMG_20200119_100651-300x225.jpg 300w, https://blog2k.ru/wp-content/uploads/2020/02/IMG_20200119_100651-768x576.jpg 768w, https://blog2k.ru/wp-content/uploads/2020/02/IMG_20200119_100651-1536x1152.jpg 1536w, https://blog2k.ru/wp-content/uploads/2020/02/IMG_20200119_100651-2048x1536.jpg 2048w" sizes="auto, (max-width: 2048px) 100vw, 2048px" /></p>
<p>Работали на заводе Volkswagen, что мы там делали &#8212; не скажу, секрет. Могу лишь сказать, что наши пропуска были с максимальным уровнем доступа и то, чем мы там занимались было бы ОЧЕНЬ интересно любому человеку.</p>
<p><img loading="lazy" decoding="async" class="aligncenter size-full wp-image-8786" src="https://blog2k.ru/wp-content/uploads/2020/02/IMG_20200112_125625-scaled.jpg" alt="Завод VW" width="2048" height="1536" srcset="https://blog2k.ru/wp-content/uploads/2020/02/IMG_20200112_125625-scaled.jpg 1024w, https://blog2k.ru/wp-content/uploads/2020/02/IMG_20200112_125625-300x225.jpg 300w, https://blog2k.ru/wp-content/uploads/2020/02/IMG_20200112_125625-768x576.jpg 768w, https://blog2k.ru/wp-content/uploads/2020/02/IMG_20200112_125625-1536x1152.jpg 1536w, https://blog2k.ru/wp-content/uploads/2020/02/IMG_20200112_125625-2048x1536.jpg 2048w" sizes="auto, (max-width: 2048px) 100vw, 2048px" /></p>
<p>Завод настолько большой, что по нему хотят три типа автобусов: Golf Line, Tiguan Line и Tuareg Line. На второй день мы сели не в тот автобус и он нас отвёз в неизведанные дали. До выхода пришлось идти минут двадцать по тёмным улочкам. Зато мы видели, как работают трёхметровые роборуки. Они собирали очередную машину на конвейере. Выглядит фантастично, звуки прямо из Звездных Войн. Там где джедаи, Йода и, мать его, император Палпатин. Зрелище того, как одна рука хватает деталь, а другая приваривает эту деталь к машине &#8212; незабываемо.</p>
<p><img loading="lazy" decoding="async" class="aligncenter size-full wp-image-8791" src="https://blog2k.ru/wp-content/uploads/2020/02/IMG_20200221_093646.jpg" alt="Завод VW" width="1607" height="1607" srcset="https://blog2k.ru/wp-content/uploads/2020/02/IMG_20200221_093646.jpg 1024w, https://blog2k.ru/wp-content/uploads/2020/02/IMG_20200221_093646-300x300.jpg 300w, https://blog2k.ru/wp-content/uploads/2020/02/IMG_20200221_093646-150x150.jpg 150w, https://blog2k.ru/wp-content/uploads/2020/02/IMG_20200221_093646-768x768.jpg 768w, https://blog2k.ru/wp-content/uploads/2020/02/IMG_20200221_093646-1536x1536.jpg 1536w" sizes="auto, (max-width: 1607px) 100vw, 1607px" /></p>
<p>Всю командировку было очень жаль, что фотографировать запрещено, а обе камеры заклеены стикером. Поверьте, там есть на что посмотреть.</p>
<p>Кстати, очень странно, что на заводе в стране, которая заботится об экологии и вторичной переработке, в туалете бумажные полотенца, которые заканчиваются к середине дня и все пользуются туалетной бумагой для вытирания рук. Одна-две электрические сушилки для рук сэкономили бы кучу бумаги.</p>
<p>На третий день ходили с корейскими коллегами потреблять суши в китайский ресторанчик. Корейцы рассказали, что они начиная с детского сада, учатся есть палочками, поэтому палочки для них самый привычный столовый прибор. Ну мы с коллегой покушали палочками кое-как, я даже доел все рисинки с помощью палочек, корейцы одобрительно охали и ахали от мастерства. Потом я взял палочки в другую руку и проделал тоже самое с рисинками. А из двух корейцев повторить за мной смог только один. Так что, корейский товарищ, будь бдителен, когда выделываешься с помощью одной руки, возможно перед тобой сидит амбидекстр, йопт.</p>
<p>Перед командировкой, сразу после Нового Года, седьмого января посетил стоматолога, где мне неудачно поставили больнющий укол с анестезией в щеку и у меня перестала работать <del>лучшая</del> правая половина языка. С нерабочей половиной языка &#8212; открою секрет &#8212; очень сложно дотянуться языком до кончика носа, а я ведь, по сути, больше ничего и не умею. А ещё моя и так херовая дикция упала до полного нуля. Но на уроке английского учитель не заметила изменений, когда я рассказал про этот случай на чистейшем американском английском языке (привет, Джесс!). Рассказал, короче, про свой язык на другом языке носителю языка. Вот такой я молодец!</p>
<p>И минутка полезной информации про поезда и железную дорогу в Германии.</p>
<p>Билеты покупают в автоматах. Билет из аэропорта Шонефёльд до центрального вокзала стоит примерно 3.6€, его надо пробить перед посадкой в поезд в автомате на платформе или по пути к поезду. На междугородних поездах билеты приобретаются в таких же автоматах и на эти поезда можно забронировать сидячее место с номером за 4€. Если доступных мест нет и автомат отказывает вам в резервировании, то проходим в вагон своего класса и садимся на места с надписью frei-что-то-там. Если на табло над местом другая надпись, значит оно зарезервировано и вас могут прогнать в любой момент. Пробивать билеты на междугородние поезда не надо, это сделает контролёр. Во внутригородских поездах, если вы не пробили билет, придётся заплатить штраф контролёру.</p>
<p><img loading="lazy" decoding="async" class="aligncenter size-full wp-image-8788" src="https://blog2k.ru/wp-content/uploads/2020/02/IMG_20200119_114107-scaled.jpg" alt="Работа контролёра" width="2048" height="1536" srcset="https://blog2k.ru/wp-content/uploads/2020/02/IMG_20200119_114107-scaled.jpg 1024w, https://blog2k.ru/wp-content/uploads/2020/02/IMG_20200119_114107-300x225.jpg 300w, https://blog2k.ru/wp-content/uploads/2020/02/IMG_20200119_114107-768x576.jpg 768w, https://blog2k.ru/wp-content/uploads/2020/02/IMG_20200119_114107-1536x1152.jpg 1536w, https://blog2k.ru/wp-content/uploads/2020/02/IMG_20200119_114107-2048x1536.jpg 2048w" sizes="auto, (max-width: 2048px) 100vw, 2048px" /></p>
<p>Будьте внимательны, лучше спросите у дежурного на вокзале &#8212; надо пробивать билет или нет. Заодно он подскажет вам &#8212; в какую часть поезда садиться. Билет из Берлина в Вольфсбург стоит 44€, поезд едет со скоростью 250 километров в час, но это совершенно незаметно.</p>
<p>Поезда могут состоят из двух составов: один состав идёт на центральный вокзал Берлина, второй <del>захватывать Польшу</del> на восточный вокзал. Обычно на платформе на электронном табло есть пояснения за 5-10 минут до прибытия поезда &#8212; в какую часть садиться.</p>
<p>P.S. Внезапно обнаружил, что мой блог недоступен с публичного WiFi вокзала в Вольфсбурге, потому что он нарушает &#171;правила защиты несовершеннолетних&#187;. Что могу сказать на эту тему: не пускайте несовершеннолетних в Интернет, Интернет от них тупеет!</p>
]]></content>
		
					<link rel="replies" type="text/html" href="https://blog2k.ru/archives/8776#comments" thr:count="4" />
			<link rel="replies" type="application/atom+xml" href="https://blog2k.ru/archives/8776/feed/atom" thr:count="4" />
			<thr:total>4</thr:total>
			</entry>
		<entry>
		<author>
			<name>eJ</name>
					</author>

		<title type="html"><![CDATA[Командировка в Германию, город Вольфсбург]]></title>
		<link rel="alternate" type="text/html" href="https://blog2k.ru/archives/8633" />

		<id>https://blog2k.ru/?p=8633</id>
		<updated>2025-10-22T12:40:01Z</updated>
		<published>2019-10-06T15:18:18Z</published>
		<category scheme="https://blog2k.ru" term="Германия" /><category scheme="https://blog2k.ru" term="Путешествия" /><category scheme="https://blog2k.ru" term="командировка" />
		<summary type="html"><![CDATA[В статье в юмористическом ключе описывается командировка на секретный завод в Германии. Автор рассказывает о забавных ситуациях, связанных с работой и несерьёзным отношением к некоторым корпоративным правилам.]]></summary>

					<content type="html" xml:base="https://blog2k.ru/archives/8633"><![CDATA[<p>Ничего не хотел писать про командировку в Германию, потому что не хотел.</p>
<p>Ну Германия, ну завод секретный, ну роботы-убийцы, ну космический корабль, ну антигравитация, ну кому это интересно? Скукота, ничего нового.</p>
<p>Животные-мутанты периодически вырываются из клеток, тогда приходится барикадировать двери с помощью шкафа и пережидать, пока охрана наведёт порядок и ликвидирует нарушителей. Выстрелы и крики немножко мешают работать, но что поделать &#8212; за это платят. Потом надеваешь бронежилет, хватаешь ружьё и идёшь с командой финальной зачистки по коридору. За каждый патрон бухгалтерия снимает два бакса с зарплаты, поэтому стараемся забивать мутантов прикладами.</p>
<p>На самом деле, у нас конечно же всё не так. Получаешь в бухгалтерии билет на Октоберфест, регистрацию в первый класс, денег на девок и немецкое пиво наликом. Плюс, само собой, набор презервативов, потому что не знаю, как у вас, а в нашей фирме главное &#8212; безопасность или security. Пьёшь пиво с девками неделю, пока здоровья хватит, танцуешь немецкие танцы до утра, творишь всяческий харасмент. Если сильно напился, то харасмент творят с тобой. Очень удобно, что ДМС покрывает лечение венерических заболеваний.</p>
<p>А вы знаете, что манекены для краш-тестов стоят по сто тысяч долларов, что более, чем в десять раз превышает цену стандартного россиянина? Так вот, значит, садишься в машину, потом разгоняешься до ста километров в час и в бетонный блок Н-НА! Потом вылезаешь из машины, подбираешь выбитые зубы сломанными руками и такой: &#171;Мужики, бля буду, этой машине максимум три звёзды!&#187;. Так и проходят тесты EuroNCAP, а вы как думали? Манекены-то дорогие, их для картинки берегут и только в рекламе показывают. С первого раза тяжело конечно, но ДМС всё покрывает, бензин, правда, за свои.</p>
<p>Из последних новостей: гражданская версия шагоходов пока откладывается. Всё не могут настроить торсионные поля, которые, как вы наверняка знаете, обеспечивают антигравитацию. Никак не могут подобрать параметры. То портал в потусторонний мир открывается, то аура у пассажиров портится. Ну ничего, парапсихологи разберутся.</p>
<p>Кстати, я получил лицензию пилота-испытателя немецкого производителя автомобилей. Теперь могу разъезжать на машинах-прототипах этой компании <del>с пивом и тёлками</del>. Даже на тех, которые местные рабочие-то не видели. Но со скоростью не более двухсот пятидесяти километров в час. Лицензия пожизненная и лично моя.</p>
<p>Ещё мы видели лисичку, правда не всю сразу. Сначала ушки, потом лапки, потом хвостик и так на протяжении пяти метров шоссе, а потом мы выбирались из перевёрнутой машины и, в целом, весело провели время.</p>
<p>Что из всего написанного правда &#8212; я вам не скажу. Не положено!</p>
<p>P.S. Тут меня спросили: &#171;Надеюсь, про лисичку &#8212; это неправда&#187;. Так вот, уточню: лисичек было две, а если быть совсем точным, то полторы.</p>
]]></content>
		
					<link rel="replies" type="text/html" href="https://blog2k.ru/archives/8633#comments" thr:count="1" />
			<link rel="replies" type="application/atom+xml" href="https://blog2k.ru/archives/8633/feed/atom" thr:count="1" />
			<thr:total>1</thr:total>
			</entry>
		<entry>
		<author>
			<name>eJ</name>
					</author>

		<title type="html"><![CDATA[Про моё первое путешествие в Тунис]]></title>
		<link rel="alternate" type="text/html" href="https://blog2k.ru/archives/8613" />

		<id>https://blog2k.ru/?p=8613</id>
		<updated>2025-12-09T08:53:44Z</updated>
		<published>2019-10-03T03:24:22Z</published>
		<category scheme="https://blog2k.ru" term="Путешествия" /><category scheme="https://blog2k.ru" term="Тунис" /><category scheme="https://blog2k.ru" term="отпуск" />
		<summary type="html"><![CDATA[Автор рассказывает о своём путешествии в Тунис, делится впечатлениями от перелёта, описывает свои наблюдения в аэропорту и в отеле, а также рассказывает о поездке в Сахару и другие города.]]></summary>

					<content type="html" xml:base="https://blog2k.ru/archives/8613"><![CDATA[<p>Вы видали какой Боинг 747-400 здоровенный? 180, сука, тонн &#8212; это десять трамвайных вагонов. Как он вообще взлетает &#8212; мне лично непонятно. Вентиляторы у него огромные, в каждый с лёгкостью может человек  уместиться, или дама с коляской, или бабка с ходунками, вентиляторов ажно четыре штуки. Но статья вообще не про это, а про путешествие в Тунис в сентябре, а всё, что сверху написано &#8212; это вступление.</p>
<p><img loading="lazy" decoding="async" src="https://blog2k.ru/wp-content/uploads/2019/10/IMG_20190912_170911.jpg" alt="Боинг 747-400" width="2048" height="1536" class="aligncenter size-full wp-image-8619" srcset="https://blog2k.ru/wp-content/uploads/2019/10/IMG_20190912_170911.jpg 1024w, https://blog2k.ru/wp-content/uploads/2019/10/IMG_20190912_170911-300x225.jpg 300w, https://blog2k.ru/wp-content/uploads/2019/10/IMG_20190912_170911-768x576.jpg 768w" sizes="auto, (max-width: 2048px) 100vw, 2048px" /></p>
<p>В самолёте мне досталось место у окошка слева, грудничок справа, а спереди &#8212; мальчик, который прыгал на сиденье. Так что первое, что я ощутил после посадки &#8212; это <del>четыреждыблядская ярость</del> лёгкий дискомфорт. Но в процессе полёта мы мимо поулыбались с <del>симпатичной молодой мамой</del> карапузом, наладили контакт и полёт прошёл достаточно комфортно, а ещё я почти выучил песню &#171;Едет трактор&#187; и угадал всех зверушек! Кто молодец? Я &#8212; молодец!</p>
<div class="sllv-video -type_youtube" data-provider="youtube" data-video="tPiagp9t5is"><a class="sllv-video__link" href="https://youtu.be/tPiagp9t5is" rel="external noopener" target="_blank"><img decoding="async" class="sllv-video__media" src="https://i.ytimg.com/vi_webp/tPiagp9t5is/sddefault.webp" alt="Видео"></a><button class="sllv-video__button" type="button" aria-label="Воспроизвести видео"><svg width="68" height="48" viewBox="0 0 68 48"><path class="sllv-video__button-shape" d="M66.52 7.74c-.78-2.93-2.49-5.41-5.42-6.19C55.79.13 34 0 34 0S12.21.13 6.9 1.55c-2.93.78-4.63 3.26-5.42 6.19C.06 13.05 0 24 0 24s.06 10.95 1.48 16.26c.78 2.93 2.49 5.41 5.42 6.19C12.21 47.87 34 48 34 48s21.79-.13 27.1-1.55c2.93-.78 4.64-3.26 5.42-6.19C67.94 34.95 68 24 68 24s-.06-10.95-1.48-16.26z"/><path class="sllv-video__button-icon" d="M45 24L27 14v20"/></svg></button></div>
<p><span id="more-8613"></span>При подлёте к Тунису  всем выдали иммиграционные карточки, где русские надписи были любезно предоставлены переводчиком от гугла. Как зовут, где живёте <del>доверяете ли Путину</del>, национальность, место жительства в Тунисе, профессия (написал &#171;Programmer&#187;, чтобы не выделываться, а так-то я &#171;Senior Research Engineer&#187; это вам не в тапки срать) и так далее.</p>
<p>После посадки ожидаемо возникла бесконечная очередь в количестве трёх штук, а одна тётка на пару со своей подругой хабалистого вида устроила локальный приступ паники по поводу иммиграционной карточки. &#171;А что это за бумажки люди заполняют, а почему они белого цвета, наверно они неправильно заполнены, бла-бла-бла&#187;, &#8212; как же я не люблю глупых людей и особенно громких глупых людей.</p>
<p>Сдаётся мне, та тётка ехала в переноске в багажном отделении, поэтому карточка ей не досталась. Надеюсь, в её переноске было достаточно сухого корма из пакета с надписью &#171;питание для хабалистых тёток&#187; и поилка, потому что я, например, чувствовал жажду на протяжении всего полёта после бутылки пива, принятого в аэропорту.</p>
<p>И раз уж зашла речь об уродцах, то у меня вопрос: &#171;Что заставляет вас прижиматься  вплотную к впереди стоящему человеку в очереди?&#187;. Я, конечно, понимаю, что я относительно симпатичный парень (относительно мешка картошки, например) и могу выдать вам немного тепла человеческого общения, но не хочу. Не надо так! Фу-фу-фу!</p>
<p>Кстати, в Пулково в Duty Free есть уголок, где можно покурить хипстерский IQOS, чем я и воспользовался. В Туниском аэропорту такого уголка нет, поэтому я покурил прямо возле бумажки с иностранной надписью красными буквами NO SMOKING. Как она переводится &#8212; я не знаю, я российский турист ващет, отвалите. Но в зону обзора камеры с дымящим фломастером старался не попадать.</p>
<p>В отделе выдачи багажа тоже была лёгкая паника у народа, потому что лента, выдав с десяток чемоданов, внезапно остановилась. Сразу же возникли идеи в толпе, что всё поломалось, праздника не будет, чо делать, чо делать и так далее. Людям невдомёк, что чемоданы возят маленькие машинки, загрузить 500 чемоданов и привезти одновременно физически невозможно, но я на всякий случай пошукал свой чемодан на других лентах. Вдруг он из Чехии прилетел или Киева. Или чемодан получше найду, а то мой старенький уже совсем, забит какими-то беспонтовыми футболками и самое дорогое, что в нём можно найти &#8212; электрическая зубная щётка да сто баксов, зашитых в подкладку трусов.</p>
<p>А вы в курсе, что незадолго до вылета может начаться распродажа билетов в бизнес-класс по дешёвке? Мне предлагали за 40 баксов увеличить уровень с эконом до бизнеса, но я не успел &#8212; сразу всё разобрали, буквально в течение 20-ти минут. Имейте ввиду.</p>
<p>По приезду в отель оказалось, что традиционно любимых мной туров на яхте толком и нет. Есть только катамаран, но он выпадал как раз на день моего отлёта.</p>
<p><img loading="lazy" decoding="async" src="https://blog2k.ru/wp-content/uploads/2019/10/IMG_20190913_132527_606.jpg" alt="Тунис, Хаммамет, отель &quot;Laico&quot;" width="2048" height="2048" class="aligncenter size-full wp-image-8626" srcset="https://blog2k.ru/wp-content/uploads/2019/10/IMG_20190913_132527_606.jpg 1024w, https://blog2k.ru/wp-content/uploads/2019/10/IMG_20190913_132527_606-150x150.jpg 150w, https://blog2k.ru/wp-content/uploads/2019/10/IMG_20190913_132527_606-300x300.jpg 300w, https://blog2k.ru/wp-content/uploads/2019/10/IMG_20190913_132527_606-768x768.jpg 768w" sizes="auto, (max-width: 2048px) 100vw, 2048px" /></p>
<p>Так что взял тур на два дня в Сахару на субботу-воскресенье, поездку в три столицы в среду и поездку хер-знает-куда во вторник. Поездку хер-знает-куда специально брать не хотел, но когда турагент рассказывал про поездку хер-знает-куда, одна девушка воскликнула: &#171;Ну, блин! Я не хочу туда одна ехать&#187; на что я не растерялся и сказал: &#171;Ну давай я с тобой поеду&#187;. И заказал поездку хер-знает-куда с этой девушкой заодно (привет, Катя!).</p>
<p><img loading="lazy" decoding="async" src="https://blog2k.ru/wp-content/uploads/2019/10/IMG_20190917_144009.jpg" alt="Тунис, Сиди Бу Саид" width="2048" height="1536" class="aligncenter size-full wp-image-8628" srcset="https://blog2k.ru/wp-content/uploads/2019/10/IMG_20190917_144009.jpg 1024w, https://blog2k.ru/wp-content/uploads/2019/10/IMG_20190917_144009-300x225.jpg 300w, https://blog2k.ru/wp-content/uploads/2019/10/IMG_20190917_144009-768x576.jpg 768w" sizes="auto, (max-width: 2048px) 100vw, 2048px" /></p>
<p>Поездка в Сахару начинается в пять сорок утра, с собой взял четыре с половиной литра воды, крем от загара, плавки, шмот разный, кепочку и очки. Тунис почти такой же, как Турция, только мусора больше. Шесть часов поездки мы все вместе наблюдали из автобуса свалку на обочине. До революции в Тунисе было специальное министерство по охране природы и экологии, которое следило за мусором, как рассказал гид. Как только министерство упразднили, народ сразу же начал гадить прямо под себя на обочину, на дорогу, в пустыне &#8212;  везде, где есть природа-мать. Сейчас в Тунисе начала работать полиция экологии или что-то в этом духе, кучу народа уже оштрафовали, некоторых даже вроде немножко посадили за мусор. Так что, в теории, через пару лет Тунис должен засиять первозданной чистотой. Посмотрим&#8230;</p>
<p>Заезжали в магазин берберских ковров. Самое забавное, что услышал: &#171;Вот на этом ковре берберы делают физические упражнения, а потом через девять месяцев появляется маленький бербер&#187;. Внезапно, захотелось этот ковёр купить, но потом вспомнил, что за берберами женского пола надо ехать в Тунис, платить нехилый калым, и резко передумал.</p>
<p>В первый день автобусная поездка заканчивается в зоопарке, который расположен в оазисе посреди пустыни. Самая забавная зверушка в зоопарке &#8212; маленькая лисичка с большими ушками &#8212; фенёк. Некоторые держат этих лисичек вместо домашних животных. В зоопарке животных разводят, а потом отпускают в природу для увеличения популяции. Так нам сказал гид. Что примечательно &#8212; также разводят и выпускают скорпионов, гадюк, варанов и саламандр. Местный эксурсовод показывал скорпиона живьём и как надо правильно его держать за хвостик с жалом. Я отошёл метров на сорок и мне зверушка сразу понравилась. Жаль, что смертельно ядовита, отвратительна на вид, имеет клешни, много-много мерзких лапок и хвостик с жалом. Б-р-р!</p>
<p>После зоопарка мы расселись по джипам и нас повезли в пустыню. Джипы полноприводные, умеют взбираться по практически отвесной стене и так же вертикально съезжать вниз. Женский пол в машине в количестве четырёх особей визжал так, что уши закладывало, а мы с водителем только друг с дружкой хихикали от этого гомона. По правде говоря, у меня тоже пару раз душа уходила в пятки, особенно, когда с бархана вниз съезжали, но виду не показывал &#8212; не положено! По пути в пустыне встретили французскую экспедицию пенсионеров на машинах такого же возраста. Как они смогли туда доехать &#8212; непонятно, я на своей машине скорее всего в песках встрял бы навсегда. В пустыне заехали в место, где снимали эпизод Starwars. Несложно представить, что планета Татуин выглядит именно так: с домиками из песка с полукруглым входом и вокруг одни песчаные дюны. Джордж Лукас несомненно очень талантливый режиссёр. Он ведь как-то нашёл это место в Тунисе, представил как всё это будет выглядеть, нарисовал декорации, выставил свет, мотор, камера и ты на другой планете. Кстати, Татавин &#8212; это древнее берберское женское имя.</p>
<p><img loading="lazy" decoding="async" src="https://blog2k.ru/wp-content/uploads/2019/10/IMG_20190914_164207.jpg" alt="" width="2048" height="1536" class="aligncenter size-full wp-image-8638" srcset="https://blog2k.ru/wp-content/uploads/2019/10/IMG_20190914_164207.jpg 1024w, https://blog2k.ru/wp-content/uploads/2019/10/IMG_20190914_164207-300x225.jpg 300w, https://blog2k.ru/wp-content/uploads/2019/10/IMG_20190914_164207-768x576.jpg 768w" sizes="auto, (max-width: 2048px) 100vw, 2048px" /></p>
<p>Вечером нас привезли в отель в город Тузор для ночёвки и ужина. А ещё можно было искупнуться в бассейне. Интересно, что заселяют в отель парами и тройками, если ты один (плак, плак), то гони двадцать туниских динар или проваливай искать себе пару в ночи.</p>
<p>Подъём в четыре часа утра, затем завтрак и выезд из отеля в пять к чёрту на кулички &#8212; встречать рассвет, который по местным традициям наступает в 6:10 утра. Поскольку погода была довольно пасмурной я было подумал, что рассвет перенесли по техническим причинам на попозже (у меня ж всё включено, я ж российский турист), но нет. Солнышко появилось точно по графику. Фотографий не делал, хотел насладиться моментом своими глазами. Ну, вы знаете &#8212; огромная жёлтая штука поднимается из-за горизонта, а ты несёшься на своей <del>сраной</del> планете вокруг звёзды спектрального класса G2V. У нас в Питере она такая же, только поменьше. В пустыне, между прочим, утром довольно прохладно. Наверно, двадцать четыре градуса. Одевайтесь теплее, если что.</p>
<p>После встречи восхода всех отвезли кататься на верблюдах. У верблюда привод на все четыре копыта, комфортная сидушка, кривые зубы и длинные ноги. Пока сидит на земле этот славный малый довольно хилый на вид. Но когда он поднимается вместе с тобой на три метра вверх, мнение сразу меняется. Во время поездки в голове почему-то вертелась фраза &#171;Олень на верблюде&#187;. С собой у верблюда запас воды, шерсти и вкусного мяса. Если внезапно соберётесь в пустыню, берите с собой верблюда, а лучше двух. Ещё за сорок пять динар можно прокатиться на квадроцикле по пустыне, но поесть песка и подышать выхлопными газами за свои деньги не очень хотелось, поэтому квадроцикл брать не стал. Ограничился верблюдом. Верблюд экологически чистый транспорт, так что вот.</p>
<p><img loading="lazy" decoding="async" src="https://blog2k.ru/wp-content/uploads/2019/10/IMG_20190915_082402.jpg" alt="Тунис, Сахара, красота" width="2048" height="1536" class="aligncenter size-full wp-image-8631" srcset="https://blog2k.ru/wp-content/uploads/2019/10/IMG_20190915_082402.jpg 1024w, https://blog2k.ru/wp-content/uploads/2019/10/IMG_20190915_082402-300x225.jpg 300w, https://blog2k.ru/wp-content/uploads/2019/10/IMG_20190915_082402-768x576.jpg 768w" sizes="auto, (max-width: 2048px) 100vw, 2048px" /></p>
<p>В Тунисе светофоры есть только в столице, движение довольно хаотичное, но в основном правостороннее. Забавно, что при виде местного поста полиции, водители торопливо начинают пристёгиваться ремнём безопасности и сбавлять скорость. В общем, ездят практически, как в нашем захолустье, только безопаснее, потому что никто не гоняет, как в последний раз, всё относительно медленно и неторопливо. Хотя южный народ на мой взгляд мог бы быть поактивнее за рулём.</p>
<p>После верблюдов посетили дом берберов, который вырублен в скале. Правительство предложило берберам нормальные дома со всеми коммуникациями, некоторые согласились и переехали, а некоторые остались жить в горах, пускают туристов во внутренний двор, угощают лепёшкой с мёдом и стригут купоны. Между прочим, однокомнатная квартира в Туниса &#8212; это минимум 70 квадратных метров.</p>
<p>Минутка бесполезной информации: школьное образование в Тунисе обязательно. Если ребенок не ходит в школу, родителям светит штраф и даже турма! Дело в том, что до 1957 года, пока Тунис был в мягких лапках Франции, образования для местных не было, 98 процентов населения было без образования. Славься, Франция и всё такое (на самом деле &#8212; нет). Тунис, как говорят местные жители, не является до сих пор полностью свободной и независимой. Природные ресурсы добываются в основном Францией.</p>
<p>Из поездки в Сахару вернулся уставший, но довольный. Как раз успел к ужину. Занятно, что в Сахаре даже толком не загорел, хотя солнцезащитным кремом не пользовался. Следующий день прошёл в тумане. Во вторник съездили в Карфаген,  развалины римских бань и сине-белый город.</p>
<p>Рассказать о чём-то, кроме пустыни особо и нечего. Развалины не очень люблю, люблю купаться в море с яхты, но в этот раз не получилось.</p>
<p>Ну ничего, получится в следующий раз.</p>
<p>Ещё в Тунисе производят компоненты для французской косметики, поэтому часто на улице пристают продавцы с вопросом &#8212; сколько это у вас в России стоит, бери брат, почти что из Франции. А я косметикой как-то не очень увлекаюсь. Но вы можете прикупить в аптеке масло орегано, женщины мажут им лицо, тело, волосы и ногти. Зачем &#8212; не знаю. Есть его нельзя. Главное пятки не мазать, а то можно на кафеле в ванной подскользнуться и уехать куда-нибудь вдаль.</p>
<p>Напоследок диалог между мной и Катей в автобусе:<br />
&#8212; А ты заметил, какие мотоциклы у них тощие?<br />
&#8212; Конечно заметил. Это ж мопед!</p>
<p>И анекдот, рассказанный гидом, куда ж без него:</p>
<p>Два ливийца в Тунисе вечером хотят закурить, а спичек нет. Один другого посылает к дороге &#8212; останови машину и попроси спички. Тот останавливает машину и просит спички, а ему в ответ: &#171;Извини, брат, спичек нет, есть зажигалка&#187;. Ливиец отпускает водителя и возвращается обратно к первому. &#171;Спичек, &#8212; говорит, &#8212; не было, была зажигалка&#187;. Первый отвечает: &#171;Вернись к дороге, останови машину и попроси зажигалку&#187;. Ливиец опять возвращается к дороге, тормозит машину, а ему говорят: &#171;Извини, брат, зажигалки нет, есть спички&#187;. Ливиец снова отпускает машину и возвращается обратно ни с чем. Первый ливиец говорит: &#171;Ладно, не получится сегодня покурить, гаси свечку и давай спать&#187;.</p>
]]></content>
		
					<link rel="replies" type="text/html" href="https://blog2k.ru/archives/8613#comments" thr:count="1" />
			<link rel="replies" type="application/atom+xml" href="https://blog2k.ru/archives/8613/feed/atom" thr:count="1" />
			<thr:total>1</thr:total>
			</entry>
		<entry>
		<author>
			<name>eJ</name>
					</author>

		<title type="html"><![CDATA[A-A-Arduino Uno и базовый набор]]></title>
		<link rel="alternate" type="text/html" href="https://blog2k.ru/archives/8371" />

		<id>https://blog2k.ru/?p=8371</id>
		<updated>2026-03-22T09:49:00Z</updated>
		<published>2018-11-25T08:04:50Z</published>
		<category scheme="https://blog2k.ru" term="Хобби" /><category scheme="https://blog2k.ru" term="Электроника" /><category scheme="https://blog2k.ru" term="arduino" />
		<summary type="html"><![CDATA[Arduino — программируемый контроллер, который позволяет соединить опыт программирования с железом. Купил базовый набор для обучения и уже экспериментирую с платой Arduino Uno. Плата работает с частотой 16MHz, имеет цифровые и аналоговые разъёмы, поддерживает ШИМ сигнал. Программируется через USB заливкой прошивки с помощью Arduino IDE. Функционал Arduino бесконечен благодаря внешним платам.]]></summary>

					<content type="html" xml:base="https://blog2k.ru/archives/8371"><![CDATA[<p>Уже лет десять периодически слышу про Arduino и Raspberry Pi. Первое &#8212; программируемый контроллер, второе &#8212; мини-компьютер с ОС Linux.</p>
<p>И, если мини-компьютер мне совершенно не интересен, поскольку с компьютерами общаюсь уже лет двадцать, то контроллер очень даже интересная штука. Запах канифоли, нагретый паяльник <strike>связанный должник</strike>, припой ПОС-61 &#8212; вот это всё будоражит воображение и радует глаз. Плюс к этому контроллер Arduino программируемый на некоем подобии C++.</p>
<p>С детства мечтал соединить опыт программирования с железом. Последнее и единственное, что сотворил такого рода &#8212; коробка с двумя кнопками, которая подключалась к COM порту компьютера, где специальная программа отслеживала нажатия кнопок и выполняла некоторый функционал: включала немедленный автодозвон до BBS, отключала/включала модем. Славные были деньки в коммуналке, мать их.</p>
<p><img loading="lazy" decoding="async" src="https://blog2k.ru/wp-content/uploads/2018/11/img_20181124_113735-423955259.jpg" alt="Arduino Uno + Базовый набор" width="2250" height="3000" class="aligncenter size-full wp-image-8388" srcset="https://blog2k.ru/wp-content/uploads/2018/11/img_20181124_113735-423955259.jpg 768w, https://blog2k.ru/wp-content/uploads/2018/11/img_20181124_113735-423955259-225x300.jpg 225w" sizes="auto, (max-width: 2250px) 100vw, 2250px" /></p>
<p>Так что, насмотревшись в интернете разных уроков по Arduino, купил базовый набор для обучения.</p>
<p><span id="more-8371"></span>В набор входят:</p>
<ul>
<li>резисторы 10 кОм</li>
<li>резисторы 220 Ом</li>
<li>потенциометр (по-нашему, крутилка)</li>
<li>фоторезистор (определяет освещенность)</li>
<li>датчик температуры</li>
<li>светодиоды синие, красные и зелёные</li>
<li>светодиод RGB (может светиться любым цветом)</li>
<li>кнопочки</li>
<li>проводочки всякие</li>
<li>макетная плата (для пробы своих задумок перед пайкой)</li>
<li>плата Arduino Uno с проводом USB для подключения к компьютеру</li>
<li>книга с экспериментами для самых маленьких (7 экспериментов), как я</li>
<li>книга с основами и экспериментами для детей постарше</li>
</ul>
<p><img loading="lazy" decoding="async" src="https://blog2k.ru/wp-content/uploads/2018/11/img_20181126_075339_391700709470.jpg" alt="Arduino Uno + Базовый набор" width="1332" height="1226" class="aligncenter size-full wp-image-8390" srcset="https://blog2k.ru/wp-content/uploads/2018/11/img_20181126_075339_391700709470.jpg 1024w, https://blog2k.ru/wp-content/uploads/2018/11/img_20181126_075339_391700709470-300x276.jpg 300w, https://blog2k.ru/wp-content/uploads/2018/11/img_20181126_075339_391700709470-768x707.jpg 768w" sizes="auto, (max-width: 1332px) 100vw, 1332px" /></p>
<p>Плата работает с частотой 16MHz и это охренительно круто! С такой скоростью мне работать ещё не приходилось. Каких-то жалких 16 миллионов операций в секунду, оперативная память в 2048 байт, медленная работа с плавающей запятой, тормозные тригонометрические функции &#8212; это прекрасно, если вы понимаете о чём я.</p>
<p>Если не понимаете, то ваш мобильник, к примеру, работает с частотой около двух миллиардов операций в секунду на четырёх ядрах с поддержкой быстрой работы с плавающей запятой и оперативной памятью в 32 миллиарда байт. Даже не зная математики, можно почувствовать разницу. И вы используете эту мощь, чтобы в Инстаграм улыбальник фильтрами поправлять. Человечество стремительно тупеет.</p>
<p>Сама по себе плата умеет немного: принимать напряжение 5 вольт, выдавать это напряжение и, в принципе, всё. Выдавать напряжение может в цифровом виде: нет напряжения, есть напряжение и в аналоговом: выдать напряжение от нуля до пяти вольт. Читать умеет тоже в цифровом и аналоговом виде.</p>
<p>Цифровых разъёмов 13 штук, аналоговых 6 штук. Плюс разъёмы питания 3.3 и 5 вольт и земля GND.</p>
<p>Казалось бы &#8212; ерунда, а нет! На некоторых разъёмах плата умеет выдавать ШИМ сигнал. Это скачки цифрового сигнала много-много раз в секунду. Этим сигналом управляются двигатели, насколько я понял. Ещё можно динамик подключить и пиликать в него.</p>
<p>Энтузиасты сотворили мини-игровую консоль с экраном, называется Arduboy.</p>
<p>В общем, полёт фантазии не ограничен.</p>
<p>Мой полёт пока остановился на мигании RGB светодиодом и это отлично хотя бы потому, что я не спалил плату, как однажды спалил жёсткий диск, подключив питание вверх ногами, хотя разъем специально сделан такой формы, чтобы нельзя воткнуть его иначе. Но хитрость, сила и глупость всегда побеждают в борьбе с разумом и интеллектом.</p>
<p><img loading="lazy" decoding="async" src="https://blog2k.ru/wp-content/uploads/2018/11/img_20181124_213313715848345.jpg" alt="Arduino Uno, макетная плата, RGB светодиод" width="3000" height="2250" class="aligncenter size-full wp-image-8387" srcset="https://blog2k.ru/wp-content/uploads/2018/11/img_20181124_213313715848345.jpg 1024w, https://blog2k.ru/wp-content/uploads/2018/11/img_20181124_213313715848345-300x225.jpg 300w, https://blog2k.ru/wp-content/uploads/2018/11/img_20181124_213313715848345-768x576.jpg 768w" sizes="auto, (max-width: 3000px) 100vw, 3000px" /></p>
<p>Пока не понял &#8212; зачем повсюду втыкать резисторы: для кнопки и светодиода, но со временем до меня дойдёт.</p>
<p>Зато понял, что цифровые порты без значка тильды &#171;~&#187; не поддерживают команду <code class="" data-line="">analogWrite()</code>, как положено.</p>
<p>Кстати, сразу вопрос: почему все порты не сделаны, как цифровые с поддержкой <code class="" data-line="">analogRead()</code> и <code class="" data-line="">analogWrite()</code>? Это сильно упростило бы работу с платой на мой непрофессиональный взгляд.</p>
<p>Плата может брать питание из трёх мест: по разъёму USB, с отдельного входа, с двух штырьков. Подключать все три входа одновременно, наверно, плохая идея.</p>
<p>Программируется через USB заливкой прошивки с помощью Arduino IDE.</p>
<p>Прошивка содержит две функции:</p>
<ul>
<li><code class="" data-line="">setup()</code> выполняется один раз при включении платы или после reset</li>
<li><code class="" data-line="">loop()</code> бесконечный цикл во время работы</li>
</ul>
<p>В первой функции устанавливаем режим работы пинов: вход или выход, вешаем прерывания, открываем порт для отладки, во второй читаем данные и пишем.</p>
<p>Отдельно хочу обратить внимание на прерывания: они позволяют задействовать режим энергосбережения, что полезно при работе от батареек. Прерывание срабатывает по определённым событиям: появился сигнал, исчез сигнал. При наступлении этого события происходит вызов вашей функции, а выполнение <code class="" data-line="">loop()</code> приостанавливается. В режиме энергосбережения плата может прожить шесть лет на батарейках без учёта саморазряда.</p>
<p>Эту информацию и всё вышенаписанное я подчерпнул с <a href="https://www.youtube.com/channel/UC4axiS76D784-ofoTdo5zOA" rel="nofollow" target="_blank">канала AlexGyver</a>, за что ему огромное спасибо! Чувак, мой тебе респект, ты молодец, я теперь твой фанат.</p>
<p>А ещё я потрогал резистор щупом мультиметра и обнаружил сопротивление в 220 Ом, как и ожидалось. Здорово, правда?</p>
<p>Функционал Arduino бесконечный, потому что она управляющая, а остальное делают различные внешние платы, например, реле, которое может управлять контактом, через который проходит 220 Вольт. По сигналу с Arduino реле замыкает или размыкает эту цепь.</p>
<p>Теперь самое интересное: цены.</p>
<p>Свой набор Arduino Uno с двумя книжками и прочим барахлишком я купил в магазине КЕЙ за 2790 рублей. Просто потому, что хотел всё, сразу и сейчас. Отдельно плата Arduino Uno в Чип&amp;Дип стоит 2270 рублей. У китайцев аналог этой платы стоит от 200 рублей. Оригинальная версия от <a href="https://store.arduino.cc/basics-bundle" rel="nofollow" target="_blank">создателей</a> обойдется вам в €28. Чувствуете некоторый разброс цен?</p>
<p>На мой дилетантский взгляд, покупать Arduino нужно у создателей, а разные реле и платы у китайцев. Просто потому, что создатели этого заслуживают.</p>
<p>Когда внезапно разбогатею (как раз после выплаты ипотеки), то планирую купить набор у создателей в районе 10-15 тысяч рублей, просто в качестве благодарности за их труд.</p>
]]></content>
		
			</entry>
		<entry>
		<author>
			<name>eJ</name>
					</author>

		<title type="html"><![CDATA[Турция. Мармарис. Всё включено]]></title>
		<link rel="alternate" type="text/html" href="https://blog2k.ru/archives/8344" />

		<id>https://blog2k.ru/?p=8344</id>
		<updated>2025-12-09T08:55:49Z</updated>
		<published>2018-09-26T10:37:54Z</published>
		<category scheme="https://blog2k.ru" term="Путешествия" /><category scheme="https://blog2k.ru" term="Турция" /><category scheme="https://blog2k.ru" term="Мармарис" /><category scheme="https://blog2k.ru" term="отпуск" />
		<summary type="html"><![CDATA[В этом году я решил исправить упущение и отдохнуть в Турции по системе «всё включено». Купил путёвку в Мармарис. Взял несколько экскурсий, в том числе на яхте и в Памукале. Поделился своими впечатлениями от отдыха.]]></summary>

					<content type="html" xml:base="https://blog2k.ru/archives/8344"><![CDATA[<p>Как-то так получилось, что я ни разу не был в Турции. И ни разу не испытал на себе, что такое система &#171;Всё включено&#187;. Настала пора исправить этот недостаток. Так что в этом году купил путёвку в Мармарис, Турция. Путевку брал турфирмы Anex Tour через родственника (спасибо, Аня!).</p>
<p>Между прочим, кардиолог запретила мне летать аж на двенадцать месяцев и перегреваться. Я врача внимательнейшим образом выслушал и полетел на девятый месяц загорать на самолёте в Турцию. Пока самолёт сам не попробуешь после операции &#8212; ничего не получится, можно до скончания веков сидеть дома и бояться даже пукнуть &#8212; вдруг чего отвалится. Надоело!</p>
<p>Система всё включено работает следующим образом: при заезде в отель цепляют бумажный браслетик, который <strike>навсегда (ахах)</strike> носят практически все на протяжении всего отпуска. Утром завтрак по системе шведский стол, днём &#8212; обед, вечером &#8212; ужин. Целый день можно подходить к бару, где наливают вино белое и красное, пиво, колу, фанту и прочее. Также есть чай-кофе, всё бесплатно, пить можно, пока печень не отвалится. Все доступные соки (апельсиновый, ананасовый и вишневый) на вкус отвратительны и скорее всего разбодяжены из порошка.</p>
<p>По традиции взял экскурсию на яхте. Потом немного подумал и взял все доступные туры на яхтах, итого получилось две штуки за $75. Плюс к этому взял тур в Памукале ($40), где находятся природные бассейны с минеральной водой. Искупаться в газировке Боржоми турецкого разлива &#8212; ну клёво же! Кстати, купаться в этих бассейнах с особой осторожностью следует сердечникам, потому что температура в них аж тридцать восемь градусов! Везде риски, куда ни плюнь. Поездка для меня &#8212; сплошная авантюра. Хорошо, что я не сердечник, потому что у меня тупо клапан стоит в сердце и голова иногда кружится.</p>
<p><img loading="lazy" decoding="async" src="https://blog2k.ru/wp-content/uploads/2018/09/img_20180918_1310211641487976.jpg" alt="Экскурсия на остров Клеопатры" width="3000" height="2250" class="aligncenter size-full wp-image-8353" srcset="https://blog2k.ru/wp-content/uploads/2018/09/img_20180918_1310211641487976.jpg 1024w, https://blog2k.ru/wp-content/uploads/2018/09/img_20180918_1310211641487976-300x225.jpg 300w, https://blog2k.ru/wp-content/uploads/2018/09/img_20180918_1310211641487976-768x576.jpg 768w" sizes="auto, (max-width: 3000px) 100vw, 3000px" /></p>
<p>Также был доступен параглайдинг &#8212; полёт с инструктором на парашюте с двух километров вниз. Но задушила жаба &#8212; ценник в 130 баксов плюс фоточки за $50. И мужик какой-то сзади привязан, а ты летишь и совершенно беззащитен. Тревожно стало, в общем. Не полетел.</p>
<p><span id="more-8344"></span>В первую экскурсию на яхте забрался на самый верхний третий этаж и нахрен сгорел. Плюс солнечный и тепловой удар по традиции. Традиции нарушать нельзя, поэтому, хорошенько прожарившись на солнце в течение восьми часов, вернулся в номер красный как рак, довольный как слон <strike>и стремительный как домкрат</strike>. Купался в пяти бухтах с изумительного цвета водой.</p>
<p><img loading="lazy" decoding="async" src="https://blog2k.ru/wp-content/uploads/2018/09/img_20180919_152727-1951988443.jpg" alt="Экскурсия на Эгейские острова" width="3000" height="2250" class="aligncenter size-full wp-image-8354" srcset="https://blog2k.ru/wp-content/uploads/2018/09/img_20180919_152727-1951988443.jpg 1024w, https://blog2k.ru/wp-content/uploads/2018/09/img_20180919_152727-1951988443-300x225.jpg 300w, https://blog2k.ru/wp-content/uploads/2018/09/img_20180919_152727-1951988443-768x576.jpg 768w" sizes="auto, (max-width: 3000px) 100vw, 3000px" /></p>
<p>Во вторую экскурсию выбрал второй этаж под тентом в качестве места дислокации на всё время путешествия. Стало гораздо лучше. Иногда было даже прохладно. Насидишься в теньке, замёрзнешь весь, потом в воду заходить сплошное удовольствие: тепло, хорошо, немного пьян &#8212; пиво и вино бесплатное же ж.</p>
<p><img loading="lazy" decoding="async" src="https://blog2k.ru/wp-content/uploads/2018/09/img_20180919_100633443737962.jpg" alt="Экскурсия на остров Клеопатры" width="3000" height="2250" class="aligncenter size-full wp-image-8352" srcset="https://blog2k.ru/wp-content/uploads/2018/09/img_20180919_100633443737962.jpg 1024w, https://blog2k.ru/wp-content/uploads/2018/09/img_20180919_100633443737962-300x225.jpg 300w, https://blog2k.ru/wp-content/uploads/2018/09/img_20180919_100633443737962-768x576.jpg 768w" sizes="auto, (max-width: 3000px) 100vw, 3000px" /></p>
<p>Тур в Памукале самый экстремальный. Вставать приходиться аж в пять утра, завтракать отвозят на автобусе, обедать тоже. В Памукале находятся руины древнего города Европолис, бассейны с термальными источниками и бассейны на белой горе &#8212; кальций там в огромных количествах. На белой горе можно ножки до колен омыть и навернуться с высоты &#8212; ограждений особых не заметил. Споткнулся и поехал вниз &#8212; до финиша сотрёшься весь, одни уши доедут.</p>
<p><img loading="lazy" decoding="async" src="https://blog2k.ru/wp-content/uploads/2018/09/img_20180916_13102927658015.jpg" alt="Вид из отеля Prestige Garden" width="3000" height="2250" class="aligncenter size-full wp-image-8351" srcset="https://blog2k.ru/wp-content/uploads/2018/09/img_20180916_13102927658015.jpg 1024w, https://blog2k.ru/wp-content/uploads/2018/09/img_20180916_13102927658015-300x225.jpg 300w, https://blog2k.ru/wp-content/uploads/2018/09/img_20180916_13102927658015-768x576.jpg 768w" sizes="auto, (max-width: 3000px) 100vw, 3000px" /></p>
<p>Кстати, на пляже возле отеля один раз всего был. Вечером в первый день прошёлся по берегу во время заката. У меня ж экскурсии на яхте заказаны &#8212; на кой мне этот пляж вообще.</p>
]]></content>
		
					<link rel="replies" type="text/html" href="https://blog2k.ru/archives/8344#comments" thr:count="2" />
			<link rel="replies" type="application/atom+xml" href="https://blog2k.ru/archives/8344/feed/atom" thr:count="2" />
			<thr:total>2</thr:total>
			</entry>
		<entry>
		<author>
			<name>eJ</name>
					</author>

		<title type="html"><![CDATA[Замена поводка заднего стеклоочистителя и дворника SEAT Altea Freetrack]]></title>
		<link rel="alternate" type="text/html" href="https://blog2k.ru/archives/8315" />

		<id>https://blog2k.ru/?p=8315</id>
		<updated>2025-12-09T08:56:43Z</updated>
		<published>2018-08-25T18:29:23Z</published>
		<category scheme="https://blog2k.ru" term="SEAT Altea Freetrack" /><category scheme="https://blog2k.ru" term="Автомобиль" /><category scheme="https://blog2k.ru" term="Seat Altea Freetrack" />
		<summary type="html"><![CDATA[Заменил старые дворники на новые Bosch, но задний не подошёл. Выяснил, что для моей машины нужен бескаркасный дворник с новым поводком. Заказал нужный поводок и колпачок, заменил.]]></summary>

					<content type="html" xml:base="https://blog2k.ru/archives/8315"><![CDATA[<p>После ремонта трапеции моторчика дворников задумал поставить новые дворники спереди и задний заодно поменять.</p>
<p>Пошёл искать в интернет и нашёл передние дворники Bosch A958S и задний Bosch A330H. Заказал, приехал на Пионерскую &#8212; купил.</p>
<p>Передние обошлись в 2100 рублей за пару, задний &#8212; 730 рублей.</p>
<p>Тут же на месте заменил передние оба два, а с задним возникла проблема. Он не подходит! Поводок дворника на моей машине предназначен только для каркасных дворников, новомодный бескаркасный туда никак не прикрепить.</p>
<p>Задумался, расстроился &#8212; это ж сейчас обратно в магазин идти, признаваться, что купил не то. Все будут пальцем показывать и смеяться.</p>
<p><img loading="lazy" decoding="async" src="https://blog2k.ru/wp-content/uploads/2018/08/img_20180825_213142_707-31554593.jpg" alt="Симпсоны. Ха-ха!" width="962" height="720" class="aligncenter size-full wp-image-8332" srcset="https://blog2k.ru/wp-content/uploads/2018/08/img_20180825_213142_707-31554593.jpg 962w, https://blog2k.ru/wp-content/uploads/2018/08/img_20180825_213142_707-31554593-300x225.jpg 300w, https://blog2k.ru/wp-content/uploads/2018/08/img_20180825_213142_707-31554593-768x575.jpg 768w" sizes="auto, (max-width: 962px) 100vw, 962px" /></p>
<p>Присмотрелся к коробке новомодного заднего дворника: SEAT ALTEA 5P в списке есть &#8212; значит кто-то из нас неправ: или я, или коробка.</p>
<p>&#171;Кто я такой, чтобы спорить с коробкой&#187;, &#8212; подумал я и снова пошёл в интернет: выяснять кто умнее &#8212; программист или она. И выяснил! С некоторых пор каркасные щётки на пятую дверь вышли из моды, теперь в тренде &#8212; бескаркасные и новый поводок для них. Выглядит гораздо лучше: стильно, модно, молодёжно!</p>
<p><span id="more-8315"></span>Заказал задний поводок с колпачком.</p>
<p>Коды, если интересно:</p>
<ul>
<li>поводок <code class="" data-line="">6Q6955707C</code> (1102 рубля)</li>
<li>колпачок <code class="" data-line="">6Q6955435D</code> (141 рубль)</li>
</ul>
<p>Было так:<br />
<img loading="lazy" decoding="async" src="https://blog2k.ru/wp-content/uploads/2018/08/img_20180825_212203_021-1191718341.jpg" alt="Задний дворник SEAT Altea Freetrack" width="2187" height="1154" class="aligncenter size-full wp-image-8328" srcset="https://blog2k.ru/wp-content/uploads/2018/08/img_20180825_212203_021-1191718341.jpg 1024w, https://blog2k.ru/wp-content/uploads/2018/08/img_20180825_212203_021-1191718341-300x158.jpg 300w, https://blog2k.ru/wp-content/uploads/2018/08/img_20180825_212203_021-1191718341-768x405.jpg 768w" sizes="auto, (max-width: 2187px) 100vw, 2187px" /></p>
<p>Стало так:<br />
<img loading="lazy" decoding="async" src="https://blog2k.ru/wp-content/uploads/2018/08/img_20180825_212239_182-1232202183.jpg" alt="Задний дворник SEAT Altea Freetrack" width="1978" height="1146" class="aligncenter size-full wp-image-8329" srcset="https://blog2k.ru/wp-content/uploads/2018/08/img_20180825_212239_182-1232202183.jpg 1024w, https://blog2k.ru/wp-content/uploads/2018/08/img_20180825_212239_182-1232202183-300x174.jpg 300w, https://blog2k.ru/wp-content/uploads/2018/08/img_20180825_212239_182-1232202183-768x445.jpg 768w" sizes="auto, (max-width: 1978px) 100vw, 1978px" /></p>
<p>Стало на два сантиметра длиннее. Не знаю &#8212; хорошо это или нет. Ведь главное не размер, а умение, хотя что-то я отвлёкся&#8230;</p>
]]></content>
		
					<link rel="replies" type="text/html" href="https://blog2k.ru/archives/8315#comments" thr:count="0" />
			<link rel="replies" type="application/atom+xml" href="https://blog2k.ru/archives/8315/feed/atom" thr:count="0" />
			<thr:total>0</thr:total>
			</entry>
		<entry>
		<author>
			<name>eJ</name>
					</author>

		<title type="html"><![CDATA[Как сломать трапецию дворников SEAT Altea Freetrack]]></title>
		<link rel="alternate" type="text/html" href="https://blog2k.ru/archives/8293" />

		<id>https://blog2k.ru/?p=8293</id>
		<updated>2025-10-22T12:40:46Z</updated>
		<published>2018-08-04T20:18:29Z</published>
		<category scheme="https://blog2k.ru" term="SEAT Altea Freetrack" /><category scheme="https://blog2k.ru" term="Автомобиль" /><category scheme="https://blog2k.ru" term="Seat Altea Freetrack" /><category scheme="https://blog2k.ru" term="своими руками" />
		<summary type="html"><![CDATA[В статье описан способ поломки трапеции дворника на SEAT Altea Freetrack. Указаны цены на запчасти и услуги по ремонту.]]></summary>

					<content type="html" xml:base="https://blog2k.ru/archives/8293"><![CDATA[<p>Отвечаю: элементарно и очень дорого! Если вам зачем-то нужно сломать трапецию дворника на SEAT Altea Freetrack, то повторяйте за мной. Алгоритм простой:</p>
<ol>
<li>Глушим машину.</li>
<li>Дёргаем ручку дворников справа от руля &#8212; это переводит дворники в сервисный режим.</li>
<li>Поднимаем дворники от стекла как бы для замены резинок.</li>
<li>Дёргаем ручку дворников ещё раз.</li>
<li>Дворники пытаются подняться обратно и ломают трапецию к херам.</li>
<li>???</li>
<li>PROFIT!</li>
</ol>
<p>Понятия не имею &#8212; зачем вам понадобится заниматься подобной ерундой. Теперь о ценах:</p>
<ul>
<li>Новый моторчик в комплекте с трапецией стоит от 11-ти до 14-ти тысяч рублей с доставкой в течение 30-ти дней</li>
<li>Бывший в употреблении моторчик стоит семь тысяч</li>
<li>Работа по снятию моторчика стоит 1500 рублей</li>
<li>Работа по установке 2200 рублей</li>
<li>Сварка аргоном сломанной трапеции стоит от одной до двух тысяч рублей</li>
</ul>
<p>Спасибо за внимание!</p>
<div class='yarpp yarpp-related yarpp-related-rss yarpp-template-list'>
<!-- YARPP List -->
<h3>Похожие записи:</h3><ol>
<li><a href="https://blog2k.ru/archives/3224" rel="bookmark" title="Пластмассовая защита двигателя SEAT Altea Freetrack &#8212; ремонт своими руками">Пластмассовая защита двигателя SEAT Altea Freetrack &#8212; ремонт своими руками</a></li>
<li><a href="https://blog2k.ru/archives/3117" rel="bookmark" title="SEAT Altea Freetrack: выпала петелька складывания задних сидений">SEAT Altea Freetrack: выпала петелька складывания задних сидений</a></li>
<li><a href="https://blog2k.ru/archives/5113" rel="bookmark" title="Замена противотуманок в SEAT Altea Freetrack">Замена противотуманок в SEAT Altea Freetrack</a></li>
</ol>
</div>
]]></content>
		
					<link rel="replies" type="text/html" href="https://blog2k.ru/archives/8293#comments" thr:count="0" />
			<link rel="replies" type="application/atom+xml" href="https://blog2k.ru/archives/8293/feed/atom" thr:count="0" />
			<thr:total>0</thr:total>
			</entry>
	</feed>
