Рабочий стол юриста v2
Решил запостить и свой рабочий стол. Предыдущий скриншот тут Рабочий стол юриста.
( читать дальше... )
>>> Просмотр (1360x768, 826 Kb)
Решил запостить и свой рабочий стол. Предыдущий скриншот тут Рабочий стол юриста.
( читать дальше... )
>>> Просмотр (1360x768, 826 Kb)
У многих Boot logo (пингвины, показывающие количество потоков или ядер) не работает из коробки. В связи с этим небольшая памятка.
Кастомизация (создание своего) Boot logo
ppmquant 224 logo_linux_clut224.ppm > logo_linux_clut224.ppm
Для конвертации можно использовать промежуточный файл, предварительно переименовав logo_linux_clut224.ppm.
Логотип готов. Осталось перекомпилировать ядро.
P.S. Кстомизированное мной Boot Logo: https://disk.yandex.ru/i/jauzt48_ydk1zg
Пример: https://ibb.co/PcfVgD7
Не секрет, что в Яндекс.Браузер реализован голосовой перевод видео. Знаю, что для некоторых пользователей, эта возможность была решающей при выборе браузера.
Но оказывается, уже давно (с 2021 года) можно прикрутить данную фишку и на firefox. Суть проста:
Возможно понадобится дать разрешение на автовоспроизведение «аудио и видео» (значок в адресной строке).
Проверил на ютубе с BBC News, ok.
Источник с
4pda
p.s. Специально не упомянул Chrome, ‘конкуренты’ пусть горят синим пламенем. :)
Обновление:
Добавлена консольная vot-cli.
Hi, All!
Помогите пожалуйста вспомнить синтаксис команды cp
, для копирования файлов и каталогов в фоновом режиме на удаленной машине.
Когда-то копировал каталоги с одного диска на другой на удаленной машине с использованием команды cp
в фоне, т.е. подключался к машине по SSH, запускал команду копирования и отключался, а команда продолжала отрабатывать. К сожалению, забыл с помощью каких опций/ключей мне это удавалось сделать, весь man
перерыл…
Заранее большое спасибо за помощь!
Всем привет!
Хотел бы услышать Ваше мнение о концепции, которую я хочу внедрить в своей организации.
Ситуация следующая - у меня большое число автономных компьютеров на Debian, которые нельзя подключить к интернету или локальной сети.
Я администратор безопасности и системный администратор в одном лице и я устал по каждой мелочи совершать обход всех ПК.
Одна смена пароля может затянуться на два дня, пока всех обойдёшь.
У меня работает система обновления баз антивируса с определённой флешкой (флешки кроме разрешённых блокированы).
При подключении определённой флешки с неё скачиваются базы вирусных сигнатур в каталог недоступный пользователю, после чего происходит обновление антивируса.
Система хорошо работает, единственное она мне не очень нравится в возможности пользователя изменить архив с обновлением и закинуть на компьютер лишние файлы (к которым доступа у него в любом случае не будет, но всё равно это не нормально).
И вот вчера я придумал следующую концепцию - использовать эту особенную флешку для автоматического выполнения загруженного мной скрипта с настройками.
Человек подключает флешку, компьютер выполняет скрипт (например смены пароля) и все счастливы.
Единственное «но» в безопасности такой реализации.
Итак концепция - есть два скрипта. Первый скрипт, размещён на моём ПК, он предназначен для подготовки скрипта (шифрования). У меня же размещён публичный ключ для шифрования.
Второй скрипт, размещён на всех автономных ПК. Он предназначен для расшифровки скриптов с настройками и их выполнения. На автономных ПЭВМ так же размещается приватный ключ для расшифровки.
#!/bin/bash
file_path_to_encrypt=$1
dir_path_to_result=./task
rm -Rf ./task && mkdir $dir_path_to_result
openssl rand 214 > ./key_to_work.key # Генерируем случайный ключ (он же пароль)
openssl enc -aes-256-ctr -pbkdf2 -in $file_path_to_encrypt -out $dir_path_to_result/encrypt_shell.sh -pass file:./key_to_work.key # Используя симметричное шифрование шифрую файл используя этот ключ (пароль)
openssl rsautl -encrypt -pubin -inkey public.pem -in ./key_to_work.key -out $dir_path_to_result/auth_key.pem # Используя публичный ключ шифрую пароль
rm ./key_to_work.key # Удаляю пароль в открытом виде
#!/bin/bash
file_path_to_decrypt="$1"
openssl rsautl -decrypt -inkey private.pem -in ./task/auth_key.pem -out ./key_to_work.key # Расшифрую пароль используя приватный ключ (асимментричное шифрование)
if [[ $? == "0" ]] # Если расшифровка прошла успешно
then
: # Значит скрипт зашифровал я, продолжаем работу
else
echo 'Скрипт не подтверждён. Завершаю работу.' # Иначе вывожу сообщение, удаляю открытый файл ключа, завершаю работу
rm -f ./key_to_work.key
exit 1
fi
openssl enc -d -aes-256-ctr -pbkdf2 -in $file_path_to_decrypt -out ./script.sh -pass file:./key_to_work.key # Расшифрую файл используя полученный пароль (симметричное шифрование)
/bin/bash ./script.sh # Запускаю расшифрованный скрипт
rm -f ./{key_to_work.key,script.sh} # Удаляю файлы пароля и скрипта
На «красоту» и оптимизацию кода прошу внимание не обращать. Это черновой вариант, просто чтобы посмотреть на концепцию.
Безопасно ли это? Какие тонкие места Вы видите в такой реализации (например, возможность замены инструкций скрипта настроек)?
Заранее спасибо!
В очередной (третий-четвёртый за несколько последних лет) раз затерев по неаккуратности файл с кодом (cp
не в ту сторону), на который был потрачен предыдущий час или больше, и который ещё не был закоммичен, решил что искать его с помощью dd
и grep
- занятие утомительное. Слышал тут про binwalk
, но, посмотрев описание, то ли не осилил найти способ её для этой цели использовать, то ли она и правда для другого.
Написал свою прогу в итоге: исходник.
Компилировать:
gcc -o rawsearch rawsearch.c
Синтаксис:
./rawsearch if=/dev/sda8 str=some_string_from_file
Прога найдёт на диске все текстовые блоки (внимание: если файл фрагментирован то он будет не одним блоком а несколькими, прога их сцеплять не будет), что содержат эту строку и создаст пачку файлов с названиями found-NNN
(NNN - байт где начинается) с этими текстами. Границы текстовых блоков определяются так:
static int is_binchar(char c) { return (c==127 || c>=0 && c<=6 || c>=14 && c!=27 && c<=31); }
(это символы которые по мнению проги в текстовых файлах не встречаются).
Возможно кому-то будет полезно.
Исходник максимально простой (всего 300 строк и 12кб), можно легко патчить под какие-то потребности по месту.
С наступающим, линукс-геймеры. После установки модов на Morrowind, всё превратилось в розовое месево. Посмотрев на это, я понял, что это из-за того, что оригинальные файлы игры названы капсом, а модифицированные нет. В Windows файловая система не чувствительна к регистру, поэтому при распаковке файлов, они автоматически заменяются. А я не могу выискивать три сотни конфликтующих файлов. Может есть архиваторы с нужной функцией или утилиты?
Начнем с 1,2,3.
Окрываем эмулятор терминала и запускаем:
$xrandr --output LVDS1 --scale 1.25x1.25
(Вместо LVDS1 возможно придется указать другое значение, не знаю как его узнать кошерно, я подсмотрел в диалоге MATE: Система->Параметры->Оборудование->Экраны. У меня там картинка экрана: Ноутбук: LVDS1)
ВСЁ! Это работает на уровне системы, решение подсказали на LOR, когда я расхваливал Xfce с таким же решением в пункте меню.
Далее идем в Система->Параметры->Персональные->Запускаемые приложения и добавляем скажем: screenresize с параметрами: $xrandr --output LVDS1 --scale 1.25x1.25
Всё, теперь параметры автоматически применяются при логине этого пользователя.
Я являюсь владельцем древнего 10" нетбука который тут все рекомендуют выкинуть... Но впрочем он вполне работает, и с собой брать не так тяжело как толстую машинку....
Но всегда мучала проблема... Открываешь в Линуксовом десктопе какое нибудь модальное окно и оно больше чем 1024x600, кнопочки: «Применить», «Сохранить», «Идинафик» - находятся где то за нижней границей экрана.
Играясь с Manjaro Linux (Я его назвал Мажориком, хотя тут ходит Ник: Бомжара) я столкнулся с оконным менеджером Xfce, у которого прямо в меню настроек можно выставить масштаб 1.2 и всё стало вмещаться на УРА!
Расписал это здесь на форуме, и анонимус подсказал мне решение, ссылкой на: https://wiki.archlinux.org/title/HiDPI.
Теперь я знаю об этом рабочем решении и хочу поделиться им с другими!
- АХТУНГ, ВАХТУНГ, БАХТУНГ, ДРЯХТУНГ, АЛЯРМ, ВНИМАНИЕ
- ЭТОТ СКРИПТ ПРЕДОСТАВЛЯЕТСЯ КАК ЕСТЬ, Я НЕ НЕСУ НИКАКОЙ
- ОТВЕТСТВЕННОСТИ ЯВНОЙ ИЛИ КОСВЕННОЙ, ВАМ ЛИБО КОМУ ТО ЕЩЁ
- ПО ПРИЧИНЕ, ПОРЧИ И/ИЛИ УНИЧТОЖЕНИИ ВАШИХ ДАННЫХ
- ЕСЛИ ВЫ НЕСОГЛАСНЫ, Я ЗАПРЕЩАЮ ВАМ ЗАПУСКАТЬ ЭТОТ КОД
- ДЕЙСТВУЙТЕ НА СВОЙ СТРАХ И РИСК, ВАШИ ЛЮБЫЕ СОМНЕНИЯ
- КАСАТЕЛЬНО СКРИПТА ДОЛЖНЫ ВЕСТИ К ОТКАЗУ ОТ ЕГО ИСПОЛЬЗОВАНИЯ
Всё, теперь если у вас что-то пойдёт не так, то я чист.
И меня никто не будет ругать, гы :) Просто будте внимательный с тем,
какой каталог указывается для сохранения бекапов. А то ведь так и затереть
чего важного можно случайно.
Вопщем решил поделится прост. Пусть будет.
Простой скрипт ручного бекапа наиболее важных файлов, использует
rsync
и zip
Настройка производится внутри стрипта. Описание
настройки бекапа тоже распологается внутри скрипта.
Типичное использование это ручной запуск в конце дня или по
завершению какой либо важной работы или перед сном :)
Используйте для бекапа, отдельный диск где нет ничего кроме бекапа!
Просто иначе, в бекапе нет никакого смысла.
Лично я просто на панельку кнопочку сделал, и перед отплытием в люльку тыкаю кнопочку.
Комп я не выключаю обычно, а если выключаю до явно дожидаюсь окончания бекапа, не проверял что
будет если увести в сон во время бекапа, так что, лучше дождаться окончания.
mkdir zip rsync notify-send lua
Настроить скрипт, после чего просто его запускать. Так как вам удобно.
source
каталог или файл источникdest
каталог приёмникsecure
применить пароль (требуется zip=true
)zip
сжать в архивmirror
сделать точную копию и обновить им текущий каталог бекапа( или архив если zip=true
)versions
сделать точную копию и пометить датой в отдельном каталоге (или архиве если zip=true
)Пример поля конфигурации:
{secure=true, zip=true, versions=true, source='~/.ssh/', dest='ssh'};
Значит что нужно сделать рекурсивный бекап каталога с ключами ssh
и расположить
бекап в каталоге с именем ssh
. secure=true
означает что данные будут запаролены, а
zip
что будут сжаты, versions=true
означает что каждый новый бекап будет
создавать новую копию ~/.ssh
помеченную датой. Описание того какие есть ключи
и как они работают друг с другом есть внутри скрипта, вместе с примерами уже
готовой настройки.
Ключи можно опускать (не указывать) обязательными являются только source
и dest
Не указанные ключи считаются заданными как false
так что вот такая запись валидна
{source='~/Изображения/', dest='картинки'}
И означает сделать копию каталога ~/Изображения
в каталоге картинки
внутри общего
каталога бекапа backup_path=...
при этом если это второй или последующий бекап и в
каталоге ~/Изображения/
была удалена картинка, она не будет удалена в каталоге
картинки
это сделано специально, дабы максимизировать сохраняемые данные.
Если нужна точная копия с удалением того чего уже нет в каталоге источнике то нужно
дополнительно явно указать опцию mirror=true
это же правило работает
если включить флаг zip=true
будет всё тоже самое, но уже в виде архива.
В каталоге относительно котрого исполняется скрипт будет лог бекапа, на рабочий стол будут приходить
уведомление о текущем статусе выполнения, в случае ошибки будет показaн код возврата
В лог попадает информация о том какая именно команда потерпела неудачу, пароль присутцвующий в команде
заменяется на звёздочки. В зависимости от типа настроенного бекапа(первый бекап будет всегда долгим),
а вот последующие при отсуцтвии изменений будут быстрыми исключение это mirror
и versions
оба
создают точную копию с нуля, а не пытаются обновить текущее содержимое бекапа. В случае если любая
программа вернёт код возврата отличный от 0
выполнение всего бекапа прерывается, и повторно он не
запустится пока не будет удалён lock файл, это сделано специально, чтобы выяснить причину, исправить её
и в ручном режиме удалить lock файл название котрого есть в срипте, в логах и уведомлении на рабочий стол.:
Если вы бекапите например ~./vimrc
в dest
каталог myvimrc
то он будет там лежать как есть, с точкой.
Так что так же чтобы его увидеть в каталоге бекапа нужно нажимать ctrl+h
. Ну, я так. На всякий случай.
Удалять из бекапов лишнее, и вообще контролировать влезет ли всё, это ваша забота =)
Нет опции отключения уведомлений. Предпочитаю явно знать что всё прошло гладко.
Логи бекапа тоже руками удалять.
Дадада, пароль на zip
для ssh
и gpg
ключей хахахаха, но хоть что-то.
Сам внешний накопитель держите шифрованным если туда важное сохраняется.
Сам сриптик. Взял его как есть.
#!/usr/env lua
local backup_rule =
{
--каталог куда будут размещаться все бекапы
backup_path = '/media/$USER/STORAGE_SSD/backup';
--пароль если используется secure=true, лучше использовать файл с паролем
backup_pass = nil;
--пароль для важныйх файлов, можно записать в файл дабы не светить
backup_pass_file = "/home/$USER/Документы/backup_pass";
---------------------------------------------------------------------------
backup_list =
{
-- backup critical --
{secure=true, zip=true, versions=true, source='~/.ssh/', dest='ssh' };
{secure=true, zip=true, versions=true, source='~/.gnupg/', dest='gpg' };
{secure=true, zip=true, mirror=true, source='~/.config/', dest='cfg' };
{secure=true, zip=true, mirror=true, source='~/.mozilla/', dest='firefox'};
{secure=true, zip=true, mirror=true, source='~/Документы/',dest='doc' };
-- diffrerent media --
{secure=false,zip=true, mirror=true, source='~/Книги/', dest='book'};
{secure=false,zip=true, mirror=true, source='~/Музыка/',dest='music'};
-- backup multimedia --
{secure=false, zip=false, versions=false, source='~/FAMILY_ARCHIVE/', dest='family'};
-- backup dev stuff --
{secure=false, zip=false, versions=true, source='~/.gitconfig',dest='gitconfig'};
{secure=false, zip=false, versions=true, source='~/.vimrc', dest='vimrc'};
{secure=false, zip=false, versions=true, source='~/.bashrc', dest='bashrc'};
{secure=false, zip=true, versions=true, source='~/.vim/', dest='vim'};
-- backups source code --
{secure=false, zip=true, mirror=true, source='/mnt/STORAGE/', dest='code'};
};
};
-------------------------------------------------------------------------------
-- :secure=true - шифровать ли сжатый бекап с паролем.
-- создать архив и запаролить, zip должен быть zip=true
-- явное указание zip=false или отсуцтвие ключа создаст ошибку
-- ----------------------------------------------------------------------------
-- :secure=false - тоже самое поведение что и при zip=false
-- ----------------------------------------------------------------------------
-- :zip=true - создать архив и добавить в него файлы если их нет в архиве
-- если version=false то обновлять архив, добавляя новые
-- файлы и обновля существующие, не удаляет отсуцтвующие
-------------------------------------------------------------------------------
-- :zip=false - создавать бекап в каталоге dest если versions=false
-- то клонировать source в dest, при повторном бекапе добавлять
-- новые файлы и обновлять текущие, не удалять отсуцтвующие
-- если versions=true создавать отдельный бекап в новом
-- каталоге с датой бекапа, полностью отельный бекап.
-------------------------------------------------------------------------------
-- :versions=true - если zip=false то создать новый каталог с датой бекапа
-- если zip=true то создать новый архив с датой бекапа
-------------------------------------------------------------------------------
-- :mirror=true - если zip=true то создаётся точная сжатая копия источника
-- если при этом versions=false то текущий архив удаляет из
-- себя файлы которых больше нет в источнике
-- если zip=false то вместо архива создаётся точная копия
-- источника с удалением файлов из каталога бекапа если их
-- нет в источнике, тоже самое зеркалирование/клонирование
-------------------------------------------------------------------------------
-- :source - файл или каталог который нужно бекапить, каталоги
-- обрабатываются рекурсивно бекапя всё что есть
-------------------------------------------------------------------------------
-- :dest - каталог внутри носителя для бекапа, оно же префикс
-- добавляющийся к каталогам и/или архивам при versions=true
-- отражает то бекап чего делается ОБЯЗАН БЫТЬ УНИКАЛЬНЫМ!!!!
-------------------------------------------------------------------------------
-- Если какого либо ключа нет то он считается равным false
-------------------------------------------------------------------------------
-- В случае если zip mkdir или rsync завершаться с кодом отличным от нуля
-- бекап тут же прекращается с уведомлением на рабочий стол и в лог ошибок
-------------------------------------------------------------------------------
-------------------------------------------------------------------------------
---- исполняет все команды, в случае ошибки прерывает всю работу
-------------------------------------------------------------------------------
local function execute(rule,command,exit_if_fail)
local success, meta, code = os.execute(command..' >> backup-info.log');
if (not success) then
-- hide pass from output
-- info log and messages
if rule.backup_pass then
command = command:gsub(rule.backup_pass,"********");
end
local msg = string.format('BACKUP ERROR %s %s %s',command,meta,code);
io.stderr:write(msg..'\n');
io.open('backup-error.log','a+'):write(msg);
execute({},'notify-send "'..msg..'" -u critical',false);
if (exit_if_fail == true) then
os.exit(127);
end
return success;
end
return success;
end
-------------------------------------------------------------------------------
--- информирует об ошибке и прерывает всю работу
-------------------------------------------------------------------------------
local function backup_fail(msg)
io.stderr:write(msg..'\n');
io.open('backup-error.log','a+'):write('\n'..msg..'\n');
execute({},'notify-send -u critical "'..msg..'"',false);
os.exit(127);
end
-------------------------------------------------------------------------------
--- просто информирует
-------------------------------------------------------------------------------
local function backup_info(msg)
io.stdout:write(msg..'\n');
local log = io.open('backup-info.log','a+');
log:write('\n'..msg..'\n');
log:close();
execute({},'notify-send -u normal "'..msg..'"',false);
end
-------------------------------------------------------------------------------
--- проверяет используется ли в конфигурации пароль
-------------------------------------------------------------------------------
function check_need_pass(rule)
for name,val in pairs(rule.backup_list) do
if val.secure and val.secure == true then
return true;
end
end
return false;
end
-------------------------------------------------------------------------------
--- делает бекап K.O. :)
-------------------------------------------------------------------------------
local function make_backup(rule)
if (rule.backup_path) then
-- replaice $USER in path if we have ite
rule.backup_path = rule.backup_path:gsub('$USER',os.getenv('USER'));
else
backup_fail('BACKUP ERROR backup_path not set, no place to save backup',true);
end
-- we use password?
if (check_need_pass(rule) == true) then
-- check pass contained in configuration
if not rule.backup_pass and not rule.backup_pass_file then
backup_fail('BACKUP ERROR you use secure option but backup_pass or backup_pass_file no set!',true);
end
-- if pass_file set read the password
-- and override/write rule.backup_pass
if (rule.backup_pass_file) then
-- replaice $USER in path if we have ite
rule.backup_pass_file = rule.backup_pass_file:gsub('$USER',os.getenv('USER'));
local pass_file = io.open(rule.backup_pass_file);
if (pass_file) then
if rule.backup_pass then
backup_info('BACKUP WARNING rewrite backup_pass from backup_pass_file');
end
rule.backup_pass = pass_file:read('*l');
else
backup_fail('BACKUP ERROR '..rule.backup_pass_file..' no readable!',true);
end
pass_file:close();
end
-- maybe pass use only numbers force to string
rule.backup_pass = tostring(rule.backup_pass);
-- check small pass, no need but jut be
if not rule.backup_pass or #rule.backup_pass <= 4 then -- kek cheburek
backup_info('BACKUP WARNING you backup_pass small, less or equal 4 symbols');
end
end
-- info about starting
backup_info("BACKUP START "..os.date());
--first check, we have storage and access?
execute(rule,'mkdir -p '..rule.backup_path, true);
-- lockfile + uuid for exclude collisions
local lockfile = '.lock-938448fc-1742-43e9-bff8-e2acf6d29710';
-- check/create lock file
-- if backup failed you self
-- delete lock file your hands
if not io.open(rule.backup_path..'/'..lockfile,'r') then
io.open(rule.backup_path..'/'..lockfile,'w'):write('lock');
else
backup_fail("OTHER BACKUP PROCESS IS WORKING, SKIPPING THIS PROCESS\n"..
"IF YOU SURE DELETE LOCK FILE "..rule.backup_path..'/'..lockfile..'\n',true);
----------------------------------------------------------------------
-- uncomment if after backup error no need locked backup for fix error
----------------------------------------------------------------------
-- os.remove(rule.backup_path..'/'..lockfile);
end
for id,item in pairs(rule.backup_list) do
local date = os.date("%Y-%m-%d_%X");
local path = rule.backup_path;
local pass = rule.backup_pass;
local dest = item.dest;
local source = item.source;
if (not source) then
backup_fail('BACKUP ERROR source path not set, what files backup?',true)
end
if (not dest) then
backup_fail('BACKUP ERROR dest path not set, wheare dir name to save?',true)
end
execute(rule,'mkdir -p '..path..'/'..dest,true);
backup_info('BACKUP: '..source);
------------------- secure: versionize backup data ---------------------
------------------------------------------------------------------------
if (item.secure and item.zip and item.versions) then
local target = string.format('%s/%s/%s-%s.zip',path,dest,dest,date);
execute(rule,'zip -r9P '..pass..' '..target..' '..source,true);
goto next_item;
end
---------------- secure: update and append backup data -----------------
------------------------------------------------------------------------
if (item.secure and item.zip and not item.versions) then
local target = string.format('%s/%s/%s.zip',path,dest,dest);
local opts = item.mirror and ' -rFS9P ' or ' -ru9P ';
execute(rule,'zip '..opts..' '..pass..' '..target..' '..source,true);
goto next_item;
end
----------- no secure: zipped update and append backup data ------------
------------------------------------------------------------------------
if (not item.secure and item.zip and not item.versions) then
local target = string.format('%s/%s/%s.zip',path,dest,dest);
local opts = item.mirror and ' -rFS9 ' or ' -ru9 ';
execute(rule,'zip '..opts..' '..target..' '..source,true);
goto next_item;
end
----- no secure: zipped, versionize update and append backup data ------
------------------------------------------------------------------------
if (not item.secure and item.zip and item.versions ) then
local target = string.format('%s/%s/%s-%s.zip',path,dest,dest,date);
execute(rule,'zip -r9 '..target..' '..source,true);
goto next_item;
end
--------- no secure: versionize update and append, no delete -----------
------------------------------------------------------------------------
if (not item.secure and not item.zip and item.versions ) then
local target = string.format('%s/%s/%s-%s/',path,dest,dest,date);
execute(rule,'mkdir -p '..target);
execute(rule,'rsync -arv '..source..' '..target,true);
goto next_item;
end
----------------- no secure: update and append, no delete --------------
------------------------------------------------------------------------
if (not item.secure and not item.zip and not item.versions) then
local target = string.format('%s/%s/',path,dest);
execute(rule,'mkdir -p '..target);
local opts = item.mirror and ' -arv --delete ' or ' -arv ';
execute(rule,'rsync '..opts..' '..source..' '..target,true);
goto next_item;
end
------------------------------------------------------------------------
if (item.secure and not item.zip) then
backup_fail('BACKUP ERROR UNSUPPORT SECURE WITCHOUT ZIP ARCHIVE :(');
end
::next_item::
end
backup_info("BACKUP END "..os.date());
os.remove(rule.backup_path..'/'..lockfile);
end
-- check depends
execute({},"zip --version",true);
execute({},"rsync --version",true);
--execute({},"mkdir --version",true);
execute({},"notify-send --version",true);
-- start backup now
make_backup(backup_rule)
Всё. Досвиданья.
Давайте я вам поясню про язык Go, откуда у него растут корни, и почему его на самом деле не стоит использовать. То что напишу ниже, это взято как из инсайдерской информации, так и из материалов, доступных в интернетах.
Дело в том, что Go это, на самом деле, «решение» внутренних гугловских проблем. Но отнюдь не проблем горизонтального масштабирования серверного ПО, как многие почему-то думают. Он приспособлен специально для использования в гугле вот в каком контексте.
Гугл нанимает большое количество тупых студентов, только-только после вуза или ПТУ, и заставлять их писать хоть какой-то простой код. И делать минимум ошибок, при этом. Для этого Go сделан таким тупым и упрощенным. И выкинут в паблик он только для того, чтобы вероятность, что у такого студента, только пришедшего в гугл, было хоть какое-то знание Go, была выше нуля.
Но дело вот в чем. В гугле, на самом деле, над каждой командой гошников стоит тимлид, или целая группа, который/которая вот этим взаимозаменяемым роботам-гошникам расписывает всю систему, чуть ли не вплоть до состояния конечного автомата, до if-ов, и показывает куда и что писать. Поэтому же Go на корню режет всю креативность, поэтому там нет практически никаких средств абстракции, и поэтому он не дает делать вообще ничего сложного. Дабы программисты на нем вообще ничего лишнего не думали, а кодировали все чуть ли не побуквенно по указаниям умных людей.
Из гугла же идет маразматическая система управления зависимостями Го, которая заточена на монорепы.
Тут возникает вопрос - а почему этому тимлиду не дать в руки кодогенератор, вместо всей этой accidental complexity, возникающей из-за огромного количества строк кода, и из-за затрат на коммуникацию?
А тут надо понимать, как внутри устроены огромные корпорации типа гугла.
Их давно пожрал рак бюрократии. Там у менеджерских и околоменеджерских должностей один из главных критериев промоушнов, или вообще даже ассесмента(усидения на должности), это количество людей у тебя в подчинении. И количество говнокода в вакууме которая твоя команда написала. И вот все эти люди, сидящие на более-менее средне-высоких должностях, постоянно бодаются за эти промоушны и ассесменты. Это их главная и единственная цель. Поэтому, ни о какой эффективности тут речи не идет вообще от слова совсем. Тут главное - корпоративные игры, количество голов в твоем стаде и количество и размер высеров, которые это твое стадо произвело(причем буквально, важны SLOC).
Естественно, это все отражается на качестве продуктов, и это видно как по полному прекращению инноваций в гугле, так и по постоянно мелькающим и закрывающимся высерам этой компании - hangouts, duo, google plus, google wave, и прочее и прочее, можете еще вспомнить много чего.
Если у вас в компании такой «модели управления» нет, и более того, у вас нет возможности нанимать крайне высококвалифицированных людей за крайне много денег, единственное назначение которых будет расписывать стаду гошников(которые тоже стоят немало денег просто из-за количества) систему до уровня конечного автомата, то вам этот язык и вся его экосистема нахрен не сдалась.
Никакой мифической простоты в отладке и в понимании кода Go не приносит. Да и сложность программных систем растет совершенно не из-за понятности/непонятности какой-то отдельной взятой строчки кода или функции. Потому, что, во-первых, понятность это понятие субъективное, во-вторых потому, что, отдельно взятая фунцкия на 5 строк понятна любому опытному программисту, будь она написана хоть на Rust, хоть на Common Lisp.
Сложность программных систем возникает из-за их размера. И Go эту проблему значительно ухудшает. Человек не может удерживать в голове слишком много вещей, даже если каждая отдельная вещь - очень простая. Количество RAM в голове ограничено.
В случае если вы не хотите выкидывать кучу денег просто так, и скорее предпочли бы нанять немного, но более-менее опытных программистов, Go будет только вреден, потому что все вменяемые люди от него, на самом деле, плюются. Он реально отталкивает опытных людей, которые способны понять сложные требования и написать, и поддерживать, более-менее сложные системы уровнем хотя бы нескольких сервисов плюс БД и MQ.
Закрыл фаерфокс. Как обычно — с сохранением сессии. 4 окна, каждое — с кучей вкладок. Попробовал запустить — не вышло, закрывается с ошибкой. Попробовал другой профиль — запустилось нормально. Попробовал Safe Mode — предложило почистить профиль или просто запустить без плагинов. Выбрал второе — снова упало. Повторил Safe Mode, почистил профиль, запустил сохранённые вкладки — опять упало.
Проапдейтил фаерфокс со 102 до 115. Запустил — пишет «Нам не удалось восстановить вашу последнюю сессию. Выберите «Восстановить сессию», чтобы попробовать снова.»
Кнопка «Восстановить сессию» неактивна, список «Предыдущие вкладки» пуст, в меню «Журнал» тоже ничего интересного: «Восстановить предыдущую сессию» и «Недавно закрытые окна» серые, в «Недавно закрытые вкладки» — только вкладки о новшествах в новой версии Фаерфокса.
Как восстановить вкладки?
Ответ: https://support.mozilla.org/ru/kb/kak-vosstanovit-sessiyu-prosmotra-iz-rezervnoj-kop
В моём случае помогло по-быстрому скопировать все файлы из ~/.mozilla/firefox/<имя профиля>/sessionstore-backups/
а затем перед запуском Фаерфокса заменить ~/.mozilla/firefox/<имя профиля>/sessionstore.jsonlz4
на самый большой из них. Там было 2 одинаковых файла: previous.jsonlz4 и upgrade.jsonlz4-20230916112848. Возможно, 2-й сохранился потому, что я закрывал браузер по Ctrl-c в терминале.
Собственно, сабж. Статья про то самое, что мы с Eddy_Em не могли осилить в прежние времена. В этом году я это, внезапно, осилил. Ну и написал статью.
Посчитать количество дней рождений за период. PHP
Я с изумлением не вижу простого решения.
Переберать весь период в цикле?
Считать количество лет. Приводить к одному году и добовля или не добавлять единицу?
Спасибо.
Сабж: Linux не для идиотов
Очень хочется почитать, а ссылки не работают. Может у кого осталась копия?
Последние месяца три мой ляптоп периодически издает кошмарные звуки из ада во время проигрывания аудио: сэмпл. Чтобы воспроизвести достаточно либо нагрузить CPU, либо поскроллить видео туда-сюда. Воспроизводится в mpv, в firefox, в cmus. Воспроизводится и через pipewire, и через чистую ALSA с выключенным pipewire. В dmesg ничего нет. В pw-top задержки в пределах нормы. Симптомы убираются если поставить видео на паузу и подождать пока буфер pipewire обнулится (с ALSA тоже помогает, понятное дело, но с pipewire проще мониторить что происходит).
Кто-нибудь сталкивался?
Причастные:
Вывод lspci:
$ doas lspci -vvvks 00:1f.3
00:1f.3 Multimedia audio controller: Intel Corporation Alder Lake PCH-P High Definition Audio Controller (rev 01)
Subsystem: Huawei Technologies Co., Ltd. Alder Lake PCH-P High Definition Audio Controller
Control: I/O- Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR- FastB2B- DisINTx+
Status: Cap+ 66MHz- UDF- FastB2B- ParErr- DEVSEL=fast >TAbort- <TAbort- <MAbort- >SERR- <PERR- INTx-
Latency: 32, Cache Line Size: 64 bytes
Interrupt: pin A routed to IRQ 199
IOMMU group: 15
Region 0: Memory at 601d1b8000 (64-bit, non-prefetchable) [size=16K]
Region 4: Memory at 601d000000 (64-bit, non-prefetchable) [size=1M]
Capabilities: [50] Power Management version 3
Flags: PMEClk- DSI- D1- D2- AuxCurrent=55mA PME(D0-,D1-,D2-,D3hot+,D3cold+)
Status: D3 NoSoftRst+ PME-Enable+ DSel=0 DScale=0 PME-
Capabilities: [80] Vendor Specific Information: Len=14 <?>
Capabilities: [60] MSI: Enable+ Count=1/1 Maskable- 64bit+
Address: 00000000fee00bf8 Data: 0000
Kernel driver in use: sof-audio-pci-intel-tgl
Kernel modules: snd_hda_intel, snd_sof_pci_intel_tgl
Выключал энергосбережение, не помогает:
$ echo 0 | doas tee /sys/module/snd_hda_intel/parameters/power_save
$ echo N | doas tee /sys/module/snd_hda_intel/parameters/power_save_controller
Девушка прислала видео, спросить что это. Извеняюсь за оффтоп, но линукс тут при том что здесь сидят самые отьявленные спецы в области всего на свете. Интересно ваше мнение. Что на видео. Видео не мое, вообще без понятия чье оно. Мое мнение - это молния чтоли шаровая маленькая ? https://vk.com/clip650811733_456239723
Что же, пора окончательно закрыть этот вопрос. По этому поводу уже написано множество статей и заметок, пусть будет ещё одна.
( читать дальше... )
Надеюсь, что моя заметка будет полезна всем начинающим пользователям этого прекрасного(или ужасного?) текстового редактора.
Статья о создании процессов в Linux
( читать дальше... )
Постоянно писать «как делать правильный код» надоедает. Поэтому для разнообразия и развлечения написал мини-книгу «60 антипаттернов для С++ программиста». Этакие вредные советы в духе «Книга для непослушных детей и их родителей».
На самом деле там, не только вредные советы, но и разбор почему они собственно вредны. Будет полезно почитать новичкам в программировании. Думаю, каждый знает кого-то, кому будет полезно почитать этот материал :). Впрочем, опытные программисты тоже смогут найти интересное для себя и узнать/освежить знания про некоторых тонкие моменты C++.
Там много букв. Приглашаю запастись кофе/энергетиком и приступать. Буду рад обсуждениям и дополнениям, основанном на вашем опыте.
Ещё я этот текст переработал для бумажного издания. Оно в подготовке для печати. Смысл там в целом тот же, но пришлось многое переделать или расписать подробнее. Ведь нельзя в бумажной книге дать 100500 ссылок на сторонние ресурсы «читать здесь про xxx подробнее». Надеюсь, успеем напечатать к осенним конференциям и будем раздавать на стенде, например по кодовым словам. Приходите на стенд и говорите, что с linux.org.ru и что там на тему бумажной книги :)
Парочка вредных советов для примера:
P.S. PDF, если кому-то так удобнее.
Сейчас я вам расскажу интересную уловку, которая очень часто встречается у работодателей. Намного чаще на фрилансе и чуть-чуть реже в реале
шапка топика: Требуется сделать хх. В теле сообщение текст того, что надо сделать и обязательно присутствует фраза «нормальный специалист сделает это за два дня»
Как всё происходит с таким заказчиком: если у вас нет опыта, то вы начинаете делать задачу. Делаете ее неделю. Полторы. Много общения с заказчиком. Заказчик подгоняет. Вы нервничаете. Но знаете, что возможно, вы затянули сроки по незнанию предметной области. В конечном итоге вы можете месяц это делать и в конечном итоге сделаете за месяц. Заказчик с вами расчитается по оглашенному в условиях работы прайсу т.е два дня
Далее, когда у вас уже будет опыт и вы возьметесь за такую же работу, то сделаете ее за 1.5 недели. Заказчик платить за 1.5 недели не будет. Слышать какие-то вменяемые аргументы он не будет. Заплатит за 2 дня
Далее, когда у вас уже будет опыт - вы перед работой попытаетесь донести до заказчика то, что это делается не два дня, а 1.5 недели. Заказчик аргументы слушать не будет, пойдет искать того, кто сделает это за 2 дня или будет готов это сделать за 2 дня оплаты
Заказчики хитровыделанные товарищи. То, что они говорят вам и то, что они реально думают - не всегда совпадает. Они могут прекрасно знать, что это не делается за два дня, но если специалист сделает за 1.5 недели или даже за месяц, но он ему заплатит за 2 дня - то это…это же ПРЕКРАСНО!!!
Достаточно популярная уловка. Завуалированный первый вариант. Вы договариваетесь с заказчиком. Полностью оговариваете то, что вы будете делать. Пошагово. Каждый день делаете отчеты. Заказчик вам ничего на это не говорит. Работа же движется! Когда приходит день зарплаты, то заказчик начинает говорить: у нас есть задачи, которые не закрыты. Вы начинаете говорить: ну так для того, чтобы сделать эту задачу, надо выполнить предварительные работы. Заказчик все такие аргументы игнорирует. В конечном итоге предлагает вам закрыть все ключевые конечные задачи и после этого вам заплатят зарплату. Но строго за отработанную неделю
Пример: прихожу я в одну микрокредитную организацию. Договариваемся, что первый месяц анализ проекта и зарплата 50%, потом зарплата 100% и расширяем функционал проекта. Проект писал школьник(реально школьник) несколько лет. Школьник ушел в армию. И они ищут человека, который приведет в порядок проект и расширит функционал
Обсуждаем пул задач. Согласовываем. Заказчик соглашается на пул задач. Пул задач на первый месяц:
Работаю месяц: закрыл 2 пункта, все доп. таски видел заказчик. Всё всех устраивало. Получаю зп 50%. Работаем дальше
Второй месяц: начинаю править в коде дебильные вещи, типа «одинаковые названия классов и функций в разных скриптах, которые подтягивают вьюшки» и прочее. Всё это протекает, естественно медленно т.к требует тестирования. Работаю с этим две недели. Пошла третья. Заказчика всё устраивает. В конце третьей недели я интересуюсь «а когда будет аванс за 2 недели?». И тут начинается замечательная история
История такая: заказчик спрашивает «а когда мы закроем сабжевый список тасок?». Имеется ввиду расширение функционала. Я ему: когда выполним третий пункт. Он: это всё очень долго происходит. Скажите время, когда вы закончите третий пункт. Я: в районе 1-2 недели. Заказчик: это очень долго. По моему опыту, нормальному специалисту на это надо 2 недели. Я: две недели? Заказчик: да, на ВСЕ ТРИ ПУНКТА. Вы же делаете это второй месяц. Я вам предлагаю такой вариант: сейчас я вам формирую список задач, который нам нужно выполнить. Вы их закрываете и получаете зарплату. Эти задачи, по моему мнению, специалист выполнит за 2-2.5 недели. Мы вам готовы заплатить за 3 недели. Я: хорошо, а с отработанными тремя неделями что будем делать? Заказчик: мы готовы платить за закрытые задачи. Я: я выполнял предварительные работы. Всё в коммитах. Заказчик: мы коммиты смотреть не будем. Мы видим, что вы затянули время и делали 1.5 месяца то, что делается 2 недели. Сейчас я сформирую список задач. Я: формируйте! Про себя ржу. Вот это поворот событий!
Заказчик формирует список задач(к уже имеющимся конечным таскам). И там работы месяца на 2-3
Я: тут работы на 2-3 месяца. Заказчик: нормальный специалист сделает это за 2-2.5 недели
Такая уловка(шантаж невыплаченной зарплатой) очень частая история. В разных вариантах развития событий. Но суть одна и та же
Коллеги, не давайте хитровыделанным товарищам на вас кататься! На фрилансе строго по предоплате. Нет? Гуляй, Вася. В реале бороться сложней. Самым лучшим решением - это офиц. трудоустройство на полностью белую зп. Если зп серая - вам ее и выдадут по уходу. Все остальные варианты - исключительно силовые. Набить кепку - забрать шекели
Дополнено1:
в комментариях есть мнение, что оценка сроков у заказчика неправильная по «незнанию предметной области». Я отвечу, что по результирующей неважно, по какой причине оценка неправильная: сознательно или по не знанию. Результирующая такая: заказчик заплатит строго по тем срокам, которые он огласил. Еще не видел, когда человеку объясняешь с фактами, почему это не делается 2 дня, а он соглашается и вы начинаете работать. Обычно такой человек пишет: «спасибо, я попробую поискать другого исполнителя» или подобное. Всё время на объяснение(которое бывает и несколько часов) - естественно никто не оплачивает
Дополнено2:
чтобы вы понимали, насколько такие уловки выгодны, я включу обычные математический расчеты уровня четвертого класса. Берем стандартный рейт $20, который является средним по СНГ среди мидл-сеньор.
Вариант1: платят за два дня, что делается по факту 1 месяц. Считаем: 6 часов в день на * 5 рабочих дня * 4 недели = 120 рабочих часов. Работаем 120 часов, платят за 12 часов. Сколько у нас оплата в час получается? Правильно, 12 * 20 = $240. 240/120 = $2 в час. Или 160 рублей в час или 21120 рублей в месяц :)
Вариант2: платят за два дня, что делается по факту 1.5 недели. Считаем: 6 часов в день на * 8 рабочих дня 48 рабочих часов. Работаем 48 часов, платят за 12 часов. Сколько у нас оплата в час получается? Правильно, 12 * 20 = $240. 240/48 = $5 в час. Или 400 рублей в час или 52 800 рублей в месяц :)
Ты такой серьезный программист, много чего знаешь. А по факту тебя заимели( поимели в 1337 порт :) ) по 160р или за 400р в час. А можешь и вообще бесплатно отработать(если не согласился на шантаж зп)
Дополнено3:
Очень частая уловка у заказчиков, у которых уже есть проект: вам дают ТЗ, что в проекте нужно сделать. Оцените так сказать. Вы оцениваете. Заказчик соглашается. И тут есть один очень интересный нюанс, который выглядит следующим образом:
Вы: сделать это - 2-3 дня, но чтобы это сделать - надо разобраться с проектом
Заказчик: а сколько на это нужно?
Вы: в районе 1-2 недели. Не знаю, как у вас проект написан. Может и меньше, может и больше. Но, обычно, в районе этого времени
Заказчик: я готов платить за выполненное ТЗ
Для тех, кто не понял, заказчик готов платить за доработку проекта, но не готов вам платить за время, которое будет потрачено на «вникнуть в проект», чтобы потом выполнить ТЗ
Считаем:
затрачено времени:
Ничего так потеря денег и времени. Согласны? Я более чем уверен, что после того, как этот человек найдет того, кто закроет ему ТЗ, он с чистой совестью пойдет и купит себе новый телефон. Или как-то по-другому, но строго с пользой для себя потратит сэкономленные деньги. А всё потому, что айтишник, по мнению заказчиков - это лошпидрон. Которого можно обхитрить и вместо 67т.р заплатить 19т.р т.е грубо говоря нанять по цене продавца в продуктовом магазине. И ему пофиг, сколько вы времени потратили в жизни на то, чтобы во всём этом IT разобраться и сколько вы тратите на актуализацию своих знаний
← предыдущие | следующие → |