JavaScript (основы). Глава 15. LiveConnect. Обзор
Оглавление | Назад | Вперёд | ИндексГлава 15. LiveConnect. Обзор
В этой главе рассматривается использование технологии LiveConnect, позволяющей коду Java и коду JavaScript взаимодействовать. Предполагается, что Вы уже знакомы с программированием на Java.
В главе имеются следующие разделы:
Дополнительно об использовании LiveConnect см. JavaScript technical notes на сайте DevEdge.
Что такое LiveConnect?
В браузере Navigator LiveConnect даёт возможность использовать:
Включение LiveConnect
Служба LiveConnect по умолчанию включена в Navigator'е 1.1 и последующих версиях. Чтобы LiveConnect работала, должны быть включены Java и JavaScript. Для проверки этого выберите Preferences в меню Edit и просмотрите раздел Advanced.
Для отключения Java или JavaScript уберите галочки в переключателях; если Вы это сделали, LiveConnect работать не будет.
Консоль Java
Консоль Java это окно Navigator-а отображающее сообщения Java. Если Вы используете переменные классов out или err в java.lang.System для вывода сообщения, сообщение появляется на консоли. Для показа Java-консоли, выберите Java Console в меню Communicator.
Вы можете использовать Java-консоль для показа сообщений пользователю или для трассировки значений переменных в различных точках при выполнении программы. Учтите, что многие пользователи отключают показ консоли.
Например, следующий код Java выводит сообщение "Hello, world!" в Java-консоль:
System.out.println("Hello, world!")
}
Работа с оболочками
В JavaScript оболочка\wrapper это объект типа данных целевого языка, который содержит объект исходного языка. На стороне JavaScript Вы можете использовать объект-оболочку для доступа в методам и полям Java-объекта; вызов метода или доступ к свойству в оболочке приводит к вызову Java-объекта. На стороне Java - JavaScript-объекты оборачиваются в экземпляры класса netscape.javascript.JSObject и передаются в Java.
Если JavaScript-объект пересылается в Java, машина выполнения создаёт Java-оболочку типа JSObject; когда JSObject высылается из Java в JavaScript, машина выполнения развёртывает его в оригинальный тип JavaScript-объекта. Класс JSObject предоставляет интерфейс для вызова методов JavaScript и проверки свойств JavaScript.
Взаимодействие JavaScript с Java
Когда Вы обращаетесь к пакету или классу Java или работаете с массивом или объектом Java, Вы используете 1 из специальных объектов LiveConnect. Все запросы JavaScript к Java выполняются с помощью этих объектов, резюме по которым дано в таблице.
Таблица 15.1 Объекты LiveConnect
ПРИМЕЧАНИЕ:
Поскольку Java является строго типизированным языком, а JavaScript типизирован слабо, машина выполнения JavaScript конвертирует значения аргументов в подходящие типы данных других языков, когда Вы используете LiveConnect. См. полную информацию в разделе "Конвертация Типов Данных".
Существование объектов LiveConnect в некотором смысле прозрачно, так как Вы взаимодействуете с Java в довольно интуитивной манере. Например, Вы можете создать Java-объект String и присвоить его JavaScript-переменной myString путём использования операции new с Java-конструктором:
var myString=new java.lang.String("Hello world")
В предыдущем примере переменная myString это JavaObject, потому что она содержит экземпляр Java-объекта String. Как JavaObject, myString имеет доступ к public-методам экземпляра java.lang.String и его суперкласса, java.lang.Object. Эти Java-методы доступны в JavaScript как методы из JavaObject, и Вы можете вызвать их так:
myString.length() // возвращает 11
Объект Packages
Если Java-класс не является частью пакетов java, sun или netscape, Вы осуществляете доступ к нему через объект Packages. Например, корпорация Redwood использует Java-пакет redwood как контейнер для различных Java-классов. Для создания экземпляра класса HelloWorld пакета redwood Вы выполняете доступ к конструктору этого класса так:
var red=new Packages.redwood.HelloWorld()
Вы можете получить доступ также к класса пакета по умолчанию (то есть к классам, которые не называют пакет явным образом). Например, если класс HelloWorld находится непосредственно в CLASSPATH и не в пакете, Вы можете выполнить к нему доступ так:
var red=new Packages.HelloWorld()
LiveConnect-объекты java, sun и netscape являются аббревиатурами для известных Java-пакетов. Например, Вы может записать:
var myString=new java.lang.String("Hello world")
вместо более длинного варианта:
var myString=new Packages.java.lang.String("Hello world")
Работа с массивами Java
Если какой-нибудь Java-метод создаёт массив и Вы обращаетесь к этому массиву в JavaScript, Вы работаете с JavaArray. Например, следующий код создаёт JavaArray x из 10 элементов типа int:
theInt=java.lang.Class.forName("java.lang.Integer")
x=java.lang.reflect.Array.newInstance(theInt, 10)
Подобно JavaScript-объекту Array, JavaArray имеет свойство length, которое возвращает количество элементов массива. в отличие от Array.length, JavaArray.length является свойством только для чтения, так как количество элементов в Java-массиве фиксируется в момент создания.
Ссылки на пакет и класс
Простые ссылки из JavaScript на пакеты и классы Java создают объекты JavaPackage и JavaClass. Ранее в примере о компании Redwood, например, ссылка Packages.redwood это объект JavaPackage. Аналогично, ссылка java.lang.String это JavaClass -объект.
В большинстве случаев Вам не нужно беспокоиться о создании объектов JavaPackage и JavaClass - Вы просто работаете с пакетами и классами Java, а LiveConnect прозрачно создаёт эти объекты.
JavaClass -объекты не конвертируются автоматически в экземпляры java.lang.Class, когда Вы передаёте их как параметры Java-методам - Вы обязаны создавать оболочку для java.lang.Class -экземпляра. В следующем примере метод forName создаёт объект-оболочку theClass, который затем передаётся методу newInstance для создания массива.
theClass=java.lang.Class.forName("java.lang.String")
theArray=java.lang.reflect.Array.newInstance(theClass, 5)
Аргументы типа char
Вы не можете передавать односимвольные строки в Java-метод, требующий аргумента типа char. Вы обязаны передавать в такие методы целое число, соответствующее Unicode-значению символа. Например, вот присвоение значения "H" переменной c:
Управления Java-аплетами
Вы можете использовать JavaScript для управления поведением Java-аплета, не зная почти ничего о внутреннем строении аплета. Все public-переменные, методы и свойства аплета доступны для работы из JavaScript. Например, Вы можете использовать кнопки, расположенные на HTML-форме, для запуска и остановки Java-аплета, находящегося в любом месте документа.
Обращение к аплетам
Каждый аплет документа отражается в JavaScript как document.appletName, где appletName это значение атрибута NAME тэга <APPLET>. Массив applets также содержит все аплеты страницы; Вы можете обратиться к элементам этого массива по имени аплета (как в ассоциативном массиве) или по порядковому номеру аплета на странице (начиная с 0).
Например, рассмотрим аплет "Hello World" на языке Java:
import java.awt.Graphics;
public class HelloWorld extends Applet {
public void paint(Graphics g){
g.drawString("Hello world!", 50, 25)}}
Следующий HTML запускает и отображает аплет и именует его "HelloWorld" (в атрибуте NAME):
<APPLET CODE="HelloWorld.class" NAME="HelloWorld" WIDTH=150 HEIGHT=25>
</APPLET>
Если это первый аплет документа (самый верхний на странице), Вы можете обратиться к нему в JavaScript одним из следующих способов:
document.applets["HelloWorld"]
document.applets[0]
Массив applets имеет свойство length, document.applets.length, указывающее количество аплетов в документе.
Все public-переменные, объявленные в аплете и его классах и пакетах-предках, доступны в JavaScript. Static-методы и свойства, объявленные в аплете, доступны в JavaScript как методы и свойства объекта Applet. Вы можете получать и устанавливать значения свойств и вызывать методы, возвращающие строковые, числовые и Булевы значения.
Пример 1: Hello World
Например, Вы можете изменить вышеприведённый аплет HelloWorld:
Исходный код Java выглядит теперь так:
import java.awt.Graphics;
public class HelloWorld extends Applet {
String myString;
myString=new String("Hello, world!")}
public void paint(Graphics g){
g.drawString(myString, 25, 20)}
public void setString(String aString){
myString=aString;
repaint()}}
Сделав стоку сообщения переменной, Вы можете модифицировать её из JavaScript. Теперь изменим HTML-файл:
<APPLET CODE="HelloWorld1.class" NAME="Hello" WIDTH=150 HEIGHT=25>
</APPLET>
<INPUT type=button VALUE="Set String"
onClick="document.HelloWorld.setString(document.form1.str.value)">
<BR>
<INPUT TYPE=text SIZE="20" NAME="str">
</FORM>
Когда Вы компилируете аплет HelloWorld и загружаете HTML-страницу в Navigator, Вы сначала увидите "Hello, World!", выведенное на серой панели аплета. Однако Вы можете теперь изменить текст, введя новый в текстовом поле и щёлкнув кнопку. Это демонстрирует управление аплетом из JavaScript.
Пример 2: аплет Flashing Color Text
Более сложный пример - аплет, отображающий "вспыхивающий" текст разными цветами. Текстовое поле и кнопка позволяют ввести новый текст. Этот аплет показан на Рисунке 15.1.
Рисунок 15.1 Аплет Flashing text
<APPLET CODE="colors.class" WIDTH=500 HEIGHT=60 NAME="colorApp">
</APPLET>
<P>Enter new text for the flashing display:
NAME="textBox"
LENGTH=50>
<P>Click the button to change the display:
<INPUT type=button
VALUE="Change Text"
onClick="document.colorApp.setString(document.colorText.textBox.value)">
Этот аплет использует public-метод setString для специфицирования вспыхивающего текста. В HTML-форме обработчик onClick кнопки позволяет менять строку "Hello, world!" через вызов метода setString.
Здесь colorText это имя HTML-формы и textBox - имя текстового поля. Обработчик события передаёт значение, которое пользователь ввёл в текстовое поле, методу setString Java-аплета.
Управление Java Plug-in-ами
Каждый plug-in документа отражается в JavaScript как элемент массива embeds. Например, следующий HTML-код включает AVI plug-in в документ:
<EMBED SRC=myavi.avi NAME="myEmbed" WIDTH=320 HEIGHT=200>
Если это первый plug-in в документе, Вы может получить к нему доступ одним из следующих способов:
document.embeds["myEmbed"]
document.myEmbed
Если plug-in ассоциирован с Java-классом netscape.plugin.Plugin, Вы можете получить доступ к его static-переменным и методам тем способом, которым Вы получаете доступ к переменным и методам.
Массив embeds имеет свойство length, document.embeds.length, указывающего количество plug-in-ов, встроенных в документ.
Взаимодействие Java и JavaScript
Если Вы хотите использовать объекты JavaScript в Java, Вы обязаны импортировать пакет netscape.javascript в Ваш Java-файл. Этот пакет определяет следующие классы:
Начиная с JavaScript 1.2, эти классы поставляются в.jar-файле; в предыдущих версиях JavaScript эти классы находились в.zip-файле. См. также книгу Клиентский JavaScript. Справочник.
Для доступа к классам LiveConnect поместите файл.jar или.zip в CLASSPATH компилятора JDK одним из следующих способов:
Например, в Navigator 4. 0 для Windows NT классы поставляются в файле java40.jar в директории Program\Java\Classes ниже директории Navigator-а. Вы можете специфицировать переменную окружения в Windows NT, открыв System из Control Panel и создав пользовательскую переменную окружения CLASSPATH со значением типа такого:
D:\Navigator\Program\Java\Classes\java40.jar
См. в документации к Sun JDK информацию о CLASSPATH.
ПРИМЕЧАНИЕ:
Поскольку Java является строго типизированным языком, а JavaScript типизирован слабо, машина выполнения JavaScript конвертирует значения аргументов в подходящие типы данных других языков, когда Вы используете LiveConnect. См. полную информацию в разделе "Конвертация Типов Данных".
Использование классов LiveConnect
Все JavaScript-объекты появляются в коде Java как экземпляры netscape.javascript.JSObject. Когда Вы вызываете метод в Вашем Java-коде, Вы можете передать ему JavaScript-объект в качестве одного из аргументов. Для этого Вы обязаны определить соответствующий формальный параметр метода как имеющего тип JSObject.
Также всегда при использовании JavaScript-объектов в Вашем Java-коде, Вы должны помещать вызов JavaScript-оъекта внутри блока операторов try…catch, который обрабатывает ошибки типа netscape.javascript.JSException. Это даёт Java-коду возможность обрабатывать ошибки выполнения кода JavaScript, которые появляются в Java как исключения типа JSException.
Доступ к JavaScript с помощью JSObject
Например, Вы работаете с Java-классом JavaDog. Как показано в следующем коде, конструктор JavaDog принимает в качестве параметра JavaScript-объект jsDog, который определён как имеющий тип JSObject:
public class JavaDog
{
public String dogBreed;
public String dogColor;
public String dogSex;
// определяется конструктор класса
public JavaDog(JSObject jsDog)
{
// здесь используйте try…catch для обработки JSException
this.dogBreed=(String)jsDog.getMember("breed");
this.dogColor=(String)jsDog.getMember("color");
this.dogSex=(String)jsDog.getMember("sex")}}
Обратите внимание, что метод getMember из JSObject используется для доступа к свойствам JavaScript-объекта. Предыдущий пример использует getMember для присвоения значения JavaScript-свойства jsDog.breed Java-члену данных JavaDog.dogBreed.
ПРИМЕЧАНИЕ:
Лучше было бы поместить вызов getMember в блоке try…catch для отлова ошибок типа JSException. См. "Обработка Исключений JavaScript в Java".
Чтобы лучше представить работу getMember, посмотрим на определение специального JavaScript-объекта Dog:
function Dog(breed,color,sex){
this.breed=breed
this.color=color
this.sex=sex
}
Вы можете создать в JavaScript Dog -экземпляр gabby:
gabby=new Dog("lab","chocolate","female")
При вычислении gabby.color Вы увидите, что оно имеет значение "chocolate". Теперь, предположим, Вы создаёте JavaDog -экземпляр в Вашем JavaScript-коде, передавая объект gabby конструктору:
javaDog=new Packages.JavaDog(gabby)
Если Вы вычисляете javaDog.dogColor, Вы увидите, что оно также имеет значение "chocolate", поскольку метод getMember Java-конструктора присваивает свойству dogColor значение gabby.color.
Обработка исключений JavaScript в Java
Если код JavaScript, вызванный из Java, терпит неудачу на этапе прогона, он вызывает исключение. Если Вы вызываете JavaScript-код из Java, Вы можете отловить это исключение в блоке операторов try…catch. Исключение JavaScript доступно Вашему Java-коду как экземпляр netscape.javascript. JSException.
JSException это Java-оболочка вокруг исключения любого типа, вызванного JavaScript, аналогично тому, как JSObject -экземпляры являются оболочками для JavaScript-объектов.
Используйте JSException при вычислении JavaScript-кода в Java. Если JavaScript-код не вычисляется из-за ошибки компиляции JavaScript или какой-нибудь другой ошибки времени выполнения, интерпретатор JavaScript генерирует сообщение об ошибке, которое конвертируется в JSException -экземпляр.
Например, Вы можете использовать try…catch для обработки исключений LiveConnect:
global.eval("foo.bar=999;")} catch (Exception e){
if(e instanceof JSException){
jsCodeFailed()"} else {
otherCodeFailed()}}
Здесь оператор eval терпит неудачу, если foo не определено. Блок catch выполняет метод jsCodeFailed, если оператор eval в блоке try вызывает JSException; метод otherCodeFailed выполняется, если блок try вызывает какую-нибудь другую ошибку.
Доступ к клиентскому JavaScript
Давайте теперь отдельно рассмотрим использование Java для доступа к клиентскому JavaScript. Автор HTML-страницы обязан разрешить аплету доступ к JavaScript, специфицировав атрибут MAYSCRIPT тэга <APPLET>. Это предотвращает доступ аплета к JavaScript на странице без ведома автора страницы. Попытка получить доступ к JavaScript из аплета, не имеющего атрибут MAYSCRIPT, генерирует исключение. Тэг MAYSCRIPT нужен только для доступа Java к JavaScript; он не требуется для доступа JavaScript к Java.
Получение дескриптора для окна JavaScript
Прежде чем Вы получите доступ к JavaScript в Navigator-е, Вы обязаны получить дескриптор/handle для окна Navigator-а. Используйте метод getWindow класса netscape.javascript.JSObject для получения дескриптора окна, передавая его объекту Applet.
Например, если win это ранее объявленная переменная типа JSObject, следующий Java-код присваивает дескриптор окна переменной win:
public class myApplet extends Applet {
public void init(){
JSObject win=JSObject.getWindow(this)}}
Доступ к объектам и свойствам JavaScript
Метод getMember класса netscape.javascript.JSObject даёт доступ к объектам и свойствам JavaScript. Вызывайте getWindow для получения дескриптора окна JavaScript, затем вызывайте getMember для доступа к каждому JavaScript-объекту. Заметьте, что JavaScript-объекты появляются в Java как экземпляры класса netscape.javascript.JSObject.
Например, следующий код Java даёт доступ к JavaScript-объекту document.testForm через переменную myForm:
win=JSObject.getWindow(this);
myForm=win.eval("document.testForm")
}
Вы могли бы использовать следующие строки вместо myForm=win.eval("document.testForm"):
JSObject doc=(JSObject) win.getMember("document");
JSObject myForm=(JSObject) doc.getMember("testForm");
Если JavaScript-объект document.testForm.jazz это переключатель/checkbox, следующий код Java даёт доступ к его свойству checked:
win=JSObject.getWindow(this);
JSObject doc=(JSObject) win.getMember("document");
JSObject myForm=(JSObject) doc.getMember("testForm");
JSObject check=(JSObject) myForm.getMember("jazz");
Boolean isChecked=(Boolean) check.getMember("checked")}
Вызов методов JavaScript
Метод eval класса netscape.javascript.JSObject позволяет вычислять произвольные выражения JavaScript. Используйте метод getWindow для получения дескриптора окна JavaScript, затем используйте eval для доступа к JavaScript-методу.
Вот синтаксис вызова методов JavaScript:
JSObject.getWindow().eval("expression")
expression это JavaScript-выражение, которое вычисляется в вызов JavaScript-метода.
Например, следующий код Java использует eval для вызова JavaScript-метода alert, если возникает событие MouseUp:
JSObject win=JSObject.getWindow(this)}
public boolean mouseUp(Event e, int x, int y){
win.eval("alert(\"Hello world!\");");
return true}
По-другому можно вызвать JavaScript-методы JSObject -методом call. Используйте следующий вызов JavaScript-метода из Java, кода Вы хотите передать Java-объекты в качестве аргументов:
JSObject.call(methodName, argArray)
где argArray это массив Java-объектов, используемый для передачи аргументов JavaScript-методу.
Если Вы хотите передать примитивные значения JavaScript-методу, Вы обязаны использовать Java-оболочки объектов (такие как Integer, Float и Boolean), а затем наполнить Array такими объектами.
Пример: Hello World
Вернёмся к примеру HelloWorld, изменим метод paint в коде Java таким образом, чтобы он вызывал JavaScript-метод alert (с сообщением "Painting!"):
public void paint(Graphics g){
g.drawString(myString, 25, 20);
JSObject win=JSObject.getWindow(this);
String args[]={"Painting!"};
win.call("alert", args)}
Затем добавим атрибут MAYSCRIPT в тэг <APPLET> на HTML-странице, рекомпилируем аплет и запустим его. При каждой прорисовке аплета (когда он инициализируется, когда Вы вводите новое текстовое значение и когда страница перезагружается) выводится JavaScript-бокс alert. Это простая иллюстрация вызова JavaScript из Java.
Можно добиться того же эффекта таким образом:
public void paint(Graphics g){
g.drawString(myString, 25, 20);
JSObject win=JSObject.getWindow(this);
win.eval("alert('Painting')")}
ПРИМЕЧАНИЕ:
Может понадобиться перезагрузка HTML-страницы путём выбора Open Page в меню File вместо щелчка по кнопке Reload, чтобы гарантировать реинициализацию аплета.
Вызов пользовательский функций
Вы можете также вызвать определённые пользователем функции из Java-аплета. Например, добавьте следующую функцию в <HEAD> HTML-страницы с аплетом HelloWorld:
function test(){
alert("You are using " + navigator.appName + " " +
navigator.appVersion)
}
</SCRIPT>
Эта простая функция выведет диалог alert, содержащий имя и версию используемого клиентского программного обеспечения. Затем измените метод init в Вашем Java-коде аналогично тому, как Вы изменили paint:
myString=new String("Hello, world!")
JSObject win=JSObject.getWindow(this)
String args2[]={""}
win.call("test", args2)
}
Заметьте, что args2 объявлен как массив без элементов, хотя этот метод не принимает аргументов. Когда Вы рекомпилируете аплет и перезагрузите HTML-страницу (и реинициализируете аплет), JavaScript-диалог alert выведет версию Navigator-а, который запущен у Вас. Это простая иллюстрация вызова пользовательской функции из Java.
Конвертация типов данных
Поскольку Java является строго типизированным языком, а JavaScript типизирован слабо, машина выполнения JavaScript конвертирует значения аргументов в подходящие типы данных других языков, когда Вы используете LiveConnect. Эта конвертация рассматривается в следующих разделах:
Конвертация JavaScript в Java
Если Вы вызываете Java-метод и передаёте ему параметры из JavaScript, тип передаваемых параметров конвертируется в соответствии с правилами, описанными в следующих разделах:
Return-значения методов netscape.javascript.JSObject всегда конвертируются в экземпляры java.lang.Object. Правила конвертации этих return-значений также описаны в этих разделах.
Например, если JSObject.eval возвращает JavaScript-число, Вы можете найти правило конвертации этого числа в экземпляр java.lang.Object в разделе "Числа".
Числа
Если Вы передаёте числовые типы JavaScript в качестве параметров Java-методам, Java конвертирует значения таким образом:
Если JavaScript-число передаётся как параметр в Java-метод, ожидающий экземпляр java.lang.String, число конвертируется в строку. Используйте операцию == для сравнения результата конвертации с другими строковыми значениями.
Булевы
Если Вы передаёте Булев тип JavaScript в качестве параметра Java-методам, Java конвертирует значения таким образом:
Если JavaScript Boolean передаётся в качестве параметра Java-методу, который ожидает экземпляр java.lang.String, Boolean конвертируется в строку. Используйте операцию == для сравнения результата конвертации с другими строковыми значениями.
Строковые
Если Вы передаёте строковые значения JavaScript в качестве параметров Java-методам, Java конвертирует значения так:
Если Вы передаёте undefined-значения JavaScript в качестве параметров Java-методам, Java конвертирует значения так:
Конвертация undefined-значений возможна только в JavaScript 1.3. Предыдущие версии JavaScript не поддерживают значение undefined.
Если JavaScript-значение undefined передаётся в качестве параметра Java-методу, который ожидает экземпляр java.lang.String, значение undefined конвертируется в строку. Используйте операцию == для сравнения результата конвертации с другими строковыми значениями.
Если Вы передаёте null-значения JavaScript в качестве параметров Java-методам, Java конвертирует значения так:
Тип Java-параметра | Правила конвертации |
---|---|
Любой класс
Интерфейс любого типа | Значение становится null. |
byte
char double float int long short | Значение становится 0. |
boolean | Значение становится false. |
Объекты JavaArray и JavaObject
В большинстве случаев, если Вы передаёте JavaScript JavaArray или JavaObject в качестве параметров Java-методу, Java просто снимает оболочку с объекта; иногда объект приводится к другому типу данных в соответствии с правила из таблицы:
Интерфейс или класс совместимы при присвоении, если развёрнутый объект является экземпляром типа Java-параметра. То есть следующий оператор обязан возвратить true:
unwrappedObject instanceof parameterType
Если Вы передаёте JavaScript JavaClass -объект как параметр Java-методу, Java конвертирует этот объект в соответствии со следующими правилами:
Если Вы передаёте любой другой объект JavaScript в качестве параметра Java-методу, Java конвертирует этот объект в соответствии со следующими правилами:
Конвертация из Java а JavaScript
Передаваемые из Java в JavaScript значения конвертируются так:
Заметьте, что экземпляры java.lang.Double и java.lang.Integer конвертируются в JavaScript-объекты, а не в числа JavaScript. Аналогично, экземпляры java.lang.String также конвертируются в объекты JavaScript, а не в строки JavaScript.
Java String -объекты также соответствуют JavaScript-оболочкам. Если Вы вызываете JavaScript-метод, который требует JavaScript-строку и передаёт её оболочке, Вы получите ошибку. Вместо этого конвертируйте оболочку в JavaScript-строку, присоединяя к ней пустую строку, как показано здесь:
var JavaString=JavaObj.methodThatReturnsAString();
var JavaScriptString=JavaString + "";
Оглавление | Назад | Вперёд | Индекс