JQuery: магия JavaScript::Журнал СА 1.2009
www.samag.ru
     
Поиск   
              
 www.samag.ru    Web  0 товаров , сумма 0 руб.
E-mail
Пароль  
 Запомнить меня
Регистрация | Забыли пароль?
Журнал "Системный администратор"
Журнал «БИТ»
Наука и технологии
Подписка
Где купить
Авторам
Рекламодателям
Архив номеров
Контакты
   

  Опросы
  Статьи

Электронный документооборот  

5 способов повысить безопасность электронной подписи

Область применения технологий электронной подписи с каждым годом расширяется. Все больше задач

 Читать далее...

Рынок труда  

Системные администраторы по-прежнему востребованы и незаменимы

Системные администраторы, практически, есть везде. Порой их не видно и не слышно,

 Читать далее...

Учебные центры  

Карьерные мечты нужно воплощать! А мы поможем

Школа Bell Integrator открывает свои двери для всех, кто хочет освоить перспективную

 Читать далее...

Гость номера  

Дмитрий Галов: «Нельзя сказать, что люди становятся доверчивее, скорее эволюционирует ландшафт киберугроз»

Использование мобильных устройств растет. А вместе с ними быстро растет количество мобильных

 Читать далее...

Прошу слова  

Твердая рука в бархатной перчатке: принципы soft skills

Лауреат Нобелевской премии, специалист по рынку труда, профессор Лондонской школы экономики Кристофер

 Читать далее...

1001 и 1 книга  
19.03.2018г.
Просмотров: 9886
Комментарии: 0
Потоковая обработка данных

 Читать далее...

19.03.2018г.
Просмотров: 8099
Комментарии: 0
Релевантный поиск с использованием Elasticsearch и Solr

 Читать далее...

19.03.2018г.
Просмотров: 8199
Комментарии: 0
Конкурентное программирование на SCALA

 Читать далее...

19.03.2018г.
Просмотров: 5194
Комментарии: 0
Машинное обучение с использованием библиотеки Н2О

 Читать далее...

12.03.2018г.
Просмотров: 5872
Комментарии: 0
Особенности киберпреступлений в России: инструменты нападения и защита информации

 Читать далее...

Друзья сайта  

 JQuery: магия JavaScript

Архив номеров / 2009 / Выпуск №1 (74) / JQuery: магия JavaScript

Рубрика: Веб /  Веб

Александр Слесарев АЛЕКСАНДР СЛЕСАРЕВ

JQuery: магия JavaScript

Эпоха WEB 2.0 диктует разработчикам новые правила. Что же скрывается за функциональностью современных веб-приложений? Какие инструменты должен использовать разработчик для решения нестандартных задач при разработке клиентских приложений эпохи WEB 2.0? Ответ на эти вопросы есть – использование фреймворка, рассчитанного на решение этих задач. И такой фреймворк, который содержит богатейший набор методов для разработки современных веб-приложений, существует – JQuery.

В последние годы возникла тенденция повышения требований к функциональности веб-приложений, причем не столько к серверной части, а именно к клиентской. Появились элементы управления, которые до этого были доступны только прикладным программам: табы, деревья, слайдеры, прогрессбары и многое другое. Появилось очень много сайтов, которые по функциональности вполне могут соперничать с прикладными программами. Еще более усилило эту тенденцию появление технологии AJAX. Очень часто в различных информационных источниках мелькает термин WEB 2.0, определяющий приложения новой формации. Да, именно приложения, потому что большинство современных веб-ресурсов трудно назвать сайтами, об этом можно много дискутировать, но факт остается фактом – многие из современных «сайтов» по-другому назвать нельзя.

Не знаю, можно ли говорить о том, что JQuery самая лучшая библиотека, так как конкурирующие продукты (например, Prototype, Mootools и ExtJS) тоже имеют ряд удобных моментов, но к явным плюсам JQuery можно отнести следующие:

  •  небольшой объем (15 Кб в сжатом виде);
  •  совместимость с основными браузерами.

И еще одно несомненное преимущество – это то, что библиотека может претендовать на то, чтобы стать стандартом в веб-разработке. Ведь не спроста такой софтверный монстр как Microsoft собирается включить ее в состав своего набора инструментов Visual Studio.

Первое знакомство

Библиотека JQuery была впервые опубликована на компьютерной конференции «BarCamp» в Нью-Йорке Джоном Ресигом (John Resig) в 2006 году. Спустя некоторое время она уже завоевала популярность у веб-разработчиков. Данный фреймворк базируется на взаимодействии JavaScript и DOM HTML-документа. К основным возможностям можно отнести следующие:

  •  переход по дереву DOM, включая поддержку XPath как плагина;
  •  обработка событий;
  •  визуальные эффекты;
  •  AJAX-дополнения.

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

Для начала нам понадобятся дистрибутив фреймворка, который можно скачать на официальном сайте разработчика [1], и тестовая веб-страница. Для подключения библиотеки к нашей веб-странице нужно всего лишь добавить ссылку на сценарий в контейнере <head>:

<head>

<script type="text/javascript" src="путь к файлу/jquery.js"></script>

</head>

Для первого знакомства давайте рассмотрим один интересный пример. В качестве этого можно привести плагин imgAreaSelect, распространяемый по лицензиям MIT и GPL (лицензии на свободное ПО). Его разработал польский программист Михал Войцеховски (Michal Wojciechowski) [4]. Для этого потребуется скачать сам плагин [5], разархивировать и подключить его к нашей странице в контейнер <head>, как было описано выше. Далее создаем в нашей странице код:

<html>

<head>

<meta http-equiv="Content-Type" content="text/html; charset=windows-1251" />

<title>Jquery</title>

<script src="js/jquery-1.2.6.js"></script>

<script src="js/jquery.imgareaselect-0.6.1.js"></script>

<script language="JavaScript" type="text/javascript">

var $x1, $y1, $x2, $y2, $w, $h;

function selectChange(img, selection)

{

$x1.text(selection.x1);

$y1.text(selection.y1);

$x2.text(selection.x2);

$y2.text(selection.y2);

$w.text(selection.width);

$h.text(selection.height);

}

 

$(document).ready(function(){

$x1 = $('#x1');

$y1 = $('#y1');

$x2 = $('#x2');

$y2 = $('#y2');

$w = $('#w');

$h = $('#h');

});

 

$(window).load(function(){

$('img#flower').imgAreaSelect({ selectionOpacity: 0, onSelectChange: selectChange });

});

</script>

</head>

<body>

<div style="float: left;">

<img id="flower" src="flower.jpg" />

</div>

<div style="float: left; margin-left: 10px;">

<p style="background: #eee; border: solid 1px #ddd; margin: 0; padding: 10px;">

<b>Координаты выделения:</b><br />

 

<b>X<sub>1</sub>:</b> <span id="x1"></span><br />

<b>Y<sub>1</sub>:</b> <span id="y1"></span><br />

<b>X<sub>2</sub>:</b> <span id="x2"></span><br />

 

<b>Y<sub>2</sub>:</b> <span id="y2"></span><br />

<br />

<b>Размеры выделения:</b><br />

<b>Width:</b> <span id="w"></span><br />

<b>Height:</b> <span id="h"></span>

</p>

</div>

</div>

</body>

</html>

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

Рисунок 1. Пример работы плагина imgAreaSelect

Рисунок 1. Пример работы плагина imgAreaSelect

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

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

Магическая функция $

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

//Код:

jQuery('div.panel');

//Эквивалентен коду:

$('div.panel');

Посмотрите на эти примеры. Они полностью эквивалентны, но второй пример кода, несомненно, выглядит более изящно. Но как же быть, если вы используете в проекте еще одну библиотеку, например, Prototype, в которой также используется функция $? Чтобы не возникало конфликтов, в JQuery на этот счет предусмотрены следующие решения:

jQuery.noConflict();

После вызова этой функции все обращения к $ будут адресованы библиотеке Prototype. Другой способ – создание анонимной функции:

(function($) {

// Внутри этого блока $ относится к jQuery

})(jQuery);

Внутри этого блока можно использовать функцию $, не опасаясь коллизий при использовании другой одноименной глобальной функции.

Готовим плацдарм

Большинство библиотек JavaScript часто используют событие window.onload. Оно вызывается после того, как документ полностью загрузился в окне браузера. Это значит, что вызываемый в обработчике этого события код не сработает, пока не загрузятся все изображения, флеш-баннеры, видеоролики и другой мультимедийный контент страницы.

JQuery предлагает очень изящное решение этой проблемы, а именно функцию ready().

$(document).ready(function() {

//Ваш код

});

Внутри этого блока код будет выполнен сразу после того, как будет готова объектная модель документа, но раньше, чем произойдет событие window.onload.

Выбираем элементы

В JQuery реализован очень интересный механизм поиска элементов, использующий CSS и XPath. То есть для нахождения требуемого элемента DOM вы можете воспользоваться как механизмом селекторов CSS, так и запросами по документу в стиле XPath.

XPath (XML Path Language) является языком для обращения к частям XML-документа. HTML, или, вернее, XHTML, является подмножеством XML, и совершенно логично, что не существует причин, по которым с помощью XPath нельзя было бы обращаться к частям HTML-документа. Вернее, их не существует для jQuery, так как эта библиотека поддерживает довольно большое подмножество XPath и легко объединяет его с некоторыми селекторами CSS для создания невероятно гибкого механизма поиска элементов на странице. Чтобы было более понятно, приведу несколько примеров.

Все элементы с атрибутом class="block":

$('.block');

Элемент p с атрибутом с id="plain":

$('p#plain');

Все видимые ссылки внутри элмента div с атрибутом id="content":

$('div#content a:visible');

Все четные строки в таблице с атрибутом class="orders":

$('table.orders tr:odd');

Все поля ввода с атрибутом name="email":

$('input[@name=email]');

Все внешние ссылки (то есть те, которые начинаются с http://);

$('a[@href^="http://"]');

Все элементы p, в которых есть хотя бы одна ссылка:

$('p[a]');

Все элементы span, являющиеся прямыми потомками элемента p, расположенные в блоке div с атрибутом id="container":

$('div#container p/span');

Как мы видим, в сочетании эти два метода дают веб-разработчику очень гибкий инструмент для выбора элементов.

Изменяем элементы

Объекты, которые возвращает функция jQuery, имеют некоторые интересные особенности.

С одной стороны, это набор элементов DOM, который обладает свойствами массива, имеет свойство lenght, к каждому элементу можно получить доступ по индексу.

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

Нет смысла описывать все доступные методы, это можно посмотреть в технической документации [3], приведу лишь несколько примеров.

Выставляет ширину блока div с атрибутом id="block" в 300 пикселей:

$('div#block').width(300);

Изменяет цвет элементов p с атрибутом class="title":

$('p.title').css('color', '#ff0000');

Применяет 2 CSS-правила для каждого нечетного пункта списка:

$('li:odd').css({color: 'white', backgroundColor: 'black'});

Добавляет стилевой класс external для всех внешних ссылок (то есть тех, которые начинаются с http://), затем добавляет для них атрибут target="_blank":

$('a[@href^="http://"]').addClass('external').attr('target', '_blank');\

Для каждого тега span на странице выводит сообщение alert() с его текстовым содержанием (включая HTML-теги):

$('span').each(function(el){alert($(this).text())});

Заменяет весь текст в ссылках на странице текстом «Нажми здесь!»:

$('a').html('Нажми здесь!');

Следует отметить, что методы JQuery обладают симметрией, то есть их можно использовать не только для изменения атрибутов элементов, но и для получения значений этих атрибутов.

Возвращает ширину первого элемента div на странице:

var width = $('div').width();

Возвращает значение атрибута src у первого элемента img на странице:

var src = $('img').attr('src');

Возвращает значение цвета первого элемента h1 на странице:

var color = $('h1').css('color');

Как было сказано выше, объект, возвращаемый функцией $, обладает свойствами массива, поэтому к любому элементу можно обратиться по индексу:

$('p')[0].className = "myclass";

В том случае, если вам необходимо пройтись по всем элементам коллекции и выполнить над ними какие-то действия, можно использовать метод each():

$('p').each(

function(){

//Действия над элементом

}

);

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

Магические цепочки (собираем все вместе)

Одной из важных особенностей JQuery является возможность объединять для преобразований в цепочки несколько вызовов селекторов. Это было показано в одном из вышеприведенных примеров. Давайте же рассмотрим эти возможности более подробно на примере связанной анимации. В нашей тестовой страничке создадим код:

<html>

<head>

<meta http-equiv="Content-Type" content="text/html; charset=windows-1251" />

<title>Jquery</title>

<style type="text/css">

#run{

border: solid 1px #000000;

background-color: #8080ff;

width: 100px;

height: 100px;

position: absolute;

top: 40px;

left: 20px;

}

</style>

<script src="js/jquery-1.2.6.js"></script>

<script language="JavaScript" type="text/javascript">

$(document).ready(function(){

$('a').click(function(){

$('div#run').

slideUp('slow').

slideDown('slow').

animate({opacity: 'hide', left: '+=400'}, 500).

animate({opacity: 'show', left: '-=400'}, 1000);

});

}

);

</script>

</head>

<body>

<a href="#">Run!</a>

<div id="run"></div>

</body>

</html>

И подробнее рассмотрим, что же происходит на этой странице (см. рис. 2).

Рисунок 2. Пример реализации функций

Рисунок 2. Пример реализации функций

 Как видно из примера, к элементу div с атрибутом id="run" применяется сразу несколько методов, выстроенных в цепочку, которые будут выполняться один за другим:

  •  slideUp – медленно скрыть элемент вверх;
  • slideDown – медленно отобразить элемент сверху;
  • animate – применить к элементу анимацию.

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

Рисунок 3. Результат работы сценария

Рисунок 3. Результат работы сценария

Магические превращения

В предыдущем примере мы затронули еще один интересный метод JQuery, а именно метод animate(). Давайте рассмотрим его более подробно. Он является одной из ключевых функций библиотеки, на которой базируются другие эффекты:

animate(params, speed, easing, callback);

 Параметрами этой функции являются:

  • params – обязательный параметр, свойства анимации в виде пар {ключ: значение};
  • speed – обязательный параметр, скорость анимации в миллисекундах;
  • easing – необязательный параметр, замедление анимации (easein – замедление к концу, easeout – ускорение);
  • callback – необязательный параметр, функция, которая будет вызвана после завершения анимации.

Функция animate является основой большинства, если не всех, эффектов JQuery. Необходимо также отметить, что эффекты применяются к элементам не сразу, а по очереди. Например, если мы написали такой код:

for(var i = 0; i < 10; i++){

$('mydiv').animate({opacity: 'hide'}, 300);

$('mydiv').animate({opacity: 'show'}, 300);

}

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

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

<html>

<head>

<meta http-equiv="Content-Type" content="text/html; charset=windows-1251" />

<title>jQuery</title>

<style type="text/css">

.block{

height: 100px;

width: 100px;

border: solid 1px #000000;

background-color: #8080ff;

margin: 5px;

}

#button{

border: solid 1px #808080;

background-color: #dfdfdf;

height: 30px;

width: 100px;

margin: 5px;

text-align: center;

cursor: pointer;

font-family: Arial;

}

</style>

<script src="js/jquery-1.2.6.js" type="text/javascript"></script>

<script type="text/javascript">

$(document).ready(function(){

$('#button').click(function(){

$('#block1').

animate({opacity: 'hide'}, 500).

animate({opacity: 'show'}, 1000);

$('#block2').

animate({opacity: 'hide'}, 500).

animate({opacity: 'show'}, 1000);

});

});

</script>

</head>

<body>

<div id="button">Go</div>

<div class="block" id="block1"></div>

<div class="block" id="block2"></div> </body>

</html>

В приведенном примере к разным элементам '#block1' и '#block2' одновременно применены одинаковые методы animate(), которые будут выполняться также одновременно.

Манипуляция свойствами элементов на странице позволяет разработчикам получать такие визуальные эффекты, которые раньше были возможны только при использовании технологии Flash. Это и плавное появление, и сокрытие объектов, плавное изменение различных свойств (цвета, размеров), движение объектов, реализация всевозможных элементов интерфейса: деревьев, drag-drop объектов и сортируемых списков.

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

Помоги себе сам

Одним из основных показателей качества библиотеки является ее расширяемость. Разумеется, эта особенность в полной мере присуща и JQuery. Она имеет очень удобный API для расширения собственной функциональности. Любой разработчик может с легкостью написать под нее свой плагин, реализующий свои методы, эффекты и даже селекторы. Достаточно следовать некоторым простым правилам. Чтобы было более понятно, давайте рассмотрим это на простом примере.

Запишем код в созданный файл:

jQuery.fn.myplugin = function()

{

alert("Мой плагин!");

return this;

};

Теперь вернемся к нашей тестовой странице и создадим в ней код:

<html>

<head>

<meta http-equiv="Content-Type" content="text/html; charset=windows-1251" />

<title>jQuery</title>

<script src="js/jquery-1.2.6.js" type="text/javascript"></script>

<script src="js/jquery.myplugin.js" type="text/javascript"></script>

<script type="text/javascript">

$(document).ready(

function()

{

$("#mydiv").myplugin();

}

);

</script>

</head>

<body>

<div id="mydiv"></div>

</body>

</html>

Плагин работает! Следует обратить внимание на то, что в конце функции мы написали return this. Это необходимо для того, чтобы можно было создавать цепочки из методов. Но это еще не все. Скорее всего, нам понадобится вызов метода с передачей в него параметров, например, в таком виде:

$("#mydiv"). myplugin(

{

key: "action",

value: "test"

}

);

Для этого можно использовать метод extend:

$.extend(target, property1, ..., propertyN)

 В данном методе:

  • target – начальный объект;
  • property1 – propertyN – объекты, свойства которых дополняют или изменяют начальный объект.

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

jQuery.fn.myplugin = function(options)

{

// Начальные параметры

var settings = {default: "Мой плагин!", value: ""};

 

// Замена параметров

settings = jQuery.extend(settings, options);

 

// Вывод новых значений

if(settings.value == "")

alert("Значение по умолчанию: " + settings.default);

else

alert("Полученное значение: " + settings.value);

return this;

};

Заменив в нашей тестовой странице строку, чтобы вызвать плагин с новыми параметрами:

$("#mydiv").myplugin({value: "Новое значение"});

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

И снова AJAX

Эпоха WEB 2.0 обязывает разработчика использовать при создании интерактивных веб-интерфейсов подход, заключающийся в фоновом обмене данными с сервером. Разумеется, речь идет об AJAX – технологии, которая в JQuery поддерживается в полной мере. По мнению некоторых разработчиков, данная библиотека имеет самый удобный API для работы с AJAX.

Для тестирования работы AJAX нам потребуется настроенный веб-сервер с любым интерпретатором серверного языка программирования, в нашем случае это будет PHP. Базовыми функциями для работы с AJAX в JQuery являются функции post() и get():

$.post(url[, params[, callback]])

$.get(url[, params[, callback]])

 В данных функциях:

  • url – адрес страницы, на которую будет отправлен запрос;
  • params – параметры, передаваемые в запросе в виде пар {ключ: значение};
  • callback – функция, которая будет вызвана в случае успешного завершения вызова.

Эти функции очень похожи друг на друга, отличаются лишь методом отправляемого запроса: POST или GET соответственно. Например, POST-запрос к странице test.php с параметрами action и id и вызов функции onGetAjax в случае успеха:

$.post(

'/test.php',

{

action: 'news',

id: 5

},

onGetAjaxs

);

function onGetAjax(data)

{

// Получение данных, отправленных сервером

alert(data);

}

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

Обратите также внимание на то, что иногда необходимо знать, каким образом была отправлена страница – запросом в браузер или через AJAX. Для этого при запросе через AJAX устанавливается HTTP заголовок HTTP_X_REQUESTED_WITH со значением XmlHTTPRequest.

На сервере при помощи PHP это можно узнать следующим образом:

<?php

if($_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest')

{

// выполнение кода

}

?>

Еще один метод для работы с AJAX, который необходимо упомянуть, – это метод load():

load(url);

 Здесь:

  • url – адрес запрашиваемой страницы на сервере.

Он передает в какой-либо элемент результат работы серверного сценария. Рассмотрим это на небольшом примере.

Допустим, у нас на сервере есть файл test.php:

<?php

echo 'Текст сформированный сервером';

?>

А в нашей тестовой странице следующий код:

$('div#mydiv').load('test.php');

В результате работы этого сценария в блок div с id="mydiv" будет записан текст, сформированный скриптом, содержащимся в файле test.php, а именно фраза «Текст, сформированный сервером».

{

"firstName": "Иван",

"lastName": "Иванов",

"address": "streetAddress": "Московское ш., 101, кв.101",

"phoneNumbers": "812 123-1234"

}

Для работы с ним в JQuery есть метод getJSON():

getJSON(url, params, callback)

 Здесь:

  • url – адрес серверной страницы;
  • params – параметры в виде {ключ: значение};
  • callback – вызываемая функция.

Чтобы было понятнее, воспользуемся опять простым примером. Код нашего тестового файла на сервере test.php:

<?php

if($_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest')

{

echo '{param: '.$_REQUEST['param'].', response: "Ответ сервера"}';

}

?>

В тестовую страницу вставьте код:

$(document).ready(function(){

$.getJSON('test.php', {param: 10}, onGetAjax);

function onGetAjax(data)

{

alert(data.param + ' ' + data.response);

}

});

После прохождения запроса ответ с сервера обрабатывается функцией eval() и полученный объект передается в функцию onGetAjax().

$('a').css('color', '#ff0000');

то после выполнения кода:

$.getScript('jstest.js');

все гиперссылки страницы будут окрашены в красный цвет.

Эпилог

Разумеется, в рамках данной статьи невозможно охватить весь инструментарий, которым располагает библиотека JQuery. Вы в любой момент можете воспользоваться технической документацией на официальном сайте фреймворка [3], а также онлайн-документацией [6], но в любом случае это не будет пустой тратой времени. Познакомившись с JQuery ближе, вы, несомненно, поймете, насколько это удобный и гибкий фреймворк, покрывающий огромный диапазон функций, предоставляя при этом удобный API для расширения собственной функциональности, работы с AJAX, визуальными эффектами и многим другим.

  1. http://jquery.com – официальный сайт разработчиков JQuery.
  2. http://docs.jquery.com/License – лицензионное соглашение.
  3. http://docs.jquery.com – техническая документация.
  4. http://odyniec.net – Михал Войцеховски.
  5. http://odyniec.net/projects/imgareaselect/imgareaselect-0.6.1.zip – плагин imgAreaSelect
  6. http://www.visualjquery.com – онлайн-справочник библиотеки JQuery.

Комментарии отсутствуют

Добавить комментарий

Комментарии могут оставлять только зарегистрированные пользователи

               Copyright © Системный администратор

Яндекс.Метрика
Tel.: (499) 277-12-41
Fax: (499) 277-12-45
E-mail: sa@samag.ru