spirit crash (картинка 150 K)
От: Alexander G Украина  
Дата: 20.03.09 08:15
Оценка: :))) :))) :))) :))) :))) :))) :))) :))) :))) :))) :))
Не знаю, сюда, в КУ или сразу в КСВ...



20.03.09 12:09: Перенесено модератором из 'C/C++' — Хитрик Денис
Русский военный корабль идёт ко дну!
Re: [spoiler] дополнительная инфа
От: Alexander G Украина  
Дата: 20.03.09 08:41
Оценка: +1
Через WinDbg удалось понять:
Исключение типа Stack overflow. Всё шло как надо, просто спирит не в состоянии обработать столько.
Крэш как бы намекает на то, что надо переходить с прототипа на спирите на нормальную реализацию.
Русский военный корабль идёт ко дну!
Re: spirit crash (картинка 150 K)
От: Erop Россия  
Дата: 20.03.09 09:04
Оценка:
Здравствуйте, Alexander G, Вы писали:

AG>Не знаю, сюда, в КУ или сразу в КСВ...

+1
Всё-таки в КУ наверное

А окошко внизу -- это call stack?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[2]: spirit crash (картинка 150 K)
От: Alexander G Украина  
Дата: 20.03.09 09:22
Оценка:
Здравствуйте, Erop, Вы писали:

E>А окошко внизу -- это call stack?


Ага. К сожалению ни имена методов полностью ни стек целиком не отображается в Студии, пришлось юзать WinDbg для отладки.
Русский военный корабль идёт ко дну!
Re: spirit crash (картинка 150 K)
От: jazzer Россия Skype: enerjazzer
Дата: 20.03.09 09:55
Оценка:
Здравствуйте, Alexander G, Вы писали:

AG>Не знаю, сюда, в КУ или сразу в КСВ...


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

К тому же в большинстве случаев ошибка у тебя в коде, и библиотечные потроха тебе просто не нужны (поэтмоу в моем скрипте они скрываются, иначе через всякие "instantiated from" невозможно продраться, ну и grep -v никто не отменял.)
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re[2]: [spoiler] дополнительная инфа
От: jazzer Россия Skype: enerjazzer
Дата: 20.03.09 09:58
Оценка:
Здравствуйте, Alexander G, Вы писали:

AG>Через WinDbg удалось понять:

AG>Исключение типа Stack overflow. Всё шло как надо, просто спирит не в состоянии обработать столько.
AG>Крэш как бы намекает на то, что надо переходить с прототипа на спирите на нормальную реализацию.

А ты уверен, что это проблема спирита, а не кривой грамматики, которую ты на нем написал?
Включи отладочный режим (есть специальный макрос на эту тему), посмотри, как именно он парсит все, может, у тебя там просто бесконечная рекурсия (самая распространенная причина Stack overflow)?
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re[2]: spirit crash (картинка 150 K)
От: Alexander G Украина  
Дата: 20.03.09 10:03
Оценка:
Здравствуйте, jazzer, Вы писали:

J>Ты просто не умеешь их готовить

J>У меня есть специальный перловый транслятор, я через него всегда прогоняю все сообщения компилятора (это автоматически в мейк-файле), стеки от дебаггера и т.п. — выглядит все в результате вполне читабельно.

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

Этот случай легко разобран WinDbg без хитроумных трансляторов.
Русский военный корабль идёт ко дну!
Re[3]: spirit crash (картинка 150 K)
От: jazzer Россия Skype: enerjazzer
Дата: 20.03.09 10:06
Оценка:
Здравствуйте, Alexander G, Вы писали:

AG>Насчёт сообщений компилятора при ошибках в STL, в bind — то к ним легко привыкнуть.

Зачем привыкать, если можно читать по-человечески

AG>Кстати, в критичном коде бинд вообще не использую.


А какие проблемы с bind? Он же инлайнится весь (если ты его в function не сохраняешь, конечно же).
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re[3]: [spoiler] дополнительная инфа
От: Alexander G Украина  
Дата: 20.03.09 10:10
Оценка:
Здравствуйте, jazzer, Вы писали:

J>А ты уверен, что это проблема спирита, а не кривой грамматики, которую ты на нем написал?

J>Включи отладочный режим (есть специальный макрос на эту тему), посмотри, как именно он парсит все, может, у тебя там просто бесконечная рекурсия (самая распространенная причина Stack overflow)?

Уверен.

Рекурсия в одном месте — такая:
      group = '(' >> +element >> ')';
      element = ...|group;
Русский военный корабль идёт ко дну!
Re[4]: spirit crash (картинка 150 K)
От: Alexander G Украина  
Дата: 20.03.09 10:15
Оценка:
Здравствуйте, jazzer, Вы писали:

J>А какие проблемы с bind? Он же инлайнится весь (если ты его в function не сохраняешь, конечно же).


Не всегда весь. Ещё, делает несколько лишних копирований, можно упустить копирование чего-то большого.
Если бинд для передачи в for_each — всегда будет лучше BOOST_FOREACH, для более сложного алгоритма можно не полениться написать функтор.
Русский военный корабль идёт ко дну!
Re[5]: spirit crash (картинка 150 K)
От: jazzer Россия Skype: enerjazzer
Дата: 20.03.09 11:20
Оценка:
Здравствуйте, Alexander G, Вы писали:

AG>Здравствуйте, jazzer, Вы писали:


J>>А какие проблемы с bind? Он же инлайнится весь (если ты его в function не сохраняешь, конечно же).


AG>Не всегда весь. Ещё, делает несколько лишних копирований, можно упустить копирование чего-то большого.

boost::ref, boost::cref тебя спасет (ну да я уверен, что ты и без меня про них знаешь)

AG>Если бинд для передачи в for_each — всегда будет лучше BOOST_FOREACH, для более сложного алгоритма можно не полениться написать функтор.

BOOST_FOREACH не всеми компиляторами поддерживается, к сожалению
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re[4]: [spoiler] дополнительная инфа
От: jazzer Россия Skype: enerjazzer
Дата: 20.03.09 11:21
Оценка:
Здравствуйте, Alexander G, Вы писали:

AG>Уверен.


Тогда минимальный код, воспроизводящий проблему, в студию
Ну и файл, который нужно распарсить, естественно.
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re[5]: [spoiler] дополнительная инфа
От: Alexander G Украина  
Дата: 20.03.09 13:40
Оценка:
Здравствуйте, jazzer, Вы писали:

J>Тогда минимальный код, воспроизводящий проблему, в студию

J>Ну и файл, который нужно распарсить, естественно.

struct dumb_grammar : public boost::spirit::grammar<dumb_grammar>
{
  template <typename ScannerT>
  struct definition
  {
    typedef boost::spirit::rule<ScannerT> rule_t;
    definition(const dumb_grammar& g)
    {
      using namespace boost::spirit;
      symbol = range_p('\x32', '\x7F') - (ch_p('\\')|'('|')');
      group = '(' >> +element >> ')';
      element = symbol|group;
    }

    const rule_t& start(void) const
    {
      return group;
    }

    rule_t symbol, element, group;
  };

};


int _tmain(int argc, _TCHAR* argv[])
{
  size_t size = 1024 * 1024;
  char *p = (char*)malloc(size);
  memset(p, '(', size);
  {
    using namespace boost::spirit;
    dumb_grammar g;
    parse(p, p+size, g);
  }
  return 0;
}

Boost 1.37 проблема повторяется.
Русский военный корабль идёт ко дну!
Re: spirit crash (картинка 150 K)
От: Eugeny__ Украина  
Дата: 20.03.09 13:57
Оценка:
Здравствуйте, Alexander G, Вы писали:

AG>http://files.rsdn.ru/74426/spirit_crash.png


Кошмар...
Новости очень смешные. Зря вы не смотрите. Как будто за наркоманами подсматриваешь. Только тетка с погодой в завязке.
There is no such thing as a winnable war.
Re[6]: spirit crash (картинка 150 K)
От: Alexander G Украина  
Дата: 20.03.09 13:59
Оценка:
Здравствуйте, jazzer, Вы писали:

J>Здравствуйте, Alexander G, Вы писали:


AG>>Здравствуйте, jazzer, Вы писали:


J>>>А какие проблемы с bind? Он же инлайнится весь (если ты его в function не сохраняешь, конечно же).


AG>>Не всегда весь. Ещё, делает несколько лишних копирований, можно упустить копирование чего-то большого.

J>boost::ref, boost::cref тебя спасет (ну да я уверен, что ты и без меня про них знаешь)

Для this'а ещё спасёт &.
Для бинда, помещаемого в function и живущего дольше контекста shared_ptr спасёт.
/* return bind(&X::x, X()); // oops. */
return bind(&X::x, shared_ptr<X>(new X()));  // ok.


J>BOOST_FOREACH не всеми компиляторами поддерживается, к сожалению


Меня больше всего интересует компилятор, поставляемый со средой на картинке
Русский военный корабль идёт ко дну!
Re: spirit crash (картинка 150 K)
От: SV.  
Дата: 20.03.09 14:32
Оценка:
Здравствуйте, Alexander G, Вы писали:

AG>Не знаю, сюда, в КУ или сразу в КСВ...


AG>[-img]http://files.rsdn.ru/74426/spirit_crash.png[/img]


На момент прочтения сверху висела тема: "Праздновал юбилей". Щелкал, не глядя, по ней, а попал сюда. Ну, думаю, хорошо отпраздновали.
Re[6]: [spoiler] дополнительная инфа
От: jazzer Россия Skype: enerjazzer
Дата: 20.03.09 17:47
Оценка:
Здравствуйте, Alexander G, Вы писали:

J>>Ну и файл, который нужно распарсить, естественно.


AG>
AG>  memset(p, '(', size);
AG>


Ну да, рекурсия не бесконечная, всего 1024 * 1024 раз
Т.е. если вызов функции занимает всего байт на стеке (чего быть не может, так как надо хранить информацию для отката), то это сразу мегабайт
Я тебе такой крэш и без всякого спирита сэмулирую.

У тебя реально файлы такие? Т.е. все эти скобки еще миллион раз закроются же? Если не секрет, что ты за задачу решаешь, что тебе нужно парсить миллион раз вложенные скобки?
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re[7]: [spoiler] дополнительная инфа
От: . Великобритания  
Дата: 20.03.09 18:42
Оценка: +1
jazzer wrote:

> У тебя реально файлы такие? Т.е. все эти скобки еще миллион раз

> закроются же? Если не секрет, что ты за задачу решаешь, что тебе нужно
> парсить миллион раз вложенные скобки?
Хм... а это реально может быть проблемой, если есть возможность DoS-аттак. Нехорошо, если какой-нибудь сервис будет падать по переполнению стека при специально сформированных входных данных.
Posted via RSDN NNTP Server 2.1 beta
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[7]: [spoiler] дополнительная инфа
От: Cyberax Марс  
Дата: 20.03.09 18:46
Оценка: :))) :)))
Здравствуйте, jazzer, Вы писали:

J>У тебя реально файлы такие? Т.е. все эти скобки еще миллион раз закроются же? Если не секрет, что ты за задачу решаешь, что тебе нужно парсить миллион раз вложенные скобки?

Интерпретатор LISP?
Sapienti sat!
Re[7]: [spoiler] дополнительная инфа
От: Alexander G Украина  
Дата: 20.03.09 18:47
Оценка:
Здравствуйте, jazzer, Вы писали:

J>У тебя реально файлы такие? Т.е. все эти скобки еще миллион раз закроются же? Если не секрет, что ты за задачу решаешь, что тебе нужно парсить миллион раз вложенные скобки?


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

Кстати, boost::regex имеет макрос BOOST_REGEX_NON_RECURSIVE для тех, кто хочет обрабатывать любые входные данные без переполнения стека.
Русский военный корабль идёт ко дну!
Re[8]: [spoiler] дополнительная инфа
От: jazzer Россия Skype: enerjazzer
Дата: 21.03.09 08:34
Оценка:
Здравствуйте, Alexander G, Вы писали:

AG>Здравствуйте, jazzer, Вы писали:


J>>У тебя реально файлы такие? Т.е. все эти скобки еще миллион раз закроются же? Если не секрет, что ты за задачу решаешь, что тебе нужно парсить миллион раз вложенные скобки?


AG>Какой файл — не знаю, в дампе кучи нет, из стекового бектрейса извлекать сложно. Да, миллион скобок — это не реально, но и реальная грамматика сложнее. Я верю, что это не ошибка в моём коде, а патологический случай входных данных.


Ну на этот случай можно и защиту поставить.
Данные могут быть патологическими по-разному, может быть просто тупой огромный файл, результат разбора которого всю память забьет безо всякой рекурсии.

AG>Кстати, boost::regex имеет макрос BOOST_REGEX_NON_RECURSIVE для тех, кто хочет обрабатывать любые входные данные без переполнения стека.


Ну так то ж регэкспы, а Спирит — это парсер, реализующий рекурсивный спуск, трудно требовать от него нерекурсивности
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re[8]: [spoiler] дополнительная инфа
От: jazzer Россия Skype: enerjazzer
Дата: 21.03.09 08:35
Оценка: 1 (1)
Здравствуйте, ., Вы писали:

.>jazzer wrote:


>> У тебя реально файлы такие? Т.е. все эти скобки еще миллион раз

>> закроются же? Если не секрет, что ты за задачу решаешь, что тебе нужно
>> парсить миллион раз вложенные скобки?
.>Хм... а это реально может быть проблемой, если есть возможность DoS-аттак. Нехорошо, если какой-нибудь сервис будет падать по переполнению стека при специально сформированных входных данных.

Ну так защиту надо поставить, ограничить глубину рекурсии, на спирите это делается в две строчки.
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re[9]: [spoiler] дополнительная инфа
От: Alexander G Украина  
Дата: 21.03.09 08:50
Оценка:
Здравствуйте, jazzer, Вы писали:

J>Ну на этот случай можно и защиту поставить.

J>Данные могут быть патологическими по-разному, может быть просто тупой огромный файл, результат разбора которого всю память забьет безо всякой рекурсии.

Можно. Просто тупо огромный файл просто кинет std::bad_alloc, оно покажется пользователю как "Недостаточно памяти для обработки команды". А к stack overflow я не был готов. Более того, глобально его обрабатывать и не собираюсь, пусть лучше крешдампы приходят для переполнений в других местах. Конечно, теперь, когда я знаю, что в спирите может быть stack overflow, я могу обернуть его в SEH обработку с восстановлением.

J>Ну так то ж регэкспы, а Спирит — это парсер, реализующий рекурсивный спуск, трудно требовать от него нерекурсивности


Ну так в моём случае нужно пересмотреть метод разбора. Например, если бы нужно было было просто проверить балланс скобок, то хватило бы одного цикла и двух переменных
Русский военный корабль идёт ко дну!
Re[9]: [spoiler] дополнительная инфа
От: . Великобритания  
Дата: 21.03.09 11:52
Оценка: 1 (1)
jazzer wrote:

> Ну на этот случай можно и защиту поставить.

Интересно как.

> Ну так то ж регэкспы, а Спирит — это парсер, реализующий рекурсивный

> спуск, трудно требовать от него нерекурсивности
Рекурсивный спуск не означает, что должен использоваться системный стек и падать по его переполнению. Можно использовать банальный массив, никто не отменял std::stack, который честно вернёт out of memory в худшем случае.
Posted via RSDN NNTP Server 2.1 beta
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[10]: [spoiler] дополнительная инфа
От: jazzer Россия Skype: enerjazzer
Дата: 22.03.09 02:57
Оценка:
Здравствуйте, ., Вы писали:

.>jazzer wrote:


>> Ну на этот случай можно и защиту поставить.

.>Интересно как.
ну как-то так:
int i = 0;
group =  ch_p( '(' )[ increment_or_throw_a(i,10000) ]
     >> +element
     >>  ch_p( ')' )[ decrement_a(i) ];

increment_a и decrement_a есть в стандартной поставке, сделать increment_or_throw_a из increment_a, думаю, не составит труда.

>> Ну так то ж регэкспы, а Спирит — это парсер, реализующий рекурсивный

>> спуск, трудно требовать от него нерекурсивности
.>Рекурсивный спуск не означает, что должен использоваться системный стек и падать по его переполнению. Можно использовать банальный массив, никто не отменял std::stack, который честно вернёт out of memory в худшем случае.
тоже верно, хотя рекурсивные вызовы все равно будут, даже если все данные вынести на внешний стек в куче, и системный стек будет расходоваться.
Не уверен, что можно сделать так, чтоб системный стек не расходовался совсем, сохранив способ описания грамматики через expression templates.
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re[11]: [spoiler] дополнительная инфа
От: Alexander G Украина  
Дата: 22.03.09 07:13
Оценка: 1 (1)
Здравствуйте, jazzer, Вы писали:

>>> Ну на этот случай можно и защиту поставить.

.>>Интересно как.
J>ну как-то так:
int i = 0;
group =  ch_p( '(' )[ increment_or_throw_a(i,10000) ]
     >> +element
     >>  ch_p( ')' )[ decrement_a(i) ];

J>increment_a и decrement_a есть в стандартной поставке, сделать increment_or_throw_a из increment_a, думаю, не составит труда.

На MSVC ещё так можно.
Русский военный корабль идёт ко дну!
Re[11]: [spoiler] дополнительная инфа
От: . Великобритания  
Дата: 22.03.09 10:14
Оценка:
jazzer wrote:

> increment_a и decrement_a есть в стандартной поставке, сделать

> increment_or_throw_a из increment_a, думаю, не составит труда.
Так-то понятно, ведь это тривиальный пример. Но далеко не очевидно, в каком месте какой-нибудь реальной, сложной грамматики нужно будет такие штуки расставить.
Posted via RSDN NNTP Server 2.1 beta
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[12]: Какой уровень допустим ? 640 хватит всем ?
От: Alexander G Украина  
Дата: 22.03.09 12:14
Оценка:
Здравствуйте, ., Вы писали:

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


А ещё, если мы таки хотим обрабатывать большие файлы, как мы можем знать ограничение имплементации ?

В моём примере, 10 K скобок валят релиз. В дебаге, естественно, намного меньше. Разумеется, сильно зависит от опций. У более сложной граматики ограничение может быть существенно ближе.
Русский военный корабль идёт ко дну!
Re[13]: Какой уровень допустим ? 640 хватит всем ?
От: jazzer Россия Skype: enerjazzer
Дата: 22.03.09 12:25
Оценка:
Здравствуйте, Alexander G, Вы писали:

AG>Здравствуйте, ., Вы писали:


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


AG>А ещё, если мы таки хотим обрабатывать большие файлы, как мы можем знать ограничение имплементации ?


AG>В моём примере, 10 K скобок валят релиз. В дебаге, естественно, намного меньше. Разумеется, сильно зависит от опций. У более сложной граматики ограничение может быть существенно ближе.


практически всегда можно разумное ограничение поставить, просто исходя из смысла задачи, а не из возможностей имплементации.
А если действительно по смыслу задачи надо поддерживать огромную вложенность, то можно просто в настройках компилятора соответствующий объем стека установить и не волноваться более на его счет.
Ну либо сменить движок парсинга на такой, которой не задействует стек процесса.
Но, имхо, это экзотическая задача и нужно такое очень редко.
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re[14]: Какой уровень допустим ? 640 хватит всем ?
От: Alexander G Украина  
Дата: 22.03.09 12:42
Оценка:
Здравствуйте, jazzer, Вы писали:

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


Понятно что надо исходить из задачи, я к тому, что для экзотической задачи таки не хватает возможностей имплементации.

J>А если действительно по смыслу задачи надо поддерживать огромную вложенность, то можно просто в настройках компилятора соответствующий объем стека установить и не волноваться более на его счет.


Ну поставлю я 80 МБ стека, и сколько тредов я после этого смогу создать ?
Хотя поставить большой стек для отдельно взятого треда со спиритом — вариант.

J>Ну либо сменить движок парсинга на такой, которой не задействует стек процесса.

J>Но, имхо, это экзотическая задача и нужно такое очень редко.

Я думаю ещё можно попробовать выделить нерекурсивную часть грамматики и оставить её на спирите, а вложенные скобки разрулить вручную.
Русский военный корабль идёт ко дну!
Re[15]: Какой уровень допустим ? 640 хватит всем ?
От: jazzer Россия Skype: enerjazzer
Дата: 22.03.09 13:13
Оценка:
Здравствуйте, Alexander G, Вы писали:

AG>Здравствуйте, jazzer, Вы писали:


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


AG>Понятно что надо исходить из задачи, я к тому, что для экзотической задачи таки не хватает возможностей имплементации.

Для экзотических задач обычно не подходят средства для широкого применения Это общее правило
Иначе бы всем хватало вижуал бейсика

J>>А если действительно по смыслу задачи надо поддерживать огромную вложенность, то можно просто в настройках компилятора соответствующий объем стека установить и не волноваться более на его счет.


AG>Ну поставлю я 80 МБ стека, и сколько тредов я после этого смогу создать ?

AG>Хотя поставить большой стек для отдельно взятого треда со спиритом — вариант.
либо отдельный процесс. Грохнется — не жалко.

J>>Ну либо сменить движок парсинга на такой, которой не задействует стек процесса.

J>>Но, имхо, это экзотическая задача и нужно такое очень редко.

AG>Я думаю ещё можно попробовать выделить нерекурсивную часть грамматики и оставить её на спирите, а вложенные скобки разрулить вручную.

Ну там еще есть то, что между скобками, с ним, я думаю, самая возня...
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.