Генератор анимационных индикаторов ожидания
Для всякого непотребства, свазанного с ожиданием:
http://ajaxload.info/
Для всякого непотребства, свазанного с ожиданием:
http://ajaxload.info/
Логическое продолжение для этой статьи, команда для получения состояния очереди.
Подкатом реализация и пример использования команд QueuePause и QueueStatus, какие эвенты получаются смотрите в документации(( тут или тут, вторая ссылка более полная, но на буржуйском, хотя кого это пугает? :wink:))
/*
* 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;
}
Собственно что тут происходит:
Собственно - радость! :)
Там же теперь и разводчик 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 файле добавил:
CONFIG += no_keywords
После чего такие конструкции перестанут компилироваться:
signals:
private slots:
public slots:
Заменить на:
Q_SIGNALS:
private Q_SLOTS:
public Q_SLOTS:
Несколько вопросов про Git внутри компании, такие как:
Тут не буду вдаваться в особые подробности, воспользовался этой статьёй: 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
По умолчанию (у нас сервер с 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
В статье про гитозис про это есть, там правда использована опция --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, проект не разрабатывается уже несколько лет.
В составе трех человек:
…Но сходили, категорически не так как ожидали Но не это главное, а главное осюсения (коих, в отличии от почти диванного похода на Облачную, про который даже написать то нечего в голову не лезет, значительно больше)
В общем, маршрут не прошли, причина проста: “Русские на войне своих не бросают…” А если проще: Настя конкретно натерла (до крови) ноги уже к тому моменту как дошли до ушуисткой базы (да, решили идти по Смольному). Поэтому сделали привал, стали держать военный совет: одну домой её не отправим и одному продолжать маршрут тоже не есть гуд. Поэтому пошли на компромисс: в первый день пробатонились чуть дальше по ручью - разбили лагерь, дышали воздухом, гоняли чаи. На следующий день Я и Серёга сгоняли в радиалку на Фалазу…
Тут тоже весело получилось: планировали топать по тропе (ну вроде как она там есть), хотя я в тех районах уже на Фалазу забирался, но поднимался по осыпям. В общем… девиз радиалки стал: “тропа!? какая тропа! идём по приборам!”
Прибора было три: распечатка карты, компас и “что-то мне подсказывает”. Последним пользовался чаще :laughing:
Тропу даже искать, в общем, не стали: планировалось выйти на седловинку и там подниматься - проверить состояние и что там вообще за условия, но обходя заросли актинидии пополам с малиновым вар… в смысле с элеутерококком, опять выбрались на осыпь, ну уже и решили по ней и забираться. Так и доползли, встречая, изредка, творения рук человеческих в виде туров ( http://picasaweb.google.com/skoulik/yZvOXG#5536649695455909314).
Немного почалившись на вершине, вдыхая воздух, решаем таки на обратном пути свалиться в седловинку и дальше по ручью. Ну что, сказано, сделано - на седловинку попали как снайперы (склон с осыпями и голый лес помогают ориентироваться), про тропы уже не думали (ибо нефиг), проходим немного и начинаем спускаться к ручью… От тут начинается красоты: толстенные поваленные деревья обросшие мхом, валуны в таком же состоянии, актинидия, которая, цепляясь за ноги, как бы намекает на слова из песенки (хоть там и морская тематика): “…оставайся мальчик с нами, будешь нашим королём…”, ну и конечно - элеутерококк :simple_smile: Скоро и сам ручей появился валуны стали более красивыми, а мы, как горные козлы, устроили горно-лесной паркур - скакали по камням (без рюкзаков, чего бы это не поскакать-то)
В лагере нас ждал обедс, покушали, собрались и обратно на электричку. Иголки от элеутерококка доставал до вчерашнего дня
И нужно будет опять выбрать время, маршрут таки сходить.
Малость фото (в художественном оформлении, ну уж какова фантазия художника):
15-16-17 октября побывали наконец на Облачной. Всеми красотами насладиться не получилось, ибо сопка в точности до каждой буквы оправдала своё название: вершина порадовала плотным туманом-облаком, хотя на высоте 1000 метров было ясно. Пока добирались до кордона Уссури встретили первый снег… За три километра до шлагбаума размытый мост и крайне неудачный объезд остановил наш автобус, но не наши ноги. Из-за этой мелочи, было накручено в каждую сторону лишних 13-14 км (на обратном пути я что-то вообще чуть не помер, но дополз, ибо нефиг).
Итак, наш путь начался с мокрого снега переходящего в дождь: не пожалел, что взял с собой пончо. Добравшись до кордона руководитель всего этого мероприятия (упали на хвоста мегафоновцам, они заказывали автобус, разрешение на въезд на территорию парка “Зов тигра”) быстро уладил дела с егерями и мы двинулись дальше.
Так потихоньку продвигаясь добрались сначала к свороту с дороги к подножию, а пока шли, познакомились с двумя парнишками - аукнулась поездка в Бастак, там с нами была девушка - Полина, это оказались её знакомые (видели меня на фотографиях). Воистину планета квадратная, а туристические тропы - тесные :)
Добравшись до стоянки у, фактически, самого подножия, сделали небольшой привал на чай, сугрев и перекус. Накормили и обогрели отставших от основной группы (мы, в составе: я, Серега, Настя, её матушка, Ярослава, Лиза и Леха, шли отдельной бандой со своими продуктами и целями). Ну а дальше был последний рывок, подъем по старой лесовозной дороге до высоты около 1000 метров, где были около семи часов вечера субботы, разбили лагерь, организовали ужин, а во круг снег лежит: привет Зима!
На стоянке проблемы с водой - или далеко вниз спускаться или далеко вверх до родника подниматься. Ситуацию спас снег и огромное количество сушняка для дров.
Ужин, сон (да, летняя палатка, с поднятыми пологами оказалась уже не совсем для этого времени года).
Утром ранний подъем, завтрак и подъем на легке до вершины.
Подъем до плато занял около часа или полутора… Ещё на подъеме ясная погода сменилась туманом. На плато, если бы не туры, было бы очень сложно ориентироваться. Хотя даже они не помогли в один момент как и не помог GPS, зато спасли сфотографированная карта и компас :)
Ветренно… Холодно… “Горка” не продувается, это спасает, хотя длительные остановки чреваты. Ярослава тем временем начинает подмерзать, отдаю ей свои перчатки, ибо теплее в них. На последнем перешейке отдаю ей возвращающейся первой партии, как оказалось - правильно.
После последнего перешейка, рывок, ещё один… На последнем пожъеме встречаю спускающихся Лизу и Леху, забираю у них термос с остатками чая. Тихо и мирно добираюсь до самой макушки… Уххххху! Ветер такой, что даже мою тушку в 90 кг порывается положить к земле, видимость - метров 20, не больше. В общем - зашибись и отлично :)
Посидели за каменной кладкой, перекусили, попили чая, я дождался замыкающих, сфотографировались и тронулись в обратный путь.
Спустившись вниз ждал уже чай кофе сиг… ну вы поняли. Правда передохнуть почти не получилось - быстрые сборы и обратный путь до автобуса…
Что-то он дался мне крайне тяжко, были мысли бросить всё и остаться ещё на одну ночевку… Но ничего отделавшись шикарнейшими мозолями, в темноте при свете луны таки добрались до автобуса. Хотя остаться ещё было бы более прикольно :)
Дома были около пяти утра понедельника, уставшие, но довольные.
В общем как-то так. Получилось довольно диванно, впечатлений не так много. По ссылкам ниже немного фото:
Уже решил было сам писать, но оказалось, что уже сделано: http://debugmo.de/2009/04/bgrep-a-binary-grep/
Выкачиваем с git-hub: git clone https://github.com/tmbinc/bgrep.git
Строим: gcc -o bgrep bgrep.c
Далее копируем bgrep куда нибудь, где она будет доступен при поиске в PATH (у меня это ~/bin) и пользуемся примерно так: find . -name ‘*.bin’ | xargs bgrep FFFE003454
или так: bgrep FFFE file.bin
Вывод на экран: имя файла: смещение
Смещение - относительно начала файла в HEX виде. Далее mcview, biew или любой HEX редактор-просмотровщик в помощь.
Повторять весь текст не буду, авторство и так моё: http://groups.google.com/group/archlinux-ru/browse_thread/thread/33c0d288bd05823d
Тут как реминдер