Xmonad: Фиксим менюшки у saleae logic
Есть довольно хороший бюджетный логический анализатор от saleae (и масса совместимых китайских клонов).
Что примечательно - это то, что ребята из этой конторы написали софт под все платформы (и не забыли линупс конечно же).
Софт написан на qt. И выглядит как бы совсем нестандартно.
В обычных DE с ним все нормально, но во всяких WM наступают грабли из-за нестандартной реализации менюшек. В частности очень сильно страдает xmonad. В нем при попытке открыть менюшки появляется цветная рамка и меню пропадает.
Фикс проблемы есть у саппорта saleae - нужно заигнорить окна с определенным классом добавив соответствующее правило к оконным хукам.
className =? "Logic" --> doIgnore
PHP: array_map и ключи массива
Интересно, почему такой вопрос часто всплывает на форумах или где-то еще?
Сначала постараюсь ответить на вопрос “нафига?”, а потом на вопрос “как?”.
Мы привыкли, что в в питоне, js и множестве других языков и фреймворков есть функция map, которая применяет некоторую функцию-обработчик к каждому элементу в списке данных и возвращающую результат в том же порядке. Пруф.
Но никто не ждал, что хеш-таблица и массив в контексте одного из языков будет означать одно и то же. Опять же пруф.
Этот постыдный момент из жизни структуры привел к тому, что одним из самых частых применений массивов (в пхп конечно же) стало создание отображений категория=>какое-то значение.
А после того как у вас появилось отображение вы, вероятно, захотите это где-нибудь на сгенерированной странице отобразить.
Т.е. показать пользователю сам параметр, а скобках его категорию.
Как мы делаем это в языках (фреймворках), которые разделяют понятие массива и хеш-таблицы? Перебираем объект, который содержит категории и формируем по нему массив выводимых данных. Наверное так.
И тут мы открываем руководство по php и видим, что она применяет некий колбек ко всем элементам массива и после этого возвращает новый массив.
Удобно же! Применили колбек к массиву и получили обработанный.
$array = [
'category1' => 'first category',
'category2' => 'second category',
];
var_dump(array_map(function(....
И что-то не заладилось. :) Ключи в колбек не попадают. Можно сделать все через foreach, но тогда нам потребуется еще одна переменная. А тут все было просто и наглядно.
И мы идем в гугель: “php array_map with keys”.
А зачем гуглить-то?
$array = [
'category1' => 'first category',
'category2' => 'second category',
];
var_dump(array_map(function($key, $value) {
return "{$key} => {$value}";
}, array_keys($array), $array));
И все отлично работает. И притом правильно. Относительно конечно же. И никаких вам лишних переменных.
А тем временем в коде вновь и вновь появляются конструкции вида
$array = [
'category1' => 'first category',
'category2' => 'second category',
];
$description = [];
foreach ($array as $key => $value) {
$description[] = "{$key} => {$value}";
}
Или еще хуже.
$array = [
'category1' => 'first category',
'category2' => 'second category',
];
$description = [];
array_walk($array, function($value, $key) {
$description[] = "{$key} => {$value}";
});
Проблема кейса из статьи может быть и раздута, но при вчитывании в сотни строк кода более-менее понятными сходу являются только первые два варианта.
Вариант же с array_walk
на понятность никак не претендует (как и решение подобной задачи при помощи .each в jquery).
Git: откат мержа, который не был запушен
Иногда мы делаем мерж некоторой ветки в master и случается такое, что нам нужно по какой либо причине откатить ветку (мы не делали push еще в удаленный репозитарий), либо просто пытаемся сделать git pull забыв, что есть непрокоммиченые изменения.
При git pull мы увидим следующую картину
Git Pull Failed
You have not concluded your merge (MERGE_HEAD exists). Please, commit your changes before you can merge.
И чтобы откатить наш неудачный мерж не нужно делать никаких reset –hard HEAD=1.
Достаточно сделать
git reset --hard ORIG_HEAD
Тем самым мы приводим локальную ветку мастера к виду, в котором она был до неудачного мержа.
Как жить в локальной сети без dns для локальных ресурсов
Или сказ о том, как перестать бояться и начать раздавать динамические адреса в локальной сети.
Задача:
- необходимо автоматизировать распределение имен различным устройствам в сети.
Проблемы
- доисторический (ископаемый) роутер, который не умеет dd-wrt/openwrt и иже. А вместе с этим он не умеет статические адреса или локальный dns.
- много iot-желаза в локальной сети к которому хочется получать доступ по имени (доменному конечно же).
- Очень много железа, которое появляется в сети лишь на короткое время, а доступ к нему по сети нужен (ну не прописывать же ему постоянно статику?)
- большое количество скриптов автоматизации, которым надо откуда-то брать именя устройств.
Проблему можно решить несколькими путями:
- Поставить слабую железку, поставить на нее bind, поднять локальную доменную зону и убрать с роутера роль dhcp и dns-сервера. Минус в том, что слабой железки может и не быть.
- Поменять роутер на менее доисторический. Минус в том, что роутера может не быть под рукой.
- Воспользоваться протоколом zeroconf. Минусы тоже есть - возможный конфликт имен устройств.
Если с первыми двума вариантами все более-менее понятно, то на третьем стоит остановиться подробно. Так как он решает проблему наименее затратным способом. Протокол описывает:
- назначение адресов устройствам в сети (диапазон 169.254.*)
- разрешение имен
- обнаружение сервисов
Поскольку адреса у устройств уже есть (dhcp же), то нас будет интересовать только та часть протокола, где рассказывается про обнаружение сервисов и разрешение имен. Это mDNS+DNSSD. В nix\bsd за эту часть протокола отвечает сервис avahi В ряде дистрибутивов он включен и нормально настроен сразу. На примере федоры посмотрим как его поставить и настроить.
$ sudo dnf install avahi-daemon avahi-utils
$ sudo systemctl enable avahi-daemon
$ sudo systemctl start avahi-daemon
Если у вас в сети уже есть устройства, где активирован avahi, то можно посмотреть на то, найдет ли оно какие-либо устройства
$ avahi-browse -alr
+ eth0 IPv4 workstation Remote Disk Management local
= eth0 IPv4 workstation Remote Disk Management local
hostname = [workstation.local]
address = [192.168.1.10]
port = [22]
txt = []
Как видим что-то нашло.
Мы можем попробовать его попинговать.
$ ping workstation.local
ping: unknown host workstation.local
Если вы увидели такую картину, то это означает лишь одно - mdns для получения имен доменов у вас не подключен. Чтобы его включить требуется отредактировать /etc/nsswitch.conf.
В строчку hosts нужно добавить mdns_minimal [NOTFOUND=return] перед dns.
hosts: files mdns_minimal [NOTFOUND=return] dns myhostname mymachines
После перезагрузки или перезапуска соотвествующего сервиса пингуем снова.
$ ping -c 4 workstation.local
PING workstation.local (192.168.1.10) 56(84) bytes of data.
64 bytes from workstation.local (192.168.1.10): icmp_req=1 ttl=64 time=0.449 ms
64 bytes from workstation.local (192.168.1.10): icmp_req=2 ttl=64 time=0.469 ms
64 bytes from workstation.local (192.168.1.10): icmp_req=3 ttl=64 time=0.467 ms
64 bytes from workstation.local (192.168.1.10): icmp_req=4 ttl=64 time=0.393 ms
--- workstation.local ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3004ms
rtt min/avg/max/mdev = 0.393/0.444/0.469/0.037 ms
Если у вас очень медленно резолвятся локальные домены, то стоит попробовать использовать модуль mdns4_minimal.
Задача раздачи локальных имен полностью решена. В данном случае я не затрагиваю dnssd поскольку цель была лишь обеспечить доступность хостов по имени.
При желании поднять zeroconf можно как на ардуине, так и на модулях esp8266.
Вы можете столнуться с проблемами из-за того, что некоторые продукты используют зону local для своих целей.
Например торренты часто используют retracker.local для обозначения внутрисетевого трекера.
Обновление нескольких git-репозитариев в папке
Порой у нас в каталоге накапливается много-много git-репозитариев, которые хочется обновить в один заход. Для этого есть маленький скрипт, который обновляет все репозитарии, которые сможет найти в папке, переданной в качестве аргумента.
#!/bin/bash
if test "$#" -ne 1; then
echo "usage: $0 <dirname>"
echo "Find and update all git repos in specified folder"
exit 1
fi
if [-d $1]; then
find $1 -type d -name .git | xargs -n 1 dirname | sort | while read line; do echo "Update repo $line" && pushd `pwd` > /dev/null && cd $line && git pull && popd > /dev/null; done
else
echo "\"$1\" does not exists"
fi
Использование очень простое
$ gitup ~/projects