Академический Документы
Профессиональный Документы
Культура Документы
июль 2010
Дизайн и верстка:
НЕВЕРОЯТНО, НО ФАКТ
Егор Горохов, Сергей Бадло
Любопытные факты ............................................. с.0х03
Авторский состав:
Utkin, WildHunter, Алексей Шишкин,
Виталий Иванов, Вадим Буренков,
НОВОСТИ ПРОГРАММИРОВАНИЯ
Александр Терлецкий, Вячеслав Мовила, Введение в Scheme. Часть 2 ................................... с.0x08
Александр Демьяненко, Алексендр Архипов,
Сергей Матрунчик, Сергей Бадло
ОТДЕЛ ТЕСТИРОВАНИЯ
Контакты: Маленькие помощники программиста ............................. с.0х13
Авторские статьи направляйте на
Разработчики - интерфейс - пользователи. Часть 1 ............. с.0х16
maindatacentr@gmail.com
Вопросы и предложения для редакции
reddatacentr@gmail.com WI-FI СЕТИ
Информационная поддержка: Беспроводная сеть масштаба микрорайона. Часть 1 .............. с.0х1F
Международная Академия Информатизации
(МАИН) РК www.academy.kz
АЛГОРИТМЫ
Журнал «Радиолюбитель»
www.radioliga.com Основы неврологии ............................................ с.0х25
Клуб ПРОграммистов
www.programmersforum.ru
2D ГРАФИКА
Примечание: Делаем динамические тени на OpenGL. Часть 1 .................. с.0х2F
Издание некоммерческое. Все материалы,
товарные знаки, торговые марки и логотипы,
упомянутые в журнале, принадлежат их ЛАБОРАТОРИЯ
владельцам. Статьи, поступающие в редакцию, MP3 изну-три ................................................. с.0х36
рецензируются. Мнение авторов не всегда
Энкодер датчика PDF на ПЛИС. Часть 2 ......................... с.0х3A
совпадает с мнением редакции. Перепечатка
материалов журнала и использование их в Библиотека файловой системы AT45DB161 ........................ с.0х43
любой форме, в том числе в электронных СМИ,
возможно только с разрешения редакции.
Тираж неограничен. Формат A4, 83 стр. ИГРОВАЯ ПЛОЩАДКА
Искусство изменения GTA ...................................... с.0х48
Учредитель:
Клуб ПРОграммистов
www.programmersforum.ru АРХИВ
Новая рубрика ................................................ с.0х4D
Обложка номера:
Дизайн Егора Горохова
Как создать собственную DLL на Дельфи ........................ с.0х4E
ЮМОР
Фразеологизмы, хохмы, загадки ................................ с.0х51
Сергей Бадло
by raxp http://raxp.radioliga.com
(min 4 4) Результат 4
Нужно помнить, что данные предикаты
нежелательно использовать на неточных числах – Нужно соблюдать осторожность при сравнении
ошибки округления могут приводить к обратным почти равных неточных чисел, поскольку
результатам. Кстати, определить является ли правильный результат работы данных предикатов
число точным или не точным можно определить с не гарантирован. Теперь напомним стандартные
помощью предикатов: арифметические операции:
(- z1 z2) Вычитание
понятно и так:
Теперь примеры (поскольку некоторые результаты
не очевидны):
(= х1 х2 х3 ...)
(< x1 x2 x3 ...)
(> x1 x2 x3 ...)
(+ 3 4) Результат 7
(<= x1 x2 x3 ...)
(+ 3) Результат 3
(>= x1 x2 x3 ...)
(+) Результат 0
(= 1 1 1) #t
(* 4) Результат 4
(= 1 2 1) #f
(*) Результат 1
(- 3 4) Результат -1
(min x1 x2 ...)
(quotient n1 n2)
(remainder n1 n2)
// Примеры:
(modulo n1 n2)
(max 3 4) Результат 4
При этом n2 не должен быть равен нулю и знаменатель дроби (знаменатель всегда
(независимо от точности числа). Если n1 / n2 есть положительное число):
целое:
(numerator q)
(denominator q)
(quotient n1 n2) Результат n1/n2
x не больше, чем y
всегда неотрицательным:
Рациональное число x более простое чем другое
рациональное число y если x = p1/q1 и y = p2/q2 и
(gcd 32 -36) Результат НОД (наибольший общий
делитель) 4
= 0/1 - самые простые рациональные числа из Теперь рассмотрим ввод и вывод чисел. Числа
всех: можно получать из строки следующим образом:
(inexact->exact .3) 1/10) Результат 1/3, точное число (string->number string radix)
(log z) Здесь все просто, стоит отметить log счисления равным 10. Если число z является
(sin z) – имеется ввиду натуральный (а не неточным и может быть выраженым с
десятичный), atan с двумя использованием точки в качестве разделителя
(cos z)
(tan z)
(atan y x)
(sqrt z) – вычисляет квадратный
(string->number "100") Результат 100
корень, включая мнимую часть числа: (string->number "100" 16) Результат 256
(sqrt -1) Результат 0+1i (всегда мечтал в Паскале (string->number "15##") Результат 1500.0
(expt z1 z2) возведение в степень, довольно-таки мощная В случае, если строку в число преобразовать не
функция, единственное ограничение – в удастся, результат функции #f.
степень запрещено возводить нуль
(real-part z) Результат реальную часть числа (x1) определен рекурсивно, как пустой список (список,
(imag-part z) Результат мнимую часть числа (x2) не содержащий элементов) или как пара поле cdr
(magnitude z) Результат |x3|
которого является списком. Если Х является
(angle z) Результат xangle
списком, то:
Точные и неточные числа можно преобразовывать
следующим образом: • в Х содержится пустой список
(inexact->exact z)
точное число в неточное, в X.
вторая выполняет обратные действия.
Естественно, такое преобразование возможно не Объекты в полях car последовательных пар списка
всегда (такая ситуация считается ошибочной). считаются элементами списка. Например,
двухэлементный список это пара, car которой Предикат (pair? obj) проверяет является ли объект
первый элемент списка и чей cdr пара, car которой парой:
(pair? '(a . b)) Результат #t
второй элемент списка и чей cdr есть пустой (pair? '(a b c)) Результат #t
Для представления пар используется точечная (car pair) – возвращает поле car пары (так и
нотация, поля разделяются точкой. Например, хочется сказать первое поле, но внутреннее
пара (4 . 5) имеет поле car 4 и поле cdr 5, при этом представление пар может быть иным, поля пары
внутреннее представление пары будет иным. могут находиться даже не в смежных областях
Списки выражаются проще (х1 х2 … хn), где х - это памяти). Попытка получения car пустой пары
элемент списка. Пустой список выражается, как (). вызовет ошибку:
Как уже было отмечено ранее, вся программа на
(car '(a b c)) Результат a
языке Scheme является списком (как и любые ее (car '((a) b c d)) Результат (a)
логически законченные фрагменты), поэтому (car '(1 . 2)) Результат 1
вызовет ошибку
списки. Неподходящий список списком не (set-cdr! pair obj) помещает соответственно в car и cdr
(define y x) y Результат (a . 4)
(define list-tail
Правило формирования функции следующее: все (lambda (x k)
(null? obj) – возвращает #t, если obj есть пустой Нумерация элементов списка осуществляется от
список, (list? obj) – возвращает #t, если obj есть нуля. Плюсом пар и неподходящих списков
список: является возможность создания древовидных
структур данных с неограниченным числом узлов
(list? '(a b c)) Результат #t
(symbol? "bar") Результат #f, строки представляются символом, используется следующая функция:
строковыми символами! (char? obj) – возвращает #t, если объект является
(symbol? 'nil) Результат #t
строковым символом:
(symbol? '()) Результат #f
и не выражение
Все строковые символы определяются на основе
Для преобразования символов в строки их порядка следования в алфавите. Поэтому
используется (symbol->string symbol). Примеры: между строковыми символами существуют
отношения, связанными с их расположением
(symbol->string 'flying-fish) Результат "flying-fish"
относительно друг друга. Для оценки строковых
(symbol->string 'Martin) Результат "martin"
символов используется ряд функций:
(symbol->string
(char=? char1 char2)
(string->symbol "Malvina")) Результат "Malvina"
(char<? char1 char2)
Несмотря на то, что задавать константы строковых Можно также получить доступ к каждому
символов их кодами нельзя, получать коды из элементу строки (строковому символу):
строковых символов разрешено: (char->integer
(string-ref string k)
char) – вернет точное целое число, которому
(string-ref "Привет" 1) Результат #\р, так как нумерация в
сопоставлен данный строковой символ. Обратная
строке идет от нуля
ей функция (integer->char n). Изменить регистр
символов можно с помощью функций: (char-upcase Изменить конкретный символ в строке можно с
char) – изменяет регистр строкового символа на помощью: (string-set! string k char). При этом
верхний, (char-downcase char) – изменяет регистр следует помнить, что string-set! возвращает
строкового символа на нижний. неопределенное значение. Строки можно
сравнивать (на порядок расположения в них
Строки строковых символов):
(make-string k char)
При этом входящие параметры должны
Здесь, k – есть длина создаваемой строки, char – удовлетворять условию:
символ, которым должна быть наполнена строка (в
0 < start < end < (string-length string)
первой функции она будет наполнена символами
вида ”\u0000\u0000\u0000”). Также строки можно Объединение (конкатенация) строк:
создавать путем конкатенации (объединении)
(string-append string ...)
символов: (string-append "Привет " "Мир!") Результат "Привет Мир!"
символов
(string-length string) (list->string list) преобразование списка в строку (список
+ (плюс) задается
(vector obj ...) – создает вектор из указанных параметр (только один),
объектов: заданный в виде списка
(vector 'a 'b 'c) Результат #(a b c), сами элементы при этом
(map proc list1 list2 ...) - применение функции proc
не вычисляются (из-за одинарной кавычки)
к каждому из списков. Списки должны иметь
(vector-length vector) – возвращает длину вектора одинаковый размер. Одна из мощнейших функций
(точное целое число). языка. Работает это следующим образом:
(vector-ref vector k) – возвращает k-й элемент
(map car '((a b) (d e) (g h))) Результат (a d g)
вектора (k как и все индексы должен быть точным
(map cdr '((a b) (d e) (g h))) Результат ((b) (e) (h))
и целым): (map cadr '((a b) (d e) (g h))) Результат (b e h)
(map + '(1 2 3) '(4 5 6) '(7 8 9)) Результат (12 15 18) того, PLT Scheme, содержит в себе не только
(define my-list '(1 2 3 4 5)) описанный выше стандарт R5RS, но также
(define (square val) (* val val))
дополнительные возможности, а именно:
(map square my-list) Результат (1 4 9 16 25)
(for-each proc list1 list2 ...) - аналогична map, но • система поддержки пространства имен и
используется в основном для функций с управления трансляцией
побочными эффектами, результат которых не • поддержка механизма исключений
определен: • приоритетные потоки
• классы и система объектов
регулярные выражения
(let ((v (make-vector 5)))
•
(for-each (lambda (i)
• поддержка юникода.
Создаем вектор v из пяти элементов. Затем
применяем (lambda (i) к вектору v. Заносим данные И более того, PLT Scheme содержит также группу
из списка '(0 1 2 3 4) (который сразу не диалектов Scheme, каждый из которых имеет свои
вычисляется из-за одинарной кавычки) задачи (например, есть диалект специально
следующим образом: в вектор v записывается адаптированный для изучения функционального
элемент списка, умноженный сам на себя (запись программирования студентами высших учебных
осуществляется посредством vector-set!, при этом заведений). Так как система построена в
в качестве индексов для доступа к вектору минималистичном и строгом стиле рекомендуется
используется все тот же список '(0 1 2 3 4)). После начинать изучение с DrScheme (он не так суров, и
выхода из блока let вектор v будет разрушен, а его не сильно отпугивает пользователей привыкших к
содержимое будет передан как результат работы обилию кнопок, картинок и иконостасу на
блока let. Рабочем столе). Его-то мы и рассмотрим
подробней...
PLT Scheme
Как уже упоминалось ранее, DrScheme имеет два
Теперь немного подробней о самой IDE. PLT окна, одно для ввода текста программы, второе
Scheme состоит из нескольких компонентов: есть командный интерпретатор (см. рисунок 1):
Поскольку PLT Scheme поддерживает несколько языке Scheme вполне функциональный exe-файл
языков программирования, то прежде чем требуется, чтобы программа была введена в окно
приступить к работе, нужно выбрать* ввода программы (обычно оно первое) (см.
соответствующий язык программирования рисунок 3). А также чтобы она была уже
Language|Choose Language (см. рисунок 2): сохранена во внешнем файле.
* Комментарий автора.
Для простых учебных примеров Stand-alone вполне
...наименование пунктов меню может немного отличаться в достаточно (однако, если необходимо
использовать программу на другом компьютере, то
зависимости от версии среды разработки
Заключение
Ресурсы
Алексей Шишкин
by Alex Cones http://flsoft.ru
В фантастических фильмах мы
часто видим, что человека
окружают маленькие роботы,
которые помогают ему,
выполняют его рутинную
работу. Рыботы пылесосы
убирают пыль и мусор,
маленькие роботы кофеварки
подадут Вам свежий кофе, а маленький
Label5 := IntToStr(5);
робосекретарь напомнит Вам о важной встрече. В
жизни все не так просто. Кстати говоря, данные строки были получены с
помощью вышеописанной программы. Итак,
Но, не смотря на такую жестокую реальность, вопрос создания многократной записи большого
программисты главным образом живут в мире количества похожего кода уже не стоял, и я
виртуальном. Поэтому ничто не мешает им занялся другими проблемами.
улучшать свою жизнь, создавая «роботов»-
помощников. «Но какие-же помощники могут быть
у программиста?» - скажете Вы. Я постараюсь
ответить на Ваш вопрос, опираясь на собственный
опыт.
История появления…
Label@@.Caption := IntToStr(@@);
Label2 := IntToStr(2);
рисунок 2). Да, возможно некоторые станут
Label3 := IntToStr(3); упрекать меня за то, что такое название уже
Label4 := IntToStr(4);
существует, но я ведь не собираюсь продавать это
творение, поэтому не обеспокоен нарушением буфере обмена (см. рисунок 3). А однажды мне
авторских прав на название программы. Моя потребовалось залить на файлообменный сервис
версия* создателя ресурсов к программам достаточно большой файл. С моей полу-диалапной
отличалась тем, что в ней можно было добавить скоростью эта задача имеет решение только
любой файл в ресурсы к программе. посредством FTP доступа. К счастью сервис
начинающему «импруверу» (от англ. improve – улучшать). Не бойтесь кнопка). Но не кликать-же по ней каждые десять
экспериментировать, и запомните одну вещь – ЛЮБАЯ работа может минут, пока файл не загрузится? Хотя-я...
Собственно, почему нет? За 15 минут был создан
быть оптимизирована. Даже если кажется, что это не так.
;lsbvrkskjvbliurbsv
p?t=92768
;srvlbsrvksrjksr • Обсуждение утилиты A.ch - Attribute Changer
open = klbhk.exe
http://www.programmersforum.ru/showthread.ph
;kjbsjvbkvksjvn
p?t=104574
Одна закрывающаяся скобка... И план вторжения
армий провалился... Но что-то я отвлекся.
Удаление файлов прокатывать не захотело по
причине аттрибута «системный» у обоих файлов.
Форматировать флешку мне не позволили, и я
накатал программу, изменяющую аттрибуты
каталогов и файлов по выбору пользователя. Так
появился на свет A.ch (см. рисунок 5):
В статье написано то, что автор смог прочесть, понять и пересказать своими
словами и немного того, до чего додумался сам; все то, что касается процесса
взаимодействия двух человек: разработчика и пользователя. Кратко это
выражается одним словом – интерфейс…
может и не понять сказанного тобою, но уж ты сам точно это используем, а другую просто имеем ввиду, зная
поймешь». что она есть.
сфер человеческой деятельности, но в своей сути интерфейсом. Явно это в ГОСТ не звучит. Но это
он отражает смысл этого явления. Далее, подумав было «тогда». По ГОСТ советских времен
немного, решил, что мир придуман не вчера и все подразумевалось, что интерфейс у нас возникает
процессы должны быть так или иначе давно сам собой, - это следует из текстов документов.
регламентированы и описаны. Я начал искать Получалось, как в известной фразе: «В СССР секса
стандарты, правила, ГОСТ-ы. Приводить здесь нет, а дети есть». Всем известна фраза о том, что в
подробное описание этих документов абсолютно мире все подвержено изменениям. Тоже самое
бессмысленно. Каждый сам может найти их в сети можно утверждать и про ГОСТ-ы. Не прошло и 20-
Интернет. Будет гораздо лучше, если выскажу ти лет, изменились требования времени, реалии,
свои соображения, которые сделал, переработав изменилось само время. Согласно документам,
найденную информацию… датируемым 2000-м годом и выше, разработчики
ГОСТ уже узнали про интерфейс и даже явно
Большинство ГОСТ-ов, найденных мною, написали об этом в «Пример шаблона
направлены на разработку технической технического задания (ТЗ) на сайт» [3], где есть
документации, связанной с процессом разработки два раздела: «Требования к графическому дизайну
программного обеспечения. Создается сайта», и «Требования к дизайну сайта». Это уже
впечатление, что изначально в 70-х начале 80-х радует. Конечно же, кажется совершенно
годов прошлого столетия упор делался на очевидным, что сайт без дизайна не сайт. Однако,
техническую сторону этого вопроса – разработку и судя по всему, на осознание этого факта
детализацию алгоритмов, средств сопряжения, разработчикам ГОСТ потребовалось время.
подбор технической базы, создание различных Думаю, что оно им еще будет нужно, чтобы
инструкций по эксплуатации и прочее. Старый создать отдельный ГОСТ, касающийся только
ГОСТ именно это и регламентировал. Впрочем, дизайна, как такового.
если подумать, так оно и должно было быть, так
как программирование по сути родилось из В итоге, проглядев различные ГОСТ, документы,
математики и на первом месте было решение шаблоны и примеры, сделал основной вывод.
задач, а не внешнее оформление. Лишь в ГОСТ, Сейчас, как и раньше, основной упор идет на
относящимся к недавним советским временам, а правильное, точное, детальное оформление
именно, ГОСТ 19.201-78 и ГОСТ 24.207-80 можно документации по всем этапам разработки
неявно увидеть фразы, частично указывающие на продукта – замысел, поиск информации для
средства взаимодействия с пользователем: начала разработки, процесс разработки,
«требования к программе или программному тестирование, внедрение, эксплуатация. С одной
изделию», «требования к маркировке и упаковке». стороны – это правильно, сложные продукты
Правда, прочтя эти фразы, явно и не скажешь, что делает много людей и для удобства их работы и
тут имеется ввиду «интерфейс». Тем не менее, в взаимодействия нужны документы, описывающие
источнике [2] нашел следующее: «Техническое детально и правильно различные этапы процесса
задание, как правило, разрабатывается на основе создания конечного продукта. А с другой стороны
ГОСТа 19.201-78 «ЕСПД. Техническое задание. – это жуткая бюрократическая формальность,
Требования к содержанию и оформлению». Таким требующая от каждого участника процесса
образом, получается, что разработчик должен сам описывать каждое свое действие и решение.
знать и подразумевать, что в задание должны Именно поэтому создание документации так не
закладываться вопросы, связанные с любят разработчики. Порой время, требуемое на
ее создание соизмеримо со временем создания
** Комментарий автора.
«стартовой базы», и лишь потом начинают программы, - такую ошибку не всегда видно. С
программировать. В экстремальных условиях точки зрения пользователя, логические ошибки
интерфейс страдает всегда. могут быть вообще никогда не обнаружены. По
известной статистике большинство пользователей
Когда вы задумываетесь о том, кто и как используют лишь 5-10% возможностей программы,
будет работать с вашей программой и какие про остальные 90-95% возможностей, где и может
ситуации могут при этом возникнуть? оказаться логическая ошибка, они могут не знать.
Визуальная ошибка всегда хуже – она просто
А вот на эти вопросы я не могу дать однозначного заметнее. Классический пример из недавнего
для всех ответа. У каждого найдется свой ответ, прошлого – это ошибка вывода изображения
но, в конечном итоге, правильный ответ на эти видеокартой. Чаще всего такие ошибки
вопросы всегда звучат из выявлялись в играх, как
**** Комментарий автора.
уст пользователя. Почему более требовательным к
Пример из моей практики. В связи с производственной
из уст пользователя? необходимостью потребовалось решить проблему автоматизации ресурсам компьютера, а
Отвечу цитатой учета. Проблема была в том, что «низы» уже не могли вести расчеты не «офисных»
«вручную» в связи с их сложностью, объемом и цикличностью, а
рецензента этой статьи, приложениях, которым
«верхи» не знали быстрого решения проблемы, то есть подходящего
литературного редактора программного решения по цене и решаемым задачам не было. В итоге, хватало
этого журнала, Utkin: по стечению различных обстоятельств, наш системный администратор «гарантированного
взялся за разработку программы «с нуля». То, что для него это было
«…даже в идеальной минимума». Они
тяжело, это мягко сказано, это было очень тяжело. Ему приходилось
программе пользователи решать проблемы абсолютно разного рода – выполнять свою проявлялись в том, что
найдут что непосредственную работу, параллельно изучать новые методы и могли «ломаться»
технологии программирования, изучать предметную область задачи,
покритиковать. Просто контуры изображаемых
решать дела домашние, между этим делать еще что-то. Мало того,
потому что пользователи периодически он «воевал» с непосредственным начальством по поводу предметов, возникали
всегда придирчивы. совмещения прямых рабочих обязанностей и работы по написанию непредвиденные
программы (программу он писал добровольно и, в том числе, на своем
Одним подавай одно, визуальные эффекты,
рабочем месте, а какому начальству понравится такое?). Смысл всей
другим требуется прямо этой предыстории таков, что ему было не до интерфейса и дизайна искажения картинки в
противоположное». программы. Для него было важным решить технические проблемы целом, в худшем
стоявшей перед ним задачи. В итоге задачу он решил для своего
Поспорить с этим сложно. варианте или просто
уровня и того времени достойно. Однако, в процессе эксплуатации
Еще классик И.А. Крылов выяснилось, что где-то он не додумал логику, где-то проиграл в ничего не было видно,
написал басню про удобстве интерфейса. При этом каждый день он решал какие-либо или компьютер шел на
проблемы, связанные с внедренной программой – дописывал,
Слона, который рисовал перезагрузку. При этом,
исправлял, модернизировал, консультировал пользователей, писал
картину в угоду всем и в документацию. Добавление новых решений и отчетов в программу, источник ошибки мог
итоге никому его шедевр привело к тому, что с каждым днем она становилась все быть с любом месте –
функциональнее и сложнее. В итоге, несмотря на то, что он видел и
не понравился. В данном как в сбое видеокарты,
знал огрехи интерфейса, переделать или исправить что-то было уже
случае – тот же самый практически невозможно, так как это означало переписывание так в используемом
процесс. программного кода практически сначала. программном
обеспечении (драйверах
Мало того, этот самый «пользователь» всегда видеокарты, драйверах DirectX или OpenGL,
найдет ту самую ошибку, которую никто из несовместимости с операционной системой и
разработчиков даже в страшном сне не мог прочее).
увидеть. При этом, сложно сказать, какая ошибка
хуже – алгоритмическая или визуальная, обе Для крупных корпораций уровня Microsoft или
одинаково неприятны. Разница лишь в том, что Adobe, когда есть рынок, бренд, сформированный
логическую ошибку среднестатистический круг пользователей, которые все равно не уйдут,
пользователь не всегда можно найти, особенно, такие ошибки менее ощутимы. Да, они неприятны,
если плохо знает логику функционирования никто не говорит, что ошибки – это хорошо, но все-
таки, менее ощутимы. Для таких корпораций они противном случае велика вероятность того, что
всего-лишь повод создания обновлений и выпуска пользователи вас не поймут и забудут навсегда
новых версий программ. При этом, вовсе на факт, ваш адрес и ваш продукт и, развернувшись, уйдут
что старые версии работали хуже или не к другим. Исключение в этой ситуации, составляет
удовлетворяли потребностям пользователя. На всеми горячо любимый Билл Гейтс, который,
мой взгляд, рассматривая, как пример, программу несмотря на то, что первые версии его
Adobe Photoshop, для большинства пользователей операционный системы Windows содержали много
(не дизайнеров) вообще достаточно ее варианта в ошибок и пользователями по всему миру
версии 9.0. Новые возможности программы, изначально вообще не воспринимались, смог
выпуск линейки продуктов от Adobe в виде продать свою систему этому миру. Возможно, одна
нескольких DVD дисков, еще раз повторю, из причин его успеха в том, что первыми
обычным пользователям, вообще не понятны и не пользователями его системы были студенты,
нужны, - они просто не пользуются ими в полной ставившие над ней эксперименты. А так как чаще
мере. Хотя, как бренд и признак «статуса», всего то, что изучается в университете, дальше
большинство просто устанавливают эти продукты используется в повседневной работе, то Windows и
на свой компьютер, не зная и 5% всех получила такое распространение. Впрочем,
возможностей. Грубо говоря, они микроскопом умалять заслуг Билл Гейтса, как удачного
забивают гвозди, изменяя размеры фотографий менеджера и торговца не стоит. Думаю что, еще
или сохраняя их в другой формат. одна хитрость, принесшая успех Windows состоит
в том, что долгое время вообще никто даже и не
Возвращаясь к теме разговора, еще раз скажу, что знал, что надо покупать лицензии на эту систему.
ошибки для крупных корпораций менее Она эксплуатировалась везде и всюду просто так,
болезненны, чем для разработчиков-одиночек. И благодаря умным ребятам, называющих себя
вот почему. Образно говоря, обслуживание ошибок хакерами. В свое время ходила шутка о том, что
у них поставлено на конвейер – службы самая лицензионная часть операционной системы
поддержки, бесплатная горячая телефонная – драйвер от мыши.
линия, консультации он-лайн и через различные
сервисы в сети. В данном случае под «ошибками» Другая исключительная ситуация, может быть
я подразумеваю не только непосредственно только одна – ваша программа настолько
ошибки в программе, найденные пользователями, уникальна и нужна пользователю, что он
но и «ошибки в мозгах пользователей», связанные вынужден терпеть и ждать, и прощать вам ваши
с обычной человеческой ленью и нежеланием ошибки. Правда, такие исключения бывают редко
разобраться и думать. С одной стороны – такая и чаще всего встречаются в сфере специфических
ситуация везде и всюду и считается обычной, а с видов деятельности человека. Например,
другой – это повод, способ, средство знать еще программа расчета поведения группы
сильнее «привязывать» пользователей к себе. Если микроорганизмов под влиянием факторов
бы большинство из нас внимательно читали бы внешней среды, или программа учета параметров
документацию и перед тем, как задать вопрос, работы газотурбинного двигателя. Рядовому
подумали над его решением, то половина вопросов пользователю такие программы просто не нужны,
исчезла, а службам поддержки нечего было бы подозреваю, что он даже не догадывается о
делать. существовании таких программ.
Если вы «один из подающих надежды», тот самый Если кратко подводить итог***** всему сказанному
герой, призванный удивить мир, то у вас просто в этих абзацах, что я бы сказал так. Если вы, как
нет права на ошибку. Вы должны выстелить точно разработчик задумались над удобством
в цель, чтобы громко и красиво заявить о себе. В использования вашего продукта не на стадии
разработки, а гораздо позднее, то можно с как сделать так, чтобы с программой, в общем
уверенностью утверждать, что чем дальше вы от смысле – продуктом, было удобно работать. Учат
точки старта, тем больше затрат и усилий только языку, логике и умению применить знания
придется приложить, чтобы внести одно на практике. А о том, чтобы умения, воплощенные
«элементарное» исправление. Это касается как в продукте, было еще и удобно использовать на
общей логики функционирования, так и практике, если и говорится, то уж очень мало,
интерфейса в целом. Копеечная ошибка на старте настолько мало, что об этом не остается даже
всегда выливается миллионные затраты на ее воспоминания.
исправление на финише. Необходимо как можно
раньше начинать глядеть на ваше творение со Говорить, что нас ничему не учили, тоже нельзя.
стороны пользователя и делать это чаще и не Если чуть-чуть подумать, то можно немного
просто глядеть (любоваться), а пытаться провести аналогии, хотя это будет слишком
использовать все то, что вы создали, именно как размыто и не очень конкретно. Уроки рисования в
пользователь. Забыть все, что известно о школе, когда каждый как умел, так и рисовал,
«внутреннем содержимом» продукта и стать теоретически можно взять в качестве
неопытным пользователем, задающим извечные элементарной базы графического дизайна. Тоже
детские вопросы: «Как?» и «Почему?». Поверьте можно сказать о черчении и геометрии, из них
мне, это правило очень и очень часто помогает можно почерпнуть понятия о проекциях,
увидеть такие интересные вещи. симметрии, способах изображения объектов,
пропорциях. Можно еще упомянуть историю,
Элементы и проблемы… все мы родом из касаемо истории искусств, обычаев, культуры –
детства оттуда можно взять некоторые элементы для
декора, дизайна, оформления. Но, мне кажется,
Насколько я помню, начиная со школьных уроков это все-таки сложно и «притянуто за уши». Мало
информатики и продолжая на того, требует определенных усилий и особого
специализированных курсах университета, везде мышления, чтобы все это собрать воедино.
учат практически одинаково. Ученику Пожалуй, из школьной программы – это и все, что
рассказывают про алгоритмы, основы написания можно взять в багаж, если не учитывать книги и
программ, грамматике языков программирования. специальные курсы, где непосредственно учат
Задавая типовые задачи, пытаются выработать дизайну и оформительскому искусству, я их не
логическое мышление, умение применять рассматриваю, так как они идут факультативно и
операторы и структуры изученного языка. Это все не входят в основную программу обучения, то есть
полезно и нужно, так как на самом деле массово не изучаются.
заставляет думать и приводит к приобретению
навыков логического мышления. Если идти обучаться далее в университет (не могу
со стопроцентной вероятностью утверждать, что в
Я могу ошибаться, утверждая следующее, но на настоящее время ситуация не изменилась), то до
мой взгляд, практически нигде нет ни слова о том, недавнего времени в большинстве высших
технических учебных заведений не было
специально выделенной дисциплины, так или
***** Замечание автора.
состояние, в котором разработчик настолько проникается идеей иначе связанной с интерфейсом. Студентам
продукта и его тонкостями, что ему начинает казаться, что и другим преподавались эргономика, трехмерная графика,
черчение, инженерное моделирование, но увязать
также все очевидно и понятно в функционале создаваемого продукта,
и опытного пользователя всегда требуется обучать и отвечать на их с интерфейсом, опять же, можно лишь
такие вопросы, которые с точки зрения разработчика находятся в косвенно. Выделенной специализированной
дисциплины, технических ВУЗах до недавнего
ряду «элементарных».
Продолжение следует...
Ресурсы
• Размышления об интерфейсе
http://tclstudy.narod.ru/articles/mytk.html
• Культура разработки программного
обеспечения http://www.orientir-
yug.ru/kult_po.htm
802.11g: 6, 9, 12, 18, 24, 36, 48, 54 Мбит/с • VSWR: 1.92 (макс.)
802.11b: 1, 2, 5.5, 11 Мбит/с • Максимальное усиление: 7dBi
• Чувствительность приемника: до -100dBm • Допустимая мощность: 1 Вт
• Выходная мощность передатчика: 20dBm • Диаграмма направленности в вертикальной
• Безопасность: WEP, WPA/WPA2, фильтрация плоскости (Вектор Е): 24 градуса.
МАС-адресов, SSID broadcast disable. • Диаграмма направленности в горизонтальной
• Дополнительные возможности: IP Aliases, плоскости (Вектор Н): 360 градусов.
IAPP, Block Relay, Firewall, Traffic Control • Разъем: Reverse SMA «мама» (встроенный в
(шейпер), DDNS, Watchdog. антенну), переходник с RP-SMA на RP-TNC
(внешний).
Антенны ANT24-0700C производства D-Link были • Материал корпуса: ABS, ABS+PC
выбраны по наилучшему показателю • Рабочая температура: От -20 до 65 градусов.
цена/качество в своем классе и из-за небольших
размеров: Построение сети
скорость передачи данных на уровне 1.2-1.4 из квартир наших клиентов (чтобы избежать
Мбайт/с, максимальная скорость у клиентов бюрократии с ЖЕКами и ОСМД), по этому же
составляет порядка 550-600 кБайт/с. Реальная кабелю клиенты входят в сеть. Взаимовыгодное
скорость передачи данных зависит от типа сотрудничество: мы получаем место для установки
клиентского оборудования и качества и запитки точки, а клиенты получают VIP-доступ к
беспроводного соединения клиент-ТД, а также от сети :)
количества клиентов и общей загрузки сети.
Качество
Покрытие каждой ТД составляет (в радиусе,
значения указаны при наличии прямой видимости На следующем скриншоте показаны
или незначительных препятствий, например характеристики соединения с ТД на расстоянии
деревьев): ~1000 метров при прямой видимости (см. рисунок
5):
• Мобильные устройства (смартфоны, КПК, PSP
и т.п.) - до 200м
• Ноутбуки, нетбуки, USB-устройства со
встроенными антеннами - до 300м
• Ноутбуки, USB-устройства с внешними (или
внутренними дипольными) антеннами - до
1500м
• ТД в режиме клиента с направленными
антеннами - до 10км
Юридическое лицо, созданное владельцами для содействия немного, но нужно учитывать особенности
использованию их собственного имущества и управления, технологии Wi-Fi, в которой мегабиты совсем
другие, чем в кабельных сетях. Кроме того, режим
содержания и использования неделимого и общего имущества.
Даже одна стена или дерево под окном, для них - 802.11g (максимальная скорость 54 Мбит/с)
уже неодолимая преграда. - 802.11n (максимальная скорость 150/300 Мбит/с)
2. Мощность передатчика и чувствительность
Другой класс – это устройства с внешними приемника. Не стоит чрезмерно увлекаться
антеннами. Даже со штатными антеннами они мощностью, слишком мощный сигнал в городских
показывают неплохую дальность при прямой условиях скорее вреден, так как вызывает
видимости, а при установке хорошей антенны многократные отражения и наложения, а также
вполне могут работать на расстояниях, создает массу помех. Да и для здоровья он не
измеряемых километрами. Поэтому при выборе очень полезен. На наш взгляд оптимальные
Wi-Fi устройства стоит обратить внимание не значения составляют до 100 мВт (20 dBm)
только на дизайн, размеры и цену, но в первую мощности и -95 dBm чувствительности.
очередь – на технические характеристики. 3. Возможность подключения внешней антенны и
характеристики штатной. «Главная часть любого
При покупке ноутбука, КПК или любого другого радиоустройства – антенна», это вам скажет
устройства, оснащенного встроенным Wi-Fi, также любой специалист по любому виду радиосвязи. К
обязательно интересуйтесь характеристиками Wi- Wi-Fi это тоже относится в полной мере. Для
Fi платы, типом и характеристиками встроенной нормальной работы (приличной дальности и
антенны. Зачастую, встроенные платы подходят скорости) любого Wi-Fi-устройства необходима
только для связи внутри комнаты или на антенна с коэффициентом усиления не менее 4dBi.
расстояниях до 100 метров на открытой местности. 4. Функционал устройства. К этому относится все,
Хотя есть и большое количество устройств, что устройство умеет делать и насколько удобно
оснащенных качественным Wi-Fi и вполне его использовать. По этому критерию выбор
способных поддерживать связь на приличных огромный, от самых простых до сложнейших
расстояниях. устройств, которые «умнее» вашего компьютера.
Главное – достаточно четко представлять, чего вы
Основные характеристики Wi-Fi устройств хотите и сколько вы согласны за это заплатить.
Перво-наперво, при выборе WLAN-аппарата, обратите внимание на не помешает консультация специалиста. Если вы,
то, чтобы выходная мощность была как можно ближе к разрешенной конечно, сами не являетесь таковым :)
20 dB. Следующим решающим фактором является чувствительность.
Как влияют эти величины на дальность связи? К примеру, аппарат с • Сетевая аутентификация на практике http://
мощностью в 20 dB сможет обеспечить в два раза большую дальность www.citforum.ru/nets/articles/authentication
• Крупнейший и самый активный сайт рунета по
приема по сравнению с 14 dB, т.е. разница в 6 dB дает двойной
by Utkin www.programmersforum.ru
АЛГОРИТМЫ СОДЕРЖАНИЕ 38
[ПРОграммист ОСНОВЫ НЕВРОЛОГИИ
июль 2010
Каждый нейрон имеет 32 входа, из них 16 Итак, помимо самих нейронов, сеть может
АЛГОРИТМЫ СОДЕРЖАНИЕ 39
[ПРОграммист ОСНОВЫ НЕВРОЛОГИИ
июль 2010
АЛГОРИТМЫ СОДЕРЖАНИЕ 40
[ПРОграммист ОСНОВЫ НЕВРОЛОГИИ
июль 2010
на ее основе формируется новая сеть путем тот факт, что логика на нейронах на порядок
случайного изменения связи случайного мощней обычной логики и всех ее смежных
дендрита случайного нейрона. Процесс дисциплин, потому-то и выразить ее в рамках
распознавания повторяется. Теперь уже стандартной довольно-таки проблемно без
сравниваются оба результата тестирования: привлечения интегралов и прочих трехэтажных
первоначальный и новый, полученный в формул (включая и логических). Далее с
результате мутации (здесь много биологических помощью нейронов можно эмулировать и работу
терминов). Например, сравнивать можно по сразу сложных блоков, таких как триггеры,
проценту правильных результатов в серии счетчики, шифраторы, дешифраторы и т.д. И,
распознавания образов. Теперь за основу берется наконец, нейронная сеть позволяет эмулировать
та сеть, в которой процент совпадений больше и аналоговые элементы (при наличии творческой
процесс повторяется до тех пор, пока результат жилки у программиста) и сложные схемы (на
тестирования не даст полного совпадения с манер программ Qucs, Electronics Workbench,
эталоном. Или заранее определенное количество Microcap и т.д.).
раз, иначе есть вероятность бесконечного
процесса обучения. Здесь же нужно сразу Далее, нейронные сети способные решать задачи
определиться какой вариант сети лучше, в даже, если никогда до этого не сталкивались с
случае если оба варианта дают одинаковый такими условиями ранее, хаотичные соединения
процент узнаваний (новый вариант сети позволяют формировать различные как
предпочтительней). положительные, так и отрицательные обратные
связи, что может порождать решения на грани
Подводные камни и течения интуиции. Однако в таких условиях возникает
новая проблема – подобно человеку, нейросети
А что вообще может решать нейронная сеть? способны ошибаться.
Теоретически даже может решить теорему
Ферма. Для этого требуется не так уж много – Еще одна частая ошибка (наблюдается даже в
нейронная сеть с числом нейронов примерно серьезных трудах) – это временные интервалы
1012 – 1015 степени, нейроны должны иметь функционирования нейрона относительно других
возможность соединяться с несколькими в нейронной сети. Представим работу какого-
тысячами других (порядка 20000). Если еще не либо нейрона. Итак, он прочитал данные и
понятно, то это мозг человека – лучшая сформировал новое состояние аксона. В
иллюстрация работы нейронных сетей. На самом результате какой-либо другой нейрон будет
деле нейронов требуется еще меньше, потому читать уже новое состояние аксона, и работа
что значительная их часть требуется на всей системы в целом будет нарушена (потому
обслуживание и управление как нейрон может обратиться к любому другому
полуавтоматическими системами, таких как нейрону и не факт, что тот уже поменял свое
легкие, мышцы, желудок, саморегуляция и т.д. А состояние на новое). Проблема усугубляется тем,
также на передачу данных для других групп что новое значение на первом нейроне не всегда
нейронов в те же самые органы. Плюс обработка влияет на состояние последующих, а только для
огромного количества датчиков. Такую некоторых дендритов или некоторых состояний
нейронную систему можно считать эталонной, но системы. Далее существует вероятность, что
не идеальной. На ее обучение требуются годы. данный нейрон также изменит свое состояние и
т.д. Таким образом, результаты работы могут
На самом деле нейрон очень мощная логическая быть полностью искажены. Отчасти благодаря
единица. С помощью нее можно эмулировать, такой проблеме персептроны и получили такое
например такие элементы как логическое «И», распространение. В них слои, нейроны и их
логическое «ИЛИ» и логическое «НЕ», то есть взаимосвязи организованы в иерархии таким
практически все современные логические образом, что все нейроны всегда получают новые
операции легко могут быть выражены через сигналы, то есть сначала первый слой берет
нейронные сети. Одной из причин сложности данные из рецепторов, второй слой берет данные
конструирования эффективных сетей является из первого слоя и т.д. Но нас это ни как не
АЛГОРИТМЫ СОДЕРЖАНИЕ 41
[ПРОграммист ОСНОВЫ НЕВРОЛОГИИ
июль 2010
АЛГОРИТМЫ СОДЕРЖАНИЕ 42
[ПРОграммист ОСНОВЫ НЕВРОЛОГИИ
июль 2010
АЛГОРИТМЫ СОДЕРЖАНИЕ 43
[ПРОграммист ОСНОВЫ НЕВРОЛОГИИ
июль 2010
procedure Update();
TNNet=class
protected
// Запись значения в кэш
// Чтение аксона
Data: Array of TNeron; // Нейроны
function GetAkson(): Boolean;
Count: Integer; // Количество нейронов
// Чтение значения дендрита (связи)
end;
CountIn: Integer; // Количество рецпеторов
Akson – значение логического типа, это выход, TableOut: Array of Boolean; // Таблица результатов
procedure Updating();
Ссылка представляет собой идентификатор // Берем все значения для таблицы выходных данных
public
а) нейрон;
procedure InitNerons; // Инициализация набора нейрона
б) элемент таблицы входных данных;
в) элемент таблицы выходных данных.
procedure InitTablein(); // Инициализация рецепторов
собственный индекс для доступа. Общий же (или constructor Create(InTable, Nerons, OutTable:
нейрона. Просто потому, что его работа без procedure SetCountIn(Value: Integer);
элементов (в том смысле, что, используя данный идентификатор, // Работа с таблицей выходных данных
дендрит, может обратиться к любому объекту, включая и свой // Устанавливает число элементов таблицы вых-х данных
собственный аксон).
АЛГОРИТМЫ СОДЕРЖАНИЕ 44
[ПРОграммист ОСНОВЫ НЕВРОЛОГИИ
июль 2010
Function GetLinkOut(Num: Integer): Integer; Итак, из полей класса нейронной сети видно, что
// Установка линка на нейрон он также не представляет собой ничего
Procedure SetLinkOut(Num, Value: Integer);
сложного. Теперь немного уделим внимание
методам, это поможет понять логику их работы.
// Очистка таблицы выходных сигналов
Сначала рассмотрим методы в секции Private.
Procedure ClearOut();
Это методы для внутреннего пользования, то
есть, они поддерживают работу класса, и не
должны вызываться извне – это может нарушить
// Работа с нейронами
// Установка линка
нормальную работу нейронной сети.
Procedure SetDendrit(Neron, Num, Value: Integer);
// Установка линка (абсолютная адресация в рамках Сразу возникает вопрос – почему RunNeron есть
// нейросети) функция? Она возвращает True (истина), если
Procedure SetDendrit2(Neron, Num, Value: Integer);
нейрон может выполнить свою работу (и тогда он
ее выполнит). Сделано так специально с
// Чтение линка
расчетом на будущую модификацию сети.
function GetDendrit(Neron, Num: Integer): Integer;
Например, в данном классе не реализовано
// Выполнение одного шага нейросети
сохранение и чтение нейронной сети во внешний
файл. Представьте себе ситуацию, что Вы
Procedure Run();
// произвольного нейрона)
Updating должен выполняться (и выполняется)
сразу после выполнения всех нейронов в сети –
Procedure Mutation();
АЛГОРИТМЫ СОДЕРЖАНИЕ 45
[ПРОграммист ОСНОВЫ НЕВРОЛОГИИ
июль 2010
Большинство остальных
методов класса
ориентированы на получение
данных об объектах нейронной
сети, а также на внесение в
нее изменений, в том числе и
внесение информации о
задаче (информация в таблице
входных данных). Пожалуй,
интерес представляет только
Run – выполнение нейронной
сети. На самом деле это
группа операций. А именно –
выполнение всех нейронов,
обновление состояний
выходов нейронов и получение
результатов в таблицу
выходных данных.
АЛГОРИТМЫ СОДЕРЖАНИЕ 46
[ПРОграммист ОСНОВЫ НЕВРОЛОГИИ
июль 2010
АЛГОРИТМЫ СОДЕРЖАНИЕ 47
[ПРОграммист ДЕЛАЕМ ДИНАМИЧЕСКИЕ ТЕНИ НА OPENGL. ЧАСТЬ 1
июль 2010
vadim_burenkov@mail.ru bTiles.Count.X:=7;
bTiles.Count.Y:=5;
end;
procedure Draw;
простейшее приложение (вы можете найти его в // Тут "рисуем" что угодно :)
program LightEngine;
procedure Update;
uses
begin
zgl_main,
// обновление клавиш
zgl_timers,
key_ClearState;
zgl_textures,
Mouse_ClearState;
zgl_textures_jpg,
end;
zgl_sprite_2d,
zgl_mouse,
procedure Timer;
zgl_keyboard,
begin
zgl_utils;
end;
bTiles:zglTTiles2D; // параметры тайлинга
procedure Quit;
procedure Init;
begin
var n,j:integer;
end;
// отключаем очищение буфера
zgl_disable(COLOR_BUFFER_CLEAR );
Begin
// Тут можно выполнять загрузку основных ресурсов
2D ГРАФИКА СОДЕРЖАНИЕ 48
[ПРОграммист ДЕЛАЕМ ДИНАМИЧЕСКИЕ ТЕНИ НА OPENGL. ЧАСТЬ 1
июль 2010
timer_Add( @Update, 10 );
// инициализации ZenGL
// работы ZenGL
wnd_ShowCursor( TRUE );
// Инициализируем ZenGL
zgl_Init;
Немного теории
2D ГРАФИКА СОДЕРЖАНИЕ 49
[ПРОграммист ДЕЛАЕМ ДИНАМИЧЕСКИЕ ТЕНИ НА OPENGL. ЧАСТЬ 1
июль 2010
• положение
• радиус
• цвет
• интенсивность
Локальные координаты нужны, так как через Как же делаются тени от объектов? При выводе
положение и угол поворота объекта его можно источника света в альфа буфер на него рисуется
разворачивать. форма тени черным цветом. Получается что от
круга света «отрезают» кусок (см. рис.7):
Для хранения данных об освещенности нам
понадобятся два буфера размером в экран. Первый
– альфа буфер. В него выводится круглый источник
света (см. рис.4):
2D ГРАФИКА СОДЕРЖАНИЕ 50
[ПРОграммист ДЕЛАЕМ ДИНАМИЧЕСКИЕ ТЕНИ НА OPENGL. ЧАСТЬ 1
июль 2010
type
TColorRGB=record
r,g,b:single;
end;
PLightSource=^TLightSource; end;
TLightSource=record
Все координаты будут храниться в типе:
position:leVect; // положение
prev,next:PLightSource; end;
end;
Подробнее о нем будет написано позже, пока нам
Все данные будут храниться в “prev-next” понадобится только формирование вектора по x и
(двухсвязных) списках (см. рис.9): y:
function le_v(x,y:single):leVect;
begin
result.x:=x;
result.y:=y;
end;
Рис. 9. Списки
Перейдем к процедурам управления источниками
Каждый элемент является звеном цепи и имеет света:
указатели на предыдущее и следующее звено. Нам
Function le_CreateLightSource(p:leVect;
же нужно иметь первый элемент и длину цепи для
radius,intensivity:single;
управления списком:
color:TColorRGB):PLightSource;
t.Prev:= nil;
Более подробно о такой системе хранения данных
можно почитать в Интернете. Как мы видим, у нас
t.position:=p;
появились новые типы данных:
2D ГРАФИКА СОДЕРЖАНИЕ 51
[ПРОграммист ДЕЛАЕМ ДИНАМИЧЕСКИЕ ТЕНИ НА OPENGL. ЧАСТЬ 1
июль 2010
t.intensivity:=intensivity;
t.color:=color;
Далее напишем процедуру, которая освобождает
память, занятую источником света:
le_Lights:= t; begin
t:=nil
В следующей процедуре происходит рисование
end;
круга света как на рисунке 4. Он рисуется через
GL_TRIANGLE_FAN. Первая точка в центре имеет Следующая процедура вспомогательная, она
цвет и интенсивность света, далее идут точки по обрабатывает каждый источник света
радиусу окружности с нулевым цветом, благодаря передаваемой в нее процедурой:
чему мы имеем плавный переход цвета:
procedure le_EachLightSource(p:le_proc);
begin
glColor4f(0, 0, 0, 0 ); end;
angle:=angle+((PI*2)/le_numSubdivisions); type
end; le_proc=procedure(d:Pointer);
glVertex2f(t.position.x+t.radius, t.position.y);
Например, данная строчка нарисует все
glEnd();
источники света:
end;
le_EachLightSource(@le_DrawLightSource);
Количество треугольников, из которого рисуется
круг, задается константой: Хочу заметить, что при попытке передать в
le_EachLightSource процедуру очищения
const
возникнет ошибка, связанная с памятью, поэтому
le_numSubdivisions = 32;
для очищения всех источников света напишем
Следующая процедура рассчитывает и рисует тень отдельную процедуру:
для объектов, но о ней я напишу позже:
2D ГРАФИКА СОДЕРЖАНИЕ 52
[ПРОграммист ДЕЛАЕМ ДИНАМИЧЕСКИЕ ТЕНИ НА OPENGL. ЧАСТЬ 1
июль 2010
procedure le_FreeAllLightSources;
le_DarkColor – переменная, которая отвечает за
begin
еще вернусь. Обобщающая процедура полной
t:= le_Lights;
обработки света:
end; // цветом
rtarget_Set( nil );
pr2d_Rect(0,0,800,600, le_DarkColor,255,PR2D_FILL);
Напишем процедуру инициализации буферов:
rtarget_Set( nil );
2D ГРАФИКА СОДЕРЖАНИЕ 53
[ПРОграммист ДЕЛАЕМ ДИНАМИЧЕСКИЕ ТЕНИ НА OPENGL. ЧАСТЬ 1
июль 2010
var
le_CreateLightSource
(le_v(520,550),400,0.3,IntToRGB($FF00FF));
Рис. 10. Различный DarkColor
le_CreateLightSource
(le_v(470,50),250,0.5,IntToRGB($FF0000));
le_CreateLightSource
(le_v(200,300),270,1,IntToRGB($00FF00));
le_CreateLightSource
(le_v(640,270),300,0.8,IntToRGB($FFFFFF));
UserLight:=le_CreateLightSource(le_v(0 ,
0),100,0.8,IntToRGB($FFFFFF));
le_EachLightSource(@le_RenderLight);
// отрисовка теней
le_FinishRender;
UserLight.radius:=UserLight.radius+3;
if UserLight.radius>0 then
теней от объектов, а также оптимизирую код,
UserLight.radius:=UserLight.radius-3;
чтобы добиться большей производительности.
Весь исходный код проекта приложен к журналу
UserLight.color.r:=random(100)/100;
UserLight.color.g:=random(100)/100;
Продолжение следует...
UserLight.color.b:=random(100)/100;
end;
Ресурсы
2D ГРАФИКА СОДЕРЖАНИЕ 54
[ПРОграммист MP3 ИЗНУ-ТРИ
июль 2010
В этой статье я расскажу, как устроен MP3 файл, и покажу, как можно работать с
ним в ваших программах. Мы попробуем извлечь информацию о файле, такую как
длину трека, его битрейт и частоту дискретизации. Воспроизведение звука мы
рассматривать не будем, это отдельная, и я думаю намного более сложная тема...
ЛАБОРАТОРИЯ СОДЕРЖАНИЕ 55
[ПРОграммист MP3 ИЗНУ-ТРИ
июль 2010
ЛАБОРАТОРИЯ СОДЕРЖАНИЕ 56
[ПРОграммист MP3 ИЗНУ-ТРИ
июль 2010
Рис. 2
я реализовал это в коде. Через третий байт мы Если Pad бит равен единице то и в формулу
пока перескочим, и я вкратце расскажу о подставляем единицу, если нулю – подставляем
четвертом. В нем есть такая интересная штука нуль. Битрейт и частоту подставляем в их
как режим стерео. Дело в том, что MP3 имеет полном виде, без округлений, битрейт в битах, а
еще один способ уменьшить вес файла, не частоту в герцах. В файлах к этой статье вы
ухудшив качество. Это режим Joint Stereo найдете пример извлечения нужной информации
(объединенное стерео). Что же это такое? из заголовка фрейма и реализацию этой
Пройдемся по порядку. Режим моно, это, как вы формулы на языке Delphi. Чтобы что-то извлечь
знаете, когда всего один звуковой канал. Стерео - из заголовка, его нужно сначала найти, это тоже
это независимые левый и правый каналы. Для там есть. На самом деле достаточно найти
хранения стерео данных, необходимо ровно в два первый фрейм, позицию каждого следующего мы
раза больше места, чем для моно. Joint Stereo же уже будем знать, прибавляя к позиции текущего
позволяет хранить два независимых канала, при фрейма его длину.
этом, занимая меньше места, это достигается за
счет "умной" паковки во время сжатия. Если Теперь поговорим о том, как найти переменный
выбран этот режим, и в данном сэмпле звука битрейт и длину трека. С постоянным битрейтом
левый и правый каналы не отличаются, то кодер все ясно, он одинаковый для всего файла, и его
сохраняет только один из них, когда же каналы можно взять из первого фрейма. С переменным
отличаются, то они сохраняются оба. Это в своем не так. Во-первых, нигде не написано что он
роде стерео по требованию, оно используется переменный, и чтобы это определить, нужно
там, где это реально нужно, а где не нужно, прочесть больше чем один фрейм. Я пошел
место экономится. В четвертом байте хранится самым простым путем, и читаю два первых
еще ряд параметров, не буду на них фрейма. Если битрейт у них одинаковый я
останавливаться, кому интересно, смотрите на считаю что битрейт постоянный, если разный то
рисунке, там все подписано, обычно они переменный. Это скорее всего не точно, ведь
интереса не представляют. переменным он может стать и после второго
фрейма. Однозначных рекомендаций по этому
Самый значимый для нас это 3-й байт заголовка. вопросу я не встречал, возможно, есть
В нем содержится информация о битрейте, соглашение, что если битрейт переменный,
частоте дискретизации, установлен или нет Pad обязательно кодировать первые два фрейма с
бит (определяет наличие добавочного байта в различным битрейтом, я бы так и сделал на
фрейме), все это вместе взятое позволяет нам месте разработчиков, но это только мои
высчитать размер этого фрейма. Размер фрейма предположения. Если у вас есть более точная
высчитывается по формуле 1: информация на этот счет, оставляйте
комментарии к статье на сайте журнала,
144 * BitRate / SampleRate + Pad; (1) интересно будет почитать. Понятно, что в случае
ЛАБОРАТОРИЯ СОДЕРЖАНИЕ 57
[ПРОграммист MP3 ИЗНУ-ТРИ
июль 2010
Заключение
ЛАБОРАТОРИЯ СОДЕРЖАНИЕ 58
[ПРОграммист ЭНКОДЕР ДАТЧИКА PDF НА ПЛИС. ЧАСТЬ 2
июль 2010
Сергей Бадло
by raxp http://raxp.radioliga.com
ЛАБОРАТОРИЯ СОДЕРЖАНИЕ 59
[ПРОграммист ЭНКОДЕР ДАТЧИКА PDF НА ПЛИС. ЧАСТЬ 2
июль 2010
Рис. 3. Схема одного канала энкодера (антидребезг, задатчик идентификатора схемы, реверсивный
счетчик импульсов, узел формирования выходного пакета данных)
заново;
• измерение относительной скорости*, т.е.
где: 4 – коэффициент, учитывающий соотношение длительности
ЛАБОРАТОРИЯ СОДЕРЖАНИЕ 60
[ПРОграммист ЭНКОДЕР ДАТЧИКА PDF НА ПЛИС. ЧАСТЬ 2
июль 2010
Рис. 7. Схема регулирования (СР) ширины ЗИ Рис. 10. Загрузка прошивки через JTAG
ЛАБОРАТОРИЯ СОДЕРЖАНИЕ 61
[ПРОграммист ЭНКОДЕР ДАТЧИКА PDF НА ПЛИС. ЧАСТЬ 2
июль 2010
Однако этот способ не лишен недостатков: с пульсациями не более 200 мВ. Выходной сигнал
требуется наличие JTAG программатора – однополярное напряжение (цифровая
практически все время «под рукой». последовательность) с током нагрузки до 10 мА.
Максимальная длина шлейфа, соединяющая
Второй способ, получивший название ISP (In выход модуля энкодера (платы UNIOxx-5) к
System Programming), более удобен, так как не входному разъему до 1.5 м. Проверка прошитой
требует извлечения микросхемы платы UNIOxx-5 производится на рабочем месте
конфигурационного ПЗУ (или самой ПЛИС) из следующим образом. Земли шасси, платы
платы или наличия дополнительного разъема на UNIOxx-5, осциллографа, генератора импульсов
плате под ПЛИС. Программирование каждой и генератора сигналов высокочастотного должны
матрицы FPGA1…FPGA4 модуля UNIOxx-5 быть объединены (заземлены) в одной точке
осуществляется с помощью программ: <isp.exe> проводником минимальной длины сечением не
(загрузка схемы с записью в EEPROM), <isl.exe> менее 2 мм2 (см. рисунок 12):
(загрузка схемы без записи в EEPROM).
Программы позволяют осуществить загрузку
файлов схем *.bit матриц FPGA. Рассмотрим на
примере…
---------------------------------------------
isp.exe 110 b21 b21 b21 b21 Рис. 12. Схема проверки платы UNIOxx-5 с
| | | | | прошивкой энкодера
| | | | +----------- Код схемы матрицы FPGA4
| | | +--------------- Код схемы матрицы FPGA3 Плата UNIOxx-5 при выключенном питании
| | +------------------- Код схемы матрицы FPGA2 шасси вставляется в ISA слот. С помощью
| +----------------------- Код схемы матрицы FPGA1 соединительного шлейфа присоединяют выход
+--------------------------- Базовый Адрес 110h датчиков с соответствующими входами модулей
гальванической развязки или модулей связи,
сигнал с которых подан на вход платы UNIOxx-5.
Далее производится включение промышленного
шасси и загрузка обслуживающей прошивки.
Осциллографом контролируют наличие
напряжения питания (+5 В) на плате модуля
UNIOxx-5. С помощью осциллографа
производится контроль ТИ с тактового
генератора платы. Включив генератор импульсов
с заранее выставленными выходными уровнями
Рис. 11. Окно командной строки. сигналов, подают импульсы по входу строба для
Запуск утилиты ISP каждой из матрицы модуля (поочередно),
контролируя одновременно с помощью
Питание и установка программы обслуживания (или осциллографом)
наличие признака строба в последовательности
Модуль с прошивкой энкодера устанавливается в (бит DO7 при втором адресе А0…А2).
слот (ISA) промышленного компьютера и запитан
от напряжения ±5В. При этом требуется Кроме того, тестирование прошивки энкодера
обеспечить стабильность питающего напряжения желательно провести в условиях, приближенных
ЛАБОРАТОРИЯ СОДЕРЖАНИЕ 62
[ПРОграммист ЭНКОДЕР ДАТЧИКА PDF НА ПЛИС. ЧАСТЬ 2
июль 2010
к «реальным». Для этого необходимо, считывания, согласно таблице (см. листинг 1):
подключить шифратор приращений через наш
модуль связи, используя несколько десятков пример считывания с портов ЛИСТИНГ-1
ЛАБОРАТОРИЯ СОДЕРЖАНИЕ 63
[ПРОграммист ЭНКОДЕР ДАТЧИКА PDF НА ПЛИС. ЧАСТЬ 2
июль 2010
Рассмотрим подробнее…
int gdriver = DETECT, gmode, errorcode;
char msg[80];
Запустим среду Turbo C++ IDE ver.3.0 от Borland
int x,x2,y,y2,ns,nc,ugg,ugg2,xr,xr2,yr,yr2,wr,wr2,hr,hr2;
и создадим пустой проект. Далее необходимо
провести инициализацию графического режима
char nbuf[25];
… }
#include "dos.h" //
#include <stdio.h> k = 1;
if (s == 2) {dba = 0x400;}
{ errorcode = graphresult();
int s,pd,i,nomer,d1,d2; }
ЛАБОРАТОРИЯ СОДЕРЖАНИЕ 64
[ПРОграммист ЭНКОДЕР ДАТЧИКА PDF НА ПЛИС. ЧАСТЬ 2
июль 2010
hr=100; {
hr2=hr; outtextxy(5,90,nbuf);
// }
setfillstyle(1,BLUE); nn=165001;
setcolor(GREEN); outtextxy(5,90,nbuf);
outtextxy(0,30, "Angle, deg:"); // угол поворота ротора // формируем из двух байт значение положения (см. схему)
ugol2 = KT2;
// градусы
outtextxy(xr2+wr2+15,yr2-5,"0"); ug = ugol*360/pd;
outtextxy(xr2-5,yr2-hr2-25,"90"); ug = 360*(ugc-(ug/360));
ugg2 = 90-ug2;
do {
f_dba(dba,d); if (k>1)
printf("Опрос:%d", k); {
if (k>1) setcolor(BLACK);
{ outtextxy(90,32, ubuf);
outtextxy(90,10, kbuf); }
} setcolor(RED);
setcolor(RED); itoa(ug,ubuf,10);
outtextxy(130,32,ibuf);
/*FPGA_1*/ //
printf("Идентификатор схемы= %c", d[14]); // см. схему FL=d[4]&0x04; // определяем направление вращения
// {
ЛАБОРАТОРИЯ СОДЕРЖАНИЕ 65
[ПРОграммист ЭНКОДЕР ДАТЧИКА PDF НА ПЛИС. ЧАСТЬ 2
июль 2010
else {setcolor(BLACK);outtextxy(90,53,"rigth");} }
} setcolor(RED);
{ y=yr+(hr*cos(ugg*pi/180)); y2=yr2+(hr2*cos(ugg2*pi/180));
setcolor(RED);outtextxy(90,53,"rigth"); line(xr,yr,x,y);
} line(xr2,yr2,x2,y2);
// конец маркер
// значение разницы
if (k>1) k+ = 1;
{ delay(100);
} if (s==0x9) break;
itoa((ug-ug2)*pd/360,pbuf,10); closegraph();
return;
// скорость вращения }
if (k==1) {ug_1=ug;ng1=ugc;}
setcolor(BLACK); {
} d[i] = PA;
setcolor(RED); }
itoa(vm,sbuf,10); }
outtextxy(90,43,sbuf);
Запустим проект на компиляцию и выполнение
ug1=ug2; ng1=ng2;
командой <Ctrl>+<F9>. При этом, появится
экран с запросом параметров считывания (см.
рисунок 13). Задав номер FPGA = 3 и
// маркер (вектор на графике)
if (k>1)
максимальное количество импульсов для
{ подключенного датчика = 2048 (для нашего
setcolor(BLUE); // 1-канал датчика RV-58N), нажмем <ENTER> и получим
line(x,y,xr,yr); экран с визуализацией состояний двух энкодеров
line(x2,y2,xr2,yr2); (см. рисунок 14-15). На рисунке 14 представлен
экран состояния датчиков приращений при
ЛАБОРАТОРИЯ СОДЕРЖАНИЕ 66
[ПРОграммист ЭНКОДЕР ДАТЧИКА PDF НА ПЛИС. ЧАСТЬ 2
июль 2010
Ресурсы
ЛАБОРАТОРИЯ СОДЕРЖАНИЕ 67
[ПРОграммист БИБЛИОТЕКА ФАЙЛОВОЙ СИСТЕМЫ AT45DB161
июль 2010
ЛАБОРАТОРИЯ СОДЕРЖАНИЕ 68
[ПРОграммист БИБЛИОТЕКА ФАЙЛОВОЙ СИСТЕМЫ AT45DB161
июль 2010
Отличительные особенности
ЛАБОРАТОРИЯ СОДЕРЖАНИЕ 69
[ПРОграммист БИБЛИОТЕКА ФАЙЛОВОЙ СИСТЕМЫ AT45DB161
июль 2010
• в первых 2-х байтах адрес 1-ой страницы 2 - Файл открыт в режиме чтения
файла */
• следующие 2 байта содержат количество
unsigned char at45_file_mode = 0;
страниц в файле
// Счетчик страниц при записи
• последние 4 байта структуры - размер файла
unsigned int at45_cpwrite = 0;
в байтах
// Номер текущей страницы
unsigned char InitialFlash(); // Размер открытого файла/счетчик байт откр. файла при записи
ЛАБОРАТОРИЯ СОДЕРЖАНИЕ 70
[ПРОграммист БИБЛИОТЕКА ФАЙЛОВОЙ СИСТЕМЫ AT45DB161
июль 2010
5. Считать из файла count байт в буфер dest Переопределить настройки интерфейса SPI в
unsigned int ReadFile(char * dest, unsigned int строке 38:
count);
// Здесь следует определить настройки SPI!!!
// Включить SPI.
dest - Указатель на буфер чтения.
count - Количество байт для считывания.
// SPI initialization
6. Записать в файл count байт из буфера source. // SPI Data Order: MSB First
unsigned int WriteFile(char * source, unsigned int #define SPI_ON SPCR=0x5c
count);
source - Указатель на буфер записи. Простой пример применения библиотеки:
count - Количество байт для записи.
unsigned char temp;
if(temp) {
считывании по прерыванию.
memset(Buff, 0, 128);
Для того, чтобы использовать библиотеку в
проект ПО следует включить файлы:
for(ic = 0;ic<256;ic++) Buff[ic] = ic;
WriteFile(Buff, 256);
CloseFile();
// DataFlash chip select
WriteFile(Buff, 55);
Вторая: CloseFile();
ЛАБОРАТОРИЯ СОДЕРЖАНИЕ 71
[ПРОграммист БИБЛИОТЕКА ФАЙЛОВОЙ СИСТЕМЫ AT45DB161
июль 2010
WriteFile(Buff, 128);
do {
Ресурсы
memset(Buff, 0, 528);
}
загрузка файлов в AT45DB161
http://movilavn.narod.ru/AT45LOAD.rar
//Считали второй файл:
• Проект для ПК (Builder C++ 6).
if(OpenFile('r', 2)) {
LoadAT45DB***
do {
http://movilavn.narod.ru/LoadAT45DB.rar
memset(Buff, 0, 528);
• Модули и проекты, использованные в статье
ic = ReadFile(Buff, 64); http://programmersclub.ru/pro/pro5.pdf
} while(ic);
CloseFile();
if(OpenFile('r', 1)) {
memset(Buff, 0, 528);
do {
ic = ReadFile(Buff, 64);
} while(ic);
CloseFile();
Заключение
** Важное замечание.
ЛАБОРАТОРИЯ СОДЕРЖАНИЕ 72
[ПРОграммист ИСКУСCТВО ИЗМЕНЕНИЯ GTA
июль 2010
Виталий Иванов
by VintProg vintprog@gmail.com
* Комментарий автора.
** Комментарий редакции.
Рис. 2. Выбор DLL Wizard
ArtMoney – программа, предназначенная для редактирования
денег, жизней, патронов и т.п. Она умеет сканировать память или Далее выделяем DLL Wizard и жмем OK. Сразу
файлы игры для поиска каких-то определенных значений (деньги, возьмем и сохраним наш проект «File->Save
Project As» и под именем ShowMessage, чтобы
ресурсы). Официальный сайт www.artmoney.ru
library ShowMessage;
uses
Windows;
begin
MessageBoxA(HWND,'Плагин загружен','Сообщение',0)
end.
“Examples\Plugin1”.
GTA и либо тратим, либо добавляем деньги к этот адрес в текстовой блокнот и вырубаем GTA-
игроку Tommy, запоминаем измененное VC и выключаем ArtMoney. Теперь он нам не
количество «денег» и сворачиваем GTA. понадобится.
Вписываем новое значение (см. рисунок 7):
Итак, первый шаг сделан. Мы нашли адрес
«денег» и остается лишь написать плагин.
плагинов.
var
Пишем свой собственный менеджер-
GTA_VC_Handle : THandle;
загрузчик плагинов
CurrentMoney : Integer;
procedure Timer_begin;
Итак, запускаем среду Delphi и по аналогии
создадим проект DLL-ки. Внутри напишем
begin
следующий код:
// Нажатие и отпуск "M"
library LoaderVc;
if not GetKeyState($4D) < 0 then
{$E .ASI}
if (GetKeyState($4D) < 0) and (keyUp = true) then
begin
CurrentMoney := P_Integer(Address_Money)^;
var
// Записываем 1000 + текущие деньги
SearchRec : TSearchRec;
P_Integer(Address_Money)^ := CurrentMoney + 1000;
filename : pAnsiChar;
keyUp := false;
end
const
end;
dir_bin = 'Bin\*.bin';
//-----------------------------------------------------------
dir_dll = 'Bin\*.dll';
begin
// подгружает их ---
if GTA_VC_Handle <> 0 then
begin
SetTimer(GTA_VC_Handle,0,25,@Timer_begin);
end;
repeat
end.
begin
LoadLibrary(filename);
end;
end;
//------------------------------------------------------------
begin
Load_libs(dir_dll);
Load_libs(dir_bin);
end.
Заключение
Ресурсы
var
Позже было написано множество модулей для
i, myi, ch:integer;
использования в Pascal, далее Delphi. На сайте
begin
http://delphibasics.ru вы можете ознакомиться с
if aAvailProjects=nil then exit;
самими популярными или необходимыми
модулями: System, SysUtils, StrUtils, DateUtils,
FileCtrl, ConvUtils, StdConvs, Math, Classes, myi:= aPlayerNumber;
проблемой. Раньше – эта проблема решалась // нулю и достаточно ресурсов на использование проекта
(aGame[myi].Metal>2) and
АРХИВ СОДЕРЖАНИЕ 78
[ПРОграммист КАК СОЗДАТЬ СОБСТВЕННУЮ DLL НА ДЕЛЬФИ
июль 2010
• хранилища ресурсов (в DLL можно хранить не external 'DLLNAME.DLL' name 'FunctionName' index FuncIndex;
всевозможные ресурсы - иконки, рисунки, procedure ProcedureName(Par1: Par1Type; Par2: Par2Type; ...);
АРХИВ СОДЕРЖАНИЕ 79
[ПРОграммист КАК СОЗДАТЬ СОБСТВЕННУЮ DLL НА ДЕЛЬФИ
июль 2010
begin
• LoadLibrary(LibFileName: PChar) - загрузка
указанной библиотеки LibFileName в память.
{"Чистим" адрес функции от "грязи"}
библиотечной функции. При успешном {...то пытаемся получить адрес функции в библиотеке}
завершении функция возвращает дескриптор
@GetSimpleText:=GetProcAddress(LibHandle,'GetSimpleText');
(TFarProc) функции в загруженной DLL.
{Если и здесь все OK}
• FreeLibrary(LibModule: THandle) - делает
недействительным LibModule и освобождает
if @GetSimpleText <> nil then {...то показываем результат}
FreeLibrary(LibHandle);
АРХИВ СОДЕРЖАНИЕ 80
[ПРОграммист КАК СОЗДАТЬ СОБСТВЕННУЮ DLL НА ДЕЛЬФИ
июль 2010
exports ShowMyDialog;
begin begin
// В зависимости от LangRus возвращаем русскую (True) {Создаем экземпляр Form1 формы TForm1}
Form1.Free;
Создание плагинов
exports GetSimpleText;
В DLL можно размещать не только функции, но и Напомню лишь, что плагин – дополнение к
курсоры, рисунки, иконки, меню, текстовые программе, расширяющее ее возможности. При
строки. На этом мы останавливаться не будем. этом, сама программа обязательно должна
Замечу лишь, что для загрузки ресурса нужно предусматривать наличие таких дополнений и
загрузить DLL, а затем, получив ее дескриптор, - позволять им выполнять свое предназначение.
загружать сам ресурс соотвествующей функцией
(LoadIcon, LoadCursor и т.д.). В этом разделе мы Заключение
лишь немного затронем размещение в
библиотеках DLL окон приложения (форм в Вот, собственно все. Надеюсь, студенту,
Дельфи). практику-испытателю и кому-либо другому это
пригодится. Удачи!
Для этого нужно создать новую DLL и добавить в
нее новую форму File / New / DLL, а затем File /
New Form. Далее, если форма представляет
** Комментарий автора.
функцию (допустим, форма называется Form1, а прочитать (правда, на английском) в тексте пустого проекта DLL,
ее класс TForm1). который создает Delphi (File / New / DLL). Так что лучше
АРХИВ СОДЕРЖАНИЕ 81
[ПРОграммист ФРАЗЕОЛОГИЗМЫ, ХОХМЫ, ЗАГАДКИ
июль 2010
Подзатыльник – традиционный
способ передачи информации
от поколения к поколению...
Популярно о протоколах
ЮМОР СОДЕРЖАНИЕ 82
[ПРОграммист ФРАЗЕОЛОГИЗМЫ, ХОХМЫ, ЗАГАДКИ
июль 2010
BSOD-у. Откройте файл SYSTEM.INI, который eжeли провeрятичегоглаголют молчаливо еси ложъ тогдауж прeрвати
C:\Windows или другой, где проинсталлирована eжeли знако еси 'q' тогдауж прeрвати аминь1
сама Windows). Вы можете сделать это очень молвити "молви второй цифирь, барин: " аминь1
Выполнить...) или используя Notepad, найдите в eжeли провeрятичегоглаголют молчаливо еси ложъ тогдауж прeрвати
буквы В ВЕРХНЕМ РЕГИСТРЕ, то есть F, а не f). отвeт буде первыйсундук бѣзо второйсундук аминь1
теперь ждите свой экран смерти (supposedly it отвeт буде первыйсундук повторити_столько_сколько второйсундук
ага
использовати площадь какобычно аминь1
молвити "Отвeт есьм: " аминь1
наместе двояко провeрятичегоглаголют молчаливо
молвити отвeт да_промолчати спасихоспади1
кагбе
ага
eжeли получалка.сломалася молчаливо тогдауж
пока (истино) аминь1
кагбе
возвeрнути нуль спасихоспади1
молвити "Не лепо молвишь, барин!" аминь1
ага
возвeрнути нуль спасихоспади1
ага
ага
кагбе
творити
кагбе
спасихоспади1
ЮМОР СОДЕРЖАНИЕ 83