4 pages de détail avec courbe (Canvas), navigation depuis home.qml, sélecteurs de variable pour circuits/batteries

This commit is contained in:
2026-08-26 17:26:52 +02:00
parent d9593518d0
commit 85ba4be46b
144 changed files with 2344 additions and 115 deletions
+86 -4
View File
@@ -2,7 +2,6 @@
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QJsonDocument>
#include <QJsonObject>
#include <QUrl>
#include <QUrlQuery>
@@ -10,51 +9,90 @@ DataProvider::DataProvider(QObject *parent) : QObject(parent)
{
}
void DataProvider::signalerSucces()
{
m_connecte = true;
m_derniereConnexionReussie = QDateTime::currentDateTime();
emit etatConnexionChange();
}
void DataProvider::signalerEchec()
{
if (m_connecte) {
m_connecte = false;
emit etatConnexionChange();
}
}
void DataProvider::get_familles(const QString &type)
{
if (m_replyFamillesEnCours) m_replyFamillesEnCours->abort();
QUrl url(m_baseUrl + "/elements/familles");
QUrlQuery query;
query.addQueryItem("type", type);
url.setQuery(query);
auto reply = m_manager.get(QNetworkRequest(url));
QNetworkRequest request(url);
request.setTransferTimeout(5000);
auto reply = m_manager.get(request);
m_replyFamillesEnCours = reply;
connect(reply, &QNetworkReply::finished, this, [this, reply, type]() {
reply->deleteLater();
if (m_replyFamillesEnCours == reply) m_replyFamillesEnCours = nullptr;
if (reply->error() == QNetworkReply::OperationCanceledError) return;
if (reply->error() != QNetworkReply::NoError) {
signalerEchec();
emit erreur(reply->errorString());
return;
}
const auto doc = QJsonDocument::fromJson(reply->readAll());
const auto obj = doc.object();
if (obj["status"].toString() != "ok") {
signalerEchec();
emit erreur(obj["message"].toString());
return;
}
signalerSucces();
emit famillesRecues(type, obj["familles"].toArray());
});
}
void DataProvider::get_elements(const QString &type, int famille)
{
if (m_replyElementsEnCours) m_replyElementsEnCours->abort();
QUrl url(m_baseUrl + "/elements");
QUrlQuery query;
query.addQueryItem("type", type);
query.addQueryItem("famille", QString::number(famille));
url.setQuery(query);
auto reply = m_manager.get(QNetworkRequest(url));
QNetworkRequest request(url);
request.setTransferTimeout(5000);
auto reply = m_manager.get(request);
m_replyElementsEnCours = reply;
connect(reply, &QNetworkReply::finished, this, [this, reply, type, famille]() {
reply->deleteLater();
if (m_replyElementsEnCours == reply) m_replyElementsEnCours = nullptr;
if (reply->error() == QNetworkReply::OperationCanceledError) return;
if (reply->error() != QNetworkReply::NoError) {
signalerEchec();
emit erreur(reply->errorString());
return;
}
const auto doc = QJsonDocument::fromJson(reply->readAll());
const auto obj = doc.object();
if (obj["status"].toString() != "ok") {
signalerEchec();
emit erreur(obj["message"].toString());
return;
}
signalerSucces();
emit elementsRecus(type, famille, obj["elements"].toArray());
});
}
@@ -64,6 +102,7 @@ void DataProvider::set_circuit(int id, int consigne)
QUrl url(m_baseUrl + "/elements/circuit/" + QString::number(id));
QNetworkRequest request(url);
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
request.setTransferTimeout(5000);
QJsonObject body;
body["consigne"] = consigne;
@@ -73,7 +112,50 @@ void DataProvider::set_circuit(int id, int consigne)
connect(reply, &QNetworkReply::finished, this, [this, reply, id]() {
reply->deleteLater();
const bool succes = (reply->error() == QNetworkReply::NoError);
if (!succes) emit erreur(reply->errorString());
if (succes) signalerSucces();
else {
signalerEchec();
emit erreur(reply->errorString());
}
emit circuitModifie(id, succes);
});
}
void DataProvider::get_mesures(const QString &type, int id, int periode, const QString &variable)
{
if (m_replyMesuresEnCours) m_replyMesuresEnCours->abort();
QUrl url(m_baseUrl + "/mesures");
QUrlQuery query;
query.addQueryItem("type", type);
query.addQueryItem("id", QString::number(id));
query.addQueryItem("periode", QString::number(periode));
if (!variable.isEmpty()) query.addQueryItem("variable", variable);
url.setQuery(query);
QNetworkRequest request(url);
request.setTransferTimeout(8000); // Requête potentiellement plus lourde (jusqu'à 200 points) qu'un simple /elements - délai un peu plus généreux.
auto reply = m_manager.get(request);
m_replyMesuresEnCours = reply;
connect(reply, &QNetworkReply::finished, this, [this, reply, type, id, periode, variable]() {
reply->deleteLater();
if (m_replyMesuresEnCours == reply) m_replyMesuresEnCours = nullptr;
if (reply->error() == QNetworkReply::OperationCanceledError) return;
if (reply->error() != QNetworkReply::NoError) {
signalerEchec();
emit erreur(reply->errorString());
return;
}
const auto doc = QJsonDocument::fromJson(reply->readAll());
const auto obj = doc.object();
if (obj["status"].toString() != "ok") {
signalerEchec();
emit erreur(obj["message"].toString());
return;
}
signalerSucces();
emit mesuresRecues(type, id, periode, variable, obj);
});
}
+37 -5
View File
@@ -2,6 +2,10 @@
#include <QObject>
#include <QNetworkAccessManager>
#include <QJsonArray>
#include <QJsonObject>
#include <QDateTime>
class QNetworkReply;
// ============================================================================
// DataProvider - couche d'accès aux données du client WASM (cas 2/3).
@@ -11,13 +15,23 @@
// HTTP/JSON est encapsulée ici - le QML ne voit que des signaux avec des
// tableaux déjà prêts à l'emploi.
//
// Portée actuelle : les 4 domaines (circuit, batterie, capteur, reservoir)
// en lecture, écriture (consigne/mode auto) sur circuit uniquement.
// Portée actuelle : les 4 domaines (circuits, batteries, capteurs, reservoirs)
// en lecture, écriture (consigne/mode auto) sur circuits uniquement, et
// désormais l'historique/courbe (capteurs uniquement pour l'instant, cf
// GET /mesures côté API).
//
// Suit également l'état de connexion (succès/échec de chaque requête) pour
// permettre à l'UI d'afficher un état "hors ligne" explicite plutôt que de
// laisser les listes silencieusement vides ou figées.
// ============================================================================
class DataProvider : public QObject
{
Q_OBJECT
Q_PROPERTY(bool connecte READ connecte NOTIFY etatConnexionChange)
Q_PROPERTY(bool aDejaEteConnecte READ aDejaEteConnecte NOTIFY etatConnexionChange)
Q_PROPERTY(QDateTime derniereConnexionReussie READ derniereConnexionReussie NOTIFY etatConnexionChange)
public:
explicit DataProvider(QObject *parent = nullptr);
@@ -30,16 +44,34 @@ public:
// Écriture rapide sur un circuit (bouton d'accueil) - PATCH /elements/circuit/<id>.
Q_INVOKABLE void set_circuit(int id, int consigne);
// Historique/courbe pour la page de détail - GET /mesures.
// periode : 0=1h, 1=24h, 2=7j, 3=30j (même convention que le natif).
// variable : requis pour circuits/batteries (sélecteur de variable côté
// client), ignoré pour capteurs/reservoirs (variable fixe côté serveur).
Q_INVOKABLE void get_mesures(const QString &type, int id, int periode, const QString &variable = QString());
bool connecte() const { return m_connecte; }
bool aDejaEteConnecte() const { return m_derniereConnexionReussie.isValid(); }
QDateTime derniereConnexionReussie() const { return m_derniereConnexionReussie; }
signals:
// Le type (et, pour les éléments, la famille) sont désormais inclus dans
// chaque signal - indispensable avec plusieurs domaines actifs en
// parallèle, pour que le QML sache à quelle réponse il a affaire.
void famillesRecues(const QString &type, const QJsonArray &familles);
void elementsRecus(const QString &type, int famille, const QJsonArray &elements);
void circuitModifie(int id, bool succes);
void mesuresRecues(const QString &type, int id, int periode, const QString &variable, const QJsonObject &donnees);
void erreur(const QString &message);
void etatConnexionChange();
private:
void signalerSucces();
void signalerEchec();
QNetworkAccessManager m_manager;
QString m_baseUrl = QStringLiteral("https://api.ship2net.fr");
bool m_connecte = false;
QDateTime m_derniereConnexionReussie;
QNetworkReply *m_replyFamillesEnCours = nullptr;
QNetworkReply *m_replyElementsEnCours = nullptr;
QNetworkReply *m_replyMesuresEnCours = nullptr;
};
+139
View File
@@ -0,0 +1,139 @@
#include "dataprovider.h"
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QJsonDocument>
#include <QJsonObject>
#include <QUrl>
#include <QUrlQuery>
DataProvider::DataProvider(QObject *parent) : QObject(parent)
{
}
void DataProvider::signalerSucces()
{
m_connecte = true;
m_derniereConnexionReussie = QDateTime::currentDateTime();
emit etatConnexionChange();
}
void DataProvider::signalerEchec()
{
// Ne touche JAMAIS m_derniereConnexionReussie ici : on veut garder la
// trace du dernier succès réel, pas la remplacer par l'instant de l'échec.
if (m_connecte) {
m_connecte = false;
emit etatConnexionChange();
}
}
void DataProvider::get_familles(const QString &type)
{
if (m_replyFamillesEnCours) {
m_replyFamillesEnCours->abort(); // Requête précédente encore en attente : remplacée par celle-ci
}
QUrl url(m_baseUrl + "/elements/familles");
QUrlQuery query;
query.addQueryItem("type", type);
url.setQuery(query);
QNetworkRequest request(url);
// Sans délai explicite, une requête vers un CM5 devenu injoignable peut
// rester en attente indéfiniment côté navigateur (ni succès ni échec) -
// 'finished' ne se déclencherait alors jamais, empêchant toute détection
// de perte de connexion.
request.setTransferTimeout(TIME_OUT_TRANSFER_DATA);
auto reply = m_manager.get(request);
m_replyFamillesEnCours = reply;
connect(reply, &QNetworkReply::finished, this, [this, reply, type]() {
reply->deleteLater();
if (m_replyFamillesEnCours == reply) m_replyFamillesEnCours = nullptr;
if (reply->error() == QNetworkReply::OperationCanceledError) {
return; // Annulée volontairement (remplacée par une requête plus récente) - pas un vrai échec réseau
}
if (reply->error() != QNetworkReply::NoError) {
signalerEchec();
emit erreur(reply->errorString());
return;
}
const auto doc = QJsonDocument::fromJson(reply->readAll());
const auto obj = doc.object();
if (obj["status"].toString() != "ok") {
signalerEchec();
emit erreur(obj["message"].toString());
return;
}
signalerSucces();
emit famillesRecues(type, obj["familles"].toArray());
});
}
void DataProvider::get_elements(const QString &type, int famille)
{
if (m_replyElementsEnCours) {
m_replyElementsEnCours->abort();
}
QUrl url(m_baseUrl + "/elements");
QUrlQuery query;
query.addQueryItem("type", type);
query.addQueryItem("famille", QString::number(famille));
url.setQuery(query);
QNetworkRequest request(url);
request.setTransferTimeout(TIME_OUT_TRANSFER_DATA);
auto reply = m_manager.get(request);
m_replyElementsEnCours = reply;
connect(reply, &QNetworkReply::finished, this, [this, reply, type, famille]() {
reply->deleteLater();
if (m_replyElementsEnCours == reply) m_replyElementsEnCours = nullptr;
if (reply->error() == QNetworkReply::OperationCanceledError) {
return;
}
if (reply->error() != QNetworkReply::NoError) {
signalerEchec();
emit erreur(reply->errorString());
return;
}
const auto doc = QJsonDocument::fromJson(reply->readAll());
const auto obj = doc.object();
if (obj["status"].toString() != "ok") {
signalerEchec();
emit erreur(obj["message"].toString());
return;
}
signalerSucces();
emit elementsRecus(type, famille, obj["elements"].toArray());
});
}
void DataProvider::set_circuit(int id, int consigne)
{
QUrl url(m_baseUrl + "/elements/circuit/" + QString::number(id));
QNetworkRequest request(url);
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
request.setTransferTimeout(TIME_OUT_TRANSFER_DATA);
QJsonObject body;
body["consigne"] = consigne;
const QByteArray data = QJsonDocument(body).toJson();
auto reply = m_manager.sendCustomRequest(request, "PATCH", data);
connect(reply, &QNetworkReply::finished, this, [this, reply, id]() {
reply->deleteLater();
const bool succes = (reply->error() == QNetworkReply::NoError);
if (succes) signalerSucces();
else {
signalerEchec();
emit erreur(reply->errorString());
}
emit circuitModifie(id, succes);
});
}
+79
View File
@@ -0,0 +1,79 @@
#pragma once
#include <QObject>
#include <QNetworkAccessManager>
#include <QJsonArray>
#include <QDateTime>
class QNetworkReply;
// ============================================================================
// DataProvider - couche d'accès aux données du client WASM (cas 2/3).
// ----------------------------------------------------------------------------
// Remplace, pour les domaines déjà portés, les appels bdd.* directs du cas 1
// (qui reste inchangé, cf décision §21.1 de la synthèse). Toute la logique
// HTTP/JSON est encapsulée ici - le QML ne voit que des signaux avec des
// tableaux déjà prêts à l'emploi.
//
// Portée actuelle : les 4 domaines (circuit, batterie, capteur, reservoir)
// en lecture, écriture (consigne/mode auto) sur circuit uniquement.
//
// Suit également l'état de connexion (succès/échec de chaque requête) pour
// permettre à l'UI d'afficher un état "hors ligne" explicite plutôt que de
// laisser les listes silencieusement vides ou figées (cf synthèse, gestion
// du hors-ligne).
// ============================================================================
#define TIME_OUT_TRANSFER_DATA 5000 // En ms
class DataProvider : public QObject
{
Q_OBJECT
Q_PROPERTY(bool connecte READ connecte NOTIFY etatConnexionChange)
Q_PROPERTY(bool aDejaEteConnecte READ aDejaEteConnecte NOTIFY etatConnexionChange)
Q_PROPERTY(QDateTime derniereConnexionReussie READ derniereConnexionReussie NOTIFY etatConnexionChange)
public:
explicit DataProvider(QObject *parent = nullptr);
// TODO : rendre l'adresse de base configurable (IP locale du CM5 en cas 2,
// domaine VPS en cas 3 - cf QR code d'accès, §"Architecture cible"/Cas 2-3
// de la synthèse) - en dur sur le relais VPS pour cette étape.
Q_INVOKABLE void get_familles(const QString &type);
Q_INVOKABLE void get_elements(const QString &type, int famille);
// Écriture rapide sur un circuit (bouton d'accueil) - PATCH /elements/circuit/<id>.
Q_INVOKABLE void set_circuit(int id, int consigne);
bool connecte() const { return m_connecte; }
bool aDejaEteConnecte() const { return m_derniereConnexionReussie.isValid(); }
QDateTime derniereConnexionReussie() const { return m_derniereConnexionReussie; }
signals:
// Le type (et, pour les éléments, la famille) sont désormais inclus dans
// chaque signal - indispensable avec plusieurs domaines actifs en
// parallèle, pour que le QML sache à quelle réponse il a affaire.
void famillesRecues(const QString &type, const QJsonArray &familles);
void elementsRecus(const QString &type, int famille, const QJsonArray &elements);
void circuitModifie(int id, bool succes);
void erreur(const QString &message);
void etatConnexionChange();
private:
void signalerSucces();
void signalerEchec();
QNetworkAccessManager m_manager;
QString m_baseUrl = QStringLiteral("https://api.ship2net.fr");
bool m_connecte = false;
QDateTime m_derniereConnexionReussie; // invalide (isValid()==false) tant qu'aucun succès n'a jamais eu lieu
// Requête en cours par type d'appel (familles/éléments) - permet d'annuler
// une requête encore en vol avant d'en émettre une nouvelle, pour éviter
// qu'une réponse "en retard" (envoyée pendant une coupure, résolue après
// qu'une requête plus récente ait déjà réussi) ne fasse clignoter l'état
// de connexion après une reconnexion.
QNetworkReply *m_replyFamillesEnCours = nullptr;
QNetworkReply *m_replyElementsEnCours = nullptr;
};
+3
View File
@@ -0,0 +1,3 @@
@echo off
powershell -ExecutionPolicy Bypass -File "%~dp0deploy_wasm.ps1"
+31 -7
View File
@@ -11,12 +11,10 @@
# ============================================================================
param(
[string]$BuildDir = "O:\Technique\Projets_Qt\koriolan\shipheart_wasm\build\WebAssembly_Qt_6_8_3_Release",
[string]$AssetsDir = "O:\Technique\Projets_Qt\koriolan\shipheart_wasm\deploy", # manifest.json, icônes, sw.js "modèle" (CACHE_NAME sans version)
[string]$CM5Host = "192.168.1.220",
[int]$CM5Port = 2022,
[string]$CM5User = "koriolan",
[string]$CM5Path = "/var/www/shipheart-poc-wasm/"
[string]$BuildDir = "C:\Users\pierr\KORIOLAN\Koriolan - Documents\Technique\Projets_Qt\koriolan\shipheart_wasm\build\WebAssembly_Qt_6_8_3_Release",
[string]$AssetsDir = "C:\Users\pierr\KORIOLAN\Koriolan - Documents\Technique\Projets_Qt\koriolan\shipheart_wasm\deploy",
[string]$CM5Alias = "cm5", # alias défini dans %USERPROFILE%\.ssh\config
[string]$CM5Path = "/var/www/shipheart-wasm/"
)
$ErrorActionPreference = "Stop"
@@ -44,6 +42,32 @@ if ('serviceWorker' in navigator) {
"@
Set-Content "$BuildDir\index.html" $html -NoNewline
# --- 2bis. Remplacer l'écran de chargement Qt par défaut (logo Qt + texte
# technique "Qt for WebAssembly: ...") par un écran plus sobre, réutilisant
# l'icône de l'app déjà déployée. Fait ici plutôt que via une configuration
# CMake dédiée : plusieurs retours d'expérience Qt confirment que Qt Creator
# régénère de toute façon le HTML par défaut au build, quelle que soit la
# tentative de template personnalisé côté CMake - rester sur ce mécanisme de
# post-traitement, déjà fiable pour le manifest/service-worker, est plus sûr.
$html = Get-Content "$BuildDir\index.html" -Raw
$ancienSpinner = '(?s)<figure[^>]*id="qtspinner">.*?</figure>'
$nouveauSpinner = @"
<figure style="overflow:visible;" id="qtspinner">
<center style="margin-top:1.5em; line-height:150%; font-family: sans-serif; color: rgb(0 118 154);">
<img src="icon-512.png" style="display:block; margin:0 auto; max-width:55vw; max-height:55vh; width:auto; height:auto;">
<p style="margin-bottom: 5%;">
<strong>ShipHeart&trade;</strong>
<br />
by Koriolan
</p>
<div id="qtstatus"></div>
<noscript>JavaScript is disabled. Please enable JavaScript to use this application.</noscript>
</center>
</figure>
"@
$html = $html -replace $ancienSpinner, $nouveauSpinner
Set-Content "$BuildDir\index.html" $html -NoNewline
# --- 3. Versionner sw.js (change le CACHE_NAME à chaque déploiement) ---
# Le fichier "modèle" (CACHE_NAME générique) vit dans $AssetsDir, sous
# contrôle de version - on ne le modifie jamais sur place, on écrit la
@@ -60,7 +84,7 @@ Copy-Item "$AssetsDir\icon-512.png" "$BuildDir\icon-512.png" -Force
$fichiers = "index.html","qtloader.js","qtlogo.svg","shipheart_wasm.js","shipheart_wasm.wasm","shipheart_wasm.worker.js","sw.js","manifest.json","icon-192.png","icon-512.png"
foreach ($f in $fichiers) {
scp -P $CM5Port "$BuildDir\$f" "${CM5User}@${CM5Host}:${CM5Path}"
scp "$BuildDir\$f" "${CM5Alias}:${CM5Path}"
}
Write-Host "Déploiement terminé - version $version"
Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

After

Width:  |  Height:  |  Size: 7.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.4 KiB

After

Width:  |  Height:  |  Size: 23 KiB

+3 -3
View File
@@ -1,7 +1,7 @@
{
"name": "ShipHeart (POC WASM)",
"short_name": "ShipHeart POC",
"description": "POC d'accès à ShipHeart via WebAssembly - jusqu'à home_accueil.qml",
"name": "ShipHeart",
"short_name": "ShipHeart",
"description": "Accès à distance à ShipHeart",
"start_url": "./index.html",
"display": "fullscreen",
"orientation": "landscape",
Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 8.3 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 8.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 418 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 596 B

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 165 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 100 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

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