• Как обеспечить безопасность данных (медицинские анализы)?

    Tkreks
    @Tkreks
    Системный инженер
    1. До запуска прод.контура тестирование независимыми экспертами. В отчете будет вся необходимая информация которую можно будет изучить и закрыть найденные уязвимости.
    2. Если данные можно получать из внешнего источника, тогда нет смысла их хранить в своей базе, получайте данные по запросу пользователя. С подтверждением по одноразовому коду из СМС или генератору.
    3. Если данные всё таки хранятся в вашей базе - хранить данные в зашифрованном виде, каждый пользователь должен иметь возмонжость расшифровать данные только своим ключом.
    4. Контроль доступа к этим данным с логирование. Чтобы можно было понять, кто, когда и какие данные получал. В идеале как вы описали с мониторингом всплесков.
    5. Постоянно обновлять систему. Если есть вариант написать самописную систему который во фронте будет отдавать только html, чтобы не было возможностей на стороне клиента запускать уязвимости, тогда лучше поступить так
    Ответ написан
    2 комментария
  • Создать алгоритм генерации блоков тетриса для картинки?

    Adamos
    @Adamos
    Если все-таки имеется в виду разбиение поля на фигуры тетриса, то я с успехом применял такой алгоритм:
    1. Разбиваем поле на фигуры нужного размера (для тетриса и поля с четными сторонами - просто квадраты 2х2)
    2. Отрываем у одной из фигур одну клетку.
    3. Обходим всех ее соседей и выбираем, какие клетки она может у них позаимствовать, не разорвав тем самым на две части.
    4. Выбираем одну из таких клеток, дополняем эту фигуру и возвращаемся на п. 3 для той, которая после отрыва клетки стала ущербной, пока через какое-то время в соседях очередной ущербной фигуры не окажется та самая оторванная в п. 2 клетка.
    5. Тогда проверяем энтропию полученных фигур (достаточно ли они разнообразны), и если результат пока не устраивает - продолжаем отрывать или присоединяем оторванную и возвращаемся в п. 2.

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

    MrDecoy
    @MrDecoy Куратор тега JavaScript
    Верставший фронтендер
    Судя по всему - они это делают на основе DRM.
    Первый ответ на СО содержит ссылку на статью про это где есть демка, где работает точно так же.
    Ответ написан
    7 комментариев
  • Почему в laravel может не работать hasMany связь?

    @unreal_serg
    Пробуй вместо get() использовать firstOrFail()
    Ответ написан
    Комментировать
  • Как с помощью библиотек python распознать соответствие жеста руки (рук) человека с первой картинки и человека со второй картинки?

    AlexNest
    @AlexNest Куратор тега Python
    Работаю с Python/Django
    Есть openCV (не только для python), умеющая в компьютерное зрение.
    Минус в том, что это довольно низкоуровневая вещь, которую нужно будет "научить". Однако плюс в том, что у нее большое сообщество и такая тривиальная вещь как распознавание жестов 100% кем-то реализована.
    Ответ написан
    1 комментарий
  • Как отправлять заявку с сайта в Telegram?

    nki
    @nki
    bezkart.ru готовая система лояльности
    Для подобной задачи я использую cloud functions в яндекс облаке. Скрипт на питоне принимает HTTP-запрос и перенаправляет мне в телегу нужные данные. При небольших объемах в месяц это бесплатно.
    Ответ написан
    1 комментарий
  • Как сделать передвижение ботов на node.js, чтобы на клиенте оно плавно отображалось?

    Alexandroppolus
    @Alexandroppolus
    кодир
    По идее, боты должны не слишком отличаться от персонажей игроков. Разница только в том, что персонаж двигается сервером по сообщению ws от игрока, а бот - по команде от самого бота, но суть сообщений и команд одна и та же, например, "начать ехать вправо". Ну а сервер должен сразу присылать игроку изменившиеся координаты тех или иных объектов.

    ботам периодически, по таймеру, предоставляется возможность оценить ситуацию и "подумать", что дальше делать, и отправить команду в механизм перемещаний.

    копия мира на клиенте обновляется по сообщениям ws. Перерисовка - по requestAnimationFrame, где берутся текущие координаты. Обычно такой подход дает плавное движение.

    тут есть досадный момент: например, игрок нажимает кнопку-стрелку вправо, но пока об этом дойдет по ws до сервера, пока сервер сдвинет игрока и сообщит об этом обратно на клиента, могут пройти десятки или даже сотни миллисекунд, это будет ощущаться как тормоза. Потому иногда делается "оптимистическое обновление" - на клиенте объект начинает ехать, не дождавшись сообщения от сервера. Выглядит более гладко, но возможен рассинхрон. Так что как лучше, непонятно, обычно это набор компромиссов.
    Ответ написан
    2 комментария
  • Как организовать структуру хранения атрибутов?

    @galaxy
    Вообще, рассуждать в отрыве от данных достаточно бессмысленно. Надо смотреть конкретные планы запросов и время выполнения.
    Например, для статистики, которую вы приводили тут где-то (похоже, ответ уже потерли), у меня получаются вполне приемлемые результаты (на мой взгляд, не факт, что вас устроит):
    Схема и данные

    create table products (
    	id serial primary key,
    	name text not null
    );
    
    create table products_attributes (
    	id serial primary key,
    	attribute_id int not null,
    	product_id int not null references products (id),
    	value double precision
    );
    
    
    -- 10 млн продуктов
    insert into products (name)
    select 'p' || n from generate_series(1, 10000000) n;
    
    -- в среднем по 10 аттрибутов на продукт
    -- всего 20 разных аттрибутов
    -- значения - случайные из 1-1000
    insert into products_attributes(attribute_id, product_id, value)
    select a,
           p.id,
           trunc(random() * 1000)
      from products p, generate_series(1, 20) a
     where random() < 0.5;
    
    
    create index ix_attr_attribute_id on products_attributes(attribute_id);
    create index ix_attr_product_id on products_attributes(product_id);
    create unique index uk_attr_attr_product on products_attributes(product_id, attribute_id);
    create index ix_attr_value on products_attributes(value);
    
    -- немного статистики
    select attribute_id, count(*) from products_attributes group by 1 order by 1;
    
     attribute_id |  count
    --------------+---------
                1 | 5001345
                2 | 5001937
                3 | 4998754
                4 | 4998706
                5 | 4999357
                6 | 5004465
                7 | 4999215
    ...
    
    select product_id, count(*) from products_attributes group by 1 order by 2 desc limit 20;
     product_id | count
    ------------+-------
        4769292 |    20
        5366802 |    20
        7241348 |    20
        3019891 |    20
        7789046 |    20
        1688646 |    19
        1585970 |    19
    ...
    
    SELECT count(*) FROM products_attributes WHERE attribute_id = 1 AND value BETWEEN 1 AND 400;
      count
    ---------
     1999212
    (1 row)
    
    SELECT count(*) FROM products_attributes WHERE attribute_id = 2 AND value BETWEEN 1 AND 400;
      count
    ---------
     1999385
    (1 row)
    
    SELECT count(*) FROM products_attributes WHERE attribute_id = 3 AND value BETWEEN 20 AND 30;
     count
    -------
     55318
    (1 row)



    explain analyze
    select * from products
     where id in (
       select product_id from products_attributes
        where attribute_id = 1 AND value BETWEEN 1 AND 400
     )
     and id in (
       select product_id from products_attributes
        where attribute_id = 2 AND value BETWEEN 1 AND 400
     )
     and id in (
       select product_id from products_attributes
        where attribute_id = 3 AND value BETWEEN 20 AND 30
     );

    Без лимита, 2189 записей - 3.8 сек:
    План

    QUERY PLAN                          
    -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
     Gather  (cost=164603.86..347381.12 rows=2047 width=12) (actual time=680.688..3753.927 rows=2189 loops=1)
       Workers Planned: 2
       Workers Launched: 2
       ->  Nested Loop  (cost=163603.86..346176.42 rows=853 width=12) (actual time=652.714..3713.617 rows=730 loops=3)
             ->  Nested Loop  (cost=163603.43..341334.66 rows=762 width=12) (actual time=652.439..3294.369 rows=730 loops=3)
                   ->  Parallel Hash Join  (cost=163602.86..313081.39 rows=4167 width=8) (actual time=649.437..1742.210 rows=3689 loops=3)
                         Hash Cond: (products_attributes_1.product_id = products_attributes_2.product_id)
                         ->  Parallel Index Scan using ix_attr_attribute_id on products_attributes products_attributes_1  (cost=0.57..147444.27 rows=775173 width=4) (actual time=0.577..880.079 rows=666462 loops=3)
                               Index Cond: (attribute_id = 2)
                               Filter: ((value >= '1'::double precision) AND (value <= '400'::double precision))
                               Rows Removed by Filter: 1000851
                         ->  Parallel Hash  (cost=163306.17..163306.17 rows=23690 width=4) (actual time=647.483..647.483 rows=18439 loops=3)
                               Buckets: 65536  Batches: 1  Memory Usage: 2752kB
                               ->  Parallel Index Scan using ix_attr_attribute_id on products_attributes products_attributes_2  (cost=0.57..163306.17 rows=23690 width=4) (actual time=18.296..639.541 rows=18439 loops=3)
                                     Index Cond: (attribute_id = 3)
                                     Filter: ((value >= '20'::double precision) AND (value <= '30'::double precision))
                                     Rows Removed by Filter: 1647812
                   ->  Index Scan using uk_attr_attr_product on products_attributes  (cost=0.57..6.78 rows=1 width=4) (actual time=0.420..0.420 rows=0 loops=11066)
                         Index Cond: ((product_id = products_attributes_1.product_id) AND (attribute_id = 1))
                         Filter: ((value >= '1'::double precision) AND (value <= '400'::double precision))
                         Rows Removed by Filter: 0
             ->  Index Scan using products_pkey on products  (cost=0.43..6.35 rows=1 width=12) (actual time=0.572..0.572 rows=1 loops=2189)
                   Index Cond: (id = products_attributes.product_id)
     Planning Time: 4.481 ms
     JIT:
       Functions: 93
       Options: Inlining false, Optimization false, Expressions true, Deforming true
       Timing: Generation 14.220 ms, Inlining 0.000 ms, Optimization 2.852 ms, Emission 50.889 ms, Total 67.961 ms
     Execution Time: 3762.035 ms
    (29 rows)



    То же, но с лимитом (LIMIT 20):
    Запрос
    explain analyze
    select * from products
     where id in (
       select product_id from products_attributes
        where attribute_id = 1 AND value BETWEEN 1 AND 400
     )
     and id in (
       select product_id from products_attributes
        where attribute_id = 2 AND value BETWEEN 1 AND 400
     )
     and id in (
       select product_id from products_attributes
        where attribute_id = 3 AND value BETWEEN 20 AND 30
     ) limit 20;


    20 записей - 48 мсек:
    spoiler
    QUERY PLAN                                   
    ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
     Limit  (cost=2.14..7292.14 rows=20 width=12) (actual time=3.743..47.724 rows=20 loops=1)
       ->  Nested Loop  (cost=2.14..746133.39 rows=2047 width=12) (actual time=3.741..47.714 rows=20 loops=1)
             ->  Nested Loop  (cost=1.70..734511.89 rows=1829 width=12) (actual time=3.313..44.710 rows=20 loops=1)
                   ->  Nested Loop  (cost=1.14..666709.45 rows=10000 width=8) (actual time=2.377..42.276 rows=95 loops=1)
                         ->  Index Scan using ix_attr_attribute_id on products_attributes products_attributes_2  (cost=0.57..209246.27 rows=56856 width=4) (actual time=1.250..14.969 rows=511 loops=1)
                               Index Cond: (attribute_id = 3)
                               Filter: ((value >= '20'::double precision) AND (value <= '30'::double precision))
                               Rows Removed by Filter: 46859
                         ->  Index Scan using uk_attr_attr_product on products_attributes products_attributes_1  (cost=0.57..8.05 rows=1 width=4) (actual time=0.053..0.053 rows=0 loops=511)
                               Index Cond: ((product_id = products_attributes_2.product_id) AND (attribute_id = 2))
                               Filter: ((value >= '1'::double precision) AND (value <= '400'::double precision))
                               Rows Removed by Filter: 0
                   ->  Index Scan using uk_attr_attr_product on products_attributes  (cost=0.57..6.78 rows=1 width=4) (actual time=0.025..0.025 rows=0 loops=95)
                         Index Cond: ((product_id = products_attributes_1.product_id) AND (attribute_id = 1))
                         Filter: ((value >= '1'::double precision) AND (value <= '400'::double precision))
                         Rows Removed by Filter: 0
             ->  Index Scan using products_pkey on products  (cost=0.43..6.35 rows=1 width=12) (actual time=0.149..0.149 rows=1 loops=20)
                   Index Cond: (id = products_attributes.product_id)
     Planning Time: 9.959 ms
     Execution Time: 47.796 ms
    (20 rows)


    Как видите, оценки планировщика по селективности адекватные. Начинает он с самого высоко-селективного условия. Лимит проносится внутрь самых глубоких джойнов (видно по количеству записей).
    Ответ написан
    3 комментария
  • Как можно с помощью QR кода сделать скачивание контакта на телефон?

    vabka
    @vabka
    Токсичный шарпист
    Да, можно.
    Для этого надо в qr код закодировать vcard: https://en.wikipedia.org/wiki/VCard
    Ответ написан
    Комментировать
  • Как сделать мигающее уведомление во вкладке браузера?

    ProgrammerForever
    @ProgrammerForever
    Учитель, автоэлектрик, программист, музыкант
    var titleState=0;
    setInterval(()=>{
    document.title=titleFlag?"Мигающий":"заголовок";
    titleState = titleState?0:1;
    },500);
    Ответ написан
    2 комментария
  • Как сделать такой div блок без использования картинок?

    @Esal
    как вариант - использовать clip-path
    вот есть такой генератор https://bennettfeely.com/clippy/
    Ответ написан
    Комментировать
  • Resource: что из себя представляю потоки в php?

    ipatiev
    @ipatiev Куратор тега PHP
    Потомок старинного рода Ипатьевых-Колотитьевых
    Я значительно переработал этот ответ, поскольку мне самому не нравились некоторые моменты плюс я обратил внимание на конкретные примеры из вопроса.

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

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

    Вот даже здесь, поскольку fopen работает поверх абстракции, нельзя говорить о едином подходе.
    Если у нас самый простой случай - локальный файл - то РНР оборачивает функции для работы с файлами языка С в свою собственную абстракцию. Но ниже - на уровне этих самых функций языка С - никаких потоков нет. Есть обращение к функциям операционной системы, которые просто позволяют прочитать выбранный кусок файла.
    Тут никаких вопросов нет, всё честно - если мы прочитали из файла 5 килобайт - значит потратили ровно 5 килобайт памяти.
    Но работаем мы с файлом не считывая его весь в память не потому что поток, а потому что так устроена файловая система. А поток этой возможностью только пользуется.

    Если же мы открываем не файл, а URL, то РНР начинает извращаться, пытаясь предоставить те же самые инструменты, какие мы используем для работы с файлами, для доступа к ресурсам совершенно другого типа.
    И здесь возможны нюансы. Я не знаю, как реализован HTTP wrapper, но в теории HTTP позволяет чтение произвольного объема данных через заголовок Range:. То есть РНР вполне может читать и из НТТР кусками, а не целиком.

    В общем поток - это абстракция. Подход. Интерфейс. Способ работы с массивом информации не забирая её всю в память.
    При этом реализация конкретного инструмента, использующего этот подход, может быть совершенно самостоятельной, никак с другими не связанной. Мне кажется, что именно этот момент является для вас камнем преткновения: на техническом уровне это совсем не обязательно одни и те же потоки. Но вполне могут быть.
    При этом важно не смешивать сам поток и его получатель (получатель вполне может накапливать всю информацию из потока).

    А упомянутый в вопросе PSR-7 вообще никакого отношения к потокам в РНР не имеет. Это совершенно отдельная реализация принципа потоков, которая не имеет отношения к потокам в РНР.
    Ответ написан
    Комментировать
  • Resource: что из себя представляю потоки в php?

    ThunderCat
    @ThunderCat Куратор тега PHP
    {PHP, MySql, HTML, JS, CSS} developer
    Официальная дока же вполне нормально объясняет. Если коротко - это общий интерфейс к последовательному набору данных, который позволяет читать, писать и искать в этих данных (как в файле). И все это в едином стиле. Интерфейс такой, типа. Грубо говоря нечто вроде юниксовского подхода "все на свете это файл".

    Мне не понятно, где тогда хранится весь ответ клиента, если не в памяти ?
    В памяти конечно, но так как это оболочка над данными, то реализация скрыта, условно вы можете считать это файлом, который может активно меняться.
    Ответ написан
  • Как получать уведомления о новых ДТП из Yandex карт?

    @tem12qaz
    Смогли получить информацию о дтп с Яндекса?
    Ответ написан
    1 комментарий
  • Почему не отправляется sendMessage в telegram API с ошибкой message text is empty?

    @ambal245
    Для группы chat_id нужно отправлять в числовом ввиде (chat_id=42323232), а для каналов можно и в форме @channeliiiii chat_id=@channeliiiii.
    Ответ написан
    1 комментарий
  • По какой причине могла дать сбой база - terminating connection because of crash of another server process?

    Melkij
    @Melkij
    PostgreSQL DBA
    Кончилось место на диске, OOM, или даже segfault при очень большом везении. Найдите в логе базы подробности, они будут перед всеми "terminating connection because of crash of another server process"
    Ответ написан
    Комментировать
  • Как правильно проксировать сайт через proxy_pass в nginx и не словить редирект?

    ky0
    @ky0 Куратор тега Nginx
    Миллиардер, филантроп, патологический лгун
    Редиректит то, куда вы обращаетесь в прокси-пассе, а не указанный конфиг. Уберите подобное поведение оттуда (а также абсолютные ссылки, которые тоже палят ваш "секретный домен", например) - и всё будет, как вам хочется.
    Ответ написан
    Комментировать