Converted project to CPP and use Qt instead of Gtk.
This commit is contained in:
parent
22c991cd26
commit
966314dae7
10 changed files with 253 additions and 641 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -1,4 +1,5 @@
|
|||
bin/
|
||||
build/
|
||||
local/
|
||||
spacetray
|
||||
*~
|
||||
|
|
|
|||
19
CMakeLists.txt
Normal file
19
CMakeLists.txt
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
cmake_minimum_required(VERSION 3.10)
|
||||
project(spacetray)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
set(CMAKE_AUTOMOC ON)
|
||||
set(CMAKE_AUTOUIC ON)
|
||||
set(CMAKE_AUTORCC ON)
|
||||
|
||||
find_package(Qt5 REQUIRED COMPONENTS Widgets Network)
|
||||
|
||||
add_executable(spacetray
|
||||
main.cpp
|
||||
spacetray.cpp
|
||||
spacetray.h
|
||||
)
|
||||
|
||||
target_link_libraries(spacetray Qt5::Widgets Qt5::Network)
|
||||
11
Makefile
11
Makefile
|
|
@ -1,11 +0,0 @@
|
|||
all:
|
||||
$(CC) -Wall -g `pkg-config --cflags --libs gtk+-2.0 --libs libcurl --libs json-c --libs libnotify` -DLIBNOTIFY -o bin/spacetray spacetray.c
|
||||
|
||||
nonotify:
|
||||
$(CC) -Wall -g `pkg-config --cflags --libs gtk+-2.0 --libs libcurl --libs json-c` -o bin/spacetray spacetray.c
|
||||
|
||||
clean:
|
||||
rm -f ./bin/spacetray
|
||||
|
||||
run:
|
||||
./bin/spacetray
|
||||
69
README.md
69
README.md
|
|
@ -1,7 +1,7 @@
|
|||
spacetray
|
||||
=========
|
||||
|
||||
A panel Applet using GTK2 for showing the Status of a Hackerspace. Compatible with the SpaceAPI version >= 0.13.
|
||||
A panel Applet using Qt5 for showing the Status of a Hackerspace. Compatible with the SpaceAPI version >= 0.13.
|
||||
|
||||
|
||||
Installation:
|
||||
|
|
@ -9,11 +9,8 @@ Installation:
|
|||
|
||||
Requirements:
|
||||
|
||||
- Standard tools like gcc, pkg-config etc.
|
||||
- curl
|
||||
- gtk+-2.0
|
||||
- json-c
|
||||
- libnotify - Only needed when compiling with libnotify support.
|
||||
- Standard tools like g++, cmake etc.
|
||||
- Qt5 (Widgets and Network modules)
|
||||
|
||||
Use the following command for getting the sources:
|
||||
|
||||
|
|
@ -25,67 +22,75 @@ Change into the new directory:
|
|||
|
||||
To compile the sources just run:
|
||||
|
||||
mkdir build
|
||||
cd build
|
||||
cmake ..
|
||||
make
|
||||
|
||||
This will compile dooris with libnotify support.
|
||||
This will compile spacetray with status icon and notification support.
|
||||
|
||||
If you don't want notifications run the following command:
|
||||
Just copy "bin/spacetray" to a folder in your $PATH. I do:
|
||||
|
||||
make nonotify
|
||||
|
||||
Just copy "spacetray" to a folder in your $PATH. I do:
|
||||
|
||||
cp ./spacetray ~/bin/
|
||||
cp ./bin/spacetray ~/bin/
|
||||
|
||||
You can copy the file to /usr/bin to make it available to all users but I don't. If you want that just run:
|
||||
|
||||
sudo cp ./spacetray /usr/bin/
|
||||
sudo cp ./bin/spacetray /usr/bin/
|
||||
|
||||
Configuration:
|
||||
--------------
|
||||
|
||||
Configuration needs to be done before compiling. There are some parameters you can set in the head of the spacetray.c file where variables are declared. A configuration file will at this point make no sense.
|
||||
Configuration is done via command line arguments.
|
||||
|
||||
Usage:
|
||||
------
|
||||
|
||||
Run spacetray with:
|
||||
|
||||
./spacetray &
|
||||
./bin/spacetray <statusurl> &
|
||||
|
||||
Or if in your $PATH:
|
||||
|
||||
spacetray
|
||||
spacetray <statusurl>
|
||||
|
||||
Status Icon "Pesthoernchen" colors:
|
||||
Status Icon "lock" colors:
|
||||
|
||||
- Red = Door closed
|
||||
- Yellow = Door open
|
||||
- Red = Door open
|
||||
- Green = Door closed
|
||||
|
||||
Themes:
|
||||
-------
|
||||
|
||||
You can create your own icon theme by generating a C header file containing the icons as "static const GdkPixdata" data structure.
|
||||
You can create your own icon theme by generating a C++ header file containing the icons as raw RGBA8888 pixel data in a `static const quint8` array.
|
||||
|
||||
This can be done using the following commands:
|
||||
The format should look like this:
|
||||
|
||||
gdk-pixbuf-csource --struct PATH_TO_OPEN_IMAGE > ./themes/THEME_NAME.h
|
||||
static const quint8 icon_open_data[] = {
|
||||
0xRR, 0xGG, 0xBB, 0xAA, ...
|
||||
};
|
||||
|
||||
gdk-pixbuf-csource --struct PATH_TO_CLOSED_IMAGE >> ./themes/THEME_NAME.h
|
||||
static const quint8 icon_closed_data[] = {
|
||||
0xRR, 0xGG, 0xBB, 0xAA, ...
|
||||
};
|
||||
|
||||
Afterwards you need to rename the first generated struct to:
|
||||
The image size used in the default theme is 52x48 pixels with 4 channels (RGBA).
|
||||
|
||||
icon_open_pixbuf
|
||||
To create these arrays from a PNG image, you can use `ImageMagick` to convert the image to raw RGBA data and then format it into a C++ header.
|
||||
|
||||
The second must be renamed to:
|
||||
Example using `magick` (ImageMagick 7):
|
||||
|
||||
icon_closed_pixbuf
|
||||
magick icon_open.png -size 52x48 -depth 8 RGBA:icon_open.raw
|
||||
hexdump -v -e '12/1 "0x%02x, " "\n"' icon_open.raw
|
||||
|
||||
in:
|
||||
Or using a simple one-liner to generate the header content:
|
||||
|
||||
./themes/THEME_NAME.h
|
||||
echo "static const quint8 icon_open_data[] = {" > themes/my_theme.h
|
||||
magick icon_open.png -size 52x48 -depth 8 RGBA:- | hexdump -v -e '12/1 "0x%02x, " "\n"' >> themes/my_theme.h
|
||||
echo "};" >> themes/my_theme.h
|
||||
|
||||
You can then use your custom icon theme when changing the line:
|
||||
Repeat the process for `icon_closed_data` and append it to the same header file.
|
||||
|
||||
You can then use your custom icon theme by changing the line:
|
||||
|
||||
#include "themes/lock.h"
|
||||
|
||||
|
|
@ -95,5 +100,5 @@ to:
|
|||
|
||||
in:
|
||||
|
||||
./spacetray.c
|
||||
./spacetray.cpp
|
||||
|
||||
|
|
|
|||
17
main.cpp
Normal file
17
main.cpp
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
#include <QApplication>
|
||||
#include <iostream>
|
||||
#include "spacetray.h"
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
QApplication app(argc, argv);
|
||||
|
||||
if (argc != 2) {
|
||||
std::cerr << "Usage: " << argv[0] << " <statusurl>" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
SpaceTray tray(argv[1]);
|
||||
|
||||
return app.exec();
|
||||
}
|
||||
291
spacetray.c
291
spacetray.c
|
|
@ -1,291 +0,0 @@
|
|||
/*
|
||||
* SpaceAPI based tray applet for BSD* / Linux / UNIX etc. using GTK2
|
||||
*
|
||||
* Author: hanez <you@hanez.org>
|
||||
* Website: https://git.xw3.org/hanez/spacetray
|
||||
*
|
||||
* Licensed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
#include <curl/curl.h>
|
||||
#include <gtk/gtk.h>
|
||||
#include <json.h>
|
||||
|
||||
#if LIBNOTIFY
|
||||
#include <libnotify/notify.h>
|
||||
#endif
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <pthread.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "themes/lock_new.h"
|
||||
|
||||
struct string {
|
||||
char *ptr;
|
||||
size_t len;
|
||||
};
|
||||
|
||||
static char *agent = "Spacetray/0.42";
|
||||
static char *name = "SpaceAPI widget for UNIX";
|
||||
static char *statusurl = NULL;
|
||||
|
||||
// The delay for polling the dooris service. Adjust this before compiling
|
||||
static int delay = 300; // ms. aka 15 minutes
|
||||
|
||||
bool door_open = false;
|
||||
bool old_door_open = false;
|
||||
int door_last_change = 0;
|
||||
char space_name[128] = "Unknown Space";
|
||||
|
||||
void on_quit_menu_item_activated(GtkMenuItem *item, gpointer data) {
|
||||
gtk_main_quit();
|
||||
}
|
||||
|
||||
void on_popup_menu(GtkStatusIcon *status_icon, guint button, guint activate_time, gpointer data) {
|
||||
GtkWidget *menu, *quit_item;
|
||||
|
||||
menu = gtk_menu_new();
|
||||
quit_item = gtk_menu_item_new_with_label("Quit");
|
||||
|
||||
g_signal_connect(G_OBJECT(quit_item), "activate",
|
||||
G_CALLBACK(on_quit_menu_item_activated), NULL);
|
||||
|
||||
gtk_menu_shell_append(GTK_MENU_SHELL(menu), quit_item);
|
||||
gtk_widget_show_all(menu);
|
||||
|
||||
gtk_menu_popup(GTK_MENU(menu), NULL, NULL,
|
||||
gtk_status_icon_position_menu, status_icon,
|
||||
button, activate_time);
|
||||
}
|
||||
|
||||
void do_it();
|
||||
void invoke_notification();
|
||||
|
||||
gboolean do_it_wrapper(gpointer data) {
|
||||
do_it();
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void *status_update_thread(void *arg) {
|
||||
while (1) {
|
||||
sleep(delay);
|
||||
g_idle_add(do_it_wrapper, NULL);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
GtkStatusIcon *tray_icon;
|
||||
|
||||
void init_string(struct string *s) {
|
||||
s->len = 0;
|
||||
s->ptr = malloc(s->len+1);
|
||||
if (s->ptr == NULL) {
|
||||
fprintf(stderr, "malloc() failed\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
s->ptr[0] = '\0';
|
||||
}
|
||||
|
||||
size_t writefunc(void *ptr, size_t size, size_t nmemb, struct string *s) {
|
||||
size_t new_len = s->len + size*nmemb;
|
||||
s->ptr = realloc(s->ptr, new_len+1);
|
||||
if (s->ptr == NULL) {
|
||||
fprintf(stderr, "realloc() failed\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
memcpy(s->ptr+s->len, ptr, size*nmemb);
|
||||
s->ptr[new_len] = '\0';
|
||||
s->len = new_len;
|
||||
|
||||
return size*nmemb;
|
||||
}
|
||||
|
||||
void get_bouncer_data() {
|
||||
CURL *curl;
|
||||
CURLcode res;
|
||||
|
||||
struct json_object *response_json_object;
|
||||
struct json_object *door_json_object;
|
||||
struct json_object *leaf_json_object;
|
||||
|
||||
bool door_status;
|
||||
struct string s;
|
||||
|
||||
printf("Called get_bouncer_data()\n");
|
||||
|
||||
old_door_open = door_open;
|
||||
|
||||
init_string(&s);
|
||||
|
||||
curl = curl_easy_init();
|
||||
if(!curl) {
|
||||
fprintf(stderr, "curl_easy_init() failed.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
curl_easy_setopt(curl, CURLOPT_URL, statusurl);
|
||||
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writefunc);
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &s);
|
||||
curl_easy_setopt(curl, CURLOPT_USERAGENT, agent);
|
||||
|
||||
res = curl_easy_perform(curl);
|
||||
|
||||
curl_easy_cleanup(curl);
|
||||
|
||||
if(res != CURLE_OK) {
|
||||
fprintf(stderr, "curl_easy_perform() failed: %s\n",
|
||||
curl_easy_strerror(res));
|
||||
return;
|
||||
}
|
||||
|
||||
response_json_object = json_tokener_parse(s.ptr);
|
||||
free(s.ptr);
|
||||
|
||||
// door objects
|
||||
door_json_object = json_object_object_get(response_json_object, "state");
|
||||
|
||||
leaf_json_object = json_object_object_get(door_json_object, "open");
|
||||
door_status = json_object_get_int(leaf_json_object);
|
||||
//door_status = true;
|
||||
leaf_json_object = json_object_object_get(door_json_object, "lastchange");
|
||||
door_last_change = json_object_get_int(leaf_json_object);
|
||||
|
||||
leaf_json_object = json_object_object_get(response_json_object, "space");
|
||||
if (leaf_json_object != NULL) {
|
||||
const char *s_name = json_object_get_string(leaf_json_object);
|
||||
if (s_name != NULL) {
|
||||
strncpy(space_name, s_name, sizeof(space_name) - 1);
|
||||
space_name[sizeof(space_name) - 1] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
// free response object
|
||||
json_object_put(response_json_object);
|
||||
|
||||
printf("Door status: = %d\n", door_status);
|
||||
printf("Door last change: = %d\n", door_last_change);
|
||||
|
||||
if (door_status == true) {
|
||||
door_open = true;
|
||||
} else {
|
||||
door_open = false;
|
||||
}
|
||||
}
|
||||
|
||||
GdkPixbuf *icon_open = NULL;
|
||||
GdkPixbuf *icon_closed = NULL;
|
||||
|
||||
static GdkPixbuf *pixbuf_new_from_data(const guint8 *data) {
|
||||
return gdk_pixbuf_new_from_data(data, GDK_COLORSPACE_RGB, TRUE, 8, 52, 48, 208, NULL, NULL);
|
||||
}
|
||||
|
||||
void update_tooltip() {
|
||||
char door[256];
|
||||
char date_str[64];
|
||||
time_t last_change_time = (time_t)door_last_change;
|
||||
struct tm *tm_info = localtime(&last_change_time);
|
||||
|
||||
strftime(date_str, sizeof(date_str), "%Y-%m-%d %H:%M:%S", tm_info);
|
||||
|
||||
if (door_open == true) {
|
||||
snprintf(door, sizeof(door), "%s: Door open since %s", space_name, date_str);
|
||||
} else {
|
||||
snprintf(door, sizeof(door), "%s: Door closed since %s", space_name, date_str);
|
||||
}
|
||||
|
||||
gtk_status_icon_set_tooltip(tray_icon, door);
|
||||
}
|
||||
|
||||
void invoke_notification() {
|
||||
char door[256];
|
||||
char date_str[64];
|
||||
time_t last_change_time = (time_t)door_last_change;
|
||||
struct tm *tm_info = localtime(&last_change_time);
|
||||
|
||||
strftime(date_str, sizeof(date_str), "%Y-%m-%d %H:%M:%S", tm_info);
|
||||
|
||||
if (door_open == true) {
|
||||
snprintf(door, sizeof(door), "%s: Door open since %s", space_name, date_str);
|
||||
} else {
|
||||
snprintf(door, sizeof(door), "%s: Door closed since %s", space_name, date_str);
|
||||
}
|
||||
|
||||
#if LIBNOTIFY
|
||||
NotifyNotification *n;
|
||||
|
||||
n = notify_notification_new(name, door, NULL);
|
||||
|
||||
if (door_open == true) {
|
||||
notify_notification_set_icon_from_pixbuf(n, icon_open);
|
||||
} else {
|
||||
notify_notification_set_icon_from_pixbuf(n, icon_closed);
|
||||
}
|
||||
notify_notification_show(n, NULL);
|
||||
g_object_unref(G_OBJECT(n));
|
||||
#endif
|
||||
}
|
||||
|
||||
void set_status() {
|
||||
if (door_open == true) {
|
||||
printf("Set to status: open\n");
|
||||
gtk_status_icon_set_from_pixbuf(tray_icon, icon_open);
|
||||
} else {
|
||||
printf("Set to status: closed\n");
|
||||
gtk_status_icon_set_from_pixbuf(tray_icon, icon_closed);
|
||||
}
|
||||
}
|
||||
|
||||
void do_it() {
|
||||
static bool first_run = true;
|
||||
get_bouncer_data();
|
||||
set_status();
|
||||
update_tooltip();
|
||||
|
||||
if (!first_run && door_open != old_door_open) {
|
||||
invoke_notification();
|
||||
}
|
||||
first_run = false;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
pthread_t thread_id;
|
||||
|
||||
if (argc != 2) {
|
||||
fprintf(stderr, "Usage: %s <statusurl>\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
statusurl = argv[1];
|
||||
|
||||
gtk_init(&argc, &argv);
|
||||
|
||||
icon_open = pixbuf_new_from_data(icon_open_data);
|
||||
icon_closed = pixbuf_new_from_data(icon_closed_data);
|
||||
|
||||
#if LIBNOTIFY
|
||||
notify_init(name);
|
||||
#endif
|
||||
|
||||
tray_icon = gtk_status_icon_new();
|
||||
g_signal_connect(G_OBJECT(tray_icon), "activate",
|
||||
G_CALLBACK(do_it), NULL);
|
||||
g_signal_connect(G_OBJECT(tray_icon), "popup-menu",
|
||||
G_CALLBACK(on_popup_menu), NULL);
|
||||
|
||||
gtk_status_icon_set_visible(tray_icon, true);
|
||||
|
||||
do_it();
|
||||
|
||||
if (pthread_create(&thread_id, NULL, status_update_thread, NULL) != 0) {
|
||||
fprintf(stderr, "Error creating thread\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
gtk_main();
|
||||
|
||||
return 0;
|
||||
}
|
||||
131
spacetray.cpp
Normal file
131
spacetray.cpp
Normal file
|
|
@ -0,0 +1,131 @@
|
|||
#include "spacetray.h"
|
||||
#include "themes/lock.h"
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
#include <QNetworkRequest>
|
||||
#include <QAction>
|
||||
#include <QCoreApplication>
|
||||
#include <QImage>
|
||||
#include <QPixmap>
|
||||
#include <QDebug>
|
||||
|
||||
SpaceTray::SpaceTray(const QString &url, QObject *parent)
|
||||
: QObject(parent),
|
||||
m_statusUrl(url),
|
||||
m_doorOpen(false),
|
||||
m_oldDoorOpen(false),
|
||||
m_doorLastChange(0),
|
||||
m_spaceName("Unknown Space"),
|
||||
m_firstRun(true)
|
||||
{
|
||||
// Initialize icons from raw data
|
||||
QImage imgOpen(icon_open_data, 52, 48, 208, QImage::Format_RGBA8888);
|
||||
m_iconOpen = QIcon(QPixmap::fromImage(imgOpen));
|
||||
|
||||
QImage imgClosed(icon_closed_data, 52, 48, 208, QImage::Format_RGBA8888);
|
||||
m_iconClosed = QIcon(QPixmap::fromImage(imgClosed));
|
||||
|
||||
// Setup tray icon
|
||||
m_trayIcon = new QSystemTrayIcon(this);
|
||||
m_trayIcon->setIcon(m_iconClosed);
|
||||
m_trayIcon->setVisible(true);
|
||||
|
||||
// Setup tray menu
|
||||
m_trayMenu = new QMenu();
|
||||
QAction *quitAction = m_trayMenu->addAction("Quit");
|
||||
connect(quitAction, &QAction::triggered, this, &SpaceTray::quit);
|
||||
m_trayIcon->setContextMenu(m_trayMenu);
|
||||
|
||||
connect(m_trayIcon, &QSystemTrayIcon::activated, [this](QSystemTrayIcon::ActivationReason reason) {
|
||||
if (reason == QSystemTrayIcon::Trigger) {
|
||||
fetchData();
|
||||
}
|
||||
});
|
||||
|
||||
// Setup network manager
|
||||
m_networkManager = new QNetworkAccessManager(this);
|
||||
|
||||
// Setup timer (300 seconds as per previous delay=300 in C code)
|
||||
m_timer = new QTimer(this);
|
||||
connect(m_timer, &QTimer::timeout, this, &SpaceTray::fetchData);
|
||||
m_timer->start(300000); // 300 seconds in ms
|
||||
|
||||
// Initial fetch
|
||||
fetchData();
|
||||
}
|
||||
|
||||
SpaceTray::~SpaceTray()
|
||||
{
|
||||
delete m_trayMenu;
|
||||
}
|
||||
|
||||
void SpaceTray::fetchData()
|
||||
{
|
||||
QNetworkRequest request(m_statusUrl);
|
||||
request.setHeader(QNetworkRequest::UserAgentHeader, "Spacetray/0.42 (Qt)");
|
||||
request.setAttribute(QNetworkRequest::RedirectPolicyAttribute, QNetworkRequest::NoLessSafeRedirectPolicy);
|
||||
QNetworkReply *reply = m_networkManager->get(request);
|
||||
connect(reply, &QNetworkReply::finished, this, [this, reply]() { onFinished(reply); });
|
||||
}
|
||||
|
||||
void SpaceTray::onFinished(QNetworkReply *reply)
|
||||
{
|
||||
if (reply->error() != QNetworkReply::NoError) {
|
||||
qWarning() << "Network error:" << reply->errorString();
|
||||
reply->deleteLater();
|
||||
return;
|
||||
}
|
||||
|
||||
QByteArray data = reply->readAll();
|
||||
reply->deleteLater();
|
||||
|
||||
// Remove UTF-8 BOM if present
|
||||
if (data.startsWith("\xEF\xBB\xBF")) {
|
||||
data.remove(0, 3);
|
||||
}
|
||||
|
||||
QJsonParseError error;
|
||||
QJsonDocument doc = QJsonDocument::fromJson(data, &error);
|
||||
if (doc.isNull()) {
|
||||
qWarning() << "Failed to parse JSON:" << error.errorString();
|
||||
qWarning() << "Raw data:" << data;
|
||||
return;
|
||||
}
|
||||
|
||||
QJsonObject obj = doc.object();
|
||||
m_spaceName = obj.value("space").toString("Unknown Space");
|
||||
|
||||
QJsonObject stateObj = obj.value("state").toObject();
|
||||
m_oldDoorOpen = m_doorOpen;
|
||||
m_doorOpen = stateObj.value("open").toBool();
|
||||
m_doorLastChange = stateObj.value("lastchange").toVariant().toLongLong();
|
||||
|
||||
updateTray();
|
||||
|
||||
if (!m_firstRun && m_doorOpen != m_oldDoorOpen) {
|
||||
QString dateStr = QDateTime::fromSecsSinceEpoch(m_doorLastChange).toString("yyyy-MM-dd HH:mm:ss");
|
||||
QString status = m_doorOpen ? "open" : "closed";
|
||||
showNotification(QString("%1: Door %2 since %3").arg(m_spaceName, status, dateStr));
|
||||
}
|
||||
m_firstRun = false;
|
||||
}
|
||||
|
||||
void SpaceTray::updateTray()
|
||||
{
|
||||
m_trayIcon->setIcon(m_doorOpen ? m_iconOpen : m_iconClosed);
|
||||
|
||||
QString dateStr = QDateTime::fromSecsSinceEpoch(m_doorLastChange).toString("yyyy-MM-dd HH:mm:ss");
|
||||
QString status = m_doorOpen ? "open" : "closed";
|
||||
QString tooltip = QString("%1: Door %2 since %3").arg(m_spaceName, status, dateStr);
|
||||
m_trayIcon->setToolTip(tooltip);
|
||||
}
|
||||
|
||||
void SpaceTray::showNotification(const QString &message)
|
||||
{
|
||||
m_trayIcon->showMessage("SpaceAPI widget for UNIX", message, m_doorOpen ? m_iconOpen : m_iconClosed);
|
||||
}
|
||||
|
||||
void SpaceTray::quit()
|
||||
{
|
||||
QCoreApplication::quit();
|
||||
}
|
||||
45
spacetray.h
Normal file
45
spacetray.h
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
#ifndef SPACETRAY_H
|
||||
#define SPACETRAY_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QSystemTrayIcon>
|
||||
#include <QMenu>
|
||||
#include <QNetworkAccessManager>
|
||||
#include <QNetworkReply>
|
||||
#include <QTimer>
|
||||
#include <QDateTime>
|
||||
|
||||
class SpaceTray : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit SpaceTray(const QString &url, QObject *parent = nullptr);
|
||||
~SpaceTray();
|
||||
|
||||
private slots:
|
||||
void fetchData();
|
||||
void onFinished(QNetworkReply *reply);
|
||||
void quit();
|
||||
|
||||
private:
|
||||
void updateTray();
|
||||
void showNotification(const QString &message);
|
||||
|
||||
QString m_statusUrl;
|
||||
QSystemTrayIcon *m_trayIcon;
|
||||
QMenu *m_trayMenu;
|
||||
QNetworkAccessManager *m_networkManager;
|
||||
QTimer *m_timer;
|
||||
|
||||
bool m_doorOpen;
|
||||
bool m_oldDoorOpen;
|
||||
qint64 m_doorLastChange;
|
||||
QString m_spaceName;
|
||||
bool m_firstRun;
|
||||
|
||||
QIcon m_iconOpen;
|
||||
QIcon m_iconClosed;
|
||||
};
|
||||
|
||||
#endif // SPACETRAY_H
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
#include <gtk/gtk.h>
|
||||
#include <QtGlobal>
|
||||
|
||||
/* width: 52, height: 48, rowstride: 208, n_channels: 4 */
|
||||
static const guint8 icon_open_data[] = {
|
||||
static const quint8 icon_open_data[] = {
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x06,
|
||||
0x80, 0x00, 0x00, 0x91, 0x80, 0x00, 0x00, 0xdf, 0x80, 0x00, 0x00, 0xf2,
|
||||
0x80, 0x00, 0x00, 0xf5, 0x80, 0x00, 0x00, 0xf5, 0x80, 0x00, 0x00, 0xf5,
|
||||
|
|
@ -838,7 +838,7 @@ static const guint8 icon_open_data[] = {
|
|||
|
||||
/* width: 52, height: 48, rowstride: 208, n_channels: 4 */
|
||||
|
||||
static const guint8 icon_closed_data[] = {
|
||||
static const quint8 icon_closed_data[] = {
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2f, 0x4d, 0x18, 0x2b,
|
||||
0x2e, 0x50, 0x15, 0xb3, 0x2e, 0x51, 0x15, 0xda, 0x2d, 0x50, 0x16, 0xe3,
|
||||
0x2d, 0x50, 0x16, 0xe3, 0x2d, 0x50, 0x16, 0xe3, 0x2d, 0x50, 0x16, 0xe3,
|
||||
|
|
@ -1,304 +0,0 @@
|
|||
static const GdkPixdata icon_open_pixbuf = {
|
||||
0x47646b50, /* Pixbuf magic: 'GdkP' */
|
||||
24 + 3515, /* header length + pixel_data length */
|
||||
0x2010002, /* pixdata_type */
|
||||
192, /* rowstride */
|
||||
48, /* width */
|
||||
48, /* height */
|
||||
/* pixel_data: */
|
||||
(guint8 *)
|
||||
"\377\0\0\0\0\243\0\0\0\0\7;'\0\15}d\0\\\215q\0\210\210m\0\237\216q\0"
|
||||
"\231\211n\0\206y`\0=\247\0\0\0\0\3w^\0\\\262\216\0\336\356\277\0\376"
|
||||
"\206\377\314\0\377\3\310\240\0\365\217r\0\23033\0\5\226\0\0\0\0\1}c\0"
|
||||
"Z\204\205j\0\202\1x_\0f\206\0\0\0\0\3]K\0)\261\216\0\341\375\312\0\377"
|
||||
"\212\377\314\0\377\2\312\241\0\365u^\0W\206\0\0\0\0\1x`\0h\202\236~\0"
|
||||
"\300\1\243\203\0\307\204\250\206\0\317\4\256\214\0\327\261\215\0\335"
|
||||
"\265\220\0\330\207p\0\40\203\0\0\0\0\1\270\223\0\333\204\377\314\0\377"
|
||||
"\1\275\227\0\347\205\0\0\0\0\2t]\0X\336\261\0\374\215\377\314\0\377\2"
|
||||
"\367\306\0\377\210l\0\245\205\0\0\0\0\1\217r\0\226\212\377\314\0\377"
|
||||
"\1[I\0\34\203\0\0\0\0\1\252\210\0\316\204\377\314\0\377\1\270\223\0\345"
|
||||
"\204\0\0\0\0\2p[\0T\352\273\0\376\217\377\314\0\377\3\376\313\0\377\233"
|
||||
"|\0\307\0\0\0\2\203\0\0\0\0\1\205j\0}\211\377\314\0\377\2\366\305\0\377"
|
||||
"\0\0\0\1\203\0\0\0\0\1\232{\0\275\204\377\314\0\377\1\306\236\0\355\203"
|
||||
"\0\0\0\0\2hP\0\40\332\257\0\373\222\377\314\0\377\1\222t\0\270\203\0"
|
||||
"\0\0\0\1x`\0b\211\377\314\0\377\1\342\264\0\374\204\0\0\0\0\1\223u\0"
|
||||
"\243\204\377\314\0\377\1\333\260\0\373\203\0\0\0\0\1\252\210\0\330\223"
|
||||
"\377\314\0\377\2\374\312\0\377\201h\0\202\202\0\0\0\0\1zb\0^\211\377"
|
||||
"\314\0\377\1\317\246\0\366\204\0\0\0\0\1\212o\0\201\204\377\314\0\377"
|
||||
"\5\376\313\0\377\223t\0!\0\0\0\0hU\0B\372\310\0\377\224\377\314\0\377"
|
||||
"\4\333\257\0\374E;\0\32\0\0\0\0\214q\0q\211\377\314\0\377\1\266\222\0"
|
||||
"\341\204\0\0\0\0\1t^\0Q\205\377\314\0\377\3\232{\0\203\0\0\0\0\233|\0"
|
||||
"\306\226\377\314\0\377\3\234}\0\304\0\0\0\0\226x\0\210\211\377\314\0"
|
||||
"\377\1\241\201\0\274\204\0\0\0\0\2""3\"\0\17\367\306\0\377\204\377\314"
|
||||
"\0\377\3\256\213\0\315\0\0\0\0\325\252\0\372\205\377\314\0\377\5\376"
|
||||
"\313\0\377\322\251\0\365\262\216\0\325\264\220\0\324\376\313\0\377\204"
|
||||
"\377\314\0\377\13\365\304\0\377\245\205\0\312\223v\0{\210m\0g\230z\0"
|
||||
"\212\260\215\0\325\370\306\0\377\377\314\0\377\351\273\0\3765+\0\30\236"
|
||||
"\177\0\265\211\377\314\0\377\1\201h\0{\205\0\0\0\0\1\313\242\0\365\204"
|
||||
"\377\314\0\377\3\325\253\0\370F:\0,\374\312\0\377\203\377\314\0\377\3"
|
||||
"\344\266\0\374\242\202\0\276\202i\0\77\203\0\0\0\0\1\256\214\0\327\203"
|
||||
"\377\314\0\377\2\370\306\0\377\203i\0k\205\0\0\0\0\5\211m\0w\372\310"
|
||||
"\0\377\377\314\0\377\207l\0\227\257\215\0\335\210\377\314\0\377\2\366"
|
||||
"\305\0\377YC\0\27\205\0\0\0\0\1\245\204\0\315\205\377\314\0\377\1\222"
|
||||
"t\0\270\202\377\314\0\377\3\373\311\0\377\224w\0\237`@\0\10\205\0\0\0"
|
||||
"\0\5cN\0>\375\312\0\377\377\314\0\377\361\301\0\376\254\212\0\325\207"
|
||||
"\0\0\0\0\4\254\212\0\321\377\314\0\377\303\234\0\353\326\253\0\367\210"
|
||||
"\377\314\0\377\1\276\230\0\353\206\0\0\0\0\1\200e\0t\205\377\314\0\377"
|
||||
"\1\371\307\0\377\202\377\314\0\377\1\304\235\0\354\210\0\0\0\0\4\353"
|
||||
"\274\0\376\352\273\0\376\236}\0\277\231{\0\242\207\0\0\0\0\3w_\0V\377"
|
||||
"\314\0\377\374\312\0\377\211\377\314\0\377\1\217s\0\240\206\0\0\0\0\2"
|
||||
"..\0\13\350\271\0\375\204\377\314\0\377\4\354\275\0\376\357\277\0\376"
|
||||
"\377\314\0\377\263\217\0\333\207\0\0\0\0\5\0\0\0\5\317\245\0\364\301"
|
||||
"\232\0\345\213o\0\212\257\214\0\317\207\0\0\0\0\3\214q\0h\332\257\0\370"
|
||||
"\262\217\0\330\210\377\314\0\377\2\347\271\0\376F:\0\26\207\0\0\0\0\1"
|
||||
"\251\210\0\315\204\377\314\0\377\4\361\301\0\376\235~\0\266\377\314\0"
|
||||
"\377\276\230\0\344\207\0\0\0\0\6yb\0""9\267\222\0\343\244\203\0\312q"
|
||||
"Z\0O\332\256\0\371\0\0\0\1\206\0\0\0\0\3\236~\0\250\263\220\0\327\271"
|
||||
"\224\0\363\210\377\314\0\377\1\234}\0\314\210\0\0\0\0\2w^\0I\375\312"
|
||||
"\0\377\204\377\314\0\377\4~e\0\232\377\314\0\377\332\256\0\371U9\0\11"
|
||||
"\206\0\0\0\0\6\216q\0s\243\202\0\310\202h\0\253-\36\0\21\372\310\0\377"
|
||||
"\205k\0d\205\0\0\0\0\4\211n\0a\351\272\0\374\245\205\0\314\303\234\0"
|
||||
"\361\207\377\314\0\377\2\371\307\0\377^K\0D\211\0\0\0\0\1\273\225\0\347"
|
||||
"\204\377\314\0\377\1\200g\0\225\202\377\314\0\377\2\305\235\0\355{a\0"
|
||||
"Y\205\0\0\0\0\6\240\200\0\256\222t\0\242C5\0""5\0\0\0\0\340\263\0\374"
|
||||
"\262\217\0\330\203\0\0\0\0\6\210n\0k\300\232\0\352\375\312\0\377\377"
|
||||
"\314\0\377\263\217\0\333\267\223\0\347\207\377\314\0\377\1\256\213\0"
|
||||
"\331\212\0\0\0\0\2\201f\0U\374\312\0\377\203\377\314\0\377\2\221s\0\222"
|
||||
"\372\310\0\377\203\377\314\0\377\7\321\247\0\371\226x\0\266kR\0\37\0"
|
||||
"\0\0\0\0\0\0\1\306\236\0\355\205j\0o\202\0\0\0\0\5\312\241\0\357\366"
|
||||
"\305\0\377\214q\0o\221u\0\216\301\232\0\353\204\377\314\0\377\2\277\231"
|
||||
"\0\353\255\213\0\327\206\377\314\0\377\2\353\274\0\376[J\0-\213\0\0\0"
|
||||
"\0\1\250\207\0\326\203\377\314\0\377\2\226x\0\241\360\300\0\377\205\377"
|
||||
"\314\0\377\5\362\302\0\376\301\233\0\347\322\250\0\363\377\314\0\377"
|
||||
"\214p\0R\202\0\0\0\0\1\265\221\0\331\210\377\314\0\377\2\307\237\0\367"
|
||||
"\252\211\0\276\206\377\314\0\377\1\213o\0\267\214\0\0\0\0\2m[\0\34\334"
|
||||
"\260\0\372\202\377\314\0\377\2\233}\0\260\346\270\0\377\211\377\314\0"
|
||||
"\377\1\213o\0\\\202\0\0\0\0\1\303\234\0\342\210\377\314\0\377\2\323\251"
|
||||
"\0\372\251\207\0\300\205\377\314\0\377\2\320\247\0\366..\0\13\215\0\0"
|
||||
"\0\0\5r\\\0^\364\303\0\377\377\314\0\377\253\210\0\310\312\242\0\366"
|
||||
"\211\377\314\0\377\1\220s\0\225\202\0\0\0\0\1\353\274\0\374\210\377\314"
|
||||
"\0\377\2\274\226\0\356\276\227\0\342\204\377\314\0\377\2\355\276\0\377"
|
||||
"s[\0I\217\0\0\0\0\4\202h\0\207\371\307\0\377\331\256\0\370\237\200\0"
|
||||
"\310\211\377\314\0\377\3\266\222\0\340WI\0#\201i\0I\211\377\314\0\377"
|
||||
"\2\217r\0\260\354\275\0\376\203\377\314\0\377\2\374\312\0\377zb\0\227"
|
||||
"\221\0\0\0\0\3\205j\0\225\370\306\0\377\311\241\0\362\211\377\314\0\377"
|
||||
"\3\363\302\0\377\227x\0\260\302\234\0\357\210\377\314\0\377\2\361\301"
|
||||
"\0\376\320\246\0\362\204\377\314\0\377\1\243\201\0\301\223\0\0\0\0\2"
|
||||
"\177e\0\203\361\301\0\377\212\377\314\0\377\1\371\307\0\377\216\377\314"
|
||||
"\0\377\2\243\203\0\313\0\0\0\1\224\0\0\0\0\2s[\0_\332\257\0\373\226\377"
|
||||
"\314\0\377\2\362\302\0\377\223v\0\236\227\0\0\0\0\23`P\0\40\263\217\0"
|
||||
"\342\366\305\0\377\331\256\0\371\367\306\0\377\340\263\0\373\336\262"
|
||||
"\0\373\377\314\0\377\256\213\0\325\204j\0Y\336\262\0\373\201f\0K\231"
|
||||
"z\0\235\373\311\0\377\271\225\0\337\353\273\0\375\376\313\0\377\322\250"
|
||||
"\0\370\376\313\0\377\203\377\314\0\377\2\302\233\0\362zb\0I\205\0\0\0"
|
||||
"\0\4bQ\0""9\200f\0\200mX\0b@@\0\10\211\0\0\0\0\5]M\0!\215q\0\243\245"
|
||||
"\203\0\316\224w\0\247..\0\13\203\0\0\0\0\6\241\201\0\307\0\0\0\0\245"
|
||||
"\204\0\301\203g\0T]F\0\13\314\244\0\366\202\0\0\0\0\1\277\230\0\347\202"
|
||||
"\0\0\0\0\12\305\235\0\355\0\0\0\0\233|\0\244\243\203\0\257\0\0\0\0\342"
|
||||
"\266\0\372\377\314\0\377\317\246\0\370\207l\0\223\0\0\0\4\205\0\0\0\0"
|
||||
"\2\230z\0\270\367\306\0\377\202\377\314\0\377\2\322\250\0\370r\\\0:\207"
|
||||
"\0\0\0\0\2\201f\0}\343\266\0\376\203\377\314\0\377\2\264\220\0\352\0"
|
||||
"\0\0\2\202\0\0\0\0\6\212o\0\263zb\0A\262\217\0\323\200e\0:33\0\5\262"
|
||||
"\216\0\340\202\0\0\0\0\1\301\232\0\346\202\0\0\0\0\10\271\224\0\344\0"
|
||||
"\0\0\0\231z\0\226\212n\0\213\0\0\0\0\304\235\0\351\202h\0x\0\0\0\3\206"
|
||||
"\0\0\0\0\2\200f\0\200\376\313\0\377\204\377\314\0\377\1\306\236\0\362"
|
||||
"\206\0\0\0\0\2cN\0$\355\276\0\376\205\377\314\0\377\1r[\0b\202\0\0\0"
|
||||
"\0\21@@\0\4\221t\0\247\245\204\0\315\250\206\0\334\266\222\0\343\315"
|
||||
"\244\0\366\253\210\0\325\245\203\0\306\336\261\0\374\221t\0\253\226x"
|
||||
"\0\263\353\274\0\376\245\204\0\313\311\240\0\360\270\224\0\347\262\216"
|
||||
"\0\335\220t\0\254\210\0\0\0\0\1\274\227\0\351\206\377\314\0\377\1gS\0"
|
||||
"4\205\0\0\0\0\1\215p\0\177\206\377\314\0\377\1\201f\0}\205\0\0\0\0\27"
|
||||
"\0\0\0\1\40\40\0\20\0\0\0\0\13\13\0\30mU\0""6\225x\0F\201h\0goY\0g0\40"
|
||||
"\0\20:.\0B/&\0""6\25\16\0%I=\0;\0\0\0\3\0\0\0\0\\G\0\31r[\0LoX\0N\202"
|
||||
"h\0V\215r\0\\\201h\0e\207l\0q\347\270\0\375\205\377\314\0\377\2\371\307"
|
||||
"\0\377H8\0\40\205\0\0\0\0\1u]\0U\206\377\314\0\377\4\333\260\0\373\322"
|
||||
"\250\0\370\333\257\0\372\340\263\0\374\202\337\262\0\375\12\233|\0\321"
|
||||
"\0\0\0\0cU\0\22\306\236\0\364\354\275\0\376\357\277\0\377\377\314\0\377"
|
||||
"\226x\0\233\212o\0\263\356\276\0\377\203\377\314\0\377\4\224v\0\253\0"
|
||||
"\0\0\0p[\0;\357\277\0\376\213\377\314\0\377\1\261\215\0\344\207\0\0\0"
|
||||
"\0\2\227y\0\272\334\260\0\372\211\377\314\0\377\4\355\276\0\376gS\0""4"
|
||||
"\0\0\0\0\242\202\0\306\203\377\314\0\377\4\312\242\0\360\200\200\0\2"
|
||||
"@0\0\20\332\257\0\373\203\377\314\0\377\4\362\302\0\377z`\0E\0\0\0\0"
|
||||
"\225x\0\244\212\377\314\0\377\2\374\312\0\377ya\0T\206\0\0\0\0\2$$\0"
|
||||
"\7\242\202\0\327\212\377\314\0\377\4\230y\0\255\0\0\0\0u]\0U\370\306"
|
||||
"\0\377\202\377\314\0\377\2\371\307\0\377\200f\0P\202\0\0\0\0\2\202h\0"
|
||||
"\207\376\313\0\377\203\377\314\0\377\4\315\244\0\363U9\0\11\0\0\0\1\304"
|
||||
"\235\0\355\211\377\314\0\377\3\346\267\0\375\305\235\0\363aO\0\35\205"
|
||||
"\0\0\0\0\1\230z\0\274\212\377\314\0\377\4\317\245\0\364UU\0\6\0\0\0\2"
|
||||
"\304\235\0\362\203\377\314\0\377\1\251\206\0\311\203\0\0\0\0\2\0\0\0"
|
||||
"\1\255\212\0\351\204\377\314\0\377\4\255\213\0\320]F\0\13y_\0;\361\301"
|
||||
"\0\376\203\377\314\0\377\1\367\306\0\377\206\377\314\0\377\1\234}\0\260"
|
||||
"\205\0\0\0\0\1\315\244\0\366\205\377\314\0\377\2\233|\0\304\333\257\0"
|
||||
"\371\202\322\250\0\370\5\310\240\0\367\201h\0]t\\\0V\240\200\0\301\327"
|
||||
"\254\0\371\202\377\314\0\377\2\345\267\0\375dN\0\27\204\0\0\0\0\2M\77"
|
||||
"\0""5\320\246\0\367\204\377\314\0\377\3\324\251\0\372pZ\0[\217r\0\217"
|
||||
"\202\261\215\0\335\2\242\201\0\305\307\240\0\356\206\377\314\0\377\1"
|
||||
"\237\177\0\305\205\0\0\0\0\1\275\226\0\352\205\377\314\0\377\1\236~\0"
|
||||
"\302\204\0\0\0\0\2\211n\0\204\367\306\0\377\205\377\314\0\377\1\250\206"
|
||||
"\0\334\204\0\0\0\0\2\200e\0t\375\312\0\377\205\377\314\0\377\2\344\266"
|
||||
"\0\375ZE\0%\203\0\0\0\0\1\264\220\0\341\205\377\314\0\377\2\376\313\0"
|
||||
"\377q[\0j\205\0\0\0\0\2\202g\0~\376\313\0\377\204\377\314\0\377\1\234"
|
||||
"}\0\302\204\0\0\0\0\1\301\232\0\356\206\377\314\0\377\1\305\235\0\363"
|
||||
"\204\0\0\0\0\1\252\210\0\331\207\377\314\0\377\1\216q\0\253\203\0\0\0"
|
||||
"\0\2t\\\0l\360\300\0\377\203\377\314\0\377\2\376\313\0\377\233|\0\311"
|
||||
"\207\0\0\0\0\2\230y\0\276\376\313\0\377\202\377\314\0\377\2\355\276\0"
|
||||
"\376hR\0;\204\0\0\0\0\1\275\230\0\355\202\377\314\0\377\5\325\252\0\371"
|
||||
"\327\253\0\367\377\314\0\377\374\312\0\377\211n\0\240\204\0\0\0\0\2\205"
|
||||
"k\0\224\376\313\0\377\202\377\314\0\377\2\333\260\0\373\323\251\0\365"
|
||||
"\202\377\314\0\377\1\221t\0\236\204\0\0\0\0\5s\\\0P\254\211\0\331\263"
|
||||
"\220\0\345\235~\0\311qY\0a\211\0\0\0\0\4\200h\0\205\301\232\0\356\275"
|
||||
"\227\0\353w_\0^\205\0\0\0\0\7zc\0w\366\305\0\377\354\275\0\376\206k\0"
|
||||
"z\205k\0\224\252\210\0\326xa\0l\206\0\0\0\0\10\201g\0y\247\206\0\316"
|
||||
"\224w\0\245ZJ\0\37\245\205\0\333\376\313\0\377\302\234\0\357dN\0\27\234"
|
||||
"\0\0\0\0\2QA\0/9+\0\22\217\0\0\0\0\2""7)\0%\0\0\0\1\377\0\0\0\0\376\0"
|
||||
"\0\0\0",
|
||||
};
|
||||
|
||||
static const GdkPixdata icon_closed_pixbuf = {
|
||||
0x47646b50, /* Pixbuf magic: 'GdkP' */
|
||||
24 + 3515, /* header length + pixel_data length */
|
||||
0x2010002, /* pixdata_type */
|
||||
192, /* rowstride */
|
||||
48, /* width */
|
||||
48, /* height */
|
||||
/* pixel_data: */
|
||||
(guint8 *)
|
||||
"\377\0\0\0\0\243\0\0\0\0\7;\0\0\15}\0\0\\\215\0\0\210\210\0\0\237\216"
|
||||
"\0\0\231\211\0\0\206y\0\0=\247\0\0\0\0\3w\0\0\\\262\0\0\336\356\0\0\376"
|
||||
"\206\377\0\0\377\3\310\0\0\365\217\0\0\2303\0\0\5\226\0\0\0\0\1}\0\0"
|
||||
"Z\204\205\0\0\202\1x\0\0f\206\0\0\0\0\3]\0\0)\261\0\0\341\375\0\0\377"
|
||||
"\212\377\0\0\377\2\312\0\0\365u\0\0W\206\0\0\0\0\1x\0\0h\202\236\0\0"
|
||||
"\300\1\243\0\0\307\204\250\0\0\317\4\256\0\0\327\261\0\0\335\265\0\0"
|
||||
"\330\207\0\0\40\203\0\0\0\0\1\270\0\0\333\204\377\0\0\377\1\275\0\0\347"
|
||||
"\205\0\0\0\0\2t\0\0X\336\0\0\374\215\377\0\0\377\2\367\0\0\377\210\0"
|
||||
"\0\245\205\0\0\0\0\1\217\0\0\226\212\377\0\0\377\1[\0\0\34\203\0\0\0"
|
||||
"\0\1\252\0\0\316\204\377\0\0\377\1\270\0\0\345\204\0\0\0\0\2p\0\0T\352"
|
||||
"\0\0\376\217\377\0\0\377\3\376\0\0\377\233\0\0\307\0\0\0\2\203\0\0\0"
|
||||
"\0\1\205\0\0}\211\377\0\0\377\2\366\0\0\377\0\0\0\1\203\0\0\0\0\1\232"
|
||||
"\0\0\275\204\377\0\0\377\1\306\0\0\355\203\0\0\0\0\2h\0\0\40\332\0\0"
|
||||
"\373\222\377\0\0\377\1\222\0\0\270\203\0\0\0\0\1x\0\0b\211\377\0\0\377"
|
||||
"\1\342\0\0\374\204\0\0\0\0\1\223\0\0\243\204\377\0\0\377\1\333\0\0\373"
|
||||
"\203\0\0\0\0\1\252\0\0\330\223\377\0\0\377\2\374\0\0\377\201\0\0\202"
|
||||
"\202\0\0\0\0\1z\0\0^\211\377\0\0\377\1\317\0\0\366\204\0\0\0\0\1\212"
|
||||
"\0\0\201\204\377\0\0\377\5\376\0\0\377\223\0\0!\0\0\0\0h\0\0B\372\0\0"
|
||||
"\377\224\377\0\0\377\4\333\0\0\374E\0\0\32\0\0\0\0\214\0\0q\211\377\0"
|
||||
"\0\377\1\266\0\0\341\204\0\0\0\0\1t\0\0Q\205\377\0\0\377\3\232\0\0\203"
|
||||
"\0\0\0\0\233\0\0\306\226\377\0\0\377\3\234\0\0\304\0\0\0\0\226\0\0\210"
|
||||
"\211\377\0\0\377\1\241\0\0\274\204\0\0\0\0\2""3\0\0\17\367\0\0\377\204"
|
||||
"\377\0\0\377\3\256\0\0\315\0\0\0\0\325\0\0\372\205\377\0\0\377\5\376"
|
||||
"\0\0\377\322\0\0\365\262\0\0\325\264\0\0\324\376\0\0\377\204\377\0\0"
|
||||
"\377\13\365\0\0\377\245\0\0\312\223\0\0{\210\0\0g\230\0\0\212\260\0\0"
|
||||
"\325\370\0\0\377\377\0\0\377\351\0\0\3765\0\0\30\236\0\0\265\211\377"
|
||||
"\0\0\377\1\201\0\0{\205\0\0\0\0\1\313\0\0\365\204\377\0\0\377\3\325\0"
|
||||
"\0\370F\0\0,\374\0\0\377\203\377\0\0\377\3\344\0\0\374\242\0\0\276\202"
|
||||
"\0\0\77\203\0\0\0\0\1\256\0\0\327\203\377\0\0\377\2\370\0\0\377\203\0"
|
||||
"\0k\205\0\0\0\0\5\211\0\0w\372\0\0\377\377\0\0\377\207\0\0\227\257\0"
|
||||
"\0\335\210\377\0\0\377\2\366\0\0\377Y\0\0\27\205\0\0\0\0\1\245\0\0\315"
|
||||
"\205\377\0\0\377\1\222\0\0\270\202\377\0\0\377\3\373\0\0\377\224\0\0"
|
||||
"\237`\0\0\10\205\0\0\0\0\5c\0\0>\375\0\0\377\377\0\0\377\361\0\0\376"
|
||||
"\254\0\0\325\207\0\0\0\0\4\254\0\0\321\377\0\0\377\303\0\0\353\326\0"
|
||||
"\0\367\210\377\0\0\377\1\276\0\0\353\206\0\0\0\0\1\200\0\0t\205\377\0"
|
||||
"\0\377\1\371\0\0\377\202\377\0\0\377\1\304\0\0\354\210\0\0\0\0\4\353"
|
||||
"\0\0\376\352\0\0\376\236\0\0\277\231\0\0\242\207\0\0\0\0\3w\0\0V\377"
|
||||
"\0\0\377\374\0\0\377\211\377\0\0\377\1\217\0\0\240\206\0\0\0\0\2.\0\0"
|
||||
"\13\350\0\0\375\204\377\0\0\377\4\354\0\0\376\357\0\0\376\377\0\0\377"
|
||||
"\263\0\0\333\207\0\0\0\0\5\0\0\0\5\317\0\0\364\301\0\0\345\213\0\0\212"
|
||||
"\257\0\0\317\207\0\0\0\0\3\214\0\0h\332\0\0\370\262\0\0\330\210\377\0"
|
||||
"\0\377\2\347\0\0\376F\0\0\26\207\0\0\0\0\1\251\0\0\315\204\377\0\0\377"
|
||||
"\4\361\0\0\376\235\0\0\266\377\0\0\377\276\0\0\344\207\0\0\0\0\6y\0\0"
|
||||
"9\267\0\0\343\244\0\0\312q\0\0O\332\0\0\371\0\0\0\1\206\0\0\0\0\3\236"
|
||||
"\0\0\250\263\0\0\327\271\0\0\363\210\377\0\0\377\1\234\0\0\314\210\0"
|
||||
"\0\0\0\2w\0\0I\375\0\0\377\204\377\0\0\377\4~\0\0\232\377\0\0\377\332"
|
||||
"\0\0\371U\0\0\11\206\0\0\0\0\6\216\0\0s\243\0\0\310\202\0\0\253-\0\0"
|
||||
"\21\372\0\0\377\205\0\0d\205\0\0\0\0\4\211\0\0a\351\0\0\374\245\0\0\314"
|
||||
"\303\0\0\361\207\377\0\0\377\2\371\0\0\377^\0\0D\211\0\0\0\0\1\273\0"
|
||||
"\0\347\204\377\0\0\377\1\200\0\0\225\202\377\0\0\377\2\305\0\0\355{\0"
|
||||
"\0Y\205\0\0\0\0\6\240\0\0\256\222\0\0\242C\0\0""5\0\0\0\0\340\0\0\374"
|
||||
"\262\0\0\330\203\0\0\0\0\6\210\0\0k\300\0\0\352\375\0\0\377\377\0\0\377"
|
||||
"\263\0\0\333\267\0\0\347\207\377\0\0\377\1\256\0\0\331\212\0\0\0\0\2"
|
||||
"\201\0\0U\374\0\0\377\203\377\0\0\377\2\221\0\0\222\372\0\0\377\203\377"
|
||||
"\0\0\377\7\321\0\0\371\226\0\0\266k\0\0\37\0\0\0\0\0\0\0\1\306\0\0\355"
|
||||
"\205\0\0o\202\0\0\0\0\5\312\0\0\357\366\0\0\377\214\0\0o\221\0\0\216"
|
||||
"\301\0\0\353\204\377\0\0\377\2\277\0\0\353\255\0\0\327\206\377\0\0\377"
|
||||
"\2\353\0\0\376[\0\0-\213\0\0\0\0\1\250\0\0\326\203\377\0\0\377\2\226"
|
||||
"\0\0\241\360\0\0\377\205\377\0\0\377\5\362\0\0\376\301\0\0\347\322\0"
|
||||
"\0\363\377\0\0\377\214\0\0R\202\0\0\0\0\1\265\0\0\331\210\377\0\0\377"
|
||||
"\2\307\0\0\367\252\0\0\276\206\377\0\0\377\1\213\0\0\267\214\0\0\0\0"
|
||||
"\2m\0\0\34\334\0\0\372\202\377\0\0\377\2\233\0\0\260\346\0\0\377\211"
|
||||
"\377\0\0\377\1\213\0\0\\\202\0\0\0\0\1\303\0\0\342\210\377\0\0\377\2"
|
||||
"\323\0\0\372\251\0\0\300\205\377\0\0\377\2\320\0\0\366.\0\0\13\215\0"
|
||||
"\0\0\0\5r\0\0^\364\0\0\377\377\0\0\377\253\0\0\310\312\0\0\366\211\377"
|
||||
"\0\0\377\1\220\0\0\225\202\0\0\0\0\1\353\0\0\374\210\377\0\0\377\2\274"
|
||||
"\0\0\356\276\0\0\342\204\377\0\0\377\2\355\0\0\377s\0\0I\217\0\0\0\0"
|
||||
"\4\202\0\0\207\371\0\0\377\331\0\0\370\237\0\0\310\211\377\0\0\377\3"
|
||||
"\266\0\0\340W\0\0#\201\0\0I\211\377\0\0\377\2\217\0\0\260\354\0\0\376"
|
||||
"\203\377\0\0\377\2\374\0\0\377z\0\0\227\221\0\0\0\0\3\205\0\0\225\370"
|
||||
"\0\0\377\311\0\0\362\211\377\0\0\377\3\363\0\0\377\227\0\0\260\302\0"
|
||||
"\0\357\210\377\0\0\377\2\361\0\0\376\320\0\0\362\204\377\0\0\377\1\243"
|
||||
"\0\0\301\223\0\0\0\0\2\177\0\0\203\361\0\0\377\212\377\0\0\377\1\371"
|
||||
"\0\0\377\216\377\0\0\377\2\243\0\0\313\0\0\0\1\224\0\0\0\0\2s\0\0_\332"
|
||||
"\0\0\373\226\377\0\0\377\2\362\0\0\377\223\0\0\236\227\0\0\0\0\23`\0"
|
||||
"\0\40\263\0\0\342\366\0\0\377\331\0\0\371\367\0\0\377\340\0\0\373\336"
|
||||
"\0\0\373\377\0\0\377\256\0\0\325\204\0\0Y\336\0\0\373\201\0\0K\231\0"
|
||||
"\0\235\373\0\0\377\271\0\0\337\353\0\0\375\376\0\0\377\322\0\0\370\376"
|
||||
"\0\0\377\203\377\0\0\377\2\302\0\0\362z\0\0I\205\0\0\0\0\4b\0\0""9\200"
|
||||
"\0\0\200m\0\0b@\0\0\10\211\0\0\0\0\5]\0\0!\215\0\0\243\245\0\0\316\224"
|
||||
"\0\0\247.\0\0\13\203\0\0\0\0\6\241\0\0\307\0\0\0\0\245\0\0\301\203\0"
|
||||
"\0T]\0\0\13\314\0\0\366\202\0\0\0\0\1\277\0\0\347\202\0\0\0\0\12\305"
|
||||
"\0\0\355\0\0\0\0\233\0\0\244\243\0\0\257\0\0\0\0\342\0\0\372\377\0\0"
|
||||
"\377\317\0\0\370\207\0\0\223\0\0\0\4\205\0\0\0\0\2\230\0\0\270\367\0"
|
||||
"\0\377\202\377\0\0\377\2\322\0\0\370r\0\0:\207\0\0\0\0\2\201\0\0}\343"
|
||||
"\0\0\376\203\377\0\0\377\2\264\0\0\352\0\0\0\2\202\0\0\0\0\6\212\0\0"
|
||||
"\263z\0\0A\262\0\0\323\200\0\0:3\0\0\5\262\0\0\340\202\0\0\0\0\1\301"
|
||||
"\0\0\346\202\0\0\0\0\10\271\0\0\344\0\0\0\0\231\0\0\226\212\0\0\213\0"
|
||||
"\0\0\0\304\0\0\351\202\0\0x\0\0\0\3\206\0\0\0\0\2\200\0\0\200\376\0\0"
|
||||
"\377\204\377\0\0\377\1\306\0\0\362\206\0\0\0\0\2c\0\0$\355\0\0\376\205"
|
||||
"\377\0\0\377\1r\0\0b\202\0\0\0\0\21@\0\0\4\221\0\0\247\245\0\0\315\250"
|
||||
"\0\0\334\266\0\0\343\315\0\0\366\253\0\0\325\245\0\0\306\336\0\0\374"
|
||||
"\221\0\0\253\226\0\0\263\353\0\0\376\245\0\0\313\311\0\0\360\270\0\0"
|
||||
"\347\262\0\0\335\220\0\0\254\210\0\0\0\0\1\274\0\0\351\206\377\0\0\377"
|
||||
"\1g\0\0""4\205\0\0\0\0\1\215\0\0\177\206\377\0\0\377\1\201\0\0}\205\0"
|
||||
"\0\0\0\27\0\0\0\1\40\0\0\20\0\0\0\0\13\0\0\30m\0\0""6\225\0\0F\201\0"
|
||||
"\0go\0\0g0\0\0\20:\0\0B/\0\0""6\25\0\0%I\0\0;\0\0\0\3\0\0\0\0\\\0\0\31"
|
||||
"r\0\0Lo\0\0N\202\0\0V\215\0\0\\\201\0\0e\207\0\0q\347\0\0\375\205\377"
|
||||
"\0\0\377\2\371\0\0\377H\0\0\40\205\0\0\0\0\1u\0\0U\206\377\0\0\377\4"
|
||||
"\333\0\0\373\322\0\0\370\333\0\0\372\340\0\0\374\202\337\0\0\375\12\233"
|
||||
"\0\0\321\0\0\0\0c\0\0\22\306\0\0\364\354\0\0\376\357\0\0\377\377\0\0"
|
||||
"\377\226\0\0\233\212\0\0\263\356\0\0\377\203\377\0\0\377\4\224\0\0\253"
|
||||
"\0\0\0\0p\0\0;\357\0\0\376\213\377\0\0\377\1\261\0\0\344\207\0\0\0\0"
|
||||
"\2\227\0\0\272\334\0\0\372\211\377\0\0\377\4\355\0\0\376g\0\0""4\0\0"
|
||||
"\0\0\242\0\0\306\203\377\0\0\377\4\312\0\0\360\200\0\0\2@\0\0\20\332"
|
||||
"\0\0\373\203\377\0\0\377\4\362\0\0\377z\0\0E\0\0\0\0\225\0\0\244\212"
|
||||
"\377\0\0\377\2\374\0\0\377y\0\0T\206\0\0\0\0\2$\0\0\7\242\0\0\327\212"
|
||||
"\377\0\0\377\4\230\0\0\255\0\0\0\0u\0\0U\370\0\0\377\202\377\0\0\377"
|
||||
"\2\371\0\0\377\200\0\0P\202\0\0\0\0\2\202\0\0\207\376\0\0\377\203\377"
|
||||
"\0\0\377\4\315\0\0\363U\0\0\11\0\0\0\1\304\0\0\355\211\377\0\0\377\3"
|
||||
"\346\0\0\375\305\0\0\363a\0\0\35\205\0\0\0\0\1\230\0\0\274\212\377\0"
|
||||
"\0\377\4\317\0\0\364U\0\0\6\0\0\0\2\304\0\0\362\203\377\0\0\377\1\251"
|
||||
"\0\0\311\203\0\0\0\0\2\0\0\0\1\255\0\0\351\204\377\0\0\377\4\255\0\0"
|
||||
"\320]\0\0\13y\0\0;\361\0\0\376\203\377\0\0\377\1\367\0\0\377\206\377"
|
||||
"\0\0\377\1\234\0\0\260\205\0\0\0\0\1\315\0\0\366\205\377\0\0\377\2\233"
|
||||
"\0\0\304\333\0\0\371\202\322\0\0\370\5\310\0\0\367\201\0\0]t\0\0V\240"
|
||||
"\0\0\301\327\0\0\371\202\377\0\0\377\2\345\0\0\375d\0\0\27\204\0\0\0"
|
||||
"\0\2M\0\0""5\320\0\0\367\204\377\0\0\377\3\324\0\0\372p\0\0[\217\0\0"
|
||||
"\217\202\261\0\0\335\2\242\0\0\305\307\0\0\356\206\377\0\0\377\1\237"
|
||||
"\0\0\305\205\0\0\0\0\1\275\0\0\352\205\377\0\0\377\1\236\0\0\302\204"
|
||||
"\0\0\0\0\2\211\0\0\204\367\0\0\377\205\377\0\0\377\1\250\0\0\334\204"
|
||||
"\0\0\0\0\2\200\0\0t\375\0\0\377\205\377\0\0\377\2\344\0\0\375Z\0\0%\203"
|
||||
"\0\0\0\0\1\264\0\0\341\205\377\0\0\377\2\376\0\0\377q\0\0j\205\0\0\0"
|
||||
"\0\2\202\0\0~\376\0\0\377\204\377\0\0\377\1\234\0\0\302\204\0\0\0\0\1"
|
||||
"\301\0\0\356\206\377\0\0\377\1\305\0\0\363\204\0\0\0\0\1\252\0\0\331"
|
||||
"\207\377\0\0\377\1\216\0\0\253\203\0\0\0\0\2t\0\0l\360\0\0\377\203\377"
|
||||
"\0\0\377\2\376\0\0\377\233\0\0\311\207\0\0\0\0\2\230\0\0\276\376\0\0"
|
||||
"\377\202\377\0\0\377\2\355\0\0\376h\0\0;\204\0\0\0\0\1\275\0\0\355\202"
|
||||
"\377\0\0\377\5\325\0\0\371\327\0\0\367\377\0\0\377\374\0\0\377\211\0"
|
||||
"\0\240\204\0\0\0\0\2\205\0\0\224\376\0\0\377\202\377\0\0\377\2\333\0"
|
||||
"\0\373\323\0\0\365\202\377\0\0\377\1\221\0\0\236\204\0\0\0\0\5s\0\0P"
|
||||
"\254\0\0\331\263\0\0\345\235\0\0\311q\0\0a\211\0\0\0\0\4\200\0\0\205"
|
||||
"\301\0\0\356\275\0\0\353w\0\0^\205\0\0\0\0\7z\0\0w\366\0\0\377\354\0"
|
||||
"\0\376\206\0\0z\205\0\0\224\252\0\0\326x\0\0l\206\0\0\0\0\10\201\0\0"
|
||||
"y\247\0\0\316\224\0\0\245Z\0\0\37\245\0\0\333\376\0\0\377\302\0\0\357"
|
||||
"d\0\0\27\234\0\0\0\0\2Q\0\0/9\0\0\22\217\0\0\0\0\2""7\0\0%\0\0\0\1\377"
|
||||
"\0\0\0\0\376\0\0\0\0",
|
||||
};
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue