Задать вопрос
  • Почему в Go вакансиях требование знания PHP?

    sergey-gornostaev
    @sergey-gornostaev
    Седой и строгий
    Или это просто такое количество кодовой базы на PHP накопилось, которую все дружно решили переписывать на Go

    Скорее всего.

    если да, то почему именно на Go?

    Если компания решилась вложиться в переписывание продукта на другом языке, то у неё на это точно очень веские причины, вероятнее всего - проблемы производительности. В этом случае Go - очевидный выбор. Python, Ruby и JS не дадут никакого выигрыша относительно PHP. Хоть на языках из мира jvm и .net можно писать высокопроизводительный софт, но они скорее решают проблемы сложности огромных кодовых баз. С++ и Rust очень сложны и для прикладного софта применяются только в крайнем случае. Всякая экзотика, типа Erlang, Elixir и Haskell - это вообще редкий случай в энтерпрайзе. Go же одновременно очень прост и ориентирован на высокую производительности.
    Ответ написан
    7 комментариев
  • Зачем нужен Kubernetes?

    Кубер для крупных микросервисных проектов, где сервисов, ну, хотя бы десяток. Для одного маленького монолита преимуществ не будет.
    Кубер нет смысла эксплуатировать в проде всего на одной ноде - все преимущества отказоустойчивости минус.
    Какие преимущества кубера - развертывание сервисов в N инстансов на K серверов, выживаемость этих серивсов при отказе нескольких нод или инстансов, балансировки, обновления без даунтаймов (rolling update)... Там еще много всего что касается массированных развертываний.

    Съехать с композов в кубер проблема незнаичительная, можно развиваться по мере необходимости
    Ответ написан
    7 комментариев
  • Как ускорить YouTube на OpenWRT?

    ValdikSS
    @ValdikSS
    Я установил на роутер zapret nfqws, не используя стандартные скрипты из поставки. Конфигурация такая, какая описана вот в этом баге:

    https://github.com/bol-van/zapret/discussions/262

    Взял бинарник из репозитория, написал простейший init-скрипт (/etc/init.d/nfqws) для openwrt с вшитыми параметрами, написал свои правила firewall’а. Оригинальные тоже хорошие (и обрабатывают разные конфигурации), но вот эти банально проще.

    # cat /etc/init.d/nfqws 
    #!/bin/sh /etc/rc.common
    
    USE_PROCD=1
    START=91
    
    PROG=/etc/zapret/nfqws/nfqws
    
    start_service() {
      procd_open_instance
      procd_set_param command "$PROG"
      procd_append_param command --dpi-desync=fake
      procd_append_param command --dpi-desync-fooling=md5sig,badseq
      procd_append_param command --dpi-desync-split-pos=1
      procd_append_param command --dpi-desync-repeats=12
      procd_append_param command --dpi-desync-ttl=4
      procd_append_param command --qnum=200
      procd_append_param command --hostlist=/etc/zapret/nfqws/youtube.txt
    #  procd_append_param command --hostlist=/tmp/domains-export.txt
      procd_set_param stdout 1 # forward stdout of the command to logd
      procd_set_param stderr 1 # same for stderr
      procd_close_instance
    }


    С моими правилами файрволла (connbytes) в nfqws копируются только первые 8 пакетов, а дальше всё маршрутизируется как обычно. /etc/zapret/zapret.nft:

    chain zapret_lan_hook {
        type filter hook forward priority mangle;
    
    #    iifname {"br-lan"} \
          ip daddr != {0.0.0.0/8, 10.0.0.0/8, 192.168.0.0/16, 172.16.0.0/12, 100.64.0.0/10, 169.254.0.0/16, 224.0.0.0/3, 255.255.255.255/32} \
          tcp dport {80, 443} ct original packets lt 8 counter queue flags bypass to 200 comment "zapret IPv4 443 tcp"
    
    #    iifname {"br-lan"} \
          ip6 daddr != {::ffff:0:0/96, fc00::/7, fe80::/10, ff00::/8} \
          tcp dport {80, 443} ct original packets lt 8 counter queue flags bypass to 200 comment "zapret IPv6 443 tcp"
    
    #    iifname {"br-lan"} \
          ip daddr != {0.0.0.0/8, 10.0.0.0/8, 192.168.0.0/16, 172.16.0.0/12, 100.64.0.0/10, 169.254.0.0/16, 224.0.0.0/3, 255.255.255.255/32} \
          udp dport 443 ct original packets lt 8 counter queue flags bypass to 200 comment "zapret IPv4 443 udp"
    
    #    iifname {"br-lan"} \
          ip6 daddr != {::ffff:0:0/96, fc00::/7, fe80::/10, ff00::/8} \
          udp dport 443 ct original packets lt 8 counter queue flags bypass to 200 comment "zapret IPv6 443 udp"
    }


    Нужно заinclude’ить скрипт в настройках firewall’а. /etc/config/firewall:

    config include 'zapret'
    	option type 'nftables'
    	option path '/etc/zapret/zapret.nft'
    	option position 'table-post'
    	option enabled '1'


    Необходимо отключить offloading, с ним, скорее всего, работать не будет (но я не проверял, оригинальные правила учитывают этот момент).

    В таком виде всё установить можно на ЛЮБОЙ роутер, даже на 4/32, при большом желании (скриптом скачивания бинарника в оперативную память, при необходимости).

    /etc/zapret/nfqws/youtube.txt:

    youtube.com
    youtu.be
    googlevideo.com
    googleapis.com
    gvt1.com
    ggpht.com
    ytimg.com
    youtube-nocookie.com
    play.google.com
    video.google.com
    youtube-ui.l.google.com
    youtubeeducation.com
    youtubekids.com
    Ответ написан
    2 комментария
  • Как уберечь сайт который у тебя используется в портфолио, от безвкусных правок заказчика?

    @Drno
    Копию на свой "хостинг" выкладываете и всё
    а то что в реальности пусть само по себе работает
    Ответ написан
  • Как вывести список элементов из структуры Map?

    alexey-m-ukolov
    @alexey-m-ukolov Куратор тега JavaScript
    Array.from(CarStore.cars).map(([key, car]) => <Text key={key}>{car.name}</Text>);
    Ответ написан
    Комментировать
  • Как сделать расплывчатый градиент для фона сайта, как на изображении ниже?

    @karminski
    Senior React.JS Developer
    Открыть консоль браузера, выбрать нужный элемент и посмотреть как сделали это разработчики сайта.
    Ответ написан
    Комментировать
  • Каковы шансы устроиться на работу в IT без военника и образования?

    xez
    @xez
    TL Junior Roo
    Отсутствие образования и военного билета - не самая большая проблема при трудоустройстве.
    Если устроетесь в акредитованую IT контору - получите отсрочку от призыва.
    Недостаток образования должен быть скомпенсирован скилом и/или опытом.

    Короче, шансы есть, но вам придется конкурировать с образованными ребятами, которые закрыли каким-то образом вопрос с армией. Перевесят ли ваши навыки ваши "недостатки" зависит только от вас.

    UPD.: все таки отсрочку it контора без профильного образования не даст...
    https://www.gosuslugi.ru/armydelay
    Ответ написан
    9 комментариев
  • Как красиво использовать динамически подгружаемый API?

    Aetae
    @Aetae Куратор тега JavaScript
    Тлен
    Вот те простой хэлпер для ленивой загрузки одной функции:
    function lazyAsync(lib) {
      let promise;
      return async function (...args) {
        promise ??= lib();
    
        return (await promise).call(this, ...args);
      };
    }
    
    const doSomething = lazyAsync(async () => {
      // тут загружаем
      const doSomething = await loadLib('doSomething');
    
      // тут что-то делаем с загруженным
    
      // тут возвращаем конечную функцию
      return data => {
        // тут делаем с аргументами
        return doSomething.process(imgData);
      };
    });
    
    // если сразу загружается нужная функция - можно не усложнять
    const doSomething = lazyAsync(loadDoSomethingProcess);
    
    await doSomething(1);
    await doSomething(2);
    await doSomething(3);
    Ответ написан
    Комментировать
  • Как добавить авторизацию в каждый последующий запрос коллекции Postman?

    petermzg
    @petermzg
    Самый лучший программист
    66b377a8d838f387114270.png
    66b377c874caf398469806.png
    var res = pm.response.json();
    pm.environment.set('token', res.token);

    66b377dacc9ab075006401.png
    Ответ написан
    Комментировать
  • Не будет ли процессор i5-9400f "бутылочным горлышком" для видеокарты 3060ti?

    Wispik
    @Wispik
    Не будет
    Ответ написан
    Комментировать
  • Как вложить span в textarea?

    Aetae
    @Aetae Куратор тега JavaScript
    Тлен
    Никак.
    Textarea - зона текста, там может быть только текст.
    Если хотите большего - есть только три варианта, два - геморройные, с кучей коссбраузерных несовместимостей и особенностей, которые обязательно заставят вас рвать волосы на заднице:
    1. Отказаться от textarea и использовать contentEditable div.
    2. Подкладывать под(или поверх с pointer-events:none) div, который копирует содержимое textarea 1:1 со всеми стилями и отступами и раскрашивает его как надо.

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

    HarisNvr
    @HarisNvr
    Начинающий кодер Python
    60 * 24 — это общее количество минут в одном дне (24 часа по 60 минут).

    n % (60 * 24) — это количество минут, оставшееся после деления на полное количество минут в одном дне. Это позволяет нам получить количество минут в пределах одного дня. Вдруг заданное кол-во минут будет больше одного дня, часы сделают полный оборот и встанут на 00:00.

    // 60 — делит количество оставшихся минут на 60, чтобы получить количество часов. Здесь используется целочисленное деление, которое отбрасывает дробную часть.

    minutes = n % 60 вычисляет количество минут, оставшихся после деления на 60. Это будет то количество минут в последнем (неполном) часе.
    Ответ написан
    Комментировать
  • Задача про часы, почему решается именно так?

    hours = n % (60 * 24) // 60
    minutes = n % 60


    Допустим n = 2000 минут

    1. 60 * 24 = 1440
    — это общее количество минут в сутках. Работаем с минутами, т.к. твоё число "n" в минутах.

    2. 2000 % 1440 = 560
    Остаток от деления (%) твоего "n" на общее количества минут в сутках, так как суток может быть несколько, если число "n" велико.

    3. 560 // 60 = 9
    Оставшееся значение минут поделено целочисленным делением на 60 (//60), чтобы узнать значение для часов, поэтому сколько бы минут небыло, у тебя останется только целая часть - часы.

    4. 2000 % 60 = 20
    С минутами наоборот — часы нам не нужны, поэтому просто получаем остаток от деления на 60, сокращая часы. Остаются только минуты.

    Время на часах 9:20
    Ответ написан
    Комментировать
  • Как предотвратить имитацию запросов?

    mayton2019
    @mayton2019
    Bigdata Engineer
    Здесь в вопросе - 2 разных вопроса. Мне кажется так:
    1) Как защититься от любого мусора который прилетает с клиента. Скорее всего никак.
    Нужно реагировать только на HTTP запросы которые имеют смысл в контексте пользовательской
    сессии. Тут - как-бы бизнес логика и FSM для сессии должен все решать. Хакеры с помощью
    wget, curl, python могут генерировать фаззингом миллионы самых вариативных запросов
    в поиске вашего слабого места в этой части защиты.

    2) Как защититься от атаки man-in-the-middle.. Это если легальный пользователь
    зашел в свой клиент банк, а некто, кто физически сидит на канале может перехватывать
    IP пакеты. Изменять их. Удалять. Задерживать на какое-то время или делать повторы.
    Здесь коробочное решение это https (TLS/SSL) протокол по идее помогает.
    Ответ написан
    Комментировать
  • Как предотвратить имитацию запросов?

    Elaryks
    @Elaryks
    Да, сымитировать запрос можно. Поэтому есть правило: "Нельзя доверять данным, которые приходят с клиента". Следовательно, данные с клиента нужно проверять на сервере. Критические данные и операции нужно подписывать или хэшировать, чтобы избежать подмены. Например, для защиты от Replay Attack используют одноразовые токены — при повторном запросе токен уже не сработает.
    Ответ написан
    4 комментария
  • Какие могут быть способы определения автоматизации Selenium?

    kshnkvn
    @kshnkvn Автор вопроса
    yay ✌️ t.me/kshnkvn
    Перепробовал кучу разных вариантов, вот что из них может сработать для кого-то (не для меня):
    1. Очень сомнительно, но некоторые люди пишут, что для них это работало:
    Изменение название переменной документа js, используемой Selenium - $cdc_. Для этого достаточно открыть файл chromedriver.exe в любом шестнадцатеричном редакторе (я использовал HxD) изменить её название на любое другое. Это не сработало для меня, но сам chromedriver работает нормально после этого. Так-же я пробовал изменить все переменные где есть слова driver, но это была плохая идея - chromedriver перестал запускать. Без изменения исходников тут точно не обойтись, но я не уверен что это может сработать.
    2. Это более действующий вариант, который даёт хоть какой-то результат. На этой странице можно определить используется chromedriver, или нет и при запуске этой страницы через selenium действительно отображается, что используется webdriver. Добавление следующего куска кода помогло обойти эту идентификацию:
    options.add_experimental_option("excludeSwitches", ['enable-automation'])

    Но это всё-равно не помогло мне.
    Так-же нашел очень сомнительное и вероятнее всего просто нерабочее решение:
    Запуск js-кода, который меняет состояние переменных navigator, включая navigator.webdriver.
    Так он запускается:
    driver.execute_script("var s=window.document.createElement('script'); s.src='javascript.js';window.document.head.appendChild(s);")

    Сам js-код
    // overwrite the 'languages' property to use a custom getter
    const setProperty = () => {
        Object.defineProperty(navigator, "languages", {
            get: function() {
                return ["en-US", "en", "es"];
            }
        });
    
        // Overwrite the 'plugins' property to use a custom getter.
        Object.defineProperty(navigator, 'plugins', {
            get: () => [1, 2, 3, 4, 5],
        });
    
        // Pass the Webdriver test
        Object.defineProperty(navigator, 'webdriver', {
          get: () => false,
        });
        callback();
    };
    setProperty();

    Ерунда в том, что в Chrome вообще отсутствует переменная navigator.webdriver, в этом можно убедиться вводом navigator в консоли браузера, её там нет. Зато эта переменная есть в Firefox, но этот код её не меняет, т.е. он просто ничего не делает, значение переменной Firefox navigator.webdriver всегда равно true при запуске через selenium. В обычном (ручном) режиме она false.

    UPD. Не знаю, как проглядел, но в конечном итоге всё уперлось в проверку reCAPTCHA v3. Эта проверка проходится практически всегда при следующих условиях:
    1. Не используется User-Agent.
    2. Не используется прокси.
    3. Не отключаются уведомления.
    4. Не блокируются запросы на разрешения.
    4. Используется вот этот параметр:
    options.add_experimental_option("excludeSwitches", ['enable-automation'])

    Но при таких параметрах зарегистрировать более одного раза с одного IP не представляется возможным. Как я и указывал в своём вопросе - прокси использовал совершенно разные - от паблик до микро-серверов google cloud, так что дело не в "качестве" прокси а сугубо в факте его использования.
    Ответ написан
    Комментировать
  • Вопрос с собеседования на Java Бекенд. Как гарантировать согласованность операций?

    Я не из МТС банка, но у нас в собесе тоже есть похожий вопрос, но я бы не назвал его простым, так как там дальше ещё много дополнительных вопросов и обсуждений можно невертеть.

    Основная идея заключается в том, что нужно как-то обеспечить транзакционнлсть при общении с левым сервисом.

    Самый простой и часто используемый вариант - Outbox.

    Смысл в том, что мы должны в нашей основной базе завести таблицу, в которой будет записано, что нам нужно отправить запрос в тот сервис и с какими параметрами. (Например отправить письмо по электронной почте)

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

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

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

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

    66ab5b548e5a9142225375.png

    Благодаря тому что мы записываем основные бизнес-данные и намерение сделать запрос в сторонний сервис в одной транзакции - мы гарантируем, что мы не будем отправлять запрос, если данные не записались и наоборот - если данные записались, то мы гарантируем, что попытаемся рано или поздно отправить запрос.
    Ответ написан
    3 комментария
  • Как сохранить нули после запятой в типе float64?

    2ord
    @2ord
    Это про валюту? Ее нельзя представлять при помощи Float64. Это противопоказано в любых ЯП.

    Просто используй строку.
    Для работы с валютой есть пакеты. Допустим, см. здесь.
    Ответ написан
    Комментировать