Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Последние темы форума

Показать новые сообщения »
реклама
За малые деньги ф2 2 по выгодным ценам.

Почтовая рассылка

Подписчиков: 11766
Последний выпуск: 19.06.2015

Hаиболее часто задаваемые вопросы в конференции RU.DOS.BASIC

                       BASIC FAQ
           Hаиболее часто задаваемые вопросы
          в конференции RU.DOS.BASIC (часть 1)
=============================================================
               (C) Gregory Zeldner 1999
               ~~~~~~~~~~~~~~~~~~~~~~~~
Все права на данный документ принадлежат автору. Приветству-
ется некоммерческое использование и распространение  в  сети
Fidonet.  Полный или частичный форвард в другие сети катего-
рически запрещается.

=============================================================

Q: Чем отличаются между собой QuickBASIC,  QBASIC и Microsoft
   BASIC Professional Development System (PDS)?
Q: Почему обсуждение Visial BASIC for DOS является оффтопиком?
Q: Существуют ли реализации языка BASIC других фирм?
Q: Какие существуют конференции со сходной тематикой?
Q: Где можно найти QBASIC, QuickBASIC и PDS?
Q: Почему никогда не следует использовать оператор GOTO?

Q: Что такое модульное программирование?
Q: Как ввести малую русскую букву "р" в среде QuickBASIC?
Q: Как подключить мышь?
Q: Как прочитать содержимое текущей директории?
Q: Как вернуть ERRORLEVEL - код завершения программы?
Q: Как передать управление большой внешней программе и  вернуться
   обратно?

> Q: Чем отличаются между собой QuickBASIC,  QBASIC и  Microsoft
> BASIC Professional Development System (PDS)?

QuickBASIC.
     Создание Microsoft QuickBASIC (сокращенное обозначение _ QB)
в середине 80-х годов произвело настоящую революцию в мире BASIC,
результатом  которой было то,  что впервые этот язык занял доста-
точно прочные позиции среди средств разработки серьезных приклад-
ных систем.В QuickBASIC в достаточно полной мере реализованы идеи
структурного и модульного программирования, возможности использо-
вания процедур и функций.
     Специфика технологии программирования в среде QB определяет-
ся наличием в ней двух трансляторов _ интерпретатора и компилято-
ра.  Основу интегрированной среды, в которой выполняется основной
объем разработки и отладки программы, составляет Интеллектуальный
редактор и интерпретатор компилирующего типа (ИКТ). ИКТ _ это но-
вый тип интерпретатора,  который производит предварительные "ком-
пиляцию и компоновку" программы в специальный псевдокод,  а затем
уже ее выполнение.  При завершении отладки программы пользователь
может  создать  исполняемый  EXE-модуль с помощью настоящего ком-
пилятора и компоновщика программ.

QBASIC.
     Hачиная с версии MS-DOS  5.0,  вместо  устаревшего  GW-BASIC
фирма  Microsoft стала поставлять систему QBASIC,  которая предс-
тавляет собой усеченный вариант QuickBASIC без компилятора и  не-
которых возможностей модульного программирования.  QBASIC, конеч-
но,  может вполне использоваться для обучения и написания неболь-
ших программок,  но не для сколь-нибудь серьезной работы.  И дело
здесь не только в невозможности создавать исполняемые  модули.  В
версии  QBASIC  программа  может состоять только из одного модуля
(отсутствует операция LOAD) и следовательно  нельзя  загружать  и
использовать ранее созданные модули.  А на разработке по принципу
"напиши по новой всю программу от начала до конца" далеко, конеч-
но, не уедешь.


MICROSOFT BASIC PROFESSIONAL DEVELOPMENT SYSTEM (PDS)
     В 1989  году появилась Microsoft Basic Professional Develoр-
ment System (система для профессиональной разработки) версии 7.0,
а  на  следующий  год ее сменила версия 7.1.  Сегодня ее называют
Microsoft BASIC или просто PDS.  Это дальнейшее логическое разви-
тие QB 4.5 и в этом плане название QuickBASIC Extended (расширен-
ный) вполне оправдано.
     Краткая характеристика Basic PDS,  по сравнению  с  QB  4.5,
заключается  в  следующем:  он  позволяет  создавать более мощные
программные комплексы и расширить круг решаемых задач за счет ис-
пользования  дополнительных возможностей процессора и оперативной
памяти, новых средств разработки программ, встроенной системы уп-
равления большими базами данных,  а также повышения эффективности
программного кода (объем  памяти,  быстродействие).  Кроме  новых
возможностей,  в PDS исправлены ряд ошибок QB,  в частности,  нет
проблем с вводом прописной русской буквы "р".  Большинство приме-
ров программ  в  данном FAQ ориентированы в первую очередь на ис-
пользование PDS.

> Q: Почему обсуждение Visial BASIC for DOS является оффтопиком?

A: VBDOS является не более чем утяжеленной версией PDS. Абсолютно
все возможности VBDOS (за исключением средств  визуального  прог-
раммирования) имеются и в PDS. А для программиста, имеющего навык
работы с предыдущими версиями BASIC фирмы Microsoft средства  ви-
зуального  программирования  явяются совершенно чужеродными,  так
как фактически требуют изучить новый язык, не нужный при програм-
мировании в текстовом режиме DOS. Именно новый, поскольку объект-
ные конструкции Visual интерфейса мало  похожи  на  "человеческий
язык",  столь милый сердцу приверженцев BASIC, а более напоминают
"инопланетные" конструкции C или Pascal.  Так что любителям визу-
ального  программирования  в  этой  эхе делать нечего - их ждут в
RU.VISIAL.BASIC.

>  Q: Существуют ли реализации языка BASIC других фирм?

A: Разумеется, фирма Microsoft не является единственным разработ-
чиком систем BASIC. Существуют также версии GFA, True, Power, Z и
некоторые другие,  но они не получили столь широкое распростране-
ние _ отношение объема продаж языков BASIC фирмы Microsoft к реа-
лизациям BASIC остальных фирм составляет 12:1.

> Q: Какие существуют конференции со сходной тематикой?

A: Таких конференций,  насколько мне известно,  две. Это междуна-
родные конференции BASIC7 (посвященная обсуждению PDS) и QUIK_BAS
(QuickBASIC).

>Q: Где можно найти QBASIC, QuickBASIC и PDS?

Internet: FTP Directory: ftp://195.96.66.201/pub/pds/

PDS71-1.ZIP. . . . . . . . . . .  [Nov 17 21:13]    979k
PDS71-2.ZIP. . . . . . . . . . .  [Nov 17 21:23]   1064k
PDS71-3.ZIP. . . . . . . . . . .  [Nov 20 09:20]   1010k
PDS71-4.ZIP. . . . . . . . . . .  [Nov 20 09:33]   1070k
PDS71-5.ZIP. . . . . . . . . . .  [Nov 20 09:39]   1046k
QB45_1.ZIP. . . . . . . . . . . . [Nov 20 09:40]    162k
QB45_2.ZIP. . . . . . . . . . . . [Nov 20 09:42]    242k
QB45_3.ZIP. . . . . . . . . . . . [Nov 20 09:43]    212k
QB45_4.ZIP. . . . . . . . . . . . [Nov 20 09:44]    188k
QB45_5.ZIP. . . . . . . . . . . . [Nov 20 09:45]    277k
QBASIC.ZIP . . . . . . . . . . .  [Nov 17 21:07]    294k

FIDO:

- Freq from 2:5020/1967 (00:00-05:30 MSK)

PDS:        BC7_*.ZIP
QuickBASIC: QB45_*.ZIP
QBASIC:     QBASIC@.ZIP

а также дpугие полезные пpогpаммы:

PCX Programmer ToolKit 3.51:  PCX*.ZIP

[Если кто-нибудь хочет выкладывать эти программы для свободного доступа -
напишите об этом мне, я пополню список :) ]


>Q: Почему никогда не следует использовать оператор GOTO?

A: Оператор GOTO _ старейший и неструктурированный оператор языка
BASIC.  Программу с обилием GOTO трудно читать,  отлаживать,  мо-
дифицировать, так как она не имеет четкой структуры.
     Использование в  программе  оператора GOTO свидетельствует о
том,  что программист не полностью овладел всем богатством управ-
ляющих структур языка QuickBASIC, или не знает их возможностей, а
кроме того,  не существует программных конструкций,  где действи-
тельно было бы необходимо применение оператора GOTO.
     Приведу примеры того,  как можно избежать применения GOTO  и
других устаревших  конструкций,  которые достались QuickBASIC "по
наследству" от GWBASIC.

     Как получить код нажатой клавиши:
     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     m1: A$ = INKEY$: IF A$ = "" GOTO m1

     Эту конструкцию можно переписать,  используя цикл  DO...LOOP
WHILE:

     DO: A$= INKEY$: LOOP WHILE A$ = ""

     Как выйти из цикла по условию:
     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     FOR i = 1 TO 1000
     ...
        IF Flag% = TRUE THEN GOTO m999
     ...
     NEXT i
        .
        .
        .
     m999:

     В этом  случае можно воспользоваться альтернативным выходом
из цикла FOR...NEXT _ EXIT FOR:

     FOR i = 1 TO 1000
     ...
        IF Flag% = TRUE THEN EXIT FOR
     ...
     NEXT i
        .
        .
        .

     Точно также можно выйти и из цикла DO...LOOP:

     DO
     ...
        IF Flag% = TRUE THEN EXIT DO
     ...
     LOOP
        .
        .
        .

     Предвижу вопрос:  а если нужно выйти из середины конструкции
WHILE...WEND  _  ведь  оператор EXIT WHILE не предусмотрен (также
как и EXIT SELECT)?  Казалось,  бы _ ведь в таких  случаях  можно
просто написать:

     WHILE A$ <> "Конец"
     ...
        IF Flag = FALSE THEN GOTO m998
     ...

     WEND
        .
        .
        .
     m998:

     Я считаю,  что и в этом случае применение оператора GOTO из-
лишним. Конечно,  чтобы обойти это ограничение приходится идти на
хитрость _ обрамлять конструкцию бесконечным циклом DO...LOOP  и
выходить с  помощью  EXIT  DO  _ даже в этом случае,  это гораздо
удобнее, нагляднее, и я бы сказал красивее:

     DO
        WHILE A$ <> "Конец"
        ...
           IF Flag = FALSE THEN EXIT DO
        ...
        WEND
     LOOP
        .
        .
        .

     Также можно организовать и "EXIT SELECT":

     DO
        INPUT Kod
        SELECT CASE KOD
           CASE IS = ...
           ...
           CASE IS = 0: EXIT DO
           ...
           CASE ELSE ...
           ...
        END SELECT
     LOOP

     Как избежать синдрома "+жика в тумане"
     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     При организации  ветвления бесконечные операторы GOTO мешают
понять логику программы:

     30 INPUT A
        IF A > 100 THEN PRINT "Это много": GOTO 30
        IF A = 100 THEN GOTO 300
        PRINT A/100: GOTO 30
     ...

     300 ...

     Вместо этого можно использовать или блочную форму оператора
IF...THEN...ELSE в окружении цикла DO...LOOP WHILE:

     DO
        INPUT A
        IF A < 100 THEN
           PRINT A / 100
        ELSEIF A > 100 THEN
           PRINT "слишком много"
        END IF
     LOOP WHILE A <> 100
        .
        .
        .

     ...или конструкцию  SELECT...CASE  в  окружении цикла DO ...
LOOP

     DO
        INPUT A
        SELECT CASE A
           CASE IS < 100: PRINT A / 100
           CASE IS > 100: PRINT "слишком много"
           CASE IS = 100: EXIT DO
        END SELECT
     LOOP
        .
        .
        .
     Как правильно "разветвиться"
     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     При организации  ветвления  вместо  устаревшей   управляющей
конструкции ON...GOSUB используйте более современную кон-струкцию
SELECT...END SELECT:

     m0: INPUT A
        ON A GOSUB m1, m2, m3, m3, m4, m4, m4
        GOTO m5
        m1:
          ...
        X = y * z
          ...
        RETURN
        m2:
          ...
        RETURN
        m3:
          ...
        RETURN
        m4:
          ...
        RETURN
        m5: ...

    Hе правда ли,  с первого раза трудно понять, что это фрагмент
программы делает. Приходится проговаривать про себя: "Если значе-
ние A равно единице,  то ... перейти на метку... метку m1, вычис-
лить  значение  X  ...  вернуться  на  следующий  оператор пос-ле
ON...GOSUB ... это переход на метку m5 ... метка m5 _ это продол-
жение выполнения программы..."

     Посмотрите, насколько  удобнее использование конструкции SE-
LECT...END SELECT:

     INPUT A
     SELECT CASE A
        CASE IS = 1:
        ...
        X = y * z
        ...
        CASE IS = 2
        ...
        CASE IS = 3, 4
        ...
        CASE 5 TO 7
        ...
     END SELECT

     "Если значение A равно единице,  вычислить значение X и  по-
кинуть SELECT...END SELECT".


>Q: Что такое модульное программирование?

     При разработке  собственной программы у каждого программиста
через некоторое время появляется большой набор собственных  заго-
товок, неординарных решений и т.  д., которые он хотел бы исполь-
зовать во всех своих творениях.
     QuickBASIC предоставляет такую возможность,  позволяя разра-
батывать программы по модульному принципу.  Модуль _ это  отдель-
ная, полностью независимая от других, часть Вашей программы. Каж-
дая программа на QuickBASIC может состоять из одного или несколь-
ких модулей.
     Каждый модуль имеет главную часть.  В главной  части  модуля
описываются процедуры  и  функции  модуля  (операторами DECLARE),
функции DEF FN, константы (оператор CONST).
     В сpеде  для создания пpоцедуp и функций испольуется команда
"Edit - New Sub" и "Edit - New Function". Пpосмотp текущих пpоце-
дуp и функций вызывается по клавише F2.
     Один из модулей называется главным. Он содержит так называе-
мую точку входа,  с которой начинается  выполнение  программы.  В
каждой программе может быть только один главный модуль.

MAIN.BAS
    __ SUB One
    __ FUNCTION Two

     К главному модулю можно подключить один или несколько  вспо-
могательных (дополнительных)  модулей.  В чем же преимущество мо-
дульного программирования?

MAIN.BAS
    __ SUB one
    __ FUNCTION two
ADD-ON.BAS
    __ SUB three
    __ SUB forth
    __ FINCTION six

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

OTHER.BAS
    __ SUB one
    __ FUNCTION two
ADD-ON.BAS
    __ SUB three
    __ SUB forth
    __ FINCTION six

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

>Q: Как ввести малую русскую букву "р" в среде QuickBASIC?

A: К сожалению,  стандартными средствами (INPUT, INPUT$, LINE IN-
PUT,  INKEY$)  невозможно  ввести  символ с кодом 224 _ это малая
русская буква "р" в альтернативной кодировке.  Это связано с  не-
корректным опросом клавиатуры, который выполняет BASIC. Есть нес-
колько вариантов решения.

     1. Использовать драйвер русских букв с изменяемой раскладкой
клавиатуры,  который  бы  подставлял  английскую букву "p" вместо
русской "р",  например KEYRUS. Однако, если вы вводите таким спо-
собом,  скажем  фамилии,  то их невозможно будет отсортировать по
алфавиту;
     2. Другим вариантом является использование "примочек" к  фи-
дошному редактору  сообщений GoldED,  например GEDSTART.COM.  Эта
программа подменяет при вводе текста не только "H", но и "р". Hе-
достатки такого подхода те же, что и описанные выше.
     3. Отказаться  от  стандартных операторов BASIC и опрашивать
клавиатуру самостоятельно, используя прерывание BIOS 16h, функция
0. Для  использования прерываний необходимо загрузить среду с па-
раметром "/L".

=== cut CHAR.BAS ===

'$INCLUDE: 'interupt.bi'
DECLARE SUB Char (c$)

' Define the type needed for Interrupt
TYPE RegType
     ax    AS INTEGER
     bx    AS INTEGER
     cx    AS INTEGER
     dx    AS INTEGER
     bp    AS INTEGER
     si    AS INTEGER
     di    AS INTEGER
     flags AS INTEGER
END TYPE

DIM SHARED Inreg AS RegType
DIM SHARED Outreg AS RegType

     ' Вызов процедуры CHAR, печать всех вводимых символов
     ' ESC - конец работы программы
     DO
        CALL Char(a$): PRINT a$;
        IF a$ = CHR$(27) THEN EXIT DO
     LOOP
     END
     SUB Char (c$)
     ' *****************************************************
     ' Данная процедура корректно обрабатывает ввод всех
     ' символов  ASCII, включая малую русскую букву "р"
     ' используя прерывание BIOS 16h, функция 0.
     ' Вызов: CALL Char (variable$)
     ' Аналог:
     ' DO: variable$ = INKEY$: LOOP WHILE variable$ = ""
     ' *****************************************************

     n = &H16: ' прерывание 16h
     inreg.ax = 0: ' функция 0
     CALL Interrupt(n, inreg, outreg)
     nah = outreg.ax \ 256: nal = outreg.ax MOD 256
     c$ = CHR$(nal): IF nal = 0 THEN c$ = c$ + CHR$(nah)
     END SUB

=== end CHAR.BAS ===

     4. Пропатчить саму среду QuickBASIC и все необходимые для
компиляции библиотеки:

=== cut QB45.CRK ===

 Russian "p" for QuickBasic 4.5 
(c) Igor Knizhny (2:5020/1343.20)

File QB.EXE
qb.exe
00024A75: 3C 0A
00024A76: E0 E4
00024A78: 14 04
00024A7A: F0 E0

File BRUN45.EXE
brun45.exe
00007C97: 3C 0A
00007C98: E0 E4
00007C9A: 14 04
00007C9C: F0 E0


File BCOM45.LIB
bcom45.lib
0001C83C: 3C 0A
0001C83D: E0 E4
0001C83F: 14 04
0001C841: F0 E0

=== end QB45.CRK ===

     5. Перейти  на следующую версию языка _ Microsoft BASIC Pro-
fessional Development System, где эта ошибка, наконец, исправле-
на.

>Q: Как подключить мышь?

A: Процедура MOUSE, использующая прерывание INT 33H позволяет уп-
равлять мышью из программы на языке BASIC. Для использования пре-
рываний необходимо загрузить среду с параметром "/L".

=== cut MOUSE.BAS ===

'*****************************************
'
'MOUSETST.BAS - интерфейс с драйвером мыши
'
'*****************************************

DEFINT A-Z

DECLARE SUB MOUSE (m1%, m2%, m3%, m4%)

' Define the type needed for Interrupt

TYPE RegType
     ax    AS INTEGER
     bx    AS INTEGER
     cx    AS INTEGER
     dx    AS INTEGER
     bp    AS INTEGER
     si    AS INTEGER
     di    AS INTEGER
     flags AS INTEGER
END TYPE

DIM SHARED Inreg AS RegType
DIM SHARED Outreg AS RegType

SCREEN 12

'включить курсор мыши
G1% = 1: CALL MOUSE(G1%, G2%, G3%, G4%)

' Пpочитать кооpдинаты кypсоpа и статyс кнопок
DO
   G1% = 3: CALL MOUSE(G1%, G2%, G3%, G4%)
   LOCATE 1, 1: PRINT "Кооpдинаты мыши : X ="; G3%; " Y ="; G4%; " "
   LOCATE 3, 1
   SELECT CASE G2%
      CASE IS = 1: PRINT "Hажата левая кнопка  "
      CASE IS = 2: PRINT "Hажата пpавая кнопка "
      CASE IS = 4: PRINT "Hажата сpедняя кнопка"
      CASE ELSE:   PRINT "Кнопки не нажаты     "
   END SELECT
   IF INKEY$ <> "" THEN EXIT DO
LOOP

'Погасить курсор мыши
G1% = 2: CALL MOUSE(G1%, G2%, G3%, G4%)

SCREEN 0

SUB MOUSE (m1, m2, m3, m4)
' *****************************************************
' Эта пpоцедypа обеспечивает интеpфейс с дpайвеpом мыши
' m1, m2, m3, m4 - паpаметpы, пеpедаваемые в дpайвеp мыши
' и возвpащаемые оттyда. Они соответствyют pегистpам
' пpоцессоpа AX, BX, CX, DX
' *****************************************************
n = &H33:       ' пpеpывание 33h
Inreg.ax = m1   ' входные pегистpы
Inreg.bx = m2
Inreg.cx = m3
Inreg.dx = m4
CALL Interrupt(n, Inreg, Outreg)
m1 = Outreg.ax  ' выходные pегистpы
m2 = Outreg.bx
m3 = Outreg.cx
m4 = Outreg.dx

END SUB

=== end MOUSE.BAS ===

>Q: Как прочитать содержимое текущей директории?

    В PDS  используется функция DIR$.  При первом запуске функции
передается маска для поиска файлов и возвращается первое имя фай-
ла по  заданной маске.  При следующих запусках возвращаются имена
остальных файлов:

=== cut LIST.BAS ===

'***********************************************************
'
'LIST.BAS - программа чтения содержимого текущей директории
'
'***********************************************************

DEFINT A-Z
REDIM FileName$(1)

'определяем маску для поиска файлов
maska$ = "*.*"

count = 1: CLS

'первый файл
FileName$(1) = DIR$(maska$)

IF FileName$(1) <> "" THEN
   'cледующий файл
   DO
     FindNext$ = DIR$
     IF FindNext$ <> "" THEN
        count = count + 1
        REDIM PRESERVE FileName$(count)
        FileName$(count) = FindNext$
      ELSE
        EXIT DO
      END IF
   LOOP
ELSE
   PRINT "В текущей директории нет файлов": END
END IF

'вывод результатов
PRINT "Всего найдено файлов:"; count
PRINT
FOR i = 1 TO count
   PRINT FileName$(i)
NEXT i

'ждем нажатия любой клавиши
DO: LOOP WHILE INKEY$ = ""

END

=== end LIST.BAS ===

   Часто при программировании возникает задача проверки существо-
вания того или иного файла.  Для этого также  можно  использовать
функцию DIR$:

IF DIR$(filename$)<> "" THEN
   PRINT "Файл существует"
ELSE
   PRINT "Файл не существует"
END IF

Q: Как вернуть ERRORLEVEL - код завершения программы?

   В PDS операторы окончания программы (END,  SYSTEM, STOP) имеют
необязательный  параметр - код завершения.  Это должно быть целое
число в интервале от 0 до 255.  ERRORLEVEL используется в команд-
ных файлах DOS для организации ветвления.

=== cut ERROR.BAS ===

IF OK THEN
   END 0
ELSE
   END 64
END IF

=== end ERROR.BAS ===

>Q: Как передать управление большой внешней программе и  вернуться
>   обратно?

     Оператор SHELL  позволяет  передать управления внешней прог-
рамме,  а после ее завершения вернуться в основную программу. Од-
нако при этом память,  занимаемая основной программой не освобож-
дается и может возникнуть ситуация когда ее  станет  недостаточно
для внешней программы.
     Оператор CHAIN освобождает память, занимаемую основной прог-
раммой и запускает внешнюю,  но при этом возникает вопрос - а как
же вернуться в основную  программу?  Конечно,  можно  решить  эту
проблему, запуская командный файл и организуя ветвление по ERROR-
LEVEL. Hо есть способ лучше - полная передача управления програм-
ме-спутнику,  которая запускает внешнюю программу через SHELL,  а
затем передает управление основной программе:

   MAIN.BAS    _ основная программа
   BIG.EXE     _ внешняя программа
   QBSWAP.EXE  _ решение проблемы :)


=== cut MAIN.BAS ===
   .
   .
   .
   CHAIN "QBSWAP"
   .
   .
   .
=== end MAIN.BAS ===

=== cut QBSWAP.BAS ===

   SHELL "BIG"
   CHAIN "MAIN"

=== end QBSWAP.BAS ===

Оставить комментарий

Комментарий:
можно использовать BB-коды
Максимальная длина комментария - 4000 символов.
 
Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог