diff --git a/deployment.pri b/deployment.pri
index 30f39b844554120225fee3e8c25b9c9c2d8ef43d..a2a7b028b669e1895c1c220b451eebec0f22bf26 100644
--- a/deployment.pri
+++ b/deployment.pri
@@ -1,9 +1,9 @@
-unix:!android {
+unix:!ios:!android {
     isEmpty(PREFIX) {
         PREFIX = /usr/local
     }
 
-    SRCDIR = src
+    SRCDIR = $${PWD}/src
     BINDIR = $${PREFIX}/bin
     DATADIR = $${PREFIX}/share
 
diff --git a/pkg/arch/PKGBUILD b/pkg/arch/PKGBUILD
index 8c6b5ce7f7d6ef393f8bf62e278db7a453649c68..6f02dee6d8a79827476b2cb15f5e1f3680392b5d 100644
--- a/pkg/arch/PKGBUILD
+++ b/pkg/arch/PKGBUILD
@@ -1,7 +1,7 @@
 # Maintainer: Akira Ohgaki <akiraohgaki@gmail.com>
 
 pkgname='xdgurl'
-pkgver='2.0.0'
+pkgver='2.0.1'
 pkgrel='1'
 pkgdesc='An install helper program for desktop stuff.'
 arch=('i686' 'x86_64')
diff --git a/pkg/build.sh b/pkg/build.sh
index f9b866ec3990a64fb4dee6ce7fbd807912face67..0408083c09839c5a07b21256abd87ced9ef347af 100644
--- a/pkg/build.sh
+++ b/pkg/build.sh
@@ -87,6 +87,7 @@ build_appimage() {
     tar -xzvf "${BUILDDIR}/${PKGNAME}.tar.gz" -C "${BUILDDIR}"
 
     cd "${BUILDDIR}/${PKGNAME}"
+    #qmake
     /opt/qt57/bin/qmake
     make
     strip ./xdgurl
diff --git a/pkg/fedora/xdgurl.spec b/pkg/fedora/xdgurl.spec
index 3d5de8cefa19da063aea82ee3fc21caf6df49c4c..82ea01aaca68749c9e8d3d0c6f098ac47ff4e871 100644
--- a/pkg/fedora/xdgurl.spec
+++ b/pkg/fedora/xdgurl.spec
@@ -1,6 +1,6 @@
 Summary: An install helper program for desktop stuff
 Name: xdgurl
-Version: 2.0.0
+Version: 2.0.1
 Release: 1%{?dist}
 License: GPLv3+
 Group: Applications/Internet
@@ -37,6 +37,10 @@ make INSTALL_ROOT="%{buildroot}" install
 rm -rf %{buildroot}
 
 %changelog
+* Mon Nov 14 2016 Akira Ohgaki <akiraohgaki@gmail.com> - 2.0.1-1
+- Update library
+- Fix download/installation process
+
 * Fri Oct 28 2016 Akira Ohgaki <akiraohgaki@gmail.com> - 2.0.0-1
 - Re-implemented xdgurl as Qt program
 - Download progress bar
diff --git a/pkg/ubuntu/debian/changelog b/pkg/ubuntu/debian/changelog
index a8ef66f2fbc93c46ee3b0ccd922fe7a02a28a6dd..20f5957efff445632eb12502cf0116cbff1cd818 100644
--- a/pkg/ubuntu/debian/changelog
+++ b/pkg/ubuntu/debian/changelog
@@ -1,3 +1,11 @@
+xdgurl (2.0.1-0ubuntu1) xenial; urgency=low
+
+  * Update library
+  * Fix download/installation process
+  * Package depends for xenial and later
+
+ -- Akira Ohgaki <akiraohgaki@gmail.com>  Mon, 14 Nov 2016 01:40:41 +0000
+
 xdgurl (2.0.0-0ubuntu1) xenial; urgency=low
 
   * Re-implemented xdgurl as Qt program
diff --git a/pkg/ubuntu/debian/control b/pkg/ubuntu/debian/control
index 6a8eb36d11c3f42d3950924b14ed9cf278cf20a8..efd11f99147e3df92679f0a9db8f6792695a8841 100644
--- a/pkg/ubuntu/debian/control
+++ b/pkg/ubuntu/debian/control
@@ -7,6 +7,6 @@ Standards-Version: 3.9.4
 
 Package: xdgurl
 Architecture: any
-Depends: ${shlibs:Depends}, ${misc:Depends}, libqt5svg5 (>= 5.3.0), qtdeclarative5-qtquick2-plugin (>= 5.3.0), qtdeclarative5-window-plugin (>= 5.3.0), qtdeclarative5-controls-plugin (>= 5.3.0), qtdeclarative5-dialogs-plugin (>= 5.3.0)
+Depends: ${shlibs:Depends}, ${misc:Depends}, libqt5svg5 (>= 5.3.0), qml-module-qtquick2 (>= 5.3.0) | qtdeclarative5-qtquick2-plugin (>= 5.3.0), qml-module-qtquick-window2 (>= 5.3.0) | qtdeclarative5-window-plugin (>= 5.3.0), qml-module-qtquick-controls (>= 5.3.0) | qtdeclarative5-controls-plugin (>= 5.3.0), qml-module-qtquick-dialogs (>= 5.3.0) | qtdeclarative5-dialogs-plugin (>= 5.3.0)
 Description: An install helper program for desktop stuff
  An install helper program for desktop stuff.
diff --git a/rpath.pri b/rpath.pri
deleted file mode 100644
index b3cd65e83d8e1df1c1d7bc94254dc152a2a91226..0000000000000000000000000000000000000000
--- a/rpath.pri
+++ /dev/null
@@ -1,5 +0,0 @@
-unix:!android {
-    QMAKE_LFLAGS += -Wl,-rpath=\\\$\$ORIGIN
-    QMAKE_LFLAGS += -Wl,-rpath=/usr/lib/$${TARGET}
-    QMAKE_RPATH =
-}
diff --git a/src/app/app.pri b/src/app/app.pri
new file mode 100644
index 0000000000000000000000000000000000000000..f192467c311e56612551a1aee77a8498e2b54bf0
--- /dev/null
+++ b/src/app/app.pri
@@ -0,0 +1,17 @@
+QT += \
+    core \
+    gui \
+    qml \
+    quick \
+    svg
+
+HEADERS += \
+    $${PWD}/handlers/xdgurl.h
+
+SOURCES += \
+    $${PWD}/main.cpp \
+    $${PWD}/handlers/xdgurl.cpp
+
+RESOURCES += \
+    $${PWD}/configs/configs.qrc \
+    $${PWD}/qml/qml.qrc
diff --git a/src/app/configs/application.json b/src/app/configs/application.json
index 415e29a2189bdad9330f60f85a291b9b1b9775bf..1e7ccc3d00a9ebaf936faeb1d7dc4099b2883813 100644
--- a/src/app/configs/application.json
+++ b/src/app/configs/application.json
@@ -1,7 +1,7 @@
 {
     "id": "xdgurl",
     "name": "xdgurl",
-    "version": "2.0.0",
+    "version": "2.0.1",
     "organization": "xdgurl",
     "domain": "com.xdgurl.xdgurl",
     "icon": ":/desktop/xdgurl.svg",
diff --git a/src/app/handlers/xdgurl.cpp b/src/app/handlers/xdgurl.cpp
index 487a83ba353471e8f9b5b12a856748d3e4f5396e..da90bdbbb1781159ad702814a852cc20029a7c9f 100644
--- a/src/app/handlers/xdgurl.cpp
+++ b/src/app/handlers/xdgurl.cpp
@@ -1,26 +1,30 @@
 #include "xdgurl.h"
 
-#include <QUrl>
 #include <QUrlQuery>
-#include <QTemporaryFile>
-#include <QNetworkReply>
 #include <QDesktopServices>
 
-#include "../../libs/utils/config.h"
-#include "../../libs/utils/network.h"
-#include "../../libs/utils/file.h"
-#include "../../libs/utils/package.h"
+#include "qtlibs/file.h"
+#include "qtlibs/dir.h"
+#include "qtlibs/networkresource.h"
+#include "qtlibs/package.h"
 
 namespace handlers {
 
-XdgUrl::XdgUrl(const QString &xdgUrl, utils::Config *config, utils::Network *network, QObject *parent) :
-    QObject(parent), xdgUrl_(xdgUrl), config_(config), network_(network)
+XdgUrl::XdgUrl(const QString &xdgUrl, const qtlibs::Config &config, QObject *parent)
+    : QObject(parent), xdgUrl_(xdgUrl), config_(config)
 {
     parse();
     loadDestinations();
+}
 
-    connect(network_, &utils::Network::finished, this, &handlers::XdgUrl::downloaded);
-    connect(network_, &utils::Network::downloadProgress, this, &handlers::XdgUrl::downloadProgress);
+QString XdgUrl::xdgUrl() const
+{
+    return xdgUrl_;
+}
+
+QJsonObject XdgUrl::metadata() const
+{
+    return metadata_;
 }
 
 void XdgUrl::process()
@@ -34,11 +38,15 @@ void XdgUrl::process()
         QJsonObject result;
         result["status"] = QString("error_validation");
         result["message"] = QString("Invalid XDG-URL " + xdgUrl_);
-        emit error(result);
+        emit finishedWithError(result);
         return;
     }
 
-    network_->get(QUrl(metadata_["url"].toString()));
+    QString url = metadata_["url"].toString();
+    qtlibs::NetworkResource *resource = new qtlibs::NetworkResource(url, QUrl(url), true, this);
+    connect(resource, &qtlibs::NetworkResource::downloadProgress, this, &XdgUrl::downloadProgress);
+    connect(resource, &qtlibs::NetworkResource::finished, this, &XdgUrl::networkResourceFinished);
+    resource->get();
     emit started();
 }
 
@@ -57,7 +65,6 @@ bool XdgUrl::isValid()
             && !filename.isEmpty()) {
         return true;
     }
-
     return false;
 }
 
@@ -68,47 +75,21 @@ void XdgUrl::openDestination()
     }
 }
 
-QString XdgUrl::xdgUrl() const
-{
-    return xdgUrl_;
-}
-
-QJsonObject XdgUrl::metadata() const
-{
-    return metadata_;
-}
-
-void XdgUrl::downloaded(QNetworkReply *reply)
+void XdgUrl::networkResourceFinished(qtlibs::NetworkResource *resource)
 {
-    if (reply->error() != QNetworkReply::NoError) {
+    if (resource->reply()->error() != QNetworkReply::NoError) {
         QJsonObject result;
         result["status"] = QString("error_network");
-        result["message"] = reply->errorString();
-        emit error(result);
-        return;
-    }
-    else if (reply->hasRawHeader("Location")) {
-        QString redirectUrl = QString(reply->rawHeader("Location"));
-        if (redirectUrl.startsWith("/")) {
-            redirectUrl = reply->url().authority() + redirectUrl;
-        }
-        network_->get(QUrl(redirectUrl));
-        return;
-    }
-    else if (reply->hasRawHeader("Refresh")) {
-        QString refreshUrl = QString(reply->rawHeader("Refresh")).split("url=").last();
-        if (refreshUrl.startsWith("/")) {
-            refreshUrl = reply->url().authority() + refreshUrl;
-        }
-        network_->get(QUrl(refreshUrl));
+        result["message"] = resource->reply()->errorString();
+        emit finishedWithError(result);
         return;
     }
 
     if (metadata_["command"].toString() == "download") {
-        saveDownloadedFile(reply);
+        saveDownloadedFile(resource);
     }
     else if (metadata_["command"].toString() == "install") {
-        installDownloadedFile(reply);
+        installDownloadedFile(resource);
     }
 }
 
@@ -150,8 +131,8 @@ void XdgUrl::parse()
 
 void XdgUrl::loadDestinations()
 {
-    QJsonObject configDestinations = config_->get("destinations");
-    QJsonObject configDestinationsAlias = config_->get("destinations_alias");
+    QJsonObject configDestinations = config_.get("destinations");
+    QJsonObject configDestinationsAlias = config_.get("destinations_alias");
 
     foreach (const QString key, configDestinations.keys()) {
         destinations_[key] = convertPathString(configDestinations[key].toString());
@@ -170,42 +151,32 @@ QString XdgUrl::convertPathString(const QString &path)
     QString newPath = path;
 
     if (newPath.contains("$HOME")) {
-        newPath.replace("$HOME", utils::File::homePath());
+        newPath.replace("$HOME", qtlibs::Dir::homePath());
     }
     else if (newPath.contains("$XDG_DATA_HOME")) {
-        newPath.replace("$XDG_DATA_HOME", utils::File::genericDataPath());
+        newPath.replace("$XDG_DATA_HOME", qtlibs::Dir::genericDataPath());
     }
     else if (newPath.contains("$KDEHOME")) {
-        newPath.replace("$KDEHOME", utils::File::kdehomePath());
+        newPath.replace("$KDEHOME", qtlibs::Dir::kdehomePath());
     }
 
     return newPath;
 }
 
-void XdgUrl::saveDownloadedFile(QNetworkReply *reply)
+void XdgUrl::saveDownloadedFile(qtlibs::NetworkResource *resource)
 {
     QJsonObject result;
 
-    QTemporaryFile temporaryFile;
-
-    if (!temporaryFile.open() || temporaryFile.write(reply->readAll()) == -1) {
-        result["status"] = QString("error_save");
-        result["message"] = temporaryFile.errorString();
-        emit error(result);
-        return;
-    }
-
     QString type = metadata_["type"].toString();
     QString destination = destinations_[type].toString();
     QString path = destination + "/" + metadata_["filename"].toString();
 
-    utils::File::makeDir(destination);
-    utils::File::remove(path); // Remove previous downloaded file
+    qtlibs::Dir(destination).make();
 
-    if (!temporaryFile.copy(path)) {
+    if (!resource->saveData(path)) {
         result["status"] = QString("error_save");
-        result["message"] = temporaryFile.errorString();
-        emit error(result);
+        result["message"] = QString("Failed to save data as " + path);
+        emit finishedWithError(result);
         return;
     }
 
@@ -213,74 +184,79 @@ void XdgUrl::saveDownloadedFile(QNetworkReply *reply)
 
     result["status"] = QString("success_download");
     result["message"] = QString("The file has been stored into " + destination);
-    emit finished(result);
+    emit finishedWithSuccess(result);
 }
 
-void XdgUrl::installDownloadedFile(QNetworkReply *reply)
+void XdgUrl::installDownloadedFile(qtlibs::NetworkResource *resource)
 {
     QJsonObject result;
 
-    QTemporaryFile temporaryFile;
+    QString tempPath = qtlibs::Dir::tempPath() + "/" + metadata_["filename"].toString();
 
-    if (!temporaryFile.open() || temporaryFile.write(reply->readAll()) == -1) {
+    if (!resource->saveData(tempPath)) {
         result["status"] = QString("error_save");
-        result["message"] = temporaryFile.errorString();
-        emit error(result);
+        result["message"] = QString("Failed to save data as " + tempPath);
+        emit finishedWithError(result);
         return;
     }
 
+    qtlibs::Package package(tempPath);
+    qtlibs::File tempFile(tempPath);
+
     QString type = metadata_["type"].toString();
     QString destination = destinations_[type].toString();
     QString path = destination + "/" + metadata_["filename"].toString();
 
-    utils::File::makeDir(destination);
-    utils::File::remove(path); // Remove previous downloaded file
+    qtlibs::Dir(destination).make();
 
     if (type == "bin"
-            && utils::Package::installProgram(temporaryFile.fileName(), path)) {
-        result["message"] = QString("The program has been installed into " + destination);
+            && package.installAsProgram(path)) {
+        result["message"] = QString("The file has been installed into " + destination);
     }
     else if ((type == "plasma_plasmoids" || type == "plasma4_plasmoids" || type == "plasma5_plasmoids")
-             && utils::Package::installPlasmapkg(temporaryFile.fileName(), "plasmoid")) {
+             && package.installAsPlasmapkg("plasmoid")) {
         result["message"] = QString("The plasmoid has been installed");
     }
     else if ((type == "plasma_look_and_feel" || type == "plasma5_look_and_feel")
-             && utils::Package::installPlasmapkg(temporaryFile.fileName(), "lookandfeel")) {
+             && package.installAsPlasmapkg("lookandfeel")) {
         result["message"] = QString("The plasma look and feel has been installed");
     }
     else if ((type == "plasma_desktopthemes" || type == "plasma5_desktopthemes")
-             && utils::Package::installPlasmapkg(temporaryFile.fileName(), "theme")) {
+             && package.installAsPlasmapkg("theme")) {
         result["message"] = QString("The plasma desktop theme has been installed");
     }
     else if (type == "kwin_effects"
-             && utils::Package::installPlasmapkg(temporaryFile.fileName(), "kwineffect")) {
+             && package.installAsPlasmapkg("kwineffect")) {
         result["message"] = QString("The KWin effect has been installed");
     }
     else if (type == "kwin_scripts"
-             && utils::Package::installPlasmapkg(temporaryFile.fileName(), "kwinscript")) {
+             && package.installAsPlasmapkg("kwinscript")) {
         result["message"] = QString("The KWin script has been installed");
     }
     else if (type == "kwin_tabbox"
-             && utils::Package::installPlasmapkg(temporaryFile.fileName(), "windowswitcher")) {
+             && package.installAsPlasmapkg("windowswitcher")) {
         result["message"] = QString("The KWin window switcher has been installed");
     }
-    else if (utils::Package::uncompressArchive(temporaryFile.fileName(), destination)) {
-        result["message"] = QString("The archive file has been uncompressed into " + destination);
+    else if (package.installAsArchive(destination)) {
+        result["message"] = QString("The archive file has been extracted into " + destination);
     }
-    else if (temporaryFile.copy(path)) {
-        result["message"] = QString("The file has been stored into " + destination);
+    else if (package.installAsFile(path)) {
+        result["message"] = QString("The file has been installed into " + destination);
     }
     else {
+        tempFile.remove();
         result["status"] = QString("error_install");
-        result["message"] = temporaryFile.errorString();
-        emit error(result);
+        result["message"] = QString("Failed to installation");
+        emit finishedWithError(result);
         return;
     }
 
+    tempFile.remove();
+
     destination_ = destination;
 
     result["status"] = QString("success_install");
-    emit finished(result);
+    emit finishedWithSuccess(result);
 }
 
 } // namespace handlers
diff --git a/src/app/handlers/xdgurl.h b/src/app/handlers/xdgurl.h
index 3cd2cd030cc882508a1372891b5eb4bf29205bf8..87ab472486719f2052f7502cab4ab1af67f4fb24 100644
--- a/src/app/handlers/xdgurl.h
+++ b/src/app/handlers/xdgurl.h
@@ -3,11 +3,10 @@
 #include <QObject>
 #include <QJsonObject>
 
-class QNetworkReply;
+#include "qtlibs/config.h"
 
-namespace utils {
-class Config;
-class Network;
+namespace qtlibs {
+class NetworkResource;
 }
 
 namespace handlers {
@@ -17,35 +16,34 @@ class XdgUrl : public QObject
     Q_OBJECT
 
 public:
-    explicit XdgUrl(const QString &xdgUrl, utils::Config *config, utils::Network *network, QObject *parent = 0);
+    explicit XdgUrl(const QString &xdgUrl, const qtlibs::Config &config, QObject *parent = 0);
 
 signals:
     void started();
-    void finished(const QJsonObject &result);
-    void error(const QJsonObject &result);
-    void downloadProgress(const qint64 &received, const qint64 &total);
+    void finishedWithSuccess(const QJsonObject &result);
+    void finishedWithError(const QJsonObject &result);
+    void downloadProgress(const qint64 &bytesReceived, const qint64 &bytesTotal);
 
 public slots:
+    QString xdgUrl() const;
+    QJsonObject metadata() const;
+
     void process();
     bool isValid();
     void openDestination();
-    QString xdgUrl() const;
-    QJsonObject metadata() const;
 
 private slots:
-    void downloaded(QNetworkReply *reply);
+    void networkResourceFinished(qtlibs::NetworkResource *resource);
 
 private:
     void parse();
     void loadDestinations();
     QString convertPathString(const QString &path);
-    void saveDownloadedFile(QNetworkReply *reply);
-    void installDownloadedFile(QNetworkReply *reply);
+    void saveDownloadedFile(qtlibs::NetworkResource *resource);
+    void installDownloadedFile(qtlibs::NetworkResource *resource);
 
     QString xdgUrl_;
-    utils::Config *config_;
-    utils::Network *network_;
-
+    qtlibs::Config config_;
     QJsonObject metadata_;
     QJsonObject destinations_;
     QString destination_;
diff --git a/src/app/main.cpp b/src/app/main.cpp
index 30d59795b5f327874556b7090344257caf1a76a4..6ed32e68340e71f0f326ef0986cce24eb6a7655c 100644
--- a/src/app/main.cpp
+++ b/src/app/main.cpp
@@ -10,8 +10,7 @@
 #include <QQmlApplicationEngine>
 #include <QQmlContext>
 
-#include "../libs/utils/config.h"
-#include "../libs/utils/network.h"
+#include "qtlibs/config.h"
 
 #include "handlers/xdgurl.h"
 
@@ -22,10 +21,9 @@ int main(int argc, char *argv[])
     QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
 #endif
     QGuiApplication app(argc, argv);
-    utils::Config *config = new utils::Config(":/configs");
-    utils::Network *network = new utils::Network(true);
 
-    QJsonObject configApplication = config->get("application");
+    qtlibs::Config config(":/configs");
+    QJsonObject configApplication = config.get("application");
 
     app.setApplicationName(configApplication["name"].toString());
     app.setApplicationVersion(configApplication["version"].toString());
@@ -52,7 +50,7 @@ int main(int argc, char *argv[])
     // Setup QML
     QQmlApplicationEngine qmlAppEngine;
     QQmlContext *qmlContext = qmlAppEngine.rootContext();
-    qmlContext->setContextProperty("xdgUrlHandler", new handlers::XdgUrl(xdgUrl, config, network));
+    qmlContext->setContextProperty("xdgUrlHandler", new handlers::XdgUrl(xdgUrl, config, &qmlAppEngine));
     qmlAppEngine.load(QUrl("qrc:/qml/main.qml"));
 
     return app.exec();
diff --git a/src/app/qml/main.qml b/src/app/qml/main.qml
index 3b1d8ea857e5c30f85ff559aa36be43270913539..1d68730b9a8f4c36b95288dde8fcc3ea26201870 100644
--- a/src/app/qml/main.qml
+++ b/src/app/qml/main.qml
@@ -114,7 +114,7 @@ Window {
             progressDialog.open();
         });
 
-        xdgUrlHandler.finished.connect(function(result) {
+        xdgUrlHandler.finishedWithSuccess.connect(function(result) {
             progressDialog.close();
             infoDialog.text = primaryMessages[result.status];
             infoDialog.informativeText = metadata.filename;
@@ -122,7 +122,7 @@ Window {
             infoDialog.open();
         });
 
-        xdgUrlHandler.error.connect(function(result) {
+        xdgUrlHandler.finishedWithError.connect(function(result) {
             progressDialog.close();
             errorDialog.text = primaryMessages[result.status];
             errorDialog.informativeText = metadata.filename;
@@ -130,12 +130,12 @@ Window {
             errorDialog.open();
         });
 
-        xdgUrlHandler.downloadProgress.connect(function(received, total) {
+        xdgUrlHandler.downloadProgress.connect(function(bytesReceived, bytesTotal) {
             progressDialog.primaryLabel.text = 'Downloading... ';
             progressDialog.informativeLabel.text = metadata.filename;
-            progressDialog.progressBar.value = received / total;
-            progressDialog.progressLabel.text = Utility.convertByteToHumanReadable(received)
-                    + ' / ' + Utility.convertByteToHumanReadable(total)
+            progressDialog.progressBar.value = bytesReceived / bytesTotal;
+            progressDialog.progressLabel.text = Utility.convertByteToHumanReadable(bytesReceived)
+                    + ' / ' + Utility.convertByteToHumanReadable(bytesTotal)
         });
 
         if (xdgUrlHandler.isValid()) {
diff --git a/src/libs/qtlibs/config.cpp b/src/libs/qtlibs/config.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..24002244d70b7c1e7f8863009485a68c01ddf799
--- /dev/null
+++ b/src/libs/qtlibs/config.cpp
@@ -0,0 +1,68 @@
+/**
+ * A library for Qt app
+ *
+ * LICENSE: The GNU Lesser General Public License, version 3.0
+ *
+ * @author      Akira Ohgaki <akiraohgaki@gmail.com>
+ * @copyright   Akira Ohgaki
+ * @license     https://opensource.org/licenses/LGPL-3.0  The GNU Lesser General Public License, version 3.0
+ * @link        https://github.com/akiraohgaki/qtlibs
+ */
+
+#include "config.h"
+
+#include "file.h"
+#include "dir.h"
+#include "json.h"
+
+namespace qtlibs {
+
+Config::Config(const QString &configDirPath, QObject *parent)
+    : QObject(parent), configDirPath_(configDirPath)
+{}
+
+Config::Config(const Config &other)
+{
+    this->setParent(other.parent());
+    setConfigDirPath(other.configDirPath());
+}
+
+Config &Config::operator =(const Config &other)
+{
+    this->setParent(other.parent());
+    setConfigDirPath(other.configDirPath());
+    return *this;
+}
+
+QString Config::configDirPath() const
+{
+    return configDirPath_;
+}
+
+void Config::setConfigDirPath(const QString &configDirPath)
+{
+    configDirPath_ = configDirPath;
+}
+
+QJsonObject Config::get(const QString &name)
+{
+    QString configFilePath = configDirPath() + "/" + name + ".json";
+    QByteArray json = qtlibs::File(configFilePath).readData();
+    if (json.isEmpty()) {
+        json = QString("{}").toUtf8(); // Blank JSON data as default
+    }
+    return qtlibs::Json(json).toObject();
+}
+
+bool Config::set(const QString &name, const QJsonObject &object)
+{
+    QString configFilePath = configDirPath() + "/" + name + ".json";
+    QByteArray json = qtlibs::Json(object).toJson();
+    qtlibs::Dir(configDirPath()).make();
+    if (qtlibs::File(configFilePath).writeData(json)) {
+        return true;
+    }
+    return false;
+}
+
+} // namespace qtlibs
diff --git a/src/libs/utils/config.h b/src/libs/qtlibs/config.h
similarity index 51%
rename from src/libs/utils/config.h
rename to src/libs/qtlibs/config.h
index 9949407873709013bd414ff9b695c31e21c05f6d..5f0df5fdc310e2e3688416dbd8074a2eeca2c467 100644
--- a/src/libs/utils/config.h
+++ b/src/libs/qtlibs/config.h
@@ -6,7 +6,7 @@
  * @author      Akira Ohgaki <akiraohgaki@gmail.com>
  * @copyright   Akira Ohgaki
  * @license     https://opensource.org/licenses/LGPL-3.0  The GNU Lesser General Public License, version 3.0
- * @link        https://github.com/akiraohgaki/qt-libs
+ * @link        https://github.com/akiraohgaki/qtlibs
  */
 
 #pragma once
@@ -14,21 +14,26 @@
 #include <QObject>
 #include <QJsonObject>
 
-namespace utils {
+namespace qtlibs {
 
 class Config : public QObject
 {
     Q_OBJECT
 
 public:
-    explicit Config(const QString &configsDir, QObject *parent = 0);
+    explicit Config(const QString &configDirPath = QString(), QObject *parent = 0);
+
+    Config(const Config &other);
+    Config &operator =(const Config &other);
+
+    QString configDirPath() const;
+    void setConfigDirPath(const QString &configDirPath);
 
     QJsonObject get(const QString &name);
-    bool set(const QString &name, const QJsonObject &jsonObj);
+    bool set(const QString &name, const QJsonObject &object);
 
 private:
-    QString configsDir_;
-    QJsonObject cacheData_;
+    QString configDirPath_;
 };
 
-} // namespace utils
+} // namespace qtlibs
diff --git a/src/libs/qtlibs/dir.cpp b/src/libs/qtlibs/dir.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..e0b579a97f3c6616f9463959c2ace7e8f12729c0
--- /dev/null
+++ b/src/libs/qtlibs/dir.cpp
@@ -0,0 +1,162 @@
+/**
+ * A library for Qt app
+ *
+ * LICENSE: The GNU Lesser General Public License, version 3.0
+ *
+ * @author      Akira Ohgaki <akiraohgaki@gmail.com>
+ * @copyright   Akira Ohgaki
+ * @license     https://opensource.org/licenses/LGPL-3.0  The GNU Lesser General Public License, version 3.0
+ * @link        https://github.com/akiraohgaki/qtlibs
+ */
+
+#include "dir.h"
+
+#include <QDir>
+#include <QFile>
+#include <QFileInfo>
+#include <QStandardPaths>
+
+namespace qtlibs {
+
+Dir::Dir(const QString &path, QObject *parent)
+    : QObject(parent), path_(path)
+{}
+
+Dir::Dir(const Dir &other)
+{
+    this->setParent(other.parent());
+    setPath(other.path());
+}
+
+Dir &Dir::operator =(const Dir &other)
+{
+    this->setParent(other.parent());
+    setPath(other.path());
+    return *this;
+}
+
+QString Dir::path() const
+{
+    return path_;
+}
+
+void Dir::setPath(const QString &path)
+{
+    path_ = path;
+}
+
+bool Dir::exists()
+{
+    QDir dir(path());
+    return dir.exists();
+}
+
+QFileInfoList Dir::list()
+{
+    QDir dir(path());
+    dir.setFilter(QDir::AllEntries | QDir::Hidden | QDir::System | QDir::NoDotAndDotDot);
+    //dir.setSorting(QDir::DirsFirst | QDir::Name);
+    return dir.entryInfoList();
+}
+
+bool Dir::make()
+{
+    // This function will create all parent directories
+    QDir dir(path());
+    if (!dir.exists() && dir.mkpath(path())) {
+        return true;
+    }
+    return false;
+}
+
+bool Dir::copy(const QString &newPath)
+{
+    // This function will copy files recursively
+    return copyRecursively(path(), newPath);
+}
+
+bool Dir::move(const QString &newPath)
+{
+    QDir dir(path());
+    return dir.rename(path(), newPath);
+}
+
+bool Dir::remove()
+{
+    // This function will remove files recursively
+    QDir dir(path());
+    return dir.removeRecursively();
+}
+
+QString Dir::rootPath()
+{
+    return QDir::rootPath();
+}
+
+QString Dir::tempPath()
+{
+    return QDir::tempPath();
+}
+
+QString Dir::homePath()
+{
+    return QDir::homePath();
+}
+
+QString Dir::genericDataPath()
+{
+    return QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation);
+}
+
+QString Dir::genericConfigPath()
+{
+    return QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation);
+}
+
+QString Dir::genericCachePath()
+{
+    return QStandardPaths::writableLocation(QStandardPaths::GenericCacheLocation);
+}
+
+QString Dir::kdehomePath()
+{
+    // KDE System Administration/Environment Variables
+    // https://userbase.kde.org/KDE_System_Administration/Environment_Variables
+
+    // KDE 4 maybe uses $KDEHOME
+    QString kdehomePath = QString::fromLocal8Bit(qgetenv("KDEHOME").constData());
+    if (kdehomePath.isEmpty()) {
+        kdehomePath = homePath() + "/.kde";
+    }
+    return kdehomePath;
+}
+
+bool Dir::copyRecursively(const QString &srcPath, const QString &newPath)
+{
+    QFileInfo fileInfo(srcPath);
+    if (fileInfo.isFile()) {
+        QFile file(srcPath);
+        if (file.copy(newPath)) {
+            return true;
+        }
+    }
+    else if (fileInfo.isDir()) {
+        QDir newDir(newPath);
+        QString newDirName = newDir.dirName();
+        newDir.cdUp();
+        if (newDir.mkdir(newDirName)) {
+            QDir dir(srcPath);
+            dir.setFilter(QDir::AllEntries | QDir::Hidden | QDir::System | QDir::NoDotAndDotDot);
+            QStringList entries = dir.entryList();
+            foreach (const QString &entry, entries) {
+                if (!copyRecursively(srcPath + "/" + entry, newPath + "/" + entry)) {
+                    return false;
+                }
+            }
+            return true;
+        }
+    }
+    return false;
+}
+
+} // namespace qtlibs
diff --git a/src/libs/qtlibs/dir.h b/src/libs/qtlibs/dir.h
new file mode 100644
index 0000000000000000000000000000000000000000..31e63a556e58a335a4b5fe808f43751f0f453042
--- /dev/null
+++ b/src/libs/qtlibs/dir.h
@@ -0,0 +1,53 @@
+/**
+ * A library for Qt app
+ *
+ * LICENSE: The GNU Lesser General Public License, version 3.0
+ *
+ * @author      Akira Ohgaki <akiraohgaki@gmail.com>
+ * @copyright   Akira Ohgaki
+ * @license     https://opensource.org/licenses/LGPL-3.0  The GNU Lesser General Public License, version 3.0
+ * @link        https://github.com/akiraohgaki/qtlibs
+ */
+
+#pragma once
+
+#include <QObject>
+#include <QFileInfoList>
+
+namespace qtlibs {
+
+class Dir : public QObject
+{
+    Q_OBJECT
+
+public:
+    explicit Dir(const QString &path = QString(), QObject *parent = 0);
+
+    Dir(const Dir &other);
+    Dir &operator =(const Dir &other);
+
+    QString path() const;
+    void setPath(const QString &path);
+
+    bool exists();
+    QFileInfoList list();
+    bool make();
+    bool copy(const QString &newPath);
+    bool move(const QString &newPath);
+    bool remove();
+
+    static QString rootPath();
+    static QString tempPath();
+    static QString homePath();
+    static QString genericDataPath();
+    static QString genericConfigPath();
+    static QString genericCachePath();
+    static QString kdehomePath();
+
+private:
+    bool copyRecursively(const QString &srcPath, const QString &newPath);
+
+    QString path_;
+};
+
+} // namespace qtlibs
diff --git a/src/libs/qtlibs/file.cpp b/src/libs/qtlibs/file.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..d092cfa776502579fe06ba4f6b4be3b8ccf4820e
--- /dev/null
+++ b/src/libs/qtlibs/file.cpp
@@ -0,0 +1,119 @@
+/**
+ * A library for Qt app
+ *
+ * LICENSE: The GNU Lesser General Public License, version 3.0
+ *
+ * @author      Akira Ohgaki <akiraohgaki@gmail.com>
+ * @copyright   Akira Ohgaki
+ * @license     https://opensource.org/licenses/LGPL-3.0  The GNU Lesser General Public License, version 3.0
+ * @link        https://github.com/akiraohgaki/qtlibs
+ */
+
+#include "file.h"
+
+#include <QIODevice>
+#include <QTextStream>
+#include <QFile>
+
+namespace qtlibs {
+
+File::File(const QString &path, QObject *parent)
+    : QObject(parent), path_(path)
+{}
+
+File::File(const File &other)
+{
+    this->setParent(other.parent());
+    setPath(other.path());
+}
+
+File &File::operator =(const File &other)
+{
+    this->setParent(other.parent());
+    setPath(other.path());
+    return *this;
+}
+
+QString File::path() const
+{
+    return path_;
+}
+
+void File::setPath(const QString &path)
+{
+    path_ = path;
+}
+
+bool File::exists()
+{
+    QFile file(path());
+    return file.exists();
+}
+
+QByteArray File::readData()
+{
+    QByteArray data;
+    QFile file(path());
+    if (file.exists() && file.open(QIODevice::ReadOnly)) {
+        data = file.readAll();
+        file.close();
+    }
+    return data;
+}
+
+bool File::writeData(const QByteArray &data)
+{
+    QFile file(path());
+    if (file.open(QIODevice::WriteOnly)) {
+        file.write(data);
+        file.close();
+        return true;
+    }
+    return false;
+}
+
+QString File::readText()
+{
+    QString data;
+    QFile file(path());
+    if (file.exists() && file.open(QIODevice::ReadOnly | QIODevice::Text)) {
+        QTextStream in(&file);
+        in.setCodec("UTF-8");
+        data = in.readAll();
+        file.close();
+    }
+    return data;
+}
+
+bool File::writeText(const QString &data)
+{
+    QFile file(path());
+    if (file.open(QIODevice::WriteOnly | QIODevice::Text)) {
+        QTextStream out(&file);
+        out.setCodec("UTF-8");
+        out << data;
+        file.close();
+        return true;
+    }
+    return false;
+}
+
+bool File::copy(const QString &newPath)
+{
+    QFile file(path());
+    return file.copy(newPath);
+}
+
+bool File::move(const QString &newPath)
+{
+    QFile file(path());
+    return file.rename(newPath);
+}
+
+bool File::remove()
+{
+    QFile file(path());
+    return file.remove();
+}
+
+} // namespace qtlibs
diff --git a/src/libs/qtlibs/file.h b/src/libs/qtlibs/file.h
new file mode 100644
index 0000000000000000000000000000000000000000..bfc1389045ffcb21db10b13381e763e6105bd18c
--- /dev/null
+++ b/src/libs/qtlibs/file.h
@@ -0,0 +1,44 @@
+/**
+ * A library for Qt app
+ *
+ * LICENSE: The GNU Lesser General Public License, version 3.0
+ *
+ * @author      Akira Ohgaki <akiraohgaki@gmail.com>
+ * @copyright   Akira Ohgaki
+ * @license     https://opensource.org/licenses/LGPL-3.0  The GNU Lesser General Public License, version 3.0
+ * @link        https://github.com/akiraohgaki/qtlibs
+ */
+
+#pragma once
+
+#include <QObject>
+
+namespace qtlibs {
+
+class File : public QObject
+{
+    Q_OBJECT
+
+public:
+    explicit File(const QString &path = QString(), QObject *parent = 0);
+
+    File(const File &other);
+    File &operator =(const File &other);
+
+    QString path() const;
+    void setPath(const QString &path);
+
+    bool exists();
+    QByteArray readData();
+    bool writeData(const QByteArray &data);
+    QString readText();
+    bool writeText(const QString &data);
+    bool copy(const QString &newPath);
+    bool move(const QString &newPath);
+    bool remove();
+
+private:
+    QString path_;
+};
+
+} // namespace qtlibs
diff --git a/src/libs/qtlibs/json.cpp b/src/libs/qtlibs/json.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..1cddfe0f6df31516a78394e85af0f1a62a28dc35
--- /dev/null
+++ b/src/libs/qtlibs/json.cpp
@@ -0,0 +1,110 @@
+/**
+ * A library for Qt app
+ *
+ * LICENSE: The GNU Lesser General Public License, version 3.0
+ *
+ * @author      Akira Ohgaki <akiraohgaki@gmail.com>
+ * @copyright   Akira Ohgaki
+ * @license     https://opensource.org/licenses/LGPL-3.0  The GNU Lesser General Public License, version 3.0
+ * @link        https://github.com/akiraohgaki/qtlibs
+ */
+
+#include "json.h"
+
+#include <QJsonDocument>
+#include <QJsonParseError>
+
+namespace qtlibs {
+
+Json::Json(const QByteArray &json, QObject *parent)
+    : QObject(parent), json_(json)
+{}
+
+Json::Json(const QJsonObject &object, QObject *parent)
+    : QObject(parent)
+{
+    fromObject(object);
+}
+
+Json::Json(const QJsonArray &array, QObject *parent)
+    : QObject(parent)
+{
+    fromArray(array);
+}
+
+Json::Json(const Json &other)
+{
+    this->setParent(other.parent());
+    setJson(other.json());
+}
+
+Json &Json::operator =(const Json &other)
+{
+    this->setParent(other.parent());
+    setJson(other.json());
+    return *this;
+}
+
+QByteArray Json::json() const
+{
+    return json_;
+}
+
+void Json::setJson(const QByteArray &json)
+{
+    json_ = json;
+}
+
+void Json::fromObject(const QJsonObject &object)
+{
+    QJsonDocument doc(object);
+    setJson(doc.toJson());
+}
+
+void Json::fromArray(const QJsonArray &array)
+{
+    QJsonDocument doc(array);
+    setJson(doc.toJson());
+}
+
+QByteArray Json::toJson()
+{
+    QJsonDocument doc = QJsonDocument::fromJson(json());
+    return doc.toJson();
+}
+
+QJsonObject Json::toObject()
+{
+    QJsonDocument doc = QJsonDocument::fromJson(json());
+    return doc.object();
+}
+
+QJsonArray Json::toArray()
+{
+    QJsonDocument doc = QJsonDocument::fromJson(json());
+    return doc.array();
+}
+
+bool Json::isValid()
+{
+    QJsonParseError parseError;
+    QJsonDocument::fromJson(json(), &parseError);
+    if (parseError.error == QJsonParseError::NoError) {
+        return true;
+    }
+    return false;
+}
+
+bool Json::isObject()
+{
+    QJsonDocument doc = QJsonDocument::fromJson(json());
+    return doc.isObject();
+}
+
+bool Json::isArray()
+{
+    QJsonDocument doc = QJsonDocument::fromJson(json());
+    return doc.isArray();
+}
+
+} // namespace qtlibs
diff --git a/src/libs/qtlibs/json.h b/src/libs/qtlibs/json.h
new file mode 100644
index 0000000000000000000000000000000000000000..9d6cd4e165bee8067b7da2d43801e1e09443a8e0
--- /dev/null
+++ b/src/libs/qtlibs/json.h
@@ -0,0 +1,48 @@
+/**
+ * A library for Qt app
+ *
+ * LICENSE: The GNU Lesser General Public License, version 3.0
+ *
+ * @author      Akira Ohgaki <akiraohgaki@gmail.com>
+ * @copyright   Akira Ohgaki
+ * @license     https://opensource.org/licenses/LGPL-3.0  The GNU Lesser General Public License, version 3.0
+ * @link        https://github.com/akiraohgaki/qtlibs
+ */
+
+#pragma once
+
+#include <QObject>
+#include <QJsonObject>
+#include <QJsonArray>
+
+namespace qtlibs {
+
+class Json : public QObject
+{
+    Q_OBJECT
+
+public:
+    explicit Json(const QByteArray &json = QByteArray(), QObject *parent = 0);
+    explicit Json(const QJsonObject &object, QObject *parent = 0);
+    explicit Json(const QJsonArray &array, QObject *parent = 0);
+
+    Json(const Json &other);
+    Json &operator =(const Json &other);
+
+    QByteArray json() const;
+    void setJson(const QByteArray &json);
+
+    void fromObject(const QJsonObject &object);
+    void fromArray(const QJsonArray &array);
+    QByteArray toJson();
+    QJsonObject toObject();
+    QJsonArray toArray();
+    bool isValid();
+    bool isObject();
+    bool isArray();
+
+private:
+    QByteArray json_;
+};
+
+} // namespace qtlibs
diff --git a/src/libs/qtlibs/networkresource.cpp b/src/libs/qtlibs/networkresource.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..16238f0f4bdac1686ed462e2d9ff88bd5c52e4d1
--- /dev/null
+++ b/src/libs/qtlibs/networkresource.cpp
@@ -0,0 +1,211 @@
+/**
+ * A library for Qt app
+ *
+ * LICENSE: The GNU Lesser General Public License, version 3.0
+ *
+ * @author      Akira Ohgaki <akiraohgaki@gmail.com>
+ * @copyright   Akira Ohgaki
+ * @license     https://opensource.org/licenses/LGPL-3.0  The GNU Lesser General Public License, version 3.0
+ * @link        https://github.com/akiraohgaki/qtlibs
+ */
+
+#include "networkresource.h"
+
+#include <QEventLoop>
+
+#include "file.h"
+
+namespace qtlibs {
+
+NetworkResource::NetworkResource(const QString &name, const QUrl &url, const bool &async, QObject *parent)
+    : QObject(parent), name_(name), url_(url), async_(async)
+{
+    setManager(new QNetworkAccessManager(this));
+}
+
+NetworkResource::~NetworkResource()
+{
+    manager()->deleteLater();
+}
+
+NetworkResource::NetworkResource(const NetworkResource &other)
+{
+    this->setParent(other.parent());
+    setName(other.name());
+    setUrl(other.url());
+    setAsync(other.async());
+    setRequest(other.request());
+    setManager(other.manager());
+    setReply(other.reply());
+    setMethod(other.method());
+}
+
+NetworkResource &NetworkResource::operator =(const NetworkResource &other)
+{
+    manager()->deleteLater();
+
+    this->setParent(other.parent());
+    setName(other.name());
+    setUrl(other.url());
+    setAsync(other.async());
+    setRequest(other.request());
+    setManager(other.manager());
+    setReply(other.reply());
+    setMethod(other.method());
+    return *this;
+}
+
+QString NetworkResource::name() const
+{
+    return name_;
+}
+
+void NetworkResource::setName(const QString &name)
+{
+    name_ = name;
+}
+
+QUrl NetworkResource::url() const
+{
+    return url_;
+}
+
+void NetworkResource::setUrl(const QUrl &url)
+{
+    url_ = url;
+}
+
+bool NetworkResource::async() const
+{
+    return async_;
+}
+
+void NetworkResource::setAsync(const bool &async)
+{
+    async_ = async;
+}
+
+QNetworkRequest NetworkResource::request() const
+{
+    return request_;
+}
+
+void NetworkResource::setRequest(const QNetworkRequest &request)
+{
+    request_ = request;
+}
+
+QNetworkAccessManager *NetworkResource::manager() const
+{
+    return manager_;
+}
+
+QNetworkReply *NetworkResource::reply() const
+{
+    return reply_;
+}
+
+QString NetworkResource::method() const
+{
+    return method_;
+}
+
+NetworkResource *NetworkResource::head()
+{
+    setMethod("HEAD");
+    QNetworkRequest networkRequest = request();
+    networkRequest.setUrl(url());
+    return send(async(), networkRequest);
+}
+
+NetworkResource *NetworkResource::get()
+{
+    setMethod("GET");
+    QNetworkRequest networkRequest = request();
+    networkRequest.setUrl(url());
+    return send(async(), networkRequest);
+}
+
+QByteArray NetworkResource::readData()
+{
+    QByteArray data;
+    if (reply()->isFinished()) {
+        data = reply()->readAll();
+    }
+    return data;
+}
+
+bool NetworkResource::saveData(const QString &path)
+{
+    if (reply()->isFinished()) {
+        return qtlibs::File(path).writeData(readData());
+    }
+    return false;
+}
+
+void NetworkResource::abort()
+{
+    if (reply()->isRunning()) {
+        reply()->abort();
+    }
+}
+
+void NetworkResource::replyFinished()
+{
+    if (reply()->error() == QNetworkReply::NoError) {
+        // Check if redirection
+        // Note: An auto redirection option is available since Qt 5.6
+        QString newUrl;
+        if (reply()->hasRawHeader("Location")) {
+            newUrl = QString(reply()->rawHeader("Location"));
+        }
+        else if (reply()->hasRawHeader("Refresh")) {
+            newUrl = QString(reply()->rawHeader("Refresh")).split("url=").last();
+        }
+        if (!newUrl.isEmpty()) {
+            if (newUrl.startsWith("/")) {
+                newUrl = reply()->url().authority() + newUrl;
+            }
+            QNetworkRequest networkRequest = request();
+            networkRequest.setUrl(QUrl(newUrl));
+            send(true, networkRequest);
+            return;
+        }
+    }
+    emit finished(this);
+}
+
+void NetworkResource::setManager(QNetworkAccessManager *manager)
+{
+    manager_ = manager;
+}
+
+void NetworkResource::setReply(QNetworkReply *reply)
+{
+    reply_ = reply;
+}
+
+void NetworkResource::setMethod(const QString &method)
+{
+    method_ = method;
+}
+
+NetworkResource *NetworkResource::send(const bool &async, const QNetworkRequest &request)
+{
+    if (method() == "HEAD") {
+        setReply(manager()->head(request));
+    }
+    else if (method() == "GET") {
+        setReply(manager()->get(request));
+        connect(reply(), &QNetworkReply::downloadProgress, this, &NetworkResource::downloadProgress);
+    }
+    connect(reply(), &QNetworkReply::finished, this, &NetworkResource::replyFinished);
+    if (!async) {
+        QEventLoop eventLoop;
+        connect(this, &NetworkResource::finished, &eventLoop, &QEventLoop::quit);
+        eventLoop.exec();
+    }
+    return this;
+}
+
+} // namespace qtlibs
diff --git a/src/libs/qtlibs/networkresource.h b/src/libs/qtlibs/networkresource.h
new file mode 100644
index 0000000000000000000000000000000000000000..4186ee64de4f3c38c76f7cfaa3dae5348737e1c9
--- /dev/null
+++ b/src/libs/qtlibs/networkresource.h
@@ -0,0 +1,76 @@
+/**
+ * A library for Qt app
+ *
+ * LICENSE: The GNU Lesser General Public License, version 3.0
+ *
+ * @author      Akira Ohgaki <akiraohgaki@gmail.com>
+ * @copyright   Akira Ohgaki
+ * @license     https://opensource.org/licenses/LGPL-3.0  The GNU Lesser General Public License, version 3.0
+ * @link        https://github.com/akiraohgaki/qtlibs
+ */
+
+#pragma once
+
+#include <QObject>
+#include <QUrl>
+#include <QNetworkRequest>
+#include <QNetworkAccessManager>
+#include <QNetworkReply>
+
+namespace qtlibs {
+
+class NetworkResource : public QObject
+{
+    Q_OBJECT
+
+public:
+    explicit NetworkResource(const QString &name = QString(), const QUrl &url = QUrl(), const bool &async = true, QObject *parent = 0);
+    ~NetworkResource();
+
+    NetworkResource(const NetworkResource &other);
+    NetworkResource &operator =(const NetworkResource &other);
+
+    QString name() const;
+    void setName(const QString &name);
+    QUrl url() const;
+    void setUrl(const QUrl &url);
+    bool async() const;
+    void setAsync(const bool &async);
+    QNetworkRequest request() const;
+    void setRequest(const QNetworkRequest &request);
+    QNetworkAccessManager *manager() const;
+    QNetworkReply *reply() const;
+    QString method() const;
+
+    NetworkResource *head();
+    NetworkResource *get();
+    QByteArray readData();
+    bool saveData(const QString &path);
+
+signals:
+    void finished(NetworkResource *resource);
+    void downloadProgress(const qint64 &bytesReceived, const qint64 &bytesTotal);
+
+public slots:
+    void abort();
+
+private slots:
+    void replyFinished();
+
+private:
+    void setManager(QNetworkAccessManager *manager);
+    void setReply(QNetworkReply *reply);
+    void setMethod(const QString &method);
+
+    NetworkResource *send(const bool &async, const QNetworkRequest &request);
+
+    QString name_;
+    QUrl url_;
+    bool async_;
+    QNetworkRequest request_;
+    QNetworkAccessManager *manager_;
+    QNetworkReply *reply_;
+    QString method_;
+};
+
+} // namespace qtlibs
diff --git a/src/libs/qtlibs/package.cpp b/src/libs/qtlibs/package.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..d857f14d3757da60393880615e8fa4d7da6d86ad
--- /dev/null
+++ b/src/libs/qtlibs/package.cpp
@@ -0,0 +1,165 @@
+/**
+ * A library for Qt app
+ *
+ * LICENSE: The GNU Lesser General Public License, version 3.0
+ *
+ * @author      Akira Ohgaki <akiraohgaki@gmail.com>
+ * @copyright   Akira Ohgaki
+ * @license     https://opensource.org/licenses/LGPL-3.0  The GNU Lesser General Public License, version 3.0
+ * @link        https://github.com/akiraohgaki/qtlibs
+ */
+
+#include "package.h"
+
+#ifdef QTLIBS_UNIX
+#include <QJsonObject>
+#include <QMimeDatabase>
+#include <QProcess>
+#endif
+
+#ifdef Q_OS_ANDROID
+#include <QAndroidJniObject>
+#endif
+
+namespace qtlibs {
+
+Package::Package(const QString &path, QObject *parent)
+    : QObject(parent), path_(path)
+{}
+
+Package::Package(const Package &other)
+{
+    this->setParent(other.parent());
+    setPath(other.path());
+}
+
+Package &Package::operator =(const Package &other)
+{
+    this->setParent(other.parent());
+    setPath(other.path());
+    return *this;
+}
+
+QString Package::path() const
+{
+    return path_;
+}
+
+void Package::setPath(const QString &path)
+{
+    path_ = path;
+}
+
+#ifdef QTLIBS_UNIX
+bool Package::installAsProgram(const QString &newPath)
+{
+    QStringList arguments;
+    arguments << "-m" << "755" << "-p" << path() << newPath;
+    return execute("install", arguments);
+}
+
+bool Package::installAsFile(const QString &newPath)
+{
+    QStringList arguments;
+    arguments << "-m" << "644" << "-p" << path() << newPath;
+    return execute("install", arguments);
+}
+
+bool Package::installAsArchive(const QString &destinationDirPath)
+{
+    QJsonObject archiveTypes;
+    archiveTypes["application/x-tar"] = QString("tar");
+    archiveTypes["application/x-gzip"] = QString("tar");
+    archiveTypes["application/gzip"] = QString("tar");
+    archiveTypes["application/x-bzip"] = QString("tar");
+    archiveTypes["application/x-bzip2"] = QString("tar");
+    archiveTypes["application/x-xz"] = QString("tar");
+    archiveTypes["application/x-lzma"] = QString("tar");
+    archiveTypes["application/x-lzip"] = QString("tar");
+    archiveTypes["application/x-compressed-tar"] = QString("tar");
+    archiveTypes["application/x-bzip-compressed-tar"] = QString("tar");
+    archiveTypes["application/x-bzip2-compressed-tar"] = QString("tar");
+    archiveTypes["application/x-xz-compressed-tar"] = QString("tar");
+    archiveTypes["application/x-lzma-compressed-tar"] = QString("tar");
+    archiveTypes["application/x-lzip-compressed-tar"] = QString("tar");
+    archiveTypes["application/zip"] = QString("zip");
+    archiveTypes["application/x-7z-compressed"] = QString("7z");
+    archiveTypes["application/x-rar"] = QString("rar");
+    archiveTypes["application/x-rar-compressed"] = QString("rar");
+
+    QMimeDatabase mimeDb;
+    QString mimeType = mimeDb.mimeTypeForFile(path()).name();
+
+    if (archiveTypes.contains(mimeType)) {
+        QString archiveType = archiveTypes[mimeType].toString();
+        QString program;
+        QStringList arguments;
+        if (archiveType == "tar") {
+            program = "tar";
+            arguments << "-xf" << path() << "-C" << destinationDirPath;
+        }
+        else if (archiveType == "zip") {
+            program = "unzip";
+            arguments << "-o" << path() << "-d" << destinationDirPath;
+        }
+        else if (archiveType == "7z") {
+            program = "7z";
+            arguments << "x" << path() << "-o" + destinationDirPath; // No space between -o and directory
+        }
+        else if (archiveType == "rar") {
+            program = "unrar";
+            arguments << "e" << path() << destinationDirPath;
+        }
+        return execute(program, arguments);
+    }
+    return false;
+}
+
+bool Package::installAsPlasmapkg(const QString &type)
+{
+    QStringList arguments;
+    arguments << "-t" << type << "-i" << path();
+    return execute("plasmapkg2", arguments);
+}
+
+bool Package::uninstallAsPlasmapkg(const QString &type)
+{
+    QStringList arguments;
+    arguments << "-t" << type << "-r" << path();
+    return execute("plasmapkg2", arguments);
+}
+#endif
+
+#ifdef Q_OS_ANDROID
+bool Package::installAsApk()
+{
+    QAndroidJniObject activity = QAndroidJniObject::callStaticObjectMethod("org/qtproject/qt5/android/QtNative", "activity", "()Landroid/app/Activity;");
+    if (activity.isValid()) {
+        QAndroidJniObject fileUri = QAndroidJniObject::fromString(path());
+        QAndroidJniObject parsedUri = QAndroidJniObject::callStaticObjectMethod("android/net/Uri", "parse", "(Ljava/lang/String;)Landroid/net/Uri;", fileUri.object());
+        QAndroidJniObject mimeType = QAndroidJniObject::fromString("application/vnd.android.package-archive");
+        QAndroidJniObject activityKind = QAndroidJniObject::fromString("android.intent.action.VIEW");
+        QAndroidJniObject intent("android/content/Intent", "(Ljava/lang/String;)V", activityKind.object());
+        intent = intent.callObjectMethod("setDataAndType", "(Landroid/net/Uri;Ljava/lang/String;)Landroid/content/Intent;", parsedUri.object(), mimeType.object());
+        intent = intent.callObjectMethod("setFlags", "(I)Landroid/content/Intent;", 0x10000000); // 0x10000000 = FLAG_ACTIVITY_NEW_TASK
+        activity.callObjectMethod("startActivity", "(Landroid/content/Intent;)V", intent.object());
+        return true;
+    }
+    return false;
+}
+#endif
+
+#ifdef QTLIBS_UNIX
+bool Package::execute(const QString &program, const QStringList &arguments)
+{
+    QProcess process;
+    process.start(program, arguments);
+    if (process.waitForFinished()) {
+        process.waitForReadyRead();
+        return true;
+    }
+    return false;
+}
+#endif
+
+} // namespace qtlibs
diff --git a/src/libs/qtlibs/package.h b/src/libs/qtlibs/package.h
new file mode 100644
index 0000000000000000000000000000000000000000..b11e77569696cbba1bc0027a19818d2c78ca5ed6
--- /dev/null
+++ b/src/libs/qtlibs/package.h
@@ -0,0 +1,51 @@
+/**
+ * A library for Qt app
+ *
+ * LICENSE: The GNU Lesser General Public License, version 3.0
+ *
+ * @author      Akira Ohgaki <akiraohgaki@gmail.com>
+ * @copyright   Akira Ohgaki
+ * @license     https://opensource.org/licenses/LGPL-3.0  The GNU Lesser General Public License, version 3.0
+ * @link        https://github.com/akiraohgaki/qtlibs
+ */
+
+#pragma once
+
+#include <QObject>
+
+namespace qtlibs {
+
+class Package : public QObject
+{
+    Q_OBJECT
+
+public:
+    explicit Package(const QString &path = QString(), QObject *parent = 0);
+
+    Package(const Package &other);
+    Package &operator =(const Package &other);
+
+    QString path() const;
+    void setPath(const QString &path);
+
+#ifdef QTLIBS_UNIX
+    bool installAsProgram(const QString &newPath);
+    bool installAsFile(const QString &newPath);
+    bool installAsArchive(const QString &destinationDirPath);
+    bool installAsPlasmapkg(const QString &type = "plasmoid");
+    bool uninstallAsPlasmapkg(const QString &type = "plasmoid");
+#endif
+
+#ifdef Q_OS_ANDROID
+    bool installAsApk();
+#endif
+
+private:
+#ifdef QTLIBS_UNIX
+    bool execute(const QString &program, const QStringList &arguments);
+#endif
+
+    QString path_;
+};
+
+} // namespace qtlibs
diff --git a/src/libs/qtlibs/qtlibs.pri b/src/libs/qtlibs/qtlibs.pri
new file mode 100644
index 0000000000000000000000000000000000000000..1050283dd6f985bfada5b46a89b1b7ecf6792d0e
--- /dev/null
+++ b/src/libs/qtlibs/qtlibs.pri
@@ -0,0 +1,27 @@
+QT += \
+    core \
+    network
+
+HEADERS += \
+    $${PWD}/file.h \
+    $${PWD}/dir.h \
+    $${PWD}/json.h \
+    $${PWD}/config.h \
+    $${PWD}/networkresource.h \
+    $${PWD}/package.h
+
+SOURCES += \
+    $${PWD}/file.cpp \
+    $${PWD}/dir.cpp \
+    $${PWD}/json.cpp \
+    $${PWD}/config.cpp \
+    $${PWD}/networkresource.cpp \
+    $${PWD}/package.cpp
+
+unix:!ios:!android {
+    DEFINES += QTLIBS_UNIX
+}
+
+android {
+    QT += androidextras
+}
diff --git a/src/libs/utils/android.cpp b/src/libs/utils/android.cpp
deleted file mode 100644
index 9cca280565c8b419b83065f6fb63e671a61970db..0000000000000000000000000000000000000000
--- a/src/libs/utils/android.cpp
+++ /dev/null
@@ -1,38 +0,0 @@
-/**
- * A library for Qt app
- *
- * LICENSE: The GNU Lesser General Public License, version 3.0
- *
- * @author      Akira Ohgaki <akiraohgaki@gmail.com>
- * @copyright   Akira Ohgaki
- * @license     https://opensource.org/licenses/LGPL-3.0  The GNU Lesser General Public License, version 3.0
- * @link        https://github.com/akiraohgaki/qt-libs
- */
-
-#include "android.h"
-
-#include <QAndroidJniObject>
-
-namespace utils {
-
-Android::Android(QObject *parent) : QObject(parent)
-{}
-
-bool Android::openApk(const QString &uri)
-{
-    QAndroidJniObject activity = QAndroidJniObject::callStaticObjectMethod("org/qtproject/qt5/android/QtNative", "activity", "()Landroid/app/Activity;");
-    if (activity.isValid()) {
-        QAndroidJniObject fileUri = QAndroidJniObject::fromString(uri);
-        QAndroidJniObject parsedUri = QAndroidJniObject::callStaticObjectMethod("android/net/Uri", "parse", "(Ljava/lang/String;)Landroid/net/Uri;", fileUri.object());
-        QAndroidJniObject mimeType = QAndroidJniObject::fromString("application/vnd.android.package-archive");
-        QAndroidJniObject activityKind = QAndroidJniObject::fromString("android.intent.action.VIEW");
-        QAndroidJniObject intent("android/content/Intent", "(Ljava/lang/String;)V", activityKind.object());
-        intent = intent.callObjectMethod("setDataAndType", "(Landroid/net/Uri;Ljava/lang/String;)Landroid/content/Intent;", parsedUri.object(), mimeType.object());
-        intent = intent.callObjectMethod("setFlags", "(I)Landroid/content/Intent;", 0x10000000); // 0x10000000 = FLAG_ACTIVITY_NEW_TASK
-        activity.callObjectMethod("startActivity", "(Landroid/content/Intent;)V", intent.object());
-        return true;
-    }
-    return false;
-}
-
-} // namespace utils
diff --git a/src/libs/utils/android.h b/src/libs/utils/android.h
deleted file mode 100644
index bbbccd36a693dc5ca086cfa1db8d4b87eabaa0e0..0000000000000000000000000000000000000000
--- a/src/libs/utils/android.h
+++ /dev/null
@@ -1,28 +0,0 @@
-/**
- * A library for Qt app
- *
- * LICENSE: The GNU Lesser General Public License, version 3.0
- *
- * @author      Akira Ohgaki <akiraohgaki@gmail.com>
- * @copyright   Akira Ohgaki
- * @license     https://opensource.org/licenses/LGPL-3.0  The GNU Lesser General Public License, version 3.0
- * @link        https://github.com/akiraohgaki/qt-libs
- */
-
-#pragma once
-
-#include <QObject>
-
-namespace utils {
-
-class Android : public QObject
-{
-    Q_OBJECT
-
-public:
-    explicit Android(QObject *parent = 0);
-
-    static bool openApk(const QString &uri);
-};
-
-} // namespace utils
diff --git a/src/libs/utils/config.cpp b/src/libs/utils/config.cpp
deleted file mode 100644
index 13b1018af9a1ee4f0feab0315794875aa8a3bb43..0000000000000000000000000000000000000000
--- a/src/libs/utils/config.cpp
+++ /dev/null
@@ -1,50 +0,0 @@
-/**
- * A library for Qt app
- *
- * LICENSE: The GNU Lesser General Public License, version 3.0
- *
- * @author      Akira Ohgaki <akiraohgaki@gmail.com>
- * @copyright   Akira Ohgaki
- * @license     https://opensource.org/licenses/LGPL-3.0  The GNU Lesser General Public License, version 3.0
- * @link        https://github.com/akiraohgaki/qt-libs
- */
-
-#include "config.h"
-
-#include "file.h"
-#include "json.h"
-
-namespace utils {
-
-Config::Config(const QString &configsDir, QObject *parent) :
-    QObject(parent), configsDir_(configsDir)
-{}
-
-QJsonObject Config::get(const QString &name)
-{
-    QString configFile = configsDir_ + "/" + name + ".json";
-
-    if (!cacheData_.contains(name)) {
-        QString json = utils::File::readText(configFile);
-        if (json.isEmpty()) {
-            json = "{}"; // Blank JSON data as default
-        }
-        cacheData_[name] = utils::Json::convertStrToObj(json);
-    }
-    return cacheData_[name].toObject();
-}
-
-bool Config::set(const QString &name, const QJsonObject &jsonObj)
-{
-    QString configFile = configsDir_ + "/" + name + ".json";
-    QString json = utils::Json::convertObjToStr(jsonObj);
-
-    utils::File::makeDir(configsDir_);
-    if (utils::File::writeText(configFile, json)) {
-        cacheData_[name] = jsonObj;
-        return true;
-    }
-    return false;
-}
-
-} // namespace utils
diff --git a/src/libs/utils/file.cpp b/src/libs/utils/file.cpp
deleted file mode 100644
index 459292abf14210ace0df70dde873e9e71612f6ca..0000000000000000000000000000000000000000
--- a/src/libs/utils/file.cpp
+++ /dev/null
@@ -1,201 +0,0 @@
-/**
- * A library for Qt app
- *
- * LICENSE: The GNU Lesser General Public License, version 3.0
- *
- * @author      Akira Ohgaki <akiraohgaki@gmail.com>
- * @copyright   Akira Ohgaki
- * @license     https://opensource.org/licenses/LGPL-3.0  The GNU Lesser General Public License, version 3.0
- * @link        https://github.com/akiraohgaki/qt-libs
- */
-
-#include "file.h"
-
-#include <QIODevice>
-#include <QStandardPaths>
-#include <QDir>
-#include <QFile>
-#include <QFileInfo>
-#include <QTextStream>
-
-namespace utils {
-
-File::File(QObject *parent) : QObject(parent)
-{}
-
-QString File::rootPath()
-{
-    return QDir::rootPath();
-}
-
-QString File::tempPath()
-{
-    return QDir::tempPath();
-}
-
-QString File::homePath()
-{
-    return QDir::homePath();
-}
-
-QString File::genericDataPath()
-{
-    return QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation);
-}
-
-QString File::genericConfigPath()
-{
-    return QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation);
-}
-
-QString File::genericCachePath()
-{
-    return QStandardPaths::writableLocation(QStandardPaths::GenericCacheLocation);
-}
-
-QString File::kdehomePath()
-{
-    // KDE System Administration/Environment Variables
-    // https://userbase.kde.org/KDE_System_Administration/Environment_Variables
-
-    // KDE 4 maybe uses $KDEHOME
-    QString path = QString::fromLocal8Bit(qgetenv("KDEHOME").constData());
-    if (path.isEmpty()) {
-        path = homePath() + "/.kde";
-    }
-    return path;
-}
-
-QFileInfoList File::readDir(const QString &path)
-{
-    QDir dir(path);
-    dir.setFilter(QDir::AllEntries | QDir::Hidden | QDir::System | QDir::NoDotAndDotDot);
-    //dir.setSorting(QDir::DirsFirst | QDir::Name);
-    return dir.entryInfoList();
-}
-
-bool File::makeDir(const QString &path)
-{
-    // This function will create all parent directories
-    QDir dir(path);
-    if (!dir.exists() && dir.mkpath(path)) {
-        return true;
-    }
-    return false;
-}
-
-QString File::readText(const QString &path)
-{
-    QString data;
-    QFile file(path);
-    if (file.exists() && file.open(QIODevice::ReadOnly | QIODevice::Text)) {
-        QTextStream in(&file);
-        in.setCodec("UTF-8");
-        data = in.readAll();
-        file.close();
-    }
-    return data;
-}
-
-bool File::writeText(const QString &path, const QString &data)
-{
-    QFile file(path);
-    if (file.open(QIODevice::WriteOnly | QIODevice::Text)) {
-        QTextStream out(&file);
-        out.setCodec("UTF-8");
-        out << data;
-        file.close();
-        return true;
-    }
-    return false;
-}
-
-QByteArray File::readBinary(const QString &path)
-{
-    QByteArray data;
-    QFile file(path);
-    if (file.exists() && file.open(QIODevice::ReadOnly)) {
-        data = file.readAll();
-        file.close();
-    }
-    return data;
-}
-
-bool File::writeBinary(const QString &path, const QByteArray &data)
-{
-    QFile file(path);
-    if (file.open(QIODevice::WriteOnly)) {
-        file.write(data);
-        file.close();
-        return true;
-    }
-    return false;
-}
-
-bool File::copy(const QString &path, const QString &targetPath)
-{
-    // This function will copy files recursively
-    QFileInfo fileInfo(path);
-    if (fileInfo.isFile()) {
-        QFile file(path);
-        if (file.copy(targetPath)) {
-            return true;
-        }
-    }
-    else if (fileInfo.isDir()) {
-        QDir targetDir(targetPath);
-        QString targetDirName = targetDir.dirName();
-        targetDir.cdUp();
-        if (targetDir.mkdir(targetDirName)) {
-            QDir dir(path);
-            dir.setFilter(QDir::AllEntries | QDir::Hidden | QDir::System | QDir::NoDotAndDotDot);
-            QStringList entries = dir.entryList();
-            foreach (const QString &entry, entries) {
-                if (!copy(path + "/" + entry, targetPath + "/" + entry)) {
-                    return false;
-                }
-            }
-            return true;
-        }
-    }
-    return false;
-}
-
-bool File::move(const QString &path, const QString &targetPath)
-{
-    QFileInfo fileInfo(path);
-    if (fileInfo.isFile()) {
-        QFile file(path);
-        if (file.rename(targetPath)) {
-            return true;
-        }
-    }
-    else if (fileInfo.isDir()) {
-        QDir dir(path);
-        if (dir.rename(path, targetPath)) {
-            return true;
-        }
-    }
-    return false;
-}
-
-bool File::remove(const QString &path)
-{
-    // This function will remove files recursively
-    QFileInfo fileInfo(path);
-    if (fileInfo.isFile()) {
-        QFile file(path);
-        if (file.remove()) {
-            return true;
-        }
-    }
-    else if (fileInfo.isDir()) {
-        QDir dir(path);
-        if (dir.removeRecursively()) {
-            return true;
-        }
-    }
-    return false;
-}
-
-} // namespace utils
diff --git a/src/libs/utils/file.h b/src/libs/utils/file.h
deleted file mode 100644
index 0ec6548a0c14fb4efe3d616e31fa80c57666ef90..0000000000000000000000000000000000000000
--- a/src/libs/utils/file.h
+++ /dev/null
@@ -1,46 +0,0 @@
-/**
- * A library for Qt app
- *
- * LICENSE: The GNU Lesser General Public License, version 3.0
- *
- * @author      Akira Ohgaki <akiraohgaki@gmail.com>
- * @copyright   Akira Ohgaki
- * @license     https://opensource.org/licenses/LGPL-3.0  The GNU Lesser General Public License, version 3.0
- * @link        https://github.com/akiraohgaki/qt-libs
- */
-
-#pragma once
-
-#include <QObject>
-
-class QFileInfo;
-typedef QList<QFileInfo> QFileInfoList;
-
-namespace utils {
-
-class File : public QObject
-{
-    Q_OBJECT
-
-public:
-    explicit File(QObject *parent = 0);
-
-    static QString rootPath();
-    static QString tempPath();
-    static QString homePath();
-    static QString genericDataPath();
-    static QString genericConfigPath();
-    static QString genericCachePath();
-    static QString kdehomePath();
-    static QFileInfoList readDir(const QString &path);
-    static bool makeDir(const QString &path);
-    static QString readText(const QString &path);
-    static bool writeText(const QString &path, const QString &data);
-    static QByteArray readBinary(const QString &path);
-    static bool writeBinary(const QString &path, const QByteArray &data);
-    static bool copy(const QString &path, const QString &targetPath);
-    static bool move(const QString &path, const QString &targetPath);
-    static bool remove(const QString &path);
-};
-
-} // namespace utils
diff --git a/src/libs/utils/json.cpp b/src/libs/utils/json.cpp
deleted file mode 100644
index 1573c847890f2d0c6365b9372542b9a4db355ec1..0000000000000000000000000000000000000000
--- a/src/libs/utils/json.cpp
+++ /dev/null
@@ -1,50 +0,0 @@
-/**
- * A library for Qt app
- *
- * LICENSE: The GNU Lesser General Public License, version 3.0
- *
- * @author      Akira Ohgaki <akiraohgaki@gmail.com>
- * @copyright   Akira Ohgaki
- * @license     https://opensource.org/licenses/LGPL-3.0  The GNU Lesser General Public License, version 3.0
- * @link        https://github.com/akiraohgaki/qt-libs
- */
-
-#include "json.h"
-
-#include <QJsonDocument>
-#include <QJsonObject>
-#include <QJsonParseError>
-
-namespace utils {
-
-Json::Json(QObject *parent) : QObject(parent)
-{}
-
-QString Json::convertObjToStr(const QJsonObject &jsonObj)
-{
-    QJsonDocument jsonDoc(jsonObj);
-    return QString::fromUtf8(jsonDoc.toJson());
-}
-
-QJsonObject Json::convertStrToObj(const QString &json)
-{
-    QJsonObject jsonObj;
-    QJsonParseError jsonError;
-    QJsonDocument jsonDoc = QJsonDocument::fromJson(json.toUtf8(), &jsonError);
-    if (jsonError.error == QJsonParseError::NoError && jsonDoc.isObject()) {
-        jsonObj = jsonDoc.object();
-    }
-    return jsonObj;
-}
-
-bool Json::isValid(const QString &json)
-{
-    QJsonParseError jsonError;
-    QJsonDocument::fromJson(json.toUtf8(), &jsonError);
-    if (jsonError.error == QJsonParseError::NoError) {
-        return true;
-    }
-    return false;
-}
-
-} // namespace utils
diff --git a/src/libs/utils/json.h b/src/libs/utils/json.h
deleted file mode 100644
index f53527ad12b13650f4a5634d005f52e4bcaf5cfe..0000000000000000000000000000000000000000
--- a/src/libs/utils/json.h
+++ /dev/null
@@ -1,30 +0,0 @@
-/**
- * A library for Qt app
- *
- * LICENSE: The GNU Lesser General Public License, version 3.0
- *
- * @author      Akira Ohgaki <akiraohgaki@gmail.com>
- * @copyright   Akira Ohgaki
- * @license     https://opensource.org/licenses/LGPL-3.0  The GNU Lesser General Public License, version 3.0
- * @link        https://github.com/akiraohgaki/qt-libs
- */
-
-#pragma once
-
-#include <QObject>
-
-namespace utils {
-
-class Json : public QObject
-{
-    Q_OBJECT
-
-public:
-    explicit Json(QObject *parent = 0);
-
-    static QString convertObjToStr(const QJsonObject &jsonObj);
-    static QJsonObject convertStrToObj(const QString &json);
-    static bool isValid(const QString &json);
-};
-
-} // namespace utils
diff --git a/src/libs/utils/network.cpp b/src/libs/utils/network.cpp
deleted file mode 100644
index 2256a941a0a761bd76ddc39fb2c57ea7138c8a47..0000000000000000000000000000000000000000
--- a/src/libs/utils/network.cpp
+++ /dev/null
@@ -1,59 +0,0 @@
-/**
- * A library for Qt app
- *
- * LICENSE: The GNU Lesser General Public License, version 3.0
- *
- * @author      Akira Ohgaki <akiraohgaki@gmail.com>
- * @copyright   Akira Ohgaki
- * @license     https://opensource.org/licenses/LGPL-3.0  The GNU Lesser General Public License, version 3.0
- * @link        https://github.com/akiraohgaki/qt-libs
- */
-
-#include "network.h"
-
-#include <QEventLoop>
-#include <QNetworkAccessManager>
-#include <QNetworkRequest>
-#include <QNetworkReply>
-
-namespace utils {
-
-Network::Network(const bool &async, QObject *parent) :
-    QObject(parent), async_(async)
-{
-    manager_ = new QNetworkAccessManager(this);
-    connect(manager_, &QNetworkAccessManager::finished, this, &utils::Network::finished);
-    if (!async_) {
-        eventLoop_ = new QEventLoop();
-        connect(manager_, &QNetworkAccessManager::finished, eventLoop_, &QEventLoop::quit);
-    }
-}
-
-Network::~Network()
-{
-    manager_->deleteLater();
-    if (!async_) {
-        delete eventLoop_;
-    }
-}
-
-QNetworkReply *Network::head(const QUrl &uri)
-{
-    QNetworkReply *reply = manager_->head(QNetworkRequest(uri));
-    if (!async_) {
-        eventLoop_->exec();
-    }
-    return reply;
-}
-
-QNetworkReply *Network::get(const QUrl &uri)
-{
-    QNetworkReply *reply = manager_->get(QNetworkRequest(uri));
-    connect(reply, &QNetworkReply::downloadProgress, this, &utils::Network::downloadProgress);
-    if (!async_) {
-        eventLoop_->exec();
-    }
-    return reply;
-}
-
-} // namespace utils
diff --git a/src/libs/utils/network.h b/src/libs/utils/network.h
deleted file mode 100644
index fcb835028def3b28e0e99d72f792a813a561a5bd..0000000000000000000000000000000000000000
--- a/src/libs/utils/network.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/**
- * A library for Qt app
- *
- * LICENSE: The GNU Lesser General Public License, version 3.0
- *
- * @author      Akira Ohgaki <akiraohgaki@gmail.com>
- * @copyright   Akira Ohgaki
- * @license     https://opensource.org/licenses/LGPL-3.0  The GNU Lesser General Public License, version 3.0
- * @link        https://github.com/akiraohgaki/qt-libs
- */
-
-#pragma once
-
-#include <QObject>
-
-class QEventLoop;
-class QNetworkAccessManager;
-class QNetworkReply;
-
-namespace utils {
-
-class Network : public QObject
-{
-    Q_OBJECT
-
-public:
-    explicit Network(const bool &async = true, QObject *parent = 0);
-    ~Network();
-
-    QNetworkReply *head(const QUrl &uri);
-    QNetworkReply *get(const QUrl &uri);
-
-signals:
-    void finished(QNetworkReply *reply);
-    void downloadProgress(const qint64 &received, const qint64 &total);
-
-private:
-    bool async_;
-    QNetworkAccessManager *manager_;
-    QEventLoop *eventLoop_;
-};
-
-} // namespace utils
diff --git a/src/libs/utils/package.cpp b/src/libs/utils/package.cpp
deleted file mode 100644
index 6196c063404fc176325665e6a0fba447b58abc83..0000000000000000000000000000000000000000
--- a/src/libs/utils/package.cpp
+++ /dev/null
@@ -1,120 +0,0 @@
-/**
- * A library for Qt app
- *
- * LICENSE: The GNU Lesser General Public License, version 3.0
- *
- * @author      Akira Ohgaki <akiraohgaki@gmail.com>
- * @copyright   Akira Ohgaki
- * @license     https://opensource.org/licenses/LGPL-3.0  The GNU Lesser General Public License, version 3.0
- * @link        https://github.com/akiraohgaki/qt-libs
- */
-
-#include "package.h"
-
-#include <QJsonObject>
-#include <QMimeDatabase>
-#include <QProcess>
-
-namespace utils {
-
-Package::Package(QObject *parent) : QObject(parent)
-{}
-
-bool Package::installProgram(const QString &path, const QString &targetPath)
-{
-    QString program = "install";
-    QStringList arguments;
-    arguments << "-m" << "755" << "-p" << path << targetPath;
-    return execute(program, arguments);
-}
-
-bool Package::installFile(const QString &path, const QString &targetPath)
-{
-    QString program = "install";
-    QStringList arguments;
-    arguments << "-m" << "644" << "-p" << path << targetPath;
-    return execute(program, arguments);
-}
-
-bool Package::installPlasmapkg(const QString &path, const QString &type)
-{
-    QString program = "plasmapkg2";
-    QStringList arguments;
-    arguments << "-t" << type << "-i" << path;
-    return execute(program, arguments);
-}
-
-bool Package::uninstallPlasmapkg(const QString &path, const QString &type)
-{
-    QString program = "plasmapkg2";
-    QStringList arguments;
-    arguments << "-t" << type << "-r" << path;
-    return execute(program, arguments);
-}
-
-bool Package::uncompressArchive(const QString &path, const QString &targetDir)
-{
-    QJsonObject archiveTypes;
-    archiveTypes["application/x-tar"] = QString("tar");
-    archiveTypes["application/x-gzip"] = QString("tar");
-    archiveTypes["application/gzip"] = QString("tar");
-    archiveTypes["application/x-bzip"] = QString("tar");
-    archiveTypes["application/x-bzip2"] = QString("tar");
-    archiveTypes["application/x-xz"] = QString("tar");
-    archiveTypes["application/x-lzma"] = QString("tar");
-    archiveTypes["application/x-lzip"] = QString("tar");
-    archiveTypes["application/x-compressed-tar"] = QString("tar");
-    archiveTypes["application/x-bzip-compressed-tar"] = QString("tar");
-    archiveTypes["application/x-bzip2-compressed-tar"] = QString("tar");
-    archiveTypes["application/x-xz-compressed-tar"] = QString("tar");
-    archiveTypes["application/x-lzma-compressed-tar"] = QString("tar");
-    archiveTypes["application/x-lzip-compressed-tar"] = QString("tar");
-    archiveTypes["application/zip"] = QString("zip");
-    archiveTypes["application/x-7z-compressed"] = QString("7z");
-    archiveTypes["application/x-rar"] = QString("rar");
-    archiveTypes["application/x-rar-compressed"] = QString("rar");
-
-    QMimeDatabase mimeDb;
-    QString mimeType = mimeDb.mimeTypeForFile(path).name();
-
-    if (archiveTypes.contains(mimeType)) {
-        QString archiveType = archiveTypes[mimeType].toString();
-
-        QString program;
-        QStringList arguments;
-
-        if (archiveType == "tar") {
-            program = "tar";
-            arguments << "-xf" << path << "-C" << targetDir;
-        }
-        else if (archiveType == "zip") {
-            program = "unzip";
-            arguments << "-o" << path << "-d" << targetDir;
-        }
-        else if (archiveType == "7z") {
-            program = "7z";
-            arguments << "x" << path << "-o" + targetDir; // No space between -o and directory
-        }
-        else if (archiveType == "rar") {
-            program = "unrar";
-            arguments << "e" << path << targetDir;
-        }
-
-        return execute(program, arguments);
-    }
-
-    return false;
-}
-
-bool Package::execute(const QString &program, const QStringList &arguments)
-{
-    QProcess process;
-    process.start(program, arguments);
-    if (process.waitForFinished()) {
-        process.waitForReadyRead();
-        return true;
-    }
-    return false;
-}
-
-} // namespace utils
diff --git a/src/libs/utils/package.h b/src/libs/utils/package.h
deleted file mode 100644
index 9f086dded976aa2384584a8c9e05d204f9681daf..0000000000000000000000000000000000000000
--- a/src/libs/utils/package.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/**
- * A library for Qt app
- *
- * LICENSE: The GNU Lesser General Public License, version 3.0
- *
- * @author      Akira Ohgaki <akiraohgaki@gmail.com>
- * @copyright   Akira Ohgaki
- * @license     https://opensource.org/licenses/LGPL-3.0  The GNU Lesser General Public License, version 3.0
- * @link        https://github.com/akiraohgaki/qt-libs
- */
-
-#pragma once
-
-#include <QObject>
-
-namespace utils {
-
-class Package : public QObject
-{
-    Q_OBJECT
-
-public:
-    explicit Package(QObject *parent = 0);
-
-    static bool installProgram(const QString &path, const QString &targetPath);
-    static bool installFile(const QString &path, const QString &targetPath);
-    static bool installPlasmapkg(const QString &path, const QString &type = "plasmoid");
-    static bool uninstallPlasmapkg(const QString &path, const QString &type = "plasmoid");
-    static bool uncompressArchive(const QString &path, const QString &targetDir);
-
-private:
-    static bool execute(const QString &program, const QStringList &arguments);
-};
-
-} // namespace utils
diff --git a/xdgurl.pro b/xdgurl.pro
index 6b12f47338694aab2c10540747296cd0bf2860a1..ac9e820402e1711abf2d80dfa1fdfa66e1f0b0c3 100644
--- a/xdgurl.pro
+++ b/xdgurl.pro
@@ -2,37 +2,13 @@ TARGET = xdgurl
 
 TEMPLATE = app
 
-QT += \
-    core \
-    gui \
-    qml \
-    quick \
-    svg \
-    network
-
 CONFIG += c++11
 
-SOURCES += \
-    src/app/main.cpp \
-    src/app/handlers/xdgurl.cpp \
-    src/libs/utils/config.cpp \
-    src/libs/utils/network.cpp \
-    src/libs/utils/file.cpp \
-    src/libs/utils/json.cpp \
-    src/libs/utils/package.cpp
-
-HEADERS += \
-    src/app/handlers/xdgurl.h \
-    src/libs/utils/config.h \
-    src/libs/utils/network.h \
-    src/libs/utils/file.h \
-    src/libs/utils/json.h \
-    src/libs/utils/package.h
-
-RESOURCES += \
-    src/app/configs/configs.qrc \
-    src/app/qml/qml.qrc \
-    src/desktop/desktop.qrc
+INCLUDEPATH += \
+    src/app \
+    src/libs
+
+RESOURCES += src/desktop/desktop.qrc
 
 DISTFILES += \
     README.md \
@@ -48,8 +24,8 @@ DISTFILES += \
     pkg/fedora/xdgurl.spec \
     pkg/arch/PKGBUILD
 
-# Additional RPATH
-#include(rpath.pri)
+include(src/app/app.pri)
+
+include(src/libs/qtlibs/qtlibs.pri)
 
-# Deployment rules
 include(deployment.pri)