• Интернет и геополитика

    На заре интернета было забавное по текущим временам мнение. Якобы он станет средой, которая объединит людей, отбросив границы и политические взгляды. Что противоречия физического мира отпадут, и все найдут согласие. Что коллективный разум возобладает над политиками и превзойдет их.

    Забавно видеть, что все из этого не только не сбылось, но и наоборот — интернет все больше становится геополитизированным. Увы, в нашу жизнь пришла геополитика — смесь двух терминов, каждый из которых тащит худшее прошлого века: политику и территории. Что из этого вышло, мы наблюдаем сегодня.

    Современный интернет геополитизирован, потому что регулируется двумя принципами: политикой и географией. Крупные сервисы блокируют людей по их положению на планете. Страны блокируют сервисы по политическим причинам. Большая часть запрещенного контента — это то, что запрещено режимом, причем не только в России.

    Тезис о едином пространстве разваливается на глазах. Все меньше остается сервисов, куда можно попасть, не испытывая ограничений. Твиттер(1) и Инстаграм(2) заблокированы Россией. На Госуслуги и Налог.ру нельзя зайти, если ты не в России. Если уехал, ставь московский ВПН, что до недавнего времени звучало анекдотом.

    Порнхаб в одной стране разрешен, в другой запрещен, в третьей — только с авторизацией через местную соцсеть. Grammarly не работает с российскими IP, нужен ВПН. Украинские сайты показывают россиянам плашку с расчлененкой.

    Надоели сайты, защищенные Cloudflare. При каждом заходе видишь уродский экран с задержкой в 5-10 секунд. Иногда Cloudflare требует капчу с гидрантами и велосипедами. Двадцать минут — и сессия рвется, проверка начинается снова.

    Гугл и Ютуб боятся ВПН как огня. С ним Ютуб показывает капчу — не дай бог ты пройдешь мимо Большого Брата. Фейсбук, Твиттер и аналоги блокируют Тор. Им лучше знать, что безопасно, а что нет.

    Про Китай писать нет смысла.

    Сервисы все больше ведут себя как государства. Пользователь, чей IP вызывает малейшее подозрение, приравнивается к нелегалу, незаконно переходящему границу. Его надо схватить и подвергнуть деанону.

    Фейсбук и Твиттер открыто занимают позиции в социальных конфликтах США: выборы, BLM и так далее. Получить бан за поддержку Трампа теперь в порядке вещей. Не лучше ситуация и у нас, когда ВК и Мейл.ру сливают данные о тех, кто состоит в группах “оппозиции”.

    В той или иной мере огораживается каждый второй сайт. Со включенным ВПН нельзя передать показания в энергослужбу или заказать б/у книгу. Знакомый справедливо заметил, что сегодня проще иметь два ноута — настроенный под иностранный сайты и для внутренних нужд.

    Выделять какую-то страну в том плане, что они блокирую больше, чем остальные, нет смысла — это тренд. Интернет — это общение и информация, и государство всегда болезненно реагирует, когда то или другое выходит из под контроля. И неважно, какой политический строй: демократия, автократия или тоталитаризм. Благородный предлог найдется всегда: терроризм, антиваксы, тридевятая колонна. В каждой стране свои пугалки про черную руку и простыню.

    Очевидно, никакого свободного интернета нет, более того — не интернет двигает обществом, а двигают им. Современная дурь оседает в интернете и приводит к ограничениям по IP, странам, действиям режима и остальному.

    Получится ли сделать что-нибудь другое? Возможно, но это будет принципиально иной вид связи. Он должен быть максимально простым для пользователя и невозможным для блокировок. Примерно как блокчейн, хоть я и не люблю аналогии с криптой. К сожалению, лично мне этот новый вид связи трудно представить хотя бы приблизительно.

    1, 2 – считаются экстремистскими организациями или вроде того.

  • Мобильная деградация

    Последнее время я делю экран пополам: слева браузер, справа Емакс. Такой сетап нужен для определенной работы, связанной с редактированием текста.

    Заметил, что с браузером происходят странные вещи. Стоит только поджать окно на жалкие пиксели, включается мобильный режим. Лучше всего это наблюдать на Гитхабе. Нормальный режим:

    Но стоит уменьшить окно на пиксель, как вдруг:

    Кто-нибудь в курсе, зачем это? Код — самое главное на этой странице — пропал под выпадашку, хотя места достаточно. Появилась адская разреженность, кнопки сплющились, как будто по ним проехали катком. Кто вообще просил? Остается выругаться и расширить окно обратно.

    Досадно от того, что кто-то сидел над этой хитрожопой версткой, трекал часы в Джире, презентовал менеджерам. А пользователь мечтает развидеть и вернуть все взад.

  • Автодополнение

    В хромо-подобных браузерах есть полезная функция — сохранение форм. Дико выручает, когда в сотый раз вводишь имя, фамилию и почту на сайте. Буквально сегодня я заполнял форму на сайте налоговой шестнадцать(!) раз. Если бы не автокомплит, я бы, наверное, стер пальцы. Тем более умники-разработчики повы..бывались с некоторыми полями, и в них не работает вставка. Какой-то скрипт блокирует событие, я начал было смотреть в консоли, но в итоге плюнул на это.

    Удивляет, однако, то, что автокомплит нельзя редактировать. В очередной раз я вставил не то значение, и оно осталось в выпадашке навсегда. Теперь каждый раз, выбирая из нее пункт, надо быть осторожнее, чтобы не тыкнуть не туда.

    Не понимаю, почему автокомплит нельзя редактировать? Хватило бы удаления: напротив каждого элемента сделать крестик, который удаляет его из выпадашки. Просто и дешево.

    Между прочим, такая функция есть в Телеграме. Предположим, вы искали сообщество LaTeX, а нашли латекс и доминирование:

    Если тыкнуть в любой канал (ну, просто так), он останется в истории поиска. Будет неприятно, если это всплывет на созвоне при шаринге экрана. Крестик справа удаляет элемент из истории поиска, и с ним я спокоен: никакого доминирования мой собеседник не увидит.

    В общем смысле это ведет к правилу: собираешь данные — позволь клиенту их удалить. Удаление стоит усилий, порой огромных (привет GDPR), но тогда незачем и начинать.

  • Win-win

    Читаю книгу Егора “Наш код”. Хорошая книга, местами спорная, но ничего — просто держите в голове, что это Егор. Есть, однако, момент, мимо которого я не мог пройти молча — это эпизод с переговорами между двумя группами.

    Я хотел привести оригинальный текст, однако электронной версии, откуда можно скопировать и вставить, в интернете нет. Поэтому расскажу завязку своими словами.

    Есть группа разработчиков, которые пилят REST API, и есть группа потребителей. Понадобилась доработка сервиса, и потребители выдвигают условие: чтобы новые данные можно было забрать одним запросом. Разработчикам сервиса это неудобно: они сделали несколько новых методов, полагая, что потребители пошлют несколько запросов. Группы не сошлись во мнении, и начинается совещание.

    Read more →

  • Программа Preview

    Если я когда-нибудь пересяду с Мака на что-либо другое, больше всего мне будет не хватать… программы Preview. Да, встроенной программы просмотра изображений. Все потому, что Preview — невероятно мощный софт. Просмотр картинок и PDF лишь малая часть ее возможностей. Ниже я расскажу, что именно она умеет.

    (1) Банально, но все-таки — Preview открывает картинки и PDF. Не нужно ставить сторонний софт, который пропишет себя в автозагрузку и службы. С тяжелым сердцем вспоминаю Adobe Reader, который разросся до размера офисного пакета.

    Поставив Windows 10 на игровой комп, был удивлен, что в ней нечем открыть PDF (браузер Edge не в счет). По клику на PDF открывается магазин Microsoft – как это возможно в 2022 году, не понимаю. А на Маке сел — и читаешь PDF.

    Read more →

  • Коротко об lndir

    Небольшая заметка о утилите, которая требуется редко, но метко – lndir.

    Когда у меня стало больше одного Мака, появилась проблема синхронизации настроек. Другими словами, чтобы всякие .thisrc и .thatrc были одинаковы и подхватывались при изменении. Сюда входит конфиг Emacs, ssh, словари aspell, профили AWS, конфиги ctags, zshell и многое другое.

    Легче всего держать dot-файлы в репозитории и ставить симлинки. Неожиданно я столкнулся с тем, что не так легко написать shell-скрипт, который бы поставил симлинки на файлы из папки. Пытался при помощи find ... -execute и xargs, но постоянно что-то мешало. То отсутствие файла, то его существование, словом, всякие досадные случаи. В итоге было две команды: сначала одна удаляет симлинки, а вторая создает их заново.

    Оказалось, что lndir делает именно то, что я искал. Они принимает две папки и строит дерево симлинков из первой во вторую. При этом учитывает случаи, что я перечислил, например если симлинк уже есть. Благодаря этому дерево можно обновлять итеративно.

    Пример: в каталоге ~/work/System/Dotfiles хранятся оригинальные файлы Emacs, .ssh и прочие. Следующая команда make расставит симлинки в домашнюю папку:

    HOME = /Users/ivan
    PWD = $(shell pwd)
    
    create-symlinks:
    	lndir ${PWD}/Dotfiles ${HOME}
    	chmod 600 ${HOME}/.ssh/*
    

    Для файлов ssh необходимо выставить права 600, иначе утилита ругается.

    Синхронизация происходит обычным способом через git. Как только вы поменяли один из файлов, делаете коммит и пуш. На другой машине пулл и make create-symlinks, и все подхватывается. Репозиторий, понятно, должен быть приватным.

    По умолчанию lndir нет в поставке Линукса и Мака. Ставится из привычных apt и brew.

  • Интерфейс Гитхаба

    У меня бомбит от интерфейса Гитхаба. Он работает по странному принципу: показывает то, что не нужно и не показывает то, что нужно.

    Когда я открываю pull request, то хочу увидеть изменения в файлах. Поскольку я обычный программист, не гений и без заскоков, полагаю, это желание подходит большинству. Почти всегда, когда мне кидают PR, я знаю заранее, с какой задачей он связан, и сразу смотрю файлы. Только в редких случаях мне нужно прочесть описание.

    В интерфейсе PR файлы задвинуты на последнюю вкладку “Files changes”, и я не верю, что этому есть разумная причина. Файлы это суть PR, с какой стати задвигать их в конец? Это же самое нужное! Изменения должны быть сразу под описанием, чтобы не кликать, а просто смотать экран.

    Есть ли на этой вкладке хоть грамм полезной информации? Если да, чем он важнее 18 измененных файлов?

    Далее эти дурацкие табы. Проблема в том, что на вкладках располагаются не только данные, но и кнопки. Например, закрыть PR можно только со вкладки “Conversation”. А поставить аппрув только со вкладки “Files”. В итоге постоянно кликаешь на первый и последний табы.

    Первый и последний, Карл! Уже это говорит, что как минимум они должны быть рядом, если не объединены в один.

    По этой причине я пользуюсь трюком: когда кидаю ссылку на PR, добавляю к концу /files, то есть не ...project/pull/3, а ...project/pull/3/files. При таком раскладе у человека сразу откроются файлы, и не придется переключать табы. Мелочь, а приятно, особенно если собеседник понимает этикет и отвечает тем же.

    Судите сами: вот мне пришел PR с комментарием. Рассмотрим действия, которые я должен выполнить для мерджа:

    • открыть ссылку на PR;
    • перейти на files, чтобы бегло посмотреть, что внутри;
    • если все хорошо, вернуться на вкладку conversation;
    • нажать merge;
    • нажать delete branch.

    По мне все можно уместить на одной странице и работать без кликов.

    Из-за особенностей интерфейса кнопка “delete branch” находится выше “merge”, то есть сначала нажимаешь ту кнопку, что ниже, а потом выше. Это ни в какие ворота: экран мотают сверху вниз, и чем ниже кнопка, тем она важнее.

    В целом интерфейс Гитхаба шумный и грязный. На закладке “Conversation” схематично указаны коммиты, хотя есть отдельная вкладка “Commits”. Зачем размазывать их по двум вкладкам? Все, что касается коммитов, должно быть в “Commits”.

    Даже если у PR нет описания, будет пустой комментарий вида:

    igrishaev commented 20 minutes ago
    No description provided
    

    Спрашивается, что именно commented? Зачем писать о том, чего нет?

    Особую грусть вызывает мобильное приложение Гитхаба. Почему-то оно не может нормально показать код: кнопка “Browse code” вечно болтается внизу. Что мешает сделать ее первой? В этом плане Гитхаб напоминает современный Дропбокс: приложение плохо показывает то, с чем работает.

    Однажды я хотел закрыть PR со спамом, но не нашел кнопку “Close pull request”. Возможно, она была под выпадашкой или вроде того, но увы, я пас.

    Слева: где посмотреть код? Справа: как закрыть PR?

    Мне кажется, интерфейс Гитхаба разжирел, и пора устроить ему чистку. Он достиг стадии “впихнуть невпихуемое”, как это бывает с продуктами, которые часто выкатывают фичи. Интерфейс должен щадить пользователя: не вываливать на голову все подряд в надежде, что кому-то пригодится. Интерфейс — это оборона пользователя от того ада, что творится на серверах. Давайте помнить об этом, хоть я и не верю, что дизайнеры Гитхаба меня услышат.

  • Деджаваскриптизиция (4)

    Пора заканчивать эпопею про избавление от Js. Чтобы не утомлять, расскажу о последнем штрихе — как внедрил капчу для комментариев.

    Как только я убрал Disqus, полезли спамные комментарии. Каждый день приходят два-три предложения купить виагру, надувную лодку или просто левые ссылки. Поскольку каждый комментарий открывает PR в репозиторий, все остается в истории Гитхаба. Посмотреть на это добро можно по ссылке.

    Разгребать подобные комментарии нет желания, поэтому должна быть минимальная защита от спама. С условием — без Js. Надумал такую схему:

    • капча генерируется на этапе сборки блога. На выходе получается HTML-форма с полем captcha и значением 2 × 5.
    • В форму добавляется поле для решения.
    • Сервер парсит капчу, решает и сверяет с ответом. Если что-то не так, заворачивает комментарий.

    Как ни странно, даже на таком примитиве боты отваливаются. Разве что с оговоркой: когда был оператор +, боты решали капчу. Как только заменил на × (знак умножения в юникоде), стала тишь да благодать. Надеюсь, читатель не забыл таблицу умножения! Тестируя форму, сам подвис с примером 8 × 9.

    Техническая сторона: вот построить капчу в шаблоне:

    
    {% assign val1 = '1 2 3 4 5 6 7 8 9' | split: ' ' | sample %}
    {% assign val2 = '1 2 3 4 5 6 7 8 9' | split: ' ' | sample %}
    {% assign op   = '×'            | split: ' ' | sample %}
    {% assign captcha = val1 | append: " " | append: op | append: " " | append: val2 %}
    
    

    Замечу, что при каждой сборке блога значения будут разные.

    Скрытое поле в форме:

    
    <input required name="captcha" type="hidden" value="{{ captcha }}">
    
    

    Виджет для ввода решения:

    
    <div class="block">
        <span class="comment-form-label"><small>{{ captcha }} = </small></span>
        <input required id="comment-form-solution" name="solution" type="text">
    </div>
    
    

    Наконец, серверный код проверки капчи:

    (dеfn validate-captcha [captcha solution]
      (when-let [[_ val1-raw op-raw val2-raw]
                 (re-find #"^(-?\d+) (.+?) (-?\d+)$" captcha)]
    
        (let [val1
              (Integer/parseInt val1-raw)
    
              val2
              (Integer/parseInt val2-raw)
    
              op
              (case op-raw
                ("+" "&#43;") +
                ("*" "×" "&#215;") *
                nil)]
    
          (when (and val1 val2 op)
            (= (str (op val1 val2))
               (str/trim solution))))))
    

    Грубо, неуклюже, но работает.

    На этом я закончу тему с избавлением от Js. На мой взгляд, цели достигнуты, жить с новыми комментариями можно. Это был интересный опыт, в будущем пригодится.

  • Деджаваскриптизиция (3)

    Сбылась мечта идиота: теперь на сайте работают комментарии без строчки кода на Джаваскрипте. Смотайте экран вниз, там форма. Требуется только имя и тело комментария. Ввели, отправили, и через некоторое время он появится в блоге.

    Форма:

    Экран возврата:

    А что, мне нравится.

    Расскажу, как это работает. В прошлый раз я перенес комментарии Disqus в репозиторий. Каждый комментарий — это файл формата YAML + markdown. В числе прочего он хранит ссылку на пост. Когда я собираю блог, в подвал каждой заметки подставляются ее комментарии.

    Для приема комментариев я следую тому же принципу: чтобы они появились на сайте, нужно создать файл в репозитории. Теоретически любой может оформить pull request, но это сложно. Должен быть сервис, который преобразует ввод пользователя в pull request для блога. Этот сервис я написал и назвал blog-backend.

    Сервис напоминает веб-приложение: оно принимает HTTP-запрос с формой. После прелюдии с валидацией перехожу к главному: интеграции с Гитхабом. Это оказалось не так-то просто. У Гитхаба уже три рестовых API, но ни одно не покрывает все возможности. Кроме REST есть убер-апишка на GraphQL — она-то мне и нужна.

    Интеграция с GraphQL была нелегкой: это самобытный язык и вещь в себе. Если бы в текущем проекте не было GraphQL, я бы полез на стенку. Во-вторых, сложность процесса: чтобы сделать PR силами API, нужно четыре вызова:

    1. получить метаданные репозитория, в том числе последний коммит;
    2. создать ветку от этого коммита;
    3. сделать коммит в новую ветку;
    4. сделать PR.

    Как по мне, апишка не консистентна: где-то на репозиторий ссылаешься по имени, а где-то по машинному ID, который приходит из метаданных. То же самое с ветками: где-то имя, где-то айдишник. Ответы GraphQL развесистые, с глубокой вложенностью. Например, последний коммит ветки погружен на пять уровней:

    (-> resp-get-repo :data :repository :ref :target :oid)
    

    С такой апишкой невозможно программировать без образца данных.

    Когда подружился с Гитхабом, настала проблема хостинга: где и как размещать логику. Мне понравился опыт с облаком Яндекса, и я продолжил эксперименты. Сервис написан на Кложе, скомпилирован Граалем в бинарь и хостится в Яндекс.Функции — аналоге AWS Lambda.

    В свою очередь, Яндекс.Функция — это облачный сервис, где размещают какой-то код и дергают его по запросу. Отличие от обычного хостинга в том, что у лямбды нет состояния: она запускается на короткое время и умирает. В зависимости от окружения лямбда может умереть не сразу, и если ее дернуть повторно, сработает уже запущенный экземпляр. На базе этого делают “прогрев” лямбд, у которых окружение стартует медленно, например Java. В моем случае граальный бинарник быстрый как не весть что, прогрева ему не надо.

    Лямбду можно вызывать разными способами, в том числе HTTP-запросом. У каждой лямбды свой урл, который может быть приватным и публичным. Его можно указать в разных сервисах, что отлично подходит для ботов.

    По сравнению с VM-хостингом у лямбды следующие плюсы:

    • не нужна виртуальная машина и ее настройка;
    • не нужен домен;
    • лямбды экстремально дешевы, потому оплачивается только время работы с округлением до 0.1 секунды;
    • лямбды поощряют писать код без компонентов и состояния, что как бальзам на душу после проектов по работе.

    Поначалу я был крайне скептичен к лямбдам, но теперь вижу в них особую прелесть. Единственный момент — пришлось написать код, чтобы подружить Кложу и Ring с окружением лямбды. Также поправил компиляцию Граалем, чтобы в бинарнике была верная кодировка. В будущем я планирую вынести код Яндекс.Облака в отдельную библиотеку, чтобы избавиться от копипасты.

    Форма поддерживает синтаксис Markdown. Пока что нет кнопок выделения текста болдом и италиком, сделаю потом. Форма отправляется чистым POST, никаких аяксов, хотя первую версию я сделал на fetch, JSON и CORS. Про CORS я все забыл, и пришлось читать свою же статью о том, как все настроить.

    Новые комментарии совмещают модерацию. После отправки создается PR в блог, мне приходит письмо, а пользователь переходит на прошлую страницу. Если все в порядке, я мерджу ветку и заливаю свежий билд блога. Таким образом, с момента публикации комментария может пройти от пяти минут до нескольких дней, но это ничего.

    Первые комментарии я получил от кого? Правильно, от спамеров. Этим утром предложили виагру, казино и просто левые ссылки. Вот ссылка на уже закрытый RP и его содержимое:

    ---
    id: 1663659055173
    is_spam: false
    is_deleted: false
    post: /bookshelf/
    date: 2022-09-20 07:30:55 +0000
    author_fullname: 'epiehuliqukib'
    ---
    
    http://slkjfdf.net/ - Tatacatay <a href="http://slkjfdf.net/">Aebaluk</a>
    lwk.wlgg.grishaev.me.mrq.mn http://slkjfdf.net/
    

    Очевидно, нужно вводить капчу для защиты от ботов. Я рассматриваю это как новый вызов: как сделать капчу без Javascript в статичном блоге? Уже есть мыслишки, расскажу в четвертой части эпопеи.

    Наконец, последний тезис — зачем вы это делаете, мистер Андерсон? Зачем эти отказы, костыли, превозможения? Ответ — потому что могу. Просто хочется экспериментов. Надоели тормозные сайты с JS, хочу маленький оазис в своем огороде.

  • REPL, Cider, Emacs (часть 4/4)

    Все части

    Оглавление

    Отладка в Cider

    Мы исследовали отладку так долго, чтобы читатель убедился: в ней нет никакой магии. Отладчик — это код, который внедряется в исходный код и заставляет его работать с паузами. Во время паузы отладчик ждет команду пользователя и исполняет ее.

    Теперь когда вы знакомы с самодельным отладчиком, рассмотрим, что предлагает Cider. В нашем распоряжении два тега: #break и #dbg. Первый тег означает точку останова (брейкпоинт) в месте, где он расположен. Поставьте #break в середину произвольного кода. Перед тем как запустить код, выполните его командой cider-eval-..., иначе эффект не вступит в силу.

    Тег #break ссылается на функцию breakpoint-reader из модуля cider.nrepl.middleware.debug. Она принимает форму и добавляет в ее метаданные особое поле – признак отладки. Далее сработает оснащение (или инструментирование) — алгоритм, который ищет отмеченные формы и оборачивает их кодом, который запускает отладку.

    Когда оснащенный код запущен, в нужных местах он прерывается, и от клиента ожидают команду. Можно узнать локальные переменные, выполнить выражение или перейти к следующей точке. Так продолжается до тех пор, пока код не выполнен целиком.

    В Emacs нет графических средств отладки. Информация выводится либо рядом с кодом, либо в отдельных буферах. В режиме отладки файл нельзя редактировать; клавиши не вводят текст, а вызывают команды. Ошибка новичков в том, что, попав в отладку, они нажимают все подряд, и процесс протекает с ошибками. Ниже мы рассмотрим процедуру так, чтобы с вами этого не случилось.

    Read more →

Страница 21 из 79