Подмена раскладки клавиатуры

В ходе набора текста мне не понравилась точка, которой в моей клавиатурной раскладке я заменяю знак умножения (ставить точку для умножения — стандартная математическая практика).

Даже на 100% (не говоря уж о 200%) этот символ 0xB7 (middle dot) в шрифте Cozette больше похож на плюс. Я собрался перерисовать его, но в ходе перерисовки обнаружил, что есть U+22C5 (dot operator) вместо этой «средней точки», и этот оператор в Cozette отрисован правильно, в виде квадратика. Я немного подправил этот символ с точки зрения его позиционирования; осталось заменить вводимый символ во всех раскладках.

Текстовый файл раскладки заменить легко, но сборка установщика MS Keyboard Layout Creator (далее — MSKLC) не сработает, поскольку клавиатурная раскладка с тем же именем уже существует в системе. Деинсталлировать обе существующих раскладки, создавать новые инсталляторы, устанавливать, после чего делать новые раскладки раскладками по-умолчанию — не слишком ли много геморроя?

Раскладку можно собрать при помощи консольных утилит, поставляемых с MSKLC — kbdutool.exe и остальных. По сути, с MSKLC поставляется минимальный комплект исходников и компилятор для сборки необходимых .dll.

Я написал makefile, который компилирует раскладки в dll и раскладывает их по папкам: WOW64 (x86) и AMD64 (x64). На живой машине подложить эти dll вместо существующих невозможно, поскольку целевые dll «заняты» понятно кем, хотя мне сразу после загрузки ОС удалось подложить русскую раскладку.

Следовательно, необходимо загрузиться с другого носителя и подложить созданные файлы на место существующих. Для этого есть Active Boot CD.

Я сначала не понял, почему системный диск не виден в Active Boot CD. Обновил Active Boot CD до 22, безрезультатно. Чуть позже понял, что системный раздел не опознаётся, ибо защищён Rollback RX, там нестандартная таблица файлов.

Деинсталляция Rollback RX решила проблему, раздел увиделся; из-под Active Boot CD я подменил файлы на новую сборку, где AltGr+Shift+X вставляет правильную точку-оператор, перезагрузился, и вуаля!

Иногда я собой доволен.

1900—2022

Читаю Ольденбурга.

Немного о благодарности наших ближайших соседей:

На Балканахъ Россія пережила за 80-е годы тягчайшія разочарованія. Освободительная война 1877−78 г., стоившая Россіи столько крови и такихъ финансовыхъ потрясеній, не принесла ей непосредственныхъ плодовъ. Австрія фактически завладѣла Босніей и Герцеговиной, и Россія вынуждена была это признать, чтобы избѣжать новой войны. Въ Сербіи находилась у власти династія Обреновичей, въ лицѣ короля Милана, явно тяготѣвшая къ Австріи. Про Болгарію — даже Бисмаркъ ѣдко отозвался въ своихъ мемуарахъ: «Освобождённые народы бываютъ не благодарны, а притязательны». Тамъ дѣло дошло до преслѣдованія русофильскихъ элементовъ. Замѣна князя Александра Баттенбергскаго, ставшаго во главѣ антирусскихъ теченій, Фердинандомъ Кобургскимъ не улучшила русско-болгарскихъ отношеній. Только въ 1894 г. долженъ былъ уйти въ отставку Стамбуловъ, главный вдохновитель русофобской политики. Единственной страной, съ которой Россія въ теченіе долгихъ лѣтъ даже не имѣла дипломатическихъ сношеній, была Болгарія, такъ недавно воскрешённая русскимъ оружіемъ изъ долгаго государственнаго небытія!

Самоуправление в городе Москве выглядит точно так же:

Россія не имѣла имперскихъ представительныхъ учрежденій; Императоръ Александръ III, говоря словами К.П. Побѣдоносцева, вѣровалъ «въ непоколебимое значеніе власти самодержавной въ Россіи» и не допускалъ для нея «въ призракѣ свободы гибельнаго смѣшенія языковъ и мнѣній». Но отъ предшествующаго царствованія въ наслѣдіе остались органы мѣстнаго самоуправленія, земства и города; и ещё со временъ Екатерины II существовало сословное самоуправленіе въ лицѣ дворянскихъ собраній, губернскихъ и уѣздныхъ (мѣщанскія управы и другіе органы самоуправленія горожанъ утратили постепенно всякое реальное значеніе).

Ничего не поменялось и с точки зрения пиара:

Можно сказать, что русская власть не имѣла ни склонности, ни способности къ саморекламѣ. Ея достиженія и успѣхи нерѣдко оставались въ тѣни, тогда какъ неудачи и слабыя стороны старательно расписывались, съ мнимой объективностью, на страницахъ русской повременной печати, а за границей распространялись русскими политическими эмигрантами, создавая во многомъ ложныя представленія о Россіи.

Позиции интеллигенции и народа всё так же разделены пропастью:

Конечно, много было недочётовъ въ русскомъ народномъ хозяйствѣ, и западныя государства, съ ихъ маленькой площадью и густымъ населеніемъ, значительно опередили Россію въ количественномъ отношеніи по части развитія техники.

Но не въ хозяйственныхъ недочётахъ и не въ технической отсталости была заложена главная угроза Россійскому государству! Корень зла былъ въ глубокой розни между властью и значительной частью образованнаго общества. Русская интеллигенція относилась къ власти съ опредѣлённой враждебностью, которая порой принимала болѣе откровенныя формы, порой загонялась вглубь, съ тѣмъ, чтобы снова проявиться съ удвоенной силой.

Въ первой половинѣ XIX вѣка лучшіе русскіе писатели ещё понимали значеніе Царской власти. Пушкинъ, Гоголь, Жуковскій, не говоря уже о Карамзинѣ, оставили немало страницъ, ярко о томъ свидѣтельствующихъ. Но русская интеллигенція уже и тогда была не съ ними. Бѣлинскій, гнѣвнымъ обличеніемъ отвѣчающій на «Переписку съ друзьями», для нея гораздо типичнѣе самого Гоголя. Среди писаній Пушкина замалчивались произведенія его зрѣлаго возраста, гдѣ онъ говорилъ объ Императорѣ Николаѣ I, и списывались и распространялись его юношескіе выпады противъ власти.

Возстаніе декабристовъ внесло этотъ расколъ на самые верхи общества, подорвало довѣріе Царя къ военному дворянству и этимъ увеличило значеніе зависящаго отъ власти служилаго сословія.

Эпоха великихъ реформъ сперва кое-что улучшила въ этомъ отношеніи; она открыла новыя поприща для работы, суды, земства, посредническую дѣятельность въ деревнѣ. Но крайнія теченія быстро отравили и тутъ сотрудничество между интеллигенціей и властью. Реформы только вызывали требованія дальнѣйшихъ реформъ; новыя возможности дѣйствія использовались для пропаганды противъ правительства. Черезъ пять лѣтъ послѣ освобожденія крестьянъ, уже произошло первое покушеніе на Царя-Освободителя.

И опять-таки: лучшіе писатели того времени были скорѣе съ властью, чѣмъ съ интеллигенціей. Графъ Л.Н. Толстой до конца 70-хъ годовъ печатался въ «Русскомъ Вѣстникѣ» Каткова. Достоевскій, въ молодости примкнувшій къ соціалистическому кружку и за это жестоко пострадавшій, въ «Бѣсахъ» съ непревзойдённой яркостью изобразилъ духъ русской революціи и въ «Дневникѣ Писателя» отстаивалъ значеніе Царской власти для Россіи. Къ консервативному лагерю принадлежали и Фетъ, и Тютчевъ, и Майковъ, и по существу даже гр. А.К. Толстой («двухъ становъ не боецъ, а только гость случайный»). Опредѣлённымъ противникомъ интеллигентскаго радикализма былъ Лѣсковъ. Писемскій въ «Взбаламученномъ морѣ» далъ неприглядный очеркъ «шестидесятниковъ»; и даже западникъ Тургеневъ въ «Отцахъ и Дѣтяхъ», «Дымѣ» и «Нови» изобразилъ такъ называемыхъ «нигилистовъ» въ малопривлекательномъ свѣтѣ…

Но тонъ задавали не они! «Властителями думъ» были радикальные критики, проповѣдники матеріализма, непримиримые обличители существующаго. Уже раздавались требованія не только политическихъ, но и коренныхъ соціальныхъ преобразованій, какъ будто отмѣна крѣпостного права не была сама по себѣ огромной соціальной реформой. Интеллигенція перенимала отъ Запада непремѣнно самыя крайнія ученія. Началось «хожденіе въ народъ» съ цѣлью распространенія этихъ ученій въ крестьянской средѣ, съ надеждой на революцію по образцамъ Пугачёва и «атамана Степана», какъ называли Стеньку Разина въ модномъ тогда романсѣ «Утёсъ».

Народная масса тогда не поддалась на эти увѣщанія и посулы; она встрѣтила съ недовѣріемъ чуждыхъ ей людей; хожденіе въ народъ окончилось полнымъ проваломъ, и тогда возникла партизанская вооружённая атака на власть, руководившаяся пресловутой «партіей Народной Воли».

Восполняя дерзостью и предпріимчивостью недостатокъ своей численности, революціонеры въ теченіе нѣсколькихъ лѣтъ сумѣли создать гипнозъ мощнаго движенія противъ власти; они смутили правителей, они производили впечатлѣніе за границей. Жизнь Царя-Освободителя подвергалась ежечасной угрозѣ: то взрывали рельсы передъ Царскимъ поѣздомъ, то — даже покои Зимняго дворца. Александръ II рѣшилъ попытаться привлечь на сторону власти колеблющіеся образованные слои, съ извѣстнымъ злорадствомъ наблюдавшіе за борьбой между правительствомъ и «нигилистами», но не успѣлъ принять никакихъ реальныхъ мѣръ въ этомъ направленіи: 1 марта 1881 г. свершилось цареубійство.

Страшная вѣсть всколыхнула Россію, многихъ отрезвила, создала пустоту вокругъ дѣятелей «Народной Воли». Императоръ Александръ III, считавшій положеніе крайне опаснымъ, тѣмъ не менѣе рѣшилъ дать врагамъ мужественный отпоръ — и вдругъ натискъ «нигилистовъ» разсѣялся, какъ наважденіе.

Но произошли ли за царствованіе Императора Александра III дѣйствительныя перемѣны въ настроеніяхъ образованныхъ классовъ? Интеллигенція притихла, смолкла, враждебность исчезла съ поверхности, но тѣмъ не менѣе она осталась. Всѣ мѣры царствованія встрѣчали глухую, по внѣшности сдержанную, но непримиримую критику. Болѣзнь оказалась только загнанной вглубь.

Грозная черта этихъ лѣтъ: новые писатели уже не отдѣлялись отъ интеллигенціи въ своёмъ отношеніи къ существующему строю. Тѣ изъ нихъ, которымъ было душно въ радикальной казармѣ, просто уходили въ область чистаго искусства, оставаясь въ сторонѣ отъ общественной жизни. Изъ ученій гр. Л.Н. Толстого, рѣзко измѣнившагося за эти годы, его «непротивленіе злу» и раціоналистическое христіанство пользовались гораздо меньшимъ успѣхомъ, чѣмъ его отрицаніе всего современнаго государства.

Пассивное сопротивленіе интеллигенціи создавало для власти большія затрудненія, особенно въ области народнаго образованія. Студенчество, несмотря на рядъ новыхъ законовъ, вводившихъ университетскую жизнь въ строгія рамки (ношеніе формы, обязательное посѣщеніе лекцій и т. д.), или отчасти благодаря этимъ законамъ, оставалось разсадникомъ революціонныхъ теченій. Власть поэтому питала недовѣріе къ высшимъ учебнымъ заведеніямъ; нѣкоторыя изъ нихъ, какъ Женскіе Медицинскіе курсы, были закрыты; на С.-Петербургскіе Высшіе женскіе курсы на три года былъ запрещёнъ пріёмъ. Правительству приходилось лавировать между Сциллой отсталости въ ученіи и Харибдой взращиванія своихъ враговъ. Насколько велика была нетерпимость этихъ враговъ, показываетъ характерный случай: проф. В.О. Ключевскій, извѣстный историкъ, пользовавшійся огромной популярностью въ студенчествѣ, вызвалъ съ его стороны враждебныя выходки своей (приведённой выше) рѣчью памяти Императора Александра III, и не скоро вернулъ себѣ былой престижъ. Сдѣлать такъ, чтобы увеличить число школъ, не создавая въ деревнѣ очаговъ противоправительственной пропаганды, было при такихъ условіяхъ весьма нелегко. Строить и совершенствовать огромнѣйшее государство при враждебномъ отношеніи значительной части образованныхъ слоёвъ — было задачей исключительной трудности!

Об отношении интеллигенции к другим формам правления:

Въ русскомъ обществѣ восшествіе на престолъ новаго Государя породило прежде всего смутную надежду на перемѣны. Въ русской печати стали помѣщаться привѣтственныя статьи по адресу молодой Императрицы, въ которыхъ мимоходомъ высказывалось предположеніе, что она внесётъ и въ русскую жизнь тѣ начала, среди которыхъ была воспитана. Интеллигенція считала преимущества западныхъ государственныхъ формъ совершенно безспорными и очевидными и была увѣрена, что жить при парламентарномъ строѣ — значитъ цѣнить его и любить…

О повадках русской интеллигенции:

За первые годы новаго вѣка въ русской литературѣ почувствовалось оживленіе; появился рядъ новыхъ имёнъ. Наряду съ А.П. Чеховымъ, обратившимся на новое поприще драматурга, и М. Горькимъ, въ которомъ «дѣятель» начиналъ уже заслонять писателя, появились Леонидъ Андреевъ, безспорно талантливый писатель со склонностью къ болѣзненнымъ, мучительнымъ переживаніямъ; Бунинъ, Купринъ (особенный успѣхъ имѣла его повѣсть изъ быта армейскаго офицерства «Поединокъ»). Кромѣ этихъ писателей, группировавшихся вокругъ «марксистскаго» издательства «Знаніе», значительно выросло и усилилось «модернистское», «декадентское» теченіе: вслѣдъ за «Міромъ Искусства» появились журналы «Новый Путь» (съ 1903 г.), «Вѣсы» (съ 1904 г.). Ещё ранѣе было основано издательство «Скорпіонъ»; Бальмонтъ, Брюсовъ, Гиппіусъ, Мережсковскій, Ѳ. Сологубъ издали за эти годы едва ли не лучшіе сборники стиховъ; Андрей Бѣлый выступилъ со своей первой «симфоніей»; А. Блокъ началъ печатать стихи въ «Новомъ Пути».

Необычный для русской интеллигенціи интересъ къ религіознымъ вопросамъ вызвалъ съ зимы 1901−1902 г. къ жизни религіозно-философскія собранія въ С.-Петербургѣ, въ которыхъ — необычайное сочетаніе — участвовали представители церкви и духовнаго вѣдомства, профессора богословія, «послѣдніе славянофилы» вродѣ ген. Кирѣева, наряду съ писателями и журналистами, близкими къ журналу «Новый Путь». Обсуждались вопросы о христіанскомъ догматѣ, о свободѣ совѣсти, о бракѣ, о ученіи Толстого. Д.С. Мережсковскій, смѣло признавшій, что Св. Сѵнодъ былъ правъ, отлучая отъ церкви гр. Л.Н. Толстого, подвергся за это рѣзкимъ нападкамъ въ средѣ интеллигенціи. «Въ Россіи», — писалъ онъ по этому поводу, — «образовалась вторая цензура, болѣе дѣйствительная, болѣе жестокая, чѣмъ первая, — цензура „общественнаго мнѣнія“».

Эта вторая цензура распространялась даже на область художественной критики. «Что мнѣ дѣлать?» — писалъ въ «Новомъ Пути» Антонъ Крайній. — «Литература, журналистика, литераторы — у насъ тщательно раздѣлены надвое и завязаны въ два мѣшка; на одномъ написано „консерваторы“, на другомъ „либералы“. Чуть журналистъ раскроетъ ротъ — онъ уже непремѣнно оказывается въ которомъ-нибудь мѣшкѣ. Есть сугубо жгучіе вопросы, имена, о которыхъ совсѣмъ нельзя высказывать собственныхъ мыслей. Мыслей этихъ никто не услышитъ — слушаютъ только одно: одобряешь или порицаешь. Порицаешь — въ одинъ мѣшокъ, одобряешь — въ другой, и сиди, и не жалуйся на неподходящую компанію. Самъ виноватъ… Великое несчастіе — эта наша литературная тѣснота, недостойная даже и такого малокультурнаго человѣка, какъ нашъ современный „литераторъ“!»

(Эти мысли служили вступленіемъ къ мѣткому отзыву о значеніи творчества Горькаго: «…Жить и дышать всё-таки ещё можно, и человѣкъ ещё человѣкъ. Нуженъ рѣзкій толчокъ, чтобы выкинуть людей сразу въ безкислородное пространство, прекратить ихъ человѣческія мученія. Этотъ толчокъ, несущій человѣку окончательное смертное освобожденіе, фонтанъ углекислоты — проповѣдь Максима Горькаго и его учениковъ».)

Въ этихъ протестахъ немногихъ остававшихся внѣ борьбы ярко сказывается трагическое раздвоеніе историческаго момента. Всё русское образованное общество, за весьма малыми исключеніями, находилось въ состояніи рѣзкой, непримиримой, слѣпой оппозиціи къ власти. Именно въ эти годы былъ выдвинутъ и сталъ ходячей фразой краткій и категорическій боевой кличъ «долой самодержавіе», принимавшій въ легальныхъ изданіяхъ форму нападокъ на «бюрократію».

Среди организованныхъ революціонныхъ силъ выдѣлялись два главныхъ теченія: соціалисты-народники, мечтавшіе о крестьянскомъ возстаніи (а то и военномъ бунтѣ — вѣдь армія въ большинствѣ изъ крестьянъ) и дѣйствовавшіе путёмъ террора; соціалисты-марксисты, дѣлавшіе ставку на рабочее движеніе и разсчитывавшіе пропагандой и забастовками «раскачать» городъ на болѣе активныя выступленія. <…> Эти организованныя революціонныя теченія были бы, однако, безсильны, если бы общественное мнѣніе русской интеллигенціи не склонилось въ то время къ революціоннымъ путямъ борьбы. Предзнаменованіемъ такого оборота было появленіе въ 1900 г. нелегальной книги «Россія на рубежѣ ХХ-го столѣтія», написанной нѣкогда враждебнымъ всякой «нелегальщинѣ» профессоромъ Б.Н. Чичеринымъ. Въ іюнѣ 1902 г. оппозиціонные не-соціалистическіе круги сдѣлали болѣе рѣшительный шагъ: въ Штутгартѣ, подъ редакціей П.Б. Струве, начало издаваться «Освобожденіе».

Ольденбург, однако, вполне очевидно пристрастен. Царский режим и царя он изображает едва ли не идеальными. Но большие массы людей не могут полностью ошибаться и быть беспочвенно настроены против; народ в целом всегда мудрее и взвешеннее отдельных лиц. Ведь не была же ненависть к самодержавию на пустом месте; душная цензура, телесные наказания и отвратительная самоуверенность того, кто почему-то считает себя наместником бога на земле, а его ставленники — народу не подотчётные — высокомерны и хамоваты, могут и должны понемногу подтачивать даже изначально хорошее отношение. Русский народ как минимум в лице его образованного класса перерос самодержавие.

Началась русско-японская война:

Извѣстіе о началѣ войны поразило, всколыхнуло Россію. Почти никто её не ждалъ; огромное большинство русскихъ людей имѣли самое смутное представленіе о Маньчжуріи. Но всюду почувствовали: на Россію напали. Въ первый періодъ войны это настроеніе преобладало: на Россію напали и надо дать отпоръ врагу.

Въ Петербургѣ, а затѣмъ и въ другихъ городахъ, возникли сами собой давно невиданныя уличныя патріотическія манифестаціи. Ихъ необычной чертой было то, что въ нихъ участвовала и учащаяся молодёжь. Въ университетѣ состоялась сходка, завершившаяся шествіемъ къ Зимнему дворцу съ пѣніемъ «Боже, Царя храни». Тѣ, кто не сочувствовалъ, — а ихъ было немало — въ этотъ день примолкли, стушевались. <…>

Оппозиціонные круги, въ началѣ января 1904 г. устроившіе въ Петербургѣ первый нелегальный съѣздъ Союза Освобожденія и выбравшіе тайный руководящій комитетъ, оказались застигнутыми врасплохъ этими настроеніями. Земскія и дворянскія собранія, городскія думы принимали вѣрноподданническіе адреса. Земскіе конституціоналисты, собравшіеся 23 февраля на совѣщаніе въ Москвѣ, приняли рѣшеніе: ввиду войны всякія провозглашенія конституціонныхъ требованій и заявленій прекращаются, по крайней мѣрѣ на первые мѣсяцы; это рѣшеніе мотивировалось патріотическимъ подъёмомъ въ странѣ, вызванномъ войной.

<…>

Настроеніе массъ отчасти проявилось въ усиленномъ спросѣ на лубочныя военныя картинки, на портреты героевъ войны. Революціонеры-террористы, скрывавшіеся подъ видомъ странствующихъ торговцевъ, вынуждены были сами торговать этими картинками. «Гонятъ народъ, какъ на бойню, и никакого протеста», — со злобнымъ раздраженіемъ говорилъ террористъ Каляевъ своему товарищу Сазонову. «Всѣхъ обуялъ патріотизмъ... Повальная эпидемія глупости... На героевъ зѣваютъ, разинувши ротъ...»

<…>

Но война не могла быть «короткой и побѣдоносной». Она начиналась при неблагопріятныхъ для Россіи условіяхъ; только время и упорныя усилія могли ихъ исправить. А первый порывъ — желаніе дать отпоръ врагу — при полномъ непониманіи значенія войны не только въ массахъ, но и въ образованныхъ слояхъ — скоро сталъ замѣняться совершенно иными настроеніями.

Каково же было поведение стран при этом нападении?

За границей къ войнѣ отнеслись очень разно. Англія и Америка опредѣлённо стали на сторону Японіи. «Борьба Японіи за свободу» — такъ назвалась еженедѣльная иллюстрированная лѣтопись войны, начавшая выходить въ Лондонѣ. Президентъ Рузвельтъ «на всякій случай» даже предупредилъ Германію и Францію, что, буде онѣ попытаются выступить противъ Японіи, онъ «немедленно станетъ на ея сторону и пойдётъ такъ далеко, какъ это потребуется». Тонъ американской печати, особенно еврейской, былъ настолько враждебенъ Россіи, что Меньшиковъ въ «Новомъ Времени» воскликнулъ: «Вся нынѣшняя война есть чуть не прямое содѣйствіе еврейской агитаціи въ тѣхъ странахъ, гдѣ печать и биржа въ рукахъ евреевъ... Нѣтъ сомнѣнія, что безъ обезпеченія Америки и Англіи Японія не сунулась бы съ нами въ войну». Это было, во всякомъ случаѣ, значительнымъ преувеличеніемъ одного изъ факторовъ сложнаго международнаго положенія.

<…> Въ Германіи — лѣвыя газеты были противъ Россіи, правыя — въ большинствѣ за неё.

Замените Японию на другую страну, на букву «У»:

Въ печати между тѣмъ всё сильнѣе разгоралась кампанія противъ власти подъ флагомъ критики веденія войны. Недооцѣнка противника и переоцѣнка русскихъ силъ побуждала многихъ вполнѣ добросовѣстно — не скорбѣть, а негодовать по поводу того, что война не принесла до сихъ поръ успѣховъ. Забывая, что Полтава была только черезъ пять лѣтъ послѣ Нарвы; забывая, что Англія такъ недавно была вынуждена воевать три года, чтобы одолѣть нѣсколько десятковъ тысячъ буровъ, не имѣвшихъ даже артиллеріи; не учитывая тотъ фактъ, что Россія продолжала держать свои главныя силы на европейской границѣ, — русскій обыватель искренне возмущался — какъ это за восемь мѣсяцевъ мы не справились съ «какой-то» Японіей?

О «кровавом воскресенье»:

Молва тотчасъ же пріумножила число жертвъ. По офиціальной сводкѣ, появившейся позже, убито было 130 человѣкъ и ранено нѣсколько сотъ. Если бы толпѣ удалось овладѣть центромъ города, число жертвъ было бы, вѣроятно, во много разъ больше. Но дѣло было не въ числѣ жертвъ, а въ самомъ фактѣ массоваго народнаго движенія противъ власти, столкновенія толпы съ войсками на улицахъ столицы. Конечно, часть демонстрантовъ была обманута руководителями, внушавшими ей, что движеніе — не противъ Царя, что ничего революціоннаго въ нёмъ нѣтъ. Но также было несомнѣнно, что революціонные лозунги встрѣтили неожиданный откликъ въ широкихъ рабочихъ массахъ. 9 января какъ бы вскрылся гнойникъ; оказалось, что не только интеллигенція, но и «простой народъ» — по крайней мѣрѣ въ городахъ — въ значительной своей части находился въ рядахъ противниковъ существующаго строя.

(с иронией) Не может быть, опять народ не тот; он _внезапно_ находился в противниках существующего строя!

The Bat & Google Mail

Долгое время я пользовался The Bat! Voyager от Ritlabs. Удобство заключалось в том, что множество почтовых ящиков с шифрованием можно было носить на флешке. Вся почта забиралась с сервера с удалением…

…пока Google не поменял у себя что-то на серверах, после чего отправлять почту по SMTP стало невозможно: Google закрывает доступ The Bat к Gmail.

Потратив на борьбу с этим три дня, установил себе Thunderbird на основную домашнюю машину, получив отличный доступ также к календарям всех используемых почтовых ящиков. На флешке останется доступ по IMAP, который почему-то ещё работает.

Я, конечно, обдумывал de-Google, но на эти несколько адресов довольно многое завязано, и на всех ресурсах менять мыло мне очень лень.

Новую версию The Bat! я, понятное дело, приобретать не буду. Так теряются клиенты.

О Скотте Мейерсе

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

Advent of Code 2021

Первое задание Advent of Code 2021 откроется первого декабря.

В этом году я буду решать его на Haskell. Конечно, решу очень мало, потому что знаком с языком слабо, но это необходимая практика. Похоже, кроме меня заняться починкой выходного модуля для Docx в pandoc некому.

Борьба с приватностью

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

Европейские министры внутренних дел поддерживают введение обязательного мониторинга и контроля чатов на смартфонах пользователей.

Что-то я не слышу возгласов из «либеральной» тусовки про то, что Европа с Австралией — тоталитарные помойки. Или это другое?

Fzf-Lsp

Если вы пользуетесь Neovim в Windows, сразу можно готовиться переписывать плагины за другими.

Не успел я объяснить автору nvim-fzf как работают named pipes в Windows, чтобы он наконец сделал нормальную поддержку этой ОС, пришлось чинить fzf-lsp. Последний использует «стандартный» плагин fzf.vim, написанный самим автором fzf, для показа сообщений из встроенного в Neovim LSP.

Конечно же, написать кроссплатформенно автор не может, у него же нет Windows (непреодолимое препятствие в наши дни!). Дёргать preview.sh, который на моей машине дёргает bash из дистибутива Git и открывает всплывающее чёрное окно для fzf preview — вот кроссплатформенность для разработчиков в наши дни.

Вот как это фиксится.

diff --git a/lua/fzf_lsp.lua b/lua/fzf_lsp.lua
index 79c0365..09c6fe0 100644
--- a/lua/fzf_lsp.lua
+++ b/lua/fzf_lsp.lua
@@ -6,7 +6,7 @@ local M = {}
local __file = debug.getinfo(1, "S").source:match("@(.*)$")
assert(__file ~= nil)
local bin_dir = fn.fnamemodify(__file, ":p:h:h") .. "/bin"
-local bin = { preview = (bin_dir .. "/preview.sh") }
+local bin = { preview = (bin_dir .. '/' .. vim.env.FZF_PREVIEW_COMMAND) }
-- }}}

-- utility functions {{{
@@ -325,8 +325,8 @@ end

local function fzf_locations(bang, prompt, header, source, infile)
   local preview_cmd = (infile and
-    (bin.preview .. " " .. fn.expand("%") .. ":{}") or
-    (bin.preview .. " {}")
+    ('for /f "delims=: tokens=1" %L in ({}) do @(IF %L GEQ 10 (set /a "pre=%L-10">nul) ELSE (set "pre=0"))&&@cmd /a /q /s /v:on /c "' .. bin.preview .. ' --line-range %pre%: --highlight-line %L ' .. fn.expand("%") .. '"')  or
+    ('for /f "delims=: tokens=1,2" %L in ({}) do @(IF %M GEQ 10 (set /a "pre=%M-10">nul) ELSE (set "pre=0"))&&@cmd /a /q /s /v:on /c "' .. bin.preview .. ' --line-range %pre%: --highlight-line %M %L"')
   )
   local options = {
   "--prompt", prompt .. ">",

Одной строкой cmd мы делим строки из диагностики на куски (разделитель: :), и берём первый из них (номер строки) для показа диагностики для текущего буфера, и два (имя файла и номер строки) — для диагностики во всех буферах сразу (это :Diagnostics и :DiagnosticsAll в fzf-lsp). Полученное скармливаем в качестве параметров программе предварительного просмотра, bat. Выводим диапазон -10 от текущей строки, подсвечиваем текущую строку.

Я в курсе, что автор ничего не должен никому. Можно даже сказать, что FOSS расшифровывается как «Fuck Off, [we're writing] Shitty Software». Поэтому придётся поддерживать собственные форки как для fzf.vim, так и для fzf-lsp.

Cozette

Для тех, кто проводит много времени в терминале, немалое значение имеет шрифт. Большой удобно читать, но информации на экране поместится меньше. Мелкие шрифты практически все страдают плохой читабельностью, если используется ClearType (я, как обычно, пишу о Windows). Несколько улучшают ситуацию шрифты растровые — если в эмуляторе терминала можно отключить ClearType, то шрифт будет невероятно резким, поскольку будет отображаться в соответствии с пиксельной сеткой монитора.

Выбор растровых шрифтов с кириллицей невелик, а с нормальной поддержкой чего-нибудь ещё, так вообще таких шрифтов единицы. К счастью, есть Cozette. Рекомендую взглянуть.

Автор поставил себе амбициозную задачу: сделать растровый шрифт с хорошей поддержкой Unicode. Что ещё интереснее, эту поддержку он планировал реализовать на площадке глифа размером 6×13 пикселей. Когда я увидел это впервые, я был приятно удивлён, автор проделал отличную работу!

Я поддержал начинание, и внёс значительные изменения и дополнения в шрифт. Часть из этих дополнений уже влилась в основную ветку, а часть, содержащая в себе множество новых глифов и доработку нескольких существовавших (в том числе и авторских, он тоже местами поторопился) пока находится на рассмотрении.

Вот полный список глифов шрифта. Помимо кириллицы, он обеспечивает вполне приличную поддержку греческого и восточноевропейских языков (не без моей помощи).

https://github.com/cpkio/Cozette/raw/master/img/showcase.png

А пока он не принял PR и не собрал шрифт, можно использовать мою сборку.

Vim Quoted-Printable Decode

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

Экспорт книжки с самсунговского телефона возможен (правда, выбор способов ограничен, и отправить книжку по электронной почте, например, не получилось; к счастью, я могу передать файл через Bluetooth на рабочую машину). Но вот незадача — весь не-латинский текст закодирован в Quoted-Printable (см. раздел 6.7 RFC 2045).

По сути, кодируется последовательность байт, что позволяет кодировать и UTF-8, и UTF-32, просто будет два литерала (=FF=FF) или четыре литерала соответственно.

Кодирование это видимо вызвано тем, что телефонная книжка экспортирует контакты в формате vCard 2.1.

К своему разочарованию, я обнаружил, что подходящих декодеров нет. Идея-то была в том, чтобы натравить декодер либо на телефонную книжку целиком, либо воспользоваться командой в Vim/Neovim [range]g/regex/command, то есть выполнить команду command на тех строках, в которых встречается регулярное выражение regex.

Писать на Rust или Go такую утилиту я поленился. Помогли китайцы.

Я бы сказал, что китайское присутствие чувствуется даже на GitHub, и оно часто полезно; к примеру, лаунчер Wox, которым я пользуюсь каждый день — китайского авторства. Автор проект забросил, но я собрал последнюю версию самостоятельно и пользуюсь с большим удовольствием уже давно. Он по крайней мере работает. Новый проект, взявший за основу код Wox, после установки падает сразу же, да и работает в принципе значительно хуже.

Так и тут: нашлось несколько строк, которые позволяют декодировать Quoted-Printable в соответствии со стандартом. Плагин к Notepad++ не в состоянии сделать даже этого (к примеру, CRLF должен быть представлен в виде закодированной последовательности, но авторы плагинов к Notepad++ стандарт не читали).

Пришлось чуть освежить в памяти С++:

#include <iostream>
#include <string>
#include "QuotedPrintable.hpp"

int main()
{
   for (std::string line; std::getline(std::cin, line); )
   {
      std::string qstring;
      for (int i = 0; i < line.length(); i++) {
         if (strchr("=", line[i]) != NULL) {
            if (strchr("0123456789ABCDEF", line[i+1]) != NULL) {
               if (strchr("0123456789ABCDEF", line[i+2]) != NULL) {
                  qstring += line[i];
                  qstring += line[i+1];
                  qstring += line[i+2];
                  i += 2;
               }
               else { std::cout << line[i]; }
            }
            else { std::cout << line[i]; }
         }
         else {
            std::cout << QuotedPrintable::decode(qstring);
            qstring = "";
            std::cout << line[i];
         }
      }
      std::cout << QuotedPrintable::decode(qstring) << std::endl;
   }
}

Колхозно? О да. Работает? Более чем.

Программа считывает произвольное количество строк с STDIN и возвращает тот же текст, но с раскодированным Quoted-Printable. Командой %g/\v(%u003d[A-F0-9]{2}){2,}/.!qpdecode/ находим все строки, в которых есть Quoted-Printable, и передаём их по одной в qpdecode. На выходе получаем нормальный UTF-8.

多谢, xuzheyang!

Отключение обновлений Firefox

На Hacker News за последние несколько недель появлялись публикации, посвященные Firefox. Общее впечатление у всех такое, что Mozilla намеренно делает всё, чтобы уничтожить даже ту постоянно уменьшающуюся пользовательскую аудиторию, которая у неё ещё осталось. Принудительное обновление интерфейса до Photon UI меня, сказать по правде, взбесило, и я начал искать способы обеспечить стабильность браузера.

Собственно, я уже давно посвящаю много времени обеспечению стабильности рабочего компьютера (взять хотя бы Rollback RX). Но Firefox очень надоел со своими предложениями обновиться, и с этим надо бороться.

Для начала откатился на v88, где этого гнусного Photon UI нет.

Помешать Firefox задалбывать вас обновлениями можно, как выяснилось, только одним способом — через настройку групповых политик (я понимаю логику Mozilla, это попытка сделать Firefox корпоративным браузером). Это можно сделать по-разному: если речь только об обновлениях, достаточно установить параметр REG_DWORD DisableAppUpdate равным 1 по адресу HKEY_CURRENT_USER\Software\Policies\Mozilla\Firefox.

Второй вариант интереснее с точки зрения выбора опций для отключения:

  • по адресу https://github.com/mozilla/policy-templates из раздела релизов загружаем файл групповых политик для Firefox нужной версии;

  • загружаем удобный маленький редактор групповых политик Policy Plus по адресу https://github.com/Fleex255/PolicyPlus;

  • распаковываем архив групповых политик, загружаем в Policy Plus файлы mozilla.admx и firefox.admx (в этой последовательности) и ищем «Отключить обновления» прямо в корне дерева политик Firefox;

  • по желанию изучаем все остальные настройки групповых политик для Firefox;

  • обязательно нажимаем <CTRL>+<S> для сохранения изменений.

Advent of Code 2020 D13

День 13 занял у того же товарища, что решает AoC на Zig, чуть более трёх часов (из которых два с половиной часа он решал вторую часть). Я, думая что могу решить быстрее, потратил на попытки сделать это два дня :( В итоге всё равно получается решение «в лоб» и грубой силой.

Часть 1

Приведу текст задачи (часть 1) полностью.

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

К счастью, есть автобусы, которые отвезут вас из морского порта в аэропорт. У каждого автобуса есть номер (ID), который показывает, как часто автобус выезжает в направлении аэропорта.

График движения автобусов определяется меткой времени, которая отмеряет число минут от какой-то отсчётной точки в прошлом. В момент 0 все автобусы отправляются из морского порта одновременно. После этого каждый автобус едет в аэропорт, потом по другим остановкам, и наконец возвращается в морской порт, чтобы продолжать это бесконечно.

Время, которое занимает этот круг, является номером (ID) автобуса: автобус с номером 5 отправляется из морского порта в моменты 0, 5, 10, 15 и так далее. Автобус с номером 11 отправляется в 0, 11, 22, 33 и так далее. Если вы будете там к моменту отправления автобуса, сможете на нём уехать в аэропорт.

Ваши заметки (исходные данные загадки) состоят из двух строк. Первая строка — оценка самого раннего времени (timestamp), когда вы сможете отправиться на автобусе. Вторая строка перечисляет номера автобусов, которые работают согласно данных от компании-перевозчика; записи с меткой x похоже что не работают, так что вы решаете их проигнорировать.

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

К примеру, заметки у вас следующие:

939
7,13,x,x,59,x,31,19

Самая ранняя метка времени, в которую вы сможете уехать — 939, а автобусы на линии — 7, 13, 59, 31 и 19. Рядом с меткой 939, эти автобусы отправляются во время, отмеченное буквой D.

time   bus 7   bus 13  bus 59  bus 31  bus 19
929      .       .       .       .       .
930      .       .       .       D       .
931      D       .       .       .       D
932      .       .       .       .       .
933      .       .       .       .       .
934      .       .       .       .       .
935      .       .       .       .       .
936      .       D       .       .       .
937      .       .       .       .       .
938      D       .       .       .       .
939      .       .       .       .       .
940      .       .       .       .       .
941      .       .       .       .       .
942      .       .       .       .       .
943      .       .       .       .       .
944      .       .       D       .       .
945      D       .       .       .       .
946      .       .       .       .       .
947      .       .       .       .       .
948      .       .       .       .       .
949      .       D       .       .       .

Самый ранний автобус, на которым вы сможете уехать — 59. Он не уедет ранее метки 944, так что потребуется подождать 944 − 939 = 5 минут до отправления. Умножение номера автобуса на число минут ожидания даст 295.

Каково число: номер самого раннего автобуса, на котором вы сможете уехать в аэропорт, умноженный на число минут ожидания этого автобуса?

Входные данные:

1003055
37,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,41,x,x,x,x,x,x,x,x,x,433,x,x,x,x,x,x,x,23,x,x,x,x,x,x,x,x,17,x,19,x,x,x,x,x,x,x,x,x,29,x,593,x,x,x,x,x,x,x,x,x,x,x,x,13

Решение, конечно, элементарное: поскольку все автобусы отправляются с заданной периодичностью, равной числу в списке, нужно найти число, у которого разница между самим числом (номером автобуса) и остатком от деления начального времени на этот номер минимальна. То есть, искомое минимальное время равно ID - @mod(Timestamp, ID), где @mod возвращает остаток от деления.

То есть создаём пару переменных (номер автобуса и время ожидания), и если полученное по формуле время меньше уже существующего, заменяем на текущее значение.

while (it.next()) |b| {
   if (std.mem.eql(u8, b, "x")) continue;
   var n = std.fmt.parseInt(usize, b, 10) catch 999999;
   var wait_time = n - @mod(start_time, n);
   if ( wait_time < minutes_wait ) {
      bus_number = n;
      minutes_wait = wait_time;
   }
}

Переходим ко второй части, которая заняла два с половиной часа у стримера.

Часть 2

Компания-перевозчик объявила конкурс: золотую монету тому, кто найдёт самую раннюю отметку времени, чтобы первый автобус отправлялся в это время, и чтобы последующие автобусы отправлялись в соответствующую минуту. (Первая строка исходных данных больше не важна).

К примеру, у вас тот же список автобусов, что и ранее:

7,13,x,x,59,x,31,19

Символ x означает, что ограничений на то, какой автобус отправится, в этом поле нет.

Это значит, что вы ищете самую раннюю метку времени (t), чтобы:

  • Автобус 7 отправлялся во время t.

  • Автобус 13 отправлялся на минуту позже t.

  • На вторую и третью минуты после t ограничения не накладываются.

  • Автобус 59 отправляется на 4 минуты позже t.

  • На пятую минуту после t ограничения не накладываются.

  • Автобус 31 отправляется через шесть минут после t.

  • Автобус 19 отправляется через семь минут после t.

Важны только те автобусы, которые указаны на соответствующих местах (смещениях) после t. Эти автобусы могут отправляться в другое время, и другие автобусы могут отправиться в это время. К примеру, в списке ниже, поскольку автобус 19 должен отправиться через семь минут после отметки времени, в которую отправится 7, автобус 7 также будет отправляться одновременно с автобусом 19 после t.

В этом примере наиболее ранняя отметка времени, в которую это произойдёт, 1068781:

time     bus 7   bus 13  bus 59  bus 31  bus 19
1068773    .       .       .       .       .
1068774    D       .       .       .       .
1068775    .       .       .       .       .
1068776    .       .       .       .       .
1068777    .       .       .       .       .
1068778    .       .       .       .       .
1068779    .       .       .       .       .
1068780    .       .       .       .       .
1068781    D       .       .       .       .   <<<
1068782    .       D       .       .       .
1068783    .       .       .       .       .
1068784    .       .       .       .       .
1068785    .       .       D       .       .
1068786    .       .       .       .       .
1068787    .       .       .       D       .
1068788    D       .       .       .       D
1068789    .       .       .       .       .
1068790    .       .       .       .       .
1068791    .       .       .       .       .
1068792    .       .       .       .       .
1068793    .       .       .       .       .
1068794    .       .       .       .       .
1068795    D       D       .       .       .
1068796    .       .       .       .       .
1068797    .       .       .       .       .

В примере выше, автобус 7 отправится во время 1068788 (через 7 минут после t). Это нормально; единственное требование в том, что 19 должен отправиться в это же время, что и происходит.

Другие примеры:

  • Наиболее ранняя метка времени для 17,x,13,19 — 3417.

  • 67,7,59,61 происходит во время 754018.

  • 67,x,7,59,61 происходит во время 779210.

  • 67,7,x,59,61 происходит во время 1261476.

  • 1789,37,47,1889 происходит во время 1202161486.

Однако, с тем количеством автобусов в вашем списке, самая ранняя метка времени будет больше 100000000000000!

Какая самая ранняя метка времени, в которую все указанные автобусы отправятся в соответствии со своими смещениями в списке?

Исходные данные не изменились.

Я рассуждал так: поскольку первый автобус должен отправиться во время, кратное его номеру (как и все остальные автобусы), то

  • получаем ближайшее кратное первому автобусу и максимально близкое к числу-подсказке 100000000000000, и далее

  • последовательно увеличиваем это кратное на номер этого первого автобуса (проход по кратным значениям) (x);

  • проверяем, кратно ли число x + номер позиции в списке автобусов номеру автобуса на этой позиции.

Если первый автобус отправляется во время t, то следующий автобус по индексу i должен отправиться во время t + i, а число t + i кратно этому номеру автобуса.

Проблема только в том, что без распараллеливания процесса этот подход реализуем только в теории; в один поток это займёт дни — проверено на себе.

Единственный вариант оптимизации, который мне доступен: проход от наиболее редких чисел к наиболее частым: сначала ищем число, кратное наибольшему номеру автобуса (таких чисел будет меньше остальных), и уже для этих чисел проверяем соответствие условиям.

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

// от наибольшего номера автобуса к наименьшему
for (list.items[1..]) |item| {
   // текущее число, кратное наибольшему номеру автобуса, уменьшаем на смещение этого наибольшего номера и прибавляем смещение следующего (в сторону уменьшения) номера автобуса; это число кратно следующему по величине номеру автобуса
   var current = @mod(value - list.items[0].index + item.index, item.bus) == 0;
   success = success and current;
   if (!success) break; // если остаток от деления [числа минус смещение плюс смещение нового] не равен нулю, переходим к следующему
}

За пять часов алгоритм проверил числа от 100000000000000 до ≈414148637009525.

Автобусы из исходных данных уезжают…

  • № 37 первым;

  • № 41 через 27 минут;

  • № 433 через 37 минут;

  • № 23 через 45 минут;

  • № 17 через 54 минуты;

  • № 19 через 56 минут;

  • № 29 через 66 минут;

  • № 593 через 68 минут;

  • № 13 через 81 минуту.

После ещё нескольких часов подсчётов я получил число 600691418730595, которое:

  • делится нацело на 37: 600691418730595 % 37 == 0;

  • (600691418730595 + 27) % 41 == 0;

  • (600691418730595 + 37) % 433 == 0;

  • (600691418730595 + 45) % 23 == 0;

  • (600691418730595 + 54) % 17 == 0;

  • (600691418730595 + 56) % 19 == 0;

  • (600691418730595 + 66) % 29 == 0;

  • (600691418730595 + 68) % 593 == 0;

  • (600691418730595 + 81) % 13 == 0.

Я намеренно не досмотрел стрим до конца, и сделаю это сейчас, чтобы понять, была ли эта задача решена быстрее.

Дополнение

Решение задачи — в китайской теореме об остатках.

Как остаться без телефона

Чтобы остаться без телефона, достаточно перезагрузить его. Под «остаться», правда, я понимаю «голый» телефон, по которому можно разве что звонить. А произошло вот что.

Сегодня я заметил, что телефон не реагирует на кнопку «убавить громкость» (нижняя часть качельки громкости). Я решил, что это может быть программным багом, и перезагрузил его, что происходит очень редко. Однако, оказалось, что телефон считает, что кнопка убавления громкости нажата постоянно! Если включить телефон Samsung, удерживая нажатой кнопку убавления громкости, то телефон будет загружен в «безопасном режиме». Безопасный режим позволяет загружать пользовательские настройки, включая аккаунт, но не загружает и не позволяет запускать какие-либо приложения, установленные в пользовательской части системы.

Для несведущих напомню, что в OC Android, как основанной на Linux, есть системная часть, и часть пользовательская. Правильнее было бы сказать, что есть пользовательский раздел жёсткого диска, который как правило шифруется во избежание доступа к нему посторонних лиц. Соответственно, при загрузке в безопасном режиме пользовательский раздел монтируется с ограничениями — получаем практически чистый телефон (настройки которого, скорее всего, не сохранятся, поскольку сохранять их некуда, сохранение в системную область недопустимо, а пользовательский раздел похоже что недоступен на запись).

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

Купить новый и перенести содержимое телефона с одного на другой мне пока крайне затруднительно, поскольку Samsung Sync (или как там зовётся приложение для миграции данных между телефонами) загрузить невозможно, копировать из безопасного режима нечего, а выяснять возможности ADB и других способов подключения в присутствии такого аппаратного дефекта нет ни времени, ни сил.

Приёмщик сказал что такое очень редко, но бывает. Этот телефон не проработал и трёх лет.

Advent of Code 2020 D11 и язык Zig

Advent of Code — конкурс для программистов, о котором я уже писал ранее. К нему я возвращаюсь нерегулярно, но в этот раз совпало два момента.

Первый: язык Zig (но изучать мне показалось удобнее здесь). Этот язык, издалека и с большим прищуром похожий на Rust, на самом деле позиционирует себя как улучшенная версия C. Мне он понравился, несмотря на то, что я довольно быстро добился падения компилятора. Думаю, если в него добавить несколько современных функций и доработать, он со временем будет весьма успешен.

Второй: стрим на YouTube с решениями Advent of Code 2020 на языке Zig. Не буду упоминать канал, но его несложно найти; в реальности на YouTube едва ли наберётся десять каналов, где Zig упоминается.

Мне, как и любому любителю, не нравятся решения профессионалов (предполагая что ведущий стрима — хотя бы джун-профессионал в области программирования). Так и здесь — от зубодробительных циклов и головоломных операций с исходными данными (по-моему он решил делать все операции с текстом без конверсии в какой-либо иной тип…) меня довольно быстро разобрало раздражение, и захотелось решить задачку самому.

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

Тут легко узнаётся игра в «жизнь», клеточные автоматы.

Исходные данные представлены в виде текста, разделенного на строки (длиной 10 для тестовых данных, 95 для реальных). В тексте L обозначает свободное место, # обозначает занятое место, а . обозначает проход, который никогда не будет занят.

Раунды заканчиваются тогда, когда состояние поля становится стабильным, то есть состояние клеток не меняется.

Учитывая, что Zig поддерживает опциональные типы (!) — хорошая замена C! — мне кажется более чем логичным представить эту доску в виде ?bool, то есть одного из трёх состояний: true, false, null.

Текстовый поток конвертируем в сплошной массив таких опциональных значений. Ширину массива можно подсчитать, разделив исходную строку по \n и взяв длину любого полученного фрагмента.

После этого создаём массив массивов: первый элемент в таком массиве будет исходным состоянием, а все последующие массивы получаются путём прохода по предыдущему состоянию; функция прохода выдаёт новое значение для каждой клетки, рассчитанное на основании предыдущих состояний.

Служебные функции:

  • функция равенства, сравнивающая два массива ?bool;

  • функция печати массива в нужном виде (для дебага);

  • функция, возвращающая количество занятых мест (это ответ для задачки).

Функция прохода принимает состояние поля (нужно же откуда-то брать состояние соседних клеток для расчёта нового состояния текущей), индекс текущей клетки в массиве и ширину массива.

Поскольку передаётся всё поле и его ширина (чтобы не считать ширину каждый раз), мы можем для каждой клетки получить:

  • состояние текущей клетки;

  • состояние соседних клеток;

  • ряд и колонку текущей клетки через деление нацело и остаток от деления (они удобнее в расчётах).

Дальше очевидное: если текущая клетка расположена во второй колонке, то можно посмотреть состояние соседней слева (потому что она существует всегда). Если клетка расположена в предпоследней строке в предпоследней колонке, то для неё точно существует сосед справа снизу… логика понятна.

В общем, решение задачи на императивном языке оказалось вполне приятным и заняло около 200 коротких строк, несмотря на некоторые несуразицы, типа того, что switch не в состоянии делать match по опциональным типам; может быть исправят в дальнейшем, потому что такое сделало бы решение заметно короче.

Язык порекомендую любопытствующим.

Luarocks в Windows

Всё началось с Moonscript и Haxe: мне захотелось поразвлечься с этими новыми для меня языками. Оба позволяют транспилировать свои программы в Lua, а Lua, на мой взгляд, это один из наиболее актуальных языков, поскольку много какое используемое мною ПО позволяет на нём писать внутренние скрипты.

В Lua .hx (Haxe) транспилировался, но выполняться отказался, требуя модуль lua-utf8. Его необходимо было поставить через luarocks.

На мой взгляд, luarocks документирован плохо и совершенно не очевидно, как оно работает. А работает он так.

luarocks при запуске ищет в директориях по умолчанию (c:\users\user\appdata\luarocks) конфигурационный файл, имя которого зависит от версии Lua. В моём случае это config-5.3.lua.

В этом файле много чего требуется написать. У меня конфиг сейчас выглядит вот так:

arch = "win32-x86_64"
cmake_generator = "MinGW Makefiles"
deploy_bin_dir = "c:/users/user/.luarocks/bin"
deploy_lib_dir = "c:/users/user/.luarocks/lib/lua/5.3"
deploy_lua_dir = "c:/users/user/.luarocks/share/lua/5.3"
export_path_separator = ";"
external_deps_dirs = {
   "c:/mingw",
   "c:/windows/SysWOW64",
   "c:/windows/System32"
}
external_deps_patterns = {
   bin = {
      "?.exe",
      "?.bat"
   },
   include = {
      "?.h"
   },
   lib = {
      "lib?.dll.a",
      "?.dll.a",
      "lib?.a",
      "cyg?.dll",
      "lib?.dll",
      "?.dll",
      "?.lib"
   }
}
external_deps_subdirs = {
   bin = "bin",
   include = "include",
   lib = {
      "",
      "lib",
      "bin"
   }
}
external_lib_extension = "dll"
home = "C:\\Users\\user\\AppData\\Roaming"
home_tree = "C:\\Users\\user\\AppData\\Roaming/luarocks"
homeconfdir = "C:\\Users\\user\\AppData\\Roaming/luarocks"
lib_extension = "dll"
link_lua_explicitly = true
local_by_default = false
local_cache = "C:\\Users\\user\\AppData\\Local/LuaRocks/Cache"
lua_extension = "lua"
lua_interpreter = "lua.exe"
lua_version = "5.3"
makefile = "Makefile"
no_manifest = false
obj_extension = "o"
processor = "x86_64"
rocks_trees = {
   {
      name = "user",
      root = "C:\\Users\\user\\AppData\\Roaming/luarocks"
   }
}
rocks_dir = "c:/users/user/.luarocks/lib/luarocks/rocks-5.3"
rocks_servers = {
   {
      "https://luarocks.org",
      "https://raw.githubusercontent.com/rocks-moonscript-org/moonrocks-mirror/master/",
      "http://luafr.org/moonrocks/",
      "http://luarocks.logiceditor.com/rocks"
   }
}
runtime_external_deps_patterns = {
   bin = {
      "?.exe",
      "?.bat"
   },
   include = {
      "?.h"
   },
   lib = {
      "?.dll",
      "cyg?.dll",
      "lib?.dll"
   }
}
runtime_external_deps_subdirs = {
   bin = "bin",
   include = "include",
   lib = {
      "",
      "lib",
      "bin"
   }
}
static_lib_extension = "a"
target_cpu = "x86_64"
variables = {
   AR = "C:\\MinGW\\bin\\ar.exe",
   CC = "C:\\MinGW\\bin\\gcc.exe",
   CFLAGS = "-O2",
   CMAKE = "cmake",
   LD = "C:\\MinGW\\bin\\gcc.exe",
   LIBFLAG = "-shared",
   LIB_EXTENSION = "dll",
   LUALIB = "lua53.dll",
   LUA_LIBDIR_FILE = "lua53.dll",
   LUA_DIR = "C:/ProgramData/chocolatey/lib/lua53/tools",
   LUA_BINDIR = "C:/ProgramData/chocolatey/lib/lua53/tools",
   LUA_INCDIR = "C:/Lua/include",
   LUA_LIBDIR = "C:/Lua/lib",
   MSVCRT = "msvcrt",
   ROCKS_TREE = "c:/users/user/.luarocks/lib/luarocks/rocks-5.3"
}
verbose = true

При таких настройках библиотеки нормально собираются (за исключением тех, которые имеют типично линуксовые зависимости) в dll и кладутся в папку C:\Users\user\AppData\Roaming\LuaRocks\lib\lua\5.3 (см. deploy_lib_dir).

Lua 5.3 — x64; его можно установить при помощи Chocolatey, а можно просто взять бинарники на SourceForge, взяв заодно и lua-5.3.6_win64_dllw6_lib.zip. MinGW x64 можно взять на nuwen.net и распаковать его в C:\MinGW.

После этого создадим C:\Lua\includes и положим туда файлы заголовков из lua-5.3.6_win64_dllw6_lib.zip, а .dll и .a положим в C:\Lua\lib.

Необходимо добавить к окружению переменную LUA_CPATH=C:\Users\user\AppData\Roaming\LuaRocks\lib\lua\5.3\?.dll, которая означает, что Lua будет искать C-библиотеки в этой папке с именем библиотека.dll. Если собрать luafilesystem (luarocks install luafilesystem), то в этой папке появится lfs.dll. Эту библиотеку можно подгрузить к интерпретатору командой lua -l lfs, и если всё нормально, то интерпретатор загрузится без сообщений.

Для точности хорошо бы ещё добавить к LUA_CPATH строки C:\Users\user\AppData\Roaming\LuaRocks\lib\lua\5.3\?\core.dll и .\?.dll.

На будущее сразу стоит добавить переменную окружения LUA_PATH: LUA_PATH=C:\Users\user\AppData\Roaming\LuaRocks\share\lua\5.3\?.lua;C:\Users\user\AppData\Roaming\LuaRocks\share\lua\5.3\?\init.lua.

Людям, не понимающим, как работает вызов функций в сишных библиотеках, возможно придётся помучаться, потому что правильно собрать эти библиотеки тоже надо уметь (немаловажно, чем собирать и под какую архитектуру). Самый важный параметр в этом — MSVCRT в конфиге, потому что содержимое этого параметра передаётся компилятору при сборке (для gcc, которым я собираю, получается -lmsvcrt).

Теперь заголовки лежат на своём месте, компилятор найден, нужная библиотека функций Windows линкована динамически.

Командой luarocks install luautf8 скачиваем и собираем библиотеку. После того, как она установится, можно попробовать запустить интерпретатор, набрав в строке lua -l lua-utf8.

Теперь Lua-код, транспилированный из Haxe, исполняется и показывает юникод (проверено).

Значимая мелочь

Сатьяджит Сат в книге «Трейдеры, пушки и деньги» рассказывает историю о том, как прогорели азиатские производители лапши:

Трейдеры заключили новую сделку с ОСМ, достигнув новых вершин креативности. По условиям этой новой трансакции, прежняя невыгодная для ОСМ сделка была отменена, и компания не понесла за это убытков. Ее заменил новый своп. Сумма новой трансакции составила 600 миллионов долларов. По условиям нового свопа компания ОСМ обязывалась следующие три года выплачивать фиксированную сумму в долларах. Эта сумма была 4 миллиона долларов в месяц. Взамен дилер будет выплачивать ОСМ сумму, рассчитываемую по сложной формуле:

Максимум от [0; NP × {7 × [(LIBOR² × 1/LIBOR) − (LIBOR⁴ × LIBOR⁻³)]} × количество дней в месяце/360],

где NP — 600 миллионов долларов; LIBOR — шестимесячная ставка LIBOR в долларах

Финансовая механика была просто ослепительной, за исключением одной проблемы. Сложная формула, приведенная выше, если вы проделаете вычисления, всегда окажется равной нулю. Дилер никогда ничего не будет платить ОСМ, а вот ОСМ должна будет выплачивать дилеру по 4 миллиона долларов в месяц в течение трех лет. Это и был нужный дилеру результат.

В компании ОСМ были финансисты. Или «финансисты»?

В книге «Countdown to Zero Day» (книга посвящена Stuxnet, первой боевой малвари, нацеленной на противодействие иранской ядерной программе), её автор Зеттер (Zetter) рассказывает следующее. Некто Хан (Khan), работавший ранее в Urenco, украл и продал Пакистану, Ливии и Ирану чертежи центрифуг, которые, работая в каскаде, позволяют осуществлять обогащение урана, а также сами центрифуги. Где-то в 2000-е ЦРУ внедрило своих агентов в цепочки этих поставок и поставляла в эти страны модифицированные компоненты, которые выходили из строя, не вызывая подозрений. В частности, были модифицированы вакуумные помпы, которые должны были ломаться через случайные промежутки времени и таким образом, чтобы было трудно установить источник проблемы и выявить общность этих поломок.

Из всех модифицированных ЦРУ помп шесть ушли в Ливию, а седьмая приехала в Иран. Инспекторы МАГАТЭ, осуществлявшие надзор за иранской ядерной программой, наткнулись на последнюю в городе Натанз; иранцы не знали, что помпа была изменена. Помпа выделялась на фоне остальных одной мелочью: на ней была наклейка, указывающая на неё как на собственность американской Национальной лаборатории Лос Аламос, где эту помпу модифицировали. В ходе расследования МАГАТЭ выяснилось, что серийный номер на помпе следует за номерами тех, что были в Ливии, что указывает на то, что эти помпы из одной партии. Инспекторы отследили заказ на помпы до американской лаборатории. Никто так и не понял, как наклейка попала на модифицированную помпу в Натанзе, и почему иранцы ничего не заподозрили и не обратили на неё никакого внимания.

Как по мне, так это примеры легендарного восточного распиздяйства.

Visual Studio Nuget.org SSL/TLS error

Некоторое время Visual Studio стояла у меня без дела, но когда она мне понадобилась, выяснилось, что доступ к репозиторию пакетов недоступен с ошибкой SSL/TLS error приблизительно следующего содержания:

Unable to load the service index for source https://api.nuget.org/v3/index.json.
An error occurred while sending the request.
The request was aborted: Could not create SSL/TLS secure channel.

Доступ к указанному URL в Firefox работает.

Эта проблема возникла не в 2020 году: об этом написано в developercommunity.visualstudio.com, на SO и на GitHub. Как это часто бывает, всё обсуждавшееся тогда не имеет отношения к сегодняшней проблеме.

Основное решение:

New-Item 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.3\Server' -Force | Out-Null
New-ItemProperty -path 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.3\Server' -name 'Enabled' -value 0 -PropertyType 'DWord' -Force | Out-Null
New-ItemProperty -path 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.3\Server' -name 'DisabledByDefault' -value 1 -PropertyType 'DWord' -Force | Out-Null
New-Item 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.3\Client' -Force | Out-Null
New-ItemProperty -path 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.3\Client' -name 'Enabled' -value 0 -PropertyType 'DWord' -Force | Out-Null
New-ItemProperty -path 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.3\Client' -name 'DisabledByDefault' -value 1 -PropertyType 'DWord' -Force | Out-Null
Write-Host 'TLS 1.3 has been disabled.'

New-Item 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.2\Server' -Force | Out-Null
New-ItemProperty -path 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.2\Server' -name 'Enabled' -value 1 -PropertyType 'DWord' -Force | Out-Null
New-ItemProperty -path 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.2\Server' -name 'DisabledByDefault' -value 0 -PropertyType 'DWord' -Force | Out-Null
New-Item 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.2\Client' -Force | Out-Null
New-ItemProperty -path 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.2\Client' -name 'Enabled' -value 1 -PropertyType 'DWord' -Force | Out-Null
New-ItemProperty -path 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.2\Client' -name 'DisabledByDefault' -value 0 -PropertyType 'DWord' -Force | Out-Null
Write-Host 'TLS 1.2 has been enabled.'

Это тоже не помогло.

После того как я исполнил все ритуальные пляски (прописав в реестре отключение TLS 1.3 и включение 1.2, отключив TLS 1.1 в настройках IE) и оставшись на том же месте, я начал искать другое. Проверка (переход по ссылке https://www.ssllabs.com/ssltest/viewMyClient.html во внутреннем браузере VS) показала, что TLS 1.2 работает, а всё ненужное — не работает, так что проблема не в этом.

Проблема — в сертификате nuget.org. Поводом к такой мысли стала статья, где сообщалось об издыхании сертификата Microsoft и обещалось вскоре сообщить о новом сертификате для сайта nuget.org. На сайте nuget.org я такого сообщения не нашёл, но всё равно заподозрил, что сертификат более невалидный. Значит, необходимо просто взять актуальный, и загрузить его в системный реестр сертификатов.

В FF это просто: переходим на сайт, открываем свойства, выгружаем сертификат, загружаем его в реестр. В картинках это выглядит так:

/images/2020-12-19_174256.png

Нажать кнопку >.

/images/2020-12-19_174338.png

Нажать кнопку Подробнее. Откроется окно Информация о странице.

/images/2020-12-19_174401.png

Нажать на кнопку Просмотреть сертификат. В FF откроется окно просмотра сертификата.

/images/2020-12-19_174426.png

Прокрутить окно вниз до раздела Разное.

/images/2020-12-19_174444.png

Нажать на ссылку PEM (сертификат) и сохранить его.

/images/2020-12-19_174542.png

Открыть консоль сертификатов, и импортировать сохраненный сертификат в Сертификаты (локальный компьютер) > Доверенные лица > Реестр > Сертификаты.

Одно не ясно мне — почему новая установка Visual Studio в виртуальной машине не имела таких проблем и работала нормально?

FOSS

Отличительная особенность FOSS (Free Open Source Software) — часто его необходимо допиливать собственными руками. Если не готовы это делать, часто лучше не браться вообще, потому что такое допиливание исходника (с последующим pull request) предполагается.

К примеру, Neovim. Досадный баг, из-за которого установленные маркеры сохраняются, но не удаляются, до версии 0.5.0 дошёл без изменений и, насколько я могу судить, изменений в этом отношении пока не предвидится.

fzf.vim, мощнейший инструмент динамической фильтрации текста для Vim / Neovim, до сих пор хранит несколько досадных недоработок. Одна из полезнейших его опций: :Lines, фильтрация по строкам ВСЕХ одновременно открытых файлов; результаты нескольких выборок могут быть помечены маркером и отправлены в Quickfix List для дальнейшей проработки. Тут стоит напомнить, что содержимое Quickfix List можно сохранить под любым именем и восстановить в любое время, а также присоединить к любому другому такому списку. Отметил места для проработки, сохранил список на диск и в любое время вернулся к этой работе.

Логично внедрить тот же функционал в :BLines, поскольку эта команда делает то же самое, но только для текущего буфера. Тем не менее, это не реализовано; пришлось сделать самому, написав десять коротких строк. Сделал в fzf.vim опцию, открывающую окно Quickfix List на всю ширину экрана, а не внизу крайнего правого окна, как это сделано по умолчанию. Также пришлось дописать функцию :Registers, которая позволяет вставлять сразу несколько регистров одним нажатием.

riv, отличный плагин для Vim / Neovim для работы с reStructuredText, хорош многим, но немного страдает качество синтаксической подсветки текста, которая не охватывает всего синтаксиса языка. Вдобавок почему-то это подсветка написана так, что проверка правописания внутри директив отключена. Из-за этого в документацию пробралось несколько досадных опечаток. Проект фактически заброшен, а значит придётся писать подсветку и всю необходимую атрибутику самому. Только попытавшись повторить, понимаешь, сколько работы вложено в казалось бы такую малозаметную вещь, как подсветка.

Конец американской эпохи

Для наблюдательного человека давно не секрет, что эпоха американского доминирования закончилась. Как уже говорилось, ничего хорошего это не сулит. Мне показалась неплохой статья «Развенчание Америки», написанная Уэйдом Дэвисом.

Ниже — её русский перевод.

Развенчание Америки

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

За четверть года цивилизация была поставлена на паузу микроскопическим паразитом в 10 тысяч раз меньше крупинки соли. COVID-19 атакует не только наши тела, но и культурные основы нашей жизни, инструменты сообществ и коммуникаций, что для человека то же, что клыки и когти для тигра.

Наши действия до сего дня в основном были сосредоточены на снижении скорости распространения и сжатии кривой смертности. Лекарства нет, и нет уверенности в появлении вакцины в ближайшем будущем. Быстрее всего вакцина была разработана от свинки. Это заняло четыре года. COVID-19 убил 100 000 американцев за четыре месяца. Есть некоторые свидетельства, намекающие, что заражение не подразумевает иммунитета, что позволяет задаться вопросом, насколько эффективной будет вакцина, даже если предположить что она будет найдена. И она должна быть безопасной. Если будет иммунизироваться всё население планеты, то смертельные осложнения у одного на тысячу будут означать смерть миллионов.

Пандемии и эпидемии меняют историю на свой лад, и не всегда так, как это сразу очевидно выжившим. В 14-м веке Чёрная Смерть убила почти половину населения Европы. Недостаток рабочей силы вызвал рост заработных плат. Возросшие ожидания достигли кульминации в крестьянском восстании 1381 года: точке, которая отметила начало конца феодального устройства, которое доминировало в средневековой Европе тысячу лет.

Эпидемию COVID-19 запомнят как именно такой момент в истории, примечательное событие, чья значимость раскроется только на исходе кризиса. Она отметит эту эпоху, равно как убийство графа Фердинанда в 1914-м, падение фондового рынка в 1929-м и восхождение Адольфа Гитлера в 1933-м стали вехами прошлого столетия, предвестниками великих последующих перемен.

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

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

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

Читать статью …

Дело Кобринского и сексуальная утопия в действии

Американские развлечения с обвинениями «после секса» докатились и до нас. Теперь вот обвиняют некоего профессора Кобринского. Цитаты из статьи прекрасны:

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

«Я помню, что он сказал лечь на пол. Ну я, видимо, и легла. Я не хотела оказаться в этом положении, [в наручниках]. Но все общение строится на таких маленьких уловках и штучках, и получается, что в какой-то момент ты делаешь какие-то вещи, даже если не хочешь их делать».

В общем, девочке не понравилось. Но ведь если не понравилось, значит она этого и не захотела бы, а значит это против её воли, а значит это изнасилование!

Эту модель переосмысления состоявшихся событий задним числом уже давно описал Роджер Девлин, в чьей стране эти развлечения с травлей уже давно стали мейнстримом.

Я вполне допускаю, что прохвессор (© Хогбены) как-то склонял, но это другой разговор. Вообще идея кары за некую «аморалку», то есть наказание за нарушение свода неписаных и весьма разнообразно понимаемых правил (не секрет, что видение морали и справедливости очень индивидуально) скорее способствует атмосфере зашуганности и постоянной опаски, но видимо в этом и замысел.


СЕКСУАЛЬНАЯ УТОПИЯ В ДЕЙСТВИИ

Роджер Девлин

The Occidental Quaterly, vol.6, no.2, summer 2006

Читателям этого журнала хорошо известно, что частота деторождений среди белых по всему миру катастрофически снизилась в последние десятилетия. В то же самое время наше общество определенно стало самым одержимым сексом за всю историю человечества. Две таких серьёзных одновременных тенденции едва ли могут быть не связаны между собой. Многие добродушные консерваторы негодуют по поводу сегодняшней ситуации, но не желают описать её и её возникновение. Правильный диагноз — предварительное требование для эффективного лечения.

Я думаю, что затертое клише «сексуальной революции» следует воспринимать с более чем обыденной серьёзностью. Как и Французская революция, типичная политическая революция современности, это была попытка реализовать утопию, но сексуальную, а не политическую. И как Французская революция, она прошла через три фазы: первую, либеральную или анархическую фазу, в которой предполагалось, что утопия возникнет спонтанно, как только прошлое будет сметено; вторую, власть террора, в которой одна сторона захватила власть и попыталась диктаторскими методами реализовать свои планы; и третью, «реакцию», в которой человеческая натура постепенно отвоевала своё место. В этом эссе мы проследуем тем же путём.

ДВЕ УТОПИИ

Давайте рассмотрим, что же такое сексуальная утопия, и начнём с мужчин, которые проще во всех отношениях.

Продолжение …

Clang Language Server

Я уже некоторое время как полностью перешёл на Neovim (после Vim), и это теперь мой основной рабочий редактор. В Sublime Text вернуться просто невозможно: ощущение такое, будто пересел с Ламборджини на советский трактор.

Писать софт в Neovim можно, хотя превращение текстового редактора в IDE скорее неразумно. Тем не менее, писать небольшие программки и скрипты в Neovim вполне удобно, если есть языковой сервер для выбранного языка. Lua, F#, Haskell вполне работают, хотя к последнему пока есть вопросы, но они скорее связаны с моей неопытностью в его экосистеме.

Описывать настройку этого не буду, но пару слов скажу про языковой сервер для C++, clangd.

Затык возник с #include. Компилирую-то я из командной строки, а редактирую в Neovim в графическом интерфейсе, в котором другие настройки переменных окружения (я не засоряю ими системную или пользовательскую область). И иногда хочется подгрузить что-нибудь из Boost, но шланг найдёт системный <iostream>, а <boost\iostreams\detail\iostream.hpp> не найдёт.

Можно сколько угодно прописывать в .clangd параметры типа --include-directory, -isystem, -cxx-system, это скорее всего не поможет. Не поможет и добавление директории с инклюдами в PATH. Мне помогла только установка переменной окружения CPLUS_INCLUDE_PATH.