OpenWRT на Vodafone EasyBox 803

Read the rest of this article

Winamp hotkeys Ctrl+Alt+PgDown/PgUp plugin

Форк Winamp multimedia keyboard plugin, добавил поддержку клавиш Ctrl+Alt+PgDown (следующая песня) и Ctrl+Alt+PgUp (WM_HOTKEY)

Скачать: gen_mmkb.dll.cab

Сырцы:

github/winamp_kbd_plugin

copy& и std::move&&

Базовый код с запретом копирования и присваивания

Если вы пока точно не знаете, как будет использоваться класс, лучше всего просто запретить копирование и присваивание. По умолчанию они разрешены и просто копируют все атрибуты класса. Часто это не то, чего вы хотите. Например, тупо копировать какие-то указатели, файловые дескрипторы или мьютексы, являющиеся атрибутами класса, явно плохая идея. Простейший код, в котором копирование и присваивание класса явно запрещены:

Вывод программы:

Пока что никаких неожиданностей. Стоит отметить, что вместо:

… можно написать:

… тем самым явно указав на то, что вас устраивают реализации по умолчанию.

Copy constructor

Объявим copy contructor:

Заметьте, что в нем мы имеем доступ к private полям второго экземпляра класса (obj), несмотря на то, что это другой экземпляр. Вывод программы:

Оба синтаксиса эквивалентны, в обоих случаях был вызван copy constructor. Конструктор для каждого объекта был вызван один раз. Можно было и не писать этот код, так как реализация copy constructor по умолчанию и так просто копирует атрибуты класса.

Copy assignment

Объявим copy assignment оператор:

Вывод:

Coord2D(x = 1, y = 2) created
Coord2D(x = 1, y = 2) copied
Coord2D(x = 1, y = 2) copied
Coord2D(x = 1, y = 2) copy-assigned
Hi!
Coord2D(x = 1, y = 2) destroyed
Coord2D(x = 1, y = 2) destroyed
Coord2D(x = 1, y = 2) destroyed

Заметьте, что деструктор при присвоении не вызывается. Это означает, что в реализации copy assignment следует освобождать старые ресурсы перед присвоением новых значений.

Move constructor

Перепишем код следующим образом:

Вывод:

Coord2D(x = 1, y = 2) created
id called
Coord2D(x = 1, y = 2) copied
Coord2D(x = 1, y = 2) destroyed
Hi!
Coord2D(x = -1, y = 2) destroyed

Как видите, мы создаем копию из временного объекта, после чего он сразу уничтожается. Для нас это не проблема, так как объект маленький. Но если бы он содержал в себе большие объемы данных, мы бы создали их полную копию, а затем одну из копий освободили бы. Для решения этой проблемы придумали move constructor:

Вывод:

Coord2D(x = 1, y = 2) created
id called
Coord2D(x = 1, y = 2) moved
Coord2D(x = 1, y = 2) destroyed
Hi!
Coord2D(x = -1, y = 2) destroyed

Move constructor вызывается вместо copy constructor в случае, когда объект, из которого создается копия, вот-вот будет уничтожен. В таком конструкторе обычно данные из временного объекта переносятся в новый объект, а полям временного объекта присваиваются nullptr или что-то такое. Важно понимать, что при выходе из move constructor оба объекта должны оставаться валидными и для обоих должен корректно отрабатывать деструктор. Ссылка T&& называется rvalue reference и означает ссылку на объект, который вот-вот будет уничтожен.

Move assignment

Аналогично move constructor, только для присваивания. Например, код:

… выведет:

Coord2D(x = 1, y = 2) created
Coord2D(x = 4, y = 5) created
Coord2D(x = 4, y = 5) copy-assigned
Coord2D(x = 4, y = 5) destroyed
Hi!
Coord2D(x = 4, y = 5) destroyed

Объявим move assignment оператор:

Вывод:

Coord2D(x = 1, y = 2) created
Coord2D(x = 4, y = 5) created
Coord2D(x = 4, y = 5) move-assigned
Coord2D(x = 4, y = 5) destroyed
Hi!
Coord2D(x = 4, y = 5) destroyed

Move assignment оператор позволяет применить те же оптимизации, что и move constructor. В move constructor поля объекта, переданного в качестве аргумента, обычно как-то зануляются. В move assignment лучше сделать swap полей в двух объектах. Это позволит избавиться от дублирования кода между оператором move assignment и деструктором.

std::move

Move constructor бывает трудно стриггерить. Например, код:

… выведет:

Coord2D(x = 1, y = 2) created
Coord2D(x = 5, y = 2) copied
Coord2D(x = 5, y = 2) destroyed
Hi!
Coord2D(x = 5, y = 2) destroyed

Так происходит, потому что метод setX возвращает lvalue reference, а у move constructor на входе совершенно другой тип, rvalue reference. Чтобы явно показать, что временный объект мы больше использовать не будем, предусмотрен std:move. Если переписать код так:

… программа выведет:

Coord2D(x = 1, y = 2) created
Coord2D(x = 5, y = 2) moved
Coord2D(x = 5, y = 2) destroyed
Hi!
Coord2D(x = 5, y = 2) destroyed

В сущности, std::move просто кастует lvalue reference (T&) в rvalue reference (T&&), больше ничего. При чтении кода std::move как бы говорит нам, что мы отдаем владение объектом в этом месте и далее не собираемся его использовать.

std::forward

Шаблон std::forward предназначен исключительно для написания шаблонных методов, способных принимать на вход как lvalue, так и rvalue, в зависимости от того, что передал пользователь, и передавать соответствующий тип далее без изменений. Техника получила название perfect forwarding.

Рассмотрим пример. Определим оператор сложения двух координат:

Вывод:

Coord2D(x = 1, y = 1) created
Coord2D(x = 1, y = 2) created
Coord2D(x = 1, y = 3) created
Creating Coord2D t…
Coord2D(x = 1, y = 1) copied
Coord2D t created!
Coord2D(x = 2, y = 3) copied
Coord2D(x = 2, y = 3) destroyed
Creating Coord2D t…
Coord2D(x = 2, y = 3) moved
Coord2D t created!
[…]

Смотрите, что происходит. При первом вызове оператора сложения переменная t инициализируется при помощи copy constructor, так как c1 не является временным объектом. Однако при втором вызове первым аргументом передается временный объект c1 + c2, и из него переменная t инициализируется уже при помощи move constructor. То есть, фактически std::forward позволил написать процедуру один раз, вместо того, чтобы писать две версии — одну, принимающую первым аргументом lvalue reference, и вторую, работающую с rvalue reference.

Заключение

Заметьте, что думать про всякие move semantics и perfect forwarding нужно только при работе с объектами, держащими в себе много данных, и только если вы часто копируете или присваиваете такие объекты. Это исключительно оптимизация, и без нее все будет совершенно корректно работать (более того, ничего этого не существовало до появления C++11). Пока профайлер не говорит вам, что вы во что-то такое не уперлись, возможно, не стоит заморачиваться. Помните также, что компилятор зачастую может избавляться от лишнего копирования объектов, см return value optimization (RVO) и copy elision.

С другой стороны, теорию понимать стоит независимо от того, упирается ваш код в копирование и перемещение объектов, или нет. Как минимум, move semantics и иже с ним может использоваться в чужом коде. В частности, он используется в STL, см например метод emplace_back класса std::vector или метод emplace класса std::map. Кроме того, понимание move semantics будет весьма нелишним при использовании умных указателей.

Дополнительные материалы:

Александр Алексеев (“R2AUK”) eax.me/cpp-copying-and-moving

Установка Linux KVM и гостевой ОС

KVM (Kernel-based Virtual Machine) – Linux-решение, которое обеспечивает виртуализацию x86-платформы, поддерживающей Intel VT (Virtualization Technology) или AMD SVM (Secure Virtual Machine).
Разрабатывается компанией Red Hat.
Чтобы проверить, поддерживает ли ваша платформа VT или SVM – дайте команду

Если вывод команды не пустой, значит поддерживает.
Устанавливаем KVM:

Создаем мост – в файл /etc/sysctl.conf добавляем строки:

и даем команду sysctl -p
Для моста в файл /etc/network/interfaces добавляем новый сетевой интерфейс, например kvmbr0 – в результате файл interfaces получился приблизительно таким:

Перезагрузим сеть:

Теперь вывод brctl show должен показать примерно следующее:
kvmbr0 8000.f46d04976c46 no eth0
У меня все будет в домашнем каталоге /home/sborka
Скачиваем (или передаем между компьютерами через scp/nc) в домашний каталог iso-образ (дистрибутив) той операционной системы, которая впоследствии будет гостевой.
Создаем файл-диск виртуальной системы (здесь 10 Гб):
dd if=/dev/zero of=/home/sborka/vmwindows.img bs=1024k count=10000

При запуске следующей команды может появиться сообщение:
Unable to connect to graphical console: virt-viewer not installed. Please install the ‘virt-viewer’ package. – не обращайте на него внимания.
Сама команда – установка гостевой ОС:

(“–os-type=linux –os-variant=generic26” для линуксов)
где:
-r 1024 – количество памяти выделяемой под виртуальную машину (в мегабайтах)
–vnc – включаем VNC (будет слушать на localhost:5900, позже сделаем SSH-туннель)
-w bridge:kvmbr0 – подключаем к сети на интерфейс kvmbr0
Как я предупреждал ранее, если после запуска этой команды не появилось никаких ошибок, а отобразилось что-то вида:
Starting install…
Creating domain… 0 B 00:01
Unable to connect to graphical console: virt-viewer not installed. Please install the ‘virt-viewer’ package.
Domain installation still in progress. You can reconnect to the console to complete the installation process.

то все отлично, виртуальная машина запустилась (можно проверить командой virsh -c qemu:///system list –all)
Теперь с любого компьютера пробрасываем SSH-туннель:

и remmina на localhost:5900
или
Устанавливаем (если в самом начале не установили, а настраивали сервер локально) ssh-клиент, или, например, kitty. Запускаем, настраиваем:
Во вкладке Session — Host Name (or IP address) адрес нашего хост-сервера (в моем случае 172.16.4.24).
Во вкладке Windows-Translation — выбираем UTF-8.
Во вкладке Connection-SSH-Tunnels — заполняем поля Source port 59000, Destination localhost:5900, нажимаем Add.

Жмем Open и мы должны подключиться по SSH к хост-серверу. Одновременно у нас произойдет перенаправление порта 5900 хост-сервера (порт vnc-сервера) на наш локальный порт 59000.
Если у вас появляется ошибка: “qemu: could not open disk image … : Permission denied”, скопируйте .img/.iso файлы в /var/lib/libvirt/images, чтобы SELinux “не был против”

Администрирование виртуальных машин:
Для начала запускаем консоль управления

и уже в ней:
list –all -посмотреть все виртуальные машины
destroy имя виртуальной машины – жесткое выключение виртуальной машины
undefine имя виртуальной машины – удалить виртуальную машину(не забываем потом удалить файл виртуальной машины, конечно если она больше не нужна)
start имя виртуальной машины – запустить виртуальную машину
autostart имя виртуальной машины – автозагрузка виртуальной машины
autostart –disable имя виртуальной машины – выключить автозагрузку виртуальной машины

P.S. gui для KVM – virt-manager

Установка DB2 под Linux

В качестве ОС была выбрана Ubuntu Server. Базу данных запланировал разместить на /home и поэтому выделил под этот раздел большую часть диска.
Для начала заполним sysctl. Я выделил для сервера 8 Гб озу, соответственно

MemTotal: 8178400 kB – в shmmax записал цифру 8000000000
Также использовал формулу shmall = shmmax * 0,9 / 4096 и взял данные из документации IBM DB2 Express-C 10.1
В /etc/sysctl.conf внес следующие строки:

далее команда sysctl -p
Устанавливаем зависимости:

apt-get install alien binutils build-essential cpp-4.4 debhelper g++-4.4 gawk gcc-4.4 gcc-4.4-base gettext html2text ia32-libs intltool-debian ksh lesstif2 lib32bz2-dev lib32z1-dev libaio-dev libaio1 libbeecrypt7 libc6 libc6-dev libc6-dev-i386 libdb4.8 libelf-dev libelf1 libltdl-dev libltdl7 libmotif4 libodbcinstq4-1 libodbcinstq4-1:i386 libqt4-core libqt4-gui libsqlite3-0 libstdc++5 libstdc++6 libstdc++6-4.4-dev lsb lsb-core lsb-cxx lsb-desktop lsb-graphics lsb-qt4 make odbcinst openjdk-6-jdk pax po-debconf rpm rpm-common sysstat tzdata-java unixodbc unixodbc-dev unzip

Как уже упоминал выше, в моем случае Ubuntu без менеджера окон, а установщик DB2 использует GUI.
Многим здесь ничего не мешает установить lubuntu-core, xinit и запустив иксы через startx произвести инсталляцию DB2 (../expc/db2setup)
Я же проброшу дисплей на свой рабочий линукс – вношу в /etc/ssh/ssh_config строки:

и подключаюсь к серверу добавив параметры -XY к ssh:

Теперь весь вывод иксов с сервера пойдет на мой рабочий стол (xauth).
Распаковываем db2_v101_linuxx64_expc.tar.gz и даем команду
./expc/db2setup
Во время установки я указал такие данные:

Пользователь Логин Группа Пароль Расположение
Администратор сервера dasusr1 dasadm1 dasusr1 /home/dasusr1
Владелец экземпляра db2inst1 db2iadm1 db2inst1 /home/db2inst1
Изолированный db2fenc1 db2fadm1 db2fenc1 /home/db2fenc1

При выборочной установке также убрал русский язык – установщик не мог найти файл русских сообщений.
Затем поправил шеллы вновь созданных пользователей в /etc/passwd с sh на bash:

Далее конфигурируем DB2 для работы с 1С. Заходим под пользователем db2inst1: su db2inst1
и даем команду db2set DB2_WORKLOAD=1C
Возвращаемся в root через Ctrl-D (logout).
Добавляем в /etc/services строку:

Настраиваем автозапуск сервера – создаем файл /etc/init.d/db2autostart

Затем выполняем update-rc.d db2autostart defaults и ./db2iauto -on db2inst1 (из /opt/ibm/db2/V10.1/bin)
Отправляем сервер на перезагрузку и пробуем создать базу – например, db_name в 1C (пользователь и пароль db2inst1).
Чтобы 1C не ругалась, что не хватает памяти, на сервере от имени db2inst1 выполняем комаанды:

При переключении языка по Ctrl+Shift не работают комбинации Ctrl+Shift+[key]

При настройке переключения раскладок по Ctrl+Shift, горячие клавиши вида Ctrl+Shift+[key] отказываются работать.
Для исправления этой проблемы необходимо установить патч (переключение языка после применения патча срабатывает не на нажатие, а на отпускание клавиш Ctrl+Shift).
Делаем все из под рута.
Создадим папку под исходные коды и будущие deb-файлы:

Получаем исходники:

Устанавливаем пакеты, необходимые для сборки:

Теперь перейдем в папку debian/patches
Сохраняем сюда файл патча, например, под именем x1_7_7p
Затем добавляем его в список:

Переходим в папку повыше:

(выход Ctrl+X)
И собираем все командой

Затем переходим в папку с собранными deb-ами и устанавливаем их:

Перезагружаемся.

LoadString (BCB Builder)

Прозрачный прокси перед Squid

На маршрутизаторе (Debian 6 Squeeze, ip1 10.2.16.181, ip2 192.168.56.1) с двумя сетевыми адаптерами необходимо предоставить интернет клиентской сети 192.168.56.0/24 как NAT (получаемый через шлюз по умолчанию). Сам маршрутизатор получает интернет от Squid (HTTP – IP 10.80.20.22, порт 3128, DNS – 10.10.110.10). В общем, необходимо выступить в роли прозрачного прокси для клиентской подсети 192.168.56.0/24.
Первым делом устанавливаем Squid 3, конфиг (/etc/squid3/squid.conf) такой:

Включаем форвардинг:

Чтобы форвардинг автоматически включался при запуске системы в /etc/sysctl.conf добавляем строчку:

Затем добавляем правила в iptables:

Чтобы работало после перезагрузки, сохраняем настройки iptables в файл:

И добавляем в конец файла /etc/network/interfaces:

Не забудьте у клиента в качестве DNS-сервера и шлюза по умолчанию выставить свой IP-адрес (192.168.56.1)

Настройка BackupPC на SUSE Linux

Создаем пользователя backuppc:

Ставим Апач:

и вводим здесь, например, такой текст:

Добро пожаловать!
Через 2 секунды вы будете перенаправлены на страницу BackupPC

Файл должен содержать:

Добавляем пользователя админа BackupPC, задаем ему пароль:

Апач должен запускаться от имени пользователя “backuppc”. Приведем файл /etc/apache/uid.conf к такому виду:

Чтобы спрашивал пароль при доступе к веб-интерфейсу, вносим такие изменения в файл /etc/apache2/default-server.conf

Вносим Апач в автостарт:

и [пере]запускаем:

Предварительно разрешаем зависимости BackupPC перед установкой.

Выключаю поиск DVD-диска, чтобы скачивалось из репозиториев.

Репозиторий ‘openSUSE 11.1-0’ успешно отключён.
И ставим необходимые библиотеки:

Забираем и устанавливаем RsyncP:

Установка BackupPC:

–> Are these paths correct? [y]? Жмем Enter.
–> BackupPC will run on host [имя_host’а]? Жмем Enter.
–> BackupPC should run as user [backuppc]? Жмем Enter.
–> Install directory (full path) [/usr/local/BackupPC]? /opt/BackupPC
–> Data directory (full path) [/data/BackupPC]? /srv/backuppc
–> CGI bin directory (full path) [ ]? /srv/www/cgi-bin
–> Apache image directory (full path) [ ]? /srv/www/htdocs/BackupPC
–> URL for image directory (omit http://host; starts with ‘/’) [ ]? /BackupPC
–> Do you want to continue? [y]? Жмем Enter.

Скрипт отработает и предложит нам “Enjoy!”

Так как BackupPC не разрабатывался под SUSE, для решения проблем с автозапуском
выполняем эти команды:

Рассмотрим вариант бэкапа данных Windows Server 2003. Для этого скачиваем файл cygwin-rsyncd-2.6.8_0.zip и распаковываем в папку C:\rsyncd\
В файле rsyncd.conf (список “общих директорий” схож с конфигом Самбы) правим:
“auth users = backuppc_user” для каждой “общей директории”.
Затем в rsyncd.secrets добавляем:

Для секюрности можно дать права на чтение файлу rsyncd.secrets только учетной записи “SYSTEM”
Запускаем отсюда же services.bat, чтобы установилась служба rsync.
Теперь снова переходим на наш SUSE-сервер:

вносим в этот файл следующие строки:

Чтобы сервер BackupPC “увидел” этого клиента, добавьте imya_client_compa в файл /etc/BackupPC/hosts и соответственно, запись с сопоставлением IP-адреса в /etc/hosts
Чтобы правильно отображались русских имена файлов и папок в файле /opt/BackupPC/lib/BackupPC/CGI/Lib.pm найдите в теле процедуры Header строчку:

и замените ее на

Открываем http://ip_адрес_SUSE_сервера/cgi-bin/BackupPC_Admin
вводим ранее созданные логин и пароль (у меня adminuser) и настраиваем.

Скриншот из сервиса Windows 7

Программа-сервис Windows XP, делающая снимки экрана, после переноса на Windows 7 начала сохранять вместо снимков просто белый фон.
Чтобы использовать основанную на коде ниже программу ru1smake, распакуйте архив в отдельную папку, установите ее как сервис (командой ru1smake.exe /install), задайте параметры в конфигурационном файле ru1smake.conf и запускайте через диспетчер служб. Удаление – командой ru1smake.exe /uninstall. Программа будет автоматически делать снимки экрана согласно указанным в конфиге параметрам.

Скачать программу ru1smake
версия 0.1 (07.08.10) | 0.3 Мб | stable

Дело в том, что начиная с Windows Vista, служба, запущенная от имени SYSTEM, более не может взаимодействовать с рабочим столом – службы теперь запускаются в изолированном сеансе (сессии) и загрузка своего процесса приведет к попытке запуска в неверном (вошедшего в систему пользователя) сеансе. Решить проблему можно, получив сессию залогинившегося пользователя. Вкратце, этот код делает следующее:

  1. Получает токен вошедшего в систему в данный момент пользователя, используя функцию WtsGetActiveConsoleSessionID
  2. Далее получает пользовательский токен, назначенный процессу (токен для службы от имени SYSTEM)
  3. Затем этот токен дублируется
  4. У скопированного токена изменяется сеанс (на вошедшего пользователя)
  5. Используя CreateProcessAsUser запускается процесс с измененным пользовательским токеном
  6. Процесс с системными правами, но будучи запущенным от имени вошедшего в систему пользователя в Windows 7, также позволит корректно работать GUI-программе как и любой другой.

Insert math as
Block
Inline
Additional settings
Formula color
Text color
#333333
Type math using LaTeX
Preview
\({}\)
Nothing to preview
Insert