Neubau ePaper (2-DIN) Display TrueNAS mal mit Anleitung xD

Bohnenhans

Captain
Registriert
Okt. 2022
Beiträge
3.100
<Update wegen Probleme des USBSerial Treibers in Linux oder vermutlich des Chips auf dem MC des ESP32 (WROOM DO1T DEVKIT V1) musste ich das umbauen auf den ESP32-S2 - der tut unter Win UND Linux>

Unter Win funktionierte der ESP DO1T WROOM USB/Serial perfekt..... - unter Linux nur halb..... und halb ist ja super schwer zu finden weil man keine echten Debugger hat.

Das hat ne Weile suchen umbauen und überlegen gekostet bis das eingegrenzt hatte :D
Zum Glück habe ich einige verschiedene Microcontroller fast immer da und sogar ein zweites auf ungenutztes 4,2" ePaper Display aus genau der Serie - das war echt praktisch.

Aber dank der Bastelkiste hab ich das jetzt auf den ESP32-S2 umgebaut - der Sourcecode ist zu 99,999% identisch bis eigentlich auf eine minimal andere PIN Belegung

Der tut jetzt (beim 2" ePaper in der kleinen Varianten hab ich zufällig einen S2 genommen, das tat auf Anhieb - das werde ich dann mal hier abändern)>


==================================================================


Da ich für meinen Backup Backup Server günstig ein altes Mainboard mit ECC Ram und Xeon gekauft habe und dafür ein neues ePaper Display + LED Anzeige für ZFS Status etc mache dachte ich ich mach da mal ne Schritt für Schritt Anleitung und evtl sieht ja jemand was das man besser machen kann.

Basis ist wie beim kleinen Display ein ESP32 (S2) der am TrueNAS dann über ein USB Kabel angeschlossen wird (hier nehm ich wieder einen der internen USB Ports des Boards)

Angesteuert wird das dann wieder über BASH Scripte auf dem TrueNAS. die muss ich etwas anpssen damit die mein kleines und grosses Display unterstützen das kommt also noch.

Schritt 1 war jetzt der Rahmen für das Display - ich habe in dem neuen Server 2 DIN 5,25 Platz und da in meiner Bastelkiste schon ewig ein 4,2" rumliegt kommt das rein - das passt fast genau.

Ich nutze aktuell Adobe Fusion 360 siehe auch Anhang des 3D Modells - finde das schön einfach für Gelegenheitsnutzer.

Das lag so 3-4 Jahre ohne Strom in der Bastelkiste und zeigt immer noch das was es anzeigte als es da reinwanderte xD

Die Clips halten das epaper Display - das funktioniert relativ ganz gut, weil sich die Clips schnell verkanten wenn man später von aussen dagegendrückt.

Als LED für Statusanzeigen werde ich eine kombinierte Rot & Grün LED nehmen.

Als 2. werde ich wohl das Display elektrisch an den ESP32 anbinden - das ja immer etwas nervig weil die Bezeichnungen auf den Displays anders sind als am ESP32 MOSI glaub ist DIN etc ..... xD da brauch ich immer ne Weile bis man die wieder richtig zugeordnet hat - glaub Löten und "Dupont" Crimpen braucht da zeitlich nur 25%... xD
 

Anhänge

  • epaper_doppeldin.gif
    epaper_doppeldin.gif
    111,2 KB · Aufrufe: 179
  • epaper42.gif
    epaper42.gif
    258 KB · Aufrufe: 157
  • DoppelDIN_EPaperBig.zip
    DoppelDIN_EPaperBig.zip
    489,2 KB · Aufrufe: 86
Zuletzt bearbeitet:
  • Gefällt mir
Reaktionen: XShocker22, Piktogramm und Banned
Als 2.
werde ich wohl das Display elektrisch an den ESP32 anbinden - das ja immer etwas nervig weil die Bezeichnungen auf den Displays anders sind als am ESP32 MOSI oder MISO(?) glaub ist DIN etc ..... xD

Das echt immer mit Arbeit verbunden das wieder rauszukramen, zumal ja die PINS bei den ESP32-xx Varianten auch immer anders sind,


In meiner Microcontroller Bastelkiste habe ich noch einen ESP32 (WROOM DO1T DEVKIT V1) gefunden, bei dem ich bereits die Stifleiste falsch herum angelötet habe - was ich immer dann mache, wenn ich den ESP32 irgendwo rankleben will - denn die Rückseite ist dann flach

Ausserdem ist da einer der Buttons abgefallen (der Enable Button)- wohl zu oft gedrückt xD so dass der für so ein Projekt ideal ist, wo man eh nie diese Buttons braucht.

Die PIN Belegung muss man sich immer raussuchen - die für das Modell ist die hier

Die Displaykabel kann man direkt an die Pins des ESPs anschliessen, da braucht es keine Widerstände oder sowas - die Displays laufen auch mit 3,3V also perfekt für den ESP.
 

Anhänge

  • esp32WROOM_PIN.gif
    esp32WROOM_PIN.gif
    103,8 KB · Aufrufe: 114
  • display_kabel.jpg
    display_kabel.jpg
    164,3 KB · Aufrufe: 120
  • esp32_WROOM.jpg
    esp32_WROOM.jpg
    125,2 KB · Aufrufe: 103
Zuletzt bearbeitet:
PIN-Belegung ist

Code:
Display        ESP32
VCC   <=>  3.3V   3V3 rechts unten
GND  <=> GND  irgendeiner ich hab den über 3V3 genommen
DIN   <=>  MOSI   ist bei mir PIN36  =  GPIO23
CLK   <=>  SCK      ist bei mir PIN35  = GPIO18
CS     <=>  SS        ist bei mir PIN34  = GPIO5
DC    <=>  MISO   ist bei mir PIN38  = GPIO19
RST   <=> frei waehlbar ich habe hier PIN25 = GPIO16 genommen (*)
BUSY <=> frei waehlbar ich habe hier PIN27 = GPIO17 genommen (*)

(*)  manche Pins verhindern aber ESP Start muss man testen
     RX2 und TX2 gehen aber meistens und wenn man keine zweite serielle Schnittstelle braucht
     sind die frei.

Das war es dann auch schon mit der Verkabelung des Displays.

Ich nutze gerne Stecker nebeneinander dann kann man die mit Heissklebe oder so einfach aneinander fixieren - diese "Dupont" Stecker sind ja manchmal wenn man die öfter ein aussteckt ziehmlich locker

Photos gehen prinzipiell - aber je näher an "LineArt" desto besser falls man Bilder anzeigen will - ich mach das meist im Komplett Aus Zustand und beim Starten etc.


Die "Testsoftware" fürs Display uppe ich mal morgen und wo man was eintragen muss
 

Anhänge

  • epaper_1st_run.jpg
    epaper_1st_run.jpg
    113,2 KB · Aufrufe: 126
  • start_truenas.png
    start_truenas.png
    389,8 KB · Aufrufe: 113
  • truenas_off.png
    truenas_off.png
    493,6 KB · Aufrufe: 119
  • mona_epaper.png
    mona_epaper.png
    189 KB · Aufrufe: 93
Zuletzt bearbeitet:
  • Gefällt mir
Reaktionen: XShocker22
Ich nutze Visual Studio Code + Platform.IO - gibt es für Windows aber auch für Linux und MacOS
Beides ist kostenlos und ich finde eine wirklich richtig gute Entwicklungsumgebung (inkl Code Completion etc)

Visual Studio Code: https://code.visualstudio.com/
Platform.IO https://platformio.org/ (lässt sich als AddOn aus Visual Studio Code einfach installieren)


Als Framework natürlich Arduino weil es da einfach viele fertigen Libraries gibt hehe und wer will schon ein rumpeliges Rad neu erfinden wenn andere schon ein perfekt rundes gemacht haben. :D

Für ePaper nutze ich GXEPD2 von Jean-Marc Zingg - installiert man die libaries über Platform.IO werden die abhängigen mitinstalliert auch Updateverwaltung ist dann richtig einfach.


Um das passende Display einzustellen nutze ich eine einfache Methode ich kopiere die Datei "GxEPD2_display_selection.h" aus irgendeinem Pfad der mitinstallierten Beispielprogs von GXEPD2 Siehe Bild2 in den Projektordner.

In der Datei muss man sich dann halt das passende Display einstellen - das Display, das ich habe ist ein Schwarz-Weiss-Rot ich nutze es aber im Schwarz / Weiss Modus weil es dann EXTREM viel schneller ist - und verzichte auf Rot.

Siehe Bild 3 - Unter DC==MISO muss man den (siehe Post 2) GPIOPIN eintragen, unter RST den in Post #3 gewählten Reset PIN, genauso unter BUSY - die GPIO Nummerierung ist hier entscheidend.

Bilder erstell ich mit https://javl.github.io/image2cpp/

und die wandern dann in die "myImages.h"


Das Testprogramm für die erste Ausgabe ist bei mir dann das hier

Code:
#include <Arduino.h>
#define HASDISPLAY

#ifdef HASDISPLAY
    #include <SPI.h>
    #include <GxEPD2_BW.h>
    #include "GxEPD2_display_selection.h"
    #include <Fonts/FreeMonoBold9pt7b.h>
    #include <Fonts/FreeMonoBold12pt7b.h>
#endif

#include <WiFi.h>

#ifdef HASDISPLAY
    #include "myImages.h"
#endif

const uint32_t mySERIALBAUDRATE = 115200;
const uint8_t myCPUMHZ = 80;

#ifdef HASDISPLAY
    const uint8_t myDisplay_Rotation = 0;
#endif

//===============================================================================================

void loop();
void setup();
#ifdef HASDISPLAY
    void demoDisplayText();
    void demoDisplayImage();
#endif

//===============================================================================================
#ifdef HASDISPLAY
void demoDisplayImage()
{
    display.setRotation(myDisplay_Rotation);
    display.setFullWindow();
    display.clearScreen();
    display.fillScreen(GxEPD_WHITE);
    do
    {
        display.drawBitmap(0, 0, &epd_bitmap_trueNas_Start_Unicorn[0], display.width(), display.height(), GxEPD_BLACK);
    } while (display.nextPage());  
}

void demoDisplayText()
{
    String myDemoText = "Display tutet :)";
    int16_t myX, myY;
    uint16_t myWidth, myHeight;

    display.setRotation(myDisplay_Rotation);
    display.setFullWindow();
    display.clearScreen();
    display.fillScreen(GxEPD_WHITE);
    display.setFont(&FreeMonoBold12pt7b);
    display.getTextBounds(myDemoText, 10, (int) (display.width()/2), &myX, &myY, &myWidth, &myHeight);
   
    display.setTextColor(GxEPD_BLACK);
    do
    {
        display.setCursor(display.width()/2 - myWidth/2, display.height()/2 - myHeight/2);
        display.print(myDemoText);     
    } while (display.nextPage());  
}
#endif

void setup()
{
  if (myCPUMHZ != 0)
     setCpuFrequencyMhz(myCPUMHZ);
  Serial.begin(mySERIALBAUDRATE);
  // Default WiFi und Bluetooth aus 
  WiFi.disconnect(true);
  WiFi.mode(WIFI_OFF);  
  btStop();
  #ifdef HASDISPLAY
    display.init(0);
    demoDisplayText();
    delay(2000);
    demoDisplayImage();
  #endif
}

void loop()
{
  delay(1000);
}

die "myImages.h"

Code:
#ifndef _MYIMAGES_H

#define _MYIMAGES_H

#include <Arduino.h>

// 'trueNas_Start_Unicorn', 400x300px
const unsigned char epd_bitmap_trueNas_Start_Unicorn [] PROGMEM = {
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x80, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x80, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 
    0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x01, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x03, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0xc0, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0xc0, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 
    0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x18, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x39, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x79, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd9, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xcd, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x8f, 0x80, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc7, 0x80, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x83, 
    0x84, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x01, 0x81, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x01, 0x81, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x01, 0x80, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xe0, 0x61, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xf0, 0x60, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x38, 
    0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x03, 0x1c, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x07, 0x0f, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x07, 0x03, 0xe0, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x01, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x71, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x18, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 
    0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x06, 0x08, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x0e, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x01, 0x0c, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0x80, 0x0c, 0x80, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0xe0, 0x0e, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x78, 0x0c, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x1f, 
    0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x18, 0x03, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x18, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x03, 0x20, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x01, 0x80, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x08, 0x01, 0x80, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 
    0x41, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x06, 0x00, 0x01, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x04, 0x0f, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x33, 0xcf, 0x82, 0x00, 0xc2, 0xe0, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0xcd, 0xe0, 0x08, 0xcf, 0xb7, 0x1e, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x1c, 0x7c, 0x00, 0xdc, 0x07, 0xbc, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x38, 0x1f, 0xe0, 0xf8, 0x00, 0x1c, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x18, 0x03, 0xfc, 0xf0, 
    0x80, 0x38, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x18, 0x00, 
    0x1f, 0xb0, 0x20, 0xbb, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xc0, 
    0x18, 0x00, 0x03, 0xe2, 0x08, 0x78, 0x0f, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x01, 0xc0, 0x18, 0x00, 0x03, 0xe0, 0x82, 0x60, 0x01, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0xc0, 0x0c, 0x00, 0x00, 0xc0, 0x23, 0x80, 0x01, 0xc0, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x01, 0xc0, 0x3f, 0x08, 0x01, 0xc9, 0x0b, 0x00, 0x00, 0xe0, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x80, 0x63, 0xc0, 0x01, 0xe0, 0x0e, 0x00, 0x00, 0xe0, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc1, 0xc1, 0xc0, 0x40, 0xc4, 0x9c, 0x00, 
    0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xc1, 0x80, 0xe0, 0x01, 0xe0, 
    0x38, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x80, 0x70, 
    0x00, 0xe2, 0x30, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 
    0x08, 0x70, 0x08, 0xe0, 0xf0, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x01, 0xe7, 0x02, 0x38, 0x20, 0xf0, 0xe0, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x07, 0x86, 0x00, 0x1e, 0x03, 0xf8, 0xe0, 0x00, 0x01, 0xc0, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x07, 0x27, 0x10, 0x0f, 0x9f, 0x7f, 0xc0, 0x00, 0x03, 0x80, 0x80, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x4f, 0x00, 0x83, 0xf8, 0x67, 0x80, 0x00, 0x03, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x4f, 0x02, 0x00, 0x00, 0xe1, 0x80, 0x08, 
    0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x39, 0x2f, 0x10, 0x00, 0x00, 0xc3, 
    0x00, 0x7f, 0x0e, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x1f, 0x00, 0x20, 
    0x01, 0xc7, 0x01, 0xc7, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6c, 0x80, 0x00, 
    0xf0, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x72, 0xd9, 
    0x82, 0x04, 0x93, 0x86, 0x01, 0x87, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xf7, 
    0xf8, 0x00, 0xf0, 0x00, 0x40, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 
    0xec, 0xf1, 0x80, 0x40, 0x07, 0x0e, 0x07, 0x06, 0x70, 0x40, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x0e, 0x00, 0x7f, 0xc3, 0xb0, 0x01, 0xc0, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x07, 0x83, 0x81, 0xc8, 0x00, 0x0e, 0x0c, 0x07, 0x0e, 0x70, 0x04, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x3c, 0x00, 0x03, 0x7e, 0x30, 0x00, 0xe0, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0xe0, 0x84, 0x3c, 0x0c, 0x0e, 0x38, 0xf9, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x30, 0x44, 0x80, 0x00, 0x38, 0x00, 0xe0, 0x3e, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x78, 0x01, 0x70, 0x00, 0x0c, 0x31, 0x9c, 0x10, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x61, 0x10, 0x08, 0x01, 0x38, 0x01, 0xf0, 0xe6, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x1e, 0x27, 0xc0, 0x00, 0x1c, 0xe7, 
    0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe4, 0x02, 0x42, 0x48, 0x30, 0x01, 0xf3, 0x96, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xc0, 0x00, 0x00, 0x07, 0xfe, 0x00, 0x00, 
    0x39, 0x8c, 0x0f, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xc0, 0x88, 0x10, 0x3f, 0xf9, 0x01, 
    0xfe, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x40, 
    0x00, 0x00, 0x3f, 0x19, 0x47, 0xff, 0x06, 0x00, 0x00, 0x00, 0x00, 0x01, 0xc2, 0x20, 0x85, 0xf4, 
    0xcf, 0xff, 0xf8, 0x4e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 
    0x3c, 0x00, 0x00, 0x00, 0x30, 0x7c, 0x50, 0xe6, 0x07, 0x00, 0x00, 0x00, 0x00, 0x03, 0x80, 0x04, 
    0x23, 0xc0, 0x01, 0xc7, 0x9c, 0x4e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x0c, 
    0x00, 0x00, 0xff, 0x80, 0x00, 0x00, 0x01, 0xdc, 0x12, 0x0e, 0x09, 0x00, 0x00, 0x00, 0x00, 0x01, 
    0x84, 0x90, 0x0e, 0x09, 0x20, 0x03, 0x3c, 0x9c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0xe0, 0x33, 0xc0, 0x01, 0x80, 0xe0, 0x00, 0x00, 0x03, 0x1d, 0x84, 0x9c, 0x09, 0x00, 0x00, 0x00, 
    0x00, 0x02, 0x00, 0x13, 0x5c, 0xa2, 0x40, 0x06, 0x1c, 0x2c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x01, 0xc0, 0xc0, 0x60, 0x04, 0x00, 0x30, 0x00, 0x00, 0x00, 0x0c, 0x24, 0x59, 0xde, 0x00, 
    0x00, 0x00, 0x00, 0x06, 0x01, 0xff, 0xfc, 0x88, 0x98, 0x46, 0x1d, 0x2c, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x07, 0x81, 0x00, 0x30, 0x0c, 0x00, 0x18, 0x00, 0x00, 0x00, 0x0e, 0x23, 0x3b, 
    0xf2, 0x00, 0x00, 0x00, 0x00, 0x06, 0x23, 0x00, 0x0f, 0xc2, 0x24, 0x70, 0x1c, 0x4c, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x03, 0x00, 0x10, 0x18, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x0c, 
    0x88, 0x37, 0xc3, 0x00, 0x00, 0x00, 0x00, 0x06, 0x18, 0x00, 0x01, 0x79, 0x24, 0x60, 0x5e, 0x1c, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x06, 0x00, 0x10, 0x10, 0x00, 0x0e, 0x00, 0x00, 
    0x00, 0x0e, 0x24, 0xef, 0x81, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x10, 0x00, 0x00, 0x3f, 0x0a, 0x00, 
    0x1c, 0x98, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x0c, 0x02, 0x10, 0x40, 0x00, 0x06, 
    0x00, 0x00, 0x00, 0x0f, 0x85, 0xf3, 0x83, 0x80, 0x00, 0x00, 0x00, 0x0e, 0x40, 0x21, 0x00, 0x03, 
    0xfa, 0x00, 0x9c, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x0e, 0x90, 0xc0, 
    0x00, 0x03, 0x00, 0x00, 0x80, 0x0f, 0xff, 0x03, 0x03, 0x80, 0x24, 0x00, 0x00, 0x0c, 0xc0, 0x04, 
    0x10, 0x00, 0x00, 0x00, 0x1f, 0x30, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xc0, 0x08, 0x02, 
    0xb1, 0x80, 0x00, 0x03, 0x00, 0x01, 0xe0, 0x0c, 0x20, 0x0b, 0x13, 0x86, 0x3f, 0xf0, 0x00, 0x0f, 
    0x80, 0x00, 0x02, 0x00, 0x00, 0x00, 0x1c, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x80, 
    0x18, 0x13, 0xa1, 0x80, 0x00, 0x03, 0x00, 0x01, 0xe0, 0x0e, 0x00, 0x87, 0x03, 0xef, 0x9f, 0xff, 
    0x00, 0x0f, 0x80, 0x08, 0x40, 0x80, 0x00, 0x82, 0x1c, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x03, 0x00, 0x18, 0x0f, 0xa3, 0x00, 0x00, 0x01, 0x00, 0x01, 0xe0, 0x0e, 0x12, 0x27, 0x03, 0xe0, 
    0x00, 0x1f, 0xc0, 0x1f, 0x02, 0x00, 0x04, 0x10, 0x84, 0x00, 0x1c, 0xe1, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x18, 0x00, 0x08, 0x0f, 0x63, 0x00, 0x00, 0x01, 0x80, 0x00, 0xe0, 0x0c, 0x00, 0x0e, 
    0x17, 0x00, 0x00, 0x01, 0xf8, 0x1f, 0x00, 0x20, 0x80, 0x00, 0x10, 0x04, 0x1c, 0xc0, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x08, 0x00, 0x46, 0x00, 0x70, 0x01, 0x80, 0x00, 0xc0, 0x0c, 
    0x89, 0x0e, 0x06, 0x00, 0x00, 0x00, 0x7c, 0x1e, 0x00, 0x02, 0x08, 0x42, 0x00, 0x80, 0x39, 0x80, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x08, 0x00, 0x86, 0x01, 0xe8, 0x01, 0x80, 0x00, 
    0xe0, 0x0e, 0x20, 0x4c, 0x2c, 0x00, 0x00, 0x00, 0x1f, 0x1e, 0x00, 0x80, 0x00, 0x00, 0x20, 0x00, 
    0x3b, 0x08, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x0c, 0x01, 0x8c, 0x02, 0x4c, 0x01, 
    0x80, 0x00, 0xe0, 0x0c, 0x04, 0x1c, 0x18, 0x00, 0x00, 0x00, 0x07, 0x9e, 0x24, 0x08, 0x21, 0x08, 
    0x02, 0x10, 0xbf, 0x01, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xc0, 0x00, 0x06, 0x06, 0x0c, 0x00, 
    0x3c, 0x03, 0x00, 0x00, 0xc0, 0x0c, 0x41, 0x3f, 0x60, 0x00, 0x00, 0x00, 0x03, 0xdc, 0x00, 0x00, 
    0x80, 0x00, 0x80, 0x02, 0x3f, 0xf7, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xc0, 0x00, 0x03, 0x18, 
    0x08, 0x04, 0x3c, 0x03, 0x00, 0x01, 0xc0, 0x0c, 0x10, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 
    0x00, 0x80, 0x04, 0x20, 0x08, 0x40, 0x70, 0xfc, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 
    0x01, 0xe0, 0x18, 0x03, 0x7e, 0x03, 0x00, 0x01, 0xc0, 0x1c, 0x84, 0xf0, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x7c, 0x24, 0x08, 0x10, 0x02, 0x00, 0x04, 0x60, 0x01, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 
    0x00, 0x00, 0x00, 0x00, 0x18, 0x03, 0xfc, 0x03, 0x00, 0x01, 0xc0, 0x18, 0x20, 0xc0, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x3c, 0x00, 0x02, 0x00, 0x80, 0x20, 0x00, 0xe1, 0x01, 0x80, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x18, 0x01, 0xf8, 0x03, 0x00, 0x01, 0xc0, 0x1f, 0x0b, 0x80, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x40, 0x40, 0x08, 0x02, 0x41, 0xc4, 0x0b, 0x80, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0xf0, 0x06, 0x00, 0x03, 0xc0, 0x1f, 
    0x8e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x02, 0x00, 0x04, 0x00, 0x80, 0x03, 0x80, 0x87, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x06, 0x00, 0x03, 
    0xc0, 0x01, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xc9, 0xf8, 0x80, 0x90, 0x08, 0x13, 
    0x08, 0x26, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x0c, 
    0x00, 0x03, 0x40, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xc3, 0x9e, 0x08, 0x02, 
    0x00, 0x86, 0x42, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 
    0x00, 0x0c, 0x00, 0x07, 0x40, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xe7, 0x8f, 
    0x80, 0x00, 0x20, 0x1c, 0x10, 0x98, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 
    0x18, 0x00, 0x00, 0x18, 0x00, 0x0e, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 
    0xf7, 0xc3, 0xe1, 0x20, 0x02, 0x79, 0x04, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00, 
    0x00, 0x00, 0x18, 0x00, 0x00, 0x18, 0x00, 0x0c, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 
    0x00, 0x00, 0x7f, 0xf0, 0xf8, 0x02, 0x40, 0xe0, 0x41, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xc0, 
    0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x30, 0x00, 0x1c, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x09, 0x80, 0x00, 0x7c, 0xf4, 0x3e, 0x08, 0x05, 0x80, 0x17, 0x80, 0x20, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x01, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x60, 0x00, 0x38, 0xc0, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x08, 0xc0, 0x00, 0x3c, 0x39, 0x0f, 0xc0, 0x9f, 0xef, 0xbe, 0x01, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x03, 0x80, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x01, 0xc0, 0x00, 0x30, 0x40, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x60, 0x0e, 0x1e, 0x3c, 0xc1, 0xff, 0xf0, 0xff, 0xe0, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x03, 0x80, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x03, 0x00, 0x00, 0xf0, 
    0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x30, 0x7f, 0x0e, 0x0f, 0x30, 0x08, 0x00, 0x7f, 
    0xc0, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x80, 0x0e, 0x00, 
    0x00, 0xf0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x1f, 0xc2, 0x0f, 0x07, 0x8c, 0x92, 
    0x4b, 0x0b, 0x80, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 
    0x38, 0x00, 0x03, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x04, 0x06, 0x07, 0x03, 
    0xe2, 0x44, 0x88, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x3f, 0xe0, 0x00, 0x07, 0x30, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x04, 
    0x03, 0x80, 0xf9, 0x24, 0xa1, 0xbe, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x0e, 0x30, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 
    0x00, 0x0c, 0x03, 0x80, 0x3c, 0x92, 0x0c, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x21, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x10, 0x00, 0x08, 0x03, 0xc0, 0x0f, 0xc0, 0x91, 0xf0, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x37, 0x80, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x60, 0x20, 0x18, 0x01, 0xc2, 0x03, 0xfd, 0x27, 0xc0, 0x82, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 
    0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x34, 0x80, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x10, 0x01, 0xe0, 0x00, 0x3f, 0xff, 0x00, 0x10, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x38, 
    0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x02, 0x30, 0x00, 0xe0, 0x00, 0x02, 0xd0, 0x04, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x03, 0x31, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x01, 0x00, 0x10, 0x00, 0xe0, 0x90, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x03, 0x60, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x10, 0x00, 0xf0, 
    0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x07, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x18, 
    0x00, 0x70, 0x01, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x30, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xe1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x84, 
    0x10, 0x08, 0x00, 0x72, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 
    0x00, 0xc8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xe1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x01, 0xe0, 0x00, 0x0c, 0x00, 0x78, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 
    0x0e, 0x00, 0x00, 0xa8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x23, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x30, 0x00, 0x86, 0x00, 0x38, 0x08, 0x40, 0x10, 0x20, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x0e, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x62, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x02, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x03, 0x30, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x62, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x22, 0x03, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x0e, 0x00, 0x00, 0x20, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x06, 0x46, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x07, 0xf9, 0x80, 0x38, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x34, 0xc0, 0x00, 0x00, 
    0x00, 0x00, 0x0e, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x1c, 0x7f, 0x00, 0x3c, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x10, 0xc0, 
    0x00, 0x00, 0x00, 0x00, 0x0c, 0xcc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x10, 0x00, 
    0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 
    0x18, 0x60, 0x00, 0x00, 0x00, 0x00, 0x0c, 0xcc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 
    0x30, 0x00, 0x00, 0x3c, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 
    0x00, 0x00, 0x0f, 0x40, 0x00, 0x00, 0x00, 0x00, 0x1c, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x06, 0x60, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 
    0x07, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x90, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x04, 0xc0, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x23, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0xb0, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x80, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x03, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x39, 0xe0, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x80, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x71, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x73, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xe0, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x18, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xe0, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x40, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x40, 0xe0, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x20, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 
    0x33, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x18, 0x1f, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x07, 0x80, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x38, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xc0, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x78, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x08, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x71, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xe0, 0x00, 0x00, 0x00, 0x00, 
    0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 
    0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x3c, 0x00, 0x00, 
    0x00, 0x07, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0xe0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 
    0xc0, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x10, 0x01, 0xfc, 0x00, 0x03, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x02, 0x40, 0x01, 0x6c, 0x80, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0x80, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x10, 0x38, 0x00, 0x1c, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xce, 0xe0, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x04, 0x00, 0x00, 0x60, 
    0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xc1, 
    0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x20, 
    0x40, 0xc0, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x82, 0x03, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x04, 0x00, 0x00, 0x07, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x08, 0x1c, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0xe0, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x98, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0xe0, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x30, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x21, 0xf8, 0x00, 
    0x01, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 
    0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 
    0xcc, 0x00, 0x03, 0x80, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x06, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x03, 0x8c, 0x00, 0x07, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 
    0xc0, 0x00, 0x00, 0x0d, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x01, 0xc6, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x01, 0xfc, 0x00, 0x00, 0x1f, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xf3, 0x80, 0x0e, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0xff, 0xc0, 0x00, 0x7c, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x79, 0x80, 0x38, 0x00, 0x00, 0x00, 0xe0, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0x27, 0xf8, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0xe0, 0x38, 0x00, 0x00, 0x03, 
    0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xbf, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xf8, 0x70, 0x00, 
    0x00, 0x07, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xfc, 0x1f, 0xfc, 0x00, 0x40, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xff, 
    0xf0, 0x00, 0x00, 0x0e, 0x0f, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xf0, 0x07, 0x80, 0x01, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x7f, 0xd8, 0x00, 0x00, 0x18, 0x03, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xc0, 0x03, 
    0xc0, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x01, 0xcc, 0x00, 0x00, 0x70, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 
    0x00, 0x01, 0xc0, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xc6, 0x00, 0x00, 0xe0, 0x80, 0x1f, 0x80, 0x00, 0x00, 0x00, 
    0x0f, 0xf8, 0x00, 0x01, 0xe2, 0x40, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xe3, 0x80, 0x03, 0x82, 0x08, 0x07, 0xf8, 0x00, 
    0x00, 0x00, 0xff, 0xc0, 0x00, 0x03, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0xf9, 0xe0, 0x0f, 0x00, 0x20, 0x00, 
    0xff, 0xc0, 0x00, 0x5f, 0xff, 0x80, 0x00, 0x06, 0x70, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x20, 0x3c, 0x78, 0x3c, 0x08, 
    0x01, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xf7, 0xe0, 0x00, 0x0c, 0xe0, 0x02, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x9f, 
    0xe0, 0x00, 0x80, 0x10, 0x00, 0xff, 0xff, 0xfe, 0x01, 0xfc, 0x00, 0x33, 0xe1, 0x20, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 
    0x03, 0xff, 0x00, 0x44, 0x00, 0x00, 0x00, 0x02, 0x6c, 0x80, 0x00, 0x7f, 0xc1, 0xff, 0x80, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x10, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xfe, 
    0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x40, 0x80, 0x00, 0x10, 0x00, 0x00, 0x84, 0x00, 0x00, 0x00, 0x00, 0x88, 0x00, 
    0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x40, 0x11, 0x00, 0x00, 0x04, 0x20, 0x00, 0x24, 
    0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x04, 0x00, 0x00, 0x00, 0x00, 0x84, 
    0x82, 0x00, 0x10, 0x80, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x40, 0x00, 0x00, 
    0x40, 0x00, 0x08, 0x00, 0x00, 0x02, 0x04, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x08, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 
    0x10, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x20, 0x00, 0x80, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x02, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x20, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x1f, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x80, 
    0x00, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x0f, 0xfe, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x7f, 0xc0, 0x01, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x00, 0xff, 0xff, 
    0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0xff, 0xe0, 0x07, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xf8, 0x00, 0x00, 0x07, 
    0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0x80, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xfe, 0xdf, 0xff, 0x80, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x01, 0xf0, 0xe0, 0x0f, 0x8f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xf8, 0x00, 
    0x00, 0x1f, 0xf0, 0x01, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x07, 0xf8, 0x00, 0x07, 0x80, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x0f, 0x80, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xc0, 0xe0, 0x1f, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 
    0xf8, 0x00, 0x00, 0x7f, 0x80, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xc0, 0x00, 0x07, 0x80, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x1f, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xc0, 0xf0, 0x1e, 0x0e, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x07, 0xf8, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 
    0x07, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xe0, 0x00, 
    0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x80, 0xe0, 0x3c, 0x0e, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x0f, 0x78, 0x00, 0x03, 0xf0, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x00, 0x3e, 
    0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 
    0xe0, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x80, 0xf0, 0x78, 0x0f, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0xf8, 0x00, 0x07, 0xe0, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x00, 
    0x00, 0xfc, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x01, 0xe0, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x01, 0xe0, 
    0xf0, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0xf8, 0x00, 0x0f, 0xc0, 0x00, 0x00, 0xf0, 0x00, 
    0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x01, 0xe0, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 
    0x01, 0xe1, 0xe0, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0xf8, 0x00, 0x0f, 0x80, 0x00, 0x03, 
    0xe0, 0x00, 0x00, 0x00, 0x01, 0xf8, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x1e, 0x01, 0xe1, 0xe0, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0xf8, 0x00, 0x1f, 0x80, 
    0x00, 0x07, 0xe0, 0x00, 0x00, 0x00, 0x01, 0xf0, 0x00, 0x01, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x1e, 0x01, 0xe3, 0xc0, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0xf0, 0x00, 
    0x1f, 0x00, 0x00, 0x1f, 0xc0, 0x00, 0x00, 0x00, 0x03, 0xf0, 0x00, 0x07, 0xf8, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x80, 0x00, 0x7c, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x03, 0xe3, 0x80, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf1, 
    0xf0, 0x00, 0x3e, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x03, 0xe0, 0x00, 0x0f, 0xf0, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xf8, 0x00, 0x7c, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x03, 0xc7, 0x80, 0x3c, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0xf1, 0xf0, 0x00, 0x3e, 0x00, 0x01, 0xff, 0x00, 0x00, 0x00, 0x00, 0x03, 0xe0, 0x00, 0x0f, 
    0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xfc, 
    0x00, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x03, 0xcf, 0x00, 0x78, 0x00, 0x00, 
    0x00, 0x00, 0x01, 0xe1, 0xf0, 0x00, 0x3e, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x03, 0xf0, 
    0x00, 0x0f, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x07, 0xf8, 0x00, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x03, 0xce, 0x00, 0x78, 
    0x00, 0x00, 0x00, 0x00, 0x01, 0xc1, 0xf0, 0x00, 0x3f, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x00, 0x00, 
    0x03, 0xf0, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x01, 0xf0, 0x01, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x07, 0xde, 
    0x00, 0x78, 0x00, 0x00, 0x00, 0x00, 0x03, 0xc1, 0xe0, 0x00, 0x3f, 0x00, 0x00, 0xf0, 0x00, 0x00, 
    0x00, 0x00, 0x01, 0xf8, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x01, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 
    0x07, 0x9c, 0x00, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x03, 0x83, 0xe0, 0x00, 0x3f, 0x00, 0x00, 0xc0, 
    0x00, 0x00, 0x00, 0x00, 0x01, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x1e, 0x07, 0xbc, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x07, 0x83, 0xe0, 0x00, 0x1f, 0x80, 
    0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x01, 0xfe, 0x00, 0x00, 0x00, 0x03, 0xc0, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xe0, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x3e, 0x0f, 0xb8, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x07, 0x03, 0xe0, 0x00, 
    0x1f, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x07, 0x80, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xe0, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x0f, 0xf0, 0x01, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x03, 
    0xe0, 0x00, 0x0f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xc0, 0x00, 0x00, 0x0f, 
    0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xe0, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x0f, 0x70, 0x01, 0xe0, 0x00, 0x00, 0x00, 0x00, 
    0x1e, 0x03, 0xc0, 0x00, 0x0f, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xe0, 0x00, 
    0x00, 0x0f, 0x80, 0x00, 0x00, 0x00, 0x00, 0x01, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x07, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x1f, 0xe0, 0x03, 0xe0, 0x00, 0x00, 
    0x00, 0x00, 0x1c, 0x07, 0xc0, 0x00, 0x03, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 
    0xf8, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x07, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x1f, 0xe0, 0x03, 0xc0, 
    0x00, 0x00, 0x00, 0x00, 0x3c, 0x07, 0xc0, 0x00, 0x01, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x0f, 0xfe, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xe0, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x07, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x1f, 0xc0, 
    0x03, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x38, 0x07, 0xc0, 0x00, 0x00, 0xff, 0xe0, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x03, 0xff, 0x80, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xe0, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 
    0x1f, 0xc0, 0x07, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x70, 0x07, 0x80, 0x00, 0x00, 0x3f, 0xf0, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xc0, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 
    0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x3f, 0x80, 0x07, 0x80, 0x00, 0x00, 0x00, 0x00, 0x70, 0x07, 0x80, 0x00, 0x00, 0x1f, 
    0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xe0, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x03, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x80, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x3f, 0x80, 0x0f, 0x80, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x0f, 0x80, 0x00, 
    0x00, 0x07, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xf8, 0x00, 0x3e, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x03, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x0f, 0x80, 0x00, 0x00, 0x00, 0x01, 0xe0, 0x0f, 
    0x80, 0x00, 0x00, 0x03, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xfc, 0x00, 0x3e, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x01, 
    0xc0, 0x0f, 0x80, 0x00, 0x00, 0x00, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xfc, 
    0x01, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x1f, 0x00, 0x00, 0x00, 
    0x00, 0x03, 0x80, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0xfe, 0x01, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x1f, 0x00, 
    0x00, 0x00, 0x00, 0x07, 0x80, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xe0, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x7f, 0x03, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xfc, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x00, 
    0x1e, 0x00, 0x00, 0x00, 0x00, 0x07, 0x80, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x07, 0xf0, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x81, 0xfe, 0x80, 0x1f, 0x38, 0x03, 0x9c, 0x3f, 0xd8, 0x03, 
    0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x73, 0x80, 0xe0, 0x1c, 0x00, 0x3e, 0x00, 0x00, 
    0xfc, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x03, 0xf0, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x80, 0x78, 0x00, 0x7f, 0xf8, 0x0f, 0x9f, 0x0f, 
    0x80, 0x0f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x01, 0xe7, 0xc3, 0xe0, 0x7c, 0x00, 0xff, 
    0x00, 0x00, 0xf8, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 
    0x01, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x80, 0x78, 0x00, 0xff, 0xf0, 0x0f, 
    0x7f, 0x0f, 0x00, 0x1f, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x01, 0xef, 0xe3, 0xe0, 0x7c, 
    0x01, 0xff, 0x80, 0x01, 0xf8, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x3d, 0xff, 0xff, 0xc0, 0x00, 
    0x00, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x80, 0xf8, 0x03, 0xf0, 
    0xf0, 0x0f, 0x7f, 0x0f, 0x00, 0x3c, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x03, 0xef, 0xe3, 
    0xe0, 0xf8, 0x03, 0xe7, 0x80, 0x01, 0xf8, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xe0, 0x1e, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x80, 0xf8, 
    0x03, 0xc1, 0xf0, 0x1f, 0xe7, 0x9f, 0x00, 0x78, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x03, 
    0xfd, 0xe3, 0xc0, 0xf8, 0x07, 0x8f, 0x80, 0x01, 0xf0, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x78, 
    0xf0, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 
    0x80, 0xf0, 0x07, 0xc1, 0xe0, 0x1f, 0xc7, 0x9f, 0x00, 0xf0, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0xf0, 0x03, 0xf8, 0xe7, 0xc0, 0xf8, 0x0f, 0x8f, 0x80, 0x03, 0xf0, 0x00, 0x7c, 0x00, 0x00, 0x00, 
    0x00, 0xf0, 0x78, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x07, 0x81, 0xf0, 0x0f, 0x83, 0xe0, 0x1f, 0x84, 0x1e, 0x01, 0xf1, 0xf0, 0x00, 0x00, 0x00, 
    0x00, 0x01, 0xe0, 0x03, 0xf0, 0x87, 0xc1, 0xf8, 0x1f, 0x1f, 0x00, 0x03, 0xe0, 0x00, 0xf8, 0x00, 
    0x00, 0x00, 0x01, 0xe0, 0x3c, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x07, 0x81, 0xf0, 0x1f, 0x03, 0xe0, 0x1f, 0x80, 0x3e, 0x03, 0xe7, 0xc0, 0x00, 
    0x00, 0x00, 0x00, 0x03, 0xc0, 0x07, 0xf0, 0x07, 0x83, 0xf0, 0x3e, 0x7e, 0x00, 0x03, 0xe0, 0x00, 
    0xf8, 0x00, 0x00, 0x00, 0x03, 0xe0, 0x1e, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x01, 0xf0, 0x1f, 0x07, 0xe0, 0x3f, 0x00, 0x3e, 0x03, 0xef, 
    0x80, 0x00, 0x00, 0x00, 0x00, 0x03, 0xc0, 0x07, 0xe0, 0x07, 0x83, 0xf0, 0x3e, 0xf8, 0x00, 0x07, 
    0xe0, 0x00, 0xf8, 0x00, 0x00, 0x00, 0x07, 0xc0, 0x0f, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 
    0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x0f, 0x03, 0xe0, 0x3e, 0x0f, 0xc0, 0x3f, 0x00, 0x3c, 
    0x07, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x80, 0x07, 0xe0, 0x0f, 0x87, 0xf0, 0x7f, 0xe0, 
    0x00, 0x07, 0xc0, 0x01, 0xf8, 0x00, 0x00, 0x00, 0x0f, 0x80, 0x0f, 0x3c, 0x00, 0x70, 0x00, 0x00, 
    0x00, 0xf0, 0x00, 0x00, 0x00, 0x07, 0xc0, 0x00, 0x00, 0x1e, 0x03, 0xe0, 0x3e, 0x0f, 0xc0, 0x3e, 
    0x00, 0x7c, 0x07, 0xf0, 0x00, 0x00, 0x02, 0x00, 0x00, 0x0f, 0x00, 0x07, 0xc0, 0x0f, 0x87, 0xe0, 
    0x7f, 0x80, 0x00, 0x07, 0xc0, 0x01, 0xf0, 0x04, 0x00, 0x00, 0x1f, 0x00, 0x07, 0xfc, 0x00, 0xf8, 
    0x00, 0x00, 0x01, 0xe0, 0x00, 0x00, 0x00, 0x0f, 0xf0, 0x00, 0x00, 0x7e, 0x03, 0xe6, 0x3e, 0x1f, 
    0xc6, 0x3e, 0x00, 0x7c, 0xe7, 0xc0, 0x70, 0x00, 0x03, 0x80, 0x00, 0x0e, 0x00, 0x0f, 0x80, 0x0f, 
    0x0f, 0xe3, 0x7e, 0x03, 0x00, 0x0f, 0xc0, 0x01, 0xf0, 0x0e, 0x00, 0x00, 0x7e, 0x00, 0x07, 0xf8, 
    0x01, 0xfe, 0x00, 0x00, 0x07, 0xc0, 0x00, 0x00, 0x00, 0x1f, 0xfc, 0x00, 0x01, 0xf8, 0x07, 0xcf, 
    0x3e, 0x3f, 0xce, 0x7c, 0x00, 0x7c, 0xe7, 0xc0, 0xf0, 0x00, 0x07, 0xe0, 0x00, 0x1c, 0x00, 0x0f, 
    0x80, 0x0f, 0x1f, 0xe7, 0x3c, 0x0f, 0x00, 0x0f, 0x80, 0x01, 0xf0, 0x0f, 0x80, 0x00, 0xfc, 0x00, 
    0x03, 0xf8, 0x03, 0xff, 0xc0, 0x00, 0x1f, 0x80, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xc0, 0x0f, 0xf0, 
    0x07, 0xdc, 0x3e, 0x77, 0x9c, 0x7c, 0x00, 0x7b, 0xc7, 0xc3, 0xe0, 0x00, 0x07, 0xf8, 0x00, 0xf8, 
    0x00, 0x0f, 0x80, 0x0f, 0x3b, 0xee, 0x3c, 0x1e, 0x00, 0x0f, 0x80, 0x03, 0xf0, 0x1f, 0xe0, 0x03, 
    0xf0, 0x00, 0x03, 0xf8, 0x00, 0xff, 0xfc, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 
    0xff, 0xe0, 0x07, 0xfc, 0x3f, 0xf7, 0xf8, 0x78, 0x00, 0xff, 0x83, 0xff, 0xc0, 0x00, 0x07, 0xff, 
    0xdf, 0xf0, 0x00, 0x0f, 0x00, 0x0f, 0x73, 0xfc, 0x3f, 0xfc, 0x00, 0x1f, 0x80, 0x03, 0xe0, 0x1f, 
    0xfe, 0x3f, 0xe0, 0x00, 0x01, 0xf8, 0x00, 0x7f, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0xff, 0xff, 0xff, 0x80, 0x03, 0xf0, 0x3f, 0xe7, 0xf0, 0x78, 0x00, 0x7f, 0x03, 0xff, 0x00, 0x00, 
    0x03, 0xff, 0xff, 0xc0, 0x00, 0x1f, 0x00, 0x0f, 0xf3, 0xf8, 0x3f, 0xf8, 0x00, 0x1f, 0x00, 0x03, 
    0xe0, 0x07, 0xff, 0xff, 0x80, 0x00, 0x01, 0xf0, 0x00, 0x0f, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x0f, 0xff, 0xfc, 0x00, 0x03, 0xe0, 0x1f, 0x87, 0xe0, 0xf8, 0x00, 0x7c, 0x01, 0xfe, 
    0x00, 0x00, 0x00, 0x7f, 0xff, 0x00, 0x00, 0x1e, 0x00, 0x07, 0xc3, 0xf0, 0x1f, 0xe0, 0x00, 0x1f, 
    0x00, 0x03, 0xe0, 0x01, 0xff, 0xfe, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x01, 0xff, 0xff, 0xc0, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x80, 0x00, 0x01, 0x80, 0x06, 0x01, 0x80, 0x00, 0x00, 0x30, 
    0x00, 0x70, 0x00, 0x00, 0x00, 0x03, 0xd0, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0xc0, 0x07, 0x00, 
    0x00, 0x00, 0x00, 0x03, 0xe0, 0x00, 0x1f, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0xe8, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};

#endif
 

Anhänge

  • 1.jpg
    1.jpg
    79,1 KB · Aufrufe: 79
  • 2.png
    2.png
    15,8 KB · Aufrufe: 80
  • 3.jpg
    3.jpg
    1,1 MB · Aufrufe: 81
Die Duo LED habe ich jetzt auch mal angeschlossen und für Rot und Grün jeweils einen 330 Ohm Widerstand in die Anode gelötet an GPIO 12+13 + 1x GND direkt daneben

Von der Hardware bin ich damit fertig - halt noch den Rahmen drucken, aber das mach ich erst, wenn das Gehäuse da ist für den Rechner. vor allem wegen der Befestgung des Rahmen in den 5,25 Schächten.

Jetzt muss ich mich mal an die Kommunikation über USB (Serial2USB) mit dem TrueNAS machen, ich hab die ja schon für das kleine Display, aber naja glaub die lohnt es sich mal etwas grundlegend zu überarbeiten - hehe die ist halt so nebenbei mal entstanden. Und denke ein paar API Funbktionen muss ich auch nachsehen, das grosse Display kann halt viel mehr Daten anzeigen - und/oder ich mach optional die Schrift grösser, je nachdem wo und wie der Rechner später steht.
 

Anhänge

  • duoled.mp4
    893 KB
Zuletzt bearbeitet:
  • Gefällt mir
Reaktionen: XShocker22
So ich hab mal kurz ein wenig an der Software gewerkelt und habe jetzt die ersten Funktionen wieder reingemacht

Dazu gehört das Ansteuern der LED - rot/grün/blinkend/beide an/aus/beide blinkend
und dann auch gleich die OTA Funktion für die Firmware - so dass sich das Display auf Wunsch mit dem lokalen WiFi verbindet und einen kleinen Minimalserver aufmacht mit dem man dann eine neue Firmware hochladen kann. Und dass man die hinterlegten Bilder für z.B. Start oder was das System anzeigen soll wenn es augeschaltet ist aufrufen kann.

Wenn das erst wieder im Rechner vebaut ist und man doch irgendwas anpassen will ist das halt einfacher als das wieder über USB zu programmieren.

Das Ansteuern funktioniert indem man in einem bash script z.B. die Befehle einfach auf die USB/serielle Schnittstelle schiebt wie z.B. echo "[LED]GREEN=BLINK" > /dev/ttyUSB0 man msus also auf dem TrueNAS selber nichts extra installieren.

Code:
#include <Arduino.h>


const String PROGVERSION="0.25";
#define HASDISPLAY
#define HASLEDS
#ifdef HASDISPLAY
    #include <SPI.h>
    #include <GxEPD2_BW.h>
    #include "GxEPD2_display_selection.h"
    #include <Fonts/FreeMonoBold9pt7b.h>
    #include <Fonts/FreeMonoBold12pt7b.h>
#endif
#ifdef HASDISPLAY
    #include "myImages.h"
#endif
const uint32_t mySERIALBAUDRATE = 115200;
const uint8_t myCPUMHZ = 0; // 80
#ifdef HASDISPLAY
    const uint8_t myDisplay_Rotation = 0;
#endif
#ifdef HASLEDS
    const uint8_t PINLED_GREEN = 12;
    const uint8_t PINLED_RED = 13;
    bool BLINKING_GREEN = false;
    bool BLINKING_RED = false;
    bool BLINKING_GREEN_FLAG = false;
    bool BLINKING_RED_FLAG = false;
    bool BLINKING_BOTH = false;
    bool BLINKING_BOTH_FLAG = false;
    uint64_t LED_BLINKING_INTERVAL = 500;
    uint64_t LED_BLINKING_TIMESTAMP = 0l;
#endif

const uint16_t MAXSERIALBUFFER = 2000;
const char mySerialEndChar = '\n';
uint64_t mySerialTimeout = 5000;
uint64_t mySerialTimeoutTimestamp = 0l;
uint16_t mySerialReadPointer = 0;
char mySerialBuffer[MAXSERIALBUFFER];


//---[ OTA Updates ]------------------------------
#include <WiFi.h>
#include <WiFiClient.h>
#include <WebServer.h>
#include <ESPmDNS.h>
#include <Update.h>
const String myHostID = "epapertruenas";
bool myOTAUpdateServerIsActive = false;
WebServer myOTAWebServer(80);
void startWIFIServerForOTA(String);
String buildOTAIndexPage();
//===============================================================================================
void loop();
void setup();
void processSerialMessage(String);
void processLEDMessage(String);
void processImageMessage(String);
void showStartImage();
void showPowerOffImage();
void processLEDBlinking();
//===============================================================================================

void setup()
{
  if (myCPUMHZ != 0)
     setCpuFrequencyMhz(myCPUMHZ);
  Serial.begin(mySERIALBAUDRATE);
  #ifdef HASLEDS
    pinMode(PINLED_GREEN, OUTPUT);
    pinMode(PINLED_RED, OUTPUT);
    digitalWrite(PINLED_RED, LOW);
    digitalWrite(PINLED_GREEN, HIGH);
  #endif
  // Default WiFi und Bluetooth aus
  WiFi.disconnect(true);
  WiFi.mode(WIFI_OFF);
  btStop();
  #ifdef HASDISPLAY
    display.init(0);
  #endif
}
void loop()
{
    #ifdef HASLEDS
        processLEDBlinking();
    #endif
  if (myOTAUpdateServerIsActive)
  {
    myOTAWebServer.handleClient();
    delay(5);
    return;      // im OTA Modus mache sonst nix anderes mehr
  }
    if (((millis() - mySerialTimeoutTimestamp) > mySerialTimeout) && (mySerialReadPointer > 0))
    {
        mySerialTimeoutTimestamp = 0l;
        mySerialReadPointer = 0;
        memset(&mySerialBuffer[0], 0, MAXSERIALBUFFER);
    }
 
    while (!Serial.available()) return;
    mySerialTimeoutTimestamp = millis();
    if (mySerialReadPointer < MAXSERIALBUFFER)
    {
        char myReadChar = Serial.read();
        if (myReadChar != mySerialEndChar)
        {
            if ((myReadChar > 31) && (myReadChar < 129))
            {
                mySerialBuffer[mySerialReadPointer] = myReadChar;
                mySerialReadPointer++;
            }
            return;
        }
        else
        {
            mySerialBuffer[mySerialReadPointer] = 0;
            processSerialMessage(String(mySerialBuffer));
            mySerialReadPointer = 0;
            memset(&mySerialBuffer[0], 0, MAXSERIALBUFFER);
        }
    }
}
 
void processLEDBlinking()
{
    if ((BLINKING_BOTH == false) && (BLINKING_GREEN == false) && (BLINKING_RED == false))
        return;
    if (millis()-LED_BLINKING_TIMESTAMP < LED_BLINKING_INTERVAL)
        return;
    LED_BLINKING_TIMESTAMP = millis();
    if (BLINKING_BOTH)
    {
        if (BLINKING_BOTH_FLAG)
        {
            processLEDMessage("RED=ON");
            processLEDMessage("GREEN=ON");
        }
        else
        {
            processLEDMessage("RED=OFF");
            processLEDMessage("GREEN=OFF");
        }
        BLINKING_BOTH_FLAG = !BLINKING_BOTH_FLAG;
        return;
    }
    if ((BLINKING_RED) && (BLINKING_GREEN))
    {
        if (BLINKING_RED_FLAG)
        {
            processLEDMessage("RED=ON");
            processLEDMessage("GREEN=OFF");
        }
        else
        {
            processLEDMessage("RED=OFF");
            processLEDMessage("GREEN=ON");
        }
        BLINKING_RED_FLAG = !BLINKING_RED_FLAG;
        return;
    }
    if (BLINKING_RED)
    {
        if (BLINKING_RED_FLAG)
            processLEDMessage("RED=ON");
        else
            processLEDMessage("RED=OFF");
        BLINKING_RED_FLAG = !BLINKING_RED_FLAG;
        return;
    }
    if (BLINKING_GREEN)
    {
        if (BLINKING_GREEN_FLAG)
            processLEDMessage("GREEN=ON");
        else
            processLEDMessage("GREEN=OFF");
        BLINKING_GREEN_FLAG = !BLINKING_GREEN_FLAG;
        return;
    }
}


void processSerialMessage(String _myMessage)
{
    if ((_myMessage == nullptr) || (_myMessage.length() < 5))
        return;
 
    #ifdef HASLEDS
        if (_myMessage.startsWith("[LED]"))
        {
            _myMessage = _myMessage.substring(String("[LED]").length());
            processLEDMessage(_myMessage);
        }
        else
    #endif
    if (_myMessage.startsWith("[SHOWIMAGE]"))
    {
        _myMessage = _myMessage.substring(String("[SHOWIMAGE]").length());
        processImageMessage(_myMessage);
    }
    else if (_myMessage.startsWith("[WIFIUPDATE]"))
    {
        _myMessage = _myMessage.substring(String("[WIFIUPDATE]").length());
        startWIFIServerForOTA(_myMessage);
    }
    else if (_myMessage.startsWith("[REBOOT]"))
    {
        processLEDMessage("ALL=OFF");
        showStartImage();
        ESP.restart();
    }
}
#ifdef HASLEDS
    void processLEDMessage(String _myMessage)
    {
        _myMessage.toUpperCase();
     
        if (_myMessage.equals("RED=ON"))
            digitalWrite(PINLED_RED, HIGH);
        else if (_myMessage.equals("RED=OFF"))
            digitalWrite(PINLED_RED, LOW);
        else if (_myMessage.equals("GREEN=ON"))
            digitalWrite(PINLED_GREEN, HIGH);
        else if (_myMessage.equals("GREEN=OFF"))
            digitalWrite(PINLED_GREEN, LOW);
        else if (_myMessage.equals("ALL=OFF"))
        {
            processLEDMessage("GREEN=OFF");
            processLEDMessage("RED=OFF");
            BLINKING_BOTH = false;
            BLINKING_RED = false;
            BLINKING_GREEN = false;
        }
        else if (_myMessage.equals("ALL=ON"))
        {
            processLEDMessage("GREEN=ON");
            processLEDMessage("RED=ON");
        }
        else if (_myMessage.equals("RED=BLINKING"))
           BLINKING_RED = true;
        else if (_myMessage.equals("GREEN=BLINKING"))
           BLINKING_GREEN = true;
        else if (_myMessage.equals("BOTH=BLINKING"))
           BLINKING_BOTH = true; 
    }
#endif

void showStartImage()
{
    display.setRotation(myDisplay_Rotation);
    display.setFullWindow();
    display.clearScreen();
    display.fillScreen(GxEPD_WHITE);
    do
    {
        display.drawBitmap(0, 0, &epd_bitmap_trueNas_Start_Image[0], display.width(), display.height(), GxEPD_BLACK);
    } while (display.nextPage());
}
void showPowerOffImage()
{
    display.setRotation(myDisplay_Rotation);
    display.setFullWindow();
    display.clearScreen();
    display.fillScreen(GxEPD_WHITE);
    do
    {
        display.drawBitmap(0, 0, &epd_bitmap_trueNas_PowerOFF_Image[0], display.width(), display.height(), GxEPD_BLACK);
    } while (display.nextPage());
}
void processImageMessage(String _myMessage)
{
    _myMessage.toUpperCase();
    if (_myMessage.equals("STARTING"))
        showStartImage();
    else if (_myMessage.equals("POWEROFF"))
        showPowerOffImage();
}



//==============================================================================================================
// Kram fuer OTA Updates

String buildOTAIndexPage()
{
  String myHTMLPage = "<html><h2>Firmware Update</h2><br>Aktuell installiert ist V" + PROGVERSION + "<br><br>";
  myHTMLPage += "Reboot des Displays erfolgt (eigentlich) automatisch...<br><br><br>";
  myHTMLPage += "<form method='POST' action='/update' enctype='multipart/form-data' id='upload_form'>";
  myHTMLPage += "<input type='file' name='update'>";
  myHTMLPage += "<input type='submit' value='Update'>";
  myHTMLPage += "</form><br>";
  myHTMLPage += "<a href=\"/abort\">OTA Firmware Modus Abbrechen</a>";
  myHTMLPage += "</html>";
  return (myHTMLPage);
}


void startWIFIServerForOTA(String _myString)
{
  String mySSID = "";
  String myPassword = "";
  if ((_myString != nullptr) && (_myString.length() > 0))
  {
      if ((_myString.indexOf("SSID=") == 0) && (_myString.indexOf("&PASSWORD=") > 0))
      {
        mySSID=_myString.substring(String("SSID=").length(), _myString.indexOf("&PASSWORD="));
        myPassword=_myString.substring(_myString.indexOf("&PASSWORD=")+String("&PASSWORD=").length());
      }
  }
  WiFi.mode(WIFI_STA);
  WiFi.begin(mySSID.c_str(), myPassword.c_str());
  uint8_t myWiFiRetryCounter=0;
  while (WiFi.status() != WL_CONNECTED)
  {
    myWiFiRetryCounter++;
    delay(500);
    if (myWiFiRetryCounter > 50)
    {
      WiFi.disconnect(true, true);
      WiFi.mode(WIFI_OFF);
      #ifdef HASDISPLAY
      //  drawAlert("Kein Connect!", mySSID);
      #endif
      processLEDMessage("ALL=OFF");
      processLEDMessage("RED=ON");
      delay(5*1000);   // Fehler 5 Sekunden anzeigen
      return;
    }
  }
  if (myHostID != nullptr)
    MDNS.begin(myHostID);
  myOTAWebServer.on("/", HTTP_GET, []()
  {
    myOTAWebServer.sendHeader("Connection", "close");
    myOTAWebServer.send(200, "text/html", buildOTAIndexPage().c_str());
  });
  myOTAWebServer.on("/abort", HTTP_GET, []()
  {
    myOTAWebServer.sendHeader("Connection", "close");
    myOTAWebServer.send(200, "text/plain", "Beende Firmware Modus => Zurueck zum Anzeigemodus");
    processLEDMessage("ALL=OFF");
    #ifdef HASDISPLAY
      // draw3Liner("FW Update Modus", "abgebrochen", "=> Normal-Modus");
    #endif
    MDNS.end();
    WiFi.disconnect();
    WiFi.mode(WIFI_OFF);
    myOTAUpdateServerIsActive = false;
    //mySerialReceivedData_Old = "~";
    return;
  });
  // -- Firmware hochladen ueber POST => Bloecke dann schreiben
  myOTAWebServer.on("/update", HTTP_POST, []()
  {
    bool myUpdateFailed = false;
    myOTAWebServer.sendHeader("Connection", "close");
    String myHTMLMessage = "<html>Alles OK - Display wird neu gestartet</html>";
    if (Update.hasError())
    {
      myUpdateFailed = true;
      myHTMLMessage = "<html>";
      myHTMLMessage += "<h2>Update Fehler</h2><br>";
      myHTMLMessage += "Fehler: " + String(Update.errorString()) + "<br><br>";
      myHTMLMessage += "Display wird NICHT neu gestartet - evtl nochmal probieren<br><br>";
      myHTMLMessage += "<a href=\"/\">Startseite</a></html>";
      #ifdef HASDISPLAY
        // drawInfo("Fehler Update", "Neu versuchen?");
      #endif
    }
    myOTAWebServer.send(200, "text/html", myHTMLMessage.c_str());
 
    if (!myUpdateFailed)
    {
        processLEDMessage("ALL=OFF");
        ESP.restart();
    }
  }, []()
  {
    HTTPUpload& myFWUploadData = myOTAWebServer.upload();
    if (myFWUploadData.status == UPLOAD_FILE_START)
    {
      if (!Update.begin(UPDATE_SIZE_UNKNOWN))
      {
        // Update.printError(Serial);
      }
    }
    else if (myFWUploadData.status == UPLOAD_FILE_WRITE)
    {
      if (Update.write(myFWUploadData.buf, myFWUploadData.currentSize) != myFWUploadData.currentSize)
      {
         //  Update.printError(Serial);
      }
    }
    else if (myFWUploadData.status == UPLOAD_FILE_END)
    {
      if (Update.end(true))
      {
        // Serial.printf("Update OK: %u\nRebooting...\n", upload.totalSize);
      }
      else
      {
        // Update.printError(Serial);
      }
    }
  });
  if (WiFi.isConnected())
  {
    myOTAWebServer.begin();
    myOTAUpdateServerIsActive = true;
    processLEDMessage("ALL=OFF");
    processLEDMessage("RED=BLINKING");
    processLEDMessage("GREEN=BLINKING");
    Serial.println(WiFi.localIP().toString().c_str());
    #ifdef HASDISPLAY
      //drawInfo("FIRMW. UPDATE", WiFi.localIP().toString());
    #endif
  }
}
 

Anhänge

  • otaupdate.jpg
    otaupdate.jpg
    59,4 KB · Aufrufe: 82
Zuletzt bearbeitet:
  • Gefällt mir
Reaktionen: chillking
also ausgewählt welches Display es ist wird es in der "GxEPD2_display_selection.h" siehe Post #4 - hehe das halt alles immer etwas schwer sinnvoll hier reinzuschreiben xD

In meinem Programm selber dann einfach unter setup() mit " display.init(0);" 0= keine keine Ausgaben auf seriell.

Allerdings habe ich beim 4.2" Display einen Nachteil jetzt entdeckt - die partial Updates tun nicht bzw nicht so wie ich will. Alles unterhalb des "partial Updates" verblasst. Wenn ich also z.B. 5 Zeilen habe die erste nur update, dann sind alle darunter weg.... das natürlich etwas ärgerlich, auf dem kleinen tut es (ist allerdings auch neuer und hat anderen Controller)

Jetzt muss ich halt (leider) fullscreen updates machen - imm,erhin wne ich auf "rot" als Farbe verzichtet sind die trotz allem recht schnell.

Immerhin die "5 Zeilen" Ausgabe tut schonmal :D ganz schön gross aber der Rechner steht ja später im Keller in ner Ecke :D


Das gerade mal der Zwischenstand der Software mit den partial Update Tests die leider ja nicht tun

Code:
#include <Arduino.h>


const String PROGVERSION="0.25";
#define HASDISPLAY
#define HASLEDS
#ifdef HASDISPLAY
    #include <SPI.h>
    #include <GxEPD2_BW.h>
    //#include <GxEPD2_3C.h>
    #include "GxEPD2_display_selection.h"
    #include <Fonts/FreeMonoBold9pt7b.h>
    #include <Fonts/FreeMonoBold12pt7b.h>
    #include <Fonts/FreeMonoBold24pt7b.h>
#endif
#ifdef HASDISPLAY
    #include "myImages.h"
#endif
const uint32_t mySERIALBAUDRATE = 115200;
const uint8_t myCPUMHZ = 80;
#ifdef HASDISPLAY
    const uint8_t myDisplay_Rotation = 0;
#endif
#ifdef HASLEDS
    const uint8_t PINLED_GREEN = 12;
    const uint8_t PINLED_RED = 13;
    bool BLINKING_GREEN = false;
    bool BLINKING_RED = false;
    bool BLINKING_GREEN_FLAG = false;
    bool BLINKING_RED_FLAG = false;
    bool BLINKING_BOTH = false;
    bool BLINKING_BOTH_FLAG = false;
    uint64_t LED_BLINKING_INTERVAL = 500;
    uint64_t LED_BLINKING_TIMESTAMP = 0l;
#endif

const uint16_t MAXSERIALBUFFER = 2000;
const char mySerialEndChar = '\n';
uint64_t mySerialTimeout = 5000;
uint64_t mySerialTimeoutTimestamp = 0l;
uint16_t mySerialReadPointer = 0;
char mySerialBuffer[MAXSERIALBUFFER];

//---[ OTA Updates ]------------------------------
#include <WiFi.h>
#include <WiFiClient.h>
#include <WebServer.h>
#include <ESPmDNS.h>
#include <Update.h>
const String myHostID = "epapertruenas";
bool myOTAUpdateServerIsActive = false;
WebServer myOTAWebServer(80);
void startWIFIServerForOTA(String);
String buildOTAIndexPage();
bool connectToWiFi(String, String);
//===============================================================================================
void loop();
void setup();
void processSerialMessage(String);
void processLEDMessage(String);
void processImageMessage(String);
void showStartImage();
void showPowerOffImage();
void processLEDBlinking();
void showClock();

const uint8_t DISPLAYLINES = 5;
String myDisplayLines[DISPLAYLINES];
void display5Liner();
void display5LinerLine(uint8_t, String);
void display5LinerFull();
void splitStringToArray(String, String);
//===============================================================================================

void setup()
{
  if (myCPUMHZ != 0)
     setCpuFrequencyMhz(myCPUMHZ);
  Serial.begin(mySERIALBAUDRATE);
  #ifdef HASLEDS
    pinMode(PINLED_GREEN, OUTPUT);
    pinMode(PINLED_RED, OUTPUT);
    digitalWrite(PINLED_RED, LOW);
    digitalWrite(PINLED_GREEN, HIGH);
  #endif
  // Default WiFi und Bluetooth aus 
  WiFi.disconnect(true);
  WiFi.mode(WIFI_OFF);  
  btStop();
  #ifdef HASDISPLAY
    display.init(0);
  #endif
}
void loop()
{
    #ifdef HASLEDS
        processLEDBlinking();
    #endif
  if (myOTAUpdateServerIsActive)
  {
    myOTAWebServer.handleClient();
    delay(5);
    return;      // im OTA Modus mache sonst nix anderes mehr
  }
    if (((millis() - mySerialTimeoutTimestamp) > mySerialTimeout) && (mySerialReadPointer > 0))
    {
        mySerialTimeoutTimestamp = 0l;
        mySerialReadPointer = 0;
        memset(&mySerialBuffer[0], 0, MAXSERIALBUFFER);
    }
   
    while (!Serial.available()) return;
    mySerialTimeoutTimestamp = millis();
    if (mySerialReadPointer < MAXSERIALBUFFER)
    {
        char myReadChar = Serial.read();
        if (myReadChar != mySerialEndChar)
        {
            if ((myReadChar > 31) && (myReadChar < 129))
            {
                mySerialBuffer[mySerialReadPointer] = myReadChar;
                mySerialReadPointer++;
            }
            return;
        }
        else
        {
            mySerialBuffer[mySerialReadPointer] = 0;
            processSerialMessage(String(mySerialBuffer));
            mySerialReadPointer = 0;
            memset(&mySerialBuffer[0], 0, MAXSERIALBUFFER);
        }
    }
}
   
void processLEDBlinking()
{
    if ((BLINKING_BOTH == false) && (BLINKING_GREEN == false) && (BLINKING_RED == false))
        return;
    if (millis()-LED_BLINKING_TIMESTAMP < LED_BLINKING_INTERVAL)
        return;
    LED_BLINKING_TIMESTAMP = millis();
    if (BLINKING_BOTH)
    {
        if (BLINKING_BOTH_FLAG)
        {
            processLEDMessage("RED=ON");
            processLEDMessage("GREEN=ON");
        }
        else
        {
            processLEDMessage("RED=OFF");
            processLEDMessage("GREEN=OFF");
        }
        BLINKING_BOTH_FLAG = !BLINKING_BOTH_FLAG;
        return;
    }
    if ((BLINKING_RED) && (BLINKING_GREEN))
    {
        if (BLINKING_RED_FLAG)
        {
            processLEDMessage("RED=ON");
            processLEDMessage("GREEN=OFF");
        }
        else
        {
            processLEDMessage("RED=OFF");
            processLEDMessage("GREEN=ON");
        }
        BLINKING_RED_FLAG = !BLINKING_RED_FLAG;
        return;
    }
    if (BLINKING_RED)
    {
        if (BLINKING_RED_FLAG)
            processLEDMessage("RED=ON");
        else
            processLEDMessage("RED=OFF");
        BLINKING_RED_FLAG = !BLINKING_RED_FLAG;
        return;
    }
    if (BLINKING_GREEN)
    {
        if (BLINKING_GREEN_FLAG)
            processLEDMessage("GREEN=ON");
        else
            processLEDMessage("GREEN=OFF");
        BLINKING_GREEN_FLAG = !BLINKING_GREEN_FLAG;
        return;
    }
}


void processSerialMessage(String _myMessage)
{
    if ((_myMessage == nullptr) || (_myMessage.length() < 5))
        return;
   
    #ifdef HASLEDS
        if (_myMessage.startsWith("[LED]"))
        {
            _myMessage = _myMessage.substring(String("[LED]").length());
            processLEDMessage(_myMessage);
        }
        else
    #endif
    if (_myMessage.startsWith("[SHOWIMAGE]"))
    {
        _myMessage = _myMessage.substring(String("[SHOWIMAGE]").length());
        processImageMessage(_myMessage);
    }
    else if (_myMessage.startsWith("[WIFIUPDATE]"))
    {
        _myMessage = _myMessage.substring(String("[WIFIUPDATE]").length());
        startWIFIServerForOTA(_myMessage);
    }
    else if (_myMessage.startsWith("[REBOOT]"))
    {
        processLEDMessage("ALL=OFF");
        showStartImage();
        ESP.restart();
    }
    else if (_myMessage.startsWith("[5LINER]"))
    {
        _myMessage = _myMessage.substring(String("[5LINER]").length());
        splitStringToArray(_myMessage, "[NEWLINE]");
        Serial.println("5Liner");
        display5LinerFull();
    }
}
#ifdef HASLEDS
    void processLEDMessage(String _myMessage)
    {
        _myMessage.toUpperCase();
       
        if (_myMessage.equals("RED=ON"))
            digitalWrite(PINLED_RED, HIGH);
        else if (_myMessage.equals("RED=OFF"))
            digitalWrite(PINLED_RED, LOW);
        else if (_myMessage.equals("GREEN=ON"))
            digitalWrite(PINLED_GREEN, HIGH);
        else if (_myMessage.equals("GREEN=OFF"))
            digitalWrite(PINLED_GREEN, LOW);
        else if (_myMessage.equals("ALL=OFF"))
        {
            processLEDMessage("GREEN=OFF");
            processLEDMessage("RED=OFF");
            BLINKING_BOTH = false;
            BLINKING_RED = false;
            BLINKING_GREEN = false;
        }
        else if (_myMessage.equals("ALL=ON"))
        {
            processLEDMessage("GREEN=ON");
            processLEDMessage("RED=ON");
        }
        else if (_myMessage.equals("RED=BLINKING"))
           BLINKING_RED = true;
        else if (_myMessage.equals("GREEN=BLINKING"))
           BLINKING_GREEN = true;  
        else if (_myMessage.equals("BOTH=BLINKING"))
           BLINKING_BOTH = true;   
    }
#endif

void showStartImage()
{
    display.setRotation(myDisplay_Rotation);
    display.setFullWindow();
    display.clearScreen();
    display.fillScreen(GxEPD_WHITE);
    do
    {
        display.drawBitmap(0, 0, &epd_bitmap_trueNas_Start_Image[0], display.width(), display.height(), GxEPD_BLACK);
    } while (display.nextPage());  
}
void showPowerOffImage()
{
    display.setRotation(myDisplay_Rotation);
    display.setFullWindow();
    display.clearScreen();
    display.fillScreen(GxEPD_WHITE);
    do
    {
        display.drawBitmap(0, 0, &epd_bitmap_trueNas_PowerOFF_Image[0], display.width(), display.height(), GxEPD_BLACK);
    } while (display.nextPage());  
}
void processImageMessage(String _myMessage)
{
    _myMessage.toUpperCase();
    if (_myMessage.equals("STARTING"))
        showStartImage();
    else if (_myMessage.equals("POWEROFF"))
        showPowerOffImage();
}

void display5LinerLine(uint8_t _myLineNumber, String _myText)
{
    uint16_t myYPos[5] = {20, 72, 124, 176, 228};
    int16_t myX, myY;
    uint16_t myWidth, myHeight;
    if (_myLineNumber > 4) return;
    display.getTextBounds("aTAgy", 100, 100, &myX, &myY, &myWidth, &myHeight);
    display.setPartialWindow(10,myYPos[_myLineNumber],display.width()-20,(myYPos[_myLineNumber]+myHeight)*1.1);
    display.firstPage();
    do
    {
        display.setCursor(20,myYPos[_myLineNumber]+myHeight);
        display.print(_myText.c_str());
    } while (display.nextPage());
}
void display5Liner()
{
    display.setRotation(myDisplay_Rotation);
    display.setTextWrap(false);
    display.setTextColor(GxEPD_BLACK);
    display.setFont(&FreeMonoBold24pt7b);
    display5LinerLine(0, "CPU: "+String(random(10,50)) + " C");
    display5LinerLine(1, "CPU: "+String(random(10,50)) + " C");
    display5LinerLine(2, "CPU: "+String(random(10,50)) + " C");
    display5LinerLine(3, "CPU: "+String(random(10,50)) + " C");
    display5LinerLine(4, "CPU: "+String(random(10,50)) + " C");
    for (int i=0; i < 3; i++)
    {
        display.firstPage();
        display.setPartialWindow(display.width()-4, display.height()-4, 3, 3);
        do
        {
            display.drawPixel(display.width()-2, display.height()-2, GxEPD_WHITE);
        } while (display.nextPage());
    }
}


void display5LinerFull()
{
    uint16_t myYPos[5] = {20, 72, 124, 176, 228};
    int16_t myX, myY;
    uint16_t myWidth, myHeight;
    String myDisplayString = "";
    display.setRotation(myDisplay_Rotation);
    display.setTextWrap(false);
    display.setTextColor(GxEPD_BLACK);
    display.setFont(&FreeMonoBold24pt7b);


    display.getTextBounds("aTAgy", 100, 100, &myX, &myY, &myWidth, &myHeight);
    display.setFullWindow();
    display.firstPage();
    do
    {
        for (int i=0; i < 5; i++)
        {
        //  if (myDisplayLines[i].length() > 0)
        //  {      
                display.setCursor(20,myYPos[i]+myHeight);
                display.print(myDisplayLines[i].c_str());
        //  }
        }
    } while (display.nextPage());
}

//==============================================================================================================
// Kram fuer OTA Updates

String buildOTAIndexPage()
{
  String myHTMLPage = "<html><h2>Firmware Update</h2><br>Aktuell installiert ist V" + PROGVERSION + "<br><br>";
  myHTMLPage += "Reboot des Displays erfolgt (eigentlich) automatisch...<br><br><br>";
  myHTMLPage += "<form method='POST' action='/update' enctype='multipart/form-data' id='upload_form'>";
  myHTMLPage += "<input type='file' name='update'>";
  myHTMLPage += "<input type='submit' value='Update'>";
  myHTMLPage += "</form><br>";
  myHTMLPage += "<a href=\"/abort\">OTA Firmware Modus Abbrechen</a>";
  myHTMLPage += "</html>";
  return (myHTMLPage);
}


void startWIFIServerForOTA(String _myString)
{
  String mySSID = "";
  String myPassword = "";
  if ((_myString != nullptr) && (_myString.length() > 0))
  {
      if ((_myString.indexOf("SSID=") == 0) && (_myString.indexOf("&PASSWORD=") > 0))
      {
        mySSID=_myString.substring(String("SSID=").length(), _myString.indexOf("&PASSWORD="));
        myPassword=_myString.substring(_myString.indexOf("&PASSWORD=")+String("&PASSWORD=").length());
      }
  }
  if (connectToWiFi(mySSID, myPassword) == false) return;
  myOTAWebServer.on("/", HTTP_GET, []()
  {
    myOTAWebServer.sendHeader("Connection", "close");
    myOTAWebServer.send(200, "text/html", buildOTAIndexPage().c_str());
  });
  myOTAWebServer.on("/abort", HTTP_GET, []()
  {
    myOTAWebServer.sendHeader("Connection", "close");
    myOTAWebServer.send(200, "text/plain", "Beende Firmware Modus => Zurueck zum Anzeigemodus");
    processLEDMessage("ALL=OFF");
    #ifdef HASDISPLAY
      // draw3Liner("FW Update Modus", "abgebrochen", "=> Normal-Modus");
    #endif
    MDNS.end();
    WiFi.disconnect();
    WiFi.mode(WIFI_OFF);
    myOTAUpdateServerIsActive = false;
    //mySerialReceivedData_Old = "~";
    return;
  });
  // -- Firmware hochladen ueber POST => Bloecke dann schreiben
  myOTAWebServer.on("/update", HTTP_POST, []()
  {
    bool myUpdateFailed = false;
    myOTAWebServer.sendHeader("Connection", "close");
    String myHTMLMessage = "<html>Alles OK - Display wird neu gestartet</html>";
    if (Update.hasError())
    {
      myUpdateFailed = true;
      myHTMLMessage = "<html>";
      myHTMLMessage += "<h2>Update Fehler</h2><br>";
      myHTMLMessage += "Fehler: " + String(Update.errorString()) + "<br><br>";
      myHTMLMessage += "Display wird NICHT neu gestartet - evtl nochmal probieren<br><br>";
      myHTMLMessage += "<a href=\"/\">Startseite</a></html>";
      #ifdef HASDISPLAY
        // drawInfo("Fehler Update", "Neu versuchen?");
      #endif
    }
    myOTAWebServer.send(200, "text/html", myHTMLMessage.c_str());
 
    if (!myUpdateFailed)
    {
        processLEDMessage("ALL=OFF");
        ESP.restart();
    }
  }, []()
  {
    HTTPUpload& myFWUploadData = myOTAWebServer.upload();
    if (myFWUploadData.status == UPLOAD_FILE_START)
    {
      if (!Update.begin(UPDATE_SIZE_UNKNOWN))
      {
        // Update.printError(Serial);
      }
    }
    else if (myFWUploadData.status == UPLOAD_FILE_WRITE)
    {
      if (Update.write(myFWUploadData.buf, myFWUploadData.currentSize) != myFWUploadData.currentSize)
      {
         //  Update.printError(Serial);
      }
    }
    else if (myFWUploadData.status == UPLOAD_FILE_END)
    {
      if (Update.end(true))
      {
        // Serial.printf("Update OK: %u\nRebooting...\n", upload.totalSize);
      }
      else
      {
        // Update.printError(Serial);
      }
    }
  });
  if (WiFi.isConnected())
  {
    myOTAWebServer.begin();
    myOTAUpdateServerIsActive = true;
    processLEDMessage("ALL=OFF");
    processLEDMessage("RED=BLINKING");
    processLEDMessage("GREEN=BLINKING");
    Serial.println(WiFi.localIP().toString().c_str());
    #ifdef HASDISPLAY
      //drawInfo("FIRMW. UPDATE", WiFi.localIP().toString());
    #endif
  }
}

bool connectToWiFi(String _mySSID, String _myWIFIPassword)
{
    uint8_t myWiFiRetryCounter = 0;
    if (!WiFi.isConnected())
    {
        if (!WiFi.mode(WIFI_STA))
            return(false);
        WiFi.begin(_mySSID.c_str(), _myWIFIPassword.c_str());
        while (WiFi.status() != WL_CONNECTED)
        {
            myWiFiRetryCounter++;
            delay(500);
            if (myWiFiRetryCounter > 50)
            {
                WiFi.disconnect(true, true);
                WiFi.mode(WIFI_OFF);
                #ifdef HASDISPLAY
                    //  drawAlert("Kein Connect!", mySSID);
                #endif
                processLEDMessage("ALL=OFF");
                processLEDMessage("RED=ON");
                delay(5*1000);   // Fehler 5 Sekunden anzeigen
                return(false);
            }
        }
        if ((myHostID != nullptr) && (myHostID.length() > 0))
            MDNS.begin(myHostID);
    }
    return(WiFi.isConnected());
}

void splitStringToArray(String _Input, String _Separator)
{
    for (int i=0; i < DISPLAYLINES; i++)
        myDisplayLines[i] = "";
   
    if (_Input.indexOf(_Separator) < 0)
    {
        myDisplayLines[0] = _Input;
        return;
    }
    uint8_t myIndex = 0;
    while ((_Input.indexOf(_Separator) >= 0) && (myIndex < DISPLAYLINES))
    {
        myDisplayLines[myIndex] = _Input.substring(0, _Input.indexOf(_Separator));
        _Input = _Input.substring(_Separator.length() + myDisplayLines[myIndex].length());
        myIndex++;
    }
    if ((_Input.length() > 0) && (myIndex < DISPLAYLINES))
           myDisplayLines[myIndex] = _Input;
}
 

Anhänge

  • truenas_4_2_aktuell.jpg
    truenas_4_2_aktuell.jpg
    94,9 KB · Aufrufe: 76
Zuletzt bearbeitet:
  • Gefällt mir
Reaktionen: HisN
Mit rot an vielleicht ein Bild alle 6-8 Sekunden und der Bildschirm invertiert dabei immer während das neu angezeigt wird - also wie so "invertiertes Flackern" und zwar dann die ganze Zeit während das Bild aufbaut.

Verzichte ich auf rot denke ich hat es ~ 1 FPS.

Das halt wie gesagt ein ePaper Display aus der Bastelkiste das da Jahre drinlag - ist also evtl nicht mehr Stand der Technik, die neuen kleinen die ich habe sind da schon besser.

Hehe ich hab mal jetzt die Scrubbing Anzeige fertig gemacht - soll ja professionell aussehen :D

Da kann ich jetzt die % Anzeige auch bei dem Display "partial updaten" weil das Bild das bleiben soll darüber ist - allerdings muss ich den % Wert 3x ausgeben an der gleichen Stelle, dass der richtig schwarz ist (das im non partial Mode nicht so) da das aber dann nicht flackert oder so kann ich damit leben.

Ich denke dass evtl der Controller des alten Displays einfach technisch überholt ist, aber zum Wegwerfen ist es halt viel zu schade.

Eigentlich würde mir ja die LED Anzeige reichen .... aber bevor das noch ein paar Jahre rumliegt....
 

Anhänge

  • scrub_1.jpg
    scrub_1.jpg
    41,9 KB · Aufrufe: 83
  • scrub_2.png
    scrub_2.png
    183 KB · Aufrufe: 85
Zuletzt bearbeitet:
  • Gefällt mir
Reaktionen: chillking
So erst mal bin ich glaub vorerst mit der Software auf dem Display fertig - es fehlt sicher noch ein bisserl kleinkram und hier und da muss ich evtl noch den Status der LED noch besser restoren, nachdem ich Warnungen Fehler usw auf dem Display angezeigt habe - aber das nur noch eher so Kleinkram

Was jetzt noch fehlt ist die TrueNAS Seite - das sind halt so Scripte die Daten auslesen per TrueNAS API und dann nach einfach per echo "lalala" nach > /dev/ttyUSB0 schicken.

Die werde ich dann hier posten wenn ich die wieder fertig habe, das abe nicht sooooo schwer, einige habe ich ja bereits für das kleine epaper Display gemacht, so dass die grundsätzliche Kommunukation mit der TrueNAS API eh schon klappt da nutze ich einfach curl und einen API Key aus TrueNAS, das dann nur noch ein wenig Fleissarbeit.

Den kann ich auch erst wirklich machen wenn mein "neuer" TrueNAS Server läuft - die Sachen die jetzt da sind die habe ich bereits beim aktuellen umgesetzt, daher weiss ich das ist nicht mehr schwer.

Da sind jetzt noch ein paar Anzeigen - dazugekommen für Warnungen, Alarme, Infos und OTA Display etc. und ein neues Startbild mit etwas mehr "3D" :D

Und den Code muss ich natürlich mal aufräumen, das halt wie immer erst mal schnell zwischendurch gemacht wenn mal ein paar Minuten Zeit sind hehe da ist ja noch hier und da ein bisserl "Debug Kram" drin z.B. für den partial Update Versuch. Glaub so nen halben Tag wenn ich alles zusammenrechne, das ja ok für so ein zwar nicht so Sinnvolles aber irgendwie nettes Projektchen.

Bilder Headerfile ist als ZIP auch mal dabei

Code:
#include <Arduino.h>


const String PROGVERSION="0.30";
const uint32_t mySERIALBAUDRATE = 9600;
const uint8_t myCPUMHZ = 80;


#define HASDISPLAY
#define HASLEDS

#ifdef HASDISPLAY
    #include <SPI.h>
    #include <GxEPD2_BW.h>
    #include "GxEPD2_display_selection.h"
    #include <Fonts/FreeMonoBold12pt7b.h>
    #include <Fonts/FreeMonoBold24pt7b.h>
    #include "myImages.h"
#endif


const uint8_t myWarningShowTime = 0;    // in Sekunden
const uint8_t myAlarmShowTime = 0;
#ifdef HASDISPLAY
    const uint8_t myDisplay_Rotation = 0;
#endif
#ifdef HASLEDS
    const uint8_t PINLED_GREEN = 17;
    const uint8_t PINLED_RED = 16;
    bool myLED_Green_Blinking = false;
    bool myLED_Red_Blinking = false;
    bool myLED_Green_Blinking_Flag = false;
    bool myLED_Red_Blinking_Flag = false;
    bool myLED_Both_Blinking = false;
    bool myLED_Both_Blinking_Flag = false;
    uint8_t myLED_Save_Green_State = LOW;
    uint8_t myLED_Save_Red_State = LOW;
    bool myLED_Save_Green_Blinking = false;
    bool myLED_Save_Red_Blinking = false;
    bool myLED_Save_Both_Blinking = false;
    uint64_t LED_BLINKING_INTERVAL = 500;
    uint64_t LED_BLINKING_TIMESTAMP = 0l;
#endif

const uint16_t MAXSERIALBUFFER = 2000;
char mySerialBuffer[MAXSERIALBUFFER];
const char mySerialEndChar = '\r';
uint64_t mySerialTimeout = 5000;
uint64_t mySerialTimeoutTimestamp = 0l;
uint16_t mySerialReadPointer = 0;

//---[ OTA Updates ]------------------------------
#include <WiFi.h>
#include <WiFiClient.h>
#include <WebServer.h>
#include <ESPmDNS.h>
#include <Update.h>
const String myHostID = "epapertruenas";
bool myOTAUpdateServerIsActive = false;
WebServer myOTAWebServer(80);
void startWIFIServerForOTA(String);
String buildOTAIndexPage();
bool connectToWiFi(String, String);
void disconnectAndStopWiFi();
//===============================================================================================
void loop();
void setup();
void processSerialMessage(String);
#ifdef HASLEDS
    void processLEDMessage(String);
    void processLEDBlinking();
#endif
#ifdef HASDISPLAY
    void processImageMessage(String*);
    void showStartImage();
    void showPowerOffImage();
    void showScrubbingImage();
#endif

const uint8_t SERIALREADLINES_MAX = 5;
String mySerialReadLines[SERIALREADLINES_MAX];
#ifdef HASDISPLAY
    void display5Liner(String*, String*, String*, String*, String*);
    void display2Liner(String*, String*);
    void displayWarning(String*, String*, String*);
    void displayInfo(String*, String*, String*);
    void displayAlarm(String*, String*, String*);
#endif
void splitStringToArray(String, String);
#ifdef HASLEDS
    void saveLEDStates();
    void restoreLEDStates();
#endif
//===============================================================================================

void setup()
{
    if (myCPUMHZ != 0)
        setCpuFrequencyMhz(myCPUMHZ);
    Serial.begin(mySERIALBAUDRATE);
 
    #ifdef HASLEDS
        pinMode(PINLED_GREEN, OUTPUT);
        pinMode(PINLED_RED, OUTPUT);
        digitalWrite(PINLED_RED, LOW);
        digitalWrite(PINLED_GREEN, HIGH);
    #endif
    // Default WiFi und Bluetooth aus 
    disconnectAndStopWiFi();
    btStop();
    #ifdef HASDISPLAY
        display.init(0);
        delay(100);
    #endif
    // Default Startanzeige
    processSerialMessage("[LED]RED=BLINKING");
    processSerialMessage("[LED]GREEN=BLINKING");
    processSerialMessage("[SHOWIMAGE]STARTING");
}
//-------------------------------------------------------------------------------------------------------------------------------
void loop()
{
    #ifdef HASLEDS
        processLEDBlinking();
    #endif
    if (myOTAUpdateServerIsActive)
    {
        myOTAWebServer.handleClient();
        delay(1);
        return;      // im OTA Modus mache sonst nix anderes mehr
    }

    // Timeout ab wann empfangene Daten verworfen werden
    if (((millis() - mySerialTimeoutTimestamp) > mySerialTimeout) && (mySerialReadPointer > 0))
    {
        mySerialTimeoutTimestamp = 0l;
        mySerialReadPointer = 0;
    }
   
    if (!Serial.available()) return;
    mySerialTimeoutTimestamp = millis();
    if (mySerialReadPointer < MAXSERIALBUFFER)
    {
        char myReadChar = (char) Serial.read();
        if (myReadChar != mySerialEndChar)
        {
            if ((myReadChar > 31) && (myReadChar < 129))
            {
                mySerialBuffer[mySerialReadPointer] = myReadChar;
                mySerialReadPointer++;
            }
            return;
        }
        else
        {
            mySerialBuffer[mySerialReadPointer] = 0;
//          while (Serial.available())
//             Serial.read();
            processSerialMessage(String(mySerialBuffer));
            mySerialReadPointer = 0;
        }
    }
}
   
#ifdef HASLEDS
void processLEDBlinking()
{
    if ((myLED_Both_Blinking == false) && (myLED_Green_Blinking == false) && (myLED_Red_Blinking == false))
        return;
    if (millis()-LED_BLINKING_TIMESTAMP < LED_BLINKING_INTERVAL)
        return;
    LED_BLINKING_TIMESTAMP = millis();
   
    if (myLED_Both_Blinking)
    {
        if (myLED_Both_Blinking_Flag)
        {
            processLEDMessage("RED=ON");
            processLEDMessage("GREEN=ON");
        }
        else
        {
            processLEDMessage("RED=OFF");
            processLEDMessage("GREEN=OFF");
        }
        myLED_Both_Blinking_Flag = !myLED_Both_Blinking_Flag;
        return;
    }
    if ((myLED_Red_Blinking) && (myLED_Green_Blinking))
    {
        if (myLED_Red_Blinking_Flag)
        {
            processLEDMessage("RED=ON");
            processLEDMessage("GREEN=OFF");
        }
        else
        {
            processLEDMessage("RED=OFF");
            processLEDMessage("GREEN=ON");
        }
        myLED_Red_Blinking_Flag = !myLED_Red_Blinking_Flag;
        return;
    }
    if (myLED_Red_Blinking)
    {
        if (myLED_Red_Blinking_Flag)
            processLEDMessage("RED=ON");
        else
            processLEDMessage("RED=OFF");
        myLED_Red_Blinking_Flag = !myLED_Red_Blinking_Flag;
        return;
    }
    if (myLED_Green_Blinking)
    {
        if (myLED_Green_Blinking_Flag)
            processLEDMessage("GREEN=ON");
        else
            processLEDMessage("GREEN=OFF");
        myLED_Green_Blinking_Flag = !myLED_Green_Blinking_Flag;
        return;
    }
}
#endif

void processSerialMessage(String _myMessage)
{
    if ((_myMessage == nullptr) || (_myMessage.length() < 5))
        return;
   
    #ifdef HASLEDS
        if (_myMessage.startsWith("[LED]"))
        {
            _myMessage = _myMessage.substring(String("[LED]").length());
            processLEDMessage(_myMessage);
        }
        else
    #endif
    #ifdef HASDISPLAY
        if (_myMessage.startsWith("[SHOWIMAGE]"))
        {
            _myMessage = _myMessage.substring(String("[SHOWIMAGE]").length());
            processImageMessage(&_myMessage);
        }
        else
    #endif
    if (_myMessage.startsWith("[WIFIUPDATE]"))
    {
        _myMessage = _myMessage.substring(String("[WIFIUPDATE]").length());
        startWIFIServerForOTA(_myMessage);
    }
    else if (_myMessage.startsWith("[REBOOT]"))
    {
        #ifdef HASLEDS
            processLEDMessage("ALL=OFF");
        #endif
        #ifdef HASDISPLAY
            processSerialMessage("[2LINER]RESTART[NEWLINE]...");
        #endif
        ESP.restart();
    }
    #ifdef HASDISPLAY
    else if (_myMessage.startsWith("[5LINER]"))
    {
        _myMessage = _myMessage.substring(String("[5LINER]").length());
        splitStringToArray(_myMessage, "[NEWLINE]");
        display5Liner(&mySerialReadLines[0], &mySerialReadLines[1], &mySerialReadLines[2], &mySerialReadLines[3], &mySerialReadLines[4]);
    }
    else if (_myMessage.startsWith("[2LINER]"))
    {
        _myMessage = _myMessage.substring(String("[2LINER]").length());
        splitStringToArray(_myMessage, "[NEWLINE]");
        display2Liner(&mySerialReadLines[0], &mySerialReadLines[1]);
    }
    #endif
    else if (_myMessage.startsWith("[WARNING]"))
    {
        _myMessage = _myMessage.substring(String("[WARNING]").length());
        splitStringToArray(_myMessage, "[NEWLINE]");
        #ifdef HASLEDS
            saveLEDStates();
            processLEDMessage("ALL=OFF");
            processLEDMessage("GREEN=ON");
            processLEDMessage("RED=ON");
        #endif
        #ifdef HASDISPLAY
            displayWarning(&mySerialReadLines[0], &mySerialReadLines[1], &mySerialReadLines[2]);
        #endif
        delay(myWarningShowTime*1000);
        #ifdef HASLEDS
            processLEDMessage("ALL=OFF");
            restoreLEDStates();
        #endif
    }
    else if (_myMessage.startsWith("[ALARM]"))
    {
        _myMessage = _myMessage.substring(String("[ALARM]").length());
        splitStringToArray(_myMessage, "[NEWLINE]");
        #ifdef HASLEDS
            saveLEDStates();
            processLEDMessage("ALL=OFF");
            processLEDMessage("RED=ON");
            processLEDMessage("RED=BLINKING");
        #endif
        #ifdef HASDISPLAY
            displayAlarm(&mySerialReadLines[0], &mySerialReadLines[1], &mySerialReadLines[2]);
        #endif
        delay(myAlarmShowTime * 1000);
    }
    else if (_myMessage.startsWith("[INFO]"))
    {
        _myMessage = _myMessage.substring(String("[INFO]").length());
        splitStringToArray(_myMessage, "[NEWLINE]");
        #ifdef HASDISPLAY
            displayInfo(&mySerialReadLines[0], &mySerialReadLines[1], &mySerialReadLines[2]);
        #endif
    }
    #ifdef HASDISPLAY
        display.powerOff();
    #endif
}
#ifdef HASLEDS
    void processLEDMessage(String _myMessage)
    {
        _myMessage.toUpperCase();
       
        if (_myMessage.equals("RED=ON"))
            digitalWrite(PINLED_RED, HIGH);
        else if (_myMessage.equals("RED=OFF"))
            digitalWrite(PINLED_RED, LOW);
        else if (_myMessage.equals("GREEN=ON"))
            digitalWrite(PINLED_GREEN, HIGH);
        else if (_myMessage.equals("GREEN=OFF"))
            digitalWrite(PINLED_GREEN, LOW);
        else if (_myMessage.equals("ALL=OFF"))
        {
            processLEDMessage("GREEN=OFF");
            processLEDMessage("RED=OFF");
            myLED_Both_Blinking = false;
            myLED_Red_Blinking = false;
            myLED_Green_Blinking = false;
        }
        else if (_myMessage.equals("ALL=ON"))
        {
            processLEDMessage("GREEN=ON");
            processLEDMessage("RED=ON");
        }
        else if (_myMessage.equals("RED=BLINKING"))
           myLED_Red_Blinking = true;
        else if (_myMessage.equals("GREEN=BLINKING"))
           myLED_Green_Blinking = true;
        else if (_myMessage.equals("BOTH=BLINKING"))
           myLED_Both_Blinking = true; 
    }
#endif
#ifdef HASDISPLAY
void showStartImage()
{
    display.setRotation(myDisplay_Rotation);
    display.setFullWindow();
    display.clearScreen();
    display.fillScreen(GxEPD_WHITE);
    do
    {
        display.drawBitmap(0, 0, &epd_bitmap_trueNas_Start_Image[0], display.width(), display.height(), GxEPD_BLACK);
    } while (display.nextPage());  
}
void showPowerOffImage()
{
    display.setRotation(myDisplay_Rotation);
    display.setFullWindow();
    display.clearScreen();
    display.fillScreen(GxEPD_WHITE);
    do
    {
        display.drawBitmap(0, 0, &epd_bitmap_trueNas_PowerOFF_Image[0], display.width(), display.height(), GxEPD_BLACK);
    } while (display.nextPage());  
}
void showScrubbingImage()
{
    display.setRotation(myDisplay_Rotation);
    display.setFullWindow();
    display.clearScreen();
    display.fillScreen(GxEPD_WHITE);
    do
    {
        display.drawBitmap(0, 0, &epd_bitmap_zfs_scrubbing[0], display.width(), display.height(), GxEPD_BLACK);
    } while (display.nextPage());  
}

void processImageMessage(String* _myMessage)
{
    _myMessage->toUpperCase();
    if (_myMessage->equals("STARTING"))
        showStartImage();
    else if (_myMessage->equals("POWEROFF"))
        showPowerOffImage();
    else if (_myMessage->equals("SCRUBBING"))
        showScrubbingImage();
}

void display5Liner(String* _Line1, String* _Line2, String* _Line3, String* _Line4, String* _Line5)
{
    uint16_t myYPos[5] = {20, 73, 126, 179, 232};
    int16_t myX, myY;
    uint16_t myWidth, myHeight;
    display.setRotation(myDisplay_Rotation);
    display.setTextWrap(false);
    display.setTextColor(GxEPD_BLACK);
    display.setFont(&FreeMonoBold24pt7b);
    display.getTextBounds("aTAgy", 100, 100, &myX, &myY, &myWidth, &myHeight);
    display.setFullWindow();
    display.firstPage();
    do
    {
       
        display.setCursor(20,myYPos[0]+myHeight);
        display.print(*_Line1);
        display.setCursor(20,myYPos[1]+myHeight);
        display.print(*_Line2);
        display.setCursor(20,myYPos[2]+myHeight);
        display.print(*_Line3);
        display.setCursor(20,myYPos[3]+myHeight);
        display.print(*_Line4);
        display.setCursor(20,myYPos[4]+myHeight);
        display.print(*_Line5);
    } while (display.nextPage());
}
void displayAlarm(String* _Line1, String* _Line2, String* _Line3)
{
    int16_t myX, myY;
    uint16_t myWidth, myHeight;
   
    display.setRotation(myDisplay_Rotation);
    display.setTextWrap(false);
    display.setTextColor(GxEPD_BLACK);
    display.setFullWindow();
    display.fillScreen(GxEPD_WHITE);
    display.firstPage();
    do
    {
        display.setFont(&FreeMonoBold24pt7b);
        display.getTextBounds(*_Line1, 0, 100, &myX, &myY, &myWidth, &myHeight);
        display.setCursor((display.width()/2)-(myWidth/2), (display.height()/2)-(myHeight/2));
        display.print(*_Line1);
        if (_Line2->length() > 0)
        {
            display.setFont(&FreeMonoBold12pt7b);
            display.getTextBounds(*_Line2, 0, 100, &myX, &myY, &myWidth, &myHeight);
            display.setCursor((display.width()/2)-(myWidth/2), (display.height()*0.7));
            display.print(*_Line2);
            if (_Line3->length() > 0)
            {
                display.getTextBounds(*_Line3, 0, 100, &myX, &myY, &myWidth, &myHeight);
                display.setCursor((display.width()/2)-(myWidth/2), (display.height()*0.7+(3*myHeight)));
                display.print(*_Line3);
            }
        }
    } while (display.nextPage());
}

void displayInfo(String* _Line1, String* _Line2, String* _Line3)
{
    int16_t myX, myY;
    uint16_t myWidth, myHeight;
   
    display.setRotation(myDisplay_Rotation);
    display.setTextWrap(false);
    display.setTextColor(GxEPD_BLACK);
    display.setFullWindow();
    display.fillScreen(GxEPD_WHITE);
    display.firstPage();
    do
    {
        display.setFont(&FreeMonoBold24pt7b);
        display.getTextBounds(*_Line1, 0, 100, &myX, &myY, &myWidth, &myHeight);
        display.setCursor((display.width()/2)-(myWidth/2), (display.height()/2)-(myHeight/2));
        display.print(*_Line1);
        if (_Line2->length() > 0)
        {
            display.setFont(&FreeMonoBold12pt7b);
            display.getTextBounds(*_Line2, 0, 100, &myX, &myY, &myWidth, &myHeight);
            display.setCursor((display.width()/2)-(myWidth/2), (display.height()*0.7));
            display.print(*_Line2);
            if (_Line3->length() > 0)
            {
                display.getTextBounds(*_Line3, 0, 100, &myX, &myY, &myWidth, &myHeight);
                display.setCursor((display.width()/2)-(myWidth/2), (display.height()*0.7+(3*myHeight)));
                display.print(*_Line3);
            }
        }
    } while (display.nextPage());
}

void displayWarning(String* _Line1, String* _Line2, String* _Line3)
{
    int16_t myX, myY;
    uint16_t myWidth, myHeight;
   
    display.setRotation(myDisplay_Rotation);
    display.setTextWrap(false);
    display.setTextColor(GxEPD_BLACK);
    display.setFullWindow();
    display.fillScreen(GxEPD_WHITE);
    display.firstPage();
    do
    {
        display.setFont(&FreeMonoBold24pt7b);
        display.getTextBounds(*_Line1, 0, 100, &myX, &myY, &myWidth, &myHeight);
        display.setCursor((display.width()/2)-(myWidth/2), (display.height()/2)-(myHeight/2));
        display.print(*_Line1);
        if (_Line2->length() > 0)
        {
            display.setFont(&FreeMonoBold12pt7b);
            display.getTextBounds(*_Line2, 0, 100, &myX, &myY, &myWidth, &myHeight);
            display.setCursor((display.width()/2)-(myWidth/2), (display.height()*0.7));
            display.print(*_Line2);
            if (_Line3->length() > 0)
            {
                display.getTextBounds(*_Line3, 0, 100, &myX, &myY, &myWidth, &myHeight);
                display.setCursor((display.width()/2)-(myWidth/2), (display.height()*0.7+(3*myHeight)));
                display.print(*_Line3);
            }
        }
    } while (display.nextPage());
}

void display2Liner(String* _Line1, String* _Line2)
{
    int16_t myX, myY;
    uint16_t myWidth, myHeight;
   
    display.setRotation(myDisplay_Rotation);
    display.setTextWrap(false);
    display.setTextColor(GxEPD_BLACK);
    display.setFullWindow();
    display.fillScreen(GxEPD_WHITE);
    display.firstPage();
    do
    {
        display.setFont(&FreeMonoBold24pt7b);
        display.getTextBounds(*_Line1, 0, 100, &myX, &myY, &myWidth, &myHeight);
        display.setCursor((display.width()/2)-(myWidth/2), (display.height()/2)-(myHeight));
        display.print(*_Line1);
        if (_Line2->length() > 0)
        {
            display.getTextBounds(*_Line2, 0, 100, &myX, &myY, &myWidth, &myHeight);
            display.setCursor((display.width()/2)-(myWidth/2), (display.height()/2)+(myHeight*2));
            display.print(*_Line2);
        }
    } while (display.nextPage());
}
#endif
//==============================================================================================================
// Kram fuer OTA Updates

String buildOTAIndexPage()
{
  String myHTMLPage = "<html><h2>Firmware Update</h2><br>Aktuell installiert ist V" + PROGVERSION + "<br><br>";
  myHTMLPage += "Reboot des Displays erfolgt (eigentlich) automatisch...<br><br><br>";
  myHTMLPage += "<form method='POST' action='/update' enctype='multipart/form-data' id='upload_form'>";
  myHTMLPage += "<input type='file' name='update'>";
  myHTMLPage += "<input type='submit' value='Update'>";
  myHTMLPage += "</form><br>";
  myHTMLPage += "<a href=\"/abort\">OTA Firmware Modus Abbrechen</a>";
  myHTMLPage += "</html>";
  return (myHTMLPage);
}

void startWIFIServerForOTA(String _myString)
{
  String mySSID = "";
  String myPassword = "";
  // SSID muss mindestens gesetzt sein
  if ((_myString != nullptr) && (_myString.length() > 0))
  {
      if ((_myString.indexOf("SSID=") == 0) && (_myString.indexOf("&PASSWORD=") > 0))
      {
        mySSID = _myString.substring(String("SSID=").length(), _myString.indexOf("&PASSWORD="));
        myPassword = _myString.substring(_myString.indexOf("&PASSWORD=")+String("&PASSWORD=").length());
      }
      else if ((_myString.indexOf("SSID=") == 0))
      {
        mySSID = _myString.substring(String("SSID=").length());
        myPassword = "";
      }
  }
  if (connectToWiFi(mySSID, myPassword) == false) return;
  myOTAWebServer.on("/", HTTP_GET, []()
  {
    myOTAWebServer.sendHeader("Connection", "close");
    myOTAWebServer.send(200, "text/html", buildOTAIndexPage().c_str());
  });
  myOTAWebServer.on("/abort", HTTP_GET, []()
  {
    myOTAUpdateServerIsActive = false;
    disconnectAndStopWiFi();
    myOTAWebServer.sendHeader("Connection", "close");
    myOTAWebServer.send(200, "text/plain", "Beende Firmware Modus => Zurueck zum Anzeigemodus");
    #ifdef HASDISPLAY
        processSerialMessage("[2LINER]OTA Update[NEWLINE]Abgebrochen");
    #endif
    #ifdef HASLEDS
        processLEDMessage("ALL=OFF");
        restoreLEDStates();
    #endif
    return;
  });
  // -- Firmware hochladen ueber POST => Bloecke dann schreiben
  myOTAWebServer.on("/update", HTTP_POST, []()
  {
    bool myUpdateFailed = false;
    myOTAWebServer.sendHeader("Connection", "close");
    String myHTMLMessage = "<html>Alles OK - Display wird neu gestartet</html>";
    if (Update.hasError())
    {
        myUpdateFailed = true;
        myHTMLMessage = "<html>";
        myHTMLMessage += "<h2>Update Fehler</h2><br>";
        myHTMLMessage += "Fehler: " + String(Update.errorString()) + "<br><br>";
        myHTMLMessage += "Display wird NICHT neu gestartet - evtl nochmal probieren<br><br>";
        myHTMLMessage += "<a href=\"/\">Startseite</a></html>";
        processSerialMessage("[ALARM]Update Fehler[NEWLINE]Neu versuchen?");
    }
    myOTAWebServer.send(200, "text/html", myHTMLMessage.c_str());
 
    if (!myUpdateFailed)
    {
        #ifdef HASLEDS
            processLEDMessage("ALL=OFF");
        #endif
        ESP.restart();
    }
  }, []()
  {
    HTTPUpload& myFWUploadData = myOTAWebServer.upload();
    if (myFWUploadData.status == UPLOAD_FILE_START)
    {
      if (!Update.begin(UPDATE_SIZE_UNKNOWN))
      {
        /* Bei richtigem LED Pin leuchtet das automatisch
        #ifdef HASLEDS
            processLEDMessage("ALL=OFF");
            processLEDMessage("GREEN=ON");     
        #endif */
      }
    }
    else if (myFWUploadData.status == UPLOAD_FILE_WRITE)
    {
      if (Update.write(myFWUploadData.buf, myFWUploadData.currentSize) != myFWUploadData.currentSize)
      {
        /* siehe Update.begin()
        #ifdef HASLEDS
            processLEDMessage("ALL=OFF");
            delay(10);
            processLEDMessage("GREEN=ON");
            delay(10);
            processLEDMessage("ALL=OFF");
        #endif */
        ;
      }
    }
    else if (myFWUploadData.status == UPLOAD_FILE_END)
    {
      if (Update.end(true))
      {
        #ifdef HASLEDS
            processLEDMessage("ALL=OFF");
            processLEDMessage("GREEN=ON");
        #endif
      }
      else
      {
        #ifdef HASLEDS
            processLEDMessage("ALL=OFF");
            processLEDMessage("RED=ON");
        #endif
      }
    }
  });
  if (WiFi.isConnected())
  {
    myOTAWebServer.begin();
    myOTAUpdateServerIsActive = true;
    #ifdef HASLEDS
        saveLEDStates();
        processLEDMessage("ALL=OFF");
        processLEDMessage("RED=BLINKING");
        processLEDMessage("GREEN=BLINKING");
    #endif

    #ifdef HASDISPLAY
        processSerialMessage("[INFO]Firmware OTA[NEWLINE]Installiert: "+ PROGVERSION + "[NEWLINE]http://" + WiFi.localIP().toString());   
    #endif
  }
}
//--[ WiFi Basic Stuff ]-------------------------------------------------------------------------------------
bool connectToWiFi(String _mySSID, String _myWIFIPassword)
{
    uint8_t myWiFiRetryCounter = 0;
    if ((_mySSID == nullptr) || (_mySSID.length() == 0))
        return (WiFi.isConnected());
    if (_myWIFIPassword == nullptr)
        _myWIFIPassword = "";
    if (!WiFi.isConnected())
    {
        if (!WiFi.mode(WIFI_STA))
            return(false);
        WiFi.begin(_mySSID.c_str(), _myWIFIPassword.c_str());
        while (WiFi.status() != WL_CONNECTED)
        {
            // Versuche ~ 25 Sek den WIFI Connect, dann geb auf
            myWiFiRetryCounter++;
            delay(500);
            if (myWiFiRetryCounter > 50)
            {
                disconnectAndStopWiFi();
                processSerialMessage(String("[WARNING]WiFi-Error[NEWLINE]" + String("SSID: " +_mySSID)));
                return(false);
            }
        }
        if ((myHostID != nullptr) && (myHostID.length() > 0))
            MDNS.begin(myHostID);
    }
    return(WiFi.isConnected());
}

void disconnectAndStopWiFi()
{
    if (WiFi.isConnected())
        WiFi.disconnect(true, true);
    MDNS.end();
    WiFi.mode(WIFI_OFF);   
}
#ifdef HASLEDS
void saveLEDStates()
{
    myLED_Save_Green_State = digitalRead(PINLED_GREEN);
    myLED_Save_Red_State = digitalRead(PINLED_RED);
    myLED_Save_Both_Blinking = myLED_Both_Blinking;
    myLED_Save_Green_Blinking = myLED_Green_Blinking;
    myLED_Save_Red_Blinking = myLED_Red_Blinking;
}
void restoreLEDStates()
{
    digitalWrite(PINLED_GREEN, myLED_Save_Green_State);
    digitalWrite(PINLED_RED, myLED_Save_Red_State);
    myLED_Both_Blinking = myLED_Save_Both_Blinking;
    myLED_Green_Blinking = myLED_Save_Green_Blinking;
    myLED_Red_Blinking = myLED_Save_Red_Blinking;
}
#endif

void splitStringToArray(String _Input, String _Separator)
{
    uint8_t myIndex = 0;
    for (uint8_t i=0; i < SERIALREADLINES_MAX; i++)
        mySerialReadLines[i] = "";
   
    if (_Input.indexOf(_Separator) < 0)
    {
        mySerialReadLines[0] = _Input;
        return;
    }

    while ((_Input.indexOf(_Separator) >= 0) && (myIndex < SERIALREADLINES_MAX))
    {
        mySerialReadLines[myIndex] = _Input.substring(0, _Input.indexOf(_Separator));
        _Input = _Input.substring(_Separator.length() + mySerialReadLines[myIndex].length());
        myIndex++;
    }
    if ((_Input.length() > 0) && (myIndex < SERIALREADLINES_MAX))
        mySerialReadLines[myIndex] = _Input;
}
 

Anhänge

  • zfserr.png
    zfserr.png
    135,7 KB · Aufrufe: 86
  • start_truenas.jpg
    start_truenas.jpg
    38,1 KB · Aufrufe: 83
  • ota_update.jpg
    ota_update.jpg
    30,9 KB · Aufrufe: 90
  • myImages.zip
    myImages.zip
    20,8 KB · Aufrufe: 74
Zuletzt bearbeitet: (Update auf V0.3)
  • Gefällt mir
Reaktionen: chillking
Ja klar schneller wäre schöner aber ist ja jetzt keine so wichtige Sache die Anzeige - hehe halt mehr als was kann man mit dem was man rumliegen hat mal im Winter bei schlechtem Wetter kurz basteln was unnötig kompliziert ist.

Die LEDS hätten mir auch gereicht um zu sehen ob der Server Probleme hat.

Ich habe auch noch altes Filament das glaub 1 Jahr offen rumlag - das muss jetzt auch mal weg xD noch funktioniert es erstaunlich gut.

Aber mir gefallen halt ePaper Displays, weil man auch was anzeigen kann wenn die aus sind und die super ablesbar sind, deshalb habe ich mir da einige geholt die ich langsam mal irgendwo einbauen "muss" - von 2" bis 7" :D
 
Zuletzt bearbeitet:
Softwareseitig vom Display her bin ich bis auf ein poaar kleine Bigfioxes die ich sicher noch finden werde, die aber für den betrieb sicher keine ShowStopper sein werden fertig - und ich kann ja per einschaltbarem OTA auch wenn das eingebaut ist, dann problemlos einen Bugfix per Wifi draufmachen.

Ich schicke dazu einfach von der CLI des Truenas ein echo "[WIFIUPDATE]SSID=ABABAB&PASSWORD=BLABLABA" > /dev/ttysUSB0
und WiFi geht an und ein WebServer auf dem ich den Bugfix hochladen kann - super cool dass das bei den ESP32 mit ein paar Zeilen Code geht.

Wenn das "neue" PC Gehäuse da ist muss ich halt noch die Löcher in den 3D Druck Rahmen bohren für die Befestigung - ansonsten ist der Rahmen bis auf ein paar sehr kleine Ungenauigkeiten durch den Druck - und evtl weil das Filament durch das sehr lange Herumliegen etwas Wasser gezogen hat - für mich ausreichend perfekt geworden - sehr viel besser als befürchtet.

Der Rahmen ist stabil und das Display sitzt fast auf den 1/10mm perfekt :D
Die LED könnte 1mm tiefer drin sein - aber das auch wirklich das einzige das mich "stört".

Den ESP32 habe ich mit so superdickem doppelseitigem Klebeband hinten draufgepappt der hält für "ewig". Das hält selbst Outdoor bei Eis und Schnee und Regen und Hitze seit sehr vielen Jahren.

Die Haltenasen muss ich noch drucken - das geht aber superfix.

Und so schaut das aus ohne irgendeine Nachbearbeitung nur mit dem Finger kurz drübergewischet an den "Seitenwänden" da war minimales Stringing.


Jetzt gibt es nur noch einen Beitrag oder so mit den Scripten auf dem TrueNAS die das Display und das was anzeigt wird steuern - und dann ist das glaub zu 99,99% fertig. :D
 

Anhänge

  • rahmen_leer.jpg
    rahmen_leer.jpg
    31,9 KB · Aufrufe: 100
  • rahmen_ruecken_mitdisplay.jpg
    rahmen_ruecken_mitdisplay.jpg
    42,4 KB · Aufrufe: 98
  • rahmen_mit_display.jpg
    rahmen_mit_display.jpg
    93,2 KB · Aufrufe: 97
  • 20240129_104000.mp4
    1 MB
Zuletzt bearbeitet:
  • Gefällt mir
Reaktionen: XShocker22
hmmm da ich das Gehäuse wechsle auf ein Fractal R5 - weil alle anderen Server bei uns in soi einem drin sind - werde ich das eh auf extern etwas umbauen :D soibald das fertig ist kommt dann das - vorerst finale - Produkt

An Soft und Hardware ändert sich aber nichts gross ausser dass das halt USB extern angeschlossen wird statt intern - und halt das Display auf so einen Plexiglas Ständer kommt.

Die ESP32-S2 Verkabelung muss ich hier noch anpassen oben - da ist SPI auf anderen Default-Ports
 
Alternativ - oder zusätzlich zu LED Anzeige und ePaper-Display - habe ich noch Unterstützung für Analoganzeigen eingebaut :D weil ich mir glaub so eine Retro anazieg Schaltschrankdesign im Serverraum basteln will - aber erst wieder im Winter jetzt ist erst mal Sommer und Gartenzeit.

LED hat die Modi Rot grün an/aus, orange (R+G an) rot / grün einzeln oder abwechselnd blinkend.

ich lass die z-.b- beim Scrubbing blinken, rot wenn eine HDD ausgefallen ist, orange wenn der Platz eng wird und grün wenn alles passt etc.....

Die Ansteuerung bleibt natürlich gleich - ich nutze den im Linux/FreebSD Kernel bzw Kernelmodul eigentlich immer vorhanden USBSeriell Treiber und habe softwaremässig einfach ein Temrinal gemacht dass dann die Sachen darstellt die ich aus z.B. einem Script nach serielle schicke. also so wie "[LED]GREEN=ON"

Die #ifdef Zweige muss ich sicher mal schauen ob die passen, ich hab halt gerade einfach erst mal die Analogdisplay zusätzlich oder alternativ in Funktion haben wollen, dachte das wäre viel komplizierter so Displays anzusteuern - aber das ja super - die optionale Startnimation der Zeiger musste auch sein :D

Code:
#include <Arduino.h>
const String PROGVERSION="0.35";
const uint32_t mySERIALBAUDRATE = 9600;
const uint8_t myCPUMHZ = 80;
// #define HASDISPLAY
#define HASLEDS
#define HASANALOGDISPLAY

#ifdef HASANALOGDISPLAY         //   DAC bzw PWM    17 + 18
    #define ANALOGDISPLAYUSEPWM   // Benutze PWM ansonten DAC....
    #ifdef ANALOGDISPLAYUSEPWM
        uint32_t PWM_FREQ = 1000;
        uint16_t PWM_CHANNEL1 = 0;
        uint16_t PWM_CHANNEL2 = 1;
        uint16_t PWM_RESOLUTION = 8;
    #endif
    bool AnalogDisplayStartAnimation = true;

    const uint8_t ANALOGDISPLAY1_PIN = 17;
    const uint16_t ANALOGDISPLAY1_MAXVOLTVALUE = 233;
    const uint16_t ANALOGDISPLAY1_MINVOLTVALUE = 0;
    uint32_t ANALOGDISPLAY1_MAXVALUE = 0l;   // siehe String.toInt()
    uint32_t ANALOGDISPLAY1_MINVALUE = 0l;
    const uint8_t ANALOGDISPLAY2_PIN = 18;
    const uint16_t ANALOGDISPLAY2_MAXVOLTVALUE = 233;
    const uint16_t ANALOGDISPLAY2_MINVOLTVALUE = 0;
    uint32_t ANALOGDISPLAY2_MAXVALUE = 0l;
    uint32_t ANALOGDISPLAY2_MINVALUE = 0l;
    void processAnalogDisplayValue(String);
#endif

#ifdef HASDISPLAY
    #include <SPI.h>
    #include <GxEPD2_BW.h>
    #include "GxEPD2_display_selection.h"
    #include <Fonts/FreeMonoBold12pt7b.h>
    #include <Fonts/FreeMonoBold24pt7b.h>
    #include "myImages.h"
#endif


const uint8_t myWarningShowTime = 0;    // in Sekunden
const uint8_t myAlarmShowTime = 0;
#ifdef HASDISPLAY
    const uint8_t myDisplay_Rotation = 0;
#endif
#ifdef HASLEDS
    const uint8_t PINLED_GREEN = 19;
    const uint8_t PINLED_RED = 20;
    bool myLED_Green_Blinking = false;
    bool myLED_Red_Blinking = false;
    bool myLED_Green_Blinking_Flag = false;
    bool myLED_Red_Blinking_Flag = false;
    bool myLED_Both_Blinking = false;
    bool myLED_Both_Blinking_Flag = false;
    uint8_t myLED_Save_Green_State = LOW;
    uint8_t myLED_Save_Red_State = LOW;
    bool myLED_Save_Green_Blinking = false;
    bool myLED_Save_Red_Blinking = false;
    bool myLED_Save_Both_Blinking = false;
    uint64_t LED_BLINKING_INTERVAL = 500;
    uint64_t LED_BLINKING_TIMESTAMP = 0l;
#endif

const uint16_t MAXSERIALBUFFER = 2000;
char mySerialBuffer[MAXSERIALBUFFER];
const char mySerialEndChar = '\r';
uint64_t mySerialTimeout = 5000;
uint64_t mySerialTimeoutTimestamp = 0l;
uint16_t mySerialReadPointer = 0;

//---[ OTA Updates ]------------------------------
#include <WiFi.h>
#include <WiFiClient.h>
#include <WebServer.h>
#include <ESPmDNS.h>
#include <Update.h>
const String myHostID = "epapertruenas";
bool myOTAUpdateServerIsActive = false;
WebServer myOTAWebServer(80);
void startWIFIServerForOTA(String);
String buildOTAIndexPage();
bool connectToWiFi(String, String);
void disconnectAndStopWiFi();
//===============================================================================================
void loop();
void setup();
void processSerialMessage(String);
#ifdef HASLEDS
    void processLEDMessage(String);
    void processLEDBlinking();
#endif
#ifdef HASDISPLAY
    void processImageMessage(String*);
    void showStartImage();
    void showPowerOffImage();
    void showScrubbingImage();
#endif

const uint8_t SERIALREADLINES_MAX = 5;
String mySerialReadLines[SERIALREADLINES_MAX];
#ifdef HASDISPLAY
    void display5Liner(String*, String*, String*, String*, String*);
    void display2Liner(String*, String*);
    void displayWarning(String*, String*, String*);
    void displayInfo(String*, String*, String*);
    void displayAlarm(String*, String*, String*);
#endif
void splitStringToArray(String, String);
#ifdef HASLEDS
    void saveLEDStates();
    void restoreLEDStates();
#endif
//===============================================================================================

void setup()
{
    if (myCPUMHZ != 0)
        setCpuFrequencyMhz(myCPUMHZ);
    Serial.begin(mySERIALBAUDRATE);
 

    #ifdef HASLEDS
        pinMode(PINLED_GREEN, OUTPUT);
        pinMode(PINLED_RED, OUTPUT);
        digitalWrite(PINLED_RED, LOW);
        digitalWrite(PINLED_GREEN, HIGH);
    #endif
    // Default WiFi und Bluetooth aus
    disconnectAndStopWiFi();
    btStop();

    #ifdef HASDISPLAY
        display.init(0);
        delay(100);
    #endif
    #ifdef HASANALOGDISPLAY
        #ifdef ANALOGDISPLAYUSEPWM
            ledcSetup(PWM_CHANNEL1, PWM_FREQ, PWM_RESOLUTION);
            ledcAttachPin(ANALOGDISPLAY1_PIN, PWM_CHANNEL1);
            ledcSetup(PWM_CHANNEL2, PWM_FREQ, PWM_RESOLUTION);
            ledcAttachPin(ANALOGDISPLAY2_PIN, PWM_CHANNEL2);
            ledcWrite(PWM_CHANNEL1, 0);
            ledcWrite(PWM_CHANNEL2, 0);
            if (AnalogDisplayStartAnimation)
            {
                for (uint16_t i=0; i < ANALOGDISPLAY1_MAXVOLTVALUE; i++)
                {
                    ledcWrite(PWM_CHANNEL1, i);
                    ledcWrite(PWM_CHANNEL2, i);
                    delay(8);
                }
                delay(500);
                for (uint16_t i=ANALOGDISPLAY1_MAXVOLTVALUE; i > 0; i--)
                {
                    ledcWrite(PWM_CHANNEL1, i);
                    ledcWrite(PWM_CHANNEL2, i);
                    delay(8);
                }
            }
    
        #else
            dacWrite(ANALOGDISPLAY1_PIN, ANALOGDISPLAY1_MINVOLTVALUE);
            dacWrite(ANALOGDISPLAY2_PIN, ANALOGDISPLAY2_MINVOLTVALUE);
        #endif
    #endif
    // Default Startanzeige
    processSerialMessage("[LED]RED=BLINKING");
    processSerialMessage("[LED]GREEN=BLINKING");
    processSerialMessage("[SHOWIMAGE]STARTING");
}
//-------------------------------------------------------------------------------------------------------------------------------
void loop()
{

    #ifdef HASLEDS
        processLEDBlinking();
    #endif
    if (myOTAUpdateServerIsActive)
    {
        myOTAWebServer.handleClient();
        delay(1);
        return;      // im OTA Modus mache sonst nix anderes mehr
    }

    // Timeout ab wann empfangene Daten verworfen werden
    if (((millis() - mySerialTimeoutTimestamp) > mySerialTimeout) && (mySerialReadPointer > 0))
    {
        mySerialTimeoutTimestamp = 0l;
        mySerialReadPointer = 0;
    }
 
    if (!Serial.available()) return;
    mySerialTimeoutTimestamp = millis();
    if (mySerialReadPointer < MAXSERIALBUFFER)
    {
        char myReadChar = (char) Serial.read();
        if (myReadChar != mySerialEndChar)
        {
            if ((myReadChar > 31) && (myReadChar < 129))
            {
                mySerialBuffer[mySerialReadPointer] = myReadChar;
                mySerialReadPointer++;
            }
            return;
        }
        else
        {
            mySerialBuffer[mySerialReadPointer] = 0;
            processSerialMessage(String(mySerialBuffer));
            mySerialReadPointer = 0;
        }
    }
}
 
#ifdef HASLEDS
void processLEDBlinking()
{
    if ((myLED_Both_Blinking == false) && (myLED_Green_Blinking == false) && (myLED_Red_Blinking == false))
        return;
    if (millis()-LED_BLINKING_TIMESTAMP < LED_BLINKING_INTERVAL)
        return;
    LED_BLINKING_TIMESTAMP = millis();
 
    if (myLED_Both_Blinking)
    {
        if (myLED_Both_Blinking_Flag)
        {
            processLEDMessage("RED=ON");
            processLEDMessage("GREEN=ON");
        }
        else
        {
            processLEDMessage("RED=OFF");
            processLEDMessage("GREEN=OFF");
        }
        myLED_Both_Blinking_Flag = !myLED_Both_Blinking_Flag;
        return;
    }
    if ((myLED_Red_Blinking) && (myLED_Green_Blinking))
    {
        if (myLED_Red_Blinking_Flag)
        {
            processLEDMessage("RED=ON");
            processLEDMessage("GREEN=OFF");
        }
        else
        {
            processLEDMessage("RED=OFF");
            processLEDMessage("GREEN=ON");
        }
        myLED_Red_Blinking_Flag = !myLED_Red_Blinking_Flag;
        return;
    }
    if (myLED_Red_Blinking)
    {
        if (myLED_Red_Blinking_Flag)
            processLEDMessage("RED=ON");
        else
            processLEDMessage("RED=OFF");
        myLED_Red_Blinking_Flag = !myLED_Red_Blinking_Flag;
        return;
    }
    if (myLED_Green_Blinking)
    {
        if (myLED_Green_Blinking_Flag)
            processLEDMessage("GREEN=ON");
        else
            processLEDMessage("GREEN=OFF");
        myLED_Green_Blinking_Flag = !myLED_Green_Blinking_Flag;
        return;
    }
}
#endif

#ifdef HASANALOGDISPLAY


void processAnalogDisplayValue(String _myMessage)
{
    if (_myMessage.indexOf("=") > 0)
    {
        String myAnalogDisplayNumberString = _myMessage.substring(0, _myMessage.indexOf("="));
        String myAnalogDisplayValueString = _myMessage.substring(_myMessage.indexOf("=")+1);

        if (myAnalogDisplayNumberString.equals("1"))
        {
            uint32_t myRAWValue = myAnalogDisplayValueString.toInt();
            // % berechnen

            if ((ANALOGDISPLAY1_MAXVALUE-ANALOGDISPLAY1_MINVALUE) == 0)
                return;
            int64_t myPercentageValue = (myRAWValue * 100) / (ANALOGDISPLAY1_MAXVALUE-ANALOGDISPLAY1_MINVALUE);
            if (myPercentageValue > 100) myPercentageValue = 100;
            if (myPercentageValue < 0) myPercentageValue = 0;
            uint16_t myDACValue = (uint16_t) (ANALOGDISPLAY1_MAXVOLTVALUE * myPercentageValue) / 100;
        
            #ifdef ANALOGDISPLAYUSEPWM
                ledcWrite(PWM_CHANNEL1, myDACValue);
            #else
                dacWrite(ANALOGDISPLAY1_PIN, myDACValue);
            #endif
        }
        if (myAnalogDisplayNumberString.equals("2"))
        {
            uint32_t myRAWValue = myAnalogDisplayValueString.toInt();
            // % berechnen
            if ((ANALOGDISPLAY2_MAXVALUE-ANALOGDISPLAY2_MINVALUE) == 0)
                return;

            int64_t myPercentageValue = (myRAWValue * 100) / (ANALOGDISPLAY2_MAXVALUE-ANALOGDISPLAY2_MINVALUE);
            if (myPercentageValue > 100) myPercentageValue = 100;
            if (myPercentageValue < 0) myPercentageValue = 0;
            uint16_t myDACValue = (uint16_t) (ANALOGDISPLAY2_MAXVOLTVALUE * myPercentageValue) / 100;
            #ifdef ANALOGDISPLAYUSEPWM
                ledcWrite(PWM_CHANNEL2, myDACValue);
            #else
                dacWrite(ANALOGDISPLAY2_PIN, myDACValue);
            #endif
        }   
    }
}

void processAnalogDisplaySetMinValue(String _myString)
{
    if (_myString.startsWith("1"))
    {
        int16_t myPos = _myString.indexOf("=");
        if (myPos > 0)
        {
            String myValue = _myString.substring(myPos+1);
            ANALOGDISPLAY1_MINVALUE = myValue.toInt();
        }
    }
    else if (_myString.startsWith("2"))
    {
        int16_t myPos = _myString.indexOf("=");
        if (myPos > 0)
        {
            String myValue = _myString.substring(myPos+1);
            ANALOGDISPLAY2_MINVALUE = myValue.toInt();
        }
    }
}
void processAnalogDisplaySetMaxValue(String _myString)
{
    if (_myString.startsWith("1"))
    {
        int16_t myPos = _myString.indexOf("=");
        if (myPos > 0)
        {
            String myValue = _myString.substring(myPos+1);
            ANALOGDISPLAY1_MAXVALUE = myValue.toInt();
        }
    }
    else if (_myString.startsWith("2"))
    {
        int16_t myPos = _myString.indexOf("=");
        if (myPos > 0)
        {
            String myValue = _myString.substring(myPos+1);
            ANALOGDISPLAY2_MAXVALUE = myValue.toInt();
        }
    }
}

#endif

void processSerialMessage(String _myMessage)
{
    if ((_myMessage == nullptr) || (_myMessage.length() < 5))
        return;
 
    #ifdef HASLEDS
        if (_myMessage.startsWith("[LED]"))
        {
            _myMessage = _myMessage.substring(String("[LED]").length());
            processLEDMessage(_myMessage);
        }
        else
    #endif
 
    #ifdef HASANALOGDISPLAY
        if (_myMessage.startsWith("[ANALOGDISPLAY]MINVALUE"))
        {
            _myMessage = _myMessage.substring(String("[ANALOGDISPLAY]MINVALUE").length());
            processAnalogDisplaySetMinValue(_myMessage);
        }
        else if (_myMessage.startsWith("[ANALOGDISPLAY]MAXVALUE"))
        {
            _myMessage = _myMessage.substring(String("[ANALOGDISPLAY]MAXVALUE").length());
            processAnalogDisplaySetMaxValue(_myMessage);
        }
        else if (_myMessage.startsWith("[ANALOGDISPLAY]SETVALUE"))
        {
            _myMessage = _myMessage.substring(String("[ANALOGDISPLAY]SETVALUE").length());
            processAnalogDisplayValue(_myMessage);
        }

    #endif
    #ifdef HASDISPLAY
        if (_myMessage.startsWith("[SHOWIMAGE]"))
        {
            _myMessage = _myMessage.substring(String("[SHOWIMAGE]").length());
            processImageMessage(&_myMessage);
        }
        else
    #endif
    if (_myMessage.startsWith("[WIFIUPDATE]"))
    {
        _myMessage = _myMessage.substring(String("[WIFIUPDATE]").length());
        startWIFIServerForOTA(_myMessage);
    }
    else if (_myMessage.startsWith("[REBOOT]"))
    {
        #ifdef HASLEDS
            processLEDMessage("ALL=OFF");
        #endif
        #ifdef HASDISPLAY
            processSerialMessage("[2LINER]RESTART[NEWLINE]...");
        #endif
        ESP.restart();
    }
    #ifdef HASDISPLAY
    else if (_myMessage.startsWith("[5LINER]"))
    {
        _myMessage = _myMessage.substring(String("[5LINER]").length());
        splitStringToArray(_myMessage, "[NEWLINE]");
        display5Liner(&mySerialReadLines[0], &mySerialReadLines[1], &mySerialReadLines[2], &mySerialReadLines[3], &mySerialReadLines[4]);
    }
    else if (_myMessage.startsWith("[2LINER]"))
    {
        _myMessage = _myMessage.substring(String("[2LINER]").length());
        splitStringToArray(_myMessage, "[NEWLINE]");
        display2Liner(&mySerialReadLines[0], &mySerialReadLines[1]);
    }
    #endif
    else if (_myMessage.startsWith("[WARNING]"))
    {
        _myMessage = _myMessage.substring(String("[WARNING]").length());
        splitStringToArray(_myMessage, "[NEWLINE]");
        #ifdef HASLEDS
            saveLEDStates();
            processLEDMessage("ALL=OFF");
            processLEDMessage("GREEN=ON");
            processLEDMessage("RED=ON");
        #endif
        #ifdef HASDISPLAY
            displayWarning(&mySerialReadLines[0], &mySerialReadLines[1], &mySerialReadLines[2]);
        #endif
        delay(myWarningShowTime*1000);
        #ifdef HASLEDS
            processLEDMessage("ALL=OFF");
            restoreLEDStates();
        #endif
    }
    else if (_myMessage.startsWith("[ALARM]"))
    {
        _myMessage = _myMessage.substring(String("[ALARM]").length());
        splitStringToArray(_myMessage, "[NEWLINE]");
        #ifdef HASLEDS
            saveLEDStates();
            processLEDMessage("ALL=OFF");
            processLEDMessage("RED=ON");
            processLEDMessage("RED=BLINKING");
        #endif
        #ifdef HASDISPLAY
            displayAlarm(&mySerialReadLines[0], &mySerialReadLines[1], &mySerialReadLines[2]);
        #endif
        delay(myAlarmShowTime * 1000);
    }
    else if (_myMessage.startsWith("[INFO]"))
    {
        _myMessage = _myMessage.substring(String("[INFO]").length());
        splitStringToArray(_myMessage, "[NEWLINE]");
        #ifdef HASDISPLAY
            displayInfo(&mySerialReadLines[0], &mySerialReadLines[1], &mySerialReadLines[2]);
        #endif
    }
    #ifdef HASDISPLAY
        display.powerOff();
    #endif
}
#ifdef HASLEDS
    void processLEDMessage(String _myMessage)
    {
        _myMessage.toUpperCase();
    
        if (_myMessage.equals("RED=ON"))
            digitalWrite(PINLED_RED, HIGH);
        else if (_myMessage.equals("RED=OFF"))
            digitalWrite(PINLED_RED, LOW);
        else if (_myMessage.equals("GREEN=ON"))
            digitalWrite(PINLED_GREEN, HIGH);
        else if (_myMessage.equals("GREEN=OFF"))
            digitalWrite(PINLED_GREEN, LOW);
        else if (_myMessage.equals("ALL=OFF"))
        {
            processLEDMessage("GREEN=OFF");
            processLEDMessage("RED=OFF");
            myLED_Both_Blinking = false;
            myLED_Red_Blinking = false;
            myLED_Green_Blinking = false;
        }
        else if (_myMessage.equals("ALL=ON"))
        {
            processLEDMessage("GREEN=ON");
            processLEDMessage("RED=ON");
        }
        else if (_myMessage.equals("RED=BLINKING"))
           myLED_Red_Blinking = true;
        else if (_myMessage.equals("GREEN=BLINKING"))
           myLED_Green_Blinking = true;
        else if (_myMessage.equals("BOTH=BLINKING"))
           myLED_Both_Blinking = true;
    }
#endif
#ifdef HASDISPLAY
void showStartImage()
{
    display.setRotation(myDisplay_Rotation);
    display.setFullWindow();
    display.clearScreen();
    display.fillScreen(GxEPD_WHITE);
    do
    {
        display.drawBitmap(0, 0, &epd_bitmap_trueNas_Start_Image[0], display.width(), display.height(), GxEPD_BLACK);
    } while (display.nextPage());
}
void showPowerOffImage()
{
    display.setRotation(myDisplay_Rotation);
    display.setFullWindow();
    display.clearScreen();
    display.fillScreen(GxEPD_WHITE);
    do
    {
        display.drawBitmap(0, 0, &epd_bitmap_trueNas_PowerOFF_Image[0], display.width(), display.height(), GxEPD_BLACK);
    } while (display.nextPage());
}
void showScrubbingImage()
{
    display.setRotation(myDisplay_Rotation);
    display.setFullWindow();
    display.clearScreen();
    display.fillScreen(GxEPD_WHITE);
    do
    {
        display.drawBitmap(0, 0, &epd_bitmap_zfs_scrubbing[0], display.width(), display.height(), GxEPD_BLACK);
    } while (display.nextPage());
}

void processImageMessage(String* _myMessage)
{
    _myMessage->toUpperCase();
    if (_myMessage->equals("STARTING"))
        showStartImage();
    else if (_myMessage->equals("POWEROFF"))
        showPowerOffImage();
    else if (_myMessage->equals("SCRUBBING"))
        showScrubbingImage();
}

void display5Liner(String* _Line1, String* _Line2, String* _Line3, String* _Line4, String* _Line5)
{
    uint16_t myYPos[5] = {20, 73, 126, 179, 232};
    int16_t myX, myY;
    uint16_t myWidth, myHeight;
    display.setRotation(myDisplay_Rotation);
    display.setTextWrap(false);
    display.setTextColor(GxEPD_BLACK);
    display.setFont(&FreeMonoBold24pt7b);
    display.getTextBounds("aTAgy", 100, 100, &myX, &myY, &myWidth, &myHeight);
    display.setFullWindow();
    display.firstPage();
    do
    {
    
        display.setCursor(20,myYPos[0]+myHeight);
        display.print(*_Line1);
        display.setCursor(20,myYPos[1]+myHeight);
        display.print(*_Line2);
        display.setCursor(20,myYPos[2]+myHeight);
        display.print(*_Line3);
        display.setCursor(20,myYPos[3]+myHeight);
        display.print(*_Line4);
        display.setCursor(20,myYPos[4]+myHeight);
        display.print(*_Line5);
    } while (display.nextPage());
}
void displayAlarm(String* _Line1, String* _Line2, String* _Line3)
{
    int16_t myX, myY;
    uint16_t myWidth, myHeight;
 
    display.setRotation(myDisplay_Rotation);
    display.setTextWrap(false);
    display.setTextColor(GxEPD_BLACK);
    display.setFullWindow();
    display.fillScreen(GxEPD_WHITE);
    display.firstPage();
    do
    {
        display.setFont(&FreeMonoBold24pt7b);
        display.getTextBounds(*_Line1, 0, 100, &myX, &myY, &myWidth, &myHeight);
        display.setCursor((display.width()/2)-(myWidth/2), (display.height()/2)-(myHeight/2));
        display.print(*_Line1);
        if (_Line2->length() > 0)
        {
            display.setFont(&FreeMonoBold12pt7b);
            display.getTextBounds(*_Line2, 0, 100, &myX, &myY, &myWidth, &myHeight);
            display.setCursor((display.width()/2)-(myWidth/2), (display.height()*0.7));
            display.print(*_Line2);
            if (_Line3->length() > 0)
            {
                display.getTextBounds(*_Line3, 0, 100, &myX, &myY, &myWidth, &myHeight);
                display.setCursor((display.width()/2)-(myWidth/2), (display.height()*0.7+(3*myHeight)));
                display.print(*_Line3);
            }
        }
    } while (display.nextPage());
}

void displayInfo(String* _Line1, String* _Line2, String* _Line3)
{
    int16_t myX, myY;
    uint16_t myWidth, myHeight;
 
    display.setRotation(myDisplay_Rotation);
    display.setTextWrap(false);
    display.setTextColor(GxEPD_BLACK);
    display.setFullWindow();
    display.fillScreen(GxEPD_WHITE);
    display.firstPage();
    do
    {
        display.setFont(&FreeMonoBold24pt7b);
        display.getTextBounds(*_Line1, 0, 100, &myX, &myY, &myWidth, &myHeight);
        display.setCursor((display.width()/2)-(myWidth/2), (display.height()/2)-(myHeight/2));
        display.print(*_Line1);
        if (_Line2->length() > 0)
        {
            display.setFont(&FreeMonoBold12pt7b);
            display.getTextBounds(*_Line2, 0, 100, &myX, &myY, &myWidth, &myHeight);
            display.setCursor((display.width()/2)-(myWidth/2), (display.height()*0.7));
            display.print(*_Line2);
            if (_Line3->length() > 0)
            {
                display.getTextBounds(*_Line3, 0, 100, &myX, &myY, &myWidth, &myHeight);
                display.setCursor((display.width()/2)-(myWidth/2), (display.height()*0.7+(3*myHeight)));
                display.print(*_Line3);
            }
        }
    } while (display.nextPage());
}

void displayWarning(String* _Line1, String* _Line2, String* _Line3)
{
    int16_t myX, myY;
    uint16_t myWidth, myHeight;
 
    display.setRotation(myDisplay_Rotation);
    display.setTextWrap(false);
    display.setTextColor(GxEPD_BLACK);
    display.setFullWindow();
    display.fillScreen(GxEPD_WHITE);
    display.firstPage();
    do
    {
        display.setFont(&FreeMonoBold24pt7b);
        display.getTextBounds(*_Line1, 0, 100, &myX, &myY, &myWidth, &myHeight);
        display.setCursor((display.width()/2)-(myWidth/2), (display.height()/2)-(myHeight/2));
        display.print(*_Line1);
        if (_Line2->length() > 0)
        {
            display.setFont(&FreeMonoBold12pt7b);
            display.getTextBounds(*_Line2, 0, 100, &myX, &myY, &myWidth, &myHeight);
            display.setCursor((display.width()/2)-(myWidth/2), (display.height()*0.7));
            display.print(*_Line2);
            if (_Line3->length() > 0)
            {
                display.getTextBounds(*_Line3, 0, 100, &myX, &myY, &myWidth, &myHeight);
                display.setCursor((display.width()/2)-(myWidth/2), (display.height()*0.7+(3*myHeight)));
                display.print(*_Line3);
            }
        }
    } while (display.nextPage());
}

void display2Liner(String* _Line1, String* _Line2)
{
    int16_t myX, myY;
    uint16_t myWidth, myHeight;
 
    display.setRotation(myDisplay_Rotation);
    display.setTextWrap(false);
    display.setTextColor(GxEPD_BLACK);
    display.setFullWindow();
    display.fillScreen(GxEPD_WHITE);
    display.firstPage();
    do
    {
        display.setFont(&FreeMonoBold24pt7b);
        display.getTextBounds(*_Line1, 0, 100, &myX, &myY, &myWidth, &myHeight);
        display.setCursor((display.width()/2)-(myWidth/2), (display.height()/2)-(myHeight));
        display.print(*_Line1);
        if (_Line2->length() > 0)
        {
            display.getTextBounds(*_Line2, 0, 100, &myX, &myY, &myWidth, &myHeight);
            display.setCursor((display.width()/2)-(myWidth/2), (display.height()/2)+(myHeight*2));
            display.print(*_Line2);
        }
    } while (display.nextPage());
}
#endif
//==============================================================================================================
// Kram fuer OTA Updates

String buildOTAIndexPage()
{
  String myHTMLPage = "<html><h2>Firmware Update</h2><br>Aktuell installiert ist V" + PROGVERSION + "<br><br>";
  myHTMLPage += "Reboot des Displays erfolgt (eigentlich) automatisch...<br><br><br>";
  myHTMLPage += "<form method='POST' action='/update' enctype='multipart/form-data' id='upload_form'>";
  myHTMLPage += "<input type='file' name='update'>";
  myHTMLPage += "<input type='submit' value='Update'>";
  myHTMLPage += "</form><br>";
  myHTMLPage += "<a href=\"/abort\">OTA Firmware Modus Abbrechen</a>";
  myHTMLPage += "</html>";
  return (myHTMLPage);
}

void startWIFIServerForOTA(String _myString)
{
  String mySSID = "";
  String myPassword = "";
  // SSID muss mindestens gesetzt sein
  if ((_myString != nullptr) && (_myString.length() > 0))
  {
      if ((_myString.indexOf("SSID=") == 0) && (_myString.indexOf("&PASSWORD=") > 0))
      {
        mySSID = _myString.substring(String("SSID=").length(), _myString.indexOf("&PASSWORD="));
        myPassword = _myString.substring(_myString.indexOf("&PASSWORD=")+String("&PASSWORD=").length());
      }
      else if ((_myString.indexOf("SSID=") == 0))
      {
        mySSID = _myString.substring(String("SSID=").length());
        myPassword = "";
      }
  }
  if (connectToWiFi(mySSID, myPassword) == false) return;
  myOTAWebServer.on("/", HTTP_GET, []()
  {
    myOTAWebServer.sendHeader("Connection", "close");
    myOTAWebServer.send(200, "text/html", buildOTAIndexPage().c_str());
  });
  myOTAWebServer.on("/abort", HTTP_GET, []()
  {
    myOTAUpdateServerIsActive = false;
    disconnectAndStopWiFi();
    myOTAWebServer.sendHeader("Connection", "close");
    myOTAWebServer.send(200, "text/plain", "Beende Firmware Modus => Zurueck zum Anzeigemodus");
    #ifdef HASDISPLAY
        processSerialMessage("[2LINER]OTA Update[NEWLINE]Abgebrochen");
    #endif
    #ifdef HASLEDS
        processLEDMessage("ALL=OFF");
        restoreLEDStates();
    #endif
    if (getCpuFrequencyMhz() != myCPUMHZ)
        setCpuFrequencyMhz(myCPUMHZ);
    return;
  });
  // -- Firmware hochladen ueber POST => Bloecke dann schreiben
  myOTAWebServer.on("/update", HTTP_POST, []()
  {
    bool myUpdateFailed = false;
    myOTAWebServer.sendHeader("Connection", "close");
    String myHTMLMessage = "<html>Alles OK - Display wird neu gestartet</html>";
    if (Update.hasError())
    {
        myUpdateFailed = true;
        myHTMLMessage = "<html>";
        myHTMLMessage += "<h2>Update Fehler</h2><br>";
        myHTMLMessage += "Fehler: " + String(Update.errorString()) + "<br><br>";
        myHTMLMessage += "Display wird NICHT neu gestartet - evtl nochmal probieren<br><br>";
        myHTMLMessage += "<a href=\"/\">Startseite</a></html>";
        processSerialMessage("[ALARM]Update Fehler[NEWLINE]Neu versuchen?");
    }
    myOTAWebServer.send(200, "text/html", myHTMLMessage.c_str());
 
    if (!myUpdateFailed)
    {
        #ifdef HASLEDS
            processLEDMessage("ALL=OFF");
        #endif
        ESP.restart();
    }
  }, []()
  {
    HTTPUpload& myFWUploadData = myOTAWebServer.upload();
    if (myFWUploadData.status == UPLOAD_FILE_START)
    {
      if (!Update.begin(UPDATE_SIZE_UNKNOWN))
      {
        /* Bei richtigem LED Pin leuchtet das automatisch
        #ifdef HASLEDS
            processLEDMessage("ALL=OFF");
            processLEDMessage("GREEN=ON");  
        #endif */
      }
    }
    else if (myFWUploadData.status == UPLOAD_FILE_WRITE)
    {
      if (Update.write(myFWUploadData.buf, myFWUploadData.currentSize) != myFWUploadData.currentSize)
      {
        /* siehe Update.begin()
        #ifdef HASLEDS
            processLEDMessage("ALL=OFF");
            delay(10);
            processLEDMessage("GREEN=ON");
            delay(10);
            processLEDMessage("ALL=OFF");
        #endif */
        ;
      }
    }
    else if (myFWUploadData.status == UPLOAD_FILE_END)
    {
      if (Update.end(true))
      {
        #ifdef HASLEDS
            processLEDMessage("ALL=OFF");
            processLEDMessage("GREEN=ON");
        #endif
      }
      else
      {
        #ifdef HASLEDS
            processLEDMessage("ALL=OFF");
            processLEDMessage("RED=ON");
        #endif
      }
    }
  });
  if (WiFi.isConnected())
  {
    myOTAWebServer.begin();
    myOTAUpdateServerIsActive = true;
    #ifdef HASLEDS
        saveLEDStates();
        processLEDMessage("ALL=OFF");
        processLEDMessage("RED=BLINKING");
        processLEDMessage("GREEN=BLINKING");
    #endif

    #ifdef HASDISPLAY
        processSerialMessage("[INFO]Firmware OTA[NEWLINE]Installiert: "+ PROGVERSION + "[NEWLINE]http://" + WiFi.localIP().toString());
    #endif
  }
}
//--[ WiFi Basic Stuff ]-------------------------------------------------------------------------------------
bool connectToWiFi(String _mySSID, String _myWIFIPassword)
{
    uint8_t myWiFiRetryCounter = 0;
    if ((_mySSID == nullptr) || (_mySSID.length() == 0))
        return (WiFi.isConnected());
    if (_myWIFIPassword == nullptr)
        _myWIFIPassword = "";
    if (!WiFi.isConnected())
    {
        if (!WiFi.mode(WIFI_STA))
            return(false);
        WiFi.begin(_mySSID.c_str(), _myWIFIPassword.c_str());
        while (WiFi.status() != WL_CONNECTED)
        {
            // Versuche ~ 25 Sek den WIFI Connect, dann geb auf
            myWiFiRetryCounter++;
            delay(500);
            if (myWiFiRetryCounter > 50)
            {
                disconnectAndStopWiFi();
                processSerialMessage(String("[WARNING]WiFi-Error[NEWLINE]" + String("SSID: " +_mySSID)));
                return(false);
            }
        }
        if ((myHostID != nullptr) && (myHostID.length() > 0))
            MDNS.begin(myHostID);
    }
    return(WiFi.isConnected());
}

void disconnectAndStopWiFi()
{
    if (WiFi.isConnected())
        WiFi.disconnect(true, true);
    MDNS.end();
    WiFi.mode(WIFI_OFF);
}
#ifdef HASLEDS
void saveLEDStates()
{
    myLED_Save_Green_State = digitalRead(PINLED_GREEN);
    myLED_Save_Red_State = digitalRead(PINLED_RED);
    myLED_Save_Both_Blinking = myLED_Both_Blinking;
    myLED_Save_Green_Blinking = myLED_Green_Blinking;
    myLED_Save_Red_Blinking = myLED_Red_Blinking;
}
void restoreLEDStates()
{
    digitalWrite(PINLED_GREEN, myLED_Save_Green_State);
    digitalWrite(PINLED_RED, myLED_Save_Red_State);
    myLED_Both_Blinking = myLED_Save_Both_Blinking;
    myLED_Green_Blinking = myLED_Save_Green_Blinking;
    myLED_Red_Blinking = myLED_Save_Red_Blinking;
}
#endif

void splitStringToArray(String _Input, String _Separator)
{
    uint8_t myIndex = 0;
    for (uint8_t i=0; i < SERIALREADLINES_MAX; i++)
        mySerialReadLines[i] = "";
 
    if (_Input.indexOf(_Separator) < 0)
    {
        mySerialReadLines[0] = _Input;
        return;
    }

    while ((_Input.indexOf(_Separator) >= 0) && (myIndex < SERIALREADLINES_MAX))
    {
        mySerialReadLines[myIndex] = _Input.substring(0, _Input.indexOf(_Separator));
        _Input = _Input.substring(_Separator.length() + mySerialReadLines[myIndex].length());
        myIndex++;
    }
    if ((_Input.length() > 0) && (myIndex < SERIALREADLINES_MAX))
        mySerialReadLines[myIndex] = _Input;
}


Das aktuell mal die vorläufige Endversion die jeder der Server dann hier bekommt - halt auf einem kleinen selbstgedruckten Ständer.
 

Anhänge

  • 20240515_093616.mp4
    1,9 MB
Zuletzt bearbeitet:
  • Gefällt mir
Reaktionen: chillking
Zurück
Oben