Русский
Русский
English
Статистика
Реклама

Pascal

Как безопасники боролись с мамонтами, или ИТ- и ИБ 25 лет назад и сейчас

28.07.2020 10:08:24 | Автор: admin
В июне нашей команде и компании исполнилось 25 лет. В юбилей принято вспоминать былое, делать выводы и строить планы на будущее. Но делать стандартное интервью нам не хотелось. Хотелось, чтобы получился разговор двух людей, которые знают сферу ИТ, могут вспомнить олдскульные ИБ-истории и поспорить на тему а вот если бы ось пополам обогнала в свое время майкрософт

Захотели сделали. Алексей Дрозд (aka @Labyrinth) поговорил с Львом Матвеевым, инженером-программистом в прошлом, основателем и владельцем компании СёрчИнформ в настоящем. Разговор получился о том, как зарождалась ИТ-отрасль на постсоветском пространстве, чем нынешние программисты отличаются от вчерашних, о поводах для гордости и уроках неудач.

Текст большой, но да пусть вас это не напугает. Для пугливых ориентируйтесь на заголовки.

Зарплату на машинное время


image


Алексей: Разговор приурочен к 25-летию компании. Тогда явно все было по-другому (лучше или хуже не знаю). Но выросло поколение, которое думает, что безопасники раньше с мамонтами боролись. А айтишники в 95 году еще бегали с копьями. Так что вопрос такой: какие ценности были тогда в 95-ом, ИТ-сфера считалась элитной?

Лев: Да. Чтобы описать, насколько программисты были небожителями, опишу, как мы работали. Компьютер я впервые увидел на первом курсе института в 86-м году. Это был ЕС 1036 с большим зеленым монитором.

image Тогда чтобы поработать за ним, тебе выделялось максимум час-два в неделю. Мне повезло, я подружился с одним из ассистентов кафедры, который вел у нашего потока Вычислительную технику. И под его логином каждый день с 9 до 11 вечера работал дополнительно. Мы тогда ценили машинное время на вес золота.

Когда заканчивал вуз в 93-м, компьютер стоил порядка 100 месячных зарплат среднего разработчика. Мало кто понимал, зачем компьютер и программирование нужно, большинство преподавателей знали меньше некоторых студентов. Не было справочников, не было интернета. Потому хорошими программистами становились те, кто сам носом землю рыл.

Общались в т.н. бибиэсках. 64 килобита считались очень большой скоростью. Dial-up был страшно дорогой.

Алексей: На чем ты тогда писал?

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

Алексей: Правильно ли я понимаю, что больший упор тогда был на алгоритмы, чем на красивый интерфейс?

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

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

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

Алексей: Не думаю, что все так просто. Как ты заметил, развитие идёт по спирали. Те же гуру остались, но они сейчас работают на другом уровне, уровне собственных баз данных Яндекса, Фейсбука или Гугла

Лев: Да, эти люди остались, но ушло главное. В 92-93-м у нас был свой круг общения, каналы Fido, где сидели профи. Так как нас было мало, мы все друг друга знали, пусть не визуально, не лично, но по бибиэскам, по бибиэсовским конфам.

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

Лев: Не совсем. Бибиэска это компьютер с одним или несколькими модемами, на нем стоит специальный софт. Это по сути сервер, который имеет структуру каталогов. Он передает все на твой компьютер, ты это просматриваешь, потом загружаешь назад.

image


По сути, это прообраз чата, но ответ был очень отложенным, потому что ты подключался к бибиэске на 15-20 минут пользоваться интернетом было дорого (особенно для студента), нельзя было надолго занимать телефонную линию в квартире. Нужно получить совет по работе бросаешь клич: ребята, спросите по знакомым может кто-то, как и я, бьется о такую же проблему Оставишь сообщение и надеешься, что нужный тебе человек ответит через день-два.

Были бибиэски, которые включались по расписанию. Например, с 7 до 9 вечера, потому что хозяин только в это время мог их поддерживать. Это ведь были энтузиасты. Можно было организовать обмен информации между несколькими бибиэсками, и это был какой-то аналог интернета. Когда в первом моем бизнесе мы держали бибиэску на четыре многоканальных линии, работающую круглосуточно, это было очень крутым сервисом для наших клиентов.

Не было ни айти, ни ибэ



image


Алексей: Получается реалии начала девяностых такие: у вас в ИТ есть непаханое поле исследуй что хочешь, разрабатывай, что хочешь. Исследовательский зуд тебя подталкивает

Лев: Не было такого названия ИТ вообще! Оно появилось, наверное, во второй половине 90-х, даже к концу 90-х началу 2000-х. Не было и понятия начальник ИТ, не было деления на системного администратора и программиста. Оно появилось позже.
Любой программист, по определению, был грамотным сисадмином, который может все настроить, проложить локальную сеть на 10 мегабит. Сейчас же процентов 80 программистов не знают, как кабель обжать

Алексей: Это уже специализация. Это другое. Но все же вот ты организуешь первый бизнес, это был продукт, который оцифровывал нормативные документы, законы, приказы?

Лев: Да. И обеспечивал поиск по этим документам. Это сейчас обычная практика, что у любой системы есть поиск по фразам, морфология. Тогда у конкурентных решений поиск был только по словам. То есть ни фразового поиска, ни хоть какого-то предвестника поиска похожих (это наша технология, которая ищет документы похожие на запрос не только технически, но и по смыслу).

Конкурентные программы тогда стоили дорого и были малоэффективными. Их использовали только крупные компании, которые готовы были выделить человека, чтобы тот занимался поиском документов по несколько часов. Для обычного предпринимателя со штатом в 20 человек, которому нужно получить ответ на вопрос за 5-10 минут, это, конечно, не годилось.
Поэтому, наш поисковый движок произвел впечатление на рынок. У тогдашнего главного нашего конкурента компании Регистр было 150 клиентов, в целом рынок оценивали на 300. Моя оценка была совершенно другой 1000-2000 клиентов. А потом в первый же год работы мы получили 500 заказчиков, отобрав еще и половину клиентов у Регистра.

Алексей: Когда впервые мысль об инфобезе пришла в голову? Думаю, в начале 90-х люди, выходящие в Сеть, не особо задумывались о вопросах безопасности.

Лев: В 90-е инфобеза не было как такового. Что тогда подразумевалось под безопасностью? Как отбиться от бандитов и милиции. Концепция ИБ родилась году в 2005-м. К этому моменту у меня за плечами были разные проекты, мы выпускали так называемые шаровары (shareware-программы). Позже продавали поиск как продукт под задачи разных бизнесов, такой корпоративный офлайн-поисковик, локальный гугл.

Он был, условно говоря, вкусной конфетой на развес без достойной упаковки. Так вот инфобез стал для нас этой упаковкой. Разрабатывая DLP, мы снова не стали делать что-то похожее на то, что было на рынке. Если ты предлагаешь еще один велосипед, который может развивать скорость не 25, а 30 км/ч, то это круто, конечно, но капитально не решает задачи человека, которому нужно проезжать быстро по 100 км в день. Ему потребуется машина.
Все игроки рынка работали тогда по принципам царской охранки главное перехватить. Образовывалась огромная мусорка из алертов. Что с ней делать? Только просматривать вручную.

Мы считали, что для ИБ главное это поиск по информации и аналитика, и это облегчало пользователям жизнь, потому что просмотреть-то надо не весь перехват, а условно, только 1%.

Алексей: Получается решили задачу кардинально по-новому?

Лев: Да. На что еще всегда ставили это на оптимизацию по двум направлениям: чтобы DLP была нетребовательной к оборудованию, и чтобы скорость поиска была высокой. Это критично, потому что, если тебе надо раз в день запустить поиск, подождать минуту-три может и нестрашно. А если тебе нужно 50 запросов за день сделать, из минут сложится 2-3 часа. Сейчас движок в 2-3 раза быстрее, чем на старте.

Алексей: А почему все-таки сфокусировался на ИБ в контексте защиты от инсайдерства? Потому что делать очередной антивирус было бы глупо?

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

Алексей: Мы же не были первопроходцами?

Лев: Когда мы в 2005 году выходили на этот рынок, там был беспредел. Доподлинно знаю, что один из конкурентов брал 6 тысяч долларов за триальную версию. Сейчас кому-то скажи: плати за триал примут за идиота.

Маркетинг был построен на том, что DLP это сложно, что внедрение занимает не меньше полугода, что должны быть специальные лингвисты для настройки. То есть чтобы поставить систему безопасности, нужно привлечь специалистов НИИ и стоит это как космический корабль. Покупали такой только самые богатые компании. А мы сделали коробочный продукт: поставил, запустил, можно работать.

image

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

Лев: Отталкивались от того, что хотели клиенты, что доставляет им самую большую головную боль. Надо понимать, кто с нами работал со стороны заказчиков. Это выходцы из органов, люди в погонах, которые по сути сформировали в России сферу ИБ. Они изначально понимали, что самый большой ущерб могут создать внутренние инциденты, а не хакеры. Эти специалисты знают, как мыслят преступники и недобросовестные сотрудники, они понимают ценность информации, требования к продуктам у них очень строгие. Так они накидывали нам нерешаемых на взгляд ИБ-специалистов задач, и мы давали им инструменты.

Сначала DLP перехватывала только мыло, документы, отправленные на печать критически важный канал, ведь тогда еще не был сильно развит интернет. Еще не было флешек, поэтому DeviceController появился позже. Функционал программы развивался, полнотекстовый поиск обрастал возможностью искать по регулярным выражениям, находить чертежи и т.д. Но мы видели, какие еще функции были нужны: нужен граф отношений, нужны карточки клиентов, нужен прообраз нашего ProgramController.

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

Алексей: Раз уж зашел разговор о зарубежье. В том же буклете, который я уже вспоминал, в разделе контактов был указан американский номер телефона. Модно тогда было, чтобы у тебя был офис в Америке?

Лев: Честно говоря, не помню. Никогда не было представительства в США, но какой-то номер, наверное, брали. Думали, сейчас выйдем на весь мир. И слава богу, что не стали этого делать. Зайдя на рынок ИБ, увидели, что он необъятен и в России. Я принял решение пока за рубеж не рваться. Это было правильное решение нужно стать 1 дома.

Мы пошли на Запад только три года назад. Главное это первое впечатление, его за деньги не купишь, продукт краеугольный камень. Нужно было отточить наше ПО, ведь в корпоративном секторе ты можешь работать на сотне ПК, но не факт, что развернешься на 500. Сейчас у нас максимальное внедрение на 70 тысяч станций в одной компании. Но до такого результата дошли, что называется, step by step. Многие наши конкуренты из подобных историй уроки не извлекают. У них при внедрении на 100-200 ПК все работает, а ставят на 5 тыс. и все падает. В том числе и репутация. Но это не наш путь.

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

Где поскользнулись


Алексей: Всегда приятнее вспоминать про победы, выстрелившие технологии, а провалы не принято афишировать. Но не верится, что при развитии все было идеально. Может есть примеры того, что не взлетело?

Лев: Самый крупный провал это TimeInformer как отдельный продукт. Мы потратили около 15 млн на разработку, наняли 60 сейлов, которые отработали полгода. Развили активность, потратили ресурсы программистов.

Программа получилась технически сильная, просто для нее нет большого рынка. Мы продаем ее заинтересованным заказчикам, но при этом понимаем, что переход на DLP неизбежен. Если клиент пришел к мысли о контроле, он не ограничится просто мониторингом рабочего времени. Вопрос безопасности данных встанет все равно.

Алексей: А были ли провалы по части не маркетинга, а технологий?

Лев: Прямо провалов и крахов не было. Технологии не все одинаково успешно внедряются, но все большую пользу приносят. Например, FTPController не забойный продукт, он для клиентов менее важен, чем MailController. Но это не значит, что его не нужно было разрабатывать, просто приступили к нему позже. Это как при добыче нефти вначале добываешь с поверхности, а потом буришь скважину. Конечно, приятно вспоминать 2007-й год, когда мы перехватили неперехватываемый Skype, но, когда продукт зрелый, каждая новая фича не будет вызывать такой же взрывной эффект.

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

Лев: Если говорить о промахах, вспоминается, как 3 года назад стали писать на Angular. В итоге уперлись в ряд неудобств: высокий порог вхождения, сложная система модулей, от версии к версии они ломают API. Сейчас перешли на Vue.

Другая история 4 года назад стали делать самописную ORM для обработки сообщений с сервера очередей в итоге прекратили разработку, т.к. увидели, что получаем только замедление как в скорости разработки, так и в быстродействии ПО.

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

Было несколько интеграций со сторонними продуктами, которые впоследствии оказались нерабочими или дальнейшее сопровождение и поддержка превращалась в ад. Помучались с ними пару лет и отказались от сотрудничества. При этом отмечу, что c некоторыми продуктами мы отлично интегрированы и успешно работаем уже очень давно.

Но я к этим промахам отношусь философски это опыт, это понимание, куда идти, а куда не стоит.

Откуда деньги


Алексей: Где ты тогда искал деньги на свои проекты? Привлекал от инвесторов?

Лев: На первый бизнес я брал взаймы, потому что денег вообще не было, а нужно было платить рыночную зарплату 5-6 разработчикам. Тогда это было 20 тысяч долларов.

А в СёрчИнформ мы вообще не собирались привлекать деньги, развивались сами. Без крутой прибыли, но детские болезни преодолели, не ломали голову над тем, из каких денег выплатить зарплату. Получилось так, что на нас вышла серьезная питерская компания из финансового сектора, написали, что было бы интересно в нас инвестировать. Это было в июне 2008-го. Я решил: почему не съездить.

Мы начали переговоры, инвестиционный менеджер был достаточно грамотный. Говорит, мы видим, что вы перспективная компания, но вы возитесь в песочнице, вам офисы нужно открывать в разных регионах. Я отвечал, мол, планируем в ближайшие полгода собрать деньги и открыть офис в Питере. Они: чего ждать? Вот деньги и вперед! Сумма и условия предполагались комфортные.

У нас слюнки потекли, что откроем офис там и там, наймем колл-центр, направим деньги на рекламу, на серию конференций Road Show. Все распланировали, я приехал в Питер на финальные переговоры был тот самый черный вторник в августе 1998-го. Говорят: Извините, мы все.

Это был удар. Но мысль о развитии уже укоренилась. И мы решили, что нам нужны инвестиции, чтобы выйти на новый уровень. На конференции ISDEF в октябре я познакомился с Максимом Шеховцовым, управляющим директором Альянс РОСНО Управление активами, и мы начали говорить про инвестиции. К декабрю ударили по рукам.

Алексей: Сильно отличались условия, которые были до чёрного вторника?

Лев: Да, конечно, потому что после денег на рынке не было. У Альянс РОСНО на тот момент оставалось 42 млн рублей, которые они могли в нас вложить. Это были не лучшие условия, но тогда вливания пошли на пользу компании. Через 4 года в фонде сменился управляющий, и мы выкупили долю за большие деньги, чем рассчитывали. Но в бизнесе спорить и ругаться надо на берегу, а потом соблюдать договоренности, даже если они уже для тебя невыгодны. Мы плодотворно поработали и расстались друзьями.

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

Мир немного сходит с ума. Когда убыточные компании стоят миллиарды или сотни миллионов долларов, я этого не понимаю.

Алексей: Может инвесторы просто хотят надуть пузырь, чтобы вернуть свое?

Лев: Вероятно. Но как по мне нельзя занимать у Васи, чтобы отдать проценты Пете. Нельзя постоянно жить в долгах на чужие деньги, это не бизнес.

Настоящее, или Как не упустить хороший кризис


Алексей: Сейчас говорят, что после пандемии мир никогда не будет прежним. С точки зрения ИБ есть прогноз, что будет? Черчилль же говорил: никогда нельзя упускать хороший кризис. С точки зрения ИБ этот кризис будет хорошим?

Лев: Однозначно хорошим.

Алексей: В чем это проявится?

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

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

Алексей: То, как компании приходят к пониманию, что ИБ это важно, можно, наверное, сравнить с тем, как меняет привычки человек, переехавший жить из деревни в город. На селе в порядке вещей закрыть дверь на щеколду. Замок же используется только в крайнем случае. В городе же уходя закрывать двери на замок сродни аксиоме.

Лев: Как-то люди не сомневаются, что на дверь квартиры нужно ставить замок, хотя хочется купить красивую банкетку в прихожую. Но купишь вместо замка банкетку есть шанс, что не будет ни ее, ни еще половины квартиры. Поэтому надо вкладываться в замок, а потом уже в мебель. Любая компания от 50 ПК нуждается в ИБ. Но не надо утрировать. Не нужны сложные ИБ-продукты в компании, где работает всего 10 человек.

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

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

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

Перевод Симулируем сцену подбора PIN из Терминатора 2

08.01.2021 12:15:36 | Автор: admin
В начале фильма Терминатор 2: Судный день Джон Коннор использует лэптоп для подбора PIN украденной дебетовой карты.


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


Номеронабиратель (War Dialer) из Военных игр (1983 год)


Чёрный ящик из Тихушников (1992 год)

Недавно я вспомнил эту сцену из Терминатора 2, поэтому начал гуглить лэптоп из Терминатора 2.

Оказалось, что это Atari Portfolio первый в мире палмтоп-компьютер (наладонный компьютер). Он был выпущен в июне 1989 года.


Компьютер имел монохромный ЖК-дисплей с разрешением 240x64 пикселей или 40 символов x 8 строк и работал от трёх батареек AA.

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

Для начала изучим нужные технические требования!

Если посмотреть видео внимательно, то видно, что первым делом отображается баннер программы.

banner

Изображение достаточно чёткое, чтобы мы могли с лёгкостью скопировать баннер.

PPPPP   IIIIIII   N    NP   PP     I      NN   N IDENTIFICATIONP   PP     I      N N  NPPPPP      I      N  N N   PROGRAMP          I      N   NNP       IIIIIII   N    NStrike a key when ready ...

После этого Джон нажимает на Enter и на экране начинают прокручиваться числа. Если посмотреть спустя несколько кадров:


то мы увидим, что первая строка чисел выглядит так:

12345678901234567890123457890123456780

Можно было бы предположить, что это просто повторяющиеся четыре раза цифры с 1 по 0, но при внимательном изучении выясняется, что строка длиной всего 38 символов. В третьем повторе пропущена цифра 6, а в последнем цифра 9.

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

Ну, всё выглядит довольно просто. Я осваивал Python, поэтому написал скрипт на Python 3:

#!/usr/bin/env python3import timeimport randomdelay = 0.025print("PPPPP   IIIIIII   N    N")time.sleep(delay)print("P   PP     I      NN   N IDENTIFICATION")time.sleep(delay)print("P   PP     I      N N  N")time.sleep(delay)print("PPPPP      I      N  N N   PROGRAM")time.sleep(delay)print("P          I      N   NN")time.sleep(delay)print("P       IIIIIII   N    N")time.sleep(delay)print('')input("Strike a key when ready ...")print("\n\n12345678901234567890123457890123456780")lines = 1length = 38decrease = 1while True:    for i in range(0, length):        print(random.randint(0,9), end='')    print('')    time.sleep(delay)    lines += 1    if (lines == 5):        lines = 0        length -= decrease        if (decrease == 1):            decrease = 2        else:            decrease = 1    if (length <= 4):        breakfor i in range(0, 10):    print("9003")print("\nPIN IDENTIFICATION NUMBER: 9003")print("\na>", end='')

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

При помощи поиска Google по картинкам я нашёл сайт, продающий пластмассовые панели для Atari Portfolio с нанесённой на экран красивой графикой:


Немного поэкспериментировав с termtosvg, в частности, с функцией SVG-шаблонов, я смог создать этот безумный SVG:


Несмотря на то, что я уже больше десяти лет поддерживаю html5zombo.com, до создания этого SVG я не ценил всех их возможностей. Они могут встраивать изображения? CSS? Javascript? Любой сайт, позволяющий пользователям загружать произвольные SVG и рендерить их, теперь получил моё величайшее уважение.

Пока я развлекался созданием своего небольшого автономного SVG, меня не покидала мысль о том, что мой код на Python на самом деле никогда бы не запустился на Atari Portfolio. В Atari Portfolio установлена DIP Operating System 2.11 (DIP DOS), по большей части совместимая с MS-DOS.

В первых классах старшей школы, ещё до того, как мне начали платить за профессиональное написание ПО, я писал софт для BBS, моды и игры на смеси Turbo Pascal и скриптового языка PCBoard Programming Language, напоминавшего BASIC. Проведя минимальные исследования, я выяснил, что если смогу написать программу на Turbo Pascal и скомпилировать её, то она, вероятно, будет работать на Atari Portfolio.

Я не писал на Turbo Pascal почти 25 лет, но ведь такое не забывается?

Мне нравится форк DOSBox под названием DOSBox-X, поэтому я скачал и установил самую последнюю SDL2-версию для OS X. Затем я нашёл Borland Turbo Pascal 7.0, который помещу сюда, потому что искать его было настоящим мучением.

В этом ZIP вы найдёте четыре файла, которые являются образами гибких дисков. Если поместить их в папку, например, ~/tp, после запуска DOSBox-X и монтирования диска C вы сможете смонтировать их как диск A следующим образом:

imgmount a ~/tp/Disk01.img ~/tp/Disk02.img ~/tp/Disk03.img ~/tp/Disk04.img -floppy

после чего переключиться на диск A: и запустить INSTALL:

A:INSTALL

turbo pascal install

turbo pascal install

turbo pascal install

turbo pascal install

Время от времени придётся заменять гибкие диски, ведь это был 1992 год.

turbo pascal install

Это можно сделать, выбрав в DOSBox-X Drive -> A -> Swap disk. Выполнится переход с Disk 1 на Disk 2. Затем просто продолжайте повторять процесс и нажимать на Ввод, пока не установятся все четыре диска.

После завершения установки она попросить настроить CONFIG.SYS и AUTOEXEC.BAT (не забывайте, это 1992 год).


Ни то, ни другое необязательно. DOSBox-X и так задаёт значение FILES выше необходимого, а добавление к путям просто позволяет запускать TURBO из любого места. После завершения можно выполнить следующую команду:

C:cd tp\binTURBO



В детстве я провёл столько времени с этим IDE, что теперь испытал своего рода ностальгию. Но потом я начал портировать свой скрипт Python на Pascal и ностальгия быстро рассеялась. Хотел бы я сказать, что написал всё целиком в IDE, но в какой-то момент мне пришлось перейти в VSCode, а потом скопировать файл обратно в папку DOS. Люди, которые до сих пор работают в WordPerfect for DOS, я вас и понимаю, и не понимаю.

Вот скрипт, который я получил, потратив много времени на этот туториал по Pascal:

program pinid;uses crt;var i: byte;var pos: byte;var lines: byte;var length: byte;var decrease: byte;var delay_amount: integer;begin     randomize;     delay_amount := 25;     clrscr;     writeln('PPPPP   IIIIIII   N    N');     delay(delay_amount);     writeln('P   PP     I      NN   N IDENTIFICATION');     delay(delay_amount);     writeln('P   PP     I      N N  N');     delay(delay_amount);     writeln('PPPPP      I      N  N N   PROGRAM');     delay(delay_amount);     writeln('P          I      N   NN');     delay(delay_amount);     writeln('P       IIIIIII   N    N');     delay(delay_amount);     writeln('');     write('Strike a key when ready ...');     readln;     writeln('');     writeln('');     writeln('12345678901234567890123457890123456780');     pos := 0;     lines := 1;     length := 38;     decrease := 1;     while true do     begin          for i:= 1 to length do                write(random(9));          writeln('');          delay(delay_amount);          lines := lines + 1;          if (lines = 5) then          begin               lines := 0;               length := length - decrease;               if (decrease = 1) then                   decrease := 2               else                   decrease := 1;          end;          if (length <= 4) then               break;     end;     for i:= 1 to 10 do     begin          writeln('9003');          delay(delay_amount);     end;     writeln('');     writeln('PIN IDENTIFICATION NUMBER: 9003');     writeln('');end.

Краткие объяснения:

  • В Pascal есть объявления типов. Тип byte может быть числом в интервале 0-255.
  • Файлы начинаются с program и названия программы, вероятно потому, что все модули имеют общее пространство имён, но имя файла не важно.
  • Модули импортируются словом uses. Модуль crt используется для манипулирования экраном.
  • := это синтаксис присвоения значения переменной, чтобы можно было сравнивать при помощи = и отличать их друг от друга.
  • Если блоки длиннее одной строки, их нужно оборачивать в begin and end, а не в фигурные скобки или пробелы.
  • Если в начале скрипта не выполнить randomize, то создаваемые случайные числа всегда будут одинаковыми, как и выходные строки.
  • WRITE выводит строку, WRITELN выводит строку с переводом строки. READLN получает ввод до получения перевода строки.

Работает ли код? Вот запущенная в DOSBox-X программа:


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

  1. Купить на Ebay Atari Portfolio.
  2. Купить параллельный интерфейс Atari Portfolio и, вероятно, новую переднюю панель, потому что старая наверняка поцарапана.
  3. Найти в моей коробке с кабелями параллельный кабель.
  4. Найти PC или лэптоп с параллельным портом, установить на него MS-DOS v6.22.
  5. Скачать FT.COM и установить его на PC.
  6. Собрать EXE в Dosbox-X и передать его на Atari Portfolio.
  7. Украсть дебетовую карту.
  8. Обернуть часть карты алюминиевой фольгой, купить последовательный интерфейс Atari Portfolio, подключить кабель к карте.
  9. Запустить программу.
  10. Лёгкие деньги!




На правах рекламы


Закажи и сразу работай! Создание VDS любой конфигурации и с любой операционной системой в течение минуты. Максимальная конфигурация позволит оторваться на полную 128 ядер CPU, 512 ГБ RAM, 4000 ГБ NVMe. Эпичненько :)

Подробнее..

Создаём установщик веб-приложения Python, включающий Apache, Django и PostgreSQL для ОС Windows

26.10.2020 08:23:53 | Автор: admin


Данный пост является продолжением первой части статьи на Хабре, где было подробно рассказано о развертывании Django стека на MS Windows. Далее будет представлена пошаговая инструкция по созданию инсталлятора, который будет автоматизировать процесс установки стека на других компьютерах без необходимости работы в командной строке, созданием виртуальных машин и т.д., где вся последовательность действий будет сводится к действиям Далее -> Далее -> Готово.

Итак, что должен делать инсталлятор:

  1. Распаковать все необходимые программы и компоненты в указанную пользователем директорию.
  2. Выполнить проверки перед установкой.
  3. Прописать интерпретатор Python в реестре Windows.
  4. Установить, если ещё не установлены, программные библиотеки зависимостей.
  5. Создать службы Apache и PostgreSQL, затем стартовать их.
  6. Дополнительным плюсом будет автоматическое создание программы деинсталлятора, который удалит установленный стек, если пользователь этого захочет.


Среди возможных вариантов установщиков выберем бесплатный установщик Inno Setup, т.к. он позволяет выполнить все вышеуказанные действия, позволяющее создавать установщики без необходимости выполнять много сценариев. По сравнению с программой Wix синтаксис установочного файла имеет формат ini, легче читать и менять, чем xml. Сегодня конкурирует и даже превосходит многие коммерческие установщики по набору функций и стабильности.

Лучше всего то, что для создания базового установщика вообще не требуется никаких сценариев, поскольку Inno Setup поставляется с графическим мастером, который на удивление хорошо справляется с базовыми установщиками.

Логика установки может быть написана на ЯП Pascal, а не на запутанных пользовательских действиях в Wix. Единственным недостатком его является то, что он создает только exe, формат файлов msi не поддерживается.

Шаг 1. Установка Inno Setup



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

Шаг 2: Создание сценария установки Inno Setup



Создадим заготовку сценария установки Inno Setup (файл *.iss) с помощью Мастера сценариев установки.

























В результате будет создан *.iss файл с следующим содержимым:
; Script generated by the Inno Setup Script Wizard.
; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES!

#define MyAppName "Severcart"
#define MyAppVersion "1.21.0"
#define MyAppPublisher "Severcart Inc."
#define MyAppURL "https://www.severcart.ru/"

[Setup]
; NOTE: The value of AppId uniquely identifies this application. Do not use the same AppId value in installers for other applications.
; (To generate a new GUID, click Tools | Generate GUID inside the IDE.)
AppId={{4FAF87DC-4DBD-42CE-A2A2-B6D559E76BDC}
AppName={#MyAppName}
AppVersion={#MyAppVersion}
;AppVerName={#MyAppName} {#MyAppVersion}
AppPublisher={#MyAppPublisher}
AppPublisherURL={#MyAppURL}
AppSupportURL={#MyAppURL}
AppUpdatesURL={#MyAppURL}
DefaultDirName=c:\severcart
DefaultGroupName={#MyAppName}
; Uncomment the following line to run in non administrative install mode (install for current user only.)
;PrivilegesRequired=lowest
OutputDir=C:\Users\Developer\Desktop\Output
OutputBaseFilename=mysetup
Compression=lzma
SolidCompression=yes
WizardStyle=modern

[Languages]
Name: "russian"; MessagesFile: "compiler:Languages\Russian.isl"

[Files]
Source: "C:\severcart\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs
; NOTE: Don't use "Flags: ignoreversion" on any shared system files




Шаг 3. Проверки перед установкой



Перед распаковкой программ в каталог и изменения в реестре необходимо проверить, что TCP порты свободны для работы Apache и PostgreSQL, также нужно проверить минимальные системные требования ОС Windows, т.к. как уже оговаривалось в Первой части данной статьи устанавливаемая версия Python будет работать только начиная с версии MS Windows 8 (версия ядра 6.2).

Для выполнения необходимых проверок воспользуемся секцией [Code] установочного файла. Раздел [Code] это необязательный раздел, определяющий сценарий Pascal. Сценарий Pascal можно использовать для настройки установки или удаления разными способами. Обратите внимание, что создать сценарий Pascal непросто и требует опыта работы с Inno Setup и умений программирования на Pascal или, по крайней мере, на аналогичном языке программирования.

function IsWindowsVersionOrNewer(Major, Minor: Integer): Boolean;
var
Version: TWindowsVersion;
begin
GetWindowsVersionEx(Version);
Result := (Version.Major > Major) or ((Version.Major = Major) and (Version.Minor >= Minor));
end;

function IsWindows8OrNewer: Boolean;
begin
Result := IsWindowsVersionOrNewer(6, 2);
end;


Для проверки доступности TCP портов создадим следующую функцию:

function CheckPortOccupied(Port:String):Boolean;
var
ResultCode: Integer;
begin
Exec(ExpandConstant('{cmd}'), '/C netstat -na | findstr'+' /C:":'+Port+' "', '',0,ewWaitUntilTerminated, ResultCode);
if ResultCode <> 1 then
begin
Log('this port('+Port+') is occupied');
Result := True;
end else
begin
Result := False;
end;
end;


Вызывать проверочные функции будем в функции InitializeSetup, вызываемой во время инициализации установки. Возвращает False, для отмены установки, в противном случае True.

function InitializeSetup(): Boolean;
var
port_80_check, port_5432_check: boolean;
begin
if not IsWindows8OrNewer() then begin
MsgBox('Установка невозможна. Программа работает начиная с Windows 2012 и Windows 8.0.',mbError,MB_OK);
Abort();
Result := False;
end;

port_80_check := CheckPortOccupied('8080');
if port_80_check then begin
MsgBox('Установка невозможна. TCP порт 8080 занят.',mbError,MB_OK);
Abort();
Result := False;
end;

port_5432_check := CheckPortOccupied('5432');
if port_5432_check then begin
MsgBox('Установка невозможна. TCP порт 5432 занят.',mbError,MB_OK);
Result := False;
Abort();
end;
Result := True;


Шаг 4. Прописываем Python в реестре Windows



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

Для этого добавляем ключи PYTHONPATH, PYTHONHOME и обновляем переменную Path.

sys.path содержит список строк, предоставляющих места поиска модулей и пакетов будущего Python проекта. Он инициализируется из переменной среды PYTHONPATH и другими настройками.

PYTHONHOME домашний каталог Python.

PATH это переменная окружения, которая ОС использует для поиска исполняемых файлов в командной строке или окне терминала.

[Registry]

Root: HKLM; Subkey: "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"; \
ValueType: expandsz; ValueName: "Path"; ValueData: "{olddata};{app}\python;{app}\python\Scripts"

Root: HKLM; Subkey: "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"; \
ValueType: expandsz; ValueName: "PYTHONPATH"; ValueData: "{app}\python"

Root: HKLM; Subkey: "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"; \
ValueType: expandsz; ValueName: "PYTHONHOME"; ValueData: "{app}\python"



Шаг 5. Создаем конфигурационные файлы служб Apache и PostgreSQL



Для создания конфигурационных файлов воспользуемся 2я Python скриптами, которые сгенерируют конфигурационные на основе заданного пользователем пути установки.

Вызов скриптов будет производиться в разделе [Run] установщика.

Раздел [Run] является необязательным и указывает любое количество программ, которые необходимо выполнить после успешной установки программы, но до того, как программа установки отобразит последнее диалоговое окно.

Далее в эту же секцию добавим скрытую установку распространяемые пакеты Visual Studio без которых службы Apache и PostgreSQL работать не будут.

[Run]

Filename: "{app}\common\VC_redist.x86apache.exe"; Parameters: "/install /passive"; Flags: waituntilterminated
Filename: "{app}\common\vcredist_x86pg.exe"; Parameters: "/install /passive"; Flags: runhidden;
Filename: "{app}\python\python.exe" ;Parameters: "{app}\common\create_http_conf.py"; Flags: runhidden
Filename: "{app}\python\python.exe" ;Parameters: "{app}\common\edit_pg_conf.py"; Flags: runhidden
Filename: "{app}\common\install.bat";Flags: runhidden
Filename: "{app}\common\services_start.bat"; Flags: runhidden


Содержимое файла create_http_conf.py

#!/usr/bin/env python3# -*- coding:utf-8 -*-import sys, osbase_path = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))base_path_un = base_path.replace('\\', '/')apache_conf_path = os.path.join(base_path, 'Apache24', 'conf', 'extra', 'httpd-wsgi.conf')print('base_path=',base_path)CONF = """LoadFile "%(base)s/python/python39.dll"LoadModule wsgi_module "%(base)s/python/lib/site-packages/mod_wsgi/server/mod_wsgi.cp39-win32.pyd"WSGIPythonHome "%(base)s/python"Alias /static "%(base)s/app/static"Alias /media "%(base)s/app/media"<Directory "%(base)s/app/static">    # for Apache 2.4    Options Indexes FollowSymLinks    AllowOverride None    Require all granted</Directory><Directory "%(base)s/app/media">    # for Apache 2.4    Options Indexes FollowSymLinks    AllowOverride None    Require all granted</Directory>WSGIScriptAlias / "%(base)s/app/conf/wsgi_prod.py"WSGIPythonPath "%(base)s/python/"<Directory "%(base)s/app/conf/"><Files wsgi_prod.py>    Require all granted</Files>   </Directory>"""conf_content = CONF % {'base': base_path_un}with open(apache_conf_path, 'w') as fp:    fp.write(conf_content)# Read in the fileapache_main = os.path.join(base_path, 'Apache24', 'conf', 'httpd.conf')with open(apache_main, 'r') as file :filedata = file.read()# Replace the target stringreplace_pattern = 'Define SRVROOT "%(base)s/Apache24"' % {'base' : base_path_un}find_pattern = 'Define SRVROOT "C:/severcart/Apache24"'filedata = filedata.replace(find_pattern, replace_pattern)# Write the file out againwith open(apache_main, 'w') as file:file.write(filedata)


Содержимое edit_pg_conf.py

#!/usr/bin/env python3# -*- coding:utf-8 -*-import sys, os"""c:/djangostack/postgresql/bin/postgres.exe "-D" "c:\djangostack\postgresql\data""""base_path = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))base_path_un = base_path.replace('\\', '/')pg_conf_path = os.path.join(base_path, 'postgresql', 'data', 'postmaster.opts')# Read in the filepg_conf_path = os.path.join(base_path, 'postgresql', 'data', 'postmaster.opts')with open(pg_conf_path, 'r') as file :filedata = file.read()# Replace the target stringreplace_pattern = base_path_un + '/'find_pattern = "C:/severcart/"filedata = filedata.replace(find_pattern, replace_pattern)# Write the file out againwith open(pg_conf_path, 'w') as file:file.write(filedata)


Содержимое файла install.bat

@echo off

..\Apache24\bin\httpd.exe -k install -n "Apache" > install.log 2>&1

..\postgresql\bin\pg_ctl.exe register -N "PostgreSQL" -D ..\postgresql\data > install.log 2>&1


Содержимое файла services_start.bat

@echo off

net start "Apache"

net start "PostgreSQL"


Шаг 6: Создаем деинсталлятор



Для любого инсталлятора также необходимо предусмотреть возможность создания программы деинсталлятора. К счастью программа Inno Setup сделает эту работу за нас, за исключением некоторых действий, которые нужно предусмотреть для очистки следов присутствия программы в ОС.

Для этого в секции [UninstallRun] пропишем выполнение bat скрипта Windows для остановки установленных служб, а также их удаления.

[UninstallRun]
Filename: "{app}\common\remove.bat"; Flags: runhidden


Содержимое bat скрипта:

@echo off

SC STOP Apache
SC STOP PostgreSQL

SC DELETE Apache
SC DELETE PostgreSQL

Скрипт выполняет остановку служб, затем удаляет службы Apache и PostgreSQL из перечня системных служб Windows.

Шаг 7. Подписание исполняемого файла инсталлятора ЭП разработчика



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

Купить сертификат разработчика PFX, например можно здесь. Сертификат приобретается на год.

Предпоследним шагом над работы с инсталлятором будет автоматический запуск программы signtool.exe для подписания готового инсталлятора в формате exe после того как программа Inno Setup завершит свою работу. SignTool это программа командной строки, которая подписывает файлы цифровой подписью, проверяет подписи в файлах и временные метки файлов. По умолчанию в комплекте поставки Windows программа signtool.exe отсутствует, поэтому скачиваем и устанавливаем Windows 10 SDK.

По окончании установки вы найдете signtool.exe в каталогах:

  • x86 -> c:\Program Files (x86)\Windows Kits\10\bin\x86\
  • x64 -> c:\Program Files (x86)\Windows Kits\10\bin\x64\


Для тех, кто хочет познакомиться с программой подписания подробнее посетите официальный сайт разработчика. В нем перечислены все опции командной строки и примеры использования. Двигаемся далее.

Далее настроим автоматическое подписание файла. Выбираем Configure Sign Tools... из меню Tools.



Далее нажимаем на кнопку Add



Дадим инструменту имя. Это имя, которое вы будете использовать при обращении к инструменту в сценариях установщика. Я назвал свой signtool, потому что использую signtool.exe.



Вставьте текст, который вы используете для подписи исполняемых файлов из командной строки. Замените имя подписываемого файла на $f. Inno Setup заменит переменную $f подписываемым файлом.

C:\Program Files (x86)\Windows Kits\10\bin\x86\signtool.exe sign /f C:\MY_CODE_SIGNING.PFX /t timestamp.comodoca.com/authenticode /p MY_PASSWORD $f



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



Добавим следующий сценарий в раздел [Setup], чтобы использовать только что настроенный инструмент подписи. Это предполагает, что вы назвали свой инструмент signtool.

SignTool=signtool


Шаг 8. Собираем инсталлятор



Итоговый InnoSetup файл инсталлятора
#define MyAppName Severcart
#define MyAppVersion 1.21.0
#define MyAppPublisher Severcart Inc.
#define MyAppURL www.severcart.ru

[Setup]
; NOTE: The value of AppId uniquely identifies this application.
; Do not use the same AppId value in installers for other applications.
; (To generate a new GUID, click Tools | Generate GUID inside the IDE.)
SignTool=signtool
AppId={{2CF113D5-B49D-47EF-B85F-AE06EB0E78EB}}
AppName={#MyAppName}
AppVersion={#MyAppVersion}
;AppVerName={#MyAppName} {#MyAppVersion}
AppPublisher={#MyAppPublisher}
AppPublisherURL={#MyAppURL}
AppSupportURL={#MyAppURL}
AppUpdatesURL={#MyAppURL}
DefaultDirName=c:\severcart
DefaultGroupName={#MyAppName}
OutputBaseFilename=setup
Compression=lzma
SolidCompression=yes
ChangesEnvironment=yes

; Uninstall options
Uninstallable=yes
CreateUninstallRegKey=yes
;WizardSmallImageFile=logo3.bmp

[Icons]
Name: "{userdesktop}\severcart"; Filename: 127.0.0.1:8080/

[Languages]
Name: russian; MessagesFile: compiler:Languages\Russian.isl

[Files]
Source: C:\severcart\*; Excludes: "*.pyc"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs

[Registry]
Root: HKLM; Subkey: SYSTEM\CurrentControlSet\Control\Session Manager\Environment; \
ValueType: expandsz; ValueName: Path; ValueData: "{olddata};{app}\python;{app}\python\Scripts"

Root: HKLM; Subkey: SYSTEM\CurrentControlSet\Control\Session Manager\Environment; \
ValueType: expandsz; ValueName: PYTHONPATH; ValueData: "{app}\python"

Root: HKLM; Subkey: SYSTEM\CurrentControlSet\Control\Session Manager\Environment; \
ValueType: expandsz; ValueName: PYTHONHOME; ValueData: "{app}\python"

[Run]
Filename: "{app}\common\VC_redist.x86apache"; Parameters: "/install /passive"; Flags: waituntilterminated
Filename: "{app}\common\vcredist_x86pg"; Parameters: "/install /passive"; Flags: runhidden;
Filename: "{app}\python\python.exe" ;Parameters: "{app}\common\create_http_conf.py"; Flags: runhidden
Filename: "{app}\python\python.exe" ;Parameters: "{app}\common\edit_pg_conf.py"; Flags: runhidden
Filename: "{app}\common\install.bat";Flags: runhidden
Filename: "{app}\common\services_start.bat"; Flags: runhidden


[UninstallRun]
Filename: "{app}\common\remove.bat"; Flags: runhidden

[Code]
function IsWindowsVersionOrNewer(Major, Minor: Integer): Boolean;
var
Version: TWindowsVersion;
begin
GetWindowsVersionEx(Version);
Result :=
(Version.Major > Major) or
((Version.Major = Major) and (Version.Minor >= Minor));
end;

function IsWindows8OrNewer: Boolean;
begin
Result := IsWindowsVersionOrNewer(6, 2);
end;

function CheckPortOccupied(Port:String):Boolean;
var
ResultCode: Integer;
begin
Exec(ExpandConstant('{cmd}'), '/C netstat -na | findstr'+' /C:":'+Port+' "', '',0,ewWaitUntilTerminated, ResultCode);
if ResultCode <> 1 then
begin
Log('this port('+Port+') is occupied');
Result := True;
end else
begin
Result := False;
end;
end;

function InitializeSetup(): Boolean;
var
port_80_check, port_5432_check: boolean;
begin
if not IsWindows8OrNewer() then begin
MsgBox('Установка невозможна. Программа работает начиная с Windows 2012 и Windows 8.0.',mbError,MB_OK);
Abort();
Result := False;
end;

port_80_check := CheckPortOccupied('8080');
if port_80_check then begin
MsgBox('Установка невозможна. TCP порт 8080 занят.',mbError,MB_OK);
Abort();
Result := False;
end;

port_5432_check := CheckPortOccupied('5432');
if port_5432_check then begin
MsgBox('Установка невозможна. TCP порт 5432 занят.',mbError,MB_OK);
Result := False;
Abort();
end;
Result := True;

end;






Шаг 9. Проверяем работу инсталлятора





















На это всё, спасибо за внимание. Собранные дистрибутивы для ОС Windows можно скачать на сайте https://www.severcart.ru/downloads/.
Подробнее..
Категории: Python , Postgresql , Apache , Pascal , Django framework

Шахматы на Delphi. Как я изобретал велосипед

11.04.2021 00:10:54 | Автор: admin

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

Начало

Это случилось в 2009 году: я решил написать простую шахматную программу, чтобы попрактиковаться в разработке игрового AI. Сам я не шахматист и даже не сказать что любитель шахмат. Но задача для тренировки вполне подходящая и интересная. Кроме того, играя в шахматы на доске или в программе, мне всегда было любопытно, почему тот или иной ход сильнее другого. Хотелось возможности наглядно видеть всё дерево развития шахматной позиций. Такой фичи в других программах я не встречал - так почему бы не написать самому? Ну а раз уж это тренировка - то придумывать и писать нужно с нуля, а не изучать другие алгоритмы и писать их собственную реализацию. В общем, думаю, дня за три можно управиться и сделать какой-то рабочий вариант :-)

Первая версия

Обычно шахматные движки используют поиск в глубину с алгоритмом "ветвей и границ" для сужения поиска. Но это не очень-то наглядно, поэтому решено: мы пойдём своим путём - пусть это будет поиск в ширину на фиксированную глубину. Тогда в памяти будет полное дерево поиска, которое можно как-то визуализировать. А также выяснить: а) на какую глубину можно просчитать шахматную игру в рамках имеющихся ресурсов CPU и памяти, б) насколько хорошо или плохо будет играть такой алгоритм?

Надо сказать, что на тот момент у меня был 2-ядерный процессор с 2 или 4 Гб памяти (точно уже не помню), 32-битная винда и 32-битный компилятор Turbo Delphi Explorer. Так что если временем работы ещё можно было как-то пожертвовать, то доступная процессу память была ограничена 2Gb. Про PE flag, расширяющий user memory до 3Gb я тогда не знал. Впрочем, поскольку память кушают и система, и Delphi и другие программы - для шахмат, чтобы не уходить в своп, доступно менее гигабайта.

В результате получилась первая версия игры, состоящая из таких модулей:

  • UI - основное окно, отрисовка доски с фигурами.

  • Игровая логика - составление списка возможных ходов, выполнение хода, детекция завершения игры.

  • AI:оценка - оценочная функция позиции.

  • AI:перебор - поиск в ширину через очередь.

  • UI:браузер - окно визуализации дерева поиска, в котором можно наглядно изучать как всё работает.

Выяснилось что:

  • Поиск на глубину 3 полухода работает быстро - меньше секунды, и расходует немного памяти - 5-15 Мб. А вот поиск на глубину 4 полухода работает уже довольно долго и расходует большую часть доступной памяти. В отдельных ситуациях памяти и вовсе не хватает.

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

  • При любой глубине поиска, компьютер совершенно не умеет играть в эндшпиле и не понимает что делать, если у противника остался один король.

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

Оценочная функция

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

В итоге пришел к примерно такому алгоритму:

  • Для каждого игрока:

    • Подсчитать стоимость фигур: конь - 3, ладья - 5 и т.д. Начальная стоимость пешки - 1, но она растёт по мере её продвижения.

    • Бонус за сделанную рокировку, штраф за потерю возможности рокировки, штраф в миттельшпиле за невыведенные фигуры (коней и ладьи в углах). Штраф за сдвоенные пешки и бонус за захваченные открытые линии.

    • Определение какие поля находятся под боем и кем. Это медленная операция - основная часть времени выполнения оценочной функции тратится именно здесь. Зато польза от неё колоссальная! Незащищённая фигура под боем на ходу противника - минус фигура. Защищённая - минус разность стоимости фигур. Это позволяет получить эффект углубления поиска на 1-2 уровня.

    • Если остался один король: штраф за расстояние от центра доски и штраф за расстояние до короля противника. Такая формула в эндшпиле заставляет AI стремиться прижать короля противника к краю доски, т.е. получить позицию, из которой можно найти возможность поставить мат.

  • Итоговая оценка = (white_rate - black_rate) * (1 + 10 / (white_rate + black_rate)). Эта формула делает разницу более значимой в эндшпиле, заставляя отстающего игрока избегать размена фигур, а ведущего - наоборот, стремиться к размену.

Углубление поиска

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

Кроме того, нужно развивать наиболее перспективные направления - ветки с наибольшей оценкой.

В итоге алгоритм получился такой:

  1. На первой стадии строится дерево с базовой глубиной 3 (при этом ветки со взятиями и шахами могут достигать заметно большей глубины).

  2. Оценка дерева алгоритмом минимакс.

  3. Если выполнены критерии принятия решения - выбирается ветка с наилучшей оценкой и алгоритм завершается.

  4. Обрезка дерева: последовательно удаляются ветки с наихудшей оценкой пока не будет свободно достаточно памяти для продолжения поиска.

  5. Переход к следующей стадии: добавляем вес всем листьям дерева и продолжаем поиск. После завершения переходим к п 2.

Критерии принятия решения:

  • Осталась единственная ветка - выбора нет.

  • Одна из веток имеет оценку существенно более высокую чем у остальных - выбираем её.

  • Истекло время на ход - выбираем ветку с наилучшей оценкой.

Кэширование

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

Всё просто: нужно вычислить хэш от позиции и если в кэше уже есть оценка с таким хэшем - использовать её вместо вычисления. А если нет - вычислить и сохранить в кэше оценок. Основная проблема - нужна достаточно качественная и быстрая хэш-функция. После множества экспериментов получилось написать приемлемую функцию, вычисляющую 64-битный хэш. Общее количество возможных шахматных позиций значительно больше 264, но количество позиций, оцениваемых в ходе партии значительно меньше 232, поэтому более-менее качественная хэш-функция должна свести вероятность хэш-коллизий к минимуму.

Процент "попаданий" в кэш в ходе игры получился в районе 30-45%, но в эндшпиле достигает 80-90%, что даёт ускорение почти в 5-10 раз, а следовательно позволяет увеличить глубину поиска. Неплохой выигрыш!

Что получилось?

Я добавил библиотеку дебютов, и в таком состоянии программа играла уже довольно неплохо - примерно на уровне 2-го разряда, а может и чуть сильнее. Результат, в принципе, достойный - можно остановиться. Хотя были вполне очевидны недостатки и направления развития:

  • AI работает в один поток - ресурс CPU задействован не полностью.

  • А что если предоставить больше памяти?

  • AI думает только во время своего хода. Почему бы не использовать время соперника для просчёта наиболее вероятных продолжений?

  • Главная слабость: детерминированность. Каждый ход рассматривается как отдельная задача, каждая позиция приводит к детерминированному решению. Достаточно выиграть один раз, чтобы запомнить последовательность ходов, которая всегда приведёт к победе. А играть с таким соперником неинтересно.

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

Дальнейшее развитие

Недавно наткнувшись на этот заброшенный проект, решил всё-таки привести его код в порядок и доработать. Доработки сделал такие:

  • Многопоточность: сейчас у меня уже 8-поточный, а не 2-поточный CPU, поэтому многопоточный вариант даёт серьёзную прибавку в скорости.

  • 64-битный режим: кроме возможности использовать больше памяти, было любопытно, будет ли алгоритм работать быстрее на архитектуре x64. Как ни странно, оказалось что нет! Хотя отдельные функции на x64 работают быстрее, в целом версия x86 оказалась на 5-10% быстрее. Возможно 64-битный компилятор Delphi не очень хорош, не знаю.

  • Больше памяти: даже в 32-битном режиме за счёт PE-флага расширения адресного пространства доступной памяти стало больше. Однако практика показала, что больше 1 Гб памяти все-равно не нужно - разве что для хранения "обрезанных" ветвей дерева. К усилению игры увеличение памяти не приводит.

  • Непрерывность поиска: теперь дерево поиска не создаётся с нуля каждый ход, а создаётся лишь в начале партии. Когда делается ход - неактуальные ветви дерева обрезаются а поиск продолжается с того состояния, которое было. В том числе и во время хода соперника - идёт проработка перспективных продолжений, поэтому когда соперник сделает ход, поиск продолжится не с нуля. Быть может и вовсе получится сразу же сделать ход. Момент времени, когда игрок сделает ход - это фактор случайности, который делает игру недетерминированной. Теперь уже нельзя запомнить выигрышную последовательность ходов.

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

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

  • База оценок и самообучение. В процессе игры какие-то позиции детально прорабатываются и получают оценку с высоким качеством. Почему бы не сохранять такие оценки для использования в других партиях? Это ещё одна фича, которая делает игру недетерминированной.

В результате этих доработок AI стал сильнее, и вполне уверенно обыгрывает старую версию игры. Я провел несколько партий против AI на chess.com и выяснил, что уровень моей программы примерно соответствует рейтингу 1800-1900. Прогресс есть, и это хорошо!

Программирование игрового AI - занятие чертовски затягивающее: всегда хочется добиться большего. И хотя у меня по прежнему есть масса идей для дальнейшего развития, наступает момент, когда надо остановиться. Думаю, он наступил. Однако если кто-либо желает - может взять мой код, побаловаться, поэкспериментировать, что-нибудь реализовать. Благо, сейчас Delphi доступен каждому благодаря бесплатной Community Edition, не говоря уже про бесплатный Free Pascal и Lazarus. Код проекта (а также скомпилированный exe-шник) можно взять тут: https://github.com/Cooler2/chess (для компиляции понадобится также кое что из https://github.com/Cooler2/ApusGameEngine). Спасибо всем, кто дочитал :-)

Подробнее..

Категории

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

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru