diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 4f72f3af4475d612007a6c6956e9b970e6c36d84..3f393253eedbd4cbe0a2bc563f6871af26f41e10 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -94,7 +94,7 @@ amd64:windows.release:
       - *fill_version_mk
     script:
       - echo "Do hard work"
-      - ./prod_build/build.sh --target windows release #-DBUILD_DIAGTOOL=ON
+      - ./prod_build/build.sh --target windows release -DBUILD_DIAGTOOL=ON
       - ./prod_build/pack.sh --target windows release 
       - /opt/buildtools/deploy_files.sh pub_cellframe windows/cellframe-node/$CI_COMMIT_REF_NAME/ build_*/*.exe 
       - /opt/buildtools/deploy_files.sh pub_cellframe windows/cellframe-node/$CI_COMMIT_REF_NAME/  build_windows_release/*.exe --redirect-from windows/cellframe-node/$CI_COMMIT_REF_NAME/latest-amd64
diff --git a/.gitmodules b/.gitmodules
index 82cf9a8b6360bb5ad9c1bcb74b1caa4b7696f6e9..1cc6d724b5dff3a7a9993c0869fc918cecdca422 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -13,3 +13,6 @@
 	path = dap-sdk
 	url = ../../dap/dap-sdk.git
 	branch = develop
+[submodule "diagtool"]
+	path = diagtool
+	url = https://gitlab.demlabs.net/cellframe/cellframe-node-diagtool.git
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 7286e454263e569e6a64babe94fbc9f017719408..d6e542ff8bc5d3d2d58a533866233b65e1dbf0f6 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -392,11 +392,7 @@ else()
     INSTALL(TARGETS ${NODE_TOOL_TARGET} DESTINATION ${CMAKE_INSTALL_PREFIX}/bin )
     
     if (BUILD_DIAGTOOL)
-        if(WIN32)
-            INSTALL(TARGETS cellframe-diagtool.exe DESTINATION ${CMAKE_INSTALL_PREFIX}/bin )
-        else()
             INSTALL(TARGETS cellframe-diagtool DESTINATION ${CMAKE_INSTALL_PREFIX}/bin )
-        endif()
     endif()
 
     INSTALL(TARGETS cellframe-node-config DESTINATION ${CMAKE_INSTALL_PREFIX}/bin )
diff --git a/diagtool b/diagtool
new file mode 160000
index 0000000000000000000000000000000000000000..70063b2e882787ce7a87b8669a102947c4755408
--- /dev/null
+++ b/diagtool
@@ -0,0 +1 @@
+Subproject commit 70063b2e882787ce7a87b8669a102947c4755408
diff --git a/diagtool/AbstractDiagnostic.cpp b/diagtool/AbstractDiagnostic.cpp
deleted file mode 100644
index b8981acfc963b7d6f5f93a037e8a851e04660a7c..0000000000000000000000000000000000000000
--- a/diagtool/AbstractDiagnostic.cpp
+++ /dev/null
@@ -1,407 +0,0 @@
-#include "AbstractDiagnostic.h"
-
-#ifdef Q_OS_LINUX
-
-#elif defined(Q_OS_WIN)
-#include "registry.h"
-#elif defined(Q_OS_MACOS)
-#include "dap_common.h"
-#endif
-
-AbstractDiagnostic::AbstractDiagnostic(QObject *parent)
-    :QObject(parent)
-{
-#ifdef Q_OS_LINUX
-    s_nodeDataPath = "/opt/cellframe-node";
-#elif defined(Q_OS_WIN)
-    s_nodeDataPath = QString("%1/cellframe-node").arg(regGetUsrPath());
-#elif defined(Q_OS_MACOS)
-    s_nodeDataPath = QString("Applications/CellframeNode.app/Contents/Resources/");
-#endif
-    s_timer_update = new QTimer();
-    s_mac = get_mac();
-}
-
-AbstractDiagnostic::~AbstractDiagnostic()
-{
-    delete s_timer_update;
-}
-
-void AbstractDiagnostic::set_timeout(int timeout){
-    s_timer_update->stop();
-    s_timeout = timeout;
-    s_timer_update->start(s_timeout);
-}
-
-void AbstractDiagnostic::start_diagnostic()
-{
-    s_timer_update->start(s_timeout);
-}
-
-void AbstractDiagnostic::stop_diagnostic()
-{
-    s_timer_update->stop();
-}
-
-QJsonValue AbstractDiagnostic::get_mac()
-{
-    QString MAC{"unknown"};
-    foreach(QNetworkInterface netInterface, QNetworkInterface::allInterfaces())
-    {
-        // Return only the first non-loopback MAC Address
-        if (!(netInterface.flags() & QNetworkInterface::IsLoopBack))
-        {
-            qDebug()<<netInterface.hardwareAddress();
-            if(!netInterface.hardwareAddress().isEmpty())
-            {
-                MAC = netInterface.hardwareAddress();
-                break;
-            }
-        }
-    }
-
-    return MAC;
-}
-
-QString AbstractDiagnostic::get_uptime_string(long sec)
-{
-    QTime time(0, 0);
-    time = time.addSecs(sec);
-    int fullHours = sec/3600;
-
-    QString uptime = QString("%1:").arg(fullHours) + time.toString("mm:ss");
-
-    return uptime;
-}
-
-quint64 AbstractDiagnostic::get_file_size (QString flag, QString path ) {
-
-    if(flag == "log")
-        path += "/var/log";
-    else
-    if (flag == "DB")
-        path += "/var/lib/global_db";
-    else
-    if (flag == "chain")
-        path += "/var/lib/network";
-    else
-        path += "";
-
-    QDir currentFolder( path );
-
-    quint64 totalsize = 0;
-
-    currentFolder.setFilter( QDir::Dirs | QDir::Files | QDir::NoSymLinks );
-    currentFolder.setSorting( QDir::Name );
-
-    QFileInfoList folderitems( currentFolder.entryInfoList() );
-
-    foreach ( QFileInfo i, folderitems ) {
-        QString iname( i.fileName() );
-        if ( iname == "." || iname == ".." || iname.isEmpty() )
-            continue;
-        if(flag == "log" && i.suffix() != "log" && !i.isDir())
-            continue;
-        else
-        if(flag == "DB" && (i.suffix() != "dat" && !i.suffix().isEmpty()) && !i.isDir())
-            continue;
-        else
-        if(flag == "chain" && i.suffix() != "dchaincell" && !i.isDir())
-            continue;
-
-        if ( i.isDir() )
-            totalsize += get_file_size("", path+"/"+iname);
-        else
-            totalsize += i.size();
-    }
-
-    return totalsize;
-}
-
-QString AbstractDiagnostic::get_memory_string(long num)
-{
-    QString result = QString::number(num);
-    return result;
-
-    int gb = (num / 1024) / 1024;
-    int mb = (num-gb*1024*1024) /1024;
-    int kb = (num - (gb*1024*1024+mb*1024));
-    if (gb > 0)
-       result = QString::number(gb) + QString(" Gb ");
-    else
-       result = QString("");
-    if (mb > 0)
-       result += QString::number(mb) + QString(" Mb ");
-    if (kb > 0)
-       result += QString::number(kb) + QString(" Kb ");
-
-    return result;
-}
-
-QJsonObject AbstractDiagnostic::roles_processing()
-{
-    QJsonObject rolesObject;
-
-    QDir currentFolder(s_nodeDataPath + "/etc/network");
-
-    currentFolder.setFilter( QDir::Dirs | QDir::Files | QDir::NoSymLinks );
-    currentFolder.setSorting( QDir::Name );
-
-    QFileInfoList folderitems( currentFolder.entryInfoList() );
-
-    foreach ( QFileInfo i, folderitems ) {
-        QString iname( i.fileName() );
-        if ( iname == "." || iname == ".." || iname.isEmpty() )
-            continue;
-        if(i.suffix() == "cfg" && !i.isDir())
-        {
-            QSettings config(i.absoluteFilePath(), QSettings::IniFormat);
-
-            rolesObject.insert(i.completeBaseName(), config.value("node-role", "unknown").toString());
-        }
-    }
-
-    return rolesObject;
-}
-
-/// ---------------------------------------------------------------
-///        Cli info
-/// ---------------------------------------------------------------
-QJsonObject AbstractDiagnostic::get_cli_info()
-{
-    QStringList networks = get_networks();
-
-    QJsonObject netObj;
-
-    for(QString net : networks)
-    {
-        QJsonObject dataObj;
-
-        dataObj.insert("net_info", get_net_info(net));
-        dataObj.insert("mempool" , get_mempool_count(net));
-//        dataObj.insert("ledger"  , get_ledger_count(net));
-        dataObj.insert("blocks"  , get_blocks_count(net));
-        dataObj.insert("events"  , get_events_count(net));
-        dataObj.insert("nodelist"  , get_nodelist(net));
-
-        netObj.insert(net, dataObj);
-    }
-
-    return netObj;
-}
-
-QStringList AbstractDiagnostic::get_networks()
-{
-    QProcess proc;
-    proc.start(QString(CLI_PATH), QStringList()<<"net"<<"list");
-    proc.waitForFinished(5000);
-    QString result = proc.readAll();
-
-    QStringList listNetworks;
-    result.remove(' ');
-    result.remove("\r");
-    result.remove("\n");
-    result.remove("networks:");
-    if(!(result.isEmpty() || result.isNull() || result.contains('\'') || result.contains("error") || result.contains("Error") || result.contains("err")))
-    {
-        listNetworks = result.split(",", QString::SkipEmptyParts);
-    }
-    
-    return listNetworks;
-}
-
-QJsonObject AbstractDiagnostic::get_net_info(QString net)
-{
-    QProcess proc;
-    proc.start(QString(CLI_PATH),
-               QStringList()<<"net"<<"-net"<<QString(net)<<"get"<<"status");
-    proc.waitForFinished(5000);
-    
-    QString result = proc.readAll();
-    
-    QRegularExpression rx_state(R"(.*current: ([A-Z,_]+).*)");
-    QRegularExpression rx_addr(R"(.*current_addr: (.+))");
-    
-    QJsonObject resultObj;
-    
-    QRegularExpressionMatch match_addr = rx_addr.match(result);
-    if (match_addr.hasMatch()) {
-        resultObj.insert("node_address", match_addr.captured(1));
-    }
-
-    QRegularExpressionMatch match_state = rx_state.match(result);
-    if (match_state.hasMatch()) {
-        resultObj.insert("state", match_state.captured(1));
-    }
-
-    // ---------- Links count ----------------
-    QRegularExpression rxLinksActive(R"(.*active: (.*))");
-    QRegularExpression rxLinksRequired(R"(.*required: (.*))");
-    
-    QRegularExpressionMatch match_active = rxLinksActive.match(result);
-    if (match_active.hasMatch()) {
-        resultObj.insert("active_links_count", match_active.captured(1));
-    }
-    
-    QRegularExpressionMatch match_req = rxLinksRequired.match(result);
-    if (match_req.hasMatch()) {
-        resultObj.insert("links_count", match_req.captured(1));
-    }
-    
-    
-    resultObj.insert("balancer", get_balancer_links(net));
-
-    return resultObj;
-}
-
-QJsonObject AbstractDiagnostic::get_mempool_count(QString net)
-{
-    QProcess proc;
-    proc.start(QString(CLI_PATH),
-               QStringList()<<"mempool_list"<<"-net"<<QString(net));
-    proc.waitForFinished(5000);
-    QString result = proc.readAll();
-
-    QRegularExpression rx(R"(\.*total: .*\.(.*): (\d+))");
-
-    QJsonObject resultObj;
-
-    QRegularExpressionMatchIterator matchItr = rx.globalMatch(result);
-
-    while (matchItr.hasNext())
-    {
-        QRegularExpressionMatch match = matchItr.next();
-        resultObj.insert(match.captured(1), match.captured(2));
-    }
-    return resultObj;
-}
-
-QJsonObject AbstractDiagnostic::get_ledger_count(QString net)
-{
-    //TODO: legder tx -all -net   NOT WORKING
-    return {};
-}
-
-QJsonObject AbstractDiagnostic::get_blocks_count(QString net)
-{
-    QProcess proc;
-    proc.start(QString(CLI_PATH),
-               QStringList()<<"block"<<"last"<<"-net"<<QString(net) <<"-chain" << "main");
-    proc.waitForFinished(5000);
-    QString result = proc.readAll();
-    
-    QRegularExpression rx_block_count(R"(\.(.+) has blocks: (.+))");
-    QRegularExpression rx_creation(R"(.*ts_created: (.*))");
-    QRegularExpression rx_hash(R"(.*Last block hash: (.*))");
-    
-
-    QRegularExpressionMatch block_count_match = rx_block_count.match(result);
-    QRegularExpressionMatch timestamp_match = rx_creation.match(result);
-    QRegularExpressionMatch hash_match = rx_hash.match(result);
-
-    if (!block_count_match.hasMatch()) {
-        return {};
-    }
-
-    QJsonObject resultObj;
-    resultObj.insert(block_count_match.captured(1), block_count_match.captured(2));
-
-    QJsonObject last_block;
-    last_block.insert("hash", hash_match.captured(1));
-    
-    qDebug() << "TS: "<<timestamp_match.captured(1);
-    QDateTime dt = QDateTime::fromString(timestamp_match.captured(1), Qt::RFC2822Date);
-    qint64 timestamp = dt.toSecsSinceEpoch();
-    last_block.insert("timestamp", QString::number(timestamp));
-
-    resultObj.insert("last_block", last_block);
-
-    qDebug() << "Block last "<<net<<":";
-    qDebug() << resultObj;
-    return resultObj;
-
-}
-
-QJsonObject AbstractDiagnostic::get_events_count(QString net)
-{
-    QProcess proc;
-    proc.start(QString(CLI_PATH),
-               QStringList()<<"dag"<<"event"<<"last"<<"-net"<<QString(net) <<"-chain" << "zerochain");
-    proc.waitForFinished(5000);
-    QString result = proc.readAll();
-
-    QRegularExpression rx_event_count(R"(\.(.+) has events: (.+))");
-    QRegularExpression rx_creation(R"(.*ts_created: (.*))");
-    QRegularExpression rx_hash(R"(.*Last event hash: (.*))");
-    
-
-    QRegularExpressionMatch event_count_match = rx_event_count.match(result);
-    QRegularExpressionMatch timestamp_match = rx_creation.match(result);
-    QRegularExpressionMatch hash_match = rx_hash.match(result);
-
-    if (!event_count_match.hasMatch()) {
-        return {};
-    }
-
-    QJsonObject resultObj;
-    resultObj.insert(event_count_match.captured(1), event_count_match.captured(2));
-
-    QJsonObject last_event;
-    last_event.insert("hash", hash_match.captured(1));
-    
-    qDebug() << "TS: "<<timestamp_match.captured(1);
-    QDateTime dt = QDateTime::fromString(timestamp_match.captured(1), Qt::RFC2822Date);
-    qint64 timestamp = dt.toSecsSinceEpoch();
-    last_event.insert("timestamp", QString::number(timestamp));
-
-    resultObj.insert("last_event", last_event);
-
-    last_event.insert("timestamp", QString::number(timestamp));
-
-    qDebug() << "Event last "<<net<<":";
-    qDebug() << resultObj;
-    
-    return resultObj;
-}
-
-
-QJsonArray AbstractDiagnostic::get_nodelist(QString net)
-{
-    QProcess proc;
-    proc.start(QString(CLI_PATH),
-               QStringList()<<"node"<<"dump"<<"-net"<<QString(net));
-    proc.waitForFinished(5000);
-    QString result = proc.readAll();
-
-    QJsonArray res;
-    for (auto l : result.split("\n"))
-        res.push_back(QJsonValue(l));
-
-    return res;
-}
-
-QJsonObject AbstractDiagnostic::get_balancer_links(QString net)
-{
-    QProcess proc;
-    proc.start(QString(CLI_PATH),
-                QStringList()<<"node"<<"connections"<<"-net"<<QString(net));
-
-
-    proc.waitForFinished(5000);
-    QString result = proc.readAll();
-
-    QJsonObject resultObj;
-
-    QRegularExpression rx(R"(Total links: \d+ \| Uplinks: (\d+) \| Downlinks: (\d+))");
-    QRegularExpressionMatch match = rx.match(result);
-
-    if (!match.hasMatch()) {
-        return {};
-    }
-
-    resultObj.insert("uplinks", match.captured(1));
-    resultObj.insert("downlinks", match.captured(2));
-
-
-    return resultObj;
-}
diff --git a/diagtool/AbstractDiagnostic.h b/diagtool/AbstractDiagnostic.h
deleted file mode 100644
index b00068f5167646aa119774f9b419d05c325b1687..0000000000000000000000000000000000000000
--- a/diagtool/AbstractDiagnostic.h
+++ /dev/null
@@ -1,67 +0,0 @@
-#ifndef ABSTRACTDIAGNOSTIC_H
-#define ABSTRACTDIAGNOSTIC_H
-
-#include <QObject>
-#include "qtimer.h"
-#include <QJsonDocument>
-#include <QJsonObject>
-#include <QJsonArray>
-#include <QDebug>
-#include <QUrl>
-#include <QFileInfo>
-#include <QCoreApplication>
-#include <QProcess>
-#include <QString>
-#include <QRegularExpression>
-#include <QSettings>
-#include <QTime>
-
-#include <QDir>
-#include <QNetworkInterface>
-
-class AbstractDiagnostic : public QObject
-{
-    Q_OBJECT
-public:
-    explicit AbstractDiagnostic(QObject * parent = nullptr);
-    ~AbstractDiagnostic();
-
-public:
-    void start_diagnostic();
-    void stop_diagnostic();
-    void set_timeout(int timeout);
-    quint64 get_file_size(QString flag, QString path);
-    QString get_uptime_string(long sec);
-    QString get_memory_string(long num);
-    QJsonValue get_mac();
-
-    QJsonDocument get_full_info(){return s_full_info;};
-
-    QJsonObject roles_processing();
-
-    //CLI
-    QJsonObject get_cli_info();
-
-    QStringList get_networks();
-    QJsonObject get_net_info(QString net);
-    QJsonObject get_mempool_count(QString net);
-    QJsonObject get_ledger_count(QString net);
-    QJsonObject get_blocks_count(QString net);
-    QJsonObject get_events_count(QString net);
-    QJsonArray get_nodelist(QString net);
-    QJsonObject get_balancer_links(QString net);
-
-public:
-    QTimer * s_timer_update;
-    int s_timeout{1000};
-    QJsonDocument s_full_info;
-    QJsonValue s_mac;
-    bool s_node_status{false};
-    QString s_nodeDataPath{""};
-
-signals:
-    void data_updated(QJsonDocument);
-
-};
-
-#endif // ABSTRACTDIAGNOSTIC_H
diff --git a/diagtool/CMakeLists.txt b/diagtool/CMakeLists.txt
deleted file mode 100644
index ad329d3a55847fc077ba92baa22fbf812870d2f7..0000000000000000000000000000000000000000
--- a/diagtool/CMakeLists.txt
+++ /dev/null
@@ -1,51 +0,0 @@
-cmake_minimum_required(VERSION 3.10)
-
-project(cellframe-diagtool)
-
-find_package(Qt5 5.15 REQUIRED COMPONENTS
-    Core
-    Network
-)
-
-set(CMAKE_AUTOMOC ON)
-
-
-
-if(UNIX)
-    if(DARWIN)
-        add_definitions(-DCLI_PATH="./cellframe-node-cli")
-        add_executable(${PROJECT_NAME}
-            main.cpp
-            DiagnosticWorker.cpp
-            AbstractDiagnostic.cpp
-            MacDiagnostic.cpp
-        )
-    endif()
-
-    if(LINUX)
-        add_definitions(-DCLI_PATH="/opt/cellframe-node/bin/cellframe-node-cli")
-        add_executable(${PROJECT_NAME}
-            main.cpp
-            DiagnosticWorker.cpp
-            AbstractDiagnostic.cpp
-            LinuxDiagnostic.cpp
-        )
-    endif()
-
-endif()
-
-if(WIN32)
-    add_definitions(-DCLI_PATH="cellframe-node-cli.exe")
-    add_executable(${PROJECT_NAME}
-        main.cpp
-        DiagnosticWorker.cpp
-        AbstractDiagnostic.cpp
-        WinDiagnostic.cpp
-    )
-endif()
-
-
-target_link_libraries(${PROJECT_NAME}
-    Qt5::Core Qt5::Network
-)
-
diff --git a/diagtool/DiagnosticWorker.cpp b/diagtool/DiagnosticWorker.cpp
deleted file mode 100644
index c83c53d4551fdb2c3ab3b1eee648fe244fd931cc..0000000000000000000000000000000000000000
--- a/diagtool/DiagnosticWorker.cpp
+++ /dev/null
@@ -1,104 +0,0 @@
-#include "DiagnosticWorker.h"
-#include <QNetworkAccessManager>
-#include <QHttpPart>
-#include <QHttpMultiPart>
-#include <QNetworkReply>
-static QString group = "global.users.statistic";
-
-DiagnosticWorker::DiagnosticWorker(QObject * parent)
-    : QObject{parent}
-{
-    s_uptime_timer = new QTimer(this);
-    connect(s_uptime_timer, &QTimer::timeout,
-            this, &DiagnosticWorker::slot_uptime,
-            Qt::QueuedConnection);
-    s_uptime_timer->start(1000);
-
-    s_elapsed_timer = new QElapsedTimer();
-    s_elapsed_timer->start();
-
-#ifdef Q_OS_LINUX
-    m_diagnostic = new LinuxDiagnostic();
-#elif defined Q_OS_WIN
-    m_diagnostic = new WinDiagnostic();
-#elif defined Q_OS_MAC
-    m_diagnostic = new MacDiagnostic();
-#endif
-
-    connect(m_diagnostic, &AbstractDiagnostic::data_updated,
-            this, &DiagnosticWorker::slot_diagnostic_data,
-            Qt::QueuedConnection);
-
-    m_diagnostic->start_diagnostic();
-    m_diagnostic->set_timeout(3000); //30 sec
-}
-DiagnosticWorker::~DiagnosticWorker()
-{
-    delete s_uptime_timer;
-    delete s_elapsed_timer;
-    delete m_diagnostic;
-}
-
-void DiagnosticWorker::slot_diagnostic_data(QJsonDocument data)
-{
-    //insert uptime dashboard and more into system info
-    QJsonObject obj = data.object();
-    QJsonObject system = data["system"].toObject();
-    QJsonObject proc = data["process"].toObject();
-
-    system.insert("uptime_dashboard", s_uptime);
-    system.insert("time_update_unix", QDateTime::currentSecsSinceEpoch());
-
-//    system.insert("time_update", QDateTime::currentDateTime().toString("dd.MM.yyyy hh:mm"));
-    obj.insert("system",system);
-
-    if(proc["status"].toString() == "Offline") //if node offline - clear version
-        m_node_version = "";
-    else
-    if(m_node_version.isEmpty())
-    {
-        QProcess proc;
-        proc.start(QString(CLI_PATH), QStringList()<<"version");
-        proc.waitForFinished(5000);
-        QString result = proc.readAll();
-        if(result.contains("version"))
-        {
-            result = result.split("version")[1];
-            m_node_version = result.split('\n', QString::SkipEmptyParts).first().trimmed();
-        }
-    }
-
-    proc.insert("version", m_node_version);
-    obj.insert("process",proc);
-    data.setObject(obj);
-
-    write_data(data);
-}
-
-void DiagnosticWorker::slot_uptime()
-{
-    s_uptime = m_diagnostic->get_uptime_string(s_elapsed_timer->elapsed()/1000);
-}
-
-void DiagnosticWorker::write_data(QJsonDocument data)
-{
-    QStringList urls = {"https://telemetry.cellframe.net/diag_report", "https://engine-minkowski.kelvpn.com/diag_report"};
-    for (auto url_s : urls)
-    {
-        QUrl url = QUrl(url_s);
-
-        QNetworkAccessManager * mgr = new QNetworkAccessManager(this);
-
-        connect(mgr, &QNetworkAccessManager::finished, this, [=](QNetworkReply*r) {qDebug() << "data sent " << urls << " " << r->error();});
-        connect(mgr,SIGNAL(finished(QNetworkReply*)),mgr,  SLOT(deleteLater()));
-
-        auto req = QNetworkRequest(url);
-        req.setHeader(QNetworkRequest::ContentTypeHeader,"application/x-www-form-urlencoded");
-        QString key = m_diagnostic->s_mac.toString();
-        QJsonObject obj = data.object();
-        obj.insert("mac",key);
-        data.setObject(obj);
-        mgr->post(req, data.toJson());
-    }
-
-}
diff --git a/diagtool/DiagnosticWorker.h b/diagtool/DiagnosticWorker.h
deleted file mode 100644
index 2216d1cfea342e42c3e03d347d396a39653f6d59..0000000000000000000000000000000000000000
--- a/diagtool/DiagnosticWorker.h
+++ /dev/null
@@ -1,48 +0,0 @@
-#ifndef DIAGNOSTICWORKER_H
-#define DIAGNOSTICWORKER_H
-
-#include <QObject>
-#include <QTimer>
-#include <QElapsedTimer>
-#include <QSettings>
-
-#include <unistd.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-
-#ifdef Q_OS_LINUX
-    #include "LinuxDiagnostic.h"
-#elif defined Q_OS_WIN
-    #include "WinDiagnostic.h"
-#elif defined Q_OS_MAC
-    #include "MacDiagnostic.h"
-#endif
-
-
-class DiagnosticWorker : public QObject
-{
-    Q_OBJECT
-public:
-    explicit DiagnosticWorker(QObject *parent = nullptr);
-    ~DiagnosticWorker();
-
-private:
-    QString m_node_version{""};
-    QSettings m_settings;
-    AbstractDiagnostic* m_diagnostic;
-
-    QTimer *s_uptime_timer;
-    QElapsedTimer *s_elapsed_timer;
-    QString s_uptime{"00:00:00"};
-
-private slots:
-    void slot_diagnostic_data(QJsonDocument);
-    void slot_uptime();
-
-private:
-    void write_data(QJsonDocument);
-
-};
-
-#endif // DIAGNOSTICWORKER_H
diff --git a/diagtool/LinuxDiagnostic.cpp b/diagtool/LinuxDiagnostic.cpp
deleted file mode 100644
index f302ad8ca11c517906d8b06a3e5ce0fc730bda92..0000000000000000000000000000000000000000
--- a/diagtool/LinuxDiagnostic.cpp
+++ /dev/null
@@ -1,347 +0,0 @@
-#include "LinuxDiagnostic.h"
-#include <sys/vfs.h>
-#include <sys/stat.h>
-
-LinuxDiagnostic::LinuxDiagnostic(AbstractDiagnostic *parent)
-    : AbstractDiagnostic{parent}
-{
-    connect(s_timer_update, &QTimer::timeout,
-            this, &LinuxDiagnostic::info_update,
-            Qt::QueuedConnection);
-}
-
-
-void LinuxDiagnostic::info_update(){
-
-    // QSettings config("/opt/cellframe-node/etc/cellframe-node.cfg",
-    //                    QSettings::IniFormat);
-
-    // bool isEnabled = config.value("Diagnostic/enabled",false).toBool();
-
-    if(true) //isEnabled
-    {
-        QJsonObject proc_info;
-        QJsonObject sys_info;
-        QJsonObject cli_info;
-        QJsonObject full_info;
-
-        sys_info = get_sys_info();
-        sys_info.insert("mac", s_mac);
-        sys_info.insert("disk", get_disk_info());
-
-        QString jsonFilePath = QString("%1/etc/diagdata.json").arg(s_nodeDataPath);
-        QFile file(jsonFilePath);
-        if(file.open(QIODevice::ReadOnly | QIODevice::Text))
-        {
-            QJsonParseError err;
-            QJsonDocument doc = QJsonDocument::fromJson(file.readAll(), &err);
-            file.close();
-
-            if(err.error == QJsonParseError::NoError && !doc.isEmpty())
-                sys_info.insert("data", doc.object());
-            else
-                qWarning()<<err.errorString();
-        }
-
-        QJsonObject obj = sys_info["memory"].toObject();
-        int mem = obj["total"].toInt();
-
-        proc_info = get_process_info(get_pid(), mem);
-        proc_info.insert("roles", roles_processing());
-
-        if(s_node_status)
-        {
-            cli_info = get_cli_info();
-            full_info.insert("cli_data", cli_info);
-        }
-
-
-        full_info.insert("system", sys_info);
-        full_info.insert("process", proc_info);
-
-        s_full_info.setObject(full_info);
-
-        emit data_updated(s_full_info);
-    }
-}
-
-QJsonObject LinuxDiagnostic::get_disk_info()
-{
-    QString path = "/opt/cellframe-node";
-
-    QString apath = QDir(path).absolutePath();
-
-    struct statfs stfs;
-
-    if (::statfs(apath.toLocal8Bit(),&stfs) == -1)
-    {
-        QJsonObject diskObj;
-        diskObj.insert("total",     -1);
-        diskObj.insert("free",      -1);
-        diskObj.insert("available", -1);
-        diskObj.insert("used",      -1);
-
-        return diskObj;
-    }
-
-    quint64 total     = stfs.f_blocks * stfs.f_bsize;
-    quint64 free      = stfs.f_bfree  * stfs.f_bsize;
-    quint64 available = stfs.f_bavail * stfs.f_bsize;
-    quint64 used      = total - free;
-
-    QJsonObject diskObj;
-    diskObj.insert("total",     QString::number(total));
-    diskObj.insert("free",      QString::number(free));
-    diskObj.insert("available", QString::number(available));
-    diskObj.insert("used",      QString::number(used));
-
-    return diskObj;
-}
-
-
-long LinuxDiagnostic::get_pid()
-{
-    long pid;
-    QString path = QString("%1/var/run/cellframe-node.pid").arg("/opt/cellframe-node/");
-
-    QFile file(path);
-    QByteArray data;
-    if (!file.open(QIODevice::ReadOnly))
-        return 0;
-    data = file.readAll();
-    pid = data.toLong();
-
-    return pid;
-}
-
-/// ---------------------------------------------------------------
-///        Sys info
-/// ---------------------------------------------------------------
-QJsonObject LinuxDiagnostic::get_sys_info()
-{
-    QJsonObject obj_sys_data, obj_cpu, obj_memory;
-
-    ifstream stat_stream;
-    string buff;
-
-    //-------
-
-    //get cpu info
-    size_t idle_time, total_time;
-    get_cpu_times(idle_time, total_time);
-
-    const float idle_time_delta = idle_time - previous_idle_time;
-    const float total_time_delta = total_time - previous_total_time;
-    const float utilization = 100.0 * (1.0 - idle_time_delta / total_time_delta);
-
-    previous_idle_time = idle_time;
-    previous_total_time = total_time;
-
-    stat_stream.open("/proc/cpuinfo");
-    for(int i = 0; i < 16;i++) stat_stream >> buff;
-    getline(stat_stream,buff);
-
-    obj_cpu.insert("load", (int)utilization);
-    obj_cpu.insert("model", QString::fromStdString(buff));
-    stat_stream.close();
-
-    //get uptime system
-    stat_stream.open("/proc/uptime");
-    stat_stream >> buff;
-    QString uptime = get_uptime_string(atoi(buff.c_str()));
-    stat_stream.close();
-
-    //get memory data
-    stat_stream.open("/proc/meminfo");
-    QString memory, memory_used, memory_free;
-    string total,free,available;
-    stat_stream >> buff >> total >> buff >> buff >> free >> buff >> buff >> available;
-    stat_stream.close();
-
-    int total_value = atoi(total.c_str());
-    int available_value = atoi(available.c_str());
-
-    memory = get_memory_string(total_value);
-    memory_used = QString::number((total_value - available_value) *100 / total_value);
-    memory_free = get_memory_string(available_value);
-
-//    obj_memory.insert("total", memory);
-    obj_memory.insert("total", total_value);
-//    obj_memory.insert("total_value", total_value);
-    obj_memory.insert("free", memory_free);
-    obj_memory.insert("load", memory_used);
-
-    //-------
-
-    obj_sys_data.insert("uptime", uptime);
-    obj_sys_data.insert("CPU", obj_cpu);
-    obj_sys_data.insert("memory", obj_memory);
-
-    return obj_sys_data;
-}
-
-QString LinuxDiagnostic::get_running(char* pid)
-{
-    char tbuf[32];
-    char *cp;
-    int fd;
-    char c;
-
-    sprintf(tbuf, "/proc/%s/stat", pid);
-    fd = open(tbuf, O_RDONLY, 0);
-    if (fd == -1) return QString("no open");
-
-    memset(tbuf, '\0', sizeof tbuf); // didn't feel like checking read()
-    read(fd, tbuf, sizeof tbuf - 1);
-
-    cp = strrchr(tbuf, ')');
-    if(!cp) return QString("no read");
-
-    c = cp[2];
-    close(fd);
-    qDebug()<<c;
-
-    if (c=='R') {
-      return "running";
-    }else
-    if (c=='D') {
-      return "blocked";
-    }
-    return QString("blocked");
-}
-
-
-QString LinuxDiagnostic::get_proc_path(long pid) // work with root
-{
-    char exePath[PATH_MAX];
-    char arg1[20];
-    sprintf( arg1, "/proc/%ld/exe", pid );
-    ssize_t len = ::readlink(arg1, exePath, sizeof(exePath));
-    if (len == -1 || len == sizeof(exePath))
-        len = 0;
-    exePath[len] = '\0';
-    return QString::fromUtf8(exePath);
-}
-
-std::vector<size_t> LinuxDiagnostic::get_cpu_times() {
-    std::ifstream proc_stat("/proc/stat");
-    proc_stat.ignore(5, ' '); // Skip the 'cpu' prefix.
-    std::vector<size_t> times;
-    for (size_t time; proc_stat >> time; times.push_back(time));
-    return times;
-}
-
-bool LinuxDiagnostic::get_cpu_times(size_t &idle_time, size_t &total_time) {
-    const std::vector<size_t> cpu_times = get_cpu_times();
-    if (cpu_times.size() < 4)
-        return false;
-    idle_time = cpu_times[3];
-    total_time = std::accumulate(cpu_times.begin(), cpu_times.end(), 0);
-    return true;
-}
-
-
-/// ---------------------------------------------------------------
-///        Process info
-/// ---------------------------------------------------------------
-QJsonObject LinuxDiagnostic::get_process_info(long proc_id, int totalRam)
-{
-   using std::ios_base;
-   using std::ifstream;
-   using std::string;
-
-//   vm_usage     = 0.0;
-//   resident_set = 0.0;
-
-   // 'file' stat seems to give the most reliable results
-   char arg1[20];
-   sprintf( arg1, "/proc/%ld/stat", proc_id );
-   ifstream stat_stream(arg1,ios_base::in);
-
-   // dummy vars for leading entries in stat that we don't care about
-   //
-   string pid, comm, state, ppid, pgrp, session, tty_nr;
-   string tpgid, flags, minflt, cminflt, majflt, cmajflt;
-   string utime, stime, cutime, cstime, priority, nice;
-   string O, itrealvalue;
-
-   // the two fields we want
-   //
-   unsigned long vsize;
-   long rss;
-   double starttime;
-
-   stat_stream >> pid >> comm >> state >> ppid >> pgrp >> session >> tty_nr
-               >> tpgid >> flags >> minflt >> cminflt >> majflt >> cmajflt
-               >> utime >> stime >> cutime >> cstime >> priority >> nice
-               >> O >> itrealvalue >> starttime >> vsize >> rss; // don't care about the rest
-
-   stat_stream.close();
-
-   long page_size_kb = sysconf(_SC_PAGE_SIZE) / 1024; // in case x86-64 is configured to use 2MB pages
-//   vm_usage     = (vsize/1024.0);
-   long resident_set = rss * page_size_kb;
-
-   int precentUseRss = (resident_set * 100) / totalRam;
-
-   QProcess proc;
-   QString program = "ps";
-   QStringList arguments;
-   arguments << "-p" << pid.c_str() << "-o" << "etimes";
-   proc.start(program, arguments);
-   proc.waitForFinished(1000);
-   QString res = proc.readAll();
-
-   static QRegularExpression rx(R"([0-9]+)");
-
-   QJsonObject process_info;
-   QString status = "Offline";
-   process_info.insert("status", "Offline");
-
-   QString node_dir = "/opt/cellframe-node/";
-
-   QString log_size, db_size, chain_size;
-   log_size = get_memory_string(get_file_size("log", node_dir) / 1024);
-   db_size = get_memory_string(get_file_size("DB", node_dir) / 1024);
-   chain_size = get_memory_string(get_file_size("chain", node_dir) / 1024);
-
-   if(log_size.isEmpty()) log_size = "0";
-   if(db_size.isEmpty()) db_size = "0";
-   if(chain_size.isEmpty()) chain_size = "0";
-
-   process_info.insert("log_size", log_size);
-   process_info.insert("DB_size", db_size);
-   process_info.insert("chain_size", chain_size);
-
-   if(QString::fromLocal8Bit(comm.c_str()).contains("cellframe-node"))
-   {
-       int uptime_sec = rx.match(res).captured(0).toInt();
-
-       QString uptime= get_uptime_string(uptime_sec);
-
-       QString memory_use_value = get_memory_string(resident_set);
-
-//       process_info.insert("PPID",QString::fromLocal8Bit(ppid.c_str()));
-//       process_info.insert("priory",QString::fromLocal8Bit(priority.c_str()));
-//       process_info.insert("start_time",QString::number(((starttime/100)/60)));
-       process_info.insert("memory_use",precentUseRss);
-       process_info.insert("memory_use_value",memory_use_value);
-       process_info.insert("uptime",uptime);
-       process_info.insert("name","cellframe-node");
-
-       status = "Online";
-   }
-
-   if(status == "Offline")
-   {
-       process_info.insert("memory_use","0");
-       process_info.insert("memory_use_value","0 Kb");
-       process_info.insert("uptime","00:00:00");
-   }
-
-   s_node_status = status == "Online" ? true : false;
-
-   process_info.insert("status", status);
-
-   return process_info;
-}
diff --git a/diagtool/LinuxDiagnostic.h b/diagtool/LinuxDiagnostic.h
deleted file mode 100644
index 37d89f52a0a691d57c8b942145071590f22cdd34..0000000000000000000000000000000000000000
--- a/diagtool/LinuxDiagnostic.h
+++ /dev/null
@@ -1,53 +0,0 @@
-#ifndef LINUXDIAGNOSTIC_H
-#define LINUXDIAGNOSTIC_H
-
-
-#include "AbstractDiagnostic.h"
-#include <unistd.h>
-#include <fcntl.h>
-#include <vector>
-
-#include <fstream>
-#include <numeric>
-#include <vector>
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <ctype.h>
-#include <locale.h>
-#include <signal.h>
-#include <dirent.h>
-
-#include <sys/sysinfo.h>
-
-using namespace std;
-
-
-class LinuxDiagnostic : public AbstractDiagnostic
-{
-    Q_OBJECT
-public:
-    explicit LinuxDiagnostic(AbstractDiagnostic * parent = nullptr);
-
-private:
-    QJsonObject get_sys_info();
-    bool get_cpu_times(size_t &idle_time, size_t &total_time);
-    std::vector<size_t> get_cpu_times();
-    long get_pid();
-    QString get_running(char* pid);
-    QString get_proc_path(long pid);
-    QJsonObject get_process_info(long pid, int totalRam);
-    QJsonObject get_disk_info();
-
-
-private slots:
-    void info_update();
-
-private:
-    size_t previous_idle_time{0}, previous_total_time{0};
-
-
-};
-
-#endif // LINUXDIAGNOSTIC_H
diff --git a/diagtool/MacDiagnostic.cpp b/diagtool/MacDiagnostic.cpp
deleted file mode 100644
index 08674958d5fdcd604ff9e1fd1b912da33cb733c3..0000000000000000000000000000000000000000
--- a/diagtool/MacDiagnostic.cpp
+++ /dev/null
@@ -1,243 +0,0 @@
-#include "MacDiagnostic.h"
-
-static unsigned long long _previousTotalTicks = 0;
-static unsigned long long _previousIdleTicks = 0;
-
-MacDiagnostic::MacDiagnostic(AbstractDiagnostic *parent)
-    : AbstractDiagnostic{parent}
-{
-    connect(s_timer_update, &QTimer::timeout,
-            this, &MacDiagnostic::info_update,
-            Qt::QueuedConnection);
-}
-
-void MacDiagnostic::info_update()
-{
-//    qInfo()<<"MacDiagnostic::info_update ";
-
-    QJsonObject proc_info;
-    QJsonObject sys_info;
-    QJsonObject cli_info;
-    QJsonObject full_info;
-
-
-    sys_info = get_sys_info();
-    sys_info.insert("mac", s_mac);
-
-    QString jsonFilePath = QString("%1/etc/diagdata.json").arg(s_nodeDataPath);
-    QFile file(jsonFilePath);
-    if(file.open(QIODevice::ReadOnly | QIODevice::Text))
-    {
-        QJsonParseError err;
-        QJsonDocument doc = QJsonDocument::fromJson(file.readAll(), &err);
-        file.close();
-
-        if(err.error == QJsonParseError::NoError && !doc.isEmpty())
-            sys_info.insert("data", doc.object());
-        else
-            qWarning()<<err.errorString();
-    }
-
-    QJsonObject obj = sys_info["memory"].toObject();
-    int mem = obj["total"].toString().toUInt();;
-
-    proc_info = get_process_info(mem);
-    proc_info.insert("roles", roles_processing());
-
-    if(s_node_status)
-    {
-        cli_info = get_cli_info();
-        full_info.insert("cli_data", cli_info);
-    }
-
-    full_info.insert("system", sys_info);
-    full_info.insert("process", proc_info);
-
-    s_full_info.setObject(full_info);
-
-    emit data_updated(s_full_info);
-}
-
-QJsonObject MacDiagnostic::get_sys_info()
-{
-//    qInfo()<<"MacDiagnostic::get_sys_info ";
-    QJsonObject obj_sys_data, obj_cpu, obj_memory;
-
-    //get memory data
-    //total mem
-    int mib[2];
-    int64_t physical_memory;
-    mib[0] = CTL_HW;
-    mib[1] = HW_MEMSIZE;
-    size_t length = sizeof(int64_t);
-    sysctl(mib, 2, &physical_memory, &length, NULL, 0);
-
-
-
-    //use mem
-
-    vm_size_t page_size;
-    mach_port_t mach_port;
-    mach_msg_type_number_t count;
-    vm_statistics64_data_t vm_stats;
-    long long free_memory = 0;
-//    long long used_memory = 0;
-
-    mach_port = mach_host_self();
-    count = sizeof(vm_stats) / sizeof(natural_t);
-    if (KERN_SUCCESS == host_page_size(mach_port, &page_size) &&
-        KERN_SUCCESS == host_statistics64(mach_port, HOST_VM_INFO,
-                                        (host_info64_t)&vm_stats, &count))
-    {
-        free_memory = (int64_t)vm_stats.free_count * (int64_t)page_size;
-
-//        used_memory = ((int64_t)vm_stats.active_count +
-//                                 (int64_t)vm_stats.inactive_count +
-//                                 (int64_t)vm_stats.wire_count) *  (int64_t)page_size;
-    }
-
-    QString memtotal = QString::number(physical_memory/1024);
-    QString memfree  = QString::number(free_memory/1024);
-//    QString memused = get_memory_string(used_memory/1024);
-
-    QString memory_used = QString::number((physical_memory - free_memory) *100 / physical_memory);
-
-    obj_memory.insert("total", memtotal);
-    obj_memory.insert("free", memfree);
-    obj_memory.insert("load", memory_used);
-
-    //get cpu info
-
-    host_cpu_load_info_data_t cpuinfo;
-    float res = -1.0f;
-    mach_msg_type_number_t counts = HOST_CPU_LOAD_INFO_COUNT;
-    if (host_statistics(mach_host_self(), HOST_CPU_LOAD_INFO, (host_info_t)&cpuinfo, &count) == KERN_SUCCESS)
-    {
-       unsigned long long totalTicks = 0;
-       for(int i=0; i<CPU_STATE_MAX; i++) totalTicks += cpuinfo.cpu_ticks[i];
-       res =  calculate_cpu_load(cpuinfo.cpu_ticks[CPU_STATE_IDLE], totalTicks);
-    }
-    obj_cpu.insert("load", int(res*100));
-
-    //get uptime system
-
-    enum { NANOSECONDS_IN_SEC = 1000 * 1000 * 1000 };
-    double multiply = 0;
-    QString uptime = "00:00:00";
-    if (multiply == 0)
-    {
-        mach_timebase_info_data_t s_timebase_info;
-        if(mach_timebase_info(&s_timebase_info) == KERN_SUCCESS)
-        {
-            // multiply to get value in the nano seconds
-            multiply = (double)s_timebase_info.numer / (double)s_timebase_info.denom;
-            // multiply to get value in the seconds
-            multiply /= NANOSECONDS_IN_SEC;
-            uptime = get_uptime_string(mach_absolute_time() * multiply);
-        }
-    }
-
-
-//    //-------
-
-    obj_sys_data.insert("uptime", uptime);
-    obj_sys_data.insert("CPU", obj_cpu);
-    obj_sys_data.insert("memory", obj_memory);
-
-    return obj_sys_data;
-}
-
-float MacDiagnostic::calculate_cpu_load(unsigned long long idleTicks, unsigned long long totalTicks)
-{
-//    qInfo()<<"MacDiagnostic::calculate_cpu_load ";
-    unsigned long long totalTicksSinceLastTime = totalTicks-_previousTotalTicks;
-    unsigned long long idleTicksSinceLastTime  = idleTicks-_previousIdleTicks;
-    float ret = 1.0f-((totalTicksSinceLastTime > 0) ? ((float)idleTicksSinceLastTime)/totalTicksSinceLastTime : 0);
-    _previousTotalTicks = totalTicks;
-    _previousIdleTicks  = idleTicks;
-    return ret;
-
-}
-
-/// ---------------------------------------------------------------
-///        Process info
-/// ---------------------------------------------------------------
-QJsonObject MacDiagnostic::get_process_info(int totalRam)
-{
-//    qInfo()<<"MacDiagnostic::get_process_info ";
-    QJsonObject process_info;
-
-    QProcess proc;
-    QString program = "ps";
-    QStringList arguments;
-    arguments << "-axm" << "-o" << "rss,pid,etime,comm";
-    proc.start(program, arguments);
-    proc.waitForFinished(1000);
-    QString res = proc.readAll();
-
-    QString string="";
-
-    for(QString str : res.split("\n"))
-    {
-        if(str.contains("cellframe-node"))
-        {
-            string = str;
-            break;
-        }
-    }
-
-    QString status = "Offline";
-    QString node_dir = s_nodeDataPath;
-
-    QString log_size, db_size, chain_size;
-    log_size   = QString::number(get_file_size("log", node_dir) / 1024);
-    db_size    = QString::number(get_file_size("DB", node_dir) / 1024);
-    chain_size = QString::number(get_file_size("chain", node_dir) / 1024);
-
-    if(log_size.isEmpty()) log_size = "0";
-    if(db_size.isEmpty()) db_size = "0";
-    if(chain_size.isEmpty()) chain_size = "0";
-
-    process_info.insert("log_size", log_size);
-    process_info.insert("DB_size", db_size);
-    process_info.insert("chain_size", chain_size);
-
-
-    if(string.isEmpty())
-    {
-        process_info.insert("memory_use","0");
-        process_info.insert("memory_use_value","0 Kb");
-        process_info.insert("uptime","00:00:00");
-    }
-    else
-    {
-        status = "Online";
-
-        int pid, rss;
-        QString uptime, path;
-
-        QStringList parseString = string.split(" ");
-        parseString.removeAll("");
-
-        rss = parseString[0].toInt();
-        pid = parseString[1].toInt();
-        uptime = parseString[2];
-        path = parseString[3];
-
-        QString memory_use_value = QString::number(rss);
-        int precentUseRss = rss *100 / totalRam;
-
-        process_info.insert("memory_use",precentUseRss);
-        process_info.insert("memory_use_value",memory_use_value);
-        process_info.insert("uptime",uptime);
-        process_info.insert("name","cellframe-node");
-        process_info.insert("path", path);
-    }
-
-    s_node_status = status == "Online" ? true : false;
-
-    process_info.insert("status", status);
-
-
-   return process_info;
-}
diff --git a/diagtool/MacDiagnostic.h b/diagtool/MacDiagnostic.h
deleted file mode 100644
index 540a1b88b540cce5833b70e0efd1e6645626cebb..0000000000000000000000000000000000000000
--- a/diagtool/MacDiagnostic.h
+++ /dev/null
@@ -1,36 +0,0 @@
-#ifndef MACDIAGNOSTIC_H
-#define MACDIAGNOSTIC_H
-
-#include "AbstractDiagnostic.h"
-
-#include <sys/sysctl.h>
-#include <sys/types.h>
-#include <mach/vm_statistics.h>
-#include <mach/mach_types.h>
-#include <mach/mach_init.h>
-#include <mach/mach_host.h>
-#include <time.h>
-#include <mach/mach_time.h>
-
-using namespace std;
-
-
-class MacDiagnostic : public AbstractDiagnostic
-{
-    Q_OBJECT
-public:
-    explicit MacDiagnostic(AbstractDiagnostic * parent = nullptr);
-
-private:
-    QJsonObject get_sys_info();
-    QJsonObject get_process_info(int totalRam);
-
-    //cpu
-    float calculate_cpu_load(unsigned long long idleTick, unsigned long long totakTicks );
-
-private slots:
-    void info_update();
-
-};
-
-#endif // MACDIAGNOSTIC_H
diff --git a/diagtool/NodeDiagnostic.pro b/diagtool/NodeDiagnostic.pro
deleted file mode 100644
index ee1416aaa153aed147c51acd0df25f9c324116a7..0000000000000000000000000000000000000000
--- a/diagtool/NodeDiagnostic.pro
+++ /dev/null
@@ -1,43 +0,0 @@
-QT -= gui
-QT += core network
-
-CONFIG += c++17 console
-CONFIG -= app_bundle
-
-# You can make your code fail to compile if it uses deprecated APIs.
-# In order to do so, uncomment the following line.
-#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0
-
-#LIBS += -L$$NODE_BUILD_PATH/dap-sdk/core/ -ldap_core
-include (../dap-sdk/core/libdap.pri)
-
-SOURCES += \
-        AbstractDiagnostic.cpp \
-        DiagnosticWorker.cpp \
-        main.cpp
-HEADERS += \
-    AbstractDiagnostic.h \
-    DiagnosticWorker.h
-
-win32 {
-    DEFINES += CLI_PATH=\\\"cellframe-node-cli.exe\\\"
-    HEADERS += WinDiagnostic.h
-    SOURCES += WinDiagnostic.cpp
-}
-
-mac {
-    DEFINES += CLI_PATH=\\\"./cellframe-node-cli\\\"
-    HEADERS += MacDiagnostic.h
-    SOURCES += MacDiagnostic.cpp
-}
-
-else: !win32 {
-    DEFINES += CLI_PATH=\\\"/opt/cellframe-node/bin/cellframe-node-cli\\\"
-    HEADERS += LinuxDiagnostic.h
-    SOURCES += LinuxDiagnostic.cpp
-}
-
-# Default rules for deployment.
-qnx: target.path = /tmp/$${TARGET}/bin
-else: unix:!android: target.path = /opt/$${TARGET}/bin
-!isEmpty(target.path): INSTALLS += target
diff --git a/diagtool/WinDiagnostic.cpp b/diagtool/WinDiagnostic.cpp
deleted file mode 100644
index 4989cc5e1502dc393dfe02720e3783c9fac0235b..0000000000000000000000000000000000000000
--- a/diagtool/WinDiagnostic.cpp
+++ /dev/null
@@ -1,274 +0,0 @@
-#include "WinDiagnostic.h"
-
-WinDiagnostic::WinDiagnostic(AbstractDiagnostic *parent)
-    : AbstractDiagnostic{parent}
-{
-    connect(s_timer_update, &QTimer::timeout,
-            this, &WinDiagnostic::info_update,
-            Qt::QueuedConnection);
-
-    GetSystemTimes(&s_prev_idle, &s_prev_kernel, &s_prev_user);
-}
-
-void WinDiagnostic::info_update()
-{
-    QJsonObject proc_info;
-    QJsonObject sys_info;
-    QJsonObject cli_info;
-    QJsonObject full_info;
-
-    sys_info = get_sys_info();
-    sys_info.insert("mac", s_mac);
-//    sys_info.insert("disk", get_disk_info());
-
-    QString jsonFilePath = QString("%1/etc/diagdata.json").arg(s_nodeDataPath);
-    QFile file(jsonFilePath);
-    if(file.open(QIODevice::ReadOnly | QIODevice::Text))
-    {
-        QJsonParseError err;
-        QJsonDocument doc = QJsonDocument::fromJson(file.readAll(), &err);
-        file.close();
-
-        if(err.error == QJsonParseError::NoError && !doc.isEmpty())
-            sys_info.insert("data", doc.object());
-        else
-            qWarning()<<err.errorString();
-    }
-
-    QJsonObject obj = sys_info["memory"].toObject();
-    int mem = obj["total"].toString().toInt();;
-
-    proc_info = get_process_info(mem);
-    proc_info.insert("roles", roles_processing());
-
-    if(s_node_status)
-    {
-        cli_info = get_cli_info();
-        full_info.insert("cli_data", cli_info);
-    }
-
-    full_info.insert("system", sys_info);
-    full_info.insert("process", proc_info);
-
-    s_full_info.setObject(full_info);
-
-    emit data_updated(s_full_info);
-}
-
-QJsonObject WinDiagnostic::get_sys_info()
-{
-    QJsonObject obj_sys_data, obj_cpu, obj_memory;
-
-    // get CPU load
-    FILETIME idle;
-    FILETIME kernel;
-    FILETIME user;
-
-    GetSystemTimes(&idle, &kernel, &user);
-
-    ULONGLONG sys = (ft2ull(user) - ft2ull(s_prev_user)) +
-        (ft2ull(kernel) - ft2ull(s_prev_kernel));
-
-    QString cpu_load = QString::number(int((sys - ft2ull(idle) + ft2ull(s_prev_idle)) * 100.0 / sys));
-    obj_cpu.insert("load", cpu_load);
-
-    s_prev_idle = idle;
-    s_prev_kernel = kernel;
-    s_prev_user = user;
-
-    MEMORYSTATUSEX memory_status;
-    ZeroMemory(&memory_status, sizeof(MEMORYSTATUSEX));
-    memory_status.dwLength = sizeof(MEMORYSTATUSEX);
-    GlobalMemoryStatusEx(&memory_status);
-
-    QString memory, memory_used, memory_free;
-
-    memory = QString::number(memory_status.ullTotalPhys / 1024);
-    size_t total_value = memory_status.ullTotalPhys / 1024;
-    size_t available_value = memory_status.ullAvailPhys / 1024;
-    memory_free = QString::number(memory_status.ullAvailPhys / 1024);
-
-    memory_used = QString::number((total_value - available_value) *100 / total_value);
-
-    obj_memory.insert("total", memory);
-    obj_memory.insert("free", memory_free);
-    obj_memory.insert("load", memory_used);
-
-    DWORD currentTime = GetTickCount();
-
-    QString uptime = get_uptime_string(currentTime/1000);
-
-
-    obj_sys_data.insert("uptime", uptime);
-    obj_sys_data.insert("CPU", obj_cpu);
-    obj_sys_data.insert("memory", obj_memory);
-    return obj_sys_data;
-
-}
-
-long WinDiagnostic::get_memory_size(Qt::HANDLE hProc)
-{
-    PROCESS_MEMORY_COUNTERS pmcInfo;
-
-    if (GetProcessMemoryInfo(hProc, &pmcInfo, sizeof(pmcInfo)))
-        return pmcInfo.WorkingSetSize/1024;
-    else return 0;
-
-}
-
-ULONGLONG WinDiagnostic::ft2ull(FILETIME &ft) {
-    ULARGE_INTEGER ul;
-    ul.HighPart = ft.dwHighDateTime;
-    ul.LowPart = ft.dwLowDateTime;
-    return ul.QuadPart;
-}
-
-void WinDiagnostic::refresh_win_snapshot()
-{
-    // Get the process list snapshot.
-    hProcessSnapShot = CreateToolhelp32Snapshot(TH32CS_SNAPALL, 0);
-
-    ProcessEntry.dwSize = sizeof( ProcessEntry );
-
-
-    // Get the first process info.
-    BOOL Return = FALSE;
-    Return = Process32First( hProcessSnapShot,&ProcessEntry );
-
-    // Getting process info failed.
-    if( !Return )
-    {
-        qDebug()<<"Getting process info failed";
-    }
-}
-
-QJsonObject WinDiagnostic::get_process_info(int totalRam)
-{
-    refresh_win_snapshot();
-
-    hProcessSnapShot = CreateToolhelp32Snapshot(TH32CS_SNAPALL, 0);
-
-    // vars for get process time
-    FILETIME lpCreation, lpExit, lpKernel, lpUser;
-    SYSTEMTIME stCreation, stExit, stKernel, stUser;
-    long memory_size;
-
-    HANDLE hSnapshot;
-    PROCESSENTRY32 pe;
-    long pid = 0;
-    BOOL hResult;
-
-    // snapshot of all processes in the system
-    hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
-
-    // initializing size: needed for using Process32First
-    pe.dwSize = sizeof(PROCESSENTRY32);
-
-    // info about first process encountered in a system snapshot
-    hResult = Process32First(hSnapshot, &pe);
-
-
-    QString proc_name = "cellframe-node.exe";
-    while (hResult) {
-        // if we find the process: return process ID
-
-        std::wstring string(pe.szExeFile);
-        std::string str(string.begin(), string.end());
-        QString s = QString::fromStdString(str);
-
-
-        if(!proc_name.compare(s)){
-            pid = pe.th32ProcessID;
-
-            // get process descriptor
-            HANDLE hProcess = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION , FALSE, pe.th32ProcessID);
-
-            if(hProcess)
-            {
-                // get process times info
-                if(GetProcessTimes(hProcess,&lpCreation, &lpExit, &lpKernel, &lpUser))
-                {
-                      FileTimeToSystemTime(&lpCreation, &stCreation);
-                      FileTimeToSystemTime(&lpExit, &stExit);
-                      FileTimeToSystemTime(&lpUser, &stUser);
-                      FileTimeToSystemTime(&lpKernel, &stKernel);
-                }
-
-                memory_size = get_memory_size(hProcess);
-
-                //TODO CPU processing
-
-                CloseHandle(hProcess);
-            }
-
-            break;
-        }
-        hResult = Process32Next(hSnapshot, &pe);
-    }
-
-    CloseHandle( hProcessSnapShot );
-
-    QJsonObject process_info;
-
-    QString status = "Offline";
-//    QString path = NODE_PATH;
-    QString node_dir = QString("%1/cellframe-node/").arg(regGetUsrPath());
-
-    QString log_size, db_size, chain_size;
-    log_size = QString::number(get_file_size("log", node_dir) / 1024);
-    db_size = QString::number(get_file_size("DB", node_dir) / 1024);
-    chain_size = QString::number(get_file_size("chain", node_dir) / 1024);
-
-    if(log_size.isEmpty()) log_size = "0";
-    if(db_size.isEmpty()) db_size = "0";
-    if(chain_size.isEmpty()) chain_size = "0";
-
-    process_info.insert("log_size", log_size);
-    process_info.insert("DB_size", db_size);
-    process_info.insert("chain_size", chain_size);
-
-
-    if(pid){
-
-        QDateTime dateStart;
-        dateStart.setMSecsSinceEpoch(0);
-        dateStart = dateStart.addYears(stCreation.wYear - 1970);
-        dateStart = dateStart.addMonths(stCreation.wMonth - 1);
-        dateStart = dateStart.addDays(stCreation.wDay - 1);
-        dateStart = dateStart.addSecs(stCreation.wHour * 60 * 60 + stCreation.wMinute * 60 + stCreation.wSecond);
-
-        QDateTime dateNow = QDateTime::currentDateTime();
-
-        quint64 sec_start = dateStart.toSecsSinceEpoch();
-        quint64 sec_now = dateNow.toSecsSinceEpoch();
-
-        long result_uptime = sec_now - sec_start;
-
-        QString uptime = get_uptime_string(result_uptime);
-
-        int precentUseRss = (memory_size * 100) / totalRam;
-        QString memory_use_value = QString::number(memory_size);
-
-        process_info.insert("memory_use",precentUseRss);
-        process_info.insert("memory_use_value",memory_use_value);
-        process_info.insert("uptime",uptime);
-        process_info.insert("name","cellframe-node");
-
-        status = "Online";
-
-    }else{
-
-        process_info.insert("memory_use",0);
-        process_info.insert("memory_use_value","0 Kb");
-        process_info.insert("uptime","00:00:00");
-    }
-
-    s_node_status = status == "Online" ? true : false;
-
-    process_info.insert("status", status);
-//    process_info.insert("path", path);
-
-
-    return process_info;
-}
-
diff --git a/diagtool/WinDiagnostic.h b/diagtool/WinDiagnostic.h
deleted file mode 100644
index 769452fa6065392943825f504a9ad27c4e54e58a..0000000000000000000000000000000000000000
--- a/diagtool/WinDiagnostic.h
+++ /dev/null
@@ -1,38 +0,0 @@
-#ifndef WINDIAGNOSTIC_H
-#define WINDIAGNOSTIC_H
-
-#include "AbstractDiagnostic.h"
-
-#include <windows.h>
-#include <psapi.h>
-#include <tlhelp32.h>
-#include "registry.h"
-#include "pdh.h"
-
-
-enum PLATFORM { WINNT1, WIN2K_XP1, WIN9X1, UNKNOWN1 };
-
-class WinDiagnostic : public AbstractDiagnostic {
-    Q_OBJECT
-public:
-    explicit WinDiagnostic(AbstractDiagnostic* parent = nullptr);
-
-private:
-    QJsonObject get_sys_info();
-    QJsonObject get_process_info(int totalRam);
-
-    long get_memory_size(HANDLE hProc);
-    ULONGLONG ft2ull(FILETIME &ft);
-
-private:
-
-    HANDLE hProcessSnapShot;
-    PROCESSENTRY32 ProcessEntry;
-    FILETIME s_prev_idle, s_prev_kernel, s_prev_user;
-
-private slots:
-    void refresh_win_snapshot();
-    void info_update();
-};
-
-#endif  // WINDIAGNOSTIC_H
diff --git a/diagtool/main.cpp b/diagtool/main.cpp
deleted file mode 100644
index c4db95221cd35ace629ce42b6333dba533428f57..0000000000000000000000000000000000000000
--- a/diagtool/main.cpp
+++ /dev/null
@@ -1,12 +0,0 @@
-#include <QCoreApplication>
-#include "DiagnosticWorker.h"
-
-int main(int argc, char *argv[])
-{
-    qSetMessagePattern("%{type} %{if-category}%{category}: %{endif}%{function}: %{message}");
-    QCoreApplication a(argc, argv);
-
-    DiagnosticWorker * wrkr = new DiagnosticWorker();
-
-    return a.exec();
-}
diff --git a/dist.linux/share/cellframe-tray.service b/dist.linux/share/cellframe-tray.service
new file mode 100644
index 0000000000000000000000000000000000000000..9f83f72e6f0d067fa55e1e2c2b2de02f5d39fedd
--- /dev/null
+++ b/dist.linux/share/cellframe-tray.service
@@ -0,0 +1,14 @@
+[Unit]
+Description=CellframeNode Tray
+PartOf=graphical-session.target
+After=graphical-session.target
+
+[Service]
+Type=exec
+Restart=no
+ExecStart=/opt/cellframe-node/bin/cellframe-diagtool --tray
+ExecStop=/bin/kill -SIGTERM $MAINPID
+
+
+[Install]
+WantedBy=graphical-session.target
\ No newline at end of file
diff --git a/os/debian/postinst b/os/debian/postinst
index 5679349c86936917e21abddcad2203b1bb4fc19b..ba34254f4a375656b7cad50e5e1ee5972a644d32 100755
--- a/os/debian/postinst
+++ b/os/debian/postinst
@@ -40,6 +40,15 @@ if [ -e "$DAP_PREFIX/bin/cellframe-diagtool" ]; then
     echo "[!] Starting up cellframe-diagtool"
     systemctl --system enable $DAP_PREFIX/share/cellframe-diagtool.service || true
     systemctl start cellframe-diagtool || true
+
+    echo "[!] Starting up cellframe-tray"
+
+    if [ -d /run/user/$SUDO_UID ]; then
+        export XDG_RUNTIME_DIR=/run/user/$SUDO_UID
+        echo "Use $XDG_RUNTIME_DIR as XDG_RUNTIME_DIR, for tray install"
+        su  $SUDO_USER -c "systemctl --user enable $DAP_PREFIX/share/cellframe-tray.service" || true
+        su  $SUDO_USER -c "systemctl --user start cellframe-tray.service" || true
+    fi
 fi
 
 if [ -e "$DAP_PREFIX/share/cellframe-updater.service" ]; then
diff --git a/os/debian/prerm b/os/debian/prerm
index 57bad87389c36b445e4b305a64c7972d6613b309..278a11135606ff984ce6c8fa0c51a5a39e7143f5 100755
--- a/os/debian/prerm
+++ b/os/debian/prerm
@@ -3,14 +3,21 @@
 case "$1" in
 	remove|purge|abort-install|abort-upgrade)
 		echo "[*] Stopping cellframe-node and services..."
-		systemctl stop cellframe-node || true
-		systemctl stop cellframe-diagtool || true
-		systemctl stop cellframe-updater || true
+		systemctl stop cellframe-node.service || true
+		systemctl stop cellframe-diagtool.service || true
+		systemctl stop cellframe-updater.service || true
 
 		echo "[*] Disabling cellframe-node and services..."
-		systemctl disable cellframe-node || true
-		systemctl disable cellframe-diagtool || true
-		systemctl disable cellframe-updater || true
+		systemctl disable cellframe-node.service || true
+		systemctl disable cellframe-diagtool.service || true
+		systemctl disable cellframe-updater.service || true
+
+		if [ -d /run/user/$SUDO_UID ]; then
+      		export XDG_RUNTIME_DIR=/run/user/$SUDO_UID
+        	echo "Use $XDG_RUNTIME_DIR as XDG_RUNTIME_DIR, for tray install"
+        	su  $SUDO_USER -c "systemctl --user stop cellframe-tray.service" || true
+        	su  $SUDO_USER -c "systemctl --user disable cellframe-tray.service" || true
+    	fi	
 		;;
 
 	disappear)
@@ -18,16 +25,28 @@ case "$1" in
 
 	upgrade)
 		echo "[*] Stopping cellframe-node and services..."
-        systemctl stop cellframe-node || true
-		systemctl stop cellframe-diagtool || true
-        systemctl stop cellframe-updater || true
+        systemctl stop cellframe-node.service || true
+		systemctl stop cellframe-diagtool.service || true
+        systemctl stop cellframe-updater.service || true
+		if [ -d /run/user/$SUDO_UID ]; then
+      		export XDG_RUNTIME_DIR=/run/user/$SUDO_UID
+        	echo "Use $XDG_RUNTIME_DIR as XDG_RUNTIME_DIR, for tray install"
+        	su  $SUDO_USER -c "systemctl --user stop cellframe-tray.service" || true
+        	su  $SUDO_USER -c "systemctl --user disable cellframe-tray.service" || true
+    	fi	
 		;;
 
 	failed-upgrade)
 		echo "[*] Stopping cellframe-node and services"
-        systemctl stop cellframe-node || true
-		systemctl stop cellframe-diagtool || true
-        systemctl stop cellframe-updater || true
+        systemctl stop cellframe-node.service || true
+		systemctl stop cellframe-diagtool.service || true
+        systemctl stop cellframe-updater.service || true
+		if [ -d /run/user/$SUDO_UID ]; then
+      		export XDG_RUNTIME_DIR=/run/user/$SUDO_UID
+        	echo "Use $XDG_RUNTIME_DIR as XDG_RUNTIME_DIR, for tray install"
+        	su  $SUDO_USER -c "systemctl --user stop cellframe-tray.service" || true
+        	su  $SUDO_USER -c "systemctl --user disable cellframe-tray.service" || true
+    	fi	
         ;;
 
 	*)
diff --git a/os/windows/cellframe-node.nsis b/os/windows/cellframe-node.nsis
index 22d8db7389d6bcfc9ff95db884015633d6895926..d92588862584423a55576c4a53a1a6727a7f85cf 100644
--- a/os/windows/cellframe-node.nsis
+++ b/os/windows/cellframe-node.nsis
@@ -201,6 +201,7 @@ Section "${APP_NAME}" CORE
 	File "opt/cellframe-node/bin/${NODE_NAME}-cli.exe"
 	File "opt/cellframe-node/bin/${NODE_NAME}-tool.exe"
 	File "opt/cellframe-node/bin/${NODE_NAME}-config.exe"
+	File "opt/cellframe-node/bin/cellframe-diagtool.exe"
 
 	Call createRuntimePaths
 
@@ -235,6 +236,12 @@ Section "${APP_NAME}" CORE
 	; check net states after install to show in checkboxes
 	Call getNetworksStates
 
+	StrCpy $0 "'$INSTDIR\cellframe-diagtool.exe' --tray"
+	${DisableX64FSRedirection}
+	nsExec::ExecToLog /OEM  'schtasks /Create /F /RL highest /SC onlogon /TR "$0" /TN "CellframeTray"'
+	nsExec::ExecToLog /OEM  'schtasks /run  /TN CellframeTray"'
+	${EnableX64FSRedirection}
+
 SectionEnd
 
 
@@ -334,6 +341,7 @@ Function pgNetSelectLeave
 	Delete "$INSTDIR\${NODE_NAME}.exe"
 	Rename 	"$INSTDIR\cellframe-node.tmp" "$INSTDIR\cellframe-node.exe"
 
+	
 FunctionEnd
 
 
@@ -342,6 +350,7 @@ Section "Uninstall"
 	nsExec::ExecToLog /OEM "$INSTDIR\${NODE_NAME}-config.exe -e service disable"
 	nsExec::ExecToLog /OEM "$INSTDIR\${NODE_NAME}-config.exe -e service stop"
 	nsExec::ExecToLog /OEM  'taskkill /f /im ${NODE_NAME}.exe'
+	nsExec::ExecToLog /OEM  'taskkill /f /im cellframe-diagtool.exe'
 	
 	Delete "$INSTDIR\${NODE_NAME}.exe"
 	Delete "$INSTDIR\${NODE_NAME}-tool.exe"