diff --git a/.DS_Store b/.DS_Store deleted file mode 100644 index 66e07fb..0000000 Binary files a/.DS_Store and /dev/null differ diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 0000000..8478dea --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1 @@ +custom: ['https://donate.softwarecrash.de'] diff --git a/.github/workflows/ISSUE_WORKFLOW.yaml b/.github/workflows/ISSUE_WORKFLOW.yaml new file mode 100644 index 0000000..d5cd3cf --- /dev/null +++ b/.github/workflows/ISSUE_WORKFLOW.yaml @@ -0,0 +1,22 @@ +name: Close inactive issues +on: + schedule: + - cron: "30 1 * * *" + +jobs: + close-issues: + runs-on: ubuntu-latest + permissions: + issues: write + pull-requests: write + steps: + - uses: actions/stale@v5 + with: + days-before-issue-stale: 30 + days-before-issue-close: 14 + stale-issue-label: "stale" + stale-issue-message: "This issue is stale because it has been open for 30 days with no activity." + close-issue-message: "This issue was closed because it has been inactive for 14 days since being marked as stale." + days-before-pr-stale: -1 + days-before-pr-close: -1 + repo-token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/update_wewbflash.yml b/.github/workflows/update_wewbflash.yml new file mode 100644 index 0000000..b41e54a --- /dev/null +++ b/.github/workflows/update_wewbflash.yml @@ -0,0 +1,106 @@ +name: Update Firmware Files and Manifests + +on: + release: + types: [published, edited] + workflow_dispatch: + +jobs: + update-firmware: + if: github.repository == 'softwarecrash/BLLEDController-NG' + runs-on: ubuntu-latest + + steps: + - name: Abort if running in upstream repo + if: github.repository != 'softwarecrash/BLLEDController-NG' + run: | + echo "❌ Running in upstream repo: ${{ github.repository }}" + exit 1 + + - name: Checkout Repository + uses: actions/checkout@v3 + + - name: Set up Git + run: | + git config --global user.name 'GitHub Actions' + git config --global user.email 'actions@github.com' + + - name: Download Last 3 Releases + 3 Pre-Releases + id: fetch-all + uses: actions/github-script@v6 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + const fs = require('fs'); + const owner = context.repo.owner; + const repo = context.repo.repo; + + const releases = await github.rest.repos.listReleases({ owner, repo }); + const stable = []; + const pre = []; + + for (const rel of releases.data) { + if (rel.draft) continue; + (rel.prerelease ? pre : stable).push(rel); + if (stable.length >= 3 && pre.length >= 3) break; + } + + const selected = [...stable.slice(0, 3), ...pre.slice(0, 3)]; + const firmwareList = []; + + for (const release of selected) { + const tag = release.tag_name; + const version = tag.replace(/^v/gi, ''); + const isPre = release.prerelease; + const assets = release.assets.filter(a => a.name.endsWith('.bin')); + + for (const asset of assets) { + const dl = await github.rest.repos.getReleaseAsset({ + owner, + repo, + asset_id: asset.id, + headers: { Accept: 'application/octet-stream' } + }); + fs.writeFileSync(asset.name, Buffer.from(dl.data)); + firmwareList.push({ + version: version, + prerelease: isPre, + file: asset.name + }); + console.log(`Downloaded: ${asset.name}`); + } + } + + fs.writeFileSync('firmware_meta.json', JSON.stringify(firmwareList, null, 2)); + + - name: Clear and Prepare /docs/firmware + run: | + mkdir -p docs/firmware + rm -f docs/firmware/*.bin + rm -f docs/firmware/*.json + cp *.bin docs/firmware/ + echo "Updated at $(date -u)" > docs/firmware/last_update.txt + cp firmware_meta.json docs/firmware/firmware.json + + - name: Generate Manifest Files for ESP Web Tools + run: node generateRelease.js + working-directory: ./docs + + - name: Commit and Push Changes (only if needed) + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + git config user.name "GitHub Actions" + git config user.email "actions@github.com" + git remote set-url origin https://x-access-token:${GH_TOKEN}@github.com/softwarecrash/BLLEDController-NG.git + git fetch origin main + git checkout main + git add -f docs/firmware + + if git diff --cached --quiet; then + echo "✅ Keine Änderungen – kein Push." + else + git commit -m "Update firmware and manifests" + git pull --rebase origin main + git push origin main + fi diff --git a/.gitignore b/.gitignore index 174cb51..c503085 100644 --- a/.gitignore +++ b/.gitignore @@ -1,11 +1,10 @@ .pio -.vscode/.browse.c_cpp.db* -.vscode/c_cpp_properties.json -.vscode/launch.json -.vscode/ipch +.vscode +.firmware build/ BLLEDController.code-workspace .python-version - -# generated .h files from html -# src/www/setuppage.h Still needs this for compilation. \ No newline at end of file +src/www/www.h +.DS_Store +**/.DS_Store +docs/firmware \ No newline at end of file diff --git a/.theia/launch.json b/.theia/launch.json deleted file mode 100644 index 7e4253b..0000000 --- a/.theia/launch.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - // Use IntelliSense to learn about possible attributes. - // Hover to view descriptions of existing attributes. - "version": "0.2.0", - "configurations": [ - - ] -} diff --git a/.vs/BLLEDController/v16/.suo b/.vs/BLLEDController/v16/.suo deleted file mode 100644 index 121a984..0000000 Binary files a/.vs/BLLEDController/v16/.suo and /dev/null differ diff --git a/.vs/slnx.sqlite b/.vs/slnx.sqlite deleted file mode 100644 index 25b3cee..0000000 Binary files a/.vs/slnx.sqlite and /dev/null differ diff --git a/.vscode/arduino.json b/.vscode/arduino.json deleted file mode 100644 index a8672d7..0000000 --- a/.vscode/arduino.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "configuration": "xtal=80,vt=flash,exception=disabled,stacksmash=disabled,ssl=all,mmu=3232,non32xfer=fast,eesz=4M2M,ip=lm2f,dbg=Disabled,lvl=None____,wipe=none,baud=921600", - "board": "esp8266:esp8266:d1_mini" -} \ No newline at end of file diff --git a/.vscode/extensions.json b/.vscode/extensions.json deleted file mode 100644 index 080e70d..0000000 --- a/.vscode/extensions.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - // See http://go.microsoft.com/fwlink/?LinkId=827846 - // for the documentation about the extensions.json format - "recommendations": [ - "platformio.platformio-ide" - ], - "unwantedRecommendations": [ - "ms-vscode.cpptools-extension-pack" - ] -} diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index 567aba2..0000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,38 +0,0 @@ -{ - "C_Cpp.errorSquiggles": "disabled", - "files.associations": { - "string": "cpp", - "*.tcc": "cpp", - "optional": "cpp", - "istream": "cpp", - "ostream": "cpp", - "ratio": "cpp", - "system_error": "cpp", - "array": "cpp", - "functional": "cpp", - "regex": "cpp", - "tuple": "cpp", - "type_traits": "cpp", - "utility": "cpp", - "variant": "cpp", - "__bit_reference": "cpp", - "__hash_table": "cpp", - "__split_buffer": "cpp", - "__tree": "cpp", - "deque": "cpp", - "initializer_list": "cpp", - "map": "cpp", - "set": "cpp", - "string_view": "cpp", - "unordered_map": "cpp", - "vector": "cpp", - "filesystem": "cpp", - "fstream": "cpp", - "locale": "cpp", - "random": "cpp", - "sstream": "cpp", - "cmath": "cpp", - "algorithm": "cpp" - }, - "cmake.configureOnOpen": false -} \ No newline at end of file diff --git a/README.md b/README.md index 9fb7547..ef01657 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,22 @@ The BL Led Controller is an ESP8266 / ESP32 based device that connects to your Bambulab X1,X1C,P1P Or P1S and controls the LED strip based on the state of the printer. +### Flashing and Setup +1. go to https://softwarecrash.github.io/BLLEDController-NG/ +2. connect your ESP32 +3. Select the Firmware build you want +4. Click on Flash +5. Search and connect to a WiFi Hotspot called "BLLED-AP" +6. Surf to http://192.168.4.1 +7. Select your WiFi and Enter passwort, Optional enter all the Printer informations +8. enjoy :) + ### Features +WiFi Setup: +![1000063279](https://github.com/user-attachments/assets/1cbe01fd-ce1f-4664-909e-7f6f50f6d80a) + +OTA Firmware Update: +![1000063277](https://github.com/user-attachments/assets/853fa8cd-def6-47e9-8b23-4a4289651510) - Connects to Bambulab X1,X1C,P1P Or P1S - Controls LED strip based on printer state diff --git a/compress_html.py b/compress_html.py index e2e0e59..2f288e3 100644 --- a/compress_html.py +++ b/compress_html.py @@ -1,66 +1,81 @@ -import sys import gzip -import subprocess import os +import glob + +SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__)) +HTML_DIR = os.path.join(SCRIPT_DIR, "src", "www") + +OUTPUT_HEADER_NAME = "www.h" +OUTPUT_HEADER = os.path.join(HTML_DIR, OUTPUT_HEADER_NAME) + +SUPPORTED_EXTENSIONS = ["*.html", "*.js", "*.css","*.svg","*.png"] + +MIME_TYPES = { + ".html": "text/html", + ".htm": "text/html", + ".js": "application/javascript", + ".css": "text/css", + ".json": "application/json", + ".png": "image/png", + ".jpg": "image/jpeg", + ".jpeg": "image/jpeg", + ".svg": "image/svg+xml", + ".ico": "image/x-icon", +} + +def generate_header_start(f): + f.write("#ifndef WWW_H\n#define WWW_H\n\n") + f.write("#include \n\n") + +def generate_header_end(f): + f.write("\n#endif // WWW_H\n") + +def guess_mime_type(filename): + _, ext = os.path.splitext(filename.lower()) + return MIME_TYPES.get(ext, "application/octet-stream") + +def compress_and_append_file(input_file, f): + compressed_file = input_file + ".gz" + + with open(input_file, "rb") as infile: + with gzip.open(compressed_file, "wb", compresslevel=6) as outfile: + outfile.write(infile.read()) + + with open(compressed_file, "rb") as cf: + data = cf.read() + + array_name = os.path.basename(input_file).replace(".", "_") + + f.write(f"const uint8_t {array_name}_gz[] PROGMEM = {{\n") + for i in range(0, len(data), 16): + line = ', '.join(f'0x{b:02x}' for b in data[i:i+16]) + f.write(f" {line},\n") + f.write("};\n\n") + f.write(f"const unsigned int {array_name}_gz_len = {len(data)};\n") + f.write(f"const char * {array_name}_gz_mime = \"{guess_mime_type(input_file)}\";\n\n") -def should_compress(html_file, header_file): - if not os.path.exists(header_file): - return True - - html_modified_time = os.path.getmtime(html_file) - header_modified_time = os.path.getmtime(header_file) - - return html_modified_time > header_modified_time - -def compress_html(html_file): - # Check if compression is necessary - header_file = os.path.splitext(html_file)[0] + ".h" - if not should_compress(html_file, header_file): - print("No need to compress:", html_file) - return - - # Compress HTML file - compressed_file = html_file + ".gz" - with open(html_file, "rb") as input_file: - with gzip.open(compressed_file, "wb", compresslevel=6) as output_file: - output_file.write(input_file.read()) - - # Check if .h file exists and if HTML file is newer - if os.path.exists(header_file): - header_modified_time = os.path.getmtime(header_file) - html_modified_time = os.path.getmtime(html_file) - if html_modified_time < header_modified_time: - print("No need to generate header file. HTML file is not modified.") - os.remove(compressed_file) - return - - # Generate header file - print("Header file path:", header_file) # Debug print - result = subprocess.run(["xxd", "-i", compressed_file], stdout=open(header_file, "w")) - if result.returncode != 0: - print("Error: xxd failed to generate the header file") - return - - # Modify the generated header file to include PROGMEM attribute - with open(header_file, "r") as file: - content = file.read() - - with open(header_file, "w") as file: - # Add PROGMEM attribute after the array declaration - content = content.replace("unsigned char ", "const uint8_t ") - # Remove "__" prefix from the length variable - content = content.replace("unsigned int ", "unsigned int ") - # Add PROGMEM attribute after the variable name - content = content.replace("const uint8_t ", "const uint8_t ", 1).replace("{", "PROGMEM {") - file.write(content) - - # Clean up os.remove(compressed_file) + print(f"Appended: {array_name}_gz to {OUTPUT_HEADER_NAME} with MIME {guess_mime_type(input_file)}") if __name__ == "__main__": - if len(sys.argv) != 2: - print("Usage: python compress_html.py ") - sys.exit(1) - - html_file = sys.argv[1] - compress_html(html_file) + if not os.path.isdir(HTML_DIR): + print(f"Error: {HTML_DIR} is not a valid directory") + exit(1) + + files_to_process = [] + for pattern in SUPPORTED_EXTENSIONS: + files_to_process.extend(glob.glob(os.path.join(HTML_DIR, pattern))) + + if not files_to_process: + print(f"No matching files found in {HTML_DIR}") + exit(0) + + with open(OUTPUT_HEADER, "w") as f: + generate_header_start(f) + + for file in files_to_process: + compress_and_append_file(file, f) + + generate_header_end(f) + + print(f"\n✅ All files combined into: {OUTPUT_HEADER}") diff --git a/docs/.nojekyll b/docs/.nojekyll new file mode 100644 index 0000000..c0a9e35 --- /dev/null +++ b/docs/.nojekyll @@ -0,0 +1 @@ +Sun May 18 11:18:13 UTC 2025 diff --git a/docs/blled.svg b/docs/blled.svg new file mode 100644 index 0000000..05b1a9a --- /dev/null +++ b/docs/blled.svg @@ -0,0 +1,42 @@ + + + + diff --git a/docs/favicon.ico b/docs/favicon.ico new file mode 100644 index 0000000..a69a720 Binary files /dev/null and b/docs/favicon.ico differ diff --git a/docs/firmware/BLLEDController_V1.0.0.nightly.170525.bin b/docs/firmware/BLLEDController_V1.0.0.nightly.170525.bin new file mode 100644 index 0000000..810d0e2 Binary files /dev/null and b/docs/firmware/BLLEDController_V1.0.0.nightly.170525.bin differ diff --git a/docs/firmware/BLLEDController_V1.0.0.nightly.170525.json b/docs/firmware/BLLEDController_V1.0.0.nightly.170525.json new file mode 100644 index 0000000..b310cfa --- /dev/null +++ b/docs/firmware/BLLEDController_V1.0.0.nightly.170525.json @@ -0,0 +1,15 @@ +{ + "name": "BLLEDController_V1.0.0.nightly.170525", + "version": "1.0.0.nightly.170525", + "builds": [ + { + "chipFamily": "ESP32", + "parts": [ + { + "path": "BLLEDController_V1.0.0.nightly.170525.bin", + "offset": 0 + } + ] + } + ] +} \ No newline at end of file diff --git a/docs/firmware/BLLEDController_V1.0.0.nightly.180525.1.bin b/docs/firmware/BLLEDController_V1.0.0.nightly.180525.1.bin new file mode 100644 index 0000000..e841a96 Binary files /dev/null and b/docs/firmware/BLLEDController_V1.0.0.nightly.180525.1.bin differ diff --git a/docs/firmware/BLLEDController_V1.0.0.nightly.180525.1.json b/docs/firmware/BLLEDController_V1.0.0.nightly.180525.1.json new file mode 100644 index 0000000..a898f97 --- /dev/null +++ b/docs/firmware/BLLEDController_V1.0.0.nightly.180525.1.json @@ -0,0 +1,15 @@ +{ + "name": "BLLEDController_V1.0.0.nightly.180525.1", + "version": "1.0.0.nightly.180525.1", + "builds": [ + { + "chipFamily": "ESP32", + "parts": [ + { + "path": "BLLEDController_V1.0.0.nightly.180525.1.bin", + "offset": 0 + } + ] + } + ] +} \ No newline at end of file diff --git a/docs/firmware/firmware.json b/docs/firmware/firmware.json new file mode 100644 index 0000000..8ed1294 --- /dev/null +++ b/docs/firmware/firmware.json @@ -0,0 +1,12 @@ +[ + { + "version": "1.0.0.nightly.170525", + "prerelease": true, + "file": "BLLEDController_V1.0.0.nightly.170525.bin" + }, + { + "version": "1.0.0.nightly.180525.1", + "prerelease": true, + "file": "BLLEDController_V1.0.0.nightly.180525.1.bin" + } +] \ No newline at end of file diff --git a/docs/firmware/last_update.txt b/docs/firmware/last_update.txt new file mode 100644 index 0000000..fc521ca --- /dev/null +++ b/docs/firmware/last_update.txt @@ -0,0 +1 @@ +Updated at Sun May 18 16:16:20 UTC 2025 diff --git a/docs/firmware/readme.md b/docs/firmware/readme.md new file mode 100644 index 0000000..e69de29 diff --git a/docs/generateRelease.js b/docs/generateRelease.js new file mode 100644 index 0000000..6e36a29 --- /dev/null +++ b/docs/generateRelease.js @@ -0,0 +1,51 @@ +const fs = require('fs'); +const path = require('path'); + +const firmwareDir = path.resolve(__dirname, 'firmware'); +const binFiles = fs.readdirSync(firmwareDir).filter(f => f.endsWith('.bin')); + +if (binFiles.length === 0) { + console.log('❌ No .bin files found in firmware folder.'); + process.exit(1); +} + +const firmwareList = []; + +for (const file of binFiles) { + const versionMatch = file.match(/_V?([\w.\-]+)\.bin$/); + const version = versionMatch ? versionMatch[1] : 'unknown'; + const isPre = file.toLowerCase().includes('nightly') || file.toLowerCase().includes('beta'); + + // 👇 Add entry to firmware.json + firmwareList.push({ + version, + prerelease: isPre, + file + }); + + // 👇 Create ESP Web Tools Manifest (merged .bin format) + const manifest = { + name: file.replace(/\.bin$/, ''), + version, + builds: [ + { + chipFamily: "ESP32", + parts: [ + { + path: file, + offset: 0 + } + ] + } + ] + }; + + const manifestPath = path.join(firmwareDir, file.replace(/\.bin$/, '.json')); + fs.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2)); + console.log(`✅ Created manifest: ${manifestPath}`); +} + +// 👇 Write firmware.json (for dropdown use in UI) +const firmwareJsonPath = path.join(firmwareDir, 'firmware.json'); +fs.writeFileSync(firmwareJsonPath, JSON.stringify(firmwareList, null, 2)); +console.log(`✅ Created firmware list: ${firmwareJsonPath}`); diff --git a/docs/index.html b/docs/index.html new file mode 100644 index 0000000..090b53e --- /dev/null +++ b/docs/index.html @@ -0,0 +1,154 @@ + + + + + + + BLLEDController-NG WebFlasher + + + + + + + +
+ + +
+

Select a firmware version below and click Connect to flash your device.

+ + + + + + +

+
+ + +
+ + + + + + + diff --git a/docs/particleCanvas.js b/docs/particleCanvas.js new file mode 100644 index 0000000..03dd4a9 --- /dev/null +++ b/docs/particleCanvas.js @@ -0,0 +1,94 @@ + const canvas = document.getElementById('particleCanvas'); + const ctx = canvas.getContext('2d'); + canvas.width = window.innerWidth; + canvas.height = window.innerHeight; + + let particlesArray = []; + const numberOfParticles = 100; + + class Particle { + constructor(x, y, directionX, directionY, size, color) { + this.x = x; + this.y = y; + this.directionX = directionX; + this.directionY = directionY; + this.size = size; + this.color = color; + } + draw() { + ctx.beginPath(); + ctx.arc(this.x, this.y, this.size, 0, Math.PI * 2, false); + ctx.fillStyle = this.color; + ctx.fill(); + } + + + update() { + if (this.x + this.size > canvas.width || this.x - this.size < 0) { + this.directionX = -this.directionX; + } + + if (this.y + this.size > canvas.height || this.y - this.size < 0) { + this.directionY = -this.directionY; + } + + this.x += this.directionX; + this.y += this.directionY; + + this.draw(); + } + } + + function init() { + particlesArray = []; + for (let i = 0; i < numberOfParticles; i++) { + let size = Math.random() * 5 + 1; + let x = Math.random() * (canvas.width - size * 2) + size; + let y = Math.random() * (canvas.height - size * 2) + size; + let directionX = (Math.random() * 0.5) - 0.25; + let directionY = (Math.random() * 0.5) - 0.25; + let color = 'rgba(255, 255, 255, 0.8)'; + + particlesArray.push(new Particle(x, y, directionX, directionY, size, color)); + } + } + + function connect() { + let opacityValue = 1; + for (let a = 0; a < particlesArray.length; a++) { + for (let b = a; b < particlesArray.length; b++) { + let distance = ((particlesArray[a].x - particlesArray[b].x) * (particlesArray[a].x - particlesArray[b].x)) + + ((particlesArray[a].y - particlesArray[b].y) * (particlesArray[a].y - particlesArray[b].y)); + + if (distance < (canvas.width / 7) * (canvas.height / 7)) { + opacityValue = 1 - (distance / 20000); + ctx.strokeStyle = 'rgba(255, 255, 255,' + opacityValue + ')'; + ctx.lineWidth = 1; + ctx.beginPath(); + ctx.moveTo(particlesArray[a].x, particlesArray[a].y); + ctx.lineTo(particlesArray[b].x, particlesArray[b].y); + ctx.stroke(); + } + } + } + } + + function animate() { + ctx.clearRect(0, 0, canvas.width, canvas.height); + + for (let i = 0; i < particlesArray.length; i++) { + particlesArray[i].update(); + } + + connect(); + requestAnimationFrame(animate); + } + + window.addEventListener('resize', () => { + canvas.width = window.innerWidth; + canvas.height = window.innerHeight; + init(); + }); + + init(); + animate(); \ No newline at end of file diff --git a/docs/script.js b/docs/script.js new file mode 100644 index 0000000..32f2152 --- /dev/null +++ b/docs/script.js @@ -0,0 +1,39 @@ +document.addEventListener("DOMContentLoaded", async () => { + const firmwareSelect = document.getElementById("firmwareSelect"); + const flashButton = document.getElementById("flashButton"); + const basePath = window.location.pathname.replace(/\/[^/]*$/, ''); + const manifestBase = window.location.origin + basePath + "/firmware/"; + + try { + const response = await fetch("firmware/firmware.json"); + const firmwares = await response.json(); + + if (!Array.isArray(firmwares)) throw new Error("Invalid JSON structure"); + + // Sortiere nach neuester Version oben (optional) + firmwares.sort((a, b) => b.version.localeCompare(a.version, undefined, { numeric: true, sensitivity: 'base' })); + + for (const fw of firmwares) { + const opt = document.createElement("option"); + const label = `${fw.version}${fw.prerelease ? " (pre)" : ""}`; + opt.value = fw.file; + opt.textContent = label; + firmwareSelect.appendChild(opt); + } + + firmwareSelect.addEventListener("change", () => { + const selected = firmwareSelect.value; + if (selected) { + flashButton.setAttribute("manifest", manifestBase + selected.replace(/\.bin$/, ".json")); + flashButton.setAttribute("enabled", ""); + } else { + flashButton.removeAttribute("manifest"); + flashButton.removeAttribute("enabled"); + } + }); + } catch (err) { + console.error("Fehler beim Laden der Firmware-Liste:", err); + const status = document.getElementById("status"); + if (status) status.textContent = "Fehler beim Laden der Firmware-Dateien."; + } +}); \ No newline at end of file diff --git a/merge_firmware.py b/merge_firmware.py index 43fbe56..8c25393 100644 --- a/merge_firmware.py +++ b/merge_firmware.py @@ -1,43 +1,61 @@ Import("env") +import os +import shutil -APP_BIN = "$BUILD_DIR/${PROGNAME}.bin" -MERGED_BIN = "$BUILD_DIR/${PROGNAME}_merged.bin" +# === Konfiguration === +ENABLE_MERGE_BIN = True # Steuert ob Merge ausgeführt wird (OTA .bin.ota wird immer erstellt!) +# ====================== + +BUILD_DIR = env.subst("$BUILD_DIR") +PROGNAME = env.subst("${PROGNAME}") +APP_BIN = os.path.normpath(os.path.join(BUILD_DIR, f"{PROGNAME}.bin")) +MERGED_BIN = os.path.normpath(os.path.join(BUILD_DIR, f"{PROGNAME}_merged.bin")) BOARD_CONFIG = env.BoardConfig() +project_name = env.GetProjectOption("custom_project_name") or "Firmware" +version = env.GetProjectOption("custom_version") or "0.0.0" +firmware_filename_merged = f"{project_name}_V{version}.bin" +firmware_filename_ota = f"{project_name}_V{version}.bin.ota" + +firmware_path_merged = os.path.normpath(os.path.join(env.subst("$PROJECT_DIR"), ".firmware", firmware_filename_merged)) +firmware_path_ota = os.path.normpath(os.path.join(env.subst("$PROJECT_DIR"), ".firmware", firmware_filename_ota)) + +def copy_bin_as_ota(source, target, env): + os.makedirs(os.path.dirname(firmware_path_ota), exist_ok=True) + shutil.copyfile(APP_BIN, firmware_path_ota) + print(f'Firmware (OTA, uncompressed) copied to: {firmware_path_ota}') def merge_bin(source, target, env): - # The list contains all extra images (bootloader, partitions, eboot) and - # the final application binary - flash_images = env.Flatten(env.get("FLASH_EXTRA_IMAGES", [])) + ["$ESP32_APP_OFFSET", APP_BIN] - - # Run esptool to merge images into a single binary - env.Execute( - " ".join( - [ - "$PYTHONEXE", - "$OBJCOPY", - "--chip", - BOARD_CONFIG.get("build.mcu", "esp32"), - "merge_bin", - "--fill-flash-size", - BOARD_CONFIG.get("upload.flash_size", "4MB"), - "-o", - MERGED_BIN, - ] - + flash_images - ) - ) - -# Add a post action that runs esptoolpy to merge available flash images -env.AddPostAction(APP_BIN , merge_bin) - -# Patch the upload command to flash the merged binary at address 0x0 -env.Replace( - UPLOADERFLAGS=[ - f - for f in env.get("UPLOADERFLAGS") - if f not in env.Flatten(env.get("FLASH_EXTRA_IMAGES")) - ] - + ["0x0", MERGED_BIN], - UPLOADCMD='"$PYTHONEXE" "$UPLOADER" $UPLOADERFLAGS', -) \ No newline at end of file + flash_images = env.Flatten(env.get("FLASH_EXTRA_IMAGES", [])) + app_offset = env.subst("$ESP32_APP_OFFSET") or "0x10000" + flash_images += [app_offset, APP_BIN] + + flash_args = [ + os.path.normpath(env.subst(str(x))) if not str(x).startswith("0x") else str(x) + for x in flash_images + ] + + cmd = [ + env.subst("$PYTHONEXE"), + env.subst("$OBJCOPY"), + "--chip", BOARD_CONFIG.get("build.mcu", "esp32"), + "merge_bin", + "--fill-flash-size", BOARD_CONFIG.get("upload.flash_size", "4MB"), + "--output", MERGED_BIN, + ] + flash_args + + command_str = " ".join(f'"{c}"' if " " in c and not c.startswith('"') else c for c in cmd) + print("Running merge_bin:\n ", command_str.replace('"', '\"')) + result = env.Execute(command_str) + + os.makedirs(os.path.dirname(firmware_path_merged), exist_ok=True) + shutil.copyfile(MERGED_BIN, firmware_path_merged) + print(f'Firmware (merged) copied to: {firmware_path_merged}') + return result + +# Immer OTA-Datei erzeugen (unkomprimiert, mit Endung .bin.ota) +env.AddPostAction(APP_BIN, copy_bin_as_ota) + +# Optional merged .bin erzeugen +if ENABLE_MERGE_BIN: + env.AddPostAction(APP_BIN, merge_bin) diff --git a/platformio.ini b/platformio.ini index 5f682be..7ab13cc 100644 --- a/platformio.ini +++ b/platformio.ini @@ -9,18 +9,25 @@ ; https://docs.platformio.org/page/projectconf.html [env:esp32dev] +custom_project_name = BLLEDController +custom_project_codename = Balder +custom_version = 1.0.0.nightly.180525.1 ; for github release name the release VX.Y.Z X=(Incerase when Modifications oder new functions Break the API/webUI) Y=(Incerase for add oder modify changes that not breake the API/webUI until X incearase) Z=(Incerase for bugfix releases until minor is incerase) platform = espressif32 board = esp32dev framework = arduino monitor_speed = 115200 +upload_speed = 921600 board_build.filesystem = littlefs +build_flags = + -DVERSION=${this.custom_version} + -DSTRVERSION=\""${this.custom_version}"\" extra_scripts = pre:pre_build.py merge_firmware.py lib_deps = - https://github.com/bblanchon/ArduinoJson.git - https://github.com/knolleary/pubsubclient.git - luc-github/ESP32SSDP@^1.2.1 - -[platformio] -build_dir = build + bblanchon/ArduinoJson@7.4.1 + knolleary/pubsubclient@2.8.0 + luc-github/ESP32SSDP@1.2.1 + ESP32Async/AsyncTCP + ESP32Async/ESPAsyncWebServer + mathieucarbou/MycilaWebSerial@^8.0.0 \ No newline at end of file diff --git a/pre_build.py b/pre_build.py index 4de140e..7c32612 100755 --- a/pre_build.py +++ b/pre_build.py @@ -6,7 +6,7 @@ def compress_html_files(): os.chdir("src/www") # List of HTML files to compress - html_files = ["setuppage.html","updatepage.html"] + html_files = ["setuppage.html, updatepage.html"] for html_file in html_files: print("Compressing file:", html_file) subprocess.run(["python", "../../compress_html.py", html_file]) diff --git a/src/.DS_Store b/src/.DS_Store deleted file mode 100644 index 246134f..0000000 Binary files a/src/.DS_Store and /dev/null differ diff --git a/src/blled/filesystem.h b/src/blled/filesystem.h index 0bce617..abe3275 100644 --- a/src/blled/filesystem.h +++ b/src/blled/filesystem.h @@ -10,30 +10,35 @@ const char *configPath = "/blledconfig.json"; -char* generateRandomString(int length) { - static const char charset[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; - int charsetLength = strlen(charset); - - char* randomString = new char[length + 1]; - for (int i = 0; i < length; i++) { - int randomIndex = random(0, charsetLength); - randomString[i] = charset[randomIndex]; - } - randomString[length] = '\0'; - - return randomString; +char *generateRandomString(int length) +{ + static const char charset[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + int charsetLength = strlen(charset); + + char *randomString = new char[length + 1]; + for (int i = 0; i < length; i++) + { + int randomIndex = random(0, charsetLength); + randomString[i] = charset[randomIndex]; + } + randomString[length] = '\0'; + + return randomString; } -void saveFileSystem(){ +void saveFileSystem() +{ Serial.println(F("Saving config")); - + JsonDocument json; json["ssid"] = globalVariables.SSID; json["appw"] = globalVariables.APPW; + json["HTTPUser"] = securityVariables.HTTPUser; + json["HTTPPass"] = securityVariables.HTTPPass; json["printerIp"] = printerConfig.printerIP; json["accessCode"] = printerConfig.accessCode; json["serialNumber"] = printerConfig.serialNumber; - //json["webpagePassword"] = printerConfig.webpagePassword; + // json["webpagePassword"] = printerConfig.webpagePassword; json["bssi"] = printerConfig.BSSID; json["brightness"] = printerConfig.brightness; // LED Behaviour (Choose One) @@ -66,7 +71,7 @@ void saveFileSystem(){ json["mqttdebug"] = printerConfig.mqttdebug; // Printer Dependant json["p1Printer"] = printerVariables.isP1Printer; - json["doorSwitch"] = printerVariables.useDoorSwtich; + json["doorSwitch"] = printerVariables.useDoorSwtich; // Customise LED Colors (during Lidar) json["stage14RGB"] = printerConfig.stage14Color.RGBhex; json["stage14WW"] = printerConfig.stage14Color.ww; @@ -117,7 +122,8 @@ void saveFileSystem(){ json["bedTempCW"] = printerConfig.bedTempRGB.cw; File configFile = LittleFS.open(configPath, "w"); - if (!configFile) { + if (!configFile) + { Serial.println(F("Failed to save config")); return; } @@ -126,25 +132,29 @@ void saveFileSystem(){ Serial.println(F("Config Saved")); } -void loadFileSystem(){ +void loadFileSystem() +{ Serial.println(F("Loading config")); - + File configFile; int attempts = 0; - while (attempts < 2) { + while (attempts < 2) + { configFile = LittleFS.open(configPath, "r"); - if (configFile) { + if (configFile) + { break; } attempts++; Serial.println(F("Failed to open config file, retrying..")); delay(2000); } - if (!configFile) { + if (!configFile) + { Serial.print(F("Failed to open config file after ")); Serial.print(attempts); Serial.println(F(" retries")); - + Serial.println(F("Clearing config")); // LittleFS.remove(configPath); saveFileSystem(); @@ -157,13 +167,16 @@ void loadFileSystem(){ JsonDocument json; auto deserializeError = deserializeJson(json, buf.get()); - if (!deserializeError) { + if (!deserializeError) + { strcpy(globalVariables.SSID, json["ssid"]); strcpy(globalVariables.APPW, json["appw"]); + strlcpy(securityVariables.HTTPUser, json["HTTPUser"] | "", sizeof(securityVariables.HTTPUser)); + strlcpy(securityVariables.HTTPPass, json["HTTPPass"] | "", sizeof(securityVariables.HTTPPass)); strcpy(printerConfig.printerIP, json["printerIp"]); strcpy(printerConfig.accessCode, json["accessCode"]); strcpy(printerConfig.serialNumber, json["serialNumber"]); - //strcpy(printerConfig.webpagePassword, json["webpagePassword"]); + // strcpy(printerConfig.webpagePassword, json["webpagePassword"]); strcpy(printerConfig.BSSID, json["bssi"]); printerConfig.brightness = json["brightness"]; // LED Behaviour (Choose One) @@ -171,14 +184,14 @@ void loadFileSystem(){ printerConfig.discoMode = json["discoMode"]; printerConfig.replicatestate = json["replicatestate"]; // Running Color - printerConfig.runningColor = hex2rgb(json["runningRGB"],json["runningWW"],json["runningCW"]); + printerConfig.runningColor = hex2rgb(json["runningRGB"], json["runningWW"], json["runningCW"]); // Test LED Colors printerConfig.testcolorEnabled = json["showtestcolor"]; - printerConfig.testColor = hex2rgb(json["testRGB"],json["testWW"],json["testCW"]); + printerConfig.testColor = hex2rgb(json["testRGB"], json["testWW"], json["testCW"]); printerConfig.debugwifi = json["debugwifi"]; // Options printerConfig.finishindication = json["finishindication"]; - printerConfig.finishColor = hex2rgb(json["finishColor"],json["finishWW"],json["finishCW"]); + printerConfig.finishColor = hex2rgb(json["finishColor"], json["finishWW"], json["finishCW"]); printerConfig.finishExit = json["finishExit"]; printerConfig.finishTimeOut = json["finishTimerMins"]; printerConfig.finish_check = json["finish_check"]; @@ -191,50 +204,56 @@ void loadFileSystem(){ // Printer Dependant printerVariables.isP1Printer = json["p1Printer"]; printerVariables.useDoorSwtich = json["doorSwitch"]; - printerConfig.stage14Color = hex2rgb(json["stage14RGB"],json["stage14WW"],json["stage14CW"]); - printerConfig.stage1Color = hex2rgb(json["stage1RGB"],json["stage1WW"],json["stage1CW"]); - printerConfig.stage8Color = hex2rgb(json["stage8RGB"],json["stage8WW"],json["stage8CW"]); - printerConfig.stage9Color = hex2rgb(json["stage9RGB"],json["stage9WW"],json["stage9CW"]); - printerConfig.stage10Color = hex2rgb(json["stage10RGB"],json["stage10WW"],json["stage10CW"]); + printerConfig.stage14Color = hex2rgb(json["stage14RGB"], json["stage14WW"], json["stage14CW"]); + printerConfig.stage1Color = hex2rgb(json["stage1RGB"], json["stage1WW"], json["stage1CW"]); + printerConfig.stage8Color = hex2rgb(json["stage8RGB"], json["stage8WW"], json["stage8CW"]); + printerConfig.stage9Color = hex2rgb(json["stage9RGB"], json["stage9WW"], json["stage9CW"]); + printerConfig.stage10Color = hex2rgb(json["stage10RGB"], json["stage10WW"], json["stage10CW"]); // Customise LED Colors printerConfig.errordetection = json["errordetection"]; - printerConfig.wifiRGB = hex2rgb(json["wifiRGB"],json["wifiWW"],json["wifiCW"]); - - printerConfig.pauseRGB = hex2rgb(json["pauseRGB"],json["pauseWW"],json["pauseCW"]); - printerConfig.firstlayerRGB = hex2rgb(json["firstlayerRGB"],json["firstlayerWW"],json["firstlayerCW"]); - printerConfig.nozzleclogRGB = hex2rgb(json["nozzleclogRGB"],json["nozzleclogWW"],json["nozzleclogCW"]); - printerConfig.hmsSeriousRGB = hex2rgb(json["hmsSeriousRGB"],json["hmsSeriousWW"],json["hmsSeriousCW"]); - printerConfig.hmsFatalRGB = hex2rgb(json["hmsFatalRGB"],json["hmsFatalWW"],json["hmsFatalCW"]); - printerConfig.filamentRunoutRGB = hex2rgb(json["filamentRunoutRGB"],json["filamentRunoutWW"],json["filamentRunoutCW"]); - printerConfig.frontCoverRGB = hex2rgb(json["frontCoverRGB"],json["frontCoverWW"],json["frontCoverCW"]); - printerConfig.nozzleTempRGB = hex2rgb(json["nozzleTempRGB"],json["nozzleTempWW"],json["nozzleTempCW"]); - printerConfig.bedTempRGB = hex2rgb(json["bedTempRGB"],json["bedTempWW"],json["bedTempCW"]); + printerConfig.wifiRGB = hex2rgb(json["wifiRGB"], json["wifiWW"], json["wifiCW"]); + + printerConfig.pauseRGB = hex2rgb(json["pauseRGB"], json["pauseWW"], json["pauseCW"]); + printerConfig.firstlayerRGB = hex2rgb(json["firstlayerRGB"], json["firstlayerWW"], json["firstlayerCW"]); + printerConfig.nozzleclogRGB = hex2rgb(json["nozzleclogRGB"], json["nozzleclogWW"], json["nozzleclogCW"]); + printerConfig.hmsSeriousRGB = hex2rgb(json["hmsSeriousRGB"], json["hmsSeriousWW"], json["hmsSeriousCW"]); + printerConfig.hmsFatalRGB = hex2rgb(json["hmsFatalRGB"], json["hmsFatalWW"], json["hmsFatalCW"]); + printerConfig.filamentRunoutRGB = hex2rgb(json["filamentRunoutRGB"], json["filamentRunoutWW"], json["filamentRunoutCW"]); + printerConfig.frontCoverRGB = hex2rgb(json["frontCoverRGB"], json["frontCoverWW"], json["frontCoverCW"]); + printerConfig.nozzleTempRGB = hex2rgb(json["nozzleTempRGB"], json["nozzleTempWW"], json["nozzleTempCW"]); + printerConfig.bedTempRGB = hex2rgb(json["bedTempRGB"], json["bedTempWW"], json["bedTempCW"]); Serial.println(F("Loaded config")); - } else { + } + else + { Serial.println(F("Failed loading config")); Serial.println(F("Clearing config")); LittleFS.remove(configPath); - //Serial.println(F("Generating new password")); - //char* pw = generateRandomString(8); - //strcpy(printerConfig.webpagePassword, pw); + // Serial.println(F("Generating new password")); + // char* pw = generateRandomString(8); + // strcpy(printerConfig.webpagePassword, pw); } configFile.close(); } -void deleteFileSystem(){ +void deleteFileSystem() +{ Serial.println(F("Deleting LittleFS")); LittleFS.remove(configPath); } -bool hasFileSystem(){ +bool hasFileSystem() +{ return LittleFS.exists(configPath); } -void setupFileSystem(){ +void setupFileSystem() +{ Serial.println(F("Mounting LittleFS")); - if (!LittleFS.begin()) { + if (!LittleFS.begin()) + { Serial.println(F("Failed to mount LittleFS")); LittleFS.format(); Serial.println(F("Formatting LittleFS")); diff --git a/src/blled/message.json b/src/blled/message.json new file mode 100644 index 0000000..d07b706 --- /dev/null +++ b/src/blled/message.json @@ -0,0 +1,588 @@ +{ + "print": { + "3D": { + "layer_num": 0, + "total_layer_num": 0 + }, + "ams": { + "ams": [ + { + "dry_time": 0, + "humidity": "5", + "humidity_raw": "20", + "id": "0", + "info": "1001", + "temp": "22.2", + "tray": [ + { + "bed_temp": "0", + "bed_temp_type": "0", + "cali_idx": 2740, + "cols": [ + "161616FF" + ], + "ctype": 0, + "drying_temp": "0", + "drying_time": "0", + "id": "0", + "nozzle_temp_max": "240", + "nozzle_temp_min": "190", + "remain": -1, + "state": 11, + "tag_uid": "0000000000000000", + "total_len": 330000, + "tray_color": "161616FF", + "tray_diameter": "1.75", + "tray_id_name": "", + "tray_info_idx": "GFL99", + "tray_sub_brands": "", + "tray_type": "PLA", + "tray_uuid": "00000000000000000000000000000000", + "tray_weight": "0", + "xcam_info": "000000000000000000000000" + }, + { + "bed_temp": "0", + "bed_temp_type": "0", + "cali_idx": -1, + "cols": [ + "F98C36FF" + ], + "ctype": 0, + "drying_temp": "0", + "drying_time": "0", + "id": "1", + "nozzle_temp_max": "240", + "nozzle_temp_min": "190", + "remain": -1, + "state": 11, + "tag_uid": "0000000000000000", + "total_len": 330000, + "tray_color": "F98C36FF", + "tray_diameter": "1.75", + "tray_id_name": "", + "tray_info_idx": "GFL99", + "tray_sub_brands": "", + "tray_type": "PLA", + "tray_uuid": "00000000000000000000000000000000", + "tray_weight": "0", + "xcam_info": "000000000000000000000000" + }, + { + "bed_temp": "35", + "bed_temp_type": "1", + "cali_idx": 3693, + "cols": [ + "792B36FF" + ], + "ctype": 0, + "drying_temp": "55", + "drying_time": "8", + "id": "2", + "nozzle_temp_max": "230", + "nozzle_temp_min": "190", + "remain": 40, + "state": 11, + "tag_uid": "A0E4C32F00000100", + "total_len": 330000, + "tray_color": "792B36FF", + "tray_diameter": "1.75", + "tray_id_name": "A08-R2", + "tray_info_idx": "GFA08", + "tray_sub_brands": "PLA Sparkle", + "tray_type": "PLA", + "tray_uuid": "D481BCAAC6E043C8BEA355364A1CF641", + "tray_weight": "1000", + "xcam_info": "1027EC2CBC02E8033333333F" + }, + { + "bed_temp": "0", + "bed_temp_type": "0", + "cali_idx": 208, + "cols": [ + "F98C36FF" + ], + "ctype": 0, + "drying_temp": "0", + "drying_time": "0", + "id": "3", + "nozzle_temp_max": "240", + "nozzle_temp_min": "190", + "remain": -1, + "state": 11, + "tag_uid": "0000000000000000", + "total_len": 330000, + "tray_color": "F98C36FF", + "tray_diameter": "1.75", + "tray_id_name": "", + "tray_info_idx": "GFL99", + "tray_sub_brands": "", + "tray_type": "PLA", + "tray_uuid": "00000000000000000000000000000000", + "tray_weight": "0", + "xcam_info": "000000000000000000000000" + } + ] + }, + { + "dry_time": 0, + "humidity": "5", + "humidity_raw": "18", + "id": "1", + "info": "2003", + "temp": "19.9", + "tray": [ + { + "bed_temp": "0", + "bed_temp_type": "0", + "cali_idx": -1, + "cols": [ + "FFFFFFFF" + ], + "ctype": 0, + "drying_temp": "65", + "drying_time": "8", + "id": "0", + "nozzle_temp_max": "260", + "nozzle_temp_min": "230", + "remain": 27, + "state": 11, + "tag_uid": "BA919CF000000100", + "total_len": 330000, + "tray_color": "FFFFFFFF", + "tray_diameter": "1.75", + "tray_id_name": "G02-W0", + "tray_info_idx": "GFG02", + "tray_sub_brands": "PETG HF", + "tray_type": "PETG", + "tray_uuid": "2B5A1171556548DDA48A14D87FC0C041", + "tray_weight": "1000", + "xcam_info": "803E803E8403E8030000803F" + }, + { + "bed_temp": "0", + "bed_temp_type": "0", + "cali_idx": -1, + "cols": [ + "87909AFF" + ], + "ctype": 0, + "drying_temp": "0", + "drying_time": "0", + "id": "1", + "nozzle_temp_max": "270", + "nozzle_temp_min": "220", + "remain": -1, + "state": 11, + "tag_uid": "0000000000000000", + "total_len": 330000, + "tray_color": "87909AFF", + "tray_diameter": "1.75", + "tray_id_name": "", + "tray_info_idx": "GFG99", + "tray_sub_brands": "", + "tray_type": "PETG", + "tray_uuid": "00000000000000000000000000000000", + "tray_weight": "0", + "xcam_info": "000000000000000000000000" + }, + { + "bed_temp": "0", + "bed_temp_type": "0", + "cali_idx": -1, + "cols": [ + "FFFFFFFF" + ], + "ctype": 0, + "drying_temp": "0", + "drying_time": "0", + "id": "2", + "nozzle_temp_max": "280", + "nozzle_temp_min": "240", + "remain": -1, + "state": 11, + "tag_uid": "0000000000000000", + "total_len": 330000, + "tray_color": "FFFFFFFF", + "tray_diameter": "1.75", + "tray_id_name": "", + "tray_info_idx": "GFB99", + "tray_sub_brands": "", + "tray_type": "ABS", + "tray_uuid": "00000000000000000000000000000000", + "tray_weight": "0", + "xcam_info": "000000000000000000000000" + }, + { + "bed_temp": "80", + "bed_temp_type": "1", + "cali_idx": -1, + "cols": [ + "87909AFF" + ], + "ctype": 0, + "drying_temp": "80", + "drying_time": "8", + "id": "3", + "nozzle_temp_max": "270", + "nozzle_temp_min": "240", + "remain": 96, + "state": 11, + "tag_uid": "205F1AFF00000100", + "total_len": 330000, + "tray_color": "87909AFF", + "tray_diameter": "1.75", + "tray_id_name": "B00-D1", + "tray_info_idx": "GFB00", + "tray_sub_brands": "ABS", + "tray_type": "ABS", + "tray_uuid": "F7B057CBC44348C4B92A1971036811E1", + "tray_weight": "1000", + "xcam_info": "D007D007E803E8036666663F" + } + ] + } + ], + "ams_exist_bits": "3", + "ams_exist_bits_raw": "3", + "cali_id": 0, + "cali_stat": 0, + "insert_flag": false, + "power_on_flag": false, + "tray_exist_bits": "ff", + "tray_is_bbl_bits": "ff", + "tray_now": "255", + "tray_pre": "255", + "tray_read_done_bits": "ff", + "tray_reading_bits": "0", + "tray_tar": "255", + "unbind_ams_stat": 0, + "version": 863 + }, + "ams_rfid_status": 0, + "ams_status": 0, + "ap_err": 0, + "aux": "280100C", + "aux_part_fan": true, + "batch_id": 0, + "bed_target_temper": 0, + "bed_temper": 19, + "big_fan1_speed": "0", + "big_fan2_speed": "0", + "cali_version": 0, + "canvas_id": 0, + "care": [ + { + "id": "cr", + "info": "20631064" + }, + { + "id": "ls", + "info": "67F984D" + } + ], + "cfg": "FCA98", + "command": "push_status", + "cooling_fan_speed": "0", + "design_id": "", + "device": { + "bed": { + "info": { + "temp": 19 + }, + "state": 0 + }, + "bed_temp": 19, + "cam": { + "laser": { + "cond": 253, + "state": 0 + } + }, + "ctc": { + "info": { + "temp": 21 + }, + "state": 0 + }, + "ext_tool": { + "calib": 2, + "low_prec": true, + "mount": 0, + "th_temp": 0, + "type": "" + }, + "extruder": { + "info": [ + { + "filam_bak": [ + 10 + ], + "hnow": 0, + "hpre": 0, + "htar": 0, + "id": 0, + "info": 8, + "snow": 65535, + "spre": 65535, + "star": 65535, + "stat": 0, + "temp": 20 + } + ], + "state": 1 + }, + "fan": 0, + "laser": { + "power": 0 + }, + "nozzle": { + "exist": 1, + "info": [ + { + "diameter": 0.4, + "id": 0, + "tm": 0, + "type": "HX01", + "wear": 0 + } + ], + "state": 0 + }, + "plate": { + "base": 1, + "cali2d_id": "", + "cur_id": "", + "mat": 1, + "tar_id": "" + }, + "type": 1 + }, + "err": "0", + "fail_reason": "0", + "fan_gear": 0, + "file": "", + "force_upgrade": false, + "fun": "11A30F9CFF", + "gcode_file": "", + "gcode_file_prepare_percent": "0", + "gcode_state": "IDLE", + "heatbreak_fan_speed": "0", + "hms": [], + + + "home_flag": -1067070056, #tür zu bin -111111100110100011001001101000 + "home_flag": -1058681448, #tür auf bin -111111000110100011001001101000 + + +1 +--------------------------------------- +-1058681448 offen +1 +--------------------------------------- +-1067070056 zu +1 + + + "hw_switch_state": 0, + "info": { + "temp": 21 + }, + "ipcam": { + "agora_service": "disable", + "brtc_service": "enable", + "bs_state": 0, + "ipcam_dev": "1", + "ipcam_record": "enable", + "laser_preview_res": 7, + "mode_bits": 2, + "resolution": "1080p", + "rtsp_url": "disable", + "timelapse": "disable", + "tl_store_hpd_type": 2, + "tl_store_path_type": 2, + "tutk_server": "disable" + }, + "job": { + "cur_stage": { + "idx": 0, + "state": 0 + }, + "stage": [] + }, + "job_attr": 3, + "job_id": "", + "layer_num": 0, + "lights_report": [ + { + "mode": "on", + "node": "chamber_light" + }, + { + "mode": "flashing", + "node": "work_light" + } + ], + "mapping": [], + "mc_action": 0, + "mc_err": 0, + "mc_percent": 0, + "mc_print_error_code": "0", + "mc_print_stage": "1", + "mc_print_sub_stage": 0, + "mc_remaining_time": 0, + "mc_stage": 1, + "model_id": "", + "net": { + "conf": 16, + "info": [ + { + "ip": 2317877770, + "mask": 16777215 + }, + { + "ip": 0, + "mask": 0 + } + ] + }, + "nozzle_diameter": "0.4", + "nozzle_target_temper": 0, + "nozzle_temper": 20, + "nozzle_type": "hardened_steel", + "online": { + "ahb": true, + "ext": false, + "version": 6 + }, + "percent": 0, + "plate_cnt": 0, + "plate_id": 0, + "plate_idx": 0, + "prepare_per": 0, + "print_error": 0, + "print_gcode_action": 0, + "print_real_action": 0, + "print_type": "", + "profile_id": "", + "project_id": "", + "queue": 0, + "queue_est": 0, + "queue_number": 0, + "queue_sts": 0, + "queue_total": 0, + "remain_time": 0, + "s_obj": [], + "sdcard": true, + "sequence_id": "2021", + "spd_lvl": 2, + "spd_mag": 100, + "stat": "7A48000", + "state": 0, + "stg": [], + "stg_cur": -1, + "subtask_id": "", + "subtask_name": "", + "task_id": "", + "total_layer_num": 0, + "upgrade_state": { + "ahb_new_version_number": "", + "ams_new_version_number": "", + "consistency_request": false, + "dis_state": 0, + "err_code": 0, + "ext_new_version_number": "", + "force_upgrade": false, + "idx": 6, + "idx2": 745459320, + "lower_limit": "00.00.00.00", + "message": "", + "module": "", + "new_version_state": 2, + "ota_new_version_number": "", + "progress": "0", + "sequence_id": 0, + "sn": "00M09B431900386", + "status": "IDLE" + }, + "upload": { + "file_size": 0, + "finish_size": 0, + "message": "Good", + "oss_url": "", + "progress": 0, + "sequence_id": "0903", + "speed": 0, + "status": "idle", + "task_id": "", + "time_remaining": 0, + "trouble_id": "" + }, + "ver": "20010", + "vir_slot": [ + { + "bed_temp": "0", + "bed_temp_type": "0", + "cali_idx": -1, + "cols": [ + "BCBCBCFF" + ], + "ctype": 0, + "drying_temp": "0", + "drying_time": "0", + "id": "255", + "nozzle_temp_max": "250", + "nozzle_temp_min": "200", + "remain": 0, + "tag_uid": "0000000000000000", + "total_len": 330000, + "tray_color": "BCBCBCFF", + "tray_diameter": "1.75", + "tray_id_name": "", + "tray_info_idx": "GFU99", + "tray_sub_brands": "", + "tray_type": "TPU", + "tray_uuid": "00000000000000000000000000000000", + "tray_weight": "0", + "xcam_info": "000000000000000000000000" + } + ], + "vt_tray": { + "bed_temp": "0", + "bed_temp_type": "0", + "cali_idx": -1, + "cols": [ + "BCBCBCFF" + ], + "ctype": 0, + "drying_temp": "0", + "drying_time": "0", + "id": "255", + "nozzle_temp_max": "250", + "nozzle_temp_min": "200", + "remain": 0, + "tag_uid": "0000000000000000", + "total_len": 330000, + "tray_color": "BCBCBCFF", + "tray_diameter": "1.75", + "tray_id_name": "", + "tray_info_idx": "GFU99", + "tray_sub_brands": "", + "tray_type": "TPU", + "tray_uuid": "00000000000000000000000000000000", + "tray_weight": "0", + "xcam_info": "000000000000000000000000" + }, + "wifi_signal": "-33dBm", + "xcam": { + "allow_skip_parts": false, + "buildplate_marker_detector": true, + "first_layer_inspector": false, + "halt_print_sensitivity": "medium", + "print_halt": true, + "printing_monitor": true, + "spaghetti_detector": true + }, + "xcam_status": "0" + } +} \ No newline at end of file diff --git a/src/blled/mqttmanager.h b/src/blled/mqttmanager.h index 6170065..95258b8 100644 --- a/src/blled/mqttmanager.h +++ b/src/blled/mqttmanager.h @@ -5,7 +5,7 @@ #include #include #include -#include +#include #include "mqttparsingutility.h" #include "AutoGrowBufferStream.h" @@ -21,83 +21,97 @@ String clientId = "BLLED-"; AutoGrowBufferStream stream; -unsigned long mqttattempt = (millis()-3000); +unsigned long mqttattempt = (millis() - 3000); unsigned long lastMQTTupdate = millis(); -//With a Default BLLED -//Expected information when viewing MQTT status messages - -//gcode_state stg_cur BLLED LED control Comments +// With a Default BLLED +// Expected information when viewing MQTT status messages + +// gcode_state stg_cur BLLED LED control Comments //------------------------------------------------------------------------ -//IDLE -1 White Printer just powered on -//RUNNING -1 White Printer sent print file -//RUNNING 2 White PREHEATING BED -//RUNNING 14 OFF (for Lidar) CLEANING NOZZLE -//RUNNING 1 OFF (for Lidar) BED LEVELING -//RUNNING 8 OFF (for Lidar) CALIBRATING EXTRUSION -//RUNNING 0 White All the printing happens here -//FINISH -1 Green After bed is lowered and filament retracted -//FINISH -1 Green BLLED logic waits for a door interaction -//FINISH -1 White After door interaction -//FINISH -1 OFF Inactivity after 30mins - - -void connectMqtt(){ - if(WiFi.status() != WL_CONNECTED){ - //Abort MQTT connection attempt when no Wifi +// IDLE -1 White Printer just powered on +// RUNNING -1 White Printer sent print file +// RUNNING 2 White PREHEATING BED +// RUNNING 14 OFF (for Lidar) CLEANING NOZZLE +// RUNNING 1 OFF (for Lidar) BED LEVELING +// RUNNING 8 OFF (for Lidar) CALIBRATING EXTRUSION +// RUNNING 0 White All the printing happens here +// FINISH -1 Green After bed is lowered and filament retracted +// FINISH -1 Green BLLED logic waits for a door interaction +// FINISH -1 White After door interaction +// FINISH -1 OFF Inactivity after 30mins + +void connectMqtt() +{ + if (WiFi.status() != WL_CONNECTED) + { + // Abort MQTT connection attempt when no Wifi + return; + } + if (strlen(printerConfig.printerIP) == 0 || strlen(printerConfig.accessCode) == 0) + { + Serial.println(F("[MQTT] Abort connect: printerIP oder accessCode wrong or empty")); return; } - if (!mqttClient.connected() && (millis() - mqttattempt) >= 3000){ - tweenToColor(10,10,10,10,10); + if (!mqttClient.connected() && (millis() - mqttattempt) >= 3000) + { + tweenToColor(10, 10, 10, 10, 10); Serial.println(F("Connecting to mqtt...")); - if (mqttClient.connect(clientId.c_str(),"bblp",printerConfig.accessCode)){ + if (mqttClient.connect(clientId.c_str(), "bblp", printerConfig.accessCode)) + { Serial.print(F("MQTT connected, subscribing to MQTT Topic: ")); Serial.println(report_topic); mqttClient.subscribe(report_topic.c_str()); printerVariables.online = true; printerVariables.disconnectMQTTms = 0; - //Serial.println(F("Updating LEDs from MQTT connect")); - //updateleds(); - }else{ + // Serial.println(F("Updating LEDs from MQTT connect")); + // updateleds(); + } + else + { Serial.println(F("Failed to connect with error code: ")); Serial.print(mqttClient.state()); Serial.print(F(" ")); ParseMQTTState(mqttClient.state()); - if(mqttClient.state() == 5){ + if (mqttClient.state() == 5) + { delay(500); - tweenToColor(127,0,0,0,0); //light red, indicating not authorized + tweenToColor(127, 0, 0, 0, 0); // light red, indicating not authorized delay(500); - mqttattempt = (millis()-3000); -// Serial.println(F("Restarting Device")); -// delay(1000); -// ESP.restart(); + mqttattempt = (millis() - 3000); + // Serial.println(F("Restarting Device")); + // delay(1000); + // ESP.restart(); } } } } -void ParseCallback(char *topic, byte *payload, unsigned int length){ +void ParseCallback(char *topic, byte *payload, unsigned int length) +{ JsonDocument messageobject; JsonDocument filter; - //Rather than showing the entire message to Serial - grabbing only the pertinent bits for BLLED. - //Device Status - filter["print"]["command"] = true; - filter["print"]["fail_reason"] = true; - filter["print"]["gcode_state"] = true; - filter["print"]["print_gcode_action"] = true; - filter["print"]["print_real_action"] = true; - filter["print"]["hms"] = true; - filter["print"]["home_flag"] = true; - filter["print"]["lights_report"] = true; - filter["print"]["stg_cur"] = true; - filter["print"]["print_error"] = true; - filter["print"]["wifi_signal"] = true; - filter["system"]["command"] = true; - filter["system"]["led_mode"] = true; + // Rather than showing the entire message to Serial - grabbing only the pertinent bits for BLLED. + // Device Status + filter["print"]["command"] = true; + filter["print"]["fail_reason"] = true; + filter["print"]["gcode_state"] = true; + filter["print"]["print_gcode_action"] = true; + filter["print"]["print_real_action"] = true; + filter["print"]["hms"] = true; + filter["print"]["home_flag"] = true; + filter["print"]["lights_report"] = true; + filter["print"]["stg_cur"] = true; + filter["print"]["print_error"] = true; + filter["print"]["wifi_signal"] = true; + filter["system"]["command"] = true; + filter["system"]["led_mode"] = true; auto deserializeError = deserializeJson(messageobject, payload, length, DeserializationOption::Filter(filter)); - if (!deserializeError){ - if (printerConfig.debuging){ + if (!deserializeError) + { + if (printerConfig.debuging) + { Serial.println(F("Mqtt message received.")); Serial.print(F("FreeHeap: ")); Serial.println(ESP.getFreeHeap()); @@ -105,25 +119,28 @@ void ParseCallback(char *topic, byte *payload, unsigned int length){ bool Changed = false; - if (messageobject["print"].containsKey("command")){ - if (messageobject["print"]["command"] == "gcode_line" //gcode_line used a lot during print initialisations - Skip these - || messageobject["print"]["command"] == "project_prepare" //1 message per print - || messageobject["print"]["command"] == "project_file" //1 message per print - || messageobject["print"]["command"] == "clean_print_error" //During error (no info) - || messageobject["print"]["command"] == "resume" //After error or pause - || messageobject["print"]["command"] == "get_accessories" //After error or pause - || messageobject["print"]["command"] == "prepare"){ //1 message per print + if (messageobject["print"]["command"].is()) + { + if (messageobject["print"]["command"] == "gcode_line" // gcode_line used a lot during print initialisations - Skip these + || messageobject["print"]["command"] == "project_prepare" // 1 message per print + || messageobject["print"]["command"] == "project_file" // 1 message per print + || messageobject["print"]["command"] == "clean_print_error" // During error (no info) + || messageobject["print"]["command"] == "resume" // After error or pause + || messageobject["print"]["command"] == "get_accessories" // After error or pause + || messageobject["print"]["command"] == "prepare") + { // 1 message per print return; } } - if(messageobject.size() == 0) + if (messageobject.size() == 0) { - //Null or Filtered message that are not 'Print' or 'System' payload - Ignore these + // Null or Filtered message that are not 'Print' or 'System' payload - Ignore these return; } - //Output Filtered MQTT message - if (printerConfig.mqttdebug){ + // Output Filtered MQTT message + if (printerConfig.mqttdebug) + { Serial.print(F("(Filtered) MQTT payload, [")); Serial.print(millis()); Serial.print(F("], ")); @@ -131,48 +148,66 @@ void ParseCallback(char *topic, byte *payload, unsigned int length){ Serial.println(); } - if(printerConfig.mqttdebug && (printerConfig.maintMode || printerConfig.testcolorEnabled || printerConfig.discoMode || printerConfig.debugwifi)) { + if (printerConfig.mqttdebug && (printerConfig.maintMode || printerConfig.testcolorEnabled || printerConfig.discoMode || printerConfig.debugwifi)) + { Serial.print(F("MQTT Message Ignored while in ")); - if (printerConfig.maintMode) Serial.print(F("Maintenance")); - if (printerConfig.testcolorEnabled) Serial.print(F("Test Color")); - if (printerConfig.discoMode) Serial.print(F("RGB Cycle")); - if (printerConfig.debugwifi) Serial.print(F("Wifi Debug")); + if (printerConfig.maintMode) + Serial.print(F("Maintenance")); + if (printerConfig.testcolorEnabled) + Serial.print(F("Test Color")); + if (printerConfig.discoMode) + Serial.print(F("RGB Cycle")); + if (printerConfig.debugwifi) + Serial.print(F("Wifi Debug")); Serial.println(F(" mode")); return; } - //Check for Door Status - if (messageobject["print"].containsKey("home_flag")){ - //https://github.com/greghesp/ha-bambulab/blob/main/custom_components/bambu_lab/pybambu/const.py#L324 + // Check for Door Status + if (messageobject["print"]["home_flag"].is()) + { + // https://github.com/greghesp/ha-bambulab/blob/main/custom_components/bambu_lab/pybambu/const.py#L324 - long homeFlag = messageobject["print"]["home_flag"]; - bool doorState = (((homeFlag >> 23) & 1) == 1); + bool doorState = false; + long homeFlag = 0; + homeFlag = messageobject["print"]["home_flag"]; + doorState = bitRead(homeFlag, 23); - if (printerVariables.doorOpen != doorState){ + if (printerVariables.doorOpen != doorState) + { printerVariables.doorOpen = doorState; - - if (printerConfig.debugingchange)Serial.print(F("MQTT Door ")); - if (printerVariables.doorOpen){ - printerVariables.lastdoorOpenms = millis(); - if (printerConfig.debugingchange) Serial.println(F("Opened")); + + if (printerConfig.debugingchange) + Serial.print(F("MQTT Door ")); + if (printerVariables.doorOpen) + { + printerVariables.lastdoorOpenms = millis(); + if (printerConfig.debugingchange) + Serial.println(F("Opened")); } - else{ - if ((millis() - printerVariables.lastdoorClosems) < 6000){ + else + { + if ((millis() - printerVariables.lastdoorClosems) < 6000) + { printerVariables.doorSwitchTriggered = true; } printerVariables.lastdoorClosems = millis(); - if (printerConfig.debugingchange) Serial.println(F("Closed")); + if (printerConfig.debugingchange) + Serial.println(F("Closed")); } Changed = true; } } - //Check BBLP Stage - if (messageobject["print"].containsKey("stg_cur")){ - if (printerVariables.stage != messageobject["print"]["stg_cur"].as() ){ + // Check BBLP Stage + if (messageobject["print"]["stg_cur"].is()) + { + if (printerVariables.stage != messageobject["print"]["stg_cur"].as()) + { printerVariables.stage = messageobject["print"]["stg_cur"]; - - if (printerConfig.debugingchange || printerConfig.debuging){ + + if (printerConfig.debugingchange || printerConfig.debuging) + { Serial.print(F("MQTT update - stg_cur now: ")); Serial.println(printerVariables.stage); } @@ -180,26 +215,31 @@ void ParseCallback(char *topic, byte *payload, unsigned int length){ } } - //Check BBLP GCode State - if (messageobject["print"].containsKey("gcode_state") && ((millis() - lastMQTTupdate) > 3000)){ + // Check BBLP GCode State + if (messageobject["print"]["gcode_state"].is() && ((millis() - lastMQTTupdate) > 3000)) + { String mqttgcodeState = messageobject["print"]["gcode_state"].as(); - if(mqttgcodeState =="RUNNING" || mqttgcodeState =="PAUSE"){ - //Never turn off light (due to idle timer) while in this state - printerConfig.inactivityStartms = millis(); + if (mqttgcodeState == "RUNNING" || mqttgcodeState == "PAUSE") + { + // Never turn off light (due to idle timer) while in this state + printerConfig.inactivityStartms = millis(); } // Onchange of gcodeState... - if(printerVariables.gcodeState != mqttgcodeState){ - if(mqttgcodeState =="FINISH"){ + if (printerVariables.gcodeState != mqttgcodeState) + { + if (mqttgcodeState == "FINISH") + { printerVariables.finished = true; - printerVariables.waitingForDoor = true; + printerVariables.waitingForDoor = true; printerConfig.finishStartms = millis(); printerConfig.finish_check = true; } printerVariables.gcodeState = mqttgcodeState; - if (printerConfig.debugingchange || printerConfig.debuging){ + if (printerConfig.debugingchange || printerConfig.debuging) + { Serial.print(F("MQTT update - gcode_state now: ")); Serial.println(printerVariables.gcodeState); } @@ -207,9 +247,11 @@ void ParseCallback(char *topic, byte *payload, unsigned int length){ } } - //Pause Command - quicker, but Only for user generated pause - error & code pauses don't trigger this. - if (messageobject["print"].containsKey("command")){ - if (messageobject["print"]["command"] == "pause"){ + // Pause Command - quicker, but Only for user generated pause - error & code pauses don't trigger this. + if (messageobject["print"]["command"].is()) + { + if (messageobject["print"]["command"] == "pause") + { lastMQTTupdate = millis(); Serial.println(F("MQTT update - manual PAUSE")); printerVariables.gcodeState = "PAUSE"; @@ -217,20 +259,26 @@ void ParseCallback(char *topic, byte *payload, unsigned int length){ } } - //Added a delay so the slower MQTT status message doesn't reverse the "system" commands - if (messageobject["print"].containsKey("lights_report") && ((millis() - lastMQTTupdate) > 3000)) { + // Added a delay so the slower MQTT status message doesn't reverse the "system" commands + if (messageobject["print"]["lights_report"].is() && ((millis() - lastMQTTupdate) > 3000)) + { JsonArray lightsReport = messageobject["print"]["lights_report"]; - for (JsonObject light : lightsReport) { - if (light["node"] == "chamber_light") { + for (JsonObject light : lightsReport) + { + if (light["node"] == "chamber_light") + { - if(printerVariables.printerledstate != (light["mode"] == "on")){ + if (printerVariables.printerledstate != (light["mode"] == "on")) + { printerVariables.printerledstate = (light["mode"] == "on"); printerConfig.replicate_update = true; - if (printerConfig.debugingchange || printerConfig.debuging){ + if (printerConfig.debugingchange || printerConfig.debuging) + { Serial.print(F("MQTT chamber_light now: ")); Serial.println(printerVariables.printerledstate); } - if(printerVariables.waitingForDoor && printerConfig.finish_check){ + if (printerVariables.waitingForDoor && printerConfig.finish_check) + { printerVariables.finished = true; } Changed = true; @@ -238,20 +286,25 @@ void ParseCallback(char *topic, byte *payload, unsigned int length){ } } } - //System Commands are sent quicker than the push_status - //Message only sent onChange - if (messageobject["system"].containsKey("command")) { - if (messageobject["system"]["command"] == "ledctrl"){ - //Ignore Printer sending attempts to turn light on when already on. - if(printerVariables.printerledstate != (messageobject["system"]["led_mode"] == "on")){ + // System Commands are sent quicker than the push_status + // Message only sent onChange + if (messageobject["system"]["command"].is()) + { + if (messageobject["system"]["command"] == "ledctrl") + { + // Ignore Printer sending attempts to turn light on when already on. + if (printerVariables.printerledstate != (messageobject["system"]["led_mode"] == "on")) + { printerVariables.printerledstate = (messageobject["system"]["led_mode"] == "on"); printerConfig.replicate_update = true; lastMQTTupdate = millis(); - if (printerConfig.debugingchange || printerConfig.debuging){ + if (printerConfig.debugingchange || printerConfig.debuging) + { Serial.print(F("MQTT led_mode now: ")); Serial.println(printerVariables.printerledstate); } - if(printerVariables.waitingForDoor && printerConfig.finish_check){ + if (printerVariables.waitingForDoor && printerConfig.finish_check) + { printerVariables.finished = true; } @@ -260,34 +313,45 @@ void ParseCallback(char *topic, byte *payload, unsigned int length){ } } - //Bambu Health Management System (HMS) - if (messageobject["print"].containsKey("hms")){ + // Bambu Health Management System (HMS) + if (messageobject["print"]["hms"].is()) + { String oldHMSlevel = ""; oldHMSlevel = printerVariables.parsedHMSlevel; printerVariables.hmsstate = false; printerVariables.parsedHMSlevel = ""; - for (const auto& hms : messageobject["print"]["hms"].as()) { - if (ParseHMSSeverity(hms["code"]) != ""){ + for (const auto &hms : messageobject["print"]["hms"].as()) + { + if (ParseHMSSeverity(hms["code"]) != "") + { printerVariables.hmsstate = true; printerVariables.parsedHMSlevel = ParseHMSSeverity(hms["code"]); printerVariables.parsedHMScode = ((uint64_t)hms["attr"] << 32) + (uint64_t)hms["code"]; } } - if(oldHMSlevel != printerVariables.parsedHMSlevel){ - - if(printerVariables.parsedHMScode == 0x0C0003000003000B) printerVariables.overridestage = 10; - if(printerVariables.parsedHMScode == 0x0300120000020001) printerVariables.overridestage = 17; - if(printerVariables.parsedHMScode == 0x0700200000030001) printerVariables.overridestage = 6; - if(printerVariables.parsedHMScode == 0x0300020000010001) printerVariables.overridestage = 20; - if(printerVariables.parsedHMScode == 0x0300010000010007) printerVariables.overridestage = 21; - - if (printerConfig.debuging || printerConfig.debugingchange){ + if (oldHMSlevel != printerVariables.parsedHMSlevel) + { + + if (printerVariables.parsedHMScode == 0x0C0003000003000B) + printerVariables.overridestage = 10; + if (printerVariables.parsedHMScode == 0x0300120000020001) + printerVariables.overridestage = 17; + if (printerVariables.parsedHMScode == 0x0700200000030001) + printerVariables.overridestage = 6; + if (printerVariables.parsedHMScode == 0x0300020000010001) + printerVariables.overridestage = 20; + if (printerVariables.parsedHMScode == 0x0300010000010007) + printerVariables.overridestage = 21; + + if (printerConfig.debuging || printerConfig.debugingchange) + { Serial.print(F("MQTT update - parsedHMSlevel now: ")); - if (printerVariables.parsedHMSlevel.length() > 0) { + if (printerVariables.parsedHMSlevel.length() > 0) + { Serial.print(printerVariables.parsedHMSlevel); Serial.print(F(" Error Code: ")); - //Serial.println(F("https://wiki.bambulab.com/en/x1/troubleshooting/how-to-enter-the-specific-code-page")); + // Serial.println(F("https://wiki.bambulab.com/en/x1/troubleshooting/how-to-enter-the-specific-code-page")); int chunk1 = (printerVariables.parsedHMScode >> 48); int chunk2 = (printerVariables.parsedHMScode >> 32) & 0xFFFF; int chunk3 = (printerVariables.parsedHMScode >> 16) & 0xFFFF; @@ -295,12 +359,17 @@ void ParseCallback(char *topic, byte *payload, unsigned int length){ char strHMScode[20]; sprintf(strHMScode, "%04X_%04X_%04X_%04X", chunk1, chunk2, chunk3, chunk4); Serial.print(strHMScode); - if(printerVariables.overridestage != printerVariables.stage){ + if (printerVariables.overridestage != printerVariables.stage) + { Serial.println(F(" **")); - }else{ + } + else + { Serial.println(F("")); } - } else { + } + else + { Serial.println(F("NULL")); printerVariables.overridestage = 999; } @@ -309,10 +378,12 @@ void ParseCallback(char *topic, byte *payload, unsigned int length){ } } - if (Changed == true){ - printerConfig.inactivityStartms = millis(); //restart idle timer + if (Changed == true) + { + printerConfig.inactivityStartms = millis(); // restart idle timer printerConfig.isIdleOFFActive = false; - if (printerConfig.debuging){ + if (printerConfig.debuging) + { Serial.println(F("Change from mqtt")); } printerConfig.maintMode_update = true; @@ -322,19 +393,22 @@ void ParseCallback(char *topic, byte *payload, unsigned int length){ updateleds(); } - }else{ + } + else + { Serial.println(F("Deserialize error while parsing mqtt")); return; } } - -void mqttCallback(char *topic, byte *payload, unsigned int length){ +void mqttCallback(char *topic, byte *payload, unsigned int length) +{ ParseCallback(topic, (byte *)stream.get_buffer(), stream.current_length()); stream.flush(); } -void setupMqtt(){ +void setupMqtt() +{ clientId += String(random(0xffff), HEX); Serial.print(F("Setting up MQTT with Bambu Lab Printer IP address: ")); Serial.println(printerConfig.printerIP); @@ -343,7 +417,7 @@ void setupMqtt(){ report_topic = device_topic + String("/report"); wifiSecureClient.setInsecure(); - mqttClient.setBufferSize(1024); //1024 + mqttClient.setBufferSize(1024); // 1024 mqttClient.setServer(printerConfig.printerIP, 8883); mqttClient.setStream(stream); mqttClient.setCallback(mqttCallback); @@ -352,17 +426,21 @@ void setupMqtt(){ connectMqtt(); } -void mqttloop(){ - if(WiFi.status() != WL_CONNECTED){ - //Abort MQTT connection attempt when no Wifi +void mqttloop() +{ + if (WiFi.status() != WL_CONNECTED) + { + // Abort MQTT connection attempt when no Wifi return; } - if (!mqttClient.connected()){ + if (!mqttClient.connected()) + { printerVariables.online = false; - //Only sent the timer from the first instance of a MQTT disconnect - if(printerVariables.disconnectMQTTms == 0) { + // Only sent the timer from the first instance of a MQTT disconnect + if (printerVariables.disconnectMQTTms == 0) + { printerVariables.disconnectMQTTms = millis(); - //Record last time MQTT dropped connection + // Record last time MQTT dropped connection Serial.println(F("MQTT dropped during mqttloop")); ParseMQTTState(mqttClient.state()); } @@ -371,7 +449,8 @@ void mqttloop(){ delay(32); return; } - else{ + else + { printerVariables.disconnectMQTTms = 0; } mqttClient.loop(); diff --git a/src/blled/serialmanager.h b/src/blled/serialmanager.h index 3d4de29..8068879 100644 --- a/src/blled/serialmanager.h +++ b/src/blled/serialmanager.h @@ -16,7 +16,7 @@ void serialLoop(){ String input = Serial.readStringUntil('\n'); JsonDocument doc; deserializeJson(doc, input); - if (doc.containsKey("ssid") && doc.containsKey("pass")) { + if (doc["ssid"].is() && doc["pass"].is()) { Serial.print(F("SSID ")); Serial.println(doc["ssid"].as()); Serial.print(F("PASS ")); diff --git a/src/blled/types.h b/src/blled/types.h index b9d7bcf..4e05e76 100644 --- a/src/blled/types.h +++ b/src/blled/types.h @@ -43,12 +43,19 @@ extern "C" unsigned long lastdoorOpenms = 0; // Last time door was closed } PrinterVariables; + typedef struct SecurityVariables{ + // Security + char HTTPUser[40] = ""; //http basic auth username + char HTTPPass[40] = ""; //http basic auth password + }SecurityVariables; + SecurityVariables securityVariables; + PrinterVariables printerVariables; typedef struct GlobalVariablesStruct{ char SSID[32]; - char APPW[63]; - String FWVersion = "Expirimental 2025.5.15"; + char APPW[32]; + String FWVersion = STRVERSION; String Host = "BLLED"; bool started = false; } GlobalVariables; @@ -83,6 +90,7 @@ extern "C" bool finish_check = false; //When updateleds() is run, should the TEST LEDS be set? unsigned long finishStartms = 0; // Time the finish countdown is measured from int finishTimeOut = 600000; //300000 = 5 mins + //Inactivity Timout bool inactivityEnabled = true; bool isIdleOFFActive = false; // Are the lights out due to inactivity Timeout? diff --git a/src/blled/web-server.h b/src/blled/web-server.h index 3b06512..5affcab 100644 --- a/src/blled/web-server.h +++ b/src/blled/web-server.h @@ -2,173 +2,126 @@ #define _BLLEDWEB_SERVER #include -#include +#include #include -#include -#include #include #include +#include #include "leds.h" #include "filesystem.h" +AsyncWebServer webServer(80); +AsyncWebSocket ws("/ws"); -WebServer webServer(80); +#include "../www/www.h" +#include "../www/blled_svg.h" +#include "../www/favicon.h" -#include "../www/setuppage.h" -#include "../www/updatepage.h" +unsigned long lastWsPush = 0; +const unsigned long wsPushInterval = 1000; // alle 1000ms -bool isAuthorized() { - return true; //webServer.authenticate("BLLC", printerConfig.webpagePassword); +bool isAuthorized(AsyncWebServerRequest *request) +{ + if (strlen(securityVariables.HTTPUser) == 0 || strlen(securityVariables.HTTPPass) == 0) + { + return true; + } + return request->authenticate(securityVariables.HTTPUser, securityVariables.HTTPPass); } -void handleSetup(){ - if (!isAuthorized()){ - webServer.requestAuthentication(); - return; +void handleSetup(AsyncWebServerRequest *request) +{ + if (!isAuthorized(request)) + { + return request->requestAuthentication(); } - webServer.sendHeader(F("Content-Encoding"), F("gzip")); - webServer.send_P(200, "text/html", (const char*)setuppage_html_gz, (int)setuppage_html_gz_len); + AsyncWebServerResponse *response = request->beginResponse(200, setupPage_html_gz_mime, setupPage_html_gz, setupPage_html_gz_len); + response->addHeader("Content-Encoding", "gzip"); + request->send(response); } -template -String toJson(T val) { - return String(val); +void handleOldSetup(AsyncWebServerRequest *request) +{ + if (!isAuthorized(request)) + { + return request->requestAuthentication(); + } + AsyncWebServerResponse *response = request->beginResponse(200, setupPageOld_html_gz_mime, setupPageOld_html_gz, setupPageOld_html_gz_len); + response->addHeader("Content-Encoding", "gzip"); + request->send(response); } -template <> -String toJson(bool val) { - return val ? "true" : "false"; +void handleUpdatePage(AsyncWebServerRequest *request) +{ + if (!isAuthorized(request)) + { + return request->requestAuthentication(); + } + AsyncWebServerResponse *response = request->beginResponse(200, updatePage_html_gz_mime, updatePage_html_gz, updatePage_html_gz_len); + response->addHeader("Content-Encoding", "gzip"); + request->send(response); } -void submitConfig(){ - bool newBSSID = false; - if (webServer.args() > 0) { - if( strcmp(printerConfig.BSSID,webServer.arg("apMAC").c_str()) != 0 ){ - newBSSID = true; - } - strcpy(printerConfig.printerIP,webServer.arg("ip").c_str()); - strcpy(printerConfig.accessCode,webServer.arg("code").c_str()); - //Force Uppercase - char temperserial[20]; - strcpy(temperserial,webServer.arg("id").c_str()); - for (int x=0; xrequestAuthentication(); } + AsyncWebServerResponse *response = request->beginResponse(200, blled_svg_gz_mime, blled_svg_gz, blled_svg_gz_len); + response->addHeader("Content-Encoding", "gzip"); + request->send(response); } -char* obfuscate(const char* charstring) { - int length = strlen(charstring); - char* blurredstring = new char[length + 1]; - strcpy(blurredstring, charstring); - if (length > 3) { - for (int i = 0; i < length - 3; i++) { - blurredstring[i] = '*'; - } +void handleGetfavicon(AsyncWebServerRequest *request) +{ + if (!isAuthorized(request)) + { + return request->requestAuthentication(); } - blurredstring[length] = '\0'; - return blurredstring; + AsyncWebServerResponse *response = request->beginResponse(200, favicon_png_gz_mime, favicon_png_gz, favicon_png_gz_len); + response->addHeader("Content-Encoding", "gzip"); + request->send(response); } -void handleGetConfig(){ - if (!isAuthorized()){ - webServer.requestAuthentication(); - return; +void handleGetPCC(AsyncWebServerRequest *request) +{ + if (!isAuthorized(request)) + { + return request->requestAuthentication(); + } + AsyncWebServerResponse *response = request->beginResponse(200, particleCanvas_js_gz_mime, (const uint8_t *)particleCanvas_js_gz, particleCanvas_js_gz_len); + response->addHeader("Content-Encoding", "gzip"); + request->send(response); +} + +void handleGetConfig(AsyncWebServerRequest *request) +{ + if (!isAuthorized(request)) + { + return request->requestAuthentication(); } JsonDocument doc; - const char* firmwareVersionChar = globalVariables.FWVersion.c_str(); - doc["firmwareversion"] = firmwareVersionChar; + + doc["firmwareversion"] = globalVariables.FWVersion.c_str(); doc["wifiStrength"] = WiFi.RSSI(); doc["ip"] = printerConfig.printerIP; - doc["code"] = obfuscate(printerConfig.accessCode); - doc["id"] = obfuscate(printerConfig.serialNumber); - + doc["code"] = printerConfig.accessCode; + doc["id"] = printerConfig.serialNumber; doc["apMAC"] = printerConfig.BSSID; doc["brightness"] = printerConfig.brightness; - // LED Behaviour (Choose One) doc["maintMode"] = printerConfig.maintMode; doc["discoMode"] = printerConfig.discoMode; doc["replicateled"] = printerConfig.replicatestate; - // Running Color doc["runningRGB"] = printerConfig.runningColor.RGBhex; doc["runningWW"] = printerConfig.runningColor.ww; doc["runningCW"] = printerConfig.runningColor.cw; - // LED Test Colors doc["showtestcolor"] = printerConfig.testcolorEnabled; doc["testRGB"] = printerConfig.testColor.RGBhex; doc["testWW"] = printerConfig.testColor.ww; doc["testCW"] = printerConfig.testColor.cw; doc["debugwifi"] = printerConfig.debugwifi; - // Options doc["finishindication"] = printerConfig.finishindication; doc["finishColor"] = printerConfig.finishColor.RGBhex; doc["finishWW"] = printerConfig.finishColor.ww; @@ -176,15 +129,12 @@ void handleGetConfig(){ doc["finishExit"] = printerConfig.finishExit; doc["finishTimerMins"] = (int)(printerConfig.finishTimeOut / 60000); doc["inactivityEnabled"] = printerConfig.inactivityEnabled; - doc["inactivityMins"] =(int)( printerConfig.inactivityTimeOut / 60000); - // Debugging + doc["inactivityMins"] = (int)(printerConfig.inactivityTimeOut / 60000); doc["debuging"] = printerConfig.debuging; doc["debugingchange"] = printerConfig.debugingchange; doc["mqttdebug"] = printerConfig.mqttdebug; - // Printer Dependant doc["p1Printer"] = printerVariables.isP1Printer; - doc["doorSwitch"] = printerVariables.useDoorSwtich; - // Customise LED Colors (during Lidar) + doc["doorSwitch"] = printerVariables.useDoorSwtich; doc["stage14RGB"] = printerConfig.stage14Color.RGBhex; doc["stage14WW"] = printerConfig.stage14Color.ww; doc["stage14CW"] = printerConfig.stage14Color.cw; @@ -200,7 +150,6 @@ void handleGetConfig(){ doc["stage10RGB"] = printerConfig.stage10Color.RGBhex; doc["stage10WW"] = printerConfig.stage10Color.ww; doc["stage10CW"] = printerConfig.stage10Color.cw; - // Customise LED Colors doc["errordetection"] = printerConfig.errordetection; doc["wifiRGB"] = printerConfig.wifiRGB.RGBhex; doc["wifiWW"] = printerConfig.wifiRGB.ww; @@ -235,63 +184,396 @@ void handleGetConfig(){ String jsonString; serializeJson(doc, jsonString); - webServer.send(200, "application/json", jsonString); + request->send(200, "application/json", jsonString); +} + +void handlePrinterConfigJson(AsyncWebServerRequest *request) +{ + if (!isAuthorized(request)) + { + return request->requestAuthentication(); + } + JsonDocument doc; + doc["ssid"] = globalVariables.SSID; + doc["pass"] = globalVariables.APPW; + doc["printerIP"] = printerConfig.printerIP; + doc["printerSerial"] = printerConfig.serialNumber; + doc["accessCode"] = printerConfig.accessCode; + doc["webUser"] = securityVariables.HTTPUser; + doc["webPass"] = securityVariables.HTTPPass; - Serial.println(F("Packet sent to setuppage")); - //serializeJson(doc, Serial); - //Serial.println(); + String json; + serializeJson(doc, json); + request->send(200, "application/json", json); } -void setupWebserver(){ - if (!MDNS.begin(globalVariables.Host.c_str())) { - Serial.println(F("Error setting up MDNS responder!")); - while (1) { - delay(1000); +void handleSubmitConfig(AsyncWebServerRequest *request) +{ + if (!isAuthorized(request)) + { + return request->requestAuthentication(); + } + + bool newBSSID = false; + printerConfig.brightness = request->getParam("brightnessslider", true)->value().toInt(); + printerConfig.rescanWiFiNetwork = (request->hasParam("rescanWiFiNetwork", true)); + printerConfig.maintMode = (request->hasParam("maintMode", true)); + printerConfig.discoMode = (request->hasParam("discoMode", true)); + printerConfig.replicatestate = (request->hasParam("replicateLedState", true)); + printerConfig.runningColor = hex2rgb(request->getParam("runningRGB", true)->value().c_str(), + request->getParam("runningWW", true)->value().toInt(), + request->getParam("runningCW", true)->value().toInt()); + printerConfig.testcolorEnabled = (request->hasParam("showtestcolor", true)); + printerConfig.testColor = hex2rgb(request->getParam("testRGB", true)->value().c_str(), + request->getParam("testWW", true)->value().toInt(), + request->getParam("testCW", true)->value().toInt()); + printerConfig.debugwifi = (request->hasParam("debugwifi", true)); + printerConfig.finishindication = (request->hasParam("finishIndication", true)); + printerConfig.finishColor = hex2rgb(request->getParam("finishColor", true)->value().c_str(), + request->getParam("finishWW", true)->value().toInt(), + request->getParam("finishCW", true)->value().toInt()); + printerConfig.finishExit = !(request->hasParam("finishEndTimer", true)); + printerConfig.finishTimeOut = request->getParam("finishTimerMins", true)->value().toInt() * 60000; + printerConfig.inactivityEnabled = (request->hasParam("inactivityEnabled", true)); + printerConfig.inactivityTimeOut = request->getParam("inactivityMins", true)->value().toInt() * 60000; + printerConfig.debuging = (request->hasParam("debuging", true)); + printerConfig.debugingchange = (request->hasParam("debugingchange", true)); + printerConfig.mqttdebug = (request->hasParam("mqttdebug", true)); + printerVariables.isP1Printer = (request->hasParam("p1Printer", true)); + printerVariables.useDoorSwtich = (request->hasParam("doorSwitch", true)); + + printerConfig.stage14Color = hex2rgb(request->getParam("stage14RGB", true)->value().c_str(), + request->getParam("stage14WW", true)->value().toInt(), + request->getParam("stage14CW", true)->value().toInt()); + printerConfig.stage1Color = hex2rgb(request->getParam("stage1RGB", true)->value().c_str(), + request->getParam("stage1WW", true)->value().toInt(), + request->getParam("stage1CW", true)->value().toInt()); + printerConfig.stage8Color = hex2rgb(request->getParam("stage8RGB", true)->value().c_str(), + request->getParam("stage8WW", true)->value().toInt(), + request->getParam("stage8CW", true)->value().toInt()); + printerConfig.stage9Color = hex2rgb(request->getParam("stage9RGB", true)->value().c_str(), + request->getParam("stage9WW", true)->value().toInt(), + request->getParam("stage9CW", true)->value().toInt()); + printerConfig.stage10Color = hex2rgb(request->getParam("stage10RGB", true)->value().c_str(), + request->getParam("stage10WW", true)->value().toInt(), + request->getParam("stage10CW", true)->value().toInt()); + printerConfig.errordetection = (request->hasParam("errorDetection", true)); + printerConfig.wifiRGB = hex2rgb(request->getParam("wifiRGB", true)->value().c_str(), + request->getParam("wifiWW", true)->value().toInt(), + request->getParam("wifiCW", true)->value().toInt()); + printerConfig.pauseRGB = hex2rgb(request->getParam("pauseRGB", true)->value().c_str(), + request->getParam("pauseWW", true)->value().toInt(), + request->getParam("pauseCW", true)->value().toInt()); + printerConfig.firstlayerRGB = hex2rgb(request->getParam("firstlayerRGB", true)->value().c_str(), + request->getParam("firstlayerWW", true)->value().toInt(), + request->getParam("firstlayerCW", true)->value().toInt()); + printerConfig.nozzleclogRGB = hex2rgb(request->getParam("nozzleclogRGB", true)->value().c_str(), + request->getParam("nozzleclogWW", true)->value().toInt(), + request->getParam("nozzleclogCW", true)->value().toInt()); + printerConfig.hmsSeriousRGB = hex2rgb(request->getParam("hmsSeriousRGB", true)->value().c_str(), + request->getParam("hmsSeriousWW", true)->value().toInt(), + request->getParam("hmsSeriousCW", true)->value().toInt()); + printerConfig.hmsFatalRGB = hex2rgb(request->getParam("hmsFatalRGB", true)->value().c_str(), + request->getParam("hmsFatalWW", true)->value().toInt(), + request->getParam("hmsFatalCW", true)->value().toInt()); + printerConfig.filamentRunoutRGB = hex2rgb(request->getParam("filamentRunoutRGB", true)->value().c_str(), + request->getParam("filamentRunoutWW", true)->value().toInt(), + request->getParam("filamentRunoutCW", true)->value().toInt()); + printerConfig.frontCoverRGB = hex2rgb(request->getParam("frontCoverRGB", true)->value().c_str(), + request->getParam("frontCoverWW", true)->value().toInt(), + request->getParam("frontCoverCW", true)->value().toInt()); + printerConfig.nozzleTempRGB = hex2rgb(request->getParam("nozzleTempRGB", true)->value().c_str(), + request->getParam("nozzleTempWW", true)->value().toInt(), + request->getParam("nozzleTempCW", true)->value().toInt()); + printerConfig.bedTempRGB = hex2rgb(request->getParam("bedTempRGB", true)->value().c_str(), + request->getParam("bedTempWW", true)->value().toInt(), + request->getParam("bedTempCW", true)->value().toInt()); + + saveFileSystem(); + Serial.println(F("Packet received from setuppage")); + printerConfig.inactivityStartms = millis(); + printerConfig.isIdleOFFActive = false; + printerConfig.replicate_update = true; + printerConfig.maintMode_update = true; + printerConfig.discoMode_update = true; + printerConfig.testcolor_update = true; + updateleds(); + request->redirect("/"); +} + +void sendJsonToAll(JsonDocument &doc) +{ + String jsonString; + serializeJson(doc, jsonString); + ws.textAll(jsonString); +} + +void handleWiFiScan(AsyncWebServerRequest *request) +{ + JsonDocument doc; + JsonArray networks = doc["networks"].to(); + + int n = WiFi.scanNetworks(); + for (int i = 0; i < n; ++i) + { + JsonObject net = networks.add(); + net["ssid"] = WiFi.SSID(i); + net["rssi"] = WiFi.RSSI(i); + net["enc"] = (WiFi.encryptionType(i) == WIFI_AUTH_OPEN) ? false : true; + } + + String json; + serializeJson(doc, json); + request->send(200, "application/json", json); +} + +void handleWiFiSetupPage(AsyncWebServerRequest *request) +{ + AsyncWebServerResponse *response = request->beginResponse(200, wifiSetup_html_gz_mime, wifiSetup_html_gz, wifiSetup_html_gz_len); + response->addHeader("Content-Encoding", "gzip"); + request->send(response); +} + +void handleSubmitWiFi(AsyncWebServerRequest *request) +{ + // Check for SSID + PASS optional handling + bool hasSSID = request->hasParam("ssid", true); + bool hasPASS = request->hasParam("pass", true); + + if (hasSSID && hasPASS) + { + String ssid = request->getParam("ssid", true)->value(); + String pass = request->getParam("pass", true)->value(); + ssid.trim(); + pass.trim(); + + if (ssid.length() > 0 && pass.length() > 0) + { + Serial.println(F("[WiFiSetup] Updating WiFi credentials:")); + Serial.print(F("SSID: ")); + Serial.println(ssid); + Serial.print(F("Password: ")); + Serial.println(pass); + + strlcpy(globalVariables.SSID, ssid.c_str(), sizeof(globalVariables.SSID)); + strlcpy(globalVariables.APPW, pass.c_str(), sizeof(globalVariables.APPW)); } + else + { + Serial.println(F("[WiFiSetup] Empty SSID or PASS received → ignoring WiFi update.")); + } + } + else + { + Serial.println(F("[WiFiSetup] No SSID or PASS provided → keeping existing WiFi credentials.")); + } + + // Optional other fields (printerIP, printerSerial, etc.) + String printerIP = request->hasParam("printerIP", true) ? request->getParam("printerIP", true)->value() : ""; + String printerSerial = request->hasParam("printerSerial", true) ? request->getParam("printerSerial", true)->value() : ""; + String accessCode = request->hasParam("accessCode", true) ? request->getParam("accessCode", true)->value() : ""; + String webUser = request->hasParam("webUser", true) ? request->getParam("webUser", true)->value() : ""; + String webPass = request->hasParam("webPass", true) ? request->getParam("webPass", true)->value() : ""; + + if (printerIP.length() > 0) + strlcpy(printerConfig.printerIP, printerIP.c_str(), sizeof(printerConfig.printerIP)); + if (printerSerial.length() > 0) + strlcpy(printerConfig.serialNumber, printerSerial.c_str(), sizeof(printerConfig.serialNumber)); + if (accessCode.length() > 0) + strlcpy(printerConfig.accessCode, accessCode.c_str(), sizeof(printerConfig.accessCode)); + + strlcpy(securityVariables.HTTPUser, webUser.c_str(), sizeof(securityVariables.HTTPUser)); + strlcpy(securityVariables.HTTPPass, webPass.c_str(), sizeof(securityVariables.HTTPPass)); + + saveFileSystem(); + + request->send(200, "text/plain", "Settings saved, restarting..."); + shouldRestart = true; + restartRequestTime = millis(); +} + +void websocketLoop() +{ + if (ws.count() == 0) + return; + if (millis() - lastWsPush > wsPushInterval) + { + lastWsPush = millis(); + + JsonDocument doc; + doc["wifi_rssi"] = WiFi.RSSI(); + doc["ip"] = WiFi.localIP().toString(); + doc["uptime"] = millis() / 1000; + doc["doorOpen"] = printerVariables.doorOpen; + doc["printerConnection"] = printerVariables.online; + doc["clients"] = ws.count(); + + sendJsonToAll(doc); + + Serial.println(F("[WS] JSON Status Push send.")); + } +} + +void handleConfigPage(AsyncWebServerRequest *request) +{ + if (!isAuthorized(request)) + return request->requestAuthentication(); + AsyncWebServerResponse *response = request->beginResponse(200, backupRestore_html_gz_mime, backupRestore_html_gz, backupRestore_html_gz_len); + response->addHeader("Content-Encoding", "gzip"); + request->send(response); +} + +void handleDownloadConfigFile(AsyncWebServerRequest *request) +{ + if (!isAuthorized(request)) + { + return request->requestAuthentication(); + } + if (!LittleFS.exists(configPath)) + { + request->send(404, "text/plain", "Config file not found"); + return; + } + request->send(LittleFS, configPath, "application/json", true, nullptr); +} + +void handleUploadConfigFileData(AsyncWebServerRequest *request, const String &filename, + size_t index, uint8_t *data, size_t len, bool final) +{ + static File uploadFile; + + if (!index) + { + Serial.println(F("[ConfigUpload] Start")); + uploadFile = LittleFS.open(configPath, "w"); + } + if (uploadFile) + { + uploadFile.write(data, len); + } + if (final) + { + uploadFile.close(); + Serial.println(F("[ConfigUpload] Finished")); + } + shouldRestart = true; + restartRequestTime = millis(); +} + +void onWsEvent(AsyncWebSocket *server, AsyncWebSocketClient *client, AwsEventType type, + void *arg, uint8_t *data, size_t len) +{ + switch (type) + { + case WS_EVT_CONNECT: + Serial.printf("[WS] Client connected: %u\n", client->id()); + break; + case WS_EVT_DISCONNECT: + Serial.printf("[WS] Client disconnected: %u\n", client->id()); + ws.cleanupClients(); + break; + case WS_EVT_DATA: + Serial.printf("[WS] Data received from client %u\n", client->id()); + break; + case WS_EVT_PONG: + Serial.printf("[WS] Pong received from %u\n", client->id()); + break; + case WS_EVT_ERROR: + Serial.printf("[WS] Error on connection %u\n", client->id()); + ws.cleanupClients(); + break; + } +} + +void setupWebserver() +{ + if (!MDNS.begin(globalVariables.Host.c_str())) + { + Serial.println(F("Error setting up MDNS responder!")); + while (1) + delay(500); } Serial.println(F("Setting up webserver")); - - webServer.on("/", handleSetup); - webServer.on("/submitConfig",HTTP_POST,submitConfig); - webServer.on("/getConfig", handleGetConfig); - - webServer.on("/update", HTTP_POST, []() { - webServer.sendHeader("Connection", "close"); - webServer.send(200, "text/plain", (Update.hasError()) ? "FAIL" : "OK"); + + webServer.on("/", HTTP_GET, [](AsyncWebServerRequest *request) + { + if (WiFi.getMode() == WIFI_AP) { + Serial.println(F("[WebServer] Captive Portal activ – redirect to /wifi")); + request->redirect("/wifi"); + } else { + //handleOldSetup(request); + handleOldSetup(request); + } }); + // webServer.on("/old", HTTP_GET, handleOldSetup); + webServer.on("/old", HTTP_GET, handleSetup); + webServer.on("/fwupdate", HTTP_GET, handleUpdatePage); + webServer.on("/getConfig", HTTP_GET, handleGetConfig); + webServer.on("/submitConfig", HTTP_POST, handleSubmitConfig); + webServer.on("/blled.png", HTTP_GET, handleGetIcon); + webServer.on("/favicon.ico", HTTP_GET, handleGetfavicon); + webServer.on("/particleCanvas.js", HTTP_GET, handleGetPCC); + webServer.on("/config.json", HTTP_GET, handlePrinterConfigJson); + webServer.on("/wifi", HTTP_GET, handleWiFiSetupPage); + webServer.on("/wifiScan", HTTP_GET, handleWiFiScan); + webServer.on("/submitWiFi", HTTP_POST, handleSubmitWiFi); + + webServer.on("/backuprestore", HTTP_GET, handleConfigPage); + webServer.on("/configfile.json", HTTP_GET, handleDownloadConfigFile); + webServer.on("/confirestore", HTTP_POST, [](AsyncWebServerRequest *request) + { + if (!isAuthorized(request)) { + return request->requestAuthentication(); + } + request->send(200, "text/plain", "Config uploaded. Restarting..."); + shouldRestart = true; + restartRequestTime = millis(); }, [](AsyncWebServerRequest *request, const String &filename, size_t index, uint8_t *data, size_t len, bool final) + { + static File uploadFile; + + if (!index) { + Serial.printf("[ConfigUpload] Start: %s\n", filename.c_str()); + uploadFile = LittleFS.open(configPath, "w"); + } + if (uploadFile) { + uploadFile.write(data, len); + } + if (final) { + uploadFile.close(); + Serial.println(F("[ConfigUpload] Finished")); + } }); + + webServer.on("/update", HTTP_POST, [](AsyncWebServerRequest *request) + { + request->send(200, "text/plain", "OK"); Serial.println(F("Restarting Device")); - delay(1000); - ESP.restart(); - }, []() { - HTTPUpload& upload = webServer.upload(); - if (upload.status == UPLOAD_FILE_START) { - Serial.printf("Update: %s\n", upload.filename.c_str()); + shouldRestart = true; + restartRequestTime = millis(); }); + + webServer.onFileUpload([](AsyncWebServerRequest *request, const String &filename, size_t index, uint8_t *data, size_t len, bool final) + { + if (!index) { + Serial.printf("Update: %s\n", filename.c_str()); if (!Update.begin(UPDATE_SIZE_UNKNOWN)) { Update.printError(Serial); } - } else if (upload.status == UPLOAD_FILE_WRITE) { - - if (Update.write(upload.buf, upload.currentSize) != upload.currentSize) { - Update.printError(Serial); - } - } else if (upload.status == UPLOAD_FILE_END) { + } + if (Update.write(data, len) != len) { + Update.printError(Serial); + } + if (final) { if (Update.end(true)) { - Serial.printf("Update Success: %u\nRebooting...\n", upload.totalSize); + Serial.printf("Update Success: %u\nRebooting...\n", index + len); } else { Update.printError(Serial); } - } - }); + } }); + ws.onEvent(onWsEvent); + webServer.addHandler(&ws); webServer.begin(); Serial.println(F("Webserver started")); - Serial.println(); -} - -void webserverloop(){ - webServer.handleClient(); - delay(10); } #endif diff --git a/src/blled/wifi-manager.h b/src/blled/wifi-manager.h index 8f4c6b0..a091f2e 100644 --- a/src/blled/wifi-manager.h +++ b/src/blled/wifi-manager.h @@ -8,6 +8,10 @@ #include "filesystem.h" #include "types.h" +#include +DNSServer dnsServer; +IPAddress apIP(192, 168, 4, 1); + bool shouldSaveConfig = true; int connectionAttempts = 1; int wifimode = 0; @@ -159,6 +163,18 @@ bool connectToWifi(){ return true; }; +void startAPMode() { + WiFi.disconnect(true, true); + WiFi.mode(WIFI_AP); + delay(500); + WiFi.softAP("BLLED_AP"); + WiFi.softAPConfig(apIP, apIP, IPAddress(255, 255, 255, 0)); + dnsServer.start(53, "*", apIP); + + Serial.println(F("[WiFiManager] AP gestartet auf IP: ")); + Serial.println(WiFi.softAPIP()); +} + void scanNetwork() { //Reference / Credit - https://www.esp32.com/viewtopic.php?t=18979#p70299 diff --git a/src/main.cpp b/src/main.cpp index 7bcbbcb..50cf6ae 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,4 +1,6 @@ #include +bool shouldRestart = false; +unsigned long restartRequestTime = 0; #include "./blled/web-server.h" #include "./blled/mqttmanager.h" #include "./blled/filesystem.h" @@ -9,34 +11,35 @@ #include "./blled/ssdp.h" int wifi_reconnect_count = 0; -void defaultcolors(){ + +void defaultcolors() +{ Serial.println(F("Setting default customisable colors")); - printerConfig.runningColor = hex2rgb("#000000",255,255);//WHITE Running - printerConfig.testColor = hex2rgb("#3F3CFB"); //Violet Test - printerConfig.finishColor = hex2rgb("#00FF00"); //Green Finish - - printerConfig.stage14Color = hex2rgb("#000000"); //OFF Cleaning Nozzle - printerConfig.stage1Color = hex2rgb("#000055"); //OFF Bed Leveling - printerConfig.stage8Color = hex2rgb("#000000"); //OFF Calibrating Extrusion - printerConfig.stage9Color = hex2rgb("#000000"); //OFF Scanning Bed Surface - printerConfig.stage10Color = hex2rgb("#000000"); //OFF First Layer Inspection - - printerConfig.wifiRGB = hex2rgb("#FFA500"); //Orange Wifi Scan - - printerConfig.pauseRGB = hex2rgb("#0000FF"); //Blue Pause - printerConfig.firstlayerRGB = hex2rgb("#0000FF"); //Blue - printerConfig.nozzleclogRGB = hex2rgb("#0000FF"); //Blue - printerConfig.hmsSeriousRGB = hex2rgb("#FF0000"); //Red - printerConfig.hmsFatalRGB = hex2rgb("#FF0000"); //Red - printerConfig.filamentRunoutRGB = hex2rgb("#FF0000"); //Red - printerConfig.frontCoverRGB = hex2rgb("#FF0000"); //Red - printerConfig.nozzleTempRGB = hex2rgb("#FF0000"); //Red - printerConfig.bedTempRGB = hex2rgb("#FF0000"); //Red + printerConfig.runningColor = hex2rgb("#000000", 255, 255); // WHITE Running + printerConfig.testColor = hex2rgb("#3F3CFB"); // Violet Test + printerConfig.finishColor = hex2rgb("#00FF00"); // Green Finish + + printerConfig.stage14Color = hex2rgb("#000000"); // OFF Cleaning Nozzle + printerConfig.stage1Color = hex2rgb("#000055"); // OFF Bed Leveling + printerConfig.stage8Color = hex2rgb("#000000"); // OFF Calibrating Extrusion + printerConfig.stage9Color = hex2rgb("#000000"); // OFF Scanning Bed Surface + printerConfig.stage10Color = hex2rgb("#000000"); // OFF First Layer Inspection + printerConfig.wifiRGB = hex2rgb("#FFA500"); // Orange Wifi Scan + printerConfig.pauseRGB = hex2rgb("#0000FF"); // Blue Pause + printerConfig.firstlayerRGB = hex2rgb("#0000FF"); // Blue + printerConfig.nozzleclogRGB = hex2rgb("#0000FF"); // Blue + printerConfig.hmsSeriousRGB = hex2rgb("#FF0000"); // Red + printerConfig.hmsFatalRGB = hex2rgb("#FF0000"); // Red + printerConfig.filamentRunoutRGB = hex2rgb("#FF0000"); // Red + printerConfig.frontCoverRGB = hex2rgb("#FF0000"); // Red + printerConfig.nozzleTempRGB = hex2rgb("#FF0000"); // Red + printerConfig.bedTempRGB = hex2rgb("#FF0000"); // Red } -void setup(){ +void setup() +{ Serial.begin(115200); delay(100); Serial.println(F("Initializing")); @@ -48,37 +51,42 @@ void setup(){ Serial.println(""); defaultcolors(); setupLeds(); - tweenToColor(100,100,100,100,100); //ALL LEDS ON + tweenToColor(100, 100, 100, 100, 100); // ALL LEDS ON Serial.println(F("")); - delay(1000); - tweenToColor(255,0,0,0,0); //RED + tweenToColor(255, 0, 0, 0, 0); // RED setupFileSystem(); loadFileSystem(); Serial.println(F("")); - delay(500); - tweenToColor(printerConfig.wifiRGB); //Customisable - Default is ORANGE + tweenToColor(printerConfig.wifiRGB); // Customisable - Default is ORANGE setupSerial(); - if (strlen(globalVariables.SSID) == 0 || strlen(globalVariables.APPW) == 0) { + if (strlen(globalVariables.SSID) == 0 || strlen(globalVariables.APPW) == 0) + { Serial.println(F("SSID or password is missing. Please configure both by going to: https://dutchdevelop.com/blled-configuration-setup/")); - tweenToColor(100,0,100,0,0); //PINK + tweenToColor(100, 0, 100, 0, 0); // PINK + startAPMode(); + setupWebserver(); return; } - - scanNetwork(); //Sets the MAC address for following connection attempt - if(!connectToWifi()){ + + if (!connectToWifi()) + { + Serial.println(F("[WiFiManager] Not connected → AP Mode")); + startAPMode(); + setupWebserver(); return; } + Serial.println(F("[WiFiManager] connected. Starting webUI.")); + setupWebserver(); - tweenToColor(0,0,255,0,0); //BLUE + tweenToColor(0, 0, 255, 0, 0); // BLUE setupWebserver(); - delay(500); start_ssdp(); - - tweenToColor(34,224,238,0,0); //CYAN + + tweenToColor(34, 224, 238, 0, 0); // CYAN setupMqtt(); Serial.println(); @@ -92,38 +100,53 @@ void setup(){ updateleds(); } -void loop(){ +void loop() +{ serialLoop(); - if (globalVariables.started){ + if (globalVariables.started) + { mqttloop(); - webserverloop(); + websocketLoop(); ledsloop(); - - if (WiFi.status() != WL_CONNECTED){ + + if (WiFi.status() != WL_CONNECTED) + { Serial.print(F("Wifi connection dropped. ")); - Serial.print(F("Wifi Status: ")); + Serial.print(F("Wifi Status: ")); Serial.println(wl_status_to_string(WiFi.status())); Serial.println(F("Attempting to reconnect to WiFi...")); wifi_reconnect_count += 1; - if(wifi_reconnect_count <= 2){ + if (wifi_reconnect_count <= 2) + { WiFi.disconnect(); delay(100); WiFi.reconnect(); - } else { - //Not connecting after 10 simple disconnect / reconnects - //Do something more drastic in case needing to switch to new AP + } + else + { + // Not connecting after 10 simple disconnect / reconnects + // Do something more drastic in case needing to switch to new AP scanNetwork(); connectToWifi(); wifi_reconnect_count = 0; } } + if (WiFi.getMode() == WIFI_AP) + { + dnsServer.processNextRequest(); + } } - if(printerConfig.rescanWiFiNetwork) + if (printerConfig.rescanWiFiNetwork) { Serial.println(F("Web submitted refresh of Wifi Scan (assigning Strongest AP)")); - tweenToColor(printerConfig.wifiRGB); //Customisable - Default is ORANGE - scanNetwork(); //Sets the MAC address for following connection attempt + tweenToColor(printerConfig.wifiRGB); // Customisable - Default is ORANGE + scanNetwork(); // Sets the MAC address for following connection attempt printerConfig.rescanWiFiNetwork = false; updateleds(); } + if (shouldRestart && millis() - restartRequestTime > 1500) + { + Serial.println(F("[WiFiSetup] Restarting now...")); + ESP.restart(); + } } \ No newline at end of file diff --git a/src/www/Icon-square.png b/src/www/Icon-square.png deleted file mode 100644 index aa12bf1..0000000 Binary files a/src/www/Icon-square.png and /dev/null differ diff --git a/src/www/backupRestore.html b/src/www/backupRestore.html new file mode 100644 index 0000000..2e9cb8a --- /dev/null +++ b/src/www/backupRestore.html @@ -0,0 +1,138 @@ + + + + + + + BLLED Config Backup + + + + + +
+ +
+

Download current config:

+ + +
+ +
+ + + +
+ +

+
+
+ + + + + \ No newline at end of file diff --git a/src/www/blled.svg b/src/www/blled.svg new file mode 100644 index 0000000..05b1a9a --- /dev/null +++ b/src/www/blled.svg @@ -0,0 +1,42 @@ + + + + diff --git a/src/www/blled_svg.h b/src/www/blled_svg.h new file mode 100644 index 0000000..9fc8a0d --- /dev/null +++ b/src/www/blled_svg.h @@ -0,0 +1,232 @@ +#include +//https://tomeko.net/online_tools/file_to_hex.php?lang=en +const unsigned int BBLED_svg_len = 3626; +const uint8_t BBLED_svg[] PROGMEM = { +0x3C, 0x3F, 0x78, 0x6D, 0x6C, 0x20, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x3D, 0x22, 0x31, +0x2E, 0x30, 0x22, 0x20, 0x65, 0x6E, 0x63, 0x6F, 0x64, 0x69, 0x6E, 0x67, 0x3D, 0x22, 0x55, 0x54, +0x46, 0x2D, 0x38, 0x22, 0x20, 0x73, 0x74, 0x61, 0x6E, 0x64, 0x61, 0x6C, 0x6F, 0x6E, 0x65, 0x3D, +0x22, 0x6E, 0x6F, 0x22, 0x3F, 0x3E, 0x0A, 0x3C, 0x21, 0x2D, 0x2D, 0x20, 0x43, 0x72, 0x65, 0x61, +0x74, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x49, 0x6E, 0x6B, 0x73, 0x63, 0x61, 0x70, +0x65, 0x20, 0x28, 0x68, 0x74, 0x74, 0x70, 0x3A, 0x2F, 0x2F, 0x77, 0x77, 0x77, 0x2E, 0x69, 0x6E, +0x6B, 0x73, 0x63, 0x61, 0x70, 0x65, 0x2E, 0x6F, 0x72, 0x67, 0x2F, 0x29, 0x20, 0x2D, 0x2D, 0x3E, +0x0A, 0x0A, 0x3C, 0x73, 0x76, 0x67, 0x0A, 0x20, 0x20, 0x20, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3D, +0x22, 0x37, 0x33, 0x2E, 0x35, 0x38, 0x33, 0x38, 0x34, 0x37, 0x6D, 0x6D, 0x22, 0x0A, 0x20, 0x20, +0x20, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x3D, 0x22, 0x31, 0x31, 0x38, 0x2E, 0x34, 0x35, 0x31, +0x36, 0x31, 0x6D, 0x6D, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x76, 0x69, 0x65, 0x77, 0x42, 0x6F, 0x78, +0x3D, 0x22, 0x30, 0x20, 0x30, 0x20, 0x37, 0x33, 0x2E, 0x35, 0x38, 0x33, 0x38, 0x34, 0x38, 0x20, +0x31, 0x31, 0x38, 0x2E, 0x34, 0x35, 0x31, 0x36, 0x32, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x76, 0x65, +0x72, 0x73, 0x69, 0x6F, 0x6E, 0x3D, 0x22, 0x31, 0x2E, 0x31, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x69, +0x64, 0x3D, 0x22, 0x73, 0x76, 0x67, 0x31, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x78, 0x6D, 0x6C, 0x3A, +0x73, 0x70, 0x61, 0x63, 0x65, 0x3D, 0x22, 0x70, 0x72, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x22, +0x0A, 0x20, 0x20, 0x20, 0x69, 0x6E, 0x6B, 0x73, 0x63, 0x61, 0x70, 0x65, 0x3A, 0x76, 0x65, 0x72, +0x73, 0x69, 0x6F, 0x6E, 0x3D, 0x22, 0x31, 0x2E, 0x34, 0x20, 0x28, 0x38, 0x36, 0x61, 0x38, 0x61, +0x64, 0x37, 0x2C, 0x20, 0x32, 0x30, 0x32, 0x34, 0x2D, 0x31, 0x30, 0x2D, 0x31, 0x31, 0x29, 0x22, +0x0A, 0x20, 0x20, 0x20, 0x73, 0x6F, 0x64, 0x69, 0x70, 0x6F, 0x64, 0x69, 0x3A, 0x64, 0x6F, 0x63, +0x6E, 0x61, 0x6D, 0x65, 0x3D, 0x22, 0x62, 0x6C, 0x6C, 0x65, 0x64, 0x2E, 0x73, 0x76, 0x67, 0x22, +0x0A, 0x20, 0x20, 0x20, 0x78, 0x6D, 0x6C, 0x6E, 0x73, 0x3A, 0x69, 0x6E, 0x6B, 0x73, 0x63, 0x61, +0x70, 0x65, 0x3D, 0x22, 0x68, 0x74, 0x74, 0x70, 0x3A, 0x2F, 0x2F, 0x77, 0x77, 0x77, 0x2E, 0x69, +0x6E, 0x6B, 0x73, 0x63, 0x61, 0x70, 0x65, 0x2E, 0x6F, 0x72, 0x67, 0x2F, 0x6E, 0x61, 0x6D, 0x65, +0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x2F, 0x69, 0x6E, 0x6B, 0x73, 0x63, 0x61, 0x70, 0x65, 0x22, +0x0A, 0x20, 0x20, 0x20, 0x78, 0x6D, 0x6C, 0x6E, 0x73, 0x3A, 0x73, 0x6F, 0x64, 0x69, 0x70, 0x6F, +0x64, 0x69, 0x3D, 0x22, 0x68, 0x74, 0x74, 0x70, 0x3A, 0x2F, 0x2F, 0x73, 0x6F, 0x64, 0x69, 0x70, +0x6F, 0x64, 0x69, 0x2E, 0x73, 0x6F, 0x75, 0x72, 0x63, 0x65, 0x66, 0x6F, 0x72, 0x67, 0x65, 0x2E, +0x6E, 0x65, 0x74, 0x2F, 0x44, 0x54, 0x44, 0x2F, 0x73, 0x6F, 0x64, 0x69, 0x70, 0x6F, 0x64, 0x69, +0x2D, 0x30, 0x2E, 0x64, 0x74, 0x64, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x78, 0x6D, 0x6C, 0x6E, 0x73, +0x3D, 0x22, 0x68, 0x74, 0x74, 0x70, 0x3A, 0x2F, 0x2F, 0x77, 0x77, 0x77, 0x2E, 0x77, 0x33, 0x2E, +0x6F, 0x72, 0x67, 0x2F, 0x32, 0x30, 0x30, 0x30, 0x2F, 0x73, 0x76, 0x67, 0x22, 0x0A, 0x20, 0x20, +0x20, 0x78, 0x6D, 0x6C, 0x6E, 0x73, 0x3A, 0x73, 0x76, 0x67, 0x3D, 0x22, 0x68, 0x74, 0x74, 0x70, +0x3A, 0x2F, 0x2F, 0x77, 0x77, 0x77, 0x2E, 0x77, 0x33, 0x2E, 0x6F, 0x72, 0x67, 0x2F, 0x32, 0x30, +0x30, 0x30, 0x2F, 0x73, 0x76, 0x67, 0x22, 0x3E, 0x3C, 0x73, 0x6F, 0x64, 0x69, 0x70, 0x6F, 0x64, +0x69, 0x3A, 0x6E, 0x61, 0x6D, 0x65, 0x64, 0x76, 0x69, 0x65, 0x77, 0x0A, 0x20, 0x20, 0x20, 0x20, +0x20, 0x69, 0x64, 0x3D, 0x22, 0x6E, 0x61, 0x6D, 0x65, 0x64, 0x76, 0x69, 0x65, 0x77, 0x31, 0x22, +0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x70, 0x61, 0x67, 0x65, 0x63, 0x6F, 0x6C, 0x6F, 0x72, 0x3D, +0x22, 0x23, 0x35, 0x30, 0x35, 0x30, 0x35, 0x30, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x62, +0x6F, 0x72, 0x64, 0x65, 0x72, 0x63, 0x6F, 0x6C, 0x6F, 0x72, 0x3D, 0x22, 0x23, 0x65, 0x65, 0x65, +0x65, 0x65, 0x65, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x62, 0x6F, 0x72, 0x64, 0x65, 0x72, +0x6F, 0x70, 0x61, 0x63, 0x69, 0x74, 0x79, 0x3D, 0x22, 0x31, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, +0x20, 0x69, 0x6E, 0x6B, 0x73, 0x63, 0x61, 0x70, 0x65, 0x3A, 0x73, 0x68, 0x6F, 0x77, 0x70, 0x61, +0x67, 0x65, 0x73, 0x68, 0x61, 0x64, 0x6F, 0x77, 0x3D, 0x22, 0x30, 0x22, 0x0A, 0x20, 0x20, 0x20, +0x20, 0x20, 0x69, 0x6E, 0x6B, 0x73, 0x63, 0x61, 0x70, 0x65, 0x3A, 0x70, 0x61, 0x67, 0x65, 0x6F, +0x70, 0x61, 0x63, 0x69, 0x74, 0x79, 0x3D, 0x22, 0x30, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, +0x69, 0x6E, 0x6B, 0x73, 0x63, 0x61, 0x70, 0x65, 0x3A, 0x70, 0x61, 0x67, 0x65, 0x63, 0x68, 0x65, +0x63, 0x6B, 0x65, 0x72, 0x62, 0x6F, 0x61, 0x72, 0x64, 0x3D, 0x22, 0x30, 0x22, 0x0A, 0x20, 0x20, +0x20, 0x20, 0x20, 0x69, 0x6E, 0x6B, 0x73, 0x63, 0x61, 0x70, 0x65, 0x3A, 0x64, 0x65, 0x73, 0x6B, +0x63, 0x6F, 0x6C, 0x6F, 0x72, 0x3D, 0x22, 0x23, 0x35, 0x30, 0x35, 0x30, 0x35, 0x30, 0x22, 0x0A, +0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6E, 0x6B, 0x73, 0x63, 0x61, 0x70, 0x65, 0x3A, 0x64, 0x6F, +0x63, 0x75, 0x6D, 0x65, 0x6E, 0x74, 0x2D, 0x75, 0x6E, 0x69, 0x74, 0x73, 0x3D, 0x22, 0x6D, 0x6D, +0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6E, 0x6B, 0x73, 0x63, 0x61, 0x70, 0x65, 0x3A, +0x7A, 0x6F, 0x6F, 0x6D, 0x3D, 0x22, 0x30, 0x2E, 0x37, 0x31, 0x38, 0x39, 0x31, 0x38, 0x33, 0x35, +0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6E, 0x6B, 0x73, 0x63, 0x61, 0x70, 0x65, 0x3A, +0x63, 0x78, 0x3D, 0x22, 0x2D, 0x33, 0x31, 0x36, 0x2E, 0x34, 0x34, 0x37, 0x36, 0x32, 0x22, 0x0A, +0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6E, 0x6B, 0x73, 0x63, 0x61, 0x70, 0x65, 0x3A, 0x63, 0x79, +0x3D, 0x22, 0x32, 0x32, 0x36, 0x2E, 0x30, 0x33, 0x34, 0x30, 0x31, 0x22, 0x0A, 0x20, 0x20, 0x20, +0x20, 0x20, 0x69, 0x6E, 0x6B, 0x73, 0x63, 0x61, 0x70, 0x65, 0x3A, 0x77, 0x69, 0x6E, 0x64, 0x6F, +0x77, 0x2D, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3D, 0x22, 0x31, 0x39, 0x32, 0x30, 0x22, 0x0A, 0x20, +0x20, 0x20, 0x20, 0x20, 0x69, 0x6E, 0x6B, 0x73, 0x63, 0x61, 0x70, 0x65, 0x3A, 0x77, 0x69, 0x6E, +0x64, 0x6F, 0x77, 0x2D, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x3D, 0x22, 0x31, 0x30, 0x30, 0x39, +0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6E, 0x6B, 0x73, 0x63, 0x61, 0x70, 0x65, 0x3A, +0x77, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x2D, 0x78, 0x3D, 0x22, 0x2D, 0x38, 0x22, 0x0A, 0x20, 0x20, +0x20, 0x20, 0x20, 0x69, 0x6E, 0x6B, 0x73, 0x63, 0x61, 0x70, 0x65, 0x3A, 0x77, 0x69, 0x6E, 0x64, +0x6F, 0x77, 0x2D, 0x79, 0x3D, 0x22, 0x2D, 0x38, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, +0x6E, 0x6B, 0x73, 0x63, 0x61, 0x70, 0x65, 0x3A, 0x77, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x2D, 0x6D, +0x61, 0x78, 0x69, 0x6D, 0x69, 0x7A, 0x65, 0x64, 0x3D, 0x22, 0x31, 0x22, 0x0A, 0x20, 0x20, 0x20, +0x20, 0x20, 0x69, 0x6E, 0x6B, 0x73, 0x63, 0x61, 0x70, 0x65, 0x3A, 0x63, 0x75, 0x72, 0x72, 0x65, +0x6E, 0x74, 0x2D, 0x6C, 0x61, 0x79, 0x65, 0x72, 0x3D, 0x22, 0x6C, 0x61, 0x79, 0x65, 0x72, 0x31, +0x22, 0x20, 0x2F, 0x3E, 0x3C, 0x64, 0x65, 0x66, 0x73, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, +0x64, 0x3D, 0x22, 0x64, 0x65, 0x66, 0x73, 0x31, 0x22, 0x20, 0x2F, 0x3E, 0x3C, 0x67, 0x0A, 0x20, +0x20, 0x20, 0x20, 0x20, 0x69, 0x6E, 0x6B, 0x73, 0x63, 0x61, 0x70, 0x65, 0x3A, 0x6C, 0x61, 0x62, +0x65, 0x6C, 0x3D, 0x22, 0x45, 0x62, 0x65, 0x6E, 0x65, 0x20, 0x31, 0x22, 0x0A, 0x20, 0x20, 0x20, +0x20, 0x20, 0x69, 0x6E, 0x6B, 0x73, 0x63, 0x61, 0x70, 0x65, 0x3A, 0x67, 0x72, 0x6F, 0x75, 0x70, +0x6D, 0x6F, 0x64, 0x65, 0x3D, 0x22, 0x6C, 0x61, 0x79, 0x65, 0x72, 0x22, 0x0A, 0x20, 0x20, 0x20, +0x20, 0x20, 0x69, 0x64, 0x3D, 0x22, 0x6C, 0x61, 0x79, 0x65, 0x72, 0x31, 0x22, 0x0A, 0x20, 0x20, +0x20, 0x20, 0x20, 0x74, 0x72, 0x61, 0x6E, 0x73, 0x66, 0x6F, 0x72, 0x6D, 0x3D, 0x22, 0x74, 0x72, +0x61, 0x6E, 0x73, 0x6C, 0x61, 0x74, 0x65, 0x28, 0x2D, 0x31, 0x38, 0x38, 0x2E, 0x36, 0x34, 0x36, +0x36, 0x32, 0x2C, 0x2D, 0x38, 0x38, 0x2E, 0x35, 0x37, 0x32, 0x30, 0x30, 0x33, 0x29, 0x22, 0x3E, +0x3C, 0x70, 0x61, 0x74, 0x68, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x74, 0x79, +0x6C, 0x65, 0x3D, 0x22, 0x66, 0x69, 0x6C, 0x6C, 0x3A, 0x23, 0x30, 0x31, 0x61, 0x37, 0x34, 0x66, +0x3B, 0x66, 0x69, 0x6C, 0x6C, 0x2D, 0x6F, 0x70, 0x61, 0x63, 0x69, 0x74, 0x79, 0x3A, 0x31, 0x22, +0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x64, 0x3D, 0x22, 0x6D, 0x20, 0x32, 0x32, 0x32, +0x2E, 0x33, 0x38, 0x33, 0x33, 0x38, 0x2C, 0x32, 0x30, 0x36, 0x2E, 0x36, 0x39, 0x34, 0x35, 0x37, +0x20, 0x63, 0x20, 0x2D, 0x34, 0x2E, 0x31, 0x31, 0x38, 0x36, 0x36, 0x2C, 0x2D, 0x31, 0x2E, 0x31, +0x39, 0x32, 0x30, 0x31, 0x20, 0x2D, 0x37, 0x2E, 0x34, 0x38, 0x30, 0x37, 0x38, 0x2C, 0x2D, 0x33, +0x2E, 0x39, 0x33, 0x31, 0x31, 0x36, 0x20, 0x2D, 0x39, 0x2E, 0x31, 0x37, 0x30, 0x32, 0x32, 0x2C, +0x2D, 0x37, 0x2E, 0x34, 0x37, 0x31, 0x30, 0x36, 0x20, 0x2D, 0x30, 0x2E, 0x35, 0x38, 0x33, 0x31, +0x39, 0x2C, 0x2D, 0x31, 0x2E, 0x32, 0x32, 0x31, 0x39, 0x35, 0x20, 0x2D, 0x31, 0x2E, 0x30, 0x36, +0x30, 0x33, 0x34, 0x2C, 0x2D, 0x32, 0x2E, 0x34, 0x35, 0x39, 0x31, 0x38, 0x20, 0x2D, 0x31, 0x2E, +0x30, 0x36, 0x30, 0x33, 0x34, 0x2C, 0x2D, 0x32, 0x2E, 0x37, 0x34, 0x39, 0x33, 0x39, 0x20, 0x30, +0x2C, 0x2D, 0x30, 0x2E, 0x33, 0x32, 0x32, 0x39, 0x31, 0x20, 0x2D, 0x30, 0x2E, 0x34, 0x37, 0x35, +0x31, 0x39, 0x2C, 0x2D, 0x30, 0x2E, 0x36, 0x31, 0x36, 0x38, 0x31, 0x20, 0x2D, 0x31, 0x2E, 0x32, +0x32, 0x34, 0x35, 0x38, 0x2C, 0x2D, 0x30, 0x2E, 0x37, 0x35, 0x37, 0x34, 0x20, 0x2D, 0x32, 0x2E, +0x30, 0x33, 0x31, 0x36, 0x35, 0x2C, 0x2D, 0x30, 0x2E, 0x33, 0x38, 0x31, 0x31, 0x34, 0x20, 0x2D, +0x32, 0x2E, 0x33, 0x30, 0x33, 0x31, 0x39, 0x2C, 0x2D, 0x31, 0x2E, 0x31, 0x34, 0x32, 0x34, 0x32, +0x20, 0x2D, 0x32, 0x2E, 0x33, 0x30, 0x33, 0x31, 0x39, 0x2C, 0x2D, 0x36, 0x2E, 0x34, 0x35, 0x37, +0x30, 0x39, 0x20, 0x76, 0x20, 0x2D, 0x34, 0x2E, 0x36, 0x38, 0x37, 0x34, 0x33, 0x20, 0x6C, 0x20, +0x31, 0x36, 0x2E, 0x37, 0x39, 0x35, 0x30, 0x31, 0x2C, 0x30, 0x2E, 0x30, 0x39, 0x31, 0x36, 0x20, +0x31, 0x36, 0x2E, 0x37, 0x39, 0x35, 0x2C, 0x30, 0x2E, 0x30, 0x39, 0x31, 0x36, 0x20, 0x2D, 0x30, +0x2E, 0x30, 0x35, 0x35, 0x39, 0x2C, 0x34, 0x2E, 0x39, 0x32, 0x34, 0x31, 0x38, 0x20, 0x63, 0x20, +0x2D, 0x30, 0x2E, 0x30, 0x33, 0x32, 0x32, 0x2C, 0x32, 0x2E, 0x38, 0x33, 0x34, 0x32, 0x34, 0x20, +0x2D, 0x30, 0x2E, 0x32, 0x31, 0x33, 0x30, 0x37, 0x2C, 0x35, 0x2E, 0x31, 0x31, 0x33, 0x36, 0x32, +0x20, 0x2D, 0x30, 0x2E, 0x34, 0x32, 0x36, 0x32, 0x39, 0x2C, 0x35, 0x2E, 0x33, 0x37, 0x30, 0x35, +0x33, 0x20, 0x2D, 0x30, 0x2E, 0x32, 0x30, 0x33, 0x37, 0x34, 0x2C, 0x30, 0x2E, 0x32, 0x34, 0x35, +0x34, 0x39, 0x20, 0x2D, 0x30, 0x2E, 0x38, 0x38, 0x39, 0x30, 0x39, 0x2C, 0x30, 0x2E, 0x35, 0x34, +0x33, 0x36, 0x34, 0x20, 0x2D, 0x31, 0x2E, 0x35, 0x32, 0x33, 0x2C, 0x30, 0x2E, 0x36, 0x36, 0x32, +0x35, 0x37, 0x20, 0x2D, 0x30, 0x2E, 0x39, 0x38, 0x33, 0x31, 0x35, 0x2C, 0x30, 0x2E, 0x31, 0x38, +0x34, 0x34, 0x33, 0x20, 0x2D, 0x31, 0x2E, 0x32, 0x31, 0x35, 0x37, 0x39, 0x2C, 0x30, 0x2E, 0x34, +0x33, 0x32, 0x31, 0x33, 0x20, 0x2D, 0x31, 0x2E, 0x35, 0x38, 0x32, 0x36, 0x2C, 0x31, 0x2E, 0x36, +0x38, 0x35, 0x30, 0x33, 0x20, 0x2D, 0x31, 0x2E, 0x30, 0x37, 0x31, 0x36, 0x38, 0x2C, 0x33, 0x2E, +0x36, 0x36, 0x30, 0x34, 0x38, 0x20, 0x2D, 0x34, 0x2E, 0x35, 0x31, 0x30, 0x38, 0x2C, 0x37, 0x2E, +0x33, 0x38, 0x32, 0x33, 0x31, 0x20, 0x2D, 0x38, 0x2E, 0x30, 0x34, 0x32, 0x35, 0x39, 0x2C, 0x38, +0x2E, 0x37, 0x30, 0x33, 0x37, 0x32, 0x20, 0x2D, 0x32, 0x2E, 0x35, 0x32, 0x32, 0x33, 0x31, 0x2C, +0x30, 0x2E, 0x39, 0x34, 0x33, 0x37, 0x32, 0x20, 0x2D, 0x36, 0x2E, 0x30, 0x39, 0x36, 0x37, 0x34, +0x2C, 0x31, 0x2E, 0x32, 0x30, 0x32, 0x32, 0x31, 0x20, 0x2D, 0x38, 0x2E, 0x32, 0x30, 0x31, 0x33, +0x35, 0x2C, 0x30, 0x2E, 0x35, 0x39, 0x33, 0x31, 0x31, 0x20, 0x7A, 0x20, 0x6D, 0x20, 0x2D, 0x31, +0x33, 0x2E, 0x37, 0x36, 0x32, 0x32, 0x32, 0x2C, 0x2D, 0x32, 0x38, 0x2E, 0x39, 0x30, 0x36, 0x35, +0x20, 0x63, 0x20, 0x2D, 0x30, 0x2E, 0x30, 0x30, 0x32, 0x2C, 0x2D, 0x30, 0x2E, 0x38, 0x32, 0x34, +0x36, 0x32, 0x20, 0x2D, 0x30, 0x2E, 0x31, 0x30, 0x32, 0x32, 0x38, 0x2C, 0x2D, 0x32, 0x2E, 0x30, +0x39, 0x34, 0x36, 0x32, 0x20, 0x2D, 0x30, 0x2E, 0x32, 0x32, 0x32, 0x35, 0x34, 0x2C, 0x2D, 0x32, +0x2E, 0x38, 0x32, 0x32, 0x32, 0x32, 0x20, 0x6C, 0x20, 0x2D, 0x30, 0x2E, 0x32, 0x31, 0x38, 0x36, +0x37, 0x2C, 0x2D, 0x31, 0x2E, 0x33, 0x32, 0x32, 0x39, 0x32, 0x20, 0x68, 0x20, 0x31, 0x37, 0x2E, +0x33, 0x37, 0x33, 0x34, 0x32, 0x20, 0x31, 0x37, 0x2E, 0x33, 0x37, 0x33, 0x34, 0x31, 0x20, 0x6C, +0x20, 0x2D, 0x30, 0x2E, 0x32, 0x31, 0x32, 0x37, 0x31, 0x2C, 0x30, 0x2E, 0x37, 0x39, 0x33, 0x37, +0x35, 0x20, 0x63, 0x20, 0x2D, 0x30, 0x2E, 0x31, 0x31, 0x37, 0x2C, 0x30, 0x2E, 0x34, 0x33, 0x36, +0x35, 0x36, 0x20, 0x2D, 0x30, 0x2E, 0x32, 0x31, 0x34, 0x38, 0x39, 0x2C, 0x31, 0x2E, 0x37, 0x30, +0x36, 0x35, 0x36, 0x20, 0x2D, 0x30, 0x2E, 0x32, 0x31, 0x37, 0x35, 0x34, 0x2C, 0x32, 0x2E, 0x38, +0x32, 0x32, 0x32, 0x32, 0x20, 0x6C, 0x20, 0x2D, 0x30, 0x2E, 0x30, 0x30, 0x35, 0x2C, 0x32, 0x2E, +0x30, 0x32, 0x38, 0x34, 0x38, 0x20, 0x68, 0x20, 0x2D, 0x31, 0x36, 0x2E, 0x39, 0x33, 0x33, 0x31, +0x35, 0x20, 0x2D, 0x31, 0x36, 0x2E, 0x39, 0x33, 0x33, 0x33, 0x33, 0x20, 0x7A, 0x20, 0x6D, 0x20, +0x2D, 0x32, 0x2E, 0x31, 0x33, 0x32, 0x37, 0x39, 0x2C, 0x2D, 0x31, 0x31, 0x2E, 0x38, 0x31, 0x38, +0x30, 0x36, 0x20, 0x63, 0x20, 0x2D, 0x31, 0x2E, 0x37, 0x38, 0x35, 0x33, 0x32, 0x2C, 0x2D, 0x35, +0x2E, 0x34, 0x32, 0x38, 0x38, 0x39, 0x20, 0x2D, 0x35, 0x2E, 0x30, 0x36, 0x38, 0x31, 0x37, 0x2C, +0x2D, 0x31, 0x31, 0x2E, 0x34, 0x32, 0x38, 0x38, 0x34, 0x20, 0x2D, 0x38, 0x2E, 0x38, 0x38, 0x37, +0x36, 0x33, 0x2C, 0x2D, 0x31, 0x36, 0x2E, 0x32, 0x34, 0x33, 0x36, 0x20, 0x2D, 0x30, 0x2E, 0x39, +0x36, 0x38, 0x39, 0x2C, 0x2D, 0x31, 0x2E, 0x32, 0x32, 0x31, 0x33, 0x38, 0x20, 0x2D, 0x31, 0x2E, +0x36, 0x39, 0x33, 0x34, 0x33, 0x2C, 0x2D, 0x32, 0x2E, 0x32, 0x38, 0x38, 0x38, 0x39, 0x20, 0x2D, +0x31, 0x2E, 0x36, 0x31, 0x30, 0x30, 0x38, 0x2C, 0x2D, 0x32, 0x2E, 0x33, 0x37, 0x32, 0x32, 0x34, +0x20, 0x30, 0x2E, 0x30, 0x38, 0x33, 0x34, 0x2C, 0x2D, 0x30, 0x2E, 0x30, 0x38, 0x33, 0x34, 0x20, +0x35, 0x2E, 0x37, 0x37, 0x38, 0x30, 0x31, 0x2C, 0x2D, 0x32, 0x2E, 0x33, 0x38, 0x30, 0x37, 0x31, +0x20, 0x31, 0x32, 0x2E, 0x36, 0x35, 0x34, 0x37, 0x38, 0x2C, 0x2D, 0x35, 0x2E, 0x31, 0x30, 0x35, +0x32, 0x33, 0x20, 0x36, 0x2E, 0x38, 0x37, 0x36, 0x37, 0x37, 0x2C, 0x2D, 0x32, 0x2E, 0x37, 0x32, +0x34, 0x35, 0x32, 0x20, 0x31, 0x32, 0x2E, 0x38, 0x36, 0x30, 0x34, 0x31, 0x2C, 0x2D, 0x35, 0x2E, +0x31, 0x30, 0x36, 0x34, 0x32, 0x20, 0x31, 0x33, 0x2E, 0x32, 0x39, 0x36, 0x39, 0x37, 0x2C, 0x2D, +0x35, 0x2E, 0x32, 0x39, 0x33, 0x31, 0x31, 0x20, 0x6C, 0x20, 0x30, 0x2E, 0x37, 0x39, 0x33, 0x37, +0x35, 0x2C, 0x2D, 0x30, 0x2E, 0x33, 0x33, 0x39, 0x34, 0x34, 0x20, 0x76, 0x20, 0x31, 0x35, 0x2E, +0x38, 0x36, 0x37, 0x34, 0x34, 0x20, 0x31, 0x35, 0x2E, 0x38, 0x36, 0x37, 0x34, 0x33, 0x20, 0x68, +0x20, 0x2D, 0x37, 0x2E, 0x37, 0x33, 0x32, 0x33, 0x35, 0x20, 0x2D, 0x37, 0x2E, 0x37, 0x33, 0x32, +0x33, 0x35, 0x20, 0x7A, 0x20, 0x6D, 0x20, 0x32, 0x32, 0x2E, 0x38, 0x34, 0x30, 0x30, 0x37, 0x2C, +0x32, 0x2E, 0x31, 0x35, 0x33, 0x31, 0x36, 0x20, 0x63, 0x20, 0x2D, 0x30, 0x2E, 0x33, 0x34, 0x36, +0x38, 0x38, 0x2C, 0x2D, 0x30, 0x2E, 0x33, 0x34, 0x36, 0x38, 0x38, 0x20, 0x2D, 0x30, 0x2E, 0x33, +0x30, 0x30, 0x38, 0x38, 0x2C, 0x2D, 0x35, 0x30, 0x2E, 0x39, 0x32, 0x34, 0x36, 0x38, 0x20, 0x30, +0x2E, 0x30, 0x34, 0x36, 0x33, 0x2C, 0x2D, 0x35, 0x30, 0x2E, 0x39, 0x32, 0x34, 0x36, 0x38, 0x20, +0x30, 0x2E, 0x31, 0x35, 0x38, 0x37, 0x33, 0x2C, 0x30, 0x20, 0x33, 0x2E, 0x39, 0x32, 0x39, 0x30, +0x34, 0x2C, 0x31, 0x2E, 0x34, 0x33, 0x39, 0x31, 0x38, 0x20, 0x38, 0x2E, 0x33, 0x37, 0x38, 0x34, +0x37, 0x2C, 0x33, 0x2E, 0x31, 0x39, 0x38, 0x31, 0x39, 0x20, 0x34, 0x2E, 0x34, 0x34, 0x39, 0x34, +0x34, 0x2C, 0x31, 0x2E, 0x37, 0x35, 0x39, 0x20, 0x31, 0x31, 0x2E, 0x37, 0x34, 0x31, 0x31, 0x34, +0x2C, 0x34, 0x2E, 0x36, 0x33, 0x39, 0x34, 0x38, 0x20, 0x31, 0x36, 0x2E, 0x32, 0x30, 0x33, 0x37, +0x37, 0x2C, 0x36, 0x2E, 0x34, 0x30, 0x31, 0x30, 0x36, 0x20, 0x34, 0x2E, 0x34, 0x36, 0x32, 0x36, +0x34, 0x2C, 0x31, 0x2E, 0x37, 0x36, 0x31, 0x35, 0x38, 0x20, 0x38, 0x2E, 0x31, 0x35, 0x36, 0x33, +0x38, 0x2C, 0x33, 0x2E, 0x32, 0x33, 0x35, 0x36, 0x31, 0x20, 0x38, 0x2E, 0x32, 0x30, 0x38, 0x33, +0x2C, 0x33, 0x2E, 0x32, 0x37, 0x35, 0x36, 0x31, 0x20, 0x30, 0x2E, 0x31, 0x39, 0x32, 0x31, 0x31, +0x2C, 0x30, 0x2E, 0x31, 0x34, 0x38, 0x30, 0x33, 0x20, 0x2D, 0x30, 0x2E, 0x39, 0x37, 0x34, 0x38, +0x36, 0x2C, 0x35, 0x2E, 0x31, 0x31, 0x31, 0x30, 0x35, 0x20, 0x2D, 0x31, 0x2E, 0x37, 0x31, 0x32, +0x33, 0x33, 0x2C, 0x37, 0x2E, 0x32, 0x38, 0x32, 0x33, 0x33, 0x20, 0x2D, 0x31, 0x2E, 0x32, 0x30, +0x31, 0x2C, 0x33, 0x2E, 0x35, 0x33, 0x36, 0x30, 0x38, 0x20, 0x2D, 0x33, 0x2E, 0x30, 0x37, 0x39, +0x34, 0x37, 0x2C, 0x36, 0x2E, 0x38, 0x38, 0x32, 0x31, 0x39, 0x20, 0x2D, 0x36, 0x2E, 0x31, 0x31, +0x31, 0x39, 0x37, 0x2C, 0x31, 0x30, 0x2E, 0x38, 0x38, 0x37, 0x32, 0x35, 0x20, 0x2D, 0x35, 0x2E, +0x31, 0x30, 0x32, 0x33, 0x37, 0x2C, 0x36, 0x2E, 0x37, 0x33, 0x38, 0x37, 0x36, 0x20, 0x2D, 0x37, +0x2E, 0x31, 0x36, 0x38, 0x31, 0x38, 0x2C, 0x31, 0x30, 0x2E, 0x33, 0x36, 0x30, 0x39, 0x37, 0x20, +0x2D, 0x39, 0x2E, 0x33, 0x35, 0x35, 0x35, 0x38, 0x2C, 0x31, 0x36, 0x2E, 0x34, 0x30, 0x34, 0x31, +0x37, 0x20, 0x6C, 0x20, 0x2D, 0x31, 0x2E, 0x32, 0x37, 0x36, 0x39, 0x32, 0x2C, 0x33, 0x2E, 0x35, +0x32, 0x37, 0x37, 0x38, 0x20, 0x2D, 0x37, 0x2E, 0x30, 0x36, 0x38, 0x38, 0x38, 0x2C, 0x30, 0x2E, +0x30, 0x39, 0x35, 0x33, 0x20, 0x63, 0x20, 0x2D, 0x33, 0x2E, 0x38, 0x38, 0x37, 0x38, 0x39, 0x2C, +0x30, 0x2E, 0x30, 0x35, 0x32, 0x34, 0x20, 0x2D, 0x37, 0x2E, 0x31, 0x37, 0x37, 0x39, 0x32, 0x2C, +0x2D, 0x30, 0x2E, 0x30, 0x31, 0x33, 0x37, 0x20, 0x2D, 0x37, 0x2E, 0x33, 0x31, 0x31, 0x31, 0x37, +0x2C, 0x2D, 0x30, 0x2E, 0x31, 0x34, 0x36, 0x39, 0x39, 0x20, 0x7A, 0x20, 0x6D, 0x20, 0x2D, 0x33, +0x38, 0x2E, 0x31, 0x32, 0x34, 0x31, 0x2C, 0x2D, 0x32, 0x38, 0x2E, 0x39, 0x36, 0x34, 0x32, 0x37, +0x20, 0x63, 0x20, 0x2D, 0x36, 0x2E, 0x30, 0x32, 0x38, 0x31, 0x2C, 0x2D, 0x31, 0x35, 0x2E, 0x39, +0x31, 0x36, 0x38, 0x37, 0x20, 0x2D, 0x31, 0x2E, 0x31, 0x37, 0x38, 0x38, 0x37, 0x2C, 0x2D, 0x33, +0x33, 0x2E, 0x30, 0x35, 0x36, 0x36, 0x20, 0x31, 0x32, 0x2E, 0x32, 0x30, 0x35, 0x39, 0x39, 0x2C, +0x2D, 0x34, 0x33, 0x2E, 0x31, 0x34, 0x32, 0x33, 0x39, 0x39, 0x20, 0x34, 0x2E, 0x37, 0x38, 0x34, +0x34, 0x33, 0x2C, 0x2D, 0x33, 0x2E, 0x36, 0x30, 0x35, 0x31, 0x37, 0x37, 0x20, 0x31, 0x31, 0x2E, +0x38, 0x31, 0x39, 0x36, 0x34, 0x2C, 0x2D, 0x36, 0x2E, 0x35, 0x33, 0x32, 0x31, 0x39, 0x37, 0x20, +0x31, 0x37, 0x2E, 0x33, 0x30, 0x30, 0x32, 0x31, 0x2C, 0x2D, 0x37, 0x2E, 0x31, 0x39, 0x37, 0x37, +0x39, 0x38, 0x20, 0x6C, 0x20, 0x32, 0x2E, 0x30, 0x33, 0x31, 0x33, 0x33, 0x2C, 0x2D, 0x30, 0x2E, +0x32, 0x34, 0x36, 0x37, 0x20, 0x2D, 0x30, 0x2E, 0x30, 0x39, 0x31, 0x2C, 0x32, 0x30, 0x2E, 0x35, +0x33, 0x31, 0x37, 0x33, 0x37, 0x20, 0x2D, 0x30, 0x2E, 0x30, 0x39, 0x31, 0x31, 0x2C, 0x32, 0x30, +0x2E, 0x35, 0x33, 0x31, 0x37, 0x34, 0x20, 0x2D, 0x31, 0x34, 0x2E, 0x39, 0x39, 0x33, 0x30, 0x36, +0x2C, 0x35, 0x2E, 0x39, 0x35, 0x30, 0x37, 0x34, 0x20, 0x63, 0x20, 0x2D, 0x38, 0x2E, 0x32, 0x34, +0x36, 0x31, 0x38, 0x2C, 0x33, 0x2E, 0x32, 0x37, 0x32, 0x39, 0x31, 0x20, 0x2D, 0x31, 0x35, 0x2E, +0x30, 0x39, 0x38, 0x32, 0x34, 0x2C, 0x35, 0x2E, 0x39, 0x35, 0x31, 0x34, 0x36, 0x20, 0x2D, 0x31, +0x35, 0x2E, 0x32, 0x32, 0x36, 0x37, 0x39, 0x2C, 0x35, 0x2E, 0x39, 0x35, 0x32, 0x33, 0x34, 0x20, +0x2D, 0x30, 0x2E, 0x31, 0x32, 0x38, 0x35, 0x36, 0x2C, 0x38, 0x2E, 0x38, 0x65, 0x2D, 0x34, 0x20, +0x2D, 0x30, 0x2E, 0x36, 0x33, 0x39, 0x35, 0x37, 0x2C, 0x2D, 0x31, 0x2E, 0x30, 0x36, 0x39, 0x39, +0x37, 0x20, 0x2D, 0x31, 0x2E, 0x31, 0x33, 0x35, 0x35, 0x38, 0x2C, 0x2D, 0x32, 0x2E, 0x33, 0x37, +0x39, 0x36, 0x36, 0x20, 0x7A, 0x20, 0x6D, 0x20, 0x35, 0x34, 0x2E, 0x38, 0x31, 0x35, 0x31, 0x35, +0x2C, 0x2D, 0x32, 0x32, 0x2E, 0x35, 0x31, 0x30, 0x37, 0x35, 0x20, 0x63, 0x20, 0x2D, 0x38, 0x2E, +0x34, 0x34, 0x30, 0x32, 0x2C, 0x2D, 0x33, 0x2E, 0x33, 0x36, 0x36, 0x32, 0x31, 0x20, 0x2D, 0x31, +0x35, 0x2E, 0x37, 0x30, 0x33, 0x30, 0x32, 0x2C, 0x2D, 0x36, 0x2E, 0x32, 0x38, 0x32, 0x39, 0x35, +0x20, 0x2D, 0x31, 0x36, 0x2E, 0x31, 0x33, 0x39, 0x35, 0x38, 0x2C, 0x2D, 0x36, 0x2E, 0x34, 0x38, +0x31, 0x36, 0x33, 0x20, 0x6C, 0x20, 0x2D, 0x30, 0x2E, 0x37, 0x39, 0x33, 0x37, 0x35, 0x2C, 0x2D, +0x30, 0x2E, 0x33, 0x36, 0x31, 0x32, 0x34, 0x20, 0x56, 0x20, 0x39, 0x39, 0x2E, 0x31, 0x39, 0x30, +0x36, 0x30, 0x39, 0x20, 0x63, 0x20, 0x30, 0x2C, 0x2D, 0x39, 0x2E, 0x39, 0x33, 0x38, 0x39, 0x37, +0x39, 0x20, 0x30, 0x2E, 0x30, 0x33, 0x39, 0x33, 0x2C, 0x2D, 0x31, 0x30, 0x2E, 0x36, 0x30, 0x33, +0x38, 0x31, 0x35, 0x20, 0x30, 0x2E, 0x36, 0x31, 0x37, 0x33, 0x36, 0x2C, 0x2D, 0x31, 0x30, 0x2E, +0x34, 0x34, 0x34, 0x31, 0x36, 0x32, 0x20, 0x30, 0x2E, 0x33, 0x33, 0x39, 0x35, 0x35, 0x2C, 0x30, +0x2E, 0x30, 0x39, 0x33, 0x37, 0x38, 0x20, 0x31, 0x2E, 0x34, 0x31, 0x31, 0x31, 0x31, 0x2C, 0x30, +0x2E, 0x32, 0x37, 0x38, 0x36, 0x34, 0x20, 0x32, 0x2E, 0x33, 0x38, 0x31, 0x32, 0x35, 0x2C, 0x30, +0x2E, 0x34, 0x31, 0x30, 0x38, 0x30, 0x31, 0x20, 0x30, 0x2E, 0x39, 0x37, 0x30, 0x31, 0x34, 0x2C, +0x30, 0x2E, 0x31, 0x33, 0x32, 0x31, 0x36, 0x31, 0x20, 0x33, 0x2E, 0x30, 0x33, 0x33, 0x38, 0x39, +0x2C, 0x30, 0x2E, 0x36, 0x33, 0x38, 0x32, 0x31, 0x36, 0x20, 0x34, 0x2E, 0x35, 0x38, 0x36, 0x31, +0x31, 0x2C, 0x31, 0x2E, 0x31, 0x32, 0x34, 0x35, 0x36, 0x36, 0x20, 0x39, 0x2E, 0x37, 0x31, 0x36, +0x31, 0x37, 0x2C, 0x33, 0x2E, 0x30, 0x34, 0x34, 0x33, 0x32, 0x31, 0x20, 0x31, 0x38, 0x2E, 0x32, +0x35, 0x35, 0x33, 0x34, 0x2C, 0x31, 0x30, 0x2E, 0x36, 0x30, 0x39, 0x33, 0x33, 0x36, 0x20, 0x32, +0x32, 0x2E, 0x36, 0x30, 0x37, 0x30, 0x34, 0x2C, 0x32, 0x30, 0x2E, 0x30, 0x32, 0x38, 0x30, 0x33, +0x36, 0x20, 0x32, 0x2E, 0x30, 0x34, 0x38, 0x32, 0x32, 0x2C, 0x34, 0x2E, 0x34, 0x33, 0x33, 0x31, +0x31, 0x20, 0x33, 0x2E, 0x37, 0x32, 0x39, 0x31, 0x2C, 0x31, 0x32, 0x2E, 0x35, 0x38, 0x33, 0x33, +0x38, 0x20, 0x32, 0x2E, 0x35, 0x37, 0x37, 0x31, 0x2C, 0x31, 0x32, 0x2E, 0x34, 0x39, 0x35, 0x38, +0x39, 0x20, 0x2D, 0x30, 0x2E, 0x32, 0x36, 0x39, 0x33, 0x33, 0x2C, 0x2D, 0x30, 0x2E, 0x30, 0x32, +0x30, 0x35, 0x20, 0x2D, 0x37, 0x2E, 0x33, 0x39, 0x35, 0x33, 0x32, 0x2C, 0x2D, 0x32, 0x2E, 0x37, +0x39, 0x31, 0x33, 0x37, 0x20, 0x2D, 0x31, 0x35, 0x2E, 0x38, 0x33, 0x35, 0x35, 0x33, 0x2C, 0x2D, +0x36, 0x2E, 0x31, 0x35, 0x37, 0x35, 0x39, 0x20, 0x7A, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x69, 0x64, 0x3D, 0x22, 0x70, 0x61, 0x74, 0x68, 0x31, 0x22, 0x20, 0x2F, 0x3E, 0x3C, +0x2F, 0x67, 0x3E, 0x3C, 0x2F, 0x73, 0x76, 0x67, 0x3E, 0x0A + }; \ No newline at end of file diff --git a/src/www/favicon.h b/src/www/favicon.h new file mode 100644 index 0000000..c6f156c --- /dev/null +++ b/src/www/favicon.h @@ -0,0 +1,278 @@ +#include +//https://tomeko.net/online_tools/file_to_hex.php?lang=en +const unsigned int BBLED_favicon_len = 4359; +const uint8_t BBLED_favicon[] PROGMEM = { +0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A, 0x00, 0x00, 0x00, 0x0D, 0x49, 0x48, 0x44, 0x52, +0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x60, 0x08, 0x06, 0x00, 0x00, 0x00, 0xE2, 0x98, 0x77, +0x38, 0x00, 0x00, 0x00, 0x01, 0x73, 0x52, 0x47, 0x42, 0x00, 0xAE, 0xCE, 0x1C, 0xE9, 0x00, 0x00, +0x10, 0xC1, 0x49, 0x44, 0x41, 0x54, 0x78, 0x5E, 0xED, 0x9D, 0x7B, 0x90, 0x1C, 0xC5, 0x7D, 0xC7, +0x3F, 0xBF, 0x99, 0xDD, 0xDB, 0xD3, 0xDD, 0xE9, 0x85, 0x10, 0x6F, 0xDB, 0x18, 0x10, 0x21, 0x60, +0x20, 0x04, 0xFC, 0x20, 0x15, 0x6C, 0x11, 0x03, 0x41, 0xC2, 0xD2, 0x81, 0xE0, 0x0E, 0x2C, 0x2C, +0x90, 0x1D, 0x47, 0x18, 0x1C, 0x08, 0x94, 0xC1, 0xA6, 0x22, 0x4C, 0x2E, 0x8E, 0x71, 0xEC, 0x32, +0xB6, 0xCB, 0x60, 0x57, 0x8C, 0x52, 0x01, 0x0C, 0x92, 0xA0, 0xEE, 0xCA, 0x12, 0x3A, 0x21, 0x04, +0x22, 0x65, 0x29, 0x54, 0x62, 0x11, 0x61, 0x61, 0x1B, 0x2C, 0x15, 0x16, 0x46, 0x15, 0x5B, 0x80, +0x64, 0x0B, 0xF4, 0x3A, 0x49, 0xF7, 0x9A, 0x99, 0x5F, 0xAE, 0x67, 0x77, 0x4F, 0xBB, 0x7B, 0xBB, +0x3B, 0xB3, 0xBB, 0xB3, 0x0F, 0x52, 0xD7, 0xFF, 0xA8, 0x74, 0xD3, 0xD3, 0xD3, 0xFD, 0xFB, 0xF6, +0xEF, 0xD1, 0xBF, 0x47, 0xAF, 0x30, 0xDE, 0xEA, 0x4A, 0x01, 0xA9, 0xEB, 0xD7, 0xC7, 0x3F, 0xCE, +0x38, 0x00, 0x75, 0xDE, 0x04, 0xE3, 0x00, 0x8C, 0x03, 0x10, 0x40, 0x01, 0x45, 0x78, 0x74, 0x66, +0x82, 0xC9, 0x53, 0x5B, 0xE9, 0x1F, 0x3E, 0x8A, 0x98, 0x75, 0x3C, 0x43, 0x96, 0x45, 0x22, 0xFE, +0x0B, 0x3A, 0x7B, 0xF6, 0xFB, 0x6F, 0x77, 0x77, 0xD8, 0xD0, 0x7F, 0x22, 0xAE, 0x35, 0x0D, 0xDB, +0x7B, 0x97, 0x61, 0xED, 0xE3, 0x5D, 0xEF, 0x30, 0xB7, 0xAD, 0x1D, 0x02, 0xB4, 0xCE, 0x34, 0x2E, +0xFA, 0xF9, 0xC6, 0xE4, 0x00, 0x43, 0xF4, 0x9E, 0x8E, 0x56, 0x06, 0x07, 0x4F, 0x24, 0x26, 0x67, +0xA3, 0xFA, 0x31, 0x84, 0x8F, 0xA3, 0x9C, 0x86, 0x48, 0x1C, 0x74, 0x1B, 0xB6, 0x37, 0x97, 0xCE, +0xA7, 0xDF, 0xF2, 0x57, 0xF7, 0xC0, 0xAC, 0x04, 0x47, 0x27, 0x16, 0x81, 0xDE, 0xE3, 0x93, 0x5B, +0xD8, 0x0A, 0xFC, 0x37, 0x1E, 0x9B, 0x89, 0x0D, 0x6F, 0xC1, 0x6A, 0x7D, 0x9B, 0x8E, 0x9E, 0x43, +0x48, 0xE3, 0x81, 0xD1, 0x58, 0x00, 0x98, 0x9D, 0x3C, 0xE0, 0x4C, 0x23, 0xE6, 0x9E, 0x0B, 0x72, +0xB5, 0xA0, 0xED, 0x2A, 0x32, 0x09, 0x25, 0x0E, 0xD8, 0x80, 0xE5, 0x13, 0x5C, 0xD8, 0x02, 0xCC, +0xE2, 0xD3, 0xAB, 0x76, 0xF8, 0xFF, 0x7F, 0x66, 0x56, 0x82, 0x7D, 0x89, 0x9B, 0x11, 0xBD, 0x0F, +0x98, 0x80, 0xFA, 0x84, 0x76, 0x01, 0xC3, 0x01, 0x07, 0x80, 0x5E, 0x2C, 0x59, 0x81, 0xE7, 0xFD, +0x8A, 0x58, 0xE2, 0x1D, 0x3A, 0x7B, 0xCC, 0xB3, 0x86, 0x68, 0x8D, 0x01, 0x80, 0xD9, 0xF1, 0x4F, +0xCC, 0x99, 0x86, 0x5A, 0x1F, 0x01, 0xEE, 0xC4, 0xE2, 0x7C, 0x94, 0x09, 0x08, 0x31, 0xCC, 0xB3, +0xDC, 0x96, 0x0F, 0x80, 0x03, 0x89, 0x9B, 0x41, 0xEF, 0xC3, 0xA3, 0x25, 0xAB, 0xBB, 0xD9, 0xF5, +0x2A, 0x0E, 0xE8, 0x00, 0xF0, 0x4B, 0x70, 0xBF, 0x8D, 0x13, 0xFF, 0x1F, 0x16, 0xAC, 0xDC, 0xDD, +0x08, 0x1C, 0x51, 0x7F, 0x00, 0x1E, 0x99, 0xD9, 0x4C, 0xD3, 0x94, 0xB3, 0x10, 0x6F, 0x31, 0x2A, +0x97, 0x20, 0x3E, 0x01, 0xCD, 0x6E, 0x2F, 0xD6, 0xB6, 0x20, 0x39, 0x1C, 0x60, 0x00, 0x50, 0xBD, +0x0F, 0xCD, 0x01, 0x20, 0x73, 0x14, 0xC1, 0x45, 0x39, 0x0C, 0xFA, 0x02, 0x9E, 0xFE, 0x13, 0x4D, +0xCD, 0xBF, 0xA6, 0xB3, 0xA7, 0xBF, 0x9E, 0xAC, 0x50, 0x3F, 0x00, 0x7C, 0x39, 0x3F, 0xEB, 0x68, +0xDC, 0xF8, 0x1C, 0x54, 0xBE, 0x81, 0x30, 0x0D, 0x25, 0x56, 0x90, 0x18, 0x66, 0xA6, 0x47, 0xD4, +0xE9, 0x58, 0x00, 0xD2, 0x22, 0x48, 0x69, 0xF1, 0xBB, 0xA6, 0x57, 0x96, 0x4F, 0x05, 0x0B, 0x8E, +0x28, 0x7B, 0x14, 0xEE, 0xC5, 0xE9, 0x5F, 0xC9, 0x82, 0x75, 0x75, 0xE3, 0x86, 0xFA, 0x00, 0xD0, +0x35, 0x33, 0xC6, 0x8C, 0xD6, 0xF7, 0x23, 0xF6, 0xB7, 0x50, 0x99, 0x8D, 0xE5, 0xCB, 0xED, 0xF0, +0x73, 0x29, 0x24, 0x82, 0x82, 0x38, 0x20, 0xA9, 0x3F, 0x92, 0x40, 0x26, 0x15, 0x72, 0x3F, 0xCA, +0x5A, 0x62, 0xDE, 0x5D, 0x6C, 0xED, 0xDB, 0x41, 0xD7, 0x06, 0xA7, 0xD6, 0xDC, 0x10, 0x7E, 0xD1, +0x51, 0xCD, 0xAC, 0xBB, 0xA3, 0x89, 0xA1, 0xA1, 0xD3, 0xB0, 0xF8, 0x31, 0xC8, 0xB9, 0x23, 0x72, +0xDB, 0x28, 0xD8, 0xD0, 0x2D, 0x45, 0xBF, 0x82, 0x22, 0x48, 0x94, 0x96, 0x62, 0x76, 0x67, 0x36, +0x23, 0xF9, 0x88, 0x0C, 0x23, 0xFA, 0x32, 0xEA, 0x2D, 0x24, 0xF6, 0xC6, 0x76, 0x3A, 0xB7, 0x1A, +0xC5, 0x5D, 0xB3, 0x56, 0x5B, 0x00, 0x8C, 0xB9, 0x78, 0x4C, 0xF3, 0x0C, 0x3C, 0xAF, 0x1B, 0xF8, +0x93, 0x51, 0xAB, 0xA6, 0xD4, 0xE5, 0x56, 0xC2, 0x01, 0xF9, 0xBE, 0xE5, 0xEB, 0x06, 0x7D, 0x0D, +0x4F, 0x3A, 0x69, 0x6A, 0xFA, 0x2D, 0x9D, 0x3D, 0x35, 0x03, 0xA1, 0x76, 0x00, 0xA4, 0x77, 0xBE, +0xD0, 0x83, 0x70, 0x46, 0xD9, 0xC4, 0x4F, 0x4A, 0x91, 0x2D, 0x9A, 0xAB, 0x84, 0x33, 0x74, 0xC0, +0x28, 0x8D, 0xC7, 0x6E, 0xF7, 0x23, 0x22, 0x68, 0x2C, 0x10, 0x1E, 0xA2, 0xAF, 0xE2, 0x70, 0x2D, +0x87, 0xDF, 0xDA, 0xCE, 0x4D, 0x9B, 0x87, 0x4B, 0xDD, 0x17, 0xE5, 0xF4, 0xAF, 0x0D, 0x00, 0xBE, +0xCC, 0x6F, 0x39, 0x11, 0x89, 0x19, 0xB1, 0x73, 0x51, 0x51, 0xE2, 0xE7, 0x23, 0xDA, 0xD8, 0x95, +0x95, 0x65, 0x05, 0x05, 0x0E, 0x9D, 0xB4, 0x92, 0xD6, 0xA3, 0xC3, 0x9F, 0xE7, 0xF5, 0xC3, 0x6F, +0xD5, 0x42, 0x27, 0x54, 0x1F, 0x80, 0xAE, 0x2E, 0x8B, 0x73, 0x7E, 0x35, 0x95, 0x01, 0xFD, 0x07, +0xD0, 0xDB, 0xA0, 0x80, 0xA5, 0x13, 0x48, 0x9D, 0x23, 0x28, 0x84, 0xE6, 0x80, 0x72, 0xB6, 0x24, +0x98, 0x33, 0xC3, 0x0F, 0x41, 0xBF, 0xCE, 0xB6, 0xF3, 0xF7, 0xD0, 0xD5, 0xE5, 0x95, 0x37, 0x4C, +0xB8, 0xB7, 0xAA, 0x0F, 0xC0, 0x63, 0x97, 0xB5, 0xD2, 0x94, 0xB8, 0x04, 0x4F, 0x96, 0x81, 0xB4, +0x86, 0x9B, 0x56, 0x60, 0xAF, 0xA2, 0x66, 0x68, 0xE0, 0xDB, 0x41, 0x1D, 0xC4, 0x9C, 0x15, 0xB8, +0x11, 0x7B, 0xFF, 0xB3, 0x74, 0x6E, 0x38, 0x18, 0xD4, 0xBD, 0x92, 0xE7, 0xD5, 0x05, 0x60, 0xFD, +0xCC, 0x18, 0x3B, 0x27, 0x9E, 0x06, 0xD6, 0x53, 0x29, 0xA5, 0x5B, 0xC9, 0x5C, 0x33, 0xDF, 0xAD, +0x2E, 0x00, 0xFE, 0x97, 0x74, 0x3B, 0xE8, 0x5C, 0xFA, 0xDE, 0xDE, 0x56, 0x4D, 0x7D, 0x50, 0x4D, +0x00, 0x84, 0x65, 0x57, 0x4C, 0x41, 0x62, 0xB7, 0x03, 0x8B, 0x47, 0x4F, 0xB7, 0x25, 0x88, 0x9A, +0x82, 0x68, 0x45, 0x6D, 0x05, 0xF9, 0xD6, 0x68, 0x4A, 0x3F, 0x1F, 0xB1, 0x61, 0x8D, 0x3E, 0xF8, +0x1E, 0xF1, 0xA6, 0x7F, 0xA1, 0xA3, 0x67, 0x6F, 0xB5, 0xDC, 0x16, 0xD5, 0x03, 0xE0, 0xE7, 0x8B, +0xE2, 0xBC, 0xBE, 0xEB, 0x5C, 0x54, 0x9E, 0x05, 0xA6, 0xA5, 0xD6, 0x98, 0x3A, 0x03, 0x95, 0xE6, +0x23, 0xCE, 0x83, 0x59, 0x36, 0x07, 0x18, 0x0B, 0xCB, 0x1B, 0x5C, 0x84, 0xCA, 0xD7, 0x51, 0x26, +0xA5, 0x8E, 0x5B, 0xA5, 0x73, 0xDB, 0xD8, 0x0F, 0xED, 0x03, 0x77, 0x36, 0xB1, 0x09, 0x9B, 0xAB, +0x65, 0x9A, 0x56, 0x0F, 0x80, 0x65, 0x57, 0x4C, 0x45, 0x62, 0x5F, 0x06, 0xBE, 0x8C, 0x60, 0x8D, +0xBA, 0x11, 0x32, 0x17, 0x99, 0x3C, 0x91, 0x96, 0xD3, 0x72, 0x01, 0xB0, 0x71, 0xFA, 0x2F, 0x04, +0xDB, 0x7C, 0xEF, 0x3C, 0x60, 0x8A, 0xEF, 0x15, 0xCD, 0xF5, 0x29, 0x95, 0xC0, 0x7D, 0xA9, 0xAE, +0x8A, 0x7A, 0x0F, 0xE2, 0xC4, 0xBE, 0xC6, 0x8D, 0x2B, 0xF7, 0x54, 0x23, 0xB6, 0x50, 0xDE, 0xF2, +0x83, 0x48, 0x66, 0xDC, 0xCA, 0xCE, 0xC0, 0x19, 0x60, 0x3D, 0x0F, 0x1C, 0x3F, 0xA6, 0x7B, 0x09, +0x84, 0x28, 0xF0, 0xA9, 0x6C, 0x00, 0x7C, 0x91, 0xDD, 0x65, 0xF1, 0xF0, 0xCB, 0xAD, 0x34, 0x73, +0x1E, 0xB6, 0x5C, 0x83, 0xA7, 0x9F, 0x40, 0xE5, 0x44, 0x84, 0x36, 0xA0, 0xA9, 0x6C, 0xA8, 0x45, +0x77, 0xE3, 0x78, 0x97, 0xF2, 0xC6, 0xC1, 0x2D, 0xD5, 0x30, 0x4B, 0xAB, 0x03, 0x80, 0xB1, 0x7C, +0xEC, 0x96, 0xEB, 0x10, 0xFD, 0x57, 0xF0, 0x7D, 0xF9, 0xC9, 0x66, 0xE4, 0xAC, 0x96, 0x26, 0x7E, +0x42, 0x03, 0x90, 0xD9, 0xF1, 0xA1, 0x45, 0x71, 0xA6, 0xBE, 0x39, 0x0D, 0x27, 0xDE, 0x0E, 0xCC, +0x05, 0xCE, 0xF1, 0xB9, 0x42, 0x68, 0x1E, 0x75, 0xF8, 0x85, 0xD9, 0x04, 0x49, 0xEA, 0x18, 0xB3, +0xF4, 0x56, 0xEC, 0xC4, 0x52, 0x3A, 0x7B, 0x22, 0xB7, 0x88, 0xAA, 0x03, 0xC0, 0x23, 0xB3, 0x8F, +0x23, 0x11, 0x5F, 0x02, 0xCC, 0xC9, 0x24, 0x7E, 0xA9, 0xF1, 0xA8, 0x22, 0x34, 0x1A, 0xCB, 0x01, +0xF9, 0x90, 0x32, 0x0E, 0xBE, 0x25, 0x73, 0x26, 0x30, 0x49, 0x8C, 0xDB, 0xE3, 0x73, 0xC0, 0x45, +0xA8, 0xBC, 0x0F, 0xA1, 0x15, 0xCD, 0xE6, 0x0A, 0x11, 0x50, 0x2D, 0x70, 0x50, 0x16, 0x5D, 0x8B, +0xED, 0x7C, 0x8E, 0xCE, 0x67, 0x76, 0x05, 0x31, 0x7F, 0xA9, 0xCF, 0xA3, 0x07, 0xC0, 0x17, 0x3F, +0x83, 0x67, 0x81, 0xAC, 0x1F, 0x09, 0x16, 0x1E, 0x55, 0xEA, 0x84, 0x42, 0xF5, 0xCF, 0xB5, 0x82, +0x0C, 0xDD, 0xD6, 0xCF, 0xB4, 0x99, 0x78, 0xBA, 0xF0, 0xF4, 0x12, 0x97, 0x2E, 0xC6, 0x1E, 0x9E, +0xCC, 0xBC, 0xFA, 0x9D, 0x29, 0xC4, 0xDD, 0x59, 0xA2, 0xB2, 0x40, 0x2D, 0x35, 0x73, 0x9C, 0x0C, +0x19, 0x5C, 0x51, 0xF8, 0xE3, 0x7B, 0x40, 0x2F, 0x26, 0x96, 0xD8, 0x12, 0x75, 0x34, 0x2D, 0x7A, +0x00, 0x1E, 0x59, 0xD8, 0x4C, 0xF3, 0x5E, 0xC3, 0xFA, 0x3F, 0x46, 0x49, 0x64, 0xAD, 0x29, 0x8C, +0xD2, 0x0D, 0x27, 0x1A, 0xB2, 0x43, 0x92, 0xE6, 0xBC, 0xB1, 0x6B, 0xF2, 0xF9, 0xB8, 0x1A, 0x43, +0x63, 0xDB, 0x99, 0x32, 0xBC, 0x9F, 0xFE, 0xE6, 0xC1, 0x02, 0xC4, 0x12, 0xBA, 0x3B, 0xE2, 0x78, +0xCE, 0xC9, 0x78, 0xEE, 0x2D, 0x20, 0x7F, 0x85, 0x70, 0x12, 0xD0, 0x92, 0x0A, 0x7D, 0x26, 0xC3, +0x9E, 0x99, 0x4D, 0x18, 0xC4, 0xD3, 0x05, 0x0C, 0x1D, 0x58, 0xCD, 0x67, 0x37, 0x98, 0xC8, 0x5A, +0x64, 0x2D, 0x7A, 0x00, 0xBA, 0x3B, 0x26, 0xE3, 0x0E, 0xDF, 0x01, 0x7A, 0x6F, 0x81, 0x70, 0x62, +0xE5, 0x4A, 0xA0, 0x50, 0x4C, 0x18, 0xFD, 0x2A, 0xE8, 0x1F, 0x41, 0x1E, 0x04, 0xEF, 0xA7, 0x78, +0xCE, 0xDB, 0x34, 0xB5, 0x0D, 0xB0, 0xB5, 0xC7, 0xC9, 0xCB, 0x15, 0x46, 0x44, 0x3D, 0x3C, 0xB7, +0x8D, 0x16, 0x2E, 0x46, 0xB9, 0x1D, 0x7C, 0x51, 0x65, 0xB8, 0x22, 0x81, 0x60, 0x8F, 0xCE, 0xDF, +0x0F, 0x6B, 0xEA, 0x62, 0xBC, 0xE1, 0x1F, 0xF2, 0x99, 0xB5, 0x26, 0xC6, 0x1C, 0x59, 0x8B, 0x1E, +0x80, 0xC7, 0xAE, 0x3A, 0x86, 0xB8, 0xFB, 0x03, 0x54, 0x3A, 0x52, 0x7A, 0x37, 0x5B, 0xF4, 0x87, +0xD9, 0xE1, 0x41, 0xCB, 0x0B, 0x8A, 0x09, 0x27, 0x9D, 0x6A, 0x7D, 0xA8, 0xFE, 0x94, 0x18, 0xDF, +0xC7, 0xE5, 0x37, 0x0C, 0x1E, 0xB5, 0x9F, 0xD6, 0x43, 0xC3, 0x05, 0x45, 0x88, 0xE1, 0xA2, 0xDD, +0x2D, 0x26, 0x42, 0x77, 0x3B, 0xEA, 0x2B, 0x6E, 0x63, 0xBD, 0x99, 0xF0, 0xA8, 0x89, 0x4B, 0x1B, +0xAE, 0x78, 0x14, 0xF1, 0xEE, 0x62, 0xFE, 0xEA, 0x77, 0x82, 0xA6, 0x57, 0xCA, 0xF3, 0xE8, 0x01, +0x58, 0x3A, 0xEF, 0x24, 0x2C, 0x67, 0x25, 0xC8, 0x05, 0x81, 0x13, 0x49, 0x83, 0x91, 0xFA, 0xB7, +0x10, 0x36, 0x63, 0xFE, 0x5E, 0x2C, 0x2B, 0xC2, 0xC4, 0x84, 0x8F, 0x8C, 0x6B, 0xF2, 0x23, 0x8C, +0x5B, 0x79, 0x27, 0xE8, 0x83, 0x38, 0xBA, 0x82, 0xE6, 0xE6, 0xDD, 0xEC, 0xDD, 0x3E, 0xC8, 0xA2, +0xCD, 0x4E, 0xC1, 0xD3, 0xAD, 0x6F, 0xC5, 0x35, 0x7F, 0x64, 0x24, 0x58, 0xB3, 0x58, 0x84, 0x33, +0xD5, 0x58, 0x50, 0xCA, 0xCF, 0xF0, 0xEC, 0x05, 0x2C, 0x58, 0xB1, 0x33, 0x70, 0x5D, 0x25, 0x74, +0x88, 0x1E, 0x80, 0x27, 0xAE, 0x3C, 0x19, 0x74, 0x3D, 0xCA, 0xC9, 0x79, 0x2D, 0xA0, 0x5C, 0x6A, +0x16, 0xE1, 0x88, 0x82, 0x80, 0x08, 0x5B, 0xB4, 0x50, 0x5A, 0x4A, 0x4E, 0x50, 0x3E, 0x63, 0x0C, +0x03, 0xC6, 0x41, 0x2C, 0x79, 0x09, 0x9C, 0x7F, 0x66, 0xA8, 0xFF, 0x55, 0x06, 0x4E, 0x3D, 0xC0, +0xCE, 0x13, 0x46, 0x94, 0x76, 0x01, 0x8F, 0x67, 0xD2, 0xA0, 0x38, 0xDA, 0xB7, 0xA0, 0x84, 0x8F, +0x32, 0x6C, 0x2F, 0xE2, 0x86, 0x95, 0x7F, 0x2C, 0x81, 0xBE, 0x81, 0x5D, 0xA3, 0x07, 0xA0, 0x7B, +0xCE, 0x07, 0x71, 0xAD, 0x8D, 0x28, 0xC7, 0x16, 0xFB, 0x7A, 0x45, 0x92, 0xA8, 0x52, 0x5F, 0x90, +0xA8, 0x89, 0xFD, 0xBE, 0x8D, 0xB2, 0x0C, 0xB1, 0x96, 0x60, 0xC7, 0xFF, 0xE0, 0xE7, 0x10, 0x75, +0xF4, 0x78, 0x05, 0xB9, 0xC2, 0x44, 0xF3, 0xF6, 0x7C, 0x74, 0x38, 0x6A, 0xF7, 0x74, 0xF4, 0x00, +0x2C, 0xBB, 0xE2, 0x14, 0xC4, 0x7E, 0x11, 0x64, 0x7A, 0x1E, 0x6B, 0x22, 0x4B, 0x01, 0x57, 0x00, +0x42, 0x70, 0x56, 0x44, 0xE0, 0xDE, 0x1B, 0xED, 0x70, 0x10, 0xE4, 0x97, 0x78, 0xEE, 0xB7, 0x70, +0x0F, 0x6F, 0x64, 0xC2, 0x51, 0xFB, 0xE8, 0xEC, 0x31, 0x66, 0x6C, 0x4D, 0x52, 0x1A, 0xA3, 0x07, +0x20, 0x83, 0x03, 0xF2, 0x12, 0x38, 0x88, 0xEA, 0x41, 0xCF, 0x93, 0x9A, 0xBD, 0x70, 0x66, 0x5C, +0xB1, 0xBC, 0xA0, 0xC2, 0xA0, 0x18, 0x7B, 0xC8, 0x43, 0x79, 0x13, 0xD1, 0xD5, 0x88, 0xF3, 0x20, +0x56, 0xEB, 0x0E, 0x3A, 0x7A, 0x06, 0xAA, 0xE5, 0x05, 0x4D, 0x4F, 0x25, 0x7A, 0x00, 0x96, 0xCD, +0xFB, 0x00, 0x96, 0xBB, 0x21, 0x4B, 0x07, 0x14, 0x58, 0x78, 0x3E, 0x5A, 0x07, 0xD2, 0x3F, 0x39, +0xE3, 0x8A, 0x00, 0x28, 0xF8, 0x0D, 0xDF, 0xDC, 0x34, 0x3B, 0x5F, 0x8D, 0xCB, 0xE1, 0x15, 0x5F, +0x3C, 0xA9, 0xB7, 0x8E, 0xBE, 0xB7, 0xF6, 0x54, 0x2B, 0x26, 0x10, 0x3D, 0x00, 0xBE, 0x15, 0xE4, +0x9A, 0x00, 0xCC, 0xF9, 0xE1, 0xA5, 0x40, 0xC8, 0x9E, 0x49, 0x02, 0x0D, 0x60, 0xE9, 0x4B, 0x58, +0xC3, 0xD7, 0xD0, 0xB9, 0x76, 0xB7, 0xFF, 0xA6, 0xC9, 0x0D, 0x0D, 0x93, 0x19, 0x17, 0xF2, 0x33, +0xA9, 0x6E, 0x46, 0x1F, 0x38, 0x28, 0x3B, 0x10, 0x9E, 0xC7, 0x71, 0x7F, 0xC4, 0x34, 0xF7, 0x35, +0x66, 0xAF, 0x1D, 0x2C, 0x6D, 0x98, 0xE2, 0xBD, 0xA3, 0x07, 0xC0, 0x9C, 0x03, 0x62, 0xDE, 0x8F, +0x80, 0xAB, 0x32, 0xD9, 0x2C, 0x4B, 0xA0, 0x06, 0x6E, 0xF3, 0x9C, 0x49, 0x1B, 0xA5, 0xA9, 0xEC, +0x05, 0xD6, 0xE3, 0xE9, 0xE3, 0xBE, 0xAC, 0xBE, 0xE1, 0xA2, 0x91, 0x20, 0x49, 0xCA, 0x7A, 0x89, +0x10, 0x80, 0x3C, 0x53, 0x4B, 0x27, 0xFA, 0x3E, 0x4E, 0xAC, 0xE9, 0x4E, 0x3A, 0x7B, 0x8C, 0x5B, +0x3A, 0xB2, 0x16, 0x3D, 0x00, 0xE6, 0x24, 0xEC, 0x0C, 0xDD, 0x8D, 0xF0, 0x95, 0x50, 0xD9, 0x6E, +0x85, 0xC1, 0x30, 0x72, 0xF9, 0x10, 0xCA, 0x6F, 0x41, 0x97, 0xE3, 0xC9, 0xB3, 0x78, 0xFD, 0xDB, +0x79, 0xDF, 0xD0, 0x20, 0x33, 0x37, 0xB8, 0x59, 0xB2, 0x39, 0x1F, 0x00, 0xA5, 0x82, 0x5C, 0xD4, +0x64, 0x33, 0x6E, 0x3A, 0xEE, 0xA5, 0x85, 0xEF, 0xD3, 0xDE, 0xDB, 0x17, 0x19, 0xF5, 0xCB, 0xF6, +0x91, 0x17, 0x9B, 0x41, 0x77, 0xC7, 0x04, 0x9C, 0xC1, 0x4E, 0x44, 0x96, 0xA4, 0x3C, 0x8E, 0xA3, +0xE7, 0xA2, 0x90, 0x13, 0x1F, 0x46, 0x79, 0x07, 0xD1, 0x75, 0x08, 0x2B, 0xB0, 0x87, 0x37, 0xD2, +0xC6, 0x01, 0x36, 0x15, 0x31, 0x01, 0x33, 0xD3, 0xD3, 0x53, 0x4A, 0x38, 0x14, 0xFD, 0x53, 0xEE, +0x71, 0x33, 0xAF, 0x00, 0x93, 0x67, 0x00, 0xE4, 0x46, 0xA6, 0x0C, 0xAE, 0x6A, 0x7C, 0x11, 0x64, +0x72, 0x80, 0x4E, 0x9F, 0xFA, 0x61, 0xF0, 0x9E, 0x49, 0x45, 0xA6, 0xC6, 0x5A, 0xA3, 0x46, 0xCD, +0x65, 0xF3, 0x9E, 0x59, 0x7F, 0x1F, 0xA2, 0x5B, 0x51, 0x56, 0xE0, 0xC9, 0x1A, 0x9A, 0x9A, 0x7E, +0x1F, 0x78, 0x62, 0x4D, 0x8F, 0x9C, 0x07, 0x80, 0x40, 0xB0, 0x4B, 0x38, 0x10, 0x02, 0xEF, 0x62, +0xB9, 0x9F, 0xE4, 0xDA, 0x0B, 0x5E, 0x1D, 0x15, 0x7B, 0x81, 0x1F, 0x08, 0xD7, 0x21, 0x7A, 0x11, +0x64, 0x8C, 0xC4, 0xEE, 0x4F, 0x9D, 0x80, 0x6B, 0xF5, 0xA2, 0xF2, 0xE7, 0xF9, 0xA6, 0x91, 0xB1, +0x76, 0x93, 0x02, 0x68, 0x9C, 0x67, 0xEB, 0xC0, 0x79, 0x8A, 0x01, 0xF7, 0x45, 0xA4, 0xBF, 0x8F, +0xDF, 0xCD, 0x1C, 0xCA, 0x7B, 0xE0, 0xE9, 0xC2, 0xE2, 0xB4, 0x59, 0x6D, 0xC4, 0x12, 0xD3, 0xD9, +0xEF, 0xEE, 0xE4, 0xA6, 0xD5, 0x26, 0x7D, 0xA4, 0x5A, 0x4A, 0x38, 0x63, 0xEA, 0x6A, 0x22, 0x7B, +0x0B, 0x98, 0xDF, 0x6B, 0x0E, 0x6C, 0x91, 0xB6, 0x6A, 0x00, 0x00, 0x4B, 0x67, 0x4D, 0xC2, 0x8E, +0xDF, 0x81, 0xCA, 0xBD, 0x26, 0x0B, 0x2E, 0x73, 0xB3, 0x89, 0xE0, 0xAA, 0x72, 0x00, 0x91, 0x57, +0x50, 0x6F, 0x0D, 0x96, 0xB3, 0x8A, 0x43, 0xB1, 0x9D, 0x9C, 0x72, 0xA0, 0x9F, 0x8B, 0x0B, 0x64, +0x27, 0x9B, 0x1D, 0x7E, 0xD0, 0x3E, 0x16, 0x37, 0xF6, 0x09, 0xF0, 0xAE, 0x44, 0x65, 0x3A, 0xAE, +0x7D, 0xED, 0xA8, 0x5F, 0xA6, 0x52, 0x25, 0x9C, 0x76, 0x93, 0xA7, 0x26, 0x9A, 0xC5, 0x1C, 0xC6, +0x12, 0xF2, 0xF4, 0x0E, 0xF6, 0x1D, 0x78, 0x94, 0x2F, 0x46, 0x9F, 0x23, 0x54, 0x1D, 0x00, 0x4C, +0x48, 0xB0, 0x6D, 0xD7, 0x85, 0x08, 0xAB, 0x05, 0x99, 0xE4, 0x4B, 0x1C, 0xA1, 0x5F, 0x55, 0x77, +0xA1, 0xF2, 0x02, 0x98, 0xFC, 0x50, 0x6F, 0x13, 0x83, 0x7D, 0x07, 0x59, 0xB8, 0x61, 0x30, 0xEF, +0x61, 0xC7, 0xF8, 0x61, 0x0E, 0x0D, 0x4F, 0x24, 0xE1, 0x7C, 0x08, 0xB1, 0x2E, 0x43, 0xE5, 0x9A, +0x91, 0xF8, 0xD6, 0x09, 0xC9, 0x02, 0x0C, 0xDD, 0x86, 0x48, 0x76, 0x89, 0x52, 0xF4, 0x66, 0x68, +0x6A, 0xA7, 0xAB, 0xA9, 0x1D, 0xF8, 0x6B, 0xEC, 0xC4, 0x2B, 0x51, 0x07, 0x63, 0xCC, 0x07, 0xAA, +0x03, 0x80, 0xB1, 0x5F, 0x1E, 0xBF, 0x6A, 0x3A, 0x31, 0xF7, 0xDF, 0x10, 0x2E, 0x04, 0xD9, 0x82, +0xE8, 0x33, 0xA8, 0xD5, 0x43, 0x8B, 0xF7, 0x2E, 0x93, 0x8A, 0xEC, 0x76, 0xA3, 0xC4, 0x87, 0x0F, +0x1F, 0x8F, 0xD8, 0x7F, 0x81, 0x70, 0x2D, 0x2A, 0x1F, 0x06, 0x3F, 0xD5, 0xC4, 0x04, 0x77, 0x0A, +0xD7, 0x88, 0x45, 0x09, 0xC0, 0x91, 0xC0, 0x91, 0x49, 0xD8, 0xFD, 0x77, 0xEC, 0xC1, 0xBB, 0xE9, +0x7C, 0x2E, 0x52, 0xF3, 0x33, 0xD3, 0x44, 0x8F, 0x54, 0xA6, 0x8D, 0x0E, 0xE6, 0xE7, 0xEA, 0xF4, +0xFF, 0x29, 0xCA, 0xD1, 0xF4, 0xBB, 0xAF, 0xF8, 0xB2, 0xBD, 0xD8, 0x6E, 0x37, 0x81, 0x10, 0x77, +0xE8, 0x2C, 0xE0, 0x72, 0x94, 0xAB, 0x11, 0x8E, 0xF3, 0x77, 0x7B, 0xFE, 0x3A, 0xB1, 0xB2, 0x92, +0x73, 0x83, 0x16, 0x9A, 0xC7, 0x72, 0xDA, 0x87, 0x6A, 0x3B, 0xF1, 0xC4, 0x8B, 0xEF, 0xBD, 0xBC, +0x20, 0x5F, 0x19, 0x77, 0x24, 0x77, 0x6C, 0xBE, 0xAA, 0xC4, 0x74, 0xC0, 0xBC, 0x4D, 0x4F, 0x44, +0x4C, 0xEC, 0xC0, 0x32, 0x41, 0xF3, 0x73, 0x10, 0x26, 0xFA, 0xBB, 0x3D, 0x19, 0x04, 0x29, 0xD4, +0x2A, 0x07, 0x20, 0x38, 0x3C, 0x6A, 0xCE, 0x1A, 0x0F, 0x63, 0x0F, 0xDC, 0x4D, 0xC7, 0x73, 0xEF, +0xC1, 0xCC, 0xB8, 0xFC, 0xA4, 0x13, 0x1E, 0x5A, 0x14, 0x23, 0xBE, 0x63, 0x0A, 0x4D, 0xB1, 0x53, +0xB1, 0xAD, 0xAB, 0x51, 0x9D, 0x07, 0x62, 0x7C, 0xEE, 0x26, 0x71, 0x37, 0x7F, 0x71, 0xDE, 0xD8, +0xAD, 0x59, 0x3E, 0x00, 0xA1, 0x0E, 0x08, 0x20, 0xA2, 0x6F, 0xA9, 0xE3, 0x5D, 0xC1, 0xE1, 0x9D, +0x5B, 0xAB, 0xE5, 0x07, 0xAA, 0x9E, 0x0E, 0xC8, 0x25, 0xBE, 0x31, 0x1F, 0xCF, 0xEC, 0x68, 0x81, +0xC1, 0xE3, 0x70, 0xC5, 0xF8, 0x88, 0xFE, 0x1E, 0xE5, 0x54, 0x3F, 0xFE, 0x2A, 0x34, 0x85, 0x3A, +0x31, 0x67, 0x8E, 0x59, 0xBC, 0x4E, 0xD8, 0x04, 0xD7, 0xCB, 0x6A, 0xA3, 0xD8, 0x98, 0xEC, 0x68, +0xE1, 0x66, 0x86, 0xFA, 0x7F, 0xC2, 0x0D, 0xEB, 0x0E, 0x95, 0x35, 0x58, 0xC8, 0x97, 0xAA, 0xA3, +0x84, 0x73, 0x3F, 0x6E, 0xF4, 0x81, 0x33, 0x7C, 0x0B, 0x78, 0xB7, 0x0A, 0x32, 0x5D, 0x95, 0x56, +0x3F, 0x5D, 0xB1, 0xD0, 0x6E, 0x4C, 0xCF, 0x2A, 0x87, 0x90, 0x19, 0xDD, 0x23, 0xCB, 0x8E, 0xCE, +0x31, 0x39, 0x4D, 0x72, 0x90, 0x09, 0x55, 0xAE, 0x44, 0xF5, 0x96, 0xFF, 0x1F, 0xF5, 0x01, 0x06, +0x0C, 0xDF, 0x2C, 0x7D, 0xF3, 0x2C, 0x24, 0x6E, 0x12, 0x75, 0x8B, 0x46, 0xCA, 0x42, 0xFA, 0x2D, +0xCA, 0x17, 0x41, 0x19, 0x85, 0x92, 0xB9, 0xFB, 0x44, 0x50, 0x55, 0xE4, 0x75, 0x1C, 0xEF, 0x72, +0xB6, 0xD7, 0xA6, 0x6A, 0xB2, 0x36, 0x1C, 0xE0, 0x83, 0x30, 0xA7, 0x85, 0x49, 0x72, 0x89, 0xA8, +0x2C, 0x55, 0x7C, 0x45, 0x5B, 0x49, 0x8B, 0x8C, 0x03, 0xB2, 0x27, 0xA1, 0xBB, 0xB1, 0xBC, 0xCB, +0xB1, 0x26, 0x98, 0x02, 0xEE, 0x9A, 0x14, 0xEA, 0xD5, 0x0E, 0x00, 0xBF, 0x30, 0xFB, 0x92, 0x49, +0x38, 0x2D, 0x8B, 0x41, 0x4C, 0xCD, 0x40, 0x56, 0xCE, 0x68, 0x18, 0xB9, 0x5D, 0x54, 0x04, 0x85, +0x3D, 0x07, 0x14, 0x16, 0x7B, 0x87, 0xF1, 0xF4, 0x6F, 0x88, 0x27, 0x56, 0xD5, 0xB2, 0x7A, 0xBE, +0x76, 0x00, 0x98, 0xAD, 0x66, 0xEA, 0xC5, 0xCE, 0xDC, 0x74, 0x0C, 0x4E, 0xEC, 0x39, 0x90, 0xB3, +0x33, 0x0F, 0x82, 0xA1, 0x8C, 0x93, 0x74, 0xA7, 0x4A, 0x83, 0xF2, 0x99, 0xA7, 0xA0, 0xA4, 0x9E, +0x71, 0x11, 0x59, 0x41, 0x33, 0x8B, 0xB8, 0xF2, 0xA9, 0xFD, 0xD5, 0x0E, 0x43, 0x66, 0xDB, 0x13, +0x95, 0x08, 0x82, 0x72, 0xDE, 0x35, 0x09, 0x50, 0x6F, 0x4F, 0x39, 0x17, 0xF1, 0x1D, 0x5C, 0x53, +0xCB, 0x19, 0xC2, 0x0F, 0x49, 0x96, 0x73, 0x57, 0x44, 0xA1, 0x8F, 0x09, 0x3B, 0x40, 0x3E, 0x8E, +0x1D, 0xDF, 0x51, 0x0D, 0x77, 0x43, 0xB1, 0x35, 0xD6, 0x96, 0x03, 0xD2, 0x33, 0x49, 0xC6, 0x0C, +0xBA, 0x40, 0xBE, 0x54, 0xF4, 0x62, 0x8E, 0xC2, 0x6C, 0x11, 0x89, 0x0E, 0x48, 0x0D, 0x3F, 0x84, +0xF0, 0x59, 0x66, 0x1C, 0xDB, 0xC3, 0x05, 0x4B, 0x6A, 0x52, 0x1B, 0x5C, 0x5F, 0x0E, 0xF0, 0x45, +0x91, 0x39, 0x17, 0xCC, 0x3E, 0x06, 0x27, 0xBE, 0x71, 0x24, 0xE5, 0xEF, 0x48, 0x02, 0x57, 0x58, +0x76, 0x28, 0x22, 0x82, 0x72, 0xAF, 0x2A, 0x28, 0x88, 0x61, 0xB2, 0x26, 0xCC, 0x98, 0x3D, 0x9B, +0x19, 0x94, 0x4B, 0x59, 0x58, 0x5B, 0xD1, 0x93, 0x29, 0x05, 0xC3, 0x2E, 0x3B, 0xDA, 0x7E, 0x26, +0x70, 0x73, 0xDA, 0xA4, 0xCF, 0x63, 0xCB, 0x83, 0x45, 0x6F, 0x49, 0xC9, 0x67, 0x36, 0x06, 0xE5, +0x86, 0x86, 0x9E, 0xA9, 0x0E, 0x20, 0xD6, 0xA7, 0xF8, 0xCD, 0x9F, 0xAD, 0x8F, 0x3A, 0xE1, 0x2A, +0xEC, 0x14, 0xEA, 0x23, 0x82, 0xCC, 0xEC, 0x92, 0xD7, 0x92, 0x4D, 0xC5, 0x19, 0xDA, 0x88, 0x30, +0xA3, 0xA4, 0xD3, 0x70, 0x11, 0x00, 0xC4, 0x2B, 0x7E, 0x59, 0x47, 0x06, 0x61, 0x4C, 0xD6, 0xC3, +0x26, 0xEC, 0xFD, 0x97, 0x56, 0xBB, 0x16, 0xB8, 0xF1, 0x74, 0x40, 0x7A, 0x46, 0x46, 0x14, 0x9D, +0x31, 0xF7, 0x56, 0x3C, 0xEB, 0xDB, 0x25, 0xDD, 0x9A, 0x12, 0x92, 0x03, 0xC6, 0x88, 0x9F, 0xAC, +0x3F, 0xA8, 0x89, 0x43, 0x74, 0x72, 0x5D, 0xEF, 0xEA, 0x5A, 0x5A, 0x3D, 0x63, 0x0F, 0x7F, 0x61, +0x79, 0xA5, 0x5A, 0xFD, 0x92, 0x69, 0x2C, 0x9B, 0x46, 0x3C, 0x8F, 0xEF, 0x2F, 0x81, 0x0B, 0xCA, +0xB7, 0x82, 0x7C, 0x10, 0xC4, 0xF8, 0xF9, 0xB7, 0x62, 0x1F, 0xFA, 0x4B, 0x3A, 0xFF, 0x23, 0x79, +0xF3, 0x62, 0x9D, 0x5A, 0xFD, 0x44, 0x50, 0x7A, 0xC1, 0xA6, 0xBA, 0xF1, 0x89, 0x5F, 0x3C, 0x84, +0xB0, 0x30, 0x48, 0x17, 0xF8, 0xAF, 0x24, 0x77, 0x71, 0x51, 0x00, 0x82, 0xCF, 0x14, 0x32, 0x8C, +0x7A, 0xF7, 0x71, 0x7D, 0xEF, 0xD7, 0x82, 0x13, 0x22, 0xAA, 0x8B, 0x4C, 0xFD, 0x01, 0x30, 0xEB, +0x5B, 0x76, 0xE5, 0xF9, 0x88, 0xF7, 0x9F, 0x45, 0xEF, 0x92, 0xC8, 0xA6, 0x6A, 0x25, 0x1C, 0x60, +0xB2, 0xEB, 0xF6, 0xA1, 0xCE, 0x05, 0x5C, 0xBF, 0x66, 0x7B, 0x75, 0xC9, 0x1B, 0x3C, 0x7A, 0x63, +0x00, 0x90, 0x0C, 0xE2, 0xBF, 0x80, 0xCA, 0x87, 0x02, 0xEF, 0x11, 0x4A, 0xCE, 0xD8, 0xE4, 0x86, +0xCE, 0x1E, 0x73, 0x6D, 0xA5, 0xB9, 0xE1, 0x24, 0x59, 0xD5, 0x32, 0xB6, 0x1D, 0x39, 0x45, 0x9B, +0xEA, 0x99, 0x97, 0xE8, 0xF3, 0x2E, 0x19, 0xCD, 0xAA, 0x08, 0xA6, 0x53, 0xD5, 0x7A, 0x34, 0x06, +0x00, 0xFE, 0xB5, 0x95, 0x73, 0xEF, 0x47, 0xE4, 0x32, 0x14, 0x7B, 0x4C, 0xA4, 0x3A, 0xED, 0x96, +0x1E, 0x25, 0xA2, 0xBE, 0x81, 0xED, 0xFC, 0xED, 0x68, 0xD9, 0xA8, 0xEF, 0xEE, 0xEE, 0xBF, 0x1E, +0xEC, 0xDB, 0x90, 0x02, 0x85, 0x81, 0xA6, 0x04, 0x35, 0x59, 0x8A, 0xEA, 0x20, 0xDA, 0xCD, 0xA7, +0x7B, 0x0D, 0x58, 0x75, 0x6F, 0x8D, 0x01, 0x80, 0x21, 0x83, 0x29, 0x80, 0x38, 0xAE, 0x2D, 0x4E, +0xDF, 0x60, 0xF0, 0x9C, 0x26, 0x26, 0x4C, 0x81, 0xC5, 0x50, 0x86, 0xDB, 0x40, 0xF8, 0xF9, 0xA2, +0x18, 0xDB, 0xF7, 0x26, 0x02, 0xDF, 0x9F, 0x98, 0x30, 0x70, 0x9A, 0x77, 0x6B, 0xE2, 0xED, 0x0C, +0x42, 0x38, 0x78, 0xB1, 0x41, 0x23, 0x8C, 0x3F, 0xAF, 0x88, 0x02, 0xE3, 0x00, 0x54, 0x44, 0xBE, +0xCA, 0x5F, 0x6E, 0x1C, 0x00, 0x8C, 0x1E, 0x78, 0xB2, 0xFD, 0x24, 0x6C, 0x6D, 0xC1, 0xC9, 0xC9, +0x1C, 0xAD, 0x7C, 0x9D, 0xC9, 0x11, 0x5C, 0x51, 0x12, 0xDE, 0xC1, 0xD1, 0x4B, 0xBF, 0xA3, 0x1A, +0xB7, 0x82, 0x71, 0x1A, 0x07, 0x80, 0x6E, 0x6C, 0x9C, 0xF6, 0xA5, 0xBE, 0x9B, 0x59, 0x35, 0x79, +0x83, 0x6E, 0x90, 0x41, 0x9F, 0xF9, 0x3C, 0xB7, 0x6F, 0xDE, 0x67, 0x62, 0xBC, 0x9D, 0x8F, 0x33, +0x7F, 0x95, 0xB9, 0xBB, 0xAE, 0x21, 0x5A, 0xE3, 0x00, 0x60, 0xC8, 0xB1, 0xBC, 0xFD, 0x01, 0x84, +0x9B, 0xD2, 0x69, 0xED, 0x91, 0x53, 0xC8, 0x5C, 0x39, 0xA0, 0xDC, 0xCF, 0xFC, 0x55, 0xF7, 0x44, +0x3E, 0x76, 0x99, 0x03, 0x36, 0x16, 0x00, 0x4F, 0xCC, 0xBD, 0x07, 0xC4, 0xFC, 0x06, 0x40, 0xF6, +0x1D, 0x13, 0x19, 0x8B, 0x4B, 0x7A, 0x12, 0x02, 0xCE, 0xAF, 0x05, 0x9E, 0x0B, 0x0C, 0x28, 0xBA, +0x98, 0xF9, 0xBD, 0xDF, 0x2D, 0x93, 0x5E, 0x91, 0xBF, 0xD6, 0x68, 0x00, 0x7C, 0x01, 0x95, 0xAF, +0x8E, 0x02, 0x90, 0xBE, 0xC7, 0xCD, 0x2C, 0x3B, 0x5F, 0x26, 0x5B, 0xEE, 0xDF, 0x82, 0xF2, 0x81, +0x44, 0x07, 0x46, 0x8A, 0xB5, 0xEF, 0xE4, 0xFA, 0xDE, 0x27, 0x23, 0xA7, 0x64, 0x99, 0x03, 0x36, +0x16, 0x00, 0x8F, 0x5C, 0x39, 0x05, 0xDB, 0x9D, 0x4A, 0x93, 0x5D, 0x2C, 0x2D, 0xB1, 0xCC, 0xA5, +0x1A, 0xEB, 0xDF, 0xF5, 0x98, 0x2C, 0xEF, 0x44, 0x5D, 0x66, 0x54, 0xFE, 0x84, 0xAA, 0x95, 0x1D, +0x5D, 0xFE, 0x8C, 0x84, 0x2E, 0xA3, 0x7A, 0xBB, 0xCA, 0x1F, 0xA1, 0xE8, 0x9B, 0x23, 0xE3, 0x76, +0xF9, 0xBC, 0x14, 0xC4, 0x2B, 0x55, 0xFA, 0xFE, 0xD8, 0x61, 0x1B, 0x8B, 0x03, 0x6A, 0xB6, 0xEC, +0xC6, 0xF9, 0x50, 0x63, 0x01, 0xB0, 0x7C, 0xCE, 0x59, 0x08, 0x1F, 0x0B, 0xE5, 0x96, 0x2E, 0x87, +0x86, 0xA6, 0xDA, 0x65, 0x48, 0x9F, 0xE7, 0xC6, 0xA7, 0x7F, 0x5F, 0xCE, 0xEB, 0xD5, 0x78, 0xA7, +0xC1, 0x00, 0x68, 0xBF, 0x69, 0xE4, 0xCA, 0x00, 0x73, 0xD1, 0x53, 0x41, 0x2B, 0x28, 0x97, 0x08, +0xE9, 0x05, 0x84, 0x93, 0x29, 0x3A, 0x80, 0xA7, 0x5F, 0xE0, 0x33, 0xAB, 0x9F, 0xAE, 0x06, 0x31, +0xCB, 0x19, 0xB3, 0xB1, 0x00, 0x78, 0xA2, 0xFD, 0x8B, 0xA8, 0xDE, 0x0F, 0xD2, 0x5C, 0xCE, 0x62, +0x02, 0xDF, 0x31, 0x59, 0xCF, 0x2A, 0x37, 0x30, 0xFF, 0xA9, 0x9F, 0x04, 0xF6, 0xAD, 0x51, 0x87, +0xC6, 0x02, 0x60, 0x79, 0xFB, 0x2D, 0xA0, 0xDF, 0x89, 0x12, 0x80, 0xAC, 0x23, 0xC1, 0x38, 0x00, +0x01, 0xDB, 0x2A, 0x17, 0x80, 0xA0, 0x03, 0x57, 0xA9, 0xBB, 0xD4, 0xFC, 0x82, 0x92, 0x8C, 0x73, +0x40, 0x61, 0xB2, 0x3D, 0xD9, 0x7E, 0x0B, 0x5E, 0x06, 0x07, 0x44, 0x0D, 0xC0, 0x38, 0x07, 0x54, +0xCE, 0x01, 0x15, 0x61, 0xE2, 0x57, 0xBE, 0xE8, 0x02, 0xAE, 0xEB, 0x5D, 0x51, 0x2A, 0xF3, 0x54, +0xAB, 0x7F, 0x63, 0xE9, 0x80, 0xA5, 0xED, 0xD7, 0x60, 0xE9, 0xA3, 0x11, 0xFE, 0xD0, 0x43, 0x2E, +0xDD, 0xFA, 0xB0, 0xB5, 0x9D, 0x6B, 0x7B, 0xCD, 0xA5, 0xB2, 0x0D, 0xD1, 0x1A, 0x0B, 0x80, 0xE5, +0x73, 0x4D, 0xF5, 0x8C, 0x89, 0x0D, 0x9B, 0x3A, 0xB2, 0x53, 0x7C, 0x73, 0x34, 0xCC, 0x96, 0xCF, +0xB9, 0x93, 0x3A, 0x47, 0xF1, 0x1A, 0x0B, 0xD5, 0x5C, 0xB6, 0xFA, 0xBF, 0x28, 0x2F, 0xD2, 0x6C, +0xDD, 0xC5, 0xBC, 0x95, 0xEF, 0x36, 0x04, 0xF5, 0xAB, 0x56, 0xA8, 0x5D, 0xEE, 0xEA, 0x4C, 0xFD, +0xC0, 0xE9, 0x9B, 0xCD, 0x75, 0xC7, 0xC7, 0x22, 0xF6, 0x23, 0xA8, 0x9A, 0xBB, 0x26, 0x82, 0x7E, +0xD6, 0x30, 0xE8, 0x6B, 0x2E, 0xE8, 0x7F, 0x61, 0xB9, 0x37, 0xE3, 0x59, 0xBB, 0x6B, 0x51, 0xF7, +0x15, 0x34, 0xA1, 0xCC, 0xE7, 0x8D, 0xC5, 0x01, 0xE9, 0x99, 0x99, 0x9A, 0xB2, 0x89, 0x7F, 0xF8, +0x47, 0xD0, 0x2F, 0x09, 0xD2, 0x1C, 0xEE, 0x90, 0x55, 0x60, 0xD9, 0x62, 0x7E, 0x2D, 0xCF, 0xFB, +0x26, 0xDB, 0xFA, 0xBE, 0x51, 0x8D, 0xEB, 0xE7, 0x4B, 0x21, 0x76, 0xBE, 0xBE, 0x8D, 0x09, 0x80, +0x99, 0xE9, 0xD2, 0xF6, 0xB3, 0xB1, 0x78, 0x2E, 0x55, 0xD4, 0x97, 0x75, 0xE1, 0x87, 0xBF, 0x90, +0x7C, 0xA2, 0x29, 0xFD, 0xB7, 0xD1, 0x67, 0xFE, 0x7D, 0xE8, 0xBB, 0xB0, 0x9C, 0xCB, 0xB8, 0x6E, +0xCD, 0xAF, 0x2B, 0x25, 0x56, 0x35, 0xDE, 0x6F, 0x5C, 0x00, 0x4C, 0x51, 0xDF, 0x44, 0xEB, 0x4E, +0x94, 0xAF, 0xA4, 0x7E, 0x61, 0x75, 0x0C, 0xD1, 0x03, 0xDD, 0x10, 0xFE, 0xAF, 0x21, 0xE9, 0x77, +0x68, 0xD3, 0x6F, 0x32, 0x27, 0x75, 0xB5, 0x4D, 0x35, 0xA8, 0x58, 0xC1, 0x98, 0x8D, 0x0B, 0x80, +0xCF, 0x05, 0xF3, 0x4E, 0xC2, 0x76, 0x1F, 0xF0, 0xB3, 0xE0, 0x32, 0x15, 0x72, 0x21, 0xC5, 0x9C, +0xFD, 0xF7, 0x21, 0x30, 0x77, 0x47, 0x7B, 0x37, 0xD1, 0xD9, 0x38, 0xCE, 0xB7, 0x5C, 0xAC, 0x1A, +0x1B, 0x00, 0xBF, 0xA8, 0xEF, 0xE5, 0x19, 0xB8, 0x18, 0xFF, 0xD0, 0x27, 0x51, 0x8C, 0x8F, 0xE8, +0xC8, 0x9C, 0xF3, 0x8B, 0x21, 0x93, 0xFB, 0x69, 0x92, 0xAE, 0x7E, 0x46, 0x8C, 0xBF, 0x63, 0xEB, +0x79, 0xAF, 0xD5, 0xAB, 0xF8, 0x22, 0x0C, 0x63, 0x34, 0x36, 0x00, 0x66, 0x05, 0x3E, 0x08, 0x9B, +0x3F, 0x80, 0x63, 0x2D, 0x1C, 0xB9, 0x3A, 0xEC, 0xD6, 0x11, 0x33, 0xB5, 0xAD, 0xC0, 0x0D, 0x2A, +0x26, 0x54, 0x6C, 0x12, 0x5A, 0x0E, 0xA3, 0x3C, 0x86, 0x65, 0xFD, 0x00, 0x2B, 0xF6, 0x46, 0xAD, +0x8B, 0xEE, 0xC2, 0x10, 0xBD, 0xF1, 0xAD, 0xA0, 0x7C, 0xAB, 0x58, 0x35, 0x77, 0x22, 0x7D, 0x9C, +0x83, 0xC5, 0x55, 0x88, 0x5C, 0xED, 0x5F, 0x83, 0x73, 0xC4, 0x44, 0x35, 0x37, 0x9B, 0xEC, 0x45, +0x59, 0x8D, 0xB2, 0x12, 0x9C, 0xCD, 0xCC, 0x5F, 0xB3, 0xAF, 0x9E, 0x85, 0x17, 0x61, 0x81, 0x68, +0x7C, 0x0E, 0xC8, 0x5C, 0x49, 0xFA, 0x8A, 0x9B, 0x56, 0xE7, 0x28, 0xEC, 0xA6, 0x0F, 0xE2, 0xE9, +0x71, 0xA8, 0x28, 0x71, 0xDD, 0x49, 0x2C, 0xF6, 0x3B, 0x0E, 0x1D, 0xDC, 0xCB, 0x82, 0x75, 0xE6, +0xA2, 0x8D, 0x8A, 0x2C, 0xD7, 0xB0, 0xC4, 0x8B, 0xA2, 0xDF, 0x7B, 0x0B, 0x80, 0x28, 0x56, 0xDC, +0x60, 0x63, 0x8C, 0x03, 0x50, 0x67, 0x40, 0xC6, 0x01, 0x18, 0x07, 0xA0, 0xCE, 0x14, 0xA8, 0xF3, +0xE7, 0xFF, 0x0F, 0xB7, 0x80, 0x16, 0xCA, 0xD9, 0x27, 0x5C, 0xC7, 0x00, 0x00, 0x00, 0x00, 0x49, +0x45, 0x4E, 0x44, 0xAE, 0x42, 0x60, 0x82 +}; \ No newline at end of file diff --git a/src/www/favicon.png b/src/www/favicon.png new file mode 100644 index 0000000..753583c Binary files /dev/null and b/src/www/favicon.png differ diff --git a/src/www/particleCanvas.js b/src/www/particleCanvas.js new file mode 100644 index 0000000..03dd4a9 --- /dev/null +++ b/src/www/particleCanvas.js @@ -0,0 +1,94 @@ + const canvas = document.getElementById('particleCanvas'); + const ctx = canvas.getContext('2d'); + canvas.width = window.innerWidth; + canvas.height = window.innerHeight; + + let particlesArray = []; + const numberOfParticles = 100; + + class Particle { + constructor(x, y, directionX, directionY, size, color) { + this.x = x; + this.y = y; + this.directionX = directionX; + this.directionY = directionY; + this.size = size; + this.color = color; + } + draw() { + ctx.beginPath(); + ctx.arc(this.x, this.y, this.size, 0, Math.PI * 2, false); + ctx.fillStyle = this.color; + ctx.fill(); + } + + + update() { + if (this.x + this.size > canvas.width || this.x - this.size < 0) { + this.directionX = -this.directionX; + } + + if (this.y + this.size > canvas.height || this.y - this.size < 0) { + this.directionY = -this.directionY; + } + + this.x += this.directionX; + this.y += this.directionY; + + this.draw(); + } + } + + function init() { + particlesArray = []; + for (let i = 0; i < numberOfParticles; i++) { + let size = Math.random() * 5 + 1; + let x = Math.random() * (canvas.width - size * 2) + size; + let y = Math.random() * (canvas.height - size * 2) + size; + let directionX = (Math.random() * 0.5) - 0.25; + let directionY = (Math.random() * 0.5) - 0.25; + let color = 'rgba(255, 255, 255, 0.8)'; + + particlesArray.push(new Particle(x, y, directionX, directionY, size, color)); + } + } + + function connect() { + let opacityValue = 1; + for (let a = 0; a < particlesArray.length; a++) { + for (let b = a; b < particlesArray.length; b++) { + let distance = ((particlesArray[a].x - particlesArray[b].x) * (particlesArray[a].x - particlesArray[b].x)) + + ((particlesArray[a].y - particlesArray[b].y) * (particlesArray[a].y - particlesArray[b].y)); + + if (distance < (canvas.width / 7) * (canvas.height / 7)) { + opacityValue = 1 - (distance / 20000); + ctx.strokeStyle = 'rgba(255, 255, 255,' + opacityValue + ')'; + ctx.lineWidth = 1; + ctx.beginPath(); + ctx.moveTo(particlesArray[a].x, particlesArray[a].y); + ctx.lineTo(particlesArray[b].x, particlesArray[b].y); + ctx.stroke(); + } + } + } + } + + function animate() { + ctx.clearRect(0, 0, canvas.width, canvas.height); + + for (let i = 0; i < particlesArray.length; i++) { + particlesArray[i].update(); + } + + connect(); + requestAnimationFrame(animate); + } + + window.addEventListener('resize', () => { + canvas.width = window.innerWidth; + canvas.height = window.innerHeight; + init(); + }); + + init(); + animate(); \ No newline at end of file diff --git a/src/www/setupPage.html b/src/www/setupPage.html new file mode 100644 index 0000000..64a531b --- /dev/null +++ b/src/www/setupPage.html @@ -0,0 +1,480 @@ + + + + + + + BLLED Setup + + + + + +
+ + +
+

Configuration

+

Use the options below to configure your BLLED Controller.

+ + + + +
+ LED Behaviour +
+
+ + Maintenance Mode (Always On) +
+ +
+ + RGB Color Cycle Mode (Always On) +
+ +
+ + Replicate LED State + + +
+ + WW + CW +
+ + +
+ + + + +
+ + Replicate LED State +
+
+
+ + + + + + + + + + + +
+ LED Color +
+ + +
+
+ +
+ MQTT Settings +
+ + +
+
+ +
+ Navigation +
+ + + +
+
+ + +
+
+ +
ℹ️Placeholder
+ + + + + + \ No newline at end of file diff --git a/src/www/setupPageOld.html b/src/www/setupPageOld.html new file mode 100644 index 0000000..031c72f --- /dev/null +++ b/src/www/setupPageOld.html @@ -0,0 +1,1078 @@ + + + + + + + + BLLED Setup + + + + + + +
+
+ + BLLED Controller + + WiFi-Signal + + + + + + + +
+
+

BLLED LED Settings

+

Firmware version: ??.??.??

+

This page allows you to change the LED behavior.

+
+
+ + + + + + + + + + + + + +
+ + +

LED + Behaviour (Choose One)

+
+ +    Maintenance Mode (Always On) +
+
+ +    RGB Color Cycle Mode (Always On) +
+
+ +    Replicate LED State +
+ +  WW  +  CW  +
+
+ +
+ + +    Test LED Colors (Always On) +
+ +  WW  +  CW  +
+
+ + + + + + +
+
+ +    Show Wifi Strength via + LEDs +
+
+ +

Options

+ + + + + + + + + + +
+
+ +    Finish Indication +
+
+
+ +  WW  +  CW  +
+
+ + + +
+
+ +    Inactivity Timeout (Minutes) + +
+
+ +    Debugging +
+
+ +    Debugging OnChange Events +
+
+ +    MQTT Logging +
+
+

Printer + Dependant

+
+ +    Connecting to a P1 Printer? (No Door + Switch, No Lidar) +
+
+ +    Door Switch used for actions (P1 has no + switch) +
+ + + + + + +
+

+ Stages with Lidar in use (if installed)

+
+ +  WW  +  CW  +    Cleaning Nozzle
+ + +  WW  +  CW  +    Bed Leveling
+ + +  WW  +  CW  +    Calibrating Extrusion
+ + +  WW  +  CW  +    Scanning Bed Surface
+ + +  WW  +  CW  +    First Layer Inspection
+ + +

Customise + Colors

+
+ +    Error Detection +
+
+ + +  WW  +  CW  +    WiFi Setup / Scanning
+ + + +  WW  +  CW  +    Pause (Gcode or User)
+ + +  WW  +  CW  +    First Layer Error (Pause for + user)
+ + +  WW  +  CW  +    Nozzle Clog (Pause for user)
+ + +  WW  +  CW  +    HMS Severity, SERIOUS
+ + +  WW  +  CW  +    HMS Severity, FATAL
+ + +  WW  +  CW  +    Filament Runout
+ + +  WW  +  CW  +    Front Cover Removed
+ + +  WW  +  CW  +    Nozzle Temp Fail
+ + +  WW  +  CW  +    Bed Temp Fail
+
+
+ +
+ + + +
+ +
+
+
+ + + + + + + + + + + \ No newline at end of file diff --git a/src/www/setuppage.h b/src/www/setuppage.h deleted file mode 100644 index 98853ca..0000000 --- a/src/www/setuppage.h +++ /dev/null @@ -1,458 +0,0 @@ -//File: setuppage.html.gz, Size: 7256 -#define setuppage_html_gz_len 7256 -const uint8_t setuppage_html_gz[] PROGMEM = { -0x1F, 0x8B, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xED, 0x5D, 0x6B, 0x77, 0xDB, 0x36, -0xD2, 0xFE, 0xBE, 0xE7, 0xEC, 0x7F, 0x40, 0xD5, 0xD3, 0x4A, 0xAE, 0xAD, 0x9B, 0x2F, 0x89, 0xEC, -0x58, 0xEE, 0xB1, 0x65, 0xBB, 0x75, 0xDF, 0xA4, 0xF1, 0xDA, 0x4E, 0xD3, 0xEC, 0x9E, 0x7E, 0x80, -0x48, 0x48, 0x62, 0x43, 0x91, 0x2C, 0x49, 0x59, 0x56, 0x77, 0xF3, 0xDF, 0xDF, 0x19, 0x80, 0x57, -0xF0, 0x22, 0x92, 0x92, 0xBC, 0xF2, 0xEE, 0x2A, 0xAD, 0x6D, 0x81, 0x83, 0x99, 0xC1, 0xE0, 0xC1, -0x60, 0x70, 0xE5, 0xE9, 0x57, 0x97, 0xEF, 0x07, 0x0F, 0x9F, 0x6E, 0xAF, 0xC8, 0xC4, 0x9D, 0xEA, -0x67, 0x7F, 0xFD, 0xCB, 0x29, 0xFE, 0x26, 0x3A, 0x35, 0xC6, 0xFD, 0x1A, 0x33, 0x6A, 0x3C, 0x85, -0x51, 0x15, 0x7E, 0x13, 0xF8, 0x9C, 0x4E, 0x99, 0x4B, 0x89, 0x32, 0xA1, 0xB6, 0xC3, 0xDC, 0x7E, -0xED, 0xC3, 0xC3, 0x75, 0xB3, 0x57, 0x8B, 0x3D, 0x9B, 0xB8, 0xAE, 0xD5, 0x64, 0x7F, 0xCC, 0xB4, -0xC7, 0x7E, 0xED, 0xD7, 0xE6, 0x87, 0xF3, 0xE6, 0xC0, 0x9C, 0x5A, 0xD4, 0xD5, 0x86, 0x3A, 0xAB, -0x11, 0xC5, 0x34, 0x5C, 0x66, 0x40, 0xC6, 0x9B, 0xAB, 0x3E, 0x53, 0xC7, 0x90, 0xD2, 0x8E, 0x65, -0x36, 0xE8, 0x94, 0xF5, 0x6B, 0x8F, 0x1A, 0x9B, 0x5B, 0xA6, 0xED, 0x46, 0xE8, 0xE7, 0x9A, 0xEA, -0x4E, 0xFA, 0x2A, 0x7B, 0xD4, 0x14, 0xD6, 0xE4, 0x5F, 0xF6, 0x88, 0x66, 0x68, 0xAE, 0x46, 0xF5, -0xA6, 0xA3, 0x50, 0x9D, 0xF5, 0xBB, 0xAD, 0x4E, 0x84, 0x9B, 0xAB, 0xB9, 0x3A, 0x3B, 0xBB, 0x78, -0xFB, 0xF6, 0xEA, 0x92, 0xDC, 0x33, 0x77, 0x66, 0x9D, 0xB6, 0x45, 0x92, 0xF7, 0x5C, 0xD7, 0x8C, -0xCF, 0xC4, 0x66, 0x7A, 0xBF, 0xEE, 0xB8, 0x0B, 0x9D, 0x39, 0x13, 0xC6, 0xDC, 0x3A, 0x99, 0xD8, -0x6C, 0xD4, 0xAF, 0x63, 0x09, 0x9C, 0x93, 0x76, 0x5B, 0x51, 0x8D, 0xDF, 0x9D, 0x96, 0xA2, 0x9B, -0x33, 0x75, 0xA4, 0x53, 0x9B, 0xB5, 0x14, 0x73, 0xDA, 0xA6, 0xBF, 0xD3, 0xA7, 0xB6, 0xAE, 0x0D, -0x9D, 0xF6, 0x08, 0x74, 0x6B, 0xD2, 0x39, 0x73, 0xCC, 0x29, 0x6B, 0x1F, 0xB5, 0xBA, 0x47, 0xAD, -0x83, 0xB6, 0xE2, 0x38, 0x6D, 0xAA, 0xEB, 0xAD, 0xA9, 0x66, 0xB4, 0xE0, 0xEF, 0x3A, 0xE8, 0xE8, -0xB2, 0xB1, 0xAD, 0xB9, 0x0B, 0x10, 0x34, 0xA1, 0x47, 0xDD, 0xFD, 0xA6, 0xF6, 0xA4, 0xBF, 0xFF, -0xFB, 0x4F, 0x4F, 0x7A, 0x8F, 0xFE, 0xDE, 0x1D, 0xFC, 0xD9, 0x99, 0xFE, 0xDF, 0xEF, 0x8B, 0xEB, -0x87, 0x9F, 0xFE, 0xF6, 0xD4, 0x76, 0x76, 0x3F, 0xBC, 0x9A, 0x9B, 0x1D, 0xF3, 0xD5, 0xED, 0xEE, -0xE0, 0xEF, 0xB7, 0x77, 0x3F, 0xFD, 0xBA, 0x3B, 0xFE, 0x93, 0x1D, 0xFC, 0x34, 0xE9, 0x5D, 0xDB, -0x66, 0x7B, 0xFA, 0xB0, 0x78, 0x6B, 0x1F, 0xD9, 0xED, 0x5F, 0x9E, 0x76, 0x67, 0xBF, 0xBC, 0xFE, -0xA9, 0x77, 0xF7, 0x78, 0x37, 0xFA, 0xBB, 0x75, 0xB4, 0xFB, 0xEB, 0xF1, 0x48, 0x7B, 0xFC, 0xE1, -0xF5, 0x79, 0xBF, 0x5F, 0x27, 0x8A, 0x6D, 0x3A, 0x8E, 0x69, 0x6B, 0x63, 0xCD, 0xE8, 0xD7, 0xA9, -0x61, 0x1A, 0x8B, 0xA9, 0x39, 0x03, 0x1D, 0xA0, 0x50, 0xCC, 0xB6, 0x99, 0x6D, 0x99, 0xBA, 0xA6, -0x80, 0x22, 0x86, 0xD9, 0xF4, 0x93, 0xEA, 0xA1, 0xC5, 0xB8, 0x1D, 0xBC, 0x2F, 0xF8, 0x39, 0xB1, -0x4D, 0xD3, 0x25, 0xFF, 0x0C, 0x13, 0xF0, 0xD3, 0x6C, 0x2A, 0xA6, 0x6E, 0xDA, 0xCD, 0xA1, 0x4E, -0x95, 0xCF, 0x27, 0x84, 0xFF, 0x7A, 0x93, 0x4E, 0xA2, 0x98, 0x6A, 0x73, 0x6C, 0xD3, 0xC5, 0x09, -0xF9, 0xBA, 0xDB, 0xC1, 0x7F, 0x19, 0x74, 0xF3, 0x89, 0xE6, 0xB2, 0x13, 0xC2, 0x7F, 0x65, 0x90, -0x80, 0xAA, 0xA6, 0x7D, 0x42, 0xEC, 0xF1, 0xB0, 0xD1, 0x3D, 0xEE, 0xEE, 0x91, 0xE3, 0x23, 0xFC, -0x7F, 0x27, 0x83, 0xDA, 0xB2, 0xB5, 0x29, 0xB5, 0x51, 0xEE, 0x61, 0xEF, 0x30, 0x42, 0xF3, 0xE5, -0xAF, 0x7F, 0x09, 0xBF, 0x7C, 0x27, 0x97, 0x0C, 0xB2, 0x80, 0xDD, 0x4E, 0x88, 0xAC, 0xA6, 0x45, -0x55, 0x55, 0x33, 0xC6, 0xC9, 0x07, 0x43, 0xF3, 0xA9, 0xE9, 0x68, 0x7F, 0xF2, 0x67, 0x43, 0xD3, -0x56, 0x19, 0x58, 0xC5, 0x7C, 0xCA, 0x92, 0x37, 0x34, 0xD5, 0x85, 0x2C, 0x72, 0xC2, 0xB4, 0xF1, -0xC4, 0x3D, 0x21, 0xDD, 0x4E, 0xE7, 0x71, 0x22, 0x71, 0x57, 0x35, 0xC7, 0xD2, 0xD1, 0x78, 0x23, -0x9D, 0x3D, 0x49, 0xCF, 0x7E, 0x9F, 0x39, 0xAE, 0x36, 0x5A, 0x34, 0xBD, 0xC6, 0x71, 0x42, 0x14, -0xF8, 0xC9, 0x6C, 0x89, 0x8A, 0xEA, 0xDA, 0xD8, 0x68, 0x82, 0x51, 0xA7, 0x4E, 0x06, 0xC5, 0x10, -0x2A, 0x6F, 0x6C, 0x9B, 0x33, 0x43, 0x15, 0x96, 0x3B, 0x21, 0x8F, 0xD4, 0x6E, 0xC4, 0xAA, 0x58, -0xB6, 0xB1, 0xF9, 0xC8, 0xEC, 0x91, 0x6E, 0xCE, 0x4F, 0xC8, 0x44, 0x53, 0x55, 0x66, 0x48, 0x8F, -0x79, 0x93, 0x18, 0xD1, 0xA9, 0xA6, 0x83, 0xE6, 0xE7, 0x36, 0x34, 0xCE, 0x3D, 0xE2, 0x50, 0xC3, -0x69, 0x3A, 0xCC, 0xD6, 0x46, 0x59, 0xB6, 0x51, 0xA8, 0xF1, 0x48, 0x1D, 0xD9, 0x3A, 0x96, 0xE9, -0x40, 0xF3, 0x36, 0xA1, 0x4A, 0xE8, 0xD0, 0x31, 0xF5, 0x59, 0x02, 0x1D, 0xAE, 0x69, 0x25, 0x6B, -0x45, 0x67, 0x23, 0x37, 0x99, 0xCA, 0x1D, 0x06, 0x37, 0xF4, 0x37, 0x6F, 0x32, 0xEB, 0x40, 0x7E, -0xF4, 0x67, 0x53, 0x33, 0x54, 0xF6, 0x04, 0xCF, 0xE2, 0x8A, 0xFB, 0x7F, 0xB6, 0xD0, 0xFE, 0x54, -0x33, 0x98, 0x2D, 0xAB, 0x9E, 0x57, 0x79, 0x98, 0xD4, 0x54, 0x35, 0x9B, 0x29, 0xA2, 0x70, 0x60, -0xEC, 0xD9, 0x54, 0xB6, 0xE3, 0xBA, 0x6A, 0xD8, 0x2F, 0x1D, 0x38, 0x48, 0xA5, 0x81, 0x45, 0x24, -0x4D, 0x2C, 0xA9, 0xF5, 0x24, 0xD7, 0x6B, 0x50, 0xD6, 0xFD, 0x8C, 0xB2, 0xEA, 0xE6, 0xD8, 0x6C, -0x56, 0x2A, 0x70, 0xBE, 0x96, 0xB2, 0x0C, 0x99, 0x73, 0x58, 0x73, 0x96, 0xCC, 0x38, 0x52, 0x75, -0x89, 0x67, 0xA2, 0x35, 0x37, 0x6D, 0x41, 0xB1, 0x1F, 0x27, 0x48, 0x94, 0xCB, 0x65, 0x4F, 0x09, -0x4F, 0xC7, 0xA1, 0x0C, 0xED, 0x1B, 0x5C, 0xD3, 0xC1, 0xAB, 0x04, 0x7F, 0xFE, 0x74, 0xEE, 0x29, -0x30, 0x34, 0x75, 0x55, 0x7A, 0xEE, 0xB5, 0xA7, 0x34, 0xA7, 0xE6, 0xB8, 0xB6, 0xF9, 0x99, 0x25, -0x7D, 0x67, 0x54, 0xAB, 0x91, 0x69, 0x4F, 0xB3, 0xAD, 0x1D, 0x36, 0x42, 0x3A, 0x73, 0xCD, 0xA5, -0x8D, 0x3A, 0x4D, 0x89, 0xC0, 0xAB, 0xED, 0x27, 0x6D, 0xE7, 0x39, 0x33, 0x9B, 0xAA, 0xDA, 0xCC, -0x41, 0xF3, 0xA6, 0x50, 0x80, 0xEB, 0x9B, 0x50, 0x15, 0x55, 0xE8, 0xC0, 0x3F, 0x24, 0x41, 0xEF, -0x4C, 0x1B, 0x9D, 0x3D, 0xE2, 0xFD, 0xD7, 0x3A, 0x90, 0x31, 0xD6, 0xFE, 0xCE, 0xAF, 0xCD, 0x63, -0x68, 0x6B, 0xE4, 0xBB, 0x76, 0x6A, 0x95, 0xF1, 0x56, 0x9D, 0x5D, 0x61, 0x3A, 0x1D, 0x32, 0x3D, -0x13, 0x7E, 0x43, 0xDD, 0x4C, 0xF4, 0x47, 0xD9, 0x6D, 0xDF, 0x93, 0x38, 0x34, 0x5D, 0xD7, 0x9C, -0x9E, 0x90, 0xA3, 0xD2, 0xB5, 0x1C, 0xC1, 0x48, 0x37, 0x89, 0x11, 0xCF, 0xFC, 0x5F, 0x1F, 0x1C, -0x1C, 0xA4, 0x97, 0x45, 0x33, 0xAC, 0x99, 0xFB, 0x0F, 0x77, 0x61, 0xB1, 0x7E, 0x1D, 0x21, 0x58, -0xFF, 0x2D, 0x1B, 0xFD, 0xB2, 0xEE, 0x41, 0x05, 0xA6, 0x56, 0x4F, 0xAC, 0x02, 0x93, 0xE5, 0x12, -0x04, 0x90, 0x17, 0xAA, 0x0D, 0x5C, 0xAB, 0xA6, 0x92, 0xAF, 0x15, 0x45, 0xC9, 0xB7, 0x4E, 0x0A, -0x50, 0xB2, 0x8B, 0x9F, 0x51, 0x48, 0x67, 0x36, 0x9C, 0x6A, 0x29, 0xC5, 0x4C, 0x62, 0xF6, 0xEB, -0xC3, 0xC1, 0xF9, 0xF5, 0x91, 0xEC, 0xC6, 0x8B, 0x00, 0x7A, 0x15, 0x7B, 0x40, 0xC8, 0x24, 0xF3, -0x55, 0x66, 0xB6, 0x83, 0x32, 0x2D, 0x53, 0x4B, 0xF1, 0xAF, 0x39, 0x98, 0xCD, 0x37, 0x50, 0xF0, -0x34, 0x03, 0x5D, 0x11, 0x03, 0x0E, 0x67, 0x50, 0x01, 0xC6, 0xFF, 0x4C, 0x56, 0xC2, 0x64, 0x2D, -0xD7, 0x1C, 0x8F, 0x75, 0xB6, 0x89, 0xFE, 0x2A, 0x52, 0x04, 0xBF, 0x65, 0x74, 0xB3, 0x7B, 0x17, -0x4F, 0x8F, 0x54, 0xA7, 0x15, 0xEF, 0xA2, 0x96, 0x33, 0x71, 0xE6, 0x9A, 0xAB, 0x4C, 0xB2, 0xA3, -0x24, 0x18, 0xCC, 0xC0, 0x28, 0xEB, 0x51, 0xAE, 0x8D, 0xA0, 0xA8, 0x9A, 0x01, 0x63, 0x1E, 0xD6, -0xCC, 0x71, 0x91, 0xAF, 0xB2, 0xFB, 0xD8, 0x83, 0xC3, 0x82, 0xEA, 0xF1, 0xE6, 0x9E, 0xE8, 0xB0, -0x2C, 0xAA, 0xC0, 0x10, 0x28, 0x33, 0x2E, 0x93, 0x93, 0x7D, 0xA9, 0x9D, 0x0C, 0x91, 0x0E, 0xB8, -0xAC, 0x64, 0xA5, 0x2E, 0x0D, 0x18, 0xF3, 0x81, 0x59, 0x22, 0x9C, 0xB4, 0x93, 0xEA, 0xE1, 0xC7, -0x07, 0x44, 0x22, 0x3D, 0xD9, 0x56, 0x93, 0xEE, 0x16, 0x60, 0x3D, 0xFC, 0xAC, 0xB9, 0x4D, 0xD7, -0x86, 0x78, 0xD9, 0x2B, 0x47, 0xEB, 0xD0, 0x91, 0x95, 0xCC, 0x7D, 0x2A, 0xB5, 0xDA, 0x9C, 0x4A, -0x13, 0x16, 0x3C, 0x19, 0x32, 0x88, 0x34, 0x58, 0x79, 0x43, 0xFA, 0x61, 0x69, 0xBD, 0x9E, 0x51, -0x73, 0xFB, 0xC9, 0xB6, 0xEB, 0xD5, 0x75, 0xCA, 0x13, 0x61, 0xE4, 0xC3, 0x14, 0x1F, 0x23, 0xEC, -0x99, 0xF2, 0xA4, 0x50, 0x90, 0xB3, 0x01, 0x93, 0x1E, 0xC5, 0x3A, 0x62, 0xB9, 0x9B, 0x3B, 0x51, -0x26, 0x4C, 0xF9, 0xCC, 0x54, 0xB2, 0x9B, 0x85, 0xD1, 0x14, 0x28, 0xEC, 0x77, 0x8F, 0x5F, 0x5D, -0xE7, 0x45, 0x08, 0x27, 0x23, 0x53, 0x99, 0x39, 0x39, 0x3C, 0xE5, 0x68, 0x0C, 0x7A, 0xF5, 0x02, -0x5C, 0x13, 0xBA, 0x66, 0xA0, 0x21, 0x66, 0x45, 0x0C, 0x4C, 0x4F, 0x84, 0xC9, 0xC0, 0xDB, 0xB0, -0x5F, 0x1B, 0x58, 0x9D, 0x89, 0x81, 0xF8, 0xD4, 0x29, 0x41, 0x5D, 0x8C, 0x32, 0x23, 0xA2, 0x80, -0x0C, 0x63, 0x56, 0x26, 0x6E, 0xCA, 0x8F, 0x6A, 0x3C, 0x29, 0xA7, 0x6D, 0x7F, 0x32, 0xE4, 0xB4, -0xED, 0xCD, 0x7D, 0x9D, 0xE2, 0x00, 0xDE, 0x9F, 0x2A, 0xF1, 0x06, 0xAC, 0x9A, 0xDA, 0xAF, 0x59, -0xD4, 0x76, 0x35, 0x45, 0x67, 0x03, 0x9E, 0x54, 0x23, 0x3C, 0x63, 0xBF, 0x16, 0xD6, 0xB3, 0x98, -0xB6, 0xD8, 0xEF, 0xEC, 0xF5, 0x3A, 0x7B, 0x87, 0xC7, 0x3B, 0x6F, 0x6A, 0x67, 0xA7, 0x6D, 0x91, -0xFF, 0xCC, 0x1F, 0x03, 0x9F, 0xAA, 0xDA, 0x23, 0x51, 0x74, 0xEA, 0x38, 0xFD, 0x7A, 0xD0, 0x65, -0xD5, 0x23, 0x53, 0x31, 0x51, 0x82, 0xF8, 0x40, 0x2C, 0x4A, 0xC5, 0x29, 0xB5, 0xE9, 0x38, 0x4A, -0x59, 0x27, 0x8E, 0xAD, 0x84, 0x33, 0x5A, 0x36, 0x9D, 0xB7, 0xC6, 0x9A, 0x3B, 0x99, 0x0D, 0x67, -0x30, 0x22, 0xF7, 0x9A, 0x31, 0x9F, 0xD6, 0xBA, 0x9C, 0x81, 0xF7, 0xBE, 0x64, 0x8F, 0x4C, 0x37, -0xAD, 0x36, 0x9F, 0x36, 0x1B, 0xC0, 0x53, 0xDB, 0xD4, 0x75, 0x66, 0xB7, 0xA7, 0x20, 0xAB, 0x0D, -0x8C, 0xDA, 0xF3, 0xF9, 0xBC, 0x7D, 0x03, 0xD9, 0x9A, 0xCE, 0x1F, 0x33, 0x9C, 0x10, 0xB3, 0x8C, -0x71, 0x1D, 0x3A, 0x4C, 0xB7, 0x5F, 0x7F, 0x8B, 0xC2, 0x64, 0x65, 0x1C, 0x8B, 0x1A, 0x31, 0xBD, -0x79, 0x94, 0xEB, 0xCD, 0xCA, 0x85, 0xFC, 0xC1, 0xDC, 0x40, 0x18, 0x2D, 0x6F, 0x1B, 0x0A, 0x9C, -0x51, 0xFE, 0xF8, 0xD0, 0x28, 0x21, 0x72, 0xD2, 0x05, 0xF6, 0x24, 0xCE, 0x1F, 0x27, 0x00, 0x5D, -0x88, 0x74, 0x1C, 0x72, 0x4B, 0xC7, 0x0C, 0xAA, 0xB4, 0x9B, 0xC8, 0xB5, 0xCF, 0x2B, 0x73, 0xA4, -0xD9, 0xD3, 0x39, 0x94, 0x0B, 0xC6, 0x57, 0x0E, 0xF8, 0x83, 0xDA, 0xD9, 0xB5, 0x97, 0x40, 0xBC, -0x94, 0x13, 0xF2, 0xFD, 0xF7, 0x2D, 0xFE, 0x1F, 0x70, 0xD9, 0x97, 0xB9, 0x58, 0x67, 0x0F, 0x13, -0xCD, 0x81, 0xB8, 0x6A, 0xCC, 0xC0, 0x28, 0x30, 0x40, 0x73, 0xC8, 0xC2, 0x9C, 0x41, 0xC7, 0x82, -0xF3, 0xA5, 0x80, 0x53, 0xE2, 0x4E, 0x18, 0x79, 0xF7, 0xB7, 0x87, 0x07, 0x32, 0xC4, 0x21, 0xA0, -0x0D, 0x48, 0x1E, 0x99, 0x84, 0x1A, 0x2A, 0xFC, 0xBF, 0x20, 0x18, 0x8D, 0xA1, 0x17, 0xA2, 0x3A, -0x71, 0x3C, 0x7D, 0x5B, 0xA7, 0x6D, 0x4B, 0x16, 0x82, 0xE5, 0x27, 0x53, 0xE6, 0x4E, 0x4C, 0xB5, -0x5F, 0xBF, 0x7D, 0x7F, 0xFF, 0x00, 0x15, 0xC0, 0xA7, 0x12, 0xFA, 0xF5, 0xB6, 0x88, 0xAF, 0xA1, -0xE0, 0x23, 0x0D, 0xEA, 0xC5, 0x34, 0xC4, 0x77, 0x68, 0x25, 0xCC, 0x9D, 0xD9, 0x06, 0x11, 0x5F, -0xAF, 0x81, 0x41, 0x63, 0xE7, 0x8D, 0x6C, 0x39, 0xCE, 0x5C, 0x04, 0x2A, 0x20, 0xA2, 0x5F, 0xD7, -0xAC, 0xFA, 0xD9, 0xAD, 0xCD, 0x3B, 0x4A, 0x72, 0x73, 0x7B, 0x72, 0xDA, 0xE6, 0xCF, 0xD2, 0x32, -0x89, 0x2E, 0x3F, 0x32, 0x8C, 0x41, 0x5B, 0x62, 0x7E, 0x31, 0x9B, 0xCB, 0xFF, 0xE2, 0x73, 0xAF, -0xFD, 0xFA, 0x15, 0x67, 0x87, 0x66, 0xB8, 0xB9, 0xC5, 0x02, 0xDB, 0xCC, 0x71, 0x88, 0x39, 0x42, -0x33, 0xD9, 0xE4, 0x82, 0x4E, 0x87, 0x33, 0x90, 0x42, 0x3C, 0xB1, 0x75, 0xF2, 0x48, 0xF5, 0x19, -0xE4, 0xAA, 0x9F, 0x9D, 0x0E, 0xED, 0x25, 0xEA, 0x2A, 0xA6, 0xCA, 0x42, 0x85, 0xCF, 0x15, 0x05, -0x39, 0x0F, 0x20, 0xB1, 0xBC, 0xE6, 0x9C, 0x95, 0xA7, 0xBB, 0xF8, 0x3B, 0xA1, 0x3D, 0x15, 0xFC, -0xF1, 0xE9, 0x7A, 0xD4, 0xD7, 0xD4, 0x50, 0xF9, 0x7B, 0x86, 0x13, 0x67, 0xE4, 0xE7, 0xD9, 0x74, -0x08, 0x4E, 0xB9, 0xBC, 0xE1, 0xD5, 0xC0, 0xF0, 0x6A, 0x8A, 0xEA, 0x4E, 0x94, 0x3B, 0x0A, 0x5F, -0x83, 0xF6, 0xD4, 0x7A, 0x77, 0x3E, 0xA8, 0x9F, 0x7D, 0xD4, 0x46, 0x9A, 0x6F, 0xFA, 0x5B, 0x8C, -0xB1, 0x08, 0x24, 0x93, 0x73, 0x51, 0xCD, 0x79, 0x05, 0x71, 0xE9, 0x50, 0x67, 0xC2, 0x69, 0xF7, -0xEB, 0xE8, 0xB4, 0xD3, 0xC0, 0xC9, 0x29, 0x1F, 0xEE, 0x32, 0x9E, 0x08, 0x3E, 0xAA, 0xC7, 0xA4, -0xB6, 0xDF, 0xF9, 0xA6, 0x96, 0x43, 0x99, 0x63, 0x3E, 0x51, 0x16, 0xCF, 0x82, 0xDE, 0x97, 0x84, -0x11, 0xB1, 0x5C, 0x32, 0x7C, 0x1D, 0x8B, 0x29, 0x60, 0x00, 0x25, 0x66, 0x81, 0xD0, 0x8C, 0xD0, -0xF3, 0x3C, 0xE9, 0xCC, 0x18, 0xF3, 0x22, 0xBE, 0x06, 0xBF, 0x0C, 0x63, 0x1C, 0xEF, 0x2F, 0xD1, -0x65, 0xF8, 0xF1, 0x11, 0xCE, 0x66, 0xE5, 0xE9, 0x7E, 0xDA, 0x76, 0xD5, 0x42, 0x46, 0xA8, 0xEF, -0x1F, 0x02, 0x2B, 0xA8, 0x3F, 0x8B, 0x3B, 0xB7, 0x39, 0x28, 0x77, 0xEF, 0xDA, 0x5C, 0x05, 0xEC, -0x84, 0xAC, 0xB3, 0xE5, 0x9C, 0x96, 0x99, 0x30, 0xE2, 0x97, 0xE5, 0x21, 0x57, 0x56, 0x15, 0xC6, -0xF2, 0x0B, 0x0C, 0xC5, 0x39, 0x88, 0x81, 0x44, 0x91, 0xEC, 0x9C, 0x45, 0xB4, 0x16, 0x79, 0x48, -0x03, 0xE1, 0x90, 0xA8, 0x49, 0xA8, 0x1D, 0xE8, 0x68, 0x3F, 0x6A, 0xD7, 0xDA, 0xCF, 0xCC, 0x9D, -0x9B, 0xF6, 0x67, 0xBF, 0x56, 0x93, 0x0F, 0x8A, 0x0A, 0x8B, 0x76, 0x68, 0x22, 0x68, 0x02, 0xF3, -0xCA, 0xBD, 0x57, 0x66, 0xEE, 0xCC, 0x06, 0x20, 0x7F, 0xBE, 0x35, 0x86, 0x8E, 0xF5, 0x26, 0xFA, -0x33, 0x26, 0x39, 0x3A, 0xAA, 0x04, 0xB7, 0xC1, 0x6C, 0xDE, 0x27, 0x18, 0x6C, 0x4E, 0x78, 0x0B, -0x34, 0x44, 0xA1, 0x08, 0x16, 0xF2, 0xF4, 0xE2, 0xEE, 0xAC, 0x71, 0xC7, 0xA0, 0x43, 0x71, 0xB0, -0x1F, 0xC2, 0xB9, 0x47, 0xE8, 0x88, 0x1C, 0x97, 0x5C, 0xDC, 0xDF, 0xDF, 0x5C, 0xEE, 0x14, 0xD2, -0x5D, 0xEE, 0x8D, 0x93, 0xCF, 0x33, 0x81, 0x72, 0xDA, 0x4E, 0x6D, 0xB0, 0x90, 0x03, 0x5B, 0xFC, -0x32, 0x9F, 0xE6, 0x4D, 0x17, 0xF9, 0x4D, 0xE8, 0x9E, 0x3E, 0x32, 0x22, 0x3A, 0xB7, 0x99, 0x4D, -0xB1, 0xCB, 0x03, 0xE3, 0x5F, 0xA4, 0xF2, 0x4F, 0x4F, 0x8D, 0x78, 0xAC, 0x21, 0x1F, 0xC2, 0x19, -0xD0, 0x4E, 0xBD, 0x6A, 0xE4, 0x4D, 0x44, 0x4E, 0xBD, 0x14, 0x63, 0xE7, 0xDA, 0xD9, 0x45, 0xF0, -0x40, 0x04, 0x95, 0xC5, 0x9C, 0x72, 0x8D, 0x47, 0xA7, 0xB5, 0x54, 0xD6, 0x35, 0x6F, 0xA9, 0x33, -0x99, 0x3E, 0xD5, 0x8C, 0x7E, 0xAD, 0x53, 0x43, 0x7F, 0xD1, 0xAF, 0x81, 0xB0, 0x9A, 0x57, 0x7E, -0xFE, 0xF7, 0x32, 0xEF, 0x89, 0x44, 0x99, 0x9E, 0x6F, 0x89, 0xF7, 0xFC, 0xAA, 0xD9, 0x04, 0xF3, -0xE2, 0x6A, 0x04, 0x79, 0x6F, 0xB0, 0x66, 0x33, 0x8F, 0xF6, 0xE1, 0x12, 0xB5, 0xD2, 0xC6, 0xA0, -0x2A, 0x8C, 0x9B, 0x6B, 0xBE, 0xF4, 0xC3, 0x63, 0x2E, 0x3C, 0xBA, 0xB8, 0x93, 0x9A, 0x7D, 0x72, -0xE0, 0x7B, 0x3D, 0x74, 0xBC, 0x4D, 0xCE, 0x29, 0x98, 0x6C, 0xF1, 0xE6, 0xAC, 0xC4, 0x88, 0x2E, -0x39, 0x62, 0xC2, 0x70, 0xFA, 0xF5, 0xAB, 0x3D, 0xD2, 0x7D, 0x7D, 0xB4, 0x47, 0x7A, 0x1D, 0x8C, -0xA8, 0x31, 0xDC, 0xBB, 0x60, 0x13, 0xFA, 0xA8, 0xA1, 0x23, 0x6E, 0x0C, 0x26, 0xA6, 0xE9, 0x30, -0x2C, 0x04, 0x00, 0x7C, 0x72, 0xF0, 0xA2, 0x9D, 0x18, 0x86, 0xDE, 0xEE, 0xBB, 0x48, 0x44, 0x12, -0x49, 0x10, 0x22, 0x6B, 0x50, 0x7A, 0xAF, 0xF0, 0x80, 0x1E, 0xD3, 0x10, 0xB1, 0x26, 0xB4, 0x1E, -0xA6, 0x33, 0xC5, 0x7D, 0x6F, 0xE8, 0x0B, 0x30, 0x44, 0xC3, 0x85, 0xC8, 0x74, 0xE7, 0x8D, 0x33, -0x31, 0xC1, 0xAC, 0x2A, 0x7B, 0x6F, 0x61, 0xF3, 0x71, 0x32, 0xC2, 0xC0, 0x54, 0x15, 0xB7, 0xD1, -0xF5, 0xBD, 0x43, 0x5B, 0x30, 0x83, 0x1A, 0x0A, 0x74, 0xC9, 0x18, 0x8B, 0x35, 0xCE, 0xF5, 0x39, -0x5D, 0x38, 0x50, 0xF5, 0xEB, 0x71, 0x6D, 0x9C, 0x66, 0xAB, 0xF1, 0xA1, 0x6A, 0x8E, 0x62, 0x46, -0xF1, 0x11, 0x49, 0x58, 0x0F, 0x3E, 0xC8, 0x0B, 0x06, 0xC8, 0xDD, 0x0F, 0x17, 0xE8, 0xD2, 0x20, -0xC8, 0x1D, 0x2C, 0x60, 0x90, 0xFE, 0xDF, 0x0A, 0x12, 0x9B, 0x59, 0xBA, 0xA6, 0x50, 0x97, 0xBD, -0x65, 0xEA, 0xBD, 0x0B, 0xBF, 0xC3, 0x48, 0x28, 0xF1, 0xE0, 0xBF, 0xDE, 0xA9, 0xDC, 0xF9, 0x36, -0xE1, 0xB3, 0x08, 0xDC, 0x2A, 0xC5, 0x55, 0x42, 0x18, 0x60, 0x77, 0x6F, 0xCF, 0x0C, 0x03, 0x46, -0xF0, 0xBC, 0xC7, 0x52, 0x26, 0xA6, 0xA6, 0xB0, 0x65, 0xC3, 0x91, 0x80, 0x45, 0x34, 0x80, 0xE0, -0xF9, 0x6B, 0xA2, 0x0E, 0x05, 0x47, 0x40, 0x74, 0x50, 0x79, 0x91, 0x14, 0x2F, 0x44, 0xFA, 0xBA, -0xC3, 0x3F, 0x45, 0xED, 0x2F, 0x6C, 0xF1, 0xF1, 0xA3, 0x67, 0x13, 0x21, 0x39, 0xD9, 0x31, 0xFB, -0xFD, 0xB2, 0x37, 0xB9, 0xCB, 0xE7, 0xCC, 0xFC, 0x29, 0xB6, 0xC3, 0x03, 0x18, 0xAD, 0x78, 0xDA, -0x1A, 0x7C, 0x4C, 0x89, 0x73, 0x60, 0xCC, 0xEA, 0x77, 0x79, 0x00, 0xB3, 0x7F, 0x74, 0xC4, 0x03, -0x9A, 0x4E, 0xB4, 0x0C, 0x1F, 0x3F, 0x4A, 0x45, 0xC0, 0x04, 0xAF, 0x04, 0x90, 0xA1, 0x9C, 0xF6, -0x83, 0xE7, 0xD6, 0x7E, 0x20, 0x6B, 0x3F, 0x28, 0xAD, 0x7D, 0x21, 0x8F, 0xE2, 0xD1, 0xBC, 0x64, -0xBF, 0x83, 0x9E, 0xC1, 0x85, 0xD1, 0x06, 0x87, 0xB1, 0x6F, 0x35, 0x29, 0xF1, 0x3F, 0xD1, 0xDF, -0x94, 0xC1, 0x6F, 0x41, 0xAF, 0xF4, 0x80, 0x83, 0x36, 0x31, 0xAD, 0x09, 0x66, 0x73, 0x48, 0xE9, -0x5E, 0x8C, 0x97, 0xC0, 0x77, 0x4F, 0x81, 0xFD, 0xD7, 0xE3, 0x9B, 0x90, 0x5D, 0xC4, 0x31, 0x05, -0x5F, 0x7D, 0xAF, 0x74, 0x70, 0x7D, 0x30, 0xB8, 0xBE, 0xD8, 0x56, 0xAF, 0x84, 0xEA, 0x86, 0x2E, -0xC9, 0xFF, 0xE6, 0xE9, 0xDE, 0x2D, 0xEB, 0x4D, 0x9F, 0xCF, 0x1F, 0xA1, 0xA6, 0x83, 0x98, 0xDE, -0x83, 0xD2, 0x7A, 0xAF, 0xD1, 0x13, 0x89, 0x61, 0xA8, 0xBF, 0xFE, 0x21, 0x96, 0xCD, 0x1C, 0x5C, -0xF8, 0x35, 0xC6, 0x27, 0x9D, 0x5A, 0x91, 0xF1, 0x69, 0x8C, 0x5D, 0xEE, 0x58, 0x35, 0x4E, 0x19, -0x8E, 0x45, 0xA7, 0x9A, 0xAA, 0xEA, 0x85, 0xE1, 0xCC, 0x73, 0xAF, 0xE8, 0x40, 0x63, 0xBC, 0x56, -0x77, 0xA6, 0x31, 0x76, 0x39, 0x51, 0x3F, 0x1B, 0xCE, 0xC6, 0x38, 0xA1, 0x17, 0x44, 0xFD, 0x61, -0xC2, 0x73, 0x3A, 0xD4, 0x98, 0xBA, 0x2B, 0x39, 0xD7, 0x18, 0xA7, 0xC2, 0x8E, 0x36, 0xFA, 0x29, -0xE5, 0x4E, 0xEF, 0xA1, 0xC8, 0x62, 0xB6, 0xCC, 0x9F, 0x12, 0x25, 0x8F, 0x1A, 0x45, 0x07, 0xEB, -0x94, 0x56, 0xB9, 0x48, 0x1B, 0x0A, 0x69, 0x1F, 0x2E, 0x2B, 0xE0, 0x9A, 0xCF, 0xB1, 0x78, 0xC3, -0x3D, 0x9C, 0x91, 0xFA, 0x18, 0x99, 0xCB, 0xF5, 0x27, 0x90, 0xFD, 0x67, 0x27, 0xB8, 0x25, 0xA7, -0x4C, 0x05, 0x2E, 0x69, 0xB9, 0x65, 0x2B, 0xEF, 0xE1, 0xCE, 0x67, 0x15, 0x9D, 0xC7, 0x49, 0x59, -0xF8, 0x3E, 0xE8, 0xE0, 0xBF, 0x37, 0x29, 0x33, 0x40, 0x65, 0x65, 0xFA, 0xE6, 0xF2, 0x7C, 0xCC, -0x6B, 0x3E, 0x83, 0x7E, 0x7A, 0x71, 0x76, 0x77, 0x7F, 0x7F, 0x73, 0xDA, 0xBE, 0x38, 0xE3, 0x56, -0x07, 0x82, 0x33, 0x0F, 0x24, 0x24, 0x48, 0x00, 0xA2, 0x7B, 0x90, 0x4C, 0xF5, 0x00, 0x07, 0x01, -0x7D, 0x59, 0xCC, 0x16, 0x76, 0x58, 0xA1, 0xC6, 0x77, 0xC9, 0xE5, 0xE2, 0xC0, 0x3A, 0x9D, 0xCE, -0x68, 0xD4, 0xE9, 0xE0, 0x72, 0x31, 0x14, 0x2C, 0x7B, 0xB2, 0xAC, 0x76, 0xD6, 0x3C, 0xE8, 0xE0, -0xD4, 0x6E, 0xF3, 0xA8, 0xE3, 0x97, 0x2A, 0x98, 0xFF, 0xE7, 0xD3, 0xFF, 0x89, 0x32, 0x5F, 0x3D, -0x29, 0x4C, 0xD7, 0x21, 0xBB, 0x48, 0x41, 0xC5, 0x0B, 0x46, 0x2C, 0xC5, 0x34, 0xA7, 0x74, 0x34, -0xA2, 0xB4, 0x88, 0xE6, 0x47, 0x5D, 0xAE, 0xF9, 0xAB, 0x4E, 0x76, 0x05, 0xFD, 0x60, 0x9A, 0xEA, -0x86, 0xF4, 0x1C, 0x8D, 0x8A, 0x5A, 0xF8, 0x95, 0xD0, 0xF3, 0x75, 0x8E, 0x9E, 0xD7, 0x54, 0xB3, -0x37, 0xA6, 0x67, 0xAF, 0x57, 0x4C, 0xCF, 0xD7, 0x42, 0xCF, 0x5E, 0x8E, 0x9E, 0xB7, 0xA6, 0xB9, -0x39, 0x3D, 0x71, 0xEC, 0x59, 0x40, 0xCF, 0x6F, 0x75, 0xF7, 0x4D, 0xBE, 0x96, 0x1F, 0x0C, 0x9B, -0xE9, 0x1A, 0xBA, 0xA5, 0x50, 0xD7, 0x32, 0x0E, 0x39, 0x6B, 0x79, 0x21, 0x9D, 0xBA, 0x50, 0x63, -0x2F, 0xA0, 0x43, 0x28, 0xF7, 0xB9, 0x27, 0xC0, 0xBD, 0x9E, 0xBB, 0xC8, 0x6C, 0x77, 0xAE, 0xB3, -0x7F, 0x13, 0x6C, 0x0A, 0xED, 0x42, 0x54, 0x5A, 0x30, 0x4E, 0x8B, 0xF5, 0x52, 0x25, 0x3A, 0xB7, -0x60, 0xA9, 0x76, 0xC9, 0x82, 0x67, 0x22, 0xEF, 0x8B, 0x0C, 0xD9, 0x46, 0x9A, 0xA1, 0x39, 0x93, -0x1B, 0x43, 0xC5, 0xB9, 0x25, 0x5C, 0xBB, 0xF2, 0x22, 0xB7, 0x64, 0x7A, 0x34, 0x58, 0x73, 0xAF, -0xF9, 0x63, 0x3E, 0xE8, 0x6B, 0xEC, 0x14, 0x9E, 0x8C, 0x8D, 0xE9, 0xF4, 0x92, 0xE2, 0x32, 0x51, -0x5C, 0x12, 0x9A, 0x63, 0x8B, 0xA2, 0xB1, 0xB2, 0x10, 0x15, 0x3B, 0x8A, 0xB0, 0x3C, 0x15, 0x86, -0xDA, 0x01, 0xA7, 0x8C, 0x21, 0xF7, 0x28, 0xC4, 0x45, 0x1C, 0x49, 0x5E, 0x52, 0x38, 0x21, 0x78, -0x7D, 0x5D, 0x7C, 0x08, 0xEB, 0x7F, 0x9E, 0x7B, 0x08, 0x2E, 0x54, 0x0F, 0x07, 0xE1, 0xE1, 0x77, -0xAF, 0x1C, 0x15, 0x4B, 0xF0, 0x7C, 0x83, 0x71, 0xCF, 0xF8, 0x52, 0x09, 0x06, 0x15, 0x4B, 0xB0, -0x01, 0x10, 0x17, 0xEC, 0x43, 0xCB, 0x79, 0xFC, 0x72, 0xE3, 0xED, 0x95, 0xDA, 0x10, 0x33, 0x54, -0xD1, 0x82, 0xF8, 0x66, 0x9C, 0xDA, 0xAA, 0x83, 0x1E, 0xFC, 0x5C, 0x3D, 0x69, 0x2E, 0xF1, 0x3C, -0x0E, 0x1D, 0x01, 0x0E, 0x4E, 0xB6, 0xC1, 0xCD, 0xAC, 0x3A, 0x99, 0x91, 0x62, 0xB2, 0xB5, 0x58, -0x4B, 0x62, 0xAE, 0x42, 0x20, 0x69, 0xF2, 0xB0, 0xA3, 0xD2, 0x68, 0x6D, 0xBD, 0xFD, 0x2E, 0x67, -0xB9, 0xAC, 0xEF, 0xBD, 0x32, 0xD4, 0x4B, 0x53, 0x76, 0x97, 0x41, 0xA2, 0xBF, 0xBD, 0x94, 0xA7, -0x8A, 0x78, 0x2A, 0xB5, 0x2B, 0x46, 0xD0, 0xF8, 0xF3, 0x26, 0x41, 0xF7, 0xCC, 0xAD, 0x5C, 0x66, -0xB5, 0x34, 0xA1, 0xFC, 0xDA, 0x3A, 0x69, 0xCE, 0xAD, 0x52, 0x47, 0x8D, 0x9F, 0x64, 0x67, 0x8D, -0xD6, 0x21, 0xEF, 0x2D, 0x66, 0xB4, 0x07, 0xBA, 0xE9, 0xB0, 0xB2, 0x11, 0x43, 0xF1, 0x56, 0x12, -0xE4, 0x89, 0xE3, 0xCC, 0xD5, 0xA6, 0x6C, 0x2B, 0x81, 0xE6, 0xEF, 0x9F, 0xCF, 0x05, 0xDC, 0x03, -0x6A, 0x9F, 0x40, 0x9C, 0x97, 0xFA, 0x3F, 0xC8, 0xE1, 0x27, 0x09, 0x39, 0x6E, 0x9E, 0xCA, 0xC1, -0xF7, 0xC6, 0x3B, 0x79, 0xAE, 0xDE, 0x3B, 0xCD, 0x70, 0xE2, 0xF5, 0x1A, 0x49, 0x0E, 0xE6, 0xE0, -0xAB, 0x40, 0x0C, 0xC4, 0xCD, 0x5C, 0xE6, 0x6C, 0xB6, 0xA1, 0xFD, 0x7B, 0x02, 0x8C, 0x62, 0x03, -0xF3, 0xED, 0x5E, 0xD3, 0xD4, 0x0C, 0xDC, 0x6E, 0xFF, 0xA8, 0xB9, 0x8B, 0x2B, 0x03, 0x0B, 0x13, -0xEE, 0xB6, 0x4E, 0x3E, 0x08, 0xDB, 0xF2, 0xCC, 0x52, 0xA9, 0xCB, 0x6E, 0xA0, 0x3F, 0xC7, 0x51, -0xDC, 0x76, 0xAD, 0x56, 0x96, 0x1A, 0xA0, 0xDD, 0x04, 0xA5, 0x24, 0x08, 0x78, 0x13, 0xAC, 0xD4, -0x78, 0x27, 0x10, 0x5B, 0x62, 0x1D, 0x32, 0xD6, 0x52, 0x45, 0x4B, 0xC4, 0xBD, 0xCA, 0x6F, 0xFC, -0xF8, 0x84, 0x1F, 0x52, 0xAC, 0x25, 0xB7, 0xB6, 0x07, 0xC2, 0xA3, 0xCD, 0x4F, 0x4E, 0xF5, 0x76, -0x6B, 0x7B, 0x3B, 0xDC, 0xCD, 0x11, 0x64, 0xD5, 0x99, 0xDF, 0xAC, 0x88, 0x77, 0xC8, 0x49, 0x9C, -0x41, 0xC1, 0xF9, 0x7E, 0x82, 0xE7, 0x3B, 0xF0, 0x7C, 0x04, 0xF8, 0x72, 0x73, 0x34, 0x22, 0x61, -0xF3, 0x8D, 0xED, 0xD9, 0x3E, 0xF2, 0xB7, 0x6C, 0x2F, 0x5D, 0xE1, 0x7F, 0xF9, 0xFB, 0x85, 0xF8, -0x6A, 0x92, 0x86, 0x67, 0x7B, 0x22, 0xAB, 0x4B, 0xF8, 0xFD, 0x25, 0x23, 0xF7, 0x12, 0x0B, 0x81, -0xA5, 0xF8, 0x2F, 0xD9, 0xF4, 0xE5, 0x57, 0x9A, 0x70, 0x41, 0x72, 0x55, 0x7A, 0xA9, 0xFF, 0x11, -0x15, 0x4A, 0xDE, 0x1B, 0x03, 0x71, 0xC0, 0xEA, 0xEA, 0x11, 0xBA, 0xFA, 0x62, 0x2B, 0x78, 0x2F, -0xBF, 0x82, 0xA7, 0x7F, 0xB8, 0x2E, 0xAF, 0xCE, 0x60, 0x6B, 0x70, 0x90, 0xF0, 0x92, 0xAB, 0x95, -0x1F, 0x90, 0x7B, 0x6B, 0xAE, 0xAF, 0xA9, 0x2E, 0x89, 0x5F, 0x72, 0x32, 0xE2, 0x8E, 0xF8, 0x7B, -0x8B, 0x2A, 0xD0, 0x8D, 0x88, 0x8D, 0xF1, 0xA5, 0x36, 0xC5, 0xFB, 0xCB, 0x88, 0x4B, 0x04, 0x78, -0x5B, 0xEE, 0x1F, 0xE6, 0xE6, 0x2A, 0x5B, 0xEE, 0xB3, 0xB2, 0xF1, 0xAC, 0x6B, 0x5E, 0x6D, 0xF0, -0x0F, 0xAA, 0x5D, 0x32, 0x18, 0x16, 0xAA, 0x14, 0x17, 0x12, 0x5F, 0xF8, 0x2E, 0x7B, 0xAB, 0x1B, -0x1C, 0x7B, 0x13, 0x4D, 0x29, 0x92, 0x10, 0x06, 0x71, 0x13, 0xEA, 0xDC, 0x76, 0x5F, 0x78, 0xFC, -0x36, 0x30, 0x0D, 0x03, 0xAF, 0x9E, 0x02, 0xAF, 0xE9, 0x9A, 0x84, 0x92, 0xDB, 0xAE, 0x7F, 0xE2, -0xEF, 0x7B, 0xD2, 0xF8, 0xD9, 0x24, 0x7C, 0xB8, 0x7F, 0xCF, 0xED, 0xBA, 0x47, 0xE0, 0xFB, 0x5B, -0x4D, 0xA5, 0xF6, 0xCE, 0x86, 0x5D, 0x29, 0x1F, 0xEE, 0x9F, 0xE3, 0x89, 0x59, 0x14, 0x2F, 0xA4, -0x17, 0x5A, 0x7C, 0xDA, 0x6C, 0x07, 0x1A, 0xE8, 0x12, 0x74, 0x9E, 0x61, 0xCA, 0x4B, 0xC6, 0x40, -0xA4, 0x8E, 0xC9, 0xCC, 0x81, 0xB0, 0x17, 0x4F, 0x81, 0x8A, 0x43, 0xC4, 0x0E, 0x69, 0x00, 0x22, -0x00, 0xE8, 0xC4, 0x30, 0x89, 0xB0, 0x64, 0xA1, 0xCA, 0x2F, 0x7E, 0x08, 0x29, 0x96, 0xB7, 0xD4, -0x26, 0xAF, 0x80, 0xF9, 0x37, 0xB5, 0x32, 0x3B, 0x34, 0xF8, 0x36, 0x8F, 0xC9, 0xE1, 0x6A, 0x1E, -0xB0, 0x7B, 0x08, 0xDE, 0xCF, 0xFF, 0x81, 0x3E, 0xF0, 0xDE, 0xA5, 0x63, 0x18, 0x4D, 0x80, 0x85, -0x26, 0xA2, 0x8D, 0x10, 0xCD, 0x40, 0x63, 0x92, 0x86, 0x06, 0x03, 0x0E, 0xC3, 0x71, 0xA9, 0x0E, -0x43, 0x40, 0x3C, 0x7F, 0x74, 0x58, 0x52, 0xD9, 0x2A, 0xE5, 0x5C, 0xDF, 0xD8, 0x3B, 0x63, 0xB9, -0xC9, 0xC1, 0xE2, 0x76, 0x0F, 0x23, 0x9B, 0x3C, 0xA3, 0x29, 0xE5, 0x76, 0x9F, 0x3F, 0xF7, 0xE2, -0x92, 0xA7, 0x69, 0xB8, 0xBA, 0x14, 0x49, 0x28, 0xBA, 0x38, 0xF3, 0xDC, 0xCB, 0x49, 0x9E, 0x8A, -0x03, 0x59, 0xE7, 0x32, 0x0B, 0x4A, 0xE5, 0xFA, 0x05, 0x9D, 0x51, 0xDC, 0xCC, 0x0E, 0x3E, 0xFF, -0xCF, 0x3F, 0x75, 0xFF, 0xC4, 0x83, 0x38, 0x48, 0xB9, 0x0A, 0x64, 0x12, 0x88, 0x49, 0x00, 0xE6, -0xFC, 0x7C, 0x3B, 0x01, 0x23, 0xE3, 0x65, 0xFB, 0xE1, 0x22, 0xA3, 0x65, 0x63, 0x60, 0xB9, 0x80, -0x3E, 0xE3, 0x2D, 0xDE, 0x15, 0x12, 0x86, 0xE8, 0x2B, 0x23, 0xA5, 0x27, 0x23, 0xA5, 0xF7, 0x52, -0x5C, 0x4B, 0x4F, 0x42, 0x4A, 0x6F, 0xEB, 0x91, 0xD2, 0x93, 0x90, 0xD2, 0xDB, 0x9C, 0x5B, 0x01, -0xF5, 0x87, 0x78, 0x58, 0x1B, 0x3C, 0xCB, 0xD5, 0x93, 0x6B, 0xCF, 0x9C, 0x70, 0x4F, 0xC7, 0xCA, -0x90, 0x39, 0x96, 0x21, 0x73, 0xFC, 0x52, 0x20, 0x73, 0x2C, 0x41, 0xE6, 0x78, 0xEB, 0x21, 0x73, -0x2C, 0x41, 0xE6, 0x78, 0x63, 0x90, 0xB9, 0x57, 0x28, 0x3F, 0x56, 0x45, 0xD0, 0xCB, 0xDC, 0xCF, -0xEC, 0x11, 0x8C, 0xBF, 0xD7, 0xD6, 0x1D, 0x75, 0x12, 0xFD, 0x51, 0xE7, 0xA5, 0x60, 0xA6, 0xDB, -0x91, 0x7B, 0xA4, 0xCE, 0xD6, 0xA3, 0xA6, 0xDB, 0x91, 0xFB, 0xA4, 0xCE, 0xC6, 0x70, 0x73, 0xAD, -0xD9, 0x78, 0x44, 0x8A, 0x2E, 0xF0, 0xC2, 0x22, 0x03, 0x6F, 0x63, 0x71, 0x93, 0xBE, 0xE6, 0x79, -0x27, 0x4A, 0x06, 0x33, 0xC7, 0x35, 0xA7, 0x9A, 0xC3, 0xBC, 0x53, 0x5B, 0x2F, 0x7E, 0x9E, 0x84, -0x5F, 0xC4, 0x7E, 0xC9, 0x5C, 0x61, 0x5B, 0xBF, 0x66, 0xE5, 0xD4, 0x70, 0xC6, 0xC4, 0xBF, 0x78, -0x6A, 0x62, 0xCE, 0x15, 0x6E, 0x0B, 0x61, 0x87, 0x17, 0x3E, 0x87, 0x72, 0x85, 0xE5, 0x25, 0x41, -0x81, 0xD7, 0x3B, 0xDD, 0x8C, 0x66, 0x1E, 0x44, 0x6C, 0x75, 0xA9, 0x3D, 0xD6, 0x97, 0x3A, 0x3D, -0x9E, 0x3B, 0xC3, 0xF1, 0xE1, 0xA9, 0xA0, 0x88, 0xD7, 0x0B, 0xBE, 0xFA, 0x2E, 0xEF, 0xFA, 0xFA, -0xFC, 0xA8, 0xD8, 0x0E, 0xC1, 0xE7, 0x76, 0x7B, 0xA8, 0x6A, 0xE8, 0xF3, 0xFC, 0x6F, 0x65, 0xF6, -0xD3, 0x3D, 0xB7, 0xD3, 0x43, 0x1D, 0x07, 0x31, 0x8D, 0xCB, 0xEE, 0x00, 0x2C, 0x05, 0x44, 0xBC, -0xC2, 0x48, 0xBC, 0xDD, 0x82, 0xB4, 0x89, 0xDF, 0x6F, 0x96, 0xF2, 0x78, 0x79, 0xC0, 0xB1, 0xE8, -0xCC, 0x61, 0x11, 0xE4, 0x84, 0xDF, 0xA3, 0xBD, 0xE5, 0xF5, 0xF5, 0x36, 0x42, 0x87, 0xEB, 0x1A, -0x62, 0x27, 0xF8, 0xBA, 0xCD, 0xE0, 0xE1, 0x4A, 0x0E, 0xE2, 0x3A, 0x6F, 0x14, 0x3E, 0xB7, 0x94, -0x4F, 0x58, 0xFD, 0x20, 0xAE, 0xB1, 0xB3, 0xC9, 0x07, 0x87, 0xD9, 0x3B, 0x25, 0x42, 0xAD, 0x3C, -0xF0, 0x8C, 0xB0, 0x37, 0xD6, 0xB1, 0x33, 0x8E, 0x20, 0x48, 0x4A, 0xDC, 0x7E, 0x18, 0x85, 0x0A, -0x47, 0xF7, 0x26, 0x47, 0xD3, 0xB6, 0x19, 0x50, 0xA1, 0xA6, 0x83, 0x14, 0xED, 0x37, 0x0A, 0xAD, -0x68, 0x30, 0x26, 0xBA, 0xCB, 0x86, 0x40, 0x1B, 0x4E, 0x35, 0xCF, 0xD6, 0x88, 0x33, 0x83, 0x4F, -0x57, 0x29, 0xBA, 0x19, 0xBD, 0x19, 0x43, 0x4A, 0xDC, 0x7E, 0x9C, 0x85, 0x0A, 0x87, 0x38, 0x8B, -0xA7, 0x6D, 0x33, 0xCE, 0x42, 0x4D, 0x07, 0x29, 0xDA, 0x6F, 0x14, 0x67, 0x62, 0xB6, 0x92, 0x0C, -0x40, 0xCE, 0xA6, 0x10, 0x36, 0x99, 0x3A, 0x78, 0x23, 0xA7, 0x39, 0x73, 0x22, 0x08, 0x93, 0x12, -0xC3, 0x58, 0xAA, 0xE8, 0xF5, 0x2B, 0xCF, 0x8D, 0xB0, 0x50, 0xE1, 0x10, 0x61, 0xF1, 0xB4, 0x6D, -0x46, 0x58, 0xA8, 0xE9, 0x20, 0x45, 0xFB, 0x8D, 0x22, 0xEC, 0xC7, 0x77, 0xF7, 0x10, 0x62, 0x3D, -0x32, 0x7C, 0x87, 0xD7, 0x1E, 0xB9, 0xBF, 0xBA, 0xBB, 0x79, 0xFF, 0xE1, 0x7E, 0x7D, 0xD0, 0xBA, -0xA6, 0x2E, 0xD5, 0xE3, 0xC0, 0x0A, 0x93, 0x5E, 0x04, 0xAC, 0xB8, 0xBA, 0x31, 0x50, 0x05, 0x29, -0x5B, 0x0E, 0x29, 0xAE, 0xE7, 0x20, 0xA1, 0xF9, 0x33, 0xC2, 0xE9, 0xFA, 0xFC, 0xE1, 0xFC, 0xED, -0xDA, 0x22, 0x2E, 0x1D, 0x8A, 0x61, 0xB8, 0x77, 0x33, 0xC3, 0x9C, 0xB9, 0xB1, 0xA8, 0x2B, 0xF1, -0x60, 0xFB, 0x81, 0x15, 0x57, 0x3A, 0x1A, 0x7D, 0xC9, 0xE9, 0xDB, 0x0C, 0xB2, 0xB8, 0xB6, 0x83, -0x8C, 0x52, 0x6C, 0x38, 0x12, 0x13, 0xA2, 0x88, 0x90, 0xB5, 0x2E, 0xB0, 0xD9, 0xA6, 0xE1, 0x0E, -0xF0, 0x45, 0x54, 0x51, 0xA0, 0xC5, 0x13, 0x5F, 0x00, 0xC8, 0x02, 0x85, 0x23, 0x00, 0x8B, 0xA5, -0x6D, 0x35, 0xB8, 0x02, 0x4D, 0x07, 0x29, 0xDA, 0x6F, 0x16, 0x54, 0x28, 0x86, 0x70, 0x39, 0xE4, -0x8E, 0x4D, 0xE1, 0xB7, 0xBA, 0xD6, 0x78, 0xFE, 0x81, 0x4D, 0xAD, 0x44, 0x3C, 0x1F, 0x24, 0x6E, -0x3F, 0xB0, 0x42, 0x85, 0xE5, 0x78, 0xDE, 0x4F, 0xDB, 0x66, 0x60, 0x85, 0x9A, 0xCA, 0xF1, 0xBC, -0x9F, 0xB6, 0xE9, 0x78, 0x1E, 0xE5, 0x90, 0x6B, 0xAA, 0xE9, 0x6B, 0x42, 0xD5, 0x90, 0xA9, 0x12, -0xA4, 0xA2, 0x29, 0xDB, 0x8F, 0x27, 0x4F, 0xDB, 0x10, 0x4C, 0x91, 0x84, 0x6D, 0x46, 0x92, 0xA7, -0xE6, 0x40, 0xD6, 0x7B, 0xA3, 0x18, 0xC2, 0x75, 0xC3, 0x74, 0x00, 0xE5, 0x42, 0xA7, 0xFA, 0x2E, -0xE2, 0x7F, 0xC3, 0x2D, 0xE7, 0xA7, 0x6D, 0xBC, 0xF3, 0x3D, 0x92, 0x18, 0x55, 0x3F, 0x7E, 0x61, -0xDB, 0xA9, 0xA3, 0xD8, 0x9A, 0xE5, 0x46, 0x68, 0x47, 0x33, 0x83, 0x2F, 0x5C, 0x90, 0xE8, 0xA9, -0x24, 0xF9, 0x15, 0x3A, 0x8F, 0xD4, 0x26, 0x4F, 0xA4, 0x4F, 0x54, 0x53, 0x99, 0x61, 0xFC, 0xD0, -0x1A, 0x33, 0xF7, 0x4A, 0x67, 0xF8, 0xE7, 0xC5, 0xE2, 0x46, 0x6D, 0xD4, 0xE2, 0xC7, 0x6E, 0x6A, -0xF2, 0x6B, 0x7D, 0xB4, 0x11, 0x69, 0x64, 0xE5, 0x4D, 0x39, 0x2B, 0xB5, 0xD3, 0xF2, 0xCE, 0x53, -0x26, 0x14, 0xC1, 0xCF, 0x53, 0x8B, 0x83, 0xB4, 0xE5, 0x9D, 0x0F, 0x02, 0xB5, 0xEA, 0xFC, 0x88, -0x90, 0xFC, 0xFA, 0xA9, 0x2F, 0x84, 0xE9, 0x4E, 0xE2, 0x0D, 0x46, 0x19, 0x1C, 0xF8, 0x21, 0xE8, -0x04, 0x83, 0xC8, 0x27, 0x7C, 0x14, 0x7B, 0x5D, 0x6D, 0x60, 0x3E, 0xF9, 0x7A, 0x0E, 0x59, 0x6E, -0xAE, 0x09, 0x12, 0xF7, 0x7E, 0xE4, 0x5B, 0x20, 0xB3, 0x1A, 0x92, 0x37, 0x4C, 0xEC, 0x14, 0x34, -0x56, 0x01, 0xB6, 0xE1, 0x09, 0xF2, 0x4D, 0x30, 0x15, 0x27, 0xF9, 0xCB, 0x70, 0x2E, 0x5A, 0xDB, -0xAB, 0x59, 0x2B, 0x0D, 0x18, 0xAB, 0x1A, 0x6B, 0x55, 0x9E, 0x99, 0xB6, 0x4A, 0x45, 0x71, 0x0C, -0xB9, 0xFE, 0x9F, 0x49, 0xDC, 0xF2, 0x83, 0xC5, 0x9A, 0xBA, 0x93, 0xD2, 0xF4, 0xA7, 0x8B, 0x81, -0xB7, 0xF2, 0x9B, 0xEE, 0x03, 0x9C, 0x8B, 0xC5, 0x00, 0x9D, 0xEF, 0xCF, 0xE0, 0xD6, 0x7D, 0x65, -0xC5, 0x11, 0xE6, 0x14, 0x4F, 0x00, 0x32, 0x02, 0x70, 0xA7, 0xD4, 0xD6, 0xB9, 0x6D, 0xD3, 0x45, -0xCB, 0xB2, 0x4D, 0xD7, 0x44, 0x97, 0x88, 0x6F, 0xBF, 0xBD, 0xA2, 0xCA, 0xA4, 0xA5, 0x50, 0x5D, -0x6F, 0x84, 0x8A, 0xEC, 0xF9, 0x05, 0x68, 0x30, 0x3D, 0x8D, 0x0D, 0x7E, 0x98, 0xEE, 0x0B, 0x02, -0xB5, 0x47, 0x14, 0xE0, 0x91, 0x62, 0xF3, 0x2F, 0xB2, 0x86, 0x5C, 0x4B, 0x35, 0x92, 0xD3, 0xB5, -0x67, 0x72, 0x46, 0x01, 0xB6, 0x67, 0xD4, 0x3E, 0x45, 0x87, 0x62, 0xCA, 0xA7, 0x15, 0x3B, 0xE6, -0xC0, 0x72, 0x31, 0xE1, 0x1F, 0x2C, 0xAF, 0xE0, 0xCC, 0xFC, 0xBB, 0x14, 0x56, 0xF2, 0x64, 0x91, -0x7B, 0x25, 0xD6, 0xE8, 0x73, 0xA2, 0xB7, 0x08, 0xE4, 0x34, 0xA2, 0x35, 0xF9, 0x97, 0x25, 0xD2, -0xAA, 0x16, 0x22, 0xDF, 0x34, 0xC5, 0x1D, 0x41, 0xBB, 0x1D, 0x7D, 0x61, 0x86, 0x93, 0x8A, 0x86, -0xE8, 0x2D, 0xA1, 0xEB, 0xF0, 0x10, 0xD1, 0xEB, 0x48, 0xA5, 0x13, 0x05, 0x6B, 0x6A, 0x40, 0x4B, -0x9B, 0x7E, 0xA2, 0xE5, 0xE4, 0x35, 0xF9, 0xD4, 0x36, 0x22, 0xDF, 0x93, 0x5A, 0xAA, 0x8D, 0xC4, -0xEF, 0xBD, 0xAE, 0xD8, 0x46, 0xE4, 0x8B, 0x9B, 0x8B, 0xA2, 0xAB, 0x02, 0x94, 0x0B, 0x88, 0x5A, -0x02, 0xB9, 0xA5, 0x26, 0x09, 0x6F, 0xAD, 0xAD, 0x68, 0x8E, 0x94, 0xEB, 0x50, 0x37, 0x69, 0x92, -0x82, 0xE2, 0x56, 0x35, 0x4B, 0xF2, 0xAD, 0x0C, 0x15, 0xCD, 0x93, 0xF2, 0x16, 0x82, 0x0D, 0x5A, -0xA7, 0x98, 0xB4, 0x02, 0xC6, 0xC9, 0x70, 0x5A, 0x62, 0x1D, 0x99, 0xB3, 0x4F, 0xF5, 0x59, 0x89, -0x4D, 0x66, 0xA5, 0x9A, 0xA7, 0xB4, 0x89, 0xAD, 0xA2, 0xC5, 0xA5, 0x9D, 0x5B, 0x9B, 0x34, 0x77, -0x01, 0x51, 0x4B, 0x47, 0x38, 0xB9, 0x9F, 0x7C, 0x67, 0xE8, 0x1D, 0x86, 0x2C, 0x63, 0xE2, 0xF0, -0x50, 0x65, 0xD5, 0xE6, 0x1E, 0x9E, 0x0E, 0xDC, 0x29, 0x10, 0xE7, 0x65, 0xF2, 0x91, 0x8F, 0x1A, -0x16, 0x8E, 0x08, 0x72, 0xB9, 0x06, 0xC7, 0x8A, 0x80, 0x1F, 0x1F, 0xCC, 0x03, 0x9F, 0xFD, 0xA3, -0xA3, 0x32, 0x8A, 0xF9, 0x27, 0x4D, 0x56, 0xE4, 0xD0, 0x5B, 0x99, 0xC3, 0xF1, 0xEA, 0xA5, 0xE8, -0xA4, 0xB0, 0x28, 0x6F, 0xCD, 0xC1, 0xCA, 0x7A, 0xAC, 0xCC, 0xA1, 0xB7, 0x32, 0x87, 0xE3, 0xD5, -0x4B, 0xD1, 0x29, 0xC0, 0x62, 0x9D, 0xF3, 0x0D, 0x05, 0xF9, 0x15, 0x0B, 0xF9, 0x97, 0x95, 0x31, -0x8B, 0x59, 0x4E, 0xDB, 0x2E, 0xCE, 0x52, 0x5C, 0xB6, 0xB5, 0xB3, 0x7C, 0x64, 0xB5, 0xB4, 0x26, -0xAA, 0x46, 0xE1, 0x25, 0x98, 0x57, 0x1D, 0x39, 0xE0, 0xE7, 0x4B, 0x32, 0xF9, 0xCB, 0xCA, 0xBD, -0x4C, 0x86, 0xCB, 0xCD, 0x30, 0xE1, 0x2A, 0x1E, 0x37, 0x28, 0x5B, 0x79, 0x27, 0x71, 0xF7, 0xC3, -0x45, 0xA4, 0x71, 0x04, 0xA7, 0x38, 0xCA, 0xB7, 0xB2, 0x75, 0x31, 0xEA, 0xAD, 0x8B, 0xD1, 0xF1, -0xDA, 0x8A, 0xD6, 0xC9, 0xE6, 0xB4, 0x62, 0x1F, 0xD7, 0x59, 0xB1, 0x87, 0x2B, 0x9F, 0xBF, 0xB7, -0x62, 0xFE, 0xE3, 0x55, 0xF5, 0xEF, 0x24, 0x18, 0xAC, 0xD8, 0xB3, 0x55, 0xD0, 0x61, 0xC5, 0xFC, -0xBD, 0x15, 0xF3, 0x1F, 0xAF, 0xAA, 0x7F, 0x27, 0xC1, 0x60, 0xF3, 0x3D, 0x5A, 0x85, 0x0E, 0x28, -0xA7, 0xB3, 0xA8, 0xD2, 0xF7, 0xE4, 0xF5, 0x67, 0x9B, 0x99, 0x19, 0x2B, 0xC0, 0xB9, 0xE0, 0xEC, -0x98, 0xCC, 0x35, 0xD1, 0xBB, 0x2C, 0x5D, 0x31, 0x11, 0x0B, 0x4E, 0x62, 0x75, 0x2B, 0x63, 0xC9, -0x69, 0x62, 0x83, 0x48, 0x7C, 0x97, 0xF1, 0xAF, 0xEF, 0xDE, 0xFE, 0xE8, 0xBA, 0xD6, 0x1D, 0xFB, -0x63, 0xC6, 0x1C, 0xB7, 0x21, 0x4F, 0xDE, 0x00, 0x61, 0xCB, 0x34, 0x6C, 0x46, 0xD5, 0x85, 0x83, -0x63, 0x64, 0x71, 0xE4, 0x08, 0x2D, 0xEC, 0x4F, 0x13, 0xA5, 0xA2, 0x00, 0x11, 0x85, 0x59, 0x79, -0x46, 0x3E, 0xB8, 0x26, 0xFD, 0x7E, 0x9F, 0x1C, 0x92, 0x6F, 0xBF, 0xE5, 0x2C, 0x91, 0xD7, 0xCC, -0xE1, 0x69, 0xFB, 0x9D, 0x4E, 0x26, 0x90, 0x50, 0x55, 0x85, 0x17, 0xE3, 0x92, 0xBA, 0x14, 0xA4, -0xFE, 0x74, 0xFF, 0xFE, 0xE7, 0x96, 0x45, 0x6D, 0x87, 0x79, 0xEC, 0x1D, 0xCB, 0x34, 0x1C, 0xF6, -0xC0, 0x9E, 0xDC, 0xB4, 0x09, 0xDB, 0x25, 0x95, 0x62, 0x4F, 0xE7, 0xD4, 0xC6, 0x5D, 0x62, 0x8E, -0xA8, 0x12, 0x5C, 0x9B, 0x05, 0xAB, 0xB9, 0x40, 0x02, 0xB2, 0x6A, 0xD7, 0x1E, 0x01, 0xF9, 0x45, -0x50, 0x9C, 0x90, 0xDA, 0x6E, 0x23, 0x54, 0xA7, 0x25, 0x31, 0x20, 0xFF, 0xFA, 0x17, 0xA9, 0x7D, -0x30, 0x3E, 0x1B, 0xE6, 0xDC, 0x20, 0x01, 0xD3, 0x0C, 0xAD, 0xB4, 0x51, 0x94, 0x53, 0xF4, 0xA5, -0xE1, 0xE4, 0x2B, 0x10, 0x5D, 0xCB, 0x9A, 0xBB, 0xCE, 0x2D, 0xD1, 0x3C, 0x3E, 0x63, 0x22, 0x15, -0xC7, 0xBF, 0x93, 0x06, 0x34, 0xF5, 0x89, 0xE4, 0x12, 0xC5, 0xF4, 0xC0, 0xE2, 0xD4, 0x76, 0x76, -0x6B, 0xEA, 0xC5, 0xB4, 0x56, 0x3C, 0x16, 0xCA, 0x53, 0xB0, 0xAE, 0x59, 0xF5, 0xD0, 0x17, 0x45, -0xE4, 0x6A, 0x16, 0x4A, 0xAB, 0x97, 0x6D, 0x57, 0x75, 0x3C, 0x52, 0x91, 0xCE, 0x91, 0x1F, 0xB6, -0xA8, 0xC4, 0x53, 0x53, 0x33, 0x74, 0x54, 0xAB, 0xF1, 0x13, 0x2F, 0xB7, 0x4F, 0x65, 0xC9, 0x1F, -0x55, 0xE3, 0x9A, 0x78, 0xB3, 0x76, 0xAA, 0x80, 0x90, 0x0A, 0xA5, 0x74, 0x3B, 0x69, 0xFD, 0x47, -0x2E, 0xA2, 0xB2, 0x5E, 0xD5, 0x9D, 0x00, 0x57, 0xF4, 0xD5, 0xDD, 0xB5, 0x5D, 0xD2, 0xC8, 0x53, -0x62, 0x87, 0xEC, 0x92, 0xDA, 0x37, 0x59, 0x98, 0xCA, 0x2C, 0x72, 0xF8, 0x4A, 0xE6, 0xA8, 0xA7, -0x8F, 0x08, 0x0A, 0x08, 0x50, 0x4E, 0x95, 0x1E, 0x20, 0xF2, 0x56, 0xDF, 0x0C, 0x11, 0x01, 0x41, -0x65, 0x11, 0x39, 0xB3, 0x8E, 0x71, 0x51, 0x01, 0xA1, 0xCE, 0xD4, 0xEA, 0xD2, 0xC2, 0x97, 0x97, -0xA6, 0x02, 0x24, 0x7C, 0x5E, 0x0D, 0x86, 0xE1, 0x9B, 0x45, 0xF3, 0xD8, 0x7F, 0xFC, 0x88, 0xDC, -0xD3, 0x47, 0xD3, 0x45, 0xD8, 0x0F, 0xF2, 0xD9, 0x0F, 0xAA, 0xB2, 0xCF, 0x58, 0x2B, 0x88, 0x0B, -0x89, 0x11, 0x55, 0xAE, 0x08, 0xFF, 0x65, 0x8D, 0xA9, 0xE5, 0xF0, 0x1E, 0x56, 0xAB, 0x02, 0xEF, -0x4D, 0x8A, 0x99, 0x8C, 0x85, 0xF1, 0xCB, 0xB6, 0x7C, 0xFF, 0x45, 0x87, 0x99, 0x6C, 0x07, 0xD5, -0xD8, 0xA6, 0xAC, 0x45, 0x48, 0x2D, 0xCC, 0x27, 0xA8, 0x6C, 0xEA, 0xEC, 0x80, 0x35, 0x2E, 0x49, -0xD0, 0x69, 0x01, 0xDD, 0x8A, 0x02, 0x07, 0x1E, 0x88, 0x52, 0xEC, 0x15, 0x21, 0xA8, 0x56, 0xC7, -0xC1, 0x8B, 0x3A, 0x72, 0xD8, 0x57, 0xAC, 0xE7, 0xE0, 0x0D, 0x1A, 0x79, 0x9A, 0xE7, 0xB2, 0x8E, -0x87, 0x32, 0xA3, 0x60, 0xCB, 0x43, 0x95, 0x10, 0xA6, 0xDA, 0x08, 0x01, 0x3F, 0xF1, 0xDD, 0x16, -0x45, 0xF9, 0x67, 0x85, 0x67, 0xD9, 0x53, 0x38, 0xC5, 0x4B, 0x50, 0x7A, 0x46, 0xAC, 0x6C, 0x11, -0x3C, 0x01, 0x99, 0x65, 0xA8, 0x84, 0x84, 0xF0, 0x7E, 0xF5, 0x1C, 0x40, 0x04, 0x44, 0xA2, 0x47, -0x2F, 0x1D, 0x62, 0x65, 0xEF, 0x4B, 0x93, 0x62, 0x2E, 0x99, 0xB0, 0x72, 0x1B, 0x95, 0x6E, 0xAF, -0x4E, 0x8F, 0xF0, 0x62, 0x34, 0x28, 0xEA, 0xA0, 0x9A, 0x7F, 0xC3, 0x3B, 0x9C, 0xF3, 0xDC, 0x1B, -0x5E, 0xBB, 0x52, 0x39, 0x44, 0x89, 0xDF, 0x2C, 0xBC, 0x44, 0x8C, 0x37, 0x5C, 0xAB, 0x2A, 0x2C, -0xBC, 0xEA, 0x36, 0x2B, 0xE4, 0xF2, 0x09, 0x2A, 0x8B, 0x48, 0x59, 0xAD, 0x8A, 0x8B, 0x08, 0x08, -0xAA, 0x9B, 0x2C, 0xBC, 0x4F, 0x32, 0xCB, 0x5C, 0x01, 0x45, 0x65, 0x21, 0x91, 0x8B, 0xFA, 0x52, -0xC1, 0x15, 0x3E, 0xAF, 0xD6, 0x05, 0x84, 0xB7, 0xE9, 0xE5, 0xB1, 0xAF, 0xD8, 0x09, 0x84, 0xD7, -0xDE, 0xE5, 0x31, 0xAF, 0xD8, 0xE5, 0x87, 0x17, 0xD2, 0xE5, 0x30, 0x5F, 0xD1, 0x2E, 0xF9, 0x66, -0x59, 0xC9, 0x2A, 0xF9, 0x46, 0x59, 0xC5, 0x26, 0xBD, 0x7C, 0x9B, 0xF4, 0x56, 0xB3, 0x49, 0x2F, -0xD7, 0x26, 0xBD, 0x55, 0x6C, 0xD2, 0xCB, 0xB5, 0x49, 0x6F, 0x15, 0x9B, 0x1C, 0xE7, 0xDB, 0xE4, -0x78, 0x35, 0x9B, 0x1C, 0xE7, 0xDA, 0xE4, 0x78, 0x15, 0x9B, 0x1C, 0xE7, 0xDA, 0xE4, 0x78, 0xA5, -0xB6, 0xD3, 0x59, 0xD2, 0x78, 0x3A, 0x2B, 0xB6, 0x9E, 0x4E, 0x7E, 0xF3, 0xE9, 0xAC, 0xD4, 0x7E, -0x3A, 0xF9, 0x0D, 0xA8, 0x53, 0xD1, 0x32, 0x59, 0x1B, 0x49, 0xE2, 0x32, 0x38, 0x95, 0xEA, 0x53, -0x55, 0x76, 0xEE, 0xFE, 0x6D, 0x3E, 0xA9, 0xE5, 0xF0, 0x1E, 0x56, 0xAB, 0x00, 0xEF, 0xBA, 0x9D, -0x4C, 0xC6, 0x15, 0x4D, 0xEF, 0xDD, 0x89, 0x93, 0xC9, 0xB6, 0xA2, 0xD1, 0x83, 0xBB, 0x69, 0x52, -0x19, 0xFB, 0x4F, 0xAB, 0x59, 0xC2, 0xBF, 0x3C, 0x26, 0x9B, 0x75, 0x45, 0x5B, 0xF8, 0x37, 0xBC, -0x64, 0x33, 0xAE, 0x68, 0x8D, 0xF8, 0x3D, 0x2B, 0x19, 0xE1, 0x72, 0x84, 0xA4, 0xEA, 0xD8, 0x2F, -0x72, 0x11, 0xCA, 0x12, 0x21, 0x95, 0xC7, 0x80, 0x91, 0xDB, 0x4A, 0x96, 0x88, 0xA8, 0x68, 0xAB, -0xF8, 0x5D, 0x21, 0xA9, 0x32, 0x62, 0x24, 0xD5, 0x6C, 0x15, 0xBB, 0xCC, 0x63, 0x89, 0x90, 0x8A, -0xB6, 0x8A, 0xDD, 0xB8, 0xB1, 0x44, 0x44, 0x45, 0x5B, 0xC5, 0x6F, 0xBD, 0x48, 0x95, 0x11, 0x23, -0xA9, 0x66, 0xAB, 0xD8, 0xB5, 0x14, 0x4B, 0x84, 0x54, 0xB4, 0x55, 0xEC, 0xEE, 0x88, 0x25, 0x22, -0xAA, 0xDB, 0x2A, 0xB8, 0xC8, 0x21, 0x4B, 0x82, 0x4F, 0x50, 0xD9, 0x4E, 0xFE, 0x4D, 0x0B, 0xB9, -0x02, 0xAA, 0xDB, 0xC8, 0xBF, 0x0E, 0x21, 0x97, 0x7D, 0x65, 0x1F, 0x25, 0xDF, 0x4A, 0x90, 0xD1, -0xBE, 0x25, 0xB2, 0xAA, 0xBE, 0x4A, 0xBA, 0x36, 0xA0, 0x80, 0xB0, 0xCA, 0x3E, 0x4B, 0x3A, 0xDB, -0x5F, 0x40, 0x54, 0x55, 0x1B, 0xC6, 0x0E, 0xDC, 0xA7, 0xCB, 0x89, 0x92, 0x54, 0xB4, 0x5D, 0xF4, -0x44, 0xFC, 0x12, 0x21, 0x55, 0x6D, 0x16, 0x3D, 0xB6, 0xBE, 0x44, 0xC4, 0x4A, 0x7E, 0xDE, 0x3F, -0xF3, 0x9B, 0xE3, 0x1F, 0x3D, 0x92, 0x55, 0xFC, 0xBC, 0x77, 0x34, 0x77, 0x89, 0x90, 0x95, 0xFC, -0xBC, 0x77, 0x8A, 0x76, 0x89, 0x88, 0x8A, 0xB6, 0x8A, 0x1C, 0x8E, 0x4E, 0x5F, 0xBD, 0x0B, 0x9E, -0x57, 0x5C, 0x23, 0x0C, 0x4E, 0x2F, 0xE7, 0xB1, 0xAF, 0x68, 0x9F, 0xF0, 0x88, 0x71, 0x1E, 0xF3, -0xD0, 0x32, 0xE9, 0xEC, 0xA3, 0x47, 0x63, 0x33, 0x34, 0x48, 0x1C, 0x07, 0xC9, 0xA1, 0x8B, 0x6F, -0x4C, 0xCF, 0x22, 0x94, 0xCE, 0x93, 0x2E, 0x25, 0xF3, 0xDF, 0x01, 0xBA, 0x7C, 0x6B, 0x46, 0xDA, -0xE6, 0x09, 0x8B, 0x19, 0x8D, 0xFA, 0x0F, 0x57, 0x0F, 0xF5, 0x3D, 0x52, 0x6F, 0x83, 0x15, 0xC5, -0xB6, 0x0C, 0xF8, 0x86, 0xB3, 0xC1, 0x69, 0xDB, 0x2D, 0x1C, 0x66, 0xA8, 0x31, 0x69, 0x11, 0x29, -0x73, 0xCD, 0x50, 0xCD, 0x79, 0xCB, 0x34, 0x74, 0x93, 0xAA, 0xB9, 0xBB, 0x30, 0x0A, 0x2F, 0xE9, -0xD6, 0x76, 0x5A, 0x54, 0x55, 0xF9, 0x2B, 0xBD, 0xDE, 0x6A, 0x8E, 0xCB, 0x0C, 0x66, 0xE3, 0xA9, -0x63, 0x6B, 0xE6, 0xD6, 0xF6, 0x42, 0xFE, 0xAC, 0xDC, 0x16, 0xF2, 0xAA, 0xEB, 0xC6, 0xAC, 0xE5, -0x52, 0x1B, 0x98, 0x79, 0x90, 0x4A, 0x5B, 0x27, 0x4E, 0x9C, 0x2F, 0xCA, 0xC1, 0xD0, 0x32, 0xEC, -0x2C, 0xC5, 0xCC, 0x12, 0xAC, 0xE4, 0x61, 0xE4, 0xCB, 0x9B, 0xF8, 0xBD, 0xA0, 0x29, 0xFB, 0x74, -0xC4, 0x99, 0xF4, 0x6B, 0xD3, 0x9E, 0x26, 0xEB, 0x8F, 0x61, 0x85, 0xB4, 0x2C, 0x9B, 0xFF, 0xBE, -0x64, 0x23, 0x3A, 0xD3, 0xC5, 0xEE, 0x9C, 0x55, 0x37, 0xF3, 0x70, 0x3C, 0xDE, 0xBE, 0xBF, 0x17, -0x80, 0x14, 0x2A, 0x14, 0xC0, 0xA4, 0xEB, 0x31, 0xFD, 0x91, 0x51, 0xA8, 0xCF, 0x46, 0xDD, 0xAB, -0xC3, 0xE6, 0xC3, 0xC2, 0x62, 0xC8, 0x89, 0x5A, 0x62, 0xB9, 0x1A, 0xCA, 0xD5, 0x7E, 0x6A, 0xCE, -0xE7, 0xF3, 0x26, 0x1E, 0x9D, 0x6F, 0xCE, 0x6C, 0x9D, 0x19, 0xB8, 0x19, 0x43, 0xAD, 0x27, 0x95, -0x5F, 0xE7, 0xE6, 0xA2, 0x94, 0xBD, 0x45, 0x91, 0xAD, 0x45, 0xE9, 0x4D, 0x9C, 0xEA, 0xCC, 0x76, -0x1B, 0xF5, 0x7B, 0xE6, 0xE2, 0xCD, 0xF9, 0x0E, 0x71, 0xE8, 0x23, 0x53, 0xA1, 0x56, 0x14, 0x05, -0xF0, 0x38, 0x9A, 0xE9, 0xFA, 0xE2, 0xAB, 0x7A, 0xC1, 0x66, 0x9F, 0xAC, 0x15, 0x2C, 0xBE, 0xB7, -0x6B, 0x09, 0xAB, 0xE6, 0xDA, 0xFB, 0x1A, 0xAE, 0xEB, 0x80, 0x39, 0xED, 0xC5, 0x3D, 0xC3, 0x23, -0x80, 0x00, 0xAD, 0x3A, 0xD2, 0x27, 0x17, 0x73, 0x90, 0x93, 0x45, 0x6D, 0x08, 0x62, 0x5C, 0x66, -0x43, 0xA1, 0xC8, 0x3F, 0x7E, 0x93, 0x28, 0x7C, 0x39, 0xFE, 0x81, 0xBE, 0x46, 0x60, 0x3C, 0xDE, -0x86, 0xF6, 0xC8, 0x67, 0xB6, 0x48, 0x35, 0x63, 0xC8, 0xB6, 0x65, 0xCD, 0x9C, 0x49, 0x43, 0xD4, -0xD3, 0x87, 0xBB, 0x9B, 0x81, 0x39, 0xB5, 0x4C, 0x03, 0x54, 0x6C, 0xF0, 0xAC, 0xBB, 0xA4, 0xDE, -0xAF, 0xC3, 0xCF, 0x94, 0xE7, 0x5C, 0x42, 0x42, 0xE7, 0x44, 0x0B, 0xC5, 0x42, 0x0C, 0x4D, 0x15, -0x77, 0xB9, 0x45, 0x84, 0xFE, 0x6E, 0x6A, 0x80, 0xC4, 0x6F, 0x33, 0x70, 0xC1, 0xBD, 0x20, 0x66, -0x4A, 0x3E, 0xF6, 0xAE, 0xBB, 0x96, 0x67, 0x72, 0xBC, 0x5A, 0x39, 0x6D, 0x07, 0x37, 0x31, 0x78, -0x09, 0x89, 0x9B, 0x19, 0xA0, 0x9F, 0x72, 0x5C, 0xA2, 0x50, 0xE3, 0x91, 0xA2, 0x49, 0x73, 0x66, -0x0E, 0x6C, 0x57, 0x53, 0x74, 0x36, 0xE0, 0x94, 0x31, 0x28, 0x78, 0x2C, 0x5C, 0x3C, 0x95, 0x29, -0x18, 0xB5, 0x84, 0x6F, 0x47, 0xFF, 0xD6, 0xA8, 0xEF, 0xAB, 0x71, 0x6A, 0x41, 0xC1, 0xEF, 0xF6, -0x80, 0x0C, 0x9E, 0x17, 0xD7, 0x0C, 0xF0, 0xB5, 0x1F, 0x31, 0x2D, 0x49, 0x2A, 0xEE, 0x04, 0x91, -0x68, 0x7F, 0xE4, 0x89, 0x31, 0x7B, 0xE8, 0xCC, 0x25, 0xBE, 0x9A, 0x0E, 0x3F, 0xE2, 0x29, 0x63, -0x44, 0x68, 0x2A, 0xEE, 0x10, 0x79, 0x3F, 0xBA, 0xF5, 0x69, 0x81, 0x4C, 0xEC, 0x07, 0x8A, 0x50, -0xE2, 0x39, 0x52, 0xE2, 0x53, 0xC8, 0x90, 0xE1, 0x7C, 0xEC, 0x19, 0x07, 0xEB, 0xD3, 0x1E, 0x59, -0xEC, 0x11, 0x55, 0xB3, 0xC5, 0xBC, 0xDA, 0xAF, 0x91, 0xBF, 0x3F, 0xED, 0xF1, 0x17, 0xB8, 0xEE, -0x89, 0x13, 0x64, 0xA9, 0xC0, 0xC3, 0x77, 0x6C, 0xB7, 0xD0, 0x70, 0x4F, 0x29, 0x6D, 0x8B, 0x3F, -0xC4, 0x42, 0x2C, 0xB2, 0x1E, 0x86, 0x62, 0xB1, 0xEE, 0x82, 0x2F, 0x4B, 0xC9, 0x3F, 0x45, 0xC9, -0x3F, 0x65, 0x91, 0xA3, 0xF2, 0x40, 0x88, 0xBF, 0xB2, 0x48, 0xC4, 0x4E, 0x90, 0xBE, 0x28, 0xA1, -0x8C, 0x7D, 0xA9, 0x17, 0xB6, 0xE9, 0x3C, 0xDD, 0x89, 0x01, 0x74, 0x20, 0x48, 0x1A, 0x6B, 0xC6, -0x2D, 0x75, 0x27, 0xA9, 0xC1, 0x05, 0x52, 0x50, 0x5B, 0x69, 0x08, 0x73, 0xED, 0x79, 0x96, 0xD9, -0x0B, 0xD5, 0xDC, 0x23, 0x9D, 0x3D, 0xF2, 0x0E, 0xB2, 0xB7, 0x6E, 0x6F, 0xC8, 0x77, 0x64, 0x7F, -0x4F, 0x34, 0x89, 0x2C, 0x5E, 0x30, 0x16, 0xD2, 0xEF, 0x71, 0xD3, 0x29, 0xAE, 0x44, 0x07, 0xE5, -0xC8, 0x21, 0x4E, 0x68, 0xF5, 0x25, 0x79, 0xD3, 0xB5, 0xE8, 0x7C, 0xB3, 0xFD, 0xB4, 0x57, 0xD7, -0xBB, 0x11, 0xE3, 0x9E, 0xC5, 0x9B, 0x03, 0xC4, 0x87, 0x1E, 0x51, 0x33, 0x42, 0x74, 0x4A, 0xB2, -0x77, 0x85, 0x26, 0x51, 0xD0, 0x94, 0x92, 0xD2, 0x7D, 0x76, 0x8E, 0x86, 0x8B, 0x74, 0x0D, 0xBD, -0x56, 0xE8, 0xAB, 0xB8, 0xA8, 0xA8, 0xE2, 0xA7, 0xA4, 0x8A, 0x69, 0xF8, 0x4B, 0x55, 0xD1, 0x37, -0x60, 0x5F, 0x2E, 0x76, 0x76, 0xDB, 0x49, 0xD0, 0x7E, 0x4A, 0x8D, 0xBF, 0x05, 0x0D, 0x07, 0x68, -0x36, 0x88, 0xD3, 0x37, 0x18, 0x43, 0xCC, 0xE3, 0x26, 0xEB, 0x3C, 0xDF, 0x0F, 0x71, 0x06, 0x78, -0x43, 0x31, 0xBA, 0x2C, 0x8D, 0xEF, 0x45, 0x87, 0x5F, 0xA7, 0x49, 0xCF, 0x04, 0xC9, 0xBB, 0xBB, -0xA9, 0x96, 0xC5, 0x9C, 0x5E, 0xFB, 0xE4, 0xB0, 0xB7, 0x29, 0xF8, 0x46, 0x8C, 0x9D, 0xBE, 0x23, -0x47, 0x50, 0x81, 0xDD, 0x14, 0x93, 0x60, 0x96, 0xA7, 0x14, 0xFA, 0x46, 0x0C, 0x83, 0x4D, 0xC1, -0x16, 0xDA, 0x10, 0x76, 0x77, 0x19, 0x6D, 0x1F, 0x59, 0x2D, 0x72, 0x58, 0x79, 0x60, 0x29, 0xCC, -0x2B, 0x86, 0xE0, 0x86, 0xCC, 0xB5, 0xD3, 0x3A, 0xDA, 0x01, 0x5E, 0x9D, 0xD6, 0x7E, 0xDA, 0xB6, -0xB6, 0x58, 0xFE, 0x4F, 0xD5, 0xF2, 0xFB, 0x6E, 0xAC, 0x6E, 0x8F, 0x87, 0xB4, 0xB1, 0x7F, 0x74, -0xB4, 0x47, 0xC2, 0x1F, 0x9D, 0x56, 0x6F, 0x27, 0xFD, 0xD0, 0x4A, 0xBC, 0x96, 0x45, 0xE8, 0x80, -0x01, 0x8E, 0x5F, 0x7F, 0x25, 0x3A, 0x87, 0xD2, 0xB8, 0x53, 0xC4, 0x16, 0xE6, 0x24, 0xF4, 0xB0, -0x3C, 0xA6, 0x45, 0x15, 0xCD, 0x5D, 0xFC, 0xE2, 0x0D, 0x46, 0x65, 0x34, 0x04, 0xD8, 0xA3, 0x02, -0x7B, 0x14, 0xB0, 0x27, 0x95, 0x45, 0xBC, 0x84, 0x1C, 0x1E, 0x65, 0xE0, 0x2F, 0x60, 0x31, 0x04, -0x16, 0xF4, 0x0D, 0xFC, 0xCA, 0x64, 0x31, 0xCC, 0x60, 0x11, 0x56, 0x1E, 0x84, 0xA9, 0x86, 0x82, -0x8A, 0x36, 0x1A, 0x71, 0x1E, 0xFF, 0xA0, 0xBF, 0x71, 0x67, 0x28, 0xA5, 0x0E, 0x21, 0x95, 0xC3, -0xAD, 0x38, 0xF5, 0x4E, 0xCE, 0x5B, 0x77, 0x83, 0xCF, 0x6E, 0xAA, 0x02, 0x8B, 0x54, 0x96, 0x8B, -0x0C, 0x05, 0xB2, 0xA8, 0x93, 0xB1, 0x9B, 0xFF, 0xE1, 0x47, 0x4E, 0x7C, 0x1B, 0x9C, 0x4A, 0xCD, -0xB1, 0x4D, 0x5E, 0xA7, 0x34, 0x2C, 0x4C, 0xCD, 0x3D, 0xF7, 0x28, 0x03, 0x00, 0x94, 0x0A, 0x65, -0xB4, 0x71, 0x34, 0x00, 0xE3, 0x81, 0x8C, 0xD1, 0x3E, 0x7E, 0xB0, 0xDF, 0x83, 0x10, 0xC7, 0xFC, -0xCC, 0xFC, 0x6E, 0x32, 0xAD, 0x69, 0x60, 0x28, 0x1C, 0x93, 0x04, 0xF1, 0xF1, 0x4E, 0xDE, 0x59, -0x44, 0x64, 0xAB, 0x6B, 0x06, 0xFB, 0xE8, 0x45, 0x7F, 0x69, 0x6E, 0x2A, 0x4A, 0x9B, 0x1F, 0x15, -0x44, 0x29, 0xF1, 0x46, 0xC8, 0x07, 0x33, 0x0D, 0x10, 0x7B, 0x72, 0x75, 0x60, 0x25, 0x2D, 0x63, -0x87, 0x4A, 0x26, 0xD9, 0x0D, 0xD3, 0xD8, 0x0D, 0x0B, 0xB0, 0x13, 0xA6, 0xCC, 0x2C, 0x44, 0x81, -0x73, 0x94, 0xCB, 0xDC, 0x01, 0x35, 0xB4, 0x69, 0x6A, 0xF4, 0x81, 0xE2, 0x41, 0x59, 0x6A, 0xDF, -0xA1, 0xB7, 0xE8, 0xF0, 0x40, 0x29, 0x8A, 0xB0, 0xBD, 0x78, 0x07, 0x9F, 0x84, 0x69, 0x5A, 0x47, -0x95, 0xD1, 0xD2, 0xB3, 0x3A, 0x2B, 0xC9, 0x62, 0xDA, 0x6F, 0x2D, 0x3F, 0x56, 0x4A, 0x8B, 0xAA, -0x62, 0xDA, 0xFB, 0x5E, 0x4E, 0x22, 0xB4, 0xC5, 0x08, 0xFC, 0x9C, 0x97, 0x1A, 0xCA, 0x7F, 0x8D, -0x43, 0xA9, 0x86, 0x67, 0x04, 0x69, 0xC2, 0x28, 0x31, 0x65, 0x94, 0x98, 0xE3, 0xA9, 0xDB, 0x0C, -0x7D, 0x31, 0x8C, 0xDD, 0xC1, 0x7E, 0xFD, 0xB3, 0x84, 0x09, 0x8B, 0x0F, 0x59, 0x22, 0xE4, 0xF9, -0xC3, 0x96, 0x68, 0x06, 0x11, 0x42, 0x44, 0x95, 0x8E, 0xD7, 0x42, 0xE2, 0x79, 0x50, 0xD9, 0x6F, -0x12, 0xE3, 0xBC, 0xD3, 0x36, 0x0E, 0x14, 0xF9, 0x1F, 0x13, 0x77, 0x8A, 0x2F, 0x22, 0xFA, 0x7F, -0xBA, 0xD2, 0x5D, 0x9F, 0x6F, 0xC9, 0x00, 0x00 -}; \ No newline at end of file diff --git a/src/www/setuppage.html b/src/www/setuppage.html deleted file mode 100644 index e305b89..0000000 --- a/src/www/setuppage.html +++ /dev/null @@ -1,864 +0,0 @@ - - - - - - - BLLED Setup - - - - - - -
-
- - BLLED Controller -
-
-

BL LED Controller Settings Page

-

Firmware version: ??.??.??

-

This page allows you to change the MQTT broker info and any additional settings.

-
- -
- -
- -
- - - - - - - -
- -

-
- -    Perform new Wifi network scan
(Resets to strongest BSSID)
-
-
-
-
- - - - - - - - - - - - - -
- - -

LED Behaviour (Choose One)

-
- -    Maintenance Mode (Always On) -
-
- -    RGB Color Cycle Mode (Always On) -
-
- -    Replicate LED State -
- -  WW  -  CW  -
-
- -
- - -    Test LED Colors (Always On) -
- -  WW  -  CW  -
-
- - - - - - -
-
- -    Show Wifi Strength via LEDs -
-
- - -

Options

- - - - - - - - - - -
-
- -    Finish Indication -
-
-
- -  WW  -  CW  -
-
- - - -
-
- -    Inactivity Timeout (Minutes) - -
-
- -    Debugging -
-
- -    Debugging OnChange Events -
-
- -    MQTT Logging -
-
-

Printer Dependant

-
- -    Connecting to a P1 Printer? (No Door Switch, No Lidar) -
-
- -    Door Switch used for actions (P1 has no switch) -
- - - - - -

Stages with Lidar in use (if installed)

- -  WW  -  CW  -    Cleaning Nozzle
- - -  WW  -  CW  -    Bed Leveling
- - -  WW  -  CW  -    Calibrating Extrusion
- - -  WW  -  CW  -    Scanning Bed Surface
- - -  WW  -  CW  -    First Layer Inspection
- - -

Customise Colors

-
- -    Error Detection -
-
- - -  WW  -  CW  -    WiFi Setup / Scanning
- - - -  WW  -  CW  -    Pause (Gcode or User)
- - -  WW  -  CW  -    First Layer Error (Pause for user)
- - -  WW  -  CW  -    Nozzle Clog (Pause for user)
- - -  WW  -  CW  -    HMS Severity, SERIOUS
- - -  WW  -  CW  -    HMS Severity, FATAL
- - -  WW  -  CW  -    Filament Runout
- - -  WW  -  CW  -    Front Cover Removed
- - -  WW  -  CW  -    Nozzle Temp Fail
- - -  WW  -  CW  -    Bed Temp Fail
-
-
-
-
-
-
- - - - - - diff --git a/src/www/setuppage.html.gz b/src/www/setuppage.html.gz deleted file mode 100644 index 5084fc4..0000000 Binary files a/src/www/setuppage.html.gz and /dev/null differ diff --git a/src/www/updatePage.h b/src/www/updatePage.h deleted file mode 100644 index 5cfd9ea..0000000 --- a/src/www/updatePage.h +++ /dev/null @@ -1,113 +0,0 @@ -//https://mischianti.org/online-converter-file-to-cpp-gzip-byte-array-3/ -#define updatePage_html_gz_len 1739 -const uint8_t updatepPage_html_gz[] PROGMEM = { -0x1F, 0x8B, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xAD, 0x58, 0x6D, 0x73, 0xD3, 0x38, -0x10, 0xFE, 0xDE, 0x5F, 0x21, 0xCC, 0x80, 0x53, 0x5A, 0xDB, 0x49, 0x73, 0x2D, 0xBD, 0x34, 0xE9, -0x4C, 0xE9, 0xCB, 0x41, 0xAF, 0x0C, 0xBD, 0x52, 0x18, 0x0E, 0x86, 0xE9, 0x28, 0xB6, 0x62, 0xAB, -0xC8, 0x96, 0x91, 0xE4, 0xBC, 0x70, 0xC3, 0x7F, 0xBF, 0x95, 0xEC, 0x04, 0xC7, 0xB1, 0xD3, 0x16, -0x70, 0x3B, 0xB5, 0x2D, 0xAD, 0x76, 0x9F, 0x7D, 0xD1, 0xA3, 0x75, 0xFB, 0x8F, 0x4E, 0xDE, 0x1C, -0x5F, 0xFF, 0x7B, 0x79, 0x8A, 0x22, 0x15, 0xB3, 0xC3, 0x8D, 0x7E, 0x7E, 0x83, 0x3B, 0xC1, 0xC1, -0xE1, 0x06, 0x82, 0xAB, 0xCF, 0x68, 0xF2, 0x05, 0x09, 0xC2, 0x06, 0xB6, 0x54, 0x33, 0x46, 0x64, -0x44, 0x88, 0xB2, 0x51, 0x24, 0xC8, 0x68, 0x60, 0x47, 0x4A, 0xA5, 0xB2, 0xE7, 0x79, 0x7E, 0x90, -0xDC, 0x4A, 0xD7, 0x67, 0x3C, 0x0B, 0x46, 0x0C, 0x0B, 0xE2, 0xFA, 0x3C, 0xF6, 0xF0, 0x2D, 0x9E, -0x7A, 0x8C, 0x0E, 0xA5, 0x37, 0xE2, 0x89, 0x72, 0xF0, 0x84, 0x48, 0x1E, 0x13, 0x6F, 0xD7, 0xED, -0xEC, 0xBA, 0x5D, 0xCF, 0x97, 0xD2, 0xC3, 0x8C, 0xB9, 0x31, 0x4D, 0x5C, 0x78, 0xB6, 0x11, 0x4D, -0x14, 0x09, 0x05, 0x55, 0x33, 0x30, 0x14, 0xE1, 0xDD, 0xCE, 0x8E, 0x43, 0xA7, 0xEC, 0xCD, 0xC7, -0xF3, 0x29, 0xDB, 0xC7, 0xB7, 0x9D, 0xE3, 0x6F, 0xED, 0xF8, 0xEF, 0xDB, 0xD9, 0xD9, 0xF5, 0xF9, -0x3F, 0x53, 0x4F, 0x6E, 0xBD, 0xDB, 0x9B, 0xF0, 0x36, 0xDF, 0xBB, 0xDC, 0x3A, 0xFE, 0x78, 0x79, -0x75, 0xFE, 0x61, 0x2B, 0xFC, 0x46, 0xBA, 0xE7, 0xD1, 0xFE, 0x99, 0xE0, 0x5E, 0x7C, 0x3D, 0xBB, -0x10, 0xBB, 0xC2, 0x7B, 0x3F, 0xDD, 0xCA, 0xDE, 0x3F, 0x3F, 0xDF, 0xBF, 0x1A, 0x5F, 0x8D, 0x3E, -0xA6, 0xBB, 0x5B, 0x1F, 0xFE, 0x1C, 0xD1, 0xF1, 0x5F, 0xCF, 0x8F, 0x06, 0x03, 0x1B, 0xF9, 0x82, -0x4B, 0xC9, 0x05, 0x0D, 0x69, 0x32, 0xB0, 0x71, 0xC2, 0x93, 0x59, 0xCC, 0x33, 0xC0, 0x00, 0x4E, -0x11, 0x21, 0x88, 0x48, 0x39, 0xA3, 0x3E, 0x00, 0x49, 0xB8, 0x33, 0x1F, 0xB2, 0x91, 0x57, 0x04, -0xC4, 0x84, 0x21, 0x7F, 0xD6, 0xD7, 0x90, 0x07, 0x33, 0xF4, 0xDF, 0xE2, 0xD5, 0x0C, 0x61, 0xFF, -0x4B, 0x28, 0x78, 0x96, 0x04, 0x8E, 0xCF, 0x19, 0x17, 0x3D, 0xF4, 0x78, 0xD4, 0xD1, 0x3F, 0x07, -0x4B, 0x62, 0x26, 0x2C, 0x23, 0x1C, 0x53, 0x36, 0xEB, 0xA1, 0x23, 0x41, 0x31, 0xDB, 0x46, 0x12, -0x27, 0xD2, 0x91, 0x44, 0xD0, 0xD1, 0x0F, 0xD9, 0xEF, 0x1B, 0x8B, 0x47, 0x08, 0x6C, 0xA2, 0x30, -0x4D, 0x88, 0xA8, 0x98, 0x0C, 0xA8, 0x4C, 0x19, 0x06, 0x3D, 0x23, 0x46, 0xA6, 0x15, 0x33, 0x30, -0xE2, 0x04, 0x54, 0x10, 0x5F, 0x51, 0x9E, 0xF4, 0x10, 0x40, 0xCA, 0xE2, 0x64, 0x59, 0x06, 0x33, -0x1A, 0x26, 0x0E, 0x55, 0x24, 0x96, 0x20, 0x40, 0x20, 0x15, 0x62, 0x59, 0xE0, 0x36, 0x93, 0x8A, -0x8E, 0x66, 0x8E, 0xB6, 0x0F, 0xD3, 0xF5, 0x42, 0x90, 0x4B, 0x27, 0x22, 0x34, 0x8C, 0x60, 0xBE, -0xD3, 0x6E, 0x8F, 0xA3, 0xCA, 0x34, 0x16, 0x10, 0xF0, 0x1E, 0x6A, 0x23, 0x9C, 0x29, 0x5E, 0xEF, -0x1F, 0xE3, 0x21, 0x77, 0x7E, 0xC2, 0xC9, 0x3B, 0x1D, 0xC8, 0x8D, 0x3B, 0x43, 0xAE, 0x14, 0x8F, -0x7B, 0x68, 0xA7, 0x9D, 0x4E, 0x9B, 0x11, 0x54, 0xEC, 0x4E, 0x68, 0xA0, 0x22, 0xE3, 0x52, 0x5A, -0x31, 0x5B, 0xF2, 0xB6, 0x3A, 0x55, 0x18, 0x14, 0xB9, 0xC0, 0x7A, 0x7B, 0x8E, 0x22, 0x53, 0x55, -0x31, 0x6A, 0xAA, 0x43, 0xD2, 0x6F, 0xA4, 0x87, 0xBA, 0x7B, 0x55, 0xE5, 0x66, 0x72, 0x52, 0x18, -0x1F, 0x72, 0x16, 0xD4, 0xEB, 0x1E, 0x71, 0x11, 0x37, 0x46, 0x73, 0xB5, 0x4A, 0x27, 0x11, 0x04, -0x70, 0xD9, 0x50, 0x8A, 0x83, 0x80, 0x26, 0x61, 0xD5, 0x01, 0xB3, 0x9E, 0x8B, 0x80, 0x08, 0x47, -0xE0, 0x80, 0x66, 0x52, 0x87, 0x60, 0x55, 0x60, 0xEA, 0xC0, 0x56, 0x0E, 0xF8, 0x44, 0xE7, 0xBC, -0x6D, 0x24, 0x90, 0x08, 0x87, 0xB8, 0xD5, 0xDE, 0x46, 0xC5, 0xAF, 0xDB, 0xDD, 0x3C, 0xA8, 0x8B, -0xF5, 0x5E, 0xFB, 0x49, 0x6D, 0x38, 0x15, 0x4F, 0xD7, 0x04, 0x93, 0xE1, 0x21, 0x61, 0x4D, 0x45, -0x33, 0x64, 0xDC, 0xFF, 0x72, 0xEF, 0x30, 0x56, 0x52, 0xD0, 0x59, 0x49, 0xC1, 0x7C, 0x67, 0x77, -0xBB, 0xDD, 0xB5, 0x95, 0xB6, 0xDB, 0x80, 0x95, 0x26, 0x69, 0xA6, 0x3E, 0xA9, 0x59, 0x4A, 0x06, -0xF6, 0x88, 0x32, 0x62, 0x7F, 0x6E, 0xAC, 0xBA, 0x27, 0x0D, 0x39, 0x59, 0x0D, 0xF9, 0x5A, 0xC4, -0x79, 0xC2, 0x60, 0x06, 0xD2, 0x20, 0x81, 0xE1, 0x02, 0xF4, 0xD8, 0xF7, 0xFD, 0xB5, 0x49, 0xDD, -0x6D, 0xA8, 0xEA, 0x3B, 0xB7, 0x51, 0xD9, 0x3B, 0x99, 0x0D, 0x63, 0xAA, 0x56, 0xFC, 0xAB, 0x61, -0xC9, 0x3F, 0x8E, 0x8F, 0xCE, 0x76, 0xDB, 0xB5, 0x71, 0x5E, 0x57, 0x9B, 0x0F, 0x8C, 0xC3, 0x1D, -0x59, 0x9F, 0x87, 0x09, 0x8E, 0x05, 0xF2, 0xB0, 0xE0, 0xF8, 0x99, 0x90, 0x1A, 0x6B, 0xCA, 0x69, -0x23, 0x01, 0xAD, 0x2F, 0xE0, 0x54, 0xF0, 0x50, 0x10, 0x29, 0xEF, 0x5B, 0x0A, 0x0B, 0xFE, 0x59, -0xC1, 0xF2, 0xF3, 0x5E, 0x54, 0x52, 0xDC, 0x69, 0x64, 0x2E, 0xA9, 0xB0, 0xCA, 0x64, 0x23, 0x77, -0x35, 0x47, 0x78, 0x5D, 0xBA, 0xCB, 0x61, 0xAA, 0x35, 0xDD, 0xF7, 0x8A, 0x03, 0xB8, 0xEF, 0xE5, -0x5D, 0xCA, 0x46, 0x5F, 0x1F, 0xC1, 0xC5, 0xE1, 0x1C, 0xD0, 0x31, 0xF2, 0x19, 0x96, 0x72, 0x60, -0x2F, 0x78, 0xCF, 0xFE, 0x71, 0x58, 0x97, 0xE7, 0x97, 0x8F, 0x9A, 0x92, 0x90, 0x11, 0xA4, 0x71, -0x58, 0x16, 0xB4, 0x91, 0x14, 0xFE, 0x8F, 0x86, 0x27, 0xC8, 0x94, 0x1F, 0x05, 0x64, 0x4C, 0x18, -0x4F, 0x4D, 0xB3, 0x33, 0x49, 0xE7, 0x47, 0xA3, 0x97, 0xA5, 0x8C, 0xE3, 0x40, 0x7A, 0x3B, 0xED, -0x9D, 0xAE, 0xD7, 0xDE, 0xF7, 0x5E, 0xC1, 0x84, 0x23, 0xBF, 0x66, 0xBA, 0x2F, 0x4A, 0x93, 0xD0, -0x86, 0xB3, 0x4A, 0x0D, 0xEC, 0x0B, 0xAD, 0xB4, 0x62, 0x53, 0xA6, 0x38, 0x59, 0x42, 0xA7, 0x43, -0x6B, 0x1F, 0xBE, 0xB8, 0xB8, 0x38, 0x3D, 0x39, 0x06, 0xED, 0x82, 0x33, 0x46, 0x04, 0x04, 0x00, -0xE4, 0x4A, 0x3E, 0x79, 0xE0, 0x54, 0xBD, 0x8B, 0xCB, 0xFC, 0x5F, 0x35, 0x17, 0x75, 0xAA, 0xAA, -0xD1, 0xBB, 0x34, 0xC0, 0x8A, 0xA0, 0x4B, 0x1C, 0x12, 0x08, 0x6F, 0xA7, 0xB2, 0x20, 0x5D, 0x7E, -0xD7, 0xD7, 0x75, 0x44, 0x25, 0x6C, 0xC4, 0x90, 0x80, 0x57, 0x8C, 0x4F, 0x24, 0x9A, 0xF1, 0x0C, -0x29, 0x8E, 0xB2, 0x5C, 0x11, 0xBC, 0x09, 0x04, 0x71, 0xA2, 0x3E, 0x71, 0x97, 0x75, 0x79, 0x15, -0x65, 0x7D, 0x8D, 0x15, 0x91, 0xC4, 0x37, 0x9C, 0x61, 0xC5, 0x19, 0x53, 0x34, 0xC5, 0x42, 0x79, -0xC6, 0x07, 0x50, 0x86, 0x2D, 0x44, 0x83, 0x81, 0x95, 0x47, 0xF7, 0x46, 0x8F, 0x5A, 0x28, 0x26, -0x2A, 0xE2, 0x30, 0x98, 0x72, 0xA9, 0xAC, 0x55, 0x70, 0x7D, 0x73, 0x1E, 0x1C, 0x0E, 0x69, 0x82, -0x34, 0xC3, 0xF6, 0xFA, 0x5E, 0x3E, 0xB0, 0x2A, 0x68, 0xE8, 0x0A, 0x61, 0xDF, 0x27, 0x29, 0xE4, -0xC6, 0x85, 0x15, 0xDB, 0xFA, 0x8F, 0x1B, 0x7E, 0xB3, 0x8B, 0x58, 0x5A, 0x46, 0xC4, 0xD1, 0x7A, -0x72, 0x20, 0xFA, 0xA9, 0x63, 0xA1, 0x04, 0xC7, 0x86, 0xC0, 0x45, 0x3C, 0x81, 0x04, 0xDB, 0x28, -0x87, 0x6F, 0xC4, 0x0E, 0xFB, 0x43, 0x51, 0x63, 0x6B, 0xB1, 0xC7, 0xB5, 0x96, 0xF9, 0xCB, 0x0B, -0x2C, 0xC0, 0x1D, 0x3C, 0x1D, 0x58, 0xB0, 0xC9, 0x2D, 0x34, 0xC6, 0x2C, 0x03, 0x35, 0x6D, 0xD0, -0xE1, 0xCD, 0x45, 0x1A, 0xD4, 0x0D, 0x33, 0xD8, 0xA7, 0x89, 0x51, 0x96, 0x3F, 0x42, 0xFB, 0x98, -0x04, 0xD6, 0x1C, 0xF6, 0xD2, 0x58, 0x0E, 0x2E, 0xE7, 0x63, 0x4B, 0x9F, 0x8C, 0x78, 0xC8, 0x48, -0x70, 0x98, 0x67, 0xBD, 0xEF, 0xE5, 0xB2, 0x95, 0xBC, 0x98, 0x04, 0x54, 0x0B, 0x61, 0xAE, 0xBD, -0x44, 0x01, 0x79, 0x54, 0xF2, 0x01, 0xEB, 0xF0, 0xAD, 0xB9, 0xF7, 0xD0, 0x15, 0x6C, 0xD1, 0xD9, -0x6A, 0xB2, 0xA5, 0x2F, 0x68, 0xAA, 0x0A, 0x3C, 0x38, 0x4D, 0xA1, 0xDD, 0xC6, 0xBA, 0x3B, 0xF5, -0x6E, 0xF1, 0x18, 0xE7, 0x93, 0x35, 0xF9, 0x1C, 0x65, 0x89, 0xE9, 0x61, 0xD1, 0x4D, 0x8B, 0xB0, -0xCD, 0x0A, 0xE7, 0xCC, 0x2F, 0x41, 0x54, 0x26, 0x12, 0x14, 0x70, 0x3F, 0x8B, 0x61, 0x3B, 0xBA, -0x21, 0x51, 0xA7, 0x8C, 0xE8, 0xC7, 0x17, 0xB3, 0x57, 0x81, 0x5E, 0x78, 0xB0, 0xB2, 0xAE, 0xC4, -0x6A, 0x2B, 0xB6, 0xF2, 0x82, 0x3B, 0x83, 0x84, 0xB6, 0x9A, 0x4C, 0x8E, 0xB1, 0x30, 0x05, 0x86, -0x06, 0x80, 0xAC, 0x28, 0x8C, 0x4D, 0x57, 0xDF, 0xE5, 0xA7, 0xF6, 0xE7, 0x55, 0x73, 0x8B, 0x35, -0x10, 0x59, 0x5D, 0xD9, 0xB0, 0x2E, 0x21, 0x13, 0x74, 0x06, 0xAF, 0x27, 0xF0, 0xDA, 0xAA, 0x41, -0x68, 0x20, 0x15, 0xE2, 0x2E, 0x04, 0x0C, 0xD2, 0xD9, 0x2A, 0xD9, 0xD2, 0x55, 0xB8, 0x6D, 0x30, -0xE4, 0x7F, 0xCD, 0x40, 0x83, 0x1A, 0x6D, 0x59, 0x7F, 0x9B, 0x15, 0x56, 0x3F, 0xBC, 0xBE, 0x78, -0x09, 0xAC, 0x76, 0x45, 0xBE, 0x66, 0x44, 0xAA, 0x26, 0xDB, 0x7A, 0x81, 0x9B, 0x87, 0xC2, 0x85, -0x63, 0xF7, 0x74, 0x0C, 0xF1, 0xBC, 0xA0, 0x12, 0x08, 0x8F, 0x88, 0xD6, 0xA2, 0x8A, 0xAD, 0xED, -0xC5, 0x09, 0xF6, 0x12, 0x27, 0x01, 0x30, 0x0A, 0xC0, 0xC1, 0x4C, 0x36, 0x41, 0x31, 0x5A, 0x57, -0xD5, 0x69, 0x2B, 0xA0, 0x0A, 0x78, 0x35, 0x65, 0x44, 0x91, 0x5F, 0x55, 0x05, 0x35, 0x29, 0x14, -0xE8, 0x33, 0xF7, 0x5F, 0x51, 0x06, 0x1F, 0x82, 0x5C, 0x80, 0x22, 0x73, 0xFF, 0x15, 0x45, 0x18, -0xCE, 0x60, 0x8D, 0xC8, 0xDC, 0xEF, 0xAF, 0x88, 0x43, 0xDA, 0x5B, 0xD6, 0xE5, 0x9B, 0xB7, 0xD7, -0xB0, 0xD6, 0xF2, 0x72, 0x8E, 0xB5, 0x36, 0x0F, 0x50, 0xF3, 0x12, 0x49, 0x54, 0x91, 0xD9, 0x97, -0xB0, 0x13, 0xC1, 0xB6, 0x7D, 0x04, 0x24, 0x27, 0xA5, 0x53, 0x90, 0xBE, 0x73, 0xA4, 0x69, 0xDB, -0xC9, 0x27, 0xA5, 0xBD, 0x8D, 0xEC, 0x67, 0xF6, 0x3A, 0x08, 0xF7, 0xD4, 0xF7, 0xC6, 0x7C, 0x5B, -0x2F, 0xD4, 0xAD, 0xD3, 0x07, 0x85, 0x3C, 0x2F, 0xEC, 0xDA, 0x9D, 0x59, 0x1D, 0x59, 0x6C, 0xCC, -0x4A, 0xA5, 0xB5, 0x88, 0x8E, 0xF1, 0xBA, 0x2D, 0x9A, 0x12, 0xA1, 0xBF, 0x0C, 0xA1, 0xEE, 0x5F, -0x63, 0x15, 0xB9, 0xA6, 0xF5, 0x6C, 0xE5, 0xCB, 0x5C, 0x5D, 0x27, 0x24, 0x40, 0x1E, 0xCA, 0x5F, -0x15, 0x57, 0x18, 0x18, 0xE6, 0x99, 0x6E, 0xB9, 0x1A, 0xC2, 0x71, 0xD3, 0x5A, 0x22, 0xEF, 0x4D, -0xD7, 0x70, 0x36, 0x28, 0x2F, 0xCC, 0x3C, 0x8C, 0x65, 0x2A, 0xB5, 0xBE, 0xDE, 0x99, 0x46, 0xD3, -0xED, 0x86, 0x52, 0x80, 0x05, 0x05, 0x31, 0x6F, 0xBA, 0x9A, 0xAB, 0x8F, 0xF3, 0x56, 0x05, 0x56, -0x58, 0x73, 0xA2, 0x2E, 0x4E, 0xFE, 0x39, 0x8E, 0x47, 0xD6, 0xC3, 0xF0, 0x97, 0xF7, 0xD6, 0x9D, -0xE0, 0xEF, 0xC6, 0xA2, 0xD3, 0x01, 0xAD, 0xBD, 0xEB, 0xBA, 0x0F, 0xC4, 0x51, 0xDE, 0x9A, 0xBF, -0x8C, 0xE3, 0x54, 0x2B, 0x43, 0x41, 0x26, 0x00, 0x4A, 0xD1, 0xD1, 0x3C, 0x14, 0x4F, 0x79, 0x87, -0xFF, 0x86, 0xB8, 0x98, 0x1C, 0x19, 0x9D, 0x24, 0xB8, 0x27, 0x94, 0x9B, 0x96, 0x5D, 0xEA, 0x99, -0xEC, 0xCD, 0x55, 0x3A, 0x9A, 0x7F, 0xA0, 0x6D, 0xA3, 0x16, 0xD9, 0x44, 0x83, 0xC3, 0x06, 0x80, -0xD0, 0xBD, 0x0A, 0xE3, 0xC1, 0x09, 0x19, 0x61, 0x68, 0xCF, 0x9A, 0x8E, 0x8A, 0xF2, 0x81, 0x59, -0x83, 0xB0, 0x8E, 0x0E, 0x00, 0xA3, 0x39, 0xC9, 0x6A, 0xD1, 0xF9, 0x11, 0x4E, 0x42, 0x02, 0xE8, -0xE6, 0x41, 0x05, 0x94, 0xBF, 0xEF, 0x1C, 0xA6, 0x23, 0xD4, 0x32, 0x6B, 0x9E, 0x3E, 0x2D, 0x9D, -0x9C, 0xF5, 0xFA, 0x0B, 0xA8, 0xA5, 0x96, 0x0A, 0x00, 0xCF, 0xBB, 0x28, 0x30, 0x6A, 0x08, 0xBC, -0xDE, 0x4C, 0xBE, 0xB4, 0x71, 0xDB, 0xD6, 0xAE, 0xF9, 0x4E, 0x40, 0xDD, 0xCF, 0x21, 0x51, 0x22, -0x6B, 0x00, 0xB2, 0x4A, 0xA8, 0x85, 0xAE, 0xBC, 0xF8, 0x40, 0x0D, 0x4D, 0x20, 0xEC, 0x2F, 0xAF, -0x5F, 0x5F, 0xE8, 0xD2, 0x3B, 0x2B, 0x1A, 0xDB, 0x62, 0x4F, 0xD6, 0xD1, 0x42, 0xE1, 0x5A, 0xCE, -0xA0, 0x37, 0xC9, 0x8D, 0xE1, 0x4E, 0xAB, 0xA2, 0xA7, 0xAE, 0x56, 0x2B, 0xD5, 0x01, 0xDF, 0x35, -0xA6, 0xF1, 0xAB, 0xFD, 0xB2, 0x29, 0x1E, 0xA1, 0x47, 0x35, 0xDF, 0x7A, 0xFA, 0xE3, 0xCF, 0xFC, -0xAB, 0xFA, 0x7F, 0xF6, 0x70, 0x0B, 0xB7, 0xC2, 0x16, 0x00, 0x00 -}; \ No newline at end of file diff --git a/src/www/updatePage.html b/src/www/updatePage.html new file mode 100644 index 0000000..4b33f46 --- /dev/null +++ b/src/www/updatePage.html @@ -0,0 +1,260 @@ + + + + + + + BLLED OTA Update + + + + + + +
+ + +
+

This page allows you to update your device firmware over the air.

+
+ + + + + +
+ +
+
+

Status: Ready

+
+
+ + + + + + \ No newline at end of file diff --git a/src/www/updatepage.html b/src/www/updatepage.html deleted file mode 100644 index 780cfe0..0000000 --- a/src/www/updatepage.html +++ /dev/null @@ -1,299 +0,0 @@ - - - - - - - BLLED Setup - - - - - - -
-
- - BLLED Controller -
-
-

BLLED OTA

-

- This page allows you to update your device over the air. -

-
- -
-
- -
-

Status: Ready

- -
-
- - - - - diff --git a/src/www/wifiSetup.html b/src/www/wifiSetup.html index c80bd15..b579ff1 100644 --- a/src/www/wifiSetup.html +++ b/src/www/wifiSetup.html @@ -1,224 +1,329 @@ - - - - - -
-
- - BLLEDController -
- - + + +
ℹ️Placeholder
- + async function loadPrinterConfig() { + try { + const res = await fetch("/config.json"); + const config = await res.json(); + document.getElementById("ssid").value = config.ssid || ""; + document.getElementById("password").value = config.pass || ""; + document.getElementById("printerIP").value = config.printerIP || ""; + document.getElementById("printerSerial").value = config.printerSerial || ""; + document.getElementById("accessCode").value = config.accessCode || ""; + document.getElementById("webUser").value = config.webUser || ""; + document.getElementById("webPass").value = config.webPass || ""; + } catch (err) { + console.warn("No existing config found or failed to load."); + } + } + loadPrinterConfig(); + loadNetworks(); + + + + \ No newline at end of file