<?xml version="1.0" encoding="utf-8"?> 
<rss version="2.0"
  xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd"
  xmlns:atom="http://www.w3.org/2005/Atom">

<channel>

<title>Математик среди биологов: заметки с тегом программирование</title>
<link>https://antonlyakh.ru/blog/tags/programmirovanie/</link>
<description>Я немного умею складывать, но от вычитания у меня всегда кружится голова</description>
<author>Антон Лях</author>
<language>ru</language>
<generator>E2 (v3559; Aegea)</generator>

<itunes:owner>
<itunes:name>Антон Лях</itunes:name>
<itunes:email></itunes:email>
</itunes:owner>
<itunes:subtitle>Я немного умею складывать, но от вычитания у меня всегда кружится голова</itunes:subtitle>
<itunes:image href="" />
<itunes:explicit></itunes:explicit>

<item>
<title>Недостаток вычисления определителя целоисчисленных матриц на Питоне</title>
<guid isPermaLink="false">496</guid>
<link>https://antonlyakh.ru/blog/all/nedostatok-vychisleniya-opredelitelya-celoischislennyh-matric-na/</link>
<pubDate>Fri, 28 Jun 2024 22:13:50 +0300</pubDate>
<author>Антон Лях</author>
<comments>https://antonlyakh.ru/blog/all/nedostatok-vychisleniya-opredelitelya-celoischislennyh-matric-na/</comments>
<description>
&lt;p&gt;&lt;i&gt;Целоисчисленная матрица&lt;/i&gt; — это матрица, все элементы которой являются целыми числами.&lt;/p&gt;
&lt;p&gt;Определитель целоисчисленной матрицы — тоже целое число. (Очевидно же.)&lt;/p&gt;
&lt;p&gt;Используем класс целоисчисленных матриц, элементы которых могут принимать только значения из заданного множества целых чисел. (Такие матрицы называют &lt;i&gt;богемными.&lt;/i&gt;)&lt;/p&gt;
&lt;p&gt;Очевидно, что если множество возможных элементов матриц конечно, то и число возможных богемных матриц заданного размера тоже конечно.&lt;/p&gt;
&lt;p&gt;Пусть мы ищем среди всех богемных матриц только те, определитель которых равен нулю. Ищем при помощи кода на Питоне. Определитель матрицы вычисляем так:&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;dt = np.linalg.det( a )&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;И вот тут возможна ошибка.&lt;/p&gt;
&lt;p&gt;Если мы будем выбирать матрицы по условию &lt;kbd&gt;dt==0&lt;/kbd&gt;, то получим неверный результат.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Using that test (dt==0) Python got the right number of [...] matrices when mdim=2 or mdim=3, but the test dt==0 failed a few times when mdim=4, and (after a long time computing) reported 15,015,617 singular matrices; the true number is 15,099,201. This is because &lt;kbd&gt;np.linalg.det&lt;/kbd&gt; is &lt;i&gt;computing the determinant from a numerical factoring&lt;/i&gt; (which introduces rational numbers and rounding error) and the roundoff error means that sometimes a zero determinant was not being reported as precisely zero.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Правильный результат получится если мы используем условие &lt;kbd&gt;dt&amp;lt;0.5&lt;/kbd&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://computational-discovery-on-jupyter.github.io/Computational-Discovery-on-Jupyter/Contents/bohemian-matrices.html#table-of-results"&gt;https://computational-discovery-on-jupyter.github.io/Computational-Discovery-on-Jupyter/Contents/bohemian-matrices.html#table-of-results&lt;/a&gt;&lt;/p&gt;
</description>
</item>

<item>
<title>Rесурсы. Выбрать строки с одинаковыми индексами из data.table</title>
<guid isPermaLink="false">495</guid>
<link>https://antonlyakh.ru/blog/all/vybiraem-v-r-stroki-s-odinakovymi-indeksami-iz-data-table/</link>
<pubDate>Fri, 21 Jun 2024 16:34:01 +0300</pubDate>
<author>Антон Лях</author>
<comments>https://antonlyakh.ru/blog/all/vybiraem-v-r-stroki-s-odinakovymi-indeksami-iz-data-table/</comments>
<description>
&lt;p class="foot"&gt;Это техническая заметка-напоминалка о некоторых возможностях пакета data.table.&lt;/p&gt;
&lt;h4&gt;Задача&lt;/h4&gt;
&lt;p&gt;Есть несколько таблиц data.table с данными. Назовем их dt_meta, dt_x, dt_y, dt_area.&lt;/p&gt;
&lt;p&gt;В каждой таблице есть колонка the_index.&lt;/p&gt;
&lt;p&gt;Из таблицы dt_meta выбираю строки, удовлетворяющие критерию. Например, все строки, в которых значение the_length &gt; 120:&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;dt_meta[the_length &amp;gt; 120]&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Задача заключается в том, чтобы из остальных таблиц выбрать строки с теми же номерами.&lt;/p&gt;
&lt;h4&gt;Решение&lt;/h4&gt;
&lt;p&gt;Использую специальный символ &lt;kbd&gt;&lt;a href="https://jangorecki.gitlab.io/data.cube/library/data.table/html/special-symbols.html"&gt;.I&lt;/a&gt;&lt;/kbd&gt;&lt;/p&gt;
&lt;p&gt;&lt;kbd&gt;.I&lt;/kbd&gt; возвращает номера строк. Но у него есть &lt;a href="https://stackoverflow.com/questions/23585999/understanding-i-in-data-table-in-r"&gt;особенности&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;br/&gt;&lt;/p&gt;
&lt;p&gt;Код&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;dt_meta[the_length &amp;gt; 120, .I]&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;вернет последовательные номера строк в новой таблице: 1, 2, 3, ....&lt;/p&gt;
&lt;p&gt;&lt;br/&gt;&lt;/p&gt;
&lt;p&gt;Код&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;dt_meta[, .I[the_length &amp;gt; 120]]&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;вернет номера строк в исходной таблице: 5, 9, 13, 63, ....&lt;/p&gt;
&lt;p&gt;&lt;br/&gt;&lt;/p&gt;
&lt;p&gt;Для решения нужен второй вариант кода. Вот решение.&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;# Номера строк исходной таблицы, в которых the_length &amp;gt; 120
indexes &amp;lt;- dt_meta[, .I[the_length &amp;gt; 120]]
# Выбираю такие же строки из других таблиц
new_x &amp;lt;- dt_x[indexes]
new_y &amp;lt;- dt_y[indexes]
new_area &amp;lt;- dt_area[indexes]&lt;/code&gt;&lt;/pre&gt;</description>
</item>

<item>
<title>Сделай сам</title>
<guid isPermaLink="false">460</guid>
<link>https://antonlyakh.ru/blog/all/sdelay-sam/</link>
<pubDate>Tue, 18 Oct 2022 16:40:00 +0300</pubDate>
<author>Антон Лях</author>
<comments>https://antonlyakh.ru/blog/all/sdelay-sam/</comments>
<description>
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://antonlyakh.ru/blog/pictures/Sdelay-sam.png" width="800" height="569" alt="" /&gt;
&lt;div class="e2-text-caption"&gt;Повторное использование чужих приемов — это нормально&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Я сам пишу большинство программ с использованием своих библиотек. То есть, конечно, у меня есть некие базовые библиотеки, однажды найденные на просторах сети, но этим дело и ограничивается.&lt;/p&gt;
&lt;p&gt;Когда у меня есть задача написать программу, я сажусь и пишу ее сам: продумываю алгоритм, интерфейс, пишу код, тестирую, правлю, опять тестирую и выпускаю релиз.&lt;/p&gt;
&lt;p&gt;Я не люблю ковыряться в чужом коде или разбираться в документации чьей-то библиотеки, так как при этом ничего не получаю взамен, кроме усталости и отупения.&lt;/p&gt;
&lt;p&gt;&lt;i&gt;Дополнено через пару месяцев.&lt;/i&gt;&lt;br /&gt;
Однако мой подход старомоден и в будущем перейду на повторное использование чужих приемов. Ибо любой код когда-нибудь кем-нибудь будет написан, будет написан хорошо и будет доступен всем. Незачем отвергать хорошие вещи.&lt;/p&gt;
</description>
</item>

<item>
<title>Ассоциативный массив в старых версиях Дельфи</title>
<guid isPermaLink="false">451</guid>
<link>https://antonlyakh.ru/blog/all/associativny-massiv-v-staryh-versiyah-delfi/</link>
<pubDate>Tue, 19 Apr 2022 11:08:05 +0300</pubDate>
<author>Антон Лях</author>
<comments>https://antonlyakh.ru/blog/all/associativny-massiv-v-staryh-versiyah-delfi/</comments>
<description>
&lt;p&gt;В Королевстве Дельфи много лет назад Дмитрий Рябов предложил &lt;a href="http://www.delphikingdom.com/asp/viewitem.asp?catalogid=868"&gt;реализацию ассоциативных массивов&lt;/a&gt;.&lt;/p&gt;
&lt;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;«На практике часто возникает потребность сохранять и обрабатывать данные в массивах, осуществляя доступ к элементам не по индексу, а по ключу. Для этого используются ассоциативные массивы, которые есть, например, во многих скриптовых языках. В &lt;abbr&gt;Delphi&lt;/abbr&gt; на уровне языка такая структура отсутствует. В качестве замены часто используются контейнерные классы &lt;abbr&gt;TStringList&lt;/abbr&gt;, &lt;abbr&gt;TParams&lt;/abbr&gt; и т. п., но они весьма неудобны в использовании и недостаточно функциональны. К тому же появляется необходимость заботиться об уничтожении экземпляра класса, что зачастую порождает лишние &lt;abbr&gt;try..finally..end&lt;/abbr&gt;.»&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;В чем фишка реализации.&lt;/p&gt;
&lt;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;«Удобное использование, неплохая производительность, отсутствие небходимости принудительного уничтожения, нескольно представлений одного массива, использование ключей разных типов, наличие функций итератора, удобное использование многомерных массивов.»»&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;Я иногда ее использую в своих проектах и всегда опасаюсь, что текст с примерами будет окончательно потерян. Потому решил воспроизвести его здесь.&lt;/p&gt;
&lt;hr /&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;program Example;
{$APPTYPE CONSOLE}
uses
  Arrays;

procedure Main;
var
  I: IIntArray;
  S: IStrArray;
  V: IVarArray;
  M: IMltArray;

begin
  // создаём массив и получаем представление в целых числах
  I := CreateArray;

  // заполняем
  I['a'] := 5;
  I['b'] := 1;
  I['c'] := 4;
  I['d'] := 2;
  I['e'] := 3;

  // выводим
  WriteLn('Original array');
  I.First;
  while not I.Eof do
  begin
    WriteLn('[', I.CurrentKey, '] = ', I.CurrentValue);
    I.Next;
  end;

  // сортируем
  I.Sort;

  // наблюдаем результат
  WriteLn('Sorted array');
  I.First;
  while not I.Eof do
  begin
    WriteLn('[', I.CurrentKey, '] = ', I.CurrentValue);
    I.Next;
  end;

  // создаём строковое представление
  S := I.Instance;

  // наблюдаем результат
  WriteLn('Two views of one array');
  S.First;
  while not S.Eof do
  begin
    WriteLn('[', S.CurrentKey, '] + ''10'' = ', S.CurrentValue + '10');
    WriteLn('[', I.CurrentKey, '] + 10 = ', I.CurrentValue + 10);
    S.Next;
  end;

  // создаём вариантное представление
  V := S.Instance;
  V.Clear;
  V['integer'] := 10;
  V['string'] := '10';

  // наблюдаем результат
  WriteLn('Variant type conversion');
  V.First;
  while not V.Eof do
  begin
    WriteLn('[', V.CurrentKey, '] + 10 = ', V.CurrentValue + 10);
    WriteLn('[', V.CurrentKey, '] + ''10'' = ', V.CurrentValue + '10');
    V.Next;
  end;

  // используем ключи разных типов, но одного значения
  S.Clear;
  S[False] := 'boolean';
  S[0] := 'integer';
  S[0.0] := 'float';
  S['0'] := 'string';

  // наблюдаем результат
  WriteLn('Variant type keys ;)');
  S.First;
  while not S.Eof do
  begin
    WriteLn('[', S.CurrentKey, '] = ', S.CurrentValue);
    S.Next;
  end;

  // создаём ещё одно представление, на этот раз - многомерное
  M := V.Instance;
  M.Clear;

  // заполняем матрицу
  M['A']['a'].AsInteger := 1;
  M['A']['b'].AsInteger := 2;
  M['A']['c'].AsInteger := 3;
  M['B']['a'].AsInteger := 4;
  M['B']['b'].AsInteger := 5;
  M['B']['c'].AsInteger := 6;
  M['C']['a'].AsInteger := 7;
  M['C']['b'].AsInteger := 8;
  M['C']['c'].AsInteger := 9;

  // выводим матрицу
  WriteLn('Multidimensional array');
  M.First;
  while not M.Eof do
  begin
    M.CurrentValue.First;
    while not M.CurrentValue.Eof do
    begin
      WriteLn('[', M.CurrentKey, ',', M.CurrentValue.CurrentKey, '] = ',
        M.CurrentValue.CurrentValue.AsInteger);
      M.CurrentValue.Next;
    end;
    M.Next;
  end;

  // перед возвратом все созданные массивы автоматически удаляются
  WriteLn('Arrays is free');
end;

var
  L: Integer;
begin
  L := AllocMemSize;
  Main;
  // проверка утечки памяти
  WriteLn('Memory leak: ', AllocMemSize - L, ' bytes');
  ReadLn;
end.&lt;/code&gt;&lt;/pre&gt;&lt;hr /&gt;
&lt;p&gt;&lt;b&gt;&lt;a href="http://www.delphikingdom.com/zip/arrays.zip"&gt;Скачать исходники из Королевства&lt;/a&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;&lt;a href="https://stackoverflow.com/a/51830939/1615266"&gt;Посмотреть рекомендацию оссоциативного массива&lt;/a&gt;&lt;/b&gt; на Стакэксчендже .&lt;/p&gt;
</description>
</item>

<item>
<title>Прием программирования: Вовремя остановиться</title>
<guid isPermaLink="false">438</guid>
<link>https://antonlyakh.ru/blog/all/priem-programmirovaniya-vovremya-ostanovitsya/</link>
<pubDate>Tue, 31 Aug 2021 22:13:58 +0300</pubDate>
<author>Антон Лях</author>
<comments>https://antonlyakh.ru/blog/all/priem-programmirovaniya-vovremya-ostanovitsya/</comments>
<description>
&lt;p&gt;Иногда я пишу одноразовый код, который, например, что-то переносит из файла в базу данных. Этот код мне понадобиться один раз, но удалять его после использования жалко.&lt;/p&gt;
&lt;p&gt;Для того, чтобы код нельзя было больше выполнить, я внедряю в него оператор die().&lt;/p&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://antonlyakh.ru/blog/pictures/program-die.png" width="800" height="361" alt="" /&gt;
&lt;/div&gt;
&lt;p&gt;Главное — вовремя остановиться.&lt;/p&gt;
</description>
</item>

<item>
<title>Приемы программирования. Вернуть вектор</title>
<guid isPermaLink="false">391</guid>
<link>https://antonlyakh.ru/blog/all/priemy-programmirovaniya-vernut-vektor/</link>
<pubDate>Wed, 16 Sep 2020 18:29:33 +0300</pubDate>
<author>Антон Лях</author>
<comments>https://antonlyakh.ru/blog/all/priemy-programmirovaniya-vernut-vektor/</comments>
<description>
&lt;p&gt;Иногда функция должна вернуть не одно, а несколько значений. Например флаг успеха или неудачи, несколько найденных параметров и массив. Фактически она возвращает векторный результат.&lt;/p&gt;
&lt;p&gt;Раньше для получения векторного результата я передавал несколько переменных по ссылке и ждал булево значение функции.&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;// Здесь ожидаю два параметра и двумерный массив, а функция возвращает флаг успеха-неудачи.
function navalniy( 
    source_data : TVector; var temperature : real; var blood_pressure : real; var spy_data : TVector
) : boolean;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Теперь я просто получаю один векторный результат.&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;function navalniy( source_data : TVector ) : TVector;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Первый компонент вектора содержит флаг успеха и вычисленные скалярные параметры, остальные — заполненный массив.&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class="cpp"&gt;
spy_data = navalniy( source_data );
if (spy_data[0][0] == 0) {
  alert(‘Явка провалена. Немедленно уходить!’);
  exit();
} else {
  temperature = spy_data[0][1];
  blood_pressure = spy_data[0][2];
  list_of_comrades = (spy_data[1], …, spy_data[M]);
  // Все в порядке, продолжаем готовить революцию
  // …
}
&lt;/code&gt;
&lt;/pre&gt;
&lt;p&gt;Единственное, при таком подходе нужно следить, чтобы размерность второй координаты массива (resulted_array[•][×]) была не меньше размерности ожидаемых дополнительных параметров (param{i}). В противном случае параметры следует вернуть в нескольких начальных  компонентах ветора-результата.&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class="cpp"&gt;
spy_data = navalniy( source_data );
if (spy_dat[0][0] &gt; 0) {
  temperature =spy_dat[0][1];
  blood_pressure = spy_dat[0][2];
  leukocytes = spy_datt[1][0];
  hemoglobin = spy_dat[1][1];
  erythrocytes = spy_dat[1][2];
  // Возвращенный массив начинается с N-ой компоненты вектора-результата
  list_of_comrades = (spy_dat[N], …, spy_dat[M]);
  // …
}
&lt;/code&gt;
&lt;/pre&gt;
&lt;p&gt;Векторы — это сила.&lt;/p&gt;
</description>
</item>

<item>
<title>Приемы веб-программирования. Разрешить Апачу сначала искать файлы в текущем каталоге</title>
<guid isPermaLink="false">385</guid>
<link>https://antonlyakh.ru/blog/all/priemy-veb-programmirovaniya-razreshit-apachu-snachala-iskat-fay/</link>
<pubDate>Wed, 10 Jun 2020 16:13:07 +0300</pubDate>
<author>Антон Лях</author>
<comments>https://antonlyakh.ru/blog/all/priemy-veb-programmirovaniya-razreshit-apachu-snachala-iskat-fay/</comments>
<description>
&lt;p&gt;Памятка тем, кто (до сих пор) руками пишет веб-движки на ПХП.&lt;/p&gt;
&lt;p&gt;У вас есть два файла с одинаковым названием ’konstituciya.php’ в текущем и каком-то системном каталоге. Файл в системном каталоге делает основную работу, например, выводит перечень статей конституции. Файл в текущем каталоге устанавливает локальные настройки, например, вносит в конституцию поправки, а потом вызывает файл из системного каталога. Чтобы поправки вступили в силу, необходимо, чтобы первым был вызван файл из текущего каталога. Вот так:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;konstituciya.php → ./system/konstituciya.php&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Чтобы установить такую последовательность вызовов, в .htaccess в списке путей первой поставьте точку, а потом перечислите прочие каталоги:&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;php_value include_path &amp;quot;.:/home/system&amp;quot;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Тогда код выполнится правильно:&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;// Сначала вызовет файл из текущего каталога с поправками, а потом системный файл с основными законами
   include_once &amp;quot;konstituciya.php&amp;quot;;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Удачи.&lt;/p&gt;
</description>
</item>

<item>
<title>Приемы программирования. Залить файлы на сервер</title>
<guid isPermaLink="false">352</guid>
<link>https://antonlyakh.ru/blog/all/priemy-programmirovaniya-zalit-fayly-na-server/</link>
<pubDate>Tue, 17 Mar 2020 17:47:11 +0300</pubDate>
<author>Антон Лях</author>
<comments>https://antonlyakh.ru/blog/all/priemy-programmirovaniya-zalit-fayly-na-server/</comments>
<description>
&lt;p&gt;Облачные сервисы предлагают загрузить файлы на виртуальный диск при помощью интерфейса. Тащишь группу файлов, бросаешь в окно и они понемногу загружаются, а сервис выдает красивые прогресс-бары. При этом внутри кипит работа: сервис проверяет формат и размер файлов, следит за устойчивой передачей и рисует прогресс-бары, по завершению выдает сообщения, заносит данные в базу данных и размещает файлы в надежном месте.&lt;/p&gt;
&lt;p&gt;Такой сценарий нужен, когда виртуальным диском пользуются десятки пользователей. А для тестирования небольших проектов, когда группа пользователей ограничена двумя-тремя персонами, рекомендую закачивать файлы в выделенный каталог сервера. По Эс-Эс-Аш или ФТП, например. После, специальный скрипт сканирует каталог, обрабатывает файлы, запоминает метаданные в таблицах и реализует дальнейший интерфейс.&lt;/p&gt;
&lt;p&gt;Именно так я тестирую «Фотосистематизатор».&lt;/p&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://antonlyakh.ru/blog/pictures/fotosistema-screen-1.png" width="800" height="526" alt="" /&gt;
&lt;div class="e2-text-caption"&gt;Фотосистематизатор берет фотографии прямо из каталога, а пользователь закачивает их туда напрямую, без интерфейсных наворотов&lt;/div&gt;
&lt;/div&gt;
</description>
</item>

<item>
<title>Приемы программирования. Ненужный файл с кодом не удаляю, а переименовываю</title>
<guid isPermaLink="false">339</guid>
<link>https://antonlyakh.ru/blog/all/priemy-programmirovaniya-nenuzhny-fayl-s-kodom-srazu-ne-udalyayu/</link>
<pubDate>Wed, 26 Feb 2020 00:39:33 +0300</pubDate>
<author>Антон Лях</author>
<comments>https://antonlyakh.ru/blog/all/priemy-programmirovaniya-nenuzhny-fayl-s-kodom-srazu-ne-udalyayu/</comments>
<description>
&lt;p&gt;Бывает, что файл с фрагментом кода уже не нужен. Например потому, что код из него переписан, усовершенствован и перенесен в другой файл. Тогда такой файл я сразу не удаляю, а приписываю к нему приставку &lt;i&gt;’del-’&lt;/i&gt;.&lt;/p&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://antonlyakh.ru/blog/pictures/del-prefix.png" width="228" height="121" alt="" /&gt;
&lt;/div&gt;
&lt;p&gt;После тестирую, нет ли ошибок и все ли работает правильно. Потом жду несколько дней и только после этого бесповоротно удаляю файл.&lt;/p&gt;
</description>
</item>

<item>
<title>Ошибки программирования. Забыл про юникод</title>
<guid isPermaLink="false">332</guid>
<link>https://antonlyakh.ru/blog/all/oshibki-programmirovaniya-1/</link>
<pubDate>Fri, 21 Feb 2020 12:39:20 +0300</pubDate>
<author>Антон Лях</author>
<comments>https://antonlyakh.ru/blog/all/oshibki-programmirovaniya-1/</comments>
<description>
&lt;p&gt;В коде повторяю одни и те же ошибки. Из-за них ничего не работает. Вот одна.&lt;/p&gt;
&lt;p&gt;&lt;i&gt;При сравнении строк без учета регистра забыл, что у меня юникод.&lt;/i&gt;&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;if (strtolower($input_name) == $name) { ... }&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;В результате функция strtolower вместо строчных русских букв выдала мусор. Сравнение не сработало. Процесс пошел по другой ветке. Пользователь в панике.&lt;/p&gt;
&lt;p&gt;А правильно использовать mb_strtolower.&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;if (mb_strtolower($input_name) == $name) { ... }&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;То же самое относиться и к другим функциям работы со строками. При юникоде и других кодировках использовать функции с префиксом &lt;i&gt;mb_&lt;/i&gt;.&lt;/p&gt;
&lt;p&gt;Успехов.&lt;/p&gt;
</description>
</item>

<item>
<title>Как быстро закомментировать блоки кода</title>
<guid isPermaLink="false">260</guid>
<link>https://antonlyakh.ru/blog/all/kak-bystro-zakommentirovat-bloki-koda/</link>
<pubDate>Fri, 01 Feb 2019 00:27:16 +0300</pubDate>
<author>Антон Лях</author>
<comments>https://antonlyakh.ru/blog/all/kak-bystro-zakommentirovat-bloki-koda/</comments>
<description>
&lt;p&gt;Блок — это фрагмент кода заключенный в условный оператор или цикл.&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;if (push_index &amp;gt; 0 ) {
  // Блок кода
}

for (i=0; i &amp;lt; row_of_areolae.length-1; i++) {
  // Блок кода
}

while (level &amp;lt; maximal_level) {
  // Блок кода
}&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Чтобы быстро исключить блок кода из потока программы, достаточно к условию дописать выражение «Ложь и».&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;if (false &amp;amp;&amp;amp; push_index &amp;gt; 0 ) {
  // Блок кода
}

for (i=0; false &amp;amp;&amp;amp; i &amp;lt; row_of_areolae.length-1; i++) {
  // Блок кода
}

while (false &amp;amp;&amp;amp; level &amp;lt; maximal_level) {
  // Блок кода
}&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Когда фрагмент кода не содержится в цикле или условном операторе, но его нужно то закомментировать, то оставить — принудительно заключаем его в блок. Потом меняем условие блока на «Истину» или «Ложь».&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;// Фрагмент выполняется
if (true) {
	angle = g_sectors[i].fi[1] - ksi;
	k = new_areolae.length-2;
	while ((k&amp;gt;push_index) &amp;amp;&amp;amp; (angle&amp;gt;=g_sectors[i].fi[0])) {
		new_areolae[k][3] = angle;
		new_areolae[k][0] = Math.cos(angle)*level_po;
		new_areolae[k][1] = Math.sin(angle)*level_po;
		//pivot_areola = new_areolae[k];
		angle -= ksi;
		k--;					
	}
}

// Фрагмент не выполняется
if (false) {
	angle = g_sectors[i].fi[1] - ksi;
	k = new_areolae.length-2;
	while ((k&amp;gt;push_index) &amp;amp;&amp;amp; (angle&amp;gt;=g_sectors[i].fi[0])) {
		new_areolae[k][3] = angle;
		new_areolae[k][0] = Math.cos(angle)*level_po;
		new_areolae[k][1] = Math.sin(angle)*level_po;
		//pivot_areola = new_areolae[k];
		angle -= ksi;
		k--;					
	}
}&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Чтобы закомментировать тот же фрагмент кода, надо поставить символы комментария в его начале и конце.&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;/*
	angle = g_sectors[i].fi[1] - ksi;
	k = new_areolae.length-2;
	while ((k&amp;gt;push_index) &amp;amp;&amp;amp; (angle&amp;gt;=g_sectors[i].fi[0])) {
		new_areolae[k][3] = angle;
		new_areolae[k][0] = Math.cos(angle)*level_po;
		new_areolae[k][1] = Math.sin(angle)*level_po;
		//pivot_areola = new_areolae[k];
		angle -= ksi;
		k--;					
	}
*/&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Очевидно, что дописать true или false к условию быстрее и удобнее, чем окружить или освободить блок от символов комментария.&lt;/p&gt;
</description>
</item>

<item>
<title>Директива reintroduce в Дельфи</title>
<guid isPermaLink="true">https://antonlyakh.ru/blog/all/direktiva-reintroduce-v-delfi/</guid>
<link>https://antonlyakh.ru/blog/all/direktiva-reintroduce-v-delfi/</link>
<pubDate>Mon, 13 Aug 2018 15:32:10 +0300</pubDate>
<author>Антон Лях</author>
<comments>https://antonlyakh.ru/blog/all/direktiva-reintroduce-v-delfi/</comments>
<description>
&lt;p&gt;Узнал, что в Дельфи есть директива &lt;b&gt;reintroduce&lt;/b&gt;. Она говорит компиляторуо том, что не надо возмущаться, когда в родственных классах определены функции с одинаковыми именами, но разным набором параметров.&lt;/p&gt;
&lt;p&gt;Здесь компилятор напомнит, что в коде непорядок:&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class="delphi"&gt;
type TFish = class
  procedure swim(); virtual;
end;

type TBoneFish = class(TFish)
  procedure swim(direction : TVector); overload; // Method 'swim' hides virtual method of base type TFish.
end;
&lt;/code&gt;
&lt;/pre&gt;
&lt;p&gt;А здесь все стало правильно:&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class="delphi"&gt;
type TFish = class
  procedure swim(); virtual;;
end;

type TBoneFish = class(TFish)
  procedure swim(direction : TVector); reintroduce; overload;
end;
&lt;/code&gt;
&lt;/pre&gt;
&lt;p&gt;В основном коде можно вызывать оба метода.&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class="pascal"&gt;
  bone_fish.swim(); // куда-то плывем
  bone_fish.swim( to_nutritious_crustacean ); // плывем за питательным рачком
&lt;/code&gt;
&lt;/pre&gt;
</description>
</item>

<item>
<title>Быстро типографируем текст перед показом на странице</title>
<guid isPermaLink="true">https://antonlyakh.ru/blog/all/bystro-tipografiruem-tekst-pered-pokazom-na-stranice/</guid>
<link>https://antonlyakh.ru/blog/all/bystro-tipografiruem-tekst-pered-pokazom-na-stranice/</link>
<pubDate>Tue, 24 Oct 2017 00:31:06 +0300</pubDate>
<author>Антон Лях</author>
<comments>https://antonlyakh.ru/blog/all/bystro-tipografiruem-tekst-pered-pokazom-na-stranice/</comments>
<description>
&lt;p&gt;Перед показом текста на странице его надо обработать по правилам типографики. Это может сделать «&lt;a href="https://www.artlebedev.ru/typograf/"&gt;Типограф&lt;/a&gt;» Студии Лебедева, «&lt;a href="https://github.com/typograf"&gt;Типограф&lt;/a&gt;» Дениса Селезнева или свой движок.&lt;/p&gt;
&lt;p&gt;Если текст написан и не меняется, то  его не надо все время типографить. Достаточно оттипографить один раз, сохранить результат и выводить его до тех пор, пока текст снова не изменится.&lt;/p&gt;
&lt;p&gt;Для этого использую такой механизм.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Создаю исходный текст и сохраняют его в файле с расширением «in».&lt;/li&gt;
&lt;li&gt;В коде страницы вызываю функцию &lt;nobr style="font-family: SegoeUI"&gt;typo_file( ’имя_файла_с_текстом’ )&lt;/nobr&gt;, которая выводит на страницу оттипографированый текст. Имя файла указывается &lt;i&gt;без расширения.&lt;/i&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Функция &lt;nobr style="font-family: SegoeUI"&gt;typo_file( $filename )&lt;/nobr&gt; делает следующее:&lt;/p&gt;
&lt;ol start="1"&gt;
&lt;li&gt;Ищет файл &lt;nobr style="font-family: SegoeUI"&gt;$filename&lt;/nobr&gt; с расширением «in».&lt;/li&gt;
&lt;li&gt;Ищет файл с таким же именем и расширением «out».&lt;/li&gt;
&lt;li&gt;Сравнивает даты модификации файлов.&lt;/li&gt;
&lt;li&gt;Если «out» изменен позже, чем «in», возвращает содержимое «out».&lt;/li&gt;
&lt;li&gt;В противном случае типографит содержимое «in», записывает его в «out» и возвращает результат в основной поток.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Код функции &lt;nobr style="font-family: SegoeUI"&gt;&lt;b&gt;typo_file&lt;/b&gt;&lt;/nobr&gt; на ПХП:&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;&amp;lt;?php

function typo_file( $file_name, $input_extension = '.in', $output_extension = '.out' ) {
   if ( !file_exists($file_name.$input_extension) )
      return '';

   $in_time  = filemtime($file_name.$input_extension);
   $out_time = file_exists($file_name.$output_extension) ? filemtime($file_name.$output_extension) : $in_time-1;

   if ($out_time &amp;lt; $in_time) {
      // типографим содержимое файла
      $in_file  = file_get_contents( $file_name.$input_extension );
      $out_file = typo( $in_file );
      // записываем данные в новый файл
      file_put_contents( $file_name.$output_extension, $out_file );
   } else
      $out_file = file_get_contents( $file_name.$output_extension );

   return $out_file;
}
?&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Функция &lt;nobr style="font-family: SegoeUI"&gt;&lt;b&gt;typo&lt;/b&gt;&lt;/nobr&gt; типографит текст удобным вам способом.&lt;/p&gt;
&lt;p&gt;Содержимое основной страницы выглядит так:&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;&amp;lt;?php
// …

echo typo_file( ‘page_content’ );

// …
?&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Вместо файла с результатом, можно использовать базу данных. В нее заносить оттипографированный текст и время последнего изменения. Ключ для доступа к записи — имя файла.&lt;/p&gt;
</description>
</item>


</channel>
</rss>