Последние записи
- Преобразовать массив байт в вещественное число (single)
- TChromium (CEF3), сохранение изображений
- Как в Delphi XE обнулить таймер?
- Изменить цвет шрифта TextBox на форме
- Ресайз PNG без потери прозрачности
- Вывод на печать графического файла
- Взаимодействие через командную строку
- Перенести программу из Delphi в Lazarus
- Определить текущую ОС
- Автоматическая смена языка (раскладки клавиатуры)
Интенсив по Python: Работа с API и фреймворками 24-26 ИЮНЯ 2022. Знаете Python, но хотите расширить свои навыки?
Slurm подготовили для вас особенный продукт! Оставить заявку по ссылке - https://slurm.club/3MeqNEk
Online-курс Java с оплатой после трудоустройства. Каждый выпускник получает предложение о работе
И зарплату на 30% выше ожидаемой, подробнее на сайте академии, ссылка - ttps://clck.ru/fCrQw
19th
Авг
УРОК 7. ПРОГРАММА ПРИНИМАЕТ РЕШЕНИЕ
Как вы уже знаете, программа представляет собой последовательность инструкций, выполняемых компьютером для реализации определенных задач. Все созданные вами до сих пор простые программы на C++ выполняли операторы по порядку, начиная с первого до конца программы. По мере усложнения программ вам потребуется, чтобы выполнялся один набор операторов, если определенное условие соблюдается, и другой набор, если условие не соблюдается. Другими словами, вам потребуется, чтобы ваши программы приняли решение и соответственно отреагировали. В этом уроке описывается оператор C++ if, который будет использоваться вашей программой для принятия подобных решений. К концу данного урока вы освоите следующие основные концепции:
- Программы на C++ используют операции сравнения, чтобы определить, равны ли два значения или одно значение больше или меньше другого.
- Для принятия решений используется оператор C++ if.
- Операторы C++ могут быть простыми (одна операция) илисоставными (несколько операций, сгруппированных внутри правой и левой фигурных скобок {}).
- Ваши программы используют оператор C++ if-else для выполнения одного набора операторов, если определенное условие соблюдается, и другого набора операторов, если условие не соблюдается.
- Комбинируя несколько операторов if-else, программы могут проверять несколько условий.
- Используя логические операторы C++ И и ИЛИ, ваши программы могут проверить несколько условий, например: Есть ли у пользователя собака И долматин ли это ?
Программы, которые принимают решения, выполняют условную обработку. Другими словами, на основании результата одного или нескольких Условий программа будет выполнять определенные операторы. Экспериментируйте с программами данного урока; ваш набор инструментальных средств C++ уже достаточно обширен для создания полезных программ.
19th
УРОК 1. СОЗДАНИЕ ВАШЕЙ ПЕРВОЙ ПРОГРАММЫ
Все вы использовали компьютерные программы, такие как текстовый процессор, электронные таблицы и даже Microsoft Windows 95. Компьютерные программы, или программное обеспечение, представляют собой файлы, содержащие инструкции, которые указывают компьютеру, что следует делать. Если вы работаете в среде MS-DOS или Windows, то, например, файлы с расширениями ЕХЕ и СОМ содержат команды, которые компьютер может выполнять. Другими словами, файлы содержат специальные инструкции, выполняемые компьютером, обычно одну за другой, для решения определенной задачи. При создании программы вы указываете инструкции, которые компьютер должен выполнить. Из этого урока вы узнаете, как указать такие инструкции с помощью операторов C++. К концу данного урока вы освоите следующие основные концепции:
• При создании программы используйте текстовый редактор, чтобы ввести операторы C++ в исходный файл программы.
• Для преобразования операторов программы C++ в выполнимую программу, в единицы и нули, которые понимает компьютер, используйте специальную программу — компилятор C++.
• Для изменения или исправления программы используйте текстовый редактор.
• При нарушении одного (или более) правил программирования на C++ компилятор выдаст на экран сообщения о синтаксических ошибках. Вам следует отредактировать программу, чтобы исправить ошибки, а затем запустить компилятор снова.
Программирование представляет собой процесс определения последовательности инструкций, которые должен выполнить компьютер для решения определенной задачи. Для указания этих инструкций вы используете язык программирования, например C++. С помощью текстового редактора вы вносите программные операторы в исходный файл. Далее вы используете специальную программу — компилятор —для преобразования операторов из формата, который вы можете читать и понимать, в единицы и нули, которые понимает компьютер.
Лучший способ понять процесс создания и компиляции программы — построить простую программу на C++. Давайте этим займемся!
19th
УРОК 2. БОЛЕЕ ВНИМАТЕЛЬНЫЙ ВЗГЛЯД НА C++
В уроке 1 вы создали несколько программ на C++. В то время ваша цель заключалась в том, чтобы понять процесс создания и компиляции программ на C++, а не в том, чтобы понять операторы C++. В данном уроке вы впервые более внимательно рассмотрите операторы, из которых состоит программа на C++. Вы увидите, что большинство программ на C++ придерживаются одного и того же формата: начинаются с одного или нескольких операторов # include, содержат строку void main(void), а затем набор операторов, сгруппированных между левой и правой фигурными скобками. Из этого урока вы поймете, что эти несколько запугивающие операторы реально очень просто освоить. К концу данного урока вы изучите следующие основные концепции:
- Оператор # include обеспечивает преимущества использования заголовочных файлов, которые содержат операторы C++ или программные определения.
- Основная часть программы на C++ начинается с оператора void main(void).
- Программы состоят из одной или нескольких функций, которые, в свою очередь, состоят из операторов, предназначенных для решения определенной задачи.
- При выводе на экран ваши программы будут широко использовать выходной поток cout.
Когда вы создаете программы на C++, вы реально работаете в терминахоператоров, но не инструкций. Позже вы изучите оператор присваивания,который присваивает значения переменным, оператор if , который позволяет программе принимать решения и т. д. А пока мы просто будем ссылаться на содержимое вашей программы, как на операторы программы.
19th
Разработчики – интерфейс – пользователи
В статье написано то, что автор смог прочесть, понять и пересказать своими словами и немного того, до чего додумался сам; все то, что касается процесса взаимодействия двух человек – разработчика и пользователя. Кратко это выражается одним словом – интерфейс…
«Встречают по одежке, а провожают по уму»
Демьяненко Александр by Grenles http://www.programmersforum.ru/member.php?u=17572
Часть первая. Философия
Надо же! Почти вступление! Не скажу, что я большой профессионал, особенно по теме данной статьи, но и не скажу, что я совсем уж любитель. Я учусь писать, читать, видеть, думать, и снова начинаю этот процесс сначала*.
* Комментарий автора.
Кто-то сказал: «хочешь что-то понять, – объясни это что-то другому, – он может и не понять
сказанного тобою, но уж ты сам точно это поймешь».
Очень сложно учить чему-то профессионалов, особенно в той области, которую они знают лучше тебя, гораздо проще – стать их учеником. Однако, как ни странно, порой именно любители пишут книги для профессионалов и учат их ремеслу и только лишь потому, что не всегда профессионалы умеют выразить доходчиво свои знаний для других. Поэтому не все так плохо, но и не так просто, как кажется на первый взгляд. В мире всегда полно тех, кто задает вопрос: «А с чего мне лучше начать?». Мало того, есть еще такие профессионалы, которые проснувшись утром, понимают, что они ничего не знают из того, что должны знать. Именно поэтому каждый день они начинают с поиска и изучения новых горизонтов знания. Каждый раз, узнав больше, они понимают, что все равно ничего не знают и снова начинают бесконечный процесс приобретения знаний. Вот для этих людей и не только для них я и начал разговор на заданную тему.
Тема, которую хочу затронуть, выражается одним словом – интерфейс. Тема с одной стороны кажется простой и легкой, а с другой – это весьма сложная и обширная область знаний, которую трудно уместить в рамки одной статьи. Анализируя современный рынок программного обеспечения, множество интернет сайтов, различных печатно-книжных изделий я пришел к выводу, что знания о правилах создания интерфейса должны быть у всех, так или иначе связанных с созданием продуктов, предназначенных для пользователей, потребителей. На сегодняшний день эта область знания вполне достойна того, чтобы идти отдельным курсом в высших учебных заведениях.
От того, насколько удачно продуман и реализован интерфейс продукта, зависит 75% успеха разработчика и 100% эффективности использования потребителем конечного продукта. Случается, что и начинающие разработчики, и гранды компьютерной индустрии, как студенты на экзаменах, «засыпаются» на плохо сделанном интерфейсе для своих великих проектов. К сожалению, не всегда с первого раза удается найти удобный способ взаимодействия пользователя и продукта. То, что ясно разработчику, не всегда очевидно пользователю и наоборот. Почти как мужчина и женщина всегда говорят на разных языках, так разработчик и пользователь живут и мыслят на основе разных категорий.
Садясь за статью и желая раскрыть тему полнее и правильнее, я решил обратиться в Интернет, чтобы узнать: «А как на мой вопрос отвечали другие?». Не скажу, что эта фраза мне попалась первой, но зацепился я за нее сразу: «Для ReGet дизайн придумывала студия Артемия Лебедева. В результате пользоваться ReGet, в отличие от FlashGet очень удобно. Можете в этом сами убедиться» [1]. При этом, я не думаю, что функционально обе программы сильно разнятся, выполняемые ими задачи практически одни и те же, но разница в том, что одну программу мы используем, а другую просто имеем ввиду, зная что она есть.
Самый веский аргумент, окончательно подтолкнувший меня на создании серии статей по заданной теме, я нашел в источнике [1]: «в России слишком много программистов-самоучек, которые все этапы создания программы от идеи программы до ее реализации выполняют сами». К сожалению, не у всех есть возможность нанять профессиональных дизайнеров или найти специалиста в этой области, поэтому приходится «изобретать велосипед» самому.
Начнем. С чего? Элементарно! What song? Книги!
Я нашел очень много информации по теме и около нее: статьи, примеры, книги, журналы. Среди множества источников выделил три книги. Не буду утверждать, что они являют собой ту самую истину, которая незыблема и нет других источников информации, но прочесть бы их я посоветовал:
ее стоит прочесть хотя бы для того, чтобы понять основные принципы «юзабилити» и того, как не стоит делать интерфейс. Кто-то скажет, – но она же только для тех, кто создает веб-сайты, Отвечу, – а кто сказал, что создание интерфейса программы сильно отличается от создания интерфейса веб-сайтов? Я бы сказал иначе, создание веб-сайтов выросло из принципов создания программ, именно поэтому внешний вид может быть разным, но подходы, принципы, правила одни и те же. Но, как ни странно, думать надо в любом случае и при создании сайта, и при создании программы. Хорошо думать, когда есть знания. Замечательно думать, когда знания перешли в умения. Надеюсь, уважаемый читатель, ты меня понял.
2. Джеф Раскин. Интерфейс: новые направления в проектировании компьютерных систем
считаю весьма полезными для разработчиков, желающих стать профессионалами. Я бы не сказал, что по году создания и издания книга нова. В найденной мною версии она датируется 1996 годом, но только что это меняет? В книге весьма интересно разложены по полочкам элементы интерфейса их плюсы и минусы, и порой высказывается совершенно иной взгляд на привычные, казалось бы, вещи: отказ от GUI, отказ от использования мыши, отказ от разбиения задач по приложениям. В определенном смысле программы интернет-браузеры реализуют эту идею, когда в одном окне выполняется все – звук, графика, редактирование, просмотр видео и прочие действия.
3. Иоханнес Иттен. Искусство цвета
книга тоже не новая, но привожу я ее из тех соображений, что дизайнеру, просто глупо ничего не знать о свете и цвете и не уметь применять эти знания на практике. Да и просто это повод открыть интернет и поискать любую литературу на тему рисования, цвета, способов изображать предметы. Скажу вам – очень интересная тема. Исследуйте на досуге, а я как-нибудь позднее чего-нибудь вам об этом расскажу. Искусство художника оказывается полезным для дизайнера – это основа его творчества.
4. В.В. Головач. Дизайн пользовательского интерфейса
Скажу сразу, она попалась мне на глаза гораздо позже других книг и понравилась намного больше тем, что в ней нет строгой теории, а сразу идет разбор конкретных ситуаций – ошибок и решений. Как ни странно, на фоне прочтения первых трех книг, эта – четвертая книга как будто подвела итоги решений, описанных теоретически в «умных» книгах.
Мало того, изложение материала таково, что я бросил чтение других книг и продолжил чтение только этой книги. При этом, на основании изложенных примеров, я реализовал несколько удобных «фишек» для своих программ на будущее, и они мне понравились. Советую прочесть эту книгу, просто потому, что это полезно и интересно.
Есть более новая версия этой книги – «Дизайн пользовательского интерфейса 2. Искусство мыть слона».
Начав читать, и, почти дочитав эти книги, я понял, что дизайн это бесконечный процесс слияния знаний, фантазии и ресурсов, которыми обладает дизайнер, в котором многое зависит от личности и ее таланта. Задумавшись, решил, что точнее назвать этого человека дизайнера – создатель: во-первых – это по-русски, а во-вторых – более отражает процесс дизайна (создавать нечто удобное, новое и оригинальное).
Что наша жизнь? И…
Классический ответ на заданный вопрос – «игра». В каком-то смысле, если задуматься, так и есть – вся наша жизнь есть одна сплошная игра. И в любой игре есть маски, костюмы, актеры, зрители. Я нашел этой игре новое обличие:
. зрители – это пользователи, потребители созданного вами продукта – программы, фильма, музыки, книги и тому подобного
. маски и костюмы – это тот самый интерфейс, в который мы облекаем наш продукт и то, что видит в первую очередь зритель. Это только потом он начинает разбираться в сюжете (логике), в таланте актера (профессионализме разработчика), имя которого завтра будет трудно вспомнить, если он оказался плох и т.д.
. актеры – это разработчики, по сути – мы с вами, те, кто хоть однажды пытался что-то проектировать, создавать, строить и прочее. От того, насколько мы талантливые актеры будет зависеть успех всего спектакля, аншлаг, признание публики, слава, деньги и прочее.
Разрабатывая программу, мы играем роль самого Создателя. Может быть, именно поэтому большинству так нравится играть, многим – нравится программировать, а некоторым из числа избранных – создавать и творить. Все это теоретически хорошо, но возникает вопрос, а какой ты создатель? И для кого ты создаешь? Мучаешься, не спишь ночами, читаешь гору разной литературы, бьешься над парой строк кода и все ради чего? Чтобы однажды узнать – твой труд никому не нужен, потому что ты не смог найти удачный способ взаимодействия пользователя с твоим творением. Не смог донести до него свою мысль и идею – ответ на главный вопрос: «…зачем ему нужно то, что ты создал?». Тебе-бы встретиться с ним, поговорить по душам за рюмкой чаю, но уже поздно – время упущено и пользователь ушел к другому, так и не поняв, что же ты хотел для него сделать. К сожалению, в жизни часто так бывает, что разработчик и пользователь встречаются друг с другом тет-а-тет весьма и весьма не часто. Особенно последняя фраза касается начинающих разработчиков – опытные-то знают, что пользователя надо завлечь пряничком, блестящей оберткой, усадить на мягкий стульчик, подать вкусный чай… Часто начинающие разработчики не то чтобы забывают о пользователе, они порой плохо представляют, а кто это вообще такой.
Пройдемся по науке
Собственно, что я хотел сказать? Для начала надо немного определиться и ответить на вопрос главный вопрос статьи: «Что такое интерфейс***?»
** Интерфейс (от англ. interface — поверхность раздела, перегородка) — совокупность средств
и методов взаимодействия между элементами системы [4].
Ответ обобщенный, подходит для разных сторон и сфер человеческой деятельности, но в своей сути он отражает смысл этого явления. Далее, подумав немного, решил, что мир придуман не вчера и все процессы должны быть так или иначе давно регламентированы и описаны. Я начал искать стандарты, правила, ГОСТ-ы. Приводить здесь подробное описание этих документов абсолютно бессмысленно. Каждый сам может найти их в сети Интернет. Будет гораздо лучше, если выскажу свои соображения, которые сделал, переработав найденную информацию…
Большинство ГОСТ-ов, найденных мною, направлены на разработку технической документации, связанной с процессом разработки программного обеспечения. Создается впечатление, что изначально в 70-х начале 80-х годов прошлого столетия упор делался на техническую сторону этого вопроса – разработку и детализацию алгоритмов, средств сопряжения, подбор технической базы, создание различных инструкций по эксплуатации и прочее. Старый ГОСТ именно это и регламентировал. Впрочем, если подумать, так оно и должно было быть, так как программирование по сути родилось из математики и на первом месте было решение задач, а не внешнее оформление. Лишь в ГОСТ, относящимся к недавним советским временам, а именно, ГОСТ 19.201-78 и ГОСТ 24.207-80 можно неявно увидеть фразы, частично указывающие на средства взаимодействия с пользователем: «требования к программе или программному изделию», «требования к маркировке и упаковке». Правда, прочтя эти фразы, явно и не скажешь, что тут имеется ввиду «интерфейс». Тем не менее, в источнике [2] нашел следующее: «Техническое задание, как правило, разрабатывается на основе ГОСТа 19.201-78 «ЕСПД.
Техническое задание. Требования к содержанию и оформлению». Таким образом, получается, что разработчик должен сам знать и подразумевать, что в задание должны закладываться вопросы, связанные с интерфейсом. Явно это в ГОСТ не звучит. Но это было «тогда». По ГОСТ советских времен подразумевалось, что интерфейс у нас возникает сам собой, – это следует из текстов документов. Получалось, как в известной фразе: «В СССР секса нет, а дети есть». Всем известна фраза о том, что в мире все подвержено изменениям. Тоже самое можно утверждать и про ГОСТ-ы. Не прошло и 20-ти лет, изменились требования времени, реалии, изменилось само время. Согласно документам, датируемым 2000-м годом и выше, разработчики ГОСТ уже узнали про интерфейс и даже явно написали об этом в «Пример шаблона технического задания (ТЗ) на сайт» [3], где есть два раздела: «Требования к графическому дизайну сайта», и «Требования к дизайну сайта». Это уже радует. Конечно же, кажется совершенно очевидным, что сайт без дизайна не сайт. Однако, судя по всему, на осознание этого факта разработчикам ГОСТ потребовалось время. Думаю, что оно им еще будет нужно, чтобы создать отдельный ГОСТ, касающийся только дизайна, как такового.
В итоге, проглядев различные ГОСТ, документы, шаблоны и примеры, сделал основной вывод. Сейчас, как и раньше, основной упор идет на правильное, точное, детальное оформление документации по всем этапам разработки продукта – замысел, поиск информации для начала разработки, процесс разработки, тестирование, внедрение, эксплуатация. С одной стороны – это правильно, сложные продукты делает много людей и для удобства их работы и взаимодействия нужны документы, описывающие детально и правильно различные этапы процесса создания конечного продукта. А с другой стороны – это жуткая бюрократическая формальность, требующая от каждого участника процесса описывать каждое свое действие и решение. Именно поэтому создание документации так не любят разработчики. Порой время, требуемое на ее создание соизмеримо со временем создания самого программного продукта. Но, опять же, мы вернулись к тому, от чего пришли – в настоящее время по ГОСТ дизайн и интерфейс упирается в «бумагу».
Если внимательно подумать, то это правильно, заказчику «нечто» не покажешь, а нарисованное и написанное на бумаге вполне возможно. Поэтому, насколько мне представляется, знание ГОСТ и этапов от создания технического задания до сопровождения готового продукта необходимо не только крупным фирмам, но и одиночным разработчикам, так как это позволяет делать все правильно и приучает к определенному порядку. Конечно же, для написания программы, из разряда «калькулятор» вряд-ли нужно техническое задание, но знание этого необходимо. Прошлись по науке? Хотя ГОСТ и прочие нормативные документы необходимо знать, но, по сути, это скучно, сухо и сложно. Пожалуй, хватит – идем дальше.
Что вы делаете после того, как решили написать собственную программу?
Предполагаю, что 95% респондентов ответят – обдумываю идею программы, способы реализации, типы данных, выбор среды программирования и прочие детали и … будут почти правы. А почему – почти? А потому «почти», что мало-кто сразу из большинства разработчиков начинает думать над тем: а как будет выглядеть ваше будущее творение перед лицом пользователя. Удобно—ли пользователю будет работать с программой***. Согласен, что на первом этапе весьма сложно представить цельный интерфейс программы, так как и программы, собственно говоря, еще и нет, но задуматься над этим стоит уже с самого начала.
*** Комментарий автора.
Скажу, что два года назад, когда я стал активно заниматься программированием, а не просто сопровождением программ и написанием мелких макросов, я больше корпел над алгоритмами и достижением результата, – программа должна делать то, что хочет от нее пользователь. Интерфейс возникал или по ходу написания, или так, как было удобно мне, а не пользователю. После запуска продукта в эксплуатацию как минимум неделя была посвящена только тому, что я отвечал на вопросы что, где, почему и зачем. Теперь же я стараюсь думать не только над «внутренностями», но и над «внешним видом».
А как вы пишете программу?
Думаю, что большинство ответят примерно так: «Сажусь за компьютер, открываю среду программирования и начинаю писать код». Если это визуальная среда программирования, то обычно 100% действий начинается с того, что на пустую форму перетаскивается мышкой какой-либо элемент из палитры компонентов и… вот тут начинается самое интересное, вы ступаете на дорогу «войны». Я не ошибся, именно дорогу войны, даже точнее будет сказать – тропу. Почему? Все очень просто – весь процесс разработки есть борьба с самим собой, с кодом, ошибками и прочими неприятностями. В любой программе во время ее написания никогда с первого раза не бывает правильно размещенного элемента в нужном месте формы, соседние элементы иногда начинают мешать друг другу или просто не помещаются на форме так, как этого хочется. В итоге вы все время воюете – с алгоритмом, со средой разработки с внешним видом. Причем чаще всего страдает от всей этой «битвы» интерфейс. Да и кто серьезно задумывается**** над тем, насколько удобно пользователю будет работать с программой, когда на первое место выходят задачи логики функционирования программного продукта?
**** Комментарий автора.
Пример из моей практики. В связи с производственной необходимостью потребовалось решить проблему автоматизации учета. Проблема была в том, что «низы» уже не могли вести расчеты «вручную» в связи с их сложностью, объемом и цикличностью, а «верхи» не знали быстрого решения проблемы, то есть подходящего программного решения по цене и решаемым задачам не было. В итоге, по стечению различных обстоятельств, наш системный администратор взялся за разработку программы «с нуля». То, что для него это было тяжело, это мягко сказано, это было очень тяжело. Ему приходилось решать проблемы абсолютно разного рода – выполнять свою непосредственную работу, параллельно изучать новые методы и технологии программирования, изучать предметную область задачи, решать дела домашние, между этим делать еще что-то. Мало того, периодически он «воевал» с непосредственным начальством по поводу совмещения прямых рабочих обязанностей и работы по написанию программы (программу он писал добровольно и, в том числе, на своем рабочем месте, а какому начальству понравится такое?). Смысл всей этой предыстории таков, что ему было не до интерфейса и дизайна программы. Для него было важным решить технические проблемы стоявшей перед ним задачи. В итоге задачу он решил для своего уровня и того времени достойно. Однако, в процессе эксплуатации выяснилось, что где-то он не додумал логику, где-то проиграл в удобстве интерфейса. При этом каждый день он решал какие-либо проблемы, связанные с внедренной программой – дописывал, исправлял, модернизировал, консультировал пользователей, писал документацию. Добавление новых решений и отчетов в программу, привело к тому, что с каждым днем она становилась все функциональнее и сложнее. В итоге, несмотря на то, что он видел и знал огрехи интерфейса, переделать или исправить что-то было уже практически невозможно, так как это означало переписывание программного кода практически сначала.
Вывод, напрашивающийся из всей этой ситуации таков – в условиях нехватки времени (а в обычных «рабочих» условиях так и есть) одному человеку практически невозможно создать удобную во всех отношениях программу. Все усилия в этом случае направлены на то, чтобы найти и реализовать логическое решение, внедрить и запустить в работу программу. Понимание того, как все должно быть, как удобнее работать, приходит уже после того, когда программа запущена в работу и эксплуатируется. И, часто получается так, что реализация «удобства интерфейса» уходит на второй план, так как возникают более важные задачи, – исправление допущенных ошибок в логике, модернизация и прочее. Именно поэтому большинство серьезных фирм очень много времени тратят на подготовку процесса, создание «стартовой базы», и лишь потом начинают программировать. В экстремальных условиях интерфейс страдает всегда.
Когда вы задумываетесь о том, кто и как будет работать с вашей программой и какие ситуации могут при этом возникнуть?
А вот на эти вопросы я не могу дать однозначного для всех ответа. У каждого найдется свой ответ, но, в конечном итоге, правильный ответ на эти вопросы всегда звучат из уст пользователя. Почему из уст пользователя? Отвечу цитатой рецензента этой статьи, литературного редактора этого журнала, Utkin: «…даже в идеальной программе пользователи найдут что покритиковать. Просто потому что пользователи всегда придирчивы. Одним подавай одно, другим требуется прямо противоположное». Поспорить с этим сложно. Еще классик И.А. Крылов написал басню про Слона, который рисовал картину в угоду всем и в итоге никому его шедевр не понравился. В данном случае – тот же самый процесс.
Мало того, этот самый «пользователь» всегда найдет ту самую ошибку, которую никто из разработчиков даже в страшном сне не мог увидеть. При этом, сложно сказать, какая ошибка хуже – алгоритмическая или визуальная, обе одинаково неприятны. Разница лишь в том, что логическую ошибку среднестатистический пользователь не всегда можно найти, особенно, если плохо знает логику функционирования программы, – такую ошибку не всегда видно. С точки зрения пользователя, логические ошибки могут быть вообще никогда не обнаружены. По известной статистике большинство пользователей используют лишь 5-10% возможностей программы, про остальные 90-95% возможностей, где и может оказаться логическая ошибка, они могут не знать. Визуальная ошибка всегда хуже – она просто заметнее. Классический пример из недавнего прошлого – это ошибка вывода изображения видеокартой. Чаще всего такие ошибки выявлялись в играх, как более требовательным к ресурсам компьютера, а не «офисных» приложениях, которым хватало «гарантированного минимума». Они проявлялись в том, что могли «ломаться» контуры изображаемых предметов, возникали непредвиденные визуальные эффекты, искажения картинки в целом, в худшем варианте или просто ничего не было видно, или компьютер шел на перезагрузку. При этом, источник ошибки мог быть с любом месте – как в сбое видеокарты, так в используемом программном обеспечении (драйверах видеокарты, драйверах DirectX или OpenGL, несовместимости с операционной системой и прочее).
Для крупных корпораций уровня Microsoft или Adobe, когда есть рынок, бренд, сформированный круг пользователей, которые все равно не уйдут, такие ошибки менее ощутимы. Да, они неприятны, никто не говорит, что ошибки – это хорошо, но все-таки, менее ощутимы. Для таких корпораций они всего-лишь повод создания обновлений и выпуска новых версий программ. При этом, вовсе на факт, что старые версии работали хуже или не удовлетворяли потребностям пользователя. На мой взгляд, рассматривая, как пример, программу Adobe Photoshop, для большинства пользователей (не дизайнеров) вообще достаточно ее варианта в версии 9.0. Новые возможности программы, выпуск линейки продуктов от Adobe в виде нескольких DVD дисков, еще раз повторю, обычным пользователям, вообще не понятны и не нужны, – они просто не пользуются ими в полной мере. Хотя, как бренд и признак «статуса», большинство просто устанавливают эти продукты на свой компьютер, не зная и 5% всех возможностей. Грубо говоря, они микроскопом забивают гвозди, изменяя размеры фотографий или сохраняя их в другой формат.
Возвращаясь к теме разговора, еще раз скажу, что ошибки для крупных корпораций менее болезненны, чем для разработчиков-одиночек. И вот почему. Образно говоря, обслуживание ошибок у них поставлено на конвейер – службы поддержки, бесплатная горячая телефонная линия, консультации он-лайн и через различные сервисы в сети. В данном случае под «ошибками» я подразумеваю не только непосредственно ошибки в программе, найденные пользователями, но и «ошибки в мозгах пользователей», связанные с обычной человеческой ленью и нежеланием разобраться и думать. С одной стороны – такая ситуация везде и всюду и считается обычной, а с другой – это повод, способ, средство знать еще сильнее «привязывать» пользователей к себе. Если бы большинство из нас внимательно читали бы документацию и перед тем, как задать вопрос, подумали над его решением, то половина вопросов исчезла, а службам поддержки нечего было бы делать.
Если вы «один из подающих надежды», тот самый герой, призванный удивить мир, то у вас просто нет права на ошибку. Вы должны выстелить точно в цель, чтобы громко и красиво заявить о себе. В противном случае велика вероятность того, что пользователи вас не поймут и забудут навсегда ваш адрес и ваш продукт и, развернувшись, уйдут к другим. Исключение в этой ситуации, составляет всеми горячо любимый Билл Гейтс, который, несмотря на то, что первые версии его операционный системы Windows содержали много ошибок и пользователями по всему миру изначально вообще не воспринимались, смог продать свою систему этому миру. Возможно, одна из причин его успеха в том, что первыми пользователями его системы были студенты, ставившие над ней эксперименты. А так как чаще всего то, что изучается в университете, дальше используется в повседневной работе, то Windows и получила такое распространение. Впрочем, умалять заслуг Билл Гейтса, как удачного менеджера и торговца не стоит. Думаю что, еще одна хитрость, принесшая успех Windows состоит в том, что долгое время вообще никто даже и не знал, что надо покупать лицензии на эту систему. Она эксплуатировалась везде и всюду просто так, благодаря умным ребятам, называющих себя хакерами. В свое время ходила шутка о том, что самая лицензионная часть операционной системы – драйвер от мыши.
Другая исключительная ситуация, может быть только одна – ваша программа настолько уникальна и нужна пользователю, что он вынужден терпеть и ждать, и прощать вам ваши ошибки. Правда, такие исключения бывают редко и чаще всего встречаются в сфере специфических видов деятельности человека. Например, программа расчета поведения группы микроорганизмов под влиянием факторов внешней среды, или программа учета параметров работы газотурбинного двигателя. Рядовому пользователю такие программы просто не нужны, подозреваю, что он даже не догадывается о существовании таких программ.
Если кратко подводить итог***** всему сказанному в этих абзацах, что я бы сказал так. Если вы, как разработчик задумались над удобством использования вашего продукта не на стадии разработки, а гораздо позднее, то можно с уверенностью утверждать, что чем дальше вы от точки старта, тем больше затрат и усилий придется приложить, чтобы внести одно «элементарное» исправление. Это касается как общей логики функционирования, так и интерфейса в целом. Копеечная ошибка на старте всегда выливается миллионные затраты на ее исправление на финише.
***** Комментарий автора.
Часто в процессе создания возникает иллюзия «понятности», – это состояние, в котором разработчик настолько проникается идеей продукта и его тонкостями, что ему начинает казаться, что и другим также все очевидно и понятно в функционале создаваемого продукта, как и ему самому. На деле же все выходит наоборот, – даже знающего и опытного пользователя всегда требуется обучать и отвечать на такие вопросы, которые с точки зрения разработчика находятся в ряду «элементарных».
Необходимо как можно раньше начинать глядеть на ваше творение со стороны пользователя и делать это чаще и не просто глядеть (любоваться), а пытаться использовать все то, что вы создали, именно как пользователь. Забыть все, что известно о «внутреннем содержимом» продукта и стать неопытным пользователем, задающим извечные детские вопросы: «Как?» и «Почему?». Поверьте мне, это правило очень и очень часто помогает увидеть такие интересные вещи.
Элементы и проблемы… все мы родом из детства
Насколько я помню, начиная со школьных уроков информатики и продолжая на специализированных курсах университета, везде учат практически одинаково. Ученику рассказывают про алгоритмы, основы написания программ, грамматике языков программирования. Задавая типовые задачи, пытаются выработать логическое мышление, умение применять операторы и структуры изученного языка. Это все полезно и нужно, так как на самом деле заставляет думать и приводит к приобретению навыков логического мышления.
Я могу ошибаться, утверждая следующее, но на мой взгляд, практически нигде нет ни слова о том, как сделать так, чтобы с программой, в общем смысле – продуктом, было удобно работать. Учат только языку, логике и умению применить знания на практике. А о том, чтобы умения, воплощенные в продукте, было еще и удобно использовать на практике, если и говорится, то уж очень мало, настолько мало, что об этом не остается даже воспоминания.
Говорить, что нас ничему не учили, тоже нельзя. Если чуть-чуть подумать, то можно немного провести аналогии, хотя это будет слишком размыто и не очень конкретно. Уроки рисования в школе, когда каждый как умел, так и рисовал, теоретически можно взять в качестве элементарной базы графического дизайна. Тоже можно сказать о черчении и геометрии, из них можно почерпнуть понятия о проекциях, симметрии, способах изображения объектов, пропорциях. Можно еще упомянуть историю, касаемо истории искусств, обычаев, культуры – оттуда можно взять некоторые элементы для декора, дизайна, оформления. Но, мне кажется, это все-таки сложно и «притянуто за уши». Мало того, требует определенных усилий и особого мышления, чтобы все это собрать воедино. Пожалуй, из школьной программы – это и все, что можно взять в багаж, если не учитывать книги и специальные курсы, где непосредственно учат дизайну и оформительскому искусству, я их не рассматриваю, так как они идут факультативно и не входят в основную программу обучения, то есть массово не изучаются.
Если идти обучаться далее в университет (не могу со стопроцентной вероятностью утверждать, что в настоящее время ситуация не изменилась), то до недавнего времени в большинстве высших технических учебных заведений не было специально выделенной дисциплины, так или иначе связанной с интерфейсом. Студентам преподавались эргономика, трехмерная графика, черчение, инженерное моделирование, но увязать их с интерфейсом, опять же, можно лишь косвенно. Выделенной специализированной дисциплины, технических ВУЗах до недавнего времени не было. Я не беру во внимание обучение специальности дизайнер, так как считаю, что её изучает отдельно взятая группа людей и, распространяемые знания, не идут в широкие массы в отличие, например, от математики, физики, химии, изучаемых всеми в обязательном порядке на первых курсах университета.
Таким образом, молодой инженер, выпускник высшего учебного заведения с техническим уклоном, может оказаться хорошим специалистом, весьма подкованным логически и технически, но имеющим слабые знания в части дизайна, интерфейса и способов взаимодействия с пользователями. В результате, придя на рабочее место, молодому специалисту приходится восполнять этот пробел в знаниях самому и, порой, «изобретать велосипед» там, где он давно уже придуман. Иначе говоря, технические ВУЗы выпускают хороших специалистов, обладающих знаниями по своей специальности, но в разной степени хорошо умеющих эти знания красиво и удобно представить в конечном продукте. Именно по этой причине, как одной из основных, имеют такую популярность различные дизайнерские фирмы. Конечно же тому есть и другие причины – не все умеют созидающе мыслить, красиво рисовать, придумывать, но научить делать это можно всех. С одной стороны удобно поручить создание интерфейса и дизайна знающим людям, а с другой стороны подобное происходит потому, что большинство просто не знает и не умеет это делать правильно. Итак, завершаю философствовать и перехожу к описанию отдельных элементов касающихся интерфейса и не только его.
Продолжение следует…
Ресурсы
. Размышления об интерфейсе http://tclstudy.narod.ru/articles/mytk.html
. Культура разработки программного обеспечения http://www.orientir-yug.ru/kult_po.htm
. Техническое задание на разработку интернет-сайта http://www.rugost.com/index.php?option=com_content&task=view&id=182&Itemid=85
. Википедия. Интерфейс http://ru.wikipedia.org/wiki/%D0%98%D0%BD%D1%82%D0%B5%D1%80%D1%84%D0%B5%D0%B9%D1%81
. Джеф Раскин. Интерфейс: новые направления в проектировании компьютерных систем
http://www.kodges.ru/9701-interfejjs-novye-napravlenija-v-proektirovanii.html
. С.Круг. Не заставляйте меня думать http://www.bookshunt.ru/b10909_veb_dizajn_kniga_stiva_kruga_ili_quotne_zastavlyajte_menya_dumatquot/download
. Об оформлении программной документации http://www.raai.org/about/persons/karpov/pages/ofdoc/ofdoc.html
. ГОСТ 19.102-77.Стадии разработки http://www.nist.ru/hr/doc/gost/19102-77.htm
. Студия Артемия Лебедева. Создание интерфейса навигатора «Штурман» http://www.artlebedev.ru/everything/shturmann/process
. Этот мерзкий, неудобный, противоестественный оконный интерфейс
http://epikoiros.narod.ru/public/antiwind.htm
. Обзор эргономических проблем и недостатков пользовательского интерфейса ПО бухгалтерского учёта на примере 1С:Предприятие 7.5 http://www.usability.ru/Articles/1.htm
. Ссылка на отдельное сообщение форума http://forums.drom.ru/1067823597-post12.html
Статья из пятого выпуска журнала ПРОграммист.
Скачать этот номер можно по ссылке.
Ознакомиться со всеми номерами журнала.
Обсудить на форуме — Разработчики – интерфейс – пользователи
19th
Введение в Scheme. Часть 2.
Здравствуйте, дорогие читатели. Как и обещал, сегодня мы продолжим рассмотрение наиболее распространенных команд языка Scheme и механизмов, облегчающих управление процессом выполнения, а также познакомимся ближе со средой разработки PLT Scheme.
Продолжение. Начало цикла смотрите в четвертом выпуске журнала…
Введение в Sсheme. Часть 2
Utkin www.programmersforum.ru
Нужно помнить, что данные предикаты нежелательно использовать на неточных числах – ошибки округления могут приводить к обратным результатам. Кстати, определить является ли число точным или не точным можно определить с помощью предикатов:
(exact? z) Тест на точность
(inexact? z) Тест на неточность
Для одного и того же числа один из этих предикатов всегда результат #t, тогда как второй #f. Для сравнения чисел можно использовать следующие предикаты, думаю назначение их понятно и так:
(= х1 х2 х3 …)
(< x1 x2 x3 …)
(> x1 x2 x3 …)
(<= x1 x2 x3 …)
(>= x1 x2 x3 …)
(= 1 1 1) #t
(= 1 2 1) #f
Аналогично, предикатам типов числа, не стоит применять сравнения на неточных числах, поскольку ошибки округления могут дать противоположный результат для почти равных чисел.
Еще предикаты для работы с числами:
(zero? z) Проверка на нуль
(positive? x) Проверка является ли число положительным
(negative? x) Проверка является ли число отрицательным
(odd? n) Проверка является ли число не четным
(even? n) Проверка является ли число четным
Поиск минимального и максимального чисел:
(max x1 x2 …)
(min x1 x2 …)
Примеры:
(max 3 4) Результат 4
(max 3.9 4 9 48 99 5) Результат 99.0 При этом число будет преобразовано в неточное.
(min 54 565 9L0) Результат 9.0
(min 4 4) Результат 4
Нужно соблюдать осторожность при сравнении почти равных неточных чисел, поскольку правильный результат работы данных предикатов не гарантирован. Теперь напомним стандартные арифметические операции:
(+ z1 …) Сложение
(* z1 …) Умножение
(- z1 z2) Вычитание
(- z) Унарный минус
(- z1 z2 …) Вычитание (с произвольным числом аргументов)
(/ z1 z2) Деление (деление на нуль не допускается)
(/ z) Деление 1 / z, при этом образуется дробь
(/ z1 z2 …) Деление z1 на произвольное число аргументов
Теперь примеры (поскольку некоторые результаты не очевидны):
(+ 3 4) Результат 7
(+ 3) Результат 3
(+) Результат 0
(* 4) Результат 4
(*) Результат 1
(- 3 4) Результат -1
(- 3 4 5) Результат -6
(- 3) Результат -3
(/ 3 4 5) Результат 3/20 (3 разделить на 4*5)
(/ 3) Результат 1/3
Кстати, дроби являются точными числами, поэтому их удобно использовать в предикатах для работы с числами (гарантируются однозначные результаты сравнений, отношений и т.д.). Дополнительные операции над числами:
(abs x) Абсолютное значение числа
Дополнительные операции деления:
(quotient n1 n2)
(remainder n1 n2)
(modulo n1 n2)
При этом n2 не должен быть равен нулю (независимо от точности числа). Если n1 / n2 есть целое:
(quotient n1 n2) Результат n1/n2
(remainder n1 n2) Результат 0
(modulo n1 n2) Результат 0
Если в результате n1 / n2 образуется не целое число:
(quotient n1 n2) Результат nq
(remainder n1 n2) Результат nr
(modulo n1 n2) Результат nm
где число nq – n1/n2, округленное к нулю, 0 <| nr | <| n2 |, 0 <| nm | <| n2 |, nr и nm отличаются от n1 множителем n2, nr получит знак n1, nm получит знак n2.
Особенностью этих функций (по сути, вариации на тему нахождение остатка от деления) является факт, того, что они возвращают точные числа, в случае если их входящие параметры также являются точными.
(modulo 13 4) Результат 1
(remainder 13 4) Результат 1
(modulo -13 4) Результат 3
(remainder -13 4) Результат -1
(modulo 13 -4) Результат -3
(remainder 13 -4) Результат 1
(modulo -13 -4) Результат -1
(remainder -13 -4) Результат -1
(remainder -13 -4.0) Результат -1.0 Обратите внимание, результат не точное число.
Следующие функции возвращают наибольший общий делитель или наименьший общий множитель их параметров. Результат является всегда неотрицательным.
(gcd 32 -36) Результат НОД (наибольший общий делитель) 4
(gcd) Результат 0
(lcm 32 -36) Результат НОМ (наименьший общий множитель) 288
(lcm 32.0 -36) Аналогично Результат 288.0, но теперь результат будет неточным.
(lcm) Результат 1
Следующие ниже функции возвращают числитель, и знаменатель дроби (знаменатель всегда положительное число):
(numerator q)
(denominator q)
Примеры:
(numerator (/ 6 4)) Результат 3
(denominator (/ 6 4)) Результат 2
(denominator
(exact->inexact (/ 6 4))) Результат 2.0, для получения неточного числа используется явное преобразование. Естественно удобно и для дробей:
(numerator 6/4) Результат 3 (рассматривается дробь 3/2, и только потом берется знаменатель)
Следующая группа функций:
(floor x)
(ceiling x)
(truncate x)
(round x)
всегда возвращает целые числа. Floor возвращает наибольшее целое число не большее чем х. Ceiling возвращает наименьшее целое число не меньше чем х. Truncate возвращает целое число, которое наиболее ближе к х, и абсолютная величина которого не больше абсолютной величины х. Round возвращает целое число путем округления х (половина икса округляется в большую сторону).
(floor -4.3) Результат -5.0 (числа целые, но не точные)
(ceiling -4.3) Результат -4.0
(truncate -4.3) Результат -4.0
(round -4.3) Результат -4.0
(floor 3.5) Результат 3.0
(ceiling 3.5) Результат 4.0
(truncate 3.5) Результат 3.0
(round 3.5) Результат 4.0 — не точное число
(round 7/2) Результат 4 — точное число
(round 7) Результат 7
(rationalize x y) – возвращает самое простое рациональное число, отличающееся от x не больше, чем y.
Рациональное число x более простое чем другое рациональное число y если x = p1/q1 и y = p2/q2 и и | p1 | < | p2 | и | q1 | <| q2 |. Таким образом, 3/5 более простое число чем 4/7. Хотя не все рациональные числа сопоставимы в этом упорядочении (например, 2/7 и 3/5), любой числовой интервал содержит рациональное число, которое более просто, чем любое рациональное число в том же интервале. Известно также, что 0 = 0/1 – самые простые рациональные числа из всех.
(rationalize
(inexact->exact .3) 1/10) Результат 1/3, точное число
(rationalize .3 1/10) Результат 0.3333333333333333
Трансцендентальные функции:
(exp z)
(log z)
(sin z)
(cos z)
(tan z)
(asin z)
(acos z)
(atan z)
(atan y x)
Здесь все просто, стоит отметить log – имеется ввиду натуральный (а не десятичный), atan с двумя параметрами использует знаки x, y для определения квадранта, к которому принадлежит результат.
(sqrt z) – вычисляет квадратный корень, включая мнимую часть числа:
(sqrt -1) Результат 0+1i (всегда мечтал в Паскале получить корень из -1)
(expt z1 z2) – возведение в степень, довольно-таки мощная функция, единственное ограничение – в степень запрещено возводить нуль.
(expt 2.1 3.3) Результат 11.569741950241465
(expt 2.1 -3.3) Результат 0.08643235124004903
Следующие функции предназначены для поддержки комплексных чисел:
(make-rectangular x1 x2)
(make-polar x3 x4)
(real-part z)
(imag-part z)
(magnitude z)
(angle z)
Здесь x1-x4 вещественные числа, z комплексное.
(make—rectangular x1 x2) Результат комплексное число
(make—polar x3 x4) Результат комплексное число
(real—part z) Результат реальную часть числа (x1)
(imag—part z) Результат мнимую часть числа (x2)
(magnitude z) Результат |x3|
(angle z) Результат xangle
Точные и неточные числа можно преобразовывать следующим образом:
(exact->inexact z)
(inexact->exact z)
Первая функция переводит точное число в неточное, вторая выполняет обратные действия. Естественно, такое преобразование возможно не всегда (такая ситуация считается ошибочной). Теперь рассмотрим ввод и вывод чисел. Числа можно получать из строки следующим образом:
(string->number string)
(string->number string radix)
Здесь radix есть основание системы счисления (точное целое число 2, 8, 10 или 16). Для первого варианта имеется ввиду основание системы счисления равным 10. Если число z является неточным и может быть выраженым с использованием точки в качестве разделителя целой и дробной частями, то число будет представлено с минимально возможным числом разрядов.
(string->number ”100″) Результат 100
(string->number ”100″ 16) Результат 256
(string->number ”1e2″) Результат 100.0
(string->number ”15##”) Результат 1500.0
В случае, если строку в число преобразовать не удастся, результат функции #f.
Пары и списки
Парой (иногда называется точечной парой) называется структура данных, представляющая собой запись, состоящую из двух полей, первое из которых называется car, а вторая cdr (названия сложились исторически). Пара создается функцией сons. Доступ к полям пары осуществляется одноименными функциями car и cdr. Присваивание значений полям пары осуществляется с помощью процедур set-car! и set-cdr!. Основное назначение пар это образование и представление списков. Список может быть определен рекурсивно, как пустой список (список, не содержащий элементов) или как пара поле cdr которого является списком. Если Х является списком, то:
. в Х содержится пустой список
. если список находится в X, то любая пара, поле cdr которой содержит список, находится также в X.
Объекты в полях car последовательных пар списка считаются элементами списка. Например, двухэлементный список это пара, car которой первый элемент списка и чей cdr пара, car которой второй элемент списка и чей cdr есть пустой список. Длина списка – это число элементов (которые можно выразить как число пар).
Список |
Список состоит из пар |
||||
Пара1 |
Car |
1-й элемент списка |
|||
Cdr |
Пара2 |
Car |
2-й элемент списка |
||
Cdr |
Пустой список |
Список (a b c d e) можно выразить так (a . (b . (c . (d . (e . ()))))). То есть в списке пары расположены не последовательно друг за другом, а являются вложенными объектами. Пустой список – специальный объект своего собственного типа (это не пара); у него нет никаких элементов, и его длина равна нулю. При этом все списки имеют конечную длину (точное число) и заканчиваются пустым списком.
Для представления пар используется точечная нотация, поля разделяются точкой. Например, пара (4 . 5) имеет поле car 4 и поле cdr 5, при этом внутреннее представление пары будет иным. Списки выражаются проще (х1 х2 … хn), где х это элемент списка. Пустой список выражается, как (). Как уже было отмечено ранее, вся программа на языке Scheme является списком (как и любые ее логически законченные фрагменты), поэтому программы, и выражения можно обрабатывать также как и списки.
Существуют структуры, похожие на списки, которые не удовлетворяют данному выше определению, они называются неподходящие списки. Неподходящий список списком не является, вот его пример:
(a b c . d) что эквивалентно (a . (b . (c . d))), то есть неподходящие списки есть пары.
(define x (list ’a ’b ’c))
(define y x)
y Результат (a b c), list создает список
(list? y) Результат #t, предикат проверки списка
(set—cdr! x 4) Результат не определен (побочный эффект cdr х равен 4)
x Результат (a . 4)
(eqv? x y) Результат #t
y Результат (a . 4)
(list? y) Результат #f
(set—cdr! x x) Результат не определен
(list? x) Результат #f
Предикат (pair? obj) проверяет является ли объект парой.
(pair? ‘(a . b)) Результат #t
(pair? ‘(a b c)) Результат #t
(pair? ‘()) Результат #f
(pair? ’#(a b)) Результат #f
Следующая функция возвращает пару:
(cons obj1 obj2)
car пары будет представлять собой obj1, cdr соответственно obj2.
(cons ‘a ‘()) Результат (а)
(cons ‘(a) ‘(b c d)) Результат (c d)
(cons “a“ ‘(b c)) Результат (”a“ b c), обратите внимание на квотирование и кавычки
(cons ’a 3) Результат (a . 3)
(cons ’(a b) ’c) Результат ((a b) . c)
Квотирование в данном случае используется для того, чтобы поля пары не вычислялись в момент внесения в пару. Это позволяет вносить в пару как простые данные, вроде чисел, так и функции и выражения.
(car pair) – возвращает поле car пары (так и хочется сказать первое поле, но внутреннее представление пар может быть иным, поля пары могут находиться даже не в смежных областях памяти). Попытка получения car пустой пары вызовет ошибку.
(car ’(a b c)) Результат a
(car ’((a) b c d)) Результат (a)
(car ’(1 . 2)) Результат 1
(car ‘()) Результат ошибка вычислений
(cdr pair) – возвращает поле cdr пары. Получение cdr пустого списка вызовет ошибку.
(cdr ‘((a) b c d)) Результат (b c d)
(cdr ’(1 . 2)) Результат 2
(cdr ’()) Результат ошибка вычислений
(set—car! pair obj) и (set—cdr! pair obj) помещает соответственно в car и cdr пары pairs объект obj.
Результат их работы не определен, функции имеют побочные эффекты. Очень часто во время манипуляций со списками возникает много car и cdr. Такие выражения допускается сокращать:
(car (cdr (cdr x))) эквивалентно caddr, то есть справедливо следующее утверждение:
(define caddr (lambda (x) (car (cdr (cdr x)))))
Правило формирования функции следующее: все car представляются как а, а все cdr как d в наименовании функции, которая начинается с с и заканчивается r. При этом допускается формирование функций не более чем из четырех car и cdr.
(null? obj) – возвращает #t, если obj есть пустой список
(list? obj) – возвращает #t, если obj есть список.
(list? ‘(a b c)) Результат #t
(list? ’()) Результат #t
(list? ‘(a . b)) Результат #f
(let ((x (list ’a)))
(set-cdr! x x)
(list? x)) Результат #f
(list obj …) – создает список.
(list ’a (+ 3 4) ’c) Результат (a 7 c)
(list) Результат ()
(length list) – передает число элементов в списке
(length ’(a b c)) Результат 3
(length ’(a (b) (c d e))) Результат 3
(length ’()) Результат 0
(append list …) – объединение списков, при этом происходит перераспределение их внутренней структуры (таким образом, чтобы результат удовлетворял определению списка).
(append ‘(x) ‘(y)) Результат (x y)
(append ’(a) ’(b c d)) Результат (a b c d)
(append ’(a (b)) ’((c))) Результат (a (b) (c))
(append ’(a b) ’(c . d)) Результат (a b c . d)
(append ‘() ‘a) Результат a, список был изменен.
(reverse list) – возвращает список, перераспределенный в обратном порядке.
(reverse ’(a b c)) Результат (c b a)
(reverse ’(a (b c) d (e (f)))) Результат ((e (f)) d (b c) a)
(list-tail list k) – возвращает список на основе списка list, но без k первых элементов. Входящий список должен содержать не менее k элементов. Работу list-tail можно выразить функцией-эквивалентом:
(define list-tail
(lambda (x k)
(if (zero? k)
x
(list-tail (cdr x) (- k 1)))))
(list-ref list k) – возвращает k-й элемент списка. В списке должно быть не менее k элементов.
Нумерация элементов списка осуществляется от нуля. Плюсом пар и неподходящих списков является возможность создания древовидных структур данных с неограниченным числом узлов (пока хватит памяти компьютера).
Символы
Это специальные объекты, особенность которых заключается в том, что символы считаются эквивалентными (для предиката eqv?), если получены одинаковым путем. Символы в частности могут представлять идентификаторы программы, и их уникальность дает возможность использовать их во внутреннем представлении программы. Правила образования символов полностью соответствуют правилам образования идентификаторов. Не следует путать данные символы (Symbols) с символами строки (Characters). Это символы программы и не предназначены для представления строк (хотя и могут быть конвертированы в строки). В частности символы можно получить, квотировав идентификаторы.
Следующий предикат подтверждает, все то, что сказано выше:
(symbol? obj) – определяет является ли объект символом.
(symbol? ’foo) Результат #t
(symbol? (car ’(a b))) Результат #t
(symbol? “bar“) Результат #f, строки представляются строковыми символами!
(symbol? ‘nil) Результат #t
(symbol? ‘()) Результат #f
(symbol? #f) Результат #f
(symbol? 5) Результат #f
(symbol? ‘5) Результат #f, это не идентификатор и не выражение
Для преобразования символов в строки используется
(symbol->string symbol)
Примеры:
(symbol->string ’flying-fish) Результат “flying-fish”
(symbol->string ’Martin) Результат “martin”
(symbol->string
(string->symbol ”Malvina”)) Результат “Malvina”
Здесь (string->symbol “Malvina“) выполняет обратную функцию.
(string->symbol “Привет“)
Символы, в частности, предоставляют программисту возможность работать с объектами программы через операции над их идентификаторами.
Строковые символы
Строковой символ – минимальная единица представления текстовой информации. Строковые символы можно образовывать так #\<character> или #\<character name>. Вот примеры образования строковых символов:
#\a; буква в нижнем регистре
#\A; буква в верхнем регистре
#\(; открывающая скобка
#\ ; пробел
#\space; пробел (образование строкового символа по его имени)
#\newline; символ перехода на новую строку
Поскольку Scheme во многом система, не зависящая от конкретной платформы, то получать константы строковых символов по кодам в какой-либо кодировке не допускается. Поэтому нельзя получить строковой символ #\13, в тоже время PLT Scheme позволяет получать символы национальных алфавитов и задать строковый символ #\й вполне допустимо. Для определения факта того, что объект является строковым символом, используется следующая функция:
(char? obj) – возвращает #t, если объект является строковым символом.
(char? ‘try) Результат #f, поскольку язык проводит четкую границу между символами и строковыми символами.
Все строковые символы определяются на основе их порядка следования в алфавите. Поэтому между строковыми символами существуют отношения, связанными с их расположением относительно друг друга. Для оценки строковых символов используется ряд функций:
(char=? char1 char2)
(char<? char1 char2)
(char>? char1 char2)
(char<=? char1 char2)
(char>=? char1 char2)
Сначала следуют цифры, потом прописные буквы, потом строчные (национальные символы «больше» латиницы). Кстати, PLT Scheme версии 350 допускает более двух символов для сравнения (на манер числовых предикатов).
(char-ci=? char1 char2)
(char-ci<? char1 char2)
(char-ci>? char1 char2)
(char-ci<=? char1 char2)
(char-ci>=? char1 char2)
Тоже самое, но без учета регистра.
(char-ci=? #\A #\a)
Результат #t. Аналогично, функции с приставкой –ci в PLT Scheme могут содержать больше чем два аргумента.
(char-alphabetic? char) – возвращает #t, если строковой символ буква.
(char-numeric? char) – возвращает #t, если строковой символ цифра.
(char-whitespace? char) – возвращает #t, если строковой символ пробел.
(char-upper-case? letter) – возвращает #t, если строковой символ буква в верхнем регистре.
(char-lower-case? letter) – возвращает #t, если строковой символ буква в нижнем регистре.
Несмотря на то, что задавать константы строковых символов их кодами нельзя, получать коды из строковых символов разрешено: (char->integer char) – вернет точное целое число, которому сопоставлен данный строковой символ. Обратная ей функция (integer->char n). Изменить регистр символов можно с помощью функций:
(char—upcase char) – изменяет регистр строкового символа на верхний
(char—downcase char) – изменяет регистр строкового символа на нижний.
Строки
Строки это последовательности символов. В Scheme строки выделяются кавычками. В строки допускается включать Escape-последовательности через использование обратного слеша (\). Например, если известны коды символов, то строку можно задать следующим образом: “\u65\u65” (чего нельзя делать для строковых символов). Длина строки есть число содержащихся в ней символов (точное целое неотрицательное число). Индексация символов начинается от нуля. Аналогично операций с символами все функции имеющие приставку –ci есть операции со строками без учета регистра. Начнем с определения строки:
(string? obj) – возвращает #t, в случае, если объект является строкой.
Существует два способа напрямую создать строку с помощью функций:
(make-string k)
(make-string k char)
Здесь, k – есть длина создаваемой строки, char – символ, которым должна быть наполнена строка (в первой функции она будет наполнена символами вида ”\u0000\u0000\u0000”). Также строки можно создавать путем конкатенации (объединении) символов:
(string char …)
Длина строки:
(string-length string)
Можно также получить доступ к каждому элементу строки (строковому символу):
(string-ref string k)
(string-ref “Привет” 1) Результат #\р, так как нумерация в строке идет от нуля
Изменить конкретный символ в строке можно с помощью: (string—set! string k char). При этом следует помнить, что string—set! возвращает неопределенное значение. Строки можно сравнивать (на порядок расположения в них строковых символов):
(string=? string1 string2)
(string-ci=? string1 string2)
(string<? string1 string2)
(string>? string1 string2)
(string<=? string1 string2)
(string>=? string1 string2)
(string-ci<? string1 string2)
(string-ci>? string1 string2)
(string-ci<=? string1 string2)
(string-ci>=? string1 string2)
PLT Scheme разрешает использовать более двух аргументов при сравнении строк.
(string=? “12″ “15″ “gsjfds”) Результат #f
При этом более короткие строки считаются меньше длинных:
(string-ci<? “fff” “ffff”) Результат #t
Выделение подстроки:
(substring string start end)
При этом входящие параметры должны удовлетворять условию:
0 < start < end < (string-length string)
Объединение (конкатенация) строк:
(string—append string …)
(string—append “Привет ” “Мир!”) Результат “Привет Мир!”
Также важны функции преобразования строк:
(string->list string) – преобразование строки в список строковых символов
(list->string list) – преобразование списка в строку (список должен быть списком строковых символов)
(string->list string) и (list->string list) являются противоположными по отношению друг к другу.
(string-copy string) – возвращает копию строки
Векторы
Векторы в Scheme есть неоднородные структуры данных индексированные целыми числами. Одним из плюсов векторов является организация, построенная таким образом, что скорость доступа к ним выше, чем к спискам. Длина вектора есть число элементов, которые он содержит (целое точное неотрицательное число, также как и индекс любого из доступных элементов вектора). Индексация элементов вектора начинается от нуля. В общем, векторы сильно похожи на массивы императивных языков программирования, но имеют одну приятную особенность – вектор может содержать данные различных типов.
Для записи векторов используется следующая нотация: #(obj …).
#(0 (2 2 2 2) ”Anna”) Вектор, состоящий из трех элементов – числа нуль, списка (2 2 2 2) и строковой константы ”Anna”.
(vector? obj) – определяет, является ли объект вектором (#t если объект вектор).
(make—vector k) – создает вектор из k элементов, сами элементы не определены.
(make—vector k fill) – создает вектор из k элементов, элементы которого являются fill.
(vector obj …) – создает вектор из указанных объектов.
(vector ‘a ‘b ‘c) Результат #(a b c), сами элементы при этом не вычисляются (из-за одинарной кавычки).
(vector-length vector) – возвращает длину вектора (точное целое число).
(vector-ref vector k) – возвращает k-тый элемент вектора (k как и все индексы должен быть точным и целым).
(vector-ref ’#(1 1 2 3 5 8 13 21) 5) Результат 8 (нумерация от нуля).
(vector—set! vector k obj) – присваивает k-тому элементу вектора значение obj. Результат не определен, функция обладает побочными эффектами.
(vector->list vector) – создает список из вектора.
(list->vector list) – создает вектор из списка.
(vector->list ’#(dah dah didah)) Результат (dah dah didah)
(list->vector ’(dididit dah)) Результат #(dididit dah)
(vector-fill! vector fill) – заполняет указанный вектор объектами fill. Результат функции не определен, функция имеет побочные эффекты.
Особенности управления
Здесь мы опишем некоторые (не все, например, отложенные вычисления уже рассматривались) механизмы, облегчающие управление процессом выполнения.
(procedure? obj) – возвращает #t, в случае если перед нами процедура. Надо отметить, что в Scheme очень часто идет слияние понятий функция и процедура.
(procedure? car) Результат #t
(procedure? ’car) Результат #f
(procedure? (lambda (x) (* x x))) Результат #t
(procedure? ‘(lambda (x) (* x x))) Результат #f
(apply proc arg1 … args) – вызывает указанную функцию к аргументам заданным списком.
(apply + (list 3 4)) Результат 7, для функции + (плюс) задается параметр (только один), заданный в виде списка.
(map proc list1 list2 …) – применение функции proc к каждому из списков. Списки должны иметь одинаковый размер. Одна из мощнейших функций языка. Работает это следующим образом:
(map car ‘((a b) (d e) (g h))) Результат (a d g)
(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)) Результат (5 7 9)
(map + ‘(1 2 3) ‘(4 5 6) ‘(7 8 9)) Результат (12 15 18)
(define my-list ‘(1 2 3 4 5))
(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)
(vector-set! v i (* i i)))
‘(0 1 2 3 4))
v)
Результат #(0 1 4 9 16). Создаем вектор v из пяти элементов. Затем применяем (lambda (i) к вектору v. Заносим данные из списка ‘(0 1 2 3 4) (который сразу не вычисляется из-за одинарной кавычки) следующим образом: в вектор v записывается элемент списка, умноженный сам на себя (запись осуществляется посредством vector—set!, при этом в качестве индексов для доступа к вектору используется все тот же список ‘(0 1 2 3 4)). После выхода из блока let вектор v будет разрушен, а его содержимое будет передан как результат работы блока let.
PLT Scheme
Теперь немного подробней о самой IDE. PLT Scheme состоит из нескольких компонентов:
. MrEd – расширение MzScheme для графического программирования
. DrScheme – среда проектирования
. Mzc – компилятор в байт-код, не зависимый от платформы (позволяет создавать переносимые приложения)
. MzScheme3m – экспериментальная версия MzScheme, особенность которой более точное управление распределением памятью (в сравнении MzScheme).
MzScheme, основной компилятор, интерпретатор, и система поддержки исполнения программ. Кроме того, PLT Scheme, содержит в себе не только описанный выше стандарт R5RS, но также дополнительные возможности, а именно:
. система поддержки пространства имен и управления трансляцией
. поддержка механизма исключений
. приоритетные потоки
. классы и система объектов
. регулярные выражения
. расширенная поддержка макросов
. поддержка хэшей (как встроенного типа данных)
. поддержка юникода.
И более того, PLT Scheme содержит также группу диалектов Scheme, каждый из которых имеет свои задачи (например, есть диалект специально адаптированный для изучения функционального программирования студентами высших учебных заведений). Так как система построена в минималистичном и строгом стиле рекомендуется начинать изучение с DrScheme (он не так суров, и не сильно отпугивает пользователей привыкших к обилию кнопок, картинок и иконостасу на Рабочем столе). Его-то мы и рассмотрим подробней.
Как уже упоминалось ранее, DrScheme имеет два окна, одно предназначено для ввода текста программы, второй есть командный интерпретатор (команды, введенные в него, исполняются немедленно, что удобно для изучения языка). В последнее же окно выводится и сообщения от drScheme, именуемое как главная текстовая область (см. рисунок 1):
Поскольку PLT Scheme поддерживает несколько языков программирования, то прежде чем приступить к работе, нужно выбрать* соответствующий язык программирования Language|Choose Language (см. рисунок 2):
* Комментарий автора
наименование пунктов меню может немного отличаться в зависимости от версии среды разработки
Стандарт языка называется Standart (R5RS), для освоения материала статьи его вполне достаточно. Остальные диалекты отличаются различными свойствами, в том числе и поддержкой графического интерфейса пользователя. PLT Scheme запоминает последний выбранный диалект и при следующем запуске сразу же готов работать в выбранном контексте.
Изюминкой PLT Scheme является возможность компиляции текстов программ. Исторически и по ряду объективных причин большинство реализаций Scheme есть интерпретаторы. Однако готовые к употреблению программы без стороннего окружения также необходимы (что, кстати, требуют и решаемые задачи, круг которых гораздо шире в PLT Scheme, чем в голом стандарте R5RS). Чтобы получить из текста программы на языке Scheme вполне функциональный exe-файл требуется, чтобы программа была введена в окно ввода программы (обычно оно первое) (см. рисунок 3). А также чтобы она была уже сохранена во внешнем файле.
Затем выбираем пункт меню Scheme|Create Executable… Далее необходимо выбрать тип исполнения файла (см. рисунок 4):
. Launcher
. Stand-alone
. Distribution.
Для простых учебных примеров Stand—alone вполне достаточно (однако, если необходимо использовать программу на другом компьютере, то потребуется перетащить некоторые библиотеки).
Заключение
Введение дает только элементарные азы и рассчитано на плавный переход от императивного стиля к функциональному. Данное введение не дает представления о функциональном программировании – это просто справочник наиболее распространенных команд языка Scheme, также знакомство с конкретной средой разработки PLT Scheme. Более полное и подробное руководство по PLT Scheme можно найти на сайте проекта (на английском языке), статья предназначена быть отправной точкой для дальнейшего самостоятельного обучения. Дополнительно можно отметить возможность встраивания Scheme и в другие языки программирования (как встроить Scheme в Дельфи, можно узнать здесь: http://www.orlovsergei.com/Progs/Scheme/SchemeToDelphi.htm). Плюсы такого союза очевидны, например, это удобно для работы с длинной арифметикой.
Ресурсы
. Лисп как альтернатива Java http://alexey.tamb.ru/scheme/lisp-scheme-java.html
. Сайт «схемщиков» http://schemers.org
. PLT Scheme http://www.plt-scheme.org
. Дополнительные библиотеки для PLT Scheme http://planet.plt-scheme.org
. Неформальное введение в Scheme http://ru.wikibooks.org/wiki/Введение_в_язык_Scheme_для_школьников
19th
MP3 изну-три
В этой статье я расскажу, как устроен MP3 файл, и покажу, как можно работать с ним в ваших программах. Мы попробуем извлечь информацию о файле, такую как длину трека, его битрейт и частоту дискретизации. Воспроизведение звука мы рассматривать не будем, это отдельная, и я думаю намного более сложная тема…
Александр Терлецкий
by mutabor altair.79@mail.ru
Немного про формат
MP3 расшифровывается как MPEG 1 Layer 3, т.е. MPEG версии 1, третья редакция, или как-то в этом роде. Нам важно понять, что бывает еще MPEG 2, а Layer не обязательно может быть третьим. Что такое MPEG, почему Layer 3, чем отличается MPEG1 от MPEG2, и прочие подобные вопросы я рассматривать не буду, т.к. это само по себе тянет на отдельную статью. MP3 это сжатый формат, сжатие достигается за счет убирания из исходного звука частот заведомо не слышимых человеком, ну и еще за счет алгоритма сжатия какого-нибудь (это я тоже не буду здесь рассматривать). Именно поэтому сжимать архиваторами MP3 файлы не получается (вернее получается, но результат не впечатляет), они уже сжатые. Внутри файл состоит из фреймов. Заголовка у MP3 файла нет, зато у каждого фрейма есть свой заголовок, с ним то мы и будем в основном работать. Фрейм можно рассматривать, как некий дискретный кусок звукового потока.
Теги
Помимо фреймов, в файле могут быть один или несколько ID3 тегов. ID3 – это теги специально разработанные для формата MP3, т.к. он сам не содержит никакой описательной части. Теги бывают разных версий, чаще всего это или ID3v1.x или ID3v2.x. Теги первой версии находятся в последних 128 байтах файла, начинаются с символов TAG (такой тег может занимать и более чем 128 байт, но это редко, это усовершенствованная первая версия ID3). Теги второй версии могут находиться в любой части файла, но чаще они располагаются в начале файла, и начинаются с символов ID3. Теги второй версии намного более расширенные, чем теги первой версии, в них нет ограничений на длину полей с описанием трека, количество доступных полей намного больше, можно использовать Юникод, тег может содержать в себе изображение. Длина тега второй версии не фиксированная, и определяется по заголовку тега (в отличие от MP3 файла, у ID3v2 тега есть заголовок). Наличие тегов в файле не является обязательным, и их может не быть совсем, а могут быть оба, и тег первой версии в конце файла, и второй в начале, это делается в целях совместимости с большим количеством плееров. Часто возникает проблема с русскими символами в тегах в плеерах мобильных телефонах, я думаю это связано с Java машиной в телефоне, дело в том, что она поддерживает строки в формате UTF-8, а русские теги часто имеют кодировку Win-1251. Чтобы избежать «козябриков» на этих устройствах, нужно сохранять теги в Юникоде.
Теперь немного о том, как читать теги программно. Я не буду подробно освещать эту тему здесь, скажу лишь, что существуют библиотеки, компоненты для их чтения, также в сети доступна спецификация на эти теги, так что можно и самому написать их обработку, если есть желание. Звуковые движки, например тот же BASS, тоже умеют читать теги. Они кстати умеют и все остальное, о чем я буду писать ниже, и если ваша задача – получить информацию о файле, и вам не интересно как он устроен, можете в принципе дальше не читать, так как через интерфейс движка это сделать намного легче. Если вам звук нужно еще и воспроизводить, то этот способ даже лучше, зачем ковыряться в спецификациях, если есть удобный инструмент. Но бывают случаи, когда звук воспроизводить не надо, а нужна только информация о файле, и тогда лучше подключить легкий модуль, чем таскать движок за программой.
Битрейт
В этой статье я затрону только те характеристики, которые мы будем читать из файла, остальную общую информацию об MP3 можно без проблем найти в Интернете, ее достаточно, в отличие от более специализированной информации о формате.
Как вы все, наверное, знаете, MP3 файл может иметь различный битрейт, это кол-во бит выделенных на кодирование звука в единицу времени. Понятно, что чем он выше, тем качество звука лучше, и размер файла соответственно тоже больше. Значение битрейта в MP3 может находиться в пределах от 8 до 320 кбит/с. Полный список смотрите в Рис 2. Битрейт может быть постоянным (constant) и переменным (variable), это обозначается аббревиатурами CBR и VBR соответственно. Переменный битрейт позволяет снизить размер файла, не снижая качества. Это достигается за счет того, что на участках, где это не требуется, например тишина в начале трека, используется меньшее количество бит для кодирования. На уровне структуры файла это выражается в том, что один фрейм может иметь битрейт, например 128, а следующий может иметь уже 192, и т.д. В каждом отдельном фрейме битрейт имеет значение кратное степени двойки, соответствующее спецификации (см. рисунок 2). В целом по файлу, битрейт, в случае если он постоянный, не будет отличаться от значения битрейта первого фрейма, таким образом, нам достаточно взять информацию из первого фрейма, и мы имеем информацию о файле. В случае если битрейт переменный, то все усложняется, нам недостаточно одного фрейма, чтобы делать выводы об общем битрейте файла.
Частота дискретизации
Вторая характеристика, которую мы рассмотрим, это частота дискретизации или Sample Rate. Это частота, с которой при кодировании звука снимаются замеры с источника звука. Например, если частота у нас 44100 Гц, то это значит, что столько раз в секунду снимаются и сохраняются значения оригинального, аналогового звука. По сути, оцифровка. Можно конечно и уже оцифрованный звук перегнать с другим сэмпл-рейтом, но качество можно только понизить, повысить уже вряд ли удастся. Как и в случае с битрейтом, от частоты дискретизации напрямую зависит качество звука. Частота дискретизации в MP3 не может варьироваться, и всегда постоянна для всего файла.
Длина
У любой музыкальной композиции или любой другой звуковой записи есть такая характеристика, как длина. Упоминаю я ее отдельно для того, чтобы обрадовать вас, что так как у MP3 файла общего заголовка нет, то и готовые сведения о длине нам взять в принципе неоткуда (ID3 тег не в счет, в нем может быть длина трека, а может и не быть, а может и самого тега не быть). Поэтому длину нам придется высчитывать самостоятельно. На этом с характеристиками закончим и перейдем к разбору фреймов.
Рис. 1.
Фреймы
Один фрейм состоит из двух блоков (последовательностей бит) – заголовка и блока данных (см. рисунок 1). Заголовок представляет собой последовательность из 32 бит (4 байта), в которых описываются все необходимые параметры звука, а также параметры самого фрейма (например, его длина). В блоке данных находиться непосредственно звуковые данные. Рассмотрим заголовок подробнее (см. рисунок 2). Вначале идут 12 бит сигнатуры (Sync), по этим битам нужно искать фреймы, все они установлены в единицу. Затем идут еще три бита: версия, слой и защита от ошибок. Я сделал вывод, что если принять по умолчанию что мы работаем с MP3 файлом, а не с какой-нибудь другой версией MPEG, томожно брать первые два байта как сигнатуру, в этом случае они могут иметь всего две комбинации: FF FA или FF FB. Мне показалось так удобнее искать фреймы, и именно так я реализовал это в коде. Через третий байт мы пока перескочим, и я вкратце расскажу о четвертом. В нем есть такая интересная штука как режим стерео. Дело в том, что MP3 имеет еще оди н способ уменьшить вес файла, не ухудшив качество. Это режим Joint Stereo (объединенное стерео). Что же это такое? Пройдемся по порядку. Режим моно, это, как вы знаете, когда всего один звуковой канал. Стерео — это независимые левый и правый каналы. Для хранения стерео данных, необходимо ровно в два раза больше места, чем для моно. Joint Stereo же позволяет хранить два независимых канала, при этом, занимая меньше места, это достигается за счет «умной» паковки во время сжатия. Если выбран этот режим, и в данном сэмпле звука левый и правый каналы не отличаются, то кодер сохраняет только один из них, когда же каналы отличаются, то они сохраняются оба. Это в своем роде стерео по требованию, оно используется там, где это реально нужно, а где не нужно, место экономится. В четвертом байте хранится еще ряд параметров, не буду на них останавливаться, кому интересно, смотрите на рисунке, там все подписано, обычно они интереса не представляют.
Самый значимый для нас это 3-й байт заголовка. В нем содержится информация о битрейте, частоте дискретизации, установлен или нет Pad бит (определяет наличие добавочного байта в фрейме), все это вместе взятое позволяет нам высчитать размер этого фрейма. Размер фрейма высчитывается по формуле 1:
144 * BitRate / SampleRate + Pad; (1)
Рис. 2.
Если Pad бит равен единице то и в формулу подставляем единицу, если нулю – подставляем нуль. Битрейт и частоту подставляем в их полном виде, без округлений, битрейт в битах, а частоту в герцах. В файлах к этой статье вы найдете пример извлечения нужной информации из заголовка фрейма и реализацию этой формулы на языке Delphi. Чтобы что-то извлечь из заголовка, его нужно сначала найти, это тоже там есть. На самом деле достаточно найти первый фрейм, позицию каждого следующего мы уже будем знать, прибавляя к позиции текущего фрейма его длину.
Теперь поговорим о том, как найти переменный битрейт и длину трека. С постоянным битрейтом все ясно, он одинаковый для всего файла, и его можно взять из первого фрейма. С переменным не так. Во-первых, нигде не написано что он переменный, и чтобы это определить, нужно прочесть больше чем один фрейм. Я пошел самым простым путем, и читаю два первых фрейма. Если битрейт у них одинаковый я считаю что битрейт постоянный, если разный то переменный. Это скорее всего не точно, ведь переменным он может стать и после второго фрейма. Однозначных рекомендаций по этому вопросу я не встречал, возможно, есть соглашение, что если битрейт переменный, обязательно кодировать первые два фрейма с различным битрейтом, я бы так и сделал на месте разработчиков, но это только мои предположения. Если у вас есть более точная информация на этот счет, оставляйте комментарии к статье на сайте журнала, интересно будет почитать. Понятно, что в случае переменного битрейта необходимо как-то высчитать его среднее значение по всем фреймам. Оставлю это вам, у меня в коде в этом месте стоит заглушка, т.е. просто в случае переменного битрейта, в качестве его значения присваивается ноль.
Заключение
Теперь про длину трека. Ее можно высчитать, поделив размер файла (за вычетом тегов и прочего мусора, нужны только фреймы, не совсем ясно только, включать заголовки или нет) на битрейт, если он постоянный. Таким образом, мы получим длину трека в секундах. Если битрейт переменный, этот способ не подходит (хотя можно на усредненный битрейт поделить), тогда мы можем задействовать сэмпл-рейт, он у нас постоянный для всего файла, и представляет собой кол-во сэмплов в секунду. Если предположить что сэмпл и фрейм это одно и то же, то можно узнать количество секунд в треке, посчитав все фреймы. Я не пробовал ни тот, ни другой способ, не буду портить вам удовольствие и позволю самим попробовать высчитать длину трека. Если что интересное получится, пишите в комментариях. Опять же, можно переменный битрейт считать от обратного, найти по сэмпл- рейту длину, и потом уже одним действием найти средний битрейт.
Все исходные коды, упомянутые в статье, приложены непосредственно к журналу «ПРОграммист. Пятый выпуск».
На этом закончим, спасибо за внимание, читайте наш журнал.
Статья из пятого выпуска журнала «ПРОграммист».
Скачать этот номер можно по ссылке.
Ознакомиться со всеми номерами журнала.
17th
Авг
Microsoft предупреждает о случаях эксплуатации новой бреши в Windows XP/Vista/7
Microsoft предупреждает о случаях эксплуатации новой бреши в Windows XP/Vista/7 связанную с инфицированными USB-накопителями. В описании, размещенном на сайте Microsoft, говорится, что хакеры используют данную уязвимость уже около месяца. Уязвимость проявляется
в том, что ОС Windows обычно работает с файлами-ярлыками, которые традиционно размещаются на Рабочем столе или в меню Пуск системы и как правило эти ярлыки указывают на конкретные локальные файлы или программы.
Методика заражения
Вы должны принять во внимание, что этот вирус заражает систему необычным путем (без файла autorun..inf), через уязвимость в lnk-файлах. Так вы открываете зараженную флешку с помощью проводника или другого менеждера способного отображать иконки (например TotalCommander) и запускаете вирус, компьютер заражен. Ниже на скриншоте вы можете увидеть содержимое флешки FAR (он не заражает систему):
На скриншоте вы можете видеть что в корне USB-устройства располагаются два tmp файла (на самом деле они приложения) и 4 файла lnk. Следующий скриншот демонстрирует содержимое lnk файлов
Операционная система Windows 7 Enterprise Edition x86 со всеми последними обновлениями также уязвима, из чего следует вывод что уязвимость присутствует и в предыдущих версиях.
Процесс заражения и скрытия в системе
Процесс заражения развивается по следующему пути:
1. Два файла (mrxnet.sys и mrxcls.sys, один из них действует как драйвер-фильтр файловой системы, а второй включает в себя вредоносный код) располагаются в директории %SystemRoot%\System32\drivers. Ниже представлен скриншот программы GMER отображающей вирусные драйверы.
Данные драйверы подписаны (имеют цифровые подписи) Realtek Semiconductor Corp. Файлы mrxnet.sys и mrxcls.sys также добавлены в вирусные базы VirusBlokAda как Rootkit.TmpHider
(http://www.virustotal.com/ru/analisis/0d8c2bcb575378f6a88d17b5f6ce70e794a264cdc8556c8e812f0b5f9c709198-1278584497) и Scope.Rookit.TmpHider.2 (http://www.virustotal.com/ru/analisis/1635ec04f069ccc8331d01fdf31132a4bc8f6fd3830ac94739df95ee093c555c-1278661251) соотвественно.
2. Два файла (oem6c.pnf и oem7a.pnf, содержимое которых зашифровано) располагаются в папке %SystemRoot%\inf .
Вирус запускается сразу после заражения, так что перезагрузка не требуется.
Драйвер-фильтр скрывает файлы ~wtr4132.tmp и ~wtr4141.tmp и соответствующие lnk файлы. Поэтому пользователя не заметят новый файлах на USB-устройстве. . Vba32 AntiRootkit (http://anti-virus.by/en/beta.shtml) детектирует вирусные модули свежующим образом:
3. Также руткит добавляет потоки в системные процессы, и в тоже время прячет модули которые запускаются в потоках. Антируткит GMER фиксирует следующие аномалии:
4. Руткит устанавливает ловушки в системных процессах
Предпосылки эксплуатации уязвимости:
Успешность эксплуатации уязвимости и последствия зависят от конфигурации вашего компьютера:
• Атакующий, который успешно поэксплуатировал уязвимость получает права того локального пользователя под чьей учетной записью производилась эксплуатации. Пользователи сидящие под ограниченной четкой понесут меньший урон, чем те что имеют права администратора.
• Когда автозапуск выключен, пользователя самому придется открыть проводником или другой программой корень переносного устройства (флешки).
• Закрыв доступ к сетевым папкам с помощью фаервола вы предотвратите риск эксплуатации уязвимости через расшаренные ресурсы.
Защита
Данные советы не исправят уязвимость, но они помогут снизить риск успешность эксплуатации уязвимости до времени выхода заплатки. Майкрософт протестила данные советы и ответственно заявляет что они помогают.
• Отключение отображения иконок ярлыков
1. Пуск- Выполнить, в открывшемся окошке написать Regedit, нажать ОК.
2. Пройти в данную ветку реестра
HKEY_CLASSES_ROOT\lnkfile\shellex\IconHandler
3. Щелкните File (Файл) в меню и выберите Export (Экспорт)
4. В окне экспорта введите LNK_Icon_Backup.reg и нажмите Save (Сохранить)
Этими действиями вы создали резервную копию ключей реестра.
5. Выберите параметр Default в правой стороне окна Редактора реестра. Нажмите Enter чтобы отредактировать значение. Удалите значение, т.е. поле станет пустым, нажмите Enter.
6. Перезапустите процесс explorer.exe или перезагрузите компьютер.
Проверка результата. Отключение иконок на ярлыках защитит от эксплуатации уязвимости на уязвимой системе. Когда вы проделаете эти действия то иконки ярлыков и IE перестанут отображаться.
• Отключение службы WebClient.
Отключение службы WebClient поможет защитить уязвимую систему от атаки путем блокирования удаленной атаки через сервис Web Distributed Authoring and Versioning (WebDAV). После произведения данных действий, останется возможность для удаленной атаки и успешной эксплуатации уязвимости связанной с Microsoft Office Outlook и запуском программ на атакуемой машине пользователей сети (LAN), но при этом пользователь получит предупреждение о попытке запуска программ из интернет.
Для выключения службы WebClient воспользуйтесь следящими пунктами:
1. Пуск-Выполнить, впишите Services.msc и нажмите ОК.
2. Правой кнопкой щелкните по службе WebClient и выберите свойства.
3. Измените тип запуска на Отключено. Если эта служба запущена, то нажмите Стоп (остановить) .
4. Нажмите ОК и закройте приложение.
Проверка результата. Когда вы отключите службу WebClient, престанут посылаться запросы Web Distributed Authoring and Versioning (WebDAV), и любая служба зависящая от WebClient также не будет запускаться. Пока в корпорации не говорят, когда будет выпущено исправление. Пока же же пользователи могут защищаться путем отключения отображения ярлыков на съемных носителях или за счет отключения сервиса WebClient. Оба метода выполняются через реестр Windows.
Интересные факты с пятого выпуска журнала “ПРОграммист”.
Скачать этот номер можно по ссылке.
Ознакомиться со всеми номерами журнала.
17th
Каждому российскому участковому – личную страничку в Интернет
Каждый российский участковый обзаведется личной интернет-страничкой, где будут размещены его персональные и контактные данные. За счет «интернетизации» участковых МВД хочет повысить качество обратной связи между населением и милицией. Однако за счет каких средств будут созданы более 54 тыс. сайтов, пока не понятно.
В России под лозунгом «Безопасность начинается с доверия» стартовала акция, в рамках которой каждый участковый уполномоченный милиции обязан будет завести собственную интернет-страницу. На персональном сайте участкового будет размещена информация о нем самом: его фотография, биография, контактные данные. Кроме того, на сайте появятся данные о курируемых участковым районах, часах приема и контактах руководства и надзорных органов, фото людей, находящихся в розыске или пропавших без вести, и другого рода полезная информация.
Такие сайты будут содержать интерактивные разделы, где граждане смогут задать участковому вопрос. Появится и раздел «Добровольный помощник», где можно будет сообщить о правонарушении, в том числе и анонимно. По задумке МВД, создание персональных сайтов для участковых должно простимулировать социальную активность граждан.
Сегодня в России работают более 54 тыс. участковых. Согласно рекомендации МВД, в городах участковый инспектор должен обслуживать 4—5 тыс., в сельской местности — 3—4 тыс. человек. В настоящий момент средняя зарплата участкового составляет 12 тыс. руб. В ходе реформы МВД к 2012 году ее планируется увеличить втрое.
Средняя стоимость создания простенького сайта в Москве составляет около 10 тыс. руб. Таким образом, только на первоначальный этап «интернетизации» корпуса участковых понадобится более 540 млн руб. Плюс немалые средства потребуются для дальнейшей поддержки сайтов. Где министерство возьмет более чем полмиллиарда рублей, источник РБК daily в МВД ответить затруднился: «Возможно, это будет происходить постепенно, пока же таких средств нигде не заложено». Получить официальный комментарий в МВД не удалось.
«Идея очень здравая, ведь сегодня своего участкового знают в лицо только гиперактивные бабушки, — считает юрист Альберт Феоктистов. — Количество пользователей Интернета постоянно множится, особенно в больших городах, и многие уже привыкли за любой информацией обращаться в Сеть. Такие сайты позволят гораздо большему количеству граждан узнать своего участкового».
Интересные факты с пятого выпуска журнала “ПРОграммист”.
Скачать этот номер можно по ссылке.
Ознакомиться со всеми номерами журнала.
16th
Авг
Как заблокировать раздел жесткого диска от записи?
Raxp:
Лично использую уже упоминавшееся на форуме создание папки Autorun.inf c LPT:
rem Антивирусный скрипт NOAUTORUN_FLASH.BAT version 1.8.1 (MOD 2010)
attrib -s -h -r autorun.*
del autorun.*
mkdir "\\?\%~d0\AUTORUN.INF\LPT3"
attrib +s +h %~d0\AUTORUN.INF
@echo off
echo Каталог AUTORUN.INF, созданный на флешке, препятствует заражению флешки autorun-вирусами. > AUTORUN.INF\readme.txt
echo Чтобы самостоятельно обезопасить другую флешку, перепишите на нее файл NOAUTORUN_FLASH.BAT и запустите его. После чего файл можно удалить. >> AUTORUN.INF\readme.txt
copy noautorun_flash.BAT AUTORUN.INF\NOAUTORUN_FLASH.BAT
и упомянутую сервисную утилиту, в частности под мою флешь AU6981-6982-6983 v6.21 [20071227]
позволяющую не только разбить на несколько дисков, но и поставить парольную защиту.
12th
Авг
Авторасширение Memo
var
Form1: TForm1;
i:Integer;
implementation
{$R *.dfm}
procedure TForm1.memo1KeyDown(Sender: TObject; var Key: Word;
Shift: TShiftState);
begin
if memo1.Lines.Count>i then
begin
memo1.Height:=memo1.Height+15;
memo1.Top:=memo1.Top-15;
i:=i+1;
end;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
i:=1;
memo1.DoubleBuffered:=True;
end;
Облако меток
css реестр ассемблер timer SaveToFile ShellExecute программы массив советы word MySQL SQL ListView pos random компоненты дата LoadFromFile form база данных сеть html php RichEdit indy строки Win Api tstringlist Image мысли макросы Edit ListBox office C/C++ memo графика StringGrid canvas поиск файл Pascal форма Файлы интернет Microsoft Office Excel excel winapi журнал ПРОграммист DelphiКупить рекламу на сайте за 1000 руб
пишите сюда - alarforum@yandex.ru
Да и по любым другим вопросам пишите на почту
пеллетные котлы
Пеллетный котел Emtas
Наши форумы по программированию:
- Форум Web программирование (веб)
- Delphi форумы
- Форумы C (Си)
- Форум .NET Frameworks (точка нет фреймворки)
- Форум Java (джава)
- Форум низкоуровневое программирование
- Форум VBA (вба)
- Форум OpenGL
- Форум DirectX
- Форум CAD проектирование
- Форум по операционным системам
- Форум Software (Софт)
- Форум Hardware (Компьютерное железо)