{
    "version": "https:\/\/jsonfeed.org\/version\/1.1",
    "title": "Блог Ильи Бирмана: заметки с тегом веб-разработка",
    "_rss_description": "Блог Ильи Бирмана о дизайне, городах, музыке и жизни.",
    "_rss_language": "ru",
    "_itunes_email": "ilyabirman@ilyabirman.ru",
    "_itunes_categories_xml": "<itunes:category text=\"Arts\"><itunes:category text=\"Design\" \/><\/itunes:category>\r\n<itunes:category text=\"Society &amp; Culture\"><itunes:category text=\"Personal Journals\" \/><\/itunes:category>\r\n<itunes:category text=\"Technology\" \/>\r\n",
    "_itunes_image": "https:\/\/ilyabirman.ru\/meanwhile\/pictures\/userpic\/userpic-square@2x.jpg?1573933764",
    "_itunes_explicit": "no",
    "home_page_url": "https:\/\/ilyabirman.ru\/meanwhile\/tags\/web-dev\/",
    "feed_url": "https:\/\/ilyabirman.ru\/meanwhile\/tags\/web-dev\/json\/",
    "icon": "https:\/\/ilyabirman.ru\/meanwhile\/pictures\/userpic\/userpic@2x.jpg?1573933764",
    "authors": [
        {
            "name": "Илья Бирман",
            "url": "https:\/\/ilyabirman.ru\/meanwhile\/",
            "avatar": "https:\/\/ilyabirman.ru\/meanwhile\/pictures\/userpic\/userpic@2x.jpg?1573933764"
        }
    ],
    "items": [
        {
            "id": "6111",
            "url": "https:\/\/ilyabirman.ru\/meanwhile\/all\/weekend-reading-190\/",
            "title": "Что почитать на выходных — 190",
            "content_html": "<p>Вот:<\/p>\n<ol start=\"1\">\n  <li><a href=\"https:\/\/blog.buro.cx\/cx-telezhka\/\">Кейс: идеальная тележка для Пятёрочки<\/a>. Про дизайн!<\/li>\n  <li><a href=\"https:\/\/medium.com\/design-pub\/тёмная-сторона-курса-таблицы-и-прочие-радости-6702899be5e3\">Тёмная сторона курса «Таблицы и прочие радости»<\/a>. Технологичный подход к тёмному режиму. «Мы не продаём, а просто показываем, так что нам можно».<\/li>\n  <li><a href=\"https:\/\/medium.com\/design-pub\/приемы-жкх-верстки-и-её-подражателей-c12c1c6ce0ba\">Приемы ЖКХ-верстки и её подражателей<\/a>.<\/li>\n  <li><a href=\"https:\/\/docs.google.com\/document\/d\/1OqfI-xV067tJzp9l2SMc9mPKeeZM9yfjUEqpZDwJT4w\/\">Джордан Питерсон о психологическом значении Библии<\/a>. Ильяхов законспектировал лекции Питерсона, которые я так и не осилил послушать. Интересно, хотя много кажется очень натянутым. Самая любимая мною мысль, которая и в других местах у Питерсона встречается:  «Нужно очень серьезно относиться к тому факту, что ты принципиально не отличаешься от людей, которые исполняли приказы в концлагерях. И только выбор другого пути делает тебя носителем нравственности»<\/li>\n  <li><a href=\"https:\/\/realt.onliner.by\/2013\/12\/12\/oil\">Нефтяные камни: город на сваях в открытом море<\/a>. Жесть!<\/li>\n  <li><a href=\"https:\/\/techcrunch.com\/2021\/06\/04\/this-one-email-explains-apple\/\">This one email explains Apple<\/a>. Любопытный анализ, но в открытые вопросы Бертран не умеет.<\/li>\n  <li><a href=\"https:\/\/waitbutwhy.com\/2024\/02\/vision-pro.html\">Тим Урбан про Вижен-про<\/a>. «VR blows everyone away when they try it, but it seems to have a hard time hooking people for the long run»<\/li>\n  <li><a href=\"https:\/\/habr.com\/ru\/articles\/776646\/\">Наша математическая Вселенная<\/a>. Саша Карпинский всё объяснил про устройство всего.<\/li>\n  <li><a href=\"https:\/\/www.telegraph.co.uk\/business\/2024\/05\/04\/argentina-javier-milei-proving-left-wing-economy-wrong\/\">Milei is already proving the Left-wing economic establishment wrong<\/a>. Кто бы мог подумать: свобода лучше, чем несвобода!<\/li>\n  <li><a href=\"https:\/\/avva.livejournal.com\/3442590.html\">О гендере<\/a>. Анатолий Воробей рассуждает.<\/li>\n  <li><a href=\"https:\/\/twitter.com\/DanHollick\/status\/1570040185500626947?s=20&t=VQu081-3fSaz92soCoTbKg\">Как работают куаркоды<\/a> (к сожалению, в форме треда).<\/li>\n  <li><a href=\"https:\/\/twitter.com\/alphyna\/status\/1314509754077777920\">Объявления из брачной газеты начала 20 века<\/a> (тоже тред)<\/li>\n<\/ol>\n",
            "summary": "Вот",
            "date_published": "2024-05-09T08:23:04+02:00",
            "date_modified": "2024-05-09T08:25:17+02:00",
            "tags": [
                "веб-разработка",
                "дизайн",
                "общество",
                "технологии",
                "философия",
                "чтиво",
                "Эпл",
                "Эпл Вижен"
            ],
            "image": "https:\/\/ilyabirman.ru\/meanwhile\/pictures\/weekend-reading.png",
            "_date_published_rfc2822": "Thu, 09 May 2024 08:23:04 +0200",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "6111",
            "_rss_enclosures": [],
            "_e2_data": {
                "is_favourite": false,
                "links_required": [],
                "og_images": [
                    "https:\/\/ilyabirman.ru\/meanwhile\/pictures\/weekend-reading.png"
                ]
            }
        },
        {
            "id": "6228",
            "url": "https:\/\/ilyabirman.ru\/meanwhile\/all\/prihodite-rabotat-razrabotchikami-v-byuro\/",
            "title": "Приходите работать разработчиками в бюро",
            "content_html": "<p><a href=\"https:\/\/ilyabirman.ru\/meanwhile\/tags\/think-on\/\">В подкасте<\/a> с Никитой Прокоповым мы всё время обсуждаем, как у Эпла всё деградирует, потому что все ресурсы направлены на новые маркетинговые фичи, а старые просто ржавеют. А недавно я слушал <a href=\"https:\/\/www.youtube.com\/watch?v=DcWqzZ3I2cY\">подкаст с Джеффом Безосом<\/a> и он рассказывал, что у них есть специальная команда, «papercut team», которая как раз сосредоточена на том, чтобы людям не мешали жить всякие бесячие мелочи. Вот бы Эплам такую завести тоже!<\/p>\n<p>У нас в техноконтуре — технической команде бюро — свой подход к тому, чтобы ничего не оказывалось заброшенным. Нет такого, что одни разработчики пилят новые продукты, а другие чинят баги в старых. Вместо этого задачи разделены на три дорожки: большие задачи, маленькие и всякие срочные жопы. Срочные — это например отвалилась оплата всего или там лёг сайт и студенты не могут смотреть лекции; тут понятно, что всё починят первым делом. Но есть ещё маленькие задачи, которые можно как орешки брать на перекусон, чтобы проветрить голову от больших. Для них нет отдельной команды, их делают те же люди. Возможно, я называю это не теми словами, которые приняты у ребят, но смысл примерно такой.<\/p>\n<p>Если вы фронтенд-разработчик или что-то около того, приходите работать в бюро. Осенью у нас была вакансия, <a href=\"https:\/\/bureau.ru\/vacancies\/frontender-4\/\">я показывал<\/a>. Она сейчас значится как закрытая, но это формальности, реально работы всегда много и мы рады познакомиться со всеми классными людьми. У нас, например, самые крутые в мире электронные книги, которые становятся всё круче. Напишите там Васе Половнёву — техдиректору бюро.<\/p>\n",
            "summary": "В подкасте с Никитой Прокоповым мы всё время обсуждаем, как у Эпла всё деградирует, потому что все ресурсы направлены на новые маркетинговые фичи, а старые просто ржавеют",
            "date_published": "2024-02-01T11:40:49+02:00",
            "date_modified": "2024-02-01T11:40:16+02:00",
            "tags": [
                "Бюро",
                "веб-разработка",
                "работа"
            ],
            "_date_published_rfc2822": "Thu, 01 Feb 2024 11:40:49 +0200",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "6228",
            "_rss_enclosures": [],
            "_e2_data": {
                "is_favourite": false,
                "links_required": [],
                "og_images": []
            }
        },
        {
            "id": "5918",
            "url": "https:\/\/ilyabirman.ru\/meanwhile\/all\/ui-course-frag-82\/",
            "title": "На интерфейсном курсе: заранее спросить у клиента про сео и персональные данные",
            "content_html": "<p>Участница подумала, что в дизайне хорошо бы сразу учесть закон о персональных данных. Я дополняю тем, что хорошо бы сразу учесть и требования сеошников. 3 минутки:<\/p>\n<div class=\"e2-text-video\">\n<iframe src=\"https:\/\/www.youtube.com\/embed\/2qV6CCRT6lA?enablejsapi=1\" allow=\"autoplay\" frameborder=\"0\" allowfullscreen><\/iframe>\n<\/div>\n<p>Это фрагмент № 82 онлайн-курса «Пользовательский интерфейс и представление информации». Записано на курсе 27 мая 2022 года.<\/p>\n<p>До 2 декабря идёт запись на курс, который пройдёт с 3 декабря по 1 января.<\/p>\n<p><a href=\"http:\/\/bureau.ru\/educenter\/ui-online\/\" class=\"button buy-button big-button\">Почитать о курсе<\/a><\/p>\n<p class=\"foot\">Программа, отзывы, запись<\/p>\n",
            "summary": "Участница подумала, что в дизайне хорошо бы сразу учесть закон о персональных данных. Я дополняю тем, что хорошо бы сразу учесть и требования сеошников",
            "date_published": "2022-12-01T09:31:50+02:00",
            "date_modified": "2023-12-26T12:13:12+02:00",
            "tags": [
                "веб-дизайн",
                "веб-разработка",
                "видео",
                "переговоры",
                "студентам",
                "фрагменты курса ПИ"
            ],
            "image": "https:\/\/ilyabirman.ru\/meanwhile\/pictures\/remote\/youtube-2qV6CCRT6lA-cover.jpg",
            "_date_published_rfc2822": "Thu, 01 Dec 2022 09:31:50 +0200",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "5918",
            "_rss_enclosures": [],
            "_e2_data": {
                "is_favourite": false,
                "links_required": [],
                "og_images": [
                    "https:\/\/ilyabirman.ru\/meanwhile\/pictures\/remote\/youtube-2qV6CCRT6lA-cover.jpg"
                ]
            }
        },
        {
            "id": "5626",
            "url": "https:\/\/ilyabirman.ru\/meanwhile\/all\/weekend-reading-187\/",
            "title": "Что почитать на выходных — 187",
            "content_html": "<p>Вот:<\/p>\n<ol start=\"1\">\n  <li><a href=\"https:\/\/lkml.org\/lkml\/2021\/6\/10\/957\">Линус Торвальдс отвечает антипрививочнику<\/a>.<\/li>\n  <li><a href=\"https:\/\/daringfireball.net\/2020\/11\/disclosing_a_few_thoughts_on_facebooks_ui_design\">Disclosing a Few Thoughts on Facebook’s UI Design<\/a>. Джон Грубер про проблемы «состояние или команда» на примере интерфейса Фейсбука и раскрывающихся древовидных списков.<\/li>\n  <li><a href=\"https:\/\/www.citywayfinding.com\/designing-new-york-citys-brand-of-wayfinding\/\">Designing New York City’s brand of wayfinding<\/a>.<\/li>\n  <li><a href=\"https:\/\/threads-web.vercel.app\/threads\/1406938083975647233?fbclid=IwAR0vjKJTHceucy74PsT1lKbs7JNtlX7Uy9501vYTYxu8uz_MrXIPljDQFi8\">Андрей Ситник о жизни в США<\/a> (откуда он свалил, с чем я его искренне поздравляю).<\/li>\n  <li><a href=\"https:\/\/avva.livejournal.com\/3368947.html\">Решение про шнурки<\/a>. Любопытная задача, но особенно понравились рассуждения о том, что такое математическая задача, и какие условия в ней важны, а какие нет.<\/li>\n  <li><a href=\"https:\/\/twitter.com\/wycats\/status\/1342484366279098369\">Почему фронтенд-разработка — это сложно<\/a> (тред)<\/li>\n<\/ol>\n<p>Однажды в Википедии: <a href=\"https:\/\/t.me\/rationalnumbers\/1730\">Закон Бе́нфорда<\/a><\/p>\n",
            "summary": "Вот",
            "date_published": "2021-06-25T20:20:54+02:00",
            "date_modified": "2021-06-25T20:20:41+02:00",
            "tags": [
                "Америка",
                "веб-разработка",
                "дизайн",
                "ковид",
                "математика",
                "чтиво"
            ],
            "image": "https:\/\/ilyabirman.ru\/meanwhile\/pictures\/weekend-reading.png",
            "_date_published_rfc2822": "Fri, 25 Jun 2021 20:20:54 +0200",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "5626",
            "_rss_enclosures": [],
            "_e2_data": {
                "is_favourite": false,
                "links_required": [],
                "og_images": [
                    "https:\/\/ilyabirman.ru\/meanwhile\/pictures\/weekend-reading.png"
                ]
            }
        },
        {
            "id": "5644",
            "url": "https:\/\/ilyabirman.ru\/meanwhile\/all\/nginx-multiuser-ssl\/",
            "title": "Научить Нгинкс обслуживать по ХТТПС сразу много доменов",
            "content_html": "<p>Вопрос спецам по Нгинксу.<\/p>\n<p>В конфигурации Нгинкса прописаны такие заклинания про ССЛ:<\/p>\n<pre class=\"e2-text-code\"><code>ssl_certificate \/etc\/letsencrypt\/live\/example.com\/fullchain.pem;\nssl_certificate_key \/etc\/letsencrypt\/live\/example.com\/privkey.pem;\nssl_trusted_certificate \/etc\/nginx\/ssl\/letsencrypt-chain.pem;<\/code><\/pre><p>Только на месте example.com настоящий домен.<\/p>\n<p>Сервер обслуживает много доменов, которые добавляются и удаляются. Каждому домену соответствует своя папка, в которой лежат эти файлы, нужные для ССЛа. Соответственно при добавлении домена приходится создавать очередной конфиг, прописывать туда пути к папкам, перезапускать Нгинкс.<\/p>\n<p>Хочется этого избежать и просто прописать единый конфиг, который сразу покроет все домены, условно говоря, вот так:<\/p>\n<pre class=\"e2-text-code\"><code>ssl_certificate \/etc\/letsencrypt\/live\/$HTTP_HOST\/fullchain.pem;\nssl_certificate_key \/etc\/letsencrypt\/live\/$HTTP_HOST\/privkey.pem;\nssl_trusted_certificate \/etc\/nginx\/ssl\/letsencrypt-chain.pem;<\/code><\/pre><p>Насколько я понял, так сделать нельзя: Нгинкс не поддерживает переменные в этих строках конфигурации, потому что они обрабатываются не во время обслуживания запроса, а при запуске самого Нгинкса. Если нужных файлов нет, Нгинкс просто не запустится, потому что конфигурация некорректна.<\/p>\n<p>Но как-то же должна решаться задача? Мне нужно, чтобы именно в момент обращения к серверу Нгинкс смотрел, есть ли сертификат в нужной папке, и соответственно, чтобы изменение набора доменов не требовало изменения конфигурации и перезапуска сервера. Куда копать?<\/p>\n",
            "summary": "Вопрос спецам по Нгинксу",
            "date_published": "2021-05-02T14:17:39+02:00",
            "date_modified": "2021-05-02T14:16:56+02:00",
            "tags": [
                "веб-разработка",
                "вопрос"
            ],
            "_date_published_rfc2822": "Sun, 02 May 2021 14:17:39 +0200",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "5644",
            "_rss_enclosures": [],
            "_e2_data": {
                "is_favourite": false,
                "links_required": [
                    "highlight\/highlight.js",
                    "highlight\/highlight.css"
                ],
                "og_images": []
            }
        },
        {
            "id": "5430",
            "url": "https:\/\/ilyabirman.ru\/meanwhile\/all\/ui-course-frag-14\/",
            "title": "На интерфейсном курсе: как работает автоматическая вёрстка рекомендаций в будущей Эгее 2.10",
            "content_html": "<p>Сегодня срыв покровов — показываю кое-что из-под капота Эгеи 2.10. Пришло время выложить очередной фрагмент моего онлайн-курса, а там я рассказывал ребятам, как Эгея 2.10 автоматически верстает этаж рекомендаций (это то, что последние пару месяцев вы видите тут под заметками).<\/p>\n<p>В общем, фрагмент № 14 онлайн-курса «Пользовательский интерфейс и представление информации». Записано на курсе 31 июля 2020 года. Покажите дизайнерам и разработчикам.<\/p>\n<div class=\"e2-text-video\">\n<iframe src=\"https:\/\/www.youtube.com\/embed\/tYJMrY5zWlo?enablejsapi=1\" allow=\"autoplay\" frameborder=\"0\" allowfullscreen><\/iframe>\n<p>\n00:00 Задача и примеры<br \/>\n01:35 Дизайн «раскладок» для разных случаев<br \/>\n04:29 Описание раскладок в коде<br \/>\n05:50 Автоматический выбор и оценка раскладок<br \/>\n07:47 Режим отладки<br \/>\n<\/p>\n<\/div>\n<p><a href=\"http:\/\/bureau.ru\/educenter\/ui-online\/\" class=\"button buy-button big-button\">Почитать о курсе<\/a><\/p>\n<p class=\"foot\">Программа, отзывы, запись<\/p>\n<p>Кстати, с тех пор, как я это рассказывал на курсе, Эгея стала ещё умнее. Думаю, уже скоро дам попробовать всем.<\/p>\n",
            "summary": "Дизайн «раскладок» для разных случаев, описание раскладок в коде, автоматический выбор и оценка раскладок, режим отладки",
            "date_published": "2020-09-14T10:48:44+02:00",
            "date_modified": "2023-12-26T11:41:45+02:00",
            "tags": [
                "автоматизация",
                "веб-разработка",
                "вёрстка",
                "видео",
                "курсы",
                "студентам",
                "фрагменты курса ПИ",
                "Эгея"
            ],
            "image": "https:\/\/ilyabirman.ru\/meanwhile\/pictures\/remote\/youtube-tYJMrY5zWlo-cover.jpg",
            "_date_published_rfc2822": "Mon, 14 Sep 2020 10:48:44 +0200",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "5430",
            "_rss_enclosures": [],
            "_e2_data": {
                "is_favourite": true,
                "links_required": [
                    "jquery\/jquery.js",
                    "jquery\/jquery.js",
                    "media-seek\/media-seek.js"
                ],
                "og_images": [
                    "https:\/\/ilyabirman.ru\/meanwhile\/pictures\/remote\/youtube-tYJMrY5zWlo-cover.jpg",
                    "https:\/\/ilyabirman.ru\/meanwhile\/pictures\/aegea-og-image.jpg"
                ]
            }
        },
        {
            "id": "5397",
            "url": "https:\/\/ilyabirman.ru\/meanwhile\/all\/doklad-pro-kollaborativnye-prilozheniya\/",
            "title": "Доклад про коллаборативные приложения",
            "content_html": "<p>Как делать коллаборативные (они же мультиплеерные) приложения. Гугль-док, Фигма, OT, CRDT, все дела. Даёт хорошее представление о проблеме и решениях:<\/p>\n<div class=\"e2-text-video\">\n<iframe src=\"https:\/\/www.youtube.com\/embed\/x7drE24geUw?enablejsapi=1\" allow=\"autoplay\" frameborder=\"0\" allowfullscreen><\/iframe>\n<\/div>\n",
            "summary": "Как делать коллаборативные (они же мультиплеерные) приложения. Гугль-док, Фигма, OT, CRDT, все дела. Даёт хорошее представление о проблеме и решениях",
            "date_published": "2020-08-11T09:08:07+02:00",
            "date_modified": "2020-08-11T09:09:44+02:00",
            "tags": [
                "веб-разработка",
                "видео",
                "программирование"
            ],
            "image": "https:\/\/ilyabirman.ru\/meanwhile\/pictures\/remote\/youtube-x7drE24geUw-cover.jpg",
            "_date_published_rfc2822": "Tue, 11 Aug 2020 09:08:07 +0200",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "5397",
            "_rss_enclosures": [],
            "_e2_data": {
                "is_favourite": false,
                "links_required": [],
                "og_images": [
                    "https:\/\/ilyabirman.ru\/meanwhile\/pictures\/remote\/youtube-x7drE24geUw-cover.jpg"
                ]
            }
        },
        {
            "id": "5320",
            "url": "https:\/\/ilyabirman.ru\/meanwhile\/all\/glavny-princip-keshirovaniya-dannye-vsegda-aktualny\/",
            "title": "Главный принцип кеширования: данные всегда актуальны",
            "content_html": "<p>В этом выпуске рассказываю, о том, как правильно должно работать кеширование:<\/p>\n<div class=\"e2-text-video\">\n<iframe src=\"https:\/\/www.youtube.com\/embed\/IfZHcbNJi2g?enablejsapi=1\" allow=\"autoplay\" frameborder=\"0\" allowfullscreen><\/iframe>\n<\/div>\n<p>Если разработчики вам говорят, что кеш обновляется раз в полчаса и «надо просто подождать», пусть послушают этот выпуск. Кеш — не оправдание для отображения устаревших данных. Кеш нужен, чтобы данные показывались быстро, но без ущерба для их актуальности. Если из-за кеша вы видите устаревшие данные, значит в кеше баг.<\/p>\n<p>Подкаст-версия для тех, кто в дороге:<\/p>\n<div class=\"e2-text-audio\">\n<div class=\"e2-jouele-wrapper\"><a class=\"jouele\" data-space-control=\"true\" data-length=\"892\" href=\"https:\/\/ilyabirman.ru\/meanwhile\/audio\/111-ilya-birman-caching.mp3\">Главный принцип кеширования: данные всегда актуальны<\/a><\/div>\n<\/div>\n<p>Тема начинается <span class=\"e2-media-seek jouele-control\" data-href=\"https:\/\/ilyabirman.ru\/meanwhile\/audio\/111-ilya-birman-caching.mp3\" data-type=\"seek\" data-to=\"2:01\">с 2:01<\/span> с рассказа о смысле кеширования, сам принцип — <span class=\"e2-media-seek jouele-control\" data-href=\"https:\/\/ilyabirman.ru\/meanwhile\/audio\/111-ilya-birman-caching.mp3\" data-type=\"seek\" data-to=\"7:00\">c 7:00<\/span><\/p>\n<p>РСС для подкастных программ:<\/p>\n<blockquote>\n<p><a href=\"https:\/\/ilyabirman.ru\/meanwhile\/tags\/podcast\/rss\/\">https:\/\/ilyabirman.ru\/meanwhile\/tags\/podcast\/rss\/<\/a><\/p>\n<\/blockquote>\n<p>И теперь можно найти подкаст в каталоге Айтюнса. Надо искать «Видеоблог-подкаст Ильи Бирмана», но в нормальных программах находит даже если просто написать «Бирман».<\/p>\n",
            "summary": "Если из-за кеша вы видите устаревшие данные, значит в кеше баг",
            "date_published": "2020-05-22T22:54:24+02:00",
            "date_modified": "2020-08-13T18:51:05+02:00",
            "tags": [
                "веб-разработка",
                "видеоблог",
                "подкаст"
            ],
            "image": "https:\/\/ilyabirman.ru\/meanwhile\/pictures\/remote\/youtube-IfZHcbNJi2g-cover.jpg",
            "_date_published_rfc2822": "Fri, 22 May 2020 22:54:24 +0200",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "5320",
            "_rss_enclosures": [
                {
                    "url": "https:\/\/ilyabirman.ru\/meanwhile\/audio\/111-ilya-birman-caching.mp3",
                    "type": "audio\/mpeg",
                    "length": 14287234
                }
            ],
            "_e2_data": {
                "is_favourite": true,
                "links_required": [
                    "jquery\/jquery.js",
                    "jouele\/jouele.css",
                    "jouele\/jouele.js"
                ],
                "og_images": [
                    "https:\/\/ilyabirman.ru\/meanwhile\/pictures\/remote\/youtube-IfZHcbNJi2g-cover.jpg"
                ]
            }
        },
        {
            "id": "5241",
            "url": "https:\/\/ilyabirman.ru\/meanwhile\/all\/listening-17\/",
            "title": "Что послушать — 17",
            "content_html": "<p>Всё, что можно слушать, <a href=\"https:\/\/ilyabirman.ru\/meanwhile\/all\/layfhak-pro-slushanie-lekciy-i-dokladov\/\">я стараюсь слушать<\/a>, а не читать и не смотреть. Потому что когда у меня свободны глаза, я предпочитаю делать что-то более полезное.<\/p>\n<p>Вот что я слушал в последнее время, что мне понравилось:<\/p>\n<ol start=\"1\">\n  <li><a href=\"https:\/\/www.youtube.com\/watch?v=hWG6DYc0u5Y\">Мастер-класс Игоря Сысоева<\/a>. Про Нгинкс и вообще про жизнь программиста.<\/li>\n  <li><a href=\"https:\/\/www.youtube.com\/watch?v=kxMGwOCC4yA\">Коронавирус: все, что нужно знать о нём<\/a>. Максим Кац разобрался.<\/li>\n  <li><a href=\"https:\/\/podcasts.apple.com\/ru\/podcast\/есть-вопрос\/id1482311300?l=en&i=1000464140230\">Нужно ли наказывать преступников?<\/a> Криминолог рассказывает, почему это бессмысленно и как надо. Очень важно для общей гуманизации собственных взглядов. Хорошо дополняет Сапольского на эту тему.<\/li>\n<\/ol>\n",
            "summary": "Игорь Сысоев про Нгинкс и жизнь программиста, Максим Кац про коронавирус и Яков Гилинский о том, почему бессмысленно наказывать преступников",
            "date_published": "2020-03-09T21:08:03+02:00",
            "date_modified": "2020-04-30T10:46:48+02:00",
            "tags": [
                "веб-разработка",
                "Кац",
                "ковид",
                "общество",
                "подкасты",
                "что послушать"
            ],
            "image": "https:\/\/ilyabirman.ru\/meanwhile\/pictures\/listening.png",
            "_date_published_rfc2822": "Mon, 09 Mar 2020 21:08:03 +0200",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "5241",
            "_rss_enclosures": [],
            "_e2_data": {
                "is_favourite": false,
                "links_required": [],
                "og_images": [
                    "https:\/\/ilyabirman.ru\/meanwhile\/pictures\/listening.png"
                ]
            }
        },
        {
            "id": "5116",
            "url": "https:\/\/ilyabirman.ru\/meanwhile\/all\/form-validation-videoblog\/",
            "title": "Валидация форм и незаполненные поля",
            "content_html": "<p>Этот выпуск видеоблога-подкаста — для веб-разработчиков. Рассказываю, как нормально валидировать формы и что делать с незаполненными полями. Обязательно покажите коллегам:<\/p>\n<div class=\"e2-text-video\">\n<iframe src=\"https:\/\/www.youtube.com\/embed\/IS_FqA3K_YI?enablejsapi=1\" allow=\"autoplay\" frameborder=\"0\" allowfullscreen><\/iframe>\n<\/div>\n<p>Подкаст-версия для тех, кто в дороге:<\/p>\n<div class=\"e2-text-audio\">\n<div class=\"e2-jouele-wrapper\"><a class=\"jouele\" data-space-control=\"true\" data-length=\"873\" href=\"https:\/\/ilyabirman.ru\/meanwhile\/audio\/104-ilya-birman-form-validation.mp3\">Валидация форм и незаполненные поля<\/a><\/div>\n<\/div>\n<p>Сначала — догонка, а тема начинается с 4:56.<\/p>\n<p>Ссылки из выпуска:<\/p>\n<ul>\n  <li><a href=\"https:\/\/ilyabirman.ru\/projects\/moscow-metro\/reloaded\/\">Как нужно назвать линии метро<\/a><\/li>\n  <li><a href=\"http:\/\/bureau.ru\/educenter\/ui\/\">Курс об интерфейсе<\/a>, где говорим, в том числе, про формы<\/li>\n<\/ul>\n<p>Кстати, на подкаст-версию теперь можно подписаться по РСС и слушать в подкастных программах:<\/p>\n<blockquote>\n<p><a href=\"https:\/\/ilyabirman.ru\/meanwhile\/tags\/podcast\/rss\/\">https:\/\/ilyabirman.ru\/meanwhile\/tags\/podcast\/rss\/<\/a><\/p>\n<\/blockquote>\n<p>В Айтюнс-каталог пока не добавил — там надо ещё доработать разное, но по прямому урлу добавляется и работает, попробуйте!<\/p>\n",
            "summary": "Этот выпуск видеоблога-подкаста — для веб-разработчиков. Рассказываю, как нормально валидировать формы и что делать с незаполненными полями...",
            "date_published": "2019-09-13T15:18:42+02:00",
            "date_modified": "2019-12-07T19:02:50+02:00",
            "tags": [
                "веб-дизайн",
                "веб-разработка",
                "видеоблог",
                "подкаст",
                "пользовательский интерфейс"
            ],
            "image": "https:\/\/ilyabirman.ru\/meanwhile\/pictures\/remote\/youtube-IS_FqA3K_YI-cover.jpg",
            "_date_published_rfc2822": "Fri, 13 Sep 2019 15:18:42 +0200",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "5116",
            "_rss_enclosures": [
                {
                    "url": "https:\/\/ilyabirman.ru\/meanwhile\/audio\/104-ilya-birman-form-validation.mp3",
                    "type": "audio\/mpeg",
                    "length": 14161689
                }
            ],
            "_e2_data": {
                "is_favourite": true,
                "links_required": [
                    "jquery\/jquery.js",
                    "jouele\/jouele.css",
                    "jouele\/jouele.js"
                ],
                "og_images": [
                    "https:\/\/ilyabirman.ru\/meanwhile\/pictures\/remote\/youtube-IS_FqA3K_YI-cover.jpg"
                ]
            }
        },
        {
            "id": "4759",
            "url": "https:\/\/ilyabirman.ru\/meanwhile\/all\/plohoy-i-horoshiy-verstalschiki\/",
            "title": "Плохой и хороший верстальщики",
            "content_html": "<p>Коля Товеровский написал <a href=\"https:\/\/ksoftware.livejournal.com\/385562.html\">про плохого верстальщика<\/a>, который не в состоянии сделать как на макете, и за ним надо бегать и подсказывать ему, какой именно цвет или отступ нужно использовать.<\/p>\n<p>Но сделать точно как в макете — это самое базовое и примитивное умение. Без него вообще говорить не о чем, но его недостаточно, чтобы считать верстальщика хорошим. Хороший верстальщик умеет делать не как в макете, а <i>как надо<\/i>.<\/p>\n<p>В макете могут быть ошибки. Например, пока рисовали главную страницу, делали отступ между абзацами текста 9 пикселей. А когда стали рисовать страницу «О компании», подумали, что 10 будет смотреться получше. Правда, в одном сквозном для всего сайта блоке забыли исправить, и там осталось 9. Но в тексте на полях отступ всего 7 пикселей, и это так специально, потому что колонка у́же. А ещё в одном месте у дизайнера дрогнула рука, и между абзацами 12 пикселей.<\/p>\n<p>Если верстальщик молча сверстает страницу «О компании» как на макете, то есть оставив отступ где-то 9, где-то 10, где-то 7, а где-то 12 пикселей, работать с ним нельзя.<\/p>\n<p>Если верстальщик молча везде поставит 10 и забьёт на разницу в макете, работать с ним тоже нельзя.<\/p>\n<p>Нормальный верстальщик сразу видит всю эту разницу и приходит к дизайнеру с вопросом: «в макете у тебя везде разные отступы между абзацами, как правильно?».<\/p>\n<p>А хороший верстальщик приходит со свёрстанным макетом. Между абзацами и на главной, и в «О компании» отступ 10 пикселей, а на полях — 7 пикселей. Ссылку на свёрстанный макет он сопровождает письмом:<\/p>\n<blockquote>\n<p>У тебя в макете везде разные отступы между абзацами. Я поставил везде 10, потому что так в последнем макете. Предположил, что между последним и предпоследним абзацем ошибка (там 12). На полях оставил 7 как в макете — видимо так задумано.<\/p>\n<p>Кстати, у нас же в мобильной версии то, что было на полях, переезжает в основную колонку. Я в этом случае там тоже врубаю 10 для единообразия.<\/p>\n<p>Посмотри плиз и скажи, что где неправильно.<\/p>\n<\/blockquote>\n",
            "summary": "Коля Товеровский написал про плохого верстальщика, который не в состоянии сделать как на макете, и за ним надо бегать и подсказывать ему, какой именно цвет или отступ нужно использовать",
            "date_published": "2018-04-24T17:46:17+02:00",
            "date_modified": "2018-04-24T19:53:23+02:00",
            "tags": [
                "веб-разработка"
            ],
            "_date_published_rfc2822": "Tue, 24 Apr 2018 17:46:17 +0200",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "4759",
            "_rss_enclosures": [],
            "_e2_data": {
                "is_favourite": true,
                "links_required": [],
                "og_images": []
            }
        },
        {
            "id": "4719",
            "url": "https:\/\/ilyabirman.ru\/meanwhile\/all\/declarative-apis-talk\/",
            "title": "Дизайн декларативных АПИ",
            "content_html": "<p>Опубликовали видос моего летнего доклада на Питер-ЦСС про декларативные АПИ (на английском):<\/p>\n<div class=\"e2-text-video\">\n<iframe src=\"https:\/\/www.youtube.com\/embed\/uCQ3JFuQ7bQ?enablejsapi=1\" allow=\"autoplay\" frameborder=\"0\" allowfullscreen><\/iframe>\n<\/div>\n<p>Рассказываю о том, почему декларативные АПИ — это хорошо, и потом привожу в пример:<\/p>\n<ul>\n  <li><a href=\"https:\/\/ilyabirman.ru\/projects\/likely\/\">Лайкли<\/a>,<\/li>\n  <li><a href=\"https:\/\/ilyabirman.ru\/projects\/emerge\/\">Эмёрдж<\/a>,<\/li>\n  <li><a href=\"https:\/\/ilyabirman.ru\/projects\/jouele\/\">Жуэль<\/a>.<\/li>\n<\/ul>\n<p>Тогда <a href=\"https:\/\/ilyabirman.ru\/projects\/jouele\/pro\/\">новый Жуэль-про<\/a> ещё был в разработке, а сейчас его уже можно купить и использовать.<\/p>\n<p>Ещё читайте <a href=\"https:\/\/ilyabirman.ru\/meanwhile\/all\/piter-css-photos\/\" class=\"nu\">«<u>Как прошёл Питер-ЦСС<\/u>»<\/a> (офигенно). Большое спасибо организаторам!<\/p>\n",
            "summary": "Опубликовали видос моего летнего доклада на Питер-ЦСС про декларативные АПИ (на английском)",
            "date_published": "2018-02-23T12:06:09+02:00",
            "date_modified": "2020-11-09T21:23:29+02:00",
            "tags": [
                "английский язык",
                "веб-разработка",
                "доклады",
                "Жуэль",
                "Лайкли",
                "Эмёрдж"
            ],
            "image": "https:\/\/ilyabirman.ru\/meanwhile\/pictures\/remote\/youtube-uCQ3JFuQ7bQ-cover.jpg",
            "_date_published_rfc2822": "Fri, 23 Feb 2018 12:06:09 +0200",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "4719",
            "_rss_enclosures": [],
            "_e2_data": {
                "is_favourite": true,
                "links_required": [],
                "og_images": [
                    "https:\/\/ilyabirman.ru\/meanwhile\/pictures\/remote\/youtube-uCQ3JFuQ7bQ-cover.jpg"
                ]
            }
        },
        {
            "id": "4610",
            "url": "https:\/\/ilyabirman.ru\/meanwhile\/all\/shrifty-v-lichnom-kabinete-megafona\/",
            "title": "Шрифты в личном кабинете «Мегафона»",
            "content_html": "<p>У «Мегафона» если потратить весь трафик по тарифу, интернет работать перестаёт. Они предусмотрели, что ты можешь захотеть купить дополнительный пакет трафика, и поэтому по-прежнему разрешают тебе заходить в «Личный кабинет». Только вот кто-то додумался в этом личном кабинете использовать веб-шрифты, загружаемые с другого домена. Ну и пожалуйста:<\/p>\n<div class=\"e2-text-picture\">\n<img src=\"https:\/\/ilyabirman.ru\/meanwhile\/pictures\/megastupid.jpg\" width=\"1024\" height=\"748\" alt=\"\" \/>\n<\/div>\n<p>Чтобы подключить дополнительный пакет, нужно на каждой странице идти и веб-инспектором заменять шрифты на системные везде. Как должен покупать дополнительный пакет человек, не умеющий пользоваться веб-инспектором — неизвестно.<\/p>\n",
            "summary": "У «Мегафона» если потратить весь трафик по тарифу, интернет работать перестаёт. Они предусмотрели, что ты можешь захотеть купить дополнительный пакет трафика",
            "date_published": "2017-11-26T21:25:40+02:00",
            "date_modified": "2017-11-26T21:25:05+02:00",
            "tags": [
                "веб-разработка",
                "идиоты"
            ],
            "image": "https:\/\/ilyabirman.ru\/meanwhile\/pictures\/megastupid.jpg",
            "_date_published_rfc2822": "Sun, 26 Nov 2017 21:25:40 +0200",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "4610",
            "_rss_enclosures": [],
            "_e2_data": {
                "is_favourite": false,
                "links_required": [],
                "og_images": [
                    "https:\/\/ilyabirman.ru\/meanwhile\/pictures\/megastupid.jpg"
                ]
            }
        },
        {
            "id": "4458",
            "url": "https:\/\/ilyabirman.ru\/meanwhile\/all\/select-element-mobile-safari\/",
            "title": "Прицеливалка в мобильном веб-инспекторе",
            "content_html": "<p>Вы, наверное, знаете, что если в Сафари зайти в меню Develop, когда к компьютеру подключен Айфон, то там можно открыть веб-инспектор для любой вкладки, открытой в мобильном Сафари:<\/p>\n<div class=\"e2-text-picture\">\n<img src=\"https:\/\/ilyabirman.ru\/meanwhile\/pictures\/safari-target-1.jpg\" width=\"920\" height=\"198\" alt=\"Прицеливалка в мобильном веб-инспекторе\" \/>\n<\/div>\n<p>Когда наводишь на что-то в веб-инспекторе —<\/p>\n<div class=\"e2-text-picture\">\n<img src=\"https:\/\/ilyabirman.ru\/meanwhile\/pictures\/safari-target-2.jpg\" width=\"920\" height=\"224\" alt=\"Прицеливалка в мобильном веб-инспекторе\" \/>\n<\/div>\n<p>Оно даже честно подсвечивается на телефоне как в обычном окне Сафари:<\/p>\n<div class=\"e2-text-picture\">\n<img src=\"https:\/\/ilyabirman.ru\/meanwhile\/pictures\/safari-target-3@2x.jpg\" width=\"414\" height=\"736\" alt=\"Прицеливалка в мобильном веб-инспекторе\" \/>\n<\/div>\n<p>Но вопрос в том, как найти нужный элемент в сложном дереве. В веб-инспекторе есть такая кнопка с прицелом:<\/p>\n<div class=\"e2-text-picture\">\n<img src=\"https:\/\/ilyabirman.ru\/meanwhile\/pictures\/safari-target-4.jpg\" width=\"414\" height=\"294\" alt=\"Прицеливалка в мобильном веб-инспекторе\" \/>\n<\/div>\n<p>Если на неё нажать (Шифт-Комманд-C), потом можно кликнуть в нужный элемент на самой странице, и тогда в инспекторе покажут именно его.<\/p>\n<p>Кто бы мог подумать, что это работает и в мобильном Сафари? Нужно нажать на прицел на компьютере, а потом тапнуть пальцем в нужный элемент на телефоне — и он выделится в дереве в веб-инспекторе на компьютере!<\/p>\n",
            "summary": "Вы, наверное, знаете, что если в Сафари зайти в меню Develop, когда к компьютеру подключен Айфон, то там можно открыть веб-инспектор для любой вкладки",
            "date_published": "2017-07-05T14:53:25+02:00",
            "date_modified": "2017-07-05T15:02:50+02:00",
            "tags": [
                "Айфон",
                "веб-разработка",
                "лайфхак",
                "Сафари"
            ],
            "image": "https:\/\/ilyabirman.ru\/meanwhile\/pictures\/safari-target-1.jpg",
            "_date_published_rfc2822": "Wed, 05 Jul 2017 14:53:25 +0200",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "4458",
            "_rss_enclosures": [],
            "_e2_data": {
                "is_favourite": false,
                "links_required": [],
                "og_images": [
                    "https:\/\/ilyabirman.ru\/meanwhile\/pictures\/safari-target-1.jpg",
                    "https:\/\/ilyabirman.ru\/meanwhile\/pictures\/safari-target-2.jpg",
                    "https:\/\/ilyabirman.ru\/meanwhile\/pictures\/safari-target-3@2x.jpg",
                    "https:\/\/ilyabirman.ru\/meanwhile\/pictures\/safari-target-4.jpg"
                ]
            }
        },
        {
            "id": "4415",
            "url": "https:\/\/ilyabirman.ru\/meanwhile\/all\/vopros-pro-fonovuyu-rabotu-php\/",
            "title": "Вопрос про фоновую работу ПХП",
            "content_html": "<p>Эгея написана на ПХП как обычное веб-приложение, отвечающее на запросы браузера к серверу. Браузер просит страницу — Эгея её генерирует и отдаёт.<\/p>\n<p>Часть работы, которую делает Эгея — медленная по своей природе, например создание бекапа или индексация большого блога для поиска. Но Эгея отдаёт страницы быстро.<\/p>\n<p>Это потому что в Эгее реализован механизм фоновой работы через запрос к себе. Когда нужно сделать что-то долгое, Эгея устанавливает ХТТП-соединение сама с собой, как бы делая вид, что она браузер, отправляет запрос по специальному урлу, который означает «сделай бекап» или «поиндексируй поиск», и тут же обрывает соединение. В результате выполнение скрипта заканчивается быстро, а вся долгая работа делается незаметно, как раз в ответ на этот запрос к себе. О таком методе я узнал лет двенадцать назад от Романа Иванова, и с тех пор пользуюсь.<\/p>\n<div class=\"e2-text-picture\">\n<img src=\"https:\/\/ilyabirman.ru\/meanwhile\/pictures\/selfrequest@2x.png\" width=\"575\" height=\"300\" alt=\"Асинхронное выполнение на ПХП\" \/>\n<\/div>\n<p>К сожалению, с этим методом возникла проблема, когда я стал поддерживать ХТТПС. Если просто отправлять запрос и сразу закрывать соединение, как я всегда делал, не происходит вообще ничего — с точки зрения сервера всё выглядит так, как будто к нему и не обращались. Если же попробовать прочитать ответ, то приходит 400 Bad Request, потому что я как бы пытаюсь говорить с ХТТПС-сервером на простом ХТТП. К сожалению, мне почему-то так и не удалось отправить самому себе запрос по ХТТПС с помощью функции <tt>fsockopen ()<\/tt> и её родственников, хотя я вроде бы исчитал документацию со всех сторон.<\/p>\n<p>Вместо запроса к себе можно использовать <tt>register_shutdown_function ()<\/tt>. Но я когда-то пользовался ей, и у меня осталось ощущение ненадёжности — кажется, она выполнялась не всегда, и там были какие-то особенности внутри странные, например, что все пути к файлам должны быть указаны абсолютно. Короче, чтобы ей воспользоваться, нужно переструктурировать код. Женя Степанищев ещё рассказал про <tt>fastcgi_finish_request ()<\/tt> — похожий вариант.<\/p>\n<p>Эти схемы мне не нравятся непрозрачностью: часть скрипта будет выполняться в каком-то мире, который не виден никому. В варианте с запросом к себе мне ничто не мешает зайти браузером по моему служебному урлу и посмотреть, что происходит. А тут придётся что-то специальное изобретать для отладки. Кроме того, запрос к себе, разумеется, запускает новую копию ПХП, в которой заново начинается отсчёт времени. Выполняя такой запрос, я могу теоретически захотеть сделать что-то ещё так же, и инициировать запрос третьго уровня. И все эти запросы — одинаковой природы, просто заход по урлу. Мне нравится эта однородность.<\/p>\n<p>Есть радикальный вариант — переделать всё так, чтобы по служебным урлам ходил аджаксом клиент, пока ни о чём не подозревающий пользователь смотрит на уже загрузившуюся страницу. Такая конфигурация мне не нравится уже эстетически. Что это за беспомощный сервер, что ему надо, чтобы его клиент приводил в чувство? Возможно, это бред, но я бы хотел, чтобы сервер мог работать самостоятельно.<\/p>\n<p>Ну и пока умники в твиттере не начали писать «расскажите кто-нибудь Бирману про крон», объясню, что моя задача — сделать максимально автономное решение, не требующее от пользователя никакой специальной настройки сервера. Закачал на сервер папку — всё работает. Если вы матёрый программист в свитере, вам такое не понять.<\/p>\n<p>Короче, в идеале я бы хотел заставить работать свою исходную конфигурацию. Для этого мне нужно научиться делать запрос к себе по ХТТПС. Причём мне нужно просто «потрогать» нужный урл и отвалиться — мне не нужно по нему передавать никаких данных, не нужно читать ответ. Как это сделать?<\/p>\n<p>Ну и если вы знаете какой-то ещё способ добиться нужного результата, лишённый всех описанных недостатков, тоже расскажите.<\/p>\n",
            "summary": "Эгея написана на ПХП как обычное веб-приложение, отвечающее на запросы браузера к серверу. Браузер просит страницу — Эгея её генерирует и отдаёт",
            "date_published": "2017-05-23T21:06:27+02:00",
            "date_modified": "2017-05-25T12:14:30+02:00",
            "tags": [
                "веб-разработка",
                "вопрос",
                "ПХП",
                "Эгея"
            ],
            "image": "https:\/\/ilyabirman.ru\/meanwhile\/pictures\/selfrequest@2x.png",
            "_date_published_rfc2822": "Tue, 23 May 2017 21:06:27 +0200",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "4415",
            "_rss_enclosures": [],
            "_e2_data": {
                "is_favourite": false,
                "links_required": [],
                "og_images": [
                    "https:\/\/ilyabirman.ru\/meanwhile\/pictures\/selfrequest@2x.png",
                    "https:\/\/ilyabirman.ru\/meanwhile\/pictures\/aegea-og-image.jpg"
                ]
            }
        },
        {
            "id": "4403",
            "url": "https:\/\/ilyabirman.ru\/meanwhile\/all\/piter-css-announcement\/",
            "title": "Анонс доклада на Питер-ЦСС",
            "content_html": "<div class=\"e2-text-picture\">\n<img src=\"https:\/\/ilyabirman.ru\/meanwhile\/pictures\/pitercss@2x.png\" width=\"500\" height=\"107\" alt=\"Анонс доклада на Питер-ЦСС\" \/>\n<\/div>\n<p>16-го июня прочитаю на <a href=\"https:\/\/pitercss.com\/\">Питер-ЦСС<\/a> доклад о декларативных АПИ на английском. Организаторы конференции ещё напоминают, что с завтрашнего дня билет стоит 4500 ₽ (сегодня ещё 4000 ₽).<\/p>\n<p>Предположим, вы сделали какой-нибудь веб-компонент. Например умную выпадайку с автодополнением под названием superComplete. Тогда вы, скорее всего, предложите инициализировать его как-нибудь так:<\/p>\n<pre class=\"e2-text-code\"><code>var superCompleteInstance = new SuperComplete ('#el')<\/code><\/pre><p>Или, если это плагин для Джейквери, то так:<\/p>\n<pre class=\"e2-text-code\"><code>$ ('#el').superComplete ()<\/code><\/pre><p>А надо не так. Пусть оно инициализируется само, увидев знакомый класс:<\/p>\n<pre class=\"e2-text-code\"><code>&lt;input id=&quot;address&quot; class=&quot;supercomplete&quot; \/&gt;<\/code><\/pre><p>Я называю это декларативными АПИ: вместо того, чтобы давать команды, ты <i>описываешь<\/i> свойства компонента параметрами. Научился я такому сто лет назад у Артёма Поликарпова с его Фоторамой, и использую в своих веб-продуктах.<\/p>\n<p>Социокнопки <a href=\"http:\/\/ilyabirman.ru\/projects\/likely\/\" class=\"nu\">«<u>Лайкли<\/u>»<\/a> вставляют на страницу так:<\/p>\n<pre class=\"e2-text-code\"><code>&lt;div class=&quot;likely&quot;&gt;\n  &lt;div class=&quot;twitter&quot;&gt;Твитнуть&lt;\/div&gt;\n  &lt;div class=&quot;facebook&quot;&gt;Поделиться&lt;\/div&gt;\n&lt;\/div&gt;<\/code><\/pre><p>Чтобы поставить плеер <a href=\"http:\/\/ilyabirman.ru\/projects\/jouele\/\" class=\"nu\">«<u>Жуэль<\/u>»<\/a>, надо дать класс ссылке на аудиофайл:<\/p>\n<pre class=\"e2-text-code\"><code>&lt;a href=&quot;news.mp3&quot; class=&quot;jouele&quot;&gt;Ilya Birman: News&lt;\/a&gt;<\/code><\/pre><p>В <a href=\"http:\/\/ilyabirman.ru\/projects\/emerge\/\" class=\"nu\">«<u>Эмёрдже<\/u>»<\/a> чтобы элемент появился только после полной загрузки всего содержимого, а до того отображалась крутилка, нужно завернуть его в такой див:<\/p>\n<pre class=\"e2-text-code\"><code>&lt;div class=&quot;emerge&quot; data-spin=&quot;true&quot;&gt;...&lt;\/div&gt;<\/code><\/pre><p>Чем больше всего умеет компонент, тем сложнее придумать такой синтаксис. Особенно сложно становится, когда у вас много параметров, и они определяют поведение во времени и при условиях. Сначала кажется, что в этих случаях без Джаваскрипта никак не обойтись. Но если немного подумать, то часто выясняется, что вполне обойтись.<\/p>\n<p>Расскажу, почему это клёво и как придумывать синтаксис таких вот декларативных АПИ.<\/p>\n<p>Как сказал Стив Джобс, «Design is how it works». Это доклад про дизайн.<\/p>\n<p>Другие объявленные доклады:<\/p>\n<ul>\n  <li>Paint the Web with CSS. On Creating Art with Code<\/li>\n  <li>Creating Magic With Houdini<\/li>\n  <li>Designing Data-Driven Products. Controlled Chaos and Evolution<\/li>\n  <li>Chinese Typography on the Web<\/li>\n<\/ul>\n",
            "summary": "16-го июня прочитаю на Питер-ЦСС доклад о декларативных АПИ на английском. Организаторы конференции ещё напоминают, что с завтрашнего дня билет стоит 4500 ₽",
            "date_published": "2017-05-05T11:42:36+02:00",
            "date_modified": "2017-05-05T13:13:52+02:00",
            "tags": [
                "веб-разработка"
            ],
            "image": "https:\/\/ilyabirman.ru\/meanwhile\/pictures\/pitercss@2x.png",
            "_date_published_rfc2822": "Fri, 05 May 2017 11:42:36 +0200",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "4403",
            "_rss_enclosures": [],
            "_e2_data": {
                "is_favourite": false,
                "links_required": [
                    "highlight\/highlight.js",
                    "highlight\/highlight.css"
                ],
                "og_images": [
                    "https:\/\/ilyabirman.ru\/meanwhile\/pictures\/pitercss@2x.png"
                ]
            }
        },
        {
            "id": "4388",
            "url": "https:\/\/ilyabirman.ru\/meanwhile\/all\/rose-aegea\/",
            "title": "Как прикрутить поисковый движок «Роза»",
            "content_html": "<p>Я уже рассказывал, что в новой Эгее 2.6 — новый поисковый движок <a href=\"https:\/\/github.com\/parpalak\/rose\" class=\"nu\">«<u>Роза<\/u>»<\/a> Романа Парпалака. На примере Эгеи расскажу немного о том, как вы можете использовать его в своих продуктах.<\/p>\n<h2>Что делает Роза<\/h2>\n<p>Роза — движок поиска по переданным ему данным.<\/p>\n<p>У Розы нет «паука» для индексации. Это специально. В случае с движком блога, например, нет никакого смысла искать ссылки, ходить по страницам, разбирать их код. И ещё убеждаться, что не индексируешь одну и ту же заметку несколько раз, потому что она встретились на страницах разных тегов. Это лишняя работа: приложение-клиент знает, как устроены данные в нём, и может отдавать их поиску сразу «в чистом виде».<\/p>\n<p>Роза понимает три команды: «проиндексируй вот это», «удали из индекса вот это» и «найди всё вот по этому запросу». Как устроен индекс и как она находит — клиенту знать не нужно, это чёрный ящик. Клиент должен только обеспечить Розе доступ к хранилищу, где она будет держать индекс, и своевременно сообщать об изменениях, чтобы этот индекс был актуален.<\/p>\n<p>Таким образом, поиск — это взаимная работа клиента и Розы. Прикрутить её сложнее, чем использовать движок поиска общего назначения. Зато понимание структуры данных позволяет гибко форматировать результаты и учитывать их природу при ранжировании.<\/p>\n<p>Любой приличной заметке в современном интернете нужна картинка. Поэтому пусть здесь будет скриншот, иллюстрирующий покрытие Розы автоматизированными тестами:<\/p>\n<div class=\"e2-text-picture\">\n<img src=\"https:\/\/ilyabirman.ru\/meanwhile\/pictures\/rose-test@2x.png\" width=\"940\" height=\"416\" alt=\"Как прикрутить поисковый движок «Роза»\" \/>\n<\/div>\n<p>Теперь к делу.<\/p>\n<h2>Хранилище<\/h2>\n<p>Хранилище — это объект, через который Роза взаимодействует с базой данных. Клиенту нужно передавать его Розе и для индексации, и для поиска. Поэтому удобно иметь функцию, которая его отдаёт, когда нужно:<\/p>\n<pre class=\"e2-text-code\"><code>function e2_rose_storage () {\n  static $pdostorage = null;\n\n  if ($pdostorage === null) {\n    $pdo = new \\PDO (\n      'mysql:'.\n      'host='. $_db_server .';'.\n      'dbname='. $_db_name. ';'.\n      'charset=utf8',\n      $_db_user,\n      $_db_password,\n    );\n    $pdo -&gt; setAttribute (\\PDO::ATTR_ERRMODE, \\PDO::ERRMODE_EXCEPTION);\n    $pdostorage = new PdoStorage ($pdo);\n  }\n\n  return $pdostorage;\n}<\/code><\/pre><p>Для простоты я убрал некоторые специфичные для Эгеи вещи. Я тут проверяю, нет ли уже и так созданного хранилища; если нет, то создаю; и в любом случае его возвращаю. На место переменных, начинающихся с подчёркивания, надо поставить настоящие реквизиты базы данных.<\/p>\n<h2>Индексация<\/h2>\n<p>Задача клиента — «рассказать» Розе о данных, чтобы она построила свой индекс. Для этого нужно добавить каждую сущность (в Эгее — заметку) в индекс:<\/p>\n<pre class=\"e2-text-code\"><code>$stemmer = new PorterStemmerRussian ();\n$indexer = new Indexer (e2_rose_storage (), $stemmer);\n$indexable = new Indexable (\n  $_note_id,\n  $_note_title,\n  $_note_text\n);\n$indexer -&gt; index ($indexable);<\/code><\/pre><p>Когда пользователь публикует или изменяет заметку, я вызываю этот код. По идентификатору Роза понимает, нужно ли добавить в индекс новую запись или переиндексировать старую.<\/p>\n<p>Стеммер — это объект, к которому обращается Роза, чтобы сравнивать слова в разных падежах и формах. Его нужно передавать при индексации и при поиске. Он обособлен для того, чтобы можно было сделать свой стеммер для другого языка и подключить, не меняя ничего в индексаторе и поисковике.<\/p>\n<p>Как видите, на индексацию я передаю идентификатор, заголовок и текст заметки, а не адрес её страницы. Когда Роза что-то находит, она мне так же возвращает список идентификаторов найденных сущностей, а не ссылки. Построить страницу выдачи с рабочими ссылками — моя забота (но Роза поможет подсветить результаты поиска в выдаче — об этом ниже).<\/p>\n<p>Можно отдавать и адрес страницы при индексациии, но для Розы это просто текстовое поле, она не пойдёт по этому адресу низачем, просто вернёт его потом вместе с результатами поиска. Я этим не пользуюсь, потому что мне сподручнее получить адрес заметки из неё идентификатора, а не от Розы.<\/p>\n<p>Индексация одной заметки — быстрая операция, поэтому поддержание индекса в актуальном состоянии не составляет проблемы.<\/p>\n<p>Но при обновлении Эгеи со старой версии, мне нужно аккуратно проиндексировать все написанные ранее заметки. В случае с моим блогом это около четырёх тысяч заметок. Поэтому просто запустить их индексацию в цикле нельзя: даже если операция уложится во временной лимит ПХП, всё это время пользователь будет думать, что сайт не отвечает. А если не уложится, то пользователь вообще ничего не увидит. Как обеспечить безболезненную фоновую индексацию — тема отдельной заметки, но важно, что это забота клиента, а не Розы.<\/p>\n<p>Когда пользователь удаляет или отзывает заметку, я делаю примерно так:<\/p>\n<pre class=\"e2-text-code\"><code>$stemmer = new PorterStemmerRussian ();\n$indexer = new Indexer (e2_rose_storage (), $stemmer);\nreturn $indexer -&gt; removeById ($_note_id);<\/code><\/pre><h2>Поиск<\/h2>\n<p>Чтобы искать, нам понадобится файндер (а ему понадобится стеммер):<\/p>\n<pre class=\"e2-text-code\"><code>$stemmer = new PorterStemmerRussian ();\n$finder = new Finder (e2_rose_storage (), $stemmer);\n$finder -&gt; setHighlightTemplate (\n  '&lt;span class=&quot;'.CSS_CLASS_HIGHLIGHT.'&quot;&gt;%s&lt;\/span&gt;'\n);<\/code><\/pre><p>Здесь я также настраиваю шаблон для подсветки найденных слов в результатах поиска.<\/p>\n<p>Теперь можно сделать запрос и достать результаты поиска:<\/p>\n<pre class=\"e2-text-code\"><code>$rose_query = new Query ($query);\n$rose_query -&gt; setLimit (SEARCH_LIMIT); \n$resultSet = $finder -&gt; find ($rose_query);<\/code><\/pre><p>Тут я не могу продолжать как ни в чём не бывало и не сделать ремарку. Объекто-ориентированное программирование делает мне больно. Просто так написать нельзя:<\/p>\n<p><s><\/p>\n<pre class=\"e2-text-code\"><code>$results = rose_find ($db_link, $query, SEARCH_LIMIT);<\/code><\/pre><p><\/s><\/p>\n<p>С объектами для выражения простых мыслей требуется много строк. Связанные фрагменты кода невозможно разместить в поле зрения, и постоянно приходится скролить туда-сюда, держа вещи в памяти. Я понимаю, что объекты имеют преимущества. Но когда-нибудь программисты поймут, что так писать — тоже не дело, и придумают способ вернуть коду выразительность, не потеряв той пользы, которую им приносят объекты.<\/p>\n<p>Итак, после того, как мы получили <tt>$resultSet<\/tt>, мы уже можем выводить результаты. Но это тот момент, когда можно попросить Розу подкрутить релевантность, что я и делаю:<\/p>\n<pre class=\"e2-text-code\"><code>foreach ($resultSet -&gt; getFoundExternalIds () as $external_id) {\n  $note_id = e2_note_id_from_rose_id ($external_id);\n  $note_rec = e2_note_by_id ($note_id);\n  if ($note_rec['IsFavourite']) {\n    $resultSet-&gt;setRelevanceRatio ($external_id, 2);\n  }\n}<\/code><\/pre><p>Так я поднимаю избранные заметки повыше.<\/p>\n<p>Тут же Розу можно попросить сделать «сниппеты» — так называются фрагменты, выводящиеся в результатах поиска. Роза сама находит предложения с найденными словами, подсвечивает в них эти слова и собирает маленький кусок текста, достаточный для узнавания заметки в выдаче. Это делается так:<\/p>\n<pre class=\"e2-text-code\"><code>$snippetBuilder = new SnippetBuilder ($stemmer);\n$snippetBuilder -&gt; setSnippetLineSeparator(' · ');\n$snippetBuilder -&gt; attachSnippets ($resultSet, function (array $external_ids) {\n  $result = array ();\n  foreach ($external_ids as $external_id) {\n    $note_id = e2_note_id_from_rose_id ($external_id);\n    $note_rec = e2_note_by_id ($note_id);\n    $note_pack = e2_package_note ($note_rec);\n    $result[$external_id] = $note_pack['text'];\n  }\n  return $result;\n});<\/code><\/pre><p>Чтобы собрать сниппеты, Розе нужны полные тексты заметок — сама она их не хранит, а о структуре моей базы данных ничего не знает. Поэтому в метод <tt>attachSnippets<\/tt> мы тут передаём колбек, который Роза вызывает, чтобы их получить. Он, как видите, вытаскивает заметки из базы.<\/p>\n<p>После этого можно собрать результаты:<\/p>\n<pre class=\"e2-text-code\"><code>foreach ($resultSet -&gt; getItems () as $external_id =&gt; $item) {\n  $note_id = e2_note_id_from_rose_id ($external_id);\n  $note_rec = e2_note_by_id ($note_id);\n  $note_pack = e2_package_note ($note_rec);\n  $note_pack['title' ] = $item -&gt; getHighlightedTitle ($stemmer);\n  $note_pack['text' ] = '&lt;p&gt;'. $item -&gt; getSnippet () .'&lt;\/p&gt;';\n  $note_packs_found[] = $note_packs;\n}<\/code><\/pre><p>Я подсвечиваю найденные слова в заголовке и показываю сниппет вместо текста заметки.<\/p>\n<p>Код выдачи результатов поиска неэлегантен — хотя бы потому, что я трижды прохожусь циклом по этим результатам, многократно вызываю одни и те же функции с одними и теми же параметрами. Никаких измеримых проблем эта неэлегантность не создаёт, а её исправление потребовало бы изменения АПИ Розы. Поэтому пока пусть будет так.<\/p>\n<p>В этой заметке я упускаю часть слишком специфичных для Эгеи решений, фрагменты кода местами несколько упрощены. Из примеров полностью выпилен весь код, отвечающий за «смешение» результатов поиска Розы и стандартными средствами БД (я это делаю, потому что у Розы более высокие системные требования, чем у Эгеи, и на некоторых хостингах она может просто не завестись).<\/p>\n<p>Если захотите использовать <a href=\"https:\/\/github.com\/parpalak\/rose\">Розу<\/a> в своих продуктах, своими мыслями делитесь с Романом, а не со мной.<\/p>\n",
            "summary": "Я уже рассказывал, что в новой Эгее 2.6 — новый поисковый движок «Роза» Романа Парпалака. На примере Эгеи расскажу немного о том, как вы можете использовать его в своих продуктах",
            "date_published": "2017-04-30T10:44:25+02:00",
            "date_modified": "2017-04-30T10:55:39+02:00",
            "tags": [
                "веб-разработка",
                "программирование",
                "Эгея"
            ],
            "image": "https:\/\/ilyabirman.ru\/meanwhile\/pictures\/rose-test@2x.png",
            "_date_published_rfc2822": "Sun, 30 Apr 2017 10:44:25 +0200",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "4388",
            "_rss_enclosures": [],
            "_e2_data": {
                "is_favourite": false,
                "links_required": [
                    "highlight\/highlight.js",
                    "highlight\/highlight.css"
                ],
                "og_images": [
                    "https:\/\/ilyabirman.ru\/meanwhile\/pictures\/rose-test@2x.png",
                    "https:\/\/ilyabirman.ru\/meanwhile\/pictures\/aegea-og-image.jpg"
                ]
            }
        },
        {
            "id": "4395",
            "url": "https:\/\/ilyabirman.ru\/meanwhile\/all\/jouele-2-3\/",
            "title": "Жуэль 2.3",
            "content_html": "<div class=\"e2-text-picture\">\n<img src=\"https:\/\/ilyabirman.ru\/meanwhile\/pictures\/jouele-2015-logo@2x.png\" width=\"273\" height=\"64\" alt=\"Жуэль 2.2\" \/>\n<\/div>\n<p>Жуэль — <a href=\"http:\/\/ilyabirman.ru\/projects\/jouele\/\">нормальный аудиоплеер для веба<\/a>. Его развитием занимается Женя Лазарев.<\/p>\n<p>У нас вышла версия 2.3. Жуэль теперь использует Хоулер (встроен, а не идёт отдельным файлом) вместо Джейплеера. Благодаря этому изменению, трафик расходуется умнее, прелоудер работает точнее и ушло много мелких ошибок. Функция <tt>data-repeat<\/tt> стала работать у отдельных треков. Если файл недоступен, Жуэль показывает это, а не «висит». Вёрстка лучше смотрится в разных браузерах.<\/p>\n<p>Пример песенки:<\/p>\n<div class=\"e2-text-audio\">\n<div class=\"e2-jouele-wrapper\"><a class=\"jouele\" data-space-control=\"true\" href=\"http:\/\/audio.ilyabirman.ru\/Ilya%20Birman%20-%20When%20I%20Am%20128.mp3\">Ilya Birman: When I Am 128<\/a><\/div>\n<\/div>\n<p>Документацию см. <a href=\"https:\/\/github.com\/ilyabirman\/Jouele\/blob\/master\/readme-ru.md\">на Гитхабе<\/a>.<\/p>\n",
            "summary": "Жуэль — нормальный аудиоплеер для веба. Его развитием занимается Женя Лазарев",
            "date_published": "2017-04-29T12:00:43+02:00",
            "date_modified": "2017-05-07T22:17:09+02:00",
            "tags": [
                "веб-разработка",
                "Жуэль",
                "продукты",
                "проекты",
                "релиз"
            ],
            "image": "https:\/\/ilyabirman.ru\/meanwhile\/pictures\/jouele-2015-logo@2x.png",
            "_date_published_rfc2822": "Sat, 29 Apr 2017 12:00:43 +0200",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "4395",
            "_rss_enclosures": [
                {
                    "url": "http:\/\/audio.ilyabirman.ru\/Ilya%20Birman%20-%20When%20I%20Am%20128.mp3",
                    "type": "audio\/mpeg",
                    "length": ""
                }
            ],
            "_e2_data": {
                "is_favourite": false,
                "links_required": [
                    "jquery\/jquery.js",
                    "jouele\/jouele.css",
                    "jouele\/jouele.js"
                ],
                "og_images": [
                    "https:\/\/ilyabirman.ru\/meanwhile\/pictures\/jouele-2015-logo@2x.png"
                ]
            }
        },
        {
            "id": "4350",
            "url": "https:\/\/ilyabirman.ru\/meanwhile\/all\/mimic-ui\/",
            "title": "Интерфейс Мимика 2.0",
            "content_html": "<p>Веб-приложения состоят из фронтенда (того, что работает у пользователя в браузере) и бэкенда (того, что происходит на сервере). Эти части разрабатывают с разной скоростью. Если при создании браузерной части сервер недоступен, разработчик обычно сильно ограничен.<\/p>\n<p>Я сделал интерфейс для второй версии Мимика — инструмента веб-разработчика для имитации ответов сервера. Можно работать, как будто сервер доступен. Настроить поддельный ответ («мок») очень легко. Например, вы хотите сделать вид, что сервер ответил строчкой джейсона:<\/p>\n<div class=\"e2-text-picture\">\n<img src=\"https:\/\/ilyabirman.ru\/meanwhile\/pictures\/mimic-qe@2x.png\" width=\"1078\" height=\"76\" alt=\"\" \/>\n<\/div>\n<p>Можно настроить навороченные моки, с хитрыми ХТТП-заголовками, задержкой и чем угодно ещё:<\/p>\n<div class=\"e2-text-picture\">\n<img src=\"https:\/\/ilyabirman.ru\/meanwhile\/pictures\/mimic-ui-preview@2x.png\" width=\"1078\" height=\"497\" alt=\"\" \/>\n<\/div>\n<p>Кайф Мимика в том, что не нужно даже поднимать локальный сервер или менять урлы в своём приложении. Он работает прямо с тем, что есть, прямо в браузере. Но даже расширения браузера не нужно, он подключается просто как скрипт к приложению.<\/p>\n<p>Подробнее об интерфейсе — <a href=\"http:\/\/ilyabirman.ru\/projects\/mimic\/\">на странице проекта<\/a>.<\/p>\n",
            "summary": "Веб-приложения состоят из фронтенда (того, что работает у пользователя в браузере) и бэкенда (того, что происходит на сервере",
            "date_published": "2017-03-17T11:12:02+02:00",
            "date_modified": "2017-03-17T11:12:49+02:00",
            "tags": [
                "веб-разработка",
                "дизайн",
                "пользовательский интерфейс",
                "проекты",
                "релиз"
            ],
            "image": "https:\/\/ilyabirman.ru\/meanwhile\/pictures\/mimic-qe@2x.png",
            "_date_published_rfc2822": "Fri, 17 Mar 2017 11:12:02 +0200",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "4350",
            "_rss_enclosures": [],
            "_e2_data": {
                "is_favourite": true,
                "links_required": [],
                "og_images": [
                    "https:\/\/ilyabirman.ru\/meanwhile\/pictures\/mimic-qe@2x.png",
                    "https:\/\/ilyabirman.ru\/meanwhile\/pictures\/mimic-ui-preview@2x.png"
                ]
            }
        },
        {
            "id": "4309",
            "url": "https:\/\/ilyabirman.ru\/meanwhile\/all\/weekend-reading-147\/",
            "title": "Что почитать на выходных — 147",
            "content_html": "<p>Вот:<\/p>\n<ol start=\"1\">\n  <li><a href=\"https:\/\/www.smashingmagazine.com\/2017\/01\/redesigning-the-paris-metro-map\/\">Redesigning The Paris Metro Map<\/a>. Костя Коновалов рассказывает в «Смэшинг-магазине». Любимые штуки: 30-градусная сетка без вертикалей, гармония линий, пересадка на «Пастере» и видос в конце.<\/li>\n  <li><a href=\"https:\/\/www.washingtonpost.com\/news\/dr-gridlock\/wp\/2017\/02\/22\/could-a-subtle-tweak-to-metros-map-fix-overcrowding-on-the-blue-line\/\">Could a subtle tweak to Metro’s map fix overcrowding on the Blue Line?<\/a> Ещё пример, как изменение схемы метро способно разгрузить линию.<\/li>\n  <li><a href=\"http:\/\/rasskazov.pro\/blog\/all\/rubinshteyn\/\">Вывеска для Рубинштейна<\/a>. Оказывается, тоже Сергей Рассказов делал, как и <a href=\"http:\/\/www.manege.spb.ru\/wp-content\/uploads\/2016\/05\/apm_5773.jpg\">ту крутую вывеску на манеже<\/a>.<\/li>\n  <li><a href=\"http:\/\/tonsky.me\/blog\/the-web-after-tomorrow\/\">The Web After Tomorrow<\/a>.<\/li>\n  <li><a href=\"http:\/\/blog.oleganza.com\/post\/156541110398\/what-does-cryptoanarchy-mean\">What does cryptoanarchy mean<\/a>.<\/li>\n<\/ol>\n<div class=\"caption\"><p><span style=\"color: #c60; background: #fff8d0\">Хотите стать спонсором рубрики?<\/span> Пишите: <a href=\"mailto:ilyabirman@ilyabirman.ru\">ilyabirman@ilyabirman.ru<\/a><\/p>\n<\/div>",
            "summary": "Вот",
            "date_published": "2017-02-24T21:04:06+02:00",
            "date_modified": "2017-02-24T23:15:38+02:00",
            "tags": [
                "будущее",
                "веб-разработка",
                "метро",
                "Санкт-Петербург",
                "чтиво"
            ],
            "image": "https:\/\/ilyabirman.ru\/meanwhile\/pictures\/weekend-reading.png",
            "_date_published_rfc2822": "Fri, 24 Feb 2017 21:04:06 +0200",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "4309",
            "_rss_enclosures": [],
            "_e2_data": {
                "is_favourite": false,
                "links_required": [],
                "og_images": [
                    "https:\/\/ilyabirman.ru\/meanwhile\/pictures\/weekend-reading.png"
                ]
            }
        }
    ],
    "_e2_version": 4259,
    "_e2_ua_string": "Aegea 12.0a (v4259e)"
}