Re[2]: Качество кода open-source
От: Lonely Dog Россия  
Дата: 23.05.08 07:17
Оценка: +1
Здравствуйте, superlexx, Вы писали:

S>им просто надо было использовать __COUNTER__ вместо __LINE__ под MSVC. Сейчас навалял себе небольшой вспомогательный класс с __COUNTER__, очень понравилось. Практически получается C#-овский yield (не так же красиво, но всё-таки).

После этого код бы собирался? Это хорошо. Но все равно, он остался бы нечитаемым.
Re[3]: Качество кода open-source
От: Lonely Dog Россия  
Дата: 23.05.08 07:20
Оценка:
Здравствуйте, azzx, Вы писали:

A>А они точно кодогенерацию не применяют нигде? У меня бывают в СПЕЦИФИЧЕСКИХ случаях такие методы — но всегда в том или ином варианте используется кодогенерация, ибо я не идиот это ручками поддерживать. Так что вся "поддержка" такого кода заключается в изменении настроек кодогенератора ( и не важно что это — список вызовов макросов в

отдельном файле, Excel-таблица с макросами на VBA или действительно специально написанная программа).
Если бы там была кодо-генерация, то вопросов бы не было. Но тогда к исходникам надо прилагать скрипт из которого эти функции генерятся. Этого там нет. Следовательно, это не кодогенерация. Кроме того, там форматирование съехавшее. Такое обычно бывает при ручном написании кода.
Re[2]: Качество кода open-source
От: squid  
Дата: 23.05.08 07:29
Оценка: +1
Здравствуйте, Константин Л., Вы писали:

КЛ>Здравствуйте, Lonely Dog, Вы писали:


КЛ>[]


КЛ>имею дело с thunderbird. резюме — дерьмо. методы на 1500 строк в порядке вещей. свичи на 1500 строк в порядке вещей. написано просто грязно. как это работает я не представляю.


ну, мне как пользователю он очень нравицца особенно если вспомнить что запускается мгновенно, а The Bat! минуту шуршит.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[3]: �������� ���� open-source
От: Roman Odaisky Украина  
Дата: 23.05.08 07:43
Оценка: 1 (1)
Здравствуйте, Lonely Dog, Вы писали:

RO>>If one calls nextMove() repeatedly, one would get something like RRRDRRURRRRRRRRDRURR... (the return value depends on the place where the function returned the previous time).

LD>Неужели этого нельзя добиться менее грязным способом?

Это была задачка с топкодера. Нужно управлять буром, который добывает минералы по мотивам флеш-игры «Motherload». Нужно сделать функцию наподобие char move(Field), т. е., они тебе информацию о ближайших видимых ячейках (которые содержат (или не содержат) полезные ископаемые), а ты им 'U', 'D', 'L' или 'R'.

Вот ты уже принял решение: нужно опуститься на глубину 42 единицы, т. е., ближайшие 42 раза нужно возвращать 'D'. Как бы ты это сделал?
for(i = 0; i < 42; ++i)
{
    YIELD('D');
}
До последнего не верил в пирамиду Лебедева.
Re[4]: GPuTTY
От: Roman Odaisky Украина  
Дата: 23.05.08 07:57
Оценка:
Здравствуйте, OCTAGRAM, Вы писали:

>> C>Нормально его поддерживают. Я вот Putty на GTK2 под Линукс помог

>> перенести, сейчас пакет делаю (https://launchpad.net/putty2).
>> А зачем он там нужен? Чем он лучше, чем сочетание вашего любимого
>> эмулятора терминала с комманд-лайновым ssh клиентом?
OCT>В команд–лайновом нужно помнить esc-последовательности, чтобы порты
OCT>форвардить. Ты вот их помнишь?

Нажми «~?», будет тебе хелп, нажми «~C» и набери «help», будет тебе хелп по командной строке.

Лично я, впрочем, использую исключительно /usr/bin/ssh. Если требуется -L, то лучше для этого завести отдельный ssh -fNT (и ControlMaster auto в ssh_config). А EscapeChar у меня всё равно отключен.

Консольный ssh чем хорош — во-первых, есть автодополнение хостов, во-вторых, можно работать в одном окне вперемежку с разными машинами, в-третьих, можно просто выполнять команды по одной (ssh server command).

Чего не хватает, и, насколько я знаю, в PuTTY этого тоже нет — чтобы ssh-agent (Pageant) задавал вопрос при попытке аутентификации через ForwardAgent. Иначе root системы, куда я логинюсь, может свободно пользоваться моим агентом. Ключ не узнает, но изменить PATH и положить затрояненную sudo сможет.
До последнего не верил в пирамиду Лебедева.
Re[4]: �������� ���� open-source
От: max779 Россия  
Дата: 23.05.08 09:12
Оценка: +1
Здравствуйте, Roman Odaisky, Вы писали:

RO>Это была задачка с топкодера. Нужно управлять буром, который добывает минералы по мотивам флеш-игры «Motherload». Нужно сделать функцию наподобие char move(Field), т. е., они тебе информацию о ближайших видимых ячейках (которые содержат (или не содержат) полезные ископаемые), а ты им 'U', 'D', 'L' или 'R'.


RO>Вот ты уже принял решение: нужно опуститься на глубину 42 единицы, т. е., ближайшие 42 раза нужно возвращать 'D'. Как бы ты это сделал?


Я бы сделал вариацию на тему:

queue<char> m_vNextMoves;
char GetCharFromNextMoves()
{
    char chRet = -1;
    if (m_vNextMoves.size())
    {
        chRet = m_vNextMoves.front();
        m_vNextMoves.pop();
    }
    return chRet;
}
public:
char move(int iField)
{
    if (m_vNextMoves.size())
         return GetCharFromNextMoves();
..........
    for (int i = 0; i < 42; i++)
    {
        m_vNextMoves.push('D');
    }
    return (GetCharFromNextMoves());
............
}


Ну там естественно от задачи все зависит, может вообще рекурсивно в каждой ячейке смотрел бы куда идти. Может и развернул бы эту рекурсию в цикл. В общем, обойти можно по разному, но только не таким извратом.
Кстати, расскажите, чем конкретно эти дикие define лучше кода выше? По читаемости и сопровождаемости, ИМХО, этот лучше.
Но может меня тут переубедят и я проникнусь и так же писать начну...
Re[5]: GPuTTY
От: OCTAGRAM Россия http://octagram.name/
Дата: 23.05.08 09:33
Оценка:
Roman Odaisky пишет:
> Консольный ssh чем хорош

Одно другому никак не мешает

--
ISO/IEC 8652:1995/Amd 1:2007
Posted via RSDN NNTP Server 2.1 beta
Re: Качество кода open-source
От: Lorenzo_LAMAS  
Дата: 23.05.08 10:00
Оценка: 2 (2) +1
ИМХО, зря ты так поспешил охаять этот код :

Simon Tatham (born May 3, 1977) is an English programmer known primarily for creating and maintaining PuTTY,


Implementations for C

Several attempts have been made, with varying degrees of success, to implement coroutines in C with combinations of subroutines and macros. Simon Tatham's contribution[8] is a good example of the genre, and his own comments provide a good evaluation of the limitations of this approach. The use of such a device truly can improve the writability, readability and maintainability of a piece of code, but is likely to prove controversial. In Tatham's words: "Of course, this trick violates every coding standard in the book... [but] any coding standard which insists on syntactic clarity at the expense of algorithmic clarity should be rewritten. If your employer fires you for using this trick, tell them that repeatedly as the security staff drag you out of the building."


http://en.wikipedia.org/wiki/Co-routines
http://en.wikipedia.org/wiki/Simon_Tatham
Of course, the code must be complete enough to compile and link.
Re[3]: Качество кода open-source
От: Константин Л.  
Дата: 23.05.08 10:29
Оценка: :)
Здравствуйте, squid, Вы писали:

[]

S>ну, мне как пользователю он очень нравицца особенно если вспомнить что запускается мгновенно, а The Bat! минуту шуршит.


мне тоже, поэтому я и удивляюсь, как _это_ работает
Re[2]: Качество кода open-source
От: Draqon  
Дата: 23.05.08 11:15
Оценка: :)
Здравствуйте, Lorenzo_LAMAS, Вы писали:

L_L>ИМХО, зря ты так поспешил охаять этот код :



PuTTY is a Win32 Telnet and SSH client. The SSH protocol code contains real-life use of this coroutine trick. As far as I know, this is the worst piece of C hackery ever seen in serious production code. © Simon Tatham


Так что он сам его хаит
Re[5]: �������� ���� open-source
От: Roman Odaisky Украина  
Дата: 23.05.08 11:17
Оценка: 2 (2)
Здравствуйте, max779, Вы писали:

M>Ну там естественно от задачи все зависит, может вообще рекурсивно в каждой ячейке смотрел бы куда идти. Может и развернул бы эту рекурсию в цикл. В общем, обойти можно по разному, но только не таким извратом.

M>Кстати, расскажите, чем конкретно эти дикие define лучше кода выше? По читаемости и сопровождаемости, ИМХО, этот лучше.
M>Но может меня тут переубедят и я проникнусь и так же писать начну...

Это сопрограмма. RTFM TAOCP 1.4.2.

Вот что я тогда написал:
class Pod
{
public:
    Pod(int fuelTank, int cargoBay, int maxMineralIndex, double costFactor):
        F(fuelTank), B(cargoBay), N(maxMineralIndex), q(costFactor),
        depth(0), f(fuelTank), b(0)
    {
    }

    char move(std::vector<std::string> const& zone)
    {
        char const c = play(zone);

        здесь обновляются всякие внутренние переменые

        return c;
    }

private:
    int depth;
    int f;
    int b;

    char delve(std::vector<std::string> const& zone)
    {
        static int seen0 = 0;
        static int seeng = 0;

        static double p0, pg, eta;

        static int aditDepth;
        static int shaftDepth;

        static int b0;
        static int bv;

        static int f0;

        static int dx = 0;

        COROUTINE
        {
            assert(depth == 0);

            while(depth < exploreDepth)
            {
                {
                    int const c0 = std::count(zone[4].begin(), zone[4].end(), CAVE);
                    int const cg = std::count(zone[4].begin(), zone[4].end(), GOB);

                    seen0 += c0;
                    seeng += cg;
                }

                YIELD('D');
            }
        
            p0 = double(seen0) / exploreDepth / zone[0].size();
            pg = double(seeng) / exploreDepth / zone[0].size();

            eta = 1. - p0 - pg;

            std::clog << "p0 = " << p0 << ", pg = " << pg << ", eta = " << eta << std::endl;

            {
                double const targetDepth = 0.25 * F - 0.5 * B/eta * (1. + 3. * p0)/(1. + p0);
                double const vertDelta = 0.5 * p0 * B / eta;
                double const aditEst = 0.5 * B / eta / (1. + p0);

                aditDepth  = (int)(targetDepth - vertDelta - horzSafetyFactor * aditEst - vertSafetyFactor * vertDelta);
                shaftDepth = (int)(targetDepth + vertDelta - horzSafetyFactor * aditEst);

                std::clog << "t = " << targetDepth << ", hs = " << horzSafetyFactor * aditEst << ", vs = " << vertSafetyFactor * vertDelta << std::endl;
            }

            std::clog << "adit = " << aditDepth << ", shaft = " << shaftDepth << std::endl;

            std::clog << "Digging...";

            while(depth < aditDepth)
            {
                if(depth % 50 == 0)
                {
                    std::clog << " " << depth << "..." << std::flush;
                }

                YIELD('D');
            }

            std::clog << std::endl;

            while(cellToBottom(zone) == CAVE && cellToRight(zone) != CAVE)
            {
                ++aditDepth;
                ++shaftDepth;
                YIELD('D');
            }

            std::clog << "depth = " << depth << ": adit" << std::endl;

            if(cellToRight(zone) != CAVE)
            {
                YIELD('R');
                YIELD('L');
            }

            b0 = b;
            std::clog << "Garbage mined: " << b0 << std::endl;

            while(depth < shaftDepth)
            {
                YIELD('D');
            }

            std::clog << "depth = " << depth << ": shaft" << std::endl;

            bv = b - b0;

            std::clog << "Mined in shaft: " << bv << std::endl;

            while(depth > aditDepth)
            {
                YIELD('U');
            }

            std::clog << "depth = " << depth << ": adit again" << std::endl;

            f0 = f;

            std::clog << "Fuel left: " << f << std::endl;

            std::clog << "Mining...";
            while(b - b0 - bv < (B - bv) / 2 && f0 - f < fuelAllowanceFactor * (f0 - 2 * shaftDepth))
            {
                if(cellToBottom(zone) != CAVE || cellToRight(zone) == CAVE)
                {
                    ++dx;

                    YIELD('R');

                    if((b - b0) % 10 == 0)
                    {
                        std::clog << " " << (b - b0) << "..." << std::flush;
                    }
                }
                else
                {
                    YIELD('D');
                }
            }
            std::clog << std::endl;

            std::clog << "depth = " << depth << ", dx = " << dx << ": time to turn back. "
                "Mined so far: " << (b - b0) << " (" << bv << " + " << (b - b0 - bv) << ")" << std::endl;

            std::clog << "Fuel left: " << f << std::endl;

            YIELD('D');

            std::clog << "Mining...";
            while(dx > 0)
            {
                if(cellToBottom(zone) != CAVE || cellToLeft(zone) == CAVE)
                {
                    --dx;

                    YIELD('L');

                    if((b - b0) % 10 == 0)
                    {
                        std::clog << " " << (b - b0) << "..." << std::flush;
                    }
                }
                else
                {
                    YIELD('D');
                }
            }
            std::clog << std::endl;

            std::clog << "Total mined: " << (b - b0) << " + " << b0 << " garbage" << std::endl;

            std::clog << "depth = " << depth << ": LIFTOFF!" << std::endl;

            while(depth > 0)
            {
                YIELD('U');
            }

            std::clog << "Fuel left: " << f << std::endl;

            while(1)
            {
                YIELD(glide(zone));
            }
        }

        return 'X';
    }

    char glide(std::vector<std::string> const& zone)
    {
        COROUTINE
        {
            while(1)
            {
                assert(depth == 0);

                while(false
                    || zone[5][4] == CAVE // v› impossible or ineffective
                    || cellToBottom(zone) == GOB && (zone[4][5] != CAVE || zone[5][5] == CAVE) // v› ineffective
                    || zone[5][5] == CAVE && zone[4][6] != CAVE // v›› impossible, have to v›^ -- ineffective
                    || zone[4][5] == GOB && zone[4][6] == GOB // M..M: v››› = f8c2, ›››v = f5c1
                )
                {
                    YIELD('R');
                }

                YIELD('D');

                while(1)
                {
                    if(false
                        || b >= B
                        || f < 4
                        || cellToBottom(zone) == CAVE && cellToRight(zone) != CAVE
                        || zone[3][5] == GOB && zone[3][6] == GOB && zone[3][7] == GOB && zone[3][8] == GOB
                    )
                    {
                        YIELD('U');
                        break;
                    }

                    YIELD('R');
                }
            }
        }

        return 'X';
    }

    char play(std::vector<std::string> const& zone)
    {
        COROUTINE
        {
            static bool isVertBetter;

            {
                std::string const tmp = zone[4] + zone[5] + zone[6];
                double const p0Est = std::count(tmp.begin(), tmp.end(), CAVE) / double(tmp.size());
                double const pgEst = std::count(tmp.begin(), tmp.end(), GOB)  / double(tmp.size());

                double const etaEst = 1. - p0Est - pgEst;

                std::clog << "etaEst: " << etaEst << std::endl;

                double const vertEst = B * std::pow(q, N * (1. - (B * vertCoefEst) / (F /* * etaEst*/)));
                double const horzEst = 0.5 * F * etaEst;

                std::clog << "vertEst: " << vertEst << " horzEst: " << horzEst << std::endl;

                isVertBetter = vertEst > horzEst;
            }

            while(1)
            {
                YIELD(isVertBetter ? delve(zone) : glide(zone));
            }
        }
    }

    int const B;
    int const N;
    int const F;
    double const q;
};

Алгоритм понимать необязательно, но обрати внимание, как часто вызывается YIELD. С точки зрения программирования, YIELD магическим образом обновляет состояние класса и продолжает выполнение (а на самом деле там return, после которого функция вызывается еще раз с обновленными параметрами).

Заодно здесь хорошо виден недостаток этого подхода — приходится объявлять переменные заранее.

И еще здесь есть «if(false\n||», но это из другого флейма :-)

А вот кусок решения этой же задачи участником, который занял второе место. Ты уверен, что так лучше?
        if (state_ == 1) {
            // Return to the surface.
            if (position_.X <= 1) {
                state_ = 5;
                continue;
            }
            return strategy_return(vs);
        } else if (state_ == 2) {
            // Find new spot to harvest.
            strategy_best_depth();
            state_ = 3;
            continue;
        } else if (state_ == 3) {
            if (harvest_depth_ < 2) {
                state_ = 5;
                continue;
            }
            // Descent.
            if (position_.X == harvest_depth_) {
                state_ = 4;
                harvest_dir_ = 0;
                continue;
            }
            return strategy_descent(vs);
        } else if (state_ == 4) {
            bool no_dir = (harvest_dir_ == 0);
            if (no_dir) harvest_dir_ = 3;
            if (!no_dir && harvest_dir_ == 3 && strategy_surface_go_down(fuel_left_ - rough_sourface_distance_ - 5, position_, 2, true)) {
                harvest_dir_ = 2;
                return pop_plan(vs);
            }
            if (no_dir) harvest_dir_ = 2;
            if (strategy_surface_go_down(fuel_left_ - rough_sourface_distance_ - 5, position_, 3, true)) {
                harvest_dir_ = 3;
                return pop_plan(vs);
            }
            if (no_dir) harvest_dir_ = 3;
            if (strategy_surface_go_down(fuel_left_ - rough_sourface_distance_ - 5, position_, 2, true)) {
                harvest_dir_ = 2;
                return pop_plan(vs);
            }
            if (no_dir) harvest_dir_ = 0;
            if (can_dig(vs, 1)) {
                do_make_move(vs, 1, MOVE_DIG);
                return dc[1];
            } else {
                do_make_move(vs, 1, MOVE_FLY);
                return dc[1];
            }
        } else if (state_ == 5) {
            if (position_.X > 1) {
                if (5 - harvest_dir_ != last_used_dir_ && strategy_surface_go_down(fuel_left_ - 5, position_, 5 - harvest_dir_)) {
                    return pop_plan(vs);
                }
                if (strategy_surface_go_down(fuel_left_ - 5, position_, harvest_dir_)) {
                    return pop_plan(vs);
                }
                if (strategy_surface_go_down(fuel_left_ - 5, position_, 5 - harvest_dir_)) {
                    return pop_plan(vs);
                }
                state_ = 6;
                continue;
            }
            last_used_dir_ = 0;
            return strategy_surface_explorer(vs);
        } else if (state_ == 6) {
            if (position_ == surface_pos_.back()) {
                surface_pos_.pop_back();
                continue;
            }
            if (surface_pos_.empty()) {
                state_ = 5;
                continue;
            }
            return strategy_shortest_path(vs, surface_pos_.back());
        } else {
            // Whatever.
            return strategy_random(vs);
        }
До последнего не верил в пирамиду Лебедева.
Re[4]: Качество кода open-source
От: squid  
Дата: 23.05.08 11:33
Оценка: +1 :))
Здравствуйте, Константин Л., Вы писали:

КЛ>Здравствуйте, squid, Вы писали:


КЛ>[]


S>>ну, мне как пользователю он очень нравицца особенно если вспомнить что запускается мгновенно, а The Bat! минуту шуршит.


КЛ>мне тоже, поэтому я и удивляюсь, как _это_ работает


вывод — если хорошо работает и все нравицца — нефиг смотреть как оно сделано
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[2]: Качество кода open-source
От: rising_edge  
Дата: 23.05.08 11:43
Оценка: 1 (1) +2 -1
Здравствуйте, Maxim S. Shatskih, Вы писали:

LD>>Мне интересно, весь open-source написан так же или это мне так повезло?


MSS>Примерно так.


LD>>Как при таком качестве кода они умудряются что-то разумное делать?


MSS>Видимо, высокое качество исходного кода не особо и нужно


Я думаю, что качество закрытого кода мегатонн всякого фри- и шароварного барахла немного ниже. Просто этого никто не видит.
Re[2]: Качество кода open-source
От: Phoenics Россия https://sourceforge.net/projects/phengine
Дата: 23.05.08 11:50
Оценка: 3 (1) :)))
Здравствуйте, SergeCpp, Вы писали:

SC>Это ещё цветочки


SC>Ягодки — вот тут
Автор: SergeCpp
Дата: 08.02.07


Детский сад! У нас на работе есть магическая мега-функция оставленная нам "демиургами", её длинна на данный момент ~1800строк, она набита свичами и goto, причём можно ивдеть и такие вещи как:
case тра-ля-ля:
goto три рубля
break;
case тра-ля-ля:
goto три рубля

Как параметр эта функция принимает структуру, объявление которой занимает ~200 строк, что составляет примерно 150 параметров, примерно 1/3 которых некоментированы, и не имеют вменяемых названий...
И наконец эта функция вызывается ресурсивно...

Ну Хто ещё чем похвастает?
---=== С наилучшими пожеланиями, Phoenics ===---
_
Re[5]: Качество кода open-source
От: Константин Л.  
Дата: 23.05.08 11:52
Оценка: +1 :)
Здравствуйте, squid, Вы писали:

[]

S>вывод — если хорошо работает и все нравицца — нефиг смотреть как оно сделано


мне туда лазить приходится. и при любой такой необходимости к каждому члену нашей команды приходит депрессия
Re[3]: Качество кода open-source
От: Phoenics Россия https://sourceforge.net/projects/phengine
Дата: 23.05.08 12:02
Оценка:
Я это всё к чему? К тому что дело тут не в том Open Source у нас или нет. Дело в программистах, но и не только в них.
Треша везде хватает, и к сожалению для его появления иногда бывают объективные (хотя чаще и субьективные) причины. Например я в своём опенсорсном проекте стараюсь всё содержать в чистоте.
Но в опенсорсе этот нерпиглядный код всегда навиду, из-за чего может сложится впечатление что оно всегда так, а в комерческих продуктах всё зашибись. Нет, я думаю я далеко не единсвтенный кто может привести примеры совершенно неоправданного мегатреша в успешном комерческом продукте.
---=== С наилучшими пожеланиями, Phoenics ===---
_
Re[6]: �������� ���� open-source
От: max779 Россия  
Дата: 23.05.08 12:47
Оценка: +3
Здравствуйте, Roman Odaisky, Вы писали:

RO>Алгоритм понимать необязательно, но обрати внимание, как часто вызывается YIELD. С точки зрения программирования, YIELD магическим образом обновляет состояние класса и продолжает выполнение (а на самом деле там return, после которого функция вызывается еще раз с обновленными параметрами).


Вот именно, что магическим образом обновляет... Я больше чем уверен, что это все можно было переписать просто рекурсией.
Второй вариант явно лучше только потому, что там нет этих магических обновлений. Правда там тоже перестарался, видимо разворачивал рекурсию в цикл. И явно этот код можно было написать лучше.
В общем, меня не убедили. А основной косяк этого подхода вот в чем: вот ты пишешь программу и пользуешься этими магическими YIELD и т.д. Потом ты увольняешься, на твое место приходит другой кодер и он не знаком с этим делом... Он конечно познакомится рано или поздно и перепишет весь твой код без этих макросов. И только потому что, чтобы хранить в уме эти магические обновления и переходы надо намного больше усилий... В общем, его мнение о тебе будет таким же как у Lonely Dog об open source.
Помните: программы пишутся для человека, а не для машины. Машина разберется в любых goto, а вот у человека голова опухнет...
Re[6]: Качество кода open-source
От: squid  
Дата: 23.05.08 14:39
Оценка: -1
Здравствуйте, Константин Л., Вы писали:

КЛ>Здравствуйте, squid, Вы писали:


КЛ>[]


S>>вывод — если хорошо работает и все нравицца — нефиг смотреть как оно сделано


КЛ>мне туда лазить приходится. и при любой такой необходимости к каждому члену нашей команды приходит депрессия


всякое бывает. судя по этому форуму (за последний месяц) плохие вещи принято писать на Дельфи а не на Сях.

вообще я реально люблю Thuderbird и на дух не переношу Firefox. как раз потому что птичка летает а лиса тормозит
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[7]: Качество кода open-source
От: Sergey Россия  
Дата: 23.05.08 15:04
Оценка:
squid пишет:

> вообще я реально люблю Thuderbird и на дух не переношу Firefox. как раз

> потому что птичка летает а лиса тормозит

Странно, а мне наоборот показалось Особенно на ньюсах — тормознее
птички я ни одной ньюсочиталки не видел.
Posted via RSDN NNTP Server 2.1 beta
Одним из 33 полных кавалеров ордена "За заслуги перед Отечеством" является Геннадий Хазанов.
Re[8]: Качество кода open-source
От: squid  
Дата: 23.05.08 15:08
Оценка: :)
Здравствуйте, Sergey, Вы писали:

S>squid пишет:


>> вообще я реально люблю Thuderbird и на дух не переношу Firefox. как раз

>> потому что птичка летает а лиса тормозит

S>Странно, а мне наоборот показалось Особенно на ньюсах — тормознее

S>птички я ни одной ньюсочиталки не видел.

ньюс это что? RSS?
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.