На правах закладки:
ejabberd - группы из LDAP на о снове OU - пример реализации. Но без документации даже не начинать читать. Модуль mod_shared_roster_ldap появился только в комплекте ejabberd 2.1.6, если версия младше, как, например, в Debian Squeeze (2.1.5), то качать отсюда:
https://alioth.debian.org/projects/ejabberd-msrl, читать документацию, компилять и настраивать.
Отчёт от Олеси aka Рыжей:
http://turizm.primkray.ru/index.php?id=365&doc=k_podnozhiiu_vorobia
PS форма изложения - доставляёт, стилизовано под реальный туристический отчёт :)
Запостил камрад AlexVK
(1161371
):
Программистский жаргон. Раз:
http://habrahabr.ru/blogs/habraquotes/111432/
И далее, по ссылке два
http://habrahabr.ru/blogs/development/96978/
И первоисточник три
http://stackoverflow.com/questions/2349378/new-programming-jargon-you-coined
Epoch & Unix Timestamp Conversion Tools:
http://www.epochconverter.com/
удобно и быстро, когда нужно прикинуть.
Для всякого непотребства, свазанного с ожиданием:
http://ajaxload.info/
Логическое продолжение для
этой статьи, команда для получения состояния очереди.
Подкатом реализация и пример использования команд QueuePause и QueueStatus, какие эвенты получаются смотрите в документации((
тут или
тут, вторая ссылка более полная, но на буржуйском, хотя кого это пугает? :wink:))
Реализацяи QueueStatus
/*
* Additonal actions for Astxx
* Copyright (C) 2010 Alexander Drozdov <hatred@inbox.ru>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/** @file
*
* Include this file to use the QueueStatus action. You should include it by hands.
*
*/
#ifndef ASTXX_MANAGER_ACTION_QUEUE_STATUS_H
#define ASTXX_MANAGER_ACTION_QUEUE_STATUS_H
#include <astxx/manager/basic_action.h>
#include <astxx/manager/message.h>
#include <astxx/manager/error.h>
namespace astxx {
namespace manager {
namespace action {
/** Ask Queue Status
*/
class queue_status : public basic_action {
public:
/** Construct a QueueStatus action.
* @param queue - concretize queue [optional]
* @param member - select member [optional]
* @param action_id - add optional action Id to all responses [optional]
*/
queue_status(const std::string& member = "",
const std::string& queue = "",
const std::string& action_id = "") :
member(member),
queue(queue),
action_id(action_id) {}
/** Format this action as a message::action.
* @return this message as a message::action
*/
message::action action() const {
message::action action("QueueStatus");
if (!queue.empty())
{
action["Queue"] = queue;
}
if (!member.empty())
{
action["Member"] = member;
}
if (!action_id.empty())
{
action["ActionID"] = action_id;
}
return action;
}
private:
std::string queue;
std::string member;
std::string action_id;
};
}
}
}
#endif // QUEUESTATUS_H
Пример
Пример основан на event-test.cc, что идёт вместе с astxx.
#include <astxx/manager.h>
#include <vector>
#include <string>
#include <iostream>
#include "queue_status.h"
#include "queue_pause.h"
void print_event(astxx::manager::message::event e)
{
//std::cout << e.format();
std::cout << e["Paused"] << "<br/>n";
}
int main(int argc, char** argv)
{
std::vector<std::string> args(argv, argv + argc);
if (args.size() != 4)
{
std::cerr << "Usage: " << args[0] << " [host] [username] [secret]<br/>n";
return 1;
}
try
{
namespace manager = astxx::manager;
namespace action = astxx::manager::action;
manager::connection connection(args[1]);
std::cout << "Connected to " << connection.name() << " v" << connection.version() << std::endl;
boost::signals::scoped_connection c1 = connection.register_event("QueueMember", print_event);
//boost::signals::scoped_connection c2 = connection.register_event("Queue", print_event);
action::login login(args[2], args[3]);
login(connection);
action::queue_pause qpause("SIP/3008", true);
manager::message::response resp = qpause(connection);
std::cout << resp.format();
action::queue_status qstatus("SIP/3008");
resp = qstatus(connection);
std::cout << resp.format();
action::queue_pause qpause2("SIP/3008", false);
resp = qpause2(connection);
std::cout << resp.format();
action::queue_status qstatus2("SIP/3008");
resp = qstatus2(connection);
std::cout << resp.format();
for (;;)
{
connection.wait_event();
connection.pump_messages();
connection.process_events();
}
return 0;
}
catch (const std::exception& e)
{
std::cerr << "Exception: " << e.what() << std::endl;
}
return 1;
}
Собственно что тут происходит:
- создаём подключение
- регистрируем обработчик для эвента QueueMember (смотрим токи на AMI)
- логинимся
- ставим мембера в паузу и спрашиваем его состояние
- убираем паузу и опять спрашиваем его состояние
- в цикле обрабатываем приходящие эвенты
Собственно - радость! :)
Там же теперь и разводчик
pcb. Двойная радость!
К сожалению, утилита
xgsch2pcb (менеджер проектов-интегратор gschem и pcb) до community ещё не добралась, но уже не плохо.
Парой слов, что такое
Astxx небольшая библиотечка для работы с Asterisk через
AMI протокол из C++. Написана с использование STL и Boost.
В
одной из прошлых заметок упоминал про дружбу Qt4 и Boost.Signal - для дружбы этой библиотечки и Qt4 это и было нужно :)
Для чего нужна команда, например для организации софтовой DnD кнопки: если интерфейс будет в паузе, из очереди на него не будут переводиться звонки.
Сами классы подкатом.
UPD Переоформил в стиле Astxx
/*
* Additonal actions for Astxx
* Copyright (C) 2010 Alexander Drozdov <hatred@inbox.ru>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/** @file
*
* Include this file to use the QueuePause action. You should include it by hands.
*
*/
#ifndef QUEUE_PAUSE_H
#define QUEUE_PAUSE_H
#include <astxx/manager/basic_action.h>
#include <astxx/manager/message.h>
#include <astxx/manager/error.h>
#include <vector>
#include <string>
namespace astxx
{
namespace manager
{
namespace action
{
/** Set Queue Pause state
*/
class queue_pause : public basic_action
{
public:
class error : public manager::error
{
public:
explicit error(const std::string& desc) throw() : manager::error(desc) { }
};
public:
/** Construct a QueuePause action.
* @param interface - member
* @param is_on - pause state
* @param queue - queue for process, if omited - all queues is used
*/
queue_pause(const std::string &interface, const bool is_on = false, const std::string &queue = "") :
_interface(interface),
_queue(queue),
_is_on(is_on) {}
/** Format this action as a message::action.
* @return this message as a message::action
*/
message::action action() const
{
message::action action("QueuePause");
if (!_queue.empty())
{
action["Queue"] = _queue;
}
action["Interface"] = _interface;
std::string on_off_str = "false";
if (_is_on)
{
on_off_str = "true";
}
action["Paused"] = on_off_str;
return action;
}
message::response handle_response(message::response response)
{
basic_action::handle_response(response);
if ("Success" != response)
{
throw queue_pause::error(response["Message"]);
}
return response;
}
private:
std::string _interface;
std::string _queue;
bool _is_on;
};
}
}
}
#endif // QUEUE_PAUSE_H
Встроенного функционала нет, для X11 можно записпользовать такой код (юзается XLib):
#ifdef Q_WS_X11
# include <X11/Xlib.h>
# include <X11/Xatom.h>
#endif
...
toAllDesktops()
{
#ifdef Q_WS_X11
Atom atom = XInternAtom(x11Info().display(), "_NET_WM_DESKTOP", True);
if (atom)
{
uint32_t data = 0xFFFFFFFF;
XChangeProperty(x11Info().display(), // Display
winId(), // Window
atom, // Property
XA_CARDINAL, // Property type
32, // Data format: 8, 16 or 32 bit
PropModeReplace, // Property change mode
reinterpret_cast<uint8_t*>(&data), // Property data
1); // Data elements count
}
#endif
}
тут предполагается, что эта функцейка будет медотом класса окна, иначе нужно будет передавать Display и Window. Специальное значение 0xFFFFFFFF как раз и говорит - разместить на всех рабочих столах, иначе воспринимается как номер стола, куда нужно поместить окно. В случае Windows этот функционал бесмесленен, поэтому портабельность не сильно пострадает, при использовании директив препроцессора.
Подробности:
Использую библиотечку astxx, которая использует Boost.Signals, использую в программе на Qt, сразу словил ошибку компиляции:
g++ -c -m64 -pipe -g -Wall -W -D_REENTRANT -DQT_CORE_LIB -DQT_SHARED -I/usr/share/qt/mkspecs/linux-g++-64 -I../queue-test -I/usr/include/QtCore -I/usr/include -I. -I../queue-test -I. -o main.o ../queue-test/main.cpp
In file included from /usr/include/boost/signals/connection.hpp:13:0,
from /usr/include/boost/signals/signal_template.hpp:18,
from /usr/include/boost/signals/signal0.hpp:24,
from /usr/include/boost/signal.hpp:19,
from /usr/include/astxx/manager/connection.h:40,
from /usr/include/astxx/manager.h:32,
from ../queue-test/main.cpp:8:
/usr/include/boost/signals/detail/signals_common.hpp:26:13: error: expected identifier before ‘protected’
/usr/include/boost/signals/detail/signals_common.hpp:26:13: error: expected unqualified-id before ‘protected’
../queue-test/main.cpp:75:1: error: expected ‘}’ at end of input
make: *** [main.o] Error 1
Описания способов решения нашел тут:
http://www.boost.org/doc/libs/1_45_0/doc/html/signals/s04.html
Пока же, временно, определил макрос:
#define BOOST_SIGNALS_NAMESPACE boost_signals
Upd:
В .pro файле добавил:
После чего такие конструкции перестанут компилироваться:
signals:
private slots:
public slots:
Заменить на:
Q_SIGNALS:
private Q_SLOTS:
public Q_SLOTS:
Несколько вопросов про Git внутри компании, такие как:
- миграция с mercurial (hg)
- организация совместного доступа, управление правами
- прикручивание к redmine
- организация анонимного ReadOnly доступа к отдельным репозиториям
Миграция с Mercurial
Тут не буду вдаваться в особые подробности, воспользовался этой статьёй:
http://hedonismbot.wordpress.com/2008/10/16/hg-fast-export-convert-mercurial-repositories-to-git-repositories/, отработало, историю правок сохранила. Единственно, на ArchLinux пришлось пробежаться и заменить вызовы python на python2.
Организация совместного доступа
Вот тут интереснее, можно это делать на основе пользователей и групп в системе, но мне захотелось что бы был один аккаунт и там уже разруливалось кому что и где можно.
Нашел статью:
http://scie.nti.st/2007/11/14/hosting-git-repositories-the-easy-and-secure-way. Где собственно описывается решение на основе
gitosis. Можно на просторах рунета найти перевод этой статьи на русский.
Из всего, что хотелось бы добавить: пользователей нужно в конфиге указывать как USER@HOST, иначе получите великий отлуп. Я на этом обжёгся. Решение мне не очень нравится, поэтому попробую раскурить как обойтись просто указанием USER.
Ну и как справка, сгенерировать ключик:
ssh-keygen -f .ssh/$USER@$HOSTNAME
pub-часть отдать админу, что бы залил (кстати, так же через git) и прописал права. Private часть прописать для хоста с git, как - man ssh_config
Прикручивание к redmine
По умолчанию (у нас сервер с Debian) http сервер запущен с указанием группы www-data, тогда как репозитории git доступны на чтение/запись пользователю git и на чтение группе git. Вариант - добавить пользователя www-data в группу git, но не очень гибко. Я сделал следующим образом.
В корень домашней директории (/home/git) поместил следующий скрипт:
#!/bin/bash
cd /home/git
source .web-access.conf
cd repositories
# 1. pass
chown $git_user:$git_group *
# 2. pass
for repo in $repos
do
chown $git_user:$web_group $repo
done
В /etc/sudoers добавил следующую строчку:
git ALL=NOPASSWD: /home/git/allow-web-access.sh
В хук /home/git/repositories/gitosis-admin.git/hooks/post-update добавил следующую строчку:
sudo -u root /home/git/allow-web-access.sh
Сделал симлинк:
ln -s /home/git/repositories/gitosis-admin.git/gitosis-export/web-access.conf /home/git/.web-access.conf
Создал в рабочей копии конфигурации гитозиса файл:
repos="repo1.git repo2.git"
git_user="git"
git_group="git"
web_group="www-data"
в repos указываются репозитории к которым разрешён доступ web-серверу. После чего, как обычно:
git commit -a
git push
Все нужные действия выполнятся автоматом.
В самом redmine указываем полные пути к репозиториям, типа:
/home/git/repositories/repo1.git
Анонимный ReadOnly доступ к некоторым репозиториям
В статье про гитозис про это есть, там правда использована опция --export-all
, убираем её. Внутри директории репы, к которой нужен анонимный доступ, делаем файл git-daemon-export-ok:
touch git-daemon-export-ok
На будущее - автоматизировать эту операцию через конфигурацию гитозиса.
Для тех случаев когда enum
нету, к примеру, при использовании BeanShell:
http://alumnus.caltech.edu/~leif/OO/Enum.html
Подкатом небольшое дополнение и пример.
Небольшая ремарка, для BeanShell придется разносить класс и сами создания констант, к примеру так:
// Не обязательно
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
/**
Хранит описание одной записи в дополнительных действиях, а так же собирает их в перечисление
дабы можно было использовать интерфейс коллекций для перебора при формировании списка
*/
class AdditionalActionId
{
private static Collection all_ids = new ArrayList();
private int value;
private String description;
/**
Конструктор, принимает ID дополнительного действия и описание (что будет в меню отображаться)
*/
AdditionalActionId(int value, String description)
{
this.value = value;
this.description = description;
all_ids.add(this);
}
/**
Возвращает Id действия
*/
public int toInt()
{
return this.value;
}
/**
Возвращает описание действия
*/
public String toString()
{
return this.description;
}
/**********************************************************************************************/
/* Statics methods (class wide methods) ------------------------------------------------------*/
/**********************************************************************************************/
/**
Получаем итератор для перебора всех ранее созданных действий
*/
public static Iterator getIterator()
{
return all_ids.iterator();
}
/**
Получаем количество дополнительных действий
*/
public static int getSize()
{
return all_ids.size();
}
}
/**
Класс-обертка, для реализации некоторого подобия Enum (который не работает в BeanShell)
*/
class AdditionalActionIds
{
private static int action = 1;
// Перечисляем наши действия
//public static final AdditionalActionId TARIFF_ADD_COMMON1 = new AdditionalActionId(action++, "TEST");
//public static final AdditionalActionId TARIFF_ADD_COMMON2 = new AdditionalActionId(action++, "TEST");
//public static final AdditionalActionId TARIFF_ADD_COMMON3 = new AdditionalActionId(action++, "TEST");
//public static final AdditionalActionId TARIFF_ADD_COMMON4 = new AdditionalActionId(action++, "TEST");
// Must be LAST
public static final AdditionalActionId ABON_RECALC_ALL = new AdditionalActionId(1000000, "Дополнительное действие");
}
// Пример перебора всех значений
/*Iterator it = AdditionalActionId.getIterator();
while (it.hasNext())
{
action = (AdditionalActionId)it.next();
print("ID: " + action.toInt() + ", desc: " + action.toString());
}
*/
// Пример обращения к конкретному элементу
/*AdditionalActionId action = AdditionalActionIds.TARIFF_ADD_COMMON3;
print("ID: " + action.toInt() + ", desc: " + action.toString());*/
Иначе имеем проблемы. Не знаю, бага или фича, но факт.
Небольшая заметка по шрифтам для редакторов кода. Мой выбор.
Выпустил версию 0.6.0 программы
Crowns.
Из основных изменений:
- Добавлена возможность задавать ограничение на отображение деревьев по возрасту (кстати это поле, как я понял, в основном используется не для возраста, а для задания года “рождения” дерева)
- Исправлен диалог редактирования данных: в нем невозможно было задать возраст дерева
Написал небольшую программу для подключения, отключения сменных дисков в Linux, использует udisks для монтирования (в планах сделать бакенд и для простых mount/unmount через sudo, класс для использования которого уже написан, для полных минималистов), udev для детекта новых дисков и изъятия существующих (опять таки, готов и бакед для использования inotify, можно будет альтернативно прикрутить его, кстати, а на други unix системах как с inotify?) и в минимальном плане DBus для возможности получать сообщения: а вдруг кто-то там снаружи примонтировал/отмонтировал диск.
Пожелания - мне на мыло
Проект разместил на Gitorius:
http://gitorious.org/h4tr3d-utils/pages/MountTray
Новый адрес:
https://github.com/h4tr3d/mount-tray, проект не разрабатывается уже несколько лет.