1. JavaScript / Говнокод #23462

    +2

    1. 1
    2. 2
    3. 3
    4. 4
    5. 5
    6. 6
    var CodeMirror = require("codemirror");
    var Thrift = require("thrift.js");
    require("./src/my.css");
    include(`gen-js/test_types.js')
    include(`gen-js/TestServ.js')
    include(`src/main.js')

    Против m4 нет приёма.

    Запостил: CHayT, 29 Октября 2017

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

    • Генератор нодоподобного thrift сломан, а браузероподобного -- не вписывался в эти модные "модули". Но нет ничего невозможного.
      Ответить
    • Что лучше, протобуф/грпц или трифт?
      Ответить
      • Про grpc не знаю ничего, кроме того, что его автор разочаровался в протобафе и пилит якобы супер-быструю либу Cap'n Proto. Thrift весь из себя универсальный, поддерживает кучу протоколов, транспортов и т.п. но при этом довольно сырой.
        Ответить
        • > его автор
          Видимо, один из авторов протобуфа, а не grpc. Протобуфы пилит довольно много людей. Я grpc не использовал, но его неопенсорсный вариант использую каждый день, ничего плохого сказать не могу. Если бы нужно было что-то сделать для себя, я бы, наверное, взял grpc.
          Ответить
          • > Видимо, один из авторов протобуфа
            Да, именно.
            > я бы, наверное, взял grpc
            Могу ошибаться, но GRPC вроде не особо умеет во фронтенд и экму. Thrift умеет, в том числе с использованием бинарного протокола и вебсокетов.
            Ответить
          • Тебя не парит странная реализация асинхронщины с очередями и войдзвездочками?
            Ответить
            • void* — это благо. Мы должны использовать void*. Используя void*, программист приближается к истинному пониманию сути вещей. Настоящее удовольствие можно получить лишь применяя void*. Ни один человек не имеет права не использовать void*. Каждый раз, когда кто-то пишет void*, мир приближается к Последней Точке Истинности. void* должно быть использовано в любой программе по крайней мере раз. Код без void* не является правильно написанным кодом. void* предотвращает ошибки и делает ваш день лучше. Не нужно бояться использовать void*. void* оздоровляет ваш код и удлинняет его жизненный цикл. Написание void* — это базовое и неотъемлемое право любого программиста, данное нам от рождения. void* — и код стал лучше.
              Ответить
              • настоящий метод должен получать два параметра: int и void*

                такой метод удобно расширять
                Ответить
                • Что это за насильственная типизация? Одного аргумента типа void* хватит всем. И возвращать тоже ничего не надо.
                  Ответить
                  • ну уж это перебор.

                    int это оператор, а void * это его операнды (один или массив в зависимости от).

                    Например:

                    int speed = 42;
                    do_all(LAUNCH_ROCKET, &speed);

                    Или
                    struct Email email = {....}
                    do_all(SEND_EMAIL, &email);

                    или
                    int length;
                    do_all(GET_LENGTH, &length);

                    Кажется я придумал ioctl
                    Ответить
                    • Можно просто использовать КОНТРАКТНОЕ ПРОГРАММИРОВАНИЕ (tm) и согласиться, что первые четыре байта в void* -- это тот самый int.
                      Ответить
                  • >> И возвращать тоже ничего не надо.

                    Еврейское программирование.
                    Ответить
                    • Ура, ура, кегги вернулся!
                      Ответить
                    • ᴋᴏʜтᴘᴀᴋтʜᴏᴇ пᴘᴏгᴘᴀммиᴘᴏʙᴀʜиᴇ™ + ᴄᴘs™: по смещению 5 в void* лежит адрес коллбэка, который нужно вызывать с правильно составленным void* на входе.
                      Ответить
                      • ᴄᴘs - это же и есть contract programming style
                        Я смотрю у вас тут тяжелые наркотики в почете
                        Ответить
                        • > ᴄᴘs - это же и есть contract programming style
                          Роман имел в виду continuation passing style, судя по "адресу коллбэка"
                          Ответить
                          • 𝕲𝖊𝖓𝖆𝖚
                            Ответить
                          • characters per second, снаут
                            Ты же в телекоме работаешь
                            Ответить
                            • Скоро перестану, кстати. Моей дакимакуре нужно больше золота.
                              Ответить
                              • В пейсбук пойдёшь работать? В Швеции вообще кроме телекома что-нибудь интересное есть?
                                Ответить
                                • Нет, крупных контор мне уже по горло хватило. Собираюсь срулить в некую локальную убийцу пейпала c функциональщиной и машин лёнингом, скажем так.
                                  Из широко известных фирм в Швеции есть ещё как минимум Volvo (self-driving cars) и Spotify.
                                  Ответить
                          • Тухленько у вас тут
                            Ответить
      • Где я работаю используют GRPC, но не просто так используют. В комплекте с Кафкоговном, Скалаговном и Аккаговном. GRPC очень органично вписывается в картину из говна.

        Из достоинств, следует отметить, что каждый наивный програмист попытавшийся использовать это говно сразу же сталкивается с проблемой: "а оперделения сервисов мне не уперлись потому что у меня нет ХТТП, я работаю с Х (например, топиками в Кафке), как же мне теперь угадать какой мессадж мне прислали".

        Естественно, тут же ваяется "решение", вот виды решений, с которыми я уже сталкивался:

        1. Захуярить размер мессаджа в 4 байта (как правило в направлении обратном сетевому), за ним строку с названием замапленного класса (ну, или варианты, типа энумератора, который в коде приложения мапится к классам).
        2. Попытаться распарсить в разные типы, авось какой-нибудь совпадет.
        3. Захуярить в другой формат, например в ХМЛ, в Бэйс64. Зато надежно.

        С опытом приходит понимание необходимости полиморфизма и работы с разными версиями говна. И тут в уже готовое месиво из байтоебства и самодельных оберток добавляется код для угадывания версии, и всякие причуды типа
        https://github.com/google/protobuf/blob/master/src/google/protobuf/struct.proto
        .

        Потом приходит понимание, что постореная система - говно, но деньги уже заплачены и потрачены. В этот момент нанимают саппорт, а гении идут строить новый и луччий проект, в этот раз с Трифтоговном и т.д.
        Ответить
        • показать все, что скрытоВремя идет, а проблемы ввхвв не меняются. Смотри, как бы соседний отдел с жейсоном вас не обошел.
          Ответить
          • Соседний отдел нахуярил опередню на нодежс на 29865 файликов, из которых около сотни - файлы конфигураций всяких вебпаков, линтеров, бабелей и ярнов. Пока что они смогли только нарисовать два текстовых поля и кнопку, при нажатии на кнопку появляется страшная красная странца с неработающими ссылками на исхдоные jsx файлы.

            Я думаю, что такими темпами, они нас не обгонят.

            https://otvet.imgsmail.ru/download/25545935_e55ceced91a423e97116f1cfb359e305_800.jpg
            Ответить
            • А ты ответ мейл ру пользуешься?

              Я предпочитаю SO
              Ответить
        • > как же мне теперь угадать какой мессадж мне прислали

          Я прям даже не знаю, использовать oneof не пробовали?
          https://developers.google.com/protocol-buffers/docs/proto3#oneof
          Если уж совсем всё равно, что слать, есть any
          https://developers.google.com/protocol-buffers/docs/proto3#any
          Ответить
          • oneof поможет только если все мессаджи складываются в одну обертку. Т.е. вместо ХМЛ + Бэйс64 у нас будет хуевая обертка из протобафа. Почему хуевая? Потому что размер сообщения в ней не записан.
            Естесственно, oneof невозможен, если формат сообщений описан кем-то другим, кто не подумал о том, что всем сообщениям нужна общая обертка.
            Ответить
            • \O////
              Ответить
            • отсутствие версионирования - давно в глаза бросилось что гуглы от некрософта этой годости набрались.

              еще ни разу не видел сетевого протокола без версионирования - и без граблей. ни разу. исключение тоже было: протокольчик для миддлваре где версия стояла в "2.1" и её ни в коем случае менять было нельзя...
              Ответить
              • В протобуфе всё тегировано, как раз с целью прикрутить поверх версионирование. В этом смысле от аналогов (ASN1, thrift) он не отличается.
                Ответить
                • тэгировано? - это какое TLV? если аналогично ASN1 - то однозначно не TLV.

                  потому что ASN1 (с которым я имел несчастье работать) сам по себе в ж неверсионирован. хуже: если определения ASN1 не одинаковы, то ты хер это можешь определить, потому что длины это г не сохраняет (как например TLV). и все исторические приложения (шифрование, телекомы) они все не версионированы. (потому что есть организации отвечающие за стандарт - но когда народ копирует в проекты, все ложат на организационную часть.)
                  Ответить
                  • Само по себе автомагически ничего не версионируется. Есть гайдлайны, как осуществлять эволюцию протобафов, чтобы сохранять backward и forward совместимость. Чтобы, например, записанные однажды на диск данные можно было прочитать в будущем.

                    Опять же, версионирование — это больше дело протокола, а не только лишь формата сериализации. Одна из частых стратегий: делаешь новое API, депрекейтишь старое, какое-то время поддерживаешь обе версии. Для большинства приложений этого обычно вполне достаточно.

                    Для протоколов уровня IETF, конечно, такой подход не работает, там, как правило, всё старьё нужно уметь поддерживать.
                    Ответить
                    • > Есть гайдлайны, как осуществлять эволюцию протобафов, чтобы сохранять backward и forward совместимость.

                      почитал.

                      все сводят к "just add new shit - old shit will just ignore it!" - это 100% говно.

                      потому что в половине случаев не только добавляется новая информация, но так же меняется интерпретация старой. потому что иначе поля в сообщениях начинаются плодится без остановки. (протокол с >10К тагов - ASN1 based - я в реале видел.)

                      > это больше дело протокола, а не только лишь формата сериализации.

                      совершенно правильно. номер версии - это номер протокола, а не формата сериализации.

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

                          Твой вопрос немного напоминает митинги на эту тему, которые в кратце можно выразить: "как мы можем исправить грабли, но при этом ничего не меняя?"
                          Ответить
                    • А я слишком творческий для общих гайдлайнов, я делаю
                      oneof yoba {
                          YobaV1 v1 = 1;
                          YobaV2 v2 = 2;
                      }
                      Ответить
                      • Да, примерно это я и собирался предложить dummy, но ты меня опередил.
                        Ответить
        • Я использую протобуф для даных на диске и шлю протобуфы по сети (не грпц), с такими проблемами не сталкивался. Может ты не совсем понимаешь, зачем он нужен, и ждешь от него чего-то не того, или просто руки кривые.
          Ответить
          • Ну, поделись рецептом тогда. Вот, открыл ты сокет, как ты знаешь сколько байтов нужно прочитать из него, чтобы прочитать сообщение? Известно, что в сокете могут быть сообщения разных типов.
            Ответить
            • > Известно, что в сокете могут быть сообщения разных типов.

              Т.е. ты даже не знаешь, какой тебе прислали? Вот это реальный ЛОЛ, шаблон проектирования "I have no idea what I'm doing".

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

                "Наш протокол комуникации" был придуман дибилом из гугла. Почты его у меня нет, и общаться с ним мне не интересно.
                Ответить
                • Ты просто не понимаешь разницы между "протоколом" и "форматом сериализации". Видимо, твои проблемы происходят из этого. Короче, это всё мы уже проходили.
                  http://govnokod.ru/20274#comment336741

                  /thread
                  Ответить
                  • Нет, это ты просто долбоеб, который читать не умеет.
                    1. https://en.wikipedia.org/wiki/GRPC

                    gRPC is an open source remote procedure call (RPC) system
                    initially developed at Google.


                    2. https://en.wikipedia.org/wiki/Remote_procedure_call

                    RPC is a kind of request–response protocol. An RPC is initiated
                    by the client, which sends a request message to a known remote server
                    to execute a specified procedure with supplied parameters.
                    Ответить
                    • > GRPC

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

                      > Вот, открыл ты сокет, как ты знаешь сколько байтов нужно прочитать из него, чтобы прочитать сообщение?

                      Это не ты написал? Protobuf -- это формат сериализации, а не протокол. Давай прочитаем вместо PROTOCOL BUFFERS, то есть это пэйлоад, который ты кладёшь в свой проткол (HTTP или кастомный бинарный). Протокол -- это то, что вы там на сокетах намутили вместо GRPC. В ваших проблемах никто кроме вас, мудаков, не виноват.

                      > Нет, это ты просто долбоеб, который читать не умеет.
                      Нет, ты
                      Ответить
                • TCP говно, кстати. Там все складывается в сегменты.
                  IP говно, кстати. Там все складывается в пакеты и явно передается размер.
                  802.3 (Ethernet) говно, кстати. Там все складывается в кадры.
                  Ответить
                  • NTFS говно, кстати. Там все складывается в файлы.
                    Ответить
                  • Медь - говно.
                    Ответить
                  • > IP говно, кстати. Там все складывается в пакеты и явно передается размер.
                    То ли дело "E1/T1".
                    Ответить
                    • нифига. MTP тоже говно - там все делится на короткие кадры и в кадрах есть размер.
                      Ответить
                      • Тащемто MTP и транковая связь -- понятия довольно перпендикулярные.
                        Ответить
                    • Ему хорошо, у него отдельный канал для синхронизации (вроде). Так что надо вместо протобуф использовать PDH и будет удобно

                      А еще можно вспомнить ATM: там все ячейки (или как их там называли) были фиксированного размера, чтобы было удобно и телефонистам, и сетевикам, и wvxvw
                      Ответить
            • Длина сообщения определяется заголовком Content-Length, а тип - урлом. Какие-то очевидности ты спрашиваешь.
              Ответить
              • >> у меня нет ХТТП, я работаю с Х

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

                    На самом деле, проблема в гомоморфна типизации в языках программирования, только всё хранится по значению. Слать сообщения разного типа в один канал — это как класть объекты в гетерогенный список. Нельзя сделать это без оверхеда RTTI ("ручного" или встроенного в язык), да и не нужно.
                    Ответить
                • Тогда сокет надо закрывать, это и будет означать конец сообщения
                  Ответить
                  • >> или просто прочитал всё, что есть в сокете, допустим

                    Это не решает основную проблему, только откладывает неизбежное. Что потом с этим говном неизвестного типа делать? Как проверить, что сообщение валидное? Можно перекладывать эти байты с места на место, но тогда аналогичная проблема ожидает того, кто обрабатывает это сообщение дальше.
                    Ответить
                    • Десериализовывать во все известные форматы и проверять чексумму

                      А вообще конечно глупая проблема, и решений у нее миллион

                      От предачи типа в первых двух байтах, до определения типа по адресу, порту итд
                      Ответить
                      • > Десериализовывать во все известные форматы

                        Сообщения разных типов могут быть сериализованы в одинаковый набор байтов. Например:
                        message Student {
                          optional string name = 1;
                        }
                        message Professor {
                          optional string name = 1;
                          repeated Student students = 2;
                        }
                        < name: "John" > может быть и студентом, и профессором без студентов.
                        Ответить
                  • Сокеты могут закрываться по миллиону причин. Ты не знаешь, можно ли отличить закрытие сокета от close() и от сегфолтнувшегося процесса? Я обычно все же горожу какой-нибудь фрейминг поверх сокетов.
                    Ответить
                    • Почитай пожалуйста про FIN у TCP, и узнаешь как отличить кошерно закрывшийся сокет от отвала по таймауту по причине смерти удаленной машины или разрыва кабеля.

                      Вот правда я не уверен: закроет-ли операционка сокет кошерно в случае смерти процесса и освобождения ресурса?
                      Ответить
                      • > Вот правда я не уверен: закроет-ли операционка сокет кошерно в случае смерти процесса и освобождения ресурса?

                        В этом и был вопрос, умник.
                        Ответить
                        • То-есть ты даже не проверил, и ничего не почитал на эту тему, и сразу стал городить свой фрейминг?
                          Ответить
                          • Даже если бы я проверил и почитал, я бы все равно нагородил фрейминг. Сегодня я аккуратно обработаю все возможные ошибки, а завтра коллега, который маны не зубрил, возьмет и обработает какую-то ошибку не так как я ожидал, и все сломается. Или сервис на том конце закроет сокет через close() без шатдауна. Или автор асио поменяет отображение еррно в ерроркод (бывает такое). Или линус добавит новый еррно. Короче я с тисипи предпочитаю работать, как с потоком байт.
                            Ответить
                            • Я сомневаюсь что линус так вот добавит новый errno и поменяет поведение, но тем не менее ты прав:

                              я цепалнулся телнетом к своему серверу на жабе, и когда я кильнул виндовый телнет у меня полетел connection reset (значит что винда послала TCP RST).

                              А тоже самое с линуксом: там убитый (kill -9) telnet успешно умер и соединение закрылось (считался -1, EOF). подозреваю что это можно менять в настройках клиентского сокета, но тем не менее дефалты у ОСей разные
                              Ответить
                      • > Вот правда я не уверен: закроет-ли операционка сокет кошерно в случае смерти процесса и освобождения ресурса?

                        официально: да, она закроет сокет. только закроет - со всеми вытекающими - shutdown() никто на сокете не вызовет. (последствий уже не помню.)

                        но в общем случае полагаться на это все - что бы узнать почему соединение закрылось - все равно нельзя. (потому что даже graceful FIN может быть потерян, и его никто повторно посылать не будет.)
                        Ответить
                        • Я имел ввиду обратный случай: мне казалось что смерть клиента не должна отличаться от обрыва провода, но вот как показала практика: винда шлет RST, а линукс шлет FIN.

                          Короче я уже понял что я зря доебался до гостя: он все правильно делает: полагаться ни на что нельзя, все зыбко.

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

                            лол. если провод был оборван - то ничего не может послатся - peer'ы будут на таймауте висеть.

                            > винда шлет RST, а линукс шлет FIN.

                            винда всегда любила соединения быстро и грязно разрывать.

                            помню еще head-banging-against-wall когда первый раз прога подвисла в close() сокета который был грязно закрыт без RST/FIN - виндами - и были еще буфернутые непосланые данные ("bye", последнее сообщение протокола).
                            Ответить
                            • >>лол. если провод был оборван - то ничего не может послатся - peer'ы будут на таймауте висеть.

                              Да, и в конце концов я получу timeout, это понятно. Я, по наивности децкой, думал что если SIGKILL процесс то он тоже ничего не пошлет и будет такой же timeout.
                              Но оказалось что ОС так не думает.
                              Ответить
                              • https://linux.die.net/man/2/_exit - это единственное мне известное место где упоминается закрытие "open file descriptors" при завершении. насчет случая сигналов манов не видел.
                                Ответить
                                • И тем не менее вот как (судя по tcpdump) помирает telnet от ``killall -9 telnet``

                                  00:50:15.709422 IP figu-s-maslom.56828 > ya.ru.http: Flags [F.], seq 1, ack 1, win 229, options [nop,nop,TS val 26756 ecr 2692125854], length 0


                                  Видишь вот эти [F.]? Это же FIN?
                                  Ответить
                                  • > Видишь вот эти [F.]? Это же FIN?

                                    другого флага с F нету.

                                    на линуксе там тьма конфигурационных опций.

                                    http://man7.org/linux/man-pages/man7/tcp.7.html

                                    он даже глобальный лингер умеет делать.

                                    ЗЫ читал вспомнил почему shutdown *них не делает: после форка сокет может шарится между процессами. а шатдаун меняет глобальное состояние соединения.
                                    Ответить
                                    • Ну линукс же умеет считать ссылки на ресурсы. Я могу открыть файл, и его наследует мой форк и даже кажется я могу послать дескриптор по unix domain socket:)) А когда ВСЕ пользователи дескриптора умрут -- линукс его закроет, небось и с сокетом так.

                                      Вполне возможно что это настраивается опциями TCP, да
                                      Ответить
                                      • > Ну линукс же умеет считать ссылки на ресурсы.

                                        более обобщенно: это стандартная фича *нихов.
                                        Ответить
                                        • более обобщенно: это стандартная фича всех серьезных ОС.

                                          У виндуос тоже есть "хендлы объектов" и они тоже самоубиваются.
                                          Ответить
                                          • не тормози: в виндах ты не можещь хэндлы шарить. юз кейс совсем не тот.
                                            Ответить
                                            • Handle Inheritance
                                              , не?
                                              https://msdn.microsoft.com/ru-ru/library/windows/desktop/ms724466(v=vs.85).aspx
                                              Ответить
                                              • уау. даже дап есть.

                                                но следует виндовым традициям - и не без граблей -
                                                https://stackoverflow.com/questions/3400675/duplicatehandle-need-to-openprocess-but-the-access-is-denied

                                                давно винды не ковырял.
                                                Ответить
                                                • Чтобы поделиться хендлом со своим дочерним процессом, емнип, не надо этой ёбли с правами.

                                                  Тут у чувака просто юзкейс ебнутый на голову, как и попытки решить проблему в духе "раздать всем приложениям привилегию на дебаг".
                                                  Ответить
              • Лол, какой content-lenght в Кафке? С чего ты взял, что все, что приходит в сокет должно соотвествовать ХТТП протоколу? Ну, или если тебе так нравится ХТТП, то чем тебя не устроил вариант с ХМЛ + Бэйс64, это же праткически то же самое.

                Другими словами, ты это говно уже жрешь черпаком, но только сейчас об этом узнал.
                Ответить
                • > какой content-lenght в Кафке
                  Ты спросил, как я делаю - я ответил. Причем тут твоя кафка? Кафка не сообщает длину пейлоада, который возвращает? Ну напиши ее перед протобуфом.

                  > говно
                  У тебя в голове.
                  Ответить
            • добавить protected "_type" во все типы
              Ответить
      • CORBA
        Ответить
    • > var CodeMirror = require("codemirror");

      ты таки решил запилить свой гк на богомерзкой динамике?
      Ответить
    • показать все, что скрытоvanished
      Ответить
    • Весь `Apache Thrift' сюда надо выкладывать, кстати. Этод гк всплыл и напомнил мне про то, как я в ужасе с него свалил, увидев, что они данные прямо из wire в эрланговскую таблицу атомов совали (а её размер фиксирован) и бинарной кучей текли.
      Ответить
      • А ты давно вуз окончил?
        Ответить
        • Какой вуз, я девочка-волшебница, мне 13
          Ответить
          • А Борманд — твоя сестрёнка?

            >>> bormand 15.03.2020 14:44 #
            >>> я девочка-волшебница.
            https://govnokod.ru/26488#comment534043
            Ответить
          • Пруф?
            Ответить
            • > девочка-волшебница
              > пруф

              Вжуууух. И ты петух.
              Ответить
              • В каком смысле «петух»?
                Ответить
                • > В каком смысле

                  У тебя теперь ник "OCETuHCKuu_nemyx" и петух на аватарке, проверь.

                  К сожалению, обратное заклинание я ещё не выучила. Так что походишь пока так.
                  Ответить
                  • Это понятно. А пруф, что Снаут - девочка-волшебница, и что ей 13?
                    Ответить
                    • Пруфы нужны? Вжууух! Я заколдовала твой проект, что весь код на нём превратился в говно. Проверь.
                      Ответить
                      • Осторожней, сестрёнка, ты и мой проект немного задела своей магией.
                        Ответить
                    • Про девочку-волшебницу мы тебе уже пруфанули.

                      А про возраст товарищу майору будешь доказывать.

                      -- Товарищ майор, бегите скорее сюда, тут какой-то петух просит пруфы показать.
                      Ответить
                      • Как определить у кого можно просить пруфы в интернете, а у кого нет? На слово верить?
                        Ответить
                        • Получить нотариально заверенную справку о пруфпригодности.
                          Ответить

    Добавить комментарий