The team of CODERS
Высказывайте своё мнение.
О работе в паре у меня другие данные. Читал в журнале (Компьтеры+Программы):
Двое сидят перед одним компьютером. Один пишет, второй смотрит, что пишет первый. Потом меняются ролями:).
Научно-популярные журналы всегда трактуют все слишком буквально. Кроме того, это не есть основная суть XP.
О работе в паре у меня другие данные. Читал в журнале (Компьтеры+Программы):
Двое сидят перед одним компьютером. Один пишет, второй смотрит, что пишет первый. Потом меняются ролями:).
С таким же успехом 10 человек напишут то же самое за то время , за которое это написали 2 человека. Смысл?
Научно-популярные журналы всегда трактуют все слишком буквально. Кроме того, это не есть основная суть XP.
Отсюда правило:
Никогда не воспринимайте всерьёз то , что написано в журнале.
Можно и по исходному коду.
AnsiString p1(" "), p2(" ");
int i;
strcpy(p1.c_str(), Edit1->Text.c_str());
c = new TLabel*[i = p1.ToInt()];
for(; i >= 0; i--)
c = new TLabel(Form1);
strcpy(p2.c_str(), Edit2->Text.c_str());
for(i = p1.ToInt(); i >= 0; i--)
delete c;
delete []c;
Мы говорим о профессионально разработке или о "шарашкеной конторе"?
В профессиональных командах существует утвержденный CodeStyle, и это касается не только XP.
Вы -- не знаю. Я говорю о том, что:
1) если мы вообще хотим написать что-то работоспособное, надо для начала взять что-то попроще;
2) "В профессиональных командах существует утвержденный CodeStyle", который для каждой команды свой, и писать проверялку CodeStyle придётся с кучей настроек, мол, допускать такое написание или вот такое или вообще третье.
Вот это действительно можно.
Спасибо на намек о научно популярности.
Я его понял :).
Значит в XP так и написано, программирование в паре, это 2программиста+1компьютер.
И снизу маленькими буквами в душках: только не принимайте это в серьез.
точно :D
AnsiString p1(" "), p2(" ");
int i;
strcpy(p1.c_str(), Edit1->Text.c_str());
c = new TLabel*[i = p1.ToInt()];
for(; i >= 0; i--)
c = new TLabel(Form1);
strcpy(p2.c_str(), Edit2->Text.c_str());
for(i = p1.ToInt(); i >= 0; i--)
delete c;
delete []c;
Проверить сейчас, к сожалению, не могу... но объясни, будь добр, что этот код может делать? создавать кучу лэйблов, а потом их удалять? сорьки за ламерство...
Проверить сейчас, к сожалению, не могу... но объясни, будь добр, что этот код может делать? создавать кучу лэйблов, а потом их удалять? сорьки за ламерство...
А как бы ты проверял , если даже код разобрать не можешь*?
Спасибо на намек о научно популярности.
Я его понял :).
Значит в XP так и написано, программирование в паре, это 2программиста+1компьютер.
И снизу маленькими буквами в душках: только не принимайте это в серьез.
"Пираты Карибского моря" смотрел?
Так вот XP - это не свод строгих правил, а рекомендации (иногда настоятельные). Никто не мешает воспринимать их по-своему и вводить что-то свое. Действительно, многие авторы рекомендуют именно такой подход (2 программиста, 1 компьютер), они приводят достаточно весомые аргументы. Но лично я считаю, что для нашей фирмы с небольшим штатом - это пока роскошь, поэтому считаю, что два рядом сидящих программиста в данный момент куда более актуально.
А по поводу научной популярности. Я действительно считаю, что журналы весьма поверхностны, за исключением сугубо специфичных (из отечественных - только RSDN). А некоторые и вовсе "гонят пургу" и "льют воду", к примеру, журнал "Хакер". Если в журнале основной упор в XP делается на парное программирование, значит, что-то там ребята в редакции схалтурили.
AnsiString p1(" "), p2(" ");
int j;
strcpy(p1.c_str(), Edit1->Text.c_str());
c = new TLabel*[j = p1.ToInt()];
for(; j >= 0; j--)
c[j] = new TLabel(Form1);
strcpy(p2.c_str(), Edit2->Text.c_str());
for(j = p1.ToInt(); j >= 0; j--)
delete c[j];
delete []c;
Напиши алгоритм, который найдёт причину Memory Leak в вышеприведённом коде.
Для начала давай приведем твой код к некоторому стилю (задача №1 для будушей утилиты):
1) определяем переменные непосредственно перед их использованием,
2) стараесмя инициализировать переменные сразу после объявления,
код приобретает вид:
strcpy(p1.c_str(), Edit1->Text.c_str());
int j = p1.ToInt();
TLabel **c = new TLabel*[j];
for(; j >= 0; j--)
c[j] = new TLabel(Form1);
strcpy(p2.c_str(), Edit2->Text.c_str());
for(j = p1.ToInt(); j >= 0; j--)
delete c[j];
delete []c;
Далее проверяем соответствие типов. Это делает и компилятор, он должен был выдать множество варнингов по этому коду, но наша доблестная утилита ещё раз шерстит код и находит, что с_str() возвращает const char*, а strcpy принимает первым аргументом char*. Опасное преобразование. В результате мы выявили [COLOR=red]Buffer Overflow![/COLOR]
Кроме того вообще неясно, зачем нужно подобное копирование, вполне можно было бы обойтись
p1 = Edit1->Text;. Непонятно и странная инициализация p1 и p2.
Исключаем эти недорозумения, повторно приводим к стилю, код приобретает вид:
int j = p1.ToInt();
TLabel **c = new TLabel*[j];
for(; j >= 0; j--)
c[j] = new TLabel(Form1);
AnsiString p2 = Edit2->Text.c_str;
for(j = p1.ToInt(); j >= 0; j--)
delete c[j];
delete []c;
Далее проверяем используемость переменных.
Смотрим...
p2 инициализируется, но далее не используется.
Гы! Теперь я понял на чем ты хотел меня поймать, но ошибся. Во втором цикле хотел написать j = p2.ToInt(); Чтож не судьба...
j - используется в двух циклах, это не очень красиво... ну да ладно
Далее смотрим дублирование.
p1.ToInt(); - повторяется дважды, можно ограничится одним разом.
Код приобретает вид:
int size = p1.ToInt();
TLabel **c = new TLabel*[size];
for(int j=size; j >= 0; j--)
c[j] = new TLabel(Form1);
for(int j=size; j >= 0; j--)
delete c[j];
delete []c;
Цикл так же повторяется дважды, p1 используется единожды. Исключаем:
TLabel **c = new TLabel*[size];
for(int j=size; j >= 0; j--)
{
c[j] = new TLabel(Form1);
delete c[j];
}
delete []c;
Далее проверяем параметры цикла...
И оказыватся, что вы выходим за границы выделенного массива! При первой же итерации:
c[[COLOR=red]size[/COLOR]] = new TLabel(Form1);
delete c[[COLOR=red]size[/COLOR]];
На лицо еще один [COLOR=red]Buffer overflow![/COLOR]
Исправляем:
TLabel **c = new TLabel*[size];
for(int j=size-1; j >= 0; j--)
{
c[j] = new TLabel(Form1);
delete c[j];
}
delete []c;
А код то бессмысленный, т.к. если его упрощать дальше, то оказывается TLabel **c ненужна. Цикл создает и тут же уничтожает объекты одного и того же класса некоторое количество раз, хотя, это может кому-то и надо. Результат:
delete new TLabel(Form1);
Вот, что реально делает твой код, если убрать ошибки. :D
Сравни ка с первоначальным кодом.
А Memory Leak мы тут не нашли в виду его отсутствия. :D
2) "В профессиональных командах существует утвержденный CodeStyle", который для каждой команды свой, и писать проверялку CodeStyle придётся с кучей настроек, мол, допускать такое написание или вот такое или вообще третье.
Правильно. Обычно CodeStyle не очень большой и его можно представить в виде набора элементарных правил, которые вводятся в анализируюшую систему.
И ещё, эта задача уже реализовывалась и не раз. Я предложил, просто, создать свою полноценную систему, которая включала бы в сеья все эти разрозненные и недостающие компоненты.
P.S. Я заменил i на j, чтоб форум не глючил на конструкциях типа [j].
Для начала давай приведем твой код к некоторому стилю (задача №1 для будушей утилиты):
1) определяем переменные непосредственно перед их использованием,
2) стараесмя инициализировать переменные сразу после объявления,
код приобретает вид:
strcpy(p1.c_str(), Edit1->Text.c_str());
int j = p1.ToInt();
TLabel **c = new TLabel*[j];
for(; j >= 0; j--)
c[j] = new TLabel(Form1);
strcpy(p2.c_str(), Edit2->Text.c_str());
for(j = p1.ToInt(); j >= 0; j--)
delete c[j];
delete []c;
Далее проверяем соответствие типов. Это делает и компилятор, он должен был выдать множество варнингов по этому коду, но наша доблестная утилита ещё раз шерстит код и находит, что с_str() возвращает const char*, а strcpy принимает первым аргументом char*. Опасное преобразование. В результате мы выявили [COLOR=red]Buffer Overflow![/COLOR]
Кроме того вообще неясно, зачем нужно подобное копирование, вполне можно было бы обойтись
p1 = Edit1->Text;. Непонятно и странная инициализация p1 и p2.
Исключаем эти недорозумения, повторно приводим к стилю, код приобретает вид:
int j = p1.ToInt();
TLabel **c = new TLabel*[j];
for(; j >= 0; j--)
c[j] = new TLabel(Form1);
AnsiString p2 = Edit2->Text.c_str;
for(j = p1.ToInt(); j >= 0; j--)
delete c[j];
delete []c;
Далее проверяем используемость переменных.
Смотрим...
p2 инициализируется, но далее не используется.
Гы! Теперь я понял на чем ты хотел меня поймать, но ошибся. Во втором цикле хотел написать j = p2.ToInt(); Чтож не судьба...
j - используется в двух циклах, это не очень красиво... ну да ладно
Далее смотрим дублирование.
p1.ToInt(); - повторяется дважды, можно ограничится одним разом.
Код приобретает вид:
int size = p1.ToInt();
TLabel **c = new TLabel*[size];
for(int j=size; j >= 0; j--)
c[j] = new TLabel(Form1);
for(int j=size; j >= 0; j--)
delete c[j];
delete []c;
Цикл так же повторяется дважды, p1 используется единожды. Исключаем:
TLabel **c = new TLabel*[size];
for(int j=size; j >= 0; j--)
{
c[j] = new TLabel(Form1);
delete c[j];
}
delete []c;
Далее проверяем параметры цикла...
И оказыватся, что вы выходим за границы выделенного массива! При первой же итерации:
c[[COLOR=red]size[/COLOR]] = new TLabel(Form1);
delete c[[COLOR=red]size[/COLOR]];
На лицо еще один [COLOR=red]Buffer overflow![/COLOR]
Исправляем:
TLabel **c = new TLabel*[size];
for(int j=size-1; j >= 0; j--)
{
c[j] = new TLabel(Form1);
delete c[j];
}
delete []c;
А код то бессмысленный, т.к. если его упрощать дальше, то оказывается TLabel **c ненужна. Цикл создает и тут же уничтожает объекты одного и того же класса некоторое количество раз, хотя, это может кому-то и надо. Результат:
delete new TLabel(Form1);
Вот, что реально делает твой код, если убрать ошибки. :D
Сравни ка с первоначальным кодом.
А Memory Leak мы тут не нашли в виду его отсутствия. :D
Правильно. Обычно CodeStyle не очень большой и его можно представить в виде набора элементарных правил, которые вводятся в анализируюшую систему.
И ещё, эта задача уже реализовывалась и не раз. Я предложил, просто, создать свою полноценную систему, которая включала бы в сеья все эти разрозненные и недостающие компоненты.
P.S. Я заменил i на j, чтоб форум не глючил на конструкциях типа [j].
Кто ты?
Для начала давай приведем твой код к некоторому стилю (задача №1 для будушей утилиты):
1) определяем переменные непосредственно перед их использованием,
Давай...
А вот это "не давай", потому как в реальных прогах это не всегда возможно.
strcpy(p1.c_str(), Edit1->Text.c_str());
int j = p1.ToInt();
TLabel **c = new TLabel*[j];
for(; j >= 0; j--)
c[j] = new TLabel(Form1);
strcpy(p2.c_str(), Edit2->Text.c_str());
for(j = p1.ToInt(); j >= 0; j--)
delete c[j];
delete []c;
Далее проверяем соответствие типов. Это делает и компилятор, он должен был выдать множество варнингов по этому коду, но наша доблестная утилита ещё раз шерстит код и находит, что с_str() возвращает const char*, а strcpy принимает первым аргументом char*. Опасное преобразование. В результате мы выявили [COLOR=red]Buffer Overflow![/COLOR]
Не факт. Я могу поставить ограничение на длину строки в Edit1 и Edit2, так что, несмотря на некузявость исходного текста, в Runtime всё будет нормально. Кстати, часть функций нашей будущей проги уже "отпадает": контроль типов с гораздо большим успехом, оказывается, делает компилятор! ;)
p1 = Edit1->Text;. Непонятно и странная инициализация p1 и p2.
Можно. Но не нужно. Этот пример -- часть сухого остатка в результате анализа кода реальной коммерческой программы, которую писала одна софтовая фирма нашего города (сразу говорю: я в этом проекте не участвовал).
1) Компилятор сделает это лучше.
2) Как я уже сказал, это всего лишь пример. От примера, как и от шахматного этюда, не требуется законченность, от него требуется наглядность.
p2 инициализируется, но далее не используется.
Гы! Теперь я понял на чем ты хотел меня поймать, но ошибся. Во втором цикле хотел написать j = p2.ToInt(); Чтож не судьба...
Не хотел. Всё написано правильно.
j = p1.ToInt();
А как же используемость переменных??? Как я уже говорил насчёт CodeStyle, у каждого свои понятия о красоте, своё чувство прекрасного.
p1.ToInt(); - повторяется дважды, можно ограничится одним разом.
Можно, если завести ещё одну переменную либо "развернуть" цикл в обратную сторону.
Но, с точки зрения оптимизации по скорости, цикл до 0 быстрее. Что касается второй переменной -- для наглядности прошу оставить именно p1.ToInt();
Исправляем:
Исправление принимается. Писал второпях, про "-1" забыл.
Итак, код приобретает вид:
strcpy(p1.c_str(), Edit1->Text.c_str());
int j = p1.ToInt() - 1;
TLabel **c = new TLabel*[j];
for(; j >= 0; j--)
c[j] = new TLabel(Form1);
strcpy(p2.c_str(), Edit2->Text.c_str());
for(j = p1.ToInt() - 1; j >= 0; j--)
delete c[j];
delete []c;
Думаем дальше.
А вот это "не давай", потому как в реальных прогах это не всегда возможно.
Поэтому я и написал "стараемся". В данном примере это вполне возможно.
Не факт. Я могу поставить ограничение на длину строки в Edit1 и Edit2, так что, несмотря на некузявость исходного текста, в Runtime всё будет нормально. Кстати, часть функций нашей будущей проги уже "отпадает": контроль типов с гораздо большим успехом, оказывается, делает компилятор! ;)
Я таковой проверки или ограничения в коде не увидел, а то что за пределами кода мы додумывать не будем, т.к. это начинает напоминать игру "кто задумает большее число" из м/ф "Котенок по имени Гаф".
Про больший успех компилятора я бы не был столь оптимистичным, все зависит от компилятора, параметров компиляции, да и кто читает варнинги (последнее сказано с эронией). Например, компилятор не сигнализирует о преобразовании к void*, что может быть очень опасным!
Можно. Но не нужно. Этот пример -- часть сухого остатка в результате анализа кода реальной коммерческой программы, которую писала одна софтовая фирма нашего города (сразу говорю: я в этом проекте не участвовал).
Если честно, код хреновый, непрофессиональный.
Лично я считаю, что такая замена просто необходима. А то, что это код "реальной комерческой программы" ни о чем не говорит, подход "если ЭТО работает, оставь все как есть и ничего не трогай" в XP не работает, рефакторинг - совершенно противоположный подход: то, что следует переделать для упрощения кода (как для чтения, так и для повышения производительности), должно быть переработанно. А чтоб код не потерял работоспособности, существуют юнит-тесты.
Кстати, если ты хочешь продолжать спор, ознакомься хотя бы с основными принципами XP.
1) Компилятор сделает это лучше.
У компилятора несколько другие задачи, поэтому он и делает это весьма поверхностно. Ты же не используешь видеокамеру для получения фотографий?
2) Как я уже сказал, это всего лишь пример. От примера, как и от шахматного этюда, не требуется законченность, от него требуется наглядность.
См. фразу про игру в числа.
Не хотел. Всё написано правильно.
j = p1.ToInt();
Тогда где ты нашел MemoryLeak?
Или это тоже осталось за пределами примера? :D
А как же используемость переменных??? Как я уже говорил насчёт CodeStyle, у каждого свои понятия о красоте, своё чувство прекрасного.
Когда у каждого "свое чувство прекрасного" тогда получается разброд и шатание. Наглядный пример - Вавилонская башня.
Можно, если завести ещё одну переменную либо "развернуть" цикл в обратную сторону.
Но, с точки зрения оптимизации по скорости, цикл до 0 быстрее. Что касается второй переменной -- для наглядности прошу оставить именно p1.ToInt();
Что касается наглядности, то переменная с соотв. названием (size) куда более наглядно, чем повторный вызов метода. О производительности спорить будем?
Исправление принимается. Писал второпях, про "-1" забыл.
Итак, код приобретает вид:
strcpy(p1.c_str(), Edit1->Text.c_str());
int j = p1.ToInt() - 1;
TLabel **c = new TLabel*[j];
for(; j >= 0; j--)
c[j] = new TLabel(Form1);
strcpy(p2.c_str(), Edit2->Text.c_str());
for(j = p1.ToInt() - 1; j >= 0; j--)
delete c[j];
delete []c;
Думаем дальше.
Строка
AnsiString p1(" "), p2(" ");
просто режет зрение!
Во второй строке потенциальный Bufferoverflow!
Где проверка на j>0 после инициализации?
[COLOR=red]Опять же опасное преобразование типа int -> size_t в new[]![/COLOR] Что может привести к MemoryLeak.
В первом цикле опять BufferOverflow, опять цикл от j, а не j-1. Вот, твоя мнимая наглядность.
Короче, я начинаю повторятся.
Код негодный и требует рефакторинга и устранения потенциальных опасностей.
Как видишь данные мной (это имени будущей утилиты) рекомендации избавили тебя от ошибки (Buffer Overflow), заставили подумать об ограничении вводимых значений и т.д.
А вот тебе пример, сможешь определить MemoryLeak без использования дебагера?
{
char* p = new char;
}
Поэтому я и написал "стараемся". В данном примере это вполне возможно.
Я таковой проверки или ограничения в коде не увидел, а то что за пределами кода мы додумывать не будем, т.к. это начинает напоминать игру "кто задумает большее число" из м/ф "Котенок по имени Гаф".
Про больший успех компилятора я бы не был столь оптимистичным, все зависит от компилятора, параметров компиляции, да и кто читает варнинги (последнее сказано с эронией). Например, компилятор не сигнализирует о преобразовании к void*, что может быть очень опасным!
Если честно, код хреновый, непрофессиональный.
Лично я считаю, что такая замена просто необходима. А то, что это код "реальной комерческой программы" ни о чем не говорит, подход "если ЭТО работает, оставь все как есть и ничего не трогай" в XP не работает, рефакторинг - совершенно противоположный подход: то, что следует переделать для упрощения кода (как для чтения, так и для повышения производительности), должно быть переработанно. А чтоб код не потерял работоспособности, существуют юнит-тесты.
Кстати, если ты хочешь продолжать спор, ознакомься хотя бы с основными принципами XP.
У компилятора несколько другие задачи, поэтому он и делает это весьма поверхностно. Ты же не используешь видеокамеру для получения фотографий?
См. фразу про игру в числа.
Тогда где ты нашел MemoryLeak?
Или это тоже осталось за пределами примера? :D
Когда у каждого "свое чувство прекрасного" тогда получается разброд и шатание. Наглядный пример - Вавилонская башня.
Что касается наглядности, то переменная с соотв. названием (size) куда более наглядно, чем повторный вызов метода. О производительности спорить будем?
Строка
AnsiString p1(" "), p2(" ");
просто режет зрение!
Во второй строке потенциальный Bufferoverflow!
Где проверка на j>0 после инициализации?
[COLOR=red]Опять же опасное преобразование типа int -> size_t в new[]![/COLOR] Что может привести к MemoryLeak.
В первом цикле опять BufferOverflow, опять цикл от j, а не j-1. Вот, твоя мнимая наглядность.
Короче, я начинаю повторятся.
Код негодный и требует рефакторинга и устранения потенциальных опасностей.
Как видишь данные мной (это имени будущей утилиты) рекомендации избавили тебя от ошибки (Buffer Overflow), заставили подумать об ограничении вводимых значений и т.д.
А вот тебе пример, сможешь определить MemoryLeak без использования дебагера?
{
char* p = new char;
}
Why new char?
Why new char?
А почему бы и нет? Какая разница под что и сколько места выделять (в контексте данного примера).
Всё поскипано.
А вот тебе пример, сможешь определить MemoryLeak без использования дебагера?
{
char* p = new char;
}
Во флейме участвовать не хочу.
И моя к тебе просьба, уважаемый Green, хватит язвить, поверь, я это тоже умею, только желания нет.
Всё поскипано.
Во флейме участвовать не хочу.
И моя к тебе просьба, уважаемый Green, хватит язвить, поверь, я это тоже умею, только желания нет.
Да ладно Вам.
Во флейме участвовать не хочу.
И моя к тебе просьба, уважаемый Green, хватит язвить, поверь, я это тоже умею, только желания нет.
Это не флейм, и язвить я не собирался.
Это пример (упрощенный до минимума), в котором показано, что некоторые виды MemoryLeak могут быть обнаружены не прибегая к отладке, что весьма упрощает жизнь.
Это не флейм, и язвить я не собирался.
Это пример (упрощенный до минимума), в котором показано, что некоторые виды MemoryLeak могут быть обнаружены не прибегая к отладке, что весьма упрощает жизнь.
Точно, флэймов нам не надо.
Точно, флэймов нам не надо.
И попугаев нам не надо тоже ;-)
<skip>
Это можно без дебагера?
Рефакторинг в первую очередь, должен был бы знать программист, чтоб с самого начала писать "нормальный код".
Ну, в данном случае не "рефакторинг", а стиль аккуратного программирования. Этим и должна заниматься та часть чудо-системы проверки кода, которая отвечает за CodeStyle. А кроме того при проверке func() должно выдаваться предупреждение о возможном MemoryLeak, которое уж программист должен отработать.
Мимоходом не знаешь хорошую книгу на рефаторинг в C++?
Читал, что книга Фаулер итд: Рефакторинг: улучшение существующего кода
вроде хорошая, но она для Java.
Книга неплохая.
В контексте С++ из литературы по рефакторингу ничего, к сожалению, не знаю.
Книги по OOA&D:
http://anatolix.naumen.ru/oodesignbooks.htm
Давайте без крайнего скептицизма.
Если я сказал, что некоторые ошибки, связанные с MemoryLeak можно выявить и устранить не прибегая к отладчику, то это не значит, что я утверждаю, что все случаи можно выявить не прибегая к дебагеру. То, что шар более аэродинамическая форма, чем куб, можно определить "на бумаге". Для этого не надо обдувать их в трубе. Но никто не отказывается от использования аэродинамических труб вовсе, но для более тонких анализов, для более сложных форм.
Конечно, нельзя написать программу, которая смогла бы досконально проверить код, написанный человеком, и выявить все его ошибки. Это из теории конечных автоматом, кажется. :D
Но, не смотря на это, неплохо было бы создать инструментарий, который упростил бы задачу поиска ошибок и дефектов.
Иначе, зачем пишут фаерволлы, которые не могут защитить от всех атак. Антивирусы, которые не защищают от всех вирусов. Калькуляторы, которые обладают ограничением по разрядной сетке и т.д.
И попугаев нам не надо тоже ;-)
Прости , а НАМ - это кому?
И попугаев нам не надо тоже ;-)
;) да ладно,что ты так на мальчика...:)
;) да ладно,что ты так на мальчика...:)
До кучи нам и мальчиков не надо. :P
;) да ладно,что ты так на мальчика...:)
Да вы шутники.
Да вы шутники.
нельзя же всегда быть такими серьёзными,как ты
или ты обиделся на то,что я тебя мальчиком назвала?:D
Это ты уже перегнул.
Без него не обойтись.
а давно ты программированием интересуешься?
нельзя же всегда быть такими серьёзными,как ты
или ты обиделся на то,что я тебя мальчиком назвала?:D
Я не всегда серьёзный , и я не обиделся. Не люблю тупые шутки.
а давно ты программированием интересуешься?
Давно. Ещё с тех времен, когда Торвальдс впервые узнал, что такое UNIX.
Если тут есть модератор, огромная просьба, удали оффтоп, плз!
Я не всегда серьёзный , и я не обиделся. Не люблю тупые шутки.
:devil: понятно.
не знаю только,где ты шутку увидел...
:devil: понятно.
не знаю только,где ты шутку увидел...
Увидел. Всё. А то многоуважаемый дядюшка Green уже ругается.
До кучи нам и мальчиков не надо. :P
:D надо!! так как я поняла,вы тут хотите какой-то проект организовать или это пока всё в планах?
:D надо!! так как я поняла,вы тут хотите какой-то проект организовать или это пока всё в планах?
Ну задание от Green'а уже есть.
Ну задание от Green'а уже есть.
ясно!Green,я смотрю,здесь всех учит!!
ясно!Green,я смотрю,здесь всех учит!!
Так и есть.
Так и есть.
:) Эт хорошо!Может лет через 10 я тоже как он буду кого-нить учить составлять проги)
:) Эт хорошо!Может лет через 10 я тоже как он буду кого-нить учить составлять проги)
Всё возможно.