к оглавлению   к 4GL - визуальному программированию

Язык визуального программирования приложений Visual Basic for Application

ПРОЦЕДУРЫ ОБРАБОТКИ ОШИБОК И ОТЛАДКА ПРОГРАММ VBA

Разработка процедур, предотвращающих появление ошибок

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

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

Private Sub CommandButtonl_Click()

Dim Числитель, Знаменатель, Результат As Double

Числитель = CDbl(TextBoxl.Text)

Знаменатель = CDbl(TextBox2.Text)

Результат = Числитель / Делитель

TextBoxS.Text = CStr(Результат)

End Sub

Рис. 12.1. Диалоговое окно Деление

Несмотря на то что рассматриваемая ситуация очень простая, она уже таит в себе множество подводных камней. Например, если пользователь по невнимательности забудет ввести в поле числитель или в поле Знаменатель число при нажатии кнопки счет происходит аварийное прерывание программы с малопонятным сообщением о несоответствии типов отображаемом в диалоговом окне Microsoft Visual Basic (рис. 12.2)

Рис. 12.2. Диалоговое окно Microsoft Visual Basic с сообщением об ошибке

Данное сообщение об ошибке связано с одной из следующих двух инструкций в программе:

Числитель = CDbl(TextBoxl.Text)

Знаменатель = CDbl(TextBox2.Text)

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

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

Рис. 12.3. Пример сообщения о некорректном вводе данных

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

Private Sub CoramandButtonl_Click()

Dim Числитель, Знаменатель, Результат As Single

'

If IsNumeric(TextBoxl.Text) = False Then MsgBox "Ошибка в числителе",

vblnformation, "Деление" TextBoxl.SetFocus

Exit Sub

End If

'

If IsNumeric(TextBox2.Text) = False Then

MsgBox "Ошибка в знаменателе",

vblnformation, "Деление"

TextBox2.SetFocus

Exit Sub

End If

'

Числитель = CDbl(TextBoxl.Text)

Знаменатель = CDbl(TextBox2.Text)

Результат = Числитель / Делитель

TextBox3.Text = CStr(Результат)

End Sub

Но это еще не все подводные камни, которые подстерегают неосторожного пользователя при вводе данных даже в этом простом примере. Если пользователь в поле Знаменатель введет 0, то также произойдет аварийная остановка выполнения программы с отображением в диалоговом окне Microsoft Visual Basic сообщения: Деление на 0. Для избежания подобной ошибки будем проверять не только, являются ли введенные в поле данные числом, но и что это не ноль. Например, добавим перед расчетным блоком в процедуре следующую дополнительную проверку:

If CDbl(TextBox2.Text) = 0 Then

MsgBox "Знаменатель не может быть нулем", vblnformation, "Деление"

TextBox2.SetFocus

Exit Sub

End If

Перехват и обработка ошибок

Из диалогового окна Microsoft Visual Basic видно, что каждая ошибка имеет свой код. В табл. 12.1 приведены коды наиболее часто встречаемых ошибок.

Таблица 12.1. Коды наиболее часто встречаемых ошибок

Код

Сообщение

5

Приложение не запущено

6

Переполнение

7

Не хватает памяти

9

Индекс выходит за пределы допустимого диапазона

11

Деление на нуль

13

Несоответствие типа

18

Произошло прерывание, вызванное пользователем

52

Неправильное имя файла или идентификатор

53

Файл не найден

54

Неверный режим работы с файлом

55

Файл уже открыт

56

Ошибка ввода-вывода

61

Переполнение диска

68

Устройство недоступно

71

Диск не готов

72

Повреждена поверхность диска

335

Невозможен доступ к системным ресурсам

368

Истек срок действия данного файла. Программе требуется файл более новой версии

482

Ошибка принтера

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

Инструкция

On Error

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

Подпрограмма обработки ошибки

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

Синтаксис 1:

On Error GoTo строка

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

Синтаксис 2:

On Error Resume Next

Указывает, что при возникновении ошибки происходит передача управления на инструкцию, непосредственно следующую за инструкцией, где возникла ошибка.

Синтаксис 3:

On Error GoTo 0

Отключает любой активизированный обработчик ошибок в текущей процедуре.

Инструкция

Resume

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

Синтаксис 1:

Resume

После обработки ошибки управление передается той инструкции, в которой произошла ошибка.

Синтаксис 2:

Resume строка

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

Синтаксис 3:

Resume Next

После обработки ошибки управление передается инструкции, следующей за инструкцией, в которой произошла ошибка.

Инструкция

Exit

Останавливает выполнение процедуры.

Допустимые синтаксисы:

  • Exit Sub
  • Exit Function
  • Exit Property

Подпрограмма обработки ошибки обычно включает объект Err, который содержит информацию об ошибках выполнения. Приведем свойства и методы объекта Err.

Свойства объекта Err

Number

Возвращает код ошибки

Source

Имя текущего проекта VBA

Description

Возвращает строковое выражение, содержащее текст сообщения об ошибке

HelpFile

Полное имя (включая диск и путь) файла справки VBA

HelpContext

Контекстный идентификатор файла справки VBA, соответствующий ошибке с кодом, указанным в свойстве

Number

LastDLLError

Содержит системный код ошибки для последнего вызова библиотеки динамической компоновки (DLL)

Методы объекта Err

Clear

Очищает все значения свойств объекта Err. Метод clear используется для явной очистки значений свойств объекта Err после завершения обработки ошибки. Это необходимо, например, при отложенной обработке ошибки, которая задается инструкцией on

Error Resume Next

Raise

Создает ошибку выполнения. Используется при моделировании ситуаций ошибки.

Синтаксис:

Raise number, source, description, helpfile, helpcontext

Аргументы:

  • number — номер ошибки, т. е. целое число от 0 до 65535
  • source — строковое выражение, определяющее имя объекта или приложения, в котором возникла ошибка
  • description — строковое выражение, содержащее описание ошибки
  • Helpfile — полное имя (включая диск и путь) файла справки Microsoft Windows, содержащего описание данной ошибки
  • helpcontext — контекстный идентификатор, определяющий соответствующий обрабатываемой ошибке раздел в файле, указанном в аргументе helpfile

На конкретном примере покажем, как применяется объект Err при создании обработчика ошибок. В предыдущем разделе в процессе создания диалотового окна деление и связанной с ним программы, на первый взгляд были предусмотрены все возможные ошибки. Но это только на первый взгляд. Введем, например, в поле Знаменатель значение 1е-40. Это число ничем не лучше или не хуже любого другого числа типа single. Тем не менее, вместо вывода результата произойдет аварийное прерывание выполнения программы с отображением сообщения об ошибке переполнения. Усовершенствуем программу с учетом возможности обработки подобной ошибки. В обработчике ошибок предусмотрим два отклика:

Рис. 12.4. Диалоговое окно с указанием типа ошибки

Private Sub CommandButtonl_Click()

Dim Числитель, Знаменатель, Результат As Single

'

' Передача управления на обработчик ошибок,

' помеченный меткой Обработка

'

On Error GoTo Обработка

'

' Проверка, является ли числитель числом

'

If IsNumeric(TextBoxl.Text) = False Then MsgBox "Ошибка в числителе",

vblnformation, "Деление" TextBoxl.SetFocus

Exit Sub

End If

' Проверка, является ли знаменатель числом

'

If IsNumeric(TextBox2.Text) = False Then

MsgBox "Ошибка в знаменателе",

vblnformation, "Деление"

TextBox2.SetFocus

Exit Sub

End If

'

' Проверка, не является ли знаменатель нулем

'

If CDbl(TextBox2.Text) = 0 Then

MsgBox "Знаменатель не может быть нулем", vblnformation, "Деление"

TextBox2.SetFocus

Exit Sub

End If

'

Числитель = CDbl(TextBoxl.Text)

Знаменатель = CDbl(TextBox2.Text)

Результат = Числитель / Знаменатель

TextBox3 . Text = CStr (.Результат)

'

' Выход из процедуры в случае успешного нахождения результата

'

Exit Sub

'

' Обработчик ошибок

'

Обработка: Select Case Err.Number

'

' Обработка ошибки переполнения

'

Case Is = 6

MsgBox " Произошла ошибка переполнения",

vblnformation, "Деление"

TextBoxl.Text = 1

TextBox2.Text = 1

Знаменатель = 1

Числитель = 1 Resume

' Обработка любой другой ошибки

'

Case Else

MsgBox "Произошла ошибка: " & Err.Description &

vblnformation, "Деление"

Exit Sub

End Select

End Sub

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

Отладка программ

При написании программ пользователь независимо от его опыта допускает те или иные ошибки. Кто-то из мудрых совершенно верно подметил, что только тот, кто ничего не делает, не совершает ошибок. Позвольте перефразировать эту жизненную мудрость для изучаемого в данной книге предмета следующим образом: в программах не делал ошибок только тот, кто никогда не писал их. Итак, ошибки — это объективная неизбежность или реальное воплощение этой неизбежности. Какие же бывают ошибки и как с ними бороться? Условно ошибки можно поделить на три типа: ошибки компиляции, выполнения и логические ошибки.

Ошибки компиляции

Ошибки компиляции возникают, если VBA не может интерпретировать введенный код. Например, при некорректном вводе числа скобок, неправильном имени, неполном вводе инструкции и т. д. Некоторые из этих ошибок обнаруживаются VBA при завершении набора строки с инструкцией в редакторе кода и после нажатия клавиши <Enter>. Строка, в которой содержится ошибка, выделяется красным цветом, и на экране отображается диалоговое окно с сообщением о возможной причине, вызвавшей ошибку (рис. 12.5).

Рис. 12.5. Сообщение об ошибке компиляции, обнаруженной при вводе инструкции

Рис. 12.6. Сообщение об ошибке компиляции в диалоговом окне Microsoft Visual Basic

Другие ошибки компиляции обнаруживаются перед выполнением программы. Отметим, что VBA каждый раз автоматически компилирует программу при ее запуске на выполнение. В VBA предусмотрена также возможность компилировать программу без запуска на выполнение посредством команды Отладка, Компилировать (Debug, Compile). В этом случае предполагаемое местоположение ошибки выделяется синим цветом и на экране отображается диалоговое окно Microsoft Visual Basic с сообщением о возможной причине, вызвавшей ошибку (рис. 12.6).

Ошибки выполнения

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

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

В этих и подобных случаях на экране отображается диалоговое окно Microsoft Visual Basic с сообщением о номере ошибки и возможной причине, ее вызвавшей (рис. 12.7).

Рис. 12.7. Сообщение об ошибке выполнения в диалоговом окне Microsoft Visual Basic

Если в диалоговом окне Microsoft Visual Basic нажать кнопку Отладка (Debug), то в строке модуля желтым цветом будет выделена строка, вызвавшая ошибку и по причине которой выполнение программы было прервано. Кроме того, эта строка будет помечена стрелочкой. При прерывании выполнения программы VBA переходит в режим прерывания. Одной из наиболее удобных возможностей режима прерывания являются возможность узнать текущее значение переменных и свойств. Для этого достаточно расположить указатель мыши на имени свойства или переменной. Это вызовет появление всплывающей подсказки с текущим значением переменной или свойства. Из текста кода, изображенного на рисунке, видно, что значение переменной у равно 0, что и вызвало ошибку прерывания. Для задания режима вывода всплывающей подсказки с текущими значениями данных должен быть установлен флажок Подсказки значений данных (Auto Data Tips) диалогового окна Параметры (Options), вызываемого с помощью команды Сервис, Параметры (Tools, Options).

Логические ошибки

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

Рис. 12.8. Редактор кода в режиме прерывания

Инструкция Option Explicit

Простейшим средством предотвращения случайных ошибок является использование инструкции Option Explicit. Эта инструкция предписывает явно описывать все переменные, встречающиеся в программе. Использование инструкции option Explicit позволяет избежать следующей трудно отслеживаемой ошибки. Предположим, что в программе используется переменная с именем ссуда, а при наборе имени этой переменной где-то в программе вместо русской буквы с по ошибке набрана латинская буква с. Визуально, эти имена ничем не отличаются друг от друга, но воспринимаются программой как имена разных переменных. Если бы использовалась инструкция option Explicit, а значит имело место явное описание переменной Ссуда, то компилятор указал бы на переменную ссуда с латинской буквой с, как на неописанную, и эта, трудно отслеживаемая ошибка, была бы быстро найдена.

Пошаговое выполнение программ

Редактор VBA позволяет выполнять пошаговую отладку программы. Ее можно выполнить либо при помощи панели инструментов Отладка (Debug), либо меню Отладка (Debug), которое включает команды и соответствующие комбинации клавиш (рис. 12.9). Если панель инструментов Отладка (Debug) не отображена на экране, то ее можно отобразить, выполнив команду Вид, Панели инструментов, Отладка (View, Toolbars, Debug).

Рис. 12.9. Панель инструментов Отладка и раскрывающееся меню Отладка

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

  1. Команда Отладка, Шаг с заходом (Debug, Step Into), либо кнопка Шаг с заходом (Step Into) панели инструментов Отладка (Debug) осуществляет последовательную шаг за шагом отладку всей программы, включая процедуры, вызываемые в программе.
  2. Команда Отладка, Шаг с обходом (Debug, Step Over), либо кнопка Шаг с обходом (Step Over) панели инструментов Отладка (Debug) осуществляет последовательную шаг за шагом отладку всей программы, исключая процедуры, т. е. если встречается процедура, то она выполняется целиком, а не пошагово, как это делается в команде Отладка, Шаг с заходом (Debug, Step Into).
  3. Команда Отладка, Шаг с выходом (Debug, Step Out), либо кнопка Шаг с выходом (Step Out) панели инструментов Отладка (Debug) завершает выполнение текущей процедуры и останавливает процесс пошаговой отладки на следующей после вызвавшей ее инструкции программы.
  4. Команда Отладка, Выполнить до текущей позиции (Debug, Run to Cursor) выполняет программу до инструкции, на которой установлен курсор.

Точка останова

Точка останова устанавливается или снимается с помощью команды Отладка, Точка останова (Debug, Toggle Breakpoint), либо посредством кнопки Точка останова (Toggle Breakpoint) панели инструментов Отладка (Debug). На листе модуля точки останова выделяются полосой кирпичного цвета и кругом того же цвета (рис. 12.10).

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

Одновременно снять все точки останова можно, выполнив команду Отладка, Снять все точки останова (Debug, Clear All Breakpoint).

Вывод значений свойств и переменных

Одним из наиболее удобных средств режима отладки является возможность узнать текущее значение переменных и свойств. Для этого достаточно расположить указатель мыши на имени свойства или переменной. Это вызовет появление всплывающей подсказки с текущим значением переменной или свойства. Для установки режима вывода всплывающей подсказки с текущими значениями данных должен быть установлен флажок Подсказки значений данных (Auto Data Tips) диалогового окна Параметры (Options), вызываемого командой Сервис, Параметры (Tools, Options).

Рис. 12.10. Точки останова

Другим способом отслеживания текущих значений данных является использование диалогового окна Контрольные значения (Quick Watch), отображаемого на экране с помощью команды Вид, Окно контрольного значения (View, Quick Watch), либо команды Отладка, Контрольное значение (Debug, Quick Watch) (рис. 12.11). Диалоговое окно Контрольные значения (Quick Watch) применяется для одновременного отображения текущих значений нескольких данных. Команда Отладка, Добавить контрольное значение (Debug, Add Watch) позволяет добавить новые контрольные значения в диалоговом окне Контрольные значения (Quick Watch).

Удаление контрольного значения из диалогового окна производится посредством его выделения и нажатия клавиши <Delete>.

Существует также программный способ вывода значений свойств и переменных в диалоговом окне Контрольные значения (Quick Watch) при помощи метода Print объекта Debug. Ниже приведен пример программного способа вывода значения переменной:

ПроверяемаяПеременная = "Вывод текста в окно отладки." Debug.Print ПроверяемаяПеременная

Окно Локальные переменные (Locals Window), отображаемое на экране командой Вид, Окно локальных переменных (View, Locals Window), выводит значения всех переменных текущей процедуры, а не только специально выбранных, как это происходит в окне Контрольные значения (Quick Watch).

Внешний же вид и структура обоих окон, Локальные переменные (Locals Window) и Контрольные значения (Quick Watch), одни и те же.

Рис. 12.11. Диалоговое окно Контрольные значения

Окно Проверка (Immediate Window), отображаемое на экране командой Вид, Окно отладки (View, Immediate Window), предоставляет пользователю возможность:

к оглавлению   к 4GL - визуальному программированию

Знаете ли Вы, в чем ложность понятия "физический вакуум"?

Физический вакуум - понятие релятивистской квантовой физики, под ним там понимают низшее (основное) энергетическое состояние квантованного поля, обладающее нулевыми импульсом, моментом импульса и другими квантовыми числами. Физическим вакуумом релятивистские теоретики называют полностью лишённое вещества пространство, заполненное неизмеряемым, а значит, лишь воображаемым полем. Такое состояние по мнению релятивистов не является абсолютной пустотой, но пространством, заполненным некими фантомными (виртуальными) частицами. Релятивистская квантовая теория поля утверждает, что, в согласии с принципом неопределённости Гейзенберга, в физическом вакууме постоянно рождаются и исчезают виртуальные, то есть кажущиеся (кому кажущиеся?), частицы: происходят так называемые нулевые колебания полей. Виртуальные частицы физического вакуума, а следовательно, он сам, по определению не имеют системы отсчета, так как в противном случае нарушался бы принцип относительности Эйнштейна, на котором основывается теория относительности (то есть стала бы возможной абсолютная система измерения с отсчетом от частиц физического вакуума, что в свою очередь однозначно опровергло бы принцип относительности, на котором постороена СТО). Таким образом, физический вакуум и его частицы не есть элементы физического мира, но лишь элементы теории относительности, которые существуют не в реальном мире, но лишь в релятивистских формулах, нарушая при этом принцип причинности (возникают и исчезают беспричинно), принцип объективности (виртуальные частицы можно считать в зависимсоти от желания теоретика либо существующими, либо не существующими), принцип фактической измеримости (не наблюдаемы, не имеют своей ИСО).

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

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

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

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

НОВОСТИ ФОРУМА

Форум Рыцари теории эфира


Рыцари теории эфира
 10.11.2021 - 12:37: ПЕРСОНАЛИИ - Personalias -> WHO IS WHO - КТО ЕСТЬ КТО - Карим_Хайдаров.
10.11.2021 - 12:36: СОВЕСТЬ - Conscience -> РАСЧЕЛОВЕЧИВАНИЕ ЧЕЛОВЕКА. КОМУ ЭТО НАДО? - Карим_Хайдаров.
10.11.2021 - 12:36: ВОСПИТАНИЕ, ПРОСВЕЩЕНИЕ, ОБРАЗОВАНИЕ - Upbringing, Inlightening, Education -> Просвещение от д.м.н. Александра Алексеевича Редько - Карим_Хайдаров.
10.11.2021 - 12:35: ЭКОЛОГИЯ - Ecology -> Биологическая безопасность населения - Карим_Хайдаров.
10.11.2021 - 12:34: ВОЙНА, ПОЛИТИКА И НАУКА - War, Politics and Science -> Проблема государственного терроризма - Карим_Хайдаров.
10.11.2021 - 12:34: ВОЙНА, ПОЛИТИКА И НАУКА - War, Politics and Science -> ПРАВОСУДИЯ.НЕТ - Карим_Хайдаров.
10.11.2021 - 12:34: ВОСПИТАНИЕ, ПРОСВЕЩЕНИЕ, ОБРАЗОВАНИЕ - Upbringing, Inlightening, Education -> Просвещение от Вадима Глогера, США - Карим_Хайдаров.
10.11.2021 - 09:18: НОВЫЕ ТЕХНОЛОГИИ - New Technologies -> Волновая генетика Петра Гаряева, 5G-контроль и управление - Карим_Хайдаров.
10.11.2021 - 09:18: ЭКОЛОГИЯ - Ecology -> ЭКОЛОГИЯ ДЛЯ ВСЕХ - Карим_Хайдаров.
10.11.2021 - 09:16: ЭКОЛОГИЯ - Ecology -> ПРОБЛЕМЫ МЕДИЦИНЫ - Карим_Хайдаров.
10.11.2021 - 09:15: ВОСПИТАНИЕ, ПРОСВЕЩЕНИЕ, ОБРАЗОВАНИЕ - Upbringing, Inlightening, Education -> Просвещение от Екатерины Коваленко - Карим_Хайдаров.
10.11.2021 - 09:13: ВОСПИТАНИЕ, ПРОСВЕЩЕНИЕ, ОБРАЗОВАНИЕ - Upbringing, Inlightening, Education -> Просвещение от Вильгельма Варкентина - Карим_Хайдаров.
Bourabai Research - Технологии XXI века Bourabai Research Institution