Страницы

Поиск по вопросам

суббота, 30 ноября 2019 г.

Интерфейс, не содержащий ни одного члена

#java #интерфейс


Возможен ли интерфейс, не содержащий ни одного члена, и если да, какой практический
смысл от такого интерфейса?
    


Ответы

Ответ 1



Да, возможен. Такие интерфейсы называют маркерными. Они нужны для индикации чего-либо JVM, компилятору или какой-либо библиотеке. Пустые они потому, что позволяют добавить некоторый признак/маркер/индикацию к типам, не меняя контракты этих типов. В Джаве такими интерфейсами являются, например, Serializable и Cloneable. Существование Serializable позволяет сделать проверку "можно ли сериализовать этот объект" более типизированным образом, сведя ее к проверке "имплементирует ли этот объект интерфейс Serializable". Заменой маркерным интерфейсам также могут служить аннотации (например, @ThreadSafe). Интерфейс-маркер на Википедии.

Ответ 2



Да, это возможно. Существует шаблон, который называется интерфейс-маркер. Классы реализуют интерфейс не содержащий, ни одного метода. Это требуется для того, чтобы отметить определенные классы, с которыми в дальнейшим возможны, какие-то определенные действия. Чтобы было понятнее, приведу пример. В стандартной библиотеке существует интерфейс java.lang.Cloneable. Он показывает, что переопределеный метод в классе java.lang.Object.clone() будет возвращать копию объекта данного класса.

Как узнать о поддержке браузером CSS свойства?

#javascript #css


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

Как я могу знать, поддерживает ли данный браузер указанное CSS свойство? Можно ли
это узнать на одном CSS?
    


Ответы

Ответ 1



С помощью одного CSS Узнать, поддерживает ли данный браузер указанное CSS свойство, можно через CSS директиву под названием @supports. Эта директива работает так же, как и @media. /* Узнаём, поддерживает ли браузер display: flex; */ @supports (display: flex) { /* Стили */ } Так же можно установить свойства при условии, если браузер не поддерживает указанное CSS свойство /* Узнаём, поддерживает ли браузер display: flex; */ @supports not (display: flex) { /* Стили */ } Ещё можно проверить несколько свойств сразу, используя оператор and /* Узнаём, поддерживает ли браузер display: flex; и flex-wrap: wrap; */ @supports (display: flex) and (flex-wrap: wrap) { /* Стили */ } А если нам нужно хотя бы одно рабочее свойство, можно использовать оператор or /* Узнаём, поддерживает ли браузер display: flex; */ @supports (display: flex) or (display: -webkit-flex) { /* Стили */ } Но нужно учесть, что данная директива новая и в IE вообще не работает. Так же, для обеспечения, какой никакой, кроссбраузерности, можете использовать вендорные префиксы. С помощью JS Данную задачу, с помощью JS, я знаю, как решить двумя способами: Использовать аналог CSS @Supports только на JS — функцию CSS.supports() // Узнаём, поддерживает ли браузер display: flex; CSS.supports("display", "flex"); // true/false Так же, как и в CSS, можно указать несколько свойств. // Узнаём, поддерживает ли браузер display: flex; и flex-wrap: wrap; CSS.supports("( display: flex ) and ( flex-wrap: wrap )"); // true/false Но так же, как и в CSS, этот метод является новым и не будет работать в IE вообще. Проверить с помощью применения стилей через JS. Суть этого метода в том, что браузер не может установить свойству элемента значение, которое не поддерживает. Таким образом, если, после применения нового значения свойству через JavaScript, оно не изменилось, то браузер не поддерживает данное значение. В итоге у нас выходит следующая функция: var SupportsCSS = function (property, value) { try { // Создаём новый элемент var element = document.createElement('span'); // Проверяем, есть ли такое свойство в браузере if (element.style[property] !== undefined) element.style[property] = value; // Если есть, то присваиваем else return false; // Если нет, то false // Если браузер поддерживает данное значение для указанного свойства, то значения будут равны return element.style[property] === value; } catch (e) { // В случае со старым IE, при присваивании значения, которое не поддерживается, вылетает ошибка return false; } }; И вот так это работает: var SupportsCSS = function (property, value) { try { var element = document.createElement('span'); if (element.style[property] !== undefined) element.style[property] = value; else return false; return element.style[property] === value; } catch (e) { return false; } }; // Проверяем console.log( SupportsCSS('display', 'flex') ); console.log( SupportsCSS('display', '-webkit-box') ); console.log( SupportsCSS('display', 'Lol :)') ); console.log( SupportsCSS('flex-wrap', 'wrap') ); console.log( SupportsCSS('-webkit-flex-wrap', 'nowrap') ); Примечание: Если вы проверяете поддержку свойства в старом браузере, через эмулятор современного браузера, то данный метод будем показывать true на значениях, которые не поддерживаются. Преимущество этого метода в том, что он будет работать во всех браузерах. Пример запуска скрипта в Safari 5.17: Специальные сервисы Чтобы не заморачиваться, поддержу можно посмотреть на специальных сайтах. К примеру, один из самых популярных сайтов — http://caniuse.com/ Подробнее можно прочитать здесь: https://habrahabr.ru/post/336466/

Ответ 2



Modernizr Modernizr — это JavaScript-библиотека, которая узнаёт, что из HTML5 и CSS3 умеет браузер пользователя. Если вкратце, то библиотека добавляет классы вашему опираясь на которые можно выбирать какие свойства будет использовать элемент: .block { display: flex; } html:not(.flexbox) .block { display: block; } Методы для js: if(Modernizr.touchevents) { // do something ... } Так же тестирование тех или иных возможностей браузера, скажем для выбора "подключать полифилы или нет": Modernizr.load({ test: Modernizr.geolocation, yep : 'geo.js', nope: 'geo-polyfill.js' }); Более подробно можно почитать в статье на Хабре - Modernizr: практическое применение

Как устроены ключи шифрования Telegram?

#telegram


Вопрос по устройству протокола telegram и ключей шифрования.

Спецслужбы просят у телеграмма ключи и настаивают, что это требование не идёт вразрез
Конституции РФ: мы не спрашиваем сообщения пользователей, мы просим только ключи.

Тогда пардон что это за такие бесполезные ключи вообще? Ими ничего нельзя расшифровать?
И вообще, как устроены эти ключи: на каждого пользователя телеграм хранится ключ и
ФСБ требует шесть ключей по уголовным делам о терроризме? Или они хотят некий золотой
ключ, которым можно будет расшифровать любое сообщение всех ста миллионов пользователей
телеграмма?

Ссылки по теме:


Тинькоф журнал. Телеграм не смог оспорить приказ ФСБ в суде. Что это значит

    


Ответы

Ответ 1



Cогласно общим часто задаваемым вопросам можно кое-что узнать о ключах для хранящейся на серверах информации: Секретные чаты там не хранятся вовсе. О ключах и речи не идёт. Для несекретных чатов они утверждают, что распределяют ключи по нескольким юрисдикциям, чтобы для раскрытия какой-либо информации потребовались распоряжения судов из нескольких сразу. Чтобы такое произошло, должно произойти нечто экстраординарное. Согласно часто задаваемым вопросам для технарей (technically inclined) можно сделать некоторые выводы о возможностях расшифровки передаваемого трафика: Из-за того, что при передаче повсюду используются ключи, согласованные по протоколу Диффи-Хеллмана (ДХ), если сервер Telegram не сохраняет сессионных ключей (что он теоретически может, но вряд ли делает), то расшифровка ранее записанных данных скорее всего невозможна, т. к. и сервер и клиент могли уже давно забыть к ним ключ. У Телеграма есть приватный RSA-ключ для проверки подлинности сервера, публичный "брат" которого зашит в клиенты. При наличии этого приватного ключа возможно устроить MITM-атаку, заставив клиентов в подконтрольной сети считать собственный сервер подлинным сервером Telegram, из-за чего клиенты будут считать канал доверенным и приступят к согласованию сессионных ключей с самозванцем, который в свою очередь сможет от лица клиента связаться с настоящим сервером. У Телеграма есть сессионные ДХ-ключи для общения с конкретными клиентами (а от одного аккаунта может подключиться несколько клиентов) об облачных чатах (где нет оконечного шифрования). Их нет смысла сохранять, когда можно в любой момент договориться о новом, поэтому, вероятнее всего, хоть этот ключ и существует, его нет смысла раскрывать, т. к. действителен он будет недолго. Для секретных чатов ДХ-ключи генерируются для защиты взаимодействия не с сервером, а непосредственно с адресатом. Так что серверы ни на каком этапе не получают готового ключа и не могут их выработать даже имея записанный трафик процедуры согласования ключа. Потому что это Диффи-Хеллман. Поскольку Telegram трубит о максимальной приватности, есть основания полагать, что сессионных ключей они не сохраняют. Исходя из всего этого, ФСБ могут интерсовать два вида ключей, т. к. это единственные ключи с достаточным временем жизни, чтобы их имело смысл получать заранее: Приватный RSA-ключ сервера — да, им нельзя ничего расшифровать, но с его помощью можно получить сессионный ключ у настоящего сервера Telegram и расшифровать данные, которые можно с его помощью запросить: якобы клиентом у настоящего сервера. Т. е. выполнить MITM-атаку. Ключи шифрования (неизвестного типа) данных на жёстких дисках серверов для облачных чатов (секретные существуют в расшифрованном виде лишь на клиентских устройствах), если вдруг удастся заполучить данные с дисков из серверов Telegram. Сколько их и какова область каждого ключа, из-за закрытости серверного кода Telegram достоверно не известно, клиенты с этими ключами никак не работают; теоретически там может и не быть шифрования. Эти ключи имеют хоть какой-то смысл при наличии, скажем, дисков из серверов. И даже в этом случае может подложить свинью полнодисковое шифрование. Разумеется, я предполагаю, что протокол Диффи-Хеллманна и RSA достаточно криптостойки в тех местах, на которые в них рассчитывают. Если их всё же проломят, устойчивость Telegram будет меньшей из проблем, которые в результате этого всплывут. На этих протоколах основывается львиная доля взаимодействий в интернете — HTTPS, например.

Ответ 2



Судя с этого документа "Пояснение специалиста №1" следует, что для шифрования трафика используется Диффи-Хеллман (генерация общего секрета), RSA (аутенфикация), AES (шифрование). Другими словами, эта связка дает такой же уровень безопасности, как набор шифров в TLS: TLS_DHE_RSA_WITH_AES_... Под передачей ключей скорее всего имеют ввиду передачу приватного RSA ключа сервера. (В случае с TLS это была бы передача приватного ключа от сертификата). Люди, имеющие этот ключ, смогут расшифровывать (и изменять) трафик при помощи man-in-the-middle. При этом, если у них будет сохраненный ранее трафик, они не смогут его расшифровать в будущем с приватным ключом (как perfect forward secrecy в TLS).

Как исключить файлы из коммита, чтобы включить их в другой

#git


Возможно ли вернуться в состояние до коммита и сделать иначе, или как исключить файлы
из коммита, чтобы включить эти файлы в другой коммит?
    


Ответы

Ответ 1



Да, исправить старый коммит можно следующим образом: создать на исправляемом коммите ветку, встать на нее (checkout -b) поправить код, залить коммит (но!) с опцией ammend last commit (есть такой переключатель в UI, и в командной строке параметр) все коммиты со старой ветки идущие после исправленного переместить на новую ветку (rebase - переместить разом, либо cherry-pick - по одному). Я предпочитаю по одному для лучшего разрешения конфликтов. cherry-pick можно так же делать из UI - правой кнопкой на коммите - и там будет такая опция. Если вы хотите исключить из него файлы - на этапе правки кода - уберите их из коммита - "спрячьте" командой git stash save, ammend last commit чтоб перезалить текущий, cherry-pick до нужного коммита, в котором вы хотите файлы вставить и командой git stash pop вытащите их из тайника и закомитьте как надо.

Ответ 2



Самый функциональный способ, который работает без исключений вида "если это последний коммит", а подходит для любого коммита -- это команда git rebase. Эта команда позволяет как угодно перекраивать коммиты: объединяя коммиты, переставляя их местами, переносить файлы из одного коммита в другой. Культура программирования -- это не только культура написания самого кода, но в связи с широким распространением систем версионного контроля -- ещё и культура ведения разработки в VCS. В командах часто важно не только чтобы код был хорош, но и был порядок в ваших коммитах и ветках. Важно! Помните о том, что в большинстве команд принято делать rebase только для локальных изменений, чтобы не пришлось потом выполнять git push -f. Итак, как исключить файлы из коммита. Прежде всего убедитесь, что нет отслеживаемых файлов с изменениями -- иначе rebase просто не запустится. Можете положить эти изменения в карман через git stash. Если это требование выполнено -- можете запускать rebase в интерактивном режиме, например: git rebase -i HEAD~4 После чего нужно у коммита, из которого вы хотите выделить файлы pick на edit (можно просто e) и выйти из редактора с сохранением изменений. Дойдя до коммита, который отмечен буквой e гит остановится и будет ожидать ваших действий по изменению коммита. Самое просто будет -- это дать команду git reset HEAD~ и собрать в коммит все файлы (как новые, так и изменённые), за исключением тех, которые вы хотите использовать в другом коммите. После того, как вы выполните добавление изменений через git add мы коммитим это как обычно через git commit -m "message". Затем оставшиеся файлы добавляем и оформляем ещё один коммит (если файлы пойдут в два коммита -- значит повторим эту операцию несколько раз) В какой-то момент в папке не останется никаких незакоммиченных изменений -- можно взять и внести новые изменения и новые коммиты. Я часто пользуюсь этим, чтобы добавить сразу несколько коммитов после какого-то выбранного. Когда вы решите, что сделано достаточно -- можно дать команду git rebase --continue. В этот момент гит начнёт добавлять все остальные коммиты, которые шли после редактируемого и если не будет конфликтов -- то будет переходить к следующему и следующему, пока не дойдёт до вашего последнего коммита. Если же конфликты будут -- их нужно будет резолвить и заново продолжать операцию git rebase --continue. Я рекомендую подобные операции делать на каких-то тестовых репозиториях, чтобы попрактиковаться и не страшно было что-то сделать не так. Для примера приведу некоторый пример выделения файлов из коммита. Итак, начнём. Допустим у нас есть такие коммиты: pick 0517714 add file1.txt pick 13ae975 add file2.txt and file3.txt pick b967f0f add file4.txt and file5.txt pick 412ab2d add file6.txt Сделанные следующим образом: $ git clone ak@localhost:aaa.git bbb Cloning into 'bbb'... warning: You appear to have cloned an empty repository. $ cd bbb $ touch .gitignore $ git add .gitignore $ git commit -m "empty .gitignore" [master (root-commit) f3f251b] empty .gitignore 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 .gitignore $ touch file1.txt $ git add file1.txt $ git commit -m "add file1.txt" [master 0517714] add file1.txt 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 file1.txt $ touch file2.txt $ git add file2.txt $ touch file2.txt $ touch file3.txt $ git add file3.txt $ git commit -m "add file2.txt and file3.txt" [master 13ae975] add file2.txt and file3.txt 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 file2.txt create mode 100644 file3.txt $ touch file4.txt $ git add file4.txt $ touch file5.txt $ git add file5.txt $ git commit -m "add file4.txt and file5.txt" [master b967f0f] add file4.txt and file5.txt 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 file4.txt create mode 100644 file5.txt $ touch file6.txt $ git add file6.txt $ git commit -m "add file6.txt" [master 412ab2d] add file6.txt 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 file6.txt $ И, допустим, мы хотим перенести файл 5 в предыдущий коммит (где файлы 2 и 3). Делаем git rebase -i HEAD~4: $ git rebase -i HEAD~4 pick 0517714 add file1.txt pick 13ae975 add file2.txt and file3.txt pick b967f0f add file4.txt and file5.txt pick 412ab2d add file6.txt # Rebase f3f251b..412ab2d onto f3f251b # # Commands: # p, pick = use commit # r, reword = use commit, but edit the commit message # e, edit = use commit, but stop for amending # s, squash = use commit, but meld into previous commit # f, fixup = like "squash", but discard this commit's log message # x, exec = run command (the rest of the line) using shell # # These lines can be re-ordered; they are executed from top to bottom. # # If you remove a line here THAT COMMIT WILL BE LOST. # # However, if you remove everything, the rebase will be aborted. # # Note that empty commits are commented out ~ "~/bbb/.git/rebase-merge/git-rebase-todo" 22L, 742C У коммита b967f0f заменяем pick на edit и сохраняем изменения, гит заново последовательно применяет коммиты 0517714 и 13ae975 (вы можете даже не заметить это, так быстро мелькают изменения на экране) и останаваливается на коммите b967f0f: $ git rebase -i HEAD~4 Stopped at b967f0f... add file4.txt and file5.txt You can amend the commit now, with git commit --amend Once you are satisfied with your changes, run git rebase --continue $ Тут мы делаем простой шаг: $ git reset HEAD~ $ git status # HEAD detached at 13ae975 # You are currently editing a commit while rebasing branch 'master' on 'f3f251b'. # (use "git commit --amend" to amend the current commit) # (use "git rebase --continue" once you are satisfied with your changes) # # Untracked files: # (use "git add ..." to include in what will be committed) # # file4.txt # file5.txt nothing added to commit but untracked files present (use "git add" to track) $ (git status просто для наглядности) Составим новый коммит из файла 4: $ clear && history -c $ git add file4.txt $ git commit -m "add file4.txt" [detached HEAD 4c72f5d] add file4.txt 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 file4.txt Остался файл 5, создадим из него новый коммит: $ git status # HEAD detached from 13ae975 # You are currently editing a commit while rebasing branch 'master' on 'f3f251b'. # (use "git commit --amend" to amend the current commit) # (use "git rebase --continue" once you are satisfied with your changes) # # Untracked files: # (use "git add ..." to include in what will be committed) # # file5.txt nothing added to commit but untracked files present (use "git add" to track) $ git add file5.txt $ git commit -m "add file5.txt" [detached HEAD f0cd810] add file5.txt 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 file5.txt $ После чего рабочий каталог чист и можно сказать гит, что можно продолжить операцию rebase и накатывать следующие коммиты: $ git rebase --continue Successfully rebased and updated refs/heads/master. $ Здесь вам не видно, между тем как вы нажали enter и перед тем, как появится надпись 'Successfully rebased' гит последовательно применит остающиеся коммиты -- в нашем случае это только коммит 412ab2d. Вот какая у нас получилась новая история: pick 0517714 add file1.txt pick 13ae975 add file2.txt and file3.txt pick 4c72f5d add file4.txt pick f0cd810 add file5.txt pick 6952a0b add file6.txt Операция перестановки местами коммитов 4 и 5 и слияния коммитов 13ae975 с последующим f0cd810 тривиальна -- нужно снова дать команду rebase, переставить местами коммиты 4c72f5d и f0cd810 и сделать squash коммита f0cd810 в коммит 13ae975 -- вот тут я писал подробнее в отдельном посте: Можно ли в GIT добавить еще один файл в последний локальный комит? При помощи rebase переносить можно не только новые файлы, но изменения и удаления. Также важно помнить, что если вы что-то неправильно сделали в середине rebase'а -- то помните, что у вас есть возможность отменить rebase: нужно дать команду git rebase --abort.

Ответ 3



Если это последний коммит и он находится локально, то без проблем. Допустим, последний коммит у нас B, предшествующий ему коммит A: Сбросим наш коммит командой git reset B. Делаем git status и видим следующую картину: Последним коммитом будет коммит A, все изменения останутся, но они будут в состоянии not stagged. Формируем новый индекс для создания нового первого коммита с помощью команды git add список_файлов_через_пробел (можно каждый файл по одному добавлять). Делаем git commit -m "C", это будет наш первый коммит. Делаем git commit -am "D", это будет наш второй коммит. Параметр -a - добавляет все изменённые файлы в индекс. Альтернативные варианты шага 5: git add . git commit -m "D" Или git add название_файлов_через_пробел git commit -m "D" Или git add название_файла_1 ... git add название_файла_N git commit -m "D"

Javascript: найти на странице черный текст на черном фоне

#javascript #jquery #css


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

Поставили задачу: сделать на сайте версию для слабовидящих. Один из пунктов - инверсия
цвета, то есть выводим белый текст на черном фоне. Я прописал черный background у body,
поправил css для прочих контейнеров, все хорошо, за исключением одного но. В админке
у некоторых страниц в редакторе WYSIWYG явно прописан черный цвет для текста (в атрибуте
style). В результате этот текст не виден на странице.

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

Например, чтобы javascript автоматически находил такой текст и менял его цвет на
белый. Вопрос в том, как найти такие элементы.

Пока я вижу только вариант рекурсивного прохода по всем элементам DOM с запоминанием
background родителя и проверкой цвета самого элемента.

Но может, есть способ проще, какое-нибудь решение в пару строк на jquery?

Иными словами, нужно добиться, чтобы в примере во втором div > p текст был виден:



.orig {
  background-color: #fff;
}

.invert {
  background-color: #000;
}

Оригинал

Текст

Инверсия

Текст


Ответы

Ответ 1



Пришла в голову мысль, что стили, заданные в редакторе, совсем не обязательно будут задавать тексту черный цвет — это может быть и темно-серый и какой-нибудь коричневый. Текст такого цвета на инвертированном фоне слабовидящим людям будет по-прежнему тяжело прочесть, потому надо определять контрастность текста и фона. Код частично скопипастил с определителя контрастности Лии Веру. Что происходит в этом коде: функция getLuminance() возвращает relative luminance; функция getContrastRatio() возвращает contrast ratio из введенных туда данных о цвете фона и текста. Проходим по каждому параграфу внутри блока .invert, определяем contrast ratio и если он меньше 7 (таково требование WCAG) — делаем текст белым, а если больше 7, то оставляем как есть. UPD: переписал код для определения цвета фона не у родителя, а у самого элемента, для этого надо прописать параграфу в CSS background-color: inherit и переменной bg присваивать значение собственного цвета фона: bg = $(item).css('background-color'). UPD: итоговый вариант, позволяющий делать что угодно с элементами, имеющими недостаточную контрастность и без использования background-color: inherit. Источники: Lea Verou, contrast ratio. Формула подсчёта relative luminance: https://www.w3.org/TR/2008/REC-WCAG20-20081211/#relativeluminancedef. Формула подсчета contrast ratio: https://www.w3.org/TR/2008/REC-WCAG20-20081211/#contrast-ratiodef. $(function() { var color, bg, textLuminance, parentLuminance, cr; $('.invert p').each(function(index, item) { color = $(item).css('color'), bg = $(item).css('background-color'); textLuminance = getLuminance(color); parentLuminance = getLuminance(bg); cr = getContrastRatio(textLuminance, parentLuminance); if(cr <= 7) $(item).css('color', '#fff'); }); function getContrastRatio(l1, l2) { l1 += .05, l2 += .05; var ratio = l1 / l2; if (l2 > l1) { ratio = 1 / ratio; } return ratio = Math.round(ratio, 1); } function getLuminance(color) { var rgb = color.slice(4, -1).split(',').map(Number); for (var i = 0; i < 3; i++) { var rgbI = rgb[i]; rgbI /= 255; rgbI = rgbI < .03928 ? rgbI / 12.92 : Math.pow((rgbI + .055) / 1.055, 2.4); rgb[i] = rgbI; } return .2126 * rgb[0] + .7152 * rgb[1] + 0.0722 * rgb[2]; } }); .orig { background-color: #fff; } .invert { background-color: #000; } .invert p { padding: 5px; background-color: inherit; }

Оригинал

Текст

Инверсия

Обычный текст без инлайновых стилей

Черный Текст

Коричневый Текст

Синий Текст

Желтый Текст

Оранжевый Текст



Ответ 2



Может быть так: $('p').each(function(){ var $this = $(this), wrap = $this.parent('div'), color = $(this).css('color'), bg = wrap.css('backgroundColor'); console.log(color + ' ' + bg); if(color === bg) { $this.css({'color':'#ffffff'}); } }); .orig { background-color: #fff; } .invert { background-color: #000; }

Оригинал

Текст

Инверсия

Текст

либо так: $('p').each(function(){ var $this = $(this), wrap = $this.closest('.invert'), color = $(this).css('color'), bg = wrap.css('backgroundColor'); console.log(color + ' ' + bg); if(color === bg) { $this.css({'color':'#ffffff'}); } }); .orig { background-color: #fff; } .invert { background-color: #000; }

Оригинал

Текст

Инверсия

Текст



Ответ 3



Может с фильтром invert? .orig { background-color: #fff; } .invert { background-color: #000; } .invert p { filter: invert(100%); }

Оригинал

Текст

Инверсия

Текст



Ответ 4



Любопытно. Можно при изменении текстовой ноды (MutationObserver) проверять её цвет, сравнивать его с чёрным и, если слишком тёмный, делать его светлее. При сохранении, обходить дерево (TreeWalker), ставить тексту принудительно цвет.

Ответ 5



Если хотите сделать быстро и просто, то сделайте на нативном CSS с помощью свойства mix-blend-mode: p { color: #fff !important;; mix-blend-mode: difference; }

Оригинал

Текст

Инверсия

Текст

mix-blend-mode

Текст



Ssh соединение постоянно рвётся после 5 минут простоя

#linux #cmd #ssh #git_bash #git_cmd


Подключаюсь к своему серверу по ssh -> иду в гугл искать команду, например, для поиска
файла -> возвращаюсь, а окно git bash не отвечает -> перезапускаю его -> ввожу заново
пароль.

Это крайне раздражает. Почему так и что с этим делать?
    


Ответы

Ответ 1



Обычно sshd сервер закрывает неактивные соединения. Часто сталкивался, что маршрутизаторы также рвут соединения, которые "молчат". Можно уговорить клиента всё время посылать я-живой сигнал. В ~/.ssh/config надо добавить (в секундах): Host * ServerAliveInterval 120 Если файла ешё нет, надо создать и во избежание ошибки Bad owner or permissions on ~/.ssh/config не забыть изменить права на запись (в некоторых версиях также и на чтение): chmod go-rw ~/.ssh/config # или chmod 600 ~/.ssh/config Без конфигурации можно попробовать: ssh -o ServerAliveInterval=120 iam@my.home.ru Подробнее man 5 ssh_config В PuTTY это устанавливается в меню - Connection>Seconds between keepalives (0 to turn off).

Ответ 2



В качестве быстрого решения можно использовать ключик в командной строке: ssh -o ServerAliveInterval=30 user@some.host.com

В чем смысл TaskCompletionSource и когда его лучше использовать?

#c_sharp #net #асинхронность #tpl


Немного не понял смысла класса TaskCompletionSource.
В некоторых источниках пишут, что лучше его возвращать из метода вместо обычного
Task.Run().

Разве есть какой-то смысл? Что так, что так я смогу вызвать await на вызывающей стороне.
    


Ответы

Ответ 1



TaskCompletionSource — это тот самый крайний случай, когда вы не можете создать «базовый» Task стандартными средствами. Давайте я поясню, что я имею в виду. Если вы создаёте Task, обычных путей для этого два. Во-первых, если ваш код не производит ожидания, а активно работает, например, проводит вычисления (CPU-bound), вы отправляете его на пул потоков при помощи Task.Run или его аналогов. Во-вторых, если вы пользуетесь другими асинхронными операциями, вы создаёте async-метод, в котором производите await на другие асинхронные операции. .NET предоставляет множество готовых асинхронных операций, например, NetworkStream.ReadAsync или там Dispatcher.InvokeAsync. Но что делать, если вам нужно самому создать примитивную асинхронную операцию, которая не выражается в терминах других, уже готовых асинхронных операций? Как созданы самые внутренние Task-методы? В этом месте вам как раз и пригодится TaskCompletionSource. Например, вы хотите асинхронно дождаться события. Для этого вам нужно превратить событие в Task. Это делается как-то так: мы подписываемся на событие, и по его приходу завершаем Task. Task WaitInput() { var tcs = new TaskCompletionSource(); source.InputReceived += (o, args) => tcs.SetResult(args.Input); return tcs.Task; } Более строгий вариант с отпиской, в которой TaskCompletionSource используется как внутренний Task, чтобы успеть отписаться после его окончания: async Task WaitInput() { var tcs = new TaskCompletionSource(); SourceInputHandler handler = (o, args) => tcs.SetResult(args.Input); source.InputReceived += handler; try { return await tcs.Task; } finally { source.InputReceived -= handler; } } Ещё один пример из реального кода: запустить и дождаться окончания процесса: Task ExecuteProcess(string path) { var p = new Process() { EnableRaisingEvents = true, StartInfo = { FileName = path } }; var tcs = new TaskCompletionSource(); p.Exited += (sender, args) => { tcs.SetResult(true); p.Dispose(); }; // запуск выгружаем на пул потоков, потому что он медленный Task.Run(() => p.Start()); return tcs.Task; } Ещё один пример взят из класса DispatcherThread. Нам нужно дождаться, пока поток стартует, и придёт в «рабочее» состояние. Обычно для этого используют AutoResetEvent, но блокироваться в ожидании его неохота, и намного проще использовать TaskCompletionSource: static public Task CreateAsync() { var waitCompletionSource = new TaskCompletionSource(); var thread = new Thread(() => { // тут могут быть любые настройки waitCompletionSource.SetResult(new DispatcherThread()); Dispatcher.Run(); }); thread.SetApartmentState(ApartmentState.STA); thread.Start(); return waitCompletionSource.Task; } Мы видим, что таким образом можно превратить в Task по сути любую операцию. Дополнительное чтение по теме: TPL and Traditional .NET Framework Asynchronous Programming. Резюме: TaskCompletionSource позволяет превратить в Task даже ту асинхронную операцию, которая не даёт await-абельного интерфейса.

Ответ 2



На SO был такой вопрос. Почитай здесь. Перевод одного из лучших ответов: В моих опытах TaskCompletionSource отлично подходит для переноса старых асинхронных шаблонов в современный шаблон async/await. Самый полезный пример, о котором я могу думать, - это работать с Socket. Он имеет старые шаблоны APM и EAP, но не методы awaitable Task, которые имеют TcpListener и TcpClient. У меня лично есть несколько проблем с классом NetworkStream и предпочитаю raw Socket. Будучи тем, что мне также нравится шаблон async/await, я создал класс расширения SocketExtender, который создает несколько методов расширения для Socket. Все эти методы используют TaskCompletionSource для обертывания асинхронных вызовов следующим образом: public static Task AcceptAsync(this Socket socket) { if (socket == null) throw new ArgumentNullException("socket"); var tcs = new TaskCompletionSource(); socket.BeginAccept(asyncResult => { try { var s = asyncResult.AsyncState as Socket; var client = s.EndAccept(asyncResult); tcs.SetResult(client); } catch (Exception ex) { tcs.SetException(ex); } }, socket); return tcs.Task; } Я передаю Socket в методы BeginAccept, так что я получаю небольшое повышение производительности от компилятора, не требуя поднять локальный параметр. Тогда красота всего этого: var listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); listener.Bind(new IPEndPoint(IPAddress.Loopback, 2610)); listener.Listen(10); var client = await listener.AcceptAsync();