Содержание Введение ................................................................................................................... 2 1 Постановка задачи................................................................................................ 3 2 Кодирование информации и ее значение ........ Error! Bookmark not defined. 3 Проектирование интерфейса в среде Borland C++ Builder .............................. 9 4 Структура программы ........................................................................................ 10 5 Инструкция пользователя.................................................................................. 11 6 Текст программы ................................................................................................ 17 Заключение ............................................................................................................ 21 Список использованной литературы ................................................................... 22 Введени е Программы, написанные на C++, уступают в скорости только созданным на языке Ассемблера. Да и сам C задумывался как некий Ассемблер высокого уровня, поэтому работающему в нем программисту открыты возможности, которых не найти в других языках. Прежде всего это касается управления памятью, адресации и работы с низкоуровневыми функциями. C++ является объектно-ориентированным расширением C, и объектного программирования превратился в наиболее мощное средство для разработки самых разнообразных программ. Поскольку C++ - системный язык Windows, программисту, владеющему этим языком, гораздо легче освоить программирование с помощью API Win32, а значит, получить доступ к огромным возможностям, предоставляемым интерфейсом прикладного программирования (API) Windows 95(98) и Windows NT. За время существования C++ написано огромное количество приложений и программных модулей, доступных к использованию в вашем приложении. На основе этого языка создан Java, а как известно, сетевое программирование относится к наиболее перспективным отраслям, специалисты которых всегда ценятся работодателями. Программирование на C++ закономерно считается признаком высокого класса. C++ обладает также и недостатками. Язык чрезмерно сложен. Это признают все без исключения. Он сложен для изучения и в использовании – программист должен точно знать, что и как происходит при выполнении того или иного оператора. Насколько легко и непринужденно можно оперировать строками в Паскале, настолько же это затруднительно в C++. Строки здесь представляются не в виде отдельного типа, а как массивы знаков. Отсюда – сложность с любыми операциями над ними. Характерно, что использование массивов также непросто. В C++ отсутствуют средства для проверки границ массива, и там, где в Паскале вы получили бы предупреждение компилятора, в C++ ничего не произойдет, вплоть до тех пор, пока вместо нужных вам данных вы не получите неизвестный "мусор". 2 1 По ст ановка за дачи Основной задачей курсового проекта является разработка просмотрщика различных кодировок, основанную на файлах-локалях (locale). База данных может включать справочники, которые отражали бы всю информацию о клиентах, данные о товарах и т.д. Логика работы с различными кодировками в C++ проста и прозрачна. В общем виде она отражена в схеме. Программа работает в одной — своей внутренней кодировке, а правильно локализованные потоки отвечают за преобразование кодировки данных из внешнего кода во внутренний и обратно. Внутреннюю кодировку программы лучше всего зафиксировать раз и навсегда. Если программа работает с не-ASCII символами, то самый логичный выбор для внутренней кодировки — Юникод, причём использование UTF-8 и char для параметризации STL как правило неоправданно (хотя существуют ситуации, в которых это необходимо); более логично перейти на расширенные символы wchar_t и использовать UCS-2. За преобразование данных из внешней кодировки во внутреннюю отвечает фасет codecvt. Локализованные потоки сами вызовут соответствующие функции фасета при получении данных. Целью создания курсовой работы является разработка программыпросмотрщика текста в различных кодировках. 2 Коди рова ние и нформаци и и ее значен ие Развитие кодировок текстов происходило одновременно с формированием отрасли IT, и они за это время успели претерпеть достаточно много изменений. Исторически все начиналось с довольно-таки не благозвучной в русском произношении EBCDIC, которая позволяла кодировать буквы латинского алфавита, арабские цифры и знаки пунктуации с управляющими символами. Но все же отправной точкой для развития современных кодировок текстов стоит считать знаменитую ASCII (American Standard Code for Information Interchange, которая по-русски обычно произносится как «аски»). Она описывает первые 128 символов из наиболее часто используемых англоязычными пользователями — латинские буквы, арабские цифры и знаки препинания. Еще в эти 128 знаков, описанных в ASCII, попадали некоторые служебные символы навроде скобок, решеток, звездочек и т.п. Именно эти 128 символов из первоначального вариант ASCII стали стандартом, и в любой другой кодировке вы их обязательно встретите и 3 стоять они будут именно в таком порядке. Но дело в том, что с помощью одного байта информации можно закодировать не 128, а целых 256 различных значений (двойка в степени восемь равняется 256), поэтому вслед за базовой версией Аски появился целый ряд расширенных кодировок ASCII, в которых можно было кроме 128 основных знаков закодировать еще и символы национальной кодировки (например, русской). Тут, наверное, стоит еще немного сказать про системы счисления, которые используются при описании. Во-первых, как вы все знаете, компьютер работает только с числами в двоичной системе, а именно с нулями и единицами («булева алгебра», если кто проходил в институте или в школе). Один байт состоит из восьми бит, каждый из которых представляет из себя двойку в степени, начиная с нулевой, и до двойки в седьмой (рис. 1). Рис. 1 – 8-битная система кодирования Не трудно понять, что всех возможных комбинаций нулей и единиц в такой конструкции может быть только 256. Переводить число из двоичной системы в десятичную довольно просто. Нужно просто сложить все степени двойки, над которыми стоят единички. Зачем вообще нужны кодировки текстов и почему это так важно. Символы на экране вашего компьютера формируются на основе двух вещей — наборов векторных форм (представлений) всевозможных знаков (они находятся в файлах со шрифтами, которые установлены на вашем компьютере) и кода, который позволяет выдернуть из этого набора векторных форм (файла шрифта) именно тот символ, который нужно будет вставить в нужное место. Понятно, что за сами векторные формы отвечают шрифты, а вот за кодирование отвечает операционная система и используемые в ней программы. Т.е. любой текст на вашем компьютере будет представлять собой набор байтов, в каждом из которых закодирован один единственный символ этого самого текста. Программа, отображающая этот текст на экране (текстовый редактор, браузер и т.п.), при разборе кода считывает кодировку очередного знака и ищет соответствующую ему векторную форму в нужном файле шрифта, который подключен для отображения данного текстового документа. Все 4 просто и банально. Значит, чтобы закодировать любой нужный нам символ (например, из национального алфавита), должно быть выполнено два условия — векторная форма этого знака должна быть в используемом шрифте и этот символ можно было бы закодировать в расширенных кодировках ASCII в один байт. Поэтому таких вариантов существует целая куча. Только лишь для кодирования символов русского языка существует несколько разновидностей расширенной Аски. Например, изначально появилась CP866, в которой была возможность использовать символы русского алфавита и она являлась расширенной версией ASCII (рис. 2). Рис. 2 – Кодировка CP866 CP866 распространяла компания IBM, но кроме этого для символов русского языка были разработаны еще ряд кодировок, например, к этому же типу (расширенных ASCII) можно отнести KOI8-R (рис. 3). 5 Рис. 3 – Кодировка KOI8-R Принцип ее работы остался тот же самый, что и у описанной чуть ранее CP866 — каждый символ текста кодируется одним единственным байтом. На скриншоте показана вторая половина таблицы KOI8-R, т.к. первая половина полностью соответствует базовой Аски, которая показана на первом скриншоте в этой статье. Среди особенностей кодировки KOI8-R можно отметить то, что русские буквы в ее таблице идут не в алфавитном порядке, как это, например, сделали в CP866. Из-за такого обилия кодировок русского языка, у производителей шрифтов и производителей программного обеспечения постоянно возникала путаница. Зачастую на сайтах у пользователей веб-ресурсов вылезали те самые пресловутые кракозябры, когда происходила путаница с используемой в тексте версией. Очень часто они вылезали при отправке и получении сообщений по электронной почте, что повлекло за собой создание очень сложных перекодировочных таблиц, которые, собственно, решить эту проблему в корне не смогли, и зачастую пользователи для переписки использовали транслит латинских букв, чтобы избежать пресловутых кракозябров при использовании русских кодировок подобных CP866, KOI8-R или Windows 1251. По сути, кракозябры, вылазящие вместо русского текста, были результатом некорректного использования кодировки данного языка, которая не соответствовала той, в которой было закодировано текстовое сообщение изначально. Допустим, если символы, закодированные с помощью CP866, попробовать отобразить, используя кодовую таблицу Windows 1251, то эти 6 самые кракозябры (бессмысленный набор знаков) и вылезут, полностью заменив собой текст сообщения (рис. 4). Рис. 4 – Сайт с неверной кодировкой Аналогичная ситуация очень часто возникает при создании и настройке сайтов, форумов или блогов, когда текст с русскими символами по ошибке сохраняется не в той кодировке, которая используется на сайте по умолчанию, или же не в том текстовом редакторе, который добавляет в код отсебятину не видимую невооруженным глазом. В конце концов такая ситуация с множеством кодировок и постоянно вылезающими кракозябрами многим надоела, появились предпосылки к созданию новой универсальной вариации, которая бы заменила собой все существующие и решила бы, наконец, на корню проблему с появлением не читаемых текстов. Кроме этого существовала проблема языков подобных китайскому, где символов языка было гораздо больше, чем 256. Эти тысячи знаков языковой группы юго-восточной Азии никак невозможно было описать в одном байте информации, который выделялся для кодирования символов в расширенных версиях ASCII. В результате был создан консорциум под названием Юникод (Unicode — Unicode Consortium) при сотрудничестве многих лидеров IT индустрии (те, кто производит софт, кто кодирует железо, кто создает шрифты), которые были заинтересованы в появлении универсальной кодировки текста. Первой вариацией, вышедшей под эгидой консорциума Юникод, была UTF 32. Цифра в названии кодировки означает количество бит, которое используется для кодирования одного символа. 32 бита составляют 4 байта информации, которые понадобятся для кодирования одного единственного знака в новой универсальной кодировке UTF. В результате чего, один и тот же файл с текстом, закодированный в расширенной версии ASCII и в UTF-32, в последнем случае будет иметь 7 размер (весить) в четыре раза больше. Это плохо, но зато теперь у нас появилась возможность закодировать с помощью ЮТФ число знаков, равное двум в тридцать второй степени (миллиарды символов, которые покроют любое реально необходимое значение с колоссальным запасом). Но многим странам с языками европейской группы такое огромное количество знаков использовать в кодировке вовсе и не было необходимости, однако при задействовании UTF-32 они ни за что ни про что получали четырехкратное увеличение веса текстовых документов, а в результате и увеличение объема интернет трафика и объема хранимых данных. Это много, и такое расточительство себе никто не мог позволить. В результате развития Юникода появилась UTF-16, которая получилась настолько удачной, что была принята по умолчанию как базовое пространство для всех символов, которые у нас используются. Она использует два байта для кодирования одного знака. В операционной системе Windows вы можете пройти по пути «Пуск» — «Программы» — «Стандартные» — «Служебные» — «Таблица символов». В результате откроется таблица с векторными формами всех установленных у вас в системе шрифтов. Если вы выберете в «Дополнительных параметрах» набор знаков Юникод, то сможете увидеть для каждого шрифта в отдельности весь ассортимент входящих в него символов (рис. 5). Кстати, щелкнув по любому из них, вы сможете увидеть его двухбайтовый код в формате UTF-16, состоящий из четырех шестнадцатеричных цифр: Рис. 5 – Таблица символов 8 Для удовлетворения всех и вся в консорциуме Unicode было решено придумать кодировку переменной длины. Ее назвали UTF-8. Несмотря на восьмерку в названии, она действительно имеет переменную длину, т.е. каждый символ текста может быть закодирован в последовательность длиной от одного до шести байт. На практике же в UTF-8 используется только диапазон от одного до четырех байт, потому что за четырьмя байтами кода ничего уже даже теоретически невозможно представить. Все латинские знаки в ней кодируются в один байт, так же как и в старой доброй ASCII. Что примечательно, в случае кодирования только латиницы, даже те программы, которые не понимают Юникод, все равно прочитают то, что закодировано в UTF-8. Т.е. базовая часть Аски просто перешла в это детище консорциума Unicode. Кириллические же знаки в UTF-8 кодируются в два байта, а, например, грузинские — в три байта. Консорциум Юникод после создания UTF 16 и 8 решил основную проблему — теперь у нас в шрифтах существует единое кодовое пространство. И теперь их производителям остается только исходя из своих сил и возможностей заполнять его векторными формами символов текста. 3 Про ек ти рован ие ин терфейс а в среде Bo rland C++ Builder Прежде всего, необходимо указать язык интерфейса для команд меню, кнопок панелей инструментов и выводимых сообщений (первоначально языком интерфейса является английский язык). Для изменения интерфейса в меню Tools (Сервис) надо выбрать команду Environment Options (Параметры среды) и во вкладке Interface (Интерфейс) диалогового окна этой команды из раскрывающегося списка поля Language (Язык) задать язык интерфейса. Стандартная библиотека языка C разбита по группам функций, например, математические функции, функции ввода-вывода и т.д. Вызов необходимой для использования в конкретной программе группы функций осуществляется по директиве препроцессора #include, имеющий следующий формат: #include <головной-файл> где головной-файл – имя головного файла для группы функций (например, math.h для математических функций). Функции ввода-вывода определены в головном файле <stdio.h>. Функции работы с таблицами кодов расположены в <windows.h>. Функции работы со стандартными библиотеками кодирования 9 <stdlib.h>. Окончательный вид программы показан на рис. 6. Рис. 6 – Окно C++ Builder 4 Ст ру к ту ра п ро грам мы При проектировании программы были использованы следующие компоненты среды программирования: Label Используется для размещения на формах и других контейнерах текста, метка который не изменяется пользователем. Компонент визуальный. LabeledEdit Используется для ввода пользователем однострочных текстов. окно Может использоваться для редактирования отображения текста. Является совмещением компонентов Label и Edit. Компонент визуальный. GroupBox Является контейнером, объединяющим группу связанных групповое окно органов управления, таких как радиокнопки RadioButton, контрольные индикаторы Checkbox и т.д. Компонент визуальный. Panel Является контейнером для группирования органов управления и панель меньших контейнеров. Панель можно 10 использовать также для построения полос состояния, инструментальных панелей, палитр инструментов. Компонент визуальный. отобразить список список ComboBox Позволяет значений определенного поля. значений Компонент визуальный. OpenDialog Компонент delphi OpenDialog не визуальный компонент Диалог открытия предназначенный для поддержки операции открытия файлов способный работать с любыми типами файлов. При обращении к этому компоненту вызывается стандартное диалоговое окно открытия файла. Типы искомых файлов задаются в свойстве Filter. Memo Предназначен для вывода на экран нескольких строк текста. Текст Текстовый хранится в свойстве Lines класса редактор TStrings и, таким образом, представляет собой пронумерованный набор строк (нумерация начинается с нуля). Далее описаны функции пользователя, предназначенные для обработки базы данных и управлением программой. Функция ButtonClick Назначение: в основном – вызов операции кодирования текста и закрытие программы. 5 Ин ст рук ци я поль зовател я Обращение к программе осуществляется командой CODING или запуск производится из среды Windows стандартными средствами. Установка программы производится как в отдельный каталог, так и в каталог с программами аналогичного назначения. Чтобы начать работать необходимо: открыть папку Мой Компьютер; 11 выбрать диск на котором расположена программа; найти папку с программой и открыть ее; запустить файл Coding.exe или открыть окно Проводника; выбрать диск на котором расположена программа; найти папку с программой и открыть ее; запустить файл Coding.exe После запуска на экране монитора компьютера появляется главное окно программы (рис. 7). Рис. 7 – Главное окно программы В верхней части окна находятся кнопки, позволяющие выполнять основные функции просмотрщика. 1.При нажатии Кодировать по умолчанию появляются диалоговые окна, осуществляющие обработку ошибок ввода («защита от дурака»). Если нажать без указания типа кодировки и без указанных галочек вывода (или без введенного текста в поле Мемо), то программа выдаст окна, уведомляющие об ошибке. 12 Рис. 8 – Ошибки ввода 2.Продолжим работу с программой. Просмотрщик работает в четырех режимах: 1)Галочка «Загрузить из файла» не указана, галочка «Сохранение в файл» не указана. Текст для кодирования следует вставить в текстовое поле 1 и выбрать в выпадающем меню исходную кодировку, а в выпадающем меню ниже указать кодировку назначения. Далее нажать Кодировать. Кодированный текст занесется в текстовое поле 2 (см. рис. 9). 13 Рис. 9 – Результат работы программы в первом режиме 2) Галочка «Загрузить из файла» не указана, галочка «Сохранение в файл» указана. Текст для кодирования следует вставить в текстовое поле 1 и выбрать в выпадающем меню исходную кодировку, а в выпадающем меню ниже указать кодировку назначения. Далее нажать Кодировать. Кодированный текст занесется в файл (указанный в текстовом поле сверху, по умолчанию – coding.txt), расположенный в корневом каталоге программы. 3) Галочка «Загрузить из файла» указана, галочка «Сохранение в файл» не указана. Текст для кодирования выбирается из диалогового окна открытия файла (рис. 10). 14 Рис. 10 – Диалоговое окно открытия До этого следует лишь указать исходную и конечные кодировки. Далее нажать Кодировать. Кодированный текст занесется в текстовое поле 2 (рис. 11). Рис. 11 – Результат обратной кодировки в 1251 15 4) Галочка «Загрузить из файла» указана, галочка «Сохранение в файл» указана. Текст для кодирования выбирается из диалогового окна открытия файла. До этого следует лишь указать исходную и конечные кодировки. Далее нажать Кодировать. Кодированный текст занесется в файл (указанный в текстовом поле сверху, по умолчанию – coding.txt), расположенный в корневом каталоге программы. 3.Выход из программы осуществляется при нажатии кнопки Выход. 4.Результаты работы кодировки текста (табл. 1) и цифровых данных (табл. 2) представлены ниже. Таблица 1 – Кодировка текста Кодировка Кодированный текст 1251 Информатика чудесная 1250 ??????????? ???????? KOI8-R йОЖПТНБФЙЛБ ЮХДЕУОБС CP866 €­д®а¬ вЁЄ з㤥᭠п UTF-8 Р˜РЅС„РѕСЂРјР°С‚РёРєР° чудесная UTF-7 +BBgEPQREBD4EQAQ8BDAEQgQ4BDoEMA+BEcEQwQ0BDUEQQQ9BDAETwSYMBOL OEM €­д®а¬ вЁЄ з㤥᭠п MAC €нформатика чудеснаЯ MS-DOS ENG ??????????? ???????? Таблица 2 – Кодировка цифр Кодировка 1251 1250 KOI8-R CP866 UTF-8 UTF-7 SYMBOL OEM MAC MS-DOS ENG Кодированный текст 125+275=400 125+275=400 125+275=400 125+275=400 125+275=400 125+-275+AD0-400 125+275=400 125+275=400 125+275=400 16 6 Текст п ро грам мы #include <vcl.h> #include <windows.h> #include <stdio.h> #include <stdlib.h> #pragma hdrstop #include "Unit1.h" //--------------------------------------------------------------------------#pragma package(smart_init) #pragma resource "*.dfm" TForm1 *Form1; //--------------------------------------------------------------------------__fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner) {} LPSTR xcode(LPCSTR src, UINT srcCodepage, UINT dstCodepage) { int wsize = MultiByteToWideChar(srcCodepage, 0, src, -1, NULL, 0); LPWSTR wbuf = (LPWSTR)malloc(wsize*sizeof(WCHAR)); MultiByteToWideChar(srcCodepage, 0, src, -1, wbuf, wsize); int size = WideCharToMultiByte(dstCodepage, 0, wbuf, -1, NULL, 0, NULL, NULL); LPSTR buf = (LPSTR)malloc(size); WideCharToMultiByte(dstCodepage, 0, wbuf, -1, buf, size, NULL, NULL); free(wbuf); return buf; } //Кодирование void __fastcall TForm1::Button1Click(TObject *Sender) { //Обработка ошибок ввода if(ComboBox1->Text==""){MessageDlg("Выберите кодировку исходного текста", mtError, TMsgDlgButtons()<<mbOK, 0);abort;} if(ComboBox2->Text==""){MessageDlg("Выберите кодировку конечного текста", mtError, TMsgDlgButtons()<<mbOK, 0);abort;} if(CheckBox1->Checked==false){ if(Memo1->Lines->Text==""){MessageDlg("Введите исходный текст", mtError, TMsgDlgButtons()<<mbOK, 0);abort;} } 17 //обработка таблицы кодов UINT cod1, cod2; if(ComboBox1->ItemIndex==0){cod1=1251;} if(ComboBox1->ItemIndex==1){cod1=1250;} if(ComboBox1->ItemIndex==2){cod1=20866;} if(ComboBox1->ItemIndex==3){cod1=866;} if(ComboBox1->ItemIndex==4){cod1=65001;} if(ComboBox1->ItemIndex==5){cod1=65000;} if(ComboBox1->ItemIndex==6){cod1=42;} if(ComboBox1->ItemIndex==7){cod1=1;} if(ComboBox1->ItemIndex==8){cod1=2;} if(ComboBox1->ItemIndex==9){cod1=437;} //-------------if(ComboBox2->ItemIndex==0){cod2=1251;} if(ComboBox2->ItemIndex==1){cod2=1250;} if(ComboBox2->ItemIndex==2){cod2=20866;} if(ComboBox2->ItemIndex==3){cod2=866;} if(ComboBox2->ItemIndex==4){cod2=65001;} if(ComboBox2->ItemIndex==5){cod2=65000;} if(ComboBox2->ItemIndex==6){cod2=42;} if(ComboBox2->ItemIndex==7){cod2=1;} if(ComboBox2->ItemIndex==8){cod2=2;} if(ComboBox2->ItemIndex==9){cod2=437;} //-------из Мемо1 в Мемо 2------------if(CheckBox1->Checked==false & CheckBox2->Checked==false){ Memo2->Lines->Clear(); LPSTR p; TStringList *list1 = new TStringList; p = xcode(Memo1->Lines->GetText(), cod1, cod2); AnsiString temp = p; list1->Add(temp); Memo2->Lines->Add(list1->GetText()); delete list1; free(p); } //--------------------------------------//-------из Мемо1 в файл------------if(CheckBox1->Checked==false & CheckBox2->Checked==true){ Memo2->Lines->Clear(); 18 LPSTR p; AnsiString file = Edit1->Text; TStringList *list1 = new TStringList; p = xcode(Memo1->Lines->GetText(), cod1, cod2); AnsiString temp = p; list1->Add(temp); list1->SaveToFile(file); delete list1; free(p); } //--------------------------------------//-------из Файла в Memo2------------if(CheckBox1->Checked==true & CheckBox2->Checked==false){ Memo2->Lines->Clear(); LPSTR p; OpenDialog1->Execute(); TStringList *list1 = new TStringList; TStringList *list2 = new TStringList; list2->LoadFromFile(OpenDialog1->FileName); p = xcode(list2->GetText(), cod1, cod2); AnsiString temp = p; list1->Add(temp); Memo2->Lines->Add(list1->GetText()); delete list1; free(p); } //--------------------------------------//-------из Файла в файл------------if(CheckBox1->Checked==true & CheckBox2->Checked==true){ Memo2->Lines->Clear(); LPSTR p; OpenDialog1->Execute(); AnsiString file = Edit1->Text; TStringList *list1 = new TStringList; TStringList *list2 = new TStringList; list2->LoadFromFile(OpenDialog1->FileName); p = xcode(list2->GetText(), cod1, cod2); AnsiString temp = p; list1->Add(temp); list1->SaveToFile(file); delete list1; 19 free(p); } //--------------------------------------} //--------------------------------------------------------------------------void __fastcall TForm1::Button2Click(TObject *Sender) { Close(); } //--------------------------------------------------------------------------- 20 Зак лючени е В данной курсовой работе была создана программа для работы с кодированными данными, в которой можно выбирать тип кодировки а также выбирать тип входных и выходных данных: 1)из файла 2)путем непосредственного набора в текстовом поле. Разработанная программа должна быть полезна разработчикам вебсайтам либо рядовым пользователям при работе с текстовыми файлами типа Word. По результатам выполнения работы можно сделать вывод, что численные данные особо не кодируются за исключением кодировки юникода UTF-7. При кодировании при помощи SYMBOL, данные должны иметь четкие границы, т.к. не весь текст кодируется в данной таблице кодов. 21 Спи со к исполь зован ной литерату ры 1. Горев А., Макашарипов С., Ахаян Р. Эффективная работа с СУБД Access. –СПб, «Питер», 2007. –704 с. 2. Джесс Либерти. Освой самостоятельно C++ за 21 день. –М.: Вильямс, 2003. –772 с. 3. Дэвис Стефан Р. C++ для «чайников». –М.: Издательский дом «Вильяме», 2003. –336 с. 4. Уотсон Карл, Нейгел Кристиан, Педерсен Якоб Хаммер, Рид Джон Д., Скиннер Морган, Уайт, Эрик. С++: базовый курс. : Пер. с англ. - М. : ООО "И.Д. Вильямс", 2009. -1216 с. 22