Issuu on Google+


2

Интро

Intro

Приветствую Вас, дорогие друзья! Как же нам все­таки повезло, что многие мы родились именно в середине 80­х (90­х). А как же повезет, тем, кто родиться еще позже! Мы живем в век офигительных технологий и с если не каждый день, то каждый месяц происходят какие­то новые открытия, появляются умопомрачительные сервисы и просто куча всего интересного. Если вчера это было за гранью фантастики, то сегодня более, чем реально. Те, кто начинал заниматься IT в конце девяностых, начала двухтысячных, должны меня понять. Как же приятно наблюдать глобальные изменения в своем любимом деле. Вспоминаю, как еще лет пять назад я плевался от убогости почтовых web­интерфейсов и юзал TheBat. А сегодня я уже не могу представить свою жизнь без продвинутого интерфейса Gmail и функциональных гугл­доков. Многое изменилось... И изменилось в лучшую сторону. Технологии становятся дружелюбней по отношению к пользователю и вносят в жизнь приятные впечатления. Пользователи рады, а мы, ИТ­Специалисты и программисты, получаем новую порцию наркотика под названием "Информация". Да, приходится употреблять его больше, но ведь в этом и кайф! Мозг постоянно прокачивает свой скил, доставляя моральное удовольствие и осознание того факта, что мы отличаемся от других. Мы способны творить умопомрачительные вещи в виртуале! Красивый и функциональный гаджет мы в первую очередь видим как крутость инженерной мысли; от ошибок в софте мы не паникуем, а ищем решение, заставляя «тупую» программу подчиниться и т.д. Цифровая жизнь и постоянный статус «в Online» ­ это наш life style. Мы не такие как все, мы дети цифровой эры! Приятного чтения, мой друг!

Игорь Антонов


Содержание

Содержание

Июнь 2010 (24)

68. "Джоэл о программировании"

IT-News Hard-News VrIP персона _

_

Урусовым

70. TeX & LaTeX. Язык разметки

_

1 3. Delphi. Работа с указателями 30. Delphi. Подружим Си и Delphi

93. "Песнь легиона". Часть 3

38. Python. Image grabbing

­

верстальщика

79. "Я так люблю свою страну"

36. Python. Auto forwarder for Joomla

_

74. Scribus. Записки начинающего

Меня тошнит Креатиff

27. JavaScript. Сжатие данных

­

продвинутых

Без рамки

1 0. Gagadget.com. Интервью с Павлом

Кодинг

­

69. Ubuntu и Debian Linux для

Безопасность

40. Python. AutoUp v0.1b для форума

1 01 . I2P. Анонимная сеть

"Амит"

42. Ajax + PHP. Повышаем

Психо

45. С#. Самопальный диспетчер задач для

Школа

интерактивность Windows Mobile

48. Delphi. Google API в Delphi

51 . Delphi. Математические процедуры и функции

1 04. Манипуляции

_

Я прусь Обзоры от VR

1 07. Unix. Именованые каналы и сокеты

Михаил Фленов aka

Horrific

(http://flenov.info)

_

1 09. Поднимаем VPS. автоматизация обслуживания

Мнение VR FAQ по FreeBSD

65. Обзор Samsung i900

Идея проекта

средствами С#

Админинг

56. Cracking. Реверсинг ASM KEYGENME #1 60. PHP. Библиотека мануалов

1 06. Скачиваем файл из Интернета

Редакторы номера

Игорь Антонов aka

Spider_NET

Роман Костенко aka

Lord_of_Fear

Верстка и оформление

Антон Козлов aka

Jimmy Jonezz

Дмитрий Редькин aka

zahod5277

Вопросы и предложения

mail@vr­online.ru antonov.igor.khv@gmail.com


Подборка новостей: Игорь Антонов aka Spider_NET Email: antonov.igor@gmail.com

4

IT-News

IT­News

Новости IT­индустрии

Все то, что нас удивляло и приводило в восторг в этом месяце

Бета версия SP1 для Windows 7 и Windows Server 2008 R2 уже доступна В начале июля софтверный гигант выплюнул тестовую версию первого большего обновления для Windows 7 (а также Win Server 2008 R2) – Service Pack. Все желающие могут скачать апдейт с официального сайта компании. Прямой линк: http://technet.microsoft.com/ru­ru/evalcenter/ff183870.aspx.

Больше поддерживать не будем!

13 июля роковой день для старушки Windows XP SP2. С этого дня, компания MS прекращает ее поддержку. Больше никаких security апдейтов для этой версии ОС не будет. Если ты все еще юзаешь SP2, то самое время обновиться до SP3, а еще лучше установить себе ОС современней. Поддержка Windows XP SP3 будет осуществляться до 8 апреля 2014 года.

Вот так надо устраивать масс-фоловинг

Bobbi Eden – порнозвезда и любительница футбола. Во время разгара чемпионата мира она опубликовала в своем микроблоге (http://twitter.com/BobbiEden/) интригующий твит – «Всем мужчинам, которые меня зафолофят, я сделаю минет». Звезда уточнила, что ей будут помогать подруги по «работе» ­ vickyvette (http://twitter.com/vickyvette), misshybrid (http://twitter.com/misshybrid), gabbyquinteros (http://twitter.com/gabbyquinteros). Предложение не осталось незамеченным. Девушка за короткий временной промежуток собрала более 75 тысяч фоловеров.

Разрешите представиться, Farman

8 – июля произошел долгожданный релиз популярного Linux­ дистрибутива – Mandriva 2010 Spring. Кодовое название ОС Farman. Это поистине долгожданный релиз, т.к. последнее время над мандривой летали черные тучи – ухудшение финансового положения, слухи о продаже, таинственное спасение спонсорами и т.д. Сейчас у компании вроде все хорошо и выход очередной версии ОС лучшее тому подтверждение.

Сколько стоит национальный поиск?

По предварительным данным стало известно, что создание национального поисковика обойдется в 3,3 млрд рублей бюджетных денег. Информация о сумме была сделана на основании закрытой презентации Минкомсвязи «Создание российской поисковой системы» vr­online | июнь 2010


5

IT-News

(по сообщению «Газеты.ру»). Предполагается, что разработка поисковика завершится в 2012 году.

OpenSUSE 11 .3 готов к труду и обороне

Июль просто богат на релизы операционных linux­like систем. Сначала Mandriva, теперь вот и Novell порадовала своих поклонников. 16 июля состоялся релиз OpenSUSE 11.3. Все желающие могут загрузить новую версию ОС с официального сайта opensuse.org и многочисленных трекеров. Обновленный дистрибутив построен на базе ядра Linux 2.6.34. Из графических оболочек присутствуют: Gnome 2.30.1, KDE 4.4.4 и Xfct. Любители экстрима и всего нестабильного могут заюзать третью тестовую версию Gnome.

Зона .РФ продолжает расти

Reg.RU сообщает, что к середине июля в национальной зоне .РФ количество зарегистрированных имен перевалило за 14 тысяч. Скоро количество доменов еще увеличится, т.к. начиная, с 15 июля стартует третий этап приоритетной регистрации.

И остались они у разбитого корыта

Все наслышаны созданием китайского интернет­фильтра – Green Dam. Теперь этот «полезный» проект остался без финансирования. Компания Dazheng Language Technology Academy (именно она занималась поддержкой GD) уже начала сокращать штат сотрудников, работающих над разработкой фильтра. Будущее проекта пока неизвестно.

Интернет кодекс

Ильзе Айгнер – немецкий министр по защите прав потребителей и просто находчивая женщина. Относительно недавно предложила создать так называемый кодекс чести в интернете. По ее задумке кодекс должен включать 10 «золотых правил», созданные, самим интернет сообществом. От себя добавлю, что с виду это все жутко напоминает хакерский манифест Ментора, написанный в 1986 году. Только будут ли его также уважать? Сомневаюсь. В инете сегодня тусуются все: начиная от президента и заканчивая «васькой­ гопником» из третьего подъезда. Глубоко сомневаюсь, что последний будет тратить время на чтение каких­то «правил».

FireFox – корпоративный стандарт для IBM

Компания IBM заявила, что FireFox стал официальным браузером компании. Причиной перехода на FireFox стало соответствие браузера отраслевым стандартам, а также безопасность и открытость.

Игры от Google: Быть или не быть?

Журналисты издания TechCrunch сообщили, что поисковый гигант вложил крупненькую сумму денег (около $100­$200 млн) в компанию Zynga. Данная компания занимается разработкой браузерных игр. Если это действительно так, то можно с уверенностью сказать, что в скором времени мы будем играть в игрушки от корпорации зла. vr­online | июнь 2010


6

IT-News YouTube опять проапгрейдили

Представители портала YouTube объявили о поддержке видеоразрешения 4K (4096). Для воспроизведения видео с таким разрешением требуется экран с диагональю в 7,62 дюйма. Только представь, что видео в формате 1080p уместится на таком размере больше 4­х раз! Эх, вот такой бы экран, да видео с таким разрешением у себя дома! Стоп. И еще бы дом соответствующих размеров.

Четвертый FireFox не за горами

В самом начале июля разработчики представили первую бету четвертой версии FireFox. Среди значимых изменений наиболее выделяются: ­ в версии для Windows вкладки теперь размещаются в самой верхней части окна браузера;

­ на Windows Vista и Windows 7 верхнее меню заменено кнопкой «Firefox»; ­ новый менеджер расширений;

­ кнопка остановки загрузки страницы и кнопка обновления страницы были объединены в одну в версиях для Windows, Mac и Linux;

Office 201 0 шагает по стране

В нашей стране начались продажи новейшей версии пакета программ MS Office. В зависимости от редакции, цена будет колебаться от 3050 до 22070 рублей.

Сети от самоубийц

Тайваньский OEM­производитель электроники Foxconn натягивает возле общежитий рабочих – сети. Речь идет не о ЛВС, а самых обычных сетях. За текущий год среди работников компании было зафиксировано двенадцать случаев попыток самоубийства, десять из которых закончились смертью. Причиной навязчивого желания свести счеты с жизнью стала – низкая заработная плата и тяжелые условия труда. Когда я впервые увидел новость, то сразу вспомнил фильмы о средневековье, где народ умирал от адской работы. Оказывается, такие времена прошли не до конца.

vr­online | июнь 2010


Подборка новостей: Роман Костенко aka Lord_of_fear. e­mail: kostenko.r.khv@gmail.com

7

Hard-News

Hard­News

Железные новости Новенький iPhone 4 от Apple

Этим летом в июне на WWDC 2010 в Сан­Франциско Стив Джобс (Steve Jobs) официально анонсировал выпуск смартфона Apple следующего поколения iPhone 4.

Смартфон Apple iPhone 4 оснащается процессором A4 SoC (System­on­a­chip), содержит 3,5­дюймовый сенсорный IPS экран с разрешением 960х640 точек (контрастность 800:1, 326 точек на дюйм) и 16 или 32 ГБ флэш­памяти. Передняя и задняя панели устройства выполнены из алюминосиликатного стекла, которое также используется в вертолетах и высокоскоростных поездах. По заверениям производителя, оно в 20 раз жестче и в 30 раз тверже, чем пластик. Шасси корпуса, выполняющее также функцию антенны, выполнено из специальной нержавеющей стали, которая в пять раз прочнее обычной.

Первый процессор APU Fusion от AMD

Компания AMD провела на выставке Computex 2010 первую публичную демонстрацию процессора Fusion. Семейство устройств ускоренной обработки (Accelerated Processing Units – APU) AMD Fusion объединяет на одном кристалле вычислительные ядра высокопроизводительных последовательных вычислений, а также графическое ядро параллельной обработки графики. В рамках платформы AMD Fusion первоначально запланирован выпуск двух серий процессоров: Llano и Ontario. Такие чипы уже доступны в виде отдельных образцов, а их официальный релиз намечен на первый квартал 2011 года. При этом отмечается, что процессоры Llano изготавливаются по нормам 32­нанометрового технологического процесса, содержат четыре вычислительных ядра и одно графическое ядро, обладающее поддержкой DirectX 11. Такие модели предназначены для применения в составе настольных компьютеров.

Утверждены спецификации Bluetooth 4.0 С ростом популярности различных мобильных устройств потребность в скоростных и энергетически эффективных беспроводных интерфейсах не снижается. Лидером сегмента в этом смысле можно признать Bluetooth, поскольку он давно прижился в мобильных телефонах и портативных компьютерах. В этом месяце организация Bluetooth SIG объявила о доступности спецификаций Bluetooth 4.0 разработчикам аппаратного обеспечения. Новая версия интерфейса сохраняет максимальную скорость передачи информации на уровне 24 Мбит/с, но

снижает уровень энергопотребления и увеличивает максимальную дальность передачи информации до 100 метров. Разработчики утверждают, что отныне станет возможным создание устройств, способных передавать информацию со скоростью 1 Мбит/с и питаться от плоской батареи размером с монету на протяжении одного года. Поддерживается шифрование данных по 128­разрядному алгоритму AES, задержки при передаче информации тоже снизились. По прогнозам аналитиков, к 2015 году версия Bluetooth с пониженным энергопотреблением займёт до половины рынка беспроводных датчиков.

vr­online | июнь 2010


8

Hard-News Универсальные блоки питания для ноутбуков

Попытки унифицировать зарядные устройства для мобильных телефонов уже предпринимались, но пока об успехе этой инициативы говорить рано. Тайваньские производители мобильных компьютеров одобрительно высказались об идее унификации блоков питания для ноутбуков. Разрабатывающая стандарты в этой сфере организация IEEE недавно сформировала рабочую группу, которая будет курировать этот вопрос.В поддержку идеи создания универсальных блоков питания для ноутбуков выступили Acer, Asus, Quanta, Compal, Wistron, Pegatron и Inventec ­ последние пять компаний контролируют львиную долю рынка контрактного производства мобильных компьютеров. Производители блоков питания подобную инициативу воспринимают без энтузиазма, поскольку унификация блоков питания приведёт к падению объёмов продаж их продукции. Один блок питания сможет пережить несколько ноутбуков, и пользователям не потребуется покупать с каждым новым мобильным компьютером новый блок питания.

Seagate предлагает внешний жёсткий диск объёмом 3 Тб

Пообещав представить до конца года винчестер объёмом три терабайта, компания Seagate сразу обозначила проблемы, которые предстоит решить до выхода подобных накопителей. Прежде всего, это неспособность материнских плат с классическим BIOS работать с винчестерами такого объёма ­ необходим переход на EFI. Во­вторых, увидеть полный объём такого винчестера могут только 64­разрядные версии Windows Vista, Windows 7 и специальные версии Linux. Драйверы контроллеров RAID тоже потребуют адаптации к накопителям такого объёма. Тем не менее, компания Seagate объявила о начале приёма заказов на внешний винчестер FreeAgent GoFlex объёмом 3 Тб. Сам накопитель стоит $249 и оснащается интерфейсом USB 2.0. Дополнительно винчестер может быть оборудован док­станцией со следующим сочетанием интерфейсов: "USB 2.0 + FireWire 800" ($49), "USB 3.0" ($39) или "USB 3.0 + интерфейсная карта PCI Express x1" ($79). На док­станции предусмотрен светодиодный индикатор заполнения диска, устанавливать диск можно как вертикально, так и горизонтально.

Портативный накопитель Aegis Bio со сканером отпечатков пальцев

Калифорнийская компания Apricorn анонсировала выпуск новой модели портативного накопителя Aegis Bio, который оснащается сканером отпечатков пальцев для ограничения несанкционированного доступа к данным. Портативный накопитель Apricorn Aegis Bio содержит 2,5­ дюймовый жесткий диск емкостью 6400 ГБ, который вращается со скоростью 5400 об/мин и оснащается кэш­буфером объемом 8 МБ. Новинка также содержит 16­точечный всенаправленный сенсор ударов. Портативный накопитель Apricorn Aegis Bio обеспечивает 128­битное AES шифрование информации при помощи чипа Oxford Semiconductor.

vr­online | июнь 2010


Игорь Антонов aka Spider_NET Email: antonov.igor@gmail.com

9

VrIP персона

Gagadget.com:

"У нас не скучный сайт о технике!" Интервью с Павлом Урусовым

Мы с самого начала понимали, что ограниченные ресурсы не дают нам возможности на равных тягаться с большими сайтами вроде ITC.ua или IXBT.com по количеству материалов. Поэтому мы решили работать в несколько другом жанре, который описывается нашим слоганом — «Нескучный сайт о технике». Мы стараемся писать живо, с юмором и понятно, без лишней зауми, доступной только посвящённым. С чего начиналась история gagadget.com? Почему Вы решили создать проект, посвященный именно технике?

Мы решили создать сайт о технике, потому что это именно то, о чём мы умеем хорошо писать. Я писал в техническую прессу с 2000 года, а Сергей Митяев (читателям нашего сайта он известен под псевдонимом Технослав Бергамот) — основатель и первый главный редактор журнала «СОТА». Мысли о создании своего интернет­проекта меня начали посещать примерно в середине 2007 года, поскольку мне надоела характерная для большинства журналов ситуация, когда редакционной политикой фактически управляет рекламный отдел. Мне хотелось создать по­настоящему независимый ресурс. Примерное такие же мысли были и у Сергея. Когда он в декабре 2007 года пришёл ко мне с идеей совместно сделать сайт, у меня уже был готов прототип будущего gagadget'а. Ваш сайт постоянно обновляется. Наверное, над проектом трудится целая команда журналистов?

Вовсе нет. Непосредственно материалами занимаются два человека — Сергей и я. Раньше мы делили все обязанности поровну, но затем решили, что я буду больше заниматься обзорами, а Сергей — новостями. Техническое сопровождение и продажа рекламы лежат на плечах наших партнёров из компании «Магнет». Сайтов с обзорами гаджетов не мало. Чем gagadget выгодно отличается от других?

Ваш сайт построен в стиле "блог". С чем связан выбор именно такого формата? По­ моему "портальный" стиль более отражает направление вашего проекта.

На самом деле для сайтов о технике такой формат не уникален. Достаточно вспомнить, что два самых популярных в мире сайта о гаджетах — Engadget и Gizmodo — работают именно в формате блога. Кроме того, блог подразумевает личный, авторский стиль подачи материалов, а это именно то, к чему мы стремились изначально. Как Вы успеваете столько делать? Ведение новостной ленты, тесты гаджетов, тусовка на форуме и т.д. Ощущение, что у вас в сутках минимум 48 часов.

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

vr­online | июнь 2010


10

VrIP персона

lifestyle или имиджевая фишка?

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

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

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

Поделитесь, пожалуйста, опытом, как вам удалось собрать такую неплохую аудиторию?

потом становятся постоянными читателями проекта. Сейчас в каждом нашем конкурсе принимают участие несколько сотен человек.

Вы посещаете зарубежные блоги/порталы о технике? Какие на ваш взгляд наиболее успешные из них?

Разумеется, посещаем. Engadget, Gizmodo, Electronista, Akihabara News, Digital Photography Review, Laptop Magazine — вот лишь некоторые из сайтов о технике, которые читаю лично я. Это очень успешные проекты, которые ежемесячно посещают миллионы человек. Как Вы относитесь к "бумажным" компьютерным изданиям? Читаете ли вы какие­нибудь журналы постоянно (бумажные)?

Лично я к ним отношусь хорошо, можно даже сказать — с теплом и ностальгией, поскольку отдал бумажной IT­журналистике 8 лет жизни. Но не могу сказать, чтобы мне было интересно читать какой­то бумажный журнал, поскольку сам формат заведомо накладывает множество ограничений, отсутствующих в интернете. Например, хороший обзор на сайте всегда будет подробнее хорошего обзора в журнале, поскольку на сайте просто нет ограничений по количеству знаков. То же самое с фотографиями: на сайте их будет столько, сколько необходимо, а не сколько помещается на полосу. На сайт можно поставить видео... Бумажные журналы лишены всех этих прелестей. Единственное их преимущество заключается в том, что журнал удобно читать в туалете.

Есть такая старая пословица — «терпение и Единственным исключением был журнал труд всё перетрут». Каких­то особых усилий «Компьютерра», который я читал регулярно вплоть до самой его смерти. по продвижению сайта мы никогда не прилагали, поскольку придерживаемся точки Как на Ваш взгляд изменится зрения, что хороший контент сам себя журналистика (в области it) в ближайшие раскручивает. Наша аудитория — это люди, пять лет? Смогут ли глянцевые журналы которым интересно читать наши тексты и мигрировать в формат "online"? которые собрались вокруг сайта за два с Я думаю, журналистика вообще и IT­ половиной года его существования. журналистика в частности будут двигаться У Вас на сайте частенько проводятся по пути повышения информативности и конкурсы. Какой эффект конкурсы приносят интерактивности. Видеоролики, трёхмерные проекту? Многие посетители решаются на модели устройств, которые можно крутить и участие? рассматривать со всех сторон — всё это Эффектов на самом деле много. Во­первых, будет внедряться ускоренными темпами. Или, скажем, сайт DPReview недавно сделал имиджевый — у нас постепенно в своих обзорах фотоаппаратов новую складывается репутация ресурса, который «фишку» — теперь вы можете напрямую регулярно разыгрывает дорогие подарки. Во­ сравнить качество снимков того аппарата, о вторых, это укрепляет лояльность котором читаете, с любой моделью из их посетителей. В­третьих, конкурсы приводят базы данных. Это не журналистика в чистом новых посетителей, некоторые из которых виде, но это путь в будущее. vr­online | июнь 2010


11

VrIP персона

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

Безусловно, затронул. В какой­то степени он даже ускорил развитие gagadget'а, поскольку IT­журналы в Украине стали закрываться один за другим и компании начали рассматривать нас как полноценное СМИ. Опять же, рекламодатели начали считать деньги, после чего выяснилось, что реклама в специализированной прессе стоит достаточно дорого, а измерить полученный от неё эффект очень сложно. Интернет­ реклама в этом смысле надёжнее, поскольку она дешевле и в ней всё подлежит учёту (количество показов, количество переходов, CTR и так далее). Сегодня очень "модным" стал подкастинг. Планируете ли Вы запуск своей подкаст ленты? Ваше отношение к подкастам?

У нас был подкаст, который мы закрыли после нескольких «пилотных» выпусков. Причина проста: у нас нет ресурсов на то, чтобы делать его хорошо, а делать плохо мы не хотим. К тому же, на мой взгляд, подкасты — это тупиковый путь, в отличие от того же видео. В наших странах отсутствует модель потребления аудиоконтента. В метро, например, подкаст не послушаешь, поскольку мешает грохот поезда. Во время работы тоже не послушаешь, потому что чужая болтовня отвлекает от работы. Остаётся слушать подкасты целенаправленно, но это занимает много времени: например, подкаст Mobile­Review обычно длится около полутора часов. Получается, что единственная целевая аудитория подкастов — это люди, которые ездят на машине и по два часа в день стоят в пробках. А в США подкасты прижились, потому что там 80% населения с 18 лет за рулём.

Какие Ваши планы на будущее? Что планируете усовершенствовать/внедрить на gagadget?

Сейчас мы работаем над каталогом устройств / сервисом сравнения цен — http://bb.gagadget.com/. В будущем планируем более активно развивать видеонаправление, работать над повышением интерактивности наших обзоров.

Чтобы Вы хотели пожелать тем, кто решится на создание интернет­проекта? Что стоит/чего не стоит делать?

В первую очередь, не стоит рассчитывать на то, что сайт сразу же превратится в курицу, несущую золотые яйца. Поддержание на плаву интернет­проекта — это постоянный тяжёлый труд. Сейчас я работаю больше, чем когда­либо в жизни. И это справедливо для любого бизнеса, который надо поднимать с нуля. И, конечно же, стоит сразу же реалистично оценить, сколько времени вы сможете уделять проекту. Если этого времени окажется немного — не стоит даже пробовать. Многих наших читателей интересует тема заработка на сайте. А на чем зарабатывает gagadget? Лишь на продаже рекламы?

Мы сразу же отказались от такого сомнительного способа заработка, как продажа ссылок (напрямую или через биржи). Сейчас мы зарабатываем в первую очередь на продаже рекламы, во вторую — на предоставлении различного рода информационных услуг производителям. Например, сейчас у нас идёт проект, посвящённый Nokia N900 и мобильной операционной системе Maemo, и под этот проект нам удалось получить небольшой бюджет. "Хорошая статья" для Вас это ­ ...

Это текст, который ставит вопросы и отвечает на них.

Как Вы относитесь к "копипастерам"? Боретесь?

Английский писатель Чарлз Колтон, известный своими афоризмами, однажды сказал: «Копирование — самая искренняя форма лести». Если нас копируют, значит, мы всё делаем правильно. В какой­то степени копипастеры даже оказывают нам услугу, поскольку люди видят наши водяные знаки на фотографиях и идут на сайт напрямую. Вы читаете какие­нибудь ресурсы для журналистов? Если да, то, какие? На регулярной основе читаю только украинский сайт «Телекритика».

vr­online | июнь 2010


12

VrIP персона Если не ошибаюсь, то Ваш сайт работает на Drupal. Почему выбрали именно эту CMS?

Изначально я думал использовать очень удобный движок блога e2, тем более что у меня хорошие отношения с его создателем Ильёй Бирманом. Потом стало понятно, что мы делаем не просто блог, и возможностей e2 стало не хватать. Выбор пал на Drupal, поскольку эта CMS хорошо себя зарекомендовала, для неё написано множество модулей на все случаи жизни, вокруг неё существует активное и доброжелательное сообщество. Ну и самое главное — у меня был знакомый, хорошо разбирающийся в Drupal, которому в случае чего можно было задавать вопросы. В целом мы довольны выбором. На начальном этапе у нас было несколько проблем, но все они были вызваны моими кривыми руками, а не недостатками CMS. Ну и напоследок, чтобы Вы хотели пожелать нашим читателям?

В первую очередь — профессиональных успехов.

vr­online | июнь 2010


Перевод: Александр Алексеев aka Gunsmoker www.transl­gunsmoker.ru

13

Кодинг

Delphi

Работа с указателями Находим правильный подход к указателям

Pointers are like jumps, leading wildly from one part of the data structure to another. Their introduction into high­level languages has been a step backwards from which we may never recover. — Charles Hoare

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

Но указатели очень важны. Даже в языках, кото­ рые явно не поддерживают указатели, или в кото­ рых использование указателей затруднено, указатели являются важными факторами "под ка­ потом" языка. Я считаю, что для программиста понимание указателей является весьма важной вещью. Существует несколько подходов к пони­ манию указателей.

бо опишу компьютерную память (Подробное описание компьютерной памяти вы можете про­ читать в цикле статей Марка Руссиновича "Pushing the Limits of Windows" ­ прим. перевод­ чика).

Кратко говоря, компьютерная память может рассматриваться как один очень­очень длинный ряд байтов. Байт ­ это единица измерения коли­ чества информации, в стандартном виде байт считается равным восьми битам и может хра­ нить одно из 256 различных значений (от 0 до 255). В текущей 32­х битной версии Delphi на па­ мять можно смотреть (за редкими исключения­ Эта статья была написана для тех, у кого есть ми) как на массив байт максимальным размером проблемы с пониманием или использованием в 2 Гб (2^31 байт). Что именно содержат эти указателей. Она демонстрирует мою точку зре­ байты ­ зависит от того, как интерпретировать их ния на указатели в Delphi для Win32. Может содержимое, т.е. от того, как их используют. Зна­ быть, это не будет абсолютно точно во всех ас­ чение 97 может означать число 97, или же букву пектах (например, память программы не являет­ 'a'. Если вы рассматриваете вместе несколько ся одним большим монолитным блоком), но байт, то вы можете хранить и большие значения. этого более чем достаточно для практических це­ Например, в 2­х байтах вы можете хранить одно лей. По­моему, таким образом указатели будет из 256*256 = 65536 различных значений и т.д. проще понять. Чтобы обратиться к конкретному байту в памяти Содержание: (адресовать его), можно присвоить каждому ­ Память (Memory) байту номер, пронумеровав их числами от 0 и до 2147483647 (в предположении, что у вас есть 2 ­ Переменные (Variables) Гб — а даже если у вас их нет, то Windows попы­ ­ Указатели (Pointers) тается сделать так, чтобы вам казалось, что они ­ Плохие указатели у вас есть). Индекс байта в этом огромном мас­ ­ Арифметика указателей и массивы сиве и называется его адресом. ­ Ссылки (References) Кто­то может сказать: байт ­ это наименьший ку­ ­ Структуры данных сок памяти, который можно адресовать. ­ Заключение В действительности, память устроена сложнее. Память (Memory) Например, существуют компьютеры, байт в кото­ рых не равен 8­ми битам, что означает, что они Скорей всего, вы и так уже знаете, что я собира­ могут содержать больше или меньше 256 значе­ юсь написать в этом параграфе, но, наверное, ний. Впрочем, для тех машин, на которых рабо­ прочитать его будет не лишним, т.к. он демонстри­ тает Delphi для Win32, байт всегда равен 8­ми рует моё видение вещей, которое может отли­ битам. Память управляется и железом и про­ чаться от вашего. граммами, так что не вся видимая вам память Указатели ­ это переменные, которые указывают может существовать (менеджеры памяти скры­ вают это от вас, выгружая память частями на на другие переменные. Чтобы объяснить это, жёсткий диск), но для целей этой статьи мы мо­ необходимо понять концепцию адреса памяти и концепцию переменной. Для этого я сначала гру­ жем смотреть на память как на один большой

vr­online | июнь 2010


14

Кодинг

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

Переменные (Variables)

Переменная ­ это место из одного или несколь­ ких байт в этом гигантском "массиве", из которого (места) вы можете читать или писать. Это место идентифицируется по имени, но также характери­ зуется своим типом, значением и адресом. Когда вы объявляете переменную, компилятор резервирует кусо­ чек памяти подходящего размера. Где именно будет лежать эта переменная ­ определяется компилятором и средой времени вы­ полнения. Вы никогда не должны делать предположения о возмож­ ном точном месте переменной в запущенной программе.

Тип переменной определяет, как будет использо­ ваться место в памяти. Тип определяет размер, т.е. сколько байт занимает место в памяти, а так­ же структуру памяти. Например, на следующей диаграмме показан кусок памяти в 4 байта, начи­ нающихся по адресу $00012344. Байты содержат значения $4D, $65, $6D и $00, соответственно.

подпрограммы. Поля объекта (которые тоже переменные) также доступны только пока объект "существует". Если вы объявляете переменную, компилятор резервирует требуемое количество байт для этой переменной. Но содержание памяти для этих переменных может быть байтами, которые лежали там при вызове другой функции или про­ цедуры. Другими словами, значение неинициа­ лизированной переменной (т.е. переменной, которой вы ещё не присвоили значения) неопре­ делено (но не обязательно неопределяемо в принципе). Простой пример в виде консольной программы демонстрирует это: program uninitializedVar; {$APPTYPE CONSOLE} procedure Test; var A: Integer; begin Writeln(A); // ещё не инициализирована A := 12345; Writeln(A); // инициализирована: 12345 end; begin Test; Readln; end.

Заметьте, что хотя я использовал адрес типа $00012344, в большинстве диаграмм это просто числа, взятые "от балды", которые просто помога­ ют отличить одно место в памяти от другого. Они не отражают настоящие адреса памяти, т.к. эти адреса зависят от множества факторов и их не­ льзя предсказать заранее. Тип определяет, как используются эти байты. Например, это может быть число типа Integer со значением 7169357 (что есть $006D654D), или же массив символов array[0..3] of AnsiChar, фор­ мирующий C­строку (т.е. PChar) 'Mem', или что­то совершенно иное, как множество, массив из отдельных байт, небольшая запись, Single, часть Double и т.д... Другими словами, смысл куска па­ мяти переменной не известен, если только вы не знаете, какого типа (или типов) эта переменная (или переменные). Адрес переменной ­ это адрес первого байта ме­ ста хранения. Например, в диаграмме выше, в предположении, что у нас переменная типа Integer, её адрес будет $00012344.

Неинициализированные переменные

Память для переменных может использоваться многократно. Память для переменных обычно ре­ зервируется только на время, пока программа мо­ жет обращаться к ним. Т.е. локальные переменные в процедуре или функции (я буду на­ зывать их одним словом: "подпрограммы") до­ ступны только в то время, пока выполняется код

Первое отображаемое значение (значение неинициализированной переменной A) зависит от уже существующего содержания памяти, за­ резервированной под A. В моём случае каждый раз значение было 2147319808 ($7FFD8000), но это число может быть совершенно другим на ва­ шей машине. Значение не определено, потому что переменная не была инициализирована. В более сложных программах, особенно (но не только) с участием указателей, это частая причи­ на для вылета программы или вывода неверных результатов. Присваивание инициализирует переменную A значением 12345 ($00003039), что и будет вторым выведенным значением.

Указатели (Pointers)

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

Например, пусть у нас есть следующие объявле­ ния и инициализация: var I: Integer; J: Integer; C: Char; begin I := 4222; J := 1357; C := 'A';

vr­online | июнь 2010


15

Кодинг

Предположим, что это дало нам такую компонов­ ку памяти:

Теперь, после выполнения этого кода (предпола­ гая что P ­ это указатель): P := @I;

Мы получаем:

означает пустой указатель (nil ­ это сокращение от Лат. nihil, что означает ничего или ноль; кое­ кто расшифровывает NIL как аббревиатуру от Not In List ­ не в списке). Это означает, что указа­ тель был определён (инициализирован, присво­ ен), но вы не должны пытаться получить значение, на которое он указывает (в языке C, nil называется NULL — см. цитату в начале секции).

Nil никогда не указывает на допустимую память, но т.к. это вполне конкретное значение, то под­ программы могут сравнивать указатели с этим значением (например, используя функцию Assigned()). Нельзя проверить, является ли лю­ бое другое (не­nil) значение указателя допусти­ мым. Мусорный или неинициализированный указатель ничем не отличается от допустимого указателя (см. ниже). Не существует способа их отличать друг от друга. Программная логика все­ гда должна гарантировать, что указатель либо допустим, либо равен nil (фича "Pushing the Limits of Windows") (Ещё одна причина для по­ всеместного использования FreeAndNil (http://gunsmoker.blogspot.com/2009/04/freeandnil­ free.html ) ­ прим. переводчика).

В Delphi, nil имеет значение 0 (прим. пер.: т.е. nil = Pointer(0) или 0 = Integer(nil)) ­ т.е. он указывает на самый первый байт в памяти. Очевидно, что этот байт никогда не будет доступен для Delphi кода. Но обычно вы не должны рассчитывать на то, что указатель nil будет равен 0, если только вы точно не знаете, что вы делаете. Числовое значение nil может быть изменено в следующих версиях Delphi по какой­то причине (Хотя это и чертовски маловероятно. Писать код без такого предположения довольно тяжело, т.к. получает­ ся, что (к примеру) после ZeroMemory мы не по­ лучаем nil ­ прим. переводчика).

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

Типизированные указатели

В простом примере выше P имеет тип Pointer. Это означает, что P содержит адрес, но вы не знаете, переменная какого типа лежит по этому адреса. Вот почему обычно используются типи­ зированные указатели, т.е. указатель интерпре­ тируется как указывающий на переменную (область памяти) определённого типа. Предположим, что у нас есть ещё один указа­ тель, Q:

Эта диаграмма более не показывает настоящих размеров (C выглядит так же, как и I или J), но этого достаточно, чтобы продемонстрировать, что происходит с указателями.

Nil

Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end. — Henry Spencer

Nil ­ это специальное значение указателя. Оно может быть присвоено любому указателю. nil

var Q: ^Integer;

Q типа ^Integer, что читается как "указатель на Integer" (мне сказали, что ^Integer расшифровы­ вается как ^Integer). Это означает, что Q ­ это не Integer, но вместо этого указывает на память, ко­ торая может быть использована как Integer. Если вы присвоите адрес J в Q, используя оператор взятия адреса @ или эквивалентную функцио­ нальность псевдо­функции Addr, то тогда Q бу­ дет указывать на место по адресу $00012348 (Q vr­online | июнь 2010


16

Кодинг

ссылается (references) на место памяти, занимае­ объявить новый тип: мое J). Но поскольку Q является типизирован­ type ным указателем, то компилятор будет трактовать PInteger = ^Integer; память, на которую указывает Q, как число типа Integer. Integer является базовым типом Q. Q := @J; // Q := Addr(J);

Хотя вы навряд­ли увидите псевдо­функцию Addr в реальном коде, она полностью эквивалентна @. Однако у @ есть недостаток: если его приме­ нять к сложному выражению, то не всегда ясно, указатель чего берётся. Addr же, используя син­ таксис функции, получается намного более чита­ бельным, поскольку целевое выражение заключается в скобки: P := @PMyRec^.Integers^[6]; Q := Addr(PMyRec^.Integers^[6]);

Прим. пер.: поэтому неплохо использовать скоб­ ки вместе с @, хотя это и не обязательно: P := @(PMyRec^.Integers^[6]);

Присваивание с использованием указателей происходит немного иначе, чем при прямом при­ своении переменной. Обычно для работы у вас будет только указатель. Если вы присваиваете значение обычной переменной, вы пишите что­то вроде: J := 98765;

Это записывает число 98765 ($000181CD) в ме­ сто памяти, занимаемое переменной J. Но чтобы получить доступ к этой памяти через указатель Q, вы должны работать косвенно, используя опе­ ратор ^: Q^ := 98765;

Это называется разыменованием указателя. Вы должны следовать по воображаемой "стрелочке" до места, на которое указывает Q (другими сло­ вами, до Integer по адресу $00012348) и сохра­ нить там значение.

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

procedure Abracadabra(I: PInteger);

Фактически, тип PInteger и некоторые другие ча­ сто используемые типы уже определены в биб­ лиотеке Delphi (модули System, SysUtils и Types). Начинать имя типов указателей с заглавной бук­ вы P и следующим за ней именем типа, на пере­ менную которого указывает указатель, является традицией, рекомендованной к выполнению. Если базовый тип указателя начинается с за­ главной T, то T обычно опускается. Например: type PByte = ^Byte; PDouble = ^Double; PRect = ^TRect; PPoint = ^TPoint;

Анонимные переменные

(прим. пер.: не путать с захваченными перемен­ ными в анонимных методах)

В предыдущих примерах переменные объявля­ лись только там, где они были необходимы. Ино­ гда вы не знаете, понадобиться ли вам переменная или как много переменных. Исполь­ зуя указатели, вы можете создавать так называе­ мые анонимные переменные. Вы можете попросить библиотеку языка выделить вам кусок памяти и вернуть указатель на него, используя псевдо­функцию New(): var PI: PInteger; begin New(PI);

New() ­ это псевдо­функция компилятора. Она резервирует память для базового типа PI и запи­ сывает адрес на эту память в указатель PI. У самой переменной здесь нет имени (т.е. она ано­ нимная) ­ имя есть только у указателя на пере­ менную. Получить доступ к такой переменной можно только используя указатель. Теперь вы можете присваивать ей значения, передавать её в подпрограммы, избавиться от неё, когда она станет вам не нужна, используя вызов Dispose(PI): PI^ := 12345; ListBox1.Add(IntToStr(PI^)); // куча кода Dispose(PI); end; end;

Вместо использования New и Dispose, вы може­ те спуститься на уровень пониже и использовать Обычно полезно определять типы для используе­ GetMem и FreeMem. Но подпрограммы New и мых в программе указателей. Например, вы не Dispose имеют несколько преимуществ: они можете использовать ^Integer при указании типа осведомлены о типе указателя (прим. пер.: параметра подпрограммы, так что вам придётся поэтому автоматически определяют размер па­

vr­online | июнь 2010


17

Кодинг

мяти), а также инициализируют и освобождают содержимое участка памяти, если это необходи­ мо. Так что рекомендуется всегда использовать New и Dispose, вместо GetMem и FreeMem, там, где это возможно.

са были придуманы мной):

Всегда гарантируйте, что каждый вызов New() бу­ дет иметь пару в виде вызова Dispose() с тем же самым значением и типом указателя, в против­ ном случае память может быть освобождена не­ верно или не до конца.

PC указывает на ту же самую память (поскольку базовые типы указателей несовместимы, вы не Сейчас может быть не очевидно, чем же это луч­ можете просто так присвоить один указатель ше, чем объявлять переменную явно, но бывают другому — вам нужно использовать преобразо­ ситуации, когда это полезно, обычно, если вы не вание типов). Но PC является указателем на знаете, как много переменных вам понадобиться. AnsiChar, так что если вы берёте PC^, то вы по­ Подумайте об узлах в связанном списке (см. ни­ лучаете AnsiChar ­ один символ с ASCII значени­ же) или о TList­е. TList хранит указатели, и если ем $4D или 'M'. вы хотите иметь список значений Double, то вы просто вызываете New() для каждого значения и Вообще­то, PC ­ это особый случай, поскольку храните его в TList: тип PAnsiChar, хотя он формально указывает на символ AnsiChar, трактуется специальным об­ var разом, немного иначе, чем остальные типы ука­ P: PDouble; зателей. PC, если он не разыменовывается, begin обычно трактуется как указатель на текст, закан­ while HasValues(SomeThing) do чивающийся нулевым символом #0, поэтому begin Writeln(PC) покажет текст, сформированный New(P); байтами $4D $65 $6D $00, т.е. 'Mem'. P^ := ReadValue(SomeThing); MyList.Add(P); // и т.д...

Конечно же, вам нужно будет потом вызывать Dispose() для каждого значения, когда список не будет больше нужен.

Используя анонимные переменные, легко пока­ зать, что типизированные указатели могут опре­ делять, как используется память. Два указателя разных типов, указывающие на одно и то же ме­ сто в памяти, будут показывать разные значения: program InterpretMem; {$APPTYPE CONSOLE} var PI: PInteger; PC: PAnsiChar; begin New(PI); PI^ := $006D654D; // Байты $4D $65 $6D $00 PC := PAnsiChar(PI); // Теперь оба указателя указывают //на одно место в памяти Writeln(PI^);// Печатаем число. Writeln(PC^);// Печатаем один символ ($4D). Writeln(PC);// Печатаем строку в //стиле C (байты $4D $65 $6D $00 //интерпретируются как PChar) Dispose(PI); Readln; end.

PI заполняет память значением $006D654D (7169357). На диаграмме (напомню, что все адре­

Когда мне нужно подумать об указателях, и осо­ бенно о сложных ситуациях с ними, я обычно бе­ ру бумажку и ручку и рисую диаграммки типа тех, что вы видели выше. Я также даю переменным выдуманные адреса, если это нужно (не обяза­ тельно использовать все 32 бита, адреса типа 30000, 40000, 40004, 40008 и 50000 тоже вполне подойдут).

Плохие указатели

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

Неинициализированные указатели

Указатели являются переменными, и как любые другие переменные они должны быть инициали­ зированы перед использованием, либо присваи­ ванием им другого указателя, либо используя подпрограммы типа New или GetMem, например: var P1: PInteger; P2: PInteger; P3: PInteger; I: Integer; begin I := 0; P1 := @I; // OK: используя оператор @ P2 := P1; // OK: присвоением другого указателя New(P3); // OK: New

vr­online | июнь 2010


18

Кодинг

Третья, похожая проблема, ­ это указание на не­ постоянные (volatile) данные, т.е. данные, кото­ рые могут исчезнуть в любой момент. Например, Если вы просто объявите, скажем, указатель ти­ па PInteger, но не проинициализируете его, то ука­ частой грубой ошибкой является функция, воз­ вращающая указатель на свои локальные пере­ затель, вероятно, будет содержать какие­то случайные байты, т.е. он фактически будет указы­ менные. Ведь как только мы выходим из подпрограммы, её локальные данные больше не вать на случайное место в памяти. существуют, а возвращённый вызывающей сто­ Если вы попробуете получить доступ к памяти по роне указатель оказывается указывающим в ни­ такому указателю, будут происходить плохие ве­ куда. Классический пример: щи. Если эта память не будет зарезервирована function VersionData: PChar; вашим приложением, то вы получите исключение var Access Violation ­ вылет программы (program V: array[0..11] of Char; crash). Но если эта память будет частью вашей begin программы, то вы можете переписать данные, ко­ CalculateVersion(V); торые не должны меняться. Если эти данные ис­ Result := V; пользуются в другой части вашей программы, то end; чуть позже, получаемые результаты выполнения вашей программы будут ошибочны. Такие ошиб­ V будет помещена в процессорном стеке. Это специальная часть памяти, которая использует­ ки чрезвычайно тяжело искать. ся для хранения локальных переменных и пара­ Поэтому, если вы вдруг увидели сообщение об метров вызываемых процедур, а также содержит ошибке типа Access Violation или другое сообще­ важные данные типа адресов возврата для каж­ ние об очевидном вылете (типа Invalid Pointer), дой вызванной подпрограммы. Результат функ­ вы, на самом деле, должны быть благодарны (ну ции указывает на V (PChar может указывать если только эта ошибка не испортила ваш прямо на массив ­ с��. статью, что я упоминал). жёсткий диск ;) . Ваша программа вылетела, да, Как только VersionData завершает выполнение, это плохо, но такие ошибки хотя бы легко отлажи­ стек изменяется следующей вызванной подпро­ вать и исправлять. Но если ваша программа про­ граммой, так что данные, вычисленные в сто втихую выводит неправильные данные, CalculateVersion оказываются перезаписанными, проблема может быть намного хуже, и вы даже а указатель указывает на это новое содержимое можете не заметить её, пока не станет слишком по всё тому же старому адресу. поздно. Вот почему вы должны использовать ука­ Похожая проблема: указывание PChar на строку затели с особым вниманием. Всегда дотошно проверяйте код на неинициализированные указа­ String, но это также обсуждалось в статье про PChar. Или использование указателя на элемент тели. динамического массива (динамические массивы Мусорные указатели могут перемещаться по памяти, если их размер Мусорные указатели (stale pointers) ­ это указате­ меняется вызовами SetLength) ­ вместо этого на­ до использовать просто индекс. ли, которые когда­то были допустимыми, но те­ Dispose(P3); end;

перь уже нет. Это может произойти, если память, на которую указывает указатель, была освобо­ ждена и/или повторно использована.

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

Использование неверного базового типа

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

Но вы также можете что­то ошибочно записать или прочитать. Например, если вы получаете до­ ступ к месту, которое хранит только Byte, с помо­ щью указателя на Integer, вы можете записать 4 Другая частая ошибка: иметь более чем один ука­ байта, среди которых только 1 байт является до­ затель на один и тот же кусок памяти. Вы можете пустимым, а остальные три ­ просто смежные с освободить память по одному указателю и даже ним, поскольку компилятор будет трактовать эти об­nil­ить его, но другой указатель всё также бу­ 4 байта подряд, как одно число типа Integer. Так­ дет содержать старое значение, указывающее на же, если вы читаете что­то с места расположе­ уже освобождённую память. Если вам повезёт, ния байта, вы можете прочитать слишком много: вы получите ошибку типа "Access Violation" или var "Invalid pointer", но реальное поведение часто PI: PInteger; неопределено.

vr­online | июнь 2010


19

Кодинг I, J: Integer; B: Byte; begin PI := PInteger(@B); I := PI^; J := B;

J будет иметь правильное значение, потому что компилятор добавит код расширения одного байта до (4­х байтового) Integer с помощью обну­ ления старшей части Integer­а. Но I не будет иметь верного значения. Она будет содержать наш байт и ещё 3 каких­то байта, которые следу­ ют за B, формируя этим некоторое неопределён­ ное (мусорное) значение.

var bitdata: array of Byte; pbBitmap: Pointer; begin SetLength(bitdata, nBufSize); GetMem(pbBitmap, nBufSize); pbBitmap := Addr(bitdata); VbMediaGetCurrentFrame(VBDev, @bmpinfo.bmiHeader, @pbBitmap, nBufSize);

Ну, вообще­то этот код делает несколько стран­ ных вещей. SetLength выделяет байты для bitdata. По какой­то причине программист потом использует GetMem для выделения такого же ко­ личества байт для pbBitmap. Но затем он не­ Указатели также позволяют вам установить значе­ медленно присваивает pbBitmap другой адрес, ние переменной без присваивания его самой что приводит к тому, что только что выделенная переменной. Это может сильно огорчать вас во GetMem­ом память становится недоступной лю­ время отладки. Вы знаете, что переменная содер­ бому коду (единственным способом добраться жит неверное значение, но не можете увидеть в до неё была pbBitmap, но он больше на неё не коде, где же это значение было присвоено, пото­ указывает). Другими словами, у нас есть утечка му что значение было установлено через указа­ памяти. тель (прим. пер.: для этого могут использоваться Фактически тут есть и другие ошибки. bitdata ­ точки останова на память). это динамический массив, и взятие адреса Владельцы и забытая память (Owners and bitdata берёт адрес указателя на данные масси­ orphans) ва, вместо адреса самих данных (см. ниже, ди­ намические массивы). Также, поскольку Указатели не только могут иметь различные базо­ pbBitmap уже является указателем, неправильно вые типы, но и различную семантику владения. использовать на него оператор @. Если вы выделяете память, используя New или GetMem или любую другую более специализиро­ Более правильный код выглядел бы так: ванную подпрограмму, вы являетесь владельцем var этой памяти. Лучше всего, если вы будете дер­ bitdata: array of Byte; pbBitmap: Pointer; жаться за эту память, заныкав указатель на неё в begin надёжное место. Указатель ­ это ваш единствен­ if nBufSize > 0 then ный способ получить доступ к этой памяти, и begin если он будет утерян ­ вы не сможете ни прочи­ SetLength(bitdata, nBufSize); тать данные, ни освободить их. Одно из общих pbBitmap := Addr(bitdata[0]); правил: тот, кто выделяет память, обязан её и VbMediaGetCurrentFrame(VBDev, @bmpinfo.bmiHeader, освободить, так что это ваша обязанность. Хоро­ pbBitmap, nBufSize); шо спроектированные программы всегда следу­ end; ют этому правилу. Или даже так: Понять правила владения очень важно. Кто вла­ var деет памятью ­ тот её и освобождает. Вы можете bitdata: array of Byte; делегировать (передать) эту задачу кому­то ещё, begin но вы должны убедиться, что задача будет выпол­ if nBufSize > 0 then begin нена верно. Частая ошибка: использовать указатель для вы­ деления памяти, а затем снова использовать этот же указатель для выделения другой памяти или присвоить ему другой указатель. Указатель, который содержал адрес старого выделенного блока памяти, начинает указывать на новый блок памяти, а старый адрес оказывается потерян на­ всегда. Не существует никакого разумного спосо­ ба получить местоположение первого выделенного блока памяти. Память оказывается забыта. Никто не может получить к ней доступ и никто не может её очистить. Это приводит к об­ разованию так называемых утечек памяти. Вот простой пример, взятый (с разрешения авто­ ра) из групп обсуждений Borland:

SetLength(bitdata, nBufSize); VbMediaGetCurrentFrame(VBDev, @bmpinfo.bmiHeader, @bitdata[0], nBufSize); end;

Это может показаться тривиальной проблемой, но в более сложном коде легко допустить подоб­ ную ошибку.

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

vr­online | июнь 2010


20

Кодинг

бождении памяти.

Арифметика указателей и массивы You can either have software quality or you can have pointer arithmetic, but you cannot have both at the same time. — Bertrand Meyer

Delphi позволяет производить над указателями несколько простых действий. Во­первых, конечно же, вы можете присваивать им значения и срав­ нивать их на равенство (if P1 = P2 then) или нера­ венство. Но вы также можете увеличивать или уменьшать их, используя псевдо­функции Inc и Dec. Приятным моментом при этом является то, что эти функции учитывают размер базового ти­ па указателя. Пример (заметьте, что я руками присвоил указателю фальшивый адрес. Пока я не попытаюсь получить по нему доступ, всё бу­ дет в порядке): program PointerArithmetic; {$APPTYPE CONSOLE} uses SysUtils; procedure WritePointer(P: PDouble); begin Writeln(Format('%8p', [Integer(P)])); end; var P: PDouble; begin P := Pointer($50000); WritePointer(P); Inc(P); WritePointer(P); Inc(P, 6); WritePointer(P); Dec(P, 4); WritePointer(P); Readln; end.

Вывод программы: 50000 50008 50038 50018

Применение этого: это способ предоставить по­ следовательный доступ к элементам массивов. Поскольку (одномерные) массивы содержат по­ следовательные элементы одного типа (т.е. если элемент расположен по адресу N, тогда следую­ щий элемент расположен по адресу N + SizeOf(element)), то можно использовать этот сценарий для прохода по массиву в цикле (На самом деле, формально такой массив должен быть объявлен с ключевым словом "packed" ­ прим. переводчика). Вы начинаете с адреса пер­ вого элемента массива, что­то с ним делаете. На следующей итерации цикла вы увеличиваете ука­ затель, так что он начинает указывать на второй

элемент и т.д.:

program IterateArray; {$APPTYPE CONSOLE} var Fractions: packed array[1..8] of Double; I: Integer; PD: ^Double; begin // Заполняем массив случайными значениями Randomize; for I := Low(Fractions) to High(Fractions) do Fractions[I] := 100.0 * Random; // Получаем доступ через указатель PD := @Fractions[Low(Fractions)]; for I := Low(Fractions) to High(Fractions) do begin Write(PD^:9:5); Inc(PD); // Указываем на следующий элемент end; Writeln; // Обычный доступ по индексу for I := Low(Fractions) to High(Fractions) do Write(Fractions[I]:9:5); Writeln; Readln; end.

Увеличение указателя немного быстрее, чем умножение индекса на размер элемента и сум­ мирование с базовым адресом на каждой итера­ ции.

В реальности же, разница между обоими спосо­ бами незначительна, если вообще заметна. Во­ первых, у современных процессоров есть специ­ альные способы для адресования при типичных случаях использования индекса. Во­вторых, компилятор всё равно обычно оптимизирует ис­ пользование индекса в использование указате­ ля, если это возможно. А в примере выше, незначительная разница и вовсе съедается вы­ полнением такой сложной функции как Write().

Как вы можете видеть в примере выше, вы може­ те легко забыть увеличить указатель в цикле. И вы всё равно должны использовать либо цикл for­to­do, либо какой­то другой способ для орга­ низации цикла и условия выхода (с ручным сдви­ гом и сравнением). Код с использованием указателей обычно труднее поддерживать. И по­ скольку подход указателями ничуть не быстрее (ну за исключением очень маленьких циклов), я бы избегал подобного кода в Delphi. Делайте так только если вы прогнали программу под про­ файлером и считаете, что доступ с указателем действительно будет выигрышным.

Указатели на массивы

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

vr­online | июнь 2010


21

Кодинг

Dec. Пример:

type PIntegerArray = ^TIntegerArray; TIntegerArray = array[0..65535] of Integer; var Buffer: Pointer; // трактуется как packed array of Integer; PInt: PInteger; PArr: PIntegerArray; ... // С использованием арифметики указателей: PInt := Buffer; for I := 0 to Count ­ 1 do begin Writeln(PInt^); Inc(PInt); end; // Используя преобразование типа, указатель на массив и индексирование: PArr := PIntegerArray(Buffer); for I := 0 to Count ­ 1 do Writeln(PArr^[I]); ... end;

лять специальный тип PIntegerArray. Также вме­ сто PInt[I] можно использовать синтаксис (PInt + I)^, который приводит к тому же результату. Кажется, в Delphi 2009 новая арифметика указа­ телей не работает, как ожидается, для указа­ телей на обобщённые типы (generics). С каким бы параметрическим типом вы не инстанцииро­ вали тип, индексы не масштабируются на SizeOf(T), как это ожидается.

Ссылки (References)

Многие типы в Delphi фактически являются ука­ зателями, но притворяются простыми типами. Я называю такие типы ссылочными. Примерами таких типов являются динамические массивы, строки, объекты и интерфейсы. Все они являют­ ся указателями "под капотом" языка, но с некото­ рой дополнительной семантикой и часто со скрытым содержанием. * Динамические массивы (dynamic arrays) * Многомерные динамические массивы * Строки (Strings) Delphi 2009 * Объекты (Objects) В Delphi 2009 и выше арифметика указателей, по­ * Интерфейсы (Interfaces) мимо типа PChar (и PAnsiChar и PWideChar), так­ же применима и для других типов указателей. * Ссылочные параметры Где и когда это становится возможным ­ контроли­ * Нетипизированные параметры руется директивой компилятора Что отличает ссылки (references) от указателей $POINTERMATH. (pointers): По­умолчанию, арифметика указателей выключе­ * Ссылки неизменяемы. Вы не можете уве­ на, но она может быть включена для участка ко­ личить или уменьшить ссылку. Ссылки указыва­ да, используя директиву {$POINTERMATH ON}, и ют на определённые структуры, но никогда не указывают в середину них, как, например, указа­ выключена после него с помощью тели на данные массива в примерах выше. {$POINTERMATH OFF}. Директива также может * Ссылки не используют синтаксис указателей. применяться при объявлении типа указателя. Это скрывает тот факт, что они являются указа­ При этом арифметика с указателями будет до­ телями, и делает их сложнее для понимания для ступна для этого типа в любом коде без предва­ тех, кто не знаком с этой темой (и поэтому люди рительной обёртки в директивы $POINTERMATH. делают с ними вещи, которых делать нельзя). Помимо операций инкремента/декремента, но­ Не путайте такие ссылки со ссылочными типами вая арифметика указателей в Delphi 2009 также (reference types) в C++. Они во многом отличают­ допускает индексацию. ся. Сейчас, кроме типов PChar, PAnsiChar и PWideChar, единственным типом с поддержкой арифметики указателей по­умолчанию является PByte. Но вы можете включить её для любого ти­ па, как например, PInteger. Это значительно упро­ стит код из примера выше: {$POINTERMATH ON} var Buffer: Pointer; // трактуется как packed array of Integer; PInt: PInteger;

...

// С использованием новой арифметики указателей: PInt := Buffer; for I := 0 to Count ­ 1 do Writeln(PInt[I]); ... end; {$POINTERMATH OFF}

Так что теперь у нас нет необходимости объяв­

Динамические массивы (dynamic arrays)

До Delphi 4 в языке не было динамических мас­ сивов, но они существовали как концепция. Ди­ намический массив ­ это блок выделенной памяти, которая управляется через указатель. Динамические массивы могут расти или умень­ шаться. Фактически это означает, что выделяет­ ся новый блок памяти для массива новой длины, в то время как старая память ещё не отпускает­ ся. После чего содержимое старой памяти копи­ руется в новую, и старый блок памяти в конце удаляется, а указатель (ссылка) массива начина­ ет указывать на новый блок памяти. Динамические массивы (например, array of Integer) в Delphi работают точно так же. Но биб­ лиотека runtime добавляет специальный код, ко­ торый управляет доступом и присваиваниями. В

vr­online | июнь 2010


22

Кодинг

участке памяти ниже адреса, на который указыва­ ет ссылка массива, располагаются служебные данные массива: два поля ­ число выделенных элементов и счётчик ссылок (reference count).

Выше мы обсуждали одномерные динамические массивы. Но динамические массивы также могут быть и многомерными. Ну, по­крайней мере, с точки зрения синтаксиса, т.к. в действительности они ими не являются. Многомерный динамиче­ ский массив является, фактически, одномерным динамическим массивом, в котором каждый эле­ мент является ссылкой на другой одномерный динамический массив. Предположим, что у нас есть такие объявления: type TMultiIntegerArray = array of array of Integer; var MyIntegers: TMultiIntegerArray;

Если, как на диаграмме выше, N ­ это адрес в переменной динамического массива, то счётчик ссылок массива лежит по адресу N ­ 8, а число выделенных элементов (указатель длинны) ле­ жит по адресу N ­ 4. Первый элемент массива (са­ ми данные) лежит по адресу N.

Ну, это выглядит как многомерный динамический массив и, действительно, мы можем обращаться к нему как MyIntegers[0, 3]. Но на самом деле это объявление следует скорее читать как (тут я поз­ воляю себе некоторые вольности с синтакси­ сом): type TMultiIntegerArray = array of (array of Integer);

Для каждой добавляемой ссылки (т.е. при присва­ Или, чтобы сделать совсем явным, это фактиче­ ски означает следующее: ивании, передаче как параметр в подпрограмму type и т.п.) увеличивается счётчик ссылок, а для каж­ TSingleIntegerArray = array of Integer; дой удаляемой ссылки (т.е. когда переменная вы­ TMultiIntegerArray = array of TSingleIntegerArray; ходит из области видимости или при переприсваивании или присваивании nil) счётчик уменьшается. Как вы можете видеть, TMultiIntegerArray факти­ Доступ к данным динамических массивов с помо­ чески является одномерным массивом из указа­ телей TSingleIntegerArray. Это означает, что щью низко­уровневых процедур типа Move или FillChar, или любых других подпрограмм, получа­ данные TMultiIntegerArray не хранятся в одном ющих доступ сразу ко всему массиву, наподобие большом непрерывном участке памяти по стро­ кам и столбцам, но является, скорее, разорван­ TStream.Write, часто выполняется неправильно. ным массивом, т.е. каждый элемент ­ просто Для обычного массива (его часто называют так­ же статическим массивом ­ в противоположность указатель на другой массив, и каждый из этих под­массивов имеет свой размер. Так что вместо динамическому массиву) переменная массива тождественна его данным. Для динамического массива это не так (см. диагармму выше). Так что если вы хотите получить доступ к данным массива ­ вы не должны использовать саму пере­ менную массива, а использовать вместо неё пер­ вый элемент массива. var Items: array of Integer; ... // Неправильно: передаётся адрес переменной Items MyStream.Write(Items, Length(Items) * SizeOf(Integer)); ... // Правильно: передаётся адрес первого элемента MyStream.Write(Items[0], Length(Items) * SizeOf(Integer));

Заметьте, что в примере выше Stream.Write ис­ пользует нетипизированный var параметр, кото­ рый также является ссылочным типом. Мы ещё обсудим их ниже.

Многомерные динамические массивы

SetLength(MyIntegers, 10, 20);

(что создаст 10 TSingleIntegerArrays по 20 Integer в каждом ­ т.е. прямоугольный массив), вы може­ те получить доступ к любому из под­массивов и установить его длину индивидуально: SetLength(MyIntegers, 10); SetLength(MyIntegers[0], 40); SetLength(MyIntegers[1], 31); // и т.д...

Строки (Strings)

Should array indices start at 0 or 1? My compromise of 0.5 was rejected without, I thought, proper consideration. — Stan Kelly­Bootle

Строки во многом похожи на динамические мас­ сивы. Они также имеют счётчик ссылок, у них по­ хожая внутренняя структура (со счётчиком ссылок и указателем длинны ниже самих дан­ ных, по тем же смещениям).

vr­online | июнь 2010


23

Кодинг

Но есть и различия между ними в синтаксисе и семантике. Вы не можете присвоить строке nil ­ вместо этого вы присваиваете ей '' (пустую стро­ ку). Строки могут быть константами (со счётчи­ ком ссылок равным ­1, что является специальным указанием для библиотеки runtime: она не будет пытаться увеличивать или умень­ шать его или удалять строку). Первый элемент строки имеет индекс 1, в то время как в массиве это 0.

// т.д. и т.п. end; var Whatsit: TWhatsit; begin Whatsit := TWhatsit.Create;

Тогда раскладка объекта в памяти будет выгля­ деть примерно вот так:

Объекты (Objects)

Объекты ­ или, более точно, экземпляры классов (class instances) — не имеют автоматич��ского управления временем жизни. Их внутренняя структура проста. Каждый экземпляр класса со­ держит по смещению 0 (т.е. ровно по адресу, на который указывает ссылка переменной объекта) указатель на так называемую таблицу VMT. Она представляет собой таблицу с указателями на каждый виртуальный метод класса. По отрица­ тельным смещениям от начала таблицы лежит много другой полезной информации о классе. Я не буду вдаваться в подробности в этой статье. Для каждого класса есть только одна VMT табли­ ца (а не для каждого объекта!).

Классы, которые реализуют интерфейсы (см. ни­ же), также имеют похожие указатели на таблицы, которые содержат ссылки на методы, реализую­ щие интерфейс, по одному на каждый реализуе­ мый интерфейс. Эти таблицы также содержат некоторую информацию по отрицательным сме­ щениям. По каким смещениям в объекте распола­ гаются эти указатели ­ определяется структурой (полями) родительского класса. За этим следит компилятор. После указателей на VMT и все таблицы интер­ фейсов, идут обычные поля объекта, которые хранятся ровно как в записях (record).

Данные RTTI и другая информация о классах по­ лучаются следованием по ссылке переменной на данные объекта (которая также указывает на ука­ затель на таблицу VMT), а затем следованием по ссылке на VMT. Далее компилятор уже знает, где найти интересующие его данные, обычно через сложные структуры, содержащие указатели на другие структуры, иногда даже с рекурсивными ссылками. Ниже следует пример. Предположим, что у нас есть такое объявление: type TWhatsit = class(TAncestor, IPrintable, IEditable, IComparable) // другие поля и объявления методов procedure Notify(Aspect: TAspect); override; procedure Clear; override; procedure Edit; procedure ClearLine(Line: Integer); function Update(Region: Integer): Boolean; virtual;

Интерфейсы (Interfaces)

Интерфейсы, фактически, представляют собой просто коллекцию (набор) методов. Внутренне они представленны указателями на указатели на массив указателей на код. Представим, что у нас есть следующие объявления: type IEditable = interface procedure Edit; procedure ClearLine(Line: Integer); function Update(Region: Integer): Boolean; end;

TWhatsit = class(TAncestor, IPrintable, IEditable, IComparable) public procedure Notify(Aspect: TAspect); override; procedure Clear; override; procedure Edit; procedure ClearLine(Line: Integer); function Update(Region: Integer): Boolean; virtual; // etc... end; var MyEditable: IEditable; begin MyEditable := TWhatsit.Create;

Тогда отношения между интерфейсов, реализую­ щим его объектом и классом, а также методами будет выглядеть вот так:

vr­online | июнь 2010


24

Кодинг

Переменная MyEditable указывает на указатель IEditable в объекте, созданном TMyClass.Create. Заметим, что MyEditable не указывает на начало объекта, а куда­то в его середину. Далее, указа­ тель MyEditable в объекте указывает на таблицу указателей ­ по одному указателю на каждый ме­ тод в интерфейсе. Каждая из таких записей ука­ зывает на кусочек­кода: заглушку (stub). Этот служебный код корректирует указатель Self (кото­ рый к моменту вызова фактически равен MyEditable), чтобы он указывал на начало объек­ та, с помощью отнимания смещения указателя IEditable в объекте от переданного в код указате­ ля, а затем вызывает настоящий метод. Эта за­ глушка вводится для каждой реализации метода каждого интерфейса, реализуемого классом. Пример: предположим у нас есть экземпляр по адресу 50000, а указатель на реализацию IEditable классом TWhatsit лежит по смещению 16 в каждом экземпляре. Тогда переменная MyEditable будет содержать 50016. Указатель IEditable по адресу 50016 будет указывать на та­ блицу интерфейса для нашего класса (которая лежит, скажем, по адресу 30000), элементы кото­ рой указывают на заглушку (скажем, по адресу 60000). Заглушка увидит значение 50016 (кото­ рое передаётся ей как параметр Self), вычтет из него смещение 16 и получит 50000. Это и будет настоящий адрес реализующего интерфейс объекта. Затем заглушка вызывает настоящий метод, передавая ему 50000 в качестве парамет­ ра Self. В диаграмме я, для ясности, опустил заглушки для методов QueryInterface, _AddRef и _Release

Ну, теперь вы видите, почему иногда я люблю ис­ пользовать бумагу и ручку? ;­)

Ссылочные параметры

Ссылочные параметры часто называются var­па­ раметрами, а также out­параметрами или пара­ метрами, передаваемыми по ссылке.

значением, а не с указателем. * Ссылочные параметры не могут быть изме­ нены (имеется ввиду сам параметр, а не его зна­ чение). Использование имени параметра даёт вам значение параметра ­ вы не можете изме­ нить указатель или инкрементировать/декремен­ тировать его. * Вы должны передать что­то, что имеет адрес ­ т.е. реальную память, если только вы не ис­ пользуете трюк с приведением типов. Так что, имея ссылочный параметр типа Integer, вы не можете передать, например, 17, 98765 или Abs(MyInteger). Передаваемый параметр должен быть переменной (это включает в себя также элементы массива, поля записей и объектов и т.д.). * Фактические параметры обязаны быть того же типа, как и параметры в объявлении подпро­ граммы, т.е. вы не можете передать TEdit, если вы объявили параметр как TObject. Чтобы избе­ жать этого, вы можете использовать только нети­ пизированные ссылочные параметры (см. ниже). Прим. пер.: как это сделано в, например, FreeAndNil. Синтаксически, наверное, кажется, что проще использовать ссылочные параметры, чем явные указатели. Но вы должны быть в курсе некото­ рых особенностей. Чтобы передавать указатели, вы должны увеличить уровень косвенности на единичку. Другими словами, если у вас есть ука­ затель P на Integer, то чтобы передать его, вы должны синтаксически передавать P^ (хотя на деле будет передаваться сам P), например: procedure SetBit(var Int: Integer; Bit: Integer); begin ... end; ... var Int: Integer; Ptr: PInteger; Arr: array of Integer; begin // Инициализация Int, Ptr и Arr не показана... SetBit(Ptr^, 3); // Передаётся сам Ptr SetBit(Arr[2], 11); // Передаётся @Arr[2] SetBit(Int, 7); // Передаётся @Int

Ссылочные параметры ­ это такие параметры подпрограммы, для которых не само значение па­ раметра передаётся и/или возвращается из под­ Прим. пер.: на самом деле по ссылке также передаются почти любые типы, размер которых программы, а только указатель на него. Пример: больше SizeOf(Pointer), даже если вы не указали procedure SetBit(var Int: Integer; Bit: Integer); var или out. Например, запись из 8 байт будет begin передаваться по ссылке. Хотя с точки зрения Int := Int or (1 shl Bit); синтаксиса никаких указателей вы опять не уви­ end; дите (хотя без наличия модификатора const бу­ Это более или менее эквивалентно следующему: дет сделана локальная копия). Аналогично: если функция возвращает тип, размер которого procedure SetBit(Int: PInteger; Bit: Integer); больше SizeOf(Pointer), то на самом деле в begin функцию будет передан указатель на память, ку­ Int^ := Int^ or (1 shl Bit); да надо записать результат. Т.е. функция end; Хотя, тут есть несколько различий: * Вы не используете синтаксис указателей. Когда вы пишете имя параметра, вы автоматиче­ ски разыменовываете указатель, т.е. использова­ ние имени параметра означает работу со

type TRec = record A: Integer;

vr­online | июнь 2010


25

Кодинг B: Integer; end; function GetRec: TRec; begin Result.A := 1; Result.B := 2; end;

На самом деле трактуется как: procedure GetRec(out Result: TRec); begin Result.A := 1; Result.B := 2; end;

Или:

type PRec = ^TRec; procedure GetRec(Result: PRec); begin Result^.A := 1; Result^.B := 2; end;

Нетипизированные параметры

Нетипизированные параметры также являются ссылочными параметрами, но они могут быть ли­ бо var, либо const либо out. Вы можете переда­ вать в этот параметр любой тип данных, что делает эти виды параметров пригодными для на­ писания подпрограмм, которые принимают почти что угодно, любого размера и типа, но это также означает, что вы должны как­то указать подпро­ грамме на тип передаваемого аргумента ­ либо отдельным параметром, либо просто по соглаше­ нию, либо же тип параметра значения не имеет. Внутренне нетипизированные параметры тоже передаются как указатели на реальное значение параметра. Ниже идёт два примера. Первый из них ­ это общая подпрограмма для заполнения произвольного буфера набором байт, т.е. тип передаваемой переменной не имеет значения:

// Пример подпрограммы, для которой не важен тип пара­ метра procedure FillBytes(var Buffer; Count: Integer; Values: array of Byte); var P: PByte; I: Integer; LenValues: Integer; begin LenValues := Length(Values); if LenValues > 0 then begin P := @Buffer; // Считаем буфер массивом байт. I := 0; while Count > 0 do begin P^ := Values[I]; I := (I + 1) mod LenValues; Inc(P); Dec(Count); end; end; end;

Второй пример ­ это метод TIntegerList ­ дочер­ него класса для TTypedList: function TIntegerList.Add(const Value): Integer; begin Grow(1); Result := Count ­ 1; // FInternalArray: array of Integer; FInternalArray[Result] := Integer(Value); end;

Как вы можете видеть, чтобы использовать ука­ затель, вы должны явно взять адрес параметра, несмотря на тот факт, что фактически параметр внутренне уже является указателем. И опять­та­ ки: уровень косвенности сдвинут на единицу.

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

Я уже упоминал уровень косвенности (level of indirection). Вы уже видели это в действии. Например, если вы хотите инициализировать ди­ намический массив с помощью FillBytes, то вы не передаёте в FillBytes саму переменную массива, а только первый элемент массива. Фактически, вы также можете передать первый элемент ста­ тического массива для достижения такого же эф­ фекта. Таким образом, если вы передаёте любой массив в подпрограмму с нетипизирован­ ным ссылочным параметром, то, по моему мне­ нию, ваш лучший выбор ­ всегда передавать первый элемент массива, чтобы не зависеть от типа массива (динамический и��и статический) (тем более, что вы потом можете изменить объ­ явление ­ и попробуйте тогда найти ошибку в ко­ де).

Структуры данных

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

vr­online | июнь 2010


26

Кодинг

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

Заключение

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

vr­online | июнь 2010


Автор: StagnantIce

27

Кодинг

Java Script

Сжатие данных Алгоритм Хаффмана

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

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

К счастью не все файлы имеют равновероятностное содержимое и не все файлы не имеют повторяющихся предложений. Благодаря этому архиваторы могут сжимать файлы, и у нас ещё остается свободное место на диске для заветного фильма. Меня всегда интересовал вопрос, а как собственно эти архиваторы работают? Недолго думая, я познакомился с очень хорошим алгоритмом ­ алгоритмом Хаффмана. Этот алгоритм благодаря универсальности и оптимальности, применяется со всеми существующими алгоритмами сжатия. Даже популярный WinRar на последней стадии сжатия пользуется этим алгоритмом. Существует множество реализаций данного алгоритма. К сожалению я не нашел такой реализации на языке Java Script. Следует сказать, что толкнуло меня на написание такой реализации ­ сделать сжатие html страниц при помощи java script. Таким же образом можно было бы закодировать html странички. То есть каждый раз Java Script берёт из некого элемента закодированное и начинает при помощи document.write выводить все на экран. Зачем это

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

function numberToCode(n) { var ret = ''; for (i = 0; i < 8; i++) { ret = n % 2 + ret; n = Math.ceil((n ­ n % 2)/ 2); } return ret; }

Кодирует любое число в двоичную систему счисления. Для этого число делится восемь раз на 2. Остаток от деления прибавляется к возвращаемому результату. function codeToNumber(c) { var ret = 0; for (var i = 7; i >=0 ; i­­) { ret += Math.pow(2,i) * parseInt(c[7 ­ i]);

}

}

return ret;

Обратная функция. Складываем различные степени 2ки. А теперь функции кодирования строк.

function stringToCode(s) { var ret = ''; for (var i = 0; i < s.length; i++) ret += numberToCode(s.charCodeAt(i)); return ret; } function codeToString(s) { var ret = ''; for (var i = 0; i < s.length; i = i + 8) ret += String.fromCharCode(codeToNumber(s.substring(i, i + 8))); return ret; }

Первая получает строку в виде двоичной записи, vr­online | июнь 2010


28

Кодинг

для этого каждый символ преобразуется в число, затем это число преобразуется при помощи уже написанных функций в двоичную систему счисления. Вторая функция делает тоже самое, но наоборот. Теперь настала пора сказать пару слов о самом методе. Метод Хаффмана использует вероятность вхождения символов. Вероятность символа можно посчитать как количество вхождений этого символа в файл деленное на размер этого файла в байтах. Например, есть файл с содержимым: < html >< body >< /body >< /html >

{ }

function pack(s) //на входе то, что надо упаковать. { var ret = ''; var obj = {}; //наши символы for (var i = 0; i < s.length; i++) //Считаем вероятности, указываем что нет родителей. { if (obj[s[i]] == null) obj[s[i]] = {count:0, code:'', use:false}; obj[s[i]].count += 1; }

Вероятность вхождения символа 'h' ­ 1/14, '<' ­ 1/7

var c = true; for (var r in obj) // вершин не больше чем символов { var k1 = getMin(obj); //Ищем 1ый элемент if (k1 == '') break; obj[k1].use = true;

Алгоритм

На начальном этапе у нас есть объекты – символы. У каждого объекта есть свойства: код (строка, пустая в начале), свойство вероятность (число) и свойство boolean (имеет родителя или нет). В алгоритме мы строим дерево. Концы дерева ­ все символы, которые входят в файл хотя бы один раз. Начало дерева ­ набор из этих всех символов. Чем больше вероятность вхождения символа ­ тем короче будет путь по этому дереву к символу. 1) Находим два элемента с самой низкой вероятностью вхождения. Если есть только один, то его вероятность равна 1. Дерево построено, выходим. 2) Каждому простому потомку(концу дерева) этого элемента прибавляем код 1 для потомков 1го элемента, 0 для потомков второго элемента. Если нет потомков, то прибавляем код к самому этому элементу. На первом этапе у нас оба элемента ­ концы дерева. Первому мы присваиваем 1, второму 0. Когда мы будем рассматривать их вершину с ещё одним элементом, то мы к этим кодам прибавим снова разные номера. Таким образом, каждый путь по дереву к символу будет иметь уникальный код из 1 и 0. 3) Создаем новый элемент, состоящий из этих двух с вероятностью равной сумме вероятностей и не имеющий родителей входящих элементов. Чтобы не рассматривать более потомков этого элемента, приравниваем нулю их вероятность вхождения. Таким образом, один элемент остается всегда ­ сумма ранее двух рассмотренных. Теперь эти элементы имеют родителем новый элемент. Не забудем указать это в свойствах. 4) Перейдем к шагу 1. Функции: function getMax(obj) //Поиск символа с минимальной вероятностью. {

var max = 0; var kk = ''; for (var k in obj) if ((obj[k].count > max)&&(obj[k].use == true)) {min = obj[k].count; kk = k;} return kk; } function bool(b) //Преобразование boolean в строку

if (b) return '1'; else return '0';

var k2 = getMin(obj); //Ищем 2ой элемент if (k2 == '') break; obj[k2].use = true; for (var j = 0; j < k1.length; j++) //К потомкам первого прибавляем код. obj[k1[j]].code = bool(c) + obj[k1[j]].code; for (var j = 0; j < k2.length; j++)/ /К потомкам второго прибавляем код. obj[k2[j]].code = bool(!c) + obj[k2[j]].code; //Добавляем новый элемент obj[k1+k2] = {count:obj[k1].count + obj[k2].count, code:'', use:false}; }

{

//Кодируем строку for (var i = 0; i < s.length; i++) }

ret += obj[s[i]].code;

//Строим объект для раскодирования var pp = {}; for (var f in obj) if (f.length == 1) pp[f] = obj[f].code; //Добавляем нули и число добавленных нулей в объект, если длина кода не делится на 8. pp['end'] = 0; var z = ret.length % 8; if ( z != 0) { for (var i = 0; i < 8 ­ z; i++) ret += '0'; pp['end'] = 8 ­ z; } //Возвращаем объект для раскодирования и закодированный текст. return JSON.stringify(pp) + codeToString(ret); }

vr­online | июнь 2010


29

Кодинг

Теперь функция распаковки.

function unpack(s) { var i = s.indexOf('"end":') + 8; //Ищем объект для распаковки. //Получаем закодированную строчку var obj = JSON.parse(s.substring(0,i)); var ss = stringToCode(s.substring(i, s.length)); ss = ss.substring(0, ss.length ­ obj.end); var ret = ''; цикл.

var error; //Если не нашли код, то будем прерывать

while(ss.length > 0) { error = true; for (var g in obj) //Поиск символа по коду. { if (obj[g].length <= ss.length) { if (ss.substring(0, obj[g].length) == obj[g]) {ret += g; ss = ss.substring(obj[g].length, ss.length); error = false; break;} } } if (error) {alert('Error for parse: ' + ss); break;} } return ret; //Возвращаем раскодированный текст. }

Как это все работает, вы можете посмотреть online по ссылке http://nets.hop.ru/download/code.html Следует сказать, что пример не работает в IE из­за того, что браузер не знает что такое объект JSON . Поэтому вывести так просто объект в виде строки в IE не получится. Но это уже другая задача и решается просто перебором всех свойств объекта. Сам алгоритм останется прежним.

vr­online | июнь 2010


Автор перевода: Толмачев Павел aka PavelDev Автор: Rudy Velthuis

30

Кодинг

Delphi

Подружим СИ и Delphi

Использование объектных файлов СИ в Дельфи Си является очень популярным языком программирования, поэтому библиотек для него создано немереное количество библиотек. А вот библиотек для Delphi ­ не очень много, поэтому было бы хорошо использовать некоторую часть от огромного количества библиотек напрямую, не переводя код этих библиотек на Delphi. К счастью, Delphi позволяет ссылаться на скомпилированные объектные файлы Си. Но есть проблема «unsatisfied externals» ­ отсутствующие объявления.

Си – простой, но одновременно – мощный язык, большая часть функциональности которого скрыта в используемых библиотеках. Почти весь необычный и сложный код помещен в функции этих библиотек. Но в базовых библиотеках Delphi нет реализации таких функций. Если просто связать объектный файл Си с необходимым проектом – компоновщик выдаст ошибку «unsatisfied external declarations». К счастью, Си понимает реализацию таких функций, независимо от того, в каком модуле они определены. Если компоновщик сумеет найти функцию с необходимым именем – ее можно будет использовать. Вы можете применять эти возможности для добавления недостающего функционала в проекте на Delphi. В этой статье будет показано, как собрать и связать объектный файл с модулем Delphi, а также будут представлены все необходимые библиотеки на Си. Я воспользуюсь известным регулярным выражением для поиска кода, которое написал Генри Спенсер из Университета Торонто. Я только немного изменил его, чтобы можно было использовать с компилятором Borland C++. Регулярные выражения немного описаны в справке Delphi, и это очень хороший способ определять модели поиска.

Объектные файлы

Как правило, Си создает объектные файлы, которые должны быть связаны с исполняемым файлом. В Win32 такие файлы, обычно, имеют расширение .obj. Но они бывают разных, несовместимых форматов. Компилятор С++ от Microsoft и некоторые другие, совместимые с ним компиляторы, создают объектные файлы в слегка модифицированном COFF­формате. Поэтому они не могут быть использованы в

Delphi. Для Delphi необходимы объектные фалы в формате OMF. Не существует нормального практического способа преобразовать объектный файл из COFF­формата в OMF. Поэтому вам нужен исходный код и компилятор, который генерирует OMF­файлы.

Обратите внимание, что утилита COFF2OMF, которая поставляется со многими версиями С++ Builder не поможет справится с этой проблемой. Эта утилита предназначена только для преобразования библиотеки импорта из одного формата в другой. Библиотеки импорта содержат информацию только о экспортируемых функциях DLL, и могут быть созданы напрямую из DLL, используя IMPLIB или подобные утилиты. Они содержат ограниченное количество тех возможностей, которые есть в полноценных библиотеках на Си или С++. COFF2OMF не сконвертирует объектный файл (или библиотеку) языка Си или С++ в COFF­ формат (причины озвучены ниже). Поэтому вам действительно понадобится исходный код и компилятор Borland для создания объектного OMF­файла, для использования его в Delphi. Автор программ и разработчик Тедди де Конинг утверждает, что COFF2OMF от фирмы DigitalMars может сделать полное преобразование форматов. Но пока я этого не проверял, но говорят – что она стоит своих денег. Агнер Фог (также разработчик и известный гуру оптимизации) создал утилиту ObjConv, которая сможет преобразовать несколько объектных файлов в другие. Мы прилагаем усилия для создания генератора OMF и не OMF объектных файлов на С++, чтобы их можно было использовать в Delphi.

C++ Builder из состава Borland/CodeGear позволяет создавать такие объектные OMF­ файлы. Но не каждый пользователь Delphi имеет и С++ Builder. К счастью, Borland создала компилятор файлы. Но не каждый пользователь Delphi имеет и С++ Builder. К счастью, Borland создала компилятор командной строки, который поставляется в свободном доступе вместе с Borland C++ Builder 5. Скачивайте его можно здесь: http://www.borland.com/products/downloads/downlo

vr­online | июнь 2010


31

Кодинг

ad_cbuilder.html. Borland уже выпустила шестую версию, так что не ясно, сколько еще бесплатная пятая версия компилятора будет доступна.

Borland / CodeGear выпустила новый бесплатный компилятор с IDE и Turbo C++ Explorer. Хотя он и имеет то же самое имя, но это уже не тот старый продукт Turbo C++, который был выпущен в прошлом веке, это, можно сказать, младший брат BDS 2006, но только для одного языка. Вы можете скачать версию этого Explorer’a, который является полноценной IDE со всем необходимым, и даже лицензию, которая позволяет создавать коммерческие приложения, за исключением возможности устанавливать новые компоненты в IDE (но вы можете использовать эти компоненты в коде). Его можно скачать со страницы закачки Turbo Explorer’a по адресу: http://www.turboexplorer.com/downloads.

Существует ограничение, которое оговаривает – какого рода файлы доступны для использования. Вы можете использовать только объектные файлы, которые были скомпилированы лишь как Си­фалы (а не С++). По некоторым причинам, у компоновщика Delphi существуют проблемы с объектными файлами, которые содержат в себе инструкции на С++. Поэтому, ваши исходные файлы должны иметь расширение «.с», а не «.cpp». Но, поскольку, вы в любом случае не можете использовать напрямую С++ классы – это не является жестким ограничением. Одно замечание: Си часто использует библиотеку файлов с расширением «.lib». Они просто содержат несколько объектных файлов. Некоторые компиляторы Си поставляются вместе с библиотечными программами для извлечения, вставки, замены или просмотра этих объектных файлов. В Delphi вы не сможете напрямую указывать ссылки на эти .lib­файлы. Но вы можете использовать утилиту TDUMP, которая поставляется с Delphi и С++Builder, чтобы посмотреть – что хранится в этих файлах. Бесплатный С++ компилятор поставляется с библиотечной программой TLIB.

Код

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

такое соответствие найдено).

Сделать полное описание кода для поиска, с помощью регулярного выражения, довольно сложно и объемно, поэтому я не буду приводить его. Но заголовочный файл, конечно, важен при использовании объектного файла в Delphi. Скачать можно здесь: http://www.rvelthuis.de/zips/cobjs.zip. /*********************************************************************** ****/ /* */ /* regexp.h */ /* */ /* Copyright (c) 1986 by Univerisity of Toronto */ /* */ /* This public domain file was originally written by Henry Spencer for the */ /* University of Toronto and was modified and reformatted by Rudy Velthuis */ /* for use with Borland C++ Builder 5. */ /* */ /*********************************************************************** ****/ #ifndef REGEXP_H #define REGEXP_H #define RE_OK 0 #define RE_NOTFOUND 1 #define RE_INVALIDPARAMETER 2 #define RE_EXPRESSIONTOOBIG 3 #define RE_OUTOFMEMORY 4 #define RE_TOOMANYSUBEXPS 5 #define RE_UNMATCHEDPARENS 6 #define RE_INVALIDREPEAT 7 #define RE_NESTEDREPEAT 8 #define RE_INVALIDRANGE 9 #define RE_UNMATCHEDBRACKET 10 #define RE_TRAILINGBACKSLASH 11 #define RE_INTERNAL 20 #define RE_NOPROG 30 #define RE_NOSTRING 31 #define RE_NOMAGIC 32 #define RE_NOMATCH 33 #define RE_NOEND 34 #define RE_INVALIDHANDLE 99 #define NSUBEXP 10 /* *Первый байт регулярного выражения внутри "program" на самом деле *«магическое» число; начало узла ­ со второго байта. */ #define MAGIC 0234 #pragma pack(push, 1) typedef struct regexp { char *startp[NSUBEXP]; char *endp[NSUBEXP]; char regstart; /* Только для внутреннего использования. */ char reganch; /* Только для внутреннего использования. */ char *regmust; /* Только для внутреннего использования. */ int regmlen; /* Только для внутреннего использования. */

vr­online | июнь 2010


32

Кодинг

char program[1]; /* Только для внутреннего использования. */ } regexp; #ifdef __cplusplus extern "C" { #endif extern int regerror; extern regexp *regcomp(char *exp); extern int regexec(register regexp* prog, register char *string); extern int reggeterror(void); extern void regseterror(int err); extern void regdump(regexp *exp); #ifdef __cplusplus } #endif #pragma pack(pop) #endif // REGEXP_H

Заголовочный файл, описанный выше, определяет некоторые постоянные значения, структуры для передачи информации между кодом регулярного выражения и кодом, который его вызвал. А также – между различными функциями кода и функциями, которые может вызвать пользователь.

#define – это значения констант, начинающихся с приставки RE_, которые были возвращены из тех функций, которые оповещают об успехе или ошибке. NSUBEXP – это число подвыражений, которые можно создать в реализации регулярного выражения. Число, называемое MAGIC, это значение, которое должно присутствовать в каждом скомпилированном регулярном выражении. Если оно отсутствует, структура, очевидно, не содержит действительного скомпилированного регулярного выражения. Обратите внимание, что запись 0234 ­ не цифровое значение. Начальный ноль говорит компилятору о том, что это восьмеричное значение. Как шестнадцатеричное число использует 16 за основу системы счисления, так десятичное число использует 10, а восьмеричное – 8. Десятичное значение рассчитывается следующим образом: 0234(oct) = 2 * 82 + 3 * 81 + 4 * 80 = 128 + 24 + 4 = 156(dec).

#pragma pack(push, 1) увеличивает текущее состояние выравнивания, устанавливая его на побайтовое выравнивание. Это важно, так как это делает структуры совместимыми с упакованными записями (packed record) Delphi.

Компиляция кода

Если у вас есть С++ Builder или BDS2006 – будет легче скомпилировать код. Вы создаете новый проект и добавляете к нему файл «regexp.c» с использованием пунктов меню «Project», «Add to project» – и компилируете проект. В результате этого, каталог будет содержать файл «regexp.obj».

Если у вас есть компилятор командной строки и он настроен правильно, то откройте командную строку, перейдите в директорию, содержащую файл «regexp.c» и введите: bcc32 ­c regexp.c

Возможно, вы получите предупреждение о неиспользуемых переменных или потере значащих цифр при преобразованиях («unsatisfied externals»), но вы можете сейчас их проигнорировать, поскольку вы код не писали. Я использую этот код уже много лет – и проблем пока не было. После компиляции, вы сможете найти объектный файл «regexp.obj» в том же каталоге, что и исходный файл.

Чтобы сейчас импортировать объектный файл в Delphi, вы должны скопировать его в директории, где находятся исходники на Delphi.

Импорт объектных файлов.

Чтобы использовать этот код в объектном файле, вы должны написать несколько объявлений. Компоновщик Delphi ничего не знает о параметрах функций, о типах регулярных выражений в заголовках, и о значениях, который были определены в файле «regexp.h». Это также не означает, что соглашения о вызовах были использованы. Для этого вы можете написать модули импорта.

Вот интерфейсная часть модуля Delphi, который используется для импорта функций и значений из объектного файла Си в Delphi:

unit RegExpObj; interface const NSUBEXP = 10; *Первый байт регулярного выражения внутри "program" на самом деле *«магическое» число; начало узла ­ со второго байта. MAGIC = 156; type PRegExp = ^_RegExp; _RegExp = packed record StartP: array[0..NSUBEXP ­ 1] of PChar; EndP: array[0..NSUBEXP ­ 1] of PChar; RegStart: Char; // Internal use only. RegAnch: Char; // Internal use only. RegMust: PChar; // Internal use only. RegMLen: Integer; // Internal use only. Prog: array[0..0] of Char; // Internal use only. end; function _regcomp(exp: PChar): PRegExp;cdecl; function _regexec(prog: PRegExp; str: PChar):LongBool; cdecl; function _reggeterror: Integer; cdecl; procedure _regseterror(Err: Integer); cdecl; end; function _regcomp(exp: PChar): PRegExp; cdecl; function _regexec(prog: PRegExp; str: PChar): LongBool; cdecl; function _reggeterror: Integer; cdecl; procedure _regseterror(Err: Integer); cdecl;

vr­online | июнь 2010


33

Кодинг

Вы заметите, что все функции начинаются со знака подчеркивания. Это все потому, что, по историческим причинам, большинство Си­ компиляторов генерируют код, в котором функции начинаются со знака подчеркивания. Чтобы импортировать их, вы должны использовать названия, со знаком «_» вначале. Вы могли бы сказать, что с помощью компилятора С++ Builder можно пропустить подчеркивания, но я, обычно, этого не делаю. Подчеркивания ясно показывают, что мы используем Си­фукции. Они должны быть объявлены с использованием соглашения о вызове в языке Си, который называется cdecl на языке Delphi. Забыв про это ­ можно получить много ошибок, которые очень трудно отследить.

Коду регулярных выражений необходима библиотечная функция Си malloc() для выделения памяти, strlen() для вычисления длины строки, strchr() для поиска одного символа в строке, strncmp() для сравнения двух строк, strcspn() чтобы найти первой символ подстроки в строке.

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

Оригинальный код Генри Спенсера не имел функций reggeterror() и regseterror(). Я должен был описать их, так как вы не можете Недостающая часть раздела реализации выглядит следующим образом: использовать переменные в объектных // так как этот блок обеспечивает код для _malloc() – он файлах со стороны Delphi напрямую, а код может использовать требует возможности сбрасывать сообщения // FreeMem и получить PRegExp. Но обычно – _regfree – об ошибках в ноль, и получать сообщения об самое лучшее решение. ошибках. Но вы можете использовать переменные Delphi из объектных файлов Си. function _malloc(Size: Cardinal): Pointer; cdecl; begin Иногда объектные файлы требуют, чтобы GetMem(Result, Size); присутствовали внешние переменные. Если end; они не существуют, вы можете объявить их function _strlen(const Str: PChar): Cardinal; cdecl; где­нибудь в вашем коде на Delphi. В идеале, часть раздела реализации будет выглядеть следующим образом: implementation uses SysUtils; {$LINK 'regexp.obj'} function _regcomp(exp: PChar): PRegExp; cdecl; external; function _regexec(prog: PRegExp; str: PChar): LongBool; cdecl; external; function _reggeterror: Integer; cdecl; external; procedure _regseterror(Err: Integer); cdecl; external; end.

Но если вы скомпилируете этот код, компоновщик Delphi будет жаловаться на отсутствующие объявления («unsatisfied externals»). Модули Delphi должны будут описать их. Большинство функций довольно просты и легко могут быть написаны на Delphi. Только функции, которые принимают переменное число аргументов, такие как printf() или scanf(), нельзя закодировать без использования сборщика. Возможно, если бы вы нашли код printf() или scanf() в бибилиотеках С++, вы могли бы извлечь объектный файл, а также связать его. Я никогда не пробовал делать это.

begin Result := StrLen(Str); end;

function _strcspn(s1, s2: PChar): Cardinal; cdecl; var SrchS2: PChar; begin Result := 0; while S1^ <> #0 do begin SrchS2 := S2; while SrchS2^ <> #0 do begin if S1^ = SrchS2^ then Exit; Inc(SrchS2); end; Inc(S1); Inc(Result); end; end; function _strchr(const S: PChar; C: Integer): PChar; cdecl; begin Result := StrScan(S, Chr(C)); end; function _strncmp(S1, S2: PChar; MaxLen: Cardinal): Integer; cdecl; begin Result := StrLComp(S1, S2, MaxLen); end; end;

vr­online | июнь 2010


34

Кодинг

function _strncmp(S1, S2: PChar; MaxLen: Cardinal): Integer; cdecl; begin Result := StrLComp(S1, S2, MaxLen); end;

Как вы можете увидеть, эти функции должны быть объявлены как cdecl и начинаться со знака подчеркивания. Имена функций чувствительны к регистру, поэтому важно их правильно писать. В моем проекте я не использую этот код. Структура _RegExp содержит информацию, которая не должна быть изменена извне, это не очень удобно. Поэтому я упаковал ее в несколько простых функций, также используя функцию RegFree, которая просто вызывает FreeMem, поскольку с помощью _malloc() я использую GetMem. В идеале, код регулярного выражения должен обеспечить функцию regfree(). Весь исходный код на Си, код модулей для импорта и упакованных модулей, а также очень простой загрузчик программы можно найти на страниц: http://www.rvelthuis.de/downloads.html#cobjszip Использование msvcrt.dll

Вместо того, чтобы писать все эти функции самостоятельно, вы можете использовать их из библиотеки от Microsoft Visual C++. Это DLL, которые использует Windows, и поэтому они должны присутствовать во всех версиях Windows. FWTW ­ это не моя идея. Я получил ее от Роба Кеннеди в группе новостей от Borland. Похоже, что проект JEDI использует эту технику в нескольких своих исходниках.

Используя msvcrt.dll вместо кода, приведенного выше, можно просто объявить большинство внешних процедур. Обязательно используйте имя с подчеркиванием во внешнем объявлении, так как эти процедуры не имеют знака подчеркивания в DLL: // Обратите внимание, что вы не можете использовать менеджер памяти Си, // так что вы все равно должны переписать процедуры, как _malloc() в Delphi. function _malloc(Size: Cardinal): Pointer; cdecl; begin GetMem(Result, Size); end; // The rest can be imported from msvcrt.dll directly. function _strlen(const Str: PChar): Cardinal; cdecl; external 'msvcrt.dll' name 'strlen'; function _strcspn(s1, s2: PChar): Cardinal; cdecl; external 'msvcrt.dll' name 'strcspn'; function _strchr(const S: PChar; C: Integer): PChar; cdecl; external 'msvcrt.dll' name 'strchr';

function _strncmp(S1, S2: PChar; MaxLen: Cardinal): Integer; cdecl; external 'msvcrt.dll' name 'strncmp';

Это будет работать даже в таких запутанных процедурах, как sprinft() или scanf(). Там, где Си требует дескриптор файла, вы просто объявите указатель. Эффект будет тот же. Для примера: function _sprintf(S: PChar; const Format: PChar): Integer; cdecl; varargs; external 'msvcrt.dll' name 'sprintf'; function _fscanf(Stream: Pointer; const Format: PChar): Integer; cdecl; varargs; external 'msvcrt.dll' name 'fscanf';

Проблемы

В то же время, я столкнулся с несколькими проблемами, которые могут быть интересны для читателя. Для преобразования я написал простую тестовую программу на Си, которая использует много процедур, импортируемых из msvcrt.dll. Но оказалось, что некоторые процедуры были не совсем процедурами. Они реализованы в виде макросов, которые непосредственно являются доступными структурами и они не всегда существуют, либо находятся в запутанной мешанине с BCB C, Delphi и Microsoft C. getchar() и putchar()

Возьмем, к примеру, процедуру getchar(). В stdio.h она заявлена в виде макроса, который доступен для повышения уровня стандартного ввода, и этот стандартный ввод ­ макрос для &_streams[0]. Если на этом уровне переменная положительная, обычно используют символы из буфера, в противном случае будет использоваться _fgetc() (IOW, __fgetc() на стороне Delphi). Поэтому, независимо от того, как вы объявите собственную структуру, он просто не вызовется.

Это значит, что я должен был объявить __streams и инициализировать уровень поля каким­нибудь отрицательным значением. Проблема заключается в том, что процедуры из msvcrt.dll будут иметь свои собственные версии подобных структур (нет гарантии, что структура FILE там такая же) и они не устанавливают или не читают из BCB процедуры _streams. Поэтому я написал собственную версию __fgetc() для Delphi, которая проверяет, если параметр stream является потоком, также как @__streams[0], указав, что он вызывается с помощью стандартного ввода в стандартный поток ввода. Если это так – это означает, что он вызывается как _fgetch(stdin); который, также как и getchar() – является макросом. Если это так, то прочитайте книги по Delphi, иначе vr­online | июнь 2010


35

Кодинг

– используйте процедуру _fgetc() из msvcrt.dll.

Я надеюсь, что это будет работать, но я хотел бы знать, если это будет не так. Пожалуйста, напишите мне (на почту <articles@rvelthuis.de>) о возникших у вас проблемах.

FWIW, я отдаю себе отчет о том, что одна из процедур (я думаю ­ fwrite()) останавливается на брейкпоинте int3 в ntdll.DbgBreakPoint, если ее запустить в отладчике. Если вы нажмете F9 или Выполнить ­ то программа будет выполнена дальше.

стандартного ввода в стандартный поток ввода. Если это так – это означает, что он вызывается как _fgetch(stdin); который, также как и getchar() – является макросом. Если это так, то прочитайте книги по Delphi, иначе – используйте процедуру _fgetc() из msvcrt.dll. Я надеюсь, что это будет работать, но я хотел бы знать, если это будет не так. Пожалуйста, напишите мне (на почту <articles@rvelthuis.de>) о возникших у вас проблемах.

FWIW, я отдаю себе отчет о том, что одна из процедур (я думаю ­ fwrite()) останавливается на брейкпоинте int3 в ntdll.DbgBreakPoint, если ее запустить в отладчике. Если вы нажмете F9 или Выполнить ­ то программа будет выполнена дальше.

Но процедура puthcar() ­ тоже макрос, и это опять может повысить уровень. Таким образом, могут возникать такие же проблемы, которые были описаны выше. Я, пока, не встречал их. Но изменения, которые я сделал для getchar(), означают, что, возможно, ungetc() может работать некорректно (AFAICS ­ это тоже макрос). В случае необходимости, я могу эмулировать всю систему в Delphi. Просто потому, что Си использует несколько макросов.

собственную версию этих функций с использованием _fseek() и _ftell().

В теории, fpos_t является непрозрачным типом, и обе процедуры используют указатель на одну. Но в BCB она объявлена как длинная, поэтому она не будет больше, чем четыре байта, а это именно то, что и выделяется. Так что, если msvcrt.dll попытается сохранить больше, чем в нее попытаются записать или часть данных будет перезаписана ­ то ваша программа не будет работать должным образом или вызовет нарушение прав доступа. Это и есть риск использования кода, который написан с использованием другого компилятора.

Заключение

При условии, что вы мало знаете про Си, и не боитесь сами писать замены для нескольких функций Си (если вы используете msvcrtl.dll ­ это число будет очень маленьким), связывая объектные файлы Си с модулями Delphi ­ очень просто. Это позволяет создавать программу, которая не нуждается в DLL и может быть развернута за один раз. Если вам нужна помощь с использованием компилятора командной строки C++ Builder (версии 5.5) ­ вы найдете отличную помощь в группе новостей от Borland:

news://newsgroups.borland.com/borland.public. cppbuilder.commandlinetools

Новости:

news://newsgroups.borland.com/borland.public. cppbuilder.language доступен для вопросов о языке. Я желаю вам хорошо провести время за экспериментами.

Это лишний раз показывает, что это не всегда просто ­ перенаправлять вызовы, в конце концов, к примеру ­ на mvscrt.dll. Макросы погубили эту идею. FWIW, макросы ­ это зло, зло, зло. fgetpos() и fsetpos()

Похоже, что в msvcrt.dll эти две процедуры хранят дополнительные данные в позициях параметров. В ВСВ позиция ­ это простое длинное целое. Использование _fgetpos() с объявлением fpos_t в stdio.h BCB вызвало нарушение прав доступа. Так я написал vr­online | июнь 2010


Автор: Toly www: http://toly­blog.ru

36

Кодинг

Python

AutoForwarder for Joomla Копируем сайт на локальный компьютер

На днях нужно было “скопипастить” один ресурс на локальный сайт (для личного пользования, конечно) с CMS типа Joomla. Решил выложить результаты сих потуг.

В первую очередь необходимо авторизоваться в Joomla­вскую админку. Так как Joomla у меня на локальном компьютере, WireShark для анализа http­заголовков (и соответственно выяснения алгоритма авторизации) не подходит. Для данной задачи я воспользовался удобным плагином FireFox. Имя ему LiveHTTPHeaders. В html­коде страницы авторизации обнаруживаем скрытые параметры.

Скрытые параметры

Особое внимание следует уделить последнему параметру со значением “1″. Но о нем позже.

Кодим

# ­*­ coding: utf­8 #импорт необходимых библиотек import urllib import urllib2 import cookielib import re import string #адрес админка локального сайта host = 'http://localhost/administrator/' #сечас стих сочиню: #информация, # для авторизации user = 'admin' pasw = 'pass' #подготовка опенера с функцией обработки кукисов CookieJar = cookielib.CookieJar() opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(CookieJar)) #запрос админской страницы conn = urllib2.Request(host) page = opener.open(conn).read() #получаем скрытые поля params = re.findall(r'name="([^"]+)" value="([^"]+)"', page)

#Предварительная подготовка параметров для отправки POST­запроса params.append( ('username', user) ) params.append( ('passwd', pasw) ) params.append( ('lang', '') ) buf = {} ident = '' for param in params: buf[param[0]] = param[1] #Отправляем подготовленные параметры post = urllib.urlencode(buf) conn = urllib2.Request(host+'index.php', post) page = opener.open(conn).read()

По тексту странички, полученной после авторизации, видно, что имя последнего скрытого поля изменяется. Поэтому необходимо его снова отловить. ident = re.findall(r'<input type="hidden" name="([^"]+)" value="1" />', page)[0]

Ну а дальше все просто: #Собственно сам постинг

title='заголовок материала' sectionid = 1 #номер раздела catid = 2 #номер категории text = 'текст материала' #Передаваемые параметры buf = { 'title':title.encode("utf­8"), #заголовок 'state':'1', 'alias':'', 'frontpage':'0', 'sectionid':section, 'catid':category, 'details%5Bcreated_by%5D':'62', #идентификатор автора 'details%5Baccess%5D':'0', 'text':text.encode("utf­8"), 'version':'0', 'mask':'0', 'option':'com_content', 'task':'apply', ident:'1' #ранее найденный скрытый параметр } #постим месседж post = urllib.urlencode(buf) conn = urllib2.Request(host+'index.php', post) page = opener.open(conn).read()

vr­online | июнь 2010


37

Кодинг

'details%5Baccess%5D':'0', 'text':text.encode("utf­8"), 'version':'0', 'mask':'0', 'option':'com_content', 'task':'apply', ident:'1' #ранее найденный скрытый параметр } #постим месседж post = urllib.urlencode(buf) conn = urllib2.Request(host+'index.php', post) page = opener.open(conn).read()

Идентификатор автора (его конечно можно из html­кода после авторизации вытащить, но заморачиваться было лень) смотреть так:

"Вычисляем" идентификатор автора

Вот, пожалуй, и все, за исключением нескольких замечаний: 1. Поля необходимые для отправки брал по­ минимуму. Точно также можно управлять и расширенными опциями, вроде “показать заголовок” и “заголовок как ссылка”

2. После добавления материла скриптом у него ставится статус “Опубликовано, но приостановлено”. Максимум через сутки статус поменяется. Если нужно публиковать мигом, добавьте к отправляемым параметр ’details%5Bpublish_up%5D’ со значением какой­ нибудь прошлой даты.

vr­online | июнь 2010


Автор: Toly www: http://toly­blog.ru

38

Кодинг

Python

ImageGrabbing

Нехитрый граббинг изображений с сайта

...although Python uses an obsolete approach to memory management, it is a good implementation of that approach, as opposed to S, which uses a combination of bad implementation and demented design decisions to arrive at what may very well be the worst memory behavior of any actually useful program.

Andrew Mullhaupt, 26 Jun 1 997

Рассмотрим создание скрипта на питоне для граббинга картинок с сайта. Объект моих преследований – сайт мебельной фабрики “Витра”. Первый скрипт собирает ссылки на картинки и помещает их в файл. Ниже код с комментариями.

Скрипт №1 import urllib import re import string

#сайт для граббинга link = 'http://vitra­mebel.ru' #элементы ссылок, по которым не нужно переходить bad = ['mailto:','javascript:', 'http://', '?', '.'] #получаем текст по ссылке def getpage(link): res = urllib.urlopen(link).read() return res #функция проверки ссылки ­ запрещенная для перехода или нет def isbad(st): global bad res = True for badword in bad: # if string.count(st, badword) > 0: res = False return res #получение из текста других ссылок def getlinks(link): res = [] page = getpage(link) #регулярное выражение ссылки links = re.findall(r"<a href="([^"#]+)", page) for i in xrange(len(links)): #исключение ненужных ссылок if isbad(links[i]): res.append(links[i]) res = list(set(res)) return res #получение адресов jpg­картинок из текста странички def getimageslink(link): res = []

page = getpage(link) #регулярное выражение для jpg­картинки links = re.findall(r"<img src="([^"#]+.jpg)", page) for i in xrange(len(links)): res.append(links[i]) return res

#массив ссылок на картинки images = [] #массив ссылок, с которых уже собрали другие ссылки и картинки passed = ['/'] #получаем ссылки с главной страницы links = getlinks(link) #пока ссылки не закончатся while len(links) > 0: #извлекаем ссылку cur_link = links.pop() print cur_link #собираем с нее картинки new_img = getimageslink(link + cur_link) #добавляем неповторяющиеся картинки в массив картинок images = list( set(images) | set(new_img) ) #если ссылка не отмечена как пройденная if cur_link not in passed: #помещаем ее в массив отработанных ссылок passed.append(cur_link) #получаем ссылки newlinks = getlinks(link+cur_link) #отсеиваем отработанные ссылки newlinks = [item for item in newlinks if item not in passed] #добавляем в массив ссылок ­ ставим на очередь links = list( set(links) | set(newlinks) ) #сохраняем ссылки картинок в файл f = open('links.txt', 'w') for img in images: f.write(img+'n') f.close()

Данный скрипт легко можно переделать под генератор карты сайта. P.S. Сразу скажу, что код не идеальный:

1. Каждая страница загружается по 2­а раза. 2. Не использована многопоточность. 3. Не использованы прокси.

vr­online | июнь 2010


39

Кодинг

Скрипт № 2

Второй скрипт для загрузки картинок с сайта. Данный скрипт загружает картинки по ссылкам в файле, сгенерированном скриптом из предыдущей статьи. Исходный код: import urllib import re #адрес сайта link = 'http://vitra­mebel.ru' #имя папки, в которую будут сохраняться картинки folder = 'img' #процедура загрузки файла #link ­ адрес файла #name ­ под каким именем сохранять def loadfile(link, name): data = urllib.urlopen(link) #открываем файл для цифровой записи ­ "wb" f = open(name, "wb") f.write(data.read()) f.close() #получаем имя файла по его адресу в интернете def getname(link): return re.findall(r"/([^/]+)$", link)[0] #открываем файл ссылок на картинки f = open('links.txt', "r") lines = f.readlines() #определяем количество n = len(lines) for i in range(376, len(lines)): #индикация ­ какая ссылка по счету и сколько осталось print str(i)+'/'+str(n), lines[i][:­1] #загрузка и сохранение картинки loadfile( link+lines[i][:­1], folder + '/' + getname(lines[i])[:­1] ) print 'ok' f.close()

vr­online | июнь 2010


Автор: Toly www: http://toly­blog.ru

40

Кодинг

Python

AutoUp v0.1b для форума “Амит” Встроенные библиотеки urllib и urllib2

You're going to be in a minority ­ you're coming to Python programming from a language which offers you a lot more in the way of comfortable operations than Python, instead of coming from medieval torture chambers like C or Fortran, which offer so much less.

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

Щипцы­зажимы.

Для продуктивной работы нам понадобится: * python 2.*

* PyScripter

* сетевой анализатор Wireshark и немного времени.

Понеслась.

Запускаем Wireshark, настраиваем фильтр только на http и логинимся на любимый форум. И

вот что он нам показывает:

(в POST­запросе передается логин и пароль) (после отправки логина и пароля осуществляется редирект на /forum/index.php? )

Из­за использования в механизме аутентификации кукисов придется использовать модуль cookielib. В прошлом посте я не использовал прокси. Исправляюсь.

Исходники:

Andrew Mullhaupt, 26 Jun 1 997

#импортируем сетевые библиотеки import urllib import urllib2 import cookielib #начальные условия message = u'up' user = u'login' pasw = u'password' prox = '94.127.88.46:3128' #номера форума и топика #1 ­ эт�� "Общий раздел" forum = '1' topic = '41298' host = 'http://www2.amit.ru/forum/index.php?' #Заголовочная информация скопированная из снифера #со вставленными логином и паролем headers = { 'User­Agent' : 'Opera/9.80 (Windows NT 5.1; U; ru) Presto/2.2.15 Version/10.00', 'Host' : 'www2.amit.ru', 'Accept' : 'text/html, application/xml;q=0.9, application/xhtml+xml, image/png, image/jpeg, image/gif, image/x­xbitmap, */*;q=0.1', 'Accept­Language' : 'ru­RU,ru;q=0.9,en;q=0.8', 'Accept­Charset' : 'Accept­Charset: iso­8859­1, utf­8, utf­16, *;q=0.1', 'Referer' : 'http://www2.amit.ru/forum/index.php', 'Connection' : 'Keep­Alive, TE', 'TE' : 'TE: deflate, gzip, chunked, identity, trailers' } post = urllib.urlencode({ 'user_usr' : user.encode('cp1251'), 'user_pwd' : pasw.encode('cp1251'), 'mode' : 'login', 'queryStr' : '', 'pagetype' : 'index' }) #делаем указатель на прокси­сервер proxy = urllib2.ProxyHandler({'http' : prox}) #Создаем кукис­агент CookieJar = cookielib.CookieJar() #создаем открывалку страниц с уже готовыми кукис­агентом и указателем прокси сервера opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(CookieJar), proxy) #Осуществляем аутентификацию conn = urllib2.Request(host, post, headers) data = opener.open(conn) #теперь в кукис­агент помещена информация о отм что мы залогинены #описываем процедуру отправления сообщения def posting(message, forum, topic): #формируем запрос с текстом сообщения post = urllib.urlencode({ 'postText':

vr­online | июнь 2010


41

Кодинг

conn = urllib2.Request(host, post, headers) #отправляем запрос data = opener.open(conn) #вызываем процедуру posting(message, forum, topic) #формируем запрос с текстом сообщения post = urllib.urlencode({ 'postText': message.encode('cp1251'), 'action' : 'pthread', 'forum' : forum, 'topic' : topic }) conn = urllib2.Request(host, post, headers) #отправляем запрос data = opener.open(conn) #вызываем процедуру posting(message, forum, topic)

P.S. Используя модуль time, данный скрипт легко модифицировать для автоматического апанья в рекламном.

vr­online | июнь 2010


Автор: AnK0r aka Анатолий Корчагин Anatoliy.Korchagin@gmail.com

42

Кодинг

AJAX + PHP:

Повышаем интерактивность Погружение в Web 2.0

Ты наверное часто слышал термин Web 2.0 который впервые определил Тим О’Рейли (Tim O'Reilly) в своей статье «What Is Web 2.0» . По словам О`Рейли это методика проектирования систем, которые путём учета сетевых взаимодействий становятся тем лучше, чем больше людей ими пользуются. Если более понятно, то Web 2.0 это сайты которые дают возможность самому пользователю наполнять и редактировать контент. Но…

В настоящее время стиль Web 2.0 принято присваивать сайтам которые обладают технологией AJAX, являющаяся одной из основных технологий лежащей в основе Web 2.0, простой навигацией, 3D эффектами, градиентными менюшками и кнопочками, отражением, крупным текстом, и прочим добром. Об одном таком чуде и будет данная статья, а именно об AJAX. О данной технологи написано уже много статей и поэтому здесь мы не будем рассматривать плюсы и минусы этого зверя, а попробуем связать AJAX с одним из признанных лидеров языков веб­программирования – серверным языком PHP.

Немного история

Для начала давай разберемся с тем, что же это вообще такое. AJAX или асинхронный JavaScript и XML (Asynchronous Javascript and XML) это технология изменения данных на сайте без перезагрузки страницы. В результате, веб­ приложения становятся более быстрыми и удобными.

Однако первые приемы динамической подзагрузки контента без полной перезагрузки веб­страници применялись задолго до появления этой технологии. Еще в 1998 году компания Microsoft предложила метод «Remote Scripting» , так же нужный эффект можно было получить используя элементы FRAME, IFRAME и OBJECT появившиеся в HTML 4.0. Но благодаря Джесси Джеймса Гарретта (Jesse James Garrett), который ввел термин AJAX в статье «Ajax: A new approach to web applications»

и компании Google использовавшей эту технологию в сервисах Gmail, Google Maps и Google Suggest технология AJAX стала, как я люблю называть, «попсовой».

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

Ближе к делу

Для того чтобы продемонстрировать связь AJAX и PHP создадим очень простую форму с 2 полями ввода. В первое поле будет вводиться любой текст, после этого наш текст отправится нашему PHP­скрипу, который преобразует его в верхний регистр и отправит его обратно к нам. В конце мы выведем результат во втором поле ввода.

Итак, что надо сделать: • Отслеживать события нажатия клавиш в поле ввода. • При нажатии клавиши отправить сообщение PHP скрипту на сервере. • Сменить регистр и отправить результат обратно. • Захватить возвращаемые данные и отобразить их.

<!DOCTYPE html PUBLIC "­//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1­transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http­equiv="Content­Type" content="text/html; charset=utf­8" /> <title>Уроки VR­Online. Дружим Ajax и PHP</title> </head> <body> <form name="formName"> Введите текст: <input type="text" onkeyup="doWork();" name="inputText" id="inputText" /> Результат: <input type="text" name="outputText" id="outputText" /> </form> </body> </html> Код 1. Пример создание формы с 2 полями

vr­online | июнь 2010


43

Кодинг

Как видишь из примера, здесь используется функция doWork(), которая вызывается каждый раз когда была нажата клавиша. Но что это еще за doWork() и как мы можем отправлять сообщения на сервер скрипту? Перед объяснением, что же такое doWork(), необходимо научиться делать HTTP­запросы к серверу без перезагрузки страницы. Для этого необходимо создать объект XMLHttpRequest: function getHTTPObject(){ if (window.ActiveXObject) return new ActiveXObject("Microsoft.XMLHTTP"); else if (window.XMLHttpRequest) return new XMLHttpRequest(); else { alert("Ваш браузер не поддерживает AJAX."); return null; } } Код 2. Получение HTTP объекта

function doWork(){ httpObject = getHTTPObject(); if (httpObject != null) { httpObject.open("GET", "upperCase.php?inputText=" +document.getElementById('inputText').value, true); httpObject.send(null); } } Код 3. Функция doWork()

Теперь давай разберемся каким образом можно поймать ответ от сервера. Для этого нужно использовать специальные свойства объекта XMLHttpRequest. Можем назначить функцию для данного параметра, и эта функция будет вызываться, если состояние объекта не изменилось. Окончательный код выглядит следующим образом: function doWork(){ httpObject = getHTTPObject(); if (httpObject != null) { httpObject.open("GET", "upperCase.php?inputText=" +document.getElementById('inputText').value, true); httpObject.send(null); httpObject.onreadystatechange = setOutput; } } Код 4. Конечный вид функции doWork()

Последним действием, выполняемым на стороне клиента является осуществление функции setOutput(), которая будет изменять значение второго поля. От этой функции нам потребуется только проверка фактического состояния объекта XMLHttpRequest, так как нам необходимо изменить значение поля, только если запрос завершен. Проверить это можно с помощью свойства ReadyState, которое имеет следующие значения:

• • • • •

0 = не инициализировано 1 = загрузка 2 = загружено 3 = интерактивный 4 = завершено

function setOutput(){ if(httpObject.readyState == 4){ document.getElementById('outputText').value = httpObject.responseText; } } Код 5. Функция setOutput()

Наконец­то, самое страшно позади, разобрались с клиентской стороной, теперь напишем PHP скрипт для сервера. Реализация функций сервера очень проста по сравнению с клиентской частью. В коде PHP, просто необходимо, проверить значение $ _GET массива, преобразовать его в верхний регистр и вернуть результат. Выглядит это так: <?php if (isset($_GET['inputText'])) echo strtoupper($_GET['inputText']); ?> Код 6. Скрипт upperCase.php

Вроде все. Но есть одна проблема, если в переменную inputText ввести значение на кириллице, то на выходе мы получим «чебурашки». Для устранения этого недостатка воспользуемся функцией iconv(). Вот теперь точно все, на этом урок закончен, ниже приведен полный код серверной и клиентской стороны. Напоследок скажу лишь, что этот материал предоставлен в качестве ликбеза, так как AJAX в чистом виде уже почти нигде не используют. Сейчас в основном используют фреймворки или сторонние библиотеки, например Jquery.

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

Клиентская часть. Форма:

vr­online | июнь 2010


44

Кодинг

<!DOCTYPE html PUBLIC "­//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1­transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http­equiv="Content­Type" content="text/html; charset=utf­8" /> <title>Уроки VR­Online. Дружим Ajax и PHP </title> </head>

Используемые материалы:

1. 2. 3. 4.

www.ajaxf1.com www.google.ru php.su www.wikipedia.org

<body> <script language="javascript" type="text/javascript"> function getHTTPObject(){ if (window.ActiveXObject) return new ActiveXObject("Microsoft.XMLHTTP"); else if (window.XMLHttpRequest) return new XMLHttpRequest(); else { alert("Ваш браузер не поддерживает AJAX."); return null; } } function setOutput(){ if(httpObject.readyState == 4){ document.getElementById('outputText').value = httpObject.responseText; } } function doWork(){ httpObject = getHTTPObject(); if (httpObject != null) { httpObject.open("GET", "upperCase.php?inputText=" +document.getElementById('inputText').value, true); httpObject.send(null); httpObject.onreadystatechange = setOutput; } } var httpObject = null; </script> <form name="formName"> Введите текст: <input type="text" onkeyup="doWork();" name="inputText" id="inputText" /> Результат: <input type="text" name="outputText" id="outputText" /> </form> </body> </html>

Серверная часть. upperCase.php:

<?php if (isset($_GET['inputText'])) $text = iconv('UTF­8', 'windows­1251', $_GET['inputText']); echo strtoupper($_GET['inputText']); ?>

vr­online | июнь 2010


Автор: Дорин Полосин

45

Кодинг

C# Самопальный диспетчер задач для Windows Mobile Работаем с поцессами

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

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

программ при помощи процедуры fillTaskList: private void fillTaskList() { Cursor.Current = Cursors.WaitCursor; //Получаем список запущенных приложений windows = WindowHelper.EnumerateTopWindows(); //Заполняем ListView ListViewItem lvi; listView.BeginUpdate(); listView.Items.Clear(); foreach(Window w in windows) { lvi = new ListViewItem(w.ToString()); listView.Items.Add(lvi); } listView.EndUpdate(); if(listView.Items.Count > 0) { listView.Items[0].Selected = true; listView.Items[0].Focused = true; } Cursor.Current = Cursors.Default; }

Данная процедура использует класс WindowHelper, который позволяет получить информацию о запущенных приложениях. Код метода EnumerateTopWindows, обнаруживающий все окна запущенных в системе приложений ниже: public static Window[] EnumerateTopWindows() { ArrayList windowList = new ArrayList(); IntPtr hWnd = IntPtr.Zero; Window window = null; // Получаем первое окно hWnd = GetActiveWindow(); hWnd = GetWindow(hWnd, GW_HWNDFIRST);

Пишем код

При активации основной формы MainForm программа получает список запущенных

while(hWnd != IntPtr.Zero) { if(IsWindow(hWnd) && IsWindowVisible(hWnd)) { IntPtr parentWin = GetParent(hWnd); if ((parentWin == IntPtr.Zero)) { int length = GetWindowTextLength(hWnd); if (length > 0) { string s = new string('\0', length + 1);

vr­online | июнь 2010


46

Кодинг

GetWindowText(hWnd, s, length + 1); s = s.Substring(0, s.IndexOf('\0')); s = s.Substring(0, s.IndexOf('\0')); if(s != "Tray" && s != "Start" && s != "Task Manager") { window = new Window(); window.Handle = hWnd; window.Text = s; windowList.Add(window); } } } } hWnd = GetWindow(hWnd, GW_HWNDNEXT); } return (Window[])windowList.ToArray(typeof(Window)); }

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

Активация и закрытие приложения

Для активации запущенного приложения вызывается функция SetForegroundWindow, использующая дескриптор окна. Для закрытия приложения применяется функция SendMessage с соответствующим сообщением ­ WM_CLOSE. Для закрытия сразу всех окон можно использовать функцию SHCloseApps, которая закрывает все запущенные программы, кроме самого Диспетчера задач. public static void ActivateWindow(IntPtr hWnd) { //Активируем приложение SetForegroundWindow(hWnd); } public static void CloseWindow(IntPtr hWnd) { Закрываем приложение SendMessage(hWnd, WM_CLOSE, 0, 0); } public static void CloseApps() { //Закрываем все приложения SHCloseApps(int.MaxValue); }

Перечисление процессов

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

}

//Получаем список запущенных процессов processes = Process.GetProcesses(); //Заполняем ListView ListViewItem lvi; listView.BeginUpdate(); listView.Items.Clear(); foreach(Process p in processes) { lvi = new ListViewItem(p.ProcessName); listView.Items.Add(lvi); } listView.EndUpdate(); if(listView.Items.Count > 0) { listView.Items[0].Selected = true; listView.Items[0].Focused = true; } Cursor.Current = Cursors.Default;

Список активных процессов извлекается при помощи класса Process. Основа класса метод GetProcesses: public static Process[] GetProcesses() { ArrayList procList = new ArrayList(); IntPtr handle = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); if((int)handle > 0) { try { PROCESSENTRY32 peCurrent; PROCESSENTRY32 pe32 = new PROCESSENTRY32(); byte[] peBytes = pe32.ToByteArray(); int retval = Process32First(handle, peBytes); while(retval == 1) { peCurrent = new PROCESSENTRY32(peBytes); Process proc = new Process(new IntPtr((int)peCurrent.PID), peCurrent.Name, (int)peCurrent.ThreadCount, (int)peCurrent.BaseAddress); procList.Add(proc); retval = Process32Next(handle, peBytes); } } catch(Exception ex) { throw new Exception("Exception: " + ex.Message); } CloseToolhelp32Snapshot(handle); return (Process[])procList.ToArray(typeof(Process)); } else { throw new Exception("Unable to get processes!"); } }

private void fillProcessList() { Cursor.Current = Cursors.WaitCursor;

vr­online | июнь 2010


47

Кодинг

С помощью данного метода можно узнать детальную информацию о каждом процессе.

Закрытие процесса

Чтобы закрыть процесс, используется метод Kill: Public void Kill() { IntPtr hProcess; hProcess = OpenProcess(PROCESS_TERMINATE, false, (int) processed); if(hProcess != (IntPtr) INVALID_HANDLE_VALUE) { Bool bRet; bRet = TerminateProcess(hProcess, 0); CloseHandle(hProcess); } }

Данный метод также использует вызовы Windows API. Функция OpenProcess получает дескриптор процесса, который затем передается функции TerminateProcess для уничтожения процесса.

vr­online | июнь 2010


Автор: Влад www.webdelphi.ru

48

Кодинг

Delphi

“Google API в Delphi” Проект, открытый для всех

О проекте в целом.

(до сих пор я имел дело только с SVN).

Дмитрий ака NMD (http://nmdsoft.blogspot.com/). Началось все с того, что одним прекрасным Детально занимается ClientLogin API, а также в зимним днем у меня напрочь пропали всякие идеи на тему программирования в Delphi. До того ближайшем будущем планируется, что Дмитрий начнет работу над Bloggerfr API (весьма момента все как­то шло гладко – всегда занятная вещь для блогеров). находилась интересная мне тема, которую я старался разобрать и поделиться своими Xabi Palmer (испанец) – неофициальный решениями и идеями в блоге. Что было делать участник проекта. Xabi изъявил желание теперь, когда темы исчерпали себя, а новых нет? провести локализацию отдельных частей Я решил поинтересоваться у читателей, что проекта на свой родной испанский язык, а также было бы им интересно увидеть в блоге. И один предложить нам свой вариант работы с Google из наиболее активных читателей и критиков (в Calendar API. Ждем результатов. хорошем смысле этого слова) как бы вскользь упомянул о том, что было бы неплохо Пример реализации Google API в Delphi переложить на Delphi API Яндекс.Спеллера В качестве примера того, что разрабатывается (проверка орфографии). Сказано – сделано. нами в проекте можно продемонстрировать Опубликовал пост на эту тему у себя в блоге. использование API Контактов. В целом работу с Сам по себе API оказался простым, но именно API можно представить в виде следующих опубликованный пост, а точнее комментарии последовательных шагов: читателей к нему, и стали отправной точкой для проекта о котором я и хочу рассказать сегодня – о проекте «Google API в Delphi». В апрельском номере журнала VR я уже упоминал об одной из частей этого проекта – реализации интерфейса Google ClientLogin. Официальной датой старта проекта можно считать 06.03.2010, когда была зарегистрирована закрытая группа обсуждений в Google и открыт репозиторий на Code.Coogle.com, содержащий все исходники, имеющиеся у меня на руках в тот момент. Не могу сказать, что работа в проекте кипела и некуда было складывать новые модули. Скорее всего сказалась моя тогдашняя сумасшедшая занятость на основной работе и если и писал что­то на Delphi, то это было что­то небольшое по объему, чтобы сильно не отвлекаться, но и не расслабляться. Однако на сегодняшний день проект продолжает жить и развиваться и теперь находится под управлением Git на одном из серверов github.com. В состав разработчиков, изъявивших желание продолжить работу в проекте сегодня входят (кроме меня):

Кирилл Краснов (http://www.kraeg.ru). На данные момент Кирилл занимается приведением и поддержанием в чистоте и порядке репозитория, а также, по совместительству, обучает потихоньку нас грешных нормальной работе с Git vr­online | июнь 2010


49

Кодинг

Аналогичная схема работы присутствует при работе практически с каждым API Google, изменяется только третий шаг – парсинг. На этом шаге используется всегда модуль для GData API, т.к. это основа всех API и без него просто никуда не деться, но изменяются модули для обработки и представления специфичной информации, например, как в нашем случае – специфичной информации по контактам. Для реализации представленной выше схемы мы используем, разработанный модуль GContacts.pas, в котором определены следующие основные типы данных:

• TContactGroup – группа контактов. Содержит всю служебную информацию по группе, название группы и её тип (системная или определенная пользователем) • TContact – контакт. Содержит всю информацию, относящуюся к конкретному контакту пользователя.

• TGoogleContact – содержит сведения по всем контактам и группам пользователя, а также свойства и методы для управления контактами. Основной класс для работы с API.

4. Корректно разобрать XML­узел в документе, который содержит необходимую нам информацию – метод ParseXML.

5. Проверить класс на полноту данных. Если метод IsEmpty возвращает false, то либо в классе не определено какое­то значимое свойство, без которого Google не примет документ, либо класс вообще не содержит сведений. 6. Очистить полностью все поля класса и, тем самым при обновлении контакта удалить эти сведения с сервера. Аналогичным образом определены и другие вспомогательные классы и типы данных, что избавляет нас от необходимости лишний раз лезть в «сырой» XML­документ и искать что­ либо – все делается вызовом одного метода (пример см. ниже) без прямого использования парсинга XML со стороны пользователя в принципе.

Если представить все связи в модуле графически, то получится примерно следующая схема:

Также в модуле определены все типы данных, позволяющие хранить и обрабатывать информацию по определенным свойствам контакта, например, класс: TcpRelation = class private FValue: string; FLabel: string; FRealition:TRelationType; function GetRelStr(aRel:TRelationType):string; public constructor Create(const ByNode: TXMLNode=nil); procedure Clear; function IsEmpty:boolean; procedure ParseXML(const Node: TXmlNode); function AddToXML(Root: TXmlNode):TXmlNode; property Realition:TRelationType read FRealition write FRealition; property Value: string read FValue write FValue; end;

Определяет такое свойство «Контакт контакта», т.е. сведения о человеке с которым поддерживает связь Контакт пользователя. Используя этот класс можно: 1.

Получить имя или email этот человека

2. Определить, кем он приходится для нашего Контакта (брат, сестра, дед и т.д.) – для этого служит свойство Realition.

3. Корректно записать все сведения в XML­ документ при отправке контакта на сервер – метод AddToXML.

Схема, конечно, упрощена, т.к. не показана связь с GData API и т.д., но суть та же – все сводится к использованию одного класса, который предоставит пользователю модуля всё, что требуется в удобном виде. Используя модуль, в настоящее время можно осуществить следующие операции по работе с Google Contacts API:

1. Получение сведений о контактах в целом, включая ��даленные не позднее чем 90 дней назад, либо частично, например, только контакты, добавленные не позднее определенной даты. При этом можно определить размер принимаемого документа, который измеряется количеством записей о контактах в нем, например, «попросить» Google отправлять нам все контакты частями по 5 штук в документе. 2. Парсинг XML­документа. При этом для каждого контакта определяется до 19 различных параметров, начиная от таких

vr­online | июнь 2010


50

Кодинг

распространенных, как Ф.И.О. и, заканчивая такими, как круг общения контакта, адреса, телефоны, явки и т.д. 3. Сохранение и загрузка локальной копии контактов из файла. 4.

Группировка контактов по группам.

5. Изменение сведений о контакте и отправка данных в Google.

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

Вот пример, как с помощью TGoogleContact можно получить документ, содержащий сведения о контактах: Contact:=TGoogleContact.Create(self, FAuth, GmailAkk); //создали экземпляр, передав в параметрах ключ Auth и адрес Gmail­почты Contact.MaximumResults:=10; //получаем по 10 контактов в документе Contact.StartIndex:=3; //начинаем получение с третьего по номеру контакта Contact.SortOrder:=TS_None; //оставляем сортировку на усмотрение Гугла Contact.ShowDeleted:=true; //просим выслать информацию по удаленным контактам Contact.RetriveContacts; //получаем контакты

Все что от нас требуется после выполнения метода RetriveContacts – это немного терпения пока прибудут все контакты. А чтобы не смотреть на уныло зависшую форму приложения можно определить события TGoogleContact: TParseElement = (T_Group, T_Contact); //события компонента TOnRetriveXML = procedure (const FromURL:string) of object; //срабатывает перед началом закачки TOnBeginParse = procedure (const What: TParseElement; Total, Number: integer) of object;//срабатывает перед тем как начнется парсинг элемента TOnEndParse = procedure (const What: TParseElement; Element: TObject) of object;//срабатывает после успешного парсинга XML­элемента TOnReadData = procedure (const TotalBytes, ReadBytes: int64) of object;//срабатывает каждый раз при получении информации из Сети

Естественно, никто не запрещает Вам, например на OnReadData заполнять ProgressBar или выполнять иные действия. Для работы с изображением, которое определено для контакта, в TGoogleContact также имеются свои методы. Например так:

Contact.RetriveContactPhoto(Selected, 'noimage.jpg')

Здесь мы попросили загрузить изображение для контакта Selected и, если этот контакт не имеет своего изображения, то показать дефолтное.

На момент написания этой статьи я заканчиваю создание демонстрационного проекта, реализующего всю работы с Контактами в Google с использованием приведенного выше модуля. Думаю, что когда выйдет журнал, проект уже будет полностью готов. Возвращаясь к началу статьи, а именно к её названию, в заключение хочется сказать, что проект «Google API в Delphi» всегда был, есть и будет бесплатным и открытым для всех желающих. Может быть поэтому я и согласился перевести проект под управление Git, которая, кстати сказать, была разработана в свое время Линусом Торвальдсом. Just For Fun . Если Вы желаете скачать исходники – не проблема. Для этого не обязательно записываться в список разработчиков – у нас полностью публичный репозиторий. Вот адрес: http://github.com/googleapi/googleapi

где вы можете скачать (бесплатно и без очереди) все исходники одним zip­архивом. Если Вас интересует конкретный API Google, то в Wiki есть сведения о том, кто конкретно разрабатывает этот модуль – найдете последние версии исходников в ветке разработчика. Ну, а для желающих поучаствовать в разработке – адрес Wiki где найдете всю необходимую информацию: http://wiki.github.com/googleapi/googleapi/

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

vr­online | июнь 2010


Автор: Агайгельдиев Руслан aka AgRuMa

51

Кодинг

Delphi

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

Сегодня вашему вниманию предлагаю несколько функций: Математические функции, Функции и процедуры для работы с символьным типом Char, Функции и процедуры для работы со строками PChar, Преобразования различных типов Для работы с этими функциями требуется в раздел uses дописать модуль Math; Пример: uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, Math;

vr­online | июнь 2010


52

Кодинг

vr­online | июнь 2010


53

Кодинг

vr­online | июнь 2010


54

Кодинг

vr­online | июнь 2010


55

Кодинг

Это далеко не все стандартные функции. Ждите продолжение в следующем номере Vr­online.

vr­online | июнь 2010


Автор: Fairhawk WWW: http://fairhawk.blogspot.com

56

Кодинг

Cracking

Реверсинг ASM KEYGENME#1 Первый урок новичкам

Данный keygenme довольно простой, но тем не мнение, рассмотрим именно его, думаю новичкам будет интересно. В качестве отладчика будем использовать всеми любимый OllyDbg)) Скачать ASM KEYGENME#1 можно в аттаче к статье. Из названия подопытного, ясно чем нам придется заняться. Перед тем как его перейти к реверсингу, запускаем его, и смотрим как он работает. После чего открываем его в отладчике. Видим следующие:

Начнем пожалуй с того, что посмотрим WinAPi функции, используемые тут, нажимаем Ctrl + N или Search for – Name(Label) in current module. Видим следующие:

Не трудно догадаться, что файл зашифрован, причем не очень хорошо. В самом начале видим прыжок на 004011AE, ПКМ – Follow. Попадаем на фрагмент кода декриптора . Так как, сейчас нам это мало интересно, пропустим этот фрагмент, нажимаем F9. Запускается программа. Дальше в отладчике, нажимаем Ctrl + A или ПКМ – Analysis – Analysis code; После чего в окне отладчика появляется основной код, нашего keygenme :

Там интересны только, GetDlgItemTexaA ( получение текста, например из поля ввода..), MessageBoxA ( вывод сообщения) и на последок wsprintfA( сравнение строк), что уже на данном этапе дает нам понять, что кейгенми довольно простой. Остановимся на GetDlgItemTexaA. Выбираем его, после чего ПКМ – Toggle Breakpoint on Import. Теперь при вызове этой функции программой, произойдет ее остановка, дабы дать нам возможность “осмотреться”.

vr­online | июнь 2010


57

Кодинг

Переходим к нашей запущенной программе, вводим любое имя, с серийником, в моем случаи Fairhawk;123456, нажимаем «ОК». После чего программа останавливается, т.к срабатывает наша точка останова, что бы убедиться в этом смотрим в нижний левый угол отладчика на строку состояния, и видим там: Breakpoint at user32.GetDlgItemTexaA. Смотрим, что у нас находиться в стеке:

Видим что, наша функция выполнилась, и теперь по адресу находиться то, что мы ввели в поле ввода «Name» !) Запоминаем адрес, думаю он нам пригодиться). Убираем Breakpoint, и нажимаем F7 что бы выйти из функции. Останавливаемся на строчке:

MOV DWORDPTRDS:[403100],EAX

Которая заносит результат выполнения функции ( в данном случаи количество символов), в «ячейку» по адресу 403100. После чего EAX обнуляется, командой: XOR EAX,EAX.

Давайте обратим внимание на выделенную зеленным цветом строчку. Тут указывается на некий буфер, куда по идеи должно занестись выполнение нашей функции. Выделяем данную строчку, и нажимаем ПКМ – Follow in Dump.

Видим что тут пока не чего нет, т.к мы остановили нашу программу только на начале функции, и она еще не успела выполниться. Нужно это исправить. Выделяем строку где произошла наша остановка, и нажимаем F2, что снимет от туда Breakpoint.

Нажимаем ПКМ на MOV DWORD PTR DS:[403100],EAX– Follow Dump – Memory address. И видим что там тоже пусто. Но стоит нам выполнить данную команду нажатием F7, как видим там:

Число 8, в моем случаи количество символов в слове «Fairhawk») Также «запоминаем» адрес). Чуть ниже, видите еще один вызов GetDlgItemTexaA, в точности похожею на первый:

Красным цветом выделен, первый, нами разборный, вызов этой функции. Заметим так же, что тут в строчке: PUSH ASM_KEYG.004030C0

И указывается, тот адрес, куда и заноситься наше имя, в моем случаи «Fairhawk». Во втором, вызове видим подобное: PUSH ASM_KEYG.004030E0

Опять же нажатием F2 ( хотя если ты читаешь этот материал, то ты наверняка знаком с этим) ставим новую точку останова.

Нажимаем F9, и наш keygenme снова останавливается, но только уже на другом месте Снова смотрим на наш адрес в дампе. После чего ставим новый, на конце этой функции:

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

Нажимаем F9. После чего ПКМ на PUSH ASM_KEYG.004030E0– Follow Dump –Immediate constant. Как видите, наши предположения оправдались:

vr­online | июнь 2010


58

Кодинг Там действительно находиться наш серийный номер. Убираем, точку останова, нажимаем ПКМ на MOV DWORD PTR DS:[403128],EAX– Follow Dump – Memory address, после чего F7,и видим что 403128 находиться число 6 ) длина нашего серийника).

Теперь осталось выяснить, где используется наши числа (6 и 8). Сделаем так, найдем в дампе первое ( 8 ), после чего выполняем следующие:

MOVS XEAX,BYTE PTR DS:[ECX+4030C0] – Начало цикла, где берется первый символ нашего имени, после чего выполняется, сам алгоритм генерации ключа, до момента: CMP ECX,DWORD PTR DS:[403100] JNZ SHORT ASM_KEYG.00401137

Где проверяется, всели буквы были «пройдены». После чего результат заноситься в стек, из регистров EDI и ESI. Затем вызваться функция wsprintfA для преобразования, всего этого в нужный нам формат:

"LOD­%lu­%lX". Затем проверка на правильность нашего, и сгенерированного недавно ключа тут:

Это тот же Breakpoint, только ставиться он на определенный участок в дампе, который срабатывает при любом вызове к этому адресу. И так, убираем наш предыдущую точку останова, и нажим��ем F9. Останавливаемся тут:

Поставим Breakpoint там, где это сделал я. Нажмем F9. И видим, что нам приходиться сравнивать.

В String1 находиться нужный нам серийник.

CMP EAX,0

Тут и видим CMP DWORD PTR DS:[403100],0 обращение к нашему адресу(где у нас находиться длина нашего имени – 8 ), в данном случаи, происходит проверка, «если по адресу 403100 находиться 0, то вывести пользователю не приятное сообщение). Чуть выше тоже самое, но уже с адресом 403128 (длина поля для серийника – 6). После того как программа убеждается, что поля не пустые, выполняется выделенный красным цветом код. Перед тем как разбирать его, уберем наш Breakpoint , который расположен в дампе. Делается это так:

ПКМ – Breakpoint­ Remove memory Breakpoint, все первые 4 строчки в выделенной рамки, Обнуляют ESI, ECX, а в EDX заноситься 0A (10);

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

Если наш серийник правильный, то в EAX должен оказаться 0. Давайте проверим это. Убираем точку останова, нажимаем F8 (тоже самое, что и F7, только не заходит внутрь функций).

Как видите зеленым выделено подтверждение того, что наш серийник не правильный, иначе бы там было 0 )). И флаг Z будет содержать 0, после чего выполниться переход выделенный синим цветом, к плохому сообщению, затем программа закроется. Перед тем как писать не посредственно keygen давайте проверим то, что я сейчас сказал). Нажимаем 2 раза F7, пока наш курсор не

vr­online | июнь 2010


59

Кодинг

окажется на:

JNZ SHORT ASM_KEYG.00401191

Как видите, красная линия показывает, что он выполниться, смотрим куда.. и видим что к не очень хорошему для нас сообщению. Кликаем 2 раза на флаг Z:

И видим, что переход стал тусклым, что означает, что «прыжка» не будет, а вместо этого выполниться строчка под ним. Давайте посмотрим, нажимаем F9!!! И как нашей радости видим, что программа говорит нам, о том, что серийник правильный. Осталось только написать keygen. Все что нам для этого нужно, так это взять кусок кода генерации, а именно:

XOR ESI,ESI XOR ECX,ECX XOR EDX,EDX MOV ECX,0 MOV EDX,0A MOVSX EAX,BYTE PTR DS:[ECX+4030C0] INC EAX ADD EAX,EDX ADD ESI,EAX INC ECX IMUL EDX,ECX MOV EDI,EDX IMUL EDI,ESI CMP ECX,DWORD PTR DS:[403100] JNZ SHORT ASM_KEYG.00401137

И переделать под свои нужды. Скачать написанный мной keygen на masm32 ты можешь скачать в аттаче. Он слегка сыроват, но зато исправно работает.

vr­online | июнь 2010


Перевод: Роман Костенко aka Lord_of_fear. e­mail: kostenko.r.khv@gmail.com

60

Кодинг

PHP

Библиотека мануалов Инструкция по созданию собственной библиотеки мануалов

Когда пользователям приходится вводить текст, они часто делают грамматические ошибки, опечатываются, используют нелепые сокращения и вообще ведут себя непредсказуемо. ­ Энди Харрис

Привет. Перед тобой инструкция по созданию собственной библиотеки мануалов, работая с которой, пользователи могут не только изучать, но и оставлять свои комментарии. Это – не подробное описание для новичков, а лишь комментарии к участкам кода. Если есть знания PHP, то разберешься дальше сам. Итак, поехали…. :)

Начнём, конечно же, с создания базы данных на сервере БД, в качестве которого выбран MySQL. Можно создать таблицы вручную, но проще воспользоваться скриптом (см. в аттаче файл mysql.txt)

Как можно заметить, у нас будут 3 таблицы: категория, комментарии и мануалы. Теперь создай в корне на веб сервере файл “dbconnect.php”, который будет отвечать за установку коннекта с мускулом. Помести в него следующий код: <?php $connection = mysql_connect ('localhost', 'username', 'password') or die ('Unable to connect!'); @mysql_select_db('database') or die (mysql_error()); ?>

Естественно, не забудь вписать свои данные: логин, пароль, имя базульки. Далее создавай прямо в корне на веб сервере директорию “admin”. Здесь будут все странички, предназначенные для администрирования. В эту директорию положим файл “index.php” и внесём в него следующий скрипт: <?php include('../dbconnect.php'); if(!isset($_GET['page'])){ $page = 1; }else{ $page = $_GET['page']; } $max_results = 10; $from = (($page * $max_results) – $max_results); $query = "SELECT * FROM `tutorials` ORDER BY id DESC LIMIT $from, $max_results"; $result = mysql_query($query) or die("Error in query: $query . " . mysql_error()); echo '<a href="add.php">Add Tutorial</a> | <a href="add_category.php">Add category</a> | <a

href="category.php">Manage Catagories</a><hr>'; if(mysql_num_rows($result) > 0) { while($row = mysql_fetch_row($result)) { ?> <table width="100%"> <tr> <td width="40"><img src="<?php echo $row[3] ?>" alt="<?php echo $row[1]; ?>"></td> <td><h1><?php echo $row[0]; ?>: <?php echo $row[1]; ?><br /><a href="edit.php?id=<?php echo $row[0]; ?>">Edit</a> | <a href="delete.php?id=<?php echo $row[0]; ?>" onClick="return confirm('Are you sure you want to delete this tutorial?')">Delete</a> | <?php $count = mysql_query("SELECT * FROM comments WHERE id='".$row[0]."' AND cat='tutorials'") or die(mysql_error()); $comments = mysql_num_rows($count); echo '<a href="comments.php?id='.$row[0].'">'.$comments.' comments</a>'; ?></h1></td> </tr> </table> <hr> <?php } } else { echo 'No Tutorials<hr class="news">'; } echo '<center>'; $total_results = mysql_result(mysql_query("SELECT COUNT(*) as Num FROM tutorials"),0); $total_pages = ceil($total_results/$max_results); for($i = 1; $i <= $total_pages; $i++){ if(($page) == $i){ echo "$i "; }else{ echo "<a href='?page=$i'>$i</a> "; }} echo '</center><hr>'; echo '<a href="add.php">Add Tutorial</a> | <a href="add_category.php">Add category</a> | <a href="category.php">Manage Catagories</a>'; mysql_close($connection); ?>

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

vr­online | июнь 2010


61

Кодинг

Продолжим с создания страницы управления категориями. Создай в папке админки файл “category.php” и внеси в него код:

<?php include ("../dbconnect.php"); $query = "SELECT * FROM `category` ORDER BY id ASC"; $result = mysql_query($query) or die("Error in query: $query . " . mysql_error()); if(mysql_num_rows($result) > 0) { while($row = mysql_fetch_object($result)) { ?> <h1><?php echo $row­>id; ?>: <?php echo $row­>name; ?> <a href="edit_category.php?id=<?php echo $row­>id; ?>">Edit category</a> | <a href="delete_category.php?id=<?php echo $row­>id; ?>" onclick="return confirm('Are you sure you want to delete category?')">Delete category</a></h1> <h2>Description</h2> <?php echo $row­>description; ?><br /> <img src="<?php echo $row­>avatar ?>" alt="<?php echo $row­ >name; ?>"><hr> <?php } } else { echo 'No Catagories'; } echo '<a href="add_category.php">Add category</a> | <a href="index.php">Go back to admin home page</a>'; mysql_close($connection); ?>

Теперь у нас уже появилась возможность просматривать и редактировать категории, но для полноценной работы этого не достаточно. Добавим скрипт добавления новой категории. Пусть файл называется “add_category.php”. Чуть позже мы подробнее разберём как это работает. А пока вот код для добавления категории: <?php include ("../dbconnect.php"); if (!isset($_POST['submit'])) { ?> <form action="<?php echo $_SERVER['PHP_SELF']; ?>" method="post"> <h1>Add Tutorial category</h1> <h2>category Name</h2> <input name="name" type="text"><br /><br /> <h2>Avatar</h2> <input name="avatar" type="text"><br /><br /> <h2>Description</h2> <textarea name="description" cols="50" rows="4"></textarea><br /><br /> <h2>Website URL</h2> <input name="site" type="text"> <p><input type="Submit" value="Submit" name="submit"></p> </form> <?php } else { $name = $_POST['name']; $avatar = $_POST['avatar']; $description = $_POST['description']; $site = $_POST['site']; $query = "INSERT INTO category (name, avatar, description,

site) VALUES ( '".$name."', '".$avatar."', '".$description."', '".$site."')"; mysql_query($query)or die(mysql_error()); echo 'Category Successfully added! <a href="index.php">Go back to admin home page</a>'; } mysql_close($connection); ?>

Эта страничка даёт нам простую форму для добавления новой категории. Добавь несколько записей и сможешь работать со списком категорий (category.php). Теперь нужно добавить возможность редактирования. Создай файл “edit_category.php” и добавь в него код: <?php include ("../dbconnect.php"); if (!isset($_POST['submit'])) { if ((!isset($_GET['id']) || trim($_GET['id']) == '')) { die ('Missing record ID!'); } $id = $_GET['id']; $query = "SELECT * FROM category WHERE id = '$id'"; $result = mysql_query($query) or die ("Error in query: $query. " . mysql_error()); if (mysql_num_rows($result) > 0) { $row = mysql_fetch_object($result); ?> <form action="<?php echo $_SERVER['PHP_SELF']; ?>" method="POST"> <h1>Edit Catagoy #<?php echo $id; ?></h1> <input type="hidden" name="id" value="<?php echo $id; ?>"> <h2>Name</h2> <input value="<?php echo stripslashes($row­>name); ?>" name="name" type="text" size="50"><br> <br> <h2>Avatar</h2> <input value="<?php echo stripslashes($row­>avatar); ?>" name="avatar" type="text" size="50"><br> <br> <h2>Description</h2> <textarea name="description" cols="50" rows="4"><?php echo stripslashes($row­>description); ?></textarea> <br> <br> <h2>Site</h2> <input value="<?php echo stripslashes($row­>site); ?>" name="site" type="text" size="50"><br> <p> <input name="submit" type="Submit" value="Submit"> <input type="reset"> </p> </form> <?php } else { echo 'News item not found!'; } } else { $id = $_POST['id']; $name = $_POST['name']; $avatar = $_POST['avatar']; $description = $_POST['description'];

vr­online | июнь 2010


62

Кодинг

$site = $_POST['site']; $query = "UPDATE category SET name = '".$name."', avatar = '".$avatar."', description = '".$description."', site = '".$site."' WHERE id = '".$id."'"; $result = mysql_query($query)or die(mysql_error()); echo 'Category successfully edited. <a href="index.php">Go back to admin home page</a>'; } mysql_close($connection); ?>

При переходе на эту страницу методом GET ( ?id= ) будет передаваться номер категории, которую необходимо отредактировать. Для сохранения изменений нужно кликнуть по пимпе “submit”. Последние действие, которое необходимо реализовать, ­ это удаление категорий. Файл delete_category.php:

<?php include ("../dbconnect.php"); if ((!isset($_GET['id']) || trim($_GET['id']) == '')) { die('Missing record ID!'); } $id = $_GET['id']; $query = "DELETE FROM category WHERE id = '$id'"; $result = mysql_query($query) or die ("Error in query : $query. " . mysql_error()); $query = "SELECT id FROM tutorials WHERE category = '".$_GET['id']."'"; $result = mysql_query($query) or die ("Error in query : $query. " . mysql_error()); while ($row = mysql_fetch_object($result)) { $query = "DELETE FROM comments WHERE id = '".$row­ >id."'"; $result = mysql_query($query) or die ("Error in query : $query. " . mysql_error()); } $query = "DELETE FROM tutorials WHERE category = '$id'"; $result = mysql_query($query) or die ("Error in query : $query. " . mysql_error()); echo 'Category records, Tutorial records and Comment records successfully deleted. <a href="index.php">Go back to admin home page</a>'; mysql_close($connection); ?>

Как и в случае с функцией редактирования, номер категории передаётся скрипту методом GET. Производится удаление категории и все записей, связанных с ней. Т.е удаляется не только категория, но и все мануалы по этой теме, а так же комментарии к ним.

Редактирование материала выполняет код из edit.php. Тут нужно учитывать, что вместо имени категории будет отображаться лишь её ID. Каждой категории соответствует уникальный ID, который можно посмотреть на страничке category.php.

Последней страницей управления самими мануалами является delete.php. Принцип функционирования такой же, как и у delete_category.php. При удалении записи так же удаляются все комментарии к ней. Последние страницы администрирования comments.php, delete_comment.php отвечают, соответственно, за отображение и удаление комментариев.

Теперь мы закончили с администрированием и подошли в плотную в к нашей основной страничке. tutorials.php – отображает 10 последних добавленных мануалов. Файл category.php в отличие от tutorials.php отображает лишь мануалы по определённой категории. Методом GET обязательно должен передаваться ID категории. Например, если обратиться к странице так: www.yoursite.com/category.php, то мы получим пустую страницу. А вот если будет так www.yoursite.com/category.php?id=2, то мы получим список мануалов по категории с ID равной 2. Страничка viewtut.php отображает содержимое мануала. Входные данные – ID мануала.

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

Оригинал статьи: http://designkai.com/complete­tutorial­ management­system­part­1­getting­started/

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

vr­online | июнь 2010


63

Я прусь!

Я прусь!

Делимся впечатлениями Только позитив...

Jimmy Jonezz: Долгое время у меня не было времени настроить систему ГИСТ (бесплатный интернет предоставляемый правительством РТ) у себя на работе. Не было "нормальной" локалки, чтобы один раз настроил и сразу пользуйся. И вот свершилось ­ некоторое время назад, я переехал в новый кабинет, более просторный, более светлый и более просторный. Радуюсь новой "локалке", но самое главное ­ настроил систему ГИСТ, и теперь у меня бесплатный интернет со скоростью ~800­900 Кб\сек. Радости нет предела, но сыр не бесплатный и это обусловлено некоторыми ограничениями ­ зарубежные сайты недоступны (не все), ограничение на открытие некоторых российских ресурсов, полный запрет серфинга по развлекательным ресурсам Рунета. В остальном, я прусь, что у меня есть такой интернет, но больше всего, что наконец реализованы все мои задумки по использованию этой системы. zahod5277: Долго перебирал самые позитивные моменты прошедшего месяца, и, если удалить наиболее личные, то остается всего ничего, и самый замечательный из них ­ это мой N900. За прошедшие два месяца, которые я его юзаю, нареканий на этот чудо­аппарат совсем чуть чуть. Пара багов, редкие зависоны. Ну а в остальном ­ офигенная штука! Ощутить весь кайф от использования этого аппарата получилось, находясь в

Тюмени. Надо найти гостиницу ­ ищем в нете адрес гостиницы, забиваем в навигатор. Приехали! А инет! Инет­то там какой! Когда я увидел в статус­ области своего N900 вместо цифр 2.5 цифру 3 и букву G, первым делом побежал на youtube. Так как MicroB с самого рождения умеет работать с Flash, смотреть видео одно удовольствие. Нажал Play, потом паузу. Подождал секунд 15­20 и наслаждался просмотром. Если бы pidgin умел работать с протоколом mail.ru агента я бы даже нетбук не включал. Иметь интернет­ планшет с функцией "позвонить" в большом городе ­ это кайф. Spider_NET: Утренняя зарядка ­ это настоящий кайф. В июне мы с lord_of_fear взяли за правило каждый день подтягиваться. Мой друг нам прислал свою программу­тренировок и решили мы придерживаться ее рамок. Помню как в первые разы было тяжело. Тогда с трудом верилось, что спустя месяц количество (и качество) подтягиваний существенно увеличиться. А теперь результат на лицо! Подтягиваться мы стали больше, а чувствовать себя лучше. Считаю, что зарядка ­ это жизненная необходимость. С утра, тело нужно обязательно размять и подготовить к дневным нагрузкам. Особенно, утренние упражнения необходимы тем людям, чья работа сводится к просиживанию целого дня в кресле (программисты,

айтишники, экономисты и т.д.). Не уделяя должного времени на физические упражнения, каждый из представителей этих профессий рискует набрать излишний вес. Не уже ли он кому­то нужен? За примером далеко ходить не надо. Я когда устраивался на первую работу весил ~83 килограмма (у меня рост 185 см). Проработав полтора года, мой весь взлетел до 95­96. Офигеть можно!!! Я реально чувствовал себя не комфортно. Потом я перешел на новую работу и взял в привычку делать утреннюю зарядку. Пролетело полтора года и теперь мой вес составляет 85,5. Т.е. я практически вернул массу, которая у меня была три года назад. Считаю это круто и не собираюсь останавливаться на достигнутом. Испытываю желание сбросить еще хотя бы пять кг. Lord_of_fear: Вот нравится мне заниматься спортом и всё тут. Хорошее физическое состояние даёт дополнительный позитивный настрой. Раньше я занимался этим только по утрам перед работой. Утренняя пробежка, подтягивания, отжимания. Другого времени, казалось мне, просто нет. Ведь на работе не позанимаешься, а после работы хочется добраться домой, принять душ, покушать и немного отдохнуть. А потом уже получается так, что и спорта никакого не хочется. Желание одно – баиньки. Да и с полным желудком заниматься не будешь. С неделю назад я изменил свой режим и стал vr­online | июнь 2010


64

Я прусь!

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

пишешь смс­ки.

WWWNET: Прусь я от того, что наконец­то закончил учебу. Свобода!!! Теперь времени будет хватать и на работу, и на личные проекты, и на VR. Кстати, не могу не похвастаться, за госы и защиту диплома получил 5. :)

Другого времени, казалось мне, просто нет. Ведь на работе не позанимаешься, а после работы хочется добраться домой, принять душ, покушать и немного отдохнуть. А потом уже получается так, что и спорта никакого не хочется. Желание одно – баиньки. Да и с полным желудком заниматься не будешь. С неделю назад я изменил свой режим и стал перекусывать на работе в 16.00. В результате я сдвинул ужин на час­полтора. Вот как раз этот час я и трачу на поддержание себя в хорошей физической форме. Прям кайф испытываешь после того, как весь день работал мозг, а вечером поработали мышцы. Я тащусь. Попробуй сам :) Kastor: В конце июня я приобрел себе коммуникатор Samsung i900. Стоит ли говорить, что я прусь от него. Мощные технические характеристики, большой экран, GSM модуль (носить телефон в довесок к КПК не хотелось бы), WiFi и GPS (само собой разумеется) и, внимание тачпад. Да­да, настоящий тачпад. Очень удобная штука, например, когда едешь в автобусе. Стилусом при наших дорогах экран и проткнуть можно. А так я спокойно могу запускать нужные приложения, водя курсором по экрану. Кстати, на счет приложений. На аппарате установлена Windows Mobile 6.1. А большинство прог для работы с WiFi написано под нее. Давно хотел такой девайс. Целый мини компьютер у меня в кармане. Теперь можно не ныкаться с нетбуком сканируя сети, а в наглую заходить в здания и делать вид, что

vr­online | июнь 2010


Автор: Kastor Email: KastorDriver@gmail.com

65

Обзоры от VR

Samsung i900

Обзор мобильного устройства Взгляд со стороны

Не могу я без девайсов. Телефон, mp3-шник, нетбук. Эти вещи почти всегда находятся при мне и, забывая их дома, появляется такое ощущение, что я: вышел на полигон без оружия, зашел в магазин без денег, поехал кататься без скутера. По разному. Так вот недавно я приобрел себе коммуникатор i900. Телефон, плеер, компьютер в одной упаковке + еще куча полезных возможностей, о которых я сейчас расскажу.

С первого взгляда коммуникатор внушает уважение. Строгий дизайн, серые и темные тона, закругленные края. Солидности добавляет металлическая окантовка, которая, на мой взгляд, очень даже не лишняя. Что бы удобно держать такой коммуникатор в руке, надо привыкнуть. Особенно после использования обычных, маленьких по сравнению с ним телефонов. Вес аппарата, где­то под 120 грамм, что совсем не много. Тяжесть вовсе не ощущается в руке, и совсем немного – в кармане. Никаких поскрипываний и люфтов нет и в помине. Даже задняя крышка от аккумулятора прилегает очень плотно.

В общем, сборка очень качественная. А о том, насколько, вы можете судить после просмотра его краштеста: http://www.youtube.com/watch?v=GDiclWPYm38

Коммуникатор держали в морозилке, оставляли в мешке работающего пылесоса, окунали в воду и пиво, роняли и даже проехались по нему автомобилем. Краштест не удался. Samsung i900 остался цел. Кнопки на корпусе вполне стандартные. На лицевой панели кнопки ответа, сброса вызова.

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

Но иногда его очень даже удобно использовать, когда надо быстро получить доступ к какому либо приложению. Ярлыки большие, можно пальцем по экрану выбрать нужное приложение, а не лезть в «пуск» ­> «программы» и так далее. Этой же волшебной кнопкой можно переключаться между запущенными приложениями, что­то похожее на Alt+Tab в обычной винде.

Кстати о системе. Коммуникатор работает под управлением Windows Mobile 6.1. Да, не андроид, как бы многим хотелось. Но для меня это наоборот плюс. Все­ таки большинство различных программ написано именно под эту платформу. И еще одно. Возможность, подключившись к сети, просматривать файлы в открытых папках, как я понимаю, есть только в Windows Mobile. Теперь мой i900 полноценный клиент моей домашней беспроводной сети. Возможно, мобильная винда и самая тормознутая из всех систем для таких девайсов, но процессор в 624 МГц и ОЗУ в 128Мб не дают ему зависнуть. Его производительности хватает с избытком. Просмотр страниц в браузере, подключившись через WiFi, прослушивание vr­online | июнь 2010


66

Обзоры от VR

музыки и еще парочка не закрытых программ вовсе не нагружают коммуникатор. Кстати, по давно сложившейся традиции в операционных системах семейства виндовс, самой ходовой программой является «Диспетчер задач». Но в этот раз он используется не для завершения зависших программ, а для их закрытия. Если в программе не предусмотрен пункт меню для выхода, то крестик в верхнем углу просто сворачивает программу. К этому быстро привыкаешь и мне кажется, что это удобнее, чем для запуска другой программы, рыться в меню, чтобы свернуть работающую. Закрывать программы при помощи диспетчера задач приходится не так часто. Оперативной памяти «хватает на всех». А памяти самого устройства в 8 гигабайт хватает с избытком. Я так говорю, потому что на нетбуке у меня тоже всего 8 гиг HDD, так что не привыкать. Плюс можно воткнуть microSD, на который записываемая информация, при желании, может шифроваться.

Рабочий стол мне пришелся по душе. Сверху подобие панели задач с бессмертной кнопкой «Пуск». Слева выезжающая панель с различными виджетами, которые можно вытаскивать на 3.2 дюймовый экран. Для меня нужными являются часы, календарь (вечно забываю какой сейчас день недели, да и выглядит он красочно) и диспетчер соединений. Ходовая вещь, ведь я так часто включаю/выключаю WiFi.

Теперь рассмотрим возможности ввода. Да, большой экран позволяет управлять приложениями, клацая пальцем по экрану. Я и сам иногда так делаю. Но не гоже пачкать экран, когда есть стилус, который, в отличие от других КПК, висит на ушке с боку, а не всовывается в корпус. Поначалу неудобно. Он может бряцать по корпусу, как ненужная примочка на телефоне, но не так уже и часто придется трусить коммуникатор. Выдвижной стилус, после нескольких проб, можно легко отсоединять от колпачка одной рукой, а так же соединять обратно. Сенсор на экране немного туговатый (по сравнению с некоторыми моделями, наверное, даже дубовый), но это не намного

затрудняет управление.

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

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

Переходим к разъемам, которых в i900 всего один. Уверен, ты уже догадался, что это собственный разъем коммуникатора, в который и зарядник, и шнур USB, и наушники втыкаются. Хотя нет. Наушники сначала в переходник вставляются, а он уже в i900. Сначала, дорогой читатель, я не хотел показывать тебе фотку наушников, что бы ты мог спать спокойно. Но я передумал, хе­хе. Вот спрашивается, как такое можно воткнуть в уши? Лично мне было страшно. Они напоминают, какие ни будь примочки злобного доктора из фильма ужасов, которые крепятся к

vr­online | июнь 2010


67

Обзоры от VR

телу. Ужас. Я их так в пакетике и оставил. Обхожусь своими родными, с нормальной формой. Вообще отсутствие разъема для наушников в 3.5мм двойственно. С одной стороны ужасно неудобно путаться в проводах, как елка в гирляндах. А с другой, i900 потому и перенес испытание пылью и влагой, что в нем нет лишних «дырок». Динамик коммуникатора достаточно громкий, что бы не скучать в дороге, но супер качества не будет. Это вам не Motorola E398, которой можно было глушить школьные дискотеки, особенно после перепрошивки.

http://kastordriver.livejournal.com

На прицеле беспроводные интерфейсы. WiFi, Bluetooth, GPS. Все на месте, ничем не обделили. Модуль WiFi я бы оценил на 4­ку. Ясное дело, что до модулей установленных в ноутбуках он не дотянул бы, но то, что он слабее модуля WiFi Nokia Т97 отнимает заветный балл. Плюс убожеская стандартная программа, которая сети разве что впритык видит. Да не страшно. Лечится это дело сторонними программами, которые такие сети найдут, что тебе и не снилось.

О Bluetooth не знаю что сказать. Работает. Особо не гонял его. А вот GPS славная вещь, пришлась мне по душе. Холодный старт, где­то минут 4­5. А дальше уже можно смотреть на Google Maps куда тебя занесло. А если же рядом есть выход в инет, то свое местоположение можно определить по координатам мобильных вышек, среди которых ты находишься. Так что заблудиться тебе будет трудно. Батарея держит прилично. Почти 1500 миллиампер хватает дня на два­три. При включенном WiFi и GPS (да­да, картографированием занимался) коммуникатор продержался три часа. После этого в запасе осталось 20% заряда. Так что аккумулятор здесь отнюдь не слабое место.

Вот немного и пролил я свет на этот замечательный коммуникатор. Пользуюсь им уже где­то две недели – нареканий нет. Планирую и дальше качать его софтом, в основном для работы с WiFi, о чем буду периодически отписывать в блоге. В место вывода могу сказать, что среди своих конкурентов Samsung i900 стоит в первых рядах. vr­online | июнь 2010


Автор: Антонов Игорь aka Spider_NET Email: antonov.igor.khv@gmail.com

68

Обзоры от VR

"Джоэл о программировании" Joel on Software

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

В прошлом году, я по рекомендации Михаила Стиль изложения: 9/10 Фленова (http://flenov.info) купил себе книгу Общие впечатления: 10/10 "Джоэл о программировании". Данная книга не является технической в полном смысле этого слова. Это просто набор заметок­ советов из блога одного талантливого программиста ­ Джоэла Спольски. Заметки Джоэла были по достоинству оценены и в итоге автор принял решение сгруппировать посты и издать книгу.

Про что книга

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

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

Мои оценки:

Интересность: 10/10 Полезность: 9/10

vr­online | июнь 2010


Автор: Роман Костенко aka Lord_of_fear Email: kostenko.r.khv@gmail.com

69

Обзоры от VR

Ubuntu и Debian Linux для продвинутых Более 1000 незаменимых команд

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

Эта книга по заверению издателя относится к “серии для профессионалов”. Спорное заявление. Если для профессионалов, то зачем рассказывать такие элементарные вещи как: копирование файлов, создание директорий, новых пользователей и пр.? Профессионалы это давно уже умеют делать. Поэтому книга не для профессионалов, а для продвинутых. Как говорится “Advanced user”…Что как раз и написано на обложке.

Стоит книга всего 330 рублей. Подведём итоги:

Полезность: 4/5 (Если это ­ твоя первая книга по Linux), 3/5 (Если книга ­ хотя бы вторая) Стиль изложения: 4/5 Перевод: 5/5

Качество печати: 5/5

Оправданность цены: 100% Купить эту книгу ты можешь в магазине ozon.ru. Прямая ссылка на книгу в магазине: http://www.ozon.ru/context/detail/id/5099661/

Перевод на высоком уровне. К этому претензий нет. Но чи��ать книгу откровенно скучно. Как­то неинтересно она написана. Т.к. эта книга не для профессионалов, то и общаться нужно с читателем на более простом языке. Но, видимо, авторам виднее. Некоторые моменты совсем не раскрыты. Как, например, работа с каналами и сокетами. Написан один абзац и всё. Типа разбирайтесь сами. Авторы не компетентны в этом вопросе? Сомневаюсь. Причина остаётся непонятной… Кстати, именно поэтому я созрел и написал для этого журнала статью про именованные каналы и сокеты Unix.

Очень понравилось оформление материала в книге. Все ключевые понятия и команды выделены разными типами и разной толщиной шрифтов. Описание даётся во вступлении.

vr­online | июнь 2010


Автор: Антон Козлов ака Jimmy Jonezz Email: jimmyjonezz@bk.ru

70

Без рамки

TeX & LaTeX Язык разметки

Погружаемся в тонкости языка разметки TeX и LaTeX TEX самостоятельно, на основе выбранного пользователем шаблона, форматирует На протяжении всего учебного процесса, нам документ, можно легко обойтись без приходится сталкиваться с проблемами дизайнера и верстальщика. При этом, оформления сложных документов, будь то пользователь сам выступает в качестве реферат по химии или физике, а может даже последних. и по геометрии. Что говорить о рефератах, дипломных и курсовых работах, которые Документы, представляют из себя обычные насчитывают, в среднем, более десятка ASCII­файлы, которые содержат страниц, но дело не объеме, а в содержании, информацию о форматировании текста или в том, как «правильно» выводе изображений, по аналогии их можно расставить\выровнять\расположить текст, сравнить с обычной html­страницей, т.к. оба изображения и формулы. являются языком разметки документов.

Введение

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

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

Огромные возможности TeX предоставляют готовые наборы макросов и расширений, к ним можно отнести: LaTeX и AMS­TeX. В связи с тем, что само ядро TeX неизменно, все дополнения к нему, в том числе макрорасширения, пользовательские оболочки, драйверы, документация и т.д. и т.п., написанные другими авторами и предлагаемые вниманию пользователей, должны носить другие имена (в которые обычно включается название TeX – прим. автора) и могут быть свободно распространяемыми, но кроме этого, и коммерческими продуктами. При использовании пакета расширения LaTeX можно превратить разросшуюся статью в книгу изменением одного слова в исходнике, вставлять оглавление одной командой, не задумываться о нумерации разделов, теорем, рисунков. Есть много пакетов для оформления химических формул (например, пакет XymTeX), диаграмм (xypic), создания презентаций и визитных карточек и тому подобного. Чтобы создавать шрифты, с помощью TeX, была придумана система ­ METAFONT, в которой шрифты описываются программами на специализированном языке Meta. Могут также использоваться

Благодаря тому, что в TeX, пользователь лишь задает текст и его структуру, с помощью специального языка разметки, и vr­online | июнь 2010


71

Без рамки

векторные шрифты в формате PostScript Type 1, TrueType и OpenType.

Немного истории

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

После того, как Д.Кнуту пришлось заново набирать второе издание второго тома книги «Искусство программирования», у него родилась идея создания собственной типографической системы. Все это благодаря вмешательству прогресса ­ монотипия была замещена фотографической техникой, и оригинальные шрифты больше не использовались, и в связи с этим приходилось заново набирать весь текст. Заинтересовавшись возможностями цифровой типографии, Д.Кнут, в своих заметках, начал описывать базовые возможности TeX (13 мая 1977).

Первая версия системы TeX, появилась в 1979 году, в 1982 году выходит новая версия, которая была переписана заново и называлась TeX82. В разработке языка принимали участие знаменитые ученые ­ Франк Лян, Гай Стил. Благодаря пытливым и находчивым умам, язык Tex все больше и больше принимал вид той системы, которая отвечает необходимым требованиям. В последнее время обновления практически не происходят (может, если только очень мелкие), основной упор стоит на исправлении ошибок. Последнее обновление датируется 2008 годом и это третья версия TeX.

LaTeX

Как я уже говорил, язык разметки LaTeX – это макропакет системы компьютерной верстки TeX. Эта система призвана расширить возможности последнего, но на самом деле как такового расширения нет, благодаря различным упрощениям,

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

Главная идея LaTeX состоит в том, что авторы должны думать о содержании, о том, что они пишут, не беспокоясь о конечном визуальном облике (печатный вариант, текст на экране монитора или что­то другое). Готовя свой документ, автор указывает логическую структуру текста (разбивая его на главы, разделы, таблицы, изображения), а LaTeX решает вопросы его отображения. Так содержание отделяется от оформления. Оформление при этом или определяется заранее (стандартное), или разрабатывается для конкретного документа.

Язык.

Пришел момент, когда немного стоит окунуться в сам язык разметки. На небольших примерах посмотрим, что же он из себя представляет. Конкретно, обратимся к языку LaTeX, как к одному из более известных и популярных микропакетов. Первое правило гласит, что все команды начинаются с обратного слеша, обязательные параметры заключаются в фигурные скобки, а необязательные – в квадратные. Для определения того, что документ имеет разметку и относится к какому­либо классу, существует команда \documentclass, в обязательных параметрах указывается один из следующих классов: article ­ короткая статья;

report ­ длинная статья, с главами book ­ книга

slides ­ набор слайдов letter ­ письмо

Конструкция, вида \begin{document} … \end{document}, говорит о том, что это тело документа. LaTeX отображает данные заключенные в этой конструкции, но кроме того, в преамбуле (все, что находится перед командой \begin{document}) могут vr­online | июнь 2010


72

Без рамки

задаваться, кроме класса документа, используемые пакеты (команда \usepackage), автор (команда \author), название документа (команда \title), дата создания (\date) и т. д. Например, код ниже, наглядно продемонстрирует нам, что документ выводит на печать слово «vr­online ­ сегодня», заглавие которого будет следующим – «Пример вывода текста». \documentclass{article} % Это комментарий!

\usepackage[russian]{babel} % Пакет поддержки русского языка

\title{Пример вывода текста} % Заглавие документа \begin{document}

vr­online – сегодня \end{document}

Текст не выводится в оригинальном виде, а форматируется следующим образом: ­ Два или больше пробелов эквивалентно одному пробелу.

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

Немного усложним задачу и попробуем вывести матрицу (матрица состоит из n­ого количества строк и столбцов.) – подключаем пакет ­ \usepackage{mathtext}. Чтобы составить матрицу нужно воспользоваться конструкцией «\begin» … «\end» и применить окружение «array». При этом, стоит четко запомнить, что формулы внутри текста надо размещать между командами «\(« и «\)» или в окружении math (между «\begin{math}» и «\end{math}»), или выделять с обеих сторон знаками доллара «$»:

должна заканчиваться командой «\\», кроме последней, а элементы внутри одной строки, относящиеся к разным столбцам, отделяются друг от друга символами «&». Команды \vdots, \ddots и \ldots задают различные виды многоточий, и как вы, наверное, догадались, нижние индексы обозначают командой подчеркивания – ��_». Легко ли будет в будущем ее редактировать? Можете не отвечать, ответ итак известен. LaTeX самостоятельно выравнивает тексты, определяет переносы, интервалы между словами, строками и абзацами. Давайте немного глянем на возможности данной системы, которые поистине неограниченны (благодаря механизму программирования новых макросов). • высококачественные алгоритмы расстановки переносов, определения междусловных пробелов, балансировки текста в абзацах;

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

• удобный механизм цитирования библиографических источников, работы с библиографическими картотеками;

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

• оформление химических формул и структурных схем молекул органической и неорганической химии; • оформление графов, схем, диаграмм, синтаксических графов;

Вышеприведенная матрица будет печататься без порядкового номера, и располагаться в отдельной строке, благодаря командам ­ «\[« и «\]». Количество столбцов мы задаем с помощью аргумента {сссс}, по количеству «с». Этот аргумент центрирует значения, но кроме «с» есть – «l» (выравнивание по левой стороне) и «r» (выравнивание по правой стороне). Каждая строка, обязательно

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

vr­online | июнь 2010


73

Без рамки

видеть, как этот язык превратился в нечто масштабное и действительно необходимую систему, которая способна облегчить многим их рутинную работу. На этой положительной ноте, я надеюсь закончить свое повествование, а в следующих выпусках журнала мы продолжим наше знакомство с этим, удивительно интересным языком разметки. Я надеюсь, у тебя появились вопросы или замечания, а может и предложения относительно этой статьи – не стесняйся, пиши мне или на форму сайта vr­online.ru, и твои messages, будь уверен, не останутся без ответа.

Дополнительные ссылки:

Формулы: http://ru.wikipedia.org/wiki/Википедия:Формулы Официальный сайт: http://www.latex­project.org/ Документация TeX: http://www.nsc.ru/TeX/ «Не очень краткое введение в LATEX2e»: http://www.nsc.ru/win/docs/TeX/Tobias/lshort2e.html

vr­online | июнь 2010


Автор: Jimmy Jonezz Email: jimmyjonezz@bk.ru

74

Без рамки

Scribus:

Записки начинающего верстальщика Учиться, учиться... и еще раз учиться...

Предысторией к этой статье служит тот момент, что я достаточно часто встречаю людей, которые испытывают затруднения с версткой документов. Все это оттого, что видимо некому было показать и указать на нужный программный продукт. Конечно, вы можете верстать (если это можно так назвать) в Worde или любом другом редакторе, не предназначенным для этого, и уверен, вы справитесь с поставленной задачей, т.к. тот же Word предоставляет такую возможность, но вот вопрос: ­ будет ли достигнут нужный результат? Стоит подумать.

В предыдущей статье мы остановились на «общем описании» программы Scribus, не затронув самое основное, скажем так «начинку», то, благодаря чему Scribus и является программой, предназначенной для облегчения труда верстальщику. Вот именно ее, мы сейчас и испробуем на вкус – заглянем «вглубь». Предупрежу сразу, свое «погружение» я буду сопровождать полезными советами относительно правил верстки, которые, надеюсь, вам пригодятся в будущем, независимо от того, будете ли вы использовать Scribus или какой­либо другой программный продукт.

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

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

Даже если у тебя 100% зрение вряд ли тебе удастся выронить все объекты на рабочем Первое, с чего стоит начать – это четко полотне. Поэтому никак не обойтись без представить себе структуру оформления направляющих линий, которые создаются будущего документа, конечно при условии, довольно просто: щелкаем на что вы полны желания и несгибаемого горизонтальную или вертикальную линейку, намерения приступить к верстке, т.к. это в зависимости от того, какая направляющая довольно нудное занятие. Если все же вас нам нужна или щелкаем на уголок, это не отпугивает или вы вынужден делать соединяющий линейки (тогда получим обе это по принуждению, то смело берите лист линии сразу – прим. автора) и «тащим» бумаги и начинайте вырисовывать дизайн мышь на рабочее полотно. Второй вариант: будущих страниц: в каком месте будет стоять Страница ­ управление направляющими. нумерация страниц, будут ли колонтитулы и, Использование этой команды даст что в нем будет находиться, размер возможность более точно текстового поля и т.д. Все это можно настроить\установть направляющие. проделать прямо в редакторе, но поверьте мне на слово, на бумаге быстрее и наглядней. Если вы справились с этой задачей, а вы, я уверен, с ней справились, приступаем к настройке документа: выбор формата, направляющих полей, ориентация, единица измерения и т.д. Диалог с настройкой

vr­online | июнь 2010


75

Без рамки

Направляющие – это то, без чего никак нельзя обойтись при «конструировании» страницы. Постарайся это запомнить.

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

Я упустил из виду, одно важное правило, 1. Свойства: междустрочный интервал, несоблюдение которого может привести к отступы перед и после абзаца, табуляторы и краху всей вашей работы. Запоминай: все отступы. файлы (изображения, текст), которые будут 2. Символьный стиль: шрифт, кегль, цвет, использоваться в проекте, должны применение эффектов (подчеркивание, находится в той же директории, в которой тень, обводка, зачеркивание и т.д.). находится сам проект. Казалось бы, пустяк, но несоблюдение этого условия лишь 3. Настройка пользовательских «горячих прибавит вам головной боли; осмелюсь клавиш». заметить, что данная ошибка довольно Здесь, я уже мало, что могу вам распространена среди новичков. Держать посоветовать – реализуйте свою фантазию, все в одном месте, это не особенность но не стоит забывать, что слишком Scribus, которая, кстати, запоминает только абсолютный путь для используемых файлов, «аляпистое» оформление ни к чему хорошему не приведет. Все должно быть а правило, которого стоит придерживаться. читабельным. Это правило применимо и ко многому другому: кодинг, рисование и т.д. Последний момент, я акцентирую на вставке изображений. Здесь есть своя особенность, Вернемся в русло нашей статьи. Настал которая заключается в следующем: после момент, когда стоит обратить внимание на оформление текста. В предыдущей статье, я вставки блока изображения на рабочее полотно\страницу, есть два варианта дал понять, что работа с текстом в Scribus загрузки изображения в этот блок. поставлена на первый план, и это действительно так. Открываем редактор 1. Вставка через буфер обмена. На свой текста, для любого текстового блока, либо практике, я, этим методом не пользуюсь, т.к. через «Правка», либо при помощи клавиш: этот метод, способен значительно сильно Ctrl+T. В диалоге Story Editor мы сразу же увеличить размер вашего проекта, но тогда можем применять к тексту нужные вам не придется заботиться о том, чтобы все параметры: кегль, цвет, расстояние между изображения были рядом с проектом – буквами и т.д. прим. автора.).

Не торопись настраивать текст в этом окне. Советую создавать стили и уже, потом применять их к тексту. Этот метод максимально сократит тебе время верстки. Слева от текста, есть поле, в котором указываются стили, применяемы для строк текста. Клацай на одном из них и выбирай пункт «Изменить стили…».

В этом диалоговом окне можно выделить два основных «раздела» ­ дерево стилей,

2. Загрузка изображения из файла. Этот метод более удобен – файлы, которые вы используете можно отредактировать, при этом проект будет обновлять изображения и вам не придется заново загружать файл, но с другой стороны все фалы должны быть на «месте», т.е. желательно находиться рядом с проектом (Почему так? Читай выше – прим. автора).

После вставки изображения («Правая кнопка мыши» – «Вставить изображение» или Ctrl+D), вызывайте свойства изображения. В появившемся диалоговом окне смотрим раздел «X,Y,Z». Благодаря этому разделу можно позиционировать изображение «как душе угодно». Поворачивать, увеличивать\уменьшать и т.д. Раздел «Фигура» отвечает за размещения изображения в тексте, а именно за обтекание. Я

vr­online | май 2010


76

Без рамки

часто использую обтекание «по контурной линии». Щелкаем на тип обтекания и кнопку «Изменить». После чего откроется новое окно – «Узлы», в котором щелкаем «Изменить контурную линию». Контурная линия может быть, не обязательно, прямоугольного вида, добавив новые узлы, контур может выглядеть как многоугольник. Теперь изменяй синюю обводку изображения и щелкай «Завершить». Раздел «Изображение» отвечает за размещение загруженного рисунка в самом блоке изображения. С остальными настройками, я советую, разобраться самому, в них нет ничего сложного.

Совершенно забыл один момент, при работе с текстом, существует одна полезная функция, чтобы каждый раз не вставлять текст по страницам вручную, можно связать текстовые блоки. После такой связки, текст, который не умещается в одном текстовом блоке автоматически переходит на следующей. Данная кнопка находится на панелях инструменов ­ "Связать текстовые блоки". Работает это так: щелкаем на текстовый блок, далее на кнопку "Связать текстовые блоки" и щелкаем на тот текстовый блок, на котором будет продолжение текста. Есть и обратная функция, позволяющая разбить связанные текстовые блоки.

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

Дополнительные ссылки:

Официальный сайт http://www.scribus.net/ Вики­страница (рус.) http://wiki.scribus.net Сообщество пользователей: http://www.linuxgraphics.ru/

vr­online | май 2010


77

Меня тошнит

Меня тошнит

Выплескиваем негатив Меня раздражало за месяц... zahod5277: Меня тошнит от отношения чиновников к внедрению информационных технологий в сферы государства. Все помнят линукс в школы за туеву хучу денег и нулевым итогом. Все помнят сайты по 8 миллионов рублей. Куда?! На что?! Я просто не представляю что должен представлять из себя сайт за 8 миллионов рублей!!! Теперь еще ОС и поисковик, бюджет которого 100 миллионов рублей. Имей я психику послабее, уже бы точно сошел с ума от таких цифр. Лучше бы не тратили (а точнее не тырили) такие деньги, а вложили бы в медицину или образование.

на них можно достаточно навариться. Наверное...

Spider_NET: С пятого июля ваш покорный слуга отправился в отпуск. В этот раз (впрочем, как и во все предыдущее) он получился маленьким ­ всего две недельки. За такое время особо не разгуляешься и решил я вместе со своей любимой отправиться в гости к родителям, в чертовски маленький городок. Ехать к месту назначения решили поездом. Собрались значит брать билеты. Я как человек не расстающийся с инетом, решил попробовать заказать билеты в режиме Online. На этом все и закончилось. Был недавно в областной Доставка билетов не Тюменской больнице. Знаете выполняется и за куда они данные о узи купленными билетами вбивают а потом печатают? В необходимо приезжать на вордовский шаблон! Цифры вокзал и стоять в общей записали, распечатали, очереди. Меня этот вариант документ закрыли без не устраивал, т.к. смысл от сохранения и заново покупки через инет, если все открыли. Вот это бесит, от равно мне придется стоять этого тошнит и вообще на равне со всеми? А стоять хочется по увольнять на хрен бы пришлось конкретно, т.к. с всех кто занимается нужного нам направления обеспечением сняли пять вагонов и из­за специализированного софта этого возле касс всегда для мед. целей. Такая же тусуется туева хуча народу в ситуация со многим другим надежде, что появятся места софтом. Имел возможность (можно и не стоять, а ужаснутся ПО для админинга распечатать билет через школы и всего что с ней спец терминал, но когда я связано (не считая 1С). был на вокзале, он не Разве нельзя писать работал). Вот тут мне и качественные программы хочется сказать "Меня для гос. учреждений? Хотя тошнит!". Зачем вкладывать зачем? Можно же схапать кучу баблосов в гос. порталы, несколько лямов за создание если до сих пор толком не одного сайта, чем автоматизированы заморачиватся на разработке (интернетизированы) такие множества программ. Хотя и жизненно­важные сервисы

как приобретение/бронирование билетов?

Некоторые посетители VR знают, что у меня есть четвероногий друг ­ собака породы английский кокер спаниель. Уезжая в отпуск, мы решили взять мохнатого зверя с собой (а с кем ему оставаться?). Все документы на собаку в порядке, поэтому мы решили съездить на вокзал и купить для песика билет. Сделаю ремарку, оказывается, купить билет на перевоз животного можно лишь на вокзале, т.е. в других официальных местах продажи билетов этого сделать нельзя. Я долго думал почему, но так и не придумал. В общем приехали мы на вокзал. Я пошел в справочное бюро и уточнил на счет покупки билета. Меня заверили, что никаких проблем нет. "Стойте в кассе как все и приобретайте билет" ­ недовольным голосом ответил информационный агент совкового режима. Ok, встали мы с любимой перед кассой и начали ждать. Долго ли коротко ли, но ожидание нашей очереди затянулось на полтора часа. Не успел я произнести долгожданную фразу: "Мне билет на собаку пожалуйста!" и протянуть свой билет кассирше, как она сразу же ответила: "Вы уезжаете не с этого вокзала, поэтому продать билет на собаку я не могу!". Меня чуть не затошнило прямо возле (на) кассы (у)! что за маразм? Какая на фиг

vr­online | июнь 2010


78

Меня тошнит

разница на каком вокзале брать? Где вообще можно почитать (именно на вокзале) правила покупки билетов для животных? Короче я в шоке. Мне пришлось потратить полтора часа времени, что выстоять очередь и так и не решить свою проблему. А цена проблемы была всего лишь 60 рублей.

Kastor: Я за рулем своего скутера на крыше многоэтажного дома. Сразу за ним объект моего уничтожения. Выкручиваю до конца ручку газа. Из под буксующего колеса выползает синяя дымка. Разгон и прыжок с крыши. Всего мгновение и я делаю сальто назад приземляясь на землю в мегакрутейшей позе. Мопед влетает в будку со Lord_of_fear: Уважаемый сторожем и взрывает ее читатель, знаешь ли ты что нахрен. Из оставшегося такое говнософт? Если да, то офиса моего провайдера значит ты с ним сталкивался. выползают странные Я имел дело с достаточно бородатые существа, со большим числом свитерами, заправленными в говнопрограмм, но на днях джинсы. Они пытаются меня моё терпение подошло к закидать пачками от чипсов и концу. Слышал об Инфо­ кипятильниками, но не тут то бухгалтере? Думаю, да. Это было. Мой гнев велик. – жесть! Криворукости Первого встречаю шлемом, программеров можно остальных добиваю позавидовать. Сколько я врукопашную. Пробираюсь к всего повидал, но сообщение главному компьютеру и “обновление вроде как ввожу пароль успешно установлено” убило самоуничтожения… Вот до на повал. Скажу честно: в таких бредовых мыслей меня первый раз даже улыбнуло довел мой провайдер. Но =) Вроде как успешно! Если надо отдать должное, они позвонят мне и спросят последний месяц, из “Вы оплатили следующий год одиннадцати пережитых, он лицензирования?”, то отвечу работает почти без выходок. “вроде как оплатил” :) Благо, И это подозрительно. мы практически полностью перебрались на 1С благодаря Spider_NET’у. Ещё WWWNET: Меня тошнит от меня прикалывает как Инфо­ погоды этим летом. Многие бухгалтер переносит сетевую люди из разных городов работу с несколькими жалуются на изнуряющую жару, пользователями а у нас погода все никак не одновременно. Точнее, он может стабилизироваться. никак её не переносит. Через Достали дожди. Очень часто некоторой время база идут ливни. Периодически начинает сыпаться и плохая погода сменяется умирает. А если открывается, теплым денечком, а потом то работать низя. снова дожди. Вываливается куча ошибок… :) Кстати, видел их сайт? www.ib.ru .Прям а­ля 90­е. Зайди чисто поржать =) Не забудь стартовую страницу пролистать до конца. =) Тошнит и хочется плакать одновременно. И они ещё хотят за свой продукт денег! Бесплатно не возьму ;)

vr­online | июнь 2010


Автор: Kastor

79

Креатиff

"Я так люблю свою страну" Для нас эти игры, для нас... Рассказ

При написании рассказа были использованы тексты песен групп «Пикник» и «Lumen». Весь рассказ был написан под бессмертный рок группы «Disturbed» и непонятно как попавший в мой playlist электро от «Infected Mushroom».

Дальше ну прямо кадр из матрицы. Я разгоняюсь. Быстро разгоняюсь, интенсивно двигая руками. Мне нужно приземлиться на центр крыши, что бы не скатиться по ее наклону. Добегаю до края и отталкиваюсь что есть сил. Полет длится секунды две. Черт! Один из самых затяжных моментов моей жизни. Дальше следует грохот. Хруст Для нас эти игры, для нас. По крайней мере, нескольких черепиц, сломанных моим для меня точно. Я стою на крыше двух незапланированно жестким приземлением. этажного дома. Время близится к полночи. Распластавшись на крыше, я хватаюсь за ее Луны сегодня нет, звезд почти не видно. Свет изгиб, что бы не упасть. И замираю. Кусок на улице давно выключили. В домах, где не гребанной черепицы со скрежетом сползает где видно в окнах подсвечивание. Кто­то в низ. Падает на землю и разбивается. Мой смотрит телевизор. Особо не переживаю по пульс учащается. Я ��е двигаюсь некоторое этому поводу. Во­первых, тьма кромешная. время, что бы меня не заметили. Медленно Во­вторых, я в черном спортивном костюме, поворачиваю голову, осматриваюсь. который больше походит на прикид ниндзя. Многоэтажки достаточно далеко. Свет нигде Плюс я в капюшоне и маске. Никто не не зажегся, движняка со стороны улицы не должен видеть моего лица. Моя цель всего в видно. Вытираю выступивший на лбу пот. пятидесяти метрах от меня, но добраться Нормально прошло. Почти. Кажется, я туда не легко. Парадный вход ясное дело не коленом и расколол ту черепицу. Защитные для меня. Забраться на крышу не так уже и накладки все же помогли. Не на сто просто. Окна первого этажа в решетках. процентов, но значительно. На секунду Пожарная лестница спилена до третьего представляю, как это было красиво. Мой этажа. Здание, куда мне необходимо попасть силуэт замирает в прыжке с крыши на состоит из двух трехэтажных корпусов, крышу. Наверняка классный кадр. соединенных на уровне второго этажа Осторожно подползаю на край. Вот и проходом. Когда­то это была обычная школа. козырек второго этажа школы. До него уже Позже одну часть строения выкупила ближе. Прыжок с места, приземление на крупная компания, по производству ноги и перекат на спину, насколько это защитных программных систем. Ту часть позволяет площадь козырька. Как и ожидал, здания переделали до неузнаваемости. тут нашлась парочка осколков, возможно от Сказать, что когда­то это была часть школы, разбитого стекла или от бутылки пива. Мой язык не поворачивается. Второй и третий костюм достаточно прочный, на руках этажи, вынесенные над первым, застеклены перчатки. Я нигде не порезался. Встаю и с лицевой стороны. На первом этаже осматриваюсь. Пытаюсь вглядеться в окно раздвижные двери. Во дворе теперь авто передо мной, с которого можно выйти на стоянка для сотрудников. Смотря на это плиту, где я стою. Кажется, в коридоре здание, даже не верится, что за ним никого нет. Локтем выбиваю часть стекла, расположена старая часть школы, которая что ближе к ручке. Просовываю руку и давно подлежит сносу. Между отделением открываю окно. Старое здание, почты, на крышу которого я залез по обшарпанные стены, мусор на полу. Двери в лестнице со стороны двора, и школой, стоит некоторые классы сорваны с петель, кое­где двух этажный дом. Заброшенный старый их нет вообще. Медленно переступая дом с треугольной крышей из черепицы. Это разные балки на полу, иду вперед. Надеюсь, мой промежуточный пункт на пути к цели. здесь не будет приключений в виде бомжей

Ночь шуршит над головой Как вампира черный плащ Мы проходим стороной Эти игры не для нас

vr­online | июнь 2010


80

Кретиff

или наркоманов. Не должно быть. Все те же решетки на окнах и заколоченные двери для такого сброда уже преграда. Прохожу мимо того самого «тоннеля». Ясное дело никто не оставит здесь проход открытым. В конце глухая стена. Замуровано при реконструкции второй части здания. Но я все же пройду по тоннелю. Но только сверху. Подымаюсь по лестнице на третий этаж. Со второго рывка, с обсыпающейся высохшей краской, открываю окно, находящееся над проходом. Переваливаю через него, свешиваюсь и аккуратно приземляюсь. В эту сторону, с части здания компании, выходят окна их кабинетов. Свет нигде не горит. Охранник, возможно, ходит по коридору с другой стороны или сидит вместе с товарищем в кабинете и смотрит в камеры наблюдения. А может и футбол. Их мы не успели всех «обработать». Эти два новенькие. За такой промежуток времени не изучишь весь персонал, их повадки и привычки. Я снова разгоняюсь. Бегу по крыше перехода прямо на стену. Подбегаю почти в притык и умудряюсь сделать два шага по стене, прежде чем выкидываю руку вверх и ухватываюсь за край крыши. Зацепившись второй рукой, подтягиваюсь и забираюсь наверх. Десять секунд передышки. Дыхание вроде не сбилось. Порядок. ­ Я на месте.

­ Понял. – доносится ответ из наушника. В паре кварталов от сюда, возле станции метро, припаркована черная Mazda 3 MPS. За рулем наверняка сидит Faila. Рядом, Void смотрит изображение с камер наблюдения на экране ноутбука. На подготовку к операции ушло достаточно много времени. Достаточно для того, что бы найти в подсобном помещении ближайшей станции метро магистраль, передающую поток видео с данного кампуса, в главный офис компании. Присоединить к нему устройство для передачи сигнала через шифрованный радиоканал. Достаточно для того, что бы молодая, красивая девушка сбила одного из сотрудников компании, катаясь на роликах. Влетела так, что его барсетка улетела в одну сторону, а ее рюкзак, с рассыпающимися безделушками в воздухе, в другую. Лежа на асфальте, она вытянула руку, прося помочь встать. Повадки всех полезных для дела людей были изучены. Мы знали, что этот точно поможет. А еще он поможет собрать все это барахло, рассыпавшееся по улице. За это время, его магнитный пропуск улетел в окно припаркованной рядом машины и его дамп был благополучно скопирован. Позже нанесен на аналогичную карточку. Именно она сейчас лежит у меня в грудном кармане. Времени хватило и на промывание мозгов

шефа отделения. Звонок от якобы их провайдера. Виновный, неуверенный голос в трубке говорил, что при установке и настройке нового оборудования был допущен ряд ошибок, в результате чего соединение в последнее время очень неустойчиво. Кто же знал, что это наших рук дело. Снятая недалеко однокомнатная квартира, с установленным возле окна шумогенератором, рандомно по времени пускающий помехи в сторону офиса компании. Начальник не дурак, но номер провайдера на определителе и подтверждение сотрудников о плохой связи сыграли свою роль. Двум парням, в кепках и синей одежде с эмблемами провайдера, было разрешено пройти на крышу и осмотреть оборудование. Вот тогда и был сломан замок двери, ведущей на крышу. Эту самую дверь я сейчас и открываю. ­ Камера номер три под контролем. Driver, ты стал невидимкой.

­ Отлично. – спускаюсь по лестнице и открываю дверь в коридор. А вот и камера номер три. Тут уже ничего не поделаешь. Остается верить, что видео пустого коридора зациклено на мониторе охранника. Все же маска не лишняя, хоть свет здесь в нерабочее время делают тусклым. Иду к заветной двери. Кабинет №15. Достаю пропуск и провожу им по щелкам считывателя. Загорается зеленная лампочка. Щелкает электра замок двери, и она чуть приоткрывается. Слегка толкаю дверь. Темно. В офисе очень темно. Но я различаю несколько деревянных столов, со специальными нишами для системника и монитора, расположенных в ряд. Над двумя окнами висят кондиционеры. В углу стоит стойка с парочкой серверов. Подхожу к первому столу и присаживаюсь на корточки. Достаю крестообразную отвертку и откручиваю винтики с одной стороны. Снимаю крышку с системника. А вот и аппаратный keylogger. Снимаю его с разъема клавиатуры и кладу в карман. Да, все же велики возможности социальной инженерии. Гениальная наша Faila. Жучки были установлены еще до того, как эти новые компьютеры были доставлены сюда. С остальными двумя поступаю так же. Значит, ключи есть. Они должны быть там. Каждый день сотрудники работают с секретными данными, а значит, ключи были записаны в память этих устройств. Что за шорох? ­ Void. – шепотом говорю я. ­ На камерах чисто.

Странно. Надеваю крышку и закручиваю vr­online | июнь 2010


81

Кретиff

винтики обратно. Я стараюсь двигаться аккуратно, ничего не задеть. По идее, меня здесь и не было. Остается последняя часть. Свалить от сюда. Выглядываю из­за двери. Никого. Выхожу и медленно закрываю дверь. Загорается красная лампочка. Щелчок замка. Дверь закрыта. ­ Driver, охранник вышел из кабинета. Делает обход против часовой. ­ Дерьмо. – Это значит, что ему до входа на лестницу раза в три меньше, чем мне. Только он пока за углом. ­ Зайди обратно. Быстрее!

Ага, обратно. Эти считыватели не такие уже и скоростные. Две секунды для меня сейчас роскошь. Бегу по коридору пытаясь скрыться за углом. Но мне не хватает пары метров. ­ Стоять! Стоять я сказал! – охранник рванул за мной.

Не знаю, что за план у меня появился в голове. Слева от меня мелькают двери офисов, справа – большие окна, выглядывающие прямо на парковку. Может, я хотел оббежать по кругу все здание и снова вернуться к лестнице? Но даже эта детская затея оборвалась. В конце коридора открывается дверь. Второй охранник поворачивает голову в мою сторону и его глаза расширяются. Еще бы! Его коллега гонится за каким­то незнакомцем в черном балахоне. Ничего лучшего, чем направить на меня пистолет, этот козел не придумал. ­ А ну стоять! Живо!

Мое сердце бьется с бешеной скорость. Каких­то тридцать секунд назад все шло по плану. Доля секунды понадобилась моему сознанию, что бы понять – другого выхода нет. Наверное, я ощутил отчаяние. Скрещивая руки перед лицом, я прыгаю в окно. Осколки стекла разлетаются в разные стороны. Руки я все еще держу перед лицом, но низ я вижу. Причем я вижу, как мне безумно повезло. Я рассчитывал, что на стоянке под окнами будет стоять ряд автомобилей. Но я и не надеялся, что попаду на крышу микроавтобуса. Она прогибается под моим весом. Я невольно скатываюсь на капот. Слышу треск переднего стекла. Падаю на землю. ­ Живее, за ним! – слышны выкрики с верху.

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

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

­ Еще бы. – В зеркале заднего вида замечаю расплывающееся в улыбке лицо девушки. Глухой стук трансмиссии. Вторая передача. Нас всех от ускорения вжимает в спинку сидений. Снимаю капюшон. Прохладный ветер из приоткрытого окна приятно бьет в лицо. Теперь я могу перевести дыхание. ­ Живой, дружище? – Void повернулся ко мне. ­ Да. Местами. – Протягиваю ему аппаратные keylogger’ы.

Думаю, хитрые усмешки на наших лицах видно за километр. Двигатель в 250 л.с. мчит нас по трассе. *

*

*

Как же я ненавижу этот звук. С лежащего на столе коммуникатора играла ужасная мелодия. А это значит, что уже пол восьмого, и через полтора часа я должен быть на работе. Я специально поставил этот бред на будильник. Так быстрее хочется проснуться, что бы вырубить его нафиг. Я присел на диване, протер глаза и взглянул в окно. Пасмурная погодка. На небе видно немного тучек закрывающих солнце. Похоже, ночью накрапывал дождь. И славно. Значит, сегодня не будет так жарко. В глазах чувствуется «песок», голова немного тяжелая. Пять часов сна, явно мало для организма. Хорошо хоть хватило сил расстелить себе простыню и лечь по человечески. Смотрю в сторону своего стола. Слышу шум куллеров из истемника. Оба двадцати двух дюймовых монитора, стоящих рядом на столе, давно ушли в спящий режим. Рядом с клавиатурой стоят две баночки энергетического напитка. Безалкогольного конечно. Он мне абсолютно ни к чему. Натягиваю штаны, подхожу к столу и беру одну из них. Капелька кофейной жидкости скатывается мне на язык. Хм, пустая. Беру вторую, в которой на дне булькает остаток, делаю глоток и иду умываться. Какое блаженство. Холодная вода хот немного «освежает» мое сознание. vr­online | июнь 2010


82

Кретиff

Сонливость медленно проходит. Делаю еще глоток этого кофейного напитка. Он мне иногда помогает не провалиться в сон. В это желанное состояние, в которое так хочется уйти утром. Или под утро, это уже как получится. Следую на кухню, где завариваю себе чай и делаю бутерброды. Да уж, завтрак чемпиона. Беру поднос с едой и кружкой и иду в комнату. Сажусь в кресло. Движение мышкой и мониторы через секунду оживают. На одном открыт Eclipse с моим кодом на С++. В свободное время я занимаюсь разработкой системы обнаружение вторжений, только для работы с беспроводными сетями. Смотрю на экран и вспоминаю этот злостный кусок кода, который не дал мне заснуть до трех ночи. На другом мониторе в Firefox открыт какой то форум программистов, документация и PSI. В этом Jabber клиенте мигает сообщение от, походу давно ушедшего в offline, Мегабайта:

расшарахать свой байк! Хорошо, хоть сам цел остался. Пара ушибов и синяков. А вот байк улетел из­под меня в повороте и куроча пластиковый обвес, терся по асфальту до самого ограждения. Вся надежда на Файлу, которая тащится по гоночной технике. Держит с друганами свою мастерскую. Надеюсь, она восстановит мой байк. Спец все­таки. Автобус тормозит на очередной остановке. Народу на улице много. Видно тоже все на работу спешат. Из этой толпы, проходящей в открытые двери автобуса, я сразу замечаю ее. Молодая девушка, с рюкзачком через плечо, заходит в автобус и становится возле окна, опираясь о кабинку водителя. Ее длинные, светлые и немного кудрявые волосы красиво лежат на плечах. Похоже, она немного улыбается. Смотрит в окно и улыбается. Тонкий проводок тянется из ее футболки к ушам. Хм, я бы сейчас тоже не отказался послушать музыку. У меня такое ощущение, что она пританцовывает. Megabyte 2:48:12 Еле заметные движения говорят мне об этом. Вот еще один плюс солнцезащитных Ну че? Компилится код? очков – я могу пялиться на кого угодно, а они Megabyte 2:54:37 об этом могут только догадываться. Хотя она на меня даже не смотрела. Вообще ни Чувак, ты где? В спящий режим ушел что на кого не смотрела, только в окно. Может ли? =) быть, она слушает электро, а в ее рюкзаке Угадал. Вспоминаю, как вчера отлучился в лежит ноутбук? Она так похожа на мой образ туалет, а когда вернулся, то между компом и девушки­хакера. Вовсе не кукла, которые диваном выбрал диван. На секундочку. любят ходить по магазинам, листать Секундочка продлилась до утра. Уже начало каталоги с косметикой и носить туфли на девятого, надо торопиться. Надеваю свои высоких каблуках. На ней белые кроссовки, любимые джинсы, футболку и кроссовки. «вареные» джинсы, по цвету напоминающие Достаю с полки ноутбук и кладу его в рюкзак. синее отражение воды на стене, футболка с Закрываю дверь, спускаюсь по лестнице и замысловатым рисунком и легкая курточка. выхожу из подъезда на улицу. Не так уже и Я не могу оторвать от нее взгляд. Такая пасмурно сегодня. Я щурюсь от солнечного милая улыбка на ее лице. Любуюсь ей минут света. Глаза начинают слезиться. Опускаю двадцать, пока она не выходит на очередной на нос солнцезащитные очки. Так намного остановке. А я тупо смотрю через окно, как лучше. В паре кварталов находится нужная она поправляет рюкзак и уходит куда­то, мне автобусная остановка. Я вообще не сливаясь с толпой. Да что со мной такое?! Я знаю, зачем устроился админом к этому придерживаю закрывающуюся дверь и провайдеру. Может, мне нужен стабильный выхожу на улицу. Ну, блин, и куда она заработок? Зарплаты хватает на оплату испарилась? Тут такой движняк. А с другой однокомнатной квартиры, продукты и стороны, что бы я ей сказал? Я ведь даже не шмотки. Почти хватает. На «нормальную подумал над этим. Я вышел на две жизнь», новые комплектующие для компа и остановки раньше, чем надо. Достаю свой девайсы, ясное дело я зарабатываю другим mp3­шник и надеваю наушники. Люблю образом. Моей части гонорара в пять штук забойный рок. Под него трудно грустить, он вечно зеленых, от последнего нашего заводит и придает энергии. На светофоре выполненного заказа, мне хватит надолго. загорается зеленый и я вместе со всеми Запрыгиваю в закрывающиеся двери ожидающими на тротуаре, двигаю по зебре, автобуса. Несмотря на то, что еще есть доставая из рюкзака свой «секретный свободные места, я становлюсь в центре, запас» кофеина. Под забойную Inside The держась за перекладину. На пути зайдет еще Fire группы Disturbed я дохожу до здания куча народу. Мамы с детьми, пожилые. своего провайдера. Ничего необычного, Лучше сразу не буду занимать место, чем простое двухэтажное здание. На первом потом уступать его и искать, где бы мне находится Интернет клуб, которым удобнее постоять до своей остановки. Блин! управляет Илья. Нормальный парень, не И надо было мне так умудриться раз, выручавший меня с моими косяками на vr­online | июнь 2010


83

Кретиff

В ответ я только подмигнул ему. Я снял свой рюкзак и присел на соседнем с ней диване. Не так уже и много людей приходят сюда, что бы посидеть в Интернете со своего ноуткуба через Wi­Fi. В основном они ­ Привет, Илюха, ­ снимая очки, здороваюсь садятся за стационары, которых в этом я. клубе предостаточно. Включаю свой ноутбук и выбираю из трех систем, установленных ­ Здаров, Андрей, ­ он отрывает свой взгляд на нем, BactTrack. Прикольный дистр, сразу от монитора – опа! Опять не спал всю ночь? содержит большинство прог необходимых ­ Не всю, ­ делаю глоток из баночки. для работы. Запускаю консоль, парой команд перевожу карточку в режим ­ Заканчивай пить эту дрянь. Здоровье мониторинга и запускаю airodump. Вот они. гробишь. Список на экране наполняется клиентами, ­ Угу, если бы не эта дрянь, ты бы уже подключенными к беспроводной сети. Их собирался домой, когда я пришел. всего четыре штуки и я знаю, какой именно Директора нет еще? мне нужен. Вот он, Broadcom’овский мак адрес, карточка вероятно от которого и стоит ­ Неа. Че то опаздывает сегодня. в ее ноутбуке. Дальше вычисляю ее ip адрес и сканирую порты, надеясь найти ­ Вот и славно. Что смотришь то? – я перевалился через стол, чтобы взглянуть на уязвимости. Уже прошло пять минут, а я все еще не получил доступа к ее компьютеру. Я монитор. все больше удивляюсь поставленной ­ Новости. В сеть попало видео с камер защите. Вдруг, неожиданно для себя, наблюдения компании SH. Помнишь, в замечаю на своем рабочем столе какой­то прошлую субботу к ним в здание вломился левый текстовик, с насмешливым названием какой­то незнакомец? «не устал?». Ну, нифига себе! Я даже растерялся на какое­то время, но быстро ­ Угу, видел, ­ говорю я, смотря на это собрался с мыслями. Ну, вот же! Вот же эта тормозящее, черно­белое изображение незаметная прореха в защите, которую я так камер наблюдения. Вот я выбегаю из­за угла. Вот открывается дверь, выходит второй долго искал. У нее на экране появляется аналогичный текстовик, но с названием охранник и направляет на меня ствол. Вот я подымаю руки и выпрыгиваю в большое окно «Неа, только размялся. Удивлена?». Замечаю на ее лице явное у��ивление, на парковку. которое через несколько секунд и пару ­ Как думаешь, что он там делал? Говорят, десятков нажатий на клавиши почему­то ничего не пропало. Странно вообще­то. исчезает. В ответ получаю себе новый текстовик «Не очень. А ты?». И, о черт. Я ­ А фиг его, ­ зевая, отвечаю я. больше не могу создавать на ее компе файлы. Будь это кто­либо другой, уже бы ­Извините. Можно мне в инет на час? Мне давно тупо отрубил от сети, задосив через Wi­Fi. – приятный женский голос пакетами деаутентификации. Но сейчас это вклинивается в наш разговор. Девушка бы означало мое поражение, а еще я очень выкладывает несколько купюр на стол, хочу продолжить разговор. Вот только как? И доставая ноутбук из рюкзака. Глазам не словно в ответ, на этот мой мысленный верю, это же она. Та самая девушка из вопрос, у меня появляется третий файл, с автобуса, которую уже и не надеялся когда­ троеточием в место названия. Я открываю либо встретить. Я стою рядом, но меня она его и вижу фразу «интересно, ради чего же не узнает. ты так старался?». Понимаю, что общение ­ Да, конечно, ­ оживился Илья – вот пароль. будет продолжаться теперь здесь. Печатаю Присаживайтесь, пожалуйста, ­ он в ответ «не мог же я так просто подойти к протягивает ей карточку с логином и такой красивой девушке и завязать паролем. разговор». Секунду задумавшись, добавляю ­ Спасибо, ­ она присаживается на диване в «не оригинально как­то». Следующие пять минут мы общались таким способом, иногда другом конце помещения и открывает поглядывая друг на друга. Я изредка крышку ноутбука. замечал легкие улыбки на ее лице, и от ­ Оу, Илюха, ты заметил, что за ноут у нее? этого мне становилось легче. Значит она не против моей компании. ­ Да Hewlett Packard кажется. А что? «­ И стоило это таких твоих усилий? ­ ХП значит, окей! работе. Впрочем, как и я его. На втором этаже серверные и мое рабочее место. Открываю входные двери и подхожу к столу, стоящему в центре.

­ Че? Понравилась? – он ехидно улыбается.

­ Сейчас узнаем.

vr­online | июнь 2010


84

Кретиff

­?

­ Давай, как ни будь, поужинаем вместе? – замечаю очередную улыбку на ее лице. ­ Я не против =) Вот мой номер…»

И она напечатала его. Хах, мой коварный план удался, хоть и не так, как я его себе представлял. В этот момент в помещение вошел Игорь Александрович, наш директор. Он подошел к Илье и что­то сказал ему. Илюхе ничего не осталось, как указать в мою сторону взглядом. ­ Андрей, зайди ко мне в кабинет. Это срочно.

Как же он не вовремя. Вечно у него что­то срочное.

«­Кажется кому­то уже пора.

­ Да. До скорой, красавица...»

Улыбнувшись ей на прощание, я последовал на второй этаж, за ИА, как мы его называем в шутку. В этот момент завибрировал коммуникатор, оповещая о новом сообщении. Это от Файлы: «Driver, байк готов. Заезжай на днях». Здорово. Еще одна хорошая новость за сегодняшнее утро. Даже угрюмый начальник мне вряд ли сможет подпортить настроение. *

*

*

­ Здесь остановите, ­ говорю я, глядя в окно.

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

Красная девятка трогается с места и скрывается за поворотом. Довольно тихий район, расположенный на окраине города. Даже людей здесь не так много. Множество кварталов с расположенными на них частными домами. Тихая улица и небольшая дорога, по которой я иду. В паре кварталов от сюда находится мастерская Файлы, где меня ждет мой Aprilia. Я специально вышел здесь. Это уже давняя моя привычка так шифроваться. Может это лишнее, но водиле совсем не обязательно знать, зачем я сюда приехал. Красивые, в основном двух этажные дома, расположены вдоль улицы. У каждого на пороге есть небольшой дворик с газоном. Вся эта картина напоминает мне кадры из американских фильмов, где показывают их жилые районы. Следующий квартал начинается с большого гаража и

парковки, расположенной рядом. На ней стоит несколько серийных, но до неузнаваемости тюнингованных автомобилей и парочка байков. Входные ворота подняты вверх. Изнутри доносится шум работающего двигателя. Захожу внутрь и вижу спортивную Subaru Impreza, которая стоит на специальном стенде. В очередной раз убеждаюсь, что эти странные знакомые Файлы, с пирсингом, татуировками и эрокезами, вовсе не сброд панков беспредельщиков. Дело свое они знаю, иначе им бы не доверили на диагностику или ремонт такую тачку. Занятые работой, они меня не заметили. Я решил немного понаблюдать за ними и оперся о стенку гаража. Один парень стоит у стола с экранами, к которому тянутся провода от стенда. Двое просто наблюдают, как с нарастающей скоростью вращаются колеса гоночной машины, стоящей на нем. За рулем этой синей, с грозным передком Subaru сидит Faila. Своеобразная, внушительная девушка. Синие прямые волосы, на которые натянуты очки вместо обруча. Белая маечка на теле. Левая рука, в синей гоночной перчатке, лежит на руле. Правая, скорее всего на рычаге КПП. Обороты возрастают, кажется, этот монстр сейчас сорвется со стенда, проделает дыру в здании и помчится прочь. Я с восхищением смотрю на нее. На ее сосредоточенное выражение лица. Возможно я так же выгляжу, когда сижу за компом, но только не так круто. Она же меня абсолютно не замечает. Вероятно, кайфует от той мощности, которая спрятана под капотом этого зверя. Мощности, которая подвластна ей всего лишь движением правой ноги на педаль газа. Вместо бетонного пола и шкафов с инструментами перед ее глазами наверняка сейчас мелькает дорожная разметка гоночного трека. Металлический стук четко сработавшей коробки передач. Двигатель снова набирает обороты и все четыре колеса полноприводной Subaru раскручиваются еще быстрее. ­ Стоп! Хватит! – чувак, стоящий за столом поднял руку верх. Faila сбрасывает обороты и глушит двигатель: «Ну как?», ­ открывая дверь спрашивает она. ­ Компрессия в норме. Впрыск топлива своевременный. Короче, можно закругляться.

­ Фух, наконец­то. Целый день маялись, ­ оживился один из парней с татуировкой на плече. vr­online | июнь 2010


85

Кретиff

­ Вот и славно, ­ Faila выходит из машины и задерживает свой взгляд на мне, ­ Привет, Андрей! Я тебя пораньше ждала.

­ Как освободился, так сразу к тебе рванул, ­ я подхожу к ней. Хм, как я и думал. Черные кроссовки с синими вставками, такой же расцветки спортивные штаны и куртка, со связанными рукавами на поясе.

­ Пошли за мной, твой пациент уже заждался тебя. ­ Это я его заждался.

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

­ Хах, мой рекорд. Не знаю, не знаю. А вот обвес свой ты раскурочил вне всяких рекордов, ­ мы подходим к другому краю гаража, ­ любуйся.

У меня нет слов. Мой Aprilia SL 750 Shiver стоит на подножке и смотрит на меня своей единственной, футуристичной фарой. Обвес как новый. Серый скелет металлической рамы, более темное сидение и оранжевые пластиковые обтекатели. Блеск! Обхожу мотоцикл и любуюсь двумя задними глушителями, выходящими из под сидения. Удивительные треугольные формы делают их больше похожими на лучеметы, готовые испепелить любого по моему приказу. ­ Ты супер! ­ Не могу сдержать своего восторга.

­ Кто? Я или твой байк? – спросила Faila, положив руку мне на плечо. Хитрая усмешка на ее лице и она протягивает мне брелок с ключами. Я сажусь на байк, выжимаю сцепление и завожу двигатель. Он послушно отзывается на мое движение рукояткой газа, издавая сочный рокот. ­ Спасибо огромное. Я даже не знаю, как тебя отблагодарить.

­ Да все нормально. Лучше просто пообещай больше не газовать так при выходе с поворота. ­ Постараюсь, ­ все еще не наслушавшись этого дивного звука от выхлопа, отвечаю я. ­ Кстати, тебе Void не звонил? ­ Нет. А что за тема?

­ Да есть одна затея, надо бы обсудить на днях. ­ Если не срочно, давай завтра или послезавтра встретимся, обсудим. ­ Че? Планы, какие есть?

­ Угу. Как у Наполеона. Залезай, подвезу домой. Я так понял вы все на сегодня?

­ Да, но я на своей малышке, ­ она кивнула в сторону своей Мазды 3 MPS Extreme. Только Faila может назвать малышкой, гоночный автомобиль, от ускорения которого в глазах темнеет. ­ Ну ладно, созвонимся тогда еще, ­ мне уже не терпится прокатиться по дороге. ­ Давай. До скорой, ­ она подмигнула мне и пошла к своим товарищам.

Я медленно выкатываю с гаража и сворачиваю на дорогу. Какое же это удовольствие, особенно после целой недели, которую я был пешеходом. Сцепление, щелчок коробки передач, рукоятку на себя и я уже мчусь под 100км/ч по этой совсем пустой дороге. Деревья и столбы по бокам мелькают все быстрее, перекресток со светофором все ближе. Сбрасываю скорость. Мандраж от падения еще не прошел. Такое бывает. Надо просто немного привыкнуть и я буду ездить не хуже прежнего. У меня в запасе еще целых два часа. Но мне стоит поторопиться, нельзя же опаздывать на свидание. Во всяком случае, парням. С самого утра моя голова была забита мыслями о том, как все может пройти. О чем мне стоит говорить с Катей. Катя, какое милое имя. Вспоминая ее улыбку, мне почему­то кажется, что оно ей подходит как никакое другое. Мысли о том, как мне стоит себя вести. Но все это глупости. Нельзя продумать все темы разговоров, все возможные варианты развития событий. Надо оставаться собой и все само получится. Я заехал домой, что бы приодеться покрасивее. Но никаких официальных брюк, рубашек и прочей фигни. Это не мое. Не понимаю людей, которые носят такие костюмы. Ладно, еще те, которым это нравится. Они действительно выглядят солидно и аккуратно. Но остальные, всякие менеджеры и даже преподы. Смешно смотреть на них. Особенно на последних, когда они роняют мел. Им же страшно присесть за ним, вот­ вот где­то треснет по швам и вся эта серьезность и официальность улетучится. Нахожу телефонную трубку и делаю звонок в одно уютное кафе, где я заказал столик. ­ Да, молодой человек. Ваш столик, заказанный Вами вчера, свободен и ждет

vr­online | июнь 2010


86

Кретиff

Вас, ­ этот ответ и спокойный женский голос успокаивают меня.

­ Спасибо большое, ­ мне просто надо было убедиться, что прокола не будет.

Кажется все. Уже начало восьмого. Пора выдвигаться. Закрываю дверь и спускаюсь во двор, к своему байку. Буквально двадцать минут езды и я на месте. Почти на месте. Я снова припарковался в паре кварталов от кафешки. Но в этот раз по другой причине. У меня в запасе еще целых пятнадцать минут, которые я простоял, опираясь о парапет. К кафе подъехало желтое такси, из которого вышла Катя. Она почти не опоздала. Я иду к ней. Подхожу и понимаю, что мое «привет», будет первым словом, которое я ей адресую. Ведь мы же не общались до этого лично, только через своеобразный чат и по телефону. Мы поздоровались. Я был одарен замечательной улыбкой. Я готов любоваться ей снова и снова. Вовсе не застенчивая, и не загадочная. Не знаю, как ее можно описать. Просто чудесная. Мы зашли в кафе, и подошли к нашему столику. ­ Андрей, кажется этот столик уже занят.

­ Все верно, ­ улыбаясь, я отдаю официантке табличку с надписью «стол заказан». Кажется, она немного удивлена. Мы присаживаемся и открываем меню… Вечер прошел чудесно. Почти все время мы разговаривали. Не было неловких моментов или минут молчания. Мы просто болтали. Приятное, милое и веселое общение. Мы начали по не многу узнавать друг о друге. Я рассказывал о себе. Рассказывал о своей работе администратором. Рассказывал, как иногда пишу софт разным заказчикам, в общем, занимаюсь фрилансом. Как снимаю квартиру, как провожу свободное время. Ничего необычного. О своей загадочной, ночной жизни я умолчал. Вообще мало людей знает о ней, и ей не следует этого знать. Мы пока не сильно лезли друг к другу в личную жизнь, задавая свои вопросы. Поэтому она до сих пор оставалась загадочной для меня девушкой. Катя тоже работает в области информационных технологий. Причем по части защиты сетей и различного оборудования. Да я это сразу понял, когда она уделала меня еще в клубе у Илюхи. В свои двадцать она уже начальник отдела одной фирмы по компьютерной безопасности. Я же старше ее всего на год, но пока лишь админ. В прочем меня это абсолютно не волнует. У меня нет никаких планов по продвижению по карьерной лестнице. И уж точно я не собираюсь работать на свою трудовую книжку. Слава

мне тоже не нужна. По крайней мере, здесь, а не в андеграунде. Катя тоже не спешит проливать свет на свою работу и нас обоих это устраивает. Разделавшись с десертом, мы начинаем собираться. Уже где­то пол десятого, за окном темно. Расплатившись с официанткой, мы выходим на улицу. Приятный, теплый летний вечер. Вернее уже ночь. Так хорошо сейчас, тихо. Мы решили немного прогуляться. Сворачиваем по небольшой тропинке в парк. Здесь очень красиво. Деревья, подстриженные кустарники, газон и тропинки, выложенные плиткой. А здесь свежо. Прохладный ветерок приятно обдувает руки и лицо. Я решаюсь взять ее за руку. Она не против. Покрепче сжимает мою ладонь, и мы продолжаем нашу беседу. Уже более раскрепощенную и более насыщенную шутками и сопровождающими их улыбками. ­ Уже поздно, Андрей. Мне пора бы вызвать такси.

­ Окей. Давай только пройдем в соседний двор. Думаю, туда водитель быстрее найдет дорогу. На долю секунды мне показалось, что я вызвал у нее подозрение. Но она соглашается. Мы выходим из парка и подходим к одной из многоэтажек, под окнами которой стоят несколько автомобилей и мой байк. Остановившись у подъезда, она достает из кармана мобильный телефон. ­ Катя, не хочешь прокатиться?

Она не понимает, о чем я. Потом замечает мой взгляд, направленный на этого двухколесного красавца. ­ Это твой? – на ее лице вновь замечаю удивление.

Вместо ответа достаю брелок с ключами. Пиликнув сигнализацией, мой Aprilia приветливо мигнул нам фарой. Катя снова расплылась в улыбке. Мы садимся на байк. Я завожу двигатель и потихоньку выезжаю на дорогу. Перестроившись в левый ряд, я прибавляю газу и чувствую, как она, обхватив руками за пояс, прижимается ко мне. На душе становится так тепло. Сейчас я чувствую, что не один. В этот момент нет больше этого гордого одиночества. Нет мысли, что мне никто не нужен. В глубине сознания закрадывается сомнение, что я могу лишиться этого состояния одинокого волка. Но сейчас не тот момент, что бы думать об этом. Я сбрасываю скорость, медленно лавируя по дороге, ведущей к нескольким девятиэтажкам. Останавливаюсь возле одного из подъездов, vr­online | июнь 2010


87

Кретиff

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

­ Мне пора, ­ улыбнувшись, она берет меня за руки. Какое­то мгновение ее глаза бегают из стороны в сторону, словно она решается на что­то, и целует меня в губы.

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

*

*

Мой любимый энергетический напиток почти закончился, а Файлы все нет. Я стою посередине моста и, опираясь на перила, смотрю на движущуюся подо мной реку. Снова эта пасмурная погода. Из небольших тучек уже давно накрапывает мелкий дождь. Теплый такой, летний, но все же противный для меня дождь. Впрочем, об этом говорит только поднятый воротник моей куртки. Я не сутулюсь и не пытаюсь прикрыться газетой, как некоторые прохожие, которые спешат побыстрее укрыться от него. Я просто стою на мосту, делаю последний глоток этого кофеина и вспоминаю прошедшую ночь. Вернее утро. Самое прекрасное утро моей жизни. Очень хотелось удивить ее еще раз. Проснуться пораньше, сделать легкий завтрак, заварить чай и принести все это в постель. Но моих сил еле хватало для того, что бы разлепить веки и я снова провалился в сон, обнимая Катю. Когда я проснулся второй раз, я поводил рукой по второй половине кровати и понял, что ее рядом нет. Я резко проснулся. Незнакомая обстановка, сквозь белые шторы в комнату вливается солнечный свет. В комнате очень светло, очень все аккуратно и очень чисто. Я слышу какой­то шум на кухне. Через несколько секунд дверь открывается и в комнату заходит Катя, держа обеими руками поднос. Она чрезвычайно красива. Кроме нижнего белья, на ней всего лишь легкая, немного просвечиваемая лучами света рубашка. Ее светлые волосы, беспорядочно, но красиво лежат на плечах. А на лице, все та же улыбка. Мои мысли рассеивает звук высоко оборотистого двигателя спортивной Мазды. Рассекая лужи, эта черная тачка с красными линиями винила по бокам и спойлером на крыше, подкатывает ко мне. Тонированное стекло с моей стороны опускается.

­ Залазь, Driver. Прокатимся, ­ выглядывая из окна, говорит Faila.

­ На пять минут опоздала. Теряем форму? – в шутку спрашиваю я, усаживаясь в кресло. ­ Да нет. Прикинь, забыла с ручника снять, ­ хлопнув себя по лбу и улыбнувшись, ответила она. После этой фразы я просто не могу не пристегнуться. Через мгновение мы трогаемся с места, проезжаем мост и едем по шоссе. Быстро едем, но не гоним. ­ А где Void? И что там за идея у вас?

­ Он уже на месте, с нашими. Пусть лучше он и расскажет свой план. Кстати, Flash и Kornev тоже там. ­ Отлично. Мы в нирвану?

­ Угу, ­ сворачивая на очередном повороте, отвечает Faila.

Следующие десять минут поездки я вспоминаю свое утро. Смотрю на стекающую по стеклу капельку воды и вспоминаю, как я не хотел, что бы оно закончилось. Мы договорились встретиться в ближайшие дни. Все так условно. И все так неизвестно, как и при первой встрече. Второе свидание, наверное, всегда не менее неожиданное и загадочное, чем первое. Faila паркуется возле одного ночного клуба, с большой вывеской «Nirvana». Это смесь ночного и Интернет клуба. Пиво, компы, электронная музыка. Все это здесь. Мы заходим внутрь. С одного из балкончиков нам махает рукой Flash, держа в другой тлеющую сигарету. ­ Привет народ! – я с Файлой подсаживаемся на диван, который огибает наш столик. ­ Оу, Андрюха! Привет. Как доехал? – усмехаясь, здоровается Kornev.

Обычные «привет. Как дела?». Все­таки больше недели не виделись. По крайней мере, я только с Файлой и пересекался пару раз. Я то, ясное дело, чем занимался. Днем работа. Вечером программинг под клевую музыку. Когда никогда выходил на турники или стадион. Faila, даю сто процентов, вечно зависала у себя в гараже. А в свободное время рассекала п��остранство наших дорог на своей тачке. Flash, оказывается успел смотаться на море. Вместе со своей подругой умотал в Крым на пару дней. Вон, даже загорел немного. А вот Void и Kornev мне не известно чем занимались. После того, как нужная информация была расшифрована добытыми нами ключами, я их не видел. Каждый получил свою долю и

vr­online | июнь 2010


88

Кретиff

проводил время, как считал нужным. Отдых мы заслужили. Если, конечно, можно считать заслугой кражу чужой информации. ­ Я так понимаю, только я и Flash не в курсе дела? ­ спрашиваю, делая глоток сока. Каждый заказал себе, что хотел. Мне же просто влом наливать каждый раз сок в бокал, поэтому пью прямо с горлышка.

И Void рассказал свою затею. Он и Kornev не сидели без дела эту неделю. Близятся выборы. После завтра в город приезжает кандидат в депутаты. Некий Калужин Виктор Иванович. Впрочем, это не важно, Калужин или кто­либо другой. Они все «хороши». Достойных, ответственных и справедливых мало. По крайней мере, я таких еще не встречал. Очередное выступление кандидата, очередная порция лжи прямо в лицо народу. Народу, который поверит этому человеку, стоящему у трибуны. Дорогой костюм, дорогие туфли и галстук. Длинный кортеж из дорогих автомобилей. Неужели еще кто­то не понимает, что это не на зарплату все куплено? Неужели люди еще не понимают, что их обворовывают. И в первую очередь крадут их права и свободы, которые можно отнимать бесконечно. Void увлекся своим монологом. ­ Ты, ты и ты, ­ он по очереди показал на нас всех пальцем, ­ вы все это понимаете. Вы все это давно знаете. Мы живем за пределами системы, можно сказать, нас это даже не касается. В сети существует настоящая демократия, здесь – нет.

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

Мы все слышали про эту программу. Кажется, называется она «Безопасный Интернет». Дибильнее не придумаешь. Многие форумы забиты этой темой. Некоторые сообщества отреагировали на это взломами государственных сайтов, оставляя на них свои возражения. Не очень предрассудительно, но так уж мы умеем. Вот и Void хочет внести свою частичку бунтарства и, хакерского такого, неповиновения. И кажется не только он один. ­ Flash, что скажешь? – Спросил Kornev, всецело согласный с Void’ом. ­ Почему бы и нет? Сотрем к хренам их наглость! – он затушил сигарету о

пепельницу.

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

­ А что ты думаешь, Driver? – Void посмотрел на меня. А что я думаю. Пару часов назад моя голова была занята совсем другими мыслями. А теперь я сижу за столом со своей тимой и обсуждаю, как бы обосрать выступление этого придурка чиновника. И похоже все ждут только моего согласия. ­ Не знаю, Void. – я откинулся на спинку дивана, ­ у тебя хоть план есть? Все так спонтанно. Впрочем, как и всегда.

­ Ну, канешн, ­ он расплылся в улыбке.

Следующие минут семь Void и Faila рассказывали нам свою идею. Вовсе не крупная, но красивая затея. И кто попало, ее не провернет. Но я почему­то еще сомневаюсь. ­ Мне надо подумать.

­ Думай, Driver. Время еще есть, ­ Faila встала из­за стола и застегнула курточку.

Закончился второй пак сока. Flash затушил третью сигарету. Kornev, похоже, набирал смс­ку. Он встал из­за стола: «Мне пора, народ. Скоро увидимся». ­ Погоди, я с тобой, ­ я встал за ним.

­ Давайте, до встречи, ­ Void махнул нам рукой.

Мы вдвоем вышли на улицу. Уже стемнело. Мокрый асфальт, кое­где лужи. Галимая погода, в общем. Kornev подошел к своему Opel. ­ Я думал, ты на своем звездолете, ­ удивился он отсутствию моего байка.

­ По такой погоде? Потом ни его, ни костюм не отмою. Faila как знала и заехала за мной после работы, ­ объясняю я. ­ Так давай я подвезу тебя.

Мне сейчас хотелось пройтись. Подумать. Взвесить все «за» и «против». А это сложно делать, когда рядом кто­то находится. ­ Спасибо, но я лучше пройдусь.

­ Что ж, тогда до скорой, ­ он махнул мне рукой и сел в автомобиль.

Я иду к ближайшей автобусной остановке,

vr­online | июнь 2010


89

Кретиff

обходя лужи. Кое­где на лавочках сидят пьяные парочки. Здесь очень малолюдно, да к тому же в такое время. Под легкими порывами ветра с деревьев капают мелкие капельки воды. Не пойму, то ли душно, то ли прохладно и сыро. Непонятная какая­то погода. Как и мое настроение. Сейчас не хочется никого видеть, особенно встретить знакомого. Задумавшись над словами Void’a, я не сразу заметил двух парней, стоящих на остановке. Один из них достает из пачки сигарету и хлопает себя по карманам. Второй, делает глоток пива из бутылки. Может, зря я не поехал с ним на машине? ­ Эй! Пацан, у тебя огонька нет?

­ Не курю, ­ коротко отвечаю я, пытаясь пройти между ними.

­ А если подумать?! – он толкает меня в грудь ладонью и ехидно усмехается.

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

­ Ты, кажется, не понял! – и этот дибил ведется. Он снова хочет меня толкнуть, но я уже готов к этому. Обеими руками крепко хватаю его за кисть и движением по дуге, выворачиваю ее наружу, на излом. Айкидошный прием. Что бы избежать перелома, тело интуитивно делает переворот в воздухе. И он падает на асфальт. Это не на маты падать. Больно, я знаю. Нет времени фиксировать его руку. Я уже получаю в челюсть кулаком от второго. Отшатываюсь назад и спиной опираюсь о фонарный столб. В последний момент успеваю пригнуться и бутылка от пива, разлетающейся на осколки над моей головой, врезаясь в столб. Сейчас не время думать о гуманизме. Бью кулаком ему в пах. Корчась от боли, он выпускает из рук только что образовавшуюся «розочку». Я встаю, хватаю обеими руками его за голову, и бью коленом. Словно спиленное дерево он грохается на траву, сзади павильона. Я поворачиваюсь ко второму. «Куряга», держась за кисть, пытается встать. Делаю шаг в его сторону и с разворота бью ногой ему в грудь. Он слетает с бордюра на край дороги. Каким способом можно побеждать? Любым. На улице по прежнему никого. Пора бы уходить отсюда. Возможно, кто­то видел драку из окна и вызвал милицию, а она не будет разбираться кто прав, а кто нет. Но я все же решаюсь склониться над лежащим на земле и держащимся за грудь мужиком, и прошептать: «Это ты не понял, пацан. Курить вредно». В его глазах видно боль и

гнев. Но теперь он не может мне возразить. Я выворачиваю свою двустороннюю куртку на изнанку и одеваю, но уже красную по цвету. Пройдя дворами к другой дороге, я вызвал такси. Мандраж прошел, когда я уже принимал душ. Такие стычки это всегда неприятно и страшно. Настроение упало в ноль. Делать ничего не хотелось. Я смотрел на город с балкона и рассуждал над планом Void’a. Я поймал себя на мысли, что я не всегда был таким. Решительным, дерзким, может наглым. А какого черта? Я достаю коммуникатор и набираю ему смс: «Я с вами». Нервное окончание дня выдалось. Единственное, что успокаивает меня это мысль о скорой встрече с Катей. *

*

*

Девять часов утра. Солнце почти высушило лужи на дорогах от недавних дождей. Легкий ветерок одаряет собравшихся людей теплым воздухом. На одной из площадей города, возле дома культуры, собралась довольно большая толпа народа. Как обычно это пенсионеры, пришедшие посмотреть на будущего депутата, который уж точно наведет порядок. Еще пришли студенты и школьники, готовые за налоги своих же родителей махать флажками необходимой партии. Причем им без разницы, какой. Сегодня платит один, завтра – другой. Некоторые родители пришли со своими детьми. Где­то в этой толпе находятся Flash и Kornev. Основную часть своей работы они уже выполнили, теперь будут снимать на камеру все происходящее. На здании ДК, с большими стеклами с одной стороны, на уровне третьего этажа висят три больших экрана. Раньше там был только один и использовался он для рекламы. Перед приездом чиновника, распорядились повесить по бокам еще по одному. Его выступление будут снимать на камеры, а изображение передавать на эти экраны. Так будет видно и слышно тем, кто не сможет подойти близко к трибуне. Так же планируется после выступления показать людям маленький патриотический видео ролик, рассказывающий о достижениях и заслугах данной партии перед народом. Ближайшие кварталы патрулируются сотрудниками милиции. Некоторые участки дорог перекрыты для свободного проезда кортежа чиновника. ­ Не много ли чести? – недовольная Faila сворачивает в объезд, куда ей показывает своим жезлом гаишник. Она проезжает еще пару кварталов и

vr­online | июнь 2010


90

Кретиff

паркуется на обочине. От сюда есть прямая видимость на здание с экранами. Как раз то, что надо. Void, как всегда, сидит рядом. На специальной подставке лежит его ноутбук. В слот расширения вставлен адаптер для беспроводной сети. От него тянется проводок к маленькой антенне, которая пока лежит на бардачке. Я давно прошмыгнул в здание и сейчас подымаюсь по лестнице на третий этаж. Все оборудование, необходимое для выступления, настраивалось техниками какой­то компании сегодня утром. Поэтому у нас не было времени подготовиться заранее и основная работа делается буквально за пол часа до выступления. В этот раз никаких костюмов и масок. На мне неброская одежда: джинсы, футболка, кепка и рюкзак через плечо. В рюкзаке точка доступа, которую специальным образом перепрошил и перепаял Flash. А еще схема с инструкцией сборки этих экранов, которую я, кажется, выучил наизусть. Подымаюсь на третий этаж и прохожу на маленький балкончик, на котором и закреплены три монитора. Снова отвертка, снова я откручиваю винтики и снимаю крышку. Все как положено, все на своих местах согласно схеме. Интересно, каким образом Kornev раздобыл эту инструкцию? Данные мониторы могут работать как один, разделяя между собой широкоформатное изображение. Вот видео регистратор, распределяющий картинку. Провода, от него спускаются с балкончика вниз. Оператор управляет всем с улицы. Он должен видеть выступающего и включать необходимые слайды или видео в определенный момент времени, подстраиваясь под его речь. Что ж, мы тоже. Я подсоединяю к нужным разъемам крокодилы, идущие с проводами от точки доступа. В нее вставлена SD карточка всего лишь с одним видео файлом, который нам необходимо запустить. Но только мне желательно быть в это время уже за пределами здания. Ведь убедившись, что оператор не напартачил, охрана думаю, сбежится сюда. В этот раз мы не переговариваемся через радио. Void переживал, что переговорные устройства охраны могут работать на той же частоте. Да в принципе, не сильно они и нужны сейчас. Тем временем, внизу на трибуну уже поднялся кандидат в депутаты. Он встал за микрофоны и начал произносить свою речь. Я не вслушивался в его слова. И так ясно, что он будет гнать пургу. Все эти сладкоголосые болтуны и политиканы говорят одно и тоже. Мы сделаем вашу жизнь лучше, мы позаботимся о вас, только выберите меня. Дайте мне власть. Я уже закончил. Дождавшись пришедшую через

минуту смс­ку «Есть линк. Сваливай», я разворачиваюсь и выхожу с балкона. В следующий момент я цепенею. Это же она. Мое сознание просто переполнено догадками. Да что она тут делает? ­ Кто вы такой и что здесь делаете? – деловым тоном спрашивает Катя.

Я подымаю козырек кепки, и она узнает меня.

­ Это… это ты? Андрей? Что… что ты здесь делаешь? – она растеряна не меньше моего. ­ У меня к тебе тот же вопрос, ­ даже не зная толком, что сказать, ответил я. ­ Я вообще­то отвечаю за работу этой мультимедиа системы. А твое присутствие здесь мне абсолютно не понятно, ­ вероятно она тоже теряется в догадках. Как же я был прав. Вторая встреча оказалась не менее неожиданной и загадочной. Чиновник тем временем уже заканчивает свою речь.

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

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

­ Это все круто, но я по­прежнему не вижу Driver’a, ­ Faila все наблюдает за стоянкой, с которой я давно должен был выехать на своем мотоцикле. Неожиданно звук с колонок экрана за моей спиной пропадает. Небольшое мгновение, кажется, что экраны вообще вышли их строя. Но потом начинает играть

vr­online | июнь 2010


91

Кретиff

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

­ Это что такое? – неуверенным голосом она спрашивает у меня, ­ Что здесь происходит?

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

Нас, всех остальных, превращают в перхоть Они проводят невнятные реформы

Меняют гаишникам название и форму Кидают стариков через одно место

Каждый день проверяя, из какого же мы теста!

Остолбеневшие, все как вкопанные смотрят на это видео. Кандидат тоже. Его лицо покраснело. Его охрана переговаривается по рации. Здесь типа демократия, на самом деле царство Я так люблю свою страну... и ненавижу

Государство, государство, государство! Я ненавижу

Государство, государство, государство!

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

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

она все еще растеряна.

­ Кардинально нет. Но это уже что­то.

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

На эти деньги продолжают войны Люди делят власть и нефть

Мы пешки в играх, мы не люди, нет! Плати налоги, живи спокойно,

И похеру на то, живешь ли ты достойно! Твое право ­ заткнуться, молчать! Ты еще не понял!?

Гони бабки, твою мать!

Она так и не сдвинулась с места. ­ Катя, ­ я хочу подойти к ней.

­ Уходи, Андрей. Тебе надо уходить, ­ она подняла на меня свои глаза, на которых я замечаю слезы. ­ Но…

­ Я сказала, уходи! – она впервые накричала на меня. Сейчас не тот момент, что бы выяснять отношения или объясняться. Если меня поймают, то я этого сделать уже не смогу. Кажется, на улице начался какой­то движняк и гул. Наверное, это видео вызвало буйную реакцию у собравшихся людей. Впрочем, я этого не вижу. Открывая ногой дверь, выбегаю на лестницу. Здесь типа демократия, на самом деле царство Я так люблю свою страну... и ненавижу

Государство, государство, государство! Я ненавижу

Государство, государство, государство!

На последнем пролете вижу мужика в черном костюме, подымающегося мне на встречу. Я на взводе. Не знаю, есть ли у меня другой выход? Бросаю ему в лицо свой рюкзак. Он ловит его руками и тут же получает в плечо ногой. Падает на спину и откатывается. Я пробегаю мимо него и выхожу в двери, ведущие на стоянку, которая находится с обратной стороны здания. Блин! Не идиоты все же. Второй охранник опускает шлагбаум на въезде и vr­online | июнь 2010


92

Кретиff

бежит в мою сторону. Я запрыгиваю на свой байк. Ключ в зажигание и двигатель заводится с пол оборота. Зажимаю передний тормоз, выкручиваю ручку газа и поворачиваю руль. Буксуя, мотоцикл разворачивается на месте. Отпускаю тормоз и, с нарастающей скоростью, переднее колесо подымается вверх. Охраннику ничего не остается, кроме как сделать перекат в сторону, что бы не попасть мне под колеса. Деревянный шлагбаум разлетается на щепки, встречаясь с рамой моего байка. Я снова становлюсь на два колеса и жму, все быстрее разгоняясь по выезду из этой стоянки. Но в следующее мгновение две милицейские семерки перекрывают мне выход. Плотно так друг к другу стали носами, я не протиснусь. Заднее колесо перестает вращаться, идя юзом и оставляя на асфальте след от резины. Мои гениальные идеи закончились. Я словно загнанный в угол зверь. На этой мысли из­за поворота с заносом вылетает Mazda Файлы и мчится в мою сторону. Она все быстрее разгоняется, и останавливаться не собирается. ­ Faila, твою мать, что ты делаешь! – я, чуть ли не кричу это.

В десяти метрах от милицейской баррикады из их автомобилей Faila делает полицейский разворот. Визг низкопрофильных покрышек и Mazda уже мчится задом. Скрежет металла и грохот разлетающихся фар. Две семерки разворачиваются под ударом Мазды и лишаются своих передних бамперов вместе с помятыми капотами. Тачка Файлы тоже пострадала. Заднего бампера как небывало, фар тоже. Спойлер слетел с крыши и процарапал по асфальту несколько метров. Она дает мне гудок пару раз и с пробуксовкой снова газует вперед. Вот он, зеленый свет. Я снова набираю скорость и пролетаю мимо двух покореженных автомобилей милиции. *

*

*

Людей здесь как всегда много. Кто­то тащит свои сумки, кто­т�� остановился, что бы посмотреть расписание поездов на табло, кто­то уже бежит за ним, явно опаздывая. Я же стою за колонной и выискиваю в толпе ее. Неужели не придет? Очень надеюсь на обратное. А может она не получила мое послание? Вряд ли. Я все проверил, оно дошло. Должно было дойти. Отрываясь от погони, признаюсь, я не сильно задумывался, когда и каким образом вновь увижу Катю. Бешеная гонка длилась не долго. Я смог скрыться дворами, лавируя на

своем мотоцикле. А догнать Файлу этим ребятам на их «мусорных ведрах» просто не дано. Собравшись в оговоренном ранее месте, решено было пропасть из виду на какое­то время. Новые снятые квартиры для вещей, гаражи для автомобилей, путевки на руках. Все по­тихому разъехались кто куда. Отснятое Flash и Kornev видео вызвало множество восторженных отзывов на youtube. Впрочем, оно разнеслось по многим сайтам. Тут я замечаю знакомую фигуру в толпе. Катя стоит в центре вокзала и пытается найти меня. Хм, кажется, пришла одна. ­ Я очень рад видеть тебя снова, ­ подкравшись сзади, тихо говорю я.

Она оборачивается. На ее лице явная грусть. Я ожидал всего. Упреков, криков, пощечины. Но я и подумать не мог, что она бросится мне на шею с объятиями. Я не могу сдержать свою радость и крепко обнимаю ее в ответ.

­ Ты дурак, Андрей, ­ с вздохом шепчет она.

Я улыбаюсь, глядя ей в глаза. Кажется, она тоже немного повеселела. Катя достает из кармана открытку, которую я послал ей вместе с цветами. Открывает и зачитывает мое послание: «Любой поступок, безразлично, чем он был вызван, тянет за собой целую цепочку следствий. А вот каких – зависит совсем не от самого поступка, только от отношения к тебе». Внизу дата, время, место и моя подпись. ­ Поехали со мной?

­ Что? Куда? – наверное, я не перестаю ее удивлять. ­ В Крым. На море. Не на долго, отдохнем, погуляем. ­ Но как же…

­ Брось все, ­ я осмелился перебить ее, ­ забудь про все на неделю. Поехали, ­ достаю из кармана билет на поезд.

­ Но у меня нет билета, ­ снова удивление на ее лице. Я пальцами расслаиваю в руке билеты, которые были сложены один на один. Катя снова улыбается и целует меня. Это значит да!

vr­online | июнь 2010


Автор: Neon_Kaligula

93

Креатиff

Песнь легиона Часть 3

09:00, 1 5 часов назад

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

­ Помогите, ­ прохрипела лежащая на полу фигура в плаще.

Они спешно подняли его под руки, он был слаб, еле стоял на ногах. Один из них подхватил его и прислонил к стенке, чтобы было легче стоять. Человек что­то бормотал и надолго закрывал глаза, норовя заснуть. Его приходилось потряхивать, чтобы он не заснул окончательно. Второй милиционер осматривал трупы.

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

то прохрипел. Номер сто двадцать шесть.

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

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

"Смерть. Идём дальше." ­ Стоять! Вы умрёте.

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

"Голову нужно отрезать следующим образом: сначала делаем надрез по окружности, Слушать. Главное ­ слушать. Он не видел, разрезая кожу и частично мышцы. Далее но слышал, как за его спиной в ярости следует приложить нож, желательно пилкой, поднялась женщина, забыв о боли и к горлу и начать пилить. Горло быстро невозможности вздохнуть. Она как паровоз разойдётся, нужно только, чтобы появилась пошла на таран. дырочка. Дойдя до позвоночника, нужно "Ярость затмевает сознание. Нельзя просто оторвать голову." выиграть на одной лишь ярости. Для С трофеем в виде головы он проследовал успешного боя нужен холодный расчёт. наверх. Всё шло по плану ­ в квартире Уклоняйся." убитых находилось три человека, а этажом Он отпрыгнул в сторону. Просто и ниже была приоткрыта дверь в квартиру. эффективно, как всё гениальное. В Внутри на кровати спал ребёнок лет семи­ восьми. Без особых предисловий он отрезал большинстве случаев эта гениальность ему голову. Тот, конечно, проснулся за миг до лежит на поверхности, только люди конца, открыл глаза, всплеснул руками и что­ привыкли издревле глядеть вдаль, поэтому

vr­online | июнь 2010


94

Креатиff

не видят очевидного. Логика проста ­ она не может вздохнуть, у неё перебито горло, а в лёгких плещется кровь. Её даже не стоит трогать. Через пару минут номер сто двадцать девять умрёт. Её имя было Зинаида Вячеславовна. Такое сложное для произношения детьми, а ведь он её знал ещё с детства. Ещё с детского сада, куда они приходили вместе с его мамой. Зинаида Вячеславовна всегда приносила ему какую­нибудь конфетку, в основном, конечно, карамельки, чтобы можно было растянуть удовольствие надолго.

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

"Ой, я же забыл, что у служителей правопорядка должно быть табельное оружие. Надо забрать."

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

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

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

Здесь не было прямого выезда на дорогу, ему нужно было развернуться и там проехать огородами. Краем глаза он заметил щуплого человечка в тени подъезда. Он остановился и открыл ему дверь. Человечек будто этого только и ждал. Он впрыгнул в машину, закрыв за собою дверь. В грудь ему тут же вошёл нож. Он смотрел на вытекающую из груди струйку крови, о чём­ то усиленно думая. Потом он закрыл глаза. Номер сто тридцать. Около помойки они остановились. Легион выгрузил тело и сунул его в мусорный бак ногами кверху.

Ещё на подъезде сюда он заметил старушенцию с сумкой для бутылок. Он быстро разбежался прочь от помойки метров на десять, остановился и обернулся. Бабуля что­то ковыряла в кирпичной окантовке помойки. Он взял низкий старт, вытянул руки вперёд.

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

"Нет, сейчас я иду вне графика."

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

"Если к тому, куда надо попасть, есть код, то этот код должен быть записан где­то неподалёку от искомого места."

Он оказался прав ­ в багажнике лежал АКМ с двумя магазинами. Ну, что ж, осталось сделать последние приготовления. Он повернулся к мусорному баку и расстегнул ширинку. Повисла пауза. Он застегнул ширинку.

­ Нет, ­ сказал он с улыбкой, ­ я сделаю это там. Ты слышишь?! ­ он обращался к небу ­ Я иду к тебе, к твоей цитадели, сейчас я её буду атаковать. Готовься!

Какой­то пьяный переходил дорогу без зебры. Легион врубил третью передачу, разогнался, прямо перед пьяным ударил по тормозам. Машину развернуло и повело. Бампер с размаху попал пьяному в живот, отбрасывая его в сторону. Он пролетел несколько метров и упал спиной на

vr­online | июнь 2010


95

Креатиff

ограждение, сложившись пополам.

с лишним человек. Ничего, оправдали."

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

Романтика, однако.

Номер сто тридцать два.

Десятка была уже на списание, но "Убивайте, убивайте, убивайте. Не думайте о патрульная всё ещё на ходу. Он поехал последствиях. За вас будет отвечать партия." дальше, минуя автобусную остановку. Здесь слева неподалёку было радио­поле, там было множество антенн. Прекрасный вид открывался из окна: Он остановился около остановки против четырёхполосная дорога, справа и слева движения. Человек, до этого прятавшийся проплывают высокие деревья. Он ехал в под навесом листвы ближайших деревьев, деревню, это всего в паре километров выскочил и подбежал к машине. отсюда по прямой. Народу здесь вообще не было, да и кому нужна эта дорога. ­ Хотите подвезу? ­ Вежливо осведомился Возвращаться будем в объезд через Легион. новостройки. Не дожидаясь ответа, он резко отворил Он выжимал сотню по дороге, где было дверь, попав человеку по лбу. Тот упал в разрешено не более половины. Но, даже на грязную лужу. этой скорости он смог заметить ­ Спать, ­ прошипел он и выпустил ему пулю образовавшуюся сзади красную десятку с в лоб. мигалками и тонированными боковыми стёклами. Она стремительно догоняла его и Номер сто тридцать пять. хотела идти на обгон. Осталось четыре пули в пистолете, он сунул Пижон. Видит, что тачка патрульная с синими его в карман. Дождь продолжал моросить, номерами, а всё равно наглеет. Мигалку но ветер вроде бы стихал. Природа. купил. На вид ему лет двадцать, не более, рядом сидит девушка, это заметно по пышным волосам. На долю секунды Легиону показалось, что пижон едет без ремней безопасности. 1 0:00, 1 4 часов назад

Лобовое стекло вылетело, а вслед за ним оттуда вылетел водитель, пролетел метров десять по мокрому асфальту и застыл в позе морской звезды. Номер сто тридцать три.

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

"Это жестокий мир, что бы там не говорили. Либо ты, либо тебя."

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

"Вон, за рубежом, говорят, паренёк в метро в качестве самообороны пристрелил двадцать

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

По дороге далее справа следовали покосившиеся и давно необитаемые дома. Пару лет назад всех выселили отсюда, аргументируя тем, что здесь будут новостройки. Все ушли, а новостроек всё нет. Они есть там, далеко в глубине деревни, там продолжение города строится. Через пару сотен метров он повернул направо. Здесь в некоторых домах всё ещё кто­то жил; тут была подстанция и ещё парочка муниципальных сооружений.

Проехав ещё пару сотен метров, он повернул налево. Вот он ­ купол церкви. У ворот заборных сидел под навесом попрошайка с протянутой рукой. Легион остановился около него. Сунув руку в карман, он выудил оттуда десятку, протянул ему. Тот трепетно принял взятку. В ту же секунду его схватили за голову, и он получил удар коленом в лицо. От неожиданности он упал и ударился головой о твёрдый бетон. Номер сто тридцать шесть.

vr­online | июнь 2010


96

Креатиff

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

Чуть подумав, он сунул труп в машину на место водителя, а сам направился к церкви.

"Всё решают мгновения. К цели можно идти долго, можно вообще даже не дойти, но, если доходишь, тогда наступает момент истины. За мгновения, редко за минуты, решается судьба всего времени, что было затрачено на подготовку." Сейчас всё должно было решиться минуты за три, максимум ­ шесть. Главное ­ это начать. Он остановился перед главным входом на пороге, о чём­то размышляя. Злорадная ухмылка озарила его лицо. Он перекрестился.

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

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

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

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

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

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

"Каждой твари по паре, плодитесь и размножайтесь."

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

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

"Цербер вышел на охоту. Он голоден."

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

Резким движением ноги он заставил её согнуться, тут же прыгнул, очутился позади неё и набросил струну ей на шею. В тот же момент боль настигла его. Такая резкая, проходящая снизу и до головы. Он молчал. Вся боль и ярость от боли он перевёл в руки. "Я видел это в американских фильмах, но С нечеловеческой силой он стягивал струну никогда не практиковал." на её шее, потом последовал рывок. В стену отлетела женская голова. Тело Легион продолжил свой поход. После трагического полёта пули, понимая, что люди перевернулось и пролетело пару метров. Номер сто сорок пять. сообразят, что случилось лишь через несколько секунд, он побежал, стремительно Его даже не испачкало кровью, так всё ускоряясь, вдоль стены, стреляя по пастве. быстро произошло. Кровь при полёте выплёскивалась из тела, разлеталась в "Стреляй в спину, бей лежачего, делай всё стороны, окропляла фрески на стенах. В тех для победы и не расслабляйся. Ибо помни: же стенах теперь были пули, как они тебя не пощадят."

vr­online | июнь 2010


97

Креатиff

напоминание о бойне.

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

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

"Это сложно ­ ощущать романтику в ситуации, когда её нет. Вот, прожив эту ситуацию, можно говорить, что это было романтично. Но почему­то никто не говорит, что то, что он сейчас делает ­ романтично." Ещё на входе он заметил стоящую за углом шестёрку. Судя по всему, хозяин её лежал здесь. Через минуту поисков он обнаружил ключи.

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

высоченными деревьями, детский сад, своя котельная и подстанция, множество площадок для игр, тренажёрные залы и прочее. Первой на очереди шла котельная, которая отвечала за подачу горячей воды в дом отдыха. Дверь была закрыта, но он постучал. Открыл ему толстый дядька с усами и раздражённым взглядом. ­ Выходи, ­ сказал ему Легион, сунув пистолетом в пузо, Развернись.

Тот покорно вышел, встал лицом к стене и расставил ноги, как при обыске. Легион подошёл к нему и ударил пистолетом в висок. Крови не было, он просто упал без сознания. Он выудил из рюкзака упаковку с одноразовым шприцем и иглой.

"Всегда только одноразовые шприцы. Надо заботиться о здоровье."

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

"Только красота спасёт мир... Хотя, нет, вру. Его уже ничто не спасёт. Армагеддон близок. Ближе, чем сотню лет назад." Шло время.

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

Немного заплетающейся походкой он прошёл мимо компрессора и вышел на улицу. Там он и увидел своего товарища, прислонённого к стене, спящего.

­ Витёк, твою мать, ­ воскликнул он, отливая на железяку рядом, ­ мы его ждём, а он дрыхнет. ­ Нет, он умер, ­ раздался голос рядом. Там стояла странная фигура с затемнённым лицом. ­ Это я его убил.

Мужчина не знал, что сказать. Он взглянул на Витька. Тот спал, не было сомнений. Только вот грудь не вздымалась. Он хотел спросить незнакомца что­то, но получил металлической трубой в дыхалку. Он упал на колени. Легион размахнулся, и снёс ему пол головы. Номер сто сорок восемь.

vr­online | июнь 2010


98

Креатиff

Женщина всё лежала на плохенькой кровати, ожидая своего милого. Его не было всего минуту или около того ­ нормальное время, сейчас он вернётся. Она даже слышала его шаги за дверью. Она предвкушала страсть, и вряд ли обратила внимание, что шаги стали тяжелее. Дверь отворилась плавно, как во сне. Здесь был полумрак, она чётко различила знакомую тень.

­ Ты ве... ­ пистолетная пуля прошила её сверху вниз ото лба до шеи и вышла наружу, выпадая как гусеница с листа. Номер сто сорок девять.

11 :00, 1 3 часов назад

"Чистая работа ­ это чистая работа, если только она не грязная. Это аксиома игры, можно сказать, одно из правил. Хочешь играть, соблюдай правила. Не хочешь ­ выбывай. А всё остальное ­ это блеф." Если отключить котельную, скоро здесь будут все. Он щёлкнул несколькими выключателями. Если план, висящий на стене, верен, то он только что отключил администрацию. Оставалось ждать.

В течение минуты он спрятал трупы в подсобке. Можно было подготовить ловушку, но это если успеет. Он направился в детский сад, так как он был ближе всего. Тут должна быть администрация и воспитатели. На входе никого не было, но сторож просто обязан быть. За зданием обнаружилась небольшая пристройка, вроде склада. Дверь была тонкая, но рядом с ней лежал амбарный замок внушительных размеров. ­ Эй ты! А ну айди оттуда! Собак натравлю! ­ грозно ругался сторож, седой дядька с тросточкой.

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

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

недель."

Парадный вход был открыт. Внутри было красиво и уютно. Когда он входил, у раздевалки сидела молодая женщина с книжкой в руках. Она как­то безразлично подняла на него глаза, за что они тут же были выколоты. Такой звук лопающегося пузыря. Она закричала. Удар сверху трубой одной рукой. Череп треснул, обнажая кроваво­розовые мозги. Номер сто пятьдесят один.

"Когда ты будешь там, ты будешь не один."

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

"В сущности, нет ничего страшного и противного. Есть просто предубеждения. Если понять, что мозг есть в каждом человеке, то противно не будет."

Женщины любят кричать, кричать пронзительно, переходя на визг. Эти стояли молча. Был ли это шок или они пока ещё ничего не поняли, разбираться не было времени. Он подкрался незаметно сзади с металлическим стулом в руках. Размах, удар. Номер сто пятьдесят два.

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

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

Под дождём по аллее, уходящей вдаль, бежала женщина лет тридцати со своей дочкой. Обе они были одеты в спортивные костюмы, а сверху на них были плащи. Стоп! Это не по правилам. Но так даже интереснее.

vr­online | июнь 2010


99

Креатиff

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

Мать была в одновременно множестве состояний: ярости, панике, горе и недоумении. Она не могла поверить, что то, что бежало только что рядом с ней, теперь представляет собой охладевающее тело. Желание спасти ребёнка придаёт иногда матерям большую силу.

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

"В критических ситуациях отказывает логика, человек двигается по интуиции и воспринимает только короткие и простые команды. Это правильно ­ у мозга задача выжить стоит, а не решать двойной интеграл." Раздался звонок мобильника. Просвистел выстрел. Пуля угодила в грудь правой женщине. Мобильник звонил у мужика, но попала пуля в женщину. Всего одно пятнышко, одна дырочка в теле. Крови не было совсем. Номер сто пятьдесят шесть.

Вторая женщина почему­то бросилась на мужика, закрывая его собой, хотя он был таким объёмным, что мог бы сам покрыть её три раза. Он приставил ей пистолет ко лбу.

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

Легион подошёл к нему спокойно и с В момент, когда они поравнялись, он схватил некоторым презрением. её за плащ и развернул. Она ударилась "Отработанный материал системы. Ты головой об угол и упала. Он встал над ней, больше никому не нужен, система тебя делая разрез на всю шею. Номер сто поюзала и отвалилась напрочь. Один против пятьдесят пять. системы идти может, но это будет тяжело." Класс! Складируем. Он спихнул тела в Он перевернул мужика на спину и одним канаву рядом. Там их скоро найдут крысы. движением разрезал ему сонную артерию. Впрочем, те, кого он ждал, ещё не После чего вторым быстрым движением появились. Дорога к домам здесь всего одна, разрезал ему кожу на шее, и достал оттуда стоит самому к ним сходить. трубочку артерии. Такая упругая, но мягкая, с бьющей оттуда кровью. Номер сто Они сами пришли к нему как миленькие. пятьдесят восемь. Такие взволнованные. Их было трое ­ две женщины в пиджаках и один мужчина, по Он шёл дальше по аллее ещё метров сто, а виду слесарь. Они остановились около него, потом перешёл на лёгкий бег. спросив, не видел ли он чего необычного. В На ствол дерева сидел большой жук с обыденной жизни это можно было назвать длинными чёрными усами, видимо, короед. хамством, но он промолчал. Они же Он обладал мощными челюстями и замолчали, когда он достал пистолет. длинными цепкими лапами. Не стоит Как раз три пули оставалось, но он не хотел поддаваться на то, что он хочет вас укусить, тратить больше одной. Ветер усиливался и совать ему пальцы. У саранчи челюсти снова, а дождь всё лил. Целиться нужно в больше, но они не могут сравниваться по голову или сердце, так умирают сразу. силе. Саранча грызёт траву, а короед ­ кору Слесарь получил пулю точно в пах, а дамы и дерево. бросились наутёк. Надо было возвращаться. Дорога была всё ­ Стоять! ­ скомандовал он. ­ Помогите ему! ещё не близкая, близился экватор. Если Быстро! отсюда выходить, то нужно идти жилыми Ему приходилось говорить громко, коротко и домами через магазины. чётко, чтобы его понимали. В одном из домов, самом богатом, эдаком vr­online | июнь 2010


100

Кретиff

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

"Наивные, непуганые. Хотя, чего им тут бояться."

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

"Хорошая проверка готовности. Нельзя думать о чём­то другом."

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

"В старину, когда вешали, у смертников часто случался стояк."

vr­online | июнь 2010


Автор: Jimmy Jonezz Email: jimmyjonezz@bk.ru

101

Безопасность

I2P

Анонимность в сети Сеть, за которой легко спрятаться

В последнее время ходит много разговоров об анонимности в сети, по большей части это связано с ужесточением ведения политики против пиратства и защите авторских прав. Известные нынче торренты и файлообменники, все чаще подвергаются нападкам голливудских студий. Вспомнить тот же, The Pirate Bay интернет просто нашпигован различными историями о разбирательствах над крупнейшим BitTorrent-трекером, читая которые невольно начинаешь задумываться об анонимности и о том, какие изменения, в связи с такой обстановкой, нас ждут. В ряде случаев анонимность стоит на первом месте, будь то корреспонденция электронной почты, переписка по «аське», общение через VoIP, веб­серфинг, хостинг, файлообмен и т.д. Первое, что приходит на ум, это прокси, но мы то знаем, каково это пребывать в постоянном поиске, свежих адресов или выкладывать немалую сумму денег за «элитные» прокси. Если даже опустить эту проблему, на ее место встанут другие – бесплатные прокси постоянно отваливаются или просто перестают работать, и нет уверенности в том, что трафик не прослушивается. Даже, в цепочке прокси­серверов, один, в любом случае будет «слабым звеном», а это уже полное аннулирование всякого понимания о безопасности.

На выручку спешит открытое программное обеспечение, а именно I2P, созданное для организации анонимной, оверлейной, зашифрованной сети. Она построена на основе самоорганизующейся распределенной сети Network database, которая является модифицированной DHT,

но отличается тем, что хранит в себе хешированные адреса узлов сети, зашифрованные AES IP­адреса, а так же публичные ключи шифрования, причем соединения по Network database тоже зашифровано. Ее особенность состоит в том, что трафик в сети, который шифруется от отправителя до получателя проходит четыре уровня шифрования: сквозное, чесночное, туннельное и шифрование транспортного уровня, а в качестве адресов сети используются криптографические идентификаторы (главным образом состоящие из пары публичных ключей). Каждое сетевое приложение на компьютере строит для себя отдельные шифрованные, анонимные туннели. Туннели в основном одностороннего типа (исходящий трафик идет через одни туннели, а входящий через другие) — направление, длину, а также какое приложение или служба создали эти туннели выяснить практически невозможно. Все передаваемые сетевые пакеты имеют свойство расходится по нескольким разным туннелям, что делает бессмысленным попытки прослушать и проанализировать с помощью сниффера проходящий поток данных. Так же происходит периодическая смена (примерно каждые 20 минут, но пользователь может самостоятельно настроить этот период – прим. автора) уже созданных туннелей на новые (с новыми подписями и ключами шифрования).

В I2P сети нет никаких центральных серверов и нет привычных DNS­серверов, также сеть абсолютно не зависит от внешних DNS, что приводит к невозможности уничтожения, блокирования и фильтрации сети, которая будет существовать и функционировать, пока на планете останутся хотя бы два компьютера в сети, поэтому анонимные сайты и различные веб­ ресурсы – это уже реальность, а не записки фантаста. Исходя из этого, выходит, что можно создавать скрытые сервера и сайты работающие в этой сети в «домашних условиях», при этом небольшим бонусом служит красивое имя, вида ­ name.i2p

vr­online | июнь 2010


102

Безопасность

(«name» – имя ресурса). Имея связку «Apache» + «PHP» + «MySQL», вполне реально поднять сервер. Второй элемент – настройка, без правильного подхода можно и не добраться до заветной цели, так и остановившись у начала, но об этом чуть ниже. Я упоминал, что данная программа кроссплатформенна? Если нет, то повторюсь – в виду того, что использовался язык Java, при программировании данной системы, мы получаем возможность использовать ее на различных платформах, начиная с ОС Windows и заканчивая Solaris, не говоря уже о Unix\Lunix, MacOS. В I2P сети используются (для разных уровней и протоколов) следующие системы и методы шифрования и подписи: 1.256 бит AES режим CBC с PKCS#5; 2.2048 бит Схема Эль­Гамаля; 3.1024 бит DSA;

4.2048 бит Алгоритм Диффи — Хеллмана; 5.Хеширование SHA256.

обновлений, а трафик сети увеличился в 5 раз.

Пришел момент, затронуть самое главное, ради чего все это затевалось – настройка и использование. Принцип работы заключается в следующем – на компьютере пользователя, после установления клиента i2p и Java­платформы (второй критерий обязателен – прим. автора), запускается виртуальный шлюз и программа начинает работать в режиме прокси­сервера, которая перенаправляет поток траффика в i2p сеть, тем самым, образуя некую «локальную петлю» – не зашифрованный траффик идёт только между локальным прокси и конкретным приложением. Затем он поступает в шлюз, шлюз его шифрует, и по миру отправляет уже в защищённом виде. Придя на адрес назначения, сообщение дешифруется только на удалённом шлюзе, на котором в свою очередь тоже присутствует «локальная петля», будь то сервер или собеседник. Для тех, кто пользуется платформой Windows, особых кривляний с настройками не требуется, лишь достаточно открыть настройки прокси в браузере и вбить следующий адрес: 127.0.0.1:4444.

История данного проекта начинается с 2003 года для поддержки всех тех, кто участвует в В качестве подопытного возьмем другую создании более свободного общества и систему — Ubuntu 10.4. Java есть по заинтересован в новом нецензурируемом, анонимном и безопасном средстве общения. умолчанию, поэтому перейдем сразу к установке программы и воспользуемся I2P — это попытка создать защищенную самым удобным способом — загрузке и децентрализованную анонимную сеть с установке через терминал (легче не малым временем отк��ика и свойствами придумаешь — при. автора): автономности, отказоустойчивости и масштабируемости. Одной из важных задач, wget "http://mirror.i2p2.de/i2pinstall­0.8.exe" ­O является способность функционировать в ./i2p_install.exe самых жестких условиях, даже под Загружаем последнюю версию прямо с давлением организаций обладающих репозитория сайта, флаг ­О позволит значительными финансовыми или загрузить файл в домашнюю директорию и политическами ресурсами. Как уже было записать файл под именем: i2p_install.exe. сказано, все аспекты сети доступны в виде Не обращайте внимания на расширение исходного кода и бесплатны. Это файла, Wine нам не понадобиться. Далее, одновременно и позволяет пользователям пробуем установить программу на свою убедиться, что программное обеспечение «тачку»: делает именно то, что заявлено, и облегчает сторонним разработчикам возможность java ­jar ./i2p_install.exe совершенствовать защиту сети, «заточив» После завершения установки, необходимо ее под свои определенные нужды, а также перейти в директорию с установленной оградиться от настойчивых попыток программой и запустить сервер: ограничить свободное общение. /home/anton/i2p/i2prouter start Выпущенная в мае 2009 года стабильная версия программы ­ 0.7.2, начала отсчет по Хочу заметить, что путь должен внедрению этого релиза в массы. До мая соответствовать вашему каталогу, куда вы 2009 года авторы проекта всеми силами установили программу. Теперь, чтобы начать удерживали пользователей от активной использовать i2p, настраиваем HTTP­прокси рекламы I2P сети, указывая на возможную в браузере: 127.0.0.1:4444. Это еще не все, нестабильность и beta­статус разработки. В если руки чешутся, а они бесспорно должны 2009 году было выпущено девять чесаться, то советую глянуть в панель vr­online | июнь 2010


103

Безопасность

администратора I2P, просто перейдите по этому адресу: http://127.0.0.1:7657/index.jsp. Панель управления полностью на русском языке, навигация очень простая, подробная статистика, дополнительные сервисы, которые я советую опробовать. Здесь же вы можете настроить запуск шлюза в режиме службы, чтобы каждый раз не загружать его вручную, но то уже на ваше усмотрение. Осталось только проверить работоспособность всего этого «хозяйство» на деле: http://i2p2.i2p – официальный сайт проекта.

Правильно говорится в одной старорусской пословице: «Не все коту масло», так и здесь. Как бы хороша не была сеть, все же есть некоторые минусы, которые не столь важны, но все же имеют свой вес. В обозримой области I2P сетей очень мало русскоязычных сайтов, поэтому стоит довольствоваться западным сегментом интернета. Для тех, у кого платный траффик, данная система противопоказана, т.к. идеология I2P такова, что система требует делиться своим траффиком с другими людьми, примерно также как в торрент­ сетях, поэтому лимит скорости можно увеличить, чтобы не находиться в долгом ожидании загрузки страниц. Безопасности и анонимности уделяется большое внимание, находясь, на волне всеобщего развития, мы не должны брезговать новыми открытиями. Тем более, что время диктует свои правила, правила которые нужно знать, чтобы всецело следовать им и умело обходить в нужный момент. Дополнительные ссылки:

vr­online | июнь 2010


Автор: Jimmy Jonezz E­mail: jimmyjonezz@bk.ru

104

Психо

Манипулирование

Воздействие и манипуляции Принципы воздействия и тонкости манипуляций

К несчастью, очень часто мы испытываем сужение сознания: получив сообщение, мы сразу же, с абсолютной уверенностью принимаем для себя одно­единственное его толкование. И оно служит для нас руководством к действию. ­ Сергей Кара­Мурза "Манипуляция сознанием"

Жизнь удивительна и многогранна. Можно бесконечное множество раз пытаться познать ее, и все равно, с каждым разом находить что­то новое для себя ­ открывать положительные, так и отрицательные аспекты социального общества и жизни в целом. Смотря на людей, как бы со стороны, с определенной долей уверенности можно сказать, что это довольно забавный процесс; забавно наблюдать за механизмами, которые управляют обществом, как многогранны способы взаимодействия людей друг с другом и в тоже время, ужасает, в хорошем смысле этого слова (если можно так выразиться — прим. автора) скрытая сторона данного аспекта. Я не зря заговорил о воздействии; в социальном обществе этому виду контакта уделяется большое внимание. Ведь без этого, по большому счету, невозможен сам контакт людей между собой. На протяжении нашей жизни, человеку приходиться воздействовать на кого­либо или на что­ либо, при этом человек и сам может находиться под чьим­либо воздействием, не зависимо от временного промежутка. И это неопровержимый факт. Вся жизнь — это не прекращаемое действие; без какого­либо действия или побуждения, все останавливается и прекращает движение.

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

Как я уже сказал, воздействие может осуществляться как осознанно, так и неосознанно. Манипуляция, как один из видов воздействия, часто применяема нами дома, на работе, с друзьями и т.д. Ведь в каждом из нас сидит маленький «божок», который хочет, чтобы все было так, как хочет он. В некоторых людях, он доминирует, превращая человека в злостного надзирателя, который хочет все контролировать. В других, он появляется, в моменты, когда это действительно необходимо, в­третьих — он постоянно дремлет. Идем дальше, уясним одну важную вещь — объект (ы) манипуляции и манипулятор, то, кто производит манипулятивные действия или воздействует — это основные составляющие любой манипуляции, т.к. должен быть объект воздействия и, скажем так, источник этого воздействия. Проще простого, но теперь попробуем углубиться в саму суть манипуляций.

Манипуляция — это жестокий вид воздействия, т.к. ее относят к одной из частей технологии власти, а не воздействию на поведение друга или партнера. В арсенале каждого манипулятора имеется несколько приемов, и они могут быть настолько разнообразны, насколько позволяет фантазия манипулятора. В основе любой манипуляции стоит «фальшивая реальность», т.е. «ложь, в которую хотят верить». И это действительно, так. Манипуляция может трактоваться иначе ­ акт влияния на людей или управления ими с ловкостью, особенно с пренебрежительным подтекстом, как скрытое управление и обработка (под словом «обработка» понимается полное подчинение себе, объекта – прим. автора). Понятие манипуляции постоянно расширяется, к примеру, он стал использоваться применительно к СМИ и политическим мероприятиям, направленным

vr­online | июнь 2010


105

Психо

на программирование мнений или устремлений масс, психического состояния населения и т.п. Конечная цель таких усилий — контроль над населением, его управляемость и послушность.

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

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

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

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

общих методических приемов реакции на манипуляцию, снижающих эффективность применяемых по отношению к вам уловок можно отметить: * выспрашивание; * осведомление; * повторение;

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

Гораздо опасней, если в ходе манипуляции применяются технические средства. Ни для кого ни секрет, что на данный момент такие средства существуют и этот факт настораживает. Человек хрупкое существо, особенно его нервная система, а если учесть, что происходит вокруг, вся эта напряженная обстановка, то представьте, что каждый индивидуум это «ходячая» мишень — стреляй в любую ­ попадешь в цель. Поэтому уделим внимание способам воздействия: 1.Светом и цветом.

2.Звуком (Не так давно, данный способ воздействия использовался для разгона демонстрантов на Красной Площади, путем подачи звука определенной тональности и вибрации ­ прим. автора). 3.На рецепторы кожи: а) Теплом.

б) Электромагнитным излучением.

Как видим, способы манипуляции перешли на новый уровень, и пока мы будем взращивать своего внутреннего «божка», манипуляции будут приобретать новые виды, будут разрабатываться способы влияния на человека, будут производиться различные технические средства, позволяющие на 100% контролировать общество и подчинить его себе. Будьте осторожны и всегда анализируйте поступающую к вам информацию. Да прибудет, с вами VR.

vr­online | июнь 2010


Автор: Игорь Антонов aka Spider_NET E­mail: antonov.igor.khv@gmail.com

106

Школа

Скачать файл из Интернета средствами C# Historically, languages designed for other people to use have been bad: Cobol, PL/I, Pascal, Ada, C++. The good languages have been those that were designed for their own creators: C, Perl, Smalltalk, Lisp. — Paul Graham

Сегодня разгребал почту и получил письмо с вопросом жизни и смерти (автор так и написал :­ )) от одного из наших посетителей. Вопрос был таким: «Spider_NET, подскажи, как можно быстро и непринужденно скачать файл из инета средствами C#». В C# это сделать проще простого, и я решил не откладывать, а сразу помочь человеку. Открыл Visual Studio и за пять секунд набросал простенький примерчик. Отправил и подумал: «А ведь наверняка, кто­то может столкнуться с аналогичным вопросом?». И решил я сразу помочь всем в виде этой небольшой заметки. Надеюсь, что она кому­нибудь пригодится. Я уже сказал, что пример крайне прост в написании и требует для реализации чертовски мало времени. Итак, первое, что я сделал – набросал дизайн приложения:

На форме у меня всего лишь одна строка ввода и кнопка «скачать». Собственно по нажатию кнопки и будет происходить загрузка.

Делай форму и переходи в редактор кода. Сразу же подключи два неймспейса: using System.Net; using System.IO;

выполнять загрузку файла из сети. Во второй, я объявляю переменную downloadFileName и присваиваю ей в качестве значения имя загружаемого файла. Имя файла я получаю при помощи метода GetFileName класса Path. На этом подготовка завершена и можно выполнять саму загрузку файла. Делается она при помощи метода DownloadFile класса WebClient. Методу требуется передать два параметра: 1. Адрес загружаемого файла

2. Путь, по которому файл будет сохранен. В первом параметре я указываю текст, который был введен в textBox1, а во втором жестко прописываю D:\ + имя загружаемого файла. Тем самым, все файлы будут сохранятся в корень диска D:. Попробуй запустить программу, заполнить поле «Адрес файла» и нажть кнопку «Скачать». Через некоторое время (все зависит от размера загружаемого файла и скорости твоего инета) ты увидишь скачанный файлик. Пользуйся на здоровье!

Первый позволит нам работать с сетью, а второй с файлами. Сделав это, создавай обработчик события Click() для единственной кнопки и напиши в нем следующий код: WebClient myWebClient = new WebClient(); string downloadFileName = System.IO.Path.GetFileName(textBox1.Text); myWebClient.DownloadFile(textBox1.Text, @"D:\" + downloadFileName);

В первой строчке кода я создаю экземпляр объекта WebClient(). С его помощью мы и будем

vr­online | июнь 2010


Автор: Роман Костенко aka Lord_of_fear kostenko.r.khv@gmail.com

107

Админинг

Unix

Именованные каналы и сокеты Просто о сложном

Одной из самых полезных возможностей unix­like систем заключается в возможности использовать пайпы (pipes) или в переводе: каналы. Если ты уже сталкивался с таким понятием, то у тебя могло сложиться впечатление, что это трудно для понимания. Да ничего подобного. Всё проще некуда. Очень странно, что в интернете нет ни одной простой и понятной статьи для начинающих. Читай и впитывай информацию! Расскажу доступнее некуда :)

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

bash’у.

Так же существуют именованные каналы, которые так же иногда называют FIFO, что означает “First In, First Out”. Тебе, как программисту, это должно быть понятно: первым вошёл, первым вышел. Этот принцип относится абсолютно ко всем байтам данным, попадающим в именованный канал. Каналы хранятся как файлы в файловой системе. Таким образом, “имя” такого канала – имя файла. И это вполне логично, т.к. всем известно, что в ОС Unix любой элемент может быть отображен в виде файла, включая устройства и наши именованные каналы. Таким образом, посмотреть список каналов можно командой ls. Ранее для создания именованных каналов использовалась утилита mknod. Сейчас же стандартом является mkfifo. Синтаксис использования достаточно прост. Нужно лишь передать программе имя, которое будет носить именованный канал. См. рисунок 2.

ls | grep x

Когда bash работает с командной строкой, то первым делом обращает внимание на вертикальную черту, разделяющую две команды. Bash и другие шеллы выполнят обе эти команды, при этом передав результат выполнения первой команды как входные данные для второй. Команда ls выведет список всех файлов в текущей директории. А команда grep в свою очередь отобразит лишь те строки, которые содержат букву “x”.

Рис. 2. Пример создания именованного канала pipe

Буква “p”, что подчеркнута на рис.2 красным, как раз и означает, что тип этого файла – именованный канал.

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

Рис.1. Пример выполнения ls | grep x

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

Рис. 3. Работа с именованным каналом на практике

Это – самый простой пример работы именованного канала. Откроем первую консоль vr­online | июнь 2010


108

Админинг

и напишем в ней: ls ­l > pipe

Теперь открываем вторую консоль и переходим в эту же директорию. Выполняем: cat < pipe

Вуаля! И мы видим список файлов и поддиректорий нашей папки. (см. рис. 3) Интересной особенностью является то, что порядок выполнения команд не имеет значения. Т.е. можно сначала выполнить чтение из канала, а только потом подать команду записи в него. Результат будет один. После приёма первой команды будет выполняться “ожидание” второй команды.

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

UNIX непривилегированные процессы не могут использовать порты меньше 1024). Слушающий процесс обычно находится в цикле ожидания, то есть просыпается при появлении нового соединения. При этом сохраняется возможность просто проверить наличие соединений на данный момент, установить тайм­аут для операции и так далее. Наверное, самым простым примером сокета является /dev/log демона syslogd, который отвечает за ведение логов.

Рис. 5. Информация о сокете /dev/log.

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

Изучаем сокеты

Сокет Unix является ещё одним способом обмена данными между процессами. Процессы при таком обмене могут исполняться как на одном компьютере, так и на различных ЭВМ, объединённых в сеть. Как и почти всё остальное в Unix, сокет – это файл. Интерфейс сокетов впервые появился в BSD Unix. Программный интерфейс сокетов описан в стандарте POSIX.1 и в той или иной мере поддерживается всеми современными операционными системами.

Существует 2 основных типа сокетов: Unix domain sockets (AF_UNIX) и Unix network sockets (AF_INET). Разница заключается в том, что Unix domain socket (Доменный сокет Unix) не использует для работы сетевой протокол. Он используется в операционных системах для межпроцессного взаимодействия. Корректным термином стандарта POSIX является POSIX Local IPC Sockets. UDS используют файловую систему как адресное пространство имен, что позволяет двум различным процессам открывать один и тот же сокет для взаимодействия между собой.

Unix network sockets используют интернет протоколы, которые позволяют обмениваться данными между несколькими Unix системами: протокол IP для соединения и протоколы TCP/UDP для транспорта.

Принцип функционирования сокетов заключается в том, что каждый процесс может создать слушающий сокет (серверный сокет) и привязать его к какому­нибудь порту операционной системы (следует учитывать, что в vr­online | июнь 2010


Автор: Gh[]st

109

Админинг

Поднимаем VPS Автоматизация обслуживания Автоматизируем рутинную работу по созданию бэкапов

Нет смысла тратить время на действия, которые реально автоматизировать. Создание бэкопов как раз такая операция. Нудная, надоедливая. Одним словом — рутина. Вот такие операции и надо в первую очередь автоматизировать.

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

#!/bin/sh backdir=/usr/home/sysop/backs #задаём папку в которой будут бакупы backtmp=$backdir/tmp #промежуточная папка user=sysop #задаём пользователя от которого будем забирать бакупы mysqluser=root #админ мускула mysqlpasswd=пароль #пароль мускула mysqlport=3306 #порт мускула mysqlhost=localhost #хост мускула DB=nullday #имя базы даных mysqldump ­u $mysqluser ­P $mysqlport ­h $mysqlhost ­p$mysqlpasswd $DB > $backtmp/sql #делаем дамп базы даных #здесь копируем все важные для нас файлы и конфиги cp /usr/local/etc/apache22/httpd.conf $backtmp/httpd.conf cp /usr/local/etc/squid/squid.conf $backtmp/squid.conf cp /usr/local/etc/squid/passwd $backtmp/passwd cp /var/sq/* $backtmp/ cp /etc/passwd $backtmp/passwd cp /etc/master.passwd $backtmp/master.passwd

tar ­cjf site.tar.bz2 administrator/ cache/ components/ images/ includes/ language/ libraries/ logs/ media/ modules/ music/ plugins/ rokdownloads/ templates/ tmp/ xmlrpc/ CHANGELOG.php configuration.php index.php index2.php #архивируем файлы сайта (можно всю папку с сайтом, но у меня там левые файлы:) mv /usr/local/www/apache22/data/site.tar.bz2 $backtmp/site.tar.bz2 #перемещаем файл архива сайта #архивируем логи cd /var tar ­cjf varlog.tar.bz2 log/auth.log log/httpd­error.log log/mysql.log log/ppp.log log/slip.log mv varlog.tar.bz2 $backtmp/varlog.tar.bz2 #задаём имя для бэкапа, в моём случае это день­год name=backup_`date +%d­%y`.tar.bz2 #архивируем всю папку cd $backdir tar ­cjf $name tmp/ #и очищаем временную директорию cd $backtmp rm * cd $backdir #меняем владельца файла на юзера который его заберёт (файл то создаёться рутом) chown $user $name #ставим права chmod 700 $name

Осталось добавить скрипт на cron, делаем следующее: ee /etc/crontab

Вводим в файл:

15 1 * * * root sh /bin/backup.sh

#копируем файлы сайта cd /usr/local/www/apache22/data

Как только файл будет сохранён, задание сразу же добавиться в очередь заданий cron

Backup compleate

Для автоматизации много времени не надо. vr­online | июнь 2010


110

Админинг

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

vr­online | июнь 2010


111

Мнение VR

Мнение VR

"Д.А. Медведев в twitter'e" Размышления на тему...

JimmyJonezz: По­поводу этой новости мне нечего сказать, т.к. со стороны это выглядит всего лишь забавно и не представляет никакого интереса. Много было разговоров, что Медведев ведет свой видеоблог, в ЖЖ зарегистрирован и теперь twitter. Может сложится впечатление, что наш президент действительно "продвинутый" в этом направлении, но как­то все это тускло выглядит на фоне внутренней обстановки (технической, транспортной и финансово­экономической) в России. zahod5277: ЖЖ, iPad, теперь

твиттер. Нет, я лично ничего против не имею, все имеют право на свободное время, хобби и так далее, но что думают другие? Если хотя бы треть населения страны знало бы о IT­увлечениях президента, думаю, отношение к нему существенно бы ухудшилось. Более старшее поколение (люди от 35 лет) наверняка думают типа "вот нифига государством не занимается, только в своих интернетах сидит, фоточки в блог о поездке в Штаты заливает". Но с другой стороны, комменты в ЖЖ и в твиттере по любому читаются, и если не самим президентом, то спец. службой. Был же случай, когда в ЖЖ кто­то на что­то нажаловался и потом, по прочтению этой службой сего коммента, это устранили. Если бы все проблемы так решались... Но

аккаунт в твиттере даже я считаю ребячеством. Ну серьезно, для кого фотки с видом из окна гостиницы и посты типа "сегодня обедал с Бараком Обамой в МакДональдсе гамбургерами"? Spider_NET: Твиттер стал по истине мировой социальной сетью нового формата. Вроде появился не так давно, а уже стал неслыханно популярным. Причем не только среди обычных пользователей, но и знаменитостей. Известные актеры, музыканты, а также представители власти обзавелись аккаунтами в "чирикалке". В нашей стране все происходит с "тормозком", но совсем недавно и наш президент завел персональный твит­ акк. Когда я впервые об этом услышал, я подумал, что скорей всего постить твиты президент будет не лично, но почитав его ленту убедился в обратном. Может я конечно и ошибаюсь, но буду верить в хорошее :­) Мне всегда нравилось, что Д.А. Медведев очень активный пользователь информационных технологий. Его появлению в твиттере я искренне рад. Считаю, что публичность действий/решений президента сможет улучшить качество обратной связи с народом. Любой желающий может зафоловить президента и читать новости из первых уст. На мой взгляд это здорово и было бы хорошо если бы все

высокопоставленные чиновники вошли бы в мир твиттера и оперативно сообщали о выполненных задачах/планах и других важных событиях. Сразу было бы видно, кто чем занимается и какая от кого эффективность. Lord_of_fear: Скажу честно: по началу мне было до лампочки. Затем через пару дней промелькнула мысль “”хм… а правильно Медведев сделал. Обама, например, давно уже во всю твиттерит, а фоловят его миллионы твиттерян. Чем наш президент хуже? Да и интересно иногда почитать чем же он там занимается”:) Рад, что глава нашего государства не стремается юзать последние достижения в ИТ сфере. И пусть, скорее всего, не сам лично он твиттерит, но всё равно я поддерживаю такое начинание. А вот сам я забросил писать в твиттер. Надоело. Хотя юзал его всего 4­5 месяцев. Надеюсь, наш президент продержится дольше. :) Kastor: Мне нравится деятельность Дмитрия Медведева. Такое ощущение, что он пытается влить новую волну в жизнь страны и сделать ее лучше. Он даже выглядит всегда бодрым и целеустремленным. Еще мне нравится его симпатия к новым технологиям. Это же здорово! Так почему бы и не vr­online | июнь 2010


112

Мнение VR

пользоваться ими в 21­ом веке. Многие могут начать шутить, мол, президенту время некуда девать больше. А вы других президентов и политиков часто видите? Наверное, только перед очередными выборами, когда надо больше мелькать перед глазами, или при различных скандалах. Может так Медведев пытается быть ближе к народу. В блоге ведь не ерунда написана, а его деятельность. WWWNET: Медведев очень активен в сети. Теперь у него появился и twitter­аккаунт. Если честно, то я его не зафоловил. Я далек от политики и в последнее время мало пользуюсь твиттером. Но само то, как ведет себя президент показывает, что он продвинутый пользователь и возможно с ним Россия займет достойное место в IT­индустрии.

vr­online | июнь 2010


Автор: Gh[]st (Hack­Labbs Team) Email: gh0st_null­day@3a.by

113

FAQ

FAQ по FreeBSD Вопрос & Ответ Вы спрашивали, мы отвечаем...

Вопрос: Установил FreeBSD 7.2 на сервер, вхожу под ssh (через putty), пускает всех пользователей кроме root. В чём дело и как разрешить рут?

Ответ: Дело в том что FreeBSD заботиться об безопасности, и возможность бродить под root’ом из сети по умолчанию отключена. В терминале можно юзать команду su (man su в помощь), а вот для доступа к файлам через sshd действительно бывает необходимым root. Для этого открываем файл /etc/ssh/sshd_config (ee /etc/ssh/sshd_config) находим строку PermitRootLogin по дефолту там будет PermitRootLogin no исправляем на PermitRootLogin yes. Делаем ребут и готово! Вопрос: Мой хостер предоставляет ssh доступ, но не предоставляет доступ к файлам бакупа MySQL базы данных, есть ли у меня возможность самостоятельно выполнить бэкап? Ответ: Да. В пакете MySQL есть такая утилита как mysqldump именно она позволит легко и безболезненно сделать бэкап базы данных. Синтаксис команды таков $ mysqldump –u LOGIN –P PORT –h HOST –p PASS DBNAME > dump.sql

где: LOGIN имя пользователя, PORT порт на котором висит мускул, PASS пароль пользователя, DBNAME имя базы данных, dump.sql файл куда произойдёт бэкап. Для восстановления базы данных из такова бэкапа можно воспользоваться следующей командой: $ mysql –u LOGIN –P PORT –h HOST –p PASS DBNAME < dump.sql

где: LOGIN имя пользователя, PORT порт на котором висит мускул, PASS пароль пользователя, DBNAME имя базы данных, dump.sql файл откуда будет произведено восстановление базы данных Подробнее смотрите mysqldump –help

Вопрос: На моей машине по умолчанию стоит редактор vi, возможно он и хороший редактор, но я не умею им пользоваться, а при создании тех же crontables открывается стандартный редактор. Как сменить редактор? Ответ: В зависимости от shella который вы используете, для csh и его модификаций выполните следующую команду: ee ~/.cshrc

Найдите строку setenv EDITOR vi и заменяете её на setenv EDITOR ee (либо другой редактор) В случае если вы используете sh выполняем: ee ~/.profile

Находим и заменяем xport EDITOR=vi на xport EDITOR=ee. Вопрос: Недавно глянул на в wmware клиент, и был повергнут в шок, какая­то личность брутила мой пароль на ssh. Есть ли способ защититься от таких напастей? Ответ: Да, есть такая утилита именуемая sshit, её задачей являеться именно защита от недоброжелательных пользователей. В портах она находиться здесь /usr/ports/security/sshit. Устанавливаем. Небольшая инструкция:

Редактируем файл /etc/syslog.conf Под auth.info;authpriv.info /var/log/auth.log

Добавляем auth.info;authpriv.info |exec /usr/local/sbin/sshit

Перезапускаем демон, /etc/rc.d/syslogd restart

В конфиге самого sshit’a в строке FIREWALL_TYPE = ipfw2 необходимо указать фаер который вы используете. Далее, необходимо добавить правило для таблицы в файрволл.

vr­online | июнь 2010


114

FAQ

Вопрос: С приятелем подняли серверок, под управлением FreeBSD. Приятель на редкость вандал, боюсь, что он может что­ нибудь поломать. Есть возможность защитить файлы от вандала? (у него есть пароль рута)

Ответ: Есть, есть стандартная утилита в каталоге /bin имя ей chflags. Сие чудо поможет сделать файлы неизменяемыми, не удаляемыми (даже от рута!). Даная команда сделает файл неизменяемым chflags schg /home/pit/porno.avi. За более подробным руководством рекомендую обратиться к man chflags

Ответа на твой вопроса здесь нет? Не стесняйся! Пиши мне на мыло и в следующем номере прочтешь свой ответ. Вопросы шли на gh0st_null-day@3a.by FAQ

vr­online | июнь 2010



VR-Online (June 2010)