Отправляет email-рассылки с помощью сервиса Sendsay
  Все выпуски  

Программирование скриптов на Perl'e (Выпуск №6)


Служба Рассылок Subscribe.Ru проекта Citycat.Ru

Программирование скриптов на Perl'e (выпуск 6).


Здравствуйте уважаемые подписчики.


Сегодня в выпуске:




Несколько слов перед началом


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

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

Мною было написано:

    "* - Соответствует образцу один или нуль раз;"
правильно эта запись должна выглядеть так:
    "* - Соответствует образцу нуль или большее количество раз;"
Огромное спасибо Михаилу Полыковскому за это замечание.

Кроме того, в разделе "CGI-программирование - Регистрация с подтверждением" в подразделе "Запись в файлы" в третьем от начала абзаце было написано:

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

Огромное спасибо всем, кто прислал мне письма, с указанием моих ошибок.   Как мне кажется, это является показателем того, что рассылка все-таки читаема.

Но я не совсем согласен с теми, кто прислал мне письма о блокировке файла по поводу работы функции flock.   И поэтому сегодня в разделе "CGI-программирование" я позволю себе, с некоторыми изменениями, привести один из выпусков предыдущей версии данной рассылки, когда она велась еще другим автором.  А точнее ее выпуск №3 от 19 мая 2000 г.

И еще у меня есть одна небольшая просьба.   Если Вы присылаете мне вопросы, то указывайте, пожалуйста, существующие обратные адреса почты.   А то бывает обидно, когда для ответа на какой-либо заданный в письме вопрос просидишь полдня над скриптом, затем отправишь его с письмом, а когда в следующий раз достаешь почту тут и приходит письмо от MAILER-демона, что, мол, извините, но ваше письмо отправить не могу, нет такого адреса.   На днях, вот, не смог пробиться к zavhoz@hotmail.ru а скрипт то готов...

А теперь перейдем к делу.   Сегодняшние темы:

  • Perl для начинающих - Ввод и вывод
  • CGI-программирование - Проблемы одновременного доступа




    Perl для начинающих - Ввод и вывод


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

    Сразу оговорюсь, сейчас здесь будет рассматриваться обычный консольный ввод/вывод данных для скрипта.   Это пока еще не имеет никакого отношения к написанию CGI-скриптов, но поверьте, язык Perl стоит того, чтобы программы на нем использовать и на локальной машине, для выполнения множества мелких задач.

    Для начала давайте разберемся, что вводить, откуда и куда.

    Как Вы уже знаете в Perl'e нет типов данных, в общепринятом смысле этого слова, поэтому ввод и строки символов и чисел ничем не отличается друг от друга.   Более того, Вы можете поочередно в одну и ту же переменную вводить и символы и цифры.

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

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

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

    Ну а теперь давайте с Вами поговорим о том, как вводить информацию в программах на Perl'e.   Пока что мы будем рассматривать только ввод информации с клавиатуры.

    Операторы ввода

    Самым простым оператором ввода является оператор "<>" (угловые скобки).   Он используется для ввода алфавитно-цифровой последовательности в указанную переменную из указанного источника.

    Синтаксис этого оператора для явного ввода следующий:

                  переменная=<дескриптор>;
    
    т. е. для ввода с клавиатуры Вы можете написать:
    
                  $var=<STDIN>;
    
    или проще:
    
                  $var=<>;
    
    При этом ввод в скалярном контексте заканчивается, как только встретится символ перевода строки - \n.   В списочном контексте Вы можете вводить несколько строк, разделяя их клавишей "Enter", но сам ввод закончится только тогда, когда Вы нажмете комбинацию клавиш Ctrl+D (или Ctrl+Z - смотря в какой операционной системе Вы работаете).
        Примеры:
    $var=<>;    # ввести одну строку символов
    @array=<>;  # ввести массив строк
    

    Следующий оператор ввода, который я предлагаю Вашему вниманию, берет из потока, указанного дескриптором, один символ.   Это оператор "getc". Его общий вид следующий:
                переменная=getc дескриптор;
    
    или
    
                переменная=getc;
    
    в последнем случае ввод будет осуществляться из STDIN.
    
        Пример:
    $var=getc;
    
    Если в программе реализован вызов этого оператора, то в ответ на его запрос ввода Вы можете вводить сколько угодно символов, но после нажатия клавиши "Enter" в указанной для ввода переменной окажется первый символ из введенных Вами.   Хотя с другой стороны, если в программе реализовано последовательно несколько вызовов этого оператора для разных переменных и при запросе ввода первого из них будет введено несколько символов, то после нажатия клавиши "Enter" в каждой из этих переменных окажется символ, следующий за тем, который был прочитан предыдущим вызовом оператора ввода.
        Пример:
    $var1=getc;
    $var2=getc;
    $var3=getc;
    $var4=getc;
    
    Если в ответ на первый запрос (для $var1) Вы введете "Perl", то в переменной $var1 окажется символ "P", а в переменных $var2, $var3 и $var4 - соответственно "e", "r" и "l".

    И рассмотрим еще один оператор ввода - "read", а точнее один из его видов:
                read дескриптор, переменная, длина;
    
    или
    
                read (дескриптор, переменная, длина);
    
    наличие скобок роли не играет.
    
    В отличие от предыдущих операторов ввода, этот оператор требует явного указания дескриптора ввода.   В "переменную" записывается количество символов равное полю "длина", причем это могут быть как алфавитно-цифровые символы, так и управляющие коды (табуляция -\t, перевод строки - \n и др.).

    Так же как и для оператора "getc" у оператора "read" ввод заканчивается после нажатия клавиши "Enter", но только в том случае если количество уже введенных символов (включая последнее нажатие клавиши "Enter") равно либо больше указанного для ввода количества символов.

        Пример:
    read STDIN, $var, 10   # прочитать с клавиатуры в переменную
                           # $var десять символов
    

    Операторы вывода

    Для посылки каких-либо данных на стандартный вывод в Perl'e служат функции "print" и "printf".   Давайте посмотрим, как они работают.

    Функция "print" получает список строк и посылает их по очереди на стандартный вывод, не добавляя никаких промежуточных или конечных символов.   Ее общий вид:

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

    Иногда в "print" нужно вводить круглые скобки, особенно когда первый элемент, который Вы хотите вывести, сам начинается с левой скобки:

                print (2+3)," hello"; # неверно!
    
    выводит 5, игнорируя " hello"
    
                print ((2+3)," hello"); # верно
    
    выводит 5 hello
    
                print 2+3," hello"; # тоже верно
    
    выводит 5 hello
    

    Вероятно, Вы захотите в большей степени контролировать выводимые данные, чем это позволяет функция "print".   Возможно, Вы привыкли к форматированному выводу С-функции "printf". Спешим обрадовать: в Perl'e есть почти сравнимая операция с таким же именем.

    Функция "printf" принимает список аргументов (заключенный в необязательные круглые скобки, как и в случае использования функции "print").   Первый аргумент - строка управления форматом, указывающая, как выводить остальные аргументы.   Ее общий вид:

                printf дескриптор, список;
    
    или
    
                printf список;
    
        Пример:
    printf "%15s %5d %10.2f\n", $s, $n, $r;
    
    Эта функция выводит $s в 15-символьном поле, затем пробел, затем $n как десятичное целое в 5-символьном поле, затем еще один пробел, затем $r как значение с плавающей запятой с двумя десятичными знаками в 10-символьном поле и, наконец, символ новой строки.

    И напоследок еще пара операторов вывода, сходных по своему назначению.   Это операторы "die" и "warn".

    Оба этих оператора предназначены для вывода в поток STDERR сообщения об ошибке.   Отличие между ними следующее: оператор "die" после вывода сообщения завершает работу программы, а "warn" - нет.

        Их синтаксис:
    
                die список;
                warn список;
    
        Пример:
    die "Деление на нуль.\n" if ($a==0);
    warn "Длина не может быть отрицательной.\n" if ($a<0);
    

    Вроде бы пока все с операторами ввода/вывода.




    CGI-программирование - Проблемы одновременного доступа


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

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

    У языка Perl есть встроенная функция flock.   Она позволяет "заблокировать" доступ к файлу со стороны других процессов, пока в этот файл будут вноситься какие-либо изменения.

    Синтаксис flock:   flock(дескриптор_файла, код_блокировки),
    где код_блокировки может быть равен:
    Код Описание
     1  для разделяемого доступа (совместная блокировка)
     2  для монопольного доступа (монопольная блокировка)
     4  асинхронная блокировка (функция flock не ожидает активизации блокировки)
     8  снятие блокировки

    Функция flock в Perl'е реализует так называемую "мягкую блокировку", блокируя другие вызовы flock, а не сами процессы.   Проще говоря, это не означает, что остальные программы не смогут использовать заблокированный файл, просто они не смогут получить от функции flock значение "истина".   Таким образом, если какой-то процесс не использует проверку блокировки при обращении к заблокированному файлу, то можно ожидать неприятностей.

    Пример использования функции flock:
    функция lock_file возвращает 1, если файл удалось заблокировать для монопольного доступа, и 0 - в противном случае.

    sub lock_file
    {  my $handle=shift;         # передаем дескриптор файла
       my $time_waut=20;         # количество циклов ожидания
    
          # ждем, пока файл не освободиться для монопольной блокировки
       until (flock($handle, 2))
         {  sleep(0.1);          # типа пауза
            if (--$time_wait)    # если не удалось заблокировать файл за
              {  return (0);     # определенное количество циклов, выходим
              }
         }
       return (1);               # установлена монопольная блокировка
    }
    
    sub unlock_file              # функция снятия блокировки
    {   my $handle=shift;        # передаем дескриптор файла
    
        flock($handle, 8);
    }
    
        Пример использования (из какой-то подпрограммки):
    
    open (FILE, $filename) or die "Can't open file";
    unless (&lock_file(FILE))    # Если не удается заблокировать файл, то
      {  return (34);            # выходим с кодом ошибки
      }
           #....
           # действие с файлом
           #....
    &unlock_file;                #разблокирование файла
    
    Но часто бывает так, что flock работает не верно или не справляется со своей задачей.   Причем, чем больше количество обращений в единицу времени к разделяемому ресурсу, тем больше шансов увидеть вместо корректной информации мусор.   Как же быть в таком случае???

    Почти во всех письмах, присланных мне, для этих целей используются подпрограммы, в которых создается специальный файл, наличие которого свидетельствует о недоступности в данный момент времени нужного нам ресурса (файла).   Приведу пример подпрограмм (написанный Крэйгом Патчетом (Craig A.Patchett) и Мэтом Райтом (Matthew Wright) и взятым с http://www.cgi-resources.com/).   Мне кажется, это самый удачный пример, кроме того, он лишний раз свидетельствует о том, что не надо изобретать велосипед.

    ##################################################################
    #
    # lock() Version 2.1
    # Written by Craig Patchett craig@patchett.com
    # Created 16/09/1996 Last Modified 12/05/2000
    #
    # Функция создает эксклюзивную блокировку для файла.  Блокировка
    # работает только если другие программы, пытающиеся получить
    # доступ к файлу, также используют эти подпрограммы.
    #
    # Функция возвращает:
    #       0  -  Если блокировка установлена
    #       1  -  При ошибке создания $LOCK_DIR/$filename.tmp
    #       2  -  Если $filename используется
    #       3  -  Если lock-файл не возможно открыть или создать
    #
    # Глобальные переменные:
    #       $error_message  -  информация о возникшей ошибке
    #       $NAME_LEN  -  максимальная длина файла
    #       $LOCK_DIR  -  каталог для создания файла блокировки
    #       $MAX_WAIT  -  максимальное время ожидания блокировки
    #
    # Во время работы создаются:
    #       $LOCK_DIR/$filename.tmp
    #       $LOCK_DIR/$filename.lok (существует только пока файл
    #                                заблокирован)
    #
    ##################################################################
    sub lock
    {  local($filename)=@_;
       local($wait, $lock_pid);
       local($temp_file)="$LOCK_DIR$$.tmp";
       local($lock_file)=$filename;
       $lock_file=~tr/\/\\:.//d;           # Удаляем разделители каталогов
       if ($NAME_LEN && ($NAME_LEN < length($lock_file)))
         {  $lock_file=substr($lock_file, -$NAME_LEN);
         }
       $lock_file="$LOCK_DIR$lock_file.lok";
       $error_message='';
           # Создание файла с PID
       if (!open(TEMP, ">$temp_file"))
         {  $error_message="Невозможно создать $temp_file ($!).";
            return(1);
         }
       print TEMP $$;
       close(TEMP);
           # Проверка lock-файла
       if (-e $lock_file)
         {
       #Ожидание, пока файл разблокируют (если lock-файл существует)
            for ($wait=$MAX_WAIT; $wait; --$wait)
              {  sleep(1);
                 last unless -e $lock_file;
              }
         }
       if ((-e $lock_file) && (-M $lock_file < 0))
         {  unlink($temp_file);
            $error_message="Файл \"$filename\" в данный момент используется.  Попытайтесь еще раз позднее.";
            return(2);
         }
       else
         {  if (!rename($temp_file, $lock_file))
              {  unlink($temp_file);
                 $error_message="Невозможно блокировать файл \"$filename\" ($!).";
                 return(3);
              }
           # Проверка блокировки
            if (!open(LOCK, "<$lock_file"))
              {  $error_message="Невозможно проверить блокировку файла \"$filename\" ($!).";
                 return(3);
              }
            $lock_pid=;
            close(LOCK);
            if ($lock_pid ne $$)
              {  $error_message="Файл \"$filename\" в данный момент используется.  Попытайтесь еще раз позднее.";
                 return(2);
              }
            else
              { return(0)
              }
         }
    }
    
     ##################################################################
    #
    # unlock() Version 2.1
    # Written by Craig Patchett craig@patchett.com
    # Created 16/09/1996 Last Modified 12/05/2000
    #
    # Разблокирует файл, заблокированный функцией lock()
    #
    # Возвращает:
    #       0  -  Если файл разблокирован
    #       1  -  Если нет доступа к lock-файлу
    #       2  -  Если файл заблокирован другим процессом
    #       3  -  Если невозможно разблокировать файл
    #
    # Глобальные переменные:
    #       $error_message  -  информация о возникшей ошибке
    #       $NAME_LEN  -  максимальная длина файла
    #       $LOCK_DIR  -  каталог для создания файла блокировки
    #
    # Во время работы удаляется $LOCK_DIR/$filename.lok
    #
    ##################################################################
    
    sub unlock
    {  local($filename)=@_;
       local($lock_file)=$filename;
       $lock_file=~tr/\/\\:.//d;          # Удаляем разделители каталогов
       if ($NAME_LEN;
       close(LOCK);
       if ($lock_pid ne $$)
         {  $error_message="Файл \"$filename\" заблокирован другим процессом.";
            return(2);
         }
           #Удаление lock-файла
       if (!unlink($lock_file))
         {  $error_message="Невозможно разблокировать файл \"$filename\" ($!).";
            return(3);
         }
       return(0);
    }
    
        Пример кода с использованием этих процедур.  Взято из одного из скриптов.
    
     ...
    if (&lock("$USERS_DIR$user_name/$MESSAGES_DIR$message_file"))
      {  $bad_users.=($bad_users eq "") ? $user_name : ", ".$user_name;
         next;
      }
    if(!open(BOX, ">>$USERS_DIR$user_name/$MESSAGES_DIR$message_file")
      {  &unlock("$USERS_DIR$user_name/$MESSAGES_DIR$message_file");
         $bad_users.=($bad_users eq "") ? $user_name : ", ".$user_name;
         next;
      }
    
    Ну, вот и все на сегодня с блокировками. Удачной работы.




    "Лучшая ссылка"


    Сегодня в этом разделе речь пойдет о компании, имеющей косвенное отношения к Perl'у.   Точнее говоря к Perl'у она вообще никак не относится.   Это компания Brainbench Inc. (ее адрес в Internet'е - http://www.brainbench.com/).

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

    Прежде всего о том, что это за компания.   Brainbench Inc занимается IT-сертификацией через Internet.   "А какое отношение это имеет к Perl'у?" - спросите Вы.   И будете не правы.   Один из 227 предлагаемых экзаменов - это сертификационный экзамен по Perl'у.

    Правда есть одно неудобство - все тесты и экзамены проводятся на английском языке, но если для Вас это не проблема - то вперед за IT-сертификатом.

    Девиз компании следующий: Brainbench Сертификация - Если Вы знаете что-либо, мы поможем Вам это показать!   В сегодняшнем быстро изменяющемся мире, ваша профессиональная ценность зависит от того, что Вы знаете.   Теперь Вы можете демонстрировать ваши навыки online, получая один или больше сертификатов Brainbench.

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

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

    При найме IT-профессионала, Вы часто должны обеспечить существенное обучение прежде, чем человек становится производительным.   Brainbench оценка Способностей Программиста/Аналитика предназначена, для измерения способностей человека.   Измеряются пять характеристик:

  • Способность решать математические проблемы;
  • Внимание к деталям;
  • Способность точно следовать инструкциям;
  • Моделирование процессов;
  • Аналитическое рассуждение.

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

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

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

    Для того чтобы пройти сертификацию Вам необходимо из 5 максимально возможных баллов набрать 2,75.   Но если Вам повезет, и Вы сможете набрать 4 и более баллов, то тогда получите сертификат мастера.

    Удачной Вам сертификации.




    Наши друзья


    Дорогие подписчики! Если Вы еще не заглядывали на сайт наших друзей "InfoCity - виртуальный город компьютерной документации" (http://www.infocity.kiev.ua), то Вам обязательно стоит там побывать.

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

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

    Рассылки Subscribe.Ru
    Новости компьютерной библиотеки InfoCity

    Адрес рассылки "Новости компьютерной библиотеки InfoCity" в Каталоге subscribe.ru: http://subscribe.ru/catalog/comp.paper.infocity/

    Архив рассылки "Новости компьютерной библиотеки InfoCity" находится на subscribe.ru по адресу: http://subscribe.ru/archive/comp.paper.infocity/

    InfoCity - виртуальный город технической документации.



    Предлагаю Вашему вниманию еще одного из наших друзей, который имеет непосредственное отношение к тематике этой рассылки, сайт посвященный скриптам:   "WebScript.Ru - каталог скриптов".   Его адрес в Internet'е - http://webscript.ru/ и там Вы найдете множество готовых скриптов как на Perl'e, так и на РНР.

    На этом сайте существуют следующие разделы:

  • Веб-технологии;
  • Новости сайта;
  • Новости Perl;
  • Новости РНР;
  • Статьи по Perl;
  • Статьи по РНР.

    Кроме того, предлагаю Вашему вниманию рассылку, посвященную новостям этого сайта, новым поступлениям скриптов и темам на форуме, а также новостям из мира Perl'а и PHP - "Новости сайта "Каталог скриптов (Perl & PHP)"".

    Подписаться на нее можно здесь:

    Рассылки Subscribe.Ru
    Новости сайта "Каталог скриптов (Perl & PHP)"

    Адрес рассылки "Новости сайта "Каталог скриптов (Perl & PHP)"" в Каталоге subscribe.ru: http://subscribe.ru/catalog/inet.webbuild.webscript/

    Архив рассылки "Новости сайта "Каталог скриптов (Perl & PHP)"" находится на subscribe.ru по адресу: http://subscribe.ru/archive/inet.webbuild.webscript/

    Заходите - Вам понравится.




    О рассылке


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

    Домашняя страница этой рассылки в Каталоге subscribe.ru: http://subscribe.ru/catalog/comp.soft.prog.perlprog/, здесь же Вы можете и подписаться на данную рассылку.

    Архив этой рассылки находится на subscribe.ru по адресу: http://subscribe.ru/archive/comp.soft.prog.perlprog/

    Данная рассылка распространяется только через subscribe.ru.

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




    Обращение к рекламодателям


    Уважаемые господа!   Если Вы хотите разместить свою рекламу на страницах этой рассылки, то обращайтесь со своими предложениями к ее автору, то есть ко мне, по адресу vitalij@newmail.ru и я сообщу Вам дополнительные сведения.




    На сегодня все.   До новых встреч.


    Виталий Ярошевский vitalij@newmail.ru


    При подготовке данной рассылки были использованы следующие материалы:

    1. "Изучаем Perl"           Рэндал Шварц, Том Кристиансен   (Перевод с английского C. M. Тимачева)



    http://subscribe.ru/
    E-mail: ask@subscribe.ru

    В избранное