feat: add images for NAT traversal and STUN concepts, and update bibliography with new references
All checks were successful
Build LaTeX Document / build_latex (push) Successful in 3m17s

This commit is contained in:
2025-03-25 21:56:42 +01:00
parent 0d4bf28092
commit 775d7ceb6f
8 changed files with 177 additions and 24 deletions

View File

@@ -293,6 +293,14 @@
note = {[Accessed 18-03-2025]} note = {[Accessed 18-03-2025]}
} }
@misc{opentelemetryWhatOpenTelemetry,
author = {},
title = {{W}hat is {O}pen{T}elemetry? --- opentelemetry.io},
howpublished = {\url{https://opentelemetry.io/docs/what-is-opentelemetry/}},
year = {},
note = {[Accessed 25-03-2025]}
}
@article{Parameswaran2001, @article{Parameswaran2001,
doi = {10.1109/2.933501}, doi = {10.1109/2.933501},
url = {https://doi.org/10.1109/2.933501}, url = {https://doi.org/10.1109/2.933501},
@@ -341,6 +349,21 @@
title = {Research Based Data Rights Management Using Blockchain Over Ethereum Network} title = {Research Based Data Rights Management Using Blockchain Over Ethereum Network}
} }
@misc{rfc2663,
series = {Request for Comments},
number = 2663,
howpublished = {RFC 2663},
publisher = {RFC Editor},
doi = {10.17487/RFC2663},
url = {https://www.rfc-editor.org/info/rfc2663},
author = {Matt Holdrege and Pyda Srisuresh},
title = {{IP Network Address Translator (NAT) Terminology and Considerations}},
pagetotal = 30,
year = 1999,
month = aug,
abstract = {This document attempts to describe the operation of NAT devices and the associated considerations in general, and to define the terminology used to identify various flavors of NAT. This memo provides information for the Internet community.}
}
@misc{rfc5128, @misc{rfc5128,
series = {Request for Comments}, series = {Request for Comments},
number = 5128, number = 5128,
@@ -356,6 +379,21 @@
abstract = {This memo documents the various methods known to be in use by applications to establish direct communication in the presence of Network Address Translators (NATs) at the current time. Although this memo is intended to be mainly descriptive, the Security Considerations section makes some purely advisory recommendations about how to deal with security vulnerabilities the applications could inadvertently create when using the methods described. This memo covers NAT traversal approaches used by both TCP- and UDP-based applications. This memo is not an endorsement of the methods described, but merely an attempt to capture them in a document. This memo provides information for the Internet community.} abstract = {This memo documents the various methods known to be in use by applications to establish direct communication in the presence of Network Address Translators (NATs) at the current time. Although this memo is intended to be mainly descriptive, the Security Considerations section makes some purely advisory recommendations about how to deal with security vulnerabilities the applications could inadvertently create when using the methods described. This memo covers NAT traversal approaches used by both TCP- and UDP-based applications. This memo is not an endorsement of the methods described, but merely an attempt to capture them in a document. This memo provides information for the Internet community.}
} }
@misc{rfc5389,
series = {Request for Comments},
number = 5389,
howpublished = {RFC 5389},
publisher = {RFC Editor},
doi = {10.17487/RFC5389},
url = {https://www.rfc-editor.org/info/rfc5389},
author = {Philip Matthews and Jonathan Rosenberg and Dan Wing and Rohan Mahy},
title = {{Session Traversal Utilities for NAT (STUN)}},
pagetotal = 51,
year = 2008,
month = oct,
abstract = {Session Traversal Utilities for NAT (STUN) is a protocol that serves as a tool for other protocols in dealing with Network Address Translator (NAT) traversal. It can be used by an endpoint to determine the IP address and port allocated to it by a NAT. It can also be used to check connectivity between two endpoints, and as a keep-alive protocol to maintain NAT bindings. STUN works with many existing NATs, and does not require any special behavior from them. STUN is not a NAT traversal solution by itself. Rather, it is a tool to be used in the context of a NAT traversal solution. This is an important change from the previous version of this specification (RFC 3489), which presented STUN as a complete solution. This document obsoletes RFC 3489. {[}STANDARDS-TRACK{]}}
}
@misc{rfc8216, @misc{rfc8216,
series = {Request for Comments}, series = {Request for Comments},
number = 8216, number = 8216,
@@ -495,7 +533,7 @@
note = {[Online; accessed 05-April-2023]} note = {[Online; accessed 05-April-2023]}
} }
@misc{wiki:PeerTube, @misc{wiki:PeerTube,
author = {Wikipedia}, author = {Wikipedia},
title = {{PeerTube} --- {W}ikipedia{,} The Free Encyclopedia}, title = {{PeerTube} --- {W}ikipedia{,} The Free Encyclopedia},
year = {2025}, year = {2025},
@@ -519,7 +557,7 @@
note = {[Accessed 08-Mar-2023]} note = {[Accessed 08-Mar-2023]}
} }
@misc{wikipediaTwitchservice, @misc{wikipediaTwitchservice,
author = {}, author = {},
title = {{T}witch (service) - {W}ikipedia --- en.wikipedia.org}, title = {{T}witch (service) - {W}ikipedia --- en.wikipedia.org},
howpublished = {\url{https://en.wikipedia.org/wiki/Twitch_(service)}}, howpublished = {\url{https://en.wikipedia.org/wiki/Twitch_(service)}},

159
Tesi.tex
View File

@@ -516,18 +516,56 @@ diretta o on-demand su Internet. Il protocollo HLS funziona dividendo il flusso
\item È compatibile con la maggior parte dei browser e dispositivi moderni \item È compatibile con la maggior parte dei browser e dispositivi moderni
\end{itemize} \cite{rfc8216} \end{itemize} \cite{rfc8216}
Per eseguire streaming video P2P, PeerTube utilizza un loader personalizzato che integra il P2P Media Loader di Novage. Questo loader consente di scaricare i segmenti video sia dal server web sia da altri spettatori tramite WebRTC, riducendo così il carico sui server e distribuendo la banda attraverso il P2P. Per eseguire streaming video P2P, PeerTube utilizza un loader/player personalizzato. Questo loader consente di scaricare i segmenti video sia dal server web sia da altri spettatori tramite WebRTC, riducendo così il carico sui server e distribuendo la banda attraverso il P2P.
\subsection{P2P Media Loader e WebRTC} \subsection{P2P Media Loader e WebRTC}
Il cuore del sistema P2P di PeerTube è costituito da: Il cuore del sistema P2P di PeerTube è costituito da:
\begin{itemize} \begin{itemize}
\item \textbf{P2P Media Loader}: Una libreria JavaScript che integra il P2P nel player video
\item \textbf{WebRTC}: Una tecnologia web standard per la comunicazione peer-to-peer diretta tra browser \item \textbf{WebRTC}: Una tecnologia web standard per la comunicazione peer-to-peer diretta tra browser
\item \textbf{WebTorrent Tracker}: Utilizzato come sistema di signaling per connettere i peer \item \textbf{P2P Media Loader}: Una libreria JavaScript che integra il P2P nel player video
\item \textbf{WebTorrent Tracker}: Un tracker\footnote{Un server che aiuta a trovare altri peer nella rete BitTorrent mantenendo un elenco dei peer che stanno scaricando un determinato file.} BitTorrent per la scoperta dei peer, utilizzato come sistema di signaling
\end{itemize} \end{itemize}
\subsubsection{WebRTC}
WebRTC \footnote{Web Real-Time Communication} è un progetto gratuito e open-source che fornisce ai browser web e alle applicazioni mobile la possibilità di instaurare comunicazioni in tempo reale tramite API standard, tipicamente in JavaScript.
Consente la comunicazione e lo streaming audio-video direttamente all'interno delle pagine web, permettendo la connessione peer-to-peer senza la necessità di installare plugin o scaricare applicazioni native.
I maggiori componenti che costituiscono WebRTC sono:
\begin{itemize}
\item \textbf{getUserMedia}: API che consente l'accesso alla fotocamera e al microfono del dispositivo.
\item \textbf{RTCPeerConnection}: API che consente la comunicazione peer-to-peer per lo scambio di audio, video e dati. Gestisce l'elaborazione del segnale, la gestione dei codec, la comunicazione peer-to-peer, la sicurezza e l'ottimizzazione della larghezza di banda.
\item \textbf{RTCDataChannel}: API che consente comunicazione bidirezionale di dati arbitrari tra peer. Utilizza le stesse API di WebSocket e offre una latenza molto bassa.
\end{itemize}
Affinché un'app WebRTC possa avviare una sessione, i suoi client devono scambiarsi le seguenti informazioni:
\begin{itemize}
\item Messaggi di controllo della sessione, utilizzati per aprire o chiudere la comunicazione.
\item Messaggi di errore.
\item Metadati dei media, come codec, impostazioni dei codec, larghezza di banda e tipi di media.
\item Chiavi di sicurezza necessarie per stabilire connessioni sicure.
\item Dati di rete, come l'indirizzo IP e la porta dell'host visibili dall'esterno.
\end{itemize}
Questo processo di signaling, ovvero la scoperta dei peer con cui connettersi e la determinazione delle modalità di stabilimento delle connessioni, richiede un meccanismo che permetta ai client di scambiarsi messaggi avanti e indietro.
L' WebRTC non include meccanismo. Questo compito è lasciato all'applicazione, che può utilizzare qualsiasi mezzo di comunicazione per lo scambio di informazioni di segnalazione.
I metodi e i protocolli di signaling da implementare sono invece definiti dal JavaScript Session Establishment Protocol (JSEP), per evitare ridondanze e massimizzare la compatibilità con le tecnologie esistenti.
\begin{figure}[H]
\centering
\includegraphics[width=300pt]{images/jsep-architecture-diagram_856.png}
\caption{Architettura JSEP.}
\end{figure}
JSEP richiede lo scambio tra peer di offerte e risposte, includendo i metadati dei media da voler condividere.
\subsubsection{P2P Media Loader}
P2P Media Loader è una libreria JavaScript open-source che sfrutta le funzionalità dei browser moderni (HTML5 video e WebRTC) per distribuire contenuti multimediali tramite P2P e riprodurli attraverso l'integrazione con molti lettori video HTML5 popolari. Non richiede plugin o estensioni del browser per funzionare. P2P Media Loader è una libreria JavaScript open-source che sfrutta le funzionalità dei browser moderni (HTML5 video e WebRTC) per distribuire contenuti multimediali tramite P2P e riprodurli attraverso l'integrazione con molti lettori video HTML5 popolari. Non richiede plugin o estensioni del browser per funzionare.
Requisiti del browser per P2P Media Loader: Requisiti del browser per P2P Media Loader:
@@ -557,38 +595,111 @@ Di tanto in tanto, peer casuali della rete scaricano nuovi segmenti tramite HTTP
\section{Signaling e NAT Traversal} \section{Signaling e NAT Traversal}
Un aspetto critico del sistema P2P è il processo di signaling, che permette ai peer di scoprirsi e connettersi tra loro. PeerTube utilizza: Come menzionato prima, un aspetto critico del sistema P2P è il processo di signaling e di NAT traversal che permette ai peer di scoprirsi e connettersi tra loro.
\textbf{NAT} è un metodo per mappare uno spazio di indirizzi IP in un altro, modificando le informazioni sugli indirizzi di rete nell'header IP dei pacchetti mentre sono in transito attraverso un dispositivo di routing del traffico.
Questa tecnica è stata inizialmente utilizzata per evitare la necessità di assegnare un nuovo indirizzo a ogni host quando una rete veniva spostata o quando il provider di servizi Internet a monte veniva sostituito ma non poteva instradare lo spazio di indirizzi della rete. Con il tempo, è diventata uno strumento essenziale per la conservazione dello spazio globale degli indirizzi a causa dell'esaurimento degli indirizzi IPv4. Un singolo indirizzo IP instradabile su Internet di un gateway NAT può essere utilizzato per un'intera rete privata.
Poiché la traduzione degli indirizzi di rete modifica le informazioni sugli indirizzi IP nei pacchetti, le implementazioni NAT possono variare nel loro comportamento specifico in diversi casi di indirizzamento e nel loro impatto sul traffico di rete. I produttori di dispositivi che implementano NAT non documentano comunemente i dettagli specifici del comportamento NAT. \cite{rfc2663}
\begin{figure}[H]
\centering
\includegraphics[width=300pt]{images/NAT_Concept-en.png}
\caption{Schema NAT.}
\end{figure}
I problemi di attraversamento del NAT (NAT traversal) si verificano quando peer situati dietro NAT diversi tentano di comunicare tra loro direttamente.
Un modo per risolvere questo problema è utilizzare il port forwarding. Un'altra soluzione consiste nell'usare diverse tecniche di attraversamento del NAT.
\textbf{NAT Traversal} è il processo di superamento delle limitazioni imposte dai router NAT (Network Address Translation) che possono impedire la comunicazione diretta tra peer.
\begin{figure}[H]
\centering
\includegraphics[width=300pt]{images/nat-traversal.png}
\caption{Schema NAT Traversal.}
\end{figure}
Esistono diverse tecniche di attraversamento del NAT, tra cui:
\begin{itemize}
\item \textbf{UPnP} (Universal Plug and Play): Un protocollo di rete di vecchia data, ampiamente implementato che consente ai dispositivi di comunicare tra loro senza la necessità di configurazioni manuali.
\item \textbf{NAT-PMP} (NAT Port Mapping Protocol): Un protocollo simile ad UPnP che consente ai dispositivi di comunicare tra loro attraverso un router NAT creato da Apple.
\item \textbf{PCP} (Port Control Protocol): Il protocollo successore di NAT-PMP.
\end{itemize}
Un port mapping riuscito può bypassare efficacemente il NAT per la porta specificata, facilitando le connessioni dirette.
I dispositivi NAT non si comportano tutti in modo uniforme, il che porta a diversi livelli di difficoltà nell'attraversamento:
\begin{itemize} \begin{itemize}
\item \textbf{WebTorrent Tracker}: Per la scoperta dei peer che stanno guardando lo stesso contenuto \item \textbf{Endpoint-Independent Mapping} (EIM): NAT `facili' che utilizzano lo stesso IP e porta pubblici per tutte le connessioni in uscita da un determinato IP e porta interni, indipendentemente dalla destinazione.
\item \textbf{Server STUN}: Per facilitare il NAT traversal, permettendo ai peer di stabilire connessioni anche quando si trovano dietro router NAT \item \textbf{Endpoint-Dependent Mapping} (EDM): NAT `difficili' o `simmetrici' che creano mapping diversi di IP e porta pubblici in base all'indirizzo IP di destinazione e, a volte, anche alla porta di destinazione. Questo rende molto più difficile per i peer prevedere il corretto endpoint pubblico. Alcuni dispositivi NAT sono ancora più complessi e generano un mapping NAT completamente diverso per ogni destinazione contattata.
\item \textbf{Server TURN} (opzionale): Come fallback quando la connessione diretta non è possibile
\end{itemize} \end{itemize}
\textbf{STUN}\footnote{Session Traversal Utilities for NAT; originariamente Simple Traversal of User Datagram Protocol (UDP) through Network Address Translators} è un insieme standardizzato di metodi, incluso un protocollo di rete, per l'attraversamento dei gateway NAT nelle applicazioni di comunicazione interattiva in tempo reale, come voce, video e messaggistica.
STUN è uno strumento utilizzato da altri protocolli, come Interactive Connectivity Establishment (ICE), Session Initiation Protocol (SIP) e WebRTC. Consente ai dispositivi di rilevare la presenza di un traduttore di indirizzi di rete e di scoprire l'indirizzo IP pubblico mappato e il numero di porta assegnati dal NAT per i flussi UDP dell'applicazione verso host remoti.
Il protocollo richiede l'assistenza di un server di rete di terze parti (un server STUN) situato sul lato opposto (pubblico) del NAT, solitamente su Internet.
STUN quindi, è fondamentale per i client dietro un NAT, dato che li consente di scoprire il proprio indirizzo IP e le porte visibili esternamente, così come vengono viste da un server su Internet.
\begin{figure}[H]
\centering
\includegraphics[width=300pt]{images/stun-server.png}
\caption{Schema STUN.}
\end{figure}
Quando le connessioni peer-to-peer dirette non possono essere stabilite, dei server di inoltro (relay) fungono da intermediari:
\begin{itemize}
\item \textbf{TURN} (Traversal Using Relays around NAT): un protocollo standard in cui i client si autenticano con un server TURN, che assegna loro un indirizzo IP pubblico e una porta, inoltrando il traffico tra i peer.
\end{itemize}
WebRTC utilizza il protocollo ICE (Interactive Connectivity Establishment) menzionato prima, per negoziare la connessione tra i peer, utilizzando server STUN e TURN per facilitare il processo.
\section{Algoritmo di selezione dei peer} \section{Algoritmo di selezione dei peer}
L'efficienza del sistema P2P dipende in modo cruciale dall'algoritmo utilizzato per selezionare i peer da cui scaricare i dati. PeerTube utilizza un algoritmo simile a quello di BitTorrent, che considera: L'efficienza del sistema P2P dipende in modo cruciale dall'algoritmo utilizzato per selezionare i peer da cui scaricare i dati. PeerTube, e di conseguenza Novage P2P Media loader utilizza come menzionato prima un WebTorrent Tracker some sistemma di signaling che utilizza un algoritmo del tutto simile a quello di BitTorrent dato che il protocollo funziona esattamente come il protocollo BitTorrent, ma utilizza WebRTC invece di TCP/uTP come protocollo di trasporto.
La specifica BitTorrent, versione 1.0, definisce vari algoritmi per la selezione dei peer; i peer vengono selezionati attraverso una combinazione di azioni da parte del tracker e dei singoli client.
Dalla parte del tracker:
\begin{itemize} \begin{itemize}
\item \textbf{Disponibilità dei segmenti}: Priorità ai peer che hanno i segmenti richiesti \item Quando un client invia una richiesta al tracker (announce), il tracker risponde con un elenco di peer che partecipano allo stesso torrent (o video su una pagina web nel nostro caso).
\item \textbf{Velocità di download}: Preferenza per i peer che offrono migliori prestazioni \item Di default a, il tracker fornisce un elenco fino a 50 peer. Se sono disponibili meno peer, l'elenco sarà più piccolo.
\item \textbf{Rarità dei segmenti}: Priorità allo scaricamento dei segmenti meno diffusi nella rete \item Il tracker generalmente seleziona i peer in modo casuale per la sua risposta. Tuttavia, può anche utilizzare un algoritmo di selezione dei peer personalizzato.
\item \textbf{Reciprocità}: Tendenza a favorire i peer che a loro volta condividono dati \end{itemize}
Una volta che un client riceve un elenco di peer dal tracker e stabilisce le connessioni, gestisce queste connessioni utilizzando un algoritmo di choking e optimistic unchoking.
Questo processo determina quali peer il client utilizzerà attivamente per scaricare e caricare i dati.
\begin{itemize}
\item \textbf{Choking}: Un peer può fare choking (rifiutarsi di caricare dati) verso altri peer per diversi motivi, tra cui: Controllo della congestione TCP, per evitare sovraccarichi di rete; Strategia tit-for-tat, per garantire un tasso di download costante, dando priorità ai peer che condividono attivamente. Quando un peer viene `strangolato', il client non deve inviare richieste per blocchi di dati a quel peer.
\item \textbf{Unchoking}: Per gestire i download e contraccambiare i peer utili, un client solitamente sblocca i quattro peer interessati che hanno il miglior tasso di upload. Questi vengono chiamati `downloaders'. Se un peer ha un tasso di upload migliore ma non è interessato, potrebbe comunque essere sbloccato, e se diventa interessato, il downloader con il tasso di upload peggiore viene bloccato. I client con un file completo utilizzano il loro tasso di upload per decidere quali peer sbloccare.
\item \textbf{Optimistic unchoking}: Per scoprire potenziali peer migliori, il client sblocca in modo ottimistico un peer per un intervallo di 30 secondi, indipendentemente dal suo tasso di upload. Il peer sbloccato ottimisticamente ruota, il che significa che i peer appena connessi hanno una maggiore probabilità di essere scelti inizialmente.
\item \textbf{Anti-snubbing}: Se un client smette di ricevere dati da un peer per più di un minuto, suppone di essere stato `snobbato' e potrebbe temporaneamente smettere di caricare dati verso quel peer. Questo può portare a più di un meccanismo di unchoking ottimistico concorrente per trovare dei peer migliori.
\end{itemize} \end{itemize}
\section{Sistema di monitoraggio integrato con OpenTelemetry} \section{Sistema di monitoraggio integrato con OpenTelemetry}
PeerTube integra OpenTelemetry per il monitoraggio delle prestazioni del sistema P2P, raccogliendo metriche come: OpenTelemetry è un framework e un toolkit open-source per l'osservabilità. Standardizza la generazione, l'esportazione e la raccolta di dati di telemetria, come tracce, metriche e log, ed è progettato per essere indipendente dai fornitori e dagli strumenti stessi.
Affronta la sfida delle pratiche di osservabilità frammentate tra diversi linguaggi, infrastrutture e fornitori, offrendo un unico set di API, specifiche e strumenti per l'instrumentazione. Questo elimina così il \textit{vendor lock-in} e la necessità di adattarsi a più sistemi proprietari.\cite{opentelemetryWhatOpenTelemetry}
PeerTube integra OpenTelemetry, per il monitoraggio delle prestazioni complessive del server, raccogliendo metriche come:
\begin{itemize} \begin{itemize}
\item \textbf{Percentuale di dati condivisi via P2P} \item \textbf{Percentuale di dati condivisi via P2P e HTTP}
\item \textbf{Numero di peer connessi} \item \textbf{Numero di utenti connessi}
\item \textbf{Latenza delle connessioni} \item \textbf{Utilizzo della CPU, della memoria etc.}
\item \textbf{Utilizzo della banda del server} \item \textbf{Utilizzo della banda del server}
\item \textbf{Errori e disconnessioni} \item \textbf{Errori e disconnessioni}
\end{itemize} \end{itemize}
Queste metriche possono essere visualizzate attraverso dashboard Grafana o altri sistemi di monitoraggio compatibili con OpenTelemetry. Queste metriche possono essere poi visualizzate attraverso dashboard Grafana o altri sistemi di monitoraggio compatibili con OpenTelemetry.
\chapter{Verifica empirica delle prestazioni P2P di PeerTube} \chapter{Verifica empirica delle prestazioni P2P di PeerTube}
@@ -1236,7 +1347,7 @@ Come descritto in precedenza, abbiamo riprodotto due scenari di test principali
\item Live streaming con impostazione \textit{High Latency}: La configurazione che privilegia il P2P a scapito della latenza \item Live streaming con impostazione \textit{High Latency}: La configurazione che privilegia il P2P a scapito della latenza
\end{itemize} \end{itemize}
Per ciascun scenario, abbiamo impostato il numero di spettatori/utenti a 5 (limite di Hetzner Cloud per account nuovi) e racolto le seguenti statistiche: Per ciascun scenario, abbiamo impostato il numero di client a 5 (limite di Hetzner Cloud), distribuiti per il globo, e raccolto le seguenti statistiche:
\begin{itemize} \begin{itemize}
\item Statistiche del player web (risoluzione, bitrate, buffering, latenza, ecc.) \item Statistiche del player web (risoluzione, bitrate, buffering, latenza, ecc.)
@@ -1245,13 +1356,17 @@ Per ciascun scenario, abbiamo impostato il numero di spettatori/utenti a 5 (limi
\item Timestamp di raccolta \item Timestamp di raccolta
\end{itemize} \end{itemize}
\chapter{Analisi dei dati e risultati} \begin{figure}[H]
\centering
[Questa sezione sarà completata la prossima settimana con i risultati dei test] \includegraphics[width=\textwidth]{images/hetzner-cloud-datacenters.png}
\caption{Distribuzione geografica delle macchine virtuali Hetzner Cloud.}
\end{figure}
\chapter{Conclusioni} \chapter{Conclusioni}
[Questa sezione sarà completata dopo l'analisi dei dati] [Questa sezione sarà completata la prossima settimana con i risultati dei test]
[Essenzialmente siamo riusciti a creare un sistema per riprodurre i test di PeerTube, e abbiamo raccolto i dati necessari, confermando quanto detto da PeerTube, e abbiamo anche raccolto dati aggiuntivi che potrebbero essere utili]
\nocite{*} \nocite{*}
\printbibliography \printbibliography

BIN
images/NAT_Concept-en.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 135 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 204 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

BIN
images/nat-traversal.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 131 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

BIN
images/stun-server.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 73 KiB