{
    "version": "https:\/\/jsonfeed.org\/version\/1",
    "title": "Математик среди биологов: заметки с тегом программирование",
    "_rss_description": "Я немного умею складывать, но от вычитания у меня всегда кружится голова",
    "_rss_language": "ru",
    "_itunes_email": "",
    "_itunes_categories_xml": "",
    "_itunes_image": "",
    "_itunes_explicit": "",
    "home_page_url": "https:\/\/antonlyakh.ru\/blog\/tags\/programmirovanie\/",
    "feed_url": "https:\/\/antonlyakh.ru\/blog\/tags\/programmirovanie\/json\/",
    "icon": false,
    "author": {
        "name": "Антон Лях",
        "url": "https:\/\/antonlyakh.ru\/blog\/",
        "avatar": false
    },
    "items": [
        {
            "id": "496",
            "url": "https:\/\/antonlyakh.ru\/blog\/all\/nedostatok-vychisleniya-opredelitelya-celoischislennyh-matric-na\/",
            "title": "Недостаток вычисления определителя целоисчисленных матриц на Питоне",
            "content_html": "<p><i>Целоисчисленная матрица<\/i> — это матрица, все элементы которой являются целыми числами.<\/p>\n<p>Определитель целоисчисленной матрицы — тоже целое число. (Очевидно же.)<\/p>\n<p>Используем класс целоисчисленных матриц, элементы которых могут принимать только значения из заданного множества целых чисел. (Такие матрицы называют <i>богемными.<\/i>)<\/p>\n<p>Очевидно, что если множество возможных элементов матриц конечно, то и число возможных богемных матриц заданного размера тоже конечно.<\/p>\n<p>Пусть мы ищем среди всех богемных матриц только те, определитель которых равен нулю. Ищем при помощи кода на Питоне. Определитель матрицы вычисляем так:<\/p>\n<pre class=\"e2-text-code\"><code class=\"\">dt = np.linalg.det( a )<\/code><\/pre><p>И вот тут возможна ошибка.<\/p>\n<p>Если мы будем выбирать матрицы по условию <kbd>dt==0<\/kbd>, то получим неверный результат.<\/p>\n<blockquote>\n<p>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 <kbd>np.linalg.det<\/kbd> is <i>computing the determinant from a numerical factoring<\/i> (which introduces rational numbers and rounding error) and the roundoff error means that sometimes a zero determinant was not being reported as precisely zero.<\/p>\n<\/blockquote>\n<p>Правильный результат получится если мы используем условие <kbd>dt&lt;0.5<\/kbd>.<\/p>\n<p><a href=\"https:\/\/computational-discovery-on-jupyter.github.io\/Computational-Discovery-on-Jupyter\/Contents\/bohemian-matrices.html#table-of-results\">https:\/\/computational-discovery-on-jupyter.github.io\/Computational-Discovery-on-Jupyter\/Contents\/bohemian-matrices.html#table-of-results<\/a><\/p>\n",
            "date_published": "2024-06-28T22:13:50+03:00",
            "date_modified": "2024-06-28T22:13:11+03:00",
            "_date_published_rfc2822": "Fri, 28 Jun 2024 22:13:50 +0300",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "496",
            "_e2_data": {
                "is_favourite": false,
                "links_required": [
                    "system\/library\/highlight\/highlight.js",
                    "system\/library\/highlight\/highlight.css",
                    "system\/library\/highlight\/highlight.js",
                    "system\/library\/highlight\/highlight.css"
                ],
                "og_images": []
            }
        },
        {
            "id": "495",
            "url": "https:\/\/antonlyakh.ru\/blog\/all\/vybiraem-v-r-stroki-s-odinakovymi-indeksami-iz-data-table\/",
            "title": "Rесурсы. Выбрать строки с одинаковыми индексами из data.table",
            "content_html": "<p class=\"foot\">Это техническая заметка-напоминалка о некоторых возможностях пакета data.table.<\/p>\n<h4>Задача<\/h4>\n<p>Есть несколько таблиц data.table с данными. Назовем их dt_meta, dt_x, dt_y, dt_area.<\/p>\n<p>В каждой таблице есть колонка the_index.<\/p>\n<p>Из таблицы dt_meta выбираю строки, удовлетворяющие критерию. Например, все строки, в которых значение the_length > 120:<\/p>\n<pre class=\"e2-text-code\"><code class=\"\">dt_meta[the_length &gt; 120]<\/code><\/pre><p>Задача заключается в том, чтобы из остальных таблиц выбрать строки с теми же номерами.<\/p>\n<h4>Решение<\/h4>\n<p>Использую специальный символ <kbd><a href=\"https:\/\/jangorecki.gitlab.io\/data.cube\/library\/data.table\/html\/special-symbols.html\">.I<\/a><\/kbd><\/p>\n<p><kbd>.I<\/kbd> возвращает номера строк. Но у него есть <a href=\"https:\/\/stackoverflow.com\/questions\/23585999\/understanding-i-in-data-table-in-r\">особенности<\/a>.<\/p>\n<p><br\/><\/p>\n<p>Код<\/p>\n<pre class=\"e2-text-code\"><code class=\"\">dt_meta[the_length &gt; 120, .I]<\/code><\/pre><p>вернет последовательные номера строк в новой таблице: 1, 2, 3, ....<\/p>\n<p><br\/><\/p>\n<p>Код<\/p>\n<pre class=\"e2-text-code\"><code class=\"\">dt_meta[, .I[the_length &gt; 120]]<\/code><\/pre><p>вернет номера строк в исходной таблице: 5, 9, 13, 63, ....<\/p>\n<p><br\/><\/p>\n<p>Для решения нужен второй вариант кода. Вот решение.<\/p>\n<pre class=\"e2-text-code\"><code class=\"\"># Номера строк исходной таблицы, в которых the_length &gt; 120\r\nindexes &lt;- dt_meta[, .I[the_length &gt; 120]]\r\n# Выбираю такие же строки из других таблиц\r\nnew_x &lt;- dt_x[indexes]\r\nnew_y &lt;- dt_y[indexes]\r\nnew_area &lt;- dt_area[indexes]<\/code><\/pre>",
            "date_published": "2024-06-21T16:34:01+03:00",
            "date_modified": "2025-03-31T09:40:14+03:00",
            "_date_published_rfc2822": "Fri, 21 Jun 2024 16:34:01 +0300",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "495",
            "_e2_data": {
                "is_favourite": false,
                "links_required": [
                    "system\/library\/highlight\/highlight.js",
                    "system\/library\/highlight\/highlight.css",
                    "system\/library\/highlight\/highlight.js",
                    "system\/library\/highlight\/highlight.css",
                    "system\/library\/highlight\/highlight.js",
                    "system\/library\/highlight\/highlight.css",
                    "system\/library\/highlight\/highlight.js",
                    "system\/library\/highlight\/highlight.css",
                    "system\/library\/highlight\/highlight.js",
                    "system\/library\/highlight\/highlight.css",
                    "system\/library\/highlight\/highlight.js",
                    "system\/library\/highlight\/highlight.css",
                    "system\/library\/highlight\/highlight.js",
                    "system\/library\/highlight\/highlight.css",
                    "system\/library\/highlight\/highlight.js",
                    "system\/library\/highlight\/highlight.css"
                ],
                "og_images": []
            }
        },
        {
            "id": "460",
            "url": "https:\/\/antonlyakh.ru\/blog\/all\/sdelay-sam\/",
            "title": "Сделай сам",
            "content_html": "<div class=\"e2-text-picture\">\n<img src=\"https:\/\/antonlyakh.ru\/blog\/pictures\/Sdelay-sam.png\" width=\"800\" height=\"569\" alt=\"\" \/>\n<div class=\"e2-text-caption\">Повторное использование чужих приемов — это нормально<\/div>\n<\/div>\n<p>Я сам пишу большинство программ с использованием своих библиотек. То есть, конечно, у меня есть некие базовые библиотеки, однажды найденные на просторах сети, но этим дело и ограничивается.<\/p>\n<p>Когда у меня есть задача написать программу, я сажусь и пишу ее сам: продумываю алгоритм, интерфейс, пишу код, тестирую, правлю, опять тестирую и выпускаю релиз.<\/p>\n<p>Я не люблю ковыряться в чужом коде или разбираться в документации чьей-то библиотеки, так как при этом ничего не получаю взамен, кроме усталости и отупения.<\/p>\n<p><i>Дополнено через пару месяцев.<\/i><br \/>\nОднако мой подход старомоден и в будущем перейду на повторное использование чужих приемов. Ибо любой код когда-нибудь кем-нибудь будет написан, будет написан хорошо и будет доступен всем. Незачем отвергать хорошие вещи.<\/p>\n",
            "date_published": "2022-10-18T16:40:00+03:00",
            "date_modified": "2022-10-18T20:59:05+03:00",
            "image": "https:\/\/antonlyakh.ru\/blog\/pictures\/Sdelay-sam.png",
            "_date_published_rfc2822": "Tue, 18 Oct 2022 16:40:00 +0300",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "460",
            "_e2_data": {
                "is_favourite": false,
                "links_required": [],
                "og_images": [
                    "https:\/\/antonlyakh.ru\/blog\/pictures\/Sdelay-sam.png"
                ]
            }
        },
        {
            "id": "451",
            "url": "https:\/\/antonlyakh.ru\/blog\/all\/associativny-massiv-v-staryh-versiyah-delfi\/",
            "title": "Ассоциативный массив в старых версиях Дельфи",
            "content_html": "<p>В Королевстве Дельфи много лет назад Дмитрий Рябов предложил <a href=\"http:\/\/www.delphikingdom.com\/asp\/viewitem.asp?catalogid=868\">реализацию ассоциативных массивов<\/a>.<\/p>\n<blockquote>\n<blockquote>\n<p>«На практике часто возникает потребность сохранять и обрабатывать данные в массивах, осуществляя доступ к элементам не по индексу, а по ключу. Для этого используются ассоциативные массивы, которые есть, например, во многих скриптовых языках. В <abbr>Delphi<\/abbr> на уровне языка такая структура отсутствует. В качестве замены часто используются контейнерные классы <abbr>TStringList<\/abbr>, <abbr>TParams<\/abbr> и т. п., но они весьма неудобны в использовании и недостаточно функциональны. К тому же появляется необходимость заботиться об уничтожении экземпляра класса, что зачастую порождает лишние <abbr>try..finally..end<\/abbr>.»<\/p>\n<\/blockquote>\n<\/blockquote>\n<p>В чем фишка реализации.<\/p>\n<blockquote>\n<blockquote>\n<p>«Удобное использование, неплохая производительность, отсутствие небходимости принудительного уничтожения, нескольно представлений одного массива, использование ключей разных типов, наличие функций итератора, удобное использование многомерных массивов.»»<\/p>\n<\/blockquote>\n<\/blockquote>\n<p>Я иногда ее использую в своих проектах и всегда опасаюсь, что текст с примерами будет окончательно потерян. Потому решил воспроизвести его здесь.<\/p>\n<hr \/>\n<pre class=\"e2-text-code\"><code class=\"\">program Example;\r\n{$APPTYPE CONSOLE}\r\nuses\r\n  Arrays;\r\n\r\nprocedure Main;\r\nvar\r\n  I: IIntArray;\r\n  S: IStrArray;\r\n  V: IVarArray;\r\n  M: IMltArray;\r\n\r\nbegin\r\n  \/\/ создаём массив и получаем представление в целых числах\r\n  I := CreateArray;\r\n\r\n  \/\/ заполняем\r\n  I['a'] := 5;\r\n  I['b'] := 1;\r\n  I['c'] := 4;\r\n  I['d'] := 2;\r\n  I['e'] := 3;\r\n\r\n  \/\/ выводим\r\n  WriteLn('Original array');\r\n  I.First;\r\n  while not I.Eof do\r\n  begin\r\n    WriteLn('[', I.CurrentKey, '] = ', I.CurrentValue);\r\n    I.Next;\r\n  end;\r\n\r\n  \/\/ сортируем\r\n  I.Sort;\r\n\r\n  \/\/ наблюдаем результат\r\n  WriteLn('Sorted array');\r\n  I.First;\r\n  while not I.Eof do\r\n  begin\r\n    WriteLn('[', I.CurrentKey, '] = ', I.CurrentValue);\r\n    I.Next;\r\n  end;\r\n\r\n  \/\/ создаём строковое представление\r\n  S := I.Instance;\r\n\r\n  \/\/ наблюдаем результат\r\n  WriteLn('Two views of one array');\r\n  S.First;\r\n  while not S.Eof do\r\n  begin\r\n    WriteLn('[', S.CurrentKey, '] + ''10'' = ', S.CurrentValue + '10');\r\n    WriteLn('[', I.CurrentKey, '] + 10 = ', I.CurrentValue + 10);\r\n    S.Next;\r\n  end;\r\n\r\n  \/\/ создаём вариантное представление\r\n  V := S.Instance;\r\n  V.Clear;\r\n  V['integer'] := 10;\r\n  V['string'] := '10';\r\n\r\n  \/\/ наблюдаем результат\r\n  WriteLn('Variant type conversion');\r\n  V.First;\r\n  while not V.Eof do\r\n  begin\r\n    WriteLn('[', V.CurrentKey, '] + 10 = ', V.CurrentValue + 10);\r\n    WriteLn('[', V.CurrentKey, '] + ''10'' = ', V.CurrentValue + '10');\r\n    V.Next;\r\n  end;\r\n\r\n  \/\/ используем ключи разных типов, но одного значения\r\n  S.Clear;\r\n  S[False] := 'boolean';\r\n  S[0] := 'integer';\r\n  S[0.0] := 'float';\r\n  S['0'] := 'string';\r\n\r\n  \/\/ наблюдаем результат\r\n  WriteLn('Variant type keys ;)');\r\n  S.First;\r\n  while not S.Eof do\r\n  begin\r\n    WriteLn('[', S.CurrentKey, '] = ', S.CurrentValue);\r\n    S.Next;\r\n  end;\r\n\r\n  \/\/ создаём ещё одно представление, на этот раз - многомерное\r\n  M := V.Instance;\r\n  M.Clear;\r\n\r\n  \/\/ заполняем матрицу\r\n  M['A']['a'].AsInteger := 1;\r\n  M['A']['b'].AsInteger := 2;\r\n  M['A']['c'].AsInteger := 3;\r\n  M['B']['a'].AsInteger := 4;\r\n  M['B']['b'].AsInteger := 5;\r\n  M['B']['c'].AsInteger := 6;\r\n  M['C']['a'].AsInteger := 7;\r\n  M['C']['b'].AsInteger := 8;\r\n  M['C']['c'].AsInteger := 9;\r\n\r\n  \/\/ выводим матрицу\r\n  WriteLn('Multidimensional array');\r\n  M.First;\r\n  while not M.Eof do\r\n  begin\r\n    M.CurrentValue.First;\r\n    while not M.CurrentValue.Eof do\r\n    begin\r\n      WriteLn('[', M.CurrentKey, ',', M.CurrentValue.CurrentKey, '] = ',\r\n        M.CurrentValue.CurrentValue.AsInteger);\r\n      M.CurrentValue.Next;\r\n    end;\r\n    M.Next;\r\n  end;\r\n\r\n  \/\/ перед возвратом все созданные массивы автоматически удаляются\r\n  WriteLn('Arrays is free');\r\nend;\r\n\r\nvar\r\n  L: Integer;\r\nbegin\r\n  L := AllocMemSize;\r\n  Main;\r\n  \/\/ проверка утечки памяти\r\n  WriteLn('Memory leak: ', AllocMemSize - L, ' bytes');\r\n  ReadLn;\r\nend.<\/code><\/pre><hr \/>\n<p><b><a href=\"http:\/\/www.delphikingdom.com\/zip\/arrays.zip\">Скачать исходники из Королевства<\/a><\/b><\/p>\n<p><b><a href=\"https:\/\/stackoverflow.com\/a\/51830939\/1615266\">Посмотреть рекомендацию оссоциативного массива<\/a><\/b> на Стакэксчендже .<\/p>\n",
            "date_published": "2022-04-19T11:08:05+03:00",
            "date_modified": "2022-04-19T11:52:43+03:00",
            "_date_published_rfc2822": "Tue, 19 Apr 2022 11:08:05 +0300",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "451",
            "_e2_data": {
                "is_favourite": false,
                "links_required": [
                    "system\/library\/highlight\/highlight.js",
                    "system\/library\/highlight\/highlight.css",
                    "system\/library\/highlight\/highlight.js",
                    "system\/library\/highlight\/highlight.css"
                ],
                "og_images": []
            }
        },
        {
            "id": "438",
            "url": "https:\/\/antonlyakh.ru\/blog\/all\/priem-programmirovaniya-vovremya-ostanovitsya\/",
            "title": "Прием программирования: Вовремя остановиться",
            "content_html": "<p>Иногда я пишу одноразовый код, который, например, что-то переносит из файла в базу данных. Этот код мне понадобиться один раз, но удалять его после использования жалко.<\/p>\n<p>Для того, чтобы код нельзя было больше выполнить, я внедряю в него оператор die().<\/p>\n<div class=\"e2-text-picture\">\n<img src=\"https:\/\/antonlyakh.ru\/blog\/pictures\/program-die.png\" width=\"800\" height=\"361\" alt=\"\" \/>\n<\/div>\n<p>Главное — вовремя остановиться.<\/p>\n",
            "date_published": "2021-08-31T22:13:58+03:00",
            "date_modified": "2021-08-31T22:13:45+03:00",
            "image": "https:\/\/antonlyakh.ru\/blog\/pictures\/program-die.png",
            "_date_published_rfc2822": "Tue, 31 Aug 2021 22:13:58 +0300",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "438",
            "_e2_data": {
                "is_favourite": false,
                "links_required": [],
                "og_images": [
                    "https:\/\/antonlyakh.ru\/blog\/pictures\/program-die.png"
                ]
            }
        },
        {
            "id": "391",
            "url": "https:\/\/antonlyakh.ru\/blog\/all\/priemy-programmirovaniya-vernut-vektor\/",
            "title": "Приемы программирования. Вернуть вектор",
            "content_html": "<p>Иногда функция должна вернуть не одно, а несколько значений. Например флаг успеха или неудачи, несколько найденных параметров и массив. Фактически она возвращает векторный результат.<\/p>\n<p>Раньше для получения векторного результата я передавал несколько переменных по ссылке и ждал булево значение функции.<\/p>\n<pre class=\"e2-text-code\"><code class=\"\">\/\/ Здесь ожидаю два параметра и двумерный массив, а функция возвращает флаг успеха-неудачи.\r\nfunction navalniy( \r\n    source_data : TVector; var temperature : real; var blood_pressure : real; var spy_data : TVector\r\n) : boolean;<\/code><\/pre><p>Теперь я просто получаю один векторный результат.<\/p>\n<pre class=\"e2-text-code\"><code class=\"\">function navalniy( source_data : TVector ) : TVector;<\/code><\/pre><p>Первый компонент вектора содержит флаг успеха и вычисленные скалярные параметры, остальные — заполненный массив.<\/p>\n<pre class=\"e2-text-code\"><code class=\"cpp\">\r\nspy_data = navalniy( source_data );\r\nif (spy_data[0][0] == 0) {\r\n  alert(‘Явка провалена. Немедленно уходить!’);\r\n  exit();\r\n} else {\r\n  temperature = spy_data[0][1];\r\n  blood_pressure = spy_data[0][2];\r\n  list_of_comrades = (spy_data[1], …, spy_data[M]);\r\n  \/\/ Все в порядке, продолжаем готовить революцию\r\n  \/\/ …\r\n}\r\n<\/code>\n<\/pre>\n<p>Единственное, при таком подходе нужно следить, чтобы размерность второй координаты массива (resulted_array[•][×]) была не меньше размерности ожидаемых дополнительных параметров (param{i}). В противном случае параметры следует вернуть в нескольких начальных  компонентах ветора-результата.<\/p>\n<pre class=\"e2-text-code\"><code class=\"cpp\">\r\nspy_data = navalniy( source_data );\r\nif (spy_dat[0][0] > 0) {\r\n  temperature =spy_dat[0][1];\r\n  blood_pressure = spy_dat[0][2];\r\n  leukocytes = spy_datt[1][0];\r\n  hemoglobin = spy_dat[1][1];\r\n  erythrocytes = spy_dat[1][2];\r\n  \/\/ Возвращенный массив начинается с N-ой компоненты вектора-результата\r\n  list_of_comrades = (spy_dat[N], …, spy_dat[M]);\r\n  \/\/ …\r\n}\r\n<\/code>\n<\/pre>\n<p>Векторы — это сила.<\/p>\n",
            "date_published": "2020-09-16T18:29:33+03:00",
            "date_modified": "2020-09-16T18:29:20+03:00",
            "_date_published_rfc2822": "Wed, 16 Sep 2020 18:29:33 +0300",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "391",
            "_e2_data": {
                "is_favourite": false,
                "links_required": [
                    "system\/library\/highlight\/highlight.js",
                    "system\/library\/highlight\/highlight.css",
                    "system\/library\/highlight\/highlight.js",
                    "system\/library\/highlight\/highlight.css",
                    "system\/library\/highlight\/highlight.js",
                    "system\/library\/highlight\/highlight.css",
                    "system\/library\/highlight\/highlight.js",
                    "system\/library\/highlight\/highlight.css",
                    "system\/library\/highlight\/highlight.js",
                    "system\/library\/highlight\/highlight.css",
                    "system\/library\/highlight\/highlight.js",
                    "system\/library\/highlight\/highlight.css"
                ],
                "og_images": []
            }
        },
        {
            "id": "385",
            "url": "https:\/\/antonlyakh.ru\/blog\/all\/priemy-veb-programmirovaniya-razreshit-apachu-snachala-iskat-fay\/",
            "title": "Приемы веб-программирования. Разрешить Апачу сначала искать файлы в текущем каталоге",
            "content_html": "<p>Памятка тем, кто (до сих пор) руками пишет веб-движки на ПХП.<\/p>\n<p>У вас есть два файла с одинаковым названием ’konstituciya.php’ в текущем и каком-то системном каталоге. Файл в системном каталоге делает основную работу, например, выводит перечень статей конституции. Файл в текущем каталоге устанавливает локальные настройки, например, вносит в конституцию поправки, а потом вызывает файл из системного каталога. Чтобы поправки вступили в силу, необходимо, чтобы первым был вызван файл из текущего каталога. Вот так:<\/p>\n<blockquote>\n<p>konstituciya.php → .\/system\/konstituciya.php<\/p>\n<\/blockquote>\n<p>Чтобы установить такую последовательность вызовов, в .htaccess в списке путей первой поставьте точку, а потом перечислите прочие каталоги:<\/p>\n<pre class=\"e2-text-code\"><code class=\"\">php_value include_path &quot;.:\/home\/system&quot;<\/code><\/pre><p>Тогда код выполнится правильно:<\/p>\n<pre class=\"e2-text-code\"><code class=\"\">\/\/ Сначала вызовет файл из текущего каталога с поправками, а потом системный файл с основными законами\r\n   include_once &quot;konstituciya.php&quot;;<\/code><\/pre><p>Удачи.<\/p>\n",
            "date_published": "2020-06-10T16:13:07+03:00",
            "date_modified": "2020-06-11T14:57:12+03:00",
            "_date_published_rfc2822": "Wed, 10 Jun 2020 16:13:07 +0300",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "385",
            "_e2_data": {
                "is_favourite": false,
                "links_required": [
                    "system\/library\/highlight\/highlight.js",
                    "system\/library\/highlight\/highlight.css",
                    "system\/library\/highlight\/highlight.js",
                    "system\/library\/highlight\/highlight.css",
                    "system\/library\/highlight\/highlight.js",
                    "system\/library\/highlight\/highlight.css",
                    "system\/library\/highlight\/highlight.js",
                    "system\/library\/highlight\/highlight.css"
                ],
                "og_images": []
            }
        },
        {
            "id": "352",
            "url": "https:\/\/antonlyakh.ru\/blog\/all\/priemy-programmirovaniya-zalit-fayly-na-server\/",
            "title": "Приемы программирования. Залить файлы на сервер",
            "content_html": "<p>Облачные сервисы предлагают загрузить файлы на виртуальный диск при помощью интерфейса. Тащишь группу файлов, бросаешь в окно и они понемногу загружаются, а сервис выдает красивые прогресс-бары. При этом внутри кипит работа: сервис проверяет формат и размер файлов, следит за устойчивой передачей и рисует прогресс-бары, по завершению выдает сообщения, заносит данные в базу данных и размещает файлы в надежном месте.<\/p>\n<p>Такой сценарий нужен, когда виртуальным диском пользуются десятки пользователей. А для тестирования небольших проектов, когда группа пользователей ограничена двумя-тремя персонами, рекомендую закачивать файлы в выделенный каталог сервера. По Эс-Эс-Аш или ФТП, например. После, специальный скрипт сканирует каталог, обрабатывает файлы, запоминает метаданные в таблицах и реализует дальнейший интерфейс.<\/p>\n<p>Именно так я тестирую «Фотосистематизатор».<\/p>\n<div class=\"e2-text-picture\">\n<img src=\"https:\/\/antonlyakh.ru\/blog\/pictures\/fotosistema-screen-1.png\" width=\"800\" height=\"526\" alt=\"\" \/>\n<div class=\"e2-text-caption\">Фотосистематизатор берет фотографии прямо из каталога, а пользователь закачивает их туда напрямую, без интерфейсных наворотов<\/div>\n<\/div>\n",
            "date_published": "2020-03-17T17:47:11+03:00",
            "date_modified": "2020-03-17T17:46:56+03:00",
            "image": "https:\/\/antonlyakh.ru\/blog\/pictures\/fotosistema-screen-1.png",
            "_date_published_rfc2822": "Tue, 17 Mar 2020 17:47:11 +0300",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "352",
            "_e2_data": {
                "is_favourite": false,
                "links_required": [],
                "og_images": [
                    "https:\/\/antonlyakh.ru\/blog\/pictures\/fotosistema-screen-1.png"
                ]
            }
        },
        {
            "id": "339",
            "url": "https:\/\/antonlyakh.ru\/blog\/all\/priemy-programmirovaniya-nenuzhny-fayl-s-kodom-srazu-ne-udalyayu\/",
            "title": "Приемы программирования. Ненужный файл с кодом не удаляю, а переименовываю",
            "content_html": "<p>Бывает, что файл с фрагментом кода уже не нужен. Например потому, что код из него переписан, усовершенствован и перенесен в другой файл. Тогда такой файл я сразу не удаляю, а приписываю к нему приставку <i>’del-’<\/i>.<\/p>\n<div class=\"e2-text-picture\">\n<img src=\"https:\/\/antonlyakh.ru\/blog\/pictures\/del-prefix.png\" width=\"228\" height=\"121\" alt=\"\" \/>\n<\/div>\n<p>После тестирую, нет ли ошибок и все ли работает правильно. Потом жду несколько дней и только после этого бесповоротно удаляю файл.<\/p>\n",
            "date_published": "2020-02-26T00:39:33+03:00",
            "date_modified": "2020-03-15T20:08:18+03:00",
            "image": "https:\/\/antonlyakh.ru\/blog\/pictures\/del-prefix.png",
            "_date_published_rfc2822": "Wed, 26 Feb 2020 00:39:33 +0300",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "339",
            "_e2_data": {
                "is_favourite": false,
                "links_required": [],
                "og_images": [
                    "https:\/\/antonlyakh.ru\/blog\/pictures\/del-prefix.png"
                ]
            }
        },
        {
            "id": "332",
            "url": "https:\/\/antonlyakh.ru\/blog\/all\/oshibki-programmirovaniya-1\/",
            "title": "Ошибки программирования. Забыл про юникод",
            "content_html": "<p>В коде повторяю одни и те же ошибки. Из-за них ничего не работает. Вот одна.<\/p>\n<p><i>При сравнении строк без учета регистра забыл, что у меня юникод.<\/i><\/p>\n<pre class=\"e2-text-code\"><code class=\"\">if (strtolower($input_name) == $name) { ... }<\/code><\/pre><p>В результате функция strtolower вместо строчных русских букв выдала мусор. Сравнение не сработало. Процесс пошел по другой ветке. Пользователь в панике.<\/p>\n<p>А правильно использовать mb_strtolower.<\/p>\n<pre class=\"e2-text-code\"><code class=\"\">if (mb_strtolower($input_name) == $name) { ... }<\/code><\/pre><p>То же самое относиться и к другим функциям работы со строками. При юникоде и других кодировках использовать функции с префиксом <i>mb_<\/i>.<\/p>\n<p>Успехов.<\/p>\n",
            "date_published": "2020-02-21T12:39:20+03:00",
            "date_modified": "2020-03-15T20:08:45+03:00",
            "_date_published_rfc2822": "Fri, 21 Feb 2020 12:39:20 +0300",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "332",
            "_e2_data": {
                "is_favourite": false,
                "links_required": [
                    "system\/library\/highlight\/highlight.js",
                    "system\/library\/highlight\/highlight.css",
                    "system\/library\/highlight\/highlight.js",
                    "system\/library\/highlight\/highlight.css",
                    "system\/library\/highlight\/highlight.js",
                    "system\/library\/highlight\/highlight.css",
                    "system\/library\/highlight\/highlight.js",
                    "system\/library\/highlight\/highlight.css"
                ],
                "og_images": []
            }
        },
        {
            "id": "260",
            "url": "https:\/\/antonlyakh.ru\/blog\/all\/kak-bystro-zakommentirovat-bloki-koda\/",
            "title": "Как быстро закомментировать блоки кода",
            "content_html": "<p>Блок — это фрагмент кода заключенный в условный оператор или цикл.<\/p>\n<pre class=\"e2-text-code\"><code class=\"\">if (push_index &gt; 0 ) {\r\n  \/\/ Блок кода\r\n}\r\n\r\nfor (i=0; i &lt; row_of_areolae.length-1; i++) {\r\n  \/\/ Блок кода\r\n}\r\n\r\nwhile (level &lt; maximal_level) {\r\n  \/\/ Блок кода\r\n}<\/code><\/pre><p>Чтобы быстро исключить блок кода из потока программы, достаточно к условию дописать выражение «Ложь и».<\/p>\n<pre class=\"e2-text-code\"><code class=\"\">if (false &amp;&amp; push_index &gt; 0 ) {\r\n  \/\/ Блок кода\r\n}\r\n\r\nfor (i=0; false &amp;&amp; i &lt; row_of_areolae.length-1; i++) {\r\n  \/\/ Блок кода\r\n}\r\n\r\nwhile (false &amp;&amp; level &lt; maximal_level) {\r\n  \/\/ Блок кода\r\n}<\/code><\/pre><p>Когда фрагмент кода не содержится в цикле или условном операторе, но его нужно то закомментировать, то оставить — принудительно заключаем его в блок. Потом меняем условие блока на «Истину» или «Ложь».<\/p>\n<pre class=\"e2-text-code\"><code class=\"\">\/\/ Фрагмент выполняется\r\nif (true) {\r\n\tangle = g_sectors[i].fi[1] - ksi;\r\n\tk = new_areolae.length-2;\r\n\twhile ((k&gt;push_index) &amp;&amp; (angle&gt;=g_sectors[i].fi[0])) {\r\n\t\tnew_areolae[k][3] = angle;\r\n\t\tnew_areolae[k][0] = Math.cos(angle)*level_po;\r\n\t\tnew_areolae[k][1] = Math.sin(angle)*level_po;\r\n\t\t\/\/pivot_areola = new_areolae[k];\r\n\t\tangle -= ksi;\r\n\t\tk--;\t\t\t\t\t\r\n\t}\r\n}\r\n\r\n\/\/ Фрагмент не выполняется\r\nif (false) {\r\n\tangle = g_sectors[i].fi[1] - ksi;\r\n\tk = new_areolae.length-2;\r\n\twhile ((k&gt;push_index) &amp;&amp; (angle&gt;=g_sectors[i].fi[0])) {\r\n\t\tnew_areolae[k][3] = angle;\r\n\t\tnew_areolae[k][0] = Math.cos(angle)*level_po;\r\n\t\tnew_areolae[k][1] = Math.sin(angle)*level_po;\r\n\t\t\/\/pivot_areola = new_areolae[k];\r\n\t\tangle -= ksi;\r\n\t\tk--;\t\t\t\t\t\r\n\t}\r\n}<\/code><\/pre><p>Чтобы закомментировать тот же фрагмент кода, надо поставить символы комментария в его начале и конце.<\/p>\n<pre class=\"e2-text-code\"><code class=\"\">\/*\r\n\tangle = g_sectors[i].fi[1] - ksi;\r\n\tk = new_areolae.length-2;\r\n\twhile ((k&gt;push_index) &amp;&amp; (angle&gt;=g_sectors[i].fi[0])) {\r\n\t\tnew_areolae[k][3] = angle;\r\n\t\tnew_areolae[k][0] = Math.cos(angle)*level_po;\r\n\t\tnew_areolae[k][1] = Math.sin(angle)*level_po;\r\n\t\t\/\/pivot_areola = new_areolae[k];\r\n\t\tangle -= ksi;\r\n\t\tk--;\t\t\t\t\t\r\n\t}\r\n*\/<\/code><\/pre><p>Очевидно, что дописать true или false к условию быстрее и удобнее, чем окружить или освободить блок от символов комментария.<\/p>\n",
            "date_published": "2019-02-01T00:27:16+03:00",
            "date_modified": "2020-10-04T20:10:26+03:00",
            "_date_published_rfc2822": "Fri, 01 Feb 2019 00:27:16 +0300",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "260",
            "_e2_data": {
                "is_favourite": false,
                "links_required": [
                    "system\/library\/highlight\/highlight.js",
                    "system\/library\/highlight\/highlight.css",
                    "system\/library\/highlight\/highlight.js",
                    "system\/library\/highlight\/highlight.css",
                    "system\/library\/highlight\/highlight.js",
                    "system\/library\/highlight\/highlight.css",
                    "system\/library\/highlight\/highlight.js",
                    "system\/library\/highlight\/highlight.css",
                    "system\/library\/highlight\/highlight.js",
                    "system\/library\/highlight\/highlight.css",
                    "system\/library\/highlight\/highlight.js",
                    "system\/library\/highlight\/highlight.css",
                    "system\/library\/highlight\/highlight.js",
                    "system\/library\/highlight\/highlight.css",
                    "system\/library\/highlight\/highlight.js",
                    "system\/library\/highlight\/highlight.css"
                ],
                "og_images": []
            }
        },
        {
            "id": "211",
            "url": "https:\/\/antonlyakh.ru\/blog\/all\/direktiva-reintroduce-v-delfi\/",
            "title": "Директива reintroduce в Дельфи",
            "content_html": "<p>Узнал, что в Дельфи есть директива <b>reintroduce<\/b>. Она говорит компиляторуо том, что не надо возмущаться, когда в родственных классах определены функции с одинаковыми именами, но разным набором параметров.<\/p>\n<p>Здесь компилятор напомнит, что в коде непорядок:<\/p>\n<pre class=\"e2-text-code\"><code class=\"delphi\">\r\ntype TFish = class\r\n  procedure swim(); virtual;\r\nend;\r\n\r\ntype TBoneFish = class(TFish)\r\n  procedure swim(direction : TVector); overload; \/\/ Method 'swim' hides virtual method of base type TFish.\r\nend;\r\n<\/code>\n<\/pre>\n<p>А здесь все стало правильно:<\/p>\n<pre class=\"e2-text-code\"><code class=\"delphi\">\r\ntype TFish = class\r\n  procedure swim(); virtual;;\r\nend;\r\n\r\ntype TBoneFish = class(TFish)\r\n  procedure swim(direction : TVector); reintroduce; overload;\r\nend;\r\n<\/code>\n<\/pre>\n<p>В основном коде можно вызывать оба метода.<\/p>\n<pre class=\"e2-text-code\"><code class=\"pascal\">\r\n  bone_fish.swim(); \/\/ куда-то плывем\r\n  bone_fish.swim( to_nutritious_crustacean ); \/\/ плывем за питательным рачком\r\n<\/code>\n<\/pre>\n",
            "date_published": "2018-08-13T15:32:10+03:00",
            "date_modified": "2018-08-13T15:18:31+03:00",
            "_date_published_rfc2822": "Mon, 13 Aug 2018 15:32:10 +0300",
            "_rss_guid_is_permalink": "true",
            "_rss_guid": "https:\/\/antonlyakh.ru\/blog\/all\/direktiva-reintroduce-v-delfi\/",
            "_e2_data": {
                "is_favourite": false,
                "links_required": [
                    "system\/library\/highlight\/highlight.js",
                    "system\/library\/highlight\/highlight.css",
                    "system\/library\/highlight\/highlight.js",
                    "system\/library\/highlight\/highlight.css",
                    "system\/library\/highlight\/highlight.js",
                    "system\/library\/highlight\/highlight.css"
                ],
                "og_images": []
            }
        },
        {
            "id": "169",
            "url": "https:\/\/antonlyakh.ru\/blog\/all\/bystro-tipografiruem-tekst-pered-pokazom-na-stranice\/",
            "title": "Быстро типографируем текст перед показом на странице",
            "content_html": "<p>Перед показом текста на странице его надо обработать по правилам типографики. Это может сделать «<a href=\"https:\/\/www.artlebedev.ru\/typograf\/\">Типограф<\/a>» Студии Лебедева, «<a href=\"https:\/\/github.com\/typograf\">Типограф<\/a>» Дениса Селезнева или свой движок.<\/p>\n<p>Если текст написан и не меняется, то  его не надо все время типографить. Достаточно оттипографить один раз, сохранить результат и выводить его до тех пор, пока текст снова не изменится.<\/p>\n<p>Для этого использую такой механизм.<\/p>\n<ul>\n<li>Создаю исходный текст и сохраняют его в файле с расширением «in».<\/li>\n<li>В коде страницы вызываю функцию <nobr style=\"font-family: SegoeUI\">typo_file( ’имя_файла_с_текстом’ )<\/nobr>, которая выводит на страницу оттипографированый текст. Имя файла указывается <i>без расширения.<\/i><\/li>\n<\/ul>\n<p>Функция <nobr style=\"font-family: SegoeUI\">typo_file( $filename )<\/nobr> делает следующее:<\/p>\n<ol start=\"1\">\n<li>Ищет файл <nobr style=\"font-family: SegoeUI\">$filename<\/nobr> с расширением «in».<\/li>\n<li>Ищет файл с таким же именем и расширением «out».<\/li>\n<li>Сравнивает даты модификации файлов.<\/li>\n<li>Если «out» изменен позже, чем «in», возвращает содержимое «out».<\/li>\n<li>В противном случае типографит содержимое «in», записывает его в «out» и возвращает результат в основной поток.<\/li>\n<\/ol>\n<p>Код функции <nobr style=\"font-family: SegoeUI\"><b>typo_file<\/b><\/nobr> на ПХП:<\/p>\n<pre class=\"e2-text-code\"><code class=\"\">&lt;?php\r\n\r\nfunction typo_file( $file_name, $input_extension = '.in', $output_extension = '.out' ) {\r\n   if ( !file_exists($file_name.$input_extension) )\r\n      return '';\r\n\r\n   $in_time  = filemtime($file_name.$input_extension);\r\n   $out_time = file_exists($file_name.$output_extension) ? filemtime($file_name.$output_extension) : $in_time-1;\r\n\r\n   if ($out_time &lt; $in_time) {\r\n      \/\/ типографим содержимое файла\r\n      $in_file  = file_get_contents( $file_name.$input_extension );\r\n      $out_file = typo( $in_file );\r\n      \/\/ записываем данные в новый файл\r\n      file_put_contents( $file_name.$output_extension, $out_file );\r\n   } else\r\n      $out_file = file_get_contents( $file_name.$output_extension );\r\n\r\n   return $out_file;\r\n}\r\n?&gt;<\/code><\/pre><p>Функция <nobr style=\"font-family: SegoeUI\"><b>typo<\/b><\/nobr> типографит текст удобным вам способом.<\/p>\n<p>Содержимое основной страницы выглядит так:<\/p>\n<pre class=\"e2-text-code\"><code class=\"\">&lt;?php\r\n\/\/ …\r\n\r\necho typo_file( ‘page_content’ );\r\n\r\n\/\/ …\r\n?&gt;<\/code><\/pre><p>Вместо файла с результатом, можно использовать базу данных. В нее заносить оттипографированный текст и время последнего изменения. Ключ для доступа к записи — имя файла.<\/p>\n",
            "date_published": "2017-10-24T00:31:06+03:00",
            "date_modified": "2020-10-04T20:09:30+03:00",
            "_date_published_rfc2822": "Tue, 24 Oct 2017 00:31:06 +0300",
            "_rss_guid_is_permalink": "true",
            "_rss_guid": "https:\/\/antonlyakh.ru\/blog\/all\/bystro-tipografiruem-tekst-pered-pokazom-na-stranice\/",
            "_e2_data": {
                "is_favourite": true,
                "links_required": [
                    "system\/library\/highlight\/highlight.js",
                    "system\/library\/highlight\/highlight.css",
                    "system\/library\/highlight\/highlight.js",
                    "system\/library\/highlight\/highlight.css",
                    "system\/library\/highlight\/highlight.js",
                    "system\/library\/highlight\/highlight.css",
                    "system\/library\/highlight\/highlight.js",
                    "system\/library\/highlight\/highlight.css"
                ],
                "og_images": []
            }
        }
    ],
    "_e2_version": 3559,
    "_e2_ua_string": "E2 (v3559; Aegea)"
}