Added frontend description
@@ -22,7 +22,17 @@
 | 
				
			|||||||
    -->
 | 
					    -->
 | 
				
			||||||
    <title>Birdmap</title>
 | 
					    <title>Birdmap</title>
 | 
				
			||||||
  </head>
 | 
					  </head>
 | 
				
			||||||
  <body style="height: 100vh;">
 | 
					  <body>
 | 
				
			||||||
 | 
					      <style>
 | 
				
			||||||
 | 
					          body {
 | 
				
			||||||
 | 
					              height: 100vh;
 | 
				
			||||||
 | 
					              -ms-overflow-style: none;
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          body::-webkit-scrollbar {
 | 
				
			||||||
 | 
					              display:none;
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					      </style>
 | 
				
			||||||
    <noscript>
 | 
					    <noscript>
 | 
				
			||||||
      You need to enable JavaScript to run this app.
 | 
					      You need to enable JavaScript to run this app.
 | 
				
			||||||
    </noscript>
 | 
					    </noscript>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -60,7 +60,7 @@ namespace Birdmap.Controllers
 | 
				
			|||||||
            var token = tokenHandler.CreateToken(tokenDescriptor);
 | 
					            var token = tokenHandler.CreateToken(tokenDescriptor);
 | 
				
			||||||
            var tokenString = tokenHandler.WriteToken(token);
 | 
					            var tokenString = tokenHandler.WriteToken(token);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var response = _mapper.Map<AuthenticateResponse>(user);
 | 
					            AuthenticateResponse response = _mapper.Map<AuthenticateResponse>(user);
 | 
				
			||||||
            response.AccessToken = tokenString;
 | 
					            response.AccessToken = tokenString;
 | 
				
			||||||
            response.TokenType = "Bearer";
 | 
					            response.TokenType = "Bearer";
 | 
				
			||||||
            response.ExpiresIn = expiresInSeconds;
 | 
					            response.ExpiresIn = expiresInSeconds;
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										1
									
								
								docs/birdmap-frontend-routes.drawio
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					<mxfile host="app.diagrams.net" modified="2020-12-04T17:21:22.434Z" agent="5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36" etag="puyzN88MKD48mWwX1Ew6" version="13.10.9" type="device"><diagram id="C5RBs43oDa-KdzZeNtuy" name="Page-1">5Vxbd5s4EP41fjQHJG5+TOKm7W52T7ZNN7uPspENG4xckJ24v34FiIskfEkKmDo+PU0YhITmm/k0M1I8gjerl48xWvt/EA+HI6B7LyM4HQFgmACM0n+6t8sljmnlgmUceLxRJfga/MBcqHPpJvBwIjSkhIQ0WIvCOYkiPKeCDMUxeRabLUgojrpGS6wIvs5RqEofA4/6udQFTiX/hIOlX4xs2JP8zgoVjflMEh955Lkmgh9G8CYmhOa/rV5ucJgqr9DL4+fdY3j3ZH/87a/kO/p2/fvDn3+P885uX/NIOYUYR/TNXS+nK7i9T5bjHfCmD+G37+vZj7HJp0Z3hb6wx9THL0lMfbIkEQo/VNLrmGwiD6e96uyqanNHyJoJDSb8D1O647aANpQwkU9XIb+bj5kOJEF0ZH68XUI28RwfaAe5maF4iQ/2V6HIzB+TFabxjj0Y4xDRYCu+HeJ2uCzbVbpmv3B1vwJV/pZbFG74SPcx9oI5ovgL2VCsIFPpPVXisx9Q/HWNMk08M98VdbwgEeUAGGyO18sQJQmHLKExeSq9IW1dmrZewnMqGlscU/xSU5WqT34XQu5InEksmzPJc+WXRuFsfs0nTf3nIWi0fl3R8QVYf0G8x81/D1ytm3+j7sE5dM80HO/+4c9nF/+mF5pVXE5f6jenO8ElhoAZOCdlFa/ZxFkjeKsylk9Ws01ynK0E/kmp6xatgjDV/iccbjFlIzRwGgqDZcQu5gwEHDcTGxsyiJbsyq6uHjJrYWtfh1xniVxnWyrXuQ1U57ZAdQecXYDuC0MuTkOuNCIbpcRrh5SrOQvIQhJnLe3vmzTGYcqCi4Wr63pdVMO7EKYdjJMMqCvWwDDXL/Un7CX/WUpuQ7IMIqFNyO/kL1M8cmEromFLVuL0uCIe4BfBTKZ4gTYhvUM7FpVcHASWfkYIGhdG1VEXKEzUcJBNkIrqVfgwVQOjzvCK31gFnpcvpJi5J5plXaXaXZMgotlErOuRNU37YmtnwqEq1a+o9VRE9vPkCeo3G7QPutK+GpXTeHOhyjfNgSnfUsOLzSwM5kPIh9pXv+GK6i/hOBv12A3hXbAdSELaAfnAoQHgKABceasgukz1m4Oz/4mifkXpOPKu0qpkyvSpCoN5Z9n9IYo8mijCZtXXVGs1aLaQnZxO8hHu0yWs5lgSsnZRMy66yKfJn6rXLKWOTLlkNJE6yvWgdJShX077J2KxE8OBFO87NMNhdzFB3YHNQ17JC+m8s1G5WtdNcL/17/XWsa4B6LgCHKAVa7E0yxS6dTV3InZCFosEd4OwWtIYnM/bv4LPA3kxlV31VJ+HUlRqOaY2qX96ZQBHTYg/J1cb6jNos7qXd5lksG9vpGIDSy92yjhQ43boAAidGowM7N7IQM29B0cGzi9BBparwdrHaokaHEOzax9HXDfOyxSGeZwpmjeceiaLMB3uGs2fllkGcVPWeeEi+3TDJ4dzAcYnhltEWxxO2IopQm3i1G3CETnLsDXX0WsfyTS7IxtHjS1HwEarNHHL/1cuz287vRsGizotx+rALhjwhmwLluYYvcHfSBdptv9OcYamK8YTLYUTbMkw+wIVNGUTwq7aq3fLTt2Ha29XrWZiskXNCKVklZWMUEyLOIiw6Ray2yCsNtvLSGkWkvlT0YTbmfvzwVI9CGrOnI5EsYZEAGoBym4nIDJ0kcOUGtbJFRGxH0fqZk+Mw3BAu1ozTgCHBjL0Zt304ERqynVGJ/LwNpjjJJvlVfret+/bo8BAPApO2vIo2dKhe4E+1RhsnsunfIzoCq3ftyPtSdCbHak7P7Kg3Y4fWZJ1F0dJ2nejsVR36tGN1KD9vPFd8r59yBzIYmQ7LTmRI52Hkc8DXsJaZLpDcqL37UBHqnKyA4GuHAhI52WBKa0epzpQmRGV0Vx3HgSatdO9B1nqOZEvzJpwzGQ3ZLUmEY7OfVSz/fMitgTt+Y9qWk1MJmm9x/2igyd6j3JBblSD3THS6kV6qfvW9o/6PV1ScGf9uNeG+pfrwdLOPgRqQNbzgUd1w3eKEn9GUOxdLgzywdNGHGCvOAAVh7zudrkoyKdPB+ANapHoU16puVwUTGdwKKg1hjuW6F8uBLYxOAjUP0RQtH7uc0BF8HA8rmtWfl9hnaOBhuMVZVz3xjoJdIAmHOsQ++09klMTsuEZzMlFgXMajAFNzdgfokN5w/PkuoCha24tvwBiwc60pH67NphhZY4Hg7JhGwxwoZA4SsC+2WCgYx/KFXs3mF/gb1Pshi9eGZ7BmHo3DGPqg2KYYhqDNhjzRIM5a2nKAiKw0inVN9sLOGiHvdvL686+ZzsWD34QMTPxUOKX+UfNfFL5PaIUx1EmATpUsgyQb4TUtkVaNLpXfe1NX+wjoGy9daNwIvaj5EKv3ubYs7pKJXceZ++NsprfqjLVfPwTDZddVt+uljevvqMOfvgf</diagram></mxfile>
 | 
				
			||||||
@@ -3,7 +3,7 @@
 | 
				
			|||||||
  url         = {https://kubernetes.io},
 | 
					  url         = {https://kubernetes.io},
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@dashboard{kubernetes-dashboard,
 | 
					@misc{kubernetes-dashboard,
 | 
				
			||||||
  title       = {A Kubernetes Dashboard hivatalos oldala},
 | 
					  title       = {A Kubernetes Dashboard hivatalos oldala},
 | 
				
			||||||
  url         = {https://kubernetes.io/docs/tasks/access-application-cluster/web-ui-dashboard/},
 | 
					  url         = {https://kubernetes.io/docs/tasks/access-application-cluster/web-ui-dashboard/},
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -53,11 +53,21 @@
 | 
				
			|||||||
  url         = {https://jwt.io/introduction/},
 | 
					  url         = {https://jwt.io/introduction/},
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@misc{automapper,
 | 
				
			||||||
 | 
					  title       = {Az AutoMapper hivatalos oldala},
 | 
				
			||||||
 | 
					  url         = {https://automapper.org/},
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@misc{react,
 | 
					@misc{react,
 | 
				
			||||||
  title       = {A React.js hivatalos oldala},
 | 
					  title       = {A React.js hivatalos oldala},
 | 
				
			||||||
  url         = {https://reactjs.org/},
 | 
					  url         = {https://reactjs.org/},
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@misc{react-context,
 | 
				
			||||||
 | 
					  title       = {A React Context dokumentációja},
 | 
				
			||||||
 | 
					  url         = {https://reactjs.org/docs/context.html},
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@misc{material,
 | 
					@misc{material,
 | 
				
			||||||
  title       = {A Material hivatalos oldala},
 | 
					  title       = {A Material hivatalos oldala},
 | 
				
			||||||
  url         = {https://material.io/},
 | 
					  url         = {https://material.io/},
 | 
				
			||||||
@@ -83,6 +93,11 @@
 | 
				
			|||||||
  url         = {https://github.com/RicoSuter/NSwag},
 | 
					  url         = {https://github.com/RicoSuter/NSwag},
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@misc{nswag-studio,
 | 
				
			||||||
 | 
					  title       = {Az NSwag Studio github oldala},
 | 
				
			||||||
 | 
					  url         = {https://github.com/RicoSuter/NSwag/wiki/NSwagStudio},
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@misc{swagger-ui,
 | 
					@misc{swagger-ui,
 | 
				
			||||||
  title       = {A Swagger UI hivatalos oldala},
 | 
					  title       = {A Swagger UI hivatalos oldala},
 | 
				
			||||||
  url         = {https://swagger.io/tools/swagger-ui/},
 | 
					  url         = {https://swagger.io/tools/swagger-ui/},
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -33,8 +33,7 @@ Az egyik a \verb+User+, mely az alkalmazás felhasználóinak adatait tárolja.
 | 
				
			|||||||
A másik a \verb+Service+, mely a külső szolgáltatások adatainak tárolását szolgálja, amelyeket azért tárolok az adatbázisban és nem mondjuk a konfigurációs fájlban,
 | 
					A másik a \verb+Service+, mely a külső szolgáltatások adatainak tárolását szolgálja, amelyeket azért tárolok az adatbázisban és nem mondjuk a konfigurációs fájlban,
 | 
				
			||||||
mert szerettem volna, hogyha a kezelőfelületen lehetne őket szerkeszteni, törölni.
 | 
					mert szerettem volna, hogyha a kezelőfelületen lehetne őket szerkeszteni, törölni.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
\lstset{style=sharpc, morekeywords={record, get, set}}
 | 
					\begin{lstlisting}[style=csharp, caption=A User és a Service modell]
 | 
				
			||||||
\begin{lstlisting}[caption=A User és a Service modell]
 | 
					 | 
				
			||||||
    public record User
 | 
					    public record User
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        public int Id { get; set; }
 | 
					        public int Id { get; set; }
 | 
				
			||||||
@@ -51,7 +50,7 @@ mert szerettem volna, hogyha a kezelőfelületen lehetne őket szerkeszteni, tö
 | 
				
			|||||||
    {
 | 
					    {
 | 
				
			||||||
        public int Id { get; set; }
 | 
					        public int Id { get; set; }
 | 
				
			||||||
        public string Name { get; set; }
 | 
					        public string Name { get; set; }
 | 
				
			||||||
        public Uri Uri { get; set; }
 | 
					        public Uri Url { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public bool IsFromConfig { get; set; }
 | 
					        public bool IsFromConfig { get; set; }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -74,7 +73,7 @@ Majd hozzáadja az újonnan beolvasott értékeket.
 | 
				
			|||||||
\section{Üzleti logikai réteg}
 | 
					\section{Üzleti logikai réteg}
 | 
				
			||||||
%----------------------------------------------------------------------------
 | 
					%----------------------------------------------------------------------------
 | 
				
			||||||
Ebben a rétegben található meg a szerver legtöbb szolgáltatása. It vannak implementálva a Birdnetes Command and Control és Input komponensekkel kommunikáló szolgáltatások is, 
 | 
					Ebben a rétegben található meg a szerver legtöbb szolgáltatása. It vannak implementálva a Birdnetes Command and Control és Input komponensekkel kommunikáló szolgáltatások is, 
 | 
				
			||||||
melyeket azok OpenAPI leírói alapján az NSwag\cite{nswag} alkalmazással generáltam. Az OpenAPI a klienseken kívül definiálja még az azok által használt modelleket is.
 | 
					melyeket azok OpenAPI leírói alapján az NSwag Studio\cite{nswag-studio} alkalmazással generáltam. Az OpenAPI a klienseken kívül definiálja még az azok által használt modelleket is.
 | 
				
			||||||
A Command and Control által használt \verb+Device+ modell tartalmazza annak egyedi azonosítóját, státuszát, koordinátáit és a használt szenzorok listáját, 
 | 
					A Command and Control által használt \verb+Device+ modell tartalmazza annak egyedi azonosítóját, státuszát, koordinátáit és a használt szenzorok listáját, 
 | 
				
			||||||
melyeknek szintén van egy modellje \verb+Sensor+ néven. Ennek szintén van azonosítója és státusza. Az Input szolgáltatásnak is van saját modellje, 
 | 
					melyeknek szintén van egy modellje \verb+Sensor+ néven. Ennek szintén van azonosítója és státusza. Az Input szolgáltatásnak is van saját modellje, 
 | 
				
			||||||
amely a hangüzenetek metaadatait reprezentálja. Többek között tartalmazza a kihelyezett eszköz egyedi azonosítóját és a hangüzenet keltének dátumát. 
 | 
					amely a hangüzenetek metaadatait reprezentálja. Többek között tartalmazza a kihelyezett eszköz egyedi azonosítóját és a hangüzenet keltének dátumát. 
 | 
				
			||||||
@@ -87,6 +86,10 @@ Minden jelszóhoz generálok egy egyedi kulcsot és azzal egy hash-t, majd ezeke
 | 
				
			|||||||
Amikor egy felhasználó be akar jelentkezni először megvizsgálom, hogy egyáltalán létezik-e az adatbázisban az adott nevű felhasználó, 
 | 
					Amikor egy felhasználó be akar jelentkezni először megvizsgálom, hogy egyáltalán létezik-e az adatbázisban az adott nevű felhasználó, 
 | 
				
			||||||
ha igen, akkor a megadott jelszóból az imént említett folyamattal generált kulcsot és hash-t összehasonlítom az adatbázisban tárolttal.
 | 
					ha igen, akkor a megadott jelszóból az imént említett folyamattal generált kulcsot és hash-t összehasonlítom az adatbázisban tárolttal.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Azért hasznos íly módon, és nem mondjuk egyszerű szöveges formában tárolni a felhasználók jelszavát, mert így a felhasználón kívül senki sem tudja, hogy mi volt az eredeti jelszava,
 | 
				
			||||||
 | 
					az algorithmus egyirányú volta miatt\footnotemark. Ha véletlenül rossz kezekbe kerülne az adatbázis tartalma, akkor sem fognak tudni bejeletkezni a felhasználók adataival.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					\footnotetext{Generálni egyszerű és gyors. Visszafejteni közel lehetetlen.}
 | 
				
			||||||
%----------------------------------------------------------------------------
 | 
					%----------------------------------------------------------------------------
 | 
				
			||||||
\subsection{Kommunikációs Szolgáltatások}
 | 
					\subsection{Kommunikációs Szolgáltatások}
 | 
				
			||||||
%----------------------------------------------------------------------------
 | 
					%----------------------------------------------------------------------------
 | 
				
			||||||
@@ -125,18 +128,17 @@ Meg lehet adni különböző szűrőket és kimeneteket, amellyel szelektálni l
 | 
				
			|||||||
Például az MQTT szolgáltalás napló bejegyzéseit a \ref{lst:nlog-config} lista alapján szűrtem.
 | 
					Például az MQTT szolgáltalás napló bejegyzéseit a \ref{lst:nlog-config} lista alapján szűrtem.
 | 
				
			||||||
Minden \verb+Debug+ szintől nagyobb és \verb+Error+ szinttől kisebb bejegyzés, mely tartalmazza az \verb+Mqtt+ kulcsszót az \verb+mqttFile+ azonosítójú fájlba kerül.
 | 
					Minden \verb+Debug+ szintől nagyobb és \verb+Error+ szinttől kisebb bejegyzés, mely tartalmazza az \verb+Mqtt+ kulcsszót az \verb+mqttFile+ azonosítójú fájlba kerül.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
\lstset{style=xml, morekeywords={targets, target, xsi:type, name, fileName, layout, rules, logger, name, minlevel, maxlevel, writeTo, final}}
 | 
					\begin{lstlisting}[style=xml, caption=Az NLog.config fájl egy részlete, label=lst:nlog-config]
 | 
				
			||||||
\begin{lstlisting}[caption=Az NLog.config fájl egy részlete, label=lst:nlog-config]
 | 
					 | 
				
			||||||
<targets>
 | 
					<targets>
 | 
				
			||||||
    ...
 | 
					    ...
 | 
				
			||||||
    <target xsi:type="File" name="mqttFile" fileName="${basedir}Logs/birdmap-mqtt-${shortdate}.log"
 | 
					    <target xsi:type="File" name="mqttFile" fileName="..." layout="..." />
 | 
				
			||||||
        layout="..." />
 | 
					 | 
				
			||||||
    ...
 | 
					    ...
 | 
				
			||||||
</targets>
 | 
					</targets>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<rules>
 | 
					<rules>
 | 
				
			||||||
    ...
 | 
					    ...
 | 
				
			||||||
    <logger name="*.*Mqtt*.*" minlevel="Trace" maxlevel="Warning" writeTo="mqttFile" final="true"/>
 | 
					    <logger name="*.*Mqtt*.*" minlevel="Trace" maxlevel="Warning" writeTo="mqttFile" 
 | 
				
			||||||
 | 
					        final="true"/>
 | 
				
			||||||
    ...
 | 
					    ...
 | 
				
			||||||
</rules>
 | 
					</rules>
 | 
				
			||||||
\end{lstlisting}
 | 
					\end{lstlisting}
 | 
				
			||||||
@@ -146,7 +148,11 @@ Azaz, hogy egy kérés-t milyen sorrendben dolgozzák fel a regisztrált szolgá
 | 
				
			|||||||
A szerveroldali kivételkezelésre szánt szolgáltatás, az \verb+ExceptionHandlerMiddleware+ is itt van használva, 
 | 
					A szerveroldali kivételkezelésre szánt szolgáltatás, az \verb+ExceptionHandlerMiddleware+ is itt van használva, 
 | 
				
			||||||
amely elkap minden kivételt, amit a csővezeték további részei dobtak és JSON formátumban visszaadja azokat a kliensnek.
 | 
					amely elkap minden kivételt, amit a csővezeték további részei dobtak és JSON formátumban visszaadja azokat a kliensnek.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Továbbá az NSwag\cite{nswag} szoftvercsomag segítségével regisztrálok egy szolgáltatást, 
 | 
					%----------------------------------------------------------------------------
 | 
				
			||||||
 | 
					\subsection{Swagger}
 | 
				
			||||||
 | 
					\label{subsect:backend-swagger}
 | 
				
			||||||
 | 
					%----------------------------------------------------------------------------
 | 
				
			||||||
 | 
					Az NSwag\cite{nswag} szoftvercsomag segítségével regisztrálok egy szolgáltatást, 
 | 
				
			||||||
mely a szerveroldalon található kontrollereket felhasználva generál egy OpenAPI specifikációt és annak egy Swagger UI\cite{swagger-ui} felületet,
 | 
					mely a szerveroldalon található kontrollereket felhasználva generál egy OpenAPI specifikációt és annak egy Swagger UI\cite{swagger-ui} felületet,
 | 
				
			||||||
ahol a végpontok kipróbálhatóak, tesztelhetőek kliensoldal nélkül is.
 | 
					ahol a végpontok kipróbálhatóak, tesztelhetőek kliensoldal nélkül is.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -161,14 +167,8 @@ ahol a végpontok kipróbálhatóak, tesztelhetőek kliensoldal nélkül is.
 | 
				
			|||||||
\subsection{Kontrollerek}
 | 
					\subsection{Kontrollerek}
 | 
				
			||||||
%----------------------------------------------------------------------------
 | 
					%----------------------------------------------------------------------------
 | 
				
			||||||
A kontrollerek határozzák meg, hogy a szerveroldalon milyen végpontokat, milyen paraméterekkel lehet meghívni, ahhoz milyen jogosultságok kellenek.
 | 
					A kontrollerek határozzák meg, hogy a szerveroldalon milyen végpontokat, milyen paraméterekkel lehet meghívni, ahhoz milyen jogosultságok kellenek.
 | 
				
			||||||
A jogosultságok kezelését a JSON Web Token-ekkel oldottam meg. A fejlasználó bejelentkezéskor kap egy ilyen token-t, 
 | 
					 | 
				
			||||||
amelyben tárolom a hozzá tartozó szerepet. A \ref{lst:devices-controller}-as listában látszik, hogy hogyan használom ezeket a szerepeket.
 | 
					 | 
				
			||||||
A \verb+DevicesController+ végpontjait alapértelmezetten \verb+User+ és \verb+Admin+ jogosultságú felhasználó hívhatja, az "api/devices/online" végpontot azonban csak \verb+Admin+ jogosultságú.
 | 
					 | 
				
			||||||
Hasonló képpen oldottam meg ezt a többi kontrollernél is. A \verb+User+ felhasználók csak olyan végpontokat hívhat, mely kizárolag az állapotok olvasásával jár.
 | 
					 | 
				
			||||||
Az \verb+Admin+ felhasználók hívhatnak bármilyen végpontot.
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
\lstset{style=sharpc, morekeywords={record, async}}
 | 
					\begin{lstlisting}[style=csharp, caption=Az eszköz kontroller és annak "online" végpontja, label=lst:devices-controller]
 | 
				
			||||||
\begin{lstlisting}[caption=Az eszköz kontroller és annak "online" végpontja, label=lst:devices-controller]
 | 
					 | 
				
			||||||
    [Authorize(Roles = "User, Admin")]
 | 
					    [Authorize(Roles = "User, Admin")]
 | 
				
			||||||
    [ApiController]
 | 
					    [ApiController]
 | 
				
			||||||
    [Route("api/[controller]")]
 | 
					    [Route("api/[controller]")]
 | 
				
			||||||
@@ -184,6 +184,42 @@ Az \verb+Admin+ felhasználók hívhatnak bármilyen végpontot.
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
\end{lstlisting}
 | 
					\end{lstlisting}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Controllersw
 | 
					A jogosultságok kezelését a JSON Web Token-ekkel oldottam meg. A fejlasználó bejelentkezéskor kap egy ilyen token-t, 
 | 
				
			||||||
Dtos
 | 
					amelyben tárolom a hozzá tartozó szerepet. A \ref{lst:devices-controller}-as listában látszik, hogy hogyan használom ezeket a szerepeket.
 | 
				
			||||||
mapper
 | 
					A \verb+DevicesController+ végpontjait alapértelmezetten \verb+User+ és \verb+Admin+ jogosultságú felhasználó hívhatja, az "api/devices/online" végpontot azonban csak \verb+Admin+ jogosultságú.
 | 
				
			||||||
 | 
					Hasonló képpen oldottam meg ezt a többi kontrollernél is. A \verb+User+ felhasználók csak olyan végpontokat hívhat, mely kizárolag az állapotok olvasásával jár.
 | 
				
			||||||
 | 
					Az \verb+Admin+ felhasználók hívhatnak bármilyen végpontot.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					A szerveroldalon négy különböző kontroller található, melyek mindegyikének alapvető feladata az üzleti logikát megvalósító szolgáltatások használata, a működés naplózás,
 | 
				
			||||||
 | 
					illetve az imént említett végpontok authorizálása és kiszolgálása. Ezeken kívül a kontrollerek speciális feladata a következő:
 | 
				
			||||||
 | 
					\begin{itemize}
 | 
				
			||||||
 | 
					    \item Az \textbf{AuthController} felel a felhasználók bejelentkezésének lebonyolításáért, a JSON Web Token elkészítéséért. Az \verb+[Authorize]+ helyett itt az \verb+[AllowAnonymous]+ attribútum van használva, mellyel azt lehet jelezni, hogy a végpont bejelentkezés nélkül is hívható.
 | 
				
			||||||
 | 
					    \item A \textbf{ServiceController} felel az alkalmazás által használt külső szolgáltatások állapotának lekérdezhetőségéért. Ilyenek például a Birdnetes rendszer vagy az MQTT szolgáltatás állapota.
 | 
				
			||||||
 | 
					    \item A \textbf{DevicesController} felel a Command and Control mikroszolgáltatással való kommunikáció megvalósításáért, illetve a SignalR használatáért. Ha egy felhasználó valamelyik végpontot használva változtat valamelyik eszköz állapotán, akkor a kontroller jelez erről a klienseknek.
 | 
				
			||||||
 | 
					    \item A \textbf{LogController} felel azért, hogy az \verb+Admin+ jogosultságú felhasználók letölthessék a szerveroldalon készült naplófájlokat.
 | 
				
			||||||
 | 
					\end{itemize}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Az adatbázisból érkező adatok gyakran túl sok vagy túl kevés információt tartalmaznak ahhoz, hogy kiolvasás után rögtön elküldjem a kliensoldalnak.
 | 
				
			||||||
 | 
					Például amikor a felhasználó bejelentkezik a kiolvasott \verb+User+ objektum tartalmazza annak jelszavát (hash-elt formában), viszont nem tartalmazza az authorizációhoz használt token adatait.
 | 
				
			||||||
 | 
					Ennek a megoldására adatátviteli objektumokat hoztam létre, melyek csak azokat a mezőket tartalmazzák amelyekre a felhasználónak szüksége van.
 | 
				
			||||||
 | 
					Az adatbázisból kiolvasott objektum hasznos részeit és egyéb használni kívánt információt átmásolom az átviteli objektumba. Majd ezt küldöm el a kliensoldal felé.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Hogy az adatok másolását ne kézzel kelljen csinálnom, az AutoMapper\cite{automapper} szoftvercsomagot alkalmaztam, melynek használata rendkívül egyszerű.
 | 
				
			||||||
 | 
					Meg lehet adni profilokat, ahol két objektum közötti leképzéseket lehet felvenni. A szoftvercsomag automatikusan átmásolja az azonos nevű mezőket az egyik objektumból a másikba,
 | 
				
			||||||
 | 
					de meg lehet adni egyedi leképzéseket is.
 | 
				
			||||||
 | 
					\pagebreak
 | 
				
			||||||
 | 
					\begin{lstlisting}[style=csharp, caption=Egy példa az AutoMapper használatára.]
 | 
				
			||||||
 | 
					    // Creating maps.
 | 
				
			||||||
 | 
					    CreateMap<User, AuthenticateResponse>()
 | 
				
			||||||
 | 
					        .ForMember(m => m.Username, opt => opt.MapFrom(m => m.Name))
 | 
				
			||||||
 | 
					        .ForMember(m => m.UserRole, opt => opt.MapFrom(m => m.Role))
 | 
				
			||||||
 | 
					        .ReverseMap();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    CreateMap<Service, ServiceRequest>()
 | 
				
			||||||
 | 
					        .ReverseMap();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Using maps.
 | 
				
			||||||
 | 
					    IMapper mapper = GetMapper();
 | 
				
			||||||
 | 
					    User user = GetUserFromDb();
 | 
				
			||||||
 | 
					    AuthenticateResponse response = mapper.Map<AuthenticateResponse>(user);
 | 
				
			||||||
 | 
					\end{lstlisting}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -0,0 +1,289 @@
 | 
				
			|||||||
 | 
					%----------------------------------------------------------------------------
 | 
				
			||||||
 | 
					\chapter{Kliens oldal}
 | 
				
			||||||
 | 
					\label{chapt:birdmap-frontend}
 | 
				
			||||||
 | 
					%----------------------------------------------------------------------------
 | 
				
			||||||
 | 
					Ebben a fejezetben bemutatom a kliensoldal architektúráját. Ismertetem a különböző komponensek felépítését.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					%----------------------------------------------------------------------------
 | 
				
			||||||
 | 
					\section{Architektúra}
 | 
				
			||||||
 | 
					%----------------------------------------------------------------------------
 | 
				
			||||||
 | 
					Az alkalmazásnak minden oldala egy külön React komponens, mely mindegyikének saját mappája van a főkönyvtár alatt, 
 | 
				
			||||||
 | 
					ahol az egyes oldalak által használt szolgáltatások és egyéb komponensek találhatóak.
 | 
				
			||||||
 | 
					A közöses használt szolgáltatások és komponensek a common mappába kerültek.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					A kliensoldal belépési pontja az \verb+App.js+ fájlban található \verb+App+ komponens.
 | 
				
			||||||
 | 
					Itt egy React \verb+Switch+-ben fel van sorolva az összes oldal komponense azok elérési útvonalai szerint.
 | 
				
			||||||
 | 
					Ezt szemlélteti a \ref{lst:react-switch}-es lista.
 | 
				
			||||||
 | 
					Az a komponens jelenik meg a felületen, amelyiknek \verb+path+ mező értéke megegyezik az URL-ben találhatóval.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					\begin{lstlisting}[style=jsx, caption=Az App.js Switch tartalma., label=lst:react-switch]
 | 
				
			||||||
 | 
					<Switch>
 | 
				
			||||||
 | 
					    <PublicRoute exact path="/login" component={AuthComponent} />
 | 
				
			||||||
 | 
					    <AdminRoute exact path="/logs" component={LogsComponent} />
 | 
				
			||||||
 | 
					    <DevicesContextProvider>
 | 
				
			||||||
 | 
					        <PrivateRoute exact path="/" component={DashboardComponent} />
 | 
				
			||||||
 | 
					        <PrivateRoute exact path="/devices/:id?" component={DevicesComponent} />
 | 
				
			||||||
 | 
					        <PrivateRoute exact path="/heatmap" component={HeatmapComponent} />
 | 
				
			||||||
 | 
					    </DevicesContextProvider>
 | 
				
			||||||
 | 
					</Switch>
 | 
				
			||||||
 | 
					\end{lstlisting}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Hozzáférés szempontjából három fajta oldalt különböztetünk meg:
 | 
				
			||||||
 | 
					\begin{itemize}
 | 
				
			||||||
 | 
					    \item \textbf{Publikus oldal}. Az oldal bejelentkezés nélkül is látogatható.
 | 
				
			||||||
 | 
					    \item \textbf{Privát oldal}. Az oldal csak bejelentkezés után látogatható.
 | 
				
			||||||
 | 
					    \item \textbf{Admin oldal}. Az oldalt csak bejelentkezett admin felhasználók látogathatják.
 | 
				
			||||||
 | 
					\end{itemize}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Ezek alapján készítettem két generikus komponenst. Az egyik a \verb+DefaultLayout+ komponens, mely az oldal alapértelmezett elrendezéséért felel.
 | 
				
			||||||
 | 
					Paraméterében át lehet adni egy másik megjeleníteni kívánt komponenst, melyet a fejléc alatt jelenít meg.
 | 
				
			||||||
 | 
					Mivel minden komponens ebbe az bázis komponensbe van csomagolva, így akárhova navigálunk az oldalon a felület mindig egységes marad.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					A másik komponens a \verb+PredicateRoute+, melynek paraméterében meg lehet adni egy feltételt, illetve egy másik komponenst.
 | 
				
			||||||
 | 
					Ha a feltétel hamis akkor átírányítja a felhasználót a bejelentkező oldalra, ha igaz akkor megjeleníti a \verb+DefaultLayout+-ba csomagolt komponenst.
 | 
				
			||||||
 | 
					Publikus oldalnál a feltétel mindig igaz. 
 | 
				
			||||||
 | 
					Privátnál a feltétel a bejelentkezéshez van kötve. 
 | 
				
			||||||
 | 
					Az admin oldal feltétele egyrészt szintén a bejelentkezés, másrészt a felhasználó \verb+Admin+ jogolsultsága.
 | 
				
			||||||
 | 
					Ezt a folyamatot próbálja szemléltetni a \ref{fig:birdmap-frontend-architecture}-es ábra. 
 | 
				
			||||||
 | 
					Legfelül sárgával vannak feltüntetve a hívható végpontok, alattuk a hozzájuk kapcsolt megjelenítendő komponensek, azok alatt pedig a hozzáférést szabályozó komponensek.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					\begin{figure}[!ht]
 | 
				
			||||||
 | 
					    \centering
 | 
				
			||||||
 | 
					    \includegraphics[width=150mm, keepaspectratio]{figures/birdmap-frontend-routes.png}
 | 
				
			||||||
 | 
					    \caption{A Birdmap kliensoldalának architektúrája}
 | 
				
			||||||
 | 
					    \label{fig:birdmap-frontend-architecture}
 | 
				
			||||||
 | 
					\end{figure}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					%----------------------------------------------------------------------------
 | 
				
			||||||
 | 
					\section{Kommunikáció a szerveroldallal}
 | 
				
			||||||
 | 
					%----------------------------------------------------------------------------
 | 
				
			||||||
 | 
					A szerveroldallal való kommunikációt rendkívül egyszerűen tudtam implementálni köszönhetően a \ref{subsect:backend-swagger}-as fejezetben bemutatott Swagger oldalnak
 | 
				
			||||||
 | 
					és annak, hogy az NSwag Studio-val\cite{nswag-studio} a C\#-on kívül lehet TypeScript\footnotemark klienseket is generálni a leíró fájlból.
 | 
				
			||||||
 | 
					Így készültek el a kommponensek kommunikációért felelős szolgáltatásai.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					\footnotetext{JavaScript-re épített statikus típusdefiníciókat tartalmazó nyelv. JavaScript és TypeScript együtt is használható.}
 | 
				
			||||||
 | 
					%----------------------------------------------------------------------------
 | 
				
			||||||
 | 
					\section{Komponensek}
 | 
				
			||||||
 | 
					%----------------------------------------------------------------------------
 | 
				
			||||||
 | 
					Ebben a szakaszban ismertete az egyes oldalak komponenseit és azok alkomponenseit,
 | 
				
			||||||
 | 
					illetve a navigációért felelős fejlécet.
 | 
				
			||||||
 | 
					%----------------------------------------------------------------------------
 | 
				
			||||||
 | 
					\subsection{Navigáció}
 | 
				
			||||||
 | 
					%----------------------------------------------------------------------------
 | 
				
			||||||
 | 
					A fejléc két komponensből áll. Az egyik az oldal címe a másik az oldalak linkjeit tartalmazó komponens.
 | 
				
			||||||
 | 
					Utóbbit a React \verb+NavLink+ komponenseivel készítettem, melyeknek meg lehet adni, hogy kattintásra hova irányítsa a felhasználót.
 | 
				
			||||||
 | 
					Ha a jelenlegi webcím tartalmazza a linknek megadott címet, akkor az aktív státuszba kerül, melyre külön stílus osztályok vonatkoznak.
 | 
				
			||||||
 | 
					Ezt használva, az aktív linkeket egy aláhúzással jelölöm. 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					\begin{figure}[!ht]
 | 
				
			||||||
 | 
					    \centering
 | 
				
			||||||
 | 
					    \includegraphics[width=150mm, keepaspectratio]{figures/appbar-user-admin.png}
 | 
				
			||||||
 | 
					    \caption{A Birdmap fejléce. Felül a User, alul az Admin felhasználóké}
 | 
				
			||||||
 | 
					    \label{fig:birdmap-appbar}
 | 
				
			||||||
 | 
					\end{figure}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					A fejléc alapértelmezetten része a \verb+DefaultLayout+ komponensnek, így minden oldalon megjelenítésre kerül.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					%----------------------------------------------------------------------------
 | 
				
			||||||
 | 
					\subsection{Login}
 | 
				
			||||||
 | 
					%----------------------------------------------------------------------------
 | 
				
			||||||
 | 
					A bejelentkező oldal viszonylag egyszerű. Két szövegdobozt és egy bejelentkező gombot tartalmaz, ahogy az a \ref{fig:birdmap-login}-as ábrán is látszik.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					\begin{figure}[!ht]
 | 
				
			||||||
 | 
					    \centering
 | 
				
			||||||
 | 
					    \includegraphics[width=60mm, keepaspectratio]{figures/birdmap-login.png}
 | 
				
			||||||
 | 
					    \caption{A Birdmap bejelentkező felülete}
 | 
				
			||||||
 | 
					    \label{fig:birdmap-login}
 | 
				
			||||||
 | 
					\end{figure}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					A generált szerverrel kommunikáló szolgáltatás be van csomagolva egy közösen használt másik szolgáltatásba.
 | 
				
			||||||
 | 
					Ennek célja, hogy a bejelentkezés eredményét több komponens is olvashassa, hiszen az alkalmazás felületét alapvetően megkülönbözteti,
 | 
				
			||||||
 | 
					egyrészt a bejelentkezés sikeressége, másrészt a bejelentkezett felhasználó jogosultsági köre.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Sikeres bejelentkezés után a szerver elküldi a felhasználó szerepét, illetve a hozzáférési token-t, amelyre a kliens többi szolgáltatásának is szüksége lesz a kommunkációhoz. 
 | 
				
			||||||
 | 
					Ezeket az oldal \verb+sessionStorage+-ában\footnotemark tárolom és a becsomagolt szolgáltatáson keresztül elérhetőek.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Kijelentkezni a navigációs fejlécben található profil ikonra való kattintással lehet.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					\footnotetext{Webtárhely objektum. Lehetővé teszi a kulcs-érték párok tárolását a böngészőben.}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					%----------------------------------------------------------------------------
 | 
				
			||||||
 | 
					\subsection{Logs}
 | 
				
			||||||
 | 
					%----------------------------------------------------------------------------
 | 
				
			||||||
 | 
					Ez az oldal az \verb+Admin+ felhasználó számára lehetővé teszi a szerveren található naplófájlok letöltését \verb+zip+ fájlformátumú archív fájlokban.
 | 
				
			||||||
 | 
					Komponense a \ref{fig:birdmap-logs}-es ábrán látható.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					\begin{figure}[!ht]
 | 
				
			||||||
 | 
					    \centering
 | 
				
			||||||
 | 
					    \includegraphics[width=75mm, keepaspectratio]{figures/birdmap-logs.png}
 | 
				
			||||||
 | 
					    \caption{A Birdmap naplófájlok letöltésének felülete}
 | 
				
			||||||
 | 
					    \label{fig:birdmap-logs}
 | 
				
			||||||
 | 
					\end{figure}
 | 
				
			||||||
 | 
					%----------------------------------------------------------------------------
 | 
				
			||||||
 | 
					\subsection{Eszköz állapot és hangüzenet kezelő szolgáltatás}
 | 
				
			||||||
 | 
					%----------------------------------------------------------------------------
 | 
				
			||||||
 | 
					A szakasz további komponenseinek van egy közös ismertetője. Mégpedig, hogy mindegyiknek szüksége van a kihelyezett eszközök adataira
 | 
				
			||||||
 | 
					és az azok által publikált hangüzenetekből képzett valószínüségre.
 | 
				
			||||||
 | 
					A Reactnek van egy beépített komponense \verb+Context+\cite{react-context} néven, mellyel különböző komponensek között lehet adatokat megosztani.
 | 
				
			||||||
 | 
					Ezt használva készítettem egy \verb+DevicesContextProvider+ osztályt, melynek feladata a szerver eszköz kontrollerével való kommunikáció a megfelelő szolgáltatáson keresztül,
 | 
				
			||||||
 | 
					illetve a SignalR csatornákra való feliratkozás. Ezekből az adatokból egy \verb+DevicesContext+ készül, mely a \verb+Provider+ által átadásra kerül annak minden gyerekének.
 | 
				
			||||||
 | 
					A \ref{lst:react-switch}-es listában látható, hogy a \verb+DevicesContextProvider+ szülője a \verb+Dashboard+, \verb+Devices+ és \verb+Heatmap+ komponenseknek.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					%----------------------------------------------------------------------------
 | 
				
			||||||
 | 
					\subsection{Dashboard}
 | 
				
			||||||
 | 
					%----------------------------------------------------------------------------
 | 
				
			||||||
 | 
					A Dashboard az alkalmazás kezdő oldala. Itt található meg a külső szolgáltatások állapotát vizsgáló komponens,
 | 
				
			||||||
 | 
					illetve a kihelyezett eszközök működési folyamatában áttekintést nyújtó diagrammok mindegyike.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Az oldal megjelenítésekor elindul egy másodpercenként ismétlődő folyamat,
 | 
				
			||||||
 | 
					mely a \verb+DevicesContext+-ből kiolvasott értékekből legenerálja a diagrammokon megjelenítendő összes adatot.
 | 
				
			||||||
 | 
					Ez azonban az adat mennyiségétől függően akár egy-két másodpercig is eltarthat, ami rendkívül lassúvá és használhatatlanná tenné a felületet.
 | 
				
			||||||
 | 
					Ennek elkerülése érdekében az adatfeldolgozó folyamat egyszerre csak egy pár elemet dolgoz fel, mely alfolyamatok között 20 milliszekundum szüneteket iktattam be.
 | 
				
			||||||
 | 
					Továbbá hogy a különböző diagrammok animációi is zökkenőmentesek legyenek, azok adatai cserélése között is van 300 milliszekundum szünet.
 | 
				
			||||||
 | 
					Így valamivel lasabb az adatfeldolgozás, de a felület használható marad.
 | 
				
			||||||
 | 
					%----------------------------------------------------------------------------
 | 
				
			||||||
 | 
					\subsubsection{Külső szolgáltatások}
 | 
				
			||||||
 | 
					%----------------------------------------------------------------------------
 | 
				
			||||||
 | 
					Az alkalmazás használatának szempontjából van néhány olyan külső szolgáltatás, melyek elérhetősége hiányában a rendszer működésképtelen.
 | 
				
			||||||
 | 
					Ilyen például a Birdnetes klasztere vagy a szerver MQTT szolgáltatása. 
 | 
				
			||||||
 | 
					Ezért készítettem el az \ref{fig:dashboard-services-loaded}-ös ábrán látható információs panelt, ahol a szolgáltatások állapotát lehet látni, hogy a felhasználó tudja miért nem működik esetleg az alkalmazás.
 | 
				
			||||||
 | 
					A felület megvalósításhoz a Material UI \verb+Accordion+ elemét használtam, ami lényegében egy lenyíló lista. 
 | 
				
			||||||
 | 
					Ennek fejlécében a szolgáltatás neve, elérési útvonala és státusza látható. A lenyíló elemben a szolgáltatástól érkezett válasz van megjelenítve. 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					\begin{figure}[!ht]
 | 
				
			||||||
 | 
					    \centering
 | 
				
			||||||
 | 
					    \includegraphics[width=150mm, keepaspectratio]{figures/dashboard-services-loaded.png}
 | 
				
			||||||
 | 
					    \caption{Az alkalmazás által használt külső komponensek állapotának megjelenítéséért felelős komponens}
 | 
				
			||||||
 | 
					    \label{fig:dashboard-services-loaded}
 | 
				
			||||||
 | 
					\end{figure}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Az oldal betöltése vagy a frissítés gomb megnyomása esetén az adatok lekérésre kerülnek a szervertől.
 | 
				
			||||||
 | 
					Ez a folyamat akár öt-hat másodpercig is eltarthat, mely közben a felhasználó egy üres listát látna.
 | 
				
			||||||
 | 
					Ennek elkerülésére használom a Material UI \verb+Skeleton+ komponensét, 
 | 
				
			||||||
 | 
					mely egy megadható méretű töltő csíkkal helyettesíti az \verb+Accordion+-ban található elemeket a \ref{fig:dashboard-services-loading}-os ábrán látható módon.
 | 
				
			||||||
 | 
					Azért célszerű ennek a használata, mert így a felhasználónak több információja van arról, hogy a felületen milyen adatok és hol fognak megjelenni.
 | 
				
			||||||
 | 
					A felhasználói élmény maximalizálása érdekében a frissítés előtt lekérdezem a szervertől, hogy hány darab szolgáltatás található az adatbázisban 
 | 
				
			||||||
 | 
					és annyi darab töltőcsíkos \verb+Accordion+-t jelenítek meg. 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					\begin{figure}[!ht]
 | 
				
			||||||
 | 
					    \centering
 | 
				
			||||||
 | 
					    \includegraphics[width=150mm, keepaspectratio]{figures/dashboard-services-loading.png}
 | 
				
			||||||
 | 
					    \caption{A Skeletonok alkalmazása a külső szolgáltatások állapotának betöltése közben.}
 | 
				
			||||||
 | 
					    \label{fig:dashboard-services-loading}
 | 
				
			||||||
 | 
					\end{figure}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					%----------------------------------------------------------------------------
 | 
				
			||||||
 | 
					\subsubsection{Eszközök és szenzorok állapota}
 | 
				
			||||||
 | 
					%----------------------------------------------------------------------------
 | 
				
			||||||
 | 
					Ennek a komponensnek a szerepe, hogy áttekintést nyújtson az eszközök és szenzorok állapotáról.
 | 
				
			||||||
 | 
					Úgy gondoltam, hogy erre a legcélravezetőbb eszköz a \ref{fig:dashboard-donut}-es ábrán is látható Apexcharts fánk diagrammja.
 | 
				
			||||||
 | 
					Látható, hogy hány darab eszköz és szenzor van bekapcsolt, kikapcsolt, illetve hibás állapotban.
 | 
				
			||||||
 | 
					Az állapotok változása esetén a \verb+DevicesContextProvider+-nek köszönhetően az adatok automatikusan frissülnek.
 | 
				
			||||||
 | 
					\begin{figure}[!ht]
 | 
				
			||||||
 | 
					    \centering
 | 
				
			||||||
 | 
					    \includegraphics[width=150mm, keepaspectratio]{figures/dashboard-donut-devices.png}
 | 
				
			||||||
 | 
					    \caption{A Dashboard eszköz- és szenzor állapotok diagrammja}
 | 
				
			||||||
 | 
					    \label{fig:dashboard-donut}
 | 
				
			||||||
 | 
					\end{figure}
 | 
				
			||||||
 | 
					%----------------------------------------------------------------------------
 | 
				
			||||||
 | 
					\subsubsection{Hőtérkép diagrammok}
 | 
				
			||||||
 | 
					%----------------------------------------------------------------------------
 | 
				
			||||||
 | 
					Ezekkel a diagrammokkal az a célom, hogy az eszközök által küldött észleléseket időrendben vizualizáljam.
 | 
				
			||||||
 | 
					Megvalósításukhoz az Apexcharts Heatmap típusú diagrammját használtam.
 | 
				
			||||||
 | 
					A \ref{fig:dashboard-heatmap-second}-as ábrán látható diagram az elmúlt egy percben küldött, másodpercenként a legnagyobb, hangüzenetekből képzett valószínűségeket ábrozolja.
 | 
				
			||||||
 | 
					A \ref{fig:dashboard-heatmap-minute}-es ábrán látható diagram pedig az elmúlt egy órában percenként a legnagyobbakat.
 | 
				
			||||||
 | 
					\begin{figure}[!ht]
 | 
				
			||||||
 | 
					    \centering
 | 
				
			||||||
 | 
					    \includegraphics[width=150mm, keepaspectratio]{figures/second-heatmap.png}
 | 
				
			||||||
 | 
					    \caption{Másodperc alapú hőtérképes diagramm}
 | 
				
			||||||
 | 
					    \label{fig:dashboard-heatmap-second}
 | 
				
			||||||
 | 
					\end{figure}
 | 
				
			||||||
 | 
					\begin{figure}[!ht]
 | 
				
			||||||
 | 
					    \centering
 | 
				
			||||||
 | 
					    \includegraphics[width=150mm, keepaspectratio]{figures/minute-heatmap.png}
 | 
				
			||||||
 | 
					    \caption{Perc alapú hőtérképes diagramm}
 | 
				
			||||||
 | 
					    \label{fig:dashboard-heatmap-minute}
 | 
				
			||||||
 | 
					\end{figure}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					A függőleges tengelyen a rendszer eszközei vannak dinamikusan megjelenítve.
 | 
				
			||||||
 | 
					A vízszintes tengelyen pedig az említett időtartományok.
 | 
				
			||||||
 | 
					A diagrammokon látható négyzetek a valószínüség nagyságától függően sötétebbek vagy világosabbak.
 | 
				
			||||||
 | 
					\newpage
 | 
				
			||||||
 | 
					%----------------------------------------------------------------------------
 | 
				
			||||||
 | 
					\subsubsection{Riasztás számláló}
 | 
				
			||||||
 | 
					%----------------------------------------------------------------------------
 | 
				
			||||||
 | 
					Ez egy egyszerű oszlopdiagram, mely aggregálja az egyes eszközök által küldött hangüzeneteket 0.5 valószínűség felett a \ref{fig:dashboard-devices-column}-es ábrán látható módon.
 | 
				
			||||||
 | 
					Segítségével megvizsgálható, hogy mely eszközök riasztanak a legtöbbet a legnagyobb valószínűséggel.
 | 
				
			||||||
 | 
					\begin{figure}[!ht]
 | 
				
			||||||
 | 
					    \centering
 | 
				
			||||||
 | 
					    \includegraphics[width=150mm, keepaspectratio]{figures/dashboard-column-devices.png}
 | 
				
			||||||
 | 
					    \caption{Eszközönkénti riasztásokat számláló diagramm}
 | 
				
			||||||
 | 
					    \label{fig:dashboard-devices-column}
 | 
				
			||||||
 | 
					\end{figure}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Az egyes oszlopok három részre vannak bontva az üzenetek öt tized, hét tized és kilenc tized fölötti valószínűsége szerint. 
 | 
				
			||||||
 | 
					\newpage
 | 
				
			||||||
 | 
					%----------------------------------------------------------------------------
 | 
				
			||||||
 | 
					\subsubsection{Üzenetek gyakorisága}
 | 
				
			||||||
 | 
					%----------------------------------------------------------------------------
 | 
				
			||||||
 | 
					Az oldalon található utolsó diagramm egy vonal diagammn, melynek célja, hogy ábrázolja a rendszer által küldött üzenetek számát másodpercenként.
 | 
				
			||||||
 | 
					A \ref{fig:dashboard-messages-line}-es ábrán látható a komponens.
 | 
				
			||||||
 | 
					A vízszintes tengelyen a legelső érték az alkalmazás által először észlelt üzenet időpontja.
 | 
				
			||||||
 | 
					Az utolsó érték a legutoljára észlelt időpontja.
 | 
				
			||||||
 | 
					A függőleges tengelyen az adott másodpercben érkező üzenetek száma van ábrázolva.
 | 
				
			||||||
 | 
					Az előzőekkel ellentétben itt az adatok nincsennek szűrve a hangüzenet valószínűsége alapján,
 | 
				
			||||||
 | 
					tehát a rendszer által küldött összes üzenet látható.
 | 
				
			||||||
 | 
					\begin{figure}[!ht]
 | 
				
			||||||
 | 
					    \centering
 | 
				
			||||||
 | 
					    \includegraphics[width=150mm, keepaspectratio]{figures/dashboard-line-messages.png}
 | 
				
			||||||
 | 
					    \caption{A másodpercenként érkező üzenetek számát ábrázoló diagram.}
 | 
				
			||||||
 | 
					    \label{fig:dashboard-messages-line}
 | 
				
			||||||
 | 
					\end{figure}
 | 
				
			||||||
 | 
					\newpage
 | 
				
			||||||
 | 
					%----------------------------------------------------------------------------
 | 
				
			||||||
 | 
					\subsection{Devices}
 | 
				
			||||||
 | 
					%----------------------------------------------------------------------------
 | 
				
			||||||
 | 
					Ez az oldal lehetővé teszi a felhasználók számára az eszközök állapotának áttekintését, \verb+Admin+ felhasználók számára azok menedszelését is.
 | 
				
			||||||
 | 
					Az eszközök dinamikusan jelennek meg a \verb+DevicesContextProvider+ adatai alapján, melyek megjelenítésére a Material UI \verb+Accrordion+ komponensét használom.
 | 
				
			||||||
 | 
					Ennek fejlécében az eszköz neve, egyedi azonosítója és státusza található. A lenyíló részben pedig az eszköz által használt szenzorok neve, azonosítója és státusza.
 | 
				
			||||||
 | 
					\verb+Admin+ felhasználók számára a felület két fajta gombbal bővül, mellyekkel be és ki lehet kapcsolni az egyes eszközöket, szenzorokat.
 | 
				
			||||||
 | 
					Az \verb+Accordion+-ok felett található egy külön panel, mellyel egyszerre lehet kezelni az összes eszközt és azok szenzorait.
 | 
				
			||||||
 | 
					A Devices oldal felülete a \ref{fig:frontend-devices}-es ábrán,
 | 
				
			||||||
 | 
					az \verb+Admin+ felhasználók számára nyújtott plusz funkciók a \ref{fig:frontend-devices-admin}-as ábrán láthatók.
 | 
				
			||||||
 | 
					\begin{figure}[!ht]
 | 
				
			||||||
 | 
					    \centering
 | 
				
			||||||
 | 
					    \includegraphics[width=150mm, keepaspectratio]{figures/devices.png}
 | 
				
			||||||
 | 
					    \caption{A Devices oldal felülete.}
 | 
				
			||||||
 | 
					    \label{fig:frontend-devices}
 | 
				
			||||||
 | 
					\end{figure}
 | 
				
			||||||
 | 
					\begin{figure}[!ht]
 | 
				
			||||||
 | 
					    \centering
 | 
				
			||||||
 | 
					    \includegraphics[width=150mm, keepaspectratio]{figures/devices-admin.png}
 | 
				
			||||||
 | 
					    \caption{Az Admin felhasználók számára elérhető plusz funkciók.}
 | 
				
			||||||
 | 
					    \label{fig:frontend-devices-admin}
 | 
				
			||||||
 | 
					\end{figure}
 | 
				
			||||||
 | 
					%----------------------------------------------------------------------------
 | 
				
			||||||
 | 
					\subsection{Heatmap}
 | 
				
			||||||
 | 
					%----------------------------------------------------------------------------
 | 
				
			||||||
 | 
					\begin{figure}[!ht]
 | 
				
			||||||
 | 
					    \centering
 | 
				
			||||||
 | 
					    \includegraphics[width=150mm, keepaspectratio]{figures/heatmap.png}
 | 
				
			||||||
 | 
					    \caption{A Heatmap oldal felülete.}
 | 
				
			||||||
 | 
					    \label{fig:frontend-heatmap}
 | 
				
			||||||
 | 
					\end{figure}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- felépítés architektúra
 | 
				
			||||||
 | 
					- App and navigation
 | 
				
			||||||
 | 
					- Components and services
 | 
				
			||||||
 | 
					- kép minden felületről
 | 
				
			||||||
 | 
					    - kép user és admin felhasználók különbségéről
 | 
				
			||||||
 | 
					        - Device service
 | 
				
			||||||
 | 
					        - dashboard systeminfo service
 | 
				
			||||||
 | 
					    - kép a skeletonról -> igazi adat
 | 
				
			||||||
@@ -46,9 +46,7 @@ A \ref{fig:grafana}-es ábra egy jó példa arra, hogy hogyan néz ki egy által
 | 
				
			|||||||
\subsection{Kibana}
 | 
					\subsection{Kibana}
 | 
				
			||||||
%----------------------------------------------------------------------------
 | 
					%----------------------------------------------------------------------------
 | 
				
			||||||
A Kibana\cite{kibana} jelentősen hasonlít a Grafanához, azonban amíg a utóbbit inkább az időben változó metrikák vizualizálására használják például processzor leterheltség vagy memória használat,
 | 
					A Kibana\cite{kibana} jelentősen hasonlít a Grafanához, azonban amíg a utóbbit inkább az időben változó metrikák vizualizálására használják például processzor leterheltség vagy memória használat,
 | 
				
			||||||
addig az előbbit elsődlegesen az Elasticsearch\footenotemark adatok, főként napló bejegyzések, analizálására használják.
 | 
					addig az előbbit elsődlegesen az Elasticsearch\footnote{Ingyenes és nyílt forráskódú index alapú keresőmotor} adatok, főként napló bejegyzések, analizálására használják.
 | 
				
			||||||
 | 
					 | 
				
			||||||
\footnotetext{Ingyenes és nyílt forráskódú index alapú keresőmotor}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
\begin{figure}[!ht]
 | 
					\begin{figure}[!ht]
 | 
				
			||||||
    \centering
 | 
					    \centering
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										
											BIN
										
									
								
								docs/thesis/figures/appbar-admin.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 5.4 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								docs/thesis/figures/appbar-user-admin.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 11 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								docs/thesis/figures/appbar-user.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 5.1 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								docs/thesis/figures/birdmap-frontend-routes.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 76 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								docs/thesis/figures/birdmap-login.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 6.4 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								docs/thesis/figures/birdmap-logs.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 16 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								docs/thesis/figures/dashboard-column-devices.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 36 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								docs/thesis/figures/dashboard-donut-devices.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 49 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								docs/thesis/figures/dashboard-line-messages.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 34 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								docs/thesis/figures/dashboard-services-loaded.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 22 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								docs/thesis/figures/dashboard-services-loading-loaded.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 34 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								docs/thesis/figures/dashboard-services-loading.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 7.8 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								docs/thesis/figures/devices-admin.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 38 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								docs/thesis/figures/devices.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 113 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								docs/thesis/figures/heatmap-on.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 2.9 MiB  | 
							
								
								
									
										
											BIN
										
									
								
								docs/thesis/figures/heatmap.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 3.0 MiB  | 
							
								
								
									
										
											BIN
										
									
								
								docs/thesis/figures/minute-heatmap.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 66 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								docs/thesis/figures/second-heatmap.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 37 KiB  | 
@@ -32,7 +32,6 @@
 | 
				
			|||||||
\usepackage[unicode]{hyperref} % For hyperlinks in the generated document.
 | 
					\usepackage[unicode]{hyperref} % For hyperlinks in the generated document.
 | 
				
			||||||
\usepackage{xcolor}
 | 
					\usepackage{xcolor}
 | 
				
			||||||
\usepackage{listings} % For source code snippets.
 | 
					\usepackage{listings} % For source code snippets.
 | 
				
			||||||
\lstdefinestyle{sharpc}{language=[Sharp]C, frame=lr, rulecolor=\color{blue!80!black}}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
\usepackage[amsmath,thmmarks]{ntheorem} % Theorem-like environments.
 | 
					\usepackage[amsmath,thmmarks]{ntheorem} % Theorem-like environments.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -42,32 +42,127 @@
 | 
				
			|||||||
%--------------------------------------------------------------------------------------
 | 
					%--------------------------------------------------------------------------------------
 | 
				
			||||||
% Set up listings
 | 
					% Set up listings
 | 
				
			||||||
%--------------------------------------------------------------------------------------
 | 
					%--------------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					\definecolor{red}{rgb}{0.6,0,0} 
 | 
				
			||||||
 | 
					\definecolor{blue}{rgb}{0,0,0.6}
 | 
				
			||||||
 | 
					\definecolor{lightblue}{rgb}{0,0.5,0.7}
 | 
				
			||||||
 | 
					\definecolor{green}{rgb}{0,0.8,0}
 | 
				
			||||||
 | 
					\definecolor{cyan}{rgb}{0.0,0.6,0.6}
 | 
				
			||||||
 | 
					\definecolor{orange}{rgb}{0.8,0.6,0}
 | 
				
			||||||
 | 
					\definecolor{white}{rgb}{0.98, 0.98, 0.98}
 | 
				
			||||||
\definecolor{lightgray}{rgb}{0.95,0.95,0.95}
 | 
					\definecolor{lightgray}{rgb}{0.95,0.95,0.95}
 | 
				
			||||||
\lstset{
 | 
					\definecolor{darkviolet}{rgb}{0.58, 0.0, 0.83}
 | 
				
			||||||
 | 
					\definecolor{royalblue}{rgb}{0.25, 0.41, 0.88}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					\lstdefinestyle{csharp}{
 | 
				
			||||||
 | 
						language=csh,
 | 
				
			||||||
 | 
						basicstyle=\scriptsize\ttfamily,
 | 
				
			||||||
 | 
						numbers=left,
 | 
				
			||||||
 | 
						numberstyle=\tiny,
 | 
				
			||||||
 | 
						numbersep=5pt,
 | 
				
			||||||
 | 
						tabsize=2,
 | 
				
			||||||
 | 
						extendedchars=true,
 | 
				
			||||||
 | 
						breaklines=true,
 | 
				
			||||||
 | 
						frame=b,
 | 
				
			||||||
 | 
						stringstyle=\color{red}\ttfamily,
 | 
				
			||||||
 | 
						showspaces=false,
 | 
				
			||||||
 | 
						captionpos=b,
 | 
				
			||||||
 | 
						showtabs=false,
 | 
				
			||||||
 | 
						xleftmargin=17pt,
 | 
				
			||||||
 | 
						framexleftmargin=17pt,
 | 
				
			||||||
 | 
						framexrightmargin=5pt,
 | 
				
			||||||
 | 
						framexbottommargin=4pt,
 | 
				
			||||||
 | 
						commentstyle=\color{green},
 | 
				
			||||||
 | 
						morecomment=[l]{//}, %use comment-line-style!
 | 
				
			||||||
 | 
						morecomment=[s]{/*}{*/}, %for multiline comments
 | 
				
			||||||
 | 
						showstringspaces=false,
 | 
				
			||||||
 | 
						morekeywords={ abstract, event, new, struct,
 | 
				
			||||||
 | 
							as, explicit, null, switch,
 | 
				
			||||||
 | 
							base, extern, object, this,
 | 
				
			||||||
 | 
							get, set,
 | 
				
			||||||
 | 
							bool, false, operator, throw,
 | 
				
			||||||
 | 
							break, finally, out, true,
 | 
				
			||||||
 | 
							byte, fixed, override, try,
 | 
				
			||||||
 | 
							case, float, params, typeof,
 | 
				
			||||||
 | 
							catch, for, private, uint,
 | 
				
			||||||
 | 
							char, foreach, protected, ulong,
 | 
				
			||||||
 | 
							checked, goto, public, unchecked,
 | 
				
			||||||
 | 
							class, record, async, if, readonly, unsafe,
 | 
				
			||||||
 | 
							const, implicit, ref, ushort,
 | 
				
			||||||
 | 
							continue, in, return, using,
 | 
				
			||||||
 | 
							decimal, int, sbyte, virtual,
 | 
				
			||||||
 | 
							default, interface, sealed, volatile,
 | 
				
			||||||
 | 
							delegate, internal, short, void,
 | 
				
			||||||
 | 
							do, is, sizeof, while,
 | 
				
			||||||
 | 
							double, lock, stackalloc,
 | 
				
			||||||
 | 
							else, long, static,
 | 
				
			||||||
 | 
							enum, namespace, string},
 | 
				
			||||||
 | 
						morekeywords=[2]{CreateMap, ForMember, MapFrom, ReverseMap, Onlineall, GetMapper, GetUserFromDb, Map},
 | 
				
			||||||
 | 
						morekeywords=[3]{Id, Name, PasswordHash, PasswordSalt, Role, IsFromConfig, Url, Username, UserRole, mapper, user, response},
 | 
				
			||||||
 | 
						keywordstyle=\color{blue},
 | 
				
			||||||
 | 
						keywordstyle={[2]\color{orange}},
 | 
				
			||||||
 | 
						keywordstyle={[3]\color{lightblue}},
 | 
				
			||||||
 | 
						identifierstyle=\color{cyan},
 | 
				
			||||||
 | 
						backgroundcolor=\color{white}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					\lstdefinestyle{jsx}{
 | 
				
			||||||
 | 
						basicstyle=\scriptsize\ttfamily,
 | 
				
			||||||
 | 
						numbers=left,
 | 
				
			||||||
 | 
						numberstyle=\tiny,
 | 
				
			||||||
 | 
						numbersep=5pt,
 | 
				
			||||||
 | 
						tabsize=2,
 | 
				
			||||||
 | 
						extendedchars=true,
 | 
				
			||||||
 | 
						breaklines=true,
 | 
				
			||||||
 | 
						frame=b,
 | 
				
			||||||
 | 
						stringstyle=\color{red}\ttfamily,
 | 
				
			||||||
 | 
						showspaces=false,
 | 
				
			||||||
 | 
						captionpos=b,
 | 
				
			||||||
 | 
						showtabs=false,
 | 
				
			||||||
 | 
						xleftmargin=17pt,
 | 
				
			||||||
 | 
						framexleftmargin=17pt,
 | 
				
			||||||
 | 
						framexrightmargin=5pt,
 | 
				
			||||||
 | 
						framexbottommargin=4pt,
 | 
				
			||||||
 | 
						commentstyle=\color{green},
 | 
				
			||||||
 | 
						morestring=*[d]{"},
 | 
				
			||||||
 | 
						morecomment=[l]{//}, %use comment-line-style!
 | 
				
			||||||
 | 
						morecomment=[s]{/*}{*/}, %for multiline comments
 | 
				
			||||||
 | 
						showstringspaces=false,
 | 
				
			||||||
 | 
						morekeywords={ },
 | 
				
			||||||
 | 
						morekeywords=[2]{AuthComponent, LogsComponent, DashboardComponent, DevicesComponent, HeatmapComponent},
 | 
				
			||||||
 | 
						morekeywords=[3]{exact, path, component},
 | 
				
			||||||
 | 
						keywordstyle=\color{blue},
 | 
				
			||||||
 | 
						keywordstyle={[2]\color{orange}},
 | 
				
			||||||
 | 
						keywordstyle={[3]\color{lightblue}},
 | 
				
			||||||
 | 
						identifierstyle=\color{cyan},
 | 
				
			||||||
 | 
						backgroundcolor=\color{white}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					\lstdefinestyle{xml}{
 | 
				
			||||||
	basicstyle=\scriptsize\ttfamily, % print whole listing small
 | 
						basicstyle=\scriptsize\ttfamily, % print whole listing small
 | 
				
			||||||
	keywordstyle=\color{black}\bfseries, % bold black keywords
 | 
					 | 
				
			||||||
	identifierstyle=, % nothing happens
 | 
					 | 
				
			||||||
	% default behavior: comments in italic, to change use
 | 
						% default behavior: comments in italic, to change use
 | 
				
			||||||
	% commentstyle=\color{green}, % for e.g. green comments
 | 
						% commentstyle=\color{green}, % for e.g. green comments
 | 
				
			||||||
	stringstyle=\scriptsize,
 | 
					 | 
				
			||||||
	showstringspaces=false, % no special string spaces
 | 
						showstringspaces=false, % no special string spaces
 | 
				
			||||||
	aboveskip=3pt,
 | 
						aboveskip=3pt,
 | 
				
			||||||
	belowskip=3pt,
 | 
						belowskip=3pt,
 | 
				
			||||||
	backgroundcolor=\color{lightgray},
 | 
						stringstyle=\color{red}\ttfamily,
 | 
				
			||||||
 | 
						backgroundcolor=\color{white},
 | 
				
			||||||
 | 
						keywordstyle=\color{blue},
 | 
				
			||||||
 | 
						identifierstyle=\color{cyan},
 | 
				
			||||||
	columns=flexible,
 | 
						columns=flexible,
 | 
				
			||||||
	keepspaces=true,
 | 
						keepspaces=true,
 | 
				
			||||||
	escapeinside={(*@}{@*)},
 | 
						escapeinside={(*@}{@*)},
 | 
				
			||||||
	captionpos=b,
 | 
						captionpos=b,
 | 
				
			||||||
	breaklines=true,
 | 
						breaklines=true,
 | 
				
			||||||
	frame=single,
 | 
						frame=b,
 | 
				
			||||||
	float=!ht,
 | 
						float=!ht,
 | 
				
			||||||
	tabsize=2,
 | 
						tabsize=2,
 | 
				
			||||||
 | 
						morestring=*[d]{"},
 | 
				
			||||||
 | 
						morekeywords={targets, target, rules, logger},
 | 
				
			||||||
	literate=*
 | 
						literate=*
 | 
				
			||||||
		{á}{{\'a}}1	{é}{{\'e}}1	{í}{{\'i}}1	{ó}{{\'o}}1	{ö}{{\"o}}1	{ő}{{\H{o}}}1	{ú}{{\'u}}1	{ü}{{\"u}}1	{ű}{{\H{u}}}1
 | 
							{á}{{\'a}}1	{é}{{\'e}}1	{í}{{\'i}}1	{ó}{{\'o}}1	{ö}{{\"o}}1	{ő}{{\H{o}}}1	{ú}{{\'u}}1	{ü}{{\"u}}1	{ű}{{\H{u}}}1
 | 
				
			||||||
		{Á}{{\'A}}1	{É}{{\'E}}1	{Í}{{\'I}}1	{Ó}{{\'O}}1	{Ö}{{\"O}}1	{Ő}{{\H{O}}}1	{Ú}{{\'U}}1	{Ü}{{\"U}}1	{Ű}{{\H{U}}}1
 | 
							{Á}{{\'A}}1	{É}{{\'E}}1	{Í}{{\'I}}1	{Ó}{{\'O}}1	{Ö}{{\"O}}1	{Ő}{{\H{O}}}1	{Ú}{{\'U}}1	{Ü}{{\"U}}1	{Ű}{{\H{U}}}1
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
%--------------------------------------------------------------------------------------
 | 
					%--------------------------------------------------------------------------------------
 | 
				
			||||||
% Set up theorem-like environments
 | 
					% Set up theorem-like environments
 | 
				
			||||||
%--------------------------------------------------------------------------------------
 | 
					%--------------------------------------------------------------------------------------
 | 
				
			||||||
 
 | 
				
			|||||||