1
0
mirror of https://github.com/jaredtao/TaoQuick.git synced 2025-01-17 20:12:54 +08:00

move app to examples

This commit is contained in:
jared 2020-06-30 00:34:25 +08:00
parent 5483b00a40
commit d7a9ccaa54
194 changed files with 737 additions and 177 deletions

View File

@ -4,4 +4,6 @@ TaoQuick_BUILD_TREE = $$PWD/build
TaoQuick_RUN_TREE = $$PWD/bin
TaoQuick_3RDPARTY_TREE = $$PWD/3rdparty
TaoQuick_VERSION_MAJOR = 0.3

View File

@ -5,6 +5,7 @@
#include <QJsonDocument>
#include <QJsonObject>
#include <QString>
#include "Logger/logger.h"
namespace TaoCommon
{
static bool readFile(const QString &filePath, QByteArray &content)
@ -12,7 +13,7 @@ namespace TaoCommon
QFile file(filePath);
if (!file.open(QFile::ReadOnly))
{
qWarning() << "open file " << filePath << "failed:" << file.errorString();
LOG_WARN << "open file " << filePath << "failed:" << file.errorString();
return false;
}
content = file.readAll();
@ -25,7 +26,7 @@ namespace TaoCommon
doc = QJsonDocument::fromJson(data, &err);
if (doc.isNull())
{
qWarning() << "parse json failed:" << err.errorString();
LOG_WARN << "parse json failed:" << err.errorString();
return false;
}
return true;
@ -83,7 +84,7 @@ namespace TaoCommon
QFile file(filePath);
if (!file.open(QFile::WriteOnly))
{
qWarning() << "open file " << filePath << "failed:" << file.errorString();
LOG_WARN << "open file " << filePath << "failed:" << file.errorString();
return false;
}
file.write(content);

125
3rdparty/TaoCommon/Common/objectmap.h vendored Normal file
View File

@ -0,0 +1,125 @@
#pragma once
#include <functional>
#include <map>
#include <memory>
#include <type_traits>
#include <typeindex>
#include <typeinfo>
#include <unordered_map>
namespace TaoCommon
{
//对象存储器
template <typename Key, typename Value>
class ObjectMap
{
public:
virtual ~ObjectMap()
{
clear();
}
void setObj(const Key &key, const Value &obj)
{
m_objMap[key] = obj;
}
Value getObj(const Key &key) const
{
auto itor = m_objMap.find(key);
if (itor == m_objMap.end())
{
return nullptr;
}
else
{
return itor->second;
}
}
void clear()
{
m_objMap.clear();
}
protected:
std::unordered_map<Key, Value> m_objMap;
};
//智能对象存储器。自动生成key自动管理对象。
template <typename ObjectType>
class CObjectMap : public ObjectMap<std::type_index, std::shared_ptr<ObjectType>>
{
public:
template <typename DeriveObjectType>
DeriveObjectType *getObject() const
{
static_assert(std::is_base_of<ObjectType, DeriveObjectType>::value, "DeriveObjectType must be derive from ObjectType");
auto objPtr = getObj(std::type_index(typeid(std::shared_ptr<DeriveObjectType>)));
return std::static_pointer_cast<DeriveObjectType>(objPtr).get();
}
template <typename DeriveObjectType, typename... Args>
void setObject(Args &&... args)
{
static_assert(std::is_base_of<ObjectType, DeriveObjectType>::value, "DeriveObjectType must be derive from ObjectType");
auto obj = std::make_shared<DeriveObjectType>(std::forward(args...));
setObj(std::type_index(typeid(obj)), std::static_pointer_cast<ObjectType>(obj));
}
void forEach(const std::function<void(ObjectType *)> &callback) const
{
for (const auto &pair : m_objMap)
{
callback(pair.second.get());
}
}
};
//优先级对象存储器。自动生成key自动管理对象。支持按优先级处理
template <typename ObjectType>
class CLevelObjectMap
{
public:
virtual ~CLevelObjectMap()
{
clear();
}
template <typename DeriveObjectType>
DeriveObjectType *getObject() const
{
static_assert(std::is_base_of<ObjectType, DeriveObjectType>::value, "DeriveObjectType must be derive from ObjectType");
auto index = std::type_index(typeid(std::shared_ptr<DeriveObjectType>));
for (const auto &mainPair : m_map)
{
const std::unordered_map<std::type_index, std::shared_ptr<ObjectType>> &subMap = mainPair.second;
auto itor = subMap.find(index);
if (itor != subMap.end())
{
return std::static_pointer_cast<DeriveObjectType>(itor->second).get();
}
}
return nullptr;
}
template <typename DeriveObjectType, typename... Args>
void setObject(uint32_t level, Args &&... args)
{
static_assert(std::is_base_of<ObjectType, DeriveObjectType>::value, "DeriveObjectType must be derive from ObjectType");
auto obj = std::make_shared<DeriveObjectType>(args...);
m_map[level][std::type_index(typeid(obj))] = std::static_pointer_cast<ObjectType>(obj);
}
void forEach(const std::function<void(ObjectType *)> &callback) const
{
for (const auto &mainPair : m_map)
{
const std::unordered_map<std::type_index, std::shared_ptr<ObjectType>> &subMap = mainPair.second;
for (const auto &subPair : subMap)
{
callback(subPair.second.get());
}
}
}
void clear()
{
m_map.clear();
}
private:
std::map<uint32_t, std::unordered_map<std::type_index, std::shared_ptr<ObjectType>>> m_map;
};
} // namespace TaoCommon

42
3rdparty/TaoCommon/Common/singleton.h vendored Normal file
View File

@ -0,0 +1,42 @@
#pragma once
namespace TaoCommon
{
//单例模板
template <typename T>
class Singleton
{
public:
static T &instance()
{
static T t;
return t;
}
virtual ~Singleton() {}
Singleton(const Singleton &) = delete;
Singleton &operator=(const Singleton &) = delete;
protected:
Singleton() {}
};
/*
使
:
class DataManager : public Singleton<DataManager>
{
friend class Singleton<DataManager>;
public:
void loadData();
protected:
DataManager();
private:
};
:
DataManager::instance().loadData();
*/
} // namespace TaoCommon

116
3rdparty/TaoCommon/Common/subject.h vendored Normal file
View File

@ -0,0 +1,116 @@
#pragma once
#include <algorithm>
#include <map>
#include <vector>
namespace TaoCommon
{
//观察者模式Subject-Observer。
//Subject 事件或消息的主体。模板参数为观察者类型
template <typename ObserverType>
class Subject
{
public:
virtual ~Subject()
{
m_obsList.clear();
}
//订阅
void subscibe(ObserverType *obs)
{
auto itor = std::find(m_obsList.begin(), m_obsList.end(), obs);
if (m_obsList.end() == itor)
{
m_obsList.push_back(obs);
}
}
//取消订阅
void unSubscibe(ObserverType *obs)
{
m_obsList.erase(std::remove(m_obsList.begin(), m_obsList.end(), obs));
}
//发布。这里的模板参数为函数类型。
template <typename FuncType>
void publish(FuncType func)
{
for (auto obs : m_obsList)
{
//调用回调函数将obs作为第一个参数传递
func(obs);
}
}
//发布。支持过滤观察者。通常用在 观察者触发消息发布时,过滤观察者自己。
template <typename FuncType>
void publish(FuncType func, ObserverType *exceptObs)
{
for (auto obs : m_obsList)
{
//调用回调函数将obs作为第一个参数传递
if (obs != exceptObs)
{
func(obs);
}
}
}
private:
std::vector<ObserverType *> m_obsList;
};
//优先级观察者模式Subject-Observer。
template <typename ObserverType>
class LevelSubject
{
public:
virtual ~LevelSubject()
{
m_obsMap.clear();
}
//订阅
void subscibe(ObserverType *obs, uint32_t level)
{
auto &vec = m_obsMap[level];
auto itor = std::find(vec.begin(), vec.end(), obs);
if (vec.end() == itor)
{
vec.push_back(obs);
}
}
//取消订阅
void unSubscibe(ObserverType *obs)
{
for (auto &obsPair : m_obsMap)
{
obsPair.second.erase(std::remove(obsPair.second.begin(), obsPair.second.end(), obs));
}
}
//发布。这里的模板参数为函数类型。
template <typename FuncType>
void publish(FuncType func)
{
for (const auto &obsPair : m_obsMap)
{
for (const auto &obs : obsPair.second)
{
func(obs);
}
}
}
template <typename FuncType>
void publish(FuncType func, ObserverType *exceptObs)
{
for (const auto &obsPair : m_obsMap)
{
for (const auto &obs : obsPair.second)
{
if (obs != exceptObs)
{
func(obs);
}
}
}
}
private:
std::map<uint32_t, std::vector<ObserverType *>> m_obsMap;
};
} // namespace TaoCommon

145
3rdparty/TaoCommon/Logger/logger.cpp vendored Normal file
View File

@ -0,0 +1,145 @@
#include "logger.h"
#include "loggertemplate.h"
#include <QCoreApplication>
#include <QDateTime>
#include <QDir>
#include <QMutex>
#include <QDebug>
#include <string>
#ifdef Q_OS_WIN
#include <Windows.h>
#else
#include <cstdio>
#endif
namespace Logger
{
static QString gLogDir;
static int gLogMaxCount;
static void outputMessage(QtMsgType type, const QMessageLogContext &context, const QString &msg);
static void outputMessageAsync(QtMsgType type, const QMessageLogContext& context, const QString& msg);
void initLog(const QString &logPath, int logMaxCount, bool async)
{
if (async)
{
qInstallMessageHandler(outputMessageAsync);
}
else
{
qInstallMessageHandler(outputMessage);
}
gLogDir = QCoreApplication::applicationDirPath() + QStringLiteral("/") + logPath;
gLogMaxCount = logMaxCount;
QDir dir(gLogDir);
if (!dir.exists())
{
dir.mkpath(dir.absolutePath());
}
QStringList infoList = dir.entryList(QDir::Files, QDir::Name);
while (infoList.size() > gLogMaxCount)
{
dir.remove(infoList.first());
infoList.removeFirst();
}
}
static void outputMessageAsync(QtMsgType type, const QMessageLogContext &context, const QString &msg)
{
static const QString messageTemp = QStringLiteral("<div class=\"%1\">%2</div>\r\n");
static const char typeList[] = { 'd', 'w', 'c', 'f', 'i' };
static QMutex mutex;
static QFile file;
static QTextStream textStream;
static uint count = 0;
static const uint maxCount = 512;
Q_UNUSED(context)
QDateTime dt = QDateTime::currentDateTime();
//每小时一个文件
QString fileNameDt = dt.toString(QStringLiteral("yyyy-MM-dd_hh"));
//每分钟一个文件
//QString fileNameDt = dt.toString("yyyy-MM-dd_hh_mm");
QString contentDt = dt.toString(QStringLiteral("yyyy-MM-dd hh:mm:ss"));
QString message = QStringLiteral("%1 %2").arg(contentDt).arg(msg);
QString htmlMessage = messageTemp.arg(typeList[static_cast<int>(type)]).arg(message);
QString newfileName = QStringLiteral("%1/%2_log.html").arg(gLogDir).arg(fileNameDt);
mutex.lock();
if (file.fileName() != newfileName)
{
if (file.isOpen())
{
file.close();
}
file.setFileName(newfileName);
bool exist = file.exists();
file.open(QIODevice::WriteOnly | QIODevice::Append);
textStream.setDevice(&file);
textStream.setCodec("UTF-8");
if (!exist)
{
textStream << logTemplate << "\r\n";
}
}
textStream << htmlMessage;
textStream.flush();
count += htmlMessage.length();
if (count >= maxCount)
{
file.close();
file.open(QIODevice::WriteOnly | QIODevice::Append);
}
mutex.unlock();
#ifdef Q_OS_WIN
::OutputDebugString(message.toStdWString().data());
::OutputDebugString(L"\r\n");
#else
fprintf(stderr, message.toStdString().data());
#endif
}
static void outputMessage(QtMsgType type, const QMessageLogContext& context, const QString& msg)
{
static const QString messageTemp = QStringLiteral("<div class=\"%1\">%2</div>\r\n");
static const char typeList[] = { 'd', 'w', 'c', 'f', 'i' };
static QMutex mutex;
Q_UNUSED(context)
QDateTime dt = QDateTime::currentDateTime();
//每小时一个文件
QString fileNameDt = dt.toString(QStringLiteral("yyyy-MM-dd_hh"));
//每分钟一个文件
//QString fileNameDt = dt.toString("yyyy-MM-dd_hh_mm");
QString contentDt = dt.toString(QStringLiteral("yyyy-MM-dd hh:mm:ss"));
QString message = QStringLiteral("%1 %2").arg(contentDt).arg(msg);
QString htmlMessage = messageTemp.arg(typeList[static_cast<int>(type)]).arg(message);
QFile file(QStringLiteral("%1/%2_log.html").arg(gLogDir).arg(fileNameDt));
mutex.lock();
bool exist = file.exists();
file.open(QIODevice::WriteOnly | QIODevice::Append);
QTextStream textStream(&file);
textStream.setCodec("UTF-8");
if (!exist)
{
textStream << logTemplate << "\r\n";
}
textStream << htmlMessage;
file.close();
mutex.unlock();
#ifdef Q_OS_WIN
::OutputDebugString(message.toStdWString().data());
::OutputDebugString(L"\r\n");
#else
fprintf(stderr, message.toStdString().data());
#endif
}
} // namespace Logger

23
3rdparty/TaoCommon/Logger/logger.h vendored Normal file
View File

@ -0,0 +1,23 @@
#pragma once
#include "taocommonglobal.h"
#include <QString>
#include <QDebug>
namespace Logger
{
#ifdef _DEBUG
#define LOG_DEBUG qDebug() << __FILE__ << __LINE__
#define LOG_INFO qInfo() << __FILE__ << __LINE__
#define LOG_WARN qWarning() << __FILE__ << __LINE__
#define LOG_CRIT qCritical() << __FILE__ << __LINE__
#else
#define LOG_DEBUG qDebug()
#define LOG_INFO qInfo()
#define LOG_WARN qWarning()
#define LOG_CRIT qCritical()
#endif
// 初始化Log存储。包括创建Log文件夹、删除超过最大数的log仅初始化时删除运行过程中不删除
// logPath 存储路径
// logMaxCount 最大数
// async 是否异步存储 默认异步存储。异步存储会缓存log达到一定数量、或者软件退出时才写入文件。
void TAO_API initLog(const QString &logPath = QStringLiteral("Log"), int logMaxCount = 1024, bool async = true);
} // namespace Logger

View File

@ -3,13 +3,13 @@
#include <string>
namespace Logger
{
const static QString logTemplate = u8R"logTemplate(
const static auto logTemplate = QString::fromUtf8(u8R"logTemplate(
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<head>
<title>TaoLogger</title>
<title>Lubansoft log file</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<style type="text/css" id="logCss">
body {
@ -86,7 +86,7 @@ namespace Logger
</head>
<body>
<h1><a href="https://jaredtao.github.io">TaoLogger</a> </h1>
<h1><a href="http://jaredtao.github.io/">TaoLogger</a> </h1>
<script type="text/JavaScript">
function objHide(obj) {
obj.style.display="none"
@ -122,5 +122,5 @@ namespace Logger
<option value='c'>Critical</option>
<option value='f'>Fatal</option>
</select>
)logTemplate";
)logTemplate");
}

25
3rdparty/TaoCommon/TaoCommon.pri vendored Normal file
View File

@ -0,0 +1,25 @@
!build_TaoCommon_lib:{
DEFINES +=TaoCommon_NO_LIB
}
INCLUDEPATH += $$PWD \
$$PWD/Common \
$$PWD/Logger \
$$PWD/Thread
HEADERS += \
$$PWD/Common/filereadwrite.h \
$$PWD/Common/objectmap.h \
$$PWD/Common/singleton.h \
$$PWD/Common/subject.h \
$$PWD/Logger/loggertemplate.h \
$$PWD/Logger/logger.h \
$$PWD/Thread/threadcommon.h \
$$PWD/Thread/threadpool.h \
$$PWD/Thread/threadworkercontroller.h \
$$PWD/taocommonglobal.h
SOURCES += \
$$PWD/Logger/logger.cpp \
$$PWD/Thread/threadpool.cpp

14
3rdparty/TaoCommon/TaoCommon.pro vendored Normal file
View File

@ -0,0 +1,14 @@
TARGET = TaoCommon
load(qt_module)
QT += core
QMAKE_TARGET_COMPANY = "jaredtao.github.io"
QMAKE_TARGET_COPYRIGHT = "Copyright (C) 2019-2022 JaredTao <jared2020@163.com>"
QMAKE_TARGET_PRODUCT = "TaoCommon"
QMAKE_TARGET_DESCRIPTION = "common use code for Qt."
CONFIG += build_TaoCommon_lib
DEFINES += TaoCommon_Library
include(TaoCommon.pri)

View File

@ -0,0 +1,10 @@
#pragma once
#include <QMetaType>
#include <functional>
namespace TaoCommon
{
using WorkCallback = std::function<bool()>;
using WorkResultCallback = std::function<void(bool)>;
}
Q_DECLARE_METATYPE(TaoCommon::WorkCallback);
Q_DECLARE_METATYPE(TaoCommon::WorkResultCallback);

View File

@ -0,0 +1,22 @@
#include "threadpool.h"
#include <QThreadPool>
namespace TaoCommon
{
ThreadObject::ThreadObject(const WorkCallback& work) : m_workCall(work) {}
void ThreadObject::run()
{
bool ok = m_workCall();
emit readyResult(ok);
}
//workCall in sub thread, resultCall in main thread
void ThreadPool::work(const WorkCallback& workCall, const WorkResultCallback& resultCall)
{
ThreadObject* obj = new ThreadObject(workCall);
obj->setAutoDelete(true);
connect(obj, &ThreadObject::readyResult, this, resultCall);
QThreadPool::globalInstance()->start(obj);
}
}

41
3rdparty/TaoCommon/Thread/threadpool.h vendored Normal file
View File

@ -0,0 +1,41 @@
#pragma once
#include "taocommonglobal.h"
#include "threadcommon.h"
#include <QObject>
#include <QRunnable>
namespace TaoCommon
{
// 对Qt线程池的简单封装适合一次性执行的任务。
// 用法: ThreadPool::getInstance()->work(workCall, resultCall)
// workCall是在新线程中执行的任务resultCall是任务执行完成后回到调用线程中用来处理执行结果。
// 不支持任务取消、暂停。
class ThreadObject
: public QObject
, public QRunnable
{
Q_OBJECT
public:
explicit ThreadObject(const WorkCallback& work);
void run() override;
signals:
void readyResult(bool);
private:
WorkCallback m_workCall;
};
class TAO_API ThreadPool : public QObject
{
Q_OBJECT
public:
static ThreadPool* getInstance()
{
static ThreadPool poll;
return &poll;
}
//workCall in sub thread, resultCall in main thread
void work(const WorkCallback& workCall, const WorkResultCallback& resultCall);
private:
ThreadPool() {}
};
} // namespace TaoCommon

View File

@ -0,0 +1,129 @@
#pragma once
#include "taocommonglobal.h"
#include "threadcommon.h"
#include <QMap>
#include <QThread>
namespace TaoCommon
{
// 对Qt Worker-Controller 线程模型的简单封装,适合精确控制的任务。
// 用法: ThreadController::getInstance()->work(workCall, resultCall)
// workCall是在新线程中执行的任务resultCall是任务执行完成后回到调用线程中用来处理执行结果。
// work函数返回值为任务id。
// 取消任务用ThreadController::getInstance()->cancle(id)函数。
class ThreadWorker : public QObject
{
Q_OBJECT
public:
ThreadWorker(uint64_t id, const WorkCallback &workCall, QObject *parent = nullptr) : QObject(parent), m_id(id), m_workCall(workCall) {}
signals:
void workFinished(bool, uint64_t);
public slots:
void doWork()
{
bool ret = m_workCall();
emit workFinished(ret, m_id);
}
private:
const uint64_t m_id;
WorkCallback m_workCall;
};
class TAO_API ThreadController : public QObject
{
Q_OBJECT
public:
static ThreadController *getInstance()
{
static ThreadController controller;
return &controller;
}
~ThreadController()
{
for (auto k : m_threadMap.uniqueKeys())
{
if (m_threadMap.value(k)->isRunning())
{
m_threadMap.value(k)->quit();
m_threadMap.value(k)->wait();
}
}
qDeleteAll(m_threadMap);
m_threadMap.clear();
m_resultCallback.clear();
}
uint64_t work(const WorkCallback &workCall, const WorkResultCallback &resultCall)
{
QThread *thread = new QThread;
m_rollId++;
ThreadWorker *obj = new ThreadWorker(m_rollId, workCall);
m_threadMap[m_rollId] = thread;
m_resultCallback[m_rollId] = resultCall;
obj->moveToThread(thread);
connect(thread, &QThread::finished, obj, &QObject::deleteLater);
connect(thread, &QThread::started, obj, &ThreadWorker::doWork);
connect(obj, &ThreadWorker::workFinished, this, &ThreadController::onWorkFinished, Qt::QueuedConnection);
thread->start();
return m_rollId;
}
void cancle(uint64_t id)
{
auto it = m_threadMap.find(id);
if (it != m_threadMap.end())
{
if ((*it)->isRunning())
{
(*it)->terminate();
}
}
m_resultCallback.remove(id);
}
void quit(uint64_t id)
{
auto it = m_threadMap.find(id);
if (it != m_threadMap.end())
{
if ((*it)->isRunning())
{
(*it)->quit();
(*it)->wait();
(*it)->deleteLater();
}
}
m_resultCallback.remove(id);
}
QList<uint64_t> getAllWorkId() const
{
return m_threadMap.uniqueKeys();
}
protected slots :
void onWorkFinished(bool ok, uint64_t id)
{
auto it = m_threadMap.find(id);
if (it != m_threadMap.end())
{
if ((*it)->isRunning())
{
(*it)->quit();
(*it)->wait();
(*it)->deleteLater();
}
m_threadMap.remove(id);
}
auto caller = m_resultCallback.find(id);
if (caller != m_resultCallback.end())
{
(*caller)(ok);
m_resultCallback.remove(id);
}
}
protected:
ThreadController(QObject *parent = nullptr) : QObject(parent) {}
private:
uint64_t m_rollId = 0;
QMap<uint64_t, QThread *> m_threadMap;
QMap<uint64_t, WorkResultCallback> m_resultCallback;
};
} // namespace LCIM

12
3rdparty/TaoCommon/taocommonglobal.h vendored Normal file
View File

@ -0,0 +1,12 @@
#pragma once
#include <QtCore/QtGlobal>
#if !defined(BUILD_STATIC) && !defined(TaoCommon_NO_LIB)
#if defined(TaoCommon_Library)
#define TAO_API Q_DECL_EXPORT
#else
#define TAO_API Q_DECL_IMPORT
#endif
#else
#define TAO_API
#endif

View File

@ -7,7 +7,9 @@ lessThan(QT_MAJOR_VERSION, 5) {
TEMPLATE = subdirs
SUBDIRS += \
src
src \
examples
CONFIG+= ordered
OTHER_FILES += *.md \
LICENSE \

View File

Before

Width:  |  Height:  |  Size: 102 KiB

After

Width:  |  Height:  |  Size: 102 KiB

View File

Before

Width:  |  Height:  |  Size: 71 KiB

After

Width:  |  Height:  |  Size: 71 KiB

View File

Before

Width:  |  Height:  |  Size: 79 KiB

After

Width:  |  Height:  |  Size: 79 KiB

View File

Before

Width:  |  Height:  |  Size: 80 KiB

After

Width:  |  Height:  |  Size: 80 KiB

View File

Before

Width:  |  Height:  |  Size: 77 KiB

After

Width:  |  Height:  |  Size: 77 KiB

View File

Before

Width:  |  Height:  |  Size: 98 KiB

After

Width:  |  Height:  |  Size: 98 KiB

View File

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

View File

Before

Width:  |  Height:  |  Size: 47 KiB

After

Width:  |  Height:  |  Size: 47 KiB

View File

Before

Width:  |  Height:  |  Size: 833 B

After

Width:  |  Height:  |  Size: 833 B

View File

Before

Width:  |  Height:  |  Size: 870 B

After

Width:  |  Height:  |  Size: 870 B

View File

Before

Width:  |  Height:  |  Size: 447 B

After

Width:  |  Height:  |  Size: 447 B

View File

Before

Width:  |  Height:  |  Size: 410 B

After

Width:  |  Height:  |  Size: 410 B

View File

Before

Width:  |  Height:  |  Size: 1.9 MiB

After

Width:  |  Height:  |  Size: 1.9 MiB

View File

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

Before

Width:  |  Height:  |  Size: 972 B

After

Width:  |  Height:  |  Size: 972 B

View File

Before

Width:  |  Height:  |  Size: 260 B

After

Width:  |  Height:  |  Size: 260 B

View File

Before

Width:  |  Height:  |  Size: 239 B

After

Width:  |  Height:  |  Size: 239 B

View File

Before

Width:  |  Height:  |  Size: 198 B

After

Width:  |  Height:  |  Size: 198 B

View File

Before

Width:  |  Height:  |  Size: 166 B

After

Width:  |  Height:  |  Size: 166 B

View File

Before

Width:  |  Height:  |  Size: 290 B

After

Width:  |  Height:  |  Size: 290 B

View File

Before

Width:  |  Height:  |  Size: 274 B

After

Width:  |  Height:  |  Size: 274 B

View File

Before

Width:  |  Height:  |  Size: 528 B

After

Width:  |  Height:  |  Size: 528 B

View File

Before

Width:  |  Height:  |  Size: 463 B

After

Width:  |  Height:  |  Size: 463 B

View File

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 17 KiB

View File

Before

Width:  |  Height:  |  Size: 981 B

After

Width:  |  Height:  |  Size: 981 B

View File

Before

Width:  |  Height:  |  Size: 2.1 MiB

After

Width:  |  Height:  |  Size: 2.1 MiB

View File

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

View File

Before

Width:  |  Height:  |  Size: 27 KiB

After

Width:  |  Height:  |  Size: 27 KiB

View File

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 30 KiB

View File

Before

Width:  |  Height:  |  Size: 35 KiB

After

Width:  |  Height:  |  Size: 35 KiB

View File

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 28 KiB

View File

Before

Width:  |  Height:  |  Size: 54 KiB

After

Width:  |  Height:  |  Size: 54 KiB

View File

Before

Width:  |  Height:  |  Size: 40 KiB

After

Width:  |  Height:  |  Size: 40 KiB

View File

Before

Width:  |  Height:  |  Size: 40 KiB

After

Width:  |  Height:  |  Size: 40 KiB

View File

Before

Width:  |  Height:  |  Size: 41 KiB

After

Width:  |  Height:  |  Size: 41 KiB

View File

Before

Width:  |  Height:  |  Size: 86 KiB

After

Width:  |  Height:  |  Size: 86 KiB

View File

Before

Width:  |  Height:  |  Size: 47 KiB

After

Width:  |  Height:  |  Size: 47 KiB

View File

Before

Width:  |  Height:  |  Size: 39 KiB

After

Width:  |  Height:  |  Size: 39 KiB

View File

Before

Width:  |  Height:  |  Size: 42 KiB

After

Width:  |  Height:  |  Size: 42 KiB

View File

Before

Width:  |  Height:  |  Size: 32 KiB

After

Width:  |  Height:  |  Size: 32 KiB

View File

Before

Width:  |  Height:  |  Size: 56 KiB

After

Width:  |  Height:  |  Size: 56 KiB

View File

Before

Width:  |  Height:  |  Size: 38 KiB

After

Width:  |  Height:  |  Size: 38 KiB

View File

Before

Width:  |  Height:  |  Size: 304 B

After

Width:  |  Height:  |  Size: 304 B

View File

Before

Width:  |  Height:  |  Size: 217 KiB

After

Width:  |  Height:  |  Size: 217 KiB

View File

Before

Width:  |  Height:  |  Size: 3.7 KiB

After

Width:  |  Height:  |  Size: 3.7 KiB

View File

Before

Width:  |  Height:  |  Size: 5.3 KiB

After

Width:  |  Height:  |  Size: 5.3 KiB

View File

Before

Width:  |  Height:  |  Size: 180 B

After

Width:  |  Height:  |  Size: 180 B

Some files were not shown because too many files have changed in this diff Show More