Няшная / Говнокод #27807 Ссылка на оригинал

0

  1. 1
  2. 2
  3. 3
  4. 4
  5. 5
  6. 6
  7. 7
  8. 8
  9. 9
  10. 10
  11. 11
  12. 12
  13. 13
  14. 14
  15. 15
  16. 16
  17. 17
  18. 18
  19. 19
  20. 20
  21. 21
  22. 22
  23. 23
  24. 24
  25. 25
  26. 26
  27. 27
  28. 28
  29. 29
  30. 30
  31. 31
  32. 32
  33. 33
  34. 34
  35. 35
  36. 36
  37. 37
  38. 38
  39. 39
  40. 40
  41. 41
  42. 42
  43. 43
  44. 44
  45. 45
  46. 46
  47. 47
  48. 48
  49. 49
  50. 50
  51. 51
  52. 52
  53. 53
  54. 54
  55. 55
  56. 56
  57. 57
  58. 58
  59. 59
  60. 60
  61. 61
  62. 62
  63. 63
  64. 64
  65. 65
  66. 66
  67. 67
  68. 68
  69. 69
  70. 70
  71. 71
  72. 72
  73. 73
  74. 74
  75. 75
  76. 76
  77. 77
  78. 78
  79. 79
  80. 80
  81. 81
  82. 82
  83. 83
  84. 84
  85. 85
  86. 86
  87. 87
  88. 88
  89. 89
  90. 90
  91. 91
  92. 92
  93. 93
  94. 94
// https://github.com/j123123/sexpr_parse/blob/584fc23de71bebe02545214f819e16b720a2c1e2/my_struct_utils.c#L119

blob *
blob_scan_fromstream
(
  FILE *stream
)
{
  size_t st_len = 0;
  size_t st_alloc;
  uint8_t *st = NULL;

  while(true)
  {
    const int fg = getc(stream);
    if(fg == EOF)
    {
      PRV_ERR_MACRO();
    }
    uint8_t c = fg;
    if(!isprint(fg))
    {
      PRV_ERR_MACRO();
    }
    switch(c)
    {
      case '\\':
        {
          int c2 = getc(stream);
          switch(c2)
          {
            case 'x':
              {
                int c3[2] =
                {
                  getc(stream),
                  getc(stream)
                };
                uint8_t tmp[2];

                for(size_t i = 0; i < 2; ++i)
                {
                  switch(c3[i])
                  {
                    case '0' ... '9':
                      tmp[i] = c3[i]-'0';
                      break;
                    case 'a' ... 'f':
                      tmp[i] = c3[i]+10-'a';
                      break;
                    case 'A' ... 'F':
                      tmp[i] = c3[i]+10-'A';
                      break;
                    default:
                      PRV_ERR_MACRO();
                  }
                }
                M_PUSH(tmp[1] | tmp[0] << 4);
              }
              break;
            case '\\':
              M_PUSH('\\');
              break;
            case 't':
              M_PUSH('\t');
              break;
            case 'n':
              M_PUSH('\n');
              break;
            case '"':
              M_PUSH('"');
              break;
            default:
              PRV_ERR_MACRO();
          }
        }
        break;
//      case '\t':
//      case '\n':
//        PRV_ERR_MACRO();
//        break;
      case '"':
        goto end;
      default:
        M_PUSH(c);
    }
  }

end:
  ;
  blob *tmp = blob_init(st_len, st);
  PRV_FREE(st);
  return tmp;
}

Эта вот хрень вычитывает из "FILE *" одно "слово".

Запостил: j123123 j123123, (Updated )

Комментарии (97) RSS

    • > генератор

      Да не, можно и без генератора что-то вменяемое накобенировать из примитивных парсеров. Там единственно класс грамматик поуже чем у бизона и надо очень аккуратно с рекурсией.
      Ответить
          • Спутать генераторы парсеров и лексеров и ленивые итераторы это пять.

            Вспоминается история Икануса про двух людей, спорящих про DN.
            Один говорил про Duke Nukem, а другой про Dos Navigator
            Ответить
            • > итераторы

              parser = Lark('''?sum: product
                                   | sum "+" product   -> add
                                   | sum "-" product   -> sub
                               ?product: item
                                   | product "*" item  -> mul
                                   | product "/" item  -> div
                               ?item: NUMBER           -> number
                                    | "-" item         -> neg
                                    | "(" sum ")"
                               %import common.NUMBER
                               %import common.WS
                               %ignore WS
                       ''', start='sum')
              Ответить
      • генераторы гавно.. все нормальные генераторы пишут ручками (по схеме но ручками). я как не опытный пытался писать на (каком то генераторе) в конечном итоге это говно парсило пол дня простой текст
        Ответить
        • > парсило полдня

          Ну... видимо ты какую-то недетерминированную грамматику туда захуярил и бедный парсер её перебором с откатами потом разбирал?

          Я не вижу других причин.
          Ответить
          • Парсер разве не должен быть детерменированным?
            Ответить
            • Документ в целом должен однозначно парситься, а вот где-то в середине парсинга может быть неоднозначность.

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

              Не помню уже названия для этих классов грамматик
              Ответить
              • > Тот же бизон умеет и вперед немножко подглядывать для разрешения конфликта и форкать стейт в неоднозначных точках и смотреть какой выживет.

                Это как в крестоговне с "жизнеспособностью" при вызове правильной функции https://govnokod.ru/27443#comment630395 ?
                Можно считать баллы у двух или более стейтов по каким-то критерям, и выживает вореант, набравший максимум баллов.

                А если сделать хуйню, где правила определения коэффициента жизнеспособности вореанта парсинга хуйни можно будет описывать на тьюринг-полном языке в виде специальной аннотации, парсинг может никогда не завершиться
                Ответить
                • Желательно чтобы эти правила можно было писать в самом разбираемом тексте. Причём в любом месте, даже в конце, чтобы парсить было интереснее. И влиять они должны даже на парсинг самих себя.
                  Ответить
                • Можно описать в аннотациях к фразе "сделать заебись" какую-то формальную спецификацию. И парсер должен будет так разобрать эту фразу, чтобы получился код, удовлетворяющий спеке.
                  Ответить
  • Какой конченный автомат )))

    Кому нужны генераторы, если есть десяток трудолюбивых олимпиадников?
    Ответить
  • > case '0' ... '9':

    Ого, не знал, что так можно.
    Ответить
      • Скажи вот мне, как рубящий в ремонте человек. Если стояк батареи это общедомовое имущество, а отводка от него (включая кран) имущество мое, и УК забыла поставить перемычку, так что когда я выключаю батарею -- я блокирую стояк, и соседи бузят, я могу же их посылать в УК? Кран -- моя собствненость, и я не обязан его открывать, верно?
        Ответить
        • Тут скорее и батарея и кран -- имущество УК т.к. они не отделены от стояка и являются его частью...

          Вряд ли без перемычки возможно это разделение ответственности.

          > посылать в УК

          Чтобы они потом засудили тебя нахуй за то что дом оставил без отопления? )))

          Лучше позвони им и попроси байпасс приделать как положено.
          Ответить
          • Кран имущество УК, но ставил я его за свой счет, и если он протечет -- меня выебут соседи

            Охуенно же

            Ну вообще я имел ввиду, что они должны поставить байпасс, а не требовать от меня "открыть кран"
            Ответить
            • > а не требовать

              У юристов не бывает транзитивности, емнип.

              Нельзя взять и сократить "сварщик не доделал работу и мне жарко" + "я закрыл кран и оставил соседей без тепла" до "сварщик не доделал работу и оставил соседей без тепла".
              Ответить
              • А причем тут сокращение?

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

                Я не могу портить общедомовое имущество
                Я могу делать что угодно со своим имуществом
                Кран -- мое имущество

                Если электрик сойдет с ума, и заземление из моей квартиры с этажа проведет к батарее соседки, и ее ебнет, буду ли я виноват в том, что включил в розетку стиралку с металлическим корпусом?
                Ответить
                • > если её ебнет

                  Первый раз наверное простят, так же как если ты откроешь кран когда соседи пожалуются.

                  Но вот если ты знал о проблеме и умышленно не открываешь кран или продолжаешь юзать эту машинку несмотря на просьбы соседей -- то ты пидор и будешь за это отвечать. Как и накосячивший электрик/сантехник.
                  Ответить
                • > своим имуществом

                  Ну как сказать... вроде бы по закону ты не можешь приварить радиатор слишком большой площади, т.к. это создаст дизбаланс соседям. Скорее всего блокировка потока в те же нормы прописана.
                  Ответить
                  • У радиаторов есть мощность. В ваттах. Есть нормы по количеству необходимого тепла. В килокалориях в час. Считается для каждого здания по своему. Если одно сильно превышает другое, другим будет холодно, и когда пидара вычислят, ему пересчитают коммуналку на фактически потреблённое тепло.
                    Ответить
                • Даже опуская вопрос, кому принадлежит кран, всю ответственность за его использование будешь нести ты.

                  Весь стояк остался без тепла? УК придётся вернуть деньги за некачественно оказанную услугу → УК стребует эти деньги с тебя. Если УК оштрафуют, они и сумму штрафа с тебя могут истребовать. Из-за резко закрытого крана выбило стык на чердаке и 10 квартир оказались залиты кипятком? Плати. Да, он был проржавевшим насквозь, но «система успешно прошла испытания перед началом отопительного сезона, экспертиза установила причиной неквалифицированные действия guest6, спровоцировавшие гидроудар, поднявший давление в отдельных участках отопительной системы намного выше нормальных эксплуатационных величин». Чей-то попугайчик замёрз? Надеюсь, он не был очень дорогим.
                  Ответить
                  • Ко мне в квартиру за 3 года никто не заходил и не проверял ни газовые трубы, ни отопление.

                    // я другой гость
                    Ответить
                • > я могу делать что угодно со своим имуществом

                  Нет. См. пример про телек ночью.
                  Ответить
        • > не обязан его открывать

          З.Ы. Я помню у нас в доме тоже как-то завёлся пидор с последовательно подключенным краном, которому было жарко зимой... Всем стояком его искали чтобы выебать.
          Ответить
            • Нашли. Он оказывается вообще не понимал, что весь стояк блочит своим краном... Приварили байпасс в итоге.
              Ответить
              • Ну то есть это в итоге была вина УК, что байпас не поставили? Он же ничего не платил, и его не заставили включать батареи?
                Ответить
                • Заставили включить конечно до установки перемычки.

                  Ситуация ничем не отличается от тех, у кого кранов вообще нет.
                  Ответить
                  • УК в итоге за свой счет поставили перемычку?
                    Ответить
                    • Ну да, их мудило же варило кран и забыло перемычку приварить.
                      Ответить
          • Только
            > со стояком его искали, чтобы выебать
            Ответить
            • Это про десктопа, у него тут у единственного ещё бывает стояк, поэтому он нам, половым дисфункционерам, иногда кажется пошлым.
              Ответить
          • То есть человек не имеет права выключить батарею зимой если ему жарко?
            пиздекц
            Ответить
            • Человек не имеет право выключить батарею тем, кто этого не желает. Себе — пожалуйста.
              Ответить
              • Я отключил свою батарею используя свой кран

                Почему при этом отключилисб батареи у соседей я не знаю
                Вероятно, УК что-то криво провел
                Разве это моя вина?
                Это вина УК

                А свет я могу себе выключить? Вдруг он тоже соседям холодильник отключит?
                Ответить
                • Вина УК в том что они забыли перемычку и тебе жарко. Твоя вина в том, что остальным холодно.
                  Ответить
                  • ее и нужно ставить
                    вопрос в том, кто это должен делать
                    Ответить
                    • Ну тут джва отдельных дела:

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

                      Ну собственно если он из УК, туда и обратись.
                      Ответить
                      • >обязан открыть кран

                        Вот этот момент мне непонятен. Кран мое имущество, стояк общедомовое.
                        Общедомовое я не имею права трогать, а кран имею: я его ставил за свои деньги, я за него отвечаю, если он протечет -- то я буду платить денег.

                        По-моему соседи должны выебать УК, и УК должны послать мне сантхника, которому я обязан предоставить доступ к стояку (как к общедомовому имуществу) и он должен поставить туда байпасс
                        Ответить
                        • И пока он будет ставить байпасс, куча народу должно без тепла сидеть?

                          Какой эгоизм ))))

                          Не, ну если они согласны -- я думаю никто и не заставит открывать кран. Но они УЖЕ пожаловались, раз управляшка к тебе пришла.
                          Ответить
                          • Ко мне еще не пришла управляйка, ко мне соседка приходила.

                            Я не против открыть кран на время пока они ставят байпасс, но мне совершенно не понятно почему я обязан постоянно сидеть с этим краном, если это косяк управляйки?

                            У меня просто горит жопа от того, что если кран протекает, то это ТВОЙ кран и ты должен нижним соседям полтора ляма

                            Если ты хочешь его поменять, то это ТВОЙ кран и ты платишь сантехнику за его замену

                            А если ты хочешь его закрыть, то сразу это общий кран, и делать этого нельзя.

                            Хуйня же, ну?
                            Ответить
                            • Ну вот у тебя есть свой телек, но ты не можешь включить его на всю громкость ночью.

                              Хотя казалось бы -- это твой телек в твоей хате.
                              Ответить
                • Я отключил себе воду используя кран в подвале. Как что провели строители я не ебу вообще. ХЗ, отключилось что-то у кого-то ещё.
                  Разве это моя вина?
                  Ответить
                  • У меня нет доступа в подвал, и подвал это не мое имущество
                    А кран мое

                    Я просто хуею с того, что если кран потечет то я буду его менять за свой счет
                    но закрыть не могу
                    Ответить
                    • Крутить протекающий кран в системе, находящейся под давлением -- не самая лучшая идея, как мне кажется...
                      Ответить
                      • Эээ? Нельзя закрыть кран на батарее? Нахуй он нужен тогджа?
                        Ответить
                    • > за свой счёт

                      Ну почему... в теории ты можешь его поменять за счёт завода, который делал кран или сварщика если они обещали, что всё будет заебись N лет.
                      Ответить
                      • Гарантия на установку батареи три года, увы.
                        но это мои отношения с тем, кто его ставил

                        Важно, что управляйка его не ставила в данном случае
                        Ответить
                        • Ну вот кто ставил -- тот и будет варить байпасс за свой счёт. А то понаварят хуйни в общий стояк.
                          Ответить
                        • > управляйка его не ставила

                          Так всё-таки кто кран то поставил?

                          Рукожоп из управляйки или рукожоп которого ты сам нанял?


                          В первом случае они откроют кран на время, приварят байпасс и дадут пиздюлей рукожопу.

                          Во втором случае они придут, откроют кран и ты будешь сам разбираться с рукожопом и/или варить за свой счёт.
                          Ответить
                • разбирайся/судись с УК, нафига ты соседям под коврик срёшь?
                  Ответить
            • То есть человек не имеет права сливать унитаз на соседей снизу если сантехник забыл подключить его к трубе?

              Как страшно жить в этом мире...
              Ответить
              • >То есть человек не имеет права сливать унитаз на соседей снизу если сантехник забыл подключить его к трубе?


                Совершенно верно.

                Если управляющая компания не заделала дырку в фановой трубе (в смысле в стояке между этажами), то она ее должна заделать.

                Она не имеет права сказать "не срите пожалуйста, потому что иначе соседей зальет"
                Ответить
    • Так можно в руби, перле (там правда в классическом варианте свича нету), и кажется в паскале
      Странно, что так можно в C

      А вон там снизу подсказывают, что это в GCC можно
      Ответить
  • https://github.com/j123123/sexpr_parse/blob/584fc23de71bebe02545214f819e16b720a2c1e2/my_struct.c#L182
    можно подумать, что тут какая-то хуйня
    // нахуя мне тут "CHAR_BIT*sizeof(unsigned long long)" ?
      const size_t bytes_allocated =
        1ULL <<
        (
          CHAR_BIT*sizeof(unsigned long long)-
          __builtin_clzll(sizeof(stack)+len*sizeof(node_elm))
        );

    _builtin_clzll() должна посчитать лидирующие нулевые биты в числе(для типа unsigned long long - см. https://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html ), а мне тут нужно получить позицию последнего единичного бита, если считать от младшего к старшему. Например, если есть число, которое в двоичном представлении имеет вид
    0b00001011
    то мне надо вернуть 4 т.к. в четвертой позиции этот бит находится
    0b00001011
          4321 // да, тут нумерация не с нуля, а с единицы

    И тут поэтому будет выделено памяти в худшем случае в 2 раза больше, а в лучшем случае на 1 бит больше, чем надо. https://wandbox.org/permlink/Plw7PlVbQ7hGajFd

    Структура stack:
    // https://github.com/j123123/sexpr_parse/blob/584fc23de71bebe02545214f819e16b720a2c1e2/my_struct.h#L61
    
    struct stack
    {
      stack_sz len;
      size_t sz_bytes;
      node_elm nodes[];
    };

    Этот nodes[] - flexible array member, чтобы не указатель на хуйню хранить, а просто сзади структуры. https://port70.net/~nsz/c/c99/n1256.html#6.7.2.1p16
    Ответить
    • Кстати, а что там в std::vector, там размер хуйни и сами данные хранятся одним куском, как в этом примере с "flexible array member" или там типа структура, в которой количество элементов и потом указатель на хуйню с этими самыми элементами?
      Я вот попробовал посмотреть в libstdc++ из GCC, там какая-то ебаная непонятная хуйня написана.
      https://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/include/bits/stl_vector.h

      Но непохоже, чтобы оно в эту "struct _Vector_base" что-то непосредственно встраивало
      Ответить
      • Три поинтера вроде в самом векторе, а данные в куче. Ну или поинтер и джва размера.

        А оптимизация для мелочи с хранением прям в самом векторе не везде есть.
        Ответить
        • А какие есть причины хранить размер вектора не в том же самом куске памяти, где и сам вектор?

          Почему реализация STL из GCC такое ебаное говно с кучей "#if" и "#ifdef" и всяким макроговном? Это принципиально нельзя написать нормальным образом?
          Ответить
          • > не в том же куске памяти

            А нафиг за ней так далеко лазить?
            Ответить
            • В смысле?
              Ну вот например можно хранить вектор как
              template <typename T> 
              struct array { 
                size_t sz;
                T *array_ptr; 
              };

              или
              template <typename T> 
              struct array { 
                size_t sz;
                T array_data[]; // flexible array member
              // данные рядом с самим размером, не нужно лишних разыменований
              };

              Чем второй вариант хуже чем первый?
              Ответить
                • Оффсет относительно начала структуры (т.е. адрес, где начинаются непосредственно данніе) там известен на этапе компиляции, так что он не влияет. А вот лишнее разыменования влиять может.
                  Ответить
                  • Разыменование у тебя хоть как есть, если твой array не фиксированной длины на стеке.

                    И вот как раз во втором варианте до длины лишнее разыменование.
                    Ответить
                    • Ну допустим я куда-то передаю указатель на первую структуру (где T *array_ptr;) - чтобы добраться до самих данных, мне надо из самой структуры достать указатель arr_ptr и потом его разыменовывать уже.
                      А если я передаю указатель на вторую структуру (где T array_data[]; // flexible array member ) то надо лишь добавить к указателю на такую структуру размер size_t, и вот уже можно читать данные
                      Ответить
                      • Это нечестное сравнение. Первую структуру ты передаешь по указателю чтобы её можно было ресайзить и т.п. Для r/o её и по значению можно передать. Ну и встраивается она напрямую.

                        Вторая структура по одному указателю r/o. Для ресайза надо двойную индирекцию. И встраивается только по указателю.
                        Ответить
                        • Да, чтобы вторую ресайзить, нужен указатель на указатель на такую структуру. Или возвращать новый указатель после ресайза через return как вариант.

                          А первая структура может сама быть выделена на стеке например, и уже указатель будет на хип указывать. И можно сделать массив таких структур т.к. размер самой структуры там фиксирован. А для второй структуры только массив из указателей получится сделать
                          Ответить
                        • > Это нечестное сравнение.

                          Ну хорошо, а допустим если мне нужны константные (т.е. неизменяемые в рантайме) строки из байт, как более адекватная замена нуль-терминированным говнострокам сишки, но чтобы без Шлемазла Шлемиэля т.е. чтоб не нужно было прочитывать строку до конца для узнавания размера строки? И для такой хуйни понаделать структурок
                          Можно например сделать варианты
                          struct array_8 { 
                            uint8_t sz;
                            uint8_t array_data[];
                          };
                          
                          struct array_16 { 
                            uint16_t sz;
                            uint8_t array_data[];
                          };
                          
                          struct array_32 { 
                            uint32_t sz;
                            uint8_t array_data[];
                          };
                          
                          ...

                          И для такой хуеты понаделать аналог strdup, типа функций вида datadup8() datadup16() datadup32(), отдельно для конкатенаций надо перебирать еще разные варианты datacat8_8() datacat8_16() datacat8_32() datacat16_8() ... и тут еще нужно как-то указывать, в какую строку оно должно попытаться сконкатенировать
                          Ну типа если надо из двух array_8 слепить array_16 то будет так
                          void datacat8_8_16(struct array8 *src1, struct array8 *src2, struct array8 *dst)

                          и это еще можно в макросню типа _Generic завернуть, чтобы удобно было
                          Ответить
                          • Какая история одного байта )))

                            Надеюсь вся эта кобенаторика не сожрёт профит от компактных строк.
                            Ответить
                            • Для контроллеров можно оставить только те функции, которые реально нужны. Если массивов размером до 256 байт хватит на всё, оставить только datadup8() и datacat8_8_8(). Ну и сделать еще макросов DATADUP8_ALLOCA() и DATACAT8_8_8_ALLOCA() которые б разворачивались в хрень с alloca для выделения на стеке, чтобы хип не использовался
                              Ответить
                              • Можно старший бит 8-битной формы пожертвовать на выбор формы. Ну и пару старших у 16-битной. Тогда datacat и datadup смогут все размеры автодетектить.
                                Ответить
                                • >Можно старший бит 8-битной формы пожертвовать на выбор формы

                                  какой утф ))
                                  Ответить
                          • А зачем тебе три вида оверинжиринга? Надо признать один основным и ветвить маркосами.
                            Ответить
                            • Средний 16-битный вариант сомнителен, да.

                              У 32-битки оверхед при n>=256 в районе процента. А меньшие покрывает компактная 8-битка.
                              Ответить
                      • Первая форма еще в регистрах может лежать. А вторая нет.
                        Ответить
                      • > размер size_t

                        max(alignof(T), sizeof(size_t)), но не суть. Подумаешь немного байтов проебали в начале вектора. Некритично.

                        Да и size_t обычно и так один из самых жирных типов. Больше только аппаратные вектора.
                        Ответить
                  • Ну или вот посмотри на двоичный поиск.

                    Первую структуру ты можешь передать по значению через регистры. И сразу начать поиск, трогая только те кешлайны, что реально нужны для работы.

                    Со второй структурой ты вынужден загрузить лишний кешлайн в котором лежит размер. А этот кешлайн в большинстве случаев не пригодится при поиске.
                    Ответить
              • Кста, в Qt насколько помню именно второй вариант юзают чтобы корова работала.
                Ответить
                • Да, в Qt QString -- это просто указатель на блок, в котором лежит счётчик ссылок, длина строки, длина буфера, какие-то флаги и сам буфер (ushort array[1]).

                  А в libstdc++ три поинтера: начало, конец строки и конец буфера.
                  Ответить
              • шото я не понял вас: Вектор же свой размер и указатель на данные хранит на стеке (ну или куда ты там его положишь), в общем содержит их внутри себя

                А сами данные могут быть где угодно, это как аллокатор решит, могут быть и в куче
                Ответить
          • Кстати, если бы все буфера передавались рейнджами, то не надо было бы тратить место в куче на хедера аллокатора. Было бы что-то в духе
            range r = malloc(80);
            range s = gets(r);
            while (s.begin < s.end) {
                range t = strtok(&s, " ");
                puts(t);
            }
            free(r);
            Красиво же.
            Ответить
              • Ну вот этот gets не переполняется, кстати. Он же диапазон получает а не указатель. Ну и возвращает заполненный им кусок для обработки. И не надо никаких ноликов и прочей срани в конце. А strtok данные не портит, просто двигает рейндж дальше и возвращает рейндж на откушенный токен.

                В асме это тоже должно неплохо смотреться.
                Ответить
              • Ну это уже кучу аллоцирует. Хотя эксплод тоже эффективный будкт в таком представлении.
                Ответить

Добавить комментарий для bormand Отменить ответ

Из-за тебя ушел bormand, guest!

    А не использовать ли нам bbcode?


    8