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

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

Интеграция Open Source-решений  

Open Source в облачной среде

Облачные решения становятся всё более популярными в мире. Компании стремятся использовать их для

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

Автоматизация  

Нейросеть вам в руки! Как использовать ИИ для автоматизации задач

Использование ИИ для автоматизации задач помогает компании получить конкурентное преимущество, поскольку объединение

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

Рынок труда  

Специалист по этическому ИИ, инженер по квантовым вычислениям или аналитик по метавселенной?

Новые тенденции в развитии ИТ могут привести к возникновению новых специальностей в

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

Книжная полка  

Учитесь убеждать и побеждать

Издательство «БХВ», как всегда, порадовало своих читателей хорошими книжными новинками. Кроме популярных

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

Сетевая инфраструктура  

Как удаленная работа меняет подход к сетевой инфраструктуре?

С увеличением числа сотрудников, работающих из дома, организации сталкиваются с необходимостью создания

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

Мониторинг  

Какой мониторинг нужен сегодня?

По мнению экспертов ГК InfoWatch, действия сотрудников – самая распространенная причина инцидентов

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

Книжная полка  

Руководство для тех, кто увлечен ИИ, программированием. И дизайном

Накануне лета издательство «БХВ» выпустило книжные новинки, от которых любителям чтения будет

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

Мобильные приложения  

Искусственный интеллект в мобильных приложениях: возможности и перспективы

Обзор современных применений ИИ в мобильных приложениях, анализ перспектив развития этой технологии,

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

ИТ-образование  

Как сделать ИТ-образование эффективным?

Эксперты ИТ-отрасли отвечают на вопросы «СА». Обсуждаем ключевые аспекты для улучшения образовательных

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

Work-life balance  

Как айтишнику найти баланс между работой и личной жизнью?

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

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

Книжная полка  

Всё самое нужное – под одной обложкой

Отличительная черта книжных новинок, выпущенных недавно издательством «БХВ» – это их универсальность. Не просто

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

ИТ-инфраструктура  

Системы мониторинга ИТ-инфраструктуры-2025

Без мониторинга ИТ-инфраструктуры не обходится ни одна компания, хотя бы потому, что

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

Открытое ПО  

Безопасность Open Source: рискуем или контролируем?

Компания «Кросс технолоджис» изучила, как используется ПО с открытым кодом в компаниях

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

Работа с нейросетью  

Скажи, есть ли у тебя AI, и я скажу, кто ты

Недавно сервис по поиску работы SuperJob выяснил, что каждый второй россиянин уже

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

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

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

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

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

12.03.2018г.
Просмотров: 7235
Комментарии: 0
Глубокое обучение с точки зрения практика

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

12.03.2018г.
Просмотров: 4513
Комментарии: 0
Изучаем pandas

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

12.03.2018г.
Просмотров: 5307
Комментарии: 0
Программирование на языке Rust (Цветное издание)

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

19.12.2017г.
Просмотров: 5317
Комментарии: 0
Глубокое обучение

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

19.12.2017г.
Просмотров: 7991
Комментарии: 0
Анализ социальных медиа на Python

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

19.12.2017г.
Просмотров: 4675
Комментарии: 0
Основы блокчейна

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

19.12.2017г.
Просмотров: 4922
Комментарии: 0
Java 9. Полный обзор нововведений

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

16.02.2017г.
Просмотров: 8962
Комментарии: 0
Опоздавших не бывает, или книга о стеке

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

17.05.2016г.
Просмотров: 12396
Комментарии: 0
Теория вычислений для программистов

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

30.03.2015г.
Просмотров: 13936
Комментарии: 0
От математики к обобщенному программированию

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

18.02.2014г.
Просмотров: 15705
Комментарии: 0
Рецензия на книгу «Читаем Тьюринга»

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

13.02.2014г.
Просмотров: 10580
Комментарии: 0
Читайте, размышляйте, действуйте

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

12.02.2014г.
Просмотров: 8609
Комментарии: 0
Рисуем наши мысли

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

10.02.2014г.
Просмотров: 6817
Комментарии: 4
Страна в цифрах

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

18.12.2013г.
Просмотров: 5966
Комментарии: 0
Большие данные меняют нашу жизнь

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

18.12.2013г.
Просмотров: 4890
Комментарии: 0
Компьютерные технологии – корень зла для точки роста

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

04.12.2013г.
Просмотров: 4534
Комментарии: 0
Паутина в облаках

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

03.12.2013г.
Просмотров: 4757
Комментарии: 1
Рецензия на книгу «MongoDB в действии»

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

Друзья сайта  

 Автоматизация веб-проектов через электронную почту

Архив номеров / 2004 / Выпуск №4 (17) / Автоматизация веб-проектов через электронную почту

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

Игорь Тетерин

Автоматизация веб-проектов через электронную почту

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

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

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

Такой вот обьем работы ради того, чтобы добавить один раздел. А кто-то ведь еще работает и делает это через dial-up. Любой, кто занимался этим, поймет – эта работа для орков. Мы же – программисты.

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

Новый принцип автоматизации. Основы. Сравнения

Как-то давно, когда я писал ret 0.8 (ядро для интернет-сайтов), мой друг заметил, что было бы весьма удобно, если бы сайтом можно было управлять через электронную почту. Тогда мы не уделили этому вопросу должного внимания. Позднее – только вспоминали про эту технологию. И вот, наконец, я решил испробовать это на одном разделе своего сайта http://revda.biz.

Написал простой скрипт, который читает почту из рассылки и публикует все, что попадет, на сайт. И тут я понял, что это очень удобно! Люди, которые писали в рассылку, просто переписывались, при этом страница сайта была в постоянном движении. Те, кто заходил на эту страницу, знали и понимали – за новой информацией туда можно заходить каждый день. Да, пока это больше похоже на обычный интернет-трэд, но все же!

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

Грубо говоря, наш почтовый ящик стал централизованным источником информации. Этого обычно не скажешь о веб-интерфейсе, где приходится (по большей части) кого-то напрягать, заставлять или самому работать ручками. Более того – мы можем автоматически обрабатывать не один ящик, а несколько, закрепив за каждым свою тематику.

Этот подход также решает вопрос вашего присутствия в Интернете. Так как мы работаем с почтовым ящиком, то для того, чтобы обработать материал, ответить кому-то или сделать что-то еще, нам достаточно просто скачать почту, поработать с ней и отослать ответы.

Пока все выглядит очень красиво. Однако, чтобы создать нечто подобное в реальности, нам придется ввязаться в битву с одним, а может, и двумя, самыми запутанными стандартами: MIME и HTML.

Победить в битве с HTML достаточно трудно – это довольно противоречивый и очень динамичный стандарт. Тут придется не один раз приложить и руки, и голову. В рамках нашей задачи мы коснемся его только слегка.

Выбор платформы, языка и оценка задачи

На чем будет работать наш обработчик почты? Ответ очевиден, если предположить, что все должно работать и на Windows, и на UNIX-платформах. Мы не станем ограничивать себя чем-то одним, поэтому после разработки обработчика сможем использовать его и там, и там. А это весьма удобно.

На чем будем писать? Немного подумаем. Учитывая, что PHP я не знаю и знать не хочу, остается один выбор – Perl. К тому же Perl, с моей точки зрения, концептуально более правильный язык и больше подходит на роль стандартного. Но не это важно, важны принципы и алгоритм, а реализовывать можно хоть на Ruby.

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

Что же нам потребуется? Один почтовый ящик, хостинг (хотя можно и локально) с поддержкой Perl и несколькими дополнительными модулями с CPAN. Ну и остальное «огнестрельное оружие», вроде putty, far, TheBat и т. д.

Переходим к практике

Рассмотрим очень простой пример. Первое, что нам потребуется – подключение нужных модулей:

use Net::POP3;use MIME::Parser;

use MIME::Entity;

use MIME::Head;

use MIME::Body;

use MIME::Words qw(:all);

use MIME::QuotedPrint;

use MIME::Base64;

Определим основные объекты и переменные:

my $parser = MIME::Parser->new;

$parser->output_to_core(1);

$parser->tmp_to_core(1);

$mail_server='127.0.0.1';

$username='login';

$password='password';

Теперь получим список писем:

$pop = Net::POP3->new($mail_server)

        or die "Can't open coonection to $mail_server :$!\n";

$pop->login($username, $password)

        or die "Can't Authenticate: $!\n";

$messages = $pop->list

        or die "Can't get listof undeleted messages: $!\n";

Начинаем обрабатывать каждое письмо:

foreach $msgid (keys %$messages)

    {

        $message = $pop->get($msgid);

        unless (defined $message)

            {

            warn "Couldn't fetch $msgid from server: $!\n";

            next;

            }

Следующий метод изначально был взят у Рэндола Шварца. Если вы поищете в Сети, то найдете нечто вроде Perl-Column, мне встречался даже перевод, правда, неполный.

Далее следует примерно такой алгоритм: если в письме есть часть типа text/plain, то берется именно эта часть, а все остальное игнорируется.

Таким образом, если мы встречаем письмо, где есть HTML-часть и текст, то в качестве входящих данных берется именно текст. Если текстовой части нет – письмо игнорируется.

        $pop->delete ( $msgid );

        @message = @$message;

        $ent = $parser->parse_data ( \@message );

        $bodyCoding = $ent->head->mime_attr( 'Content-type.charset' );

        $origType = $ent->head->get( 'Content-Transfer-Encoding',0 );

        if ( $ent->effective_type eq 'text/plain' )

            {

            # письмо - только текст

            $bodyCoding = $ent->head->mime_attr (

'Content-type.charset');

            $origType = $ent->head->get(

'Content-Transfer-Encoding',0 );

            $body = $ent->body_as_string;

            }

        elsif (

$ent->effective_type eq 'multipart/alternative'

                 and $ent->parts(0)->effective_type eq 'text/plain' )

                 {

      # письмо, где первая часть мультипар - текст

      $bodyCoding = $ent->parts(0)->head->mime_attr(

'Content-type.charset' );

      $origType = $ent->parts(0)->head->get(

'Content-Transfer-Encoding',0 );

      $body = $ent->parts(0)->body_as_string;

      }

  elsif (

$ent->effective_type eq 'multipart/alternative'

            and $ent->parts(1)->ffective_type eq 'text/plain' )

                 {

      # письмо, где вторая часть мультипарт - текст

      $bodyCoding = $ent->parts(1)->head->mime_attr(

'Content-type.charset');

      $origType = $ent->parts(1)->head->get(

'Content-Transfer-Encoding',0 );

      $body = $ent->parts(1)->body_as_string;

      }

  else {next}

  chomp $origType;

Чем универсален этот код, так это тем, что в нём происходят все стандартные MIME-декодировки – Base64 и Quoted-Printable – и перекодирование из ISO и KOI в Windows-1251.

        # Если закодировано, декодируем его, во имя счастья

        if (lc($origType) eq 'quoted-printable')

            { $body  =  MIME::QuotedPrint::decode($body); }

        if (lc($origType) eq 'base64')

            { $body  =  MIME::Base64::decode($body); }

        $bodyCoding = lc($bodyCoding);

        # Перекодировка кирилицы у тела, если надо.

        if ($bodyCoding ne '')

            {

      if ($bodyCoding eq 'koi8-r') {$bodyCoding = 'koi'}

            if ($bodyCoding eq 'koi8r') {$bodyCoding = 'koi'}

            if ($bodyCoding eq 'iso8859-5') {$bodyCoding = 'iso'}

            if ($bodyCoding eq 'koi8-u') {$bodyCoding = 'koi'}

      if ($bodyCoding eq 'koi' || $bodyCoding eq 'iso')

                { $body = encoder($body, $bodyCoding, 'win') }

        }

        $subj  =  join( "",

map {xcode( ${$_}[1], ${$_}[0])}

     decode_mimewords(

         $ent->head->get('Subject',0)

     )

      );

  $date = $ent->head->get('Date',0);

  }

Собственно, все. Переменная $subj содержит тему письма, $body – тело письма, а $date – дату. Остальные параметры письма вы сможете легко получить, используя уже подключенные в программе модули.

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

        use collector;

        ($r) = Add2Revorum ( \$subj, \$body, \$date );

где модуль collector.pm – часть моего движка сайта, которая создает необходимую структуру и, используя ядро ret WebOS и модуль Storable, пишет её базу (обычные плоские файлы).

О проблеме альтернативной СУБД я напишу в другой статье. Те, кого это заинтересовало, могут обратиться за подробностями по интернет-адресу: http://jkeks.far.ru/ret.

Подпрограммы или процедуры, ответственные за перекодировку:

sub xcode {

  # определяем кодировку и вызываем перекодировщик, если нужно

  my ($charset, $src)  =  @_;

  my %charsets = (

    'windows-1251' =>'win',

    'iso8859-5' =>'iso',

    'koi8-r' =>'koi',

    'koi8r' =>'koi',

    'koi8-u' =>'koi',

  );

  return $src unless ($charsets{lc($charset)});

  return encoder($src, $charsets{lc($charset)}, 'win');

}

Огромная благодарность российскому разработчику библиотек pvd – Денису Познякову (Denis Poznyakov, pvdenis@usa.net) – за минимальный код перекодировки русских символов. Перекодировка основывается на данных полей письма, тут нет попытки создания какого-либо анализатора.

sub encoder {

  my $enstring = shift; my $cfrom = shift; my $cto = shift;

  my %codefunk = (

    win => "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF\xD0\xD1\xD2\xD3\xD4\xD5\xD6\xD7\xD8\xD9\xDA\xDB\xDC\xDD\xDE\xDF\xE0\xE1\xE2\xE3\xE4\xE5\xE6\xE7\xE8\xE9\xEA\xEB\xEC\xED\xEE\xEF\xF0\xF1\xF2\xF3\xF4\xF5\xF6\xF7\xF8\xF9\xFA\xFB\xFC\xFD\xFE\xFF",

    koi => "\xE1\xE2\xF7\xE7\xE4\xE5\xF6\xFA\xE9\xEA\xEB\xEC\xED\xEE\xEF\xF0\xF2\xF3\xF4\xF5\xE6\xE8\xE3\xFE\xFB\xFD\xFF\xF9\xF8\xFC\xE0\xF1\xC1\xC2\xD7\xC7\xC4\xC5\xD6\xDA\xC9\xCA\xCB\xCC\xCD\xCE\xCF\xD0\xD2\xD3\xD4\xD5\xC6\xC8\xC3\xDE\xDB\xDD\xDF\xD9\xD8\xDC\xC0\xD1",

    iso => "\xB0\xB1\xB2\xB3\xB4\xB5\xB6\xB7\xB8\xB9\xBA\xBB\xBC\xBD\xBE\xBF\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF\xD0\xD1\xD2\xD3\xD4\xD5\xD6\xD7\xD8\xD9\xDA\xDB\xDC\xDD\xDE\xDF\xE0\xE1\xE2\xE3\xE4\xE5\xE6\xE7\xE8\xE9\xEA\xEB\xEC\xED\xEE\xEF",

    dos => "\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8A\x8B\x8C\x8D\x8E\x8F\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9A\x9B\x9C\x9D\x9E\x9F\xA0\xA1\xA2\xA3\xA4\xA5\xA6\xA7\xA8\xA9\xAA\xAB\xAC\xAD\xAE\xAF\xE0\xE1\xE2\xE3\xE4\xE5\xE6\xE7\xE8\xE9\xEA\xEB\xEC\xED\xEE\xEF",

    koi_lc => "tr/\xB3\xE0-\xFF/\xA3\xC0-\xDF/",

    koi_uc =>"tr/\xA3\xC0-\xDF/\xB3\xE0-\xFF/",

    win_lc => "tr/\xA8\xC0-\xDF/\xB8\xE0-\xFF/",

    win_uc =>"tr/\xB8\xE0-\xFF/\xA8\xC0-\xDF/",

    alt_lc => "tr/\xF0\x80-\x9F/\xF1\xA0-\xAF\xE0-\xEF/",

    alt_uc => alt_lc => "tr/\xF1\xA0-\xAF\xE0-\xEF/\xF0\x80-\x9F/",

    iso_lc => "tr/\xA1\xB0-\xCF/\xF1\xD0-\xEF/",

    iso_uc => "tr/\xF1\xD0-\xEF/\xA1\xB0-\xCF/",

    dos_lc => "tr/\x80-\x9F/\xA0-\xAF\xE0-\xEF/",

    dos_uc => "tr/\xA0-\xAF\xE0-\xEF/\x80-\x9F/",

    mac_lc => "tr/\xDD\x80-\xDF/\xDE\xE0-\xFE\xDF/",

    mac_uc => mac_lc => "tr/\xDE\xE0-\xFE\xDF/\xDD\x80-\xDF/"

  );

  if (!$enstring or !$cfrom or !$cto) {return 0}

  else {

    if ($cfrom ne "" and $cto ne "lc" and $cto ne "uc") {

      $_ = $enstring;$cfrom = $codefunk{$cfrom};$cto = $codefunk{$cto};

      eval "tr/$cfrom/$cto/"; return $_;

    }

    elsif (($cfrom ne "") and ($cto eq "lc" or $cto eq "uc")) {

      $_ = $enstring; $cfrom = $codefunk{"$cfrom\_$cto"};

      eval $cfrom; return $_;

    }

  }

  return $enstring;

}

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

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

Поэтому процедура xcode при работе с такими заголовками не диагностировала необходимость перекодирования. Немного подумав, была придумана небольшая модификация. Это не панацея, а скромная попытка перекрыть некоторые проблемы – угадать кодировку KOI8-R в заголовке. Для этого внесем только одну коррективу в процедуру xcode – чуть усилим проверку:

    # закомментируем строку, возвращающую неизмененный

    # заголовок и продолжим проверку:

    # return $src unless ($charsets{lc($charset)});

    unless ($charsets{lc($charset)})

      {

    # если кодировка неопределенна, считаем вхождение

    # больших и маленьких русских букв

      $upper = "ЁЙЦУКЕНГШЩЗХЪФЫВАПРОЛДЖЭЯЧСМИТЬБЮ";

      $lower = "ёйцукенгшщзхъфывапролджэячсмитьбю";

      $ucount = eval("\$src =~ tr/$upper/$upper/;");

      $lcount = eval("\$src =~ tr/$lower/$lower/;");

      # если больших букв больше - скорее всего это KOI8

    # и мы перекодируем это в Windows

      return encoder($src, 'koi', 'win') if ($ucount > $lcount);

    # иначе, как и ранее, возвращаем неизмененный заголовок

      return $src;

      }

Собственно, идея основана на том факте, что слово «Новость» в кодировке KOI будет восприниматься как «оПЧПУФШ» в кодировке Windows. Прием довольно спорный, но имеет право на существование. Абсолютно не применим на больших объемах текста – поверьте на слово.

Тема безопасности, аутентификация, вклинивания

Любое письмо, попавшее на ящик, может стать атакой или просто спамом. Как с этим бороться?

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

Описанный выше сценарий также подходит к делу принципиально. Принимаются только те сообщения, которые пришли в виде текста. Кроме того, вырезаются баннеры, расположенные обычно после символов «\n— \n» (это – стандарт TheBat). Также скрипт соблюдает логику: «можно только то, что разрешено», а не «можно то, что не запрещено».

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

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

Немного рекламы

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

Ради этого всего появилось на свет ядро ret WebOS, которое (как одно из направлений) предлагает альтернативу серверу SQL. Код системы минималистичен и для своей работы требует лишь наличия модуля Storable (который входит в стандартную поставку с Perl 5.8).

В свою очередь модуль blogs.pm предоставляет возможность хранить структуры данных любой сложности и осуществлять к ним доступ как к разделам сайта. Данные хранятся в плоских файлах. Интернет-адрес проекта: http://jkeks.far.ru/ret. Добро пожаловать!


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

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

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

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

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