Для того, что бы программировать было легко и комфортно, первым делом нужно научиться диагностировать и исправлять ошибки. По этому, прежде чем двинуться дальше, пройдемся немного по дебаггингу.
Научиться отлаживать и оптимизировать скрипты - значит научиться программировать. Потому что мало написать рабочий код, нужно суметь написать хорошо работающий код. Без ошибок.
Вообще в программировании действует принцип 90-10-90. То есть на первые 90% работы уходит 10% времени, а на последние 10% работы - остальные 90. Написать программу можно довольно быстро, но вот на её отладку иногда (да почти всегда, что греха таить) уходит жутко много времени. По этому настоящий программист не станет расстраиваться, если что то не получилось с первого захода. Тут как раз и начинается самый интересный и творческий момент - дебаггинг.
Синтаксические ошибки.
Самое простое дело. Мой вам совет: не бойтесь нотисов и варнингов (сообщений об ошибках), бойтесь их отсутствия. Программа более чем из пяти строк, не вызвавшая нотис при первом запуске - повод для паники. Что то тут не чисто.
Нотисы и варнинги (предупреждения о ошибках) нужно любить - это наши помошники, а не злые враги, которые не дают запустить скрипт В КОТОРОМ ВСЕ ПРАВИЛЬНО!!!!! Ведь никак не хочется верить, что это ты ошибся, а не эта чертова груда железа.
Запомните:
Человек умнее компьютера, но компьютер умнее программиста.
Логические ошибки
Тут дело гораздо сложнее.
Логическая ошибка, это когда все работает, но результат совсем не тот, который ожидался. Допустим переопределилась какая нибудь переменная или ветвление не так пошло. Помочь уже ни какой интерпретатор не сможет.
Самый действенный способ поймать логическую ошибку - трассировка. То есть поэтапный вывод результатов работы с остановкой скрипта.
Для трассировки очень хорошо подходят три функции - print_r() , var_dump() и debug_print_backtrace(). А лучше написать свою, это будет проще и красивее.
Теперь в любом месте программы стоит написать три буквы и мы увидим, что находится в переменной.
Семантические ошибки
Самая печальная история. Дело в том, что семантические ошибки крайне редко себя проявляют. Но при этом часто или тормозят скрипт, или повышают ресурсоемкость. К тому же они никак не диагностируются. Тут вся надежда только на себя. Главное правило - следить за типами данных.
Еще очень важно обращать внимание на область видимости переменных. Особенно при процедурном подходе, где большая часть переменных находится в глобальной области видимости. Неправильно расположенные переменные могут очень сильно изменить сценарий.
Неверное применение функций тоже относится к семантике.
Ну и конечно настройки. Нельзя писать скрипт под какой то определенным образом настроенный сервер. Весьма вероятно, что настройки могут измениться и тогда не избежать беды. Это касается тех же преславутых магических кавычек к примеру или даже mod_rewrite. Скрипт должен быть написан так, что бы при переносе его на другой сервер потребовалось минимальное количество настроек.
Вообще семантические ошибки пропадают с накоплением опыта, так что все наживное.
Не забывайте, что главное оружие программиста - трезвый ум и холодный рассудок. Ни в коем случае не впадать в панику. Все очень просто налаживается, нужно только захотеть и постараться.
Полный урок тут.
Спустя 10 минут, 20 секунд (27.11.2009 - 22:45) VolCh написал(а):
баг детектед: Дбагинг 
А вообще как-то давно ничего не отлаживал такими методами, всё через IDE+xDebug (наверное поэтому и необходимости в пробелах не вижу
). Кстати, там и тот-же var_dump переписан куда круче, чем родной php, и куча других интерсных функций отладочных и профилировочных, даже если не пользоваться реал-тайм отладкой.
А еще умных статей про всякие PHPUnit начитался, но хотя там и тестирование больше, но поощряется цикл разработки типа задача, набор тестов, реализация -- тесты прошли - отладка не нужна

А вообще как-то давно ничего не отлаживал такими методами, всё через IDE+xDebug (наверное поэтому и необходимости в пробелах не вижу

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

Спустя 1 час, 32 минуты, 26 секунд (28.11.2009 - 00:17) glock18 написал(а):
можно еще стрикт включить. тоже полезно бывает
Спустя 51 минута, 53 секунды (28.11.2009 - 01:09) VolCh написал(а):
twin
Цитата |
Но вот я не пойму, как он может помочь логические ошибки искать? Когда все работает, а результат не тот, какой должен быть... Допустим переменная случайным образом посреди скрипта перезаписалась... Там как это реализовано? |
Сидишь в своей любимой IDE (для Notepad++ есть плагин, как и для большинсмтва других распространенных от vim и emacs до eclipse и netbeans ). Слева у тебя дерево файлов, по центу файл а справа переменные из этого файла. Ставишь курсор на первую строку файла, жмешь F5 (чисто пример), комп пожужжит, модем помигает (имеется в виду отладка на удаленном серваке), курсор опустится на строку ниже, а в окошке справа отобразятся значения переменных, вклячая _GET и т. п. разные еще фишки есть, типа точки останова, следить за значением переменной и т. д. В общем всё что типично для обычных интерактивных отладчиков со времен TurboPascal и Microsoft Basic под DOS (а скорее всего, и раньше), только в вебе и на PHP .
Логические ошибки, конечно, он не найдёт, но поможет найти (если сам понимаешь, что программа должна делать



Спустя 5 часов, 36 минут, 5 секунд (28.11.2009 - 06:45) twin написал(а):
VolCh
Вот в который раз попытался разобраться... и плюнул уже на стадии поиска плагина. Жалко на это времени даже. А самое обидное (как очень часто бывает), что разрекламированные и расхваленные средства на поверку оказываются не стоящими того времени.
Не мог бы ты пошагово расписать, где что скачать, как установить и как начать пользоваться?
А то первый же запрос в гугл выдал следующее:
Вот в который раз попытался разобраться... и плюнул уже на стадии поиска плагина. Жалко на это времени даже. А самое обидное (как очень часто бывает), что разрекламированные и расхваленные средства на поверку оказываются не стоящими того времени.
Не мог бы ты пошагово расписать, где что скачать, как установить и как начать пользоваться?
А то первый же запрос в гугл выдал следующее:
Цитата |
Но вот появился свет в окне – обнаружен плагин к notepad++, который превращает этот шустрый и удобный редактор в полноценную php ide. Превращает он пока не очень хорошо (плагин не вышел из alpha-версий) – не работают половина hotkey-ев (вероятно из-за конфликтов с другими плагинами) да и интерфейсные глюки имеются. |
Печальное зрелище... А дальше еще хуже:
Цитата |
А вот стартовать debug-сессию из notepad++ у меня не получилось. Но это не беда, поскольку есть xdebug helper – extension для firefox, с помощью которого |
То есть я еще должен в лисе теперь работать? Грустно...
Спустя 6 часов, 46 минут, 10 секунд (28.11.2009 - 13:31) VolCh написал(а):
Самая частая ошибка, насколько я знаю - пытаются настроить клиента (IDE) на доступ к серваку, а надо наоборот, чтоб сервак стучался к клиенту, а клиент слушал 9000 (по умолчанию) порт
Для денвера локального:
в php.ini пишешь что-то вроде:
xdebug.remote_enable=On
xdebug.remote_host=127.0.0.1
xdebug.remote_handler=dbgp
В нотпаде заходишь в Дополнения - DBGp - Config... Там ставишь первые 3 и последнюю гакли, жмешь OK, потом в том же меню Debugger
Затем с браузера заходишь на http://localhost/index.php?XDEBUG_SESSION_START=Test и в нотпаде панель должна подключиться к серваку (точнее сервак к ней подключиться должен
), там, думаю, понятно будет
Для денвера локального:
в php.ini пишешь что-то вроде:
xdebug.remote_enable=On
xdebug.remote_host=127.0.0.1
xdebug.remote_handler=dbgp
В нотпаде заходишь в Дополнения - DBGp - Config... Там ставишь первые 3 и последнюю гакли, жмешь OK, потом в том же меню Debugger
Затем с браузера заходишь на http://localhost/index.php?XDEBUG_SESSION_START=Test и в нотпаде панель должна подключиться к серваку (точнее сервак к ней подключиться должен

Спустя 29 минут, 13 секунд (28.11.2009 - 14:01) sergeiss написал(а):
Можно, я тоже вклинюсь? 
И в С++, и в ПХП не пользуюсь никакими встроенными дебаггингами. Если что-то "не так" идет, то делаю "контрольные распечатки". Типа того, как Твин показал. Реализация которых не важно какая. Более важен принцип, подход.
Это очень хорошо помогает при поиске любых видов ошибок. Сначала локализуешь место, а потом анализируешь, что же в этом месте "не так".
Хотя, конечно, в ряде случаев помогает только одно средство - "звонок другу" (вопрос на форуме и т.п.)
Стараюсь этим средством пользоваться как можно реже, потому что когда сам находишь причину ошибки, то вероятность ее повтора в будущем становится очень маленькой.

И в С++, и в ПХП не пользуюсь никакими встроенными дебаггингами. Если что-то "не так" идет, то делаю "контрольные распечатки". Типа того, как Твин показал. Реализация которых не важно какая. Более важен принцип, подход.
Это очень хорошо помогает при поиске любых видов ошибок. Сначала локализуешь место, а потом анализируешь, что же в этом месте "не так".
Хотя, конечно, в ряде случаев помогает только одно средство - "звонок другу" (вопрос на форуме и т.п.)

Спустя 2 часа, 14 минут, 58 секунд (28.11.2009 - 16:16) Krevedko написал(а):
можно подробнее про семантику ?
например
тут как надо ?
??
например
$var = array();
$var = 'Строка';
тут как надо ?
$var = array();
$var[] = 'Строка';
??
Спустя 18 минут, 31 секунда (28.11.2009 - 16:34) Shturman написал(а):
А зачем вообще преобразовать массив в строку. Не проще отдальные переменные пользовать, если конечно строку не как элемент масива пытаешься поместить строкой
Если как элемент - ну тогда конечно
или вместо
использовать
$var = 'Строка';
Если как элемент - ну тогда конечно
$var[...] = 'string';
или вместо
$var[] = 'string';
использовать
int array_push ( array &array, mixed var [, mixed ...] );
Спустя 4 часа, 25 минут, 33 секунды (28.11.2009 - 21:00) Хозяин Огня написал(а):
А что значит &$var и зачем это?
Спустя 4 минуты, 5 секунд (28.11.2009 - 21:04) twin написал(а):
Это ссылка. Нужна для того, что бы можно было работать не с копией переменной, которая объявлена в функции, а с самой переменной, которая в глобальной области видимости.
Спустя 1 час, 6 минут, 16 секунд (28.11.2009 - 22:10) Хозяин Огня написал(а):
Цитата (twin @ 28.11.2009 - 23:04) |
Это ссылка. Нужна для того, что бы можно было работать не с копией переменной, которая объявлена в функции, а с самой переменной, которая в глобальной области видимости. |
Ага...значит уже потом в теле функции можно писать просто $var, уже без &, и это тоже будет ссылка на переменную, а не её копия, так?
Непонятно зачем там microtime(). По идее если мы в $var записываем время работы скрипта, то как тогда работает условие
if($val === $var)?
теперь по этим условиям:
if(empty($vname) && empty($var))
elseif(empty($var))
elseif(empty($vname))
никак не могу врубиться...
empty($vname) может быть только если мы в debug(); проставим несуществующую переменную.
empty($var) - если мы оставим debug(); без аргументов
Правильно? Видать не правильно. Но почему?...
Спустя 8 минут, 19 секунд (28.11.2009 - 22:18) twin написал(а):
Эта функция для определения имени переменной, переданной в аргументе. Вообще она немного из области извращений. Но она не для широкой публики и работает.
По этому вполне сгодится. Работает так.

По этому вполне сгодится. Работает так.
/**
* Function of diagnosing of logic errors (trace)
* Функция диагностирования логических ошибок (трассировки)
* @param mixed $var, boolean $exit
* @return void
*/
function debug(&$var, $exit = false)
{
?>
<pre>
<b style="color:blue">
<?php
static $num = 0; .// Устанвливаем счетчик
++$num; // Плюс один
$old = $var; // Записываем значение переменной для хранения
$var = microtime(); // перезаписываем переменную, нужно уникальное значение, по этому microtime()
$vname = false; // Объявляем переменную
foreach($GLOBALS as $key => $val) // Проходим по массиву $GLOBALS и ищем в нем уникальное значение
if($val === $var) // Если нашли
$vname = $key; // Берем ключ - это и будет имя переменной, переданной в функцию
$var = $old; // Возвращаем переменной её родное значение
$vstring = $num .')';
if(empty($vname) && empty($var))
$vstring .= '</b><b style="color:red">The variable is not defined in function</b><br>';
elseif(empty($var))
$vstring .= '</b><b style="color:red">The variable is not defined or empty</b><br>';
elseif(empty($vname))
$vstring .= '</b><b style="color:green">It was not possible to define a variable name</b><br>';
else
$vstring .= '$'. $vname .'</b><b style="color:green"> = </b>';
echo $vstring;
if(is_array($var))
print_r($var);
elseif(!empty($var))
var_dump($var);
?>
</pre>
<?php
if($exit)
exit();
}
Спустя 13 минут, 10 секунд (28.11.2009 - 22:31) Хозяин Огня написал(а):
twin, я так просто не отстану))
Ок, мы в вар записали кучу циферек.
Откуда в значениях переменных нашего скрипта могут оказаться эти циферки?
И вот конкретный вопрос
Это сообщение выведется, если мы в скрипте напишем например так
Но почему? Ведь $var у нас не может быть пустым!
$var = microtime(); // перезаписываем переменную, нужно уникальное значение, по этому microtime()
Ок, мы в вар записали кучу циферек.
if($val === $var) // Если нашли
Откуда в значениях переменных нашего скрипта могут оказаться эти циферки?
И вот конкретный вопрос
elseif(empty($var))
$vstring .= '</b><b style="color:red">The variable is not defined or empty</b><br>';
Это сообщение выведется, если мы в скрипте напишем например так
debug($obladioblada);
Но почему? Ведь $var у нас не может быть пустым!
Спустя 11 часов, 1 минута, 48 секунд (29.11.2009 - 09:33) Хозяин Огня написал(а):
Уфф, вроде разобрался. Плохо себе представлял массив $GLOBALS, и не обратил должного внимания на & перед $var.
Растолкуйте только при каком условии может получиться
Растолкуйте только при каком условии может получиться
elseif(empty($vname))
Цитата |
А можно через get_defined_vars() тоже самое сделать? Мне кажется, массив поменьше $GLOBALS получится... |
Да нет, не меньше точно, а может и чуть больше)
Спустя 44 минуты, 14 секунд (29.11.2009 - 10:17) twin написал(а):
Хозяин Огня
Цитата |
Растолкуйте только при каком условии может получиться |
Ну ты бы перевел сообщение, которое в скрипте.
Это произойдет тогда, когда переменная есть, но в массиве $GLOBALS её нету. То есть она определена в функции или классе.
Спустя 7 часов, 59 минут, 54 секунды (29.11.2009 - 18:17) Хозяин Огня написал(а):
Пока ничего лучше предложить не могу, только дополнить)
Выносим функцию в отдельный файл, начало будет такое:
Таким образом мы можем отключить функцию, присвоив новой константе false.
Ну а вызов, как легко догадаться, будет таким:
Вывод можно сделать примерно таким:
Выносим функцию в отдельный файл, начало будет такое:
define('TRACEON', TRUE);
function debug(&$var, $line, $file)
{
if (TRACEON)
{
Таким образом мы можем отключить функцию, присвоив новой константе false.
Ну а вызов, как легко догадаться, будет таким:
debug($var, __LINE__, __FILE__);
Вывод можно сделать примерно таким:
if (is_array($var))
{
echo '<b>File </b>'. $file .
'<br><b>Line </b>'.$line.'!<br>';
print_r($var);
Спустя 1 месяц, 25 дней, 18 часов, 37 минут, 48 секунд (25.01.2010 - 12:55) baston написал(а):
Николай, вы можете пояснить, в чем разница между выводом $_POST и _POST в следующем примере:
Если я правильно понимаю, то это массив "$_POST". Но почему мы не пишем в последней строке $_POST, а пишем без "доллара"?
Спасибо.
if(empty($vname) && isset($_POST))
foreach($_POST as $key => $val)
if($val === $var)
$vname = '_POST[<span style="color:red" >"'. $key .'"</span>]';</span>
Если я правильно понимаю, то это массив "$_POST". Но почему мы не пишем в последней строке $_POST, а пишем без "доллара"?
Спасибо.
Спустя 10 минут, 1 секунда (25.01.2010 - 13:05) twin написал(а):
В первом случае это переменная (массив), а во втором просто строка для красоты.

Спустя 14 минут, 52 секунды (25.01.2010 - 13:20) baston написал(а):
Эх, не сообразил, что в апострофах... Привык, что строки обязательно в двойных кавычках (в vba).
Спустя 20 дней, 2 часа, 27 минут, 44 секунды (17.02.2010 - 15:48) Michael написал(а):
twin, я себе PHP Expert Editor поставил. Он для жителей бывшего СССР бесплатен.
Зарегался, потом приходит на мыло код.
Специально его установил для дебагинга. Настроить его не сложно. И позволяет то о чем Volch писал делать: Пошаговая отладка, с заходом в функции/без захода, точки останова, переменные просматривать по ходу работы скрипта.
Хотя как для себя я еще сделаю что-то типа твоего, но чтобы сохранял дебаг инфу в отдельный html файл который можно держать в отдельной закладке. Т.е. работаешь с сайтом и параллельно просматриваешь дебаг листинг.

Специально его установил для дебагинга. Настроить его не сложно. И позволяет то о чем Volch писал делать: Пошаговая отладка, с заходом в функции/без захода, точки останова, переменные просматривать по ходу работы скрипта.
Хотя как для себя я еще сделаю что-то типа твоего, но чтобы сохранял дебаг инфу в отдельный html файл который можно держать в отдельной закладке. Т.е. работаешь с сайтом и параллельно просматриваешь дебаг листинг.
Спустя 6 минут, 11 секунд (17.02.2010 - 15:54) twin написал(а):
Рад за тебя.
Я вообще то специально расслабляться не хочу, практически ничем не пользуюсь. Только подсветкой в редакторе.
Вот такая функция выручает иногда, когда совсем завал.
Хотя наверно это не правильно, от прелестей прогресса нельзя отказываться... Но что поделаешь - привычка.
Лень матушка.

Я вообще то специально расслабляться не хочу, практически ничем не пользуюсь. Только подсветкой в редакторе.
Вот такая функция выручает иногда, когда совсем завал.
Хотя наверно это не правильно, от прелестей прогресса нельзя отказываться... Но что поделаешь - привычка.
Лень матушка.

Спустя 8 минут, 7 секунд (17.02.2010 - 16:02) Michael написал(а):
Та я тоже когда сам пишу в основном по ходу написания дебажу, тестю ("защитное программирование"
). Так что особых потребностей в пошаговой отладке не возникает.
Но тут столкнулся с одной большой чужой кодинкой и смотрю что прологировать его не зная направления не очень удобно. Вот тут то пошаговая и выручила.

Но тут столкнулся с одной большой чужой кодинкой и смотрю что прологировать его не зная направления не очень удобно. Вот тут то пошаговая и выручила.
Спустя 1 месяц, 10 дней, 20 часов, 23 минуты, 5 секунд (28.03.2010 - 11:25) Guest написал(а):
извините,в уроки №0 описание идет: что писать в tpl.все начинается с такого начала <?php а окончания данного действия необязательно?
Спустя 11 часов, 16 минут, 42 секунды (28.03.2010 - 22:42) Guest написал(а):
извиняюсь конечно,я в этом деле полное Нубло,и поэтому родился вопрос :
при написании <?php
/**
* Подключаем шапку
* Includes a header template
*/
include './header.tpl';
/**
* Подключаем шаблон контента
* Includes a content template
*/
include './main.tpl';
/**
* Подключаем подвал
* Includes a footer template
*/
include './footer.tpl'; не нужно в конце ставить "?>"-это?
и еще один вопрос: схема №3 сильно отличается от схемы №4 там где был файл:появилась папка,а в папке этой появляется файл?
объясните нубику Плиииз почему так ?
при написании <?php
/**
* Подключаем шапку
* Includes a header template
*/
include './header.tpl';
/**
* Подключаем шаблон контента
* Includes a content template
*/
include './main.tpl';
/**
* Подключаем подвал
* Includes a footer template
*/
include './footer.tpl'; не нужно в конце ставить "?>"-это?
и еще один вопрос: схема №3 сильно отличается от схемы №4 там где был файл:появилась папка,а в папке этой появляется файл?
объясните нубику Плиииз почему так ?

Спустя 10 минут, 53 секунды (28.03.2010 - 22:53) twin написал(а):
Цитата |
не нужно в конце ставить "?>"-это? |
нет, это вредная привычка.
Цитата |
появилась папка,а в папке этой появляется файл? объясните нубику Плиииз почему так ? |
ну наверно потому, что мы их туда добавили... иначе как можно строить сайты, не делая папок и файлов?
Спустя -1 лет, 11 месяцев, 29 дней, 1 час, 30 минут, 58 секунд (29.03.2010 - 00:24) Guest написал(а):
посмотрел и прочитал еще разок.извиняюс.все понял
Спустя 21 день, 8 часов, 5 минут, 7 секунд (20.04.2010 - 08:29) Гость_dprus написал(а):
Здравствуйте уважаемые!!!
Тоже вопрос по Уроку 0.
Подскажите пожалуйста, не совсем понял по поводу урока 8, откуда взялся файл debug.php если его на схеме нет?
А также подскажите почему функция
Тоже вопрос по Уроку 0.
Подскажите пожалуйста, не совсем понял по поводу урока 8, откуда взялся файл debug.php если его на схеме нет?
define('IRB_TRACE', true);
include './debug.php';
А также подскажите почему функция
dbg($page);не работает. Я так понимаю эти два вопроса имеют отношение друг к другу так как должны выявлять ошибки, но пока в моем случае они их только добавляют. Может я что то сделал не так ? Но я вроде бы не чего лишнего не писал от себя.
Спустя 16 минут, 58 секунд (20.04.2010 - 08:46) Гость_dprus написал(а):
Спасибо с файлом debag.php разобрался но проблемы с функцией остались. Пишет сообщение:
а также выдает ошибку
Warning: Cannot modify header information - headers already sent by (output started at Z:\home\test3.ru\www\index.php:1) in Z:\home\test3.ru\www\index.php on line 15
ругается на заголовок с кадрировкой
Хотя кодеровка на всех файлах стоит utf-8 без BOM. В чем может быть причина?
TRACE № 1.
File: Z:\home\test3.ru\www\modules\main\view.php
Function: include
Line: 9
$page =
string(4) "main"
а также выдает ошибку
Warning: Cannot modify header information - headers already sent by (output started at Z:\home\test3.ru\www\index.php:1) in Z:\home\test3.ru\www\index.php on line 15
ругается на заголовок с кадрировкой
header("Content-Type: text/html; charset=utf-8");
error_reporting(E_ALL);
Хотя кодеровка на всех файлах стоит utf-8 без BOM. В чем может быть причина?
Спустя 2 часа, 12 минут, 12 секунд (20.04.2010 - 10:58) twin написал(а):
Цитата |
Хотя кодеровка на всех файлах стоит utf-8 без BOM. В чем может быть причина? |
99% на то, что BOM все таки имеет место быть. Либо там пробел.
output started at Z:\home\test3.ru\www\index.php:1
Спустя 5 месяцев, 28 дней, 6 часов, 46 минут, 3 секунды (18.10.2010 - 17:44) lopzan написал(а):
Я чайник, хочу научиться РНР.
Установил из интера ApachHTTPServer2,2 и PHP5.
Настроил ApachHTTPServer2,2 через httpd.conf
Проверил как положено сервер - отвечает.
DHS в службах включен.
В PHP5 не могу найти php.ini, нашел вроде, но он чисто текстовый файл,
но всё равно вставил туда нужный doc_root.
Все попытки написать программку на рнр не получается,
с сервера приходят пустые картинки.
Помогите пожалуйста!
lopzan
lopzan@rambler.ru
Установил из интера ApachHTTPServer2,2 и PHP5.
Настроил ApachHTTPServer2,2 через httpd.conf
Проверил как положено сервер - отвечает.
DHS в службах включен.
В PHP5 не могу найти php.ini, нашел вроде, но он чисто текстовый файл,
но всё равно вставил туда нужный doc_root.
Все попытки написать программку на рнр не получается,
с сервера приходят пустые картинки.
Помогите пожалуйста!
lopzan
lopzan@rambler.ru
_____________
Если вам недостаточно собственных заблуждений, можно расширить их мнениями экспертов.
Нужно уважать мнение оппонета. Ведь заблуждаться - его святое право.
Настаивал, настаиваю и буду настаивать на своем. На кедровых орешках.
