LittleFS mount OK, updated interface, upload to littlefs from browser

This commit is contained in:
Emanuele Trabattoni
2026-04-09 13:41:50 +02:00
parent de9ffe40e5
commit 1e068476af
12 changed files with 686 additions and 72 deletions

View File

@@ -1,16 +1,23 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<title>ESP32 Dashboard</title> <title>Astro Rotax Monitor</title>
<link rel="stylesheet" href="style.css"> <link rel="stylesheet" href="style.css">
</head> </head>
<body> <body>
<header class="page-header">
<div class="header-content">
<img src="logo_astro_dev.svg" alt="Astro Tecnologie" class="logo">
<h1>Ignition Box Monitor</h1>
</div>
</header>
<h2>RotaxMonitor realtime data</h2> <div id="loadingIndicator" class="loading-indicator">
<span class="spinner"></span> Waiting for data...
<button onclick="start()">Start</button> </div>
<button onclick="stop()">Stop</button>
<div style="max-width: 900px; margin: 0 auto; text-align: left;"> <div style="max-width: 900px; margin: 0 auto; text-align: left;">
<p><strong>Timestamp:</strong> <span id="timestamp">-</span></p> <p><strong>Timestamp:</strong> <span id="timestamp">-</span></p>
@@ -24,8 +31,8 @@
<thead> <thead>
<tr> <tr>
<th>Property</th> <th>Property</th>
<th>Coils 12</th> <th>Pickup 12</th>
<th>Coils 34</th> <th>Pickup 34</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
@@ -70,12 +77,12 @@
<td id="coils34_level_spark">-</td> <td id="coils34_level_spark">-</td>
</tr> </tr>
<tr> <tr>
<td>Events</td> <td>Spark Events</td>
<td id="coils12_n_events">-</td> <td id="coils12_n_events">-</td>
<td id="coils34_n_events">-</td> <td id="coils34_n_events">-</td>
</tr> </tr>
<tr> <tr>
<td>Missed firings</td> <td>Missed Events</td>
<td id="coils12_n_missed_firing">-</td> <td id="coils12_n_missed_firing">-</td>
<td id="coils34_n_missed_firing">-</td> <td id="coils34_n_missed_firing">-</td>
</tr> </tr>
@@ -83,6 +90,15 @@
</table> </table>
</div> </div>
<div class="upload-section">
<h3>Upload file to Flash</h3>
<p>Select a file and upload it to Flash.</p>
<input type="file" id="littlefsFile">
<button onclick="uploadLittleFS()">Upload</button>
<div id="uploadStatus" class="upload-status">No file uploaded yet.</div>
</div>
<script src="script.js"></script> <script src="script.js"></script>
</body> </body>
</html> </html>

View File

@@ -0,0 +1,306 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 26.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="e_astro_logo_negativo" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
x="0px" y="0px" viewBox="0 0 374 56" style="enable-background:new 0 0 374 56;" xml:space="preserve">
<style type="text/css">
.st0{fill:#FFFFFF;}
</style>
<g>
<polygon class="st0" points="53.9,46 59.2,46 59.2,44.8 55.3,44.8 55.3,42.4 59,42.4 59,41.2 55.3,41.2 55.3,38.8 59.2,38.8
59.2,37.6 53.9,37.6 "/>
<rect x="61.5" y="37.1" class="st0" width="1.4" height="8.9"/>
<path class="st0" d="M70.3,41.8c-0.1-0.4-0.2-0.8-0.4-1.2c-0.2-0.3-0.5-0.6-0.9-0.8c-0.4-0.2-0.8-0.3-1.3-0.3c-0.5,0-1,0.1-1.5,0.4
c-0.4,0.3-0.8,0.6-1.1,1.1c-0.3,0.5-0.4,1.1-0.4,1.8c0,0.7,0.1,1.2,0.4,1.7c0.3,0.5,0.6,0.9,1.1,1.2c0.4,0.3,0.9,0.4,1.5,0.4
c0.5,0,0.9-0.1,1.3-0.3c0.4-0.2,0.7-0.4,0.9-0.7c0.2-0.3,0.4-0.7,0.5-1.1h-1.4c-0.1,0.3-0.2,0.5-0.4,0.7c-0.2,0.2-0.5,0.2-0.8,0.2
c-0.3,0-0.6-0.1-0.9-0.3c-0.2-0.2-0.4-0.4-0.5-0.7c-0.1-0.3-0.2-0.6-0.2-1h4.2C70.4,42.6,70.4,42.2,70.3,41.8z M66.2,42.3
c0-0.3,0.1-0.5,0.2-0.8c0.1-0.3,0.3-0.5,0.5-0.7c0.2-0.2,0.5-0.3,0.9-0.3c0.3,0,0.5,0.1,0.7,0.2c0.2,0.1,0.3,0.3,0.4,0.4
c0.1,0.2,0.2,0.4,0.2,0.6c0,0.2,0,0.3,0,0.5H66.2z"/>
<path class="st0" d="M73.8,41c0.2-0.1,0.5-0.2,0.7-0.2c0.3,0,0.6,0.1,0.8,0.3c0.2,0.2,0.4,0.4,0.4,0.7l1.4-0.1
c0-0.3-0.1-0.5-0.3-0.8c-0.1-0.3-0.3-0.5-0.5-0.7c-0.2-0.2-0.5-0.4-0.8-0.5c-0.3-0.1-0.7-0.2-1.1-0.2c-0.5,0-1,0.1-1.5,0.4
c-0.4,0.3-0.8,0.6-1.1,1.1c-0.3,0.5-0.4,1.1-0.4,1.8c0,0.7,0.1,1.3,0.4,1.8c0.3,0.5,0.6,0.9,1.1,1.2c0.5,0.3,0.9,0.4,1.5,0.4
c0.6,0,1-0.1,1.4-0.3c0.4-0.2,0.7-0.5,0.9-0.9c0.2-0.4,0.3-0.8,0.3-1.2h-1.4c0,0.3-0.1,0.6-0.3,0.8c-0.2,0.2-0.5,0.3-0.9,0.3
c-0.3,0-0.5-0.1-0.8-0.2c-0.2-0.2-0.4-0.4-0.6-0.7c-0.1-0.3-0.2-0.7-0.2-1.1c0-0.5,0.1-0.9,0.2-1.2C73.4,41.4,73.6,41.1,73.8,41z"
/>
<path class="st0" d="M81.8,45c-0.2,0-0.3,0.1-0.5,0.1c-0.5,0-0.8-0.3-0.8-0.8v-3.6h1.8v-0.9h-1.8V38h-1.4v1.7h-0.9v0.9h0.9v3.7
c0,0.4,0.1,0.8,0.3,1.1c0.2,0.3,0.4,0.5,0.7,0.6c0.3,0.1,0.6,0.2,1,0.2c0.2,0,0.5,0,0.7-0.1c0.2-0.1,0.5-0.1,0.7-0.2l-0.2-1
C82.2,44.9,82,45,81.8,45z"/>
<path class="st0" d="M87.3,39.6c-0.4,0-0.7,0.1-1.1,0.4c-0.3,0.2-0.5,0.6-0.6,1v-1.3h-1.4V46h1.4v-2.8h0c0-0.5,0.1-0.9,0.2-1.2
c0.1-0.3,0.3-0.6,0.5-0.8c0.2-0.2,0.5-0.3,0.9-0.3c0.1,0,0.2,0,0.4,0c0.1,0,0.3,0,0.4,0.1l0-1.4c-0.1,0-0.2-0.1-0.3-0.1
C87.5,39.6,87.4,39.6,87.3,39.6z"/>
<path class="st0" d="M93.1,39.9c-0.5-0.2-1-0.4-1.5-0.4c-0.6,0-1.1,0.1-1.5,0.4c-0.5,0.2-0.8,0.6-1.1,1.1c-0.3,0.5-0.4,1.1-0.4,1.9
c0,0.7,0.1,1.3,0.4,1.8c0.3,0.5,0.6,0.9,1.1,1.1c0.5,0.2,1,0.4,1.5,0.4c0.6,0,1.1-0.1,1.5-0.4c0.5-0.2,0.8-0.6,1.1-1.1
c0.3-0.5,0.4-1.1,0.4-1.8c0-0.7-0.1-1.4-0.4-1.9C94,40.5,93.6,40.1,93.1,39.9z M93,44c-0.1,0.3-0.3,0.6-0.6,0.7
c-0.3,0.2-0.5,0.2-0.9,0.2c-0.5,0-0.9-0.2-1.2-0.5C90.1,44,90,43.5,90,42.9c0-0.5,0.1-0.9,0.2-1.2c0.1-0.3,0.3-0.6,0.6-0.7
c0.3-0.2,0.5-0.2,0.9-0.2c0.5,0,0.9,0.2,1.2,0.5c0.3,0.4,0.4,0.9,0.4,1.6C93.2,43.3,93.2,43.7,93,44z"/>
<path class="st0" d="M101.2,39.9c-0.4-0.2-0.8-0.3-1.3-0.3c-0.5,0-1,0.1-1.3,0.4c-0.3,0.2-0.5,0.5-0.7,0.9l-0.2-1.1h-1.2V46h1.4
v-2.9c0-0.5,0.1-0.9,0.2-1.3c0.1-0.4,0.3-0.6,0.6-0.8c0.2-0.2,0.5-0.3,0.9-0.3c0.4,0,0.7,0.1,1,0.4c0.2,0.3,0.4,0.6,0.4,1.2V46h1.4
v-3.7c0-0.6-0.1-1.1-0.3-1.5C101.8,40.4,101.5,40.1,101.2,39.9z"/>
<rect x="104.7" y="39.7" class="st0" width="1.4" height="6.3"/>
<path class="st0" d="M105.4,36.8c-0.3,0-0.5,0.1-0.6,0.2c-0.2,0.1-0.2,0.3-0.2,0.6c0,0.3,0.1,0.5,0.2,0.6c0.2,0.1,0.4,0.2,0.6,0.2
c0.3,0,0.5-0.1,0.6-0.2c0.2-0.1,0.2-0.4,0.2-0.6c0-0.2-0.1-0.4-0.2-0.6C105.9,36.9,105.6,36.8,105.4,36.8z"/>
<path class="st0" d="M110.3,41c0.2-0.1,0.5-0.2,0.7-0.2c0.3,0,0.6,0.1,0.8,0.3c0.2,0.2,0.4,0.4,0.4,0.7l1.4-0.1
c0-0.3-0.1-0.5-0.3-0.8c-0.1-0.3-0.3-0.5-0.5-0.7c-0.2-0.2-0.5-0.4-0.8-0.5c-0.3-0.1-0.7-0.2-1.1-0.2c-0.5,0-1,0.1-1.5,0.4
c-0.5,0.3-0.8,0.6-1.1,1.1c-0.3,0.5-0.4,1.1-0.4,1.8c0,0.7,0.1,1.3,0.4,1.8c0.3,0.5,0.6,0.9,1.1,1.2c0.4,0.3,0.9,0.4,1.5,0.4
c0.6,0,1-0.1,1.4-0.3c0.4-0.2,0.7-0.5,0.9-0.9c0.2-0.4,0.3-0.8,0.3-1.2h-1.4c0,0.3-0.1,0.6-0.3,0.8c-0.2,0.2-0.5,0.3-0.9,0.3
c-0.3,0-0.5-0.1-0.8-0.2c-0.2-0.2-0.4-0.4-0.6-0.7c-0.1-0.3-0.2-0.7-0.2-1.1c0-0.5,0.1-0.9,0.2-1.2C109.9,41.4,110.1,41.1,110.3,41
z"/>
<path class="st0" d="M123.7,38.1c-0.6-0.3-1.4-0.5-2.2-0.5h-2.6V46h2.6c0.9,0,1.6-0.2,2.2-0.5c0.6-0.3,1.1-0.8,1.5-1.5
c0.4-0.6,0.5-1.4,0.5-2.2c0-0.9-0.2-1.6-0.5-2.2C124.9,38.9,124.4,38.5,123.7,38.1z M123.9,43.3c-0.2,0.4-0.5,0.8-1,1.1
c-0.4,0.3-0.9,0.4-1.5,0.4h-1.3v-5.9h1.3c0.6,0,1.1,0.1,1.5,0.4c0.4,0.3,0.7,0.6,1,1c0.2,0.4,0.3,1,0.3,1.5
C124.2,42.4,124.1,42.9,123.9,43.3z"/>
<path class="st0" d="M132.6,41.8c-0.1-0.4-0.2-0.8-0.4-1.2c-0.2-0.3-0.5-0.6-0.9-0.8c-0.4-0.2-0.8-0.3-1.3-0.3
c-0.5,0-1,0.1-1.5,0.4c-0.4,0.3-0.8,0.6-1.1,1.1c-0.3,0.5-0.4,1.1-0.4,1.8c0,0.7,0.1,1.2,0.4,1.7c0.3,0.5,0.6,0.9,1.1,1.2
c0.4,0.3,0.9,0.4,1.5,0.4c0.5,0,0.9-0.1,1.3-0.3c0.4-0.2,0.7-0.4,0.9-0.7c0.2-0.3,0.4-0.7,0.5-1.1h-1.4c-0.1,0.3-0.2,0.5-0.4,0.7
c-0.2,0.2-0.5,0.2-0.8,0.2c-0.3,0-0.6-0.1-0.9-0.3c-0.2-0.2-0.4-0.4-0.5-0.7c-0.1-0.3-0.2-0.6-0.2-1h4.2
C132.7,42.6,132.7,42.2,132.6,41.8z M128.5,42.3c0-0.3,0.1-0.5,0.2-0.8c0.1-0.3,0.3-0.5,0.5-0.7c0.2-0.2,0.5-0.3,0.9-0.3
c0.3,0,0.5,0.1,0.7,0.2c0.2,0.1,0.3,0.3,0.4,0.4c0.1,0.2,0.2,0.4,0.2,0.6c0,0.2,0,0.3,0,0.5H128.5z"/>
<path class="st0" d="M137.9,42.6l-1.4-0.5c-0.6-0.2-0.9-0.4-0.9-0.8c0-0.2,0.1-0.4,0.3-0.5c0.2-0.1,0.5-0.2,0.8-0.2
c0.4,0,0.7,0.1,0.9,0.2c0.2,0.1,0.3,0.3,0.3,0.5h1.3c0-0.5-0.2-1-0.7-1.3c-0.4-0.3-1.1-0.5-1.9-0.5c-0.8,0-1.4,0.2-1.9,0.5
c-0.5,0.3-0.7,0.7-0.7,1.3c0,0.4,0.1,0.8,0.4,1c0.3,0.3,0.7,0.5,1.2,0.7l1.3,0.5c0.3,0.1,0.5,0.2,0.7,0.3c0.1,0.1,0.2,0.3,0.2,0.5
c0,0.2-0.1,0.3-0.2,0.4c-0.1,0.1-0.3,0.2-0.4,0.3c-0.2,0.1-0.4,0.1-0.6,0.1c-0.4,0-0.8-0.1-1-0.2c-0.3-0.2-0.4-0.4-0.4-0.7H134
c0,0.4,0.1,0.8,0.4,1.1c0.2,0.3,0.6,0.6,1,0.7c0.4,0.2,0.9,0.3,1.6,0.3c0.5,0,1-0.1,1.4-0.3c0.4-0.2,0.7-0.4,0.9-0.7
c0.2-0.3,0.3-0.6,0.3-0.9c0-0.4-0.1-0.7-0.4-1C138.8,43,138.4,42.8,137.9,42.6z"/>
<rect x="141.6" y="39.7" class="st0" width="1.4" height="6.3"/>
<path class="st0" d="M142.3,36.8c-0.3,0-0.5,0.1-0.6,0.2c-0.2,0.1-0.2,0.3-0.2,0.6c0,0.3,0.1,0.5,0.2,0.6c0.2,0.1,0.4,0.2,0.6,0.2
c0.3,0,0.5-0.1,0.6-0.2c0.2-0.1,0.2-0.4,0.2-0.6c0-0.2-0.1-0.4-0.2-0.6C142.7,36.9,142.5,36.8,142.3,36.8z"/>
<path class="st0" d="M151.1,45.5c-0.4-0.2-0.9-0.4-1.5-0.4h-2.2c-0.4,0-0.7-0.1-0.8-0.2c-0.2-0.1-0.2-0.3-0.2-0.4
c0-0.2,0-0.3,0.1-0.4c0.1-0.1,0.2-0.2,0.3-0.2c0.1,0,0.1,0,0.2,0c0.4,0.1,0.7,0.2,1.2,0.2c0.5,0,0.9-0.1,1.3-0.3
c0.4-0.2,0.7-0.5,1-0.8c0.2-0.3,0.4-0.7,0.4-1.2c0-0.5-0.1-0.9-0.4-1.2c0,0-0.1-0.1-0.1-0.1c0-0.3,0.1-0.5,0.3-0.6
c0.2-0.1,0.5-0.2,0.9-0.2l0.1-1.3c-0.4,0-0.7,0.1-1,0.2c-0.3,0.2-0.5,0.4-0.7,0.7c-0.1,0.2-0.2,0.5-0.2,0.8
c-0.1-0.1-0.2-0.1-0.2-0.2c-0.4-0.2-0.8-0.3-1.3-0.3c-0.5,0-0.9,0.1-1.4,0.3c-0.4,0.2-0.7,0.5-1,0.8c-0.2,0.3-0.4,0.7-0.4,1.2
c0,0.5,0.1,0.9,0.4,1.2c0.1,0.2,0.3,0.3,0.4,0.4c-0.1,0-0.2,0-0.2,0.1c-0.3,0.1-0.4,0.2-0.6,0.4c-0.1,0.2-0.2,0.4-0.2,0.7
c0,0.3,0.1,0.5,0.3,0.7c0.1,0.2,0.3,0.3,0.5,0.4c-0.3,0.1-0.6,0.1-0.8,0.3c-0.3,0.2-0.5,0.6-0.5,1.1c0,0.4,0.1,0.7,0.4,1
c0.3,0.3,0.7,0.6,1.2,0.8c0.5,0.2,1.1,0.3,1.8,0.3c0.8,0,1.4-0.1,2-0.4c0.5-0.3,1-0.6,1.3-1c0.3-0.4,0.4-0.8,0.4-1.3
C151.7,46.1,151.5,45.8,151.1,45.5z M147.1,40.9c0.2-0.2,0.5-0.4,1-0.4c0.4,0,0.7,0.1,1,0.4c0.2,0.2,0.3,0.6,0.3,0.9
c0,0.4-0.1,0.7-0.3,0.9c-0.2,0.3-0.5,0.4-1,0.4c-0.4,0-0.7-0.1-1-0.4c-0.2-0.3-0.3-0.6-0.3-0.9C146.8,41.4,146.9,41.1,147.1,40.9z
M150,47.4c-0.2,0.2-0.5,0.4-0.8,0.5c-0.3,0.1-0.7,0.2-1.2,0.2c-0.6,0-1.1-0.1-1.5-0.3c-0.4-0.2-0.5-0.4-0.5-0.8
c0-0.3,0.1-0.5,0.4-0.7c0.2-0.2,0.6-0.3,1-0.3h2.2c0.2,0,0.4,0.1,0.5,0.2c0.1,0.1,0.2,0.3,0.2,0.4C150.3,47,150.2,47.2,150,47.4z"
/>
<path class="st0" d="M157.9,39.9c-0.3-0.2-0.8-0.3-1.3-0.3c-0.5,0-1,0.1-1.3,0.4c-0.3,0.2-0.5,0.5-0.7,0.9l-0.2-1.1h-1.2V46h1.4
v-2.9c0-0.5,0.1-0.9,0.2-1.3c0.1-0.4,0.3-0.6,0.6-0.8c0.2-0.2,0.5-0.3,0.9-0.3c0.4,0,0.7,0.1,1,0.4c0.2,0.3,0.4,0.6,0.4,1.2V46h1.4
v-3.7c0-0.6-0.1-1.1-0.3-1.5C158.5,40.4,158.2,40.1,157.9,39.9z"/>
<path class="st0" d="M166.7,37c-0.3,0-0.7,0.1-0.9,0.2c-0.3,0.1-0.5,0.3-0.7,0.6c-0.2,0.3-0.3,0.6-0.3,1.1v0.8h-1v0.9h1V46h1.4
v-5.4h1.2v-0.9h-1.2v-0.8c0-0.2,0-0.4,0.1-0.5c0.1-0.1,0.2-0.2,0.3-0.3c0.1,0,0.2-0.1,0.4-0.1c0.1,0,0.2,0,0.3,0
c0.1,0,0.2,0.1,0.3,0.1l0.3-1.1c-0.2,0-0.4-0.1-0.6-0.1C167.1,37,166.9,37,166.7,37z"/>
<path class="st0" d="M173.1,39.9c-0.5-0.2-1-0.4-1.5-0.4c-0.6,0-1.1,0.1-1.5,0.4c-0.5,0.2-0.8,0.6-1.1,1.1
c-0.3,0.5-0.4,1.1-0.4,1.9c0,0.7,0.1,1.3,0.4,1.8c0.3,0.5,0.6,0.9,1.1,1.1c0.5,0.2,1,0.4,1.5,0.4c0.6,0,1.1-0.1,1.5-0.4
c0.5-0.2,0.8-0.6,1.1-1.1c0.3-0.5,0.4-1.1,0.4-1.8c0-0.7-0.1-1.4-0.4-1.9C173.9,40.5,173.6,40.1,173.1,39.9z M173,44
c-0.1,0.3-0.3,0.6-0.6,0.7c-0.3,0.2-0.5,0.2-0.9,0.2c-0.5,0-0.9-0.2-1.2-0.5c-0.3-0.4-0.4-0.9-0.4-1.6c0-0.5,0.1-0.9,0.2-1.2
c0.1-0.3,0.3-0.6,0.6-0.7c0.3-0.2,0.5-0.2,0.9-0.2c0.5,0,0.9,0.2,1.2,0.5c0.3,0.4,0.4,0.9,0.4,1.6C173.2,43.3,173.2,43.7,173,44z"
/>
<path class="st0" d="M179.6,39.6c-0.4,0-0.7,0.1-1.1,0.4c-0.3,0.2-0.5,0.6-0.6,1v-1.3h-1.4V46h1.4v-2.8h0c0-0.5,0.1-0.9,0.2-1.2
c0.1-0.3,0.3-0.6,0.5-0.8c0.2-0.2,0.5-0.3,0.9-0.3c0.1,0,0.2,0,0.4,0c0.1,0,0.3,0,0.4,0.1l0-1.4c-0.1,0-0.2-0.1-0.3-0.1
C179.8,39.6,179.7,39.6,179.6,39.6z"/>
<path class="st0" d="M188.9,41.4l-1.8-0.7c-0.4-0.1-0.6-0.3-0.8-0.4c-0.2-0.1-0.3-0.4-0.3-0.6c0-0.3,0.1-0.5,0.4-0.7
c0.3-0.2,0.6-0.3,1.1-0.3c0.5,0,0.9,0.1,1.1,0.3c0.3,0.2,0.4,0.5,0.5,0.8h1.4c-0.1-0.7-0.4-1.3-0.9-1.8c-0.5-0.4-1.2-0.6-2.1-0.6
c-1,0-1.7,0.2-2.2,0.6c-0.5,0.4-0.8,1-0.8,1.6c0,0.6,0.2,1.1,0.5,1.4c0.3,0.3,0.9,0.6,1.5,0.9l1.6,0.6c0.4,0.1,0.7,0.3,0.9,0.5
c0.2,0.2,0.3,0.4,0.3,0.7c0,0.2-0.1,0.4-0.2,0.6c-0.1,0.2-0.3,0.3-0.6,0.4c-0.3,0.1-0.6,0.1-0.9,0.1c-0.3,0-0.6-0.1-0.9-0.2
c-0.3-0.1-0.5-0.3-0.7-0.5c-0.2-0.2-0.3-0.5-0.3-0.8h-1.4c0,0.6,0.2,1.1,0.5,1.6c0.3,0.4,0.7,0.7,1.2,0.9c0.5,0.2,1,0.3,1.6,0.3
c0.7,0,1.3-0.1,1.8-0.3c0.5-0.2,0.8-0.5,1.1-0.9c0.3-0.4,0.4-0.8,0.4-1.3c0-0.6-0.2-1-0.5-1.4C190,42,189.5,41.7,188.9,41.4z"/>
<path class="st0" d="M197.5,39.9c-0.4-0.3-0.9-0.4-1.4-0.4c-0.4,0-0.8,0.1-1.1,0.3c-0.3,0.2-0.5,0.4-0.7,0.8l-0.1-0.9h-1.1v9.4h1.4
v-3.7c0.1,0.2,0.3,0.3,0.5,0.5c0.3,0.2,0.7,0.3,1.2,0.3c0.5,0,1-0.1,1.4-0.4c0.4-0.3,0.8-0.6,1.1-1.1c0.3-0.5,0.4-1.1,0.4-1.8
c0-0.7-0.1-1.3-0.4-1.8C198.3,40.6,197.9,40.2,197.5,39.9z M197.3,44c-0.2,0.3-0.4,0.5-0.6,0.7c-0.3,0.2-0.5,0.2-0.8,0.2
c-0.3,0-0.5-0.1-0.7-0.2c-0.2-0.1-0.4-0.3-0.6-0.5c-0.1-0.2-0.2-0.5-0.2-0.8v-1.1c0-0.3,0.1-0.6,0.2-0.9c0.1-0.2,0.3-0.4,0.6-0.5
c0.2-0.1,0.5-0.2,0.8-0.2c0.3,0,0.6,0.1,0.9,0.2c0.3,0.2,0.5,0.4,0.6,0.7c0.1,0.3,0.2,0.7,0.2,1.1C197.5,43.3,197.4,43.7,197.3,44z
"/>
<path class="st0" d="M205.7,41.8c-0.1-0.4-0.2-0.8-0.4-1.2c-0.2-0.3-0.5-0.6-0.9-0.8c-0.4-0.2-0.8-0.3-1.3-0.3
c-0.5,0-1,0.1-1.5,0.4c-0.4,0.3-0.8,0.6-1.1,1.1c-0.3,0.5-0.4,1.1-0.4,1.8c0,0.7,0.1,1.2,0.4,1.7c0.3,0.5,0.6,0.9,1.1,1.2
c0.4,0.3,0.9,0.4,1.5,0.4c0.5,0,0.9-0.1,1.3-0.3c0.4-0.2,0.7-0.4,0.9-0.7c0.2-0.3,0.4-0.7,0.5-1.1h-1.4c-0.1,0.3-0.2,0.5-0.4,0.7
c-0.2,0.2-0.5,0.2-0.8,0.2c-0.3,0-0.6-0.1-0.9-0.3c-0.2-0.2-0.4-0.4-0.5-0.7c-0.1-0.3-0.2-0.6-0.2-1h4.2
C205.8,42.6,205.8,42.2,205.7,41.8z M201.6,42.3c0-0.3,0.1-0.5,0.2-0.8c0.1-0.3,0.3-0.5,0.5-0.7c0.2-0.2,0.5-0.3,0.9-0.3
c0.3,0,0.5,0.1,0.7,0.2c0.2,0.1,0.3,0.3,0.4,0.4c0.1,0.2,0.2,0.4,0.2,0.6c0,0.2,0,0.3,0,0.5H201.6z"/>
<path class="st0" d="M209.3,41c0.2-0.1,0.5-0.2,0.7-0.2c0.3,0,0.6,0.1,0.8,0.3c0.2,0.2,0.4,0.4,0.4,0.7l1.4-0.1
c0-0.3-0.1-0.5-0.3-0.8c-0.1-0.3-0.3-0.5-0.5-0.7c-0.2-0.2-0.5-0.4-0.8-0.5c-0.3-0.1-0.7-0.2-1.1-0.2c-0.5,0-1,0.1-1.5,0.4
c-0.5,0.3-0.8,0.6-1.1,1.1c-0.3,0.5-0.4,1.1-0.4,1.8c0,0.7,0.1,1.3,0.4,1.8c0.3,0.5,0.6,0.9,1.1,1.2c0.4,0.3,0.9,0.4,1.5,0.4
c0.6,0,1-0.1,1.4-0.3c0.4-0.2,0.7-0.5,0.9-0.9c0.2-0.4,0.3-0.8,0.3-1.2h-1.4c0,0.3-0.1,0.6-0.3,0.8c-0.2,0.2-0.5,0.3-0.9,0.3
c-0.3,0-0.5-0.1-0.8-0.2c-0.2-0.2-0.4-0.4-0.6-0.7c-0.1-0.3-0.2-0.7-0.2-1.1c0-0.5,0.1-0.9,0.2-1.2C208.8,41.4,209,41.1,209.3,41z"
/>
<path class="st0" d="M215.3,36.8c-0.3,0-0.5,0.1-0.6,0.2c-0.2,0.1-0.2,0.3-0.2,0.6c0,0.3,0.1,0.5,0.2,0.6c0.2,0.1,0.4,0.2,0.6,0.2
c0.3,0,0.5-0.1,0.6-0.2c0.2-0.1,0.2-0.4,0.2-0.6c0-0.2-0.1-0.4-0.2-0.6C215.8,36.9,215.6,36.8,215.3,36.8z"/>
<rect x="214.6" y="39.7" class="st0" width="1.4" height="6.3"/>
<path class="st0" d="M222.6,39.8c-0.4-0.2-0.9-0.3-1.4-0.3c-0.6,0-1.1,0.1-1.5,0.2c-0.4,0.1-0.7,0.4-1,0.6
c-0.2,0.3-0.3,0.7-0.3,1.2h1.5c0-0.2,0.1-0.4,0.2-0.5c0.1-0.1,0.3-0.3,0.5-0.3c0.2-0.1,0.4-0.1,0.7-0.1c0.4,0,0.8,0.1,1,0.3
c0.2,0.2,0.3,0.6,0.3,1.1v0.7c-0.3-0.1-0.5-0.1-0.8-0.2c-0.3-0.1-0.6-0.1-1-0.1c-0.5,0-0.9,0.1-1.3,0.2c-0.4,0.1-0.7,0.3-0.9,0.6
c-0.2,0.3-0.3,0.6-0.3,1c0,0.3,0.1,0.7,0.3,1c0.2,0.3,0.4,0.6,0.8,0.7c0.4,0.2,0.8,0.3,1.3,0.3c0.5,0,0.9-0.1,1.2-0.3
c0.3-0.2,0.6-0.5,0.7-0.9l0.1,1h1.2v-4c0-0.6-0.1-1-0.3-1.4C223.3,40.2,223,39.9,222.6,39.8z M222.5,43.7c0,0.2-0.1,0.4-0.2,0.7
c-0.1,0.2-0.3,0.4-0.5,0.5c-0.2,0.1-0.5,0.2-0.8,0.2c-0.4,0-0.8-0.1-1-0.3c-0.2-0.2-0.3-0.4-0.3-0.7c0-0.3,0.1-0.6,0.4-0.7
c0.2-0.1,0.6-0.2,0.9-0.2c0.3,0,0.5,0,0.8,0.1c0.2,0,0.5,0.1,0.7,0.2V43.7z"/>
<rect x="226.2" y="37.1" class="st0" width="1.4" height="8.9"/>
<polygon class="st0" points="233.3,46 238.7,46 238.7,44.8 234.7,44.8 234.7,42.4 238.4,42.4 238.4,41.2 234.7,41.2 234.7,38.8
238.7,38.8 238.7,37.6 233.3,37.6 "/>
<path class="st0" d="M246.4,47.6c-0.1-0.2-0.1-0.4-0.1-0.6v-7.3h-0.9l-0.3,1c-0.2-0.4-0.5-0.7-0.8-0.9c-0.3-0.2-0.7-0.3-1.1-0.3
c-0.5,0-1,0.1-1.4,0.4c-0.4,0.3-0.8,0.6-1.1,1.1c-0.3,0.5-0.4,1.1-0.4,1.8c0,0.7,0.1,1.3,0.4,1.8c0.3,0.5,0.6,0.9,1.1,1.1
c0.4,0.3,0.9,0.4,1.4,0.4c0.5,0,0.8-0.1,1.1-0.3c0.2-0.2,0.4-0.4,0.5-0.8v1.8c0,0.7,0.1,1.2,0.4,1.5c0.3,0.4,0.8,0.6,1.4,0.8l0.4-1
c-0.2-0.1-0.4-0.2-0.5-0.2C246.5,47.9,246.4,47.8,246.4,47.6z M244.9,43.4c0,0.3-0.1,0.6-0.2,0.8c-0.1,0.2-0.3,0.4-0.6,0.5
c-0.2,0.1-0.5,0.2-0.7,0.2c-0.3,0-0.5-0.1-0.8-0.2c-0.3-0.2-0.5-0.4-0.6-0.7c-0.2-0.3-0.3-0.7-0.3-1.2c0-0.4,0.1-0.8,0.2-1.1
c0.1-0.3,0.3-0.6,0.6-0.7c0.3-0.2,0.5-0.2,0.9-0.2c0.3,0,0.5,0.1,0.7,0.2c0.2,0.1,0.4,0.3,0.5,0.5c0.1,0.2,0.2,0.5,0.2,0.9V43.4z"
/>
<path class="st0" d="M253,42.7c0,0.5-0.1,0.9-0.2,1.2c-0.2,0.3-0.4,0.6-0.6,0.7c-0.3,0.2-0.6,0.3-0.9,0.3c-0.4,0-0.7-0.1-0.9-0.3
c-0.2-0.2-0.3-0.6-0.3-1v-3.9h-1.4v4c0,0.6,0.1,1,0.3,1.4c0.2,0.4,0.5,0.6,0.9,0.8c0.4,0.2,0.8,0.2,1.2,0.2c0.5,0,0.9-0.1,1.2-0.4
c0.3-0.2,0.5-0.5,0.7-0.9V46h1.4v-6.3H253V42.7z"/>
<path class="st0" d="M257.7,36.8c-0.3,0-0.5,0.1-0.6,0.2c-0.2,0.1-0.2,0.3-0.2,0.6c0,0.3,0.1,0.5,0.2,0.6c0.2,0.1,0.4,0.2,0.6,0.2
c0.3,0,0.5-0.1,0.6-0.2c0.2-0.1,0.2-0.4,0.2-0.6c0-0.2-0.1-0.4-0.2-0.6C258.2,36.9,258,36.8,257.7,36.8z"/>
<rect x="257" y="39.7" class="st0" width="1.4" height="6.3"/>
<path class="st0" d="M265.6,39.9c-0.4-0.3-0.9-0.4-1.4-0.4c-0.4,0-0.8,0.1-1.1,0.3c-0.3,0.2-0.5,0.4-0.7,0.8l-0.1-0.9h-1.1v9.4h1.4
v-3.7c0.1,0.2,0.3,0.3,0.5,0.5c0.3,0.2,0.7,0.3,1.2,0.3c0.5,0,1-0.1,1.4-0.4c0.4-0.3,0.8-0.6,1.1-1.1c0.3-0.5,0.4-1.1,0.4-1.8
c0-0.7-0.1-1.3-0.4-1.8C266.4,40.6,266,40.2,265.6,39.9z M265.4,44c-0.2,0.3-0.4,0.5-0.6,0.7c-0.3,0.2-0.5,0.2-0.8,0.2
c-0.3,0-0.5-0.1-0.7-0.2c-0.2-0.1-0.4-0.3-0.6-0.5c-0.1-0.2-0.2-0.5-0.2-0.8v-1.1c0-0.3,0.1-0.6,0.2-0.9c0.1-0.2,0.3-0.4,0.6-0.5
c0.2-0.1,0.5-0.2,0.8-0.2c0.3,0,0.6,0.1,0.9,0.2c0.3,0.2,0.5,0.4,0.6,0.7c0.1,0.3,0.2,0.7,0.2,1.1C265.6,43.3,265.6,43.7,265.4,44z
"/>
<path class="st0" d="M277.9,39.9c-0.3-0.2-0.8-0.3-1.3-0.3c-0.4,0-0.7,0.1-1,0.2c-0.3,0.1-0.6,0.3-0.8,0.6
c-0.1,0.2-0.2,0.4-0.3,0.6c0,0,0-0.1,0-0.1c-0.2-0.4-0.4-0.7-0.8-1c-0.4-0.2-0.8-0.3-1.3-0.3c-0.5,0-0.9,0.1-1.2,0.3
c-0.3,0.2-0.6,0.5-0.8,1l-0.2-1.1h-1.2V46h1.4v-2.9c0-0.5,0.1-0.9,0.2-1.3c0.1-0.4,0.3-0.6,0.6-0.8c0.2-0.2,0.5-0.3,0.9-0.3
c0.4,0,0.7,0.1,1,0.4c0.2,0.3,0.4,0.6,0.4,1.2V46h1.4v-2.9c0-0.8,0.1-1.3,0.4-1.7c0.3-0.4,0.7-0.6,1.2-0.6c0.4,0,0.7,0.1,1,0.4
c0.2,0.3,0.4,0.6,0.4,1.2V46h1.4v-3.7c0-0.6-0.1-1.1-0.3-1.5C278.5,40.4,278.3,40.1,277.9,39.9z"/>
<path class="st0" d="M286.2,41.8c-0.1-0.4-0.2-0.8-0.4-1.2c-0.2-0.3-0.5-0.6-0.9-0.8c-0.4-0.2-0.8-0.3-1.3-0.3
c-0.5,0-1,0.1-1.5,0.4c-0.4,0.3-0.8,0.6-1.1,1.1c-0.3,0.5-0.4,1.1-0.4,1.8c0,0.7,0.1,1.2,0.4,1.7c0.3,0.5,0.6,0.9,1.1,1.2
c0.4,0.3,0.9,0.4,1.5,0.4c0.5,0,0.9-0.1,1.3-0.3c0.4-0.2,0.7-0.4,0.9-0.7c0.2-0.3,0.4-0.7,0.5-1.1h-1.4c-0.1,0.3-0.2,0.5-0.4,0.7
c-0.2,0.2-0.5,0.2-0.8,0.2c-0.3,0-0.6-0.1-0.9-0.3c-0.2-0.2-0.4-0.4-0.5-0.7c-0.1-0.3-0.2-0.6-0.2-1h4.2
C286.3,42.6,286.2,42.2,286.2,41.8z M282,42.3c0-0.3,0.1-0.5,0.2-0.8c0.1-0.3,0.3-0.5,0.5-0.7c0.2-0.2,0.5-0.3,0.9-0.3
c0.3,0,0.5,0.1,0.7,0.2c0.2,0.1,0.3,0.3,0.4,0.4c0.1,0.2,0.2,0.4,0.2,0.6c0,0.2,0,0.3,0,0.5H282z"/>
<path class="st0" d="M292.8,39.9c-0.3-0.2-0.8-0.3-1.3-0.3c-0.5,0-1,0.1-1.3,0.4c-0.3,0.2-0.5,0.5-0.7,0.9l-0.2-1.1h-1.2V46h1.4
v-2.9c0-0.5,0.1-0.9,0.2-1.3c0.1-0.4,0.3-0.6,0.6-0.8c0.2-0.2,0.5-0.3,0.9-0.3c0.4,0,0.7,0.1,1,0.4c0.2,0.3,0.4,0.6,0.4,1.2V46h1.4
v-3.7c0-0.6-0.1-1.1-0.3-1.5C293.4,40.4,293.2,40.1,292.8,39.9z"/>
<path class="st0" d="M298.9,45c-0.2,0-0.3,0.1-0.5,0.1c-0.5,0-0.8-0.3-0.8-0.8v-3.6h1.8v-0.9h-1.8V38h-1.4v1.7h-0.9v0.9h0.9v3.7
c0,0.4,0.1,0.8,0.3,1.1c0.2,0.3,0.4,0.5,0.7,0.6c0.3,0.1,0.6,0.2,1,0.2c0.2,0,0.5,0,0.7-0.1c0.2-0.1,0.5-0.1,0.7-0.2l-0.2-1
C299.3,44.9,299.1,45,298.9,45z"/>
<path class="st0" d="M58.3,21.7H65l1.3,4h3.1L63.5,8.1h-3.6l-6,17.5H57L58.3,21.7z M61.7,11.6l2.6,7.9h-5.2L61.7,11.6z"/>
<path class="st0" d="M80.4,23.1c-0.5,0.2-1.2,0.3-1.9,0.3c-0.7,0-1.3-0.1-1.9-0.3c-0.6-0.2-1.1-0.6-1.4-1c-0.4-0.5-0.5-1.1-0.5-1.8
h-2.8c0,1.3,0.4,2.4,1,3.2c0.6,0.9,1.4,1.5,2.4,1.9c1,0.4,2.1,0.6,3.3,0.6c1.4,0,2.7-0.2,3.7-0.6c1-0.4,1.8-1,2.3-1.8
c0.5-0.8,0.8-1.7,0.8-2.7c0-1.2-0.4-2.1-1.1-2.9c-0.7-0.8-1.7-1.4-3-1.9l-3.8-1.4c-0.7-0.3-1.3-0.6-1.6-0.9
c-0.3-0.3-0.5-0.7-0.5-1.3c0-0.6,0.3-1.1,0.8-1.6c0.6-0.4,1.3-0.6,2.3-0.6c1.1,0,1.9,0.2,2.4,0.6c0.5,0.4,0.9,1,1,1.7h2.8
c-0.1-1.6-0.7-2.8-1.8-3.7c-1.1-0.9-2.5-1.3-4.4-1.3c-2,0-3.5,0.4-4.6,1.3c-1.1,0.9-1.7,2-1.7,3.4c0,1.2,0.4,2.2,1.1,2.9
c0.7,0.7,1.8,1.3,3.2,1.8l3.4,1.3c0.8,0.3,1.4,0.6,1.8,1c0.4,0.4,0.6,0.9,0.6,1.5c0,0.5-0.2,0.9-0.5,1.2
C81.3,22.6,80.9,22.9,80.4,23.1z"/>
<polygon class="st0" points="92.7,25.6 95.7,25.6 95.7,10.6 101.2,10.6 101.2,8.1 87.2,8.1 87.2,10.6 92.7,10.6 "/>
<path class="st0" d="M106.8,18.7h2.6l4,6.9h3.8l-4.8-7.2c1-0.2,1.9-0.6,2.5-1.2c1.1-1,1.6-2.2,1.6-3.8c0-1.6-0.5-2.9-1.6-3.9
c-1.1-1-2.7-1.5-4.7-1.5h-6.4v17.5h2.9V18.7z M106.8,10.6h3.5c1.1,0,2,0.3,2.6,0.8c0.6,0.6,0.9,1.3,0.9,2.2c0,0.9-0.3,1.6-0.9,2.2
c-0.6,0.6-1.5,0.9-2.8,0.9h-3.2V10.6z"/>
<path class="st0" d="M123.7,25c1.2,0.7,2.5,1,4.1,1c1.5,0,2.9-0.3,4.1-1c1.2-0.7,2.1-1.7,2.8-3c0.7-1.4,1-3.1,1-5.1
c0-2-0.3-3.7-1-5c-0.7-1.3-1.6-2.4-2.8-3c-1.2-0.7-2.5-1-4.1-1c-1.5,0-2.9,0.3-4.1,1c-1.2,0.7-2.1,1.7-2.8,3s-1,3-1,5.1
c0,2,0.3,3.7,1,5.1C121.6,23.3,122.5,24.3,123.7,25z M124.2,12.1c0.9-1.1,2-1.7,3.5-1.7c1.5,0,2.7,0.6,3.5,1.7s1.3,2.7,1.3,4.8
c0,2.1-0.4,3.7-1.3,4.8c-0.9,1.1-2.1,1.7-3.5,1.7c-1.5,0-2.6-0.6-3.5-1.7c-0.9-1.1-1.3-2.7-1.3-4.8
C122.9,14.8,123.4,13.2,124.2,12.1z"/>
<polygon class="st0" points="149.4,25.6 152.3,25.6 152.3,10.6 157.8,10.6 157.8,8.1 143.9,8.1 143.9,10.6 149.4,10.6 "/>
<polygon class="st0" points="171.6,23.1 163.4,23.1 163.4,18.1 171.1,18.1 171.1,15.6 163.4,15.6 163.4,10.6 171.6,10.6 171.6,8.1
160.5,8.1 160.5,25.6 171.6,25.6 "/>
<path class="st0" d="M178.6,24.9c1.1,0.7,2.5,1.1,4,1.1c1.4,0,2.7-0.2,3.7-0.7c1-0.5,1.8-1.2,2.4-2.1c0.6-0.9,0.8-2,0.8-3.3h-3.1
c0,1-0.3,1.8-1,2.5c-0.7,0.6-1.6,1-2.8,1c-1,0-1.8-0.3-2.4-0.8c-0.7-0.5-1.2-1.3-1.5-2.3c-0.3-1-0.5-2.1-0.5-3.4
c0-1.4,0.2-2.6,0.6-3.6c0.4-1,0.9-1.7,1.6-2.1c0.7-0.5,1.4-0.7,2.2-0.7c0.9,0,1.7,0.3,2.4,0.9c0.7,0.6,1.1,1.4,1.5,2.3l3.1-0.6
c-0.4-1.6-1.1-2.8-2.2-3.8c-1.1-1-2.7-1.5-4.7-1.5c-1.5,0-2.8,0.3-3.9,1c-1.1,0.7-2,1.7-2.7,3c-0.7,1.3-1,3-1,5
c0,1.9,0.3,3.5,0.9,4.9C176.6,23.1,177.5,24.1,178.6,24.9z"/>
<polygon class="st0" points="196.3,12.7 204.5,25.6 207.5,25.6 207.5,8.1 204.6,8.1 204.6,20.8 196.6,8.1 193.4,8.1 193.4,25.6
196.3,25.6 "/>
<path class="st0" d="M215.2,25c1.2,0.7,2.5,1,4.1,1c1.5,0,2.9-0.3,4.1-1c1.2-0.7,2.1-1.7,2.8-3c0.7-1.4,1-3.1,1-5.1
c0-2-0.3-3.7-1-5c-0.7-1.3-1.6-2.4-2.8-3c-1.2-0.7-2.5-1-4.1-1c-1.5,0-2.9,0.3-4.1,1c-1.2,0.7-2.1,1.7-2.8,3c-0.7,1.3-1,3-1,5.1
c0,2,0.3,3.7,1,5.1C213.1,23.3,214,24.3,215.2,25z M215.7,12.1c0.9-1.1,2-1.7,3.5-1.7c1.5,0,2.7,0.6,3.5,1.7
c0.9,1.1,1.3,2.7,1.3,4.8c0,2.1-0.4,3.7-1.3,4.8c-0.9,1.1-2.1,1.7-3.5,1.7c-1.5,0-2.6-0.6-3.5-1.7c-0.9-1.1-1.3-2.7-1.3-4.8
C214.4,14.8,214.9,13.2,215.7,12.1z"/>
<polygon class="st0" points="241.3,23.1 233.9,23.1 233.9,8.1 231,8.1 231,25.6 241.3,25.6 "/>
<path class="st0" d="M246.8,25c1.2,0.7,2.5,1,4.1,1c1.5,0,2.9-0.3,4.1-1c1.2-0.7,2.1-1.7,2.8-3c0.7-1.4,1-3.1,1-5.1
c0-2-0.3-3.7-1-5c-0.7-1.3-1.6-2.4-2.8-3c-1.2-0.7-2.5-1-4.1-1c-1.5,0-2.9,0.3-4.1,1c-1.2,0.7-2.1,1.7-2.8,3c-0.7,1.3-1,3-1,5.1
c0,2,0.3,3.7,1,5.1C244.7,23.3,245.6,24.3,246.8,25z M247.3,12.1c0.9-1.1,2-1.7,3.5-1.7c1.5,0,2.7,0.6,3.5,1.7
c0.9,1.1,1.3,2.7,1.3,4.8c0,2.1-0.4,3.7-1.3,4.8c-0.9,1.1-2.1,1.7-3.5,1.7c-1.5,0-2.6-0.6-3.5-1.7c-0.9-1.1-1.3-2.7-1.3-4.8
C246,14.8,246.4,13.2,247.3,12.1z"/>
<path class="st0" d="M265.1,24.9c1.2,0.7,2.4,1.1,3.8,1.1c1.2,0,2.1-0.3,2.9-0.9c0.7-0.6,1.2-1.4,1.6-2.4l0.3,2.9h2.4v-8.9h-6.9
v1.9l4.1,0.1v0.1c0,1-0.2,1.8-0.5,2.5c-0.4,0.7-0.8,1.2-1.5,1.5c-0.6,0.4-1.3,0.5-2.1,0.5c-0.9,0-1.8-0.3-2.5-0.8
c-0.7-0.5-1.3-1.3-1.7-2.2c-0.4-1-0.6-2.1-0.6-3.3c0-1.4,0.2-2.5,0.7-3.5c0.5-1,1.1-1.7,1.8-2.3c0.8-0.5,1.6-0.8,2.5-0.8
c0.8,0,1.5,0.2,2.1,0.6c0.6,0.4,1.2,1,1.7,1.7l2.9-0.7c-0.7-1.4-1.5-2.5-2.6-3.2c-1.1-0.7-2.4-1-4-1c-1.2,0-2.2,0.2-3.2,0.6
c-1,0.4-1.9,1-2.6,1.8c-0.8,0.8-1.3,1.8-1.8,2.9c-0.4,1.1-0.6,2.4-0.6,3.9c0,1.8,0.3,3.4,1,4.7C263,23.1,263.9,24.1,265.1,24.9z"/>
<rect x="280.8" y="8.1" class="st0" width="2.9" height="17.5"/>
<polygon class="st0" points="300,23.1 291.8,23.1 291.8,18.1 299.5,18.1 299.5,15.6 291.8,15.6 291.8,10.6 300,10.6 300,8.1
288.9,8.1 288.9,25.6 300,25.6 "/>
<path class="st0" d="M40.6,6.7H0v40.6h40.6V32.2H300v-1.2H40.6V6.7z M7.9,36.7H3.3c-0.4,0-0.7-0.3-0.7-0.7c0-0.4,0.3-0.7,0.7-0.7
h4.7c0.4,0,0.7,0.3,0.7,0.7C8.7,36.4,8.3,36.7,7.9,36.7z M7.9,32.2H3.3c-0.4,0-0.7-0.3-0.7-0.7c0-0.4,0.3-0.7,0.7-0.7h4.7
c0.4,0,0.7,0.3,0.7,0.7C8.7,31.9,8.3,32.2,7.9,32.2z M7.9,27.7H3.3c-0.4,0-0.7-0.3-0.7-0.7c0-0.4,0.3-0.7,0.7-0.7h4.7
c0.4,0,0.7,0.3,0.7,0.7C8.7,27.4,8.3,27.7,7.9,27.7z M7.9,23.3H3.3c-0.4,0-0.7-0.3-0.7-0.7c0-0.4,0.3-0.7,0.7-0.7h4.7
c0.4,0,0.7,0.3,0.7,0.7C8.7,22.9,8.3,23.3,7.9,23.3z M7.9,18.8H3.3c-0.4,0-0.7-0.3-0.7-0.7c0-0.4,0.3-0.7,0.7-0.7h4.7
c0.4,0,0.7,0.3,0.7,0.7C8.7,18.4,8.3,18.8,7.9,18.8z M12.1,43.5c0,0.4-0.3,0.7-0.7,0.7c-0.4,0-0.7-0.3-0.7-0.7v-4.7
c0-0.4,0.3-0.7,0.7-0.7c0.4,0,0.7,0.3,0.7,0.7V43.5z M12.1,15.2c0,0.4-0.3,0.7-0.7,0.7c-0.4,0-0.7-0.3-0.7-0.7v-4.7
c0-0.4,0.3-0.7,0.7-0.7c0.4,0,0.7,0.3,0.7,0.7V15.2z M16.6,43.5c0,0.4-0.3,0.7-0.7,0.7c-0.4,0-0.7-0.3-0.7-0.7v-4.7
c0-0.4,0.3-0.7,0.7-0.7c0.4,0,0.7,0.3,0.7,0.7V43.5z M16.6,15.2c0,0.4-0.3,0.7-0.7,0.7c-0.4,0-0.7-0.3-0.7-0.7v-4.7
c0-0.4,0.3-0.7,0.7-0.7c0.4,0,0.7,0.3,0.7,0.7V15.2z M21.1,43.5c0,0.4-0.3,0.7-0.7,0.7c-0.4,0-0.7-0.3-0.7-0.7v-4.7
c0-0.4,0.3-0.7,0.7-0.7c0.4,0,0.7,0.3,0.7,0.7V43.5z M21.1,15.2c0,0.4-0.3,0.7-0.7,0.7c-0.4,0-0.7-0.3-0.7-0.7v-4.7
c0-0.4,0.3-0.7,0.7-0.7c0.4,0,0.7,0.3,0.7,0.7V15.2z M25.5,43.5c0,0.4-0.3,0.7-0.7,0.7c-0.4,0-0.7-0.3-0.7-0.7v-4.7
c0-0.4,0.3-0.7,0.7-0.7c0.4,0,0.7,0.3,0.7,0.7V43.5z M25.5,15.2c0,0.4-0.3,0.7-0.7,0.7c-0.4,0-0.7-0.3-0.7-0.7v-4.7
c0-0.4,0.3-0.7,0.7-0.7c0.4,0,0.7,0.3,0.7,0.7V15.2z M30,43.5c0,0.4-0.3,0.7-0.7,0.7s-0.7-0.3-0.7-0.7v-4.7c0-0.4,0.3-0.7,0.7-0.7
s0.7,0.3,0.7,0.7V43.5z M30,15.2c0,0.4-0.3,0.7-0.7,0.7s-0.7-0.3-0.7-0.7v-4.7c0-0.4,0.3-0.7,0.7-0.7s0.7,0.3,0.7,0.7V15.2z
M37.3,36.7h-4.7c-0.4,0-0.7-0.3-0.7-0.7c0-0.4,0.3-0.7,0.7-0.7h4.7c0.4,0,0.7,0.3,0.7,0.7C38.1,36.4,37.7,36.7,37.3,36.7z
M37.3,32.2h-4.7c-0.4,0-0.7-0.3-0.7-0.7c0-0.4,0.3-0.7,0.7-0.7h4.7c0.4,0,0.7,0.3,0.7,0.7C38.1,31.9,37.7,32.2,37.3,32.2z
M37.3,27.7h-4.7c-0.4,0-0.7-0.3-0.7-0.7c0-0.4,0.3-0.7,0.7-0.7h4.7c0.4,0,0.7,0.3,0.7,0.7C38.1,27.4,37.7,27.7,37.3,27.7z
M37.3,23.3h-4.7c-0.4,0-0.7-0.3-0.7-0.7c0-0.4,0.3-0.7,0.7-0.7h4.7c0.4,0,0.7,0.3,0.7,0.7C38.1,22.9,37.7,23.3,37.3,23.3z
M37.3,18.8h-4.7c-0.4,0-0.7-0.3-0.7-0.7c0-0.4,0.3-0.7,0.7-0.7h4.7c0.4,0,0.7,0.3,0.7,0.7C38.1,18.4,37.7,18.8,37.3,18.8z"/>
<path class="st0" d="M360.9,50.7v0.7c0.3,0,0.6-0.1,0.9-0.3v4.6h0.7v-5.3h-0.5C361.6,50.5,361.3,50.7,360.9,50.7z"/>
<rect x="341" y="52.9" class="st0" width="2.3" height="0.6"/>
<path class="st0" d="M332.1,50.4c-0.3-0.1-0.5-0.2-0.8-0.2c-0.6,0-1,0.1-1.3,0.4c-0.3,0.3-0.5,0.7-0.5,1.2c0,0.5,0.2,0.9,0.5,1.2
c0.3,0.3,0.7,0.5,1.1,0.5c0.4,0,0.8-0.1,1.1-0.3c0.3-0.2,0.4-0.6,0.5-1c0,0.2,0,0.4,0,0.6c0,1.1-0.3,1.9-0.8,2.2
c-0.2,0.1-0.4,0.2-0.7,0.2c-0.3,0-0.5-0.1-0.7-0.3c-0.2-0.2-0.3-0.4-0.3-0.8h-0.7c0,0.5,0.2,0.9,0.5,1.2c0.3,0.3,0.8,0.5,1.4,0.5
c0.3,0,0.6-0.1,0.9-0.2c0.8-0.4,1.2-1.3,1.2-2.7c0-0.8-0.2-1.4-0.6-1.9C332.6,50.7,332.3,50.5,332.1,50.4z M332,52.6
c-0.2,0.2-0.5,0.3-0.8,0.3s-0.6-0.1-0.8-0.3c-0.2-0.2-0.3-0.4-0.3-0.8c0-0.3,0.1-0.6,0.3-0.8c0.2-0.2,0.5-0.3,0.8-0.3
c0.3,0,0.6,0.1,0.8,0.3c0.2,0.2,0.3,0.4,0.3,0.7C332.3,52.2,332.2,52.4,332,52.6z"/>
<path class="st0" d="M347,54.2c0.1-0.1,0.3-0.3,0.6-0.4l1.1-0.4c0.4-0.2,0.7-0.4,0.9-0.6c0.2-0.3,0.3-0.6,0.3-1
c0-0.4-0.2-0.8-0.5-1.1c-0.3-0.3-0.8-0.4-1.3-0.4c-0.5,0-1,0.1-1.3,0.4c-0.3,0.2-0.5,0.6-0.6,1.1h0.7c0-0.3,0.2-0.5,0.4-0.6
c0.2-0.1,0.5-0.2,0.8-0.2c0.3,0,0.6,0.1,0.8,0.3c0.2,0.2,0.3,0.4,0.3,0.7c0,0.5-0.3,0.8-0.8,1.1l-1.1,0.4c-0.2,0.1-0.4,0.2-0.5,0.3
c-0.5,0.3-0.7,0.8-0.7,1.4v0.8h3.8V55h-3.1v-0.3C346.8,54.5,346.9,54.4,347,54.2z"/>
<path class="st0" d="M336.5,52.4c-0.4,0-0.8,0.1-1.1,0.4c-0.3,0.2-0.4,0.6-0.5,1.1c0-0.2,0-0.4,0-0.7c0-0.7,0.1-1.3,0.4-1.7
c0.3-0.4,0.7-0.6,1.2-0.6c0.5,0,0.8,0.3,0.9,0.8h0.7c0-0.4-0.2-0.8-0.5-1c-0.3-0.3-0.7-0.4-1.2-0.4c-0.7,0-1.2,0.3-1.6,0.8
c-0.4,0.5-0.6,1.2-0.6,2s0.2,1.5,0.6,2c0.4,0.5,0.9,0.8,1.5,0.8c0.5,0,1-0.2,1.3-0.5c0.3-0.3,0.5-0.7,0.5-1.2
c0-0.5-0.2-0.9-0.5-1.2C337.3,52.6,337,52.4,336.5,52.4z M337.1,54.9c-0.2,0.2-0.5,0.3-0.8,0.3s-0.6-0.1-0.8-0.3
c-0.2-0.2-0.3-0.4-0.3-0.7c0-0.3,0.1-0.6,0.3-0.8c0.2-0.2,0.5-0.3,0.8-0.3c0.3,0,0.6,0.1,0.8,0.3c0.2,0.2,0.3,0.4,0.3,0.8
C337.5,54.4,337.3,54.7,337.1,54.9z"/>
<path class="st0" d="M353.1,50.2c-0.6,0-1.2,0.2-1.5,0.7c-0.4,0.5-0.6,1.2-0.6,2.1c0,0.9,0.2,1.6,0.6,2.1c0.4,0.5,0.9,0.7,1.5,0.7
c0.6,0,1.2-0.2,1.5-0.7c0.4-0.5,0.6-1.2,0.6-2c0-0.9-0.2-1.6-0.6-2C354.2,50.5,353.7,50.2,353.1,50.2z M354.1,54.6
c-0.2,0.4-0.6,0.6-1,0.6c-0.5,0-0.8-0.2-1-0.6c-0.2-0.4-0.4-0.9-0.4-1.6c0-0.7,0.1-1.2,0.4-1.6c0.2-0.4,0.6-0.6,1-0.6
c0.5,0,0.8,0.2,1,0.6c0.2,0.4,0.4,0.9,0.4,1.6C354.5,53.7,354.3,54.2,354.1,54.6z"/>
<path class="st0" d="M327.1,50.4c-0.3-0.1-0.5-0.2-0.8-0.2c-0.6,0-1,0.1-1.3,0.4c-0.3,0.3-0.5,0.7-0.5,1.2c0,0.5,0.2,0.9,0.5,1.2
c0.3,0.3,0.7,0.5,1.1,0.5c0.4,0,0.8-0.1,1.1-0.3c0.3-0.2,0.4-0.6,0.5-1c0,0.2,0,0.4,0,0.6c0,1.1-0.3,1.9-0.8,2.2
c-0.2,0.1-0.4,0.2-0.7,0.2c-0.3,0-0.5-0.1-0.7-0.3c-0.2-0.2-0.3-0.4-0.3-0.8h-0.7c0,0.5,0.2,0.9,0.5,1.2c0.3,0.3,0.8,0.5,1.4,0.5
c0.3,0,0.6-0.1,0.9-0.2c0.8-0.4,1.2-1.3,1.2-2.7c0-0.8-0.2-1.4-0.6-1.9C327.6,50.7,327.4,50.5,327.1,50.4z M327.1,52.6
c-0.2,0.2-0.5,0.3-0.8,0.3c-0.3,0-0.6-0.1-0.8-0.3c-0.2-0.2-0.3-0.4-0.3-0.8c0-0.3,0.1-0.6,0.3-0.8c0.2-0.2,0.5-0.3,0.8-0.3
c0.3,0,0.6,0.1,0.8,0.3c0.2,0.2,0.3,0.4,0.3,0.7C327.4,52.2,327.3,52.4,327.1,52.6z"/>
<path class="st0" d="M321.5,50.7v0.7c0.3,0,0.6-0.1,0.9-0.3v4.6h0.7v-5.3h-0.5C322.3,50.5,321.9,50.7,321.5,50.7z"/>
<path class="st0" d="M357,54.2c0.1-0.1,0.3-0.3,0.6-0.4l1.1-0.4c0.4-0.2,0.7-0.4,0.9-0.6c0.2-0.3,0.3-0.6,0.3-1
c0-0.4-0.2-0.8-0.5-1.1c-0.3-0.3-0.8-0.4-1.3-0.4c-0.5,0-1,0.1-1.3,0.4c-0.3,0.2-0.5,0.6-0.6,1.1h0.7c0-0.3,0.2-0.5,0.4-0.6
c0.2-0.1,0.5-0.2,0.8-0.2c0.3,0,0.6,0.1,0.8,0.3c0.2,0.2,0.3,0.4,0.3,0.7c0,0.5-0.3,0.8-0.8,1.1l-1.1,0.4c-0.2,0.1-0.4,0.2-0.5,0.3
c-0.5,0.3-0.7,0.8-0.7,1.4v0.8h3.8V55h-3.1v-0.3C356.8,54.5,356.9,54.4,357,54.2z"/>
<rect x="350.4" y="41" class="st0" width="1" height="5.5"/>
<polygon class="st0" points="342.8,46.5 342.8,41 341.8,41 341.8,44.9 339.4,41 338.3,41 338.3,46.5 339.3,46.5 339.3,42.5
341.8,46.5 "/>
<polygon class="st0" points="348.9,46.5 348.9,41 347.9,41 347.9,44.9 345.4,41 344.4,41 344.4,46.5 345.4,46.5 345.4,42.5
347.9,46.5 "/>
<path class="st0" d="M336.3,46.5h1.1l-1.8-5.5h-1.3l-1.9,5.5h1.1l0.4-1.2h2L336.3,46.5z M334.1,44.6l0.8-2.4l0.8,2.4H334.1z"/>
<path class="st0" d="M373.5,33.6c-0.1-0.1-0.2-0.2-0.3-0.3c-0.1-0.1-0.2-0.2-0.3-0.4c-0.1-0.1-0.3-0.3-0.4-0.4c0,0-0.1-0.1-0.1-0.1
c0,0-0.1-0.1-0.1-0.1c-0.1-0.1-0.2-0.2-0.2-0.2c-0.1-0.1-0.2-0.2-0.3-0.2c0,0-0.1-0.1-0.1-0.1c0,0-0.1-0.1-0.1-0.1
c-0.2-0.2-0.4-0.3-0.6-0.5c-0.2-0.2-0.5-0.4-0.7-0.6c-0.1-0.1-0.2-0.2-0.4-0.3c-0.1,0-0.1-0.1-0.2-0.1c-0.1,0-0.1-0.1-0.2-0.1
c-1.1-0.8-2.4-1.5-3.9-2.2c-0.2-0.1-0.4-0.2-0.6-0.3c-0.1,0-0.2-0.1-0.3-0.1c-0.1,0-0.2-0.1-0.3-0.1c-0.2-0.1-0.4-0.2-0.6-0.2
c-0.2-0.1-0.4-0.1-0.6-0.2c-0.1,0-0.2-0.1-0.3-0.1c-0.1,0-0.2-0.1-0.3-0.1c-0.2-0.1-0.4-0.1-0.7-0.2l-0.1,0l-0.1,0
c-0.1,0-0.1,0-0.2,0c-0.1,0-0.2-0.1-0.3-0.1c-0.2-0.1-0.5-0.1-0.7-0.2c-0.2,0-0.5-0.1-0.7-0.1c-0.1,0-0.2,0-0.4-0.1
c-0.1,0-0.2,0-0.4-0.1c-0.5-0.1-1-0.1-1.5-0.2c-0.3,0-0.5,0-0.8-0.1c-0.1,0-0.3,0-0.4,0c0.1,0,0.1,0,0.2,0c1.1-1.6,1.8-3.5,1.8-5.7
c0-2.8-0.9-5.1-2.6-6.8c-1.7-1.8-3.9-2.7-6.5-2.7c-0.3,0-0.6,0-0.9,0.1c-0.3,0-0.6,0.1-1,0.2l1.2-5.2h9.4V0.2h-13.5l-2.1,9.7
c-0.2-0.7-0.5-1.4-0.9-2c-0.8-1.4-1.9-2.5-3.2-3.2c-1.3-0.7-2.9-1.1-4.7-1.1c-2.9,0-5.2,0.9-7,2.7c-1.8,1.8-2.8,4.3-2.9,7.4h5.4
c0.1-1.5,0.5-2.7,1.3-3.6c0.8-0.9,1.8-1.3,3-1.3c1.2,0,2.1,0.4,2.9,1.1c0.7,0.7,1.1,1.7,1.1,2.8c0,1.1-0.4,2.3-1.1,3.6
c-0.7,1.3-2.2,3.1-4.3,5.3l-9,9.1v2.6c-0.1,0-0.2,0-0.3,0c-0.8,0-1.6,0-2.4-0.1c-1.5-0.1-2.9-0.4-4.1-0.8c-0.6-0.2-1.2-0.4-1.7-0.5
c-0.1,0-0.3-0.1-0.4-0.1c-0.1,0-0.1,0-0.2-0.1c-0.1,0-0.1,0-0.2-0.1c-0.1,0-0.2-0.1-0.3-0.1c-0.1,0-0.2-0.1-0.3-0.1
c-0.1,0-0.2-0.1-0.3-0.1c-0.1,0-0.2-0.1-0.3-0.1c-0.2-0.1-0.4-0.2-0.5-0.3c-0.2-0.1-0.3-0.2-0.4-0.2c-0.1-0.1-0.3-0.1-0.4-0.2
c-0.2-0.1-0.4-0.2-0.5-0.3c-0.1-0.1-0.2-0.1-0.2-0.1c0,0,0.1,0.1,0.1,0.1c0,0,0.1,0.1,0.2,0.2c0,0,0.1,0.1,0.1,0.1
c0,0,0.1,0.1,0.1,0.1c0.1,0.1,0.2,0.2,0.3,0.3c0.1,0.1,0.2,0.2,0.4,0.3c0.1,0.1,0.3,0.2,0.4,0.4c0.1,0.1,0.2,0.1,0.3,0.2
c0.1,0.1,0.2,0.1,0.3,0.2c0.1,0.1,0.2,0.1,0.3,0.2c0.1,0.1,0.2,0.1,0.3,0.2c0.1,0,0.1,0.1,0.2,0.1c0.1,0,0.1,0.1,0.2,0.1
c0.1,0.1,0.2,0.2,0.4,0.2c0.1,0.1,0.2,0.2,0.4,0.2c0.1,0.1,0.3,0.2,0.4,0.2c0.1,0.1,0.3,0.2,0.4,0.2c0.1,0,0.1,0.1,0.2,0.1
c0.1,0,0.1,0.1,0.2,0.1c1.2,0.6,2.6,1.2,4.2,1.6c0.8,0.2,1.7,0.4,2.5,0.5c0.9,0.1,1.8,0.2,2.8,0.2c1.9,0.1,3.9-0.1,6-0.4
c2-0.3,4.1-0.8,6.2-1.5c2.1-0.6,4.1-1.4,6.1-2.3c0.1-0.1,0.2-0.1,0.4-0.2l0.3-0.2c0.2-0.1,0.5-0.2,0.7-0.3l0.1,0l0.1,0l0.2-0.1
l0.3-0.1l0.2-0.1c0.1,0,0.1,0,0.2-0.1l0.3-0.1c0.9-0.3,1.9-0.6,2.8-0.9c0.1,0,0.1,0,0.2,0l0.2,0c0.1,0,0.2-0.1,0.4-0.1
c0.2-0.1,0.5-0.1,0.7-0.2c0.1,0,0.2-0.1,0.4-0.1c0.1,0,0.1,0,0.2,0l0.2,0c0.1,0,0.2,0,0.4-0.1l0.2,0c0.1,0,0.1,0,0.2,0
c0.2,0,0.5-0.1,0.7-0.1c0.1,0,0.2,0,0.4,0c0.1,0,0.2,0,0.4,0c0.1,0,0.2,0,0.4,0c0.1,0,0.2,0,0.4,0c0.1,0,0.2,0,0.3,0
c0.1,0,0.2,0,0.3,0c0.9-0.1,1.8-0.1,2.7-0.1c0.2,0,0.4,0,0.7,0c0.1,0,0.1,0,0.2,0l0.1,0l0.1,0c0.1,0,0.2,0,0.3,0c0.1,0,0.2,0,0.3,0
c0.1,0,0.2,0,0.3,0c0.2,0,0.4,0,0.6,0.1c0.2,0,0.4,0,0.6,0.1c0.1,0,0.2,0,0.3,0c0.1,0,0.1,0,0.2,0l0.1,0l0.1,0
c0.2,0,0.4,0.1,0.6,0.1c0.1,0,0.2,0,0.3,0c0.1,0,0.2,0,0.3,0.1c0.2,0,0.4,0.1,0.6,0.1c0,0,0.1,0,0.1,0c0,0,0.1,0,0.1,0
c0.1,0,0.2,0,0.3,0.1c0.1,0,0.2,0,0.3,0.1c0.1,0,0.2,0,0.3,0.1c0.2,0.1,0.4,0.1,0.6,0.2c1.5,0.4,2.8,0.9,3.9,1.4
c0.1,0,0.1,0.1,0.2,0.1c0.1,0,0.1,0.1,0.2,0.1c0.1,0.1,0.3,0.1,0.4,0.2c0.1,0.1,0.3,0.1,0.4,0.2c0.1,0.1,0.3,0.1,0.4,0.2
c0.2,0.1,0.5,0.3,0.7,0.4c0.1,0,0.1,0.1,0.2,0.1c0.1,0,0.1,0.1,0.2,0.1c0.1,0.1,0.2,0.1,0.3,0.2c0.1,0.1,0.2,0.1,0.3,0.2
c0,0,0.1,0.1,0.1,0.1c0,0,0.1,0.1,0.1,0.1c0.2,0.1,0.3,0.2,0.5,0.3c0.2,0.1,0.3,0.2,0.4,0.3c0.1,0.1,0.2,0.2,0.3,0.2
c0.4,0.3,0.6,0.4,0.6,0.4C374,34.2,373.8,34,373.5,33.6z M335.8,24.8c2.6-2.7,4.4-5,5.4-7c0.2-0.4,0.4-0.9,0.6-1.3l3.6,0.8
c0.6-0.6,1.1-1,1.7-1.3c0.6-0.3,1.2-0.4,1.8-0.4c1.1,0,2.1,0.4,2.9,1.3c0.8,0.9,1.2,1.9,1.2,3.3c0,1.4-0.4,2.5-1.3,3.4
c-0.8,0.9-1.9,1.3-3.1,1.3c-0.9,0-1.7-0.2-2.4-0.7c-0.7-0.5-1.3-1.1-1.7-2h-5.7c0.5,2.4,1.7,4.3,3.5,5.7c0.2,0.1,0.3,0.2,0.5,0.4
c0,0,0,0,0,0c-0.2,0.1-0.3,0.1-0.5,0.2c0,0,0,0,0,0h-9.6L335.8,24.8z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 31 KiB

View File

@@ -1,14 +1,35 @@
let ws; let ws;
let lastMessageTimestamp = 0;
const IDLE_THRESHOLD_MS = 1000;
const loadingIndicator = document.getElementById("loadingIndicator");
function setLoadingIndicator(visible) {
if (!loadingIndicator) {
return;
}
loadingIndicator.classList.toggle("hidden", !visible);
}
function updateLoadingState() {
const isConnected = ws && ws.readyState === WebSocket.OPEN;
const idle = Date.now() - lastMessageTimestamp >= IDLE_THRESHOLD_MS;
setLoadingIndicator(isConnected && idle);
}
function connectWS() { function connectWS() {
ws = new WebSocket("ws://" + location.host + "/ws"); ws = new WebSocket("ws://" + location.host + "/ws");
ws.onopen = () => { ws.onopen = () => {
console.log("WebSocket connesso"); console.log("WebSocket connesso");
lastMessageTimestamp = Date.now();
setLoadingIndicator(false);
}; };
ws.onclose = () => { ws.onclose = () => {
console.log("WebSocket disconnesso, retry..."); console.log("WebSocket disconnesso, retry...");
setLoadingIndicator(false);
setTimeout(connectWS, 5000); setTimeout(connectWS, 5000);
}; };
@@ -22,6 +43,9 @@ function connectWS() {
return; return;
} }
lastMessageTimestamp = Date.now();
setLoadingIndicator(false);
document.getElementById("datavalid").textContent = data.datavalid ?? "-"; document.getElementById("datavalid").textContent = data.datavalid ?? "-";
document.getElementById("timestamp").textContent = data.timestamp ?? "-"; document.getElementById("timestamp").textContent = data.timestamp ?? "-";
document.getElementById("volts_gen").textContent = data.volts_gen ?? "-"; document.getElementById("volts_gen").textContent = data.volts_gen ?? "-";
@@ -63,4 +87,39 @@ function stop() {
fetch("/stop"); fetch("/stop");
} }
function uploadLittleFS() {
const fileInput = document.getElementById("littlefsFile");
const status = document.getElementById("uploadStatus");
if (!fileInput || fileInput.files.length === 0) {
if (status) status.textContent = "Select a file first.";
return;
}
const file = fileInput.files[0];
const formData = new FormData();
formData.append("file", file, file.name);
if (status) status.textContent = "Uploading...";
fetch("/upload", {
method: "POST",
body: formData,
})
.then((resp) => {
if (!resp.ok) {
throw new Error("Upload failed: " + resp.status + " " + resp.statusText);
}
return resp.text();
})
.then(() => {
if (status) status.textContent = "Uploaded: " + file.name;
fileInput.value = "";
})
.catch((err) => {
if (status) status.textContent = err.message;
});
}
setInterval(updateLoadingState, 200);
connectWS(); connectWS();

View File

@@ -1,7 +1,46 @@
:root {
--primary-dark: #0a1929;
--primary-blue: #0144a8;
--accent-blue: #1e88e5;
--light-bg: #f5f7fa;
--border-color: #d0d6dd;
--text-dark: #1a1a1a;
--text-muted: #666666;
}
body { body {
font-family: Arial; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
text-align: center; margin: 0;
margin-top: 40px; padding: 0;
background-color: var(--light-bg);
color: var(--text-dark);
}
.page-header {
background: linear-gradient(135deg, var(--primary-dark) 0%, #1a3a52 100%);
color: white;
padding: 30px 20px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
margin-bottom: 30px;
}
.header-content {
max-width: 900px;
margin: 0 auto;
display: flex;
align-items: center;
gap: 20px;
}
.logo {
height: 50px;
width: auto;
}
.page-header h1 {
margin: 0;
font-size: 28px;
font-weight: 600;
} }
table { table {
@@ -9,21 +48,136 @@ table {
border-collapse: collapse; border-collapse: collapse;
width: 100%; width: 100%;
max-width: 900px; max-width: 900px;
background: white;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);
border-radius: 6px;
overflow: hidden;
} }
th, td { th, td {
border: 1px solid #ccc; border: 1px solid var(--border-color);
padding: 10px; padding: 12px;
font-size: 16px; font-size: 14px;
text-align: left; text-align: center;
} }
th { th {
background-color: #f4f4f4; background-color: var(--primary-blue);
color: white;
font-weight: 600;
}
tr:hover {
background-color: #f9fbfc;
} }
button { button {
margin: 10px; margin: 10px;
padding: 10px 20px; padding: 10px 20px;
font-size: 16px; font-size: 16px;
background-color: var(--primary-blue);
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
transition: background-color 0.2s;
}
button:hover {
background-color: var(--accent-blue);
}
.upload-section {
margin: 30px auto 20px;
max-width: 900px;
text-align: left;
padding: 20px;
border: 1px solid var(--border-color);
border-radius: 6px;
background: white;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);
}
.upload-section h3 {
margin-top: 0;
margin-bottom: 8px;
color: var(--primary-blue);
font-size: 16px;
}
.upload-section p {
margin: 8px 0;
color: var(--text-muted);
font-size: 14px;
}
.upload-section input[type="file"] {
margin-top: 8px;
margin-bottom: 12px;
}
.upload-status {
margin-top: 10px;
font-size: 14px;
color: var(--text-muted);
}
.loading-indicator {
display: flex;
align-items: center;
justify-content: center;
gap: 8px;
margin: 0;
padding: 16px 20px;
font-size: 20px;
color: var(--primary-blue);
border-bottom: 1px solid var(--border-color);
background: white;
width: 100%;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);
}
.loading-indicator.hidden {
display: none;
}
.spinner {
width: 16px;
height: 16px;
border: 2px solid transparent;
border-top-color: var(--primary-blue);
border-radius: 50%;
animation: spin 0.8s linear infinite;
}
@keyframes spin {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
/* Data section */
div[style*="max-width: 900px"] {
background: white;
padding: 20px;
border-radius: 6px;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);
margin-bottom: 20px;
}
div[style*="max-width: 900px"] p {
margin: 8px 0;
font-size: 14px;
}
div[style*="max-width: 900px"] strong {
color: var(--primary-blue);
}
span {
color: var(--text-dark);
}
} }

View File

@@ -1,6 +0,0 @@
# Name, Type, SubType, Offset, Size, Flags
nvs, data, nvs, 0x9000, 0x5000,
otadata, data, ota, 0xe000, 0x2000,
app0, app, ota_0, 0x10000, 0x700000,
app1, app, ota_1, 0x710000,0x700000,
spiffs, data, spiffs, 0xE10000,0x1F0000,
1 # Name Type SubType Offset Size Flags
2 nvs data nvs 0x9000 0x5000
3 otadata data ota 0xe000 0x2000
4 app0 app ota_0 0x10000 0x700000
5 app1 app ota_1 0x710000 0x700000
6 spiffs data spiffs 0xE10000 0x1F0000

View File

@@ -21,13 +21,13 @@ lib_deps =
me-no-dev/AsyncTCP@^3.3.2 me-no-dev/AsyncTCP@^3.3.2
me-no-dev/ESPAsyncWebServer@^3.6.0 me-no-dev/ESPAsyncWebServer@^3.6.0
upload_protocol = esptool upload_protocol = esptool
upload_port = COM4 upload_port = COM8
upload_speed = 921600 upload_speed = 921600
monitor_port = COM4 monitor_port = COM4
monitor_speed = 921600 monitor_speed = 921600
build_type = release build_type = release
build_flags = build_flags =
-DCORE_DEBUG_LEVEL=5 -DCORE_DEBUG_LEVEL=1
-DARDUINO_USB_CDC_ON_BOOT=0 -DARDUINO_USB_CDC_ON_BOOT=0
-DARDUINO_USB_MODE=0 -DARDUINO_USB_MODE=0
-DCONFIG_FREERTOS_GENERATE_RUN_TIME_STATS=1 -DCONFIG_FREERTOS_GENERATE_RUN_TIME_STATS=1
@@ -59,7 +59,7 @@ build_flags =
-O0 -O0
-g3 -g3
-ggdb3 -ggdb3
-DCORE_DEBUG_LEVEL=5 -DCORE_DEBUG_LEVEL=3
-DARDUINO_USB_CDC_ON_BOOT=0 -DARDUINO_USB_CDC_ON_BOOT=0
-DARDUINO_USB_MODE=0 -DARDUINO_USB_MODE=0
-DCONFIG_FREERTOS_GENERATE_RUN_TIME_STATS=1 -DCONFIG_FREERTOS_GENERATE_RUN_TIME_STATS=1

View File

@@ -1,7 +1,26 @@
#include "datasave.h" #include "datasave.h"
#include <math.h> #include <math.h>
static const size_t min_free = 1024 * 1024; // minimum free space in SPIFFS to allow saving history (1MB) static const size_t min_free = 1024 * 1024; // minimum free space in LittleFS to allow saving history (1MB)
LITTLEFSGuard::LITTLEFSGuard()
{
if (!LittleFS.begin(true, "/littlefs", 10, "littlefs"))
{
LOG_ERROR("Failed to mount LittleFS");
}
else
{
LOG_INFO("LittleFS mounted successfully");
LOG_INFO("LittleFS Free KBytes:", (LittleFS.totalBytes() - LittleFS.usedBytes()) /1024);
}
}
LITTLEFSGuard::~LITTLEFSGuard()
{
LittleFS.end();
LOG_INFO("LittleFS unmounted successfully");
}
void ignitionBoxStatusAverage::filter(int32_t &old, const int32_t value, const uint32_t k) void ignitionBoxStatusAverage::filter(int32_t &old, const int32_t value, const uint32_t k)
{ {
@@ -42,18 +61,18 @@ void ignitionBoxStatusAverage::update(const ignitionBoxStatus &new_status)
filter(m_last.coils12.peak_p_out, new_status.coils12.peak_p_out, m_max_count); // incremental average calculation filter(m_last.coils12.peak_p_out, new_status.coils12.peak_p_out, m_max_count); // incremental average calculation
filter(m_last.coils12.peak_n_out, new_status.coils12.peak_n_out, m_max_count); // incremental average calculation filter(m_last.coils12.peak_n_out, new_status.coils12.peak_n_out, m_max_count); // incremental average calculation
m_last.coils34.n_events = new_status.coils34.n_events; // sum events instead of averaging m_last.coils34.n_events = new_status.coils34.n_events; // sum events instead of averaging
m_last.coils34.n_missed_firing = new_status.coils34.n_missed_firing; // sum missed firings instead of averaging m_last.coils34.n_missed_firing = new_status.coils34.n_missed_firing; // sum missed firings instead of averaging
m_last.coils34.spark_status = new_status.coils34.spark_status; // take latest spark status m_last.coils34.spark_status = new_status.coils34.spark_status; // take latest spark status
m_last.coils34.sstart_status = new_status.coils34.sstart_status; // take latest soft start status m_last.coils34.sstart_status = new_status.coils34.sstart_status; // take latest soft start status
filter(m_last.coils34.spark_delay, new_status.coils34.spark_delay, m_max_count); // incremental average calculation filter(m_last.coils34.spark_delay, new_status.coils34.spark_delay, m_max_count); // incremental average calculation
filter(m_last.coils34.peak_p_in, new_status.coils34.peak_p_in, m_max_count); // incremental average calculation filter(m_last.coils34.peak_p_in, new_status.coils34.peak_p_in, m_max_count); // incremental average calculation
filter(m_last.coils34.peak_n_in, new_status.coils34.peak_n_in, m_max_count); // incremental average calculation filter(m_last.coils34.peak_n_in, new_status.coils34.peak_n_in, m_max_count); // incremental average calculation
filter(m_last.coils34.peak_p_out, new_status.coils34.peak_p_out, m_max_count); // incremental average calculation filter(m_last.coils34.peak_p_out, new_status.coils34.peak_p_out, m_max_count); // incremental average calculation
filter(m_last.coils34.peak_n_out, new_status.coils34.peak_n_out, m_max_count); // incremental average calculation filter(m_last.coils34.peak_n_out, new_status.coils34.peak_n_out, m_max_count); // incremental average calculation
filter(m_last.eng_rpm, new_status.eng_rpm, m_max_count); // incremental average calculation // incremental average calculation filter(m_last.eng_rpm, new_status.eng_rpm, m_max_count); // incremental average calculation // incremental average calculation
filter(m_last.adc_read_time, m_last.adc_read_time, m_max_count); // incremental average calculation filter(m_last.adc_read_time, m_last.adc_read_time, m_max_count); // incremental average calculation
m_last.n_queue_errors = new_status.n_queue_errors; // take last of queue errors since it's a cumulative count of errors in the queue, not an average value m_last.n_queue_errors = new_status.n_queue_errors; // take last of queue errors since it's a cumulative count of errors in the queue, not an average value
if (m_count >= m_max_count) if (m_count >= m_max_count)
{ {
@@ -126,7 +145,8 @@ void save_history(const PSRAMVector<ignitionBoxStatus> &history, const std::file
// Initialize SPIFFS // Initialize SPIFFS
if (!SAVE_HISTORY_TO_LITTLEFS) if (!SAVE_HISTORY_TO_LITTLEFS)
return; return;
// auto spiffs_guard = LITTLEFSGuard(); // use RAII guard to ensure SPIFFS is properly mounted and unmounted
auto littlefs_guard = LITTLEFSGuard(); // use RAII guard to ensure LittleFS is properly mounted and unmounted
if (LittleFS.totalBytes() - LittleFS.usedBytes() < min_free) // check if at least 1MB is free for saving history if (LittleFS.totalBytes() - LittleFS.usedBytes() < min_free) // check if at least 1MB is free for saving history
{ {
@@ -142,7 +162,7 @@ void save_history(const PSRAMVector<ignitionBoxStatus> &history, const std::file
if (first_save && LittleFS.exists(file_path.c_str())) if (first_save && LittleFS.exists(file_path.c_str()))
{ {
first_save = false; first_save = false;
save_flags |= std::ios::trunc; // overwrite existing file save_flags |= std::ios::trunc; // overwrite existing file
LittleFS.remove(file_path.c_str()); // ensure file is removed before saving to avoid issues with appending to existing file in SPIFFS LittleFS.remove(file_path.c_str()); // ensure file is removed before saving to avoid issues with appending to existing file in SPIFFS
LOG_INFO("Saving history to LittleFS, new file:", file_path.c_str()); LOG_INFO("Saving history to LittleFS, new file:", file_path.c_str());
} }

View File

@@ -4,19 +4,19 @@
// System Includes // System Includes
#include <Arduino.h> #include <Arduino.h>
#include <DebugLog.h> #include <DebugLog.h>
#include <LittleFS.h>
#include <string> #include <string>
#include <fstream> #include <fstream>
#include <filesystem>
#include <ArduinoJson.h> #include <ArduinoJson.h>
#include <filesystem>
#include <LittleFS.h>
// Project Includes // Project Includes
#include "isr.h" #include "isr.h"
#include "psvector.h" #include "psvector.h"
const uint32_t max_history = 256; const uint32_t max_history = 256;
const bool SAVE_HISTORY_TO_LITTLEFS = false; // Set to true to enable saving history to SPIFFS, false to disable const bool SAVE_HISTORY_TO_LITTLEFS = false; // Set to true to enable saving history to LittleFS, false to disable
static bool first_save = true; // flag to indicate if this is the first save (to write header) static bool first_save = true; // flag to indicate if this is the first save (to write header)
struct dataSaveParams struct dataSaveParams
{ {
@@ -27,20 +27,8 @@ struct dataSaveParams
class LITTLEFSGuard class LITTLEFSGuard
{ {
public: public:
LITTLEFSGuard() LITTLEFSGuard();
{ ~LITTLEFSGuard();
if (!LittleFS.begin(true))
{
LOG_ERROR("Failed to mount LittleFS");
}
LOG_INFO("SPIFFS mounted successfully");
}
~LITTLEFSGuard()
{
LittleFS.end();
LOG_INFO("LittleFS unmounted successfully");
}
}; };
class ignitionBoxStatusAverage class ignitionBoxStatusAverage
@@ -53,7 +41,8 @@ private:
public: public:
ignitionBoxStatusAverage() = default; ignitionBoxStatusAverage() = default;
ignitionBoxStatusAverage(const uint32_t max_count) : m_max_count(max_count) { ignitionBoxStatusAverage(const uint32_t max_count) : m_max_count(max_count)
{
m_data_valid = false; m_data_valid = false;
m_count = 0; m_count = 0;
} }

View File

@@ -1,4 +1,4 @@
#define DEBUGLOG_DEFAULT_LOG_LEVEL_INFO #define DEBUGLOG_DEFAULT_LOG_LEVEL_DEBUG
// Arduino Libraries // Arduino Libraries
#include <Arduino.h> #include <Arduino.h>
@@ -16,6 +16,9 @@
#include <datasave.h> #include <datasave.h>
#include <ui.h> #include <ui.h>
static File uploadFile;
static bool uploadFailed = false;
// FreeRTOS directives // FreeRTOS directives
#include "freertos/FreeRTOS.h" #include "freertos/FreeRTOS.h"
#include "freertos/task.h" #include "freertos/task.h"
@@ -61,11 +64,6 @@ void setup()
LOG_DEBUG("ESP32 Heap:", ESP.getHeapSize()); LOG_DEBUG("ESP32 Heap:", ESP.getHeapSize());
LOG_DEBUG("ESP32 Sketch:", ESP.getFreeSketchSpace()); LOG_DEBUG("ESP32 Sketch:", ESP.getFreeSketchSpace());
// Initialize Interrupt pins on PICKUP detectors
initTriggerPinsInputs();
// Initialize Interrupt pins on SPARK detectors
initSparkPinInputs();
// Init Wifi station // Init Wifi station
LOG_INFO("Initializing WiFi..."); LOG_INFO("Initializing WiFi...");
WiFi.mode(WIFI_AP); WiFi.mode(WIFI_AP);
@@ -87,6 +85,11 @@ void setup()
vTaskDelay(pdMS_TO_TICKS(5000)); vTaskDelay(pdMS_TO_TICKS(5000));
esp_restart(); esp_restart();
} }
// Initialize Interrupt pins on PICKUP detectors
initTriggerPinsInputs();
// Initialize Interrupt pins on SPARK detectors
initSparkPinInputs();
} }
void loop() void loop()
@@ -123,7 +126,15 @@ void loop()
.spark_pin_34 = SPARK_PIN_A34}, .spark_pin_34 = SPARK_PIN_A34},
.rt_resets = rtTaskResets{.rst_io_12p = RST_EXT_A12P, .rst_io_12n = RST_EXT_A12N, .rst_io_34p = RST_EXT_A34P, .rst_io_34n = RST_EXT_A34N}}; .rt_resets = rtTaskResets{.rst_io_12p = RST_EXT_A12P, .rst_io_12n = RST_EXT_A12N, .rst_io_34p = RST_EXT_A34P, .rst_io_34n = RST_EXT_A34N}};
LOG_DEBUG("Task Variables OK"); if (!rt_taskA_queue || !rt_taskB_queue)
{
LOG_ERROR("Unable To Create task queues");
LOG_ERROR("5 seconds to restart...");
vTaskDelay(pdMS_TO_TICKS(5000));
esp_restart();
}
else
LOG_DEBUG("Task Variables OK");
#ifdef CH_B_ENABLE #ifdef CH_B_ENABLE
QueueHandle_t rt_taskB_queue = xQueueCreate(max_queue, sizeof(ignitionBoxStatus)); QueueHandle_t rt_taskB_queue = xQueueCreate(max_queue, sizeof(ignitionBoxStatus));
@@ -190,6 +201,7 @@ void loop()
RT_TASK_PRIORITY, RT_TASK_PRIORITY,
&trigA_TaskHandle, &trigA_TaskHandle,
CORE_0); CORE_0);
delay(100);
// Ignition B on Core 1 // Ignition B on Core 1
auto ignB_task_success = pdPASS; auto ignB_task_success = pdPASS;
@@ -202,11 +214,12 @@ void loop()
RT_TASK_PRIORITY, // priorità leggermente più alta RT_TASK_PRIORITY, // priorità leggermente più alta
&trigB_TaskHandle, &trigB_TaskHandle,
CORE_1); CORE_1);
delay(100);
#endif #endif
if ((ignA_task_success && ignB_task_success) != pdPASS) if (ignA_task_success != pdPASS || ignB_task_success != pdPASS)
{ {
LOG_ERROR("Una ble to initialize ISR task"); LOG_ERROR("Unable to initialize ISR task");
LOG_ERROR("5 seconds to restart..."); LOG_ERROR("5 seconds to restart...");
vTaskDelay(pdMS_TO_TICKS(5000)); vTaskDelay(pdMS_TO_TICKS(5000));
esp_restart(); esp_restart();
@@ -220,6 +233,7 @@ void loop()
uint32_t wait_count = 0; uint32_t wait_count = 0;
ignitionBoxStatus ign_info; ignitionBoxStatus ign_info;
ignitionBoxStatusAverage ign_info_avg(filter_k); ignitionBoxStatusAverage ign_info_avg(filter_k);
LITTLEFSGuard fsGuard;
// Initialize Web page // Initialize Web page
AsyncWebServer server(80); AsyncWebServer server(80);
@@ -227,6 +241,67 @@ void loop()
ws.onEvent(onWsEvent); ws.onEvent(onWsEvent);
server.addHandler(&ws); server.addHandler(&ws);
server.serveStatic("/", LittleFS, "/").setDefaultFile("index.html"); server.serveStatic("/", LittleFS, "/").setDefaultFile("index.html");
server.on("/upload", HTTP_POST,
[](AsyncWebServerRequest *request) {
if (uploadFailed)
{
request->send(500, "text/plain", "Upload failed");
}
else
{
request->send(200, "text/plain", "Upload successful");
}
},
[](AsyncWebServerRequest *request, const String &filename, size_t index, uint8_t *data, size_t len, bool final) {
if (index == 0)
{
uploadFailed = false;
String safeName = filename;
int slashIndex = safeName.lastIndexOf('/');
if (slashIndex >= 0)
{
safeName = safeName.substring(slashIndex + 1);
}
if (safeName.length() == 0)
{
uploadFailed = true;
return;
}
String filePath = "/" + safeName;
if (LittleFS.exists(filePath))
{
LittleFS.remove(filePath);
}
uploadFile = LittleFS.open(filePath, FILE_WRITE);
if (!uploadFile)
{
uploadFailed = true;
LOG_ERROR("Failed to open upload file:", filePath);
return;
}
}
if (!uploadFailed && uploadFile)
{
if (uploadFile.write(data, len) != len)
{
uploadFailed = true;
}
}
if (final && uploadFile)
{
uploadFile.close();
if (!uploadFailed)
{
LOG_INFO("Uploaded file to LittleFS:", filename);
}
}
});
server.begin(); server.begin();
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request) server.on("/", HTTP_GET, [](AsyncWebServerRequest *request)
@@ -253,12 +328,12 @@ void loop()
auto &hist = *active_history; auto &hist = *active_history;
hist[counter++ % active_history->size()] = ign_info; hist[counter++ % active_history->size()] = ign_info;
ign_info_avg.update(ign_info); // update moving average with latest ignition status ign_info_avg.update(ign_info); // update moving average with latest ignition status
Serial.print("Data Received: " + String(counter) + "/" + String(hist.size()) + '\r'); Serial.print("\033[2K Data Received: " + String(counter) + "/" + String(hist.size()) + '\r');
if (ws.count() > 0 && counter % 10 == 0) // send data every 10 samples if (ws.count() > 0 && counter % filter_k == 0) // send data every 10 samples
{ {
Serial.println(); Serial.println();
LOG_INFO("Sending average ignition status to websocket clients..."); LOG_DEBUG("Sending average ignition status to websocket clients...");
auto msg = ign_info_avg.toJson().as<String>(); auto msg = ign_info_avg.toJson().as<String>();
ws.textAll(msg); ws.textAll(msg);
} }

View File

@@ -110,7 +110,6 @@ void rtIgnitionTask(void *pvParameters)
#ifdef DEBUG #ifdef DEBUG
Serial.print("\033[2J"); // clear screen Serial.print("\033[2J"); // clear screen
Serial.print("\033[H"); // cursor home Serial.print("\033[H"); // cursor home
LOG_INFO("Iteration [", it++, "]");
if (!names.contains(pickup_flag)) if (!names.contains(pickup_flag))
{ {
@@ -267,9 +266,11 @@ void rtIgnitionTask(void *pvParameters)
// send essage to main loop with ignition info, by copy so local static variable is ok // send essage to main loop with ignition info, by copy so local static variable is ok
if (rt_queue) if (rt_queue)
{
ign_box_sts.timestamp = esp_timer_get_time(); // update data timestamp ign_box_sts.timestamp = esp_timer_get_time(); // update data timestamp
if (xQueueSendToBack(rt_queue, (void *)&ign_box_sts, 0) != pdPASS) if (xQueueSendToBack(rt_queue, (void *)&ign_box_sts, 0) != pdPASS)
ign_box_sts.n_queue_errors = ++n_errors; ign_box_sts.n_queue_errors = ++n_errors;
}
} }
} }
// Delete the timeout timer // Delete the timeout timer

View File

View File