On-line: PSP, гостей 0. Всего: 1 [подробнее..]
АвторСообщение





Пост N: 166
Зарегистрирован: 12.11.06
ссылка на сообщение  Отправлено: 07.11.10 10:24. Заголовок: Волшебные числа и операции


Доброе утро!

Вот наткнулся на очередную ошибку xHarbour и Clipper. Думал, что глюк ОС или ПК, но нет. Пример ошибки - оператор "остаток от деления":

8.8 * 3 = 26.4 или 3.3 * 3 = 9.9, но операции (%) дают
26.4%8.8 = 8.8 или (НО правильно) 9.9%3.3 = 0

Вопрос - как Вы обходите данные глюки? Или где в "арифметике" ожидать очередных "засад"? До кучи напомню об ошибочной работе функции Int в Clipper (в xHarbour кажется работает правильно)

Спасибо: 0 
ПрофильЦитата Ответить
Ответов - 149 , стр: 1 2 3 4 5 6 7 8 All [только новые]


Администратор




Пост N: 2071
Зарегистрирован: 23.05.05
ссылка на сообщение  Отправлено: 23.09.11 12:48. Заголовок: AndreyZh пишет: 4. ..


AndreyZh пишет:

 цитата:
4. Ваше объяснение не поясняет факт, что в Харб и Клиппере корректно считает (1.00 - (3.00 - 2.00) * 10000000000 = 0.0000



Как так ?!! А мне показалось, что я все обьяснил

Тестовая программа:

Local n1 := 10000.00
Local n2, n3, i
Local i1 := 0
Local i2 := 0
for i := 1 to 10000000
n2 := Round(n1+i*0.01, 2)
n3 := Round(n1+n1+i*0.01, 2)
if n1-(n3-n2) == 0.00
i1 ++
else
i2 ++
endif
next
qout(i1, i2)
__Wait('')

Результат:

8733568 1266432

Т.е., в 87.3% сравнений получаем равенство, а в 12.7% - неравенство
Вот такая она, арифметика с плавающей точкой. Это как повезет. Считайте, что для (1.00 - (3.00 - 2.00) - повезло

Кстати, если варьировать параметры цикла, например поставить i до 100000, то результат будет совершенно другим, 52% на 48%


Спасибо: 0 
ПрофильЦитата Ответить
Администратор




Пост N: 2072
Зарегистрирован: 23.05.05
ссылка на сообщение  Отправлено: 25.09.11 12:57. Заголовок: Докладываю о продела..


Докладываю о проделанной работе.
На форуме фокса выяснил, что в vfp используется вобщем-то некрасивое и недокументированное решение:
при сравнении double числа не просто сравниваются, а сравниваются с округлением до количества десятичных знаков, которое задается для отображения переменной numeric.
Это количество десятичных знаков задается при создании переменной в соответсвии со значением set decimals (или прямо в константе), и по умолчанию равно двум.
Если перед созданием переменных задать SET DECIMALS TO 18, то при сравнении возникнет ошибка (.F.), точно такая же, как в харборе.
Я рассказал об этом в devlist, предложив добавить подобную фичу и в харбор (по отдельной настройке SET).
Виктор, естественно, отказал. Да я бы и сам подумал бы 10 раз, прежде чем это делать. Одно дело - предложить, другое - реализовать.
Есть еще вариант решения этого вопроса - добавить в харбор еще один числовой подтип - currency.
Имеется в виду хранение чисел в целом формате (4 или 8 байт), но с некоторой базой: например, 2 или 4. Если это 2, то, грубо говоря, значения хранятся в "копейках", если 4 - в десятитысячных долях целого. И используется целочисленная арифметика, при которой подобных пролбем в принципе быть не может.
В формате dbf есть подобный тип данных - "Y"
Несколько лет назад у меня самого чесались руки сделать это, но там есть свои подводные камни. Вобшем, пока этот вопрос открыт.

В свою очередь, могу предложить такую функцию для проверки double на 0. В этой функции помимо сравнения значения с нулем проверяется еще и эксонента, и, если она меньше или равна -36 (т.е. значение меньше или равно 2**-36), то считается, что число равно нулю. Как показывает практика, при вычислениях большей погрешности не возникаает.
Вот эта функция:

#pragma BEGINDUMP 

#include "hbapi.h"

static int exponent( double d )
{

int iExponent = 0;

union
{
double value;
char string[sizeof( double )];
} xConvert;

xConvert.value = d;

if( xConvert.value != 0 )
{
iExponent = ( int ) ( xConvert.string[7] & 0x07F );
iExponent = iExponent << 4;
iExponent += ( int ) ( ( xConvert.string[6] & 0xF0 ) >> 4 );
iExponent -= 1023;
}

return iExponent;
}

HB_FUNC( EQU0 )
{
double d = hb_parnd(1);
hb_retl( d == 0.0 || exponent( d ) <= -36 );
}

#pragma ENDDUMP



Спасибо: 0 
ПрофильЦитата Ответить



Не зарегистрирован
Зарегистрирован: 01.01.70
ссылка на сообщение  Отправлено: 25.09.11 13:39. Заголовок: Учет неполных копеек


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

Вопрос возник из учетной задачи с финансовыми суммами с дробями( где копейки - десятичные дроби).
В этой среде -дополнительно к погрешности,вызванной машинным представлением чисел (то есть неточно),
есть другая погрешность - из-за необходимости представлять промежуточные и конечные результаты целым числом копеек.
Поскольку принципиально есть операции деления с потерей значаших разрядов ( например расчет сумм НДС),
и где всегда ошибка (неточность) вычисления суммы частей не равна сумме ошибок(неточностей) частей.
Как правило, при вычислениях необходимо , наборот, явно определять и контролировать получаемую погрешность
и относить ее на особую статью учета.
Например, товар 3 упаковки (упаковка = 1/3 часть целого) на общую сумму 1.00 руб (100 коп) при ставке НДС 10 % с суммой НДС 0.10 руб
при продаже тремя частями
при необходимости указывать цену продажи в целых копейках и фиксировать, как полную сумму, так и сумму НДС - при каждой продаже,
приводит к разнице в копейку по сумме товара и сумме НДС:
1.00 руб(0.10 ндс) <> 3*0,33 (0,03 ндс - потеря значимости) = 0,99 ( 0,09 ндс)

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





Спасибо: 0 
Цитата Ответить
Администратор




Пост N: 2073
Зарегистрирован: 23.05.05
ссылка на сообщение  Отправлено: 25.09.11 17:11. Заголовок: petr707 пишет: По п..


petr707 пишет:

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



Числовой тип харбора сейчас имеет несколько подтипов: целый (integer и long), и double.
Операндами бинарной арифметической операции могут быть любые значения, и подтип результата такой операции определяется автоматически, чтобы избежать потери значности:
скажем, если это операция long-long, то ее результатом может быть как long, так и double, если для long не хватает разрядности.
Результат операции long div long - всегда double.
Такие же правила можно выработать и для нового целого типа currency.
Пусть результат операции currency div currency будет double, а результат остальных трех операций - currency или double (если разрядности currency не хватает).
Так что этот вопрос как раз проблемы не составляет.


Спасибо: 0 
ПрофильЦитата Ответить





Пост N: 211
Зарегистрирован: 12.11.06
ссылка на сообщение  Отправлено: 25.09.11 18:53. Заголовок: Уважаемые господа! О..


Уважаемые господа! Особенно поклон Pasha за большие усилия по нахождению вариантов решения проблем!

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

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

Спасибо: 0 
ПрофильЦитата Ответить
Администратор




Пост N: 2079
Зарегистрирован: 23.05.05
ссылка на сообщение  Отправлено: 27.09.11 18:45. Заголовок: Pasha пишет: Тестов..


Pasha пишет:

 цитата:
Тестовая программа:

Local n1 := 10000.00
Local n2, n3, i
Local i1 := 0
Local i2 := 0
for i := 1 to 10000000
n2 := Round(n1+i*0.01, 2)
n3 := Round(n1+n1+i*0.01, 2)
if n1-(n3-n2) == 0.00
i1 ++
else
i2 ++
endif
next
qout(i1, i2)
__Wait('')



Из любопытства запустил подобную програмку на vfp6. Харбор показал в 2 раза лучший результат: фокс ее выполнил за 18 сек, харбор - за 9.

Спасибо: 0 
ПрофильЦитата Ответить





Пост N: 215
Зарегистрирован: 12.11.06
ссылка на сообщение  Отправлено: 19.03.12 08:58. Заголовок: Строгость xHarbour, несовместимая с допусками Clipper


Доброе утро!

Опишу очередные геморрои с исправлениями "несовместимостей" между Clipper и xHarbour (может быть кто-то избежит ненужных потерь времени, сразу исправляя несовместимости):

1. Передаю в функцию переменную
- func mmm(xPar)
- ....
- xPar := AllTrim(Upper(xPar))

Если переменная не задана ( =mmm() ), то клиппер нормально продолжает работать, воспринимая xPar, как пустое символьное значение... по крайней мере в моём последующем коде... xHarbour вылетает по ошибке "неопределенный тип"... Выявилось, когда user, самостоятельно настраивая прогу забыл задать параметр.

2. USE ls_works SHAR NEW Открываю таблицу, но алиас ls_works уже используется... Клиппер на это реагирует спокойно и правильно обрабатывает рабочую область... xHarbour вылетает по ошибке... На это натыкался в самом начале переделки системы и описывал, но среди кода затесалась эта фигня, к которой обращаются крайне редко... но обратились... и программа вылетела... и на меня справедливо наехали пользователи.

3. Фигня - конечно. Для просмотра создаётся пустой файл, есть "чужая" функция просмотра текстовых файлов неограниченного размера через класс TBroseDB... так и не смог подружить её с xHarbour... но выкрутился - memedit работает с файлами неогр. размера... но народ привык, что можно при просмотре Home/End просматривать широкий отчёт, но первая строка "пустая", т.е. не работает... выкрутился - заставляю курсор перемещаться вниз на реальные строки... но когда 40 чел "проедают плешь" не очень приятно.

Это то, что вспомнил с "последнего" сообщения... на тему 100% совместимостей Clipper и [x]Harbour...



Спасибо: 0 
ПрофильЦитата Ответить
Администратор




Пост N: 2307
Зарегистрирован: 23.05.05
ссылка на сообщение  Отправлено: 19.03.12 10:14. Заголовок: AndreyZh пишет: - x..


AndreyZh пишет:

 цитата:
- xPar := AllTrim(Upper(xPar))

Если переменная не задана ( =mmm() ), то клиппер нормально продолжает работать, воспринимая xPar, как пустое символьное значение... по крайней мере в моём последующем коде... xHarbour вылетает по ошибке "неопределенный тип"... Выявилось, когда user, самостоятельно настраивая прогу забыл задать параметр.



Это не соответствует действительности. Клиппер (я проверил на 5.2е) работает точно так же, как Харбор
Upper(nil) генерирует argument error

Спасибо: 0 
ПрофильЦитата Ответить





Пост N: 216
Зарегистрирован: 12.11.06
ссылка на сообщение  Отправлено: 19.03.12 10:51. Заголовок: Pasha пишет: Это не..


Pasha пишет:

 цитата:
Это не соответствует действительности. Клиппер (я проверил на 5.2е) работает точно так же, как Харбор
Upper(nil) генерирует argument error


Вот "Фома неверущий"... Clipper 5.01r + CTII... использовалось без ошибок с корректной обработкой:
 
#include "laks.ch"

* ----------------------------------------------------------------------------
* Стартовая процедура.
PROC Main( cPar, cSaveLog )
LOCA lRep:=FALSE, nSel:=1, nSelWork:=1, cTxt:="", aArr:={}, nC:=0, nI:=0

// Глобальные системные установки пакета и конфигурация по df.
#include "cfg.ch"
cnProgramm := "Администр."

// Загружаем/изменяем значения переменных настройки из стандартной базы данных
IF !NetUse( "LS.CFG", SHAR_MODE, 5 ) THEN fErrQuit("Недоступна БД конфигурации!","W+*/N")
#include "config.ch"
cpZatr := IF(Empty(Alltrim(cpZatr)),"В.РАСХОД",cpZatr)

// Вставка моего заголовка и блокирование закрытия окна
pWind(" Администратор и бухгалтерский модуль (УС Land)... Предприятие: "+Alltrim(cpName),"hla.ico")
.....

// Настройка и ремонт запускается до открытия файлов.
cPar := IF( Pcount()==0, "", cPar )
IF Upper(cPar)=="R" THEN pRepair() // Ремонт
IF Upper(cPar)=="C" THEN aConfig(FALSE) // Конфигурация
IF Upper(cPar)=="O" THEN lRep:=TRUE // Признак отчетной программы.

ZhSoft()
pOpAllBase()

// Пользователь в режиме неопределенный. Принудительный вызов режима проверки логики после открытия БД
IF Upper(cPar)=="L"
CLS
pChLogic(Upper(Alltrim(cPar)),Upper(Alltrim(cSaveLog))) ENDI


// Вызов системы нуления программы.
IF Upper(cPar)=="D" THEN pDestroyBase()
....
// Блок ввода и проверки допуска к работе с программой



Сейчас исправлено:
 
PROC Main( cPar, cSaveLog )
LOCA lRep:=FALSE, nSel:=1, nSelWork:=1, cTxt:="", aArr:={}, nC:=0, nI:=0
DEFAULT cPar TO "", cSaveLog TO ""



где default команда препроцессора:

 
#xcommand DEFAULT <p> TO <v> [, <p2> TO <v2> ] => ;
<p> := IF(<p> == NIL, <v>, <p>) ;
[; <p2> := IF (<p2> == NIL, <v2>, <p2>) ]


Спасибо: 0 
ПрофильЦитата Ответить
Администратор




Пост N: 2308
Зарегистрирован: 23.05.05
ссылка на сообщение  Отправлено: 19.03.12 11:22. Заголовок: AndreyZh пишет: Вот..


AndreyZh пишет:

 цитата:
Вот "Фома неверущий"... Clipper 5.01r + CTII... использовалось без ошибок с корректной обработкой:



Точнее формулировать надо.
AllTrim(Upper()) это не то же самое, что Upper(Alltrim())

Проверяем:

Alltrim(nil)

501 - работает
52, харбор - возникает ошибка
Т.е. речь идет не о совместимости клиппера и харбора, а о несовместимости разных версий клиппера.
Харбор естественно совместим с версиями 5.2e и 5.3b, которые считаются "каноническими".


Спасибо: 0 
ПрофильЦитата Ответить





Пост N: 217
Зарегистрирован: 12.11.06
ссылка на сообщение  Отправлено: 19.03.12 12:18. Заголовок: Pasha пишет: Alltri..


Pasha пишет:

 цитата:
Alltrim(nil)

501 - работает
52, харбор - возникает ошибка
Т.е. речь идет не о совместимости клиппера и харбора, а о несовместимости разных версий клиппера.
Харбор естественно совместим с версиями 5.2e и 5.3b, которые считаются "каноническими

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


 цитата:
Точнее формулировать надо.
AllTrim(Upper()) это не то же самое, что Upper(Alltrim())


Нормально, но

Спасибо: 0 
ПрофильЦитата Ответить
Администратор




Пост N: 2309
Зарегистрирован: 23.05.05
ссылка на сообщение  Отправлено: 19.03.12 12:47. Заголовок: AndreyZh пишет: Об ..


AndreyZh пишет:

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



Если бы вы переводили программу с 501 на 52/53, то столкнулись с такой же проблемой. Дело не в харборе, а самом клиппере.
Кстати, разработчики харбора предусмотрели возможность поведения харбора как для старых версий клиппера
Если харбор собрать без флага HB_COMPAT_C53, то Alltrim не будет генерировать ошибку, если ему не передать параметр
Так что слова о какой-то особой сложности перехода на харбор некорректны. Надо просто понимать эти несовместимости и учитывать их при переходе. Множество казалось бы несовместимостей связано с особенностиями ms dos, которых просто нет в современных ОС.

По поводу ошибки, которую генерирует use, если попытаться 2-й раз открыть уже открытый файл
5.2 генерирует при этом ошибку, как и харбор, а 501 - игнорирует ошибку. Ну и что правильного в таком поведении ?
И опять таки, мы имеем дело с разным поведением версий клиппера, а не с несовместимостью клиппера и харбора.
Харбор же не может одновременно воспроизвести противоположное поведение разных версий клиппера.

По TBrowseDB. Вообще-то это не класс, а функция с уже определенными блоками кода для навигации по таблице БД, и как ее можно прикрутить для навигации по текстовому файлу, я не представляю.


Спасибо: 0 
ПрофильЦитата Ответить





Пост N: 218
Зарегистрирован: 12.11.06
ссылка на сообщение  Отправлено: 19.03.12 13:32. Заголовок: Pasha пишет: По TBr..


Pasha пишет:

 цитата:
По TBrowseDB. Вообще-то это не класс, а функция с уже определенными блоками кода для навигации по таблице БД, и как ее можно прикрутить для навигации по текстовому файлу, я не представляю.


Не придирайтесь!!! - Да? Что по технологии - ловите, имеющий самостоятельную ценность исходник:

Скрытый текст



Спасибо: 0 
ПрофильЦитата Ответить
Администратор




Пост N: 2312
Зарегистрирован: 23.05.05
ссылка на сообщение  Отправлено: 19.03.12 17:34. Заголовок: AndreyZh пишет: Не ..


AndreyZh пишет:

 цитата:
Не придирайтесь!!! - Да? Что по технологии - ловите, имеющий самостоятельную ценность исходник:



Да я не придираюсь, просто не очень был понятен вопрос.
Что касается xHarbour TBrowse - то он не на 100% совместим с клипперовским. И с такой сложной схемой могут быть несовместимости. В этом отношении Harbour TBrowse лучше, я так и делал: собирал xHarbour, а TBrowse брал от Harbour
А касательно этой процедуры: ну зачем же делать так сложно ? Лучше загнать текстовый файл в массив, используя MLCount/MemoLine(), и затем этот массив просматривать тем же TBrowse. Это будет и быстрее, и куда проще.
Массив строк можно сформировать и другим способом: через TokenInit/TokenNext/ToeknEnd


Спасибо: 0 
ПрофильЦитата Ответить





Пост N: 232
Зарегистрирован: 12.11.06
ссылка на сообщение  Отправлено: 25.05.12 15:44. Заголовок: Здравствуйте! ... оч..


Здравствуйте! ... очередной глобальный глюк [x]harbour? Если так, то может быть послать разработчикам.

Програмка примерно структуры:
loca cc:=spac(1)
....
@ 1,1 say "введите символ" get cc
read
....
построение отчета
....
вызов запросов печати из формы и в зависимости от устройства вывод куда требуется.

Проблема: Если введен символ точка или запятая, то как-бы в форме печати харб нажимает PgDn, на прочих знаках/буквах спокойненько ожидает что ему введут в качестве устройства и нажмут клавиши подтверждения. Можно, если интересно дать полный пример отчёта, но данный глюк во всех, где самым последним get вводится один символ.

Как её можно побороть: Пока сделал так, благо после каждого read у меня есть вызов ф-ции верификации user, т.е. просто добавил в неё:

if lastkey() = 44 .or. lastkey() = 46
keyb chr(K_ENTER)
inkey(0)
endi

P.S. Уже была чем-то схожая проблема, когда харб не любил цифру 1, но Pasha связывался с разработчиками и они порешали её.

Спасибо: 0 
ПрофильЦитата Ответить
администратор




Пост N: 2381
Зарегистрирован: 17.05.05
ссылка на сообщение  Отправлено: 25.05.12 16:11. Заголовок: AndreyZh Проверил в..


AndreyZh
Проверил в Harbour и XHarbour , проблемы не увидел.

Спасибо: 0 
ПрофильЦитата Ответить



Пост N: 493
Зарегистрирован: 11.06.10
ссылка на сообщение  Отправлено: 25.05.12 17:26. Заголовок: Т.к. AndreyZh пишет:..


Т.к. AndreyZh пишет:

 цитата:
loca cc:=spac(1)

, то при вводе любого символа read завершается
пробуйте так
@ 1,1 say "введите символ" get cc valid lastkey()=13

Спасибо: 0 
ПрофильЦитата Ответить





Пост N: 233
Зарегистрирован: 12.11.06
ссылка на сообщение  Отправлено: 25.05.12 21:38. Заголовок: Уважаемые господа. ..


Уважаемые господа.

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

Dima пишет:

 цитата:
AndreyZh
Проверил в Harbour и XHarbour , проблемы не увидел.


Вы скачивали систему... желающие могут это сделать уже с нормальным дистрибутивом дистрибутив с версией июня 2012 (34мб) где ещё имеется данная проблема: программа аналитика/динамические... любой отчет, на последний запрос знака разделителя вводите различные знаки (глюки только на точке и запятой)

AlexMyr пишет:

 цитата:
, то при вводе любого символа read завершается
пробуйте так
@ 1,1 say "введите символ" get cc valid lastkey()=13


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

Спасибо: 0 
ПрофильЦитата Ответить



Пост N: 494
Зарегистрирован: 11.06.10
ссылка на сообщение  Отправлено: 25.05.12 22:06. Заголовок: AndreyZh пишет: но ..


AndreyZh пишет:

 цитата:
но поведение проги в дальнейшем зависит от символа.

каким боком Harbour к проблеме в Вашей проге ввиде обработки символа?

Спасибо: 0 
ПрофильЦитата Ответить



Не зарегистрирован
Зарегистрирован: 01.01.70
ссылка на сообщение  Отправлено: 25.05.12 22:27. Заголовок: get, lastkey() and picture


1) в общем случае содержимое GET не совпадает с lastkey()
2) для исключения дефолтового поведения лучше использовать конструкцию с Picture
3) ниже код, где можно посмотреть разницу - при нажатии Esc , PageDown и прочее

proc main()
loca cc:=space(1) , dd:=space(1),ff:=space(1),i
@0,0
cls
for i=1 to 20
@ 1,1 say "введите символ 1 " get cc
read
@2,1 say "cc="+str( asc(cc),3)
@3,1 say "lastkey()="+str( lastkey(),3)

@ 5,1 say "введите символ 2" get dd picture "X"
read
@6,1 say "dd="+str( asc(dd),3)
@7,1 say "lastkey()="+str( lastkey(),3)

@10,1 say "введите символ 3" get ff picture "9"
read
@11,1 say "ff="+str( asc(ff),3)
@12,1 say "lastkey()="+str( lastkey(),3)
next i
return


Спасибо: 0 
Цитата Ответить
Ответов - 149 , стр: 1 2 3 4 5 6 7 8 All [только новые]
Ответ:
1 2 3 4 5 6 7 8 9
большой шрифт малый шрифт надстрочный подстрочный заголовок большой заголовок видео с youtube.com картинка из интернета картинка с компьютера ссылка файл с компьютера русская клавиатура транслитератор  цитата  кавычки моноширинный шрифт моноширинный шрифт горизонтальная линия отступ точка LI бегущая строка оффтопик свернутый текст

показывать это сообщение только модераторам
не делать ссылки активными
Имя, пароль:      зарегистрироваться    
Тему читают:
- участник сейчас на форуме
- участник вне форума
Все даты в формате GMT  3 час. Хитов сегодня: 231
Права: смайлы да, картинки да, шрифты да, голосования нет
аватары да, автозамена ссылок вкл, премодерация откл, правка нет