diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index dd84ea7..6867cf8 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -1,38 +1,38 @@ ---- -name: Bug report -about: Create a report to help us improve -title: '' -labels: '' -assignees: '' - ---- - -**Describe the bug** -A clear and concise description of what the bug is. - -**To Reproduce** -Steps to reproduce the behavior: -1. Go to '...' -2. Click on '....' -3. Scroll down to '....' -4. See error - -**Expected behavior** -A clear and concise description of what you expected to happen. - -**Screenshots** -If applicable, add screenshots to help explain your problem. - -**Desktop (please complete the following information):** - - OS: [e.g. iOS] - - Browser [e.g. chrome, safari] - - Version [e.g. 22] - -**Smartphone (please complete the following information):** - - Device: [e.g. iPhone6] - - OS: [e.g. iOS8.1] - - Browser [e.g. stock browser, safari] - - Version [e.g. 22] - -**Additional context** -Add any other context about the problem here. +--- +name: Bug report +about: Create a report to help us improve +title: '' +labels: '' +assignees: '' + +--- + +**Describe the bug** +A clear and concise description of what the bug is. + +**To Reproduce** +Steps to reproduce the behavior: +1. Go to '...' +2. Click on '....' +3. Scroll down to '....' +4. See error + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Screenshots** +If applicable, add screenshots to help explain your problem. + +**Desktop (please complete the following information):** + - OS: [e.g. iOS] + - Browser [e.g. chrome, safari] + - Version [e.g. 22] + +**Smartphone (please complete the following information):** + - Device: [e.g. iPhone6] + - OS: [e.g. iOS8.1] + - Browser [e.g. stock browser, safari] + - Version [e.g. 22] + +**Additional context** +Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md index bbcbbe7..72718d5 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -1,20 +1,20 @@ ---- -name: Feature request -about: Suggest an idea for this project -title: '' -labels: '' -assignees: '' - ---- - -**Is your feature request related to a problem? Please describe.** -A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] - -**Describe the solution you'd like** -A clear and concise description of what you want to happen. - -**Describe alternatives you've considered** -A clear and concise description of any alternative solutions or features you've considered. - -**Additional context** -Add any other context or screenshots about the feature request here. +--- +name: Feature request +about: Suggest an idea for this project +title: '' +labels: '' +assignees: '' + +--- + +**Is your feature request related to a problem? Please describe.** +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + +**Describe the solution you'd like** +A clear and concise description of what you want to happen. + +**Describe alternatives you've considered** +A clear and concise description of any alternative solutions or features you've considered. + +**Additional context** +Add any other context or screenshots about the feature request here. diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 43c08ef..2d74112 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,47 +1,47 @@ -name: Release -on: - push: - branches: - - main -jobs: - release: - name: Release - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v2 - with: - fetch-depth: 0 - - name: Setup node - uses: actions/setup-node@v3 - with: - node-version: 18 - - run: npm install -g conventional-changelog-conventionalcommits@6 - - run: npm install -g semantic-release@v19.0.5 - - run: npm install -g @semantic-release/exec - - run: npm install -g @semantic-release/git - - run: npm install -g @semantic-release/github - - run: npm install -g @semantic-release/changelog - - run: npm install -g @semantic-release/release-notes-generator - - name: Cache pip - uses: actions/cache@v2 - with: - path: ~/.cache/pip - key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }} - restore-keys: ${{ runner.os }}-pip- - - name: Cache PlatformIO - uses: actions/cache@v2 - with: - path: ~/.platformio - key: ${{ runner.os }}-${{ hashFiles('**/lockfiles') }} - - name: Set up Python - uses: actions/setup-python@v2 - - name: Install PlatformIO - run: | - python -m pip install --upgrade pip - pip install --upgrade platformio - - name: Release - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - PLATFORMIO_AUTH_TOKEN: ${{ secrets.PLATFORMIO_AUTH_TOKEN }} - run: semantic-release +name: Release +on: + push: + branches: + - main +jobs: + release: + name: Release + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v2 + with: + fetch-depth: 0 + - name: Setup node + uses: actions/setup-node@v3 + with: + node-version: 18 + - run: npm install -g conventional-changelog-conventionalcommits@6 + - run: npm install -g semantic-release@v19.0.5 + - run: npm install -g @semantic-release/exec + - run: npm install -g @semantic-release/git + - run: npm install -g @semantic-release/github + - run: npm install -g @semantic-release/changelog + - run: npm install -g @semantic-release/release-notes-generator + - name: Cache pip + uses: actions/cache@v2 + with: + path: ~/.cache/pip + key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }} + restore-keys: ${{ runner.os }}-pip- + - name: Cache PlatformIO + uses: actions/cache@v2 + with: + path: ~/.platformio + key: ${{ runner.os }}-${{ hashFiles('**/lockfiles') }} + - name: Set up Python + uses: actions/setup-python@v2 + - name: Install PlatformIO + run: | + python -m pip install --upgrade pip + pip install --upgrade platformio + - name: Release + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + PLATFORMIO_AUTH_TOKEN: ${{ secrets.PLATFORMIO_AUTH_TOKEN }} + run: semantic-release diff --git a/.gitignore b/.gitignore index 75defe0..195d15d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,36 +1,36 @@ -# Prerequisites -*.d - -# Compiled Object files -*.slo -*.lo -*.o -*.obj - -# Precompiled Headers -*.gch -*.pch - -# Compiled Dynamic libraries -*.so -*.dylib -*.dll - -# Fortran module files -*.mod -*.smod - -# Compiled Static libraries -*.lai -*.la -*.a -*.lib - -# Executables -*.exe -*.out -*.app - -# Other files -.DS_Store +# Prerequisites +*.d + +# Compiled Object files +*.slo +*.lo +*.o +*.obj + +# Precompiled Headers +*.gch +*.pch + +# Compiled Dynamic libraries +*.so +*.dylib +*.dll + +# Fortran module files +*.mod +*.smod + +# Compiled Static libraries +*.lai +*.la +*.a +*.lib + +# Executables +*.exe +*.out +*.app + +# Other files +.DS_Store .vscode/ \ No newline at end of file diff --git a/.releaserc b/.releaserc index 279bd51..f101346 100644 --- a/.releaserc +++ b/.releaserc @@ -1,173 +1,173 @@ -{ - "branches": [ - "main", - "master" - ], - "plugins": [ - [ - "@semantic-release/commit-analyzer", - { - "preset": "conventionalcommits", - "parserOpts": { - "noteKeywords": [ - "BREAKING CHANGE", - "BREAKING CHANGES", - "BREAKING" - ] - }, - "releaseRules": [ - { - "breaking": true, - "release": "major" - }, - { - "type": "feat", - "release": "minor" - }, - { - "type": "fix", - "release": "patch" - }, - { - "type": "perf", - "release": "patch" - }, - { - "type": "revert", - "release": "patch" - }, - { - "type": "docs", - "release": "minor" - }, - { - "type": "style", - "release": "patch" - }, - { - "type": "refactor", - "release": "patch" - }, - { - "type": "test", - "release": "patch" - }, - { - "type": "build", - "release": "patch" - }, - { - "type": "ci", - "scope": "ci-*", - "release": "patch" - }, - { - "type": "chore", - "release": false - }, - { - "type": "no-release", - "release": false - } - ] - } - ], - [ - "@semantic-release/release-notes-generator", - { - "preset": "conventionalcommits", - "parserOpts": { - "noteKeywords": [ - "BREAKING CHANGE", - "BREAKING CHANGES", - "BREAKING" - ] - }, - "writerOpts": { - "commitsSort": [ - "subject", - "scope" - ] - }, - "presetConfig": { - "types": [ - { - "type": "feat", - "section": "🍕 Features" - }, - { - "type": "feature", - "section": "🍕 Features" - }, - { - "type": "fix", - "section": "🐛 Bug Fixes" - }, - { - "type": "perf", - "section": "🔥 Performance Improvements" - }, - { - "type": "revert", - "section": "⏩ Reverts" - }, - { - "type": "docs", - "section": "📝 Documentation" - }, - { - "type": "style", - "section": "🎨 Styles" - }, - { - "type": "refactor", - "section": "🧑‍💻 Code Refactoring" - }, - { - "type": "test", - "section": "✅ Tests" - }, - { - "type": "build", - "section": "🤖 Build System" - }, - { - "type": "ci", - "section": "🔁 Continuous Integration" - } - ] - } - } - ], - [ - "@semantic-release/changelog", - { - "changelogTitle": "# 📦 Changelog \n[![conventional commits](https://img.shields.io/badge/conventional%20commits-1.0.0-yellow.svg)](https://conventionalcommits.org)\n[![semantic versioning](https://img.shields.io/badge/semantic%20versioning-2.0.0-green.svg)](https://semver.org)\n> All notable changes to this project will be documented in this file" - } - ], - [ - "@semantic-release/exec", - { - "prepareCmd": "sed -i 's/\"version\": \"[0-9\\.]*\",/\"version\": \"${nextRelease.version}\",/g' ./NetworkManager/library.json", - "publishCmd": "pio pkg publish --no-interactive" - } - ], - [ - "@semantic-release/github", - { - "addReleases": "bottom" - } - ], - [ - "@semantic-release/git", - { - "assets": [ - "NetworkManager/library.json", - "LICENSE*", - "CHANGELOG.md" - ], - "message": "chore(${nextRelease.type}): ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}" - } - ] - ] +{ + "branches": [ + "main", + "master" + ], + "plugins": [ + [ + "@semantic-release/commit-analyzer", + { + "preset": "conventionalcommits", + "parserOpts": { + "noteKeywords": [ + "BREAKING CHANGE", + "BREAKING CHANGES", + "BREAKING" + ] + }, + "releaseRules": [ + { + "breaking": true, + "release": "major" + }, + { + "type": "feat", + "release": "minor" + }, + { + "type": "fix", + "release": "patch" + }, + { + "type": "perf", + "release": "patch" + }, + { + "type": "revert", + "release": "patch" + }, + { + "type": "docs", + "release": "minor" + }, + { + "type": "style", + "release": "patch" + }, + { + "type": "refactor", + "release": "patch" + }, + { + "type": "test", + "release": "patch" + }, + { + "type": "build", + "release": "patch" + }, + { + "type": "ci", + "scope": "ci-*", + "release": "patch" + }, + { + "type": "chore", + "release": false + }, + { + "type": "no-release", + "release": false + } + ] + } + ], + [ + "@semantic-release/release-notes-generator", + { + "preset": "conventionalcommits", + "parserOpts": { + "noteKeywords": [ + "BREAKING CHANGE", + "BREAKING CHANGES", + "BREAKING" + ] + }, + "writerOpts": { + "commitsSort": [ + "subject", + "scope" + ] + }, + "presetConfig": { + "types": [ + { + "type": "feat", + "section": "🍕 Features" + }, + { + "type": "feature", + "section": "🍕 Features" + }, + { + "type": "fix", + "section": "🐛 Bug Fixes" + }, + { + "type": "perf", + "section": "🔥 Performance Improvements" + }, + { + "type": "revert", + "section": "⏩ Reverts" + }, + { + "type": "docs", + "section": "📝 Documentation" + }, + { + "type": "style", + "section": "🎨 Styles" + }, + { + "type": "refactor", + "section": "🧑‍💻 Code Refactoring" + }, + { + "type": "test", + "section": "✅ Tests" + }, + { + "type": "build", + "section": "🤖 Build System" + }, + { + "type": "ci", + "section": "🔁 Continuous Integration" + } + ] + } + } + ], + [ + "@semantic-release/changelog", + { + "changelogTitle": "# 📦 Changelog \n[![conventional commits](https://img.shields.io/badge/conventional%20commits-1.0.0-yellow.svg)](https://conventionalcommits.org)\n[![semantic versioning](https://img.shields.io/badge/semantic%20versioning-2.0.0-green.svg)](https://semver.org)\n> All notable changes to this project will be documented in this file" + } + ], + [ + "@semantic-release/exec", + { + "prepareCmd": "sed -i 's/\"version\": \"[0-9\\.]*\",/\"version\": \"${nextRelease.version}\",/g' ./NetworkManager/library.json", + "publishCmd": "pio pkg publish --no-interactive" + } + ], + [ + "@semantic-release/github", + { + "addReleases": "bottom" + } + ], + [ + "@semantic-release/git", + { + "assets": [ + "NetworkManager/library.json", + "LICENSE*", + "CHANGELOG.md" + ], + "message": "chore(${nextRelease.type}): ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}" + } + ] + ] } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 6d679a7..e060c7c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,684 +1,684 @@ -# 📦 Changelog -[![conventional commits](https://img.shields.io/badge/conventional%20commits-1.0.0-yellow.svg)](https://conventionalcommits.org) -[![semantic versioning](https://img.shields.io/badge/semantic%20versioning-2.0.0-green.svg)](https://semver.org) -> All notable changes to this project will be documented in this file - -## [5.5.1](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v5.5.0...v5.5.1) (2024-04-16) - - -### 🐛 Bug Fixes - -* Fix the issue with the wifi handler not starting the access point ([2638d40](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/2638d40c4a26534c3495db3303fc76355c2e8351)) - -## [5.5.0](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v5.4.5...v5.5.0) (2024-04-15) - - -### 🍕 Features - -* Update setWifiConfig function in ProjectConfig class to toggle reboot status ([da92fd2](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/da92fd20deee4b4695885619e784245fe64dddf7)) - -## [5.4.5](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v5.4.4...v5.4.5) (2024-04-07) - - -### 🐛 Bug Fixes - -* update to new version of EasyHelpers ([4bf43a9](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/4bf43a9ea9f50bc9a91b731bff938166bce77771)) - -## [5.4.4](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v5.4.3...v5.4.4) (2024-04-06) - - -### 🐛 Bug Fixes - -* attach default handler to an endpoint ([c71b7d4](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/c71b7d42a0d091309c516d45e7981905265e5b41)) - -## [5.4.3](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v5.4.2...v5.4.3) (2024-04-06) - - -### 🐛 Bug Fixes - -* Refactor handleJson function parameters to pass JsonVariant by reference ([e4c9671](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/e4c9671d313f676689e1c44268f1b805f497fbd5)) - -## [5.4.2](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v5.4.1...v5.4.2) (2024-04-06) - - -### 🧑‍💻 Code Refactoring - -* Refactor handleJson function parameters in NetworkManager code ([46e6513](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/46e65135b12e27b9c33a9c9d9232f59d420ed336)) - -## [5.4.1](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v5.4.0...v5.4.1) (2024-04-06) - - -### 🐛 Bug Fixes - -* clean up some extranious left overs ([38eff9d](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/38eff9d4ab7f31150c777fac6f9942bf08c09890)) - -## [5.4.0](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v5.3.5...v5.4.0) (2024-04-05) - - -### 🍕 Features - -* update to new Helpers library ([3d10979](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/3d10979fa4c0bf6c40bf0c0e9866a3138a223817)) - -## [5.3.5](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v5.3.4...v5.3.5) (2024-04-01) - - -### 🐛 Bug Fixes - -* change to IId interface to replace getName() ([a7e2025](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/a7e2025162d039fccc0ac1f5b1a0e202d95b21cd)) - -## [5.3.4](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v5.3.3...v5.3.4) (2024-03-31) - - -### 🤖 Build System - -* Update ArduinoJson dependency in dev_config.ini ([58cb244](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/58cb24494ac29206c24ad207c244b006da6112f5)) - -## [5.3.3](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v5.3.2...v5.3.3) (2024-03-31) - - -### 🧑‍💻 Code Refactoring - -* migrate to helper lib, Update include paths and dependencies ([102ba5d](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/102ba5d2c702abd3653efe5b85d8c207ca0844f8)) - -## [5.3.2](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v5.3.1...v5.3.2) (2024-03-31) - - -### 🐛 Bug Fixes - -* Update ArduinoJson dependency ([fc4b182](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/fc4b1829507d38b2cbd4dd41fbf876542b40ffb6)) - -## [5.3.1](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v5.3.0...v5.3.1) (2024-03-31) - - -### 🧑‍💻 Code Refactoring - -* Update NetworkManager configuration and API handlers ([8c425c9](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/8c425c9b38b6f6c315385c47637f3f1bb79c3149)) - -## [5.3.0](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v5.2.3...v5.3.0) (2024-03-31) - - -### 🍕 Features - -* added ability to handle JSON data POST and GET ([53035ab](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/53035abc31fd4810fb3fd1f03cab1363525f2a69)) - -## [5.2.3](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v5.2.2...v5.2.3) (2024-03-30) - - -### 🧑‍💻 Code Refactoring - -* Update NetworkManager version and fix struct initialization ([764f579](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/764f579d3c826f9ff5731323fd420f8df5e140ad)) - -## [5.2.2](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v5.2.1...v5.2.2) (2024-03-30) - - -### 🧑‍💻 Code Refactoring - -* clean up project manager ([395ce7b](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/395ce7b0416543ea503fe062809fe6eda3c9f7ba)) - -## [5.2.1](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v5.2.0...v5.2.1) (2024-03-03) - - -### 🐛 Bug Fixes - -* update html file path ([33d1e13](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/33d1e135e654720614f5322a9a7eb5719fc79b6a)) - -## [5.2.0](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v5.1.4...v5.2.0) (2024-01-15) - - -### 📝 Documentation - -* add blurb about c++17 ([4d5027c](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/4d5027c7ea53d824421e03c485b791a7c017174e)) - -## [5.1.4](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v5.1.3...v5.1.4) (2023-12-21) - - -### 🐛 Bug Fixes - -* wifi activating before config load ([60dc0a3](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/60dc0a3b134c07dc2bc61b0ebf3f7e3e20480daf)) - -## [5.1.3](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v5.1.2...v5.1.3) (2023-12-21) - - -### 🐛 Bug Fixes - -* wifi reset issue when STA cannot be found ([2a67bb8](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/2a67bb8b8105d0547594b91fba44c64b15251f89)) - -## [5.1.2](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v5.1.1...v5.1.2) (2023-12-21) - - -### 🐛 Bug Fixes - -* wifi reset issue when STA cannot be found ([a2c679e](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/a2c679e0b1795aeb88e2cb255410ef29fac8b766)) - -## [5.1.1](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v5.1.0...v5.1.1) (2023-12-21) - - -### 🧑‍💻 Code Refactoring - -* add id to ISubject ([85fa400](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/85fa400241b514aa63b33b6cd8b76df859dceedd)) - -## [5.1.0](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v5.0.0...v5.1.0) (2023-12-21) - - -### 🍕 Features - -* add wifi event mappings to native wifi class ([2ff3a86](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/2ff3a86e1059e818df74a09d6f3179519bb16a6d)) - -## [5.0.0](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v4.5.8...v5.0.0) (2023-12-21) - - -### ⚠ BREAKING CHANGES - -* CHANGES - -- simplify the api A LOT -- setup the state machine to follow the observer pattern for easier use -- create a wrapper for updating the state -- update examples - -### 🍕 Features - -* add more fine grained examples ([2e18135](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/2e181358942ecccd7892c6a631deabad660db43e)) -* total project refactor ([0f70bec](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/0f70becd098fc582b07cd66cddd1d9c569cc6bc9)) - -## [4.5.8](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v4.5.7...v4.5.8) (2023-12-19) - - -### 🐛 Bug Fixes - -* fix error with logger ([c9e4acc](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/c9e4acccd2d3841fe5b18b6552c2723b8a68634e)) - -## [4.5.7](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v4.5.6...v4.5.7) (2023-12-18) - - -### 🧑‍💻 Code Refactoring - -* set wifi waiting printout to verbose log only ([f07add0](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/f07add01401d3f57955f270b52f59ce234dc651f)) - -## [4.5.6](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v4.5.5...v4.5.6) (2023-12-18) - - -### 🧑‍💻 Code Refactoring - -* set wifi waiting printout to verbose log only ([ce5bfc2](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/ce5bfc261a54366def17d15f608ef8260e95fe96)) - -## [4.5.5](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v4.5.4...v4.5.5) (2023-12-18) - - -### 🐛 Bug Fixes - -* minor change to wifi ([4d0d3ba](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/4d0d3ba92a6d7cbd97d50bf06904add27a0bbae6)) - -## [4.5.4](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v4.5.3...v4.5.4) (2023-12-15) - - -### 🧑‍💻 Code Refactoring - -* add id to ISubject ([6c8bf4c](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/6c8bf4c120b088dd46a6bcf05f9c610656b8191e)) - -## [4.5.3](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v4.5.2...v4.5.3) (2023-12-15) - - -### 🐛 Bug Fixes - -* set to ingest observer event enum as const reference ([25e5866](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/25e586656f4048808e6c8fc2a162fb4f9b3cd04c)) - -## [4.5.2](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v4.5.1...v4.5.2) (2023-11-25) - - -### 🐛 Bug Fixes - -* update examples ([867db66](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/867db6602fcb6936ba773209f3b1eadbe6130ebc)) - -## [4.5.1](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v4.5.0...v4.5.1) (2023-10-13) - - -### 🧑‍💻 Code Refactoring - -* total api structure refactor ([bc19316](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/bc1931647d06d6d4297552070b3bdbb663ea5306)) - -## [4.5.0](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v4.4.0...v4.5.0) (2023-09-26) - - -### 📝 Documentation - -* Update README.md ([4a24454](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/4a244545ccff822cf19f1147816483004b72a43c)) -* Update README.md ([c586bb3](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/c586bb34ba27547a5658210c59491ede00abbbf3)) -* Update README.md ([75617e8](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/75617e8a121bed6fe48765ca9e7ba67111274af6)) -* Update README.md ([5ef6c16](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/5ef6c168b9f1eb10eb7a78cfb24ac45fae98899e)) -* Update README.md ([e8b2aaf](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/e8b2aaf8c7679e3f0c2ff03fd631215f610f2a74)) -* Update README.md ([7eec690](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/7eec690df96dab275c43e75cb662ba8653efd66f)) - - -### 🔁 Continuous Integration - -* Update release.yml ([6f478a0](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/6f478a01bb9211a737187aa475dfc8086ec670ff)) - -## [4.4.0](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v4.3.0...v4.4.0) (2023-07-05) - - -### 📝 Documentation - -* Update README.md ([3dd93d7](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/3dd93d7995345e8be3afd43f8ccbadf62c53a098)) - -## [4.3.0](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v4.2.3...v4.3.0) (2023-06-24) - - -### 🍕 Features - -* Add captive portal feature ([8534d51](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/8534d51a1338b318fc52b3a3365413c48059194c)) - -## [4.2.3](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v4.2.2...v4.2.3) (2023-06-24) - - -### 🐛 Bug Fixes - -* lib exports ([3fabdc6](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/3fabdc6bed294e0628b829f18fa0b63ca3c6c64d)) - -## [4.2.2](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v4.2.1...v4.2.2) (2023-06-24) - - -### 🐛 Bug Fixes - -* file case issue ([1c9e893](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/1c9e8933c9f0864df66a35b2c56f550a61bc2454)) - -## [4.2.1](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v4.2.0...v4.2.1) (2023-06-22) - - -### 🐛 Bug Fixes - -* issue with case on observer.cpp ([24ef808](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/24ef80821178f9bc10afe1c12cbfe8483c45e88e)) - -## [4.2.0](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v4.1.2...v4.2.0) (2023-06-22) - - -### 🍕 Features - -* add compatibility with esp_web_server.h ([ade38aa](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/ade38aa6e7c917e5749ff8e99aa675976fb0fa12)) - -## [4.1.2](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v4.1.1...v4.1.2) (2023-06-22) - - -### 🐛 Bug Fixes - -* bug in asyncota ([fe8a2bd](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/fe8a2bd70698660cfcf9598a67d7f95a2f0c9399)) - -## [4.1.1](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v4.1.0...v4.1.1) (2023-06-22) - - -### 🐛 Bug Fixes - -* bug in asyncota ([d5678b5](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/d5678b522c0e697b02ad17e8bd30f51c440932d8)) - -## [4.1.0](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v4.0.0...v4.1.0) (2023-06-21) - - -### 🍕 Features - -* add async ota ([6846fb4](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/6846fb4f771702000f8e3b11ef399d6992daeef7)) - -## [4.0.0](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v3.1.2...v4.0.0) (2023-06-21) - - -### ⚠ BREAKING CHANGES - -* changed API method names - -### 🧑‍💻 Code Refactoring - -* total project naming refactor ([39c8722](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/39c87220586ad75f39d17541a30a57686531637f)) - -## [3.1.2](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v3.1.1...v3.1.2) (2023-06-11) - - -### 🐛 Bug Fixes - -* bug in Observer.hpp ([f2c0d00](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/f2c0d00c2f76b5d8fdd23b337e5a512a70bee39d)) - -## [3.1.1](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v3.1.0...v3.1.1) (2023-06-04) - - -### 🧑‍💻 Code Refactoring - -* minor update to project state ([a977934](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/a97793488c21564c36a833d1884c4ac2120e57e7)) - -## [3.1.0](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v3.0.2...v3.1.0) (2023-05-29) - - -### 📝 Documentation - -* add example of custom config API ([83180de](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/83180de508e069e8f7ecdd7a3b534359a26e05b6)) - -## [3.0.2](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v3.0.1...v3.0.2) (2023-05-29) - - -### 🐛 Bug Fixes - -* improve custom config handler API ([04452b5](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/04452b55bba0db8fa13302fd90bef16ef253fcba)) - -## [3.0.1](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v3.0.0...v3.0.1) (2023-05-29) - - -### 🧑‍💻 Code Refactoring - -* improve custom config handler API ([a711812](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/a711812536e4af8a20921cfdd83590e3025f5a60)) - -## [3.0.0](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v2.1.2...v3.0.0) (2023-05-28) - - -### ⚠ BREAKING CHANGES - -* CHANGES - -- implement hot-reload handler for config - -### 🐛 Bug Fixes - -* duplicate config glitch ([16a20ca](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/16a20ca9ef021139b3a679307f7fdb3ccbd8e599)) - -## [2.1.2](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v2.1.1...v2.1.2) (2023-05-13) - - -### 🧑‍💻 Code Refactoring - -* simplify api ([56fdfd3](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/56fdfd3d67a182fcee86e111a3979dca56f4c3f2)) - -## [2.1.1](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v2.1.0...v2.1.1) (2023-05-13) - - -### 🧑‍💻 Code Refactoring - -* simplify api ([15ca82b](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/15ca82b2cd108ae66e4b8a4aa5241ae5c0f51a64)) - -## [2.1.0](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v2.0.0...v2.1.0) (2023-05-07) - - -### 🍕 Features - -* add wifi support for other boards ([9b1c5b5](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/9b1c5b518b4c99ebc72b6d386235b145cecd10fb)) - -## [2.0.0](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v1.12.0...v2.0.0) (2023-03-19) - - -### ⚠ BREAKING CHANGES - -* CHANGES - -### 🔁 Continuous Integration - -* update examples ([2119cb3](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/2119cb3ed63a4a0ae621bb41cf887a69f53a5067)) - - -### 🧑‍💻 Code Refactoring - -* simplify library interface ([4da399b](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/4da399bfde73f6c877810a3c3eebb3013fb3c05d)) - -## [1.12.0](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v1.11.4...v1.12.0) (2023-03-12) - - -### 🍕 Features - -* update Observer to be more event driven ([83d8c1c](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/83d8c1c4b08d275d08f658f57a826a5c8c0df464)) - -## [1.11.4](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v1.11.3...v1.11.4) (2023-03-09) - - -### 🐛 Bug Fixes - -* pathing error on linux ([ad1f13f](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/ad1f13f5b7e1e0a768bb34eab0818aa1ffd635ee)) - -## [1.11.3](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v1.11.2...v1.11.3) (2023-03-09) - - -### 🐛 Bug Fixes - -* pathing error on linux ([1d2840b](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/1d2840b57d8aad72868514468a7e61f94b42029c)) -* pathing error on linux ([3d3ba0f](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/3d3ba0f347fbb56d14c9d850bcc40b2eabd0bf83)) -* pathing error on linux ([c5acf62](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/c5acf6285b5a3f1e9e174c9e6e2abb45757e9894)) -* pathing error on linux ([24d37f8](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/24d37f8ca99e5af4721e22b7ab4cfdcd9799a194)) - -## [1.11.2](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v1.11.1...v1.11.2) (2023-03-09) - - -### 🐛 Bug Fixes - -* python script not working on linux ([54a9433](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/54a94332c4448404157c47d4c1d682216803b0aa)) - -## [1.11.1](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v1.11.0...v1.11.1) (2023-03-09) - - -### 🐛 Bug Fixes - -* pathing error on linux ([d2695d2](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/d2695d2dab2b23de74a1d1c9061c52c4e1e5e5b9)) - -## [1.11.0](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v1.10.1...v1.11.0) (2023-03-09) - - -### 🍕 Features - -* add local code to repo ([be1d00c](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/be1d00c912dc88afac965128b184c65677b2e59e)) - -## [1.10.1](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v1.10.0...v1.10.1) (2023-03-09) - - -### 🐛 Bug Fixes - -* fixed some bugs , made api cleaner to use ([f2bee95](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/f2bee95bffadb19f26d20107770554452cf8042c)) - -## [1.10.0](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v1.9.2...v1.10.0) (2023-03-09) - - -### 🍕 Features - -* remove the need for spiffs for wifimanager ([7c02ba3](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/7c02ba31e0010ed0f15b79d0fec506710723a973)) - -## [1.9.2](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v1.9.1...v1.9.2) (2023-03-03) - - -### 🐛 Bug Fixes - -* esp restar time on save ([c5c04f2](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/c5c04f2f047097d164d5082e56937777542761bf)) - -## [1.9.1](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v1.9.0...v1.9.1) (2023-03-01) - - -### 🐛 Bug Fixes - -* bug in wifi manager ([72cbf26](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/72cbf26679cd0dcbd48d3e501663f72f17613ada)) - -## [1.9.0](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v1.8.3...v1.9.0) (2023-02-27) - - -### 🍕 Features - -* add some network features ([e5ac88e](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/e5ac88e3035b8a678b5ebcbb737192cfbc979509)) - -## [1.8.3](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v1.8.2...v1.8.3) (2023-02-26) - - -### 🐛 Bug Fixes - -* fix static issue with checkWifiState() ([46ab85c](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/46ab85c2194b5bd0de2b316146c69d1767203730)) - -## [1.8.2](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v1.8.1...v1.8.2) (2023-02-26) - - -### 🐛 Bug Fixes - -* fix static issue with checkWifiState() ([58ffc52](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/58ffc52d3616f309f08c323859c40e0ec5ad423a)) - -## [1.8.1](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v1.8.0...v1.8.1) (2023-02-25) - - -### 🐛 Bug Fixes - -* fix multiple bugs ([cebcff1](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/cebcff1c7d3d2e7bd216f498686b29b1a47e30c3)) - -## [1.8.0](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v1.7.0...v1.8.0) (2023-02-19) - - -### 🍕 Features - -* add check for valid hostname ([22ee635](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/22ee635515237176bd832617c83a7c59781814d7)) - -## [1.7.0](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v1.6.0...v1.7.0) (2023-02-18) - - -### 🍕 Features - -* add proper mdns support ([dc497d0](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/dc497d0b1caaeea576f270f3cfa0d3a07d9d9389)) - -## [1.6.0](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v1.5.2...v1.6.0) (2023-02-18) - - -### 🍕 Features - -* add proper mdns support ([78afaa4](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/78afaa48ff15fe0a4c7b96989ee005841af4a1ab)) - -## [1.5.2](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v1.5.1...v1.5.2) (2023-02-16) - - -### 🐛 Bug Fixes - -* bug in helpers util ([e28117f](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/e28117f385334ac0491b048492a16bf7217ce6fa)) - -## [1.5.1](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v1.5.0...v1.5.1) (2023-02-16) - - -### 🐛 Bug Fixes - -* bug in detachAll ([3c0de59](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/3c0de59b2bc8a2bb9a57a3e18ffe5479ac1d2b04)) - -## [1.5.0](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v1.4.29...v1.5.0) (2023-02-16) - - -### 🍕 Features - -* add detachAll method to obersevers ([ff13bf8](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/ff13bf8c697f811da81b472499e47c1d5d84065c)) - -## [1.4.29](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v1.4.28...v1.4.29) (2023-02-16) - - -### 🐛 Bug Fixes - -* map network route-method maps public ([ec28bb2](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/ec28bb222f995fe0287de8f49869815398dcaf97)) - -## [1.4.28](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v1.4.27...v1.4.28) (2023-02-16) - - -### 🐛 Bug Fixes - -* api_utilities protected members ([f65e575](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/f65e5759052635d7d7a50815675099c41e12d25e)) - -## [1.4.27](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v1.4.26...v1.4.27) (2023-02-16) - - -### 🐛 Bug Fixes - -* make network maps public ([abfb7ee](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/abfb7ee407372c554a44f6f0a2b7fb8f9d4dee1a)) - -## [1.4.26](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v1.4.25...v1.4.26) (2023-02-16) - - -### 🐛 Bug Fixes - -* update Observer as template class ([c1447ef](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/c1447ef66f7755cbb81043358df8c5ce411a19de)) - -## [1.4.25](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v1.4.24...v1.4.25) (2023-02-16) - - -### 🐛 Bug Fixes - -* user defined functions ([352c06c](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/352c06c1a5e246af8905175303e3a73a662b11be)) - -## [1.4.24](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v1.4.23...v1.4.24) (2023-02-14) - - -### 🐛 Bug Fixes - -* make project config easier to use ([6abea1c](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/6abea1cfa6f31fa087a71035cc1a798b56b62508)) - -## [1.4.23](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v1.4.22...v1.4.23) (2023-02-14) - - -### 🐛 Bug Fixes - -* state manager ([5ca5ea6](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/5ca5ea647c54745e0a65cd136503868cca6de197)) - -## [1.4.22](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v1.4.21...v1.4.22) (2023-02-14) - - -### 🐛 Bug Fixes - -* state manager ([b929b3d](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/b929b3d821a72c61dd93a1d8db0c1c92b7d0e907)) - -## [1.4.21](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v1.4.20...v1.4.21) (2023-02-13) - - -### 🐛 Bug Fixes - -* library.json include pattern ([e2185e1](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/e2185e123956e79ce5ed94a8c570cbe234a9a7b7)) - -## [1.4.20](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v1.4.19...v1.4.20) (2023-02-13) - - -### 🐛 Bug Fixes - -* refactor project and simplify includes ([2efd957](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/2efd957a12278f03594456750e6e655b7e14b5d1)) - -## [1.4.19](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v1.4.18...v1.4.19) (2023-02-13) - - -### 🐛 Bug Fixes - -* create a platformio project using the lib structure ([3553ab1](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/3553ab19172f3a0f02d44ca159c3fe814983c6aa)) - -## [1.4.18](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v1.4.17...v1.4.18) (2023-01-19) - - -### 🧑‍💻 Code Refactoring - -* added new more verbose example ([f6f7581](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/f6f7581c58d2433cdf6ecf35bcad0d517679b623)) -* rename example to customHTML ([9f6dc77](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/9f6dc77b10ee90af711103b27f6f81b861cee5f7)) - -## [1.4.17](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v1.4.16...v1.4.17) (2023-01-18) - - -### 🧑‍💻 Code Refactoring - -* remove uneeded define from example ([151ce64](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/151ce6405aa7dfbf0816e2947db8bad609af8b88)) - -## [1.4.16](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v1.4.15...v1.4.16) (2023-01-18) - - -### 🧑‍💻 Code Refactoring - -* remove uneeded define from example ([e8dbcf1](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/e8dbcf1903900bc32134b0b623296e854ec773b2)) - -## [1.4.15](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v1.4.14...v1.4.15) (2023-01-18) - - -### 🧑‍💻 Code Refactoring - -* remove uneeded define from example ([0bf0492](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/0bf0492386974b71e4c0b42d8331c216e41ba831)) - -## [1.4.14](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v1.4.13...v1.4.14) (2023-01-18) - - -### 🧑‍💻 Code Refactoring - -* move ethernet to its own class ([45deb25](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/45deb2524125732ba694188abb6a15f3c0aabbd5)) - -## [1.4.13](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v1.4.12...v1.4.13) (2023-01-18) - - -### 🧑‍💻 Code Refactoring - -* move ethernet to its own class ([d5851a7](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/d5851a7bbaa9102182f158454b74755acd7329d2)) - -## [1.4.12](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v1.4.11...v1.4.12) (2023-01-18) - - -### 🔁 Continuous Integration - -* **ci-semver:** add automated changelog ([985eca0](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/985eca0d352ea44ef0833df7167a4dc9216feafd)) +# 📦 Changelog +[![conventional commits](https://img.shields.io/badge/conventional%20commits-1.0.0-yellow.svg)](https://conventionalcommits.org) +[![semantic versioning](https://img.shields.io/badge/semantic%20versioning-2.0.0-green.svg)](https://semver.org) +> All notable changes to this project will be documented in this file + +## [5.5.1](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v5.5.0...v5.5.1) (2024-04-16) + + +### 🐛 Bug Fixes + +* Fix the issue with the wifi handler not starting the access point ([2638d40](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/2638d40c4a26534c3495db3303fc76355c2e8351)) + +## [5.5.0](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v5.4.5...v5.5.0) (2024-04-15) + + +### 🍕 Features + +* Update setWifiConfig function in ProjectConfig class to toggle reboot status ([da92fd2](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/da92fd20deee4b4695885619e784245fe64dddf7)) + +## [5.4.5](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v5.4.4...v5.4.5) (2024-04-07) + + +### 🐛 Bug Fixes + +* update to new version of EasyHelpers ([4bf43a9](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/4bf43a9ea9f50bc9a91b731bff938166bce77771)) + +## [5.4.4](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v5.4.3...v5.4.4) (2024-04-06) + + +### 🐛 Bug Fixes + +* attach default handler to an endpoint ([c71b7d4](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/c71b7d42a0d091309c516d45e7981905265e5b41)) + +## [5.4.3](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v5.4.2...v5.4.3) (2024-04-06) + + +### 🐛 Bug Fixes + +* Refactor handleJson function parameters to pass JsonVariant by reference ([e4c9671](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/e4c9671d313f676689e1c44268f1b805f497fbd5)) + +## [5.4.2](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v5.4.1...v5.4.2) (2024-04-06) + + +### 🧑‍💻 Code Refactoring + +* Refactor handleJson function parameters in NetworkManager code ([46e6513](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/46e65135b12e27b9c33a9c9d9232f59d420ed336)) + +## [5.4.1](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v5.4.0...v5.4.1) (2024-04-06) + + +### 🐛 Bug Fixes + +* clean up some extranious left overs ([38eff9d](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/38eff9d4ab7f31150c777fac6f9942bf08c09890)) + +## [5.4.0](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v5.3.5...v5.4.0) (2024-04-05) + + +### 🍕 Features + +* update to new Helpers library ([3d10979](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/3d10979fa4c0bf6c40bf0c0e9866a3138a223817)) + +## [5.3.5](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v5.3.4...v5.3.5) (2024-04-01) + + +### 🐛 Bug Fixes + +* change to IId interface to replace getName() ([a7e2025](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/a7e2025162d039fccc0ac1f5b1a0e202d95b21cd)) + +## [5.3.4](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v5.3.3...v5.3.4) (2024-03-31) + + +### 🤖 Build System + +* Update ArduinoJson dependency in dev_config.ini ([58cb244](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/58cb24494ac29206c24ad207c244b006da6112f5)) + +## [5.3.3](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v5.3.2...v5.3.3) (2024-03-31) + + +### 🧑‍💻 Code Refactoring + +* migrate to helper lib, Update include paths and dependencies ([102ba5d](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/102ba5d2c702abd3653efe5b85d8c207ca0844f8)) + +## [5.3.2](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v5.3.1...v5.3.2) (2024-03-31) + + +### 🐛 Bug Fixes + +* Update ArduinoJson dependency ([fc4b182](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/fc4b1829507d38b2cbd4dd41fbf876542b40ffb6)) + +## [5.3.1](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v5.3.0...v5.3.1) (2024-03-31) + + +### 🧑‍💻 Code Refactoring + +* Update NetworkManager configuration and API handlers ([8c425c9](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/8c425c9b38b6f6c315385c47637f3f1bb79c3149)) + +## [5.3.0](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v5.2.3...v5.3.0) (2024-03-31) + + +### 🍕 Features + +* added ability to handle JSON data POST and GET ([53035ab](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/53035abc31fd4810fb3fd1f03cab1363525f2a69)) + +## [5.2.3](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v5.2.2...v5.2.3) (2024-03-30) + + +### 🧑‍💻 Code Refactoring + +* Update NetworkManager version and fix struct initialization ([764f579](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/764f579d3c826f9ff5731323fd420f8df5e140ad)) + +## [5.2.2](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v5.2.1...v5.2.2) (2024-03-30) + + +### 🧑‍💻 Code Refactoring + +* clean up project manager ([395ce7b](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/395ce7b0416543ea503fe062809fe6eda3c9f7ba)) + +## [5.2.1](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v5.2.0...v5.2.1) (2024-03-03) + + +### 🐛 Bug Fixes + +* update html file path ([33d1e13](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/33d1e135e654720614f5322a9a7eb5719fc79b6a)) + +## [5.2.0](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v5.1.4...v5.2.0) (2024-01-15) + + +### 📝 Documentation + +* add blurb about c++17 ([4d5027c](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/4d5027c7ea53d824421e03c485b791a7c017174e)) + +## [5.1.4](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v5.1.3...v5.1.4) (2023-12-21) + + +### 🐛 Bug Fixes + +* wifi activating before config load ([60dc0a3](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/60dc0a3b134c07dc2bc61b0ebf3f7e3e20480daf)) + +## [5.1.3](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v5.1.2...v5.1.3) (2023-12-21) + + +### 🐛 Bug Fixes + +* wifi reset issue when STA cannot be found ([2a67bb8](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/2a67bb8b8105d0547594b91fba44c64b15251f89)) + +## [5.1.2](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v5.1.1...v5.1.2) (2023-12-21) + + +### 🐛 Bug Fixes + +* wifi reset issue when STA cannot be found ([a2c679e](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/a2c679e0b1795aeb88e2cb255410ef29fac8b766)) + +## [5.1.1](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v5.1.0...v5.1.1) (2023-12-21) + + +### 🧑‍💻 Code Refactoring + +* add id to ISubject ([85fa400](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/85fa400241b514aa63b33b6cd8b76df859dceedd)) + +## [5.1.0](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v5.0.0...v5.1.0) (2023-12-21) + + +### 🍕 Features + +* add wifi event mappings to native wifi class ([2ff3a86](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/2ff3a86e1059e818df74a09d6f3179519bb16a6d)) + +## [5.0.0](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v4.5.8...v5.0.0) (2023-12-21) + + +### ⚠ BREAKING CHANGES + +* CHANGES + +- simplify the api A LOT +- setup the state machine to follow the observer pattern for easier use +- create a wrapper for updating the state +- update examples + +### 🍕 Features + +* add more fine grained examples ([2e18135](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/2e181358942ecccd7892c6a631deabad660db43e)) +* total project refactor ([0f70bec](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/0f70becd098fc582b07cd66cddd1d9c569cc6bc9)) + +## [4.5.8](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v4.5.7...v4.5.8) (2023-12-19) + + +### 🐛 Bug Fixes + +* fix error with logger ([c9e4acc](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/c9e4acccd2d3841fe5b18b6552c2723b8a68634e)) + +## [4.5.7](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v4.5.6...v4.5.7) (2023-12-18) + + +### 🧑‍💻 Code Refactoring + +* set wifi waiting printout to verbose log only ([f07add0](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/f07add01401d3f57955f270b52f59ce234dc651f)) + +## [4.5.6](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v4.5.5...v4.5.6) (2023-12-18) + + +### 🧑‍💻 Code Refactoring + +* set wifi waiting printout to verbose log only ([ce5bfc2](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/ce5bfc261a54366def17d15f608ef8260e95fe96)) + +## [4.5.5](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v4.5.4...v4.5.5) (2023-12-18) + + +### 🐛 Bug Fixes + +* minor change to wifi ([4d0d3ba](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/4d0d3ba92a6d7cbd97d50bf06904add27a0bbae6)) + +## [4.5.4](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v4.5.3...v4.5.4) (2023-12-15) + + +### 🧑‍💻 Code Refactoring + +* add id to ISubject ([6c8bf4c](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/6c8bf4c120b088dd46a6bcf05f9c610656b8191e)) + +## [4.5.3](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v4.5.2...v4.5.3) (2023-12-15) + + +### 🐛 Bug Fixes + +* set to ingest observer event enum as const reference ([25e5866](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/25e586656f4048808e6c8fc2a162fb4f9b3cd04c)) + +## [4.5.2](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v4.5.1...v4.5.2) (2023-11-25) + + +### 🐛 Bug Fixes + +* update examples ([867db66](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/867db6602fcb6936ba773209f3b1eadbe6130ebc)) + +## [4.5.1](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v4.5.0...v4.5.1) (2023-10-13) + + +### 🧑‍💻 Code Refactoring + +* total api structure refactor ([bc19316](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/bc1931647d06d6d4297552070b3bdbb663ea5306)) + +## [4.5.0](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v4.4.0...v4.5.0) (2023-09-26) + + +### 📝 Documentation + +* Update README.md ([4a24454](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/4a244545ccff822cf19f1147816483004b72a43c)) +* Update README.md ([c586bb3](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/c586bb34ba27547a5658210c59491ede00abbbf3)) +* Update README.md ([75617e8](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/75617e8a121bed6fe48765ca9e7ba67111274af6)) +* Update README.md ([5ef6c16](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/5ef6c168b9f1eb10eb7a78cfb24ac45fae98899e)) +* Update README.md ([e8b2aaf](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/e8b2aaf8c7679e3f0c2ff03fd631215f610f2a74)) +* Update README.md ([7eec690](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/7eec690df96dab275c43e75cb662ba8653efd66f)) + + +### 🔁 Continuous Integration + +* Update release.yml ([6f478a0](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/6f478a01bb9211a737187aa475dfc8086ec670ff)) + +## [4.4.0](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v4.3.0...v4.4.0) (2023-07-05) + + +### 📝 Documentation + +* Update README.md ([3dd93d7](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/3dd93d7995345e8be3afd43f8ccbadf62c53a098)) + +## [4.3.0](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v4.2.3...v4.3.0) (2023-06-24) + + +### 🍕 Features + +* Add captive portal feature ([8534d51](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/8534d51a1338b318fc52b3a3365413c48059194c)) + +## [4.2.3](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v4.2.2...v4.2.3) (2023-06-24) + + +### 🐛 Bug Fixes + +* lib exports ([3fabdc6](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/3fabdc6bed294e0628b829f18fa0b63ca3c6c64d)) + +## [4.2.2](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v4.2.1...v4.2.2) (2023-06-24) + + +### 🐛 Bug Fixes + +* file case issue ([1c9e893](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/1c9e8933c9f0864df66a35b2c56f550a61bc2454)) + +## [4.2.1](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v4.2.0...v4.2.1) (2023-06-22) + + +### 🐛 Bug Fixes + +* issue with case on observer.cpp ([24ef808](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/24ef80821178f9bc10afe1c12cbfe8483c45e88e)) + +## [4.2.0](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v4.1.2...v4.2.0) (2023-06-22) + + +### 🍕 Features + +* add compatibility with esp_web_server.h ([ade38aa](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/ade38aa6e7c917e5749ff8e99aa675976fb0fa12)) + +## [4.1.2](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v4.1.1...v4.1.2) (2023-06-22) + + +### 🐛 Bug Fixes + +* bug in asyncota ([fe8a2bd](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/fe8a2bd70698660cfcf9598a67d7f95a2f0c9399)) + +## [4.1.1](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v4.1.0...v4.1.1) (2023-06-22) + + +### 🐛 Bug Fixes + +* bug in asyncota ([d5678b5](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/d5678b522c0e697b02ad17e8bd30f51c440932d8)) + +## [4.1.0](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v4.0.0...v4.1.0) (2023-06-21) + + +### 🍕 Features + +* add async ota ([6846fb4](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/6846fb4f771702000f8e3b11ef399d6992daeef7)) + +## [4.0.0](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v3.1.2...v4.0.0) (2023-06-21) + + +### ⚠ BREAKING CHANGES + +* changed API method names + +### 🧑‍💻 Code Refactoring + +* total project naming refactor ([39c8722](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/39c87220586ad75f39d17541a30a57686531637f)) + +## [3.1.2](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v3.1.1...v3.1.2) (2023-06-11) + + +### 🐛 Bug Fixes + +* bug in Observer.hpp ([f2c0d00](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/f2c0d00c2f76b5d8fdd23b337e5a512a70bee39d)) + +## [3.1.1](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v3.1.0...v3.1.1) (2023-06-04) + + +### 🧑‍💻 Code Refactoring + +* minor update to project state ([a977934](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/a97793488c21564c36a833d1884c4ac2120e57e7)) + +## [3.1.0](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v3.0.2...v3.1.0) (2023-05-29) + + +### 📝 Documentation + +* add example of custom config API ([83180de](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/83180de508e069e8f7ecdd7a3b534359a26e05b6)) + +## [3.0.2](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v3.0.1...v3.0.2) (2023-05-29) + + +### 🐛 Bug Fixes + +* improve custom config handler API ([04452b5](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/04452b55bba0db8fa13302fd90bef16ef253fcba)) + +## [3.0.1](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v3.0.0...v3.0.1) (2023-05-29) + + +### 🧑‍💻 Code Refactoring + +* improve custom config handler API ([a711812](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/a711812536e4af8a20921cfdd83590e3025f5a60)) + +## [3.0.0](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v2.1.2...v3.0.0) (2023-05-28) + + +### ⚠ BREAKING CHANGES + +* CHANGES + +- implement hot-reload handler for config + +### 🐛 Bug Fixes + +* duplicate config glitch ([16a20ca](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/16a20ca9ef021139b3a679307f7fdb3ccbd8e599)) + +## [2.1.2](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v2.1.1...v2.1.2) (2023-05-13) + + +### 🧑‍💻 Code Refactoring + +* simplify api ([56fdfd3](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/56fdfd3d67a182fcee86e111a3979dca56f4c3f2)) + +## [2.1.1](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v2.1.0...v2.1.1) (2023-05-13) + + +### 🧑‍💻 Code Refactoring + +* simplify api ([15ca82b](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/15ca82b2cd108ae66e4b8a4aa5241ae5c0f51a64)) + +## [2.1.0](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v2.0.0...v2.1.0) (2023-05-07) + + +### 🍕 Features + +* add wifi support for other boards ([9b1c5b5](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/9b1c5b518b4c99ebc72b6d386235b145cecd10fb)) + +## [2.0.0](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v1.12.0...v2.0.0) (2023-03-19) + + +### ⚠ BREAKING CHANGES + +* CHANGES + +### 🔁 Continuous Integration + +* update examples ([2119cb3](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/2119cb3ed63a4a0ae621bb41cf887a69f53a5067)) + + +### 🧑‍💻 Code Refactoring + +* simplify library interface ([4da399b](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/4da399bfde73f6c877810a3c3eebb3013fb3c05d)) + +## [1.12.0](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v1.11.4...v1.12.0) (2023-03-12) + + +### 🍕 Features + +* update Observer to be more event driven ([83d8c1c](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/83d8c1c4b08d275d08f658f57a826a5c8c0df464)) + +## [1.11.4](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v1.11.3...v1.11.4) (2023-03-09) + + +### 🐛 Bug Fixes + +* pathing error on linux ([ad1f13f](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/ad1f13f5b7e1e0a768bb34eab0818aa1ffd635ee)) + +## [1.11.3](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v1.11.2...v1.11.3) (2023-03-09) + + +### 🐛 Bug Fixes + +* pathing error on linux ([1d2840b](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/1d2840b57d8aad72868514468a7e61f94b42029c)) +* pathing error on linux ([3d3ba0f](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/3d3ba0f347fbb56d14c9d850bcc40b2eabd0bf83)) +* pathing error on linux ([c5acf62](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/c5acf6285b5a3f1e9e174c9e6e2abb45757e9894)) +* pathing error on linux ([24d37f8](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/24d37f8ca99e5af4721e22b7ab4cfdcd9799a194)) + +## [1.11.2](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v1.11.1...v1.11.2) (2023-03-09) + + +### 🐛 Bug Fixes + +* python script not working on linux ([54a9433](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/54a94332c4448404157c47d4c1d682216803b0aa)) + +## [1.11.1](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v1.11.0...v1.11.1) (2023-03-09) + + +### 🐛 Bug Fixes + +* pathing error on linux ([d2695d2](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/d2695d2dab2b23de74a1d1c9061c52c4e1e5e5b9)) + +## [1.11.0](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v1.10.1...v1.11.0) (2023-03-09) + + +### 🍕 Features + +* add local code to repo ([be1d00c](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/be1d00c912dc88afac965128b184c65677b2e59e)) + +## [1.10.1](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v1.10.0...v1.10.1) (2023-03-09) + + +### 🐛 Bug Fixes + +* fixed some bugs , made api cleaner to use ([f2bee95](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/f2bee95bffadb19f26d20107770554452cf8042c)) + +## [1.10.0](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v1.9.2...v1.10.0) (2023-03-09) + + +### 🍕 Features + +* remove the need for spiffs for wifimanager ([7c02ba3](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/7c02ba31e0010ed0f15b79d0fec506710723a973)) + +## [1.9.2](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v1.9.1...v1.9.2) (2023-03-03) + + +### 🐛 Bug Fixes + +* esp restar time on save ([c5c04f2](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/c5c04f2f047097d164d5082e56937777542761bf)) + +## [1.9.1](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v1.9.0...v1.9.1) (2023-03-01) + + +### 🐛 Bug Fixes + +* bug in wifi manager ([72cbf26](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/72cbf26679cd0dcbd48d3e501663f72f17613ada)) + +## [1.9.0](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v1.8.3...v1.9.0) (2023-02-27) + + +### 🍕 Features + +* add some network features ([e5ac88e](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/e5ac88e3035b8a678b5ebcbb737192cfbc979509)) + +## [1.8.3](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v1.8.2...v1.8.3) (2023-02-26) + + +### 🐛 Bug Fixes + +* fix static issue with checkWifiState() ([46ab85c](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/46ab85c2194b5bd0de2b316146c69d1767203730)) + +## [1.8.2](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v1.8.1...v1.8.2) (2023-02-26) + + +### 🐛 Bug Fixes + +* fix static issue with checkWifiState() ([58ffc52](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/58ffc52d3616f309f08c323859c40e0ec5ad423a)) + +## [1.8.1](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v1.8.0...v1.8.1) (2023-02-25) + + +### 🐛 Bug Fixes + +* fix multiple bugs ([cebcff1](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/cebcff1c7d3d2e7bd216f498686b29b1a47e30c3)) + +## [1.8.0](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v1.7.0...v1.8.0) (2023-02-19) + + +### 🍕 Features + +* add check for valid hostname ([22ee635](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/22ee635515237176bd832617c83a7c59781814d7)) + +## [1.7.0](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v1.6.0...v1.7.0) (2023-02-18) + + +### 🍕 Features + +* add proper mdns support ([dc497d0](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/dc497d0b1caaeea576f270f3cfa0d3a07d9d9389)) + +## [1.6.0](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v1.5.2...v1.6.0) (2023-02-18) + + +### 🍕 Features + +* add proper mdns support ([78afaa4](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/78afaa48ff15fe0a4c7b96989ee005841af4a1ab)) + +## [1.5.2](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v1.5.1...v1.5.2) (2023-02-16) + + +### 🐛 Bug Fixes + +* bug in helpers util ([e28117f](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/e28117f385334ac0491b048492a16bf7217ce6fa)) + +## [1.5.1](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v1.5.0...v1.5.1) (2023-02-16) + + +### 🐛 Bug Fixes + +* bug in detachAll ([3c0de59](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/3c0de59b2bc8a2bb9a57a3e18ffe5479ac1d2b04)) + +## [1.5.0](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v1.4.29...v1.5.0) (2023-02-16) + + +### 🍕 Features + +* add detachAll method to obersevers ([ff13bf8](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/ff13bf8c697f811da81b472499e47c1d5d84065c)) + +## [1.4.29](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v1.4.28...v1.4.29) (2023-02-16) + + +### 🐛 Bug Fixes + +* map network route-method maps public ([ec28bb2](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/ec28bb222f995fe0287de8f49869815398dcaf97)) + +## [1.4.28](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v1.4.27...v1.4.28) (2023-02-16) + + +### 🐛 Bug Fixes + +* api_utilities protected members ([f65e575](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/f65e5759052635d7d7a50815675099c41e12d25e)) + +## [1.4.27](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v1.4.26...v1.4.27) (2023-02-16) + + +### 🐛 Bug Fixes + +* make network maps public ([abfb7ee](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/abfb7ee407372c554a44f6f0a2b7fb8f9d4dee1a)) + +## [1.4.26](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v1.4.25...v1.4.26) (2023-02-16) + + +### 🐛 Bug Fixes + +* update Observer as template class ([c1447ef](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/c1447ef66f7755cbb81043358df8c5ce411a19de)) + +## [1.4.25](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v1.4.24...v1.4.25) (2023-02-16) + + +### 🐛 Bug Fixes + +* user defined functions ([352c06c](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/352c06c1a5e246af8905175303e3a73a662b11be)) + +## [1.4.24](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v1.4.23...v1.4.24) (2023-02-14) + + +### 🐛 Bug Fixes + +* make project config easier to use ([6abea1c](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/6abea1cfa6f31fa087a71035cc1a798b56b62508)) + +## [1.4.23](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v1.4.22...v1.4.23) (2023-02-14) + + +### 🐛 Bug Fixes + +* state manager ([5ca5ea6](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/5ca5ea647c54745e0a65cd136503868cca6de197)) + +## [1.4.22](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v1.4.21...v1.4.22) (2023-02-14) + + +### 🐛 Bug Fixes + +* state manager ([b929b3d](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/b929b3d821a72c61dd93a1d8db0c1c92b7d0e907)) + +## [1.4.21](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v1.4.20...v1.4.21) (2023-02-13) + + +### 🐛 Bug Fixes + +* library.json include pattern ([e2185e1](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/e2185e123956e79ce5ed94a8c570cbe234a9a7b7)) + +## [1.4.20](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v1.4.19...v1.4.20) (2023-02-13) + + +### 🐛 Bug Fixes + +* refactor project and simplify includes ([2efd957](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/2efd957a12278f03594456750e6e655b7e14b5d1)) + +## [1.4.19](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v1.4.18...v1.4.19) (2023-02-13) + + +### 🐛 Bug Fixes + +* create a platformio project using the lib structure ([3553ab1](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/3553ab19172f3a0f02d44ca159c3fe814983c6aa)) + +## [1.4.18](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v1.4.17...v1.4.18) (2023-01-19) + + +### 🧑‍💻 Code Refactoring + +* added new more verbose example ([f6f7581](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/f6f7581c58d2433cdf6ecf35bcad0d517679b623)) +* rename example to customHTML ([9f6dc77](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/9f6dc77b10ee90af711103b27f6f81b861cee5f7)) + +## [1.4.17](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v1.4.16...v1.4.17) (2023-01-18) + + +### 🧑‍💻 Code Refactoring + +* remove uneeded define from example ([151ce64](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/151ce6405aa7dfbf0816e2947db8bad609af8b88)) + +## [1.4.16](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v1.4.15...v1.4.16) (2023-01-18) + + +### 🧑‍💻 Code Refactoring + +* remove uneeded define from example ([e8dbcf1](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/e8dbcf1903900bc32134b0b623296e854ec773b2)) + +## [1.4.15](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v1.4.14...v1.4.15) (2023-01-18) + + +### 🧑‍💻 Code Refactoring + +* remove uneeded define from example ([0bf0492](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/0bf0492386974b71e4c0b42d8331c216e41ba831)) + +## [1.4.14](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v1.4.13...v1.4.14) (2023-01-18) + + +### 🧑‍💻 Code Refactoring + +* move ethernet to its own class ([45deb25](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/45deb2524125732ba694188abb6a15f3c0aabbd5)) + +## [1.4.13](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v1.4.12...v1.4.13) (2023-01-18) + + +### 🧑‍💻 Code Refactoring + +* move ethernet to its own class ([d5851a7](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/d5851a7bbaa9102182f158454b74755acd7329d2)) + +## [1.4.12](https://github.com/ZanzyTHEbar/EasyNetworkManager/compare/v1.4.11...v1.4.12) (2023-01-18) + + +### 🔁 Continuous Integration + +* **ci-semver:** add automated changelog ([985eca0](https://github.com/ZanzyTHEbar/EasyNetworkManager/commit/985eca0d352ea44ef0833df7167a4dc9216feafd)) diff --git a/EasyNetworkManager.code-workspace b/EasyNetworkManager.code-workspace index 04e0630..d7143dd 100644 --- a/EasyNetworkManager.code-workspace +++ b/EasyNetworkManager.code-workspace @@ -1,131 +1,131 @@ -{ - "folders": [ - { - "name": "Source", - "path": "./NetworkManager" - }, - { - "name": "Root", - "path": "." - } - ], - "settings": { - "cSpell.words": [ - "APIURL", - "ASYNCOTA", - "devkitc", - "GIGA", - "MKRWIFI", - "mycommands", - "NICLA", - "PORTENTA", - "PROGMEM", - "SAMD", - "successs", - "txpower", - "WEBMANAGER", - "wokwi", - "zopfli" - ], - "files.associations": { - "*.json.liquid": "json", - "*.yaml.liquid": "yaml", - "*.md.liquid": "markdown", - "*.js.liquid": "liquid-javascript", - "*.css.liquid": "liquid-css", - "*.scss.liquid": "liquid-scss", - "*.Rmd": "rmd", - "*.rmd": "markdown", - "functional": "cpp", - "array": "cpp", - "atomic": "cpp", - "*.tcc": "cpp", - "bitset": "cpp", - "cctype": "cpp", - "clocale": "cpp", - "cmath": "cpp", - "cstdarg": "cpp", - "cstddef": "cpp", - "cstdint": "cpp", - "cstdio": "cpp", - "cstdlib": "cpp", - "cstring": "cpp", - "ctime": "cpp", - "cwchar": "cpp", - "cwctype": "cpp", - "deque": "cpp", - "unordered_map": "cpp", - "unordered_set": "cpp", - "vector": "cpp", - "exception": "cpp", - "algorithm": "cpp", - "iterator": "cpp", - "map": "cpp", - "memory": "cpp", - "memory_resource": "cpp", - "numeric": "cpp", - "optional": "cpp", - "random": "cpp", - "regex": "cpp", - "string": "cpp", - "string_view": "cpp", - "system_error": "cpp", - "tuple": "cpp", - "type_traits": "cpp", - "utility": "cpp", - "fstream": "cpp", - "initializer_list": "cpp", - "iomanip": "cpp", - "iosfwd": "cpp", - "iostream": "cpp", - "istream": "cpp", - "limits": "cpp", - "new": "cpp", - "ostream": "cpp", - "sstream": "cpp", - "stdexcept": "cpp", - "streambuf": "cpp", - "cinttypes": "cpp", - "typeinfo": "cpp", - "bit": "cpp", - "charconv": "cpp", - "chrono": "cpp", - "compare": "cpp", - "concepts": "cpp", - "condition_variable": "cpp", - "coroutine": "cpp", - "format": "cpp", - "forward_list": "cpp", - "ios": "cpp", - "list": "cpp", - "locale": "cpp", - "mutex": "cpp", - "queue": "cpp", - "ranges": "cpp", - "ratio": "cpp", - "span": "cpp", - "stack": "cpp", - "stop_token": "cpp", - "thread": "cpp", - "xfacet": "cpp", - "xhash": "cpp", - "xiosbase": "cpp", - "xlocale": "cpp", - "xlocbuf": "cpp", - "xlocinfo": "cpp", - "xlocmes": "cpp", - "xlocmon": "cpp", - "xlocnum": "cpp", - "xloctime": "cpp", - "xmemory": "cpp", - "xstddef": "cpp", - "xstring": "cpp", - "xtr1common": "cpp", - "xtree": "cpp", - "xutility": "cpp", - "variant": "cpp", - "set": "cpp", - "future": "cpp" - } - } +{ + "folders": [ + { + "name": "Source", + "path": "./NetworkManager" + }, + { + "name": "Root", + "path": "." + } + ], + "settings": { + "cSpell.words": [ + "APIURL", + "ASYNCOTA", + "devkitc", + "GIGA", + "MKRWIFI", + "mycommands", + "NICLA", + "PORTENTA", + "PROGMEM", + "SAMD", + "successs", + "txpower", + "WEBMANAGER", + "wokwi", + "zopfli" + ], + "files.associations": { + "*.json.liquid": "json", + "*.yaml.liquid": "yaml", + "*.md.liquid": "markdown", + "*.js.liquid": "liquid-javascript", + "*.css.liquid": "liquid-css", + "*.scss.liquid": "liquid-scss", + "*.Rmd": "rmd", + "*.rmd": "markdown", + "functional": "cpp", + "array": "cpp", + "atomic": "cpp", + "*.tcc": "cpp", + "bitset": "cpp", + "cctype": "cpp", + "clocale": "cpp", + "cmath": "cpp", + "cstdarg": "cpp", + "cstddef": "cpp", + "cstdint": "cpp", + "cstdio": "cpp", + "cstdlib": "cpp", + "cstring": "cpp", + "ctime": "cpp", + "cwchar": "cpp", + "cwctype": "cpp", + "deque": "cpp", + "unordered_map": "cpp", + "unordered_set": "cpp", + "vector": "cpp", + "exception": "cpp", + "algorithm": "cpp", + "iterator": "cpp", + "map": "cpp", + "memory": "cpp", + "memory_resource": "cpp", + "numeric": "cpp", + "optional": "cpp", + "random": "cpp", + "regex": "cpp", + "string": "cpp", + "string_view": "cpp", + "system_error": "cpp", + "tuple": "cpp", + "type_traits": "cpp", + "utility": "cpp", + "fstream": "cpp", + "initializer_list": "cpp", + "iomanip": "cpp", + "iosfwd": "cpp", + "iostream": "cpp", + "istream": "cpp", + "limits": "cpp", + "new": "cpp", + "ostream": "cpp", + "sstream": "cpp", + "stdexcept": "cpp", + "streambuf": "cpp", + "cinttypes": "cpp", + "typeinfo": "cpp", + "bit": "cpp", + "charconv": "cpp", + "chrono": "cpp", + "compare": "cpp", + "concepts": "cpp", + "condition_variable": "cpp", + "coroutine": "cpp", + "format": "cpp", + "forward_list": "cpp", + "ios": "cpp", + "list": "cpp", + "locale": "cpp", + "mutex": "cpp", + "queue": "cpp", + "ranges": "cpp", + "ratio": "cpp", + "span": "cpp", + "stack": "cpp", + "stop_token": "cpp", + "thread": "cpp", + "xfacet": "cpp", + "xhash": "cpp", + "xiosbase": "cpp", + "xlocale": "cpp", + "xlocbuf": "cpp", + "xlocinfo": "cpp", + "xlocmes": "cpp", + "xlocmon": "cpp", + "xlocnum": "cpp", + "xloctime": "cpp", + "xmemory": "cpp", + "xstddef": "cpp", + "xstring": "cpp", + "xtr1common": "cpp", + "xtree": "cpp", + "xutility": "cpp", + "variant": "cpp", + "set": "cpp", + "future": "cpp" + } + } } \ No newline at end of file diff --git a/LICENSE b/LICENSE index 4776480..011dd10 100644 --- a/LICENSE +++ b/LICENSE @@ -1,21 +1,21 @@ -MIT License - -Copyright (c) 2022 DaOfficialWizard - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +MIT License + +Copyright (c) 2022 DaOfficialWizard + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/NetworkManager/.clang-format b/NetworkManager/.clang-format index a0c80f5..e1371aa 100644 --- a/NetworkManager/.clang-format +++ b/NetworkManager/.clang-format @@ -1,13 +1,13 @@ -# http://clang.llvm.org/docs/ClangFormatStyleOptions.html - -BasedOnStyle: Google -Standard: Cpp03 -IndentWidth: 4 -AllowShortFunctionsOnASingleLine: Empty -IncludeBlocks: Preserve -IndentPPDirectives: AfterHash -DerivePointerAlignment: false - -# Always break after if to get accurate coverage -AllowShortIfStatementsOnASingleLine: false -AllowShortLoopsOnASingleLine: false +# http://clang.llvm.org/docs/ClangFormatStyleOptions.html + +BasedOnStyle: Google +Standard: Cpp03 +IndentWidth: 4 +AllowShortFunctionsOnASingleLine: Empty +IncludeBlocks: Preserve +IndentPPDirectives: AfterHash +DerivePointerAlignment: false + +# Always break after if to get accurate coverage +AllowShortIfStatementsOnASingleLine: false +AllowShortLoopsOnASingleLine: false diff --git a/NetworkManager/.editorconfig b/NetworkManager/.editorconfig index 74f32b3..98aec7e 100644 --- a/NetworkManager/.editorconfig +++ b/NetworkManager/.editorconfig @@ -1,13 +1,13 @@ -# top-most EditorConfig file -root = true - -# Unix-style newlines with a newline ending every file -#[*] -#charset = utf-8 -#trim_trailing_whitespace = true -#end_of_line = lf -#insert_final_newline = true - -# Tab indentation (no size specified) -[Makefile] -indent_style = tab +# top-most EditorConfig file +root = true + +# Unix-style newlines with a newline ending every file +#[*] +#charset = utf-8 +#trim_trailing_whitespace = true +#end_of_line = lf +#insert_final_newline = true + +# Tab indentation (no size specified) +[Makefile] +indent_style = tab diff --git a/NetworkManager/.gitignore b/NetworkManager/.gitignore index 51e7ee1..61f9332 100644 --- a/NetworkManager/.gitignore +++ b/NetworkManager/.gitignore @@ -1,11 +1,11 @@ -.pio -.vscode/.browse.c_cpp.db* -.vscode/c_cpp_properties.json -.vscode/launch.json -.vscode/ipch -src/main.cpp -node_modules -/include/secrets.h -/tools/__pycache__ -/tools/firmware_name.txt -/logs +.pio +.vscode/.browse.c_cpp.db* +.vscode/c_cpp_properties.json +.vscode/launch.json +.vscode/ipch +src/main.cpp +node_modules +/include/secrets.h +/tools/__pycache__ +/tools/firmware_name.txt +/logs diff --git a/NetworkManager/diagram.json b/NetworkManager/diagram.json index 32824f9..4c25183 100644 --- a/NetworkManager/diagram.json +++ b/NetworkManager/diagram.json @@ -1,73 +1,73 @@ -{ - "version": 1, - "author": "DaOfficialWizard", - "editor": "wokwi", - "parts": [ - { - "type": "board-esp32-s3-devkitc-1", - "id": "esp", - "top": 0, - "left": 0, - "attrs": {} - }, - { - "type": "wokwi-led", - "id": "led1", - "top": 114, - "left": 208.2, - "rotate": 90, - "attrs": { - "color": "red" - } - }, - { - "type": "wokwi-resistor", - "id": "r1", - "top": 138.35, - "left": 124.8, - "attrs": { - "value": "220" - } - } - ], - "connections": [ - [ - "esp:TX", - "$serialMonitor:RX", - "", - [] - ], - [ - "esp:RX", - "$serialMonitor:TX", - "", - [] - ], - [ - "r1:1", - "esp:4", - "green", - [ - "v0" - ] - ], - [ - "r1:2", - "led1:A", - "green", - [ - "v0" - ] - ], - [ - "led1:C", - "esp:GND.2", - "green", - [ - "h0", - "v-105.2" - ] - ] - ], - "dependencies": {} +{ + "version": 1, + "author": "DaOfficialWizard", + "editor": "wokwi", + "parts": [ + { + "type": "board-esp32-s3-devkitc-1", + "id": "esp", + "top": 0, + "left": 0, + "attrs": {} + }, + { + "type": "wokwi-led", + "id": "led1", + "top": 114, + "left": 208.2, + "rotate": 90, + "attrs": { + "color": "red" + } + }, + { + "type": "wokwi-resistor", + "id": "r1", + "top": 138.35, + "left": 124.8, + "attrs": { + "value": "220" + } + } + ], + "connections": [ + [ + "esp:TX", + "$serialMonitor:RX", + "", + [] + ], + [ + "esp:RX", + "$serialMonitor:TX", + "", + [] + ], + [ + "r1:1", + "esp:4", + "green", + [ + "v0" + ] + ], + [ + "r1:2", + "led1:A", + "green", + [ + "v0" + ] + ], + [ + "led1:C", + "esp:GND.2", + "green", + [ + "h0", + "v-105.2" + ] + ] + ], + "dependencies": {} } \ No newline at end of file diff --git a/NetworkManager/examples/captivePortal.cpp b/NetworkManager/examples/captivePortal.cpp index 5f96531..9f80f87 100644 --- a/NetworkManager/examples/captivePortal.cpp +++ b/NetworkManager/examples/captivePortal.cpp @@ -1,87 +1,87 @@ -#include -#include // (*) used for captive portal -#include - -/** - * @brief Setup the EasyNetworkManager Instance - * @note The EasyNetworkManager constructor takes 12 parameters: - * @param config_name The name of the project (used to create the config - * file name) - * @param hostname The hostname for your device on the network(used for - * mDNS, OTA, etc.) - * @param ssid The SSID of the WiFi network to connect to - * @param password The password of the WiFi network to connect to - * @param channel The channel of the WiFi network to connect to - * @param service_name The name of the service - * @param service_instance_name The instance name of the service - * @param service_protocol The protocol of the service - * @param service_description The description of the service - * @param service_port The port of the service - * @param enable_mdns Enable mDNS - * @param enable_adhoc Enable Adhoc - */ -EasyNetworkManager networkManager("easynetwork", MDNS_HOSTNAME, WIFI_SSID, - WIFI_PASSWORD, 1, "_easynetwork", "test", - "_tcp", "_api_port", "80", true, false); - -/** - * @brief Setup the AsyncServer Instance - * @note The AsyncServer constructor takes 5 parameters: - * @param port The port to listen on - * @param config The config manager - * @param api_path The path to the API - * @param wifi_manager_path The path to the WiFi Manager - * @param command_path The path to the command handler - */ -AsyncServer_t async_server(80, networkManager.configHandler->config, "/api", - "/wifimanager", "/mycommands", "/json"); - -/** - * @brief Setup the API Server Instance - * @note The API Server constructor takes 2 parameters: - * @param config The config manager - * @param server The AsyncServer instance - */ -APIServer api(networkManager.configHandler->config, async_server); - -DNSServer dnsServer; - -// Note: Here are two functions that can be used to handle custom API requests -void printHelloWorld(AsyncWebServerRequest* request) { - Serial.println("Hello World!"); - request->send(200, "text/plain", "Hello World!"); -} - -void blink(AsyncWebServerRequest* request) { - digitalWrite(4, HIGH); - Network_Utilities::my_delay(1); // delay for 1sec - digitalWrite(4, LOW); - Network_Utilities::my_delay(1); // delay for 1sec - request->send(200, "text/plain", "Blink!"); -} - -void setupServer() { - // add command handlers to the API server - // you can add as many as you want - you can also add methods. - log_d("[SETUP]: Starting API Server"); - api.setupCaptivePortal(true); - api.addAPICommand("blink", blink); - api.addAPICommand("helloWorld", printHelloWorld); - api.begin(); - log_d("[SETUP]: API Server Started"); -} - -void setup() { - Serial.begin(115200); - pinMode(4, OUTPUT); - Serial.println("\nHello, EasyNetworkManager!"); - - networkManager.begin(); - dnsServer.start(53, "*", WiFi.softAPIP()); - - setupServer(); -} - -void loop() { - dnsServer.processNextRequest(); -} +#include +#include // (*) used for captive portal +#include + +/** + * @brief Setup the EasyNetworkManager Instance + * @note The EasyNetworkManager constructor takes 12 parameters: + * @param config_name The name of the project (used to create the config + * file name) + * @param hostname The hostname for your device on the network(used for + * mDNS, OTA, etc.) + * @param ssid The SSID of the WiFi network to connect to + * @param password The password of the WiFi network to connect to + * @param channel The channel of the WiFi network to connect to + * @param service_name The name of the service + * @param service_instance_name The instance name of the service + * @param service_protocol The protocol of the service + * @param service_description The description of the service + * @param service_port The port of the service + * @param enable_mdns Enable mDNS + * @param enable_adhoc Enable Adhoc + */ +EasyNetworkManager networkManager("easynetwork", MDNS_HOSTNAME, WIFI_SSID, + WIFI_PASSWORD, 1, "_easynetwork", "test", + "_tcp", "_api_port", "80", true, false); + +/** + * @brief Setup the AsyncServer Instance + * @note The AsyncServer constructor takes 5 parameters: + * @param port The port to listen on + * @param config The config manager + * @param api_path The path to the API + * @param wifi_manager_path The path to the WiFi Manager + * @param command_path The path to the command handler + */ +AsyncServer_t async_server(80, networkManager.configHandler->config, "/api", + "/wifimanager", "/mycommands", "/json"); + +/** + * @brief Setup the API Server Instance + * @note The API Server constructor takes 2 parameters: + * @param config The config manager + * @param server The AsyncServer instance + */ +APIServer api(networkManager.configHandler->config, async_server); + +DNSServer dnsServer; + +// Note: Here are two functions that can be used to handle custom API requests +void printHelloWorld(AsyncWebServerRequest* request) { + Serial.println("Hello World!"); + request->send(200, "text/plain", "Hello World!"); +} + +void blink(AsyncWebServerRequest* request) { + digitalWrite(4, HIGH); + Network_Utilities::my_delay(1); // delay for 1sec + digitalWrite(4, LOW); + Network_Utilities::my_delay(1); // delay for 1sec + request->send(200, "text/plain", "Blink!"); +} + +void setupServer() { + // add command handlers to the API server + // you can add as many as you want - you can also add methods. + log_d("[SETUP]: Starting API Server"); + api.setupCaptivePortal(true); + api.addAPICommand("blink", blink); + api.addAPICommand("helloWorld", printHelloWorld); + api.begin(); + log_d("[SETUP]: API Server Started"); +} + +void setup() { + Serial.begin(115200); + pinMode(4, OUTPUT); + Serial.println("\nHello, EasyNetworkManager!"); + + networkManager.begin(); + dnsServer.start(53, "*", WiFi.softAPIP()); + + setupServer(); +} + +void loop() { + dnsServer.processNextRequest(); +} diff --git a/NetworkManager/examples/class.cpp b/NetworkManager/examples/class.cpp index 9681190..5c8e436 100644 --- a/NetworkManager/examples/class.cpp +++ b/NetworkManager/examples/class.cpp @@ -1,96 +1,96 @@ -#include -#include - -/** - * @brief Setup the EasyNetworkManager Instance - * @note The EasyNetworkManager constructor takes 12 parameters: - * @param config_name The name of the project (used to create the config - * file name) - * @param hostname The hostname for your device on the network(used for - * mDNS, OTA, etc.) - * @param ssid The SSID of the WiFi network to connect to - * @param password The password of the WiFi network to connect to - * @param channel The channel of the WiFi network to connect to - * @param service_name The name of the service - * @param service_instance_name The instance name of the service - * @param service_protocol The protocol of the service - * @param service_description The description of the service - * @param service_port The port of the service - * @param enable_mdns Enable mDNS - * @param enable_adhoc Enable Adhoc - */ -EasyNetworkManager networkManager("easynetwork", MDNS_HOSTNAME, WIFI_SSID, - WIFI_PASSWORD, 1, "_easynetwork", "test", - "_tcp", "_api_port", "80", true, false); - -/** - * @brief Setup the AsyncServer Instance - * @note The AsyncServer constructor takes 5 parameters: - * @param port The port to listen on - * @param config The config manager - * @param api_path The path to the API - * @param wifi_manager_path The path to the WiFi Manager - * @param command_path The path to the command handler - */ -AsyncServer_t async_server(80, networkManager.configHandler->config, "/api", - "/wifimanager", "/mycommands", "/json"); - -/** - * @brief Setup the API Server Instance - * @note The API Server constructor takes 2 parameters: - * @param config The config manager - * @param server The AsyncServer instance - */ -APIServer api(networkManager.configHandler->config, async_server); - -class Temp { - public: - Temp() { - Serial.println("Temp created"); - } - ~Temp() { - Serial.println("Temp destroyed"); - } - // Note: Here is a function that can be used to handle custom API requests - // inside Note: of a class - void grabParams(AsyncWebServerRequest* request) { - int params = request->params(); - log_d("Number of Params: %d", params); - std::string y; - std::string x; - for (int i = 0; i < params; i++) { - AsyncWebParameter* param = request->getParam(i); - if (param->name() == "Axes1") { - x = param->value().c_str(); - } else if (param->name() == "Axes2") { - y = param->value().c_str(); - } - } - Serial.printf("Axes1: %s, Axes2: %s\n", x.c_str(), y.c_str()); - request->send(200, "text/plain", "OK"); - } -}; - -void setupServer() { - // add command handlers to the API server - // you can add as many as you want - you can also add methods. - log_d("[SETUP]: Starting API Server"); - api.addAPICommand("paramsClass", [&](AsyncWebServerRequest* request) { - Temp t; - t.grabParams(request); - }); - - api.begin(); - log_d("[SETUP]: API Server Started"); -} - -void setup() { - Serial.begin(115200); - pinMode(4, OUTPUT); - Serial.println("\nHello, EasyNetworkManager!"); - networkManager.begin(); - - setupServer(); -} - -void loop() {} +#include +#include + +/** + * @brief Setup the EasyNetworkManager Instance + * @note The EasyNetworkManager constructor takes 12 parameters: + * @param config_name The name of the project (used to create the config + * file name) + * @param hostname The hostname for your device on the network(used for + * mDNS, OTA, etc.) + * @param ssid The SSID of the WiFi network to connect to + * @param password The password of the WiFi network to connect to + * @param channel The channel of the WiFi network to connect to + * @param service_name The name of the service + * @param service_instance_name The instance name of the service + * @param service_protocol The protocol of the service + * @param service_description The description of the service + * @param service_port The port of the service + * @param enable_mdns Enable mDNS + * @param enable_adhoc Enable Adhoc + */ +EasyNetworkManager networkManager("easynetwork", MDNS_HOSTNAME, WIFI_SSID, + WIFI_PASSWORD, 1, "_easynetwork", "test", + "_tcp", "_api_port", "80", true, false); + +/** + * @brief Setup the AsyncServer Instance + * @note The AsyncServer constructor takes 5 parameters: + * @param port The port to listen on + * @param config The config manager + * @param api_path The path to the API + * @param wifi_manager_path The path to the WiFi Manager + * @param command_path The path to the command handler + */ +AsyncServer_t async_server(80, networkManager.configHandler->config, "/api", + "/wifimanager", "/mycommands", "/json"); + +/** + * @brief Setup the API Server Instance + * @note The API Server constructor takes 2 parameters: + * @param config The config manager + * @param server The AsyncServer instance + */ +APIServer api(networkManager.configHandler->config, async_server); + +class Temp { + public: + Temp() { + Serial.println("Temp created"); + } + ~Temp() { + Serial.println("Temp destroyed"); + } + // Note: Here is a function that can be used to handle custom API requests + // inside Note: of a class + void grabParams(AsyncWebServerRequest* request) { + int params = request->params(); + log_d("Number of Params: %d", params); + std::string y; + std::string x; + for (int i = 0; i < params; i++) { + AsyncWebParameter* param = request->getParam(i); + if (param->name() == "Axes1") { + x = param->value().c_str(); + } else if (param->name() == "Axes2") { + y = param->value().c_str(); + } + } + Serial.printf("Axes1: %s, Axes2: %s\n", x.c_str(), y.c_str()); + request->send(200, "text/plain", "OK"); + } +}; + +void setupServer() { + // add command handlers to the API server + // you can add as many as you want - you can also add methods. + log_d("[SETUP]: Starting API Server"); + api.addAPICommand("paramsClass", [&](AsyncWebServerRequest* request) { + Temp t; + t.grabParams(request); + }); + + api.begin(); + log_d("[SETUP]: API Server Started"); +} + +void setup() { + Serial.begin(115200); + pinMode(4, OUTPUT); + Serial.println("\nHello, EasyNetworkManager!"); + networkManager.begin(); + + setupServer(); +} + +void loop() {} diff --git a/NetworkManager/examples/customConfig.cpp b/NetworkManager/examples/customConfig.cpp index 257a60d..94881b2 100644 --- a/NetworkManager/examples/customConfig.cpp +++ b/NetworkManager/examples/customConfig.cpp @@ -1,94 +1,94 @@ -#include -#include - -/** - * @brief Setup the EasyNetworkManager Instance - * @note The EasyNetworkManager constructor takes 12 parameters: - * @param config_name The name of the project (used to create the config - * file name) - * @param hostname The hostname for your device on the network(used for - * mDNS, OTA, etc.) - * @param ssid The SSID of the WiFi network to connect to - * @param password The password of the WiFi network to connect to - * @param channel The channel of the WiFi network to connect to - * @param service_name The name of the service - * @param service_instance_name The instance name of the service - * @param service_protocol The protocol of the service - * @param service_description The description of the service - * @param service_port The port of the service - * @param enable_mdns Enable mDNS - * @param enable_adhoc Enable Adhoc - */ -EasyNetworkManager networkManager("easynetwork", MDNS_HOSTNAME, WIFI_SSID, - WIFI_PASSWORD, 1, "_easynetwork", "test", - "_tcp", "_api_port", "80", true, false); - -/** - * @brief Setup the AsyncServer Instance - * @note The AsyncServer constructor takes 5 parameters: - * @param port The port to listen on - * @param config The config manager - * @param api_path The path to the API - * @param wifi_manager_path The path to the WiFi Manager - * @param command_path The path to the command handler - */ -AsyncServer_t async_server(80, networkManager.configHandler->config, "/api", - "/wifimanager", "/mycommands", "/json"); - -/** - * @brief Setup the API Server Instance - * @note The API Server constructor takes 2 parameters: - * @param config The config manager - * @param server The AsyncServer instance - */ -APIServer api(networkManager.configHandler->config, async_server); - -/** - * @brief Setup the API Server Instance - * @note The API Server constructor takes 2 parameters: - * @param config The config manager - * @param server The AsyncServer instance - */ -APIServer api(networkManager.configHandler->config, async_server); - -// Note: Not required if you are going to use the AsyncOTA feature -// OTA ota(networkManager.configHandler->config); - -class CustomConfig : public CustomConfigInterface { - void save() override { - Serial.println("Saving custom config"); - } - - void load() override { - Serial.println("Loading custom config"); - } -}; - -CustomConfig customConfig; - -void printHelloWorld(AsyncWebServerRequest* request) { - Serial.println("Hello World!"); - request->send(200, "text/plain", "Hello World!"); -} - -void setupServer() { - // add command handlers to the API server - // you can add as many as you want - you can also add methods. - log_d("[SETUP]: Starting API Server"); - api.addAPICommand("helloWorld", printHelloWorld); - api.begin(); - log_d("[SETUP]: API Server Started"); -} - -void setup() { - Serial.begin(115200); - pinMode(4, OUTPUT); - Serial.println("\nHello, EasyNetworkManager!"); - - //* Optionally register a custom config - this will be saved and loaded - networkManager.configHandler->config.registerUserConfig(&customConfig); - networkManager.begin(); - setupServer(); -} - -void loop() {} +#include +#include + +/** + * @brief Setup the EasyNetworkManager Instance + * @note The EasyNetworkManager constructor takes 12 parameters: + * @param config_name The name of the project (used to create the config + * file name) + * @param hostname The hostname for your device on the network(used for + * mDNS, OTA, etc.) + * @param ssid The SSID of the WiFi network to connect to + * @param password The password of the WiFi network to connect to + * @param channel The channel of the WiFi network to connect to + * @param service_name The name of the service + * @param service_instance_name The instance name of the service + * @param service_protocol The protocol of the service + * @param service_description The description of the service + * @param service_port The port of the service + * @param enable_mdns Enable mDNS + * @param enable_adhoc Enable Adhoc + */ +EasyNetworkManager networkManager("easynetwork", MDNS_HOSTNAME, WIFI_SSID, + WIFI_PASSWORD, 1, "_easynetwork", "test", + "_tcp", "_api_port", "80", true, false); + +/** + * @brief Setup the AsyncServer Instance + * @note The AsyncServer constructor takes 5 parameters: + * @param port The port to listen on + * @param config The config manager + * @param api_path The path to the API + * @param wifi_manager_path The path to the WiFi Manager + * @param command_path The path to the command handler + */ +AsyncServer_t async_server(80, networkManager.configHandler->config, "/api", + "/wifimanager", "/mycommands", "/json"); + +/** + * @brief Setup the API Server Instance + * @note The API Server constructor takes 2 parameters: + * @param config The config manager + * @param server The AsyncServer instance + */ +APIServer api(networkManager.configHandler->config, async_server); + +/** + * @brief Setup the API Server Instance + * @note The API Server constructor takes 2 parameters: + * @param config The config manager + * @param server The AsyncServer instance + */ +APIServer api(networkManager.configHandler->config, async_server); + +// Note: Not required if you are going to use the AsyncOTA feature +// OTA ota(networkManager.configHandler->config); + +class CustomConfig : public CustomConfigInterface { + void save() override { + Serial.println("Saving custom config"); + } + + void load() override { + Serial.println("Loading custom config"); + } +}; + +CustomConfig customConfig; + +void printHelloWorld(AsyncWebServerRequest* request) { + Serial.println("Hello World!"); + request->send(200, "text/plain", "Hello World!"); +} + +void setupServer() { + // add command handlers to the API server + // you can add as many as you want - you can also add methods. + log_d("[SETUP]: Starting API Server"); + api.addAPICommand("helloWorld", printHelloWorld); + api.begin(); + log_d("[SETUP]: API Server Started"); +} + +void setup() { + Serial.begin(115200); + pinMode(4, OUTPUT); + Serial.println("\nHello, EasyNetworkManager!"); + + //* Optionally register a custom config - this will be saved and loaded + networkManager.configHandler->config.registerUserConfig(&customConfig); + networkManager.begin(); + setupServer(); +} + +void loop() {} diff --git a/NetworkManager/examples/customHTML.cpp b/NetworkManager/examples/customHTML.cpp index a76d0ea..a15fcd3 100644 --- a/NetworkManager/examples/customHTML.cpp +++ b/NetworkManager/examples/customHTML.cpp @@ -1,77 +1,77 @@ -#include -#include - -/** - * @brief Setup the EasyNetworkManager Instance - * @note The EasyNetworkManager constructor takes 12 parameters: - * @param config_name The name of the project (used to create the config - * file name) - * @param hostname The hostname for your device on the network(used for - * mDNS, OTA, etc.) - * @param ssid The SSID of the WiFi network to connect to - * @param password The password of the WiFi network to connect to - * @param channel The channel of the WiFi network to connect to - * @param service_name The name of the service - * @param service_instance_name The instance name of the service - * @param service_protocol The protocol of the service - * @param service_description The description of the service - * @param service_port The port of the service - * @param enable_mdns Enable mDNS - * @param enable_adhoc Enable Adhoc - */ -EasyNetworkManager networkManager("easynetwork", MDNS_HOSTNAME, WIFI_SSID, - WIFI_PASSWORD, 1, "_easynetwork", "test", - "_tcp", "_api_port", "80", true, false); - -/** - * @brief Setup the AsyncServer Instance - * @note The AsyncServer constructor takes 5 parameters: - * @param port The port to listen on - * @param config The config manager - * @param api_path The path to the API - * @param wifi_manager_path The path to the WiFi Manager - * @param command_path The path to the command handler - */ -AsyncServer_t async_server(80, networkManager.configHandler->config, "/api", - "/wifimanager", "/mycommands", "/json"); - -/** - * @brief Setup the API Server Instance - * @note The API Server constructor takes 2 parameters: - * @param config The config manager - * @param server The AsyncServer instance - */ -APIServer api(networkManager.configHandler->config, async_server); - -/** - * @brief Setup the API Server Instance - * @note The API Server constructor takes 2 parameters: - * @param config The config manager - * @param server The AsyncServer instance - */ -APIServer api(networkManager.configHandler->config, async_server); - -void setupServer() { - // This is an example of how to add a custom html file to the web server - // Note: The first parameter is the url endpoint to access the file - // Note: The second parameter is the path to the file on the SPIFFS - // Note: The third parameter is the HTTP method to use to access the file - async_server.custom_html_files.emplace_back("/hello", "/helloWorld.html", - "GET"); - async_server.custom_html_files.emplace_back("/goodbye", "/goodbye.html", - "POST"); - - api.begin(); - log_d("[SETUP]: API Server Started"); -} - -void setup() { - Serial.begin(115200); - pinMode(4, OUTPUT); - Serial.println("\nHello, EasyNetworkManager!"); - networkManager.begin(); - - setupServer(); -} - -void loop() {} +#include +#include + +/** + * @brief Setup the EasyNetworkManager Instance + * @note The EasyNetworkManager constructor takes 12 parameters: + * @param config_name The name of the project (used to create the config + * file name) + * @param hostname The hostname for your device on the network(used for + * mDNS, OTA, etc.) + * @param ssid The SSID of the WiFi network to connect to + * @param password The password of the WiFi network to connect to + * @param channel The channel of the WiFi network to connect to + * @param service_name The name of the service + * @param service_instance_name The instance name of the service + * @param service_protocol The protocol of the service + * @param service_description The description of the service + * @param service_port The port of the service + * @param enable_mdns Enable mDNS + * @param enable_adhoc Enable Adhoc + */ +EasyNetworkManager networkManager("easynetwork", MDNS_HOSTNAME, WIFI_SSID, + WIFI_PASSWORD, 1, "_easynetwork", "test", + "_tcp", "_api_port", "80", true, false); + +/** + * @brief Setup the AsyncServer Instance + * @note The AsyncServer constructor takes 5 parameters: + * @param port The port to listen on + * @param config The config manager + * @param api_path The path to the API + * @param wifi_manager_path The path to the WiFi Manager + * @param command_path The path to the command handler + */ +AsyncServer_t async_server(80, networkManager.configHandler->config, "/api", + "/wifimanager", "/mycommands", "/json"); + +/** + * @brief Setup the API Server Instance + * @note The API Server constructor takes 2 parameters: + * @param config The config manager + * @param server The AsyncServer instance + */ +APIServer api(networkManager.configHandler->config, async_server); + +/** + * @brief Setup the API Server Instance + * @note The API Server constructor takes 2 parameters: + * @param config The config manager + * @param server The AsyncServer instance + */ +APIServer api(networkManager.configHandler->config, async_server); + +void setupServer() { + // This is an example of how to add a custom html file to the web server + // Note: The first parameter is the url endpoint to access the file + // Note: The second parameter is the path to the file on the SPIFFS + // Note: The third parameter is the HTTP method to use to access the file + async_server.custom_html_files.emplace_back("/hello", "/helloWorld.html", + "GET"); + async_server.custom_html_files.emplace_back("/goodbye", "/goodbye.html", + "POST"); + + api.begin(); + log_d("[SETUP]: API Server Started"); +} + +void setup() { + Serial.begin(115200); + pinMode(4, OUTPUT); + Serial.println("\nHello, EasyNetworkManager!"); + networkManager.begin(); + + setupServer(); +} + +void loop() {} diff --git a/NetworkManager/examples/customHandlers.cpp b/NetworkManager/examples/customHandlers.cpp index a76324a..df993e3 100644 --- a/NetworkManager/examples/customHandlers.cpp +++ b/NetworkManager/examples/customHandlers.cpp @@ -1,80 +1,80 @@ -#include -#include - -/** - * @brief Setup the EasyNetworkManager Instance - * @note The EasyNetworkManager constructor takes 12 parameters: - * @param config_name The name of the project (used to create the config - * file name) - * @param hostname The hostname for your device on the network(used for - * mDNS, OTA, etc.) - * @param ssid The SSID of the WiFi network to connect to - * @param password The password of the WiFi network to connect to - * @param channel The channel of the WiFi network to connect to - * @param service_name The name of the service - * @param service_instance_name The instance name of the service - * @param service_protocol The protocol of the service - * @param service_description The description of the service - * @param service_port The port of the service - * @param enable_mdns Enable mDNS - * @param enable_adhoc Enable Adhoc - */ -EasyNetworkManager networkManager("easynetwork", MDNS_HOSTNAME, WIFI_SSID, - WIFI_PASSWORD, 1, "_easynetwork", "test", - "_tcp", "_api_port", "80", true, false); - -/** - * @brief Setup the AsyncServer Instance - * @note The AsyncServer constructor takes 5 parameters: - * @param port The port to listen on - * @param config The config manager - * @param api_path The path to the API - * @param wifi_manager_path The path to the WiFi Manager - * @param command_path The path to the command handler - */ -AsyncServer_t async_server(80, networkManager.configHandler->config, "/api", - "/wifimanager", "/mycommands", "/json"); - -/** - * @brief Setup the API Server Instance - * @note The API Server constructor takes 2 parameters: - * @param config The config manager - * @param server The AsyncServer instance - */ -APIServer api(networkManager.configHandler->config, async_server); - -void setupServer() { - log_d("[SETUP]: Starting API Server"); - - // Add a custom handler - // This handler will return a custom JSON response when a POST request is - // made to /api/customJson - async_server.server.addHandler(new AsyncCallbackJsonWebHandler( - "/api/customJson", - [&](AsyncWebServerRequest* request, JsonVariant& json) { - JsonDocument doc; - doc["hello"] = "world"; - doc["number"] = 42; - - AsyncJsonResponse* response = new AsyncJsonResponse(); - response->addHeader("EasyNetworkManager", "1.0"); - auto root = response->getRoot(); - root["deviceData"].set(doc); - response->setLength(); - request->send(response); - })); - - api.begin(); - log_d("[SETUP]: API Server Started"); -} - -void setup() { - Serial.begin(115200); - pinMode(4, OUTPUT); - Serial.println("\nHello, EasyNetworkManager!"); - networkManager.begin(); - - setupServer(); -} - -void loop() {} +#include +#include + +/** + * @brief Setup the EasyNetworkManager Instance + * @note The EasyNetworkManager constructor takes 12 parameters: + * @param config_name The name of the project (used to create the config + * file name) + * @param hostname The hostname for your device on the network(used for + * mDNS, OTA, etc.) + * @param ssid The SSID of the WiFi network to connect to + * @param password The password of the WiFi network to connect to + * @param channel The channel of the WiFi network to connect to + * @param service_name The name of the service + * @param service_instance_name The instance name of the service + * @param service_protocol The protocol of the service + * @param service_description The description of the service + * @param service_port The port of the service + * @param enable_mdns Enable mDNS + * @param enable_adhoc Enable Adhoc + */ +EasyNetworkManager networkManager("easynetwork", MDNS_HOSTNAME, WIFI_SSID, + WIFI_PASSWORD, 1, "_easynetwork", "test", + "_tcp", "_api_port", "80", true, false); + +/** + * @brief Setup the AsyncServer Instance + * @note The AsyncServer constructor takes 5 parameters: + * @param port The port to listen on + * @param config The config manager + * @param api_path The path to the API + * @param wifi_manager_path The path to the WiFi Manager + * @param command_path The path to the command handler + */ +AsyncServer_t async_server(80, networkManager.configHandler->config, "/api", + "/wifimanager", "/mycommands", "/json"); + +/** + * @brief Setup the API Server Instance + * @note The API Server constructor takes 2 parameters: + * @param config The config manager + * @param server The AsyncServer instance + */ +APIServer api(networkManager.configHandler->config, async_server); + +void setupServer() { + log_d("[SETUP]: Starting API Server"); + + // Add a custom handler + // This handler will return a custom JSON response when a POST request is + // made to /api/customJson + async_server.server.addHandler(new AsyncCallbackJsonWebHandler( + "/api/customJson", + [&](AsyncWebServerRequest* request, JsonVariant& json) { + JsonDocument doc; + doc["hello"] = "world"; + doc["number"] = 42; + + AsyncJsonResponse* response = new AsyncJsonResponse(); + response->addHeader("EasyNetworkManager", "1.0"); + auto root = response->getRoot(); + root["deviceData"].set(doc); + response->setLength(); + request->send(response); + })); + + api.begin(); + log_d("[SETUP]: API Server Started"); +} + +void setup() { + Serial.begin(115200); + pinMode(4, OUTPUT); + Serial.println("\nHello, EasyNetworkManager!"); + networkManager.begin(); + + setupServer(); +} + +void loop() {} diff --git a/NetworkManager/examples/functions.cpp b/NetworkManager/examples/functions.cpp index a5231e2..f716f4a 100644 --- a/NetworkManager/examples/functions.cpp +++ b/NetworkManager/examples/functions.cpp @@ -1,103 +1,103 @@ -#include -#include - -/** - * @brief Setup the EasyNetworkManager Instance - * @note The EasyNetworkManager constructor takes 12 parameters: - * @param config_name The name of the project (used to create the config - * file name) - * @param hostname The hostname for your device on the network(used for - * mDNS, OTA, etc.) - * @param ssid The SSID of the WiFi network to connect to - * @param password The password of the WiFi network to connect to - * @param channel The channel of the WiFi network to connect to - * @param service_name The name of the service - * @param service_instance_name The instance name of the service - * @param service_protocol The protocol of the service - * @param service_description The description of the service - * @param service_port The port of the service - * @param enable_mdns Enable mDNS - * @param enable_adhoc Enable Adhoc - */ -EasyNetworkManager networkManager("easynetwork", MDNS_HOSTNAME, WIFI_SSID, - WIFI_PASSWORD, 1, "_easynetwork", "test", - "_tcp", "_api_port", "80", true, false); - -/** - * @brief Setup the AsyncServer Instance - * @note The AsyncServer constructor takes 5 parameters: - * @param port The port to listen on - * @param config The config manager - * @param api_path The path to the API - * @param wifi_manager_path The path to the WiFi Manager - * @param command_path The path to the command handler - */ -AsyncServer_t async_server(80, networkManager.configHandler->config, "/api", - "/wifimanager", "/mycommands", "/json"); - -/** - * @brief Setup the API Server Instance - * @note The API Server constructor takes 2 parameters: - * @param config The config manager - * @param server The AsyncServer instance - */ -APIServer api(networkManager.configHandler->config, async_server); - -// Note: Here is a function that can be used to handle custom API requests -void grabParams(AsyncWebServerRequest* request) { - int params = request->params(); - std::string axes1; - std::string axes2; - - for (int i = 0; i < params; i++) { - AsyncWebParameter* param = request->getParam(i); - if (param->name() == "Axes1") { - axes1 = param->value().c_str(); - } else if (param->name() == "Axes2") { - axes2 = param->value().c_str(); - } - } - int ax1 = atoi(axes1.c_str()); - int ax2 = atoi(axes2.c_str()); - int ax5 = ax1 - ax2; - int ax6 = ax1 + ax2; - Serial.printf("Axes1: %d, Axes2: %d\n", ax1, ax2); - request->send(200, "text/plain", "OK"); -} - -// Note: Here are two functions that can be used to handle custom API requests -void printHelloWorld(AsyncWebServerRequest* request) { - Serial.println("Hello World!"); - request->send(200, "text/plain", "Hello World!"); -} - -void blink(AsyncWebServerRequest* request) { - digitalWrite(4, HIGH); - Network_Utilities::my_delay(1); // delay for 1sec - digitalWrite(4, LOW); - Network_Utilities::my_delay(1); // delay for 1sec - request->send(200, "text/plain", "Blink!"); -} - -void setupServer() { - // add command handlers to the API server - // you can add as many as you want - you can also add methods. - log_d("[SETUP]: Starting API Server"); - api.addAPICommand("blink", blink); - api.addAPICommand("helloWorld", printHelloWorld); - api.addAPICommand("params", grabParams); - api.begin(); - log_d("[SETUP]: API Server Started"); -} - -void setup() { - Serial.begin(115200); - pinMode(4, OUTPUT); - Serial.println("\nHello, EasyNetworkManager!"); - - networkManager.begin(); - - setupServer(); -} - -void loop() {} +#include +#include + +/** + * @brief Setup the EasyNetworkManager Instance + * @note The EasyNetworkManager constructor takes 12 parameters: + * @param config_name The name of the project (used to create the config + * file name) + * @param hostname The hostname for your device on the network(used for + * mDNS, OTA, etc.) + * @param ssid The SSID of the WiFi network to connect to + * @param password The password of the WiFi network to connect to + * @param channel The channel of the WiFi network to connect to + * @param service_name The name of the service + * @param service_instance_name The instance name of the service + * @param service_protocol The protocol of the service + * @param service_description The description of the service + * @param service_port The port of the service + * @param enable_mdns Enable mDNS + * @param enable_adhoc Enable Adhoc + */ +EasyNetworkManager networkManager("easynetwork", MDNS_HOSTNAME, WIFI_SSID, + WIFI_PASSWORD, 1, "_easynetwork", "test", + "_tcp", "_api_port", "80", true, false); + +/** + * @brief Setup the AsyncServer Instance + * @note The AsyncServer constructor takes 5 parameters: + * @param port The port to listen on + * @param config The config manager + * @param api_path The path to the API + * @param wifi_manager_path The path to the WiFi Manager + * @param command_path The path to the command handler + */ +AsyncServer_t async_server(80, networkManager.configHandler->config, "/api", + "/wifimanager", "/mycommands", "/json"); + +/** + * @brief Setup the API Server Instance + * @note The API Server constructor takes 2 parameters: + * @param config The config manager + * @param server The AsyncServer instance + */ +APIServer api(networkManager.configHandler->config, async_server); + +// Note: Here is a function that can be used to handle custom API requests +void grabParams(AsyncWebServerRequest* request) { + int params = request->params(); + std::string axes1; + std::string axes2; + + for (int i = 0; i < params; i++) { + AsyncWebParameter* param = request->getParam(i); + if (param->name() == "Axes1") { + axes1 = param->value().c_str(); + } else if (param->name() == "Axes2") { + axes2 = param->value().c_str(); + } + } + int ax1 = atoi(axes1.c_str()); + int ax2 = atoi(axes2.c_str()); + int ax5 = ax1 - ax2; + int ax6 = ax1 + ax2; + Serial.printf("Axes1: %d, Axes2: %d\n", ax1, ax2); + request->send(200, "text/plain", "OK"); +} + +// Note: Here are two functions that can be used to handle custom API requests +void printHelloWorld(AsyncWebServerRequest* request) { + Serial.println("Hello World!"); + request->send(200, "text/plain", "Hello World!"); +} + +void blink(AsyncWebServerRequest* request) { + digitalWrite(4, HIGH); + Network_Utilities::my_delay(1); // delay for 1sec + digitalWrite(4, LOW); + Network_Utilities::my_delay(1); // delay for 1sec + request->send(200, "text/plain", "Blink!"); +} + +void setupServer() { + // add command handlers to the API server + // you can add as many as you want - you can also add methods. + log_d("[SETUP]: Starting API Server"); + api.addAPICommand("blink", blink); + api.addAPICommand("helloWorld", printHelloWorld); + api.addAPICommand("params", grabParams); + api.begin(); + log_d("[SETUP]: API Server Started"); +} + +void setup() { + Serial.begin(115200); + pinMode(4, OUTPUT); + Serial.println("\nHello, EasyNetworkManager!"); + + networkManager.begin(); + + setupServer(); +} + +void loop() {} diff --git a/NetworkManager/examples/main.cpp b/NetworkManager/examples/main.cpp index 4f010f2..6c2a3f4 100644 --- a/NetworkManager/examples/main.cpp +++ b/NetworkManager/examples/main.cpp @@ -1,168 +1,168 @@ -#include -#include - -/** - * @brief Setup the EasyNetworkManager Instance - * @note The EasyNetworkManager constructor takes 12 parameters: - * @param config_name The name of the project (used to create the config - * file name) - * @param hostname The hostname for your device on the network(used for - * mDNS, OTA, etc.) - * @param ssid The SSID of the WiFi network to connect to - * @param password The password of the WiFi network to connect to - * @param channel The channel of the WiFi network to connect to - * @param service_name The name of the service - * @param service_instance_name The instance name of the service - * @param service_protocol The protocol of the service - * @param service_description The description of the service - * @param service_port The port of the service - * @param enable_mdns Enable mDNS - * @param enable_adhoc Enable Adhoc - */ -EasyNetworkManager networkManager("easynetwork", MDNS_HOSTNAME, WIFI_SSID, - WIFI_PASSWORD, 1, "_easynetwork", "test", - "_tcp", "_api_port", "80", true, false); - -/** - * @brief Setup the AsyncServer Instance - * @note The AsyncServer constructor takes 5 parameters: - * @param port The port to listen on - * @param config The config manager - * @param api_path The path to the API - * @param wifi_manager_path The path to the WiFi Manager - * @param command_path The path to the command handler - */ -AsyncServer_t async_server(80, networkManager.configHandler->config, "/api", - "/wifimanager", "/mycommands", "/json"); - -/** - * @brief Setup the API Server Instance - * @note The API Server constructor takes 2 parameters: - * @param config The config manager - * @param server The AsyncServer instance - */ -APIServer api(networkManager.configHandler->config, async_server); - -// Note: Not required if you are going to use the AsyncOTA feature -// OTA ota(networkManager.configHandler->config); - -class CustomConfig : public CustomConfigInterface { - void save() override { - Serial.println("Saving custom config"); - } - - void load() override { - Serial.println("Loading custom config"); - } -}; - -CustomConfig customConfig; - -class Temp { - public: - Temp() { - Serial.println("Temp created"); - } - ~Temp() { - Serial.println("Temp destroyed"); - } - // Note: Here is a function that can be used to handle custom API requests - // inside Note: of a class - void grabParams(AsyncWebServerRequest* request) { - int params = request->params(); - log_d("Number of Params: %d", params); - std::string y; - std::string x; - for (int i = 0; i < params; i++) { - AsyncWebParameter* param = request->getParam(i); - if (param->name() == "Axes1") { - x = param->value().c_str(); - } else if (param->name() == "Axes2") { - y = param->value().c_str(); - } - } - Serial.printf("Axes1: %s, Axes2: %s\n", x.c_str(), y.c_str()); - request->send(200, "text/plain", "OK"); - } -}; - -// Note: Here is a function that can be used to handle custom API requests -void grabParams(AsyncWebServerRequest* request) { - int params = request->params(); - std::string axes1; - std::string axes2; - - for (int i = 0; i < params; i++) { - AsyncWebParameter* param = request->getParam(i); - if (param->name() == "Axes1") { - axes1 = param->value().c_str(); - } else if (param->name() == "Axes2") { - axes2 = param->value().c_str(); - } - } - int ax1 = atoi(axes1.c_str()); - int ax2 = atoi(axes2.c_str()); - int ax5 = ax1 - ax2; - int ax6 = ax1 + ax2; - Serial.printf("Axes1: %d, Axes2: %d\n", ax1, ax2); - request->send(200, "text/plain", "OK"); -} - -// Note: Here are two functions that can be used to handle custom API requests -void printHelloWorld(AsyncWebServerRequest* request) { - Serial.println("Hello World!"); - request->send(200, "text/plain", "Hello World!"); -} - -void blink(AsyncWebServerRequest* request) { - digitalWrite(4, HIGH); - Network_Utilities::my_delay(1); // delay for 1sec - digitalWrite(4, LOW); - Network_Utilities::my_delay(1); // delay for 1sec - request->send(200, "text/plain", "Blink!"); -} - -void setupServer() { - // add command handlers to the API server - // you can add as many as you want - you can also add methods. - log_d("[SETUP]: Starting API Server"); - api.addAPICommand("blink", blink); - api.addAPICommand("helloWorld", printHelloWorld); - api.addAPICommand("params", grabParams); - api.addAPICommand("paramsClass", [&](AsyncWebServerRequest* request) { - Temp t; - t.grabParams(request); - }); - - async_server.server.addHandler(new AsyncCallbackJsonWebHandler( - "/api/customJson", - [&](AsyncWebServerRequest* request, JsonVariant& json) { - JsonDocument doc; - doc["hello"] = "world"; - doc["number"] = 42; - - AsyncJsonResponse* response = new AsyncJsonResponse(); - response->addHeader("EasyNetworkManager", "1.0"); - auto root = response->getRoot(); - root["deviceData"].set(doc); - response->setLength(); - request->send(response); - })); - - api.begin(); - log_d("[SETUP]: API Server Started"); -} - -void setup() { - Serial.begin(115200); - pinMode(4, OUTPUT); - Serial.println("\nHello, EasyNetworkManager!"); - - //* Optionally register a custom config - this will be saved and loaded - networkManager.configHandler->config.registerUserConfig(&customConfig); - networkManager.begin(); - - setupServer(); -} - -void loop() {} +#include +#include + +/** + * @brief Setup the EasyNetworkManager Instance + * @note The EasyNetworkManager constructor takes 12 parameters: + * @param config_name The name of the project (used to create the config + * file name) + * @param hostname The hostname for your device on the network(used for + * mDNS, OTA, etc.) + * @param ssid The SSID of the WiFi network to connect to + * @param password The password of the WiFi network to connect to + * @param channel The channel of the WiFi network to connect to + * @param service_name The name of the service + * @param service_instance_name The instance name of the service + * @param service_protocol The protocol of the service + * @param service_description The description of the service + * @param service_port The port of the service + * @param enable_mdns Enable mDNS + * @param enable_adhoc Enable Adhoc + */ +EasyNetworkManager networkManager("easynetwork", MDNS_HOSTNAME, WIFI_SSID, + WIFI_PASSWORD, 1, "_easynetwork", "test", + "_tcp", "_api_port", "80", true, false); + +/** + * @brief Setup the AsyncServer Instance + * @note The AsyncServer constructor takes 5 parameters: + * @param port The port to listen on + * @param config The config manager + * @param api_path The path to the API + * @param wifi_manager_path The path to the WiFi Manager + * @param command_path The path to the command handler + */ +AsyncServer_t async_server(80, networkManager.configHandler->config, "/api", + "/wifimanager", "/mycommands", "/json"); + +/** + * @brief Setup the API Server Instance + * @note The API Server constructor takes 2 parameters: + * @param config The config manager + * @param server The AsyncServer instance + */ +APIServer api(networkManager.configHandler->config, async_server); + +// Note: Not required if you are going to use the AsyncOTA feature +// OTA ota(networkManager.configHandler->config); + +class CustomConfig : public CustomConfigInterface { + void save() override { + Serial.println("Saving custom config"); + } + + void load() override { + Serial.println("Loading custom config"); + } +}; + +CustomConfig customConfig; + +class Temp { + public: + Temp() { + Serial.println("Temp created"); + } + ~Temp() { + Serial.println("Temp destroyed"); + } + // Note: Here is a function that can be used to handle custom API requests + // inside Note: of a class + void grabParams(AsyncWebServerRequest* request) { + int params = request->params(); + log_d("Number of Params: %d", params); + std::string y; + std::string x; + for (int i = 0; i < params; i++) { + AsyncWebParameter* param = request->getParam(i); + if (param->name() == "Axes1") { + x = param->value().c_str(); + } else if (param->name() == "Axes2") { + y = param->value().c_str(); + } + } + Serial.printf("Axes1: %s, Axes2: %s\n", x.c_str(), y.c_str()); + request->send(200, "text/plain", "OK"); + } +}; + +// Note: Here is a function that can be used to handle custom API requests +void grabParams(AsyncWebServerRequest* request) { + int params = request->params(); + std::string axes1; + std::string axes2; + + for (int i = 0; i < params; i++) { + AsyncWebParameter* param = request->getParam(i); + if (param->name() == "Axes1") { + axes1 = param->value().c_str(); + } else if (param->name() == "Axes2") { + axes2 = param->value().c_str(); + } + } + int ax1 = atoi(axes1.c_str()); + int ax2 = atoi(axes2.c_str()); + int ax5 = ax1 - ax2; + int ax6 = ax1 + ax2; + Serial.printf("Axes1: %d, Axes2: %d\n", ax1, ax2); + request->send(200, "text/plain", "OK"); +} + +// Note: Here are two functions that can be used to handle custom API requests +void printHelloWorld(AsyncWebServerRequest* request) { + Serial.println("Hello World!"); + request->send(200, "text/plain", "Hello World!"); +} + +void blink(AsyncWebServerRequest* request) { + digitalWrite(4, HIGH); + Network_Utilities::my_delay(1); // delay for 1sec + digitalWrite(4, LOW); + Network_Utilities::my_delay(1); // delay for 1sec + request->send(200, "text/plain", "Blink!"); +} + +void setupServer() { + // add command handlers to the API server + // you can add as many as you want - you can also add methods. + log_d("[SETUP]: Starting API Server"); + api.addAPICommand("blink", blink); + api.addAPICommand("helloWorld", printHelloWorld); + api.addAPICommand("params", grabParams); + api.addAPICommand("paramsClass", [&](AsyncWebServerRequest* request) { + Temp t; + t.grabParams(request); + }); + + async_server.server.addHandler(new AsyncCallbackJsonWebHandler( + "/api/customJson", + [&](AsyncWebServerRequest* request, JsonVariant& json) { + JsonDocument doc; + doc["hello"] = "world"; + doc["number"] = 42; + + AsyncJsonResponse* response = new AsyncJsonResponse(); + response->addHeader("EasyNetworkManager", "1.0"); + auto root = response->getRoot(); + root["deviceData"].set(doc); + response->setLength(); + request->send(response); + })); + + api.begin(); + log_d("[SETUP]: API Server Started"); +} + +void setup() { + Serial.begin(115200); + pinMode(4, OUTPUT); + Serial.println("\nHello, EasyNetworkManager!"); + + //* Optionally register a custom config - this will be saved and loaded + networkManager.configHandler->config.registerUserConfig(&customConfig); + networkManager.begin(); + + setupServer(); +} + +void loop() {} diff --git a/NetworkManager/extras/ethernet/ethernet_handler.cpp b/NetworkManager/extras/ethernet/ethernet_handler.cpp index 2dab0ed..9436e3c 100644 --- a/NetworkManager/extras/ethernet/ethernet_handler.cpp +++ b/NetworkManager/extras/ethernet/ethernet_handler.cpp @@ -1,126 +1,126 @@ -#if ENABLE_ETHERNET -# include - -EthernetManager::EthernetManager(StateManager* stateManager, - const std::string& hostName, IPAddress* ethIP, - IPAddress* ethGW, IPAddress* ethSN, - IPAddress* ethDNS) - : _WT32_ETH01_eth_connected(false), - hostName(std::move(hostName)), - ethIP(ethIP), - ethGW(ethGW), - ethSN(ethSN), - ethDNS(ethDNS) {} - -EthernetManager::~EthernetManager() {} - -void EthernetManager::WT32_ETH01_onEvent() { - WiFi.onEvent(std::bind(&EthernetManager::WT32_ETH01_event, this, - std::placeholders::_1)); -} - -void EthernetManager::WT32_ETH01_waitForConnect() { - while (!_WT32_ETH01_eth_connected) - delay(100); -} - -bool EthernetManager::WT32_ETH01_isConnected() { - return _WT32_ETH01_eth_connected; -} - -void EthernetManager::WT32_ETH01_event(WiFiEvent_t event) { - switch (event) { - // #if USING_CORE_ESP32_CORE_V200_PLUS -# if ((defined(ESP_ARDUINO_VERSION_MAJOR) && \ - (ESP_ARDUINO_VERSION_MAJOR >= 2)) && \ - (ARDUINO_ESP32_GIT_VER != 0x46d5afb1)) - // For breaking core v2.0.0 - // Why so strange to define a breaking enum - // arduino_event_id_t in WiFiGeneric.h compared to - // the old system_event_id_t, now in - // tools/sdk/esp32/include/esp_event/include/esp_event_legacy.h - // You can preserve the old enum order and just - // adding new items to do no harm - case ARDUINO_EVENT_ETH_START: - log_i("\nETH Started"); - // set eth hostname here - ETH.setHostname(hostName.c_str()); - break; - case ARDUINO_EVENT_ETH_CONNECTED: - log_i("ETH Connected"); - break; - case ARDUINO_EVENT_ETH_GOT_IP: - if (!_WT32_ETH01_eth_connected) { - log_i("ETH MAC: %s, IPv4: %s", ETH.macAddress().c_str(), - ETH.localIP().toString().c_str()); - log_i("%s", - ETH.fullDuplex() ? "FULL_DUPLEX, " : "HALF_DUPLEX, "); - log_i("%d Mbps", ETH.linkSpeed()); - _WT32_ETH01_eth_connected = true; - } - break; - case ARDUINO_EVENT_ETH_DISCONNECTED: - log_i("ETH Disconnected"); - _WT32_ETH01_eth_connected = false; - break; - case ARDUINO_EVENT_ETH_STOP: - log_i("\nETH Stopped"); - _WT32_ETH01_eth_connected = false; - break; -# else - // For old core v1.0.6- - // Core v2.0.0 defines a stupid enum - // arduino_event_id_t, breaking any code for - // WT32_ETH01 written for previous core Why so - // strange to define a breaking enum - // arduino_event_id_t in WiFiGeneric.h compared to - // the old system_event_id_t, now in - // tools/sdk/esp32/include/esp_event/include/esp_event_legacy.h - // You can preserve the old enum order and just - // adding new items to do no harm - case SYSTEM_EVENT_ETH_START: - log_i("\nETH Started"); - // set eth hostname here - ETH.setHostname(hostName.c_str()); - break; - case SYSTEM_EVENT_ETH_CONNECTED: - log_i(F("ETH Connected")); - break; - case SYSTEM_EVENT_ETH_GOT_IP: - if (!_WT32_ETH01_eth_connected) { - log_i("ETH MAC: %s, IPv4: %s", ETH.macAddress().c_str(), - ETH.localIP().toString().c_str()); - log_i("%s", - ETH.fullDuplex() ? "FULL_DUPLEX, " : "HALF_DUPLEX, "); - log_i("%d Mbps", ETH.linkSpeed()); - _WT32_ETH01_eth_connected = true; - } - break; - case SYSTEM_EVENT_ETH_DISCONNECTED: - log_i("ETH Disconnected"); - _WT32_ETH01_eth_connected = false; - break; - case SYSTEM_EVENT_ETH_STOP: - log_i("\nETH Stopped"); - _WT32_ETH01_eth_connected = false; - break; -# endif - default: - break; - } -} - -void EthernetManager::begin() { - WT32_ETH01_onEvent(); - ETH.begin(ETH_PHY_ADDR, ETH_PHY_POWER); - ETH.config(*ethIP, *ethGW, *ethSN, *ethDNS); - WT32_ETH01_waitForConnect(); - if (WT32_ETH01_isConnected()) { - // WiFi.softAP(); - stateManager->setState(WiFiState_e::WiFiState_Connected); - return; - } - log_e("Ethernet connection failed!"); - return; -} +#if ENABLE_ETHERNET +# include + +EthernetManager::EthernetManager(StateManager* stateManager, + const std::string& hostName, IPAddress* ethIP, + IPAddress* ethGW, IPAddress* ethSN, + IPAddress* ethDNS) + : _WT32_ETH01_eth_connected(false), + hostName(std::move(hostName)), + ethIP(ethIP), + ethGW(ethGW), + ethSN(ethSN), + ethDNS(ethDNS) {} + +EthernetManager::~EthernetManager() {} + +void EthernetManager::WT32_ETH01_onEvent() { + WiFi.onEvent(std::bind(&EthernetManager::WT32_ETH01_event, this, + std::placeholders::_1)); +} + +void EthernetManager::WT32_ETH01_waitForConnect() { + while (!_WT32_ETH01_eth_connected) + delay(100); +} + +bool EthernetManager::WT32_ETH01_isConnected() { + return _WT32_ETH01_eth_connected; +} + +void EthernetManager::WT32_ETH01_event(WiFiEvent_t event) { + switch (event) { + // #if USING_CORE_ESP32_CORE_V200_PLUS +# if ((defined(ESP_ARDUINO_VERSION_MAJOR) && \ + (ESP_ARDUINO_VERSION_MAJOR >= 2)) && \ + (ARDUINO_ESP32_GIT_VER != 0x46d5afb1)) + // For breaking core v2.0.0 + // Why so strange to define a breaking enum + // arduino_event_id_t in WiFiGeneric.h compared to + // the old system_event_id_t, now in + // tools/sdk/esp32/include/esp_event/include/esp_event_legacy.h + // You can preserve the old enum order and just + // adding new items to do no harm + case ARDUINO_EVENT_ETH_START: + log_i("\nETH Started"); + // set eth hostname here + ETH.setHostname(hostName.c_str()); + break; + case ARDUINO_EVENT_ETH_CONNECTED: + log_i("ETH Connected"); + break; + case ARDUINO_EVENT_ETH_GOT_IP: + if (!_WT32_ETH01_eth_connected) { + log_i("ETH MAC: %s, IPv4: %s", ETH.macAddress().c_str(), + ETH.localIP().toString().c_str()); + log_i("%s", + ETH.fullDuplex() ? "FULL_DUPLEX, " : "HALF_DUPLEX, "); + log_i("%d Mbps", ETH.linkSpeed()); + _WT32_ETH01_eth_connected = true; + } + break; + case ARDUINO_EVENT_ETH_DISCONNECTED: + log_i("ETH Disconnected"); + _WT32_ETH01_eth_connected = false; + break; + case ARDUINO_EVENT_ETH_STOP: + log_i("\nETH Stopped"); + _WT32_ETH01_eth_connected = false; + break; +# else + // For old core v1.0.6- + // Core v2.0.0 defines a stupid enum + // arduino_event_id_t, breaking any code for + // WT32_ETH01 written for previous core Why so + // strange to define a breaking enum + // arduino_event_id_t in WiFiGeneric.h compared to + // the old system_event_id_t, now in + // tools/sdk/esp32/include/esp_event/include/esp_event_legacy.h + // You can preserve the old enum order and just + // adding new items to do no harm + case SYSTEM_EVENT_ETH_START: + log_i("\nETH Started"); + // set eth hostname here + ETH.setHostname(hostName.c_str()); + break; + case SYSTEM_EVENT_ETH_CONNECTED: + log_i(F("ETH Connected")); + break; + case SYSTEM_EVENT_ETH_GOT_IP: + if (!_WT32_ETH01_eth_connected) { + log_i("ETH MAC: %s, IPv4: %s", ETH.macAddress().c_str(), + ETH.localIP().toString().c_str()); + log_i("%s", + ETH.fullDuplex() ? "FULL_DUPLEX, " : "HALF_DUPLEX, "); + log_i("%d Mbps", ETH.linkSpeed()); + _WT32_ETH01_eth_connected = true; + } + break; + case SYSTEM_EVENT_ETH_DISCONNECTED: + log_i("ETH Disconnected"); + _WT32_ETH01_eth_connected = false; + break; + case SYSTEM_EVENT_ETH_STOP: + log_i("\nETH Stopped"); + _WT32_ETH01_eth_connected = false; + break; +# endif + default: + break; + } +} + +void EthernetManager::begin() { + WT32_ETH01_onEvent(); + ETH.begin(ETH_PHY_ADDR, ETH_PHY_POWER); + ETH.config(*ethIP, *ethGW, *ethSN, *ethDNS); + WT32_ETH01_waitForConnect(); + if (WT32_ETH01_isConnected()) { + // WiFi.softAP(); + stateManager->setState(WiFiState_e::WiFiState_Connected); + return; + } + log_e("Ethernet connection failed!"); + return; +} #endif \ No newline at end of file diff --git a/NetworkManager/extras/ethernet/ethernet_handler.hpp b/NetworkManager/extras/ethernet/ethernet_handler.hpp index 3984a36..2248c6c 100644 --- a/NetworkManager/extras/ethernet/ethernet_handler.hpp +++ b/NetworkManager/extras/ethernet/ethernet_handler.hpp @@ -1,131 +1,131 @@ -#if ENABLE_ETHERNET -# pragma once - -# ifndef ETHERNETHANDLER_WT32_ETH01_H -# define ETHERNETHANDLER_WT32_ETH01_H - -////////////////////////////////////////////////////////////// - -// #if !defined(USING_CORE_ESP32_CORE_V200_PLUS) -# if ((defined(ESP_ARDUINO_VERSION_MAJOR) && \ - (ESP_ARDUINO_VERSION_MAJOR >= 2)) && \ - (ARDUINO_ESP32_GIT_VER != 0x46d5afb1)) -# define USING_CORE_ESP32_CORE_V200_PLUS true - -# if (_ETHERNET_ETHERNETHANDLER_LOGLEVEL_ > 2) -#warning Using code for ESP32 core v2.0.0+ in ETHERNETHANDLER_WT32_ETH01.h -# endif - -# define ETHERNETHANDLER_WT32_ETH01_VERSION \ - "ETHERNETHANDLER_WT32_ETH01 v1.5.1 for core v2.0.0+" -# else -# if (_ETHERNET_ETHERNETHANDLER_LOGLEVEL_ > 2) -#warning Using code for ESP32 core v1.0.6- in ETHERNETHANDLER_WT32_ETH01.h -# endif - -# define ETHERNETHANDLER_WT32_ETH01_VERSION \ - "ETHERNETHANDLER_WT32_ETH01 v1.5.1 for core v1.0.6-" -# endif - -# define ETHERNETHANDLER_WT32_ETH01_VERSION_MAJOR 1 -# define ETHERNETHANDLER_WT32_ETH01_VERSION_MINOR 5 -# define ETHERNETHANDLER_WT32_ETH01_VERSION_PATCH 1 - -# define ETHERNETHANDLER_WT32_ETH01_VERSION_INT 1005001 - -# if ESP32 - -# warning Using ESP32 architecture for ETHERNETHANDLER_WT32_ETH01 -# define BOARD_NAME "WT32-ETH01" -# else -#error This code is designed to run on ESP32 platform! Please check your Tools->Board setting. -# endif -# include - -# include -# include "data/statemanager/StateManager.hpp" - -// defined here before #include to override - -// I²C-address of Ethernet PHY (0 or 1 for LAN8720, 31 for -// TLK110) -# ifndef ETH_PHY_ADDR -# define ETH_PHY_ADDR 1 -# endif - -// Type of the Ethernet PHY (LAN8720 or TLK110) -// typedef enum { ETH_PHY_LAN8720, ETH_PHY_TLK110, -// ETH_PHY_RTL8201, ETH_PHY_DP83848, ETH_PHY_DM9051, -// ETH_PHY_KSZ8081, ETH_PHY_MAX } eth_phy_type_t; - -# ifndef ETH_PHY_TYPE -# define ETH_PHY_TYPE ETH_PHY_LAN8720 -# endif - -// Pin# of the enable signal for the external crystal -// oscillator (-1 to disable for internal APLL source) -# ifndef ETH_PHY_POWER -# define ETH_PHY_POWER 16 -# endif - -// Pin# of the I²C clock signal for the Ethernet PHY -# ifndef ETH_PHY_MDC -# define ETH_PHY_MDC 23 -# endif - -// Pin# of the I²C IO signal for the Ethernet PHY -# ifndef ETH_PHY_MDIO -# define ETH_PHY_MDIO 18 -# endif - -/* - //typedef enum { ETH_CLOCK_GPIO0_IN, ETH_CLOCK_GPIO0_OUT, - ETH_CLOCK_GPIO16_OUT, ETH_CLOCK_GPIO17_OUT } - eth_clock_mode_t; ETH_CLOCK_GPIO0_IN - default: external - clock from crystal oscillator ETH_CLOCK_GPIO0_OUT - 50MHz - clock from internal APLL output on GPIO0 - possibly an - inverter is needed for LAN8720 ETH_CLOCK_GPIO16_OUT - - 50MHz clock from internal APLL output on GPIO16 - possibly - an inverter is needed for LAN8720 ETH_CLOCK_GPIO17_OUT - - 50MHz clock from internal APLL inverted output on GPIO17 - - tested with LAN8720 -*/ -# ifndef ETH_CLK_MODE -# define ETH_CLK_MODE ETH_CLOCK_GPIO0_IN // ETH_CLOCK_GPIO17_OUT -# endif - -# include -# include - -# ifndef SHIELD_TYPE -# define SHIELD_TYPE "ETH_PHY_LAN8720" -# endif - -class EthernetManager { - private: - StateManager* stateManager; - bool _WT32_ETH01_eth_connected; // false; - std::string hostName; - // Device IP Address - IPAddress* ethIP; - // Gateway IP Address - IPAddress* ethGW; - // Subnet Mask - IPAddress* ethSN; - // Google DNS Server IP - IPAddress* ethDNS; - - public: - EthernetManager(StateManager* stateManager, - const std::string& hostName, IPAddress* ethIP, - IPAddress* ethGW, IPAddress* ethSN, IPAddress* ethDNS); - virtual ~EthernetManager(); - void WT32_ETH01_onEvent(); - void WT32_ETH01_waitForConnect(); - bool WT32_ETH01_isConnected(); - void WT32_ETH01_event(WiFiEvent_t event); - void begin(); -}; - -# endif // ETHERNETHANDLER_WT32_ETH01_H -#endif +#if ENABLE_ETHERNET +# pragma once + +# ifndef ETHERNETHANDLER_WT32_ETH01_H +# define ETHERNETHANDLER_WT32_ETH01_H + +////////////////////////////////////////////////////////////// + +// #if !defined(USING_CORE_ESP32_CORE_V200_PLUS) +# if ((defined(ESP_ARDUINO_VERSION_MAJOR) && \ + (ESP_ARDUINO_VERSION_MAJOR >= 2)) && \ + (ARDUINO_ESP32_GIT_VER != 0x46d5afb1)) +# define USING_CORE_ESP32_CORE_V200_PLUS true + +# if (_ETHERNET_ETHERNETHANDLER_LOGLEVEL_ > 2) +#warning Using code for ESP32 core v2.0.0+ in ETHERNETHANDLER_WT32_ETH01.h +# endif + +# define ETHERNETHANDLER_WT32_ETH01_VERSION \ + "ETHERNETHANDLER_WT32_ETH01 v1.5.1 for core v2.0.0+" +# else +# if (_ETHERNET_ETHERNETHANDLER_LOGLEVEL_ > 2) +#warning Using code for ESP32 core v1.0.6- in ETHERNETHANDLER_WT32_ETH01.h +# endif + +# define ETHERNETHANDLER_WT32_ETH01_VERSION \ + "ETHERNETHANDLER_WT32_ETH01 v1.5.1 for core v1.0.6-" +# endif + +# define ETHERNETHANDLER_WT32_ETH01_VERSION_MAJOR 1 +# define ETHERNETHANDLER_WT32_ETH01_VERSION_MINOR 5 +# define ETHERNETHANDLER_WT32_ETH01_VERSION_PATCH 1 + +# define ETHERNETHANDLER_WT32_ETH01_VERSION_INT 1005001 + +# if ESP32 + +# warning Using ESP32 architecture for ETHERNETHANDLER_WT32_ETH01 +# define BOARD_NAME "WT32-ETH01" +# else +#error This code is designed to run on ESP32 platform! Please check your Tools->Board setting. +# endif +# include + +# include +# include "data/statemanager/StateManager.hpp" + +// defined here before #include to override + +// I²C-address of Ethernet PHY (0 or 1 for LAN8720, 31 for +// TLK110) +# ifndef ETH_PHY_ADDR +# define ETH_PHY_ADDR 1 +# endif + +// Type of the Ethernet PHY (LAN8720 or TLK110) +// typedef enum { ETH_PHY_LAN8720, ETH_PHY_TLK110, +// ETH_PHY_RTL8201, ETH_PHY_DP83848, ETH_PHY_DM9051, +// ETH_PHY_KSZ8081, ETH_PHY_MAX } eth_phy_type_t; + +# ifndef ETH_PHY_TYPE +# define ETH_PHY_TYPE ETH_PHY_LAN8720 +# endif + +// Pin# of the enable signal for the external crystal +// oscillator (-1 to disable for internal APLL source) +# ifndef ETH_PHY_POWER +# define ETH_PHY_POWER 16 +# endif + +// Pin# of the I²C clock signal for the Ethernet PHY +# ifndef ETH_PHY_MDC +# define ETH_PHY_MDC 23 +# endif + +// Pin# of the I²C IO signal for the Ethernet PHY +# ifndef ETH_PHY_MDIO +# define ETH_PHY_MDIO 18 +# endif + +/* + //typedef enum { ETH_CLOCK_GPIO0_IN, ETH_CLOCK_GPIO0_OUT, + ETH_CLOCK_GPIO16_OUT, ETH_CLOCK_GPIO17_OUT } + eth_clock_mode_t; ETH_CLOCK_GPIO0_IN - default: external + clock from crystal oscillator ETH_CLOCK_GPIO0_OUT - 50MHz + clock from internal APLL output on GPIO0 - possibly an + inverter is needed for LAN8720 ETH_CLOCK_GPIO16_OUT - + 50MHz clock from internal APLL output on GPIO16 - possibly + an inverter is needed for LAN8720 ETH_CLOCK_GPIO17_OUT - + 50MHz clock from internal APLL inverted output on GPIO17 - + tested with LAN8720 +*/ +# ifndef ETH_CLK_MODE +# define ETH_CLK_MODE ETH_CLOCK_GPIO0_IN // ETH_CLOCK_GPIO17_OUT +# endif + +# include +# include + +# ifndef SHIELD_TYPE +# define SHIELD_TYPE "ETH_PHY_LAN8720" +# endif + +class EthernetManager { + private: + StateManager* stateManager; + bool _WT32_ETH01_eth_connected; // false; + std::string hostName; + // Device IP Address + IPAddress* ethIP; + // Gateway IP Address + IPAddress* ethGW; + // Subnet Mask + IPAddress* ethSN; + // Google DNS Server IP + IPAddress* ethDNS; + + public: + EthernetManager(StateManager* stateManager, + const std::string& hostName, IPAddress* ethIP, + IPAddress* ethGW, IPAddress* ethSN, IPAddress* ethDNS); + virtual ~EthernetManager(); + void WT32_ETH01_onEvent(); + void WT32_ETH01_waitForConnect(); + bool WT32_ETH01_isConnected(); + void WT32_ETH01_event(WiFiEvent_t event); + void begin(); +}; + +# endif // ETHERNETHANDLER_WT32_ETH01_H +#endif diff --git a/NetworkManager/extras/ota/basic_ota.cpp b/NetworkManager/extras/ota/basic_ota.cpp index 545f439..fca2b48 100644 --- a/NetworkManager/extras/ota/basic_ota.cpp +++ b/NetworkManager/extras/ota/basic_ota.cpp @@ -1,76 +1,76 @@ -#include - -OTA::OTA(ProjectConfig& deviceConfig) - : _deviceConfig(deviceConfig), _bootTimestamp(0), _isOtaEnabled(true) {} - -OTA::~OTA() {} - -void OTA::begin() { - log_i("[Basic OTA]: Setting up OTA updates"); - auto localConfig = _deviceConfig.getDeviceConfig(); - auto mdnsConfig = _deviceConfig.getMDNSConfig(); - if (localConfig.ota_password.empty()) { - log_e("[Basic OTA]: THE OTA PASSWORD IS REQUIRED, [[ABORTING]]"); - return; - } - - ArduinoOTA.setPort(localConfig.ota_port); - - ArduinoOTA - .onStart([]() { - String type; - if (ArduinoOTA.getCommand() == U_FLASH) - type = "sketch"; - else // U_SPIFFS - type = "filesystem"; - }) - .onEnd([]() { - this->log("[Basic OTA]: OTA updated finished successfully!"); - }) - .onProgress([](unsigned int progress, unsigned int total) { - Serial.printf("[Basic OTA]: Progress: %u%%\r", - (progress / (total / 100))); - }) - .onError([](ota_error_t error) { - log_e("Error[%u]: ", error); - switch (error) { - case OTA_AUTH_ERROR: - log_e("[Basic OTA]: Auth Failed"); - break; - case OTA_BEGIN_ERROR: - log_e("[Basic OTA]: Begin Failed"); - break; - case OTA_CONNECT_ERROR: - log_e("[Basic OTA]: Connect Failed"); - break; - case OTA_RECEIVE_ERROR: - log_e("[Basic OTA]: Receive Failed"); - break; - case OTA_END_ERROR: - log_e("[Basic OTA]: End Failed"); - break; - } - }); - - this->log("[Basic OTA]: Starting up basic OTA server"); - this->log( - "[Basic OTA]: OTA will be live for 5mins, after which it will be " - "disabled until " - "restart"); - ArduinoOTA.setHostname(mdnsConfig.hostname.c_str()); - ArduinoOTA.begin(); - _bootTimestamp = millis(); -} - -void OTA::handleOTAUpdate() { - if (_isOtaEnabled) { - if (_bootTimestamp + (60000 * 5) < millis()) { - // we're disabling ota after first 5 minutes so that nothing bad - // happens during runtime - _isOtaEnabled = false; - this->log("[Basic OTA]: From now on, OTA is disabled"); - return; - } - ArduinoOTA.handle(); - } +#include + +OTA::OTA(ProjectConfig& deviceConfig) + : _deviceConfig(deviceConfig), _bootTimestamp(0), _isOtaEnabled(true) {} + +OTA::~OTA() {} + +void OTA::begin() { + log_i("[Basic OTA]: Setting up OTA updates"); + auto localConfig = _deviceConfig.getDeviceConfig(); + auto mdnsConfig = _deviceConfig.getMDNSConfig(); + if (localConfig.ota_password.empty()) { + log_e("[Basic OTA]: THE OTA PASSWORD IS REQUIRED, [[ABORTING]]"); + return; + } + + ArduinoOTA.setPort(localConfig.ota_port); + + ArduinoOTA + .onStart([]() { + String type; + if (ArduinoOTA.getCommand() == U_FLASH) + type = "sketch"; + else // U_SPIFFS + type = "filesystem"; + }) + .onEnd([]() { + this->log("[Basic OTA]: OTA updated finished successfully!"); + }) + .onProgress([](unsigned int progress, unsigned int total) { + Serial.printf("[Basic OTA]: Progress: %u%%\r", + (progress / (total / 100))); + }) + .onError([](ota_error_t error) { + log_e("Error[%u]: ", error); + switch (error) { + case OTA_AUTH_ERROR: + log_e("[Basic OTA]: Auth Failed"); + break; + case OTA_BEGIN_ERROR: + log_e("[Basic OTA]: Begin Failed"); + break; + case OTA_CONNECT_ERROR: + log_e("[Basic OTA]: Connect Failed"); + break; + case OTA_RECEIVE_ERROR: + log_e("[Basic OTA]: Receive Failed"); + break; + case OTA_END_ERROR: + log_e("[Basic OTA]: End Failed"); + break; + } + }); + + this->log("[Basic OTA]: Starting up basic OTA server"); + this->log( + "[Basic OTA]: OTA will be live for 5mins, after which it will be " + "disabled until " + "restart"); + ArduinoOTA.setHostname(mdnsConfig.hostname.c_str()); + ArduinoOTA.begin(); + _bootTimestamp = millis(); +} + +void OTA::handleOTAUpdate() { + if (_isOtaEnabled) { + if (_bootTimestamp + (60000 * 5) < millis()) { + // we're disabling ota after first 5 minutes so that nothing bad + // happens during runtime + _isOtaEnabled = false; + this->log("[Basic OTA]: From now on, OTA is disabled"); + return; + } + ArduinoOTA.handle(); + } } \ No newline at end of file diff --git a/NetworkManager/extras/ota/basic_ota.hpp b/NetworkManager/extras/ota/basic_ota.hpp index 5de730c..245cc2d 100644 --- a/NetworkManager/extras/ota/basic_ota.hpp +++ b/NetworkManager/extras/ota/basic_ota.hpp @@ -1,20 +1,20 @@ -#ifndef OTA_HPP -#define OTA_HPP -#include - -#include "data/config/project_config.hpp" - -class OTA { - private: - unsigned long _bootTimestamp; - bool _isOtaEnabled; - ProjectConfig& _deviceConfig; - - public: - OTA(ProjectConfig& deviceConfig); - virtual ~OTA(); - - void begin(); - void handleOTAUpdate(); -}; +#ifndef OTA_HPP +#define OTA_HPP +#include + +#include "data/config/project_config.hpp" + +class OTA { + private: + unsigned long _bootTimestamp; + bool _isOtaEnabled; + ProjectConfig& _deviceConfig; + + public: + OTA(ProjectConfig& deviceConfig); + virtual ~OTA(); + + void begin(); + void handleOTAUpdate(); +}; #endif // OTA_HPP \ No newline at end of file diff --git a/NetworkManager/include/EasyNetworkManager.h b/NetworkManager/include/EasyNetworkManager.h index e2e4311..2ca0986 100644 --- a/NetworkManager/include/EasyNetworkManager.h +++ b/NetworkManager/include/EasyNetworkManager.h @@ -1,4 +1,4 @@ -#ifndef EASY_NETWORK_MANAGER_H -#define EASY_NETWORK_MANAGER_H -#include "EasyNetworkManager.hpp" +#ifndef EASY_NETWORK_MANAGER_H +#define EASY_NETWORK_MANAGER_H +#include "EasyNetworkManager.hpp" #endif // EASY_NETWORK_MANAGER_H \ No newline at end of file diff --git a/NetworkManager/include/EasyNetworkManager.hpp b/NetworkManager/include/EasyNetworkManager.hpp index 4d89ca8..f7480ba 100644 --- a/NetworkManager/include/EasyNetworkManager.hpp +++ b/NetworkManager/include/EasyNetworkManager.hpp @@ -1,65 +1,65 @@ -#pragma once - -//! Required header files -#include -#include -#include - -#include - -/* #if ENABLE_ETHERNET -#include -#else -#endif */ - -#include - -class EasyNetworkManager { - public: - EasyNetworkManager(const std::string& config_name, - const std::string& hostname, const std::string& ssid, - const std::string& password, int channel, - const std::string& service_name, - const std::string& service_instance_name, - const std::string& service_protocol, - const std::string& service_description, - const std::string& service_port, - bool enable_mdns = false, bool enable_adhoc = false); - virtual ~EasyNetworkManager(); - - void begin(); - - /** - * @brief - * @note The Project Config Manager is used to store and retrieve the - * configuration - * @param config_name The name of the project (used to create the config - * file name) - * @param hostname The hostname for your device on the network(used for - * mDNS, OTA, etc.) - */ - std::shared_ptr configHandler; - - /** - * @brief The WiFi Handler is used to manage the WiFi connection - * @note The WiFi Handler constructor takes four parameters: - * @param configHandler A pointer to the config manager - * @param wifi_ssid The SSID of the WiFi network to connect to - * @param wifi_password The password of the WiFi network to connect to - * @param wifi_channel The channel of the WiFi network to connect to - */ - std::shared_ptr wifiHandler; - - /** - * @brief The mDNS Manager is used to create a mDNS service for the device - * @note Service name and service protocol have to be lowercase and begin - * with an underscore - * @param configHandler A reference to the config manager - * @param service_name The name of the service - * @param service_instance_name The instance name of the service - * @param service_protocol The protocol of the service - * @param service_description The description of the service - * @param service_port The port of the service - */ - std::shared_ptr mdnsHandler = nullptr; +#pragma once + +//! Required header files +#include +#include +#include + +#include + +/* #if ENABLE_ETHERNET +#include +#else +#endif */ + +#include + +class EasyNetworkManager { + public: + EasyNetworkManager(const std::string& config_name, + const std::string& hostname, const std::string& ssid, + const std::string& password, int channel, + const std::string& service_name, + const std::string& service_instance_name, + const std::string& service_protocol, + const std::string& service_description, + const std::string& service_port, + bool enable_mdns = false, bool enable_adhoc = false); + virtual ~EasyNetworkManager(); + + void begin(); + + /** + * @brief + * @note The Project Config Manager is used to store and retrieve the + * configuration + * @param config_name The name of the project (used to create the config + * file name) + * @param hostname The hostname for your device on the network(used for + * mDNS, OTA, etc.) + */ + std::shared_ptr configHandler; + + /** + * @brief The WiFi Handler is used to manage the WiFi connection + * @note The WiFi Handler constructor takes four parameters: + * @param configHandler A pointer to the config manager + * @param wifi_ssid The SSID of the WiFi network to connect to + * @param wifi_password The password of the WiFi network to connect to + * @param wifi_channel The channel of the WiFi network to connect to + */ + std::shared_ptr wifiHandler; + + /** + * @brief The mDNS Manager is used to create a mDNS service for the device + * @note Service name and service protocol have to be lowercase and begin + * with an underscore + * @param configHandler A reference to the config manager + * @param service_name The name of the service + * @param service_instance_name The instance name of the service + * @param service_protocol The protocol of the service + * @param service_description The description of the service + * @param service_port The port of the service + */ + std::shared_ptr mdnsHandler = nullptr; }; \ No newline at end of file diff --git a/NetworkManager/include/api/Hash.h b/NetworkManager/include/api/Hash.h index d98e562..7b436b9 100644 --- a/NetworkManager/include/api/Hash.h +++ b/NetworkManager/include/api/Hash.h @@ -1,17 +1,17 @@ -#ifndef HASH_H_ -#define HASH_H_ - -#include -#include - -// #define DEBUG_SHA1 - -void sha1(const uint8_t* data, uint32_t size, uint8_t hash[20]); -void sha1(const char* data, uint32_t size, uint8_t hash[20]); -void sha1(const std::string& data, uint8_t hash[20]); - -std::string sha1(const uint8_t* data, uint32_t size); -std::string sha1(const char* data, uint32_t size); -std::string sha1(const std::string& data); - -#endif /* HASH_H_ */ +#ifndef HASH_H_ +#define HASH_H_ + +#include +#include + +// #define DEBUG_SHA1 + +void sha1(const uint8_t* data, uint32_t size, uint8_t hash[20]); +void sha1(const char* data, uint32_t size, uint8_t hash[20]); +void sha1(const std::string& data, uint8_t hash[20]); + +std::string sha1(const uint8_t* data, uint32_t size); +std::string sha1(const char* data, uint32_t size); +std::string sha1(const std::string& data); + +#endif /* HASH_H_ */ diff --git a/NetworkManager/include/api/asyncota.hpp b/NetworkManager/include/api/asyncota.hpp index de693b1..f880a23 100644 --- a/NetworkManager/include/api/asyncota.hpp +++ b/NetworkManager/include/api/asyncota.hpp @@ -1,24 +1,24 @@ -#pragma once - -#include -#include -#include "server.hpp" - -using AsyncOTACustomHandlerFunction = std::function; -class AsyncOTA { - AsyncOTACustomHandlerFunction customHandlerFunction = NULL; - AsyncServer_t& async_server; - - protected: - ProjectConfig& configManager; - - public: - AsyncOTA(ProjectConfig& configManager, AsyncServer_t& async_server); - virtual ~AsyncOTA(); - void begin(); - void checkAuthentication(AsyncWebServerRequest* request, const char* login, - const char* password); - void setOTAHandler(AsyncOTACustomHandlerFunction customHandlerFunction); - - bool _authRequired; -}; +#pragma once + +#include +#include +#include "server.hpp" + +using AsyncOTACustomHandlerFunction = std::function; +class AsyncOTA { + AsyncOTACustomHandlerFunction customHandlerFunction = NULL; + AsyncServer_t& async_server; + + protected: + ProjectConfig& configManager; + + public: + AsyncOTA(ProjectConfig& configManager, AsyncServer_t& async_server); + virtual ~AsyncOTA(); + void begin(); + void checkAuthentication(AsyncWebServerRequest* request, const char* login, + const char* password); + void setOTAHandler(AsyncOTACustomHandlerFunction customHandlerFunction); + + bool _authRequired; +}; diff --git a/NetworkManager/include/api/base_api.hpp b/NetworkManager/include/api/base_api.hpp index ea4c630..d7a150f 100644 --- a/NetworkManager/include/api/base_api.hpp +++ b/NetworkManager/include/api/base_api.hpp @@ -1,46 +1,46 @@ -#ifndef BASEAPI_HPP -#define BASEAPI_HPP - -#include -#include - -#include -#include - -#include -#include -#include - -class BaseAPI : public API_Utilities { - protected: - ProjectConfig& configManager; - - /* Commands */ - void setWiFi(AsyncWebServerRequest* request); - void setWiFiTXPower(AsyncWebServerRequest* request); - void factoryReset(AsyncWebServerRequest* request); - void rebootDevice(AsyncWebServerRequest* request); - void removeRoute(AsyncWebServerRequest* request); - void getDeviceConfigData(AsyncWebServerRequest* request); - void getJsonConfig(AsyncWebServerRequest* request); - void ping(AsyncWebServerRequest* request); - void save(AsyncWebServerRequest* request); - void rssi(AsyncWebServerRequest* request); - - void handleJson(AsyncWebServerRequest* request, JsonVariant& jsonData); - - using route_method = void (BaseAPI::*)(AsyncWebServerRequest*); - using route_t = std::unordered_map; - using route_map_t = std::unordered_map; - - route_t routes; - route_map_t route_map; - - public: - BaseAPI(ProjectConfig& configManager); - virtual ~BaseAPI(); - - std::unordered_map useRouteHandler; -}; - +#ifndef BASEAPI_HPP +#define BASEAPI_HPP + +#include +#include + +#include +#include + +#include +#include +#include + +class BaseAPI : public API_Utilities { + protected: + ProjectConfig& configManager; + + /* Commands */ + void setWiFi(AsyncWebServerRequest* request); + void setWiFiTXPower(AsyncWebServerRequest* request); + void factoryReset(AsyncWebServerRequest* request); + void rebootDevice(AsyncWebServerRequest* request); + void removeRoute(AsyncWebServerRequest* request); + void getDeviceConfigData(AsyncWebServerRequest* request); + void getJsonConfig(AsyncWebServerRequest* request); + void ping(AsyncWebServerRequest* request); + void save(AsyncWebServerRequest* request); + void rssi(AsyncWebServerRequest* request); + + void handleJson(AsyncWebServerRequest* request, JsonVariant& jsonData); + + using route_method = void (BaseAPI::*)(AsyncWebServerRequest*); + using route_t = std::unordered_map; + using route_map_t = std::unordered_map; + + route_t routes; + route_map_t route_map; + + public: + BaseAPI(ProjectConfig& configManager); + virtual ~BaseAPI(); + + std::unordered_map useRouteHandler; +}; + #endif // BASEAPI_HPP \ No newline at end of file diff --git a/NetworkManager/include/api/elegantWebpage.h b/NetworkManager/include/api/elegantWebpage.h index 11c59e4..f6f77b1 100644 --- a/NetworkManager/include/api/elegantWebpage.h +++ b/NetworkManager/include/api/elegantWebpage.h @@ -1,1799 +1,1799 @@ -#ifndef ElegantOTAWebpage_h -#define ElegantOTAWebpage_h - -const uint32_t ELEGANT_HTML_SIZE = 53715; -const uint8_t ELEGANT_HTML[] PROGMEM = { -31,139,8,0,0,0,0,0,2,3,148,58,233,122,26,185,178,255,243,20,141,206,249,56,221,99,185,1,219,113, -98,136,236,155,197,158,53,147,57,217,102,33,190,254,68,119,1,74,26,137,145,4,14,99,243,238,183,164,110,209, -128,177,103,238,44,109,45,165,82,237,85,146,120,244,172,241,234,205,203,247,191,255,114,30,141,237,164,56,125,244, -204,253,137,10,46,71,12,228,233,35,236,3,207,79,31,69,248,207,179,9,88,30,101,99,174,13,88,54,179,195, -253,167,235,19,99,107,167,251,240,231,76,204,217,111,251,31,158,239,191,84,147,41,183,98,80,64,148,41,105,65, -90,70,190,63,103,144,143,128,172,175,147,124,2,108,46,224,122,170,180,173,65,175,69,110,199,44,135,185,200,96, -223,119,168,144,194,10,94,236,155,140,23,192,58,1,75,33,228,151,72,67,193,4,46,142,198,26,134,172,53,228, -115,215,75,241,115,26,61,179,194,22,112,122,94,192,136,75,251,230,253,243,103,45,63,82,173,55,153,22,83,27, -229,220,242,125,79,12,121,241,250,229,254,175,2,9,181,36,226,102,33,179,200,232,140,17,199,161,233,182,90,89, -46,63,155,116,48,91,76,128,103,106,56,4,72,51,53,105,117,210,118,218,110,93,251,117,233,84,171,60,157,8, -153,126,54,164,68,45,114,70,142,255,251,237,199,233,187,207,213,72,14,229,214,66,73,70,222,205,166,94,0,19, -136,144,139,23,179,133,107,241,168,196,223,168,86,76,192,24,62,66,10,127,87,179,40,227,50,226,197,53,95,152, -200,132,197,139,232,90,233,47,209,96,17,33,121,66,142,118,33,201,84,161,52,35,255,186,184,120,218,57,188,168, -6,167,202,136,146,16,45,70,99,91,141,126,189,154,112,61,18,56,122,112,84,13,45,214,135,78,159,181,74,22, -208,112,90,206,82,156,197,12,84,190,136,140,93,20,72,167,154,131,30,22,234,186,27,141,69,158,131,236,5,165, -73,21,22,186,110,169,7,171,149,28,157,254,10,255,209,16,25,165,181,99,194,70,181,218,162,92,129,145,255,177, -37,143,40,225,41,232,2,57,22,118,172,16,240,7,62,231,239,74,93,130,228,104,119,121,26,253,82,0,55,80, -245,35,97,35,171,188,137,9,57,131,20,137,247,91,86,36,181,54,105,122,150,139,121,132,74,227,211,41,178,137, -157,45,115,129,33,232,211,120,56,147,153,147,91,108,147,155,57,215,17,176,155,101,47,12,70,58,150,201,141,24, -198,208,151,151,137,6,59,211,50,114,237,20,190,58,125,153,158,91,162,152,27,98,55,162,43,105,209,109,116,104, -53,217,189,89,46,123,213,34,235,22,161,217,23,177,10,107,169,162,117,91,39,216,41,88,163,93,143,45,117,58, -97,150,234,52,99,128,223,156,213,164,82,160,72,151,78,149,107,38,183,183,111,6,159,33,179,41,178,36,36,252, -226,229,106,23,30,236,6,228,108,2,218,73,175,139,200,209,178,187,114,153,44,17,159,102,235,172,147,153,44,87, -231,164,193,152,93,76,65,13,163,119,139,201,64,21,205,102,249,55,181,234,157,213,104,147,239,249,168,217,188,111, -203,187,176,20,229,90,204,160,75,94,171,124,86,0,89,38,244,190,197,228,234,10,76,5,22,150,53,218,37,189, -118,131,127,175,149,78,19,154,205,216,50,141,28,36,244,105,19,146,32,237,30,206,30,185,89,162,252,86,132,173, -152,178,205,166,251,47,173,183,170,87,57,109,74,86,81,151,105,224,22,98,57,43,138,196,225,67,145,197,242,62, -218,37,37,56,194,103,133,37,219,50,47,217,176,200,246,129,167,200,120,193,144,198,138,160,100,168,116,236,13,41, -18,18,187,168,107,196,167,232,138,95,228,118,101,70,112,185,76,7,66,230,158,46,170,146,36,88,152,116,66,146, -236,174,61,111,113,123,182,130,88,195,186,34,254,114,217,221,49,191,50,99,71,26,80,194,9,133,132,130,219,81, -109,170,37,44,169,164,132,62,110,149,227,51,29,115,243,230,90,6,121,121,87,240,11,28,142,41,35,45,66,53, -74,216,176,118,178,76,226,155,118,119,195,216,117,114,99,131,91,160,182,201,227,227,252,9,193,165,164,221,6,32, -119,96,189,26,29,220,224,248,224,128,36,84,49,25,147,53,139,196,33,225,220,92,244,213,37,35,127,17,90,35, -39,253,210,96,162,191,46,157,205,148,75,98,225,247,58,60,62,126,96,175,78,214,30,144,164,87,163,218,134,68, -19,114,90,161,115,37,242,168,141,200,215,12,207,96,12,204,198,49,66,101,46,220,181,187,213,204,14,93,148,162, -67,193,245,60,104,231,14,168,190,3,75,117,128,62,184,11,77,229,14,120,42,195,138,195,93,43,168,218,185,6, -135,151,203,7,40,199,72,92,44,16,20,243,15,58,136,180,6,193,157,96,31,63,62,122,64,176,39,199,252,8, -5,27,252,166,246,100,137,206,47,89,191,111,83,129,123,19,114,121,153,80,153,22,10,9,50,56,85,107,34,12, -38,101,184,118,72,143,78,78,128,36,105,101,246,61,133,250,123,114,220,233,60,61,124,74,16,23,122,237,141,81, -51,157,193,107,62,117,17,221,140,121,174,174,209,129,0,123,203,196,19,253,100,248,0,209,195,236,152,59,203,115, -237,131,163,78,134,123,13,189,209,173,34,35,229,108,21,156,2,71,215,66,226,54,205,102,248,91,121,209,8,236, -154,239,252,204,39,96,206,238,159,138,203,213,73,183,127,73,205,70,60,176,122,17,148,161,176,191,204,184,51,186, -218,105,121,106,10,145,65,140,106,169,237,56,29,174,225,168,65,155,205,149,171,252,234,247,115,254,34,42,191,78, -206,12,126,186,202,27,124,226,117,124,156,61,36,174,167,135,124,16,196,149,119,224,9,182,133,119,244,236,56,195, -54,95,19,169,113,237,172,125,4,216,206,60,76,231,240,49,182,11,215,110,103,67,135,103,198,118,138,231,85,85, -175,41,221,3,100,75,158,205,186,119,114,138,101,220,57,41,48,19,3,218,1,226,77,214,196,54,115,112,65,112, -200,192,18,87,100,126,44,248,178,136,27,42,29,214,241,141,186,144,237,68,224,105,251,167,34,104,31,158,4,17, -100,89,231,96,35,174,52,208,238,27,42,142,239,122,216,147,6,219,157,157,4,162,20,115,146,248,200,125,227,138, -128,29,139,151,203,36,229,203,196,25,119,231,132,115,178,37,155,7,3,91,35,182,145,144,198,114,153,57,59,70, -113,216,177,86,215,209,123,180,235,115,173,21,242,241,189,204,148,214,206,94,200,94,172,207,244,30,137,72,151,144, -100,143,8,57,71,247,116,24,145,207,85,202,113,100,12,224,161,192,144,183,143,143,55,36,35,113,76,101,62,180, -16,186,106,98,253,233,71,28,99,46,72,255,19,198,60,83,36,244,215,115,245,54,95,85,134,176,9,242,35,76, -36,149,141,184,15,126,187,248,201,158,252,211,108,37,44,104,110,149,246,86,208,232,244,156,13,58,64,206,218,212, -176,27,9,95,119,232,240,38,87,18,3,84,131,239,237,225,118,229,216,58,20,98,106,163,107,27,151,246,118,196, -231,177,48,75,250,92,107,190,72,135,90,77,98,67,215,109,172,100,252,96,153,4,243,207,208,252,119,27,69,105, -18,128,102,42,42,183,64,14,28,245,122,157,21,233,82,176,220,73,203,131,252,105,207,5,50,104,99,185,78,75, -40,81,74,73,231,217,3,146,62,60,58,24,110,88,78,43,22,211,49,34,191,21,83,149,227,135,231,73,250,141, -75,87,112,13,131,47,194,182,68,106,193,184,13,29,242,252,105,251,31,27,81,200,246,119,45,135,188,228,238,44, -228,34,69,52,1,59,86,185,59,56,146,61,187,101,52,121,254,128,209,132,80,161,214,12,72,248,164,147,183,219, -62,114,170,152,152,41,100,2,204,58,199,187,98,186,56,101,143,59,183,183,13,185,22,91,66,17,137,185,68,51, -119,76,150,198,234,89,102,149,118,218,11,34,239,243,93,74,28,42,213,237,32,11,157,6,99,208,183,151,241,11, -165,10,224,50,73,113,102,233,243,194,193,193,241,241,3,33,241,224,241,42,137,194,9,182,67,86,104,103,71,33, -43,184,170,44,100,133,195,199,188,19,178,194,201,32,207,177,93,108,25,166,51,242,212,88,53,157,66,206,44,245, -93,13,102,86,88,6,75,58,99,247,69,57,58,163,195,146,178,156,78,233,152,78,232,156,14,232,136,46,24,143, -253,244,217,65,183,227,143,9,195,4,17,247,160,48,224,212,63,101,46,19,210,29,161,100,122,215,32,222,115,61, -2,27,194,136,176,229,25,130,120,180,42,158,38,9,138,84,199,99,12,1,19,38,98,155,22,32,71,118,156,244, -38,167,227,222,120,111,47,113,230,198,102,103,139,88,198,35,102,251,227,203,164,223,190,164,163,126,231,50,233,46, -98,63,64,231,205,230,124,61,84,23,33,113,205,87,7,9,184,142,138,184,209,73,150,57,155,134,132,190,28,176, -60,117,94,217,187,30,139,2,226,6,238,48,40,39,243,36,73,157,99,150,219,103,113,78,23,116,148,250,83,15, -157,37,244,78,145,131,20,252,127,136,232,205,188,190,118,24,108,0,106,83,235,19,236,193,97,246,80,130,229,199, -39,29,111,77,175,185,29,167,19,254,149,138,170,41,100,239,190,64,86,70,45,183,233,202,216,159,181,207,84,172, -247,128,182,147,174,136,53,133,106,115,120,242,144,155,242,167,71,193,148,125,45,228,235,65,111,168,157,206,65,48, -230,99,128,193,170,196,129,186,196,129,167,39,135,161,196,57,57,202,56,73,30,38,216,89,43,173,12,21,77,218, -122,187,162,115,108,142,10,53,224,5,29,96,19,165,239,207,201,51,54,63,147,221,193,153,236,79,46,111,111,77, -60,161,55,203,164,27,151,93,108,214,135,56,58,243,71,213,161,59,166,66,82,154,55,244,135,151,212,166,82,149, -198,251,45,216,51,180,80,21,59,127,161,57,27,55,155,227,210,22,146,110,206,102,14,88,179,34,158,159,13,187, -147,189,120,112,70,82,210,37,255,194,42,96,136,72,16,121,6,121,66,27,186,217,44,227,38,70,142,220,111,20, -156,166,174,254,243,36,220,3,245,178,120,74,243,100,25,35,79,99,62,185,189,205,155,205,220,55,147,102,83,224, -28,113,109,226,171,57,238,8,67,193,88,127,244,240,165,249,3,90,203,214,180,246,228,105,85,147,41,23,5,51, -110,99,82,250,31,161,100,37,33,146,248,202,242,254,226,252,246,118,151,29,227,198,34,41,233,217,85,35,146,153, -129,200,29,127,50,75,234,187,169,13,11,181,253,14,106,139,16,42,177,121,120,233,244,218,144,73,48,89,215,197, -116,92,71,161,90,140,3,171,120,137,4,57,139,165,51,68,153,150,103,31,131,78,50,141,227,187,4,147,214,55, -255,138,74,152,15,111,127,98,36,8,36,44,124,171,148,117,196,36,97,194,82,18,125,211,34,201,114,117,93,209, -215,151,97,146,175,192,250,226,50,73,63,43,33,99,242,73,34,116,13,186,54,184,226,95,213,87,28,142,137,120, -38,193,100,124,10,49,200,76,229,72,217,247,238,6,91,73,144,54,254,225,221,155,159,211,242,0,41,134,11,92, -136,255,160,33,146,213,33,111,138,51,142,23,119,69,218,197,110,33,202,138,180,245,217,40,217,219,184,51,239,13, -184,129,227,35,186,98,27,144,169,90,46,171,97,29,152,222,229,170,117,94,13,113,5,86,39,195,221,181,217,182, -54,214,130,19,208,58,60,65,255,224,242,140,252,207,4,114,193,107,90,220,40,146,115,67,146,53,234,150,36,233, -234,101,18,68,238,10,100,72,197,122,60,241,151,3,119,15,222,214,223,186,245,251,254,10,202,250,147,119,56,90, -223,44,157,173,201,213,149,150,96,237,158,120,230,201,47,189,165,39,48,81,85,165,172,27,70,157,99,146,234,57, -84,13,198,17,177,114,197,4,186,234,50,160,48,136,194,60,179,97,189,9,235,51,20,222,202,192,250,6,73,144, -205,166,234,103,136,14,93,33,214,136,43,115,194,112,31,70,54,212,194,101,30,213,162,112,0,73,215,131,233,4, -69,48,157,25,87,81,58,135,4,239,148,143,135,237,191,113,202,16,49,66,4,87,107,229,139,8,101,90,136,242, -60,63,206,125,148,39,65,227,132,102,236,45,140,206,191,78,215,130,109,193,50,228,138,206,152,216,113,214,35,45, -222,26,144,6,43,202,28,92,221,86,116,221,249,110,88,240,145,233,146,1,89,58,127,163,67,132,113,175,34,13, -102,122,241,12,227,15,6,69,25,223,217,205,208,237,162,207,50,21,59,13,185,195,112,56,229,84,14,238,124,199, -166,126,35,42,195,228,234,94,11,37,191,113,26,44,247,194,211,64,76,252,18,34,100,148,37,103,60,212,22,93, -93,59,16,217,131,61,247,149,203,132,222,204,164,225,195,112,3,124,112,124,112,252,143,148,16,14,134,84,149,117, -224,48,212,196,161,62,230,107,199,109,195,196,195,245,113,237,170,216,116,124,171,116,216,67,59,5,228,7,80,63, -205,166,142,157,244,110,208,152,134,98,52,219,184,106,191,231,144,181,44,99,253,160,13,127,99,86,27,177,247,81, -235,155,198,163,232,155,232,227,12,240,81,42,154,31,164,199,105,167,227,70,208,88,163,131,118,231,104,31,63,39, -209,249,156,203,8,223,151,220,204,91,240,239,39,121,228,174,247,53,238,14,209,235,239,223,71,63,137,12,164,129, -20,65,90,143,124,20,9,41,107,168,1,254,130,24,211,254,70,162,89,209,191,82,50,6,120,231,179,174,181,30, -146,183,33,27,56,223,108,122,239,222,128,20,53,100,163,189,137,132,175,77,117,54,167,76,61,181,35,42,97,202, -145,179,201,0,244,214,160,241,79,18,91,131,131,242,44,178,62,90,239,147,173,241,17,104,223,249,150,176,116,194, -43,216,157,219,238,224,216,181,16,103,53,202,213,197,89,185,204,95,52,23,193,25,106,34,134,59,86,148,174,116, -223,138,188,54,214,169,75,88,23,133,226,182,190,161,168,115,196,41,107,55,155,190,246,29,22,74,233,24,18,68, -136,22,45,204,133,123,163,133,13,172,211,154,14,175,224,221,117,132,77,209,184,228,125,115,254,148,94,163,28,111, -201,23,33,207,8,233,150,119,15,194,248,191,8,114,123,59,243,251,217,149,60,29,223,103,219,201,156,250,60,116, -144,116,87,156,214,59,77,118,138,164,78,151,194,252,204,127,70,254,207,108,23,234,85,243,178,180,10,25,72,239, -122,18,162,210,213,208,211,66,216,152,80,31,109,218,61,245,76,134,52,165,48,77,233,190,187,222,112,217,108,37, -249,179,29,229,159,238,59,6,127,82,215,160,95,114,3,113,130,143,48,187,193,46,151,203,121,76,76,161,44,205, -66,109,227,235,90,31,251,6,12,39,191,192,130,106,24,82,7,228,63,251,38,83,83,160,194,144,53,151,30,213, -247,157,21,193,171,66,50,21,50,135,175,111,134,49,148,175,94,167,251,157,80,71,150,252,102,16,107,218,73,150, -222,246,23,236,111,94,122,234,61,175,55,30,136,214,159,128,86,32,95,107,109,237,122,132,219,241,210,81,198,124, -192,26,49,204,74,204,253,174,207,44,206,87,84,94,177,214,126,252,233,58,105,141,232,23,246,117,87,73,139,188, -105,152,22,28,153,187,162,241,206,39,45,56,115,126,253,97,58,13,106,234,18,76,177,62,199,254,116,47,82,87, -57,62,183,113,59,217,92,186,103,171,171,246,142,95,255,154,181,62,189,136,251,207,247,255,184,116,52,190,252,91, -26,95,83,178,255,239,14,73,54,237,6,81,213,226,254,92,18,191,234,235,90,92,171,247,151,96,172,65,116,103, -242,180,115,182,235,157,166,91,63,243,212,237,100,117,229,150,94,149,136,88,176,38,170,107,165,190,219,144,162,45, -95,47,33,241,138,121,195,46,42,176,218,128,60,192,217,187,238,231,154,151,231,37,10,96,112,123,219,174,110,18, -195,86,251,64,37,115,55,1,101,212,208,73,117,67,161,247,247,19,233,237,160,175,247,160,54,143,154,176,247,91, -94,94,30,107,173,91,179,110,80,182,94,241,115,108,107,120,192,98,151,106,244,122,93,23,167,122,111,207,35,104, -54,223,163,172,92,171,14,186,53,154,243,144,236,189,12,190,223,186,106,170,147,223,146,254,197,118,153,193,178,150, -204,191,107,71,94,123,81,108,4,33,185,68,134,226,201,42,103,110,104,119,189,23,128,176,78,115,111,9,171,168, -89,191,119,66,178,186,165,85,108,59,42,83,177,53,84,226,86,152,62,66,160,8,242,112,36,85,77,23,197,97, -14,122,177,110,217,53,179,37,35,78,94,203,196,163,219,168,32,95,113,139,217,9,182,135,234,237,70,96,223,139, -9,196,62,143,213,61,79,215,237,237,214,45,52,15,193,5,99,165,113,12,153,141,1,88,169,140,215,108,152,21, -27,252,14,27,27,76,32,11,129,143,112,57,93,172,105,180,54,130,87,155,214,183,195,144,144,248,128,48,169,143, -242,101,99,191,83,99,250,165,142,154,200,225,221,247,87,112,17,17,147,16,13,158,237,138,208,218,185,67,144,188, -96,196,255,64,200,128,70,6,247,53,184,146,17,114,66,63,176,62,89,75,55,36,23,26,16,247,28,176,61,20, -133,5,77,46,233,239,8,52,0,228,6,94,186,144,237,230,50,215,112,8,170,137,215,106,230,215,79,240,239,250, -248,135,105,94,46,152,249,70,61,241,10,140,213,106,225,182,44,91,126,142,187,189,43,184,28,214,123,160,181,194, -80,56,69,1,248,126,201,201,47,26,134,128,122,64,34,223,178,27,53,117,82,121,13,122,4,104,236,184,112,36, -192,116,119,229,119,35,10,228,215,189,254,78,181,202,103,94,154,239,197,212,13,228,48,183,74,21,198,79,130,70, -90,39,206,44,93,215,211,240,29,151,121,1,186,235,16,209,107,174,229,198,128,24,73,133,4,86,239,82,198,189, -211,162,225,189,84,249,61,132,8,243,22,60,43,249,123,62,234,126,191,214,127,110,173,246,3,31,228,23,169,174, -101,133,18,135,208,5,16,216,95,57,77,57,82,118,78,125,249,243,75,193,173,163,182,154,235,254,69,39,51,99, -63,24,255,84,136,203,252,143,229,220,233,229,170,16,67,200,22,89,1,223,41,245,197,116,127,95,210,23,172,197, -247,255,194,28,245,105,214,110,191,120,226,190,47,219,251,238,207,171,99,255,125,234,59,23,199,254,235,59,135,79, -94,249,239,5,118,58,23,23,23,159,102,7,184,104,223,255,121,229,190,135,23,190,115,212,118,223,39,109,215,233, -60,117,96,47,219,190,115,113,142,157,195,118,187,131,157,87,79,28,130,139,19,63,115,241,234,229,133,251,94,184, -14,98,126,213,170,99,226,127,107,127,136,237,30,33,137,207,194,78,190,62,19,7,15,57,60,102,204,37,148,147, -199,238,111,237,78,223,58,199,44,175,62,238,253,93,85,248,113,146,166,235,191,245,105,72,122,173,133,13,39,192, -173,19,225,178,76,121,223,185,100,85,21,242,49,233,255,47,217,123,81,157,170,247,72,250,239,171,79,159,242,203, -245,74,237,215,234,29,169,241,157,127,129,194,94,224,109,85,125,166,228,110,105,100,183,35,11,172,71,22,143,208, -86,49,165,103,49,69,186,144,117,185,172,223,157,60,169,31,233,111,140,92,93,249,204,124,117,69,132,196,132,247, -7,219,241,83,177,240,203,5,250,195,238,217,95,127,59,151,115,161,149,116,214,137,89,167,177,49,144,78,43,171, -164,127,178,31,154,205,221,115,155,149,14,253,145,253,17,126,38,145,74,62,23,35,247,88,154,206,12,232,231,35, -183,108,19,218,90,246,99,179,217,154,24,1,183,86,139,28,33,90,165,56,127,76,40,248,201,31,87,117,47,113, -96,209,73,218,38,201,105,155,234,237,89,200,71,208,242,83,210,178,120,115,14,189,92,43,225,46,119,220,118,171, -39,69,158,87,239,138,202,172,182,197,35,40,118,221,33,233,207,132,170,18,83,43,27,107,53,129,79,173,79,249, -94,77,159,155,152,142,185,180,106,242,217,212,195,126,231,137,79,48,173,161,208,48,84,95,63,181,98,92,153,180, -146,132,10,235,126,107,114,237,166,41,183,46,47,160,202,255,72,66,86,55,110,186,183,219,188,141,165,100,202,141, -17,115,184,251,99,1,110,253,235,107,66,43,217,243,60,63,159,131,180,63,9,99,65,130,142,137,163,111,127,181, -222,7,60,99,67,42,252,194,171,162,39,179,117,101,115,247,114,225,99,179,25,127,100,13,84,113,3,13,98,167, -73,249,59,200,190,187,121,207,192,24,130,21,87,21,238,157,72,215,39,82,144,243,244,227,135,243,171,243,159,63, -162,96,62,46,105,97,215,140,231,234,202,205,189,58,255,248,254,205,155,159,222,93,125,251,211,155,23,207,127,186, -250,238,205,155,31,175,174,214,78,239,182,174,191,118,158,112,81,71,146,187,156,24,185,187,231,74,75,245,185,53, -78,74,231,31,90,154,91,246,224,143,45,113,171,178,153,220,195,249,91,24,22,144,89,15,89,181,83,140,253,63, -194,194,96,220,184,15,59,148,11,240,111,114,246,110,83,167,43,46,109,28,30,72,193,254,31,99,95,194,29,183, -141,252,249,85,70,253,188,27,114,13,107,236,188,155,109,76,191,196,113,102,146,141,115,223,94,143,30,221,13,89, -140,187,65,13,136,150,227,72,218,207,254,175,31,10,71,241,144,198,57,212,32,136,179,0,20,234,230,18,3,150, -240,195,132,219,43,43,57,145,233,196,166,192,183,42,81,7,155,102,84,71,20,196,238,26,149,165,27,168,117,165, -244,253,3,164,170,183,21,51,195,151,94,63,87,23,30,186,82,63,171,222,145,98,202,63,124,168,184,173,227,235, -129,68,201,183,235,195,100,140,63,28,95,207,135,137,210,44,33,246,212,221,168,138,51,135,254,202,76,107,189,169, -114,61,53,171,178,51,151,198,238,228,248,14,172,174,195,114,229,36,6,243,153,185,12,13,77,91,176,189,39,33, -136,158,201,110,115,167,201,166,107,93,248,150,199,170,176,79,107,243,212,173,77,96,91,204,171,83,166,192,42,116, -146,58,215,128,108,0,233,149,39,48,149,51,241,218,135,123,214,39,104,136,42,130,101,122,227,43,46,212,95,86, -178,200,149,127,121,149,89,184,39,175,88,152,224,167,90,119,152,193,118,170,85,67,132,190,111,223,36,173,61,104, -85,109,56,189,37,142,111,231,140,213,142,159,189,249,147,198,205,105,179,63,232,158,147,118,208,140,98,98,173,222, -134,130,29,63,158,219,103,156,33,10,33,247,155,64,49,14,147,220,31,32,85,249,98,39,115,193,62,104,240,41, -72,112,78,38,155,83,35,237,36,255,139,200,209,140,218,33,82,141,94,141,178,92,251,142,144,56,167,187,225,7, -79,184,102,43,50,160,113,163,166,140,3,122,78,153,164,254,194,21,42,138,61,219,83,167,59,145,241,13,186,78, -143,129,248,251,188,133,113,199,123,61,136,188,23,198,183,114,52,224,252,144,255,45,100,17,23,253,126,103,156,6, -183,250,142,110,149,176,20,205,68,26,14,171,163,119,158,151,9,220,217,2,238,95,6,203,237,162,185,117,103,134, -234,189,56,4,212,49,31,122,90,59,121,244,242,125,194,10,171,213,138,75,25,80,96,180,217,132,230,13,171,238, -149,145,64,123,172,140,224,179,207,188,96,192,185,122,21,33,50,254,41,210,214,114,6,222,134,202,178,235,202,99, -43,43,31,118,177,138,144,113,144,159,150,116,58,184,202,135,241,41,143,173,140,178,189,229,231,217,238,162,44,185, -134,69,244,128,157,239,233,143,50,101,243,248,156,164,92,236,92,143,191,35,24,248,146,86,70,156,15,95,210,202, -136,19,226,75,90,25,113,70,124,73,43,35,182,148,47,105,101,196,246,4,232,1,173,175,60,75,26,196,74,191, -152,226,253,175,124,173,158,121,98,62,129,133,160,138,239,47,193,249,93,116,231,30,28,165,77,41,150,92,34,209, -59,60,59,112,241,131,89,189,90,63,11,134,7,207,91,34,79,22,188,65,190,194,173,180,254,103,245,194,43,63, -83,145,57,216,69,205,229,105,81,2,101,73,2,229,224,25,146,223,211,3,235,73,85,167,141,100,198,29,180,82, -72,17,61,210,191,38,202,35,26,132,123,54,8,231,201,53,72,230,41,53,189,118,235,215,4,132,183,107,228,167, -9,34,59,238,156,143,107,126,159,174,237,30,194,139,254,117,32,147,88,114,211,83,183,184,131,226,45,66,123,173, -99,137,102,24,229,31,254,30,67,6,2,72,173,126,192,57,41,135,228,155,176,207,41,147,245,34,159,248,249,245, -25,216,166,136,194,209,115,56,15,135,248,124,117,120,6,209,0,221,79,224,193,86,12,138,149,98,37,228,84,12, -181,169,126,221,252,232,169,28,13,164,249,154,19,234,15,95,115,83,114,154,56,140,77,200,125,215,238,223,210,147, -56,215,104,129,237,247,50,159,35,121,193,208,174,81,174,112,83,150,70,7,16,199,149,182,79,251,181,77,26,233, -78,59,172,48,6,223,41,3,107,134,91,33,244,243,194,94,3,212,248,54,232,54,38,150,179,239,125,22,245,188, -19,48,8,74,16,78,203,210,159,248,141,211,233,5,169,63,168,185,173,175,168,112,181,172,74,169,179,73,121,55, -60,255,211,27,59,192,189,143,199,65,205,116,3,233,22,169,178,99,121,170,71,13,69,25,142,254,139,139,3,170, -73,200,118,191,240,229,162,78,48,136,43,218,254,55,27,108,212,100,169,100,75,82,73,24,9,182,167,242,218,224, -246,6,24,5,180,104,68,109,57,57,24,191,30,48,211,155,155,143,81,105,114,248,160,250,7,67,27,77,18,246, -250,132,246,61,1,223,213,235,15,118,147,186,95,151,27,49,195,176,25,138,6,59,161,90,65,190,85,93,36,239, -232,88,237,233,113,143,199,146,53,145,161,210,18,124,230,233,7,16,191,85,131,236,48,66,194,78,122,52,90,107, -82,118,152,147,160,186,179,39,225,41,2,166,218,110,182,69,193,210,56,109,84,6,132,161,83,158,15,60,237,80, -185,73,255,242,197,168,123,182,135,200,170,138,42,207,100,188,201,156,174,74,57,176,122,207,170,34,163,158,0,187, -177,9,18,36,236,216,164,156,154,104,142,74,211,88,61,237,168,14,79,59,109,240,4,227,180,83,73,3,77,243, -78,27,115,227,26,187,169,104,67,218,104,123,104,208,175,29,163,55,87,55,85,106,93,92,208,15,194,180,239,155, -180,156,79,205,214,157,225,32,151,193,149,81,201,227,114,115,195,106,47,90,255,157,217,27,111,194,228,20,138,140, -70,86,75,201,176,151,226,155,76,26,58,194,60,182,208,237,238,169,13,178,28,163,89,68,12,186,147,135,82,82, -31,180,227,110,63,145,252,4,80,164,94,18,35,153,169,212,124,65,174,244,133,207,82,124,53,106,85,162,227,89, -235,247,48,37,180,93,217,127,34,108,133,111,189,254,254,116,81,128,91,16,250,231,101,41,79,132,131,85,234,39, -178,20,122,231,55,19,222,153,32,209,140,213,0,170,165,25,182,79,187,52,168,22,42,93,221,145,125,82,198,203, -39,193,218,165,178,188,6,189,54,248,193,138,187,122,131,19,73,39,238,88,217,26,127,123,250,75,131,3,162,108, -194,49,115,148,170,23,148,76,63,229,51,24,223,185,205,4,247,88,189,36,131,48,27,195,71,222,97,155,27,213, -47,150,242,27,47,74,249,162,250,75,99,235,111,27,179,241,11,94,130,84,224,190,110,153,144,193,31,116,126,111, -215,162,164,175,169,187,70,204,254,55,121,77,106,140,196,23,59,187,102,186,133,55,166,161,237,81,166,225,54,223, -3,211,55,226,138,250,94,158,166,104,201,62,215,181,60,130,165,137,201,146,60,44,39,173,87,180,5,187,75,143, -247,105,190,253,120,188,253,132,54,141,54,50,165,234,230,199,170,87,6,48,254,150,73,255,114,22,166,75,158,119, -65,51,50,220,60,17,112,247,13,23,162,195,246,219,50,9,251,109,16,169,252,230,161,99,254,233,238,34,15,87, -36,39,211,159,134,98,223,122,150,26,206,56,241,172,100,236,152,155,98,172,84,43,147,178,76,206,42,7,239,14, -120,20,241,51,160,82,76,7,179,213,32,174,7,192,202,83,251,201,90,176,39,130,74,13,218,208,15,12,176,78, -198,123,161,5,138,109,53,29,206,90,161,164,110,55,109,218,56,195,100,227,80,198,134,212,46,67,22,120,247,183, -152,55,28,210,7,77,9,246,198,8,201,206,98,2,72,129,217,58,122,179,91,6,204,124,58,247,24,48,240,204, -128,178,121,63,168,220,255,21,201,166,245,79,62,52,241,221,88,26,50,151,146,98,7,72,30,245,159,163,163,19, -231,3,88,59,206,139,194,20,0,122,118,209,57,82,43,88,237,230,12,76,31,104,90,53,55,183,234,65,225,232, -183,129,135,0,188,175,145,31,20,92,68,81,224,130,252,27,108,203,209,112,54,228,196,170,58,180,8,187,70,212, -29,98,93,96,199,77,223,112,19,253,237,58,84,127,188,78,75,210,138,203,241,95,147,73,242,2,201,89,230,204, -229,137,150,241,176,197,142,19,22,59,48,24,8,22,59,215,112,128,106,144,198,96,228,92,228,14,117,105,107,58, -236,73,203,51,105,107,58,229,92,191,187,85,109,221,112,154,230,192,179,18,115,249,69,200,5,252,105,86,171,134, -53,51,245,196,46,65,154,186,72,236,42,189,97,241,82,95,195,126,162,177,138,101,121,141,29,17,120,63,75,2, -111,17,157,135,147,108,226,53,75,11,68,187,10,229,213,191,226,47,13,218,224,136,159,158,193,14,26,165,79,13, -88,137,221,16,208,2,119,144,178,168,66,77,79,135,238,207,142,218,170,199,76,84,202,159,242,82,185,17,126,141, -237,231,152,152,143,187,23,205,116,236,43,63,84,93,93,158,77,141,187,183,35,110,135,243,139,221,96,198,208,132, -239,44,153,7,127,231,215,45,37,96,226,138,246,77,232,68,217,44,226,110,11,200,126,245,163,147,62,63,9,46, -181,13,82,5,107,247,174,234,49,241,132,92,176,98,40,128,29,239,234,84,160,19,5,58,46,208,234,175,170,46, -23,104,69,129,150,11,12,154,26,163,209,163,6,253,69,118,44,50,136,53,254,125,118,45,193,251,10,126,132,239, -42,167,124,48,128,69,198,160,189,73,62,89,170,63,197,108,66,231,3,76,190,232,183,35,36,139,129,228,224,0, -117,221,66,147,148,14,196,10,48,32,222,173,165,159,103,89,49,185,69,171,44,5,203,141,86,219,167,143,105,77, -158,110,25,73,195,186,91,184,198,233,150,244,74,250,203,64,127,40,159,216,182,31,252,154,228,9,84,84,17,17, -216,214,138,30,246,75,203,243,101,217,209,128,155,145,195,77,103,230,52,102,101,106,11,236,244,131,184,197,25,201, -144,61,9,93,42,121,72,75,175,9,244,197,47,5,132,127,120,67,185,27,145,110,238,56,155,171,207,197,21,254, -31,95,25,6,205,198,102,142,206,138,37,164,2,50,126,131,84,36,37,157,223,191,255,223,240,127,114,121,50,110, -131,222,175,16,26,134,252,65,96,159,150,75,252,95,47,47,17,238,64,243,72,4,35,228,77,161,158,167,180,86, -220,141,104,9,14,7,155,199,205,163,39,249,198,102,230,196,76,153,19,106,7,197,65,21,251,123,109,88,140,73, -171,72,106,5,182,62,162,186,5,235,165,27,73,219,211,7,44,30,79,123,219,150,149,26,217,127,4,219,159,137, -31,66,47,157,16,138,75,109,48,51,198,153,226,181,176,138,135,130,22,218,56,104,161,191,180,134,126,148,157,152, -155,252,237,130,236,36,86,240,42,178,105,42,183,36,102,160,246,222,95,67,7,34,22,215,153,153,208,132,39,172, -157,48,190,147,134,118,10,71,177,203,2,154,75,194,18,156,113,17,236,74,118,65,216,192,35,156,219,13,50,112, -209,25,185,40,87,36,246,56,116,131,249,123,144,188,214,193,37,71,149,134,112,52,197,84,77,156,106,159,15,94, -87,166,97,141,56,120,223,159,74,195,23,233,50,63,126,19,33,12,173,48,87,22,189,189,109,217,206,186,231,94, -81,102,197,146,152,81,19,52,230,62,117,45,76,207,229,104,88,115,124,115,35,84,161,229,48,82,147,3,225,188, -232,126,233,215,241,153,251,128,116,48,172,136,81,109,208,140,12,129,99,216,34,93,238,147,189,33,182,136,243,88, -219,54,24,150,185,194,188,100,72,167,64,63,150,58,183,181,41,28,71,210,183,85,1,15,46,42,108,227,58,5, -165,109,76,71,124,118,52,154,51,160,113,164,145,95,5,67,55,35,117,42,71,19,172,177,43,154,165,130,193,197, -192,6,113,61,181,245,188,190,13,51,123,156,105,52,239,239,0,212,139,163,111,209,224,55,204,188,195,118,144,26, -152,230,214,37,18,196,172,198,179,226,46,252,10,115,155,190,151,250,241,206,44,107,174,105,236,95,28,130,59,147, -103,104,200,140,90,242,169,242,5,166,62,10,101,35,64,176,55,138,118,121,17,226,156,27,13,147,46,8,46,103, -51,8,32,188,52,58,5,19,136,244,252,143,68,223,124,221,239,210,69,87,157,27,98,229,119,89,206,81,93,26, -117,13,163,163,118,235,141,195,221,17,236,127,212,120,149,168,95,170,248,240,73,253,191,62,166,46,152,31,44,237, -197,101,18,70,243,102,34,64,30,34,123,42,181,18,88,207,112,250,18,238,152,31,103,163,86,214,252,73,208,216, -18,190,226,93,224,130,23,75,192,5,91,3,233,33,122,166,209,86,148,113,66,251,231,190,29,90,11,165,88,204, -154,32,33,237,111,163,249,195,129,129,124,238,203,81,186,50,40,243,26,115,59,16,168,15,81,227,95,137,163,253, -90,78,92,89,53,51,73,101,134,178,58,233,33,252,12,194,238,44,229,254,220,245,127,25,27,242,102,114,118,0, -43,137,239,146,240,218,75,201,89,23,46,145,96,227,80,101,114,109,29,108,3,232,25,71,151,240,119,145,90,9, -195,99,26,50,75,229,24,192,215,118,46,60,179,119,212,178,84,15,21,163,13,214,27,163,255,92,210,75,173,254, -55,78,170,48,48,95,123,109,54,197,172,188,241,209,4,120,245,255,231,5,221,172,32,100,74,39,211,130,137,90, -210,118,84,94,93,195,159,140,126,123,216,60,58,181,229,43,176,177,42,154,253,16,87,58,50,69,127,111,102,182, -232,60,13,95,164,247,10,220,231,185,29,214,115,210,195,22,202,193,84,150,47,134,92,15,219,249,234,17,142,71, -186,29,214,133,191,43,58,212,133,251,159,26,195,157,207,237,249,89,59,197,186,29,195,210,94,170,61,222,165,27, -188,135,109,66,164,123,213,30,110,215,161,247,45,51,39,123,226,8,182,240,224,51,248,57,215,111,76,181,173,21, -161,101,218,141,149,173,142,245,166,162,7,52,15,186,152,75,107,2,214,158,218,164,33,87,231,167,128,176,120,215, -82,22,96,79,93,157,159,70,176,83,73,183,144,77,41,94,13,78,185,246,64,109,54,240,100,58,82,123,199,48, -167,189,10,173,30,235,186,140,218,212,182,66,46,122,77,35,238,83,251,152,135,232,89,122,110,24,233,60,221,174, -199,135,141,37,70,44,242,58,5,161,68,243,23,79,250,58,169,28,7,230,161,132,35,22,29,176,101,171,101,245, -166,106,49,11,181,173,111,45,36,58,45,64,135,145,55,125,53,68,160,118,148,58,64,84,188,35,88,183,154,234, -227,69,246,240,108,184,206,160,168,150,106,99,73,160,62,140,66,11,38,227,108,52,189,174,240,199,69,200,114,98, -129,35,120,250,52,33,5,117,120,235,189,163,198,165,44,134,198,70,171,223,163,247,180,79,247,128,123,23,47,119, -226,164,72,80,244,214,84,173,226,29,117,242,152,202,135,231,129,159,159,8,46,72,216,24,20,162,146,154,10,29, -153,58,243,68,133,27,205,238,13,170,187,185,137,42,9,60,82,63,235,88,216,78,11,219,113,97,139,194,113,12, -39,130,134,255,42,160,242,123,72,158,153,48,6,96,206,157,77,84,253,81,120,23,23,159,104,48,191,36,44,127, -97,4,157,11,204,186,121,25,76,53,94,53,51,125,241,31,40,218,48,255,86,26,120,102,102,238,109,244,23,22, -23,72,182,149,176,129,16,219,253,143,209,149,20,151,10,214,81,152,253,130,120,185,101,5,129,173,218,122,209,247, -176,197,165,171,143,217,30,74,237,245,17,103,109,42,227,220,180,177,200,63,30,7,78,154,198,209,170,202,80,155, -8,164,116,182,122,232,200,26,130,242,94,62,198,1,166,212,30,231,24,77,105,2,203,62,76,235,33,222,134,20, -246,124,48,38,192,61,127,12,167,34,130,251,8,233,67,51,160,199,208,200,102,218,4,156,159,78,52,20,178,92, -175,162,119,168,130,206,209,243,98,37,238,180,169,186,138,149,101,100,52,202,240,110,97,13,67,41,130,15,110,200, -144,7,188,199,143,176,65,190,218,83,89,114,14,230,73,62,164,156,85,26,50,250,205,91,227,40,252,142,140,148, -174,73,118,30,82,214,53,17,147,24,70,124,220,221,175,82,161,81,75,54,249,27,209,244,39,166,18,173,179,228, -17,123,21,237,67,128,241,164,86,99,181,210,92,14,15,209,101,80,157,185,236,58,162,88,246,33,250,252,164,176, -230,254,191,186,38,46,233,183,252,88,191,229,23,93,22,35,126,131,223,34,208,129,208,115,117,217,107,31,140,50, -100,154,106,200,124,249,16,198,53,20,112,146,125,173,124,196,118,186,134,148,84,139,76,136,175,216,64,101,160,236, -200,214,223,2,149,14,64,21,89,142,131,187,148,170,38,241,18,210,69,160,67,15,139,75,151,21,224,166,110,182, -89,244,90,98,68,21,11,16,33,242,240,196,226,100,135,72,46,43,180,18,14,104,157,69,151,254,14,251,143,32, -76,108,117,23,238,54,0,16,22,11,124,13,228,4,209,36,61,93,136,17,157,202,76,213,37,227,46,214,233,119, -176,179,42,25,52,184,54,121,93,183,161,66,93,185,8,9,26,121,73,19,34,170,107,62,27,157,80,86,15,177, -150,218,6,9,60,213,192,15,10,175,87,222,28,96,105,111,0,193,14,167,113,179,149,248,96,171,186,108,151,118, -115,67,53,154,109,106,159,64,41,239,49,71,38,79,251,87,209,71,234,107,83,231,137,34,59,171,233,132,133,141, -196,191,2,217,18,41,63,182,102,35,28,247,55,140,142,113,179,176,171,49,41,30,110,178,172,154,28,183,132,48, -97,97,181,57,161,86,31,12,209,69,163,83,131,102,81,32,149,197,106,249,196,19,88,120,244,236,187,191,204,46, -95,133,50,51,174,44,204,15,88,3,60,192,22,35,52,67,227,134,176,134,30,136,107,248,58,212,200,28,82,222, -73,129,210,234,177,157,124,13,98,139,56,172,7,56,99,136,93,129,16,24,192,155,95,192,214,96,171,240,186,142, -108,26,235,200,36,180,77,29,126,122,90,203,158,224,171,255,66,165,189,80,43,223,109,240,51,158,166,238,73,210, -15,89,111,4,206,74,181,49,3,147,90,169,33,62,149,89,173,84,87,171,94,152,2,141,72,36,59,179,72,158, -25,234,108,18,97,55,38,232,235,198,33,252,64,158,193,29,158,247,51,5,32,174,126,255,170,9,4,129,2,193, -201,98,220,100,20,244,68,60,209,146,19,160,197,197,190,97,170,160,145,129,110,9,75,253,73,171,121,143,205,80, -8,166,172,238,179,28,2,207,111,133,117,77,68,53,115,23,61,25,222,87,152,165,140,25,95,182,132,198,222,155, -91,119,73,173,132,12,43,236,132,107,108,198,108,1,137,117,18,137,117,64,98,108,172,104,88,35,98,235,34,231, -231,168,10,247,183,29,26,165,150,188,108,201,62,124,34,27,2,111,14,204,190,243,88,129,24,41,58,69,58,36, -252,14,115,202,40,253,159,191,174,16,214,115,31,98,144,85,117,138,66,118,228,200,99,142,145,145,169,142,209,246, -199,165,169,202,74,124,136,48,242,153,7,168,156,74,59,1,83,59,5,19,225,81,64,40,65,11,202,204,1,211, -204,68,164,3,127,135,201,80,195,153,208,1,91,225,132,145,79,60,46,2,113,177,1,232,131,224,175,191,251,129, -16,245,0,211,211,110,67,77,145,236,13,119,79,176,205,251,177,250,177,194,3,172,153,112,135,119,161,63,88,21, -164,6,98,85,202,140,106,165,96,110,132,236,52,198,118,195,69,153,106,136,110,131,85,185,5,212,53,74,147,210, -146,45,66,138,171,169,196,214,80,140,161,149,68,252,36,111,208,97,165,60,179,45,127,149,154,159,143,247,254,236, -236,194,0,99,20,124,160,9,119,158,48,139,153,75,205,201,26,40,57,78,190,52,52,93,151,151,32,224,230,147, -209,235,13,141,160,39,168,53,29,82,157,130,198,101,243,172,178,53,186,153,177,5,191,141,122,11,218,101,108,96, -250,73,18,251,169,90,57,172,205,215,40,192,64,47,8,176,101,189,225,118,79,252,120,84,153,173,66,120,253,248, -240,26,20,44,173,190,188,169,125,34,26,98,34,104,139,214,29,76,252,190,63,21,62,155,33,246,12,81,233,158, -14,194,1,25,3,109,189,242,0,206,186,137,77,224,5,167,144,203,94,88,250,45,84,107,123,98,58,219,40,68, -219,50,51,10,35,189,125,74,86,176,121,210,142,254,168,62,9,161,105,132,189,165,38,241,131,246,214,199,151,171, -168,113,94,61,164,210,35,9,32,170,195,169,112,61,49,5,104,171,129,79,229,2,103,247,189,68,126,209,54,122, -8,246,234,63,58,99,48,155,89,94,56,113,54,40,55,83,131,216,6,102,99,155,138,179,245,104,195,158,114,221, -239,131,167,243,231,22,103,134,105,70,110,217,133,252,111,113,15,176,144,136,13,145,191,51,149,133,1,24,87,38, -226,248,161,7,83,174,108,45,44,131,204,196,160,135,42,121,84,130,64,7,85,12,98,224,6,94,6,49,112,113, -90,84,158,59,74,223,99,134,41,181,232,107,91,248,76,160,38,160,110,25,98,62,33,108,206,255,103,196,237,204, -69,89,229,34,106,254,231,76,157,82,178,174,139,159,64,16,140,176,147,139,242,201,121,196,9,211,140,66,73,27, -156,150,35,253,228,245,195,54,193,159,77,64,94,72,213,141,160,102,172,48,114,136,38,39,93,144,60,172,145,214, -253,166,196,250,130,234,156,76,43,238,218,55,191,20,196,202,1,35,174,51,189,231,74,127,204,250,248,5,214,199, -131,245,25,195,188,171,55,212,106,199,230,88,29,206,67,162,14,42,144,232,252,0,213,25,140,190,1,160,87,26, -249,73,78,195,166,25,129,58,212,150,202,8,107,140,48,214,123,92,117,245,199,210,238,99,57,6,58,90,143,14, -188,40,245,240,9,49,144,115,176,252,58,194,191,243,134,252,198,60,244,141,23,86,4,84,33,216,197,247,250,83, -163,232,215,234,3,126,6,125,129,159,189,126,16,114,189,254,44,252,254,71,63,192,79,167,63,195,207,65,127,31, -114,207,245,183,225,247,173,254,41,252,190,214,191,133,223,43,18,11,224,151,132,219,225,247,168,127,9,249,111,244, -191,194,239,78,255,28,126,47,245,175,70,168,250,35,169,15,177,43,195,37,8,215,32,23,220,235,54,137,228,214, -193,102,225,236,8,63,220,77,53,76,24,228,190,86,3,205,201,117,111,160,156,213,116,189,81,145,94,245,186,47, -185,140,193,17,120,109,127,122,6,187,175,142,84,163,136,164,118,114,92,23,223,51,175,144,102,201,222,204,17,205, -142,60,185,122,126,218,71,39,217,33,34,79,135,236,36,51,192,208,33,76,216,199,103,213,215,252,58,92,231,11, -30,83,219,120,211,223,220,128,5,58,21,100,131,74,175,52,49,183,22,56,59,231,44,59,84,69,225,234,74,180, -81,62,99,113,111,60,179,89,215,101,200,108,92,174,32,110,30,97,93,205,136,52,13,81,86,80,51,10,72,207, -59,40,117,105,94,180,64,3,123,22,109,24,105,111,231,246,121,241,96,31,93,53,168,152,167,206,75,4,168,25, -39,193,87,158,240,95,42,157,40,193,146,235,30,238,50,205,221,221,198,14,38,253,74,43,143,180,159,187,188,159, -181,79,219,88,109,193,31,238,245,32,101,199,251,130,253,143,192,152,251,122,251,242,248,74,147,197,207,81,237,21, -33,187,132,210,251,202,242,93,79,115,241,174,218,170,244,168,240,6,45,150,55,252,200,155,254,28,132,48,14,154, -85,91,213,42,144,73,106,71,99,224,187,80,104,239,207,105,206,128,34,200,249,177,172,63,219,137,152,106,135,25, -199,67,160,134,88,124,12,236,93,93,208,223,165,126,97,40,3,2,6,117,33,40,242,203,76,145,31,8,65,30, -158,166,231,245,129,208,246,5,197,169,213,212,215,37,253,206,186,139,67,185,16,64,167,162,51,58,242,173,12,9, -38,151,216,169,78,248,183,89,101,162,240,166,170,88,196,115,115,19,19,65,133,17,94,106,46,131,189,145,251,244, -238,142,80,67,48,8,99,113,252,45,225,219,47,77,17,127,243,114,24,146,57,33,34,219,194,119,10,230,206,146, -16,153,204,115,193,128,196,64,42,16,203,69,181,203,91,99,46,63,217,119,87,133,192,90,27,240,188,230,50,104, -139,131,123,68,38,71,173,94,104,87,247,152,212,55,180,225,72,214,17,66,186,84,102,19,124,20,35,49,205,129, -145,83,147,114,6,185,83,51,119,97,180,218,204,251,90,234,127,253,133,171,172,114,197,60,75,185,130,96,177,192, -25,25,215,183,170,11,190,177,205,92,141,90,220,41,221,98,39,129,127,123,193,1,107,104,177,229,35,200,161,111, -93,229,74,64,155,186,86,83,240,226,230,23,117,54,95,58,152,167,63,64,181,32,222,85,49,178,205,108,104,203, -115,30,173,38,6,52,237,111,243,153,171,12,154,110,136,224,136,109,7,68,172,156,27,11,198,156,140,240,232,248, -76,176,54,147,149,89,201,158,111,175,93,70,221,108,243,89,156,215,42,175,247,209,212,19,229,151,173,254,35,195, -128,90,22,219,182,219,161,230,17,247,167,126,231,128,184,196,55,113,138,149,216,123,188,74,99,90,51,37,119,171, -254,196,192,84,79,64,61,16,95,7,237,198,224,170,130,51,77,194,98,103,16,132,121,212,132,33,99,41,113,154, -70,216,238,83,79,140,134,207,185,47,174,191,131,130,207,162,42,126,233,129,99,59,124,99,149,108,170,125,77,224, -109,183,9,80,151,241,228,175,13,16,247,37,205,145,159,245,37,153,10,184,42,14,237,162,96,120,232,84,105,86, -131,58,36,175,224,213,213,209,60,202,171,254,136,56,11,128,235,97,117,177,89,209,195,69,96,21,140,90,244,59, -118,234,250,153,239,93,227,85,62,16,205,185,202,7,162,217,41,18,234,54,131,74,135,2,188,253,49,227,188,195, -173,192,144,189,147,103,244,154,118,92,14,164,28,66,3,49,130,253,217,210,2,80,119,252,212,24,136,198,227,110, -236,236,190,179,230,199,40,76,40,114,17,27,152,228,120,151,104,27,19,202,77,249,48,109,167,57,181,2,132,230, -30,207,167,152,115,37,25,151,206,141,149,144,190,232,155,147,170,57,250,127,56,39,53,116,41,232,183,75,142,60, -204,129,4,135,206,30,66,241,155,27,146,42,16,145,200,74,98,106,208,48,99,210,186,170,131,148,164,147,55,123, -59,2,225,248,99,75,62,252,40,19,126,132,192,49,182,60,145,19,13,163,150,60,111,123,66,227,156,8,216,143, -196,9,65,234,181,82,118,94,192,32,58,11,149,232,236,229,17,17,101,77,22,6,152,34,12,168,131,158,55,214, -8,109,173,179,158,219,162,104,100,242,161,218,0,96,134,92,24,4,193,235,118,251,118,221,67,87,56,185,219,219, -40,214,105,179,88,103,168,27,24,249,5,123,7,180,164,95,14,34,14,120,221,132,188,129,101,19,78,147,26,212, -233,143,69,20,150,136,166,18,7,192,160,155,25,248,211,145,162,191,232,162,215,22,242,0,229,178,107,74,87,181, -252,98,239,136,160,23,237,137,45,20,179,165,42,29,226,29,250,27,141,131,50,230,8,162,200,81,129,46,76,205, -104,164,96,37,47,75,178,92,72,209,25,92,79,198,108,239,8,170,106,89,31,144,228,127,78,18,194,250,58,106, -123,26,148,162,211,151,173,14,97,237,162,105,130,27,11,122,202,214,13,30,183,236,167,246,21,50,234,5,119,14, -3,94,9,122,210,43,156,107,236,31,78,157,218,1,34,167,73,60,49,246,142,251,254,116,20,154,140,50,55,17, -145,125,127,186,16,110,12,181,0,213,9,230,242,117,67,99,195,69,14,13,87,95,109,53,4,139,66,170,152,14, -61,152,18,83,231,62,204,114,91,22,52,173,83,158,222,153,96,225,65,25,134,51,50,186,155,171,213,27,222,191, -125,133,245,219,185,10,151,142,226,101,189,116,244,3,71,14,172,161,8,182,27,119,73,164,198,44,120,192,21,77, -214,116,111,236,55,69,93,1,93,154,112,142,82,142,206,55,90,46,113,30,152,164,47,31,247,41,111,178,227,225, -211,97,221,150,176,231,165,0,52,168,4,176,168,61,175,44,37,45,204,75,32,18,134,24,232,42,200,128,226,123, -76,107,139,17,75,68,117,25,208,229,150,134,19,36,146,84,234,202,228,7,133,252,32,182,76,249,252,32,108,18, -93,20,18,132,189,162,89,74,54,150,201,33,111,61,213,194,43,155,183,26,161,18,121,163,168,94,67,166,145,200, -178,181,23,172,172,73,50,185,103,113,254,129,71,30,243,139,142,50,36,55,22,143,183,228,198,10,14,129,45,141, -242,19,49,248,135,214,133,13,41,99,73,12,152,53,190,65,139,191,122,16,16,235,10,86,219,93,66,183,142,69, -136,88,252,88,40,222,205,40,152,65,240,85,202,147,21,216,116,210,169,43,199,192,44,134,145,1,250,16,212,8, -190,97,20,61,233,65,178,244,156,199,104,138,6,165,28,83,72,86,74,64,158,105,240,148,97,89,139,211,70,46, -100,186,208,85,79,73,185,148,235,30,27,127,198,206,247,76,36,136,92,133,66,57,81,242,225,59,148,118,73,207, -17,73,29,36,45,218,70,213,254,88,70,107,38,11,185,104,250,202,21,86,53,181,98,226,182,205,118,250,17,192, -73,122,54,119,5,151,74,68,54,105,131,161,141,154,24,187,129,216,208,64,22,244,70,72,128,196,169,123,227,164, -48,174,146,159,231,36,59,43,40,60,249,129,99,153,205,63,169,250,170,230,222,147,194,63,156,212,122,99,10,45, -46,37,121,239,221,140,227,197,240,10,195,59,142,252,227,85,39,98,180,92,99,177,26,163,226,121,108,92,161,32, -109,32,41,251,91,201,233,190,139,51,99,170,155,109,234,113,53,166,52,40,201,124,125,138,60,190,69,125,178,104, -223,149,50,57,43,218,179,94,57,148,117,220,38,217,182,152,32,227,136,234,35,126,206,228,6,186,206,153,80,17, -82,142,194,184,246,125,187,35,80,98,100,229,105,50,54,145,27,123,60,17,93,102,107,152,152,161,65,55,14,32, -222,246,140,6,143,124,88,193,60,217,106,5,218,179,17,81,76,171,185,40,141,236,25,129,155,235,200,194,220,227, -38,223,78,221,228,91,196,238,122,64,133,182,49,152,42,45,46,164,20,169,32,213,138,97,236,247,148,27,12,172, -179,49,124,29,7,92,167,34,199,105,145,99,29,39,19,248,85,253,237,216,112,169,44,144,166,109,237,224,206,58, -108,74,199,205,57,236,152,96,209,116,49,170,73,123,100,188,41,168,215,248,8,32,134,90,161,218,65,251,106,167, -46,242,110,221,86,7,148,189,164,159,141,21,59,134,50,15,236,245,128,210,13,189,47,220,2,42,136,199,82,76, -245,148,159,54,169,28,14,230,194,111,48,35,46,87,54,77,217,51,165,108,204,192,252,193,200,30,232,108,238,219, -247,155,92,146,102,213,236,181,112,67,144,91,32,238,153,201,124,172,56,65,165,203,8,158,39,0,143,138,221,220, -220,80,68,213,56,76,207,237,51,147,125,71,127,199,197,254,46,42,228,162,217,210,10,253,131,109,253,68,229,254, -55,163,201,55,165,5,129,224,254,116,119,89,245,140,141,122,132,133,45,106,220,171,238,154,27,148,102,174,136,182, -127,33,195,241,51,101,20,65,20,209,152,92,93,76,201,165,237,108,162,98,2,179,52,44,154,212,209,91,50,125, -65,48,220,231,40,68,16,153,17,53,179,75,28,54,128,127,48,66,20,86,178,17,67,30,24,51,140,95,190,144, -47,207,207,39,111,159,141,120,193,67,86,119,139,47,117,100,143,207,101,219,154,53,158,57,46,69,238,193,74,122, -144,135,171,28,134,160,189,122,7,49,10,51,31,95,57,245,194,169,103,193,129,148,222,77,21,230,63,184,34,185, -250,251,191,3,186,251,251,122,68,138,244,242,227,212,197,78,8,36,197,250,190,117,239,199,198,42,253,211,142,93, -181,25,124,164,173,75,122,204,202,198,21,100,227,135,209,163,48,137,195,55,126,82,44,93,16,205,211,133,125,44, -63,169,61,153,193,214,44,125,110,141,231,48,90,5,1,93,149,214,194,201,15,31,167,46,72,188,172,141,138,123, -1,165,221,184,83,52,115,119,159,16,213,77,237,170,242,14,191,119,63,187,37,152,151,139,230,14,51,199,56,45, -214,34,215,197,156,47,57,103,59,1,114,30,220,232,27,100,133,31,150,5,25,23,185,117,178,81,28,249,197,12, -228,23,3,98,66,183,28,52,32,216,65,66,40,143,20,249,13,167,184,60,131,122,50,9,119,54,5,164,57,116, -126,233,243,232,137,164,29,143,28,170,251,28,15,129,190,138,240,73,8,43,178,46,240,249,164,74,128,71,215,4, -172,143,66,253,228,63,2,59,163,191,173,62,122,232,31,126,180,250,8,238,39,128,78,154,90,247,180,77,46,40, -48,96,13,58,32,35,188,44,205,45,127,29,97,74,240,127,34,14,217,55,233,248,163,152,87,2,185,211,179,145, -6,174,110,193,14,154,167,204,248,42,81,55,166,72,52,175,25,248,66,242,155,94,5,196,193,245,106,167,115,26, -116,78,34,12,115,120,84,159,222,106,167,40,237,250,158,82,27,199,169,198,43,95,234,208,249,12,69,204,57,4, -82,192,182,33,10,137,113,153,167,236,108,8,245,110,114,6,199,75,248,34,101,227,138,146,210,121,60,75,105,121, -201,249,212,208,221,37,179,133,53,106,128,213,136,25,98,163,150,59,143,160,178,0,130,217,131,251,137,252,68,248, -64,2,60,253,83,6,45,79,40,163,251,13,68,72,65,31,114,118,22,130,128,52,50,131,27,162,14,130,61,73, -87,213,202,50,130,58,35,185,240,217,25,211,96,220,20,229,135,223,252,206,133,23,161,59,177,68,33,201,99,208, -101,177,226,176,208,70,202,66,91,60,145,49,51,56,162,42,151,163,204,174,203,98,225,122,79,233,18,75,118,220, -94,36,130,23,219,98,132,182,176,72,20,167,134,86,102,250,93,128,122,121,61,31,151,155,57,110,206,19,194,25, -102,94,148,124,2,231,27,252,230,230,77,101,202,198,196,117,119,199,4,189,105,221,174,127,71,51,136,172,73,121, -55,204,157,251,196,75,98,21,100,101,122,3,38,43,71,239,26,63,167,72,98,143,30,205,246,51,204,113,202,238, -73,203,170,120,155,48,192,10,203,65,211,96,228,141,4,239,160,240,59,217,93,69,2,88,165,100,226,97,153,56, -148,33,13,221,200,228,55,225,35,222,76,70,9,224,50,215,77,119,242,44,143,56,209,52,86,249,149,136,90,141, -44,136,125,58,135,152,37,87,12,209,220,110,131,94,192,132,171,83,61,87,215,220,68,35,107,10,156,0,5,233, -68,29,154,122,22,223,161,160,41,6,49,141,3,194,96,107,123,9,148,185,6,208,143,53,128,194,36,218,101,123, -149,236,61,177,32,253,24,208,190,204,32,75,171,147,10,33,142,218,100,171,78,34,109,54,52,63,25,74,22,149, -24,87,12,38,70,84,174,13,137,90,237,209,78,39,119,249,84,128,118,115,179,13,2,108,81,66,74,112,116,159, -246,3,39,207,4,20,70,91,163,175,213,221,157,232,142,94,178,76,44,77,63,9,197,240,162,88,197,88,228,152, -121,108,142,250,154,29,105,242,237,123,204,209,55,212,185,184,211,56,15,206,46,193,132,96,71,12,195,238,233,121, -58,138,187,196,48,208,183,132,95,238,96,97,48,237,135,108,24,47,131,49,5,62,156,107,16,173,59,70,32,89, -138,6,66,119,172,197,136,153,110,57,220,203,7,220,243,78,91,21,104,110,171,14,28,38,82,10,60,59,213,39, -65,40,6,49,230,240,107,97,88,238,170,124,103,39,95,203,116,73,131,122,42,215,167,248,66,208,220,129,239,65, -17,222,240,223,197,91,54,116,22,155,97,147,234,165,146,177,192,122,220,123,249,104,96,201,227,51,90,58,88,143, -173,225,4,145,32,245,117,24,107,121,19,2,180,225,40,202,207,195,140,98,42,150,169,85,184,13,150,166,246,88, -157,240,220,96,253,122,247,0,31,127,216,0,63,187,107,128,59,179,60,196,240,214,196,0,40,220,124,217,55,8, -26,105,53,25,110,114,156,17,166,80,199,28,146,27,115,72,76,93,130,61,226,15,228,177,2,100,194,198,210,89, -99,194,56,74,168,200,48,181,86,8,87,194,95,4,10,241,141,127,10,127,127,11,222,79,223,7,164,248,105,248, -251,29,166,95,12,70,225,211,77,89,159,167,97,232,159,114,234,113,169,29,170,242,119,80,28,229,255,226,52,157, -37,68,177,127,23,62,80,1,192,71,98,245,103,167,227,39,26,196,23,118,214,63,187,69,77,25,149,70,27,244, -241,16,26,198,63,38,193,26,194,76,171,85,248,89,213,65,178,65,6,173,7,104,232,169,255,185,32,142,219,194, -231,212,132,249,164,43,82,240,176,254,52,124,244,21,96,241,88,209,172,135,222,73,25,203,248,155,103,221,238,145, -161,63,183,117,205,96,251,206,61,205,128,162,7,88,238,18,228,94,126,231,64,5,243,109,132,165,225,20,245,98, -52,218,32,48,210,62,72,4,176,59,22,202,131,96,157,60,221,45,53,148,30,214,88,21,245,159,160,192,250,221, -225,235,206,123,90,242,239,79,227,247,139,200,188,124,239,79,121,249,207,247,8,49,45,102,252,187,100,27,198,228, -140,121,244,72,138,94,168,75,196,59,93,219,66,180,135,187,202,142,175,94,59,191,122,109,249,230,147,60,9,95, -162,235,9,86,160,109,152,248,10,97,64,23,10,254,151,32,43,163,179,171,128,55,40,19,55,188,176,9,27,205, -149,195,62,48,162,10,16,15,104,35,164,208,194,167,142,139,138,189,254,232,73,34,244,254,241,29,77,252,115,24, -17,80,51,255,64,91,53,17,127,107,42,153,62,157,72,46,49,208,83,50,230,252,60,79,106,253,61,200,163,239, -195,110,186,48,213,175,249,219,133,30,172,184,177,11,95,70,72,33,181,233,238,81,61,176,126,129,63,94,8,186, -53,73,191,57,219,110,170,24,126,219,92,18,133,96,67,66,133,44,124,64,39,100,33,193,89,251,246,175,247,33, -11,9,206,130,0,47,100,33,193,89,188,83,181,141,137,186,41,61,148,134,75,123,165,153,244,241,129,237,107,237, -84,250,56,199,195,135,222,242,67,89,56,110,176,35,99,213,210,78,14,35,14,211,127,126,32,122,240,51,241,140, -151,95,236,134,24,118,164,20,153,229,226,195,191,206,12,3,65,88,175,86,106,217,27,24,5,161,10,247,52,25, -211,84,242,241,23,40,183,75,6,22,83,190,126,94,215,170,4,64,47,51,72,158,103,169,108,133,192,52,226,99, -136,200,155,177,74,235,215,158,151,50,49,58,188,13,130,134,204,107,209,109,250,104,227,40,10,12,88,172,188,38, -49,10,210,219,118,157,52,100,31,161,106,148,95,240,238,97,57,198,24,70,144,106,148,0,87,121,177,89,77,204, -87,72,92,87,120,186,31,47,177,38,149,176,75,87,163,73,242,247,77,202,60,199,135,113,188,104,33,26,139,129, -135,213,56,31,141,80,254,104,23,164,195,37,182,66,169,239,227,55,94,24,148,245,120,72,114,220,203,172,42,154, -155,176,121,62,225,69,83,74,64,156,180,52,1,154,24,141,65,124,52,38,126,221,133,49,139,24,239,90,110,227, -113,75,211,237,236,38,25,41,148,142,114,101,60,226,200,136,194,163,166,38,13,13,249,26,159,128,232,56,19,10, -148,109,93,78,43,244,30,249,184,115,126,184,185,26,32,93,122,154,0,30,47,245,56,160,145,64,4,114,1,248, -184,0,85,195,83,172,28,174,155,27,142,1,148,55,165,92,19,46,130,74,227,207,17,148,243,128,51,196,8,137, -79,79,60,92,202,171,133,88,74,233,229,71,201,14,234,67,142,13,163,254,187,59,185,157,64,196,96,148,75,144, -230,209,23,88,40,9,245,39,104,101,249,83,67,31,186,151,229,38,206,97,196,199,205,38,57,198,189,107,22,103, -183,36,128,121,147,166,94,174,42,85,80,219,135,143,110,114,140,214,162,127,128,130,45,53,156,213,31,16,232,255, -185,26,240,87,4,214,181,37,60,179,189,251,243,53,160,209,97,200,173,168,16,181,48,194,102,229,181,246,119,186, -96,40,167,156,116,34,139,85,11,100,232,82,155,41,157,214,134,89,82,10,47,128,81,198,167,90,153,20,197,152, -212,122,244,162,60,227,21,120,240,205,128,230,155,231,30,116,3,155,176,179,220,195,228,80,199,20,220,3,85,75, -6,94,98,48,100,252,16,19,39,28,252,249,128,114,49,75,204,160,29,139,75,23,184,104,246,107,205,236,60,198, -208,47,113,244,152,59,34,152,22,153,30,201,53,88,42,48,117,183,36,81,75,31,131,19,164,119,191,123,246,222, -82,190,134,137,14,59,92,40,14,33,75,44,41,70,185,226,1,192,171,125,226,166,104,130,155,98,12,70,42,12, -51,237,146,88,157,205,128,144,195,48,93,166,35,182,54,132,208,108,216,166,249,200,215,25,204,134,19,61,63,9, -68,111,103,176,35,40,85,37,47,173,109,241,123,142,231,164,79,55,82,167,193,10,174,31,67,162,252,14,0,160, -30,191,35,0,229,217,99,180,97,242,248,66,196,152,58,222,90,193,152,138,200,142,126,137,188,72,47,179,193,13, -26,174,234,85,173,174,111,199,1,49,249,219,249,116,36,113,97,208,225,19,7,238,56,217,55,103,105,3,254,146, -78,194,114,212,147,173,23,223,57,235,121,241,82,196,38,112,194,203,235,209,109,186,166,195,185,6,120,104,33,0, -41,157,229,138,180,69,159,171,231,106,15,179,201,62,238,152,115,188,232,213,200,228,23,121,50,254,193,73,24,204, -82,127,110,83,69,60,98,55,59,88,66,52,151,176,164,72,120,227,121,221,164,247,14,127,55,180,100,225,243,40, -32,231,104,246,165,14,94,227,8,167,154,14,127,105,184,245,157,24,198,140,49,12,181,228,151,194,17,148,251,114, -6,122,194,39,139,249,73,111,150,53,124,134,47,34,96,138,116,129,201,15,192,81,126,249,50,133,225,171,76,218, -37,46,143,44,229,204,62,36,32,170,94,196,205,51,147,238,45,125,232,123,49,178,62,189,216,60,111,190,73,113, -107,75,211,135,216,244,221,161,185,231,90,85,97,223,185,16,111,231,10,45,58,133,120,59,209,115,43,229,200,41, -93,45,120,149,177,173,3,91,55,187,211,168,117,92,178,236,117,193,130,24,179,13,50,196,128,163,43,110,76,196, -88,20,216,140,191,249,185,120,197,49,86,131,55,201,253,165,2,192,111,239,250,194,168,252,116,219,234,1,99,30, -83,171,15,41,28,145,180,155,152,57,98,247,255,229,199,121,28,119,70,63,152,100,47,125,221,96,106,139,112,20, -225,142,175,108,9,8,92,12,177,65,43,38,77,83,159,144,133,8,28,12,83,240,28,164,20,56,211,164,216,194, -61,239,245,132,50,187,64,74,118,202,78,104,200,92,91,82,147,253,140,148,156,159,144,94,168,150,82,12,73,43, -37,117,239,237,76,199,217,217,187,84,227,160,47,224,74,171,223,144,250,95,25,14,65,204,252,56,4,84,210,55, -100,243,46,221,106,249,224,33,144,251,159,148,123,186,45,129,96,105,229,0,67,44,248,216,126,83,27,100,12,102, -127,78,169,31,29,238,189,183,225,239,69,248,251,45,253,85,227,79,140,211,150,49,120,213,91,252,253,193,164,98, -229,211,227,212,71,193,2,208,121,153,228,171,54,202,151,103,237,221,29,52,203,244,219,30,114,78,37,90,190,157, -152,51,175,93,82,145,152,152,80,110,84,64,219,180,135,102,54,75,84,183,104,27,122,233,232,54,215,34,244,194, -247,205,205,20,48,125,182,24,199,203,212,15,44,250,233,21,62,68,104,162,54,78,250,231,152,187,253,115,204,52, -71,70,130,148,27,40,1,134,213,0,195,145,142,116,130,44,202,113,14,160,22,147,223,148,226,142,16,50,161,187, -241,11,237,34,180,206,208,203,186,199,23,52,124,180,122,141,69,84,207,226,82,177,5,157,154,148,161,18,112,190, -98,239,188,226,94,240,146,115,137,70,167,13,49,255,220,203,89,153,153,114,165,7,30,189,105,247,38,53,63,38, -65,92,13,130,2,179,161,31,244,152,104,61,101,40,67,227,229,210,199,101,222,102,198,129,207,231,72,240,249,21, -191,4,26,90,60,183,92,137,22,105,79,163,250,118,127,124,67,15,212,237,242,11,216,70,1,226,226,243,55,53, -62,1,32,48,122,36,75,199,54,47,197,117,41,126,147,48,180,127,135,23,224,105,236,117,147,83,41,172,39,130, -42,220,241,77,101,47,173,216,96,183,53,18,232,136,67,251,130,225,193,95,140,24,65,68,76,66,110,9,249,172, -230,237,61,139,237,109,9,243,37,115,130,39,235,180,139,198,172,157,14,248,108,61,54,9,65,205,192,201,156,193, -67,13,160,231,20,214,29,176,238,201,130,42,1,24,233,117,10,63,204,62,129,110,228,35,56,230,112,22,246,69, -14,235,83,144,250,4,93,57,233,33,32,138,73,44,166,91,122,131,25,27,66,245,237,232,0,73,80,181,47,87, -225,72,174,104,239,150,98,137,11,253,3,241,110,74,182,224,37,127,224,55,9,134,46,38,40,135,87,205,241,47, -61,99,87,59,252,189,235,163,69,45,172,198,28,253,9,209,235,233,76,149,254,196,105,198,71,128,208,225,24,129, -164,146,121,36,233,141,87,237,248,24,235,16,170,164,45,200,29,11,5,32,73,123,201,37,108,183,76,111,90,59, -166,101,206,50,45,35,172,40,23,155,75,48,156,182,120,62,110,145,163,71,202,48,149,161,181,37,24,130,60,134, -58,163,0,245,127,120,251,242,238,182,109,165,239,175,242,152,39,231,30,242,122,226,52,207,125,86,42,172,78,154, -165,73,155,165,77,220,213,55,175,15,45,81,18,18,154,80,73,202,75,98,125,247,119,126,24,128,0,36,218,237, -187,254,97,11,203,96,33,150,153,193,96,48,19,57,159,74,253,155,43,108,72,216,93,183,22,142,204,122,44,90, -187,76,123,39,89,140,222,7,219,113,229,18,25,37,131,87,27,91,209,232,129,8,53,91,191,53,173,243,91,211, -50,130,12,235,62,169,140,155,42,51,243,64,25,227,121,219,109,100,51,51,66,1,230,138,228,73,64,174,221,87, -128,4,6,165,142,155,187,77,85,5,86,170,128,39,243,49,99,42,226,47,176,79,19,74,178,29,240,131,3,32, -88,227,212,163,234,98,247,27,111,98,222,67,206,123,212,136,107,94,156,249,157,222,197,228,118,63,68,192,46,131, -53,9,30,128,114,95,23,218,184,207,172,204,83,183,103,120,148,10,238,83,199,154,61,254,192,17,250,182,57,208, -198,231,162,225,25,96,241,16,191,252,46,118,196,232,128,127,123,78,253,112,103,185,228,182,248,115,153,1,253,212, -100,116,38,63,239,91,243,243,166,149,68,252,136,20,228,37,43,5,90,63,50,239,170,229,179,171,181,88,195,253, -64,159,155,66,44,144,39,120,246,126,191,172,177,186,200,233,111,65,140,103,118,86,206,150,19,102,245,102,94,229, -47,27,170,174,134,32,187,170,204,93,197,111,96,217,14,50,59,203,48,230,59,34,86,153,129,81,105,131,243,248, -13,242,57,60,227,143,107,112,147,212,99,146,124,117,25,143,174,143,81,239,171,202,182,100,53,137,242,113,245,56, -252,115,71,184,196,126,94,66,209,190,54,107,104,204,11,200,177,176,231,226,224,151,162,154,48,58,127,189,166,131, -168,166,45,9,155,56,222,99,171,204,226,30,42,81,85,24,69,127,106,129,11,246,205,63,68,126,188,30,27,169, -136,22,154,170,152,83,181,31,76,37,135,109,151,81,0,4,224,128,5,55,232,151,162,38,99,161,150,24,231,228, -120,137,120,228,153,173,147,250,102,133,27,255,186,144,193,183,143,92,24,75,33,58,109,13,170,144,247,247,173,177, -136,154,228,172,31,97,130,120,136,159,27,176,9,236,175,76,211,49,155,21,200,217,79,230,77,80,211,38,163,90, -88,153,77,150,229,41,32,139,202,39,201,228,240,58,229,251,121,167,129,108,222,211,190,108,250,212,229,201,230,157, -81,205,79,208,168,150,34,130,28,240,108,46,54,11,129,3,155,99,104,129,240,196,0,38,31,227,239,241,86,250, -222,1,229,159,155,64,6,247,244,207,37,2,239,110,63,225,59,207,45,137,56,131,221,244,170,46,190,92,150,109, -147,175,123,18,250,144,31,147,121,241,110,167,62,255,185,39,169,229,157,40,200,240,102,237,161,59,58,156,237,195, -3,253,240,174,17,27,200,186,221,128,16,127,140,247,131,136,59,35,212,229,16,255,232,134,190,141,78,238,16,153, -145,178,178,161,98,34,88,244,132,163,201,62,91,194,99,158,145,225,223,233,181,249,255,196,252,55,180,122,251,84, -112,226,232,160,114,78,36,10,97,179,108,198,69,73,34,150,72,103,253,246,47,22,236,186,214,218,183,73,232,46, -41,142,211,121,12,34,71,190,236,246,142,230,104,240,118,85,214,114,70,244,13,26,233,71,254,93,197,197,185,95, -220,127,185,114,255,215,163,255,56,122,248,48,17,63,175,77,113,145,138,137,68,18,171,137,25,61,71,154,88,49, -32,212,84,242,240,147,140,46,117,21,12,93,3,235,47,219,202,64,255,212,220,226,89,211,90,74,16,5,149,231, -141,33,196,201,217,166,239,69,2,8,75,234,82,91,53,183,64,137,52,130,88,207,185,140,49,102,159,124,166,233, -144,203,59,223,4,197,96,226,90,155,28,118,207,105,58,111,52,249,128,220,149,81,224,164,121,91,46,151,38,212, -173,171,186,54,53,115,223,223,25,96,121,140,64,179,146,251,77,60,113,160,86,235,186,84,102,24,239,235,166,134, -250,243,55,241,103,122,13,38,172,92,238,208,162,172,59,97,188,166,54,156,239,246,2,185,208,9,106,196,155,106, -210,183,60,60,91,250,209,116,130,79,105,250,114,193,43,188,227,213,94,53,100,158,110,81,185,233,245,66,207,54, -157,9,113,167,174,201,142,10,97,153,243,230,37,52,210,234,186,227,29,205,19,216,86,228,240,191,253,117,240,54, -202,3,231,35,110,252,17,175,90,154,171,14,253,156,83,213,200,47,116,193,26,205,243,168,192,39,210,74,205,231, -220,53,240,88,125,213,158,171,6,137,170,225,149,72,170,59,47,215,164,250,234,220,40,201,82,173,245,154,206,185, -9,181,230,65,151,70,27,189,106,171,5,255,240,202,81,159,43,14,116,171,114,94,145,111,129,131,151,45,215,195, -53,192,195,9,31,75,52,99,31,213,19,175,192,57,38,130,3,127,108,84,91,205,57,128,245,204,1,180,135,159, -170,60,175,121,69,210,240,77,157,110,101,242,251,182,108,186,26,213,99,196,121,1,112,38,246,39,108,123,26,15, -111,116,161,140,177,102,158,230,111,121,127,172,250,126,157,63,120,112,121,121,121,116,249,143,35,221,46,31,60,252, -239,255,254,239,7,87,181,106,62,37,244,98,236,208,155,228,145,67,151,127,199,82,23,120,36,59,135,85,244,239, -76,194,127,25,61,52,191,64,100,234,32,255,131,6,3,194,240,44,71,63,143,150,177,10,211,240,232,142,86,2, -130,242,107,116,182,1,125,194,233,1,220,173,187,172,74,155,125,122,153,101,77,49,146,60,232,186,187,167,247,198, -198,194,239,77,42,49,226,114,67,173,144,143,59,101,88,88,154,136,224,43,146,184,183,153,253,29,39,90,249,214, -19,32,31,170,246,204,30,252,30,109,183,47,1,112,254,7,103,197,165,195,88,38,248,44,215,131,45,133,233,9, -66,65,51,31,114,27,8,21,226,226,237,173,141,126,131,198,142,69,115,244,61,54,47,38,37,208,140,139,75,244, -211,106,218,179,242,40,235,119,230,61,174,29,67,88,46,222,223,113,218,65,107,185,188,47,71,112,252,184,19,53, -222,235,72,45,143,218,34,73,110,179,57,205,95,81,160,3,144,135,96,129,26,44,140,243,32,254,14,11,238,114, -70,252,91,101,35,182,227,43,29,248,67,74,226,211,113,111,238,119,48,203,248,179,21,241,111,27,200,218,12,176, -46,190,176,157,140,124,100,131,241,147,218,175,30,112,94,66,188,33,87,249,248,22,252,175,7,240,127,111,254,189, -126,197,187,162,209,140,56,25,244,188,166,51,61,191,38,240,2,180,98,76,65,216,121,116,94,241,226,20,202,214, -171,158,255,179,14,18,104,22,149,45,175,17,196,59,166,27,140,227,52,35,51,83,14,63,15,105,245,175,180,250, -7,173,254,141,86,255,78,171,255,160,213,178,213,155,53,53,229,5,117,98,59,146,241,228,5,205,25,105,214,52, -239,137,57,175,89,41,196,209,232,55,84,180,86,179,30,191,171,150,212,249,146,59,195,31,165,26,210,53,173,105, -205,233,155,154,74,58,227,83,212,89,75,103,115,197,127,154,56,56,99,236,73,51,236,52,179,173,230,139,134,170, -115,82,244,233,108,206,21,180,159,232,15,106,215,212,246,212,246,51,106,55,103,215,196,200,142,117,107,137,81,111, -93,51,97,43,27,194,201,136,169,87,183,57,227,191,53,65,255,150,54,196,131,79,151,220,130,33,228,229,102,174, -52,1,91,227,12,247,137,12,241,228,150,206,24,43,138,237,119,50,62,140,168,211,155,118,198,61,42,155,139,146, -91,154,181,106,221,243,152,219,0,115,136,48,245,70,238,219,103,186,198,159,12,150,197,187,102,46,122,51,55,253, -156,163,220,34,9,3,96,62,177,86,29,134,175,170,231,204,119,26,90,67,194,116,212,229,25,215,94,87,75,200, -172,206,65,107,192,126,72,213,150,15,209,155,30,144,194,135,56,172,31,176,43,115,158,124,5,162,168,202,90,47, -185,146,102,99,254,129,66,241,208,156,243,128,94,147,165,207,84,137,17,11,2,57,210,151,228,76,115,211,89,173, -103,159,254,216,104,14,170,5,15,9,127,18,86,11,175,110,109,150,30,47,88,42,27,117,14,216,153,106,103,134, -135,82,235,53,47,80,154,109,90,38,64,32,172,160,204,221,140,27,225,44,94,160,98,184,155,22,220,246,253,69, -201,3,28,25,178,161,37,45,235,235,245,138,184,214,101,133,133,92,153,201,175,90,254,233,120,81,171,174,99,140, -112,95,128,208,18,254,113,133,76,47,117,125,189,212,242,107,202,181,168,175,187,84,160,112,157,49,108,97,198,199, -252,51,37,123,179,102,32,252,187,80,213,101,98,84,82,148,30,37,53,22,15,226,39,160,51,165,14,96,76,230, -20,131,194,212,16,219,216,160,173,169,4,157,213,111,115,44,28,247,216,237,149,32,80,145,248,150,244,79,40,56, -170,144,238,82,30,34,165,135,209,31,253,74,95,50,215,203,155,63,117,134,21,58,125,210,15,50,95,68,156,50, -207,174,186,186,76,124,96,145,210,11,156,216,12,28,100,72,83,83,188,136,165,183,133,211,151,127,113,252,250,213, -79,205,39,102,91,26,91,215,205,205,29,160,22,38,151,58,31,236,151,126,96,5,85,161,183,70,81,222,48,11, -206,76,159,184,8,48,14,224,46,117,107,56,159,150,103,184,98,36,131,9,174,105,211,214,73,48,156,27,55,156, -251,212,132,211,119,198,229,143,77,213,94,191,55,155,73,183,193,184,48,29,187,101,236,18,198,134,201,152,25,228, -133,14,37,108,127,54,242,246,44,96,116,3,166,109,158,86,150,117,168,130,87,76,129,75,224,48,249,200,241,153, -198,244,126,213,63,230,68,197,120,166,74,19,151,147,144,15,102,145,24,120,173,35,234,61,222,205,55,239,211,22, -83,22,153,8,88,133,139,255,54,167,149,145,74,195,29,5,172,209,134,8,254,66,123,195,224,98,85,243,27,121, -164,16,219,15,63,179,95,208,91,205,60,115,21,25,201,58,151,3,68,185,134,26,200,62,196,117,216,53,103,73, -7,31,224,65,46,99,16,72,5,222,51,211,204,11,42,184,144,140,97,122,177,69,230,243,79,135,142,96,37,63, -17,244,91,132,55,113,14,32,158,199,138,146,68,246,193,171,1,119,44,218,170,250,92,165,95,162,137,202,23,154, -118,102,46,95,107,138,39,37,95,105,138,70,61,63,215,20,14,48,35,43,10,198,50,63,211,20,12,92,190,212, -228,7,40,191,214,20,140,69,126,169,201,126,118,126,165,9,54,65,252,151,230,167,38,229,61,120,18,99,240,56, -255,164,183,25,189,214,133,253,138,29,203,173,79,52,38,201,73,233,227,60,107,255,145,15,84,126,55,112,132,57, -48,46,213,27,84,142,226,183,217,61,117,64,219,0,155,63,137,54,172,111,192,217,251,144,156,38,48,228,170,198, -44,167,222,220,24,211,180,84,22,141,188,50,159,84,211,29,43,112,184,59,153,46,205,47,44,204,227,23,118,31, -185,243,8,58,11,130,185,239,194,203,230,185,110,71,107,193,255,1,103,171,236,17,59,107,67,146,200,247,92,221, -44,171,151,128,18,45,141,143,122,48,3,154,16,95,60,193,153,193,123,93,156,88,101,134,196,63,109,227,32,15, -191,4,100,73,112,192,14,104,18,120,79,124,27,163,17,177,221,111,229,155,252,89,102,47,32,46,54,234,2,51, -45,72,244,49,49,146,100,14,73,156,161,45,22,100,102,253,177,212,15,123,115,61,70,0,210,1,54,249,55,171, -86,186,102,190,53,219,181,246,130,106,163,4,152,184,137,83,196,222,77,116,135,163,221,203,61,17,255,8,54,70, -151,61,29,182,14,114,10,156,245,122,215,59,68,218,193,8,118,107,60,104,144,50,48,213,93,48,131,245,15,177, -250,89,139,221,82,254,81,225,29,145,142,52,135,160,80,234,156,51,193,91,121,243,168,104,39,135,135,77,38,46, -193,48,224,132,10,176,152,112,47,233,77,17,150,193,237,143,14,244,11,76,125,198,117,228,185,49,5,214,81,205, -97,156,121,223,218,171,69,121,238,244,222,249,52,229,230,170,140,211,185,129,247,154,175,92,96,242,196,90,58,157, -121,144,54,211,233,140,23,157,133,225,14,57,112,89,156,65,94,72,173,3,12,106,215,104,237,16,41,103,197,236, -142,172,93,111,145,49,32,190,35,110,96,97,43,233,254,253,192,116,51,219,41,76,251,129,116,7,25,69,21,218, -69,157,251,163,95,29,144,6,208,110,241,29,88,199,148,39,234,200,122,120,68,101,204,113,90,35,159,6,67,152, -69,209,137,125,181,142,125,111,137,109,240,140,176,192,223,105,221,191,52,40,185,56,40,233,96,229,106,241,62,81, -68,248,176,8,76,52,210,92,22,43,247,106,158,77,165,13,76,100,55,173,247,200,57,146,105,158,229,59,57,233, -156,59,79,167,41,255,187,22,75,197,48,244,180,225,62,94,153,1,53,247,106,166,98,116,37,87,145,207,74,215, -100,189,67,211,133,218,237,150,13,128,67,226,52,14,29,234,92,198,215,133,165,29,9,65,210,101,230,174,35,245, -152,217,114,254,142,224,166,194,22,41,196,51,44,231,73,4,154,14,0,76,197,215,202,120,69,142,185,62,223,31, -22,82,102,82,207,134,126,50,157,9,250,47,37,190,56,60,119,4,186,202,132,83,38,219,88,116,13,189,225,85, -52,10,54,154,58,152,85,192,184,142,116,218,152,252,184,76,49,81,118,54,49,209,89,110,40,102,160,241,18,242, -86,241,96,27,47,118,206,90,206,200,168,192,49,99,209,221,42,66,3,94,226,108,139,16,17,81,71,70,56,169, -208,152,53,9,36,238,147,203,35,71,129,60,66,81,153,79,101,204,150,126,212,48,186,109,187,221,57,147,60,225, -84,4,44,160,195,161,226,119,213,208,243,105,184,155,57,46,226,233,58,230,53,165,88,94,71,172,35,6,47,228, -30,111,117,161,83,101,140,118,38,177,23,157,224,139,154,108,109,108,59,147,237,178,179,195,201,181,53,246,237,78, -231,61,196,198,125,144,2,245,184,151,120,87,40,236,229,165,127,184,63,182,162,113,150,188,109,226,188,93,237,93, -5,134,43,81,231,136,191,176,148,78,69,31,106,211,240,181,152,56,120,45,13,189,52,147,245,194,202,63,2,136, -152,11,74,1,66,158,114,219,164,29,89,173,167,14,81,219,173,205,45,120,215,26,89,86,31,69,204,167,29,193, -42,112,91,217,14,171,187,205,80,188,117,156,158,184,137,13,140,145,14,110,58,56,231,182,122,201,75,131,183,40, -253,182,197,55,129,165,112,213,218,168,247,2,241,191,211,76,112,122,8,108,198,42,153,20,176,7,218,174,52,113, -117,100,141,254,236,40,101,191,10,249,129,38,196,169,78,171,28,29,107,60,166,68,47,45,31,136,175,2,2,17, -46,161,116,201,33,179,48,36,50,181,103,80,63,61,177,101,98,225,33,124,106,200,76,188,74,125,122,172,123,244, -90,62,219,126,112,37,252,144,83,149,23,109,18,97,172,240,49,102,253,78,83,120,99,163,87,248,182,124,206,137, -60,146,17,145,121,50,48,130,218,92,111,13,92,233,224,33,177,40,45,209,183,125,60,20,99,18,0,159,86,158, -147,56,44,154,188,42,22,233,64,28,192,6,142,83,38,228,56,51,78,18,117,152,242,137,216,186,148,209,241,237, -250,177,113,105,60,46,166,227,19,212,21,236,46,87,187,5,203,166,173,1,203,43,231,169,208,162,147,208,237,180, -93,75,42,240,127,4,167,243,48,117,66,176,179,112,94,84,222,135,244,69,81,65,55,224,172,168,224,26,101,89, -180,62,235,186,104,145,117,201,63,203,15,116,197,236,140,221,98,243,71,197,57,191,24,123,84,44,179,38,189,200, -166,168,227,240,112,254,33,111,210,179,108,138,170,238,223,63,255,144,243,201,226,130,174,121,202,222,226,151,251,211, -194,152,166,3,70,245,28,88,125,200,0,120,70,151,0,196,175,1,92,102,228,234,65,7,56,176,20,192,11,11, -120,225,1,175,70,80,255,133,224,216,240,176,159,158,153,129,242,61,136,43,62,179,93,61,115,93,29,175,216,84, -34,213,7,93,244,223,146,54,194,24,178,98,32,175,40,154,19,90,156,21,58,189,54,78,171,167,221,137,9,124, -200,223,167,215,36,249,212,164,179,108,186,78,209,174,237,185,108,243,21,87,183,41,140,63,125,238,224,198,118,112, -227,59,136,44,123,230,28,237,236,38,232,108,150,143,182,144,249,190,79,230,95,159,79,211,69,209,164,60,225,240, -16,54,5,81,203,37,98,202,0,77,45,80,140,150,164,184,198,213,215,124,36,124,45,159,25,42,40,122,222,99, -80,65,43,90,230,13,26,24,180,115,220,31,56,1,65,39,216,41,230,24,90,14,220,153,10,182,244,91,91,157, -89,199,217,23,251,150,215,112,98,85,204,141,87,3,55,94,13,22,114,43,97,170,240,31,173,221,114,10,205,244, -206,25,211,155,60,157,190,145,45,38,236,68,53,82,26,111,60,204,102,52,245,87,131,47,60,238,18,154,11,162, -149,61,93,247,246,116,45,208,79,106,198,40,120,233,45,209,183,134,77,205,254,162,139,27,79,3,231,180,182,135, -86,198,34,107,51,42,243,98,237,208,8,34,243,193,121,15,39,128,25,114,254,70,2,124,14,244,48,68,48,98, -82,215,101,90,89,54,79,44,38,149,242,178,59,64,102,243,204,165,157,204,29,50,219,239,128,64,12,205,111,155, -180,18,134,103,170,211,21,160,96,178,151,95,140,2,195,124,76,23,188,212,206,169,229,105,207,77,70,170,67,166, -42,150,81,49,48,92,159,124,226,95,172,91,46,199,168,206,99,179,150,215,43,154,152,190,78,87,156,179,26,114, -144,252,39,149,230,146,143,85,103,2,163,112,246,59,232,246,177,215,93,31,15,126,168,77,249,56,96,69,85,234, -236,97,187,43,105,23,26,59,60,84,178,248,238,224,85,193,187,121,154,98,177,68,138,84,145,77,30,67,68,111, -4,28,114,245,76,225,221,180,132,13,251,66,188,106,67,1,253,155,157,19,29,117,34,39,162,153,93,136,84,239, -44,38,99,13,107,246,183,191,205,176,18,201,238,77,82,105,32,73,194,151,239,108,198,1,45,220,178,251,152,241, -150,149,138,61,102,78,134,179,241,147,161,188,90,37,36,142,108,175,44,56,28,98,42,134,106,97,201,219,185,86, -3,250,129,117,6,195,203,131,113,239,82,36,74,171,174,193,193,183,106,208,131,166,106,113,109,34,85,149,224,30, -131,196,193,206,150,217,205,222,132,25,204,56,131,205,84,109,215,155,22,73,182,95,29,25,44,195,141,211,130,181, -41,222,240,50,172,121,247,89,121,3,23,127,104,207,86,108,30,54,18,124,163,196,134,223,168,198,13,243,121,168, -34,60,162,112,163,233,108,161,5,6,183,86,184,56,159,101,168,224,56,93,49,4,231,50,245,49,3,102,27,59, -88,243,4,159,88,95,182,31,140,185,15,31,205,182,210,148,44,229,96,75,165,146,98,227,78,246,229,117,18,99, -93,45,239,131,170,178,189,52,102,98,22,44,208,178,78,164,178,108,134,158,193,251,237,34,11,176,36,211,98,145, -145,29,27,15,106,168,100,110,233,15,87,37,196,70,80,136,252,235,108,97,6,156,155,54,161,179,226,107,128,252, -146,151,131,23,249,63,199,26,116,87,26,97,178,117,235,33,155,251,141,180,51,172,184,199,232,166,184,120,157,244, -197,6,210,45,135,153,65,123,206,99,1,214,202,244,219,124,26,99,178,211,186,42,89,134,117,38,244,122,135,237, -97,88,57,128,73,113,59,88,23,254,169,217,89,1,220,110,89,187,11,79,178,151,188,208,150,99,135,130,101,112, -40,88,126,224,34,232,139,97,42,132,216,210,153,175,228,154,43,185,30,57,86,94,251,99,229,181,57,86,114,45, -128,191,42,46,246,16,21,170,191,58,18,199,71,153,171,248,148,159,218,156,62,186,226,3,88,231,106,61,229,173, -96,18,78,78,63,56,246,152,5,36,168,153,107,181,199,185,173,161,35,175,83,220,137,125,69,95,9,242,23,215, -39,175,48,232,219,104,62,102,153,224,40,46,213,15,16,104,254,153,191,249,120,169,229,158,3,161,209,27,139,151, -88,90,31,117,116,99,129,52,156,83,156,44,201,189,128,128,207,226,106,55,137,91,254,44,240,129,53,191,240,202, -67,206,141,5,68,242,60,148,188,133,36,208,21,79,245,126,3,212,123,115,129,51,64,84,123,16,149,135,168,33, -33,222,96,87,153,99,158,108,254,166,232,196,3,214,12,63,13,147,229,35,70,197,63,27,75,35,141,245,174,110, -146,30,183,75,78,40,219,37,61,215,169,246,55,18,144,180,50,196,28,215,62,230,199,35,99,88,46,20,179,18, -34,39,208,144,115,73,105,188,253,24,43,43,203,4,101,234,161,12,22,141,67,146,50,74,129,133,236,93,103,186, -117,104,147,143,219,170,241,89,137,171,86,154,220,78,212,244,170,74,43,151,158,240,230,205,23,105,6,84,186,25, -220,125,8,196,64,233,19,74,111,109,116,179,211,232,198,52,26,141,131,111,60,99,98,164,178,97,10,186,12,35, -127,115,195,197,58,83,108,211,200,224,244,212,83,41,168,227,222,159,40,43,60,221,93,65,99,224,98,107,119,120, -132,54,9,207,250,65,247,113,88,199,74,192,61,132,90,168,202,248,14,11,98,197,61,141,151,81,63,224,52,255, -1,254,182,48,111,112,225,84,5,46,156,252,2,76,168,49,207,110,40,176,179,30,58,152,143,47,107,219,242,242, -141,125,163,131,66,135,201,81,114,24,185,238,15,123,197,79,235,142,62,106,213,164,12,21,108,167,231,122,223,253, -73,47,107,204,252,88,231,1,202,60,211,102,12,110,240,92,47,240,251,22,127,6,233,83,240,81,172,86,231,250, -199,193,193,72,163,197,39,63,241,29,222,107,77,207,116,112,51,247,155,190,219,13,38,58,148,30,104,227,204,76, -108,63,196,15,151,84,179,170,90,213,63,182,23,87,198,95,99,160,124,128,82,76,61,195,20,231,183,94,110,60, -44,54,175,139,176,148,24,35,225,172,56,201,44,12,243,206,136,23,178,53,74,140,54,99,72,121,44,183,201,50, -254,43,139,13,172,154,119,69,109,126,96,145,150,53,140,153,233,48,130,139,161,190,180,103,197,20,35,55,220,8, -98,97,192,90,66,22,220,249,181,179,249,25,213,89,147,162,110,180,255,162,129,99,238,217,46,53,230,123,148,111, -27,250,5,153,89,254,27,255,240,96,236,1,33,51,96,208,223,121,165,6,119,173,181,167,114,243,141,131,201,127, -52,186,210,63,55,144,86,239,51,3,21,204,119,20,187,170,211,238,245,219,179,215,223,60,123,138,200,208,208,84, -84,174,243,138,246,244,11,90,249,2,110,108,47,235,155,198,230,191,184,163,51,126,44,42,134,116,117,4,89,242, -61,238,203,66,255,245,58,56,178,152,202,179,145,47,245,220,83,223,227,69,25,255,75,142,159,253,122,252,248,221, -179,199,209,55,114,250,218,115,245,110,44,18,107,210,24,70,172,85,181,94,57,225,96,248,250,2,218,179,122,253, -210,25,67,0,227,93,46,75,65,186,228,186,244,236,34,120,11,239,110,137,141,115,69,99,227,237,182,108,114,13, -227,117,204,200,224,203,246,253,209,179,3,191,89,118,0,161,128,224,127,27,109,102,217,89,202,157,146,194,171,176, -131,148,151,99,160,14,140,173,139,148,153,13,115,118,201,171,149,255,239,1,149,22,40,27,238,210,126,197,248,208, -12,210,73,127,93,99,10,84,221,196,30,151,186,130,245,128,59,232,7,207,184,32,118,34,192,249,120,118,97,0, -25,98,87,55,73,56,121,56,191,11,1,139,206,14,198,11,77,191,248,241,248,214,142,7,66,172,15,174,139,228, -244,180,77,232,87,19,152,37,126,132,126,119,218,94,252,123,242,179,254,144,13,122,224,253,52,97,245,244,102,201, -27,192,185,168,52,239,5,189,187,127,83,128,144,8,163,206,25,201,43,160,127,49,201,91,212,247,43,215,103,216, -114,169,40,44,138,60,114,25,81,113,41,22,104,88,199,247,249,197,11,189,231,92,69,167,146,169,254,204,185,138, -98,194,162,184,58,13,26,98,7,238,15,93,148,112,208,156,194,123,180,188,58,228,224,9,75,226,30,21,255,254, -143,128,116,127,63,80,43,51,96,127,104,247,0,243,69,139,69,53,169,10,197,6,193,90,238,64,232,161,77,70, -215,217,214,17,173,255,77,219,194,198,131,73,97,2,234,237,222,126,93,232,40,254,168,248,10,113,41,43,238,172, -158,90,69,48,254,154,185,13,14,226,59,249,120,177,189,19,56,52,217,190,208,251,155,13,159,82,246,211,47,80, -200,221,180,85,46,26,130,120,219,213,108,243,16,225,244,202,127,118,202,114,132,23,58,27,219,220,0,26,62,255, -230,38,70,90,149,114,23,4,1,61,212,77,72,12,17,245,27,85,82,184,53,177,58,22,198,39,47,180,221,201, -191,131,10,195,17,78,75,154,190,215,212,43,250,78,135,108,52,67,90,61,82,81,40,87,212,168,97,139,84,74, -182,8,66,1,202,208,35,93,245,130,5,223,97,159,232,186,13,18,106,123,214,21,59,5,209,113,208,246,253,84, -207,225,51,102,8,104,248,30,176,144,241,25,144,69,38,39,130,155,27,209,127,74,146,44,56,39,136,44,75,14, -9,73,160,55,7,220,206,19,147,12,226,15,147,96,160,189,180,136,27,246,145,29,183,165,224,121,51,140,173,106, -54,213,68,188,199,206,6,121,204,192,140,151,145,118,71,8,2,143,124,96,220,163,151,94,201,15,239,222,126,251, -238,217,251,247,160,57,165,35,75,112,31,115,106,192,10,53,17,95,215,134,167,72,146,92,110,108,57,50,81,42, -45,169,206,140,145,1,129,173,179,193,236,121,244,157,104,72,235,212,87,15,196,29,139,135,90,85,180,234,79,180, -86,169,85,190,76,145,60,98,221,229,175,147,67,117,152,60,122,96,130,166,167,27,174,39,16,29,217,35,126,25, -36,101,241,16,69,89,22,124,19,131,135,23,217,97,150,255,92,117,96,39,8,172,178,232,174,5,12,242,54,148, -121,42,21,234,158,57,199,244,80,19,231,145,76,222,254,112,252,242,237,155,144,71,128,63,3,101,213,201,58,9, -132,134,4,85,64,98,33,147,71,7,188,254,174,104,32,184,113,132,252,45,236,150,83,37,2,191,239,248,204,202, -215,221,69,117,91,16,177,73,120,241,218,157,46,134,91,87,172,228,230,72,212,157,189,72,177,205,32,214,6,71, -100,178,121,241,156,187,204,214,196,82,0,84,54,56,244,8,105,226,236,216,99,12,109,49,6,66,91,170,85,113, -149,166,251,38,94,96,132,170,120,48,73,167,7,39,255,35,253,240,247,127,102,217,131,37,247,249,65,158,30,29, -102,15,28,237,114,86,8,218,108,220,142,6,104,134,255,112,129,109,178,137,119,123,132,157,122,130,171,66,219,115, -88,221,120,232,34,25,140,45,80,197,255,2,77,49,229,251,184,80,131,39,217,160,67,94,228,60,61,78,163,184, -185,252,12,180,197,212,93,207,146,222,220,246,20,169,86,59,238,47,231,42,58,12,243,208,97,146,108,130,246,175, -207,70,132,198,186,208,119,232,205,240,110,119,79,201,218,130,63,92,98,89,6,163,68,13,40,147,36,247,59,201, -206,212,139,109,87,21,202,201,239,84,84,157,138,203,5,94,201,140,224,86,209,74,177,167,181,251,247,31,208,57, -7,254,217,253,253,64,113,79,91,238,99,127,239,1,93,40,207,29,120,86,126,165,156,209,137,204,78,13,248,191, -225,229,46,192,134,235,174,115,11,219,142,195,62,1,251,137,203,107,195,217,51,180,185,162,73,134,62,36,129,96, -182,41,150,74,54,199,158,179,238,63,113,98,224,154,62,105,196,82,146,244,46,76,220,110,233,76,177,150,236,47, -213,217,39,213,39,196,174,83,63,67,179,158,229,209,180,220,219,61,16,173,170,98,253,103,56,88,234,167,190,248, -196,133,40,145,231,49,160,29,120,58,15,2,184,86,131,121,164,65,124,94,249,183,150,95,65,39,242,167,245,218, -233,68,30,186,71,148,15,157,198,192,153,26,241,62,127,166,24,167,30,86,6,137,196,173,52,219,104,155,93,135, -107,218,29,53,212,206,81,163,13,55,23,47,35,73,113,97,181,151,171,36,215,29,49,98,65,65,4,78,27,142, -55,240,201,80,171,207,213,28,105,140,191,109,121,195,133,44,138,250,230,102,67,115,32,1,233,158,173,28,185,19, -73,217,173,161,208,233,220,241,38,83,240,33,208,133,156,79,228,154,98,174,228,130,199,140,182,177,203,186,200,154, -116,205,78,225,224,155,90,165,51,234,176,0,125,246,58,43,11,100,19,46,34,22,28,112,96,214,167,79,9,50, -95,90,246,252,210,227,223,107,139,127,17,218,210,149,217,90,135,15,252,208,159,122,214,205,60,45,28,176,186,220, -31,201,57,13,252,106,22,200,16,254,69,100,8,149,197,177,87,106,12,33,123,77,237,160,22,107,214,156,103,63, -223,79,13,149,164,32,122,226,230,151,35,199,57,30,116,30,26,8,167,38,109,216,167,195,10,105,70,61,189,31, -63,7,166,237,97,149,185,239,11,61,102,254,127,30,4,225,100,226,113,136,51,40,76,149,157,117,115,227,242,247, -62,236,127,125,228,168,41,134,17,179,152,219,143,101,147,125,205,252,107,91,120,116,216,16,62,119,130,36,25,24, -106,167,227,99,12,9,204,173,253,12,199,252,149,242,36,27,172,167,188,139,12,105,159,103,14,6,231,62,162,216, -214,117,32,34,21,189,86,169,179,48,150,48,150,203,8,137,61,104,184,192,143,209,83,148,201,242,240,132,243,122, -23,171,186,119,208,48,43,208,202,51,104,126,108,124,223,68,19,50,63,199,122,39,253,126,175,109,214,99,195,187, -237,102,11,71,151,80,93,149,97,38,162,46,21,117,70,233,168,83,178,124,157,65,182,171,211,176,45,79,84,241, -187,145,89,209,71,85,36,94,130,146,208,123,142,203,3,74,19,125,187,147,253,56,138,87,144,204,31,199,37,222, -132,81,0,76,158,224,21,137,12,161,127,123,167,155,168,26,255,142,204,3,92,26,154,182,3,150,162,71,66,237, -142,119,250,117,185,147,250,140,27,207,104,191,97,215,187,187,219,141,161,210,227,161,217,199,241,183,94,6,137,174, -81,225,114,158,241,32,79,109,173,48,146,80,117,30,236,57,222,174,222,153,121,132,123,143,84,32,178,220,123,50, -206,199,236,251,165,89,120,5,167,144,245,76,5,171,212,68,113,219,18,94,180,197,156,255,136,32,141,15,191,35, -201,98,49,209,111,255,202,160,208,212,106,191,66,133,123,239,0,115,207,54,53,82,27,239,205,229,104,43,12,79, -22,209,6,142,172,84,44,168,122,46,0,164,139,198,190,112,65,64,6,202,188,118,130,45,44,227,64,208,176,5, -122,56,150,164,153,53,135,164,113,163,168,166,143,85,254,70,209,172,128,3,243,96,212,198,101,172,29,76,24,181, -41,222,129,197,226,90,47,129,98,78,233,240,112,246,53,68,255,53,38,231,22,79,212,179,71,22,32,35,117,200, -220,145,33,109,251,141,25,196,243,3,136,241,89,106,6,10,47,179,111,88,200,158,165,116,115,47,11,232,243,243, -152,221,119,139,154,59,245,68,204,232,9,179,145,246,24,179,180,57,121,203,39,235,167,240,161,157,124,48,200,126, -48,220,6,131,1,106,128,216,180,178,226,71,128,202,226,39,149,66,185,151,58,128,31,223,85,225,76,32,238,174, -176,70,133,120,151,194,163,203,74,34,208,224,149,57,42,191,54,235,140,131,156,83,114,142,26,44,114,0,226,189, -154,214,22,226,61,32,106,134,152,57,8,232,27,194,74,1,108,71,25,137,6,241,41,227,235,175,184,206,122,250, -81,229,239,85,110,196,153,11,120,104,149,214,92,229,249,204,5,152,253,18,61,11,129,96,31,78,114,70,176,131, -228,206,6,201,96,208,244,11,150,100,222,82,111,119,238,134,134,229,152,47,136,117,43,142,221,92,230,161,251,240, -159,236,28,58,197,120,105,126,80,124,130,90,252,32,227,29,206,69,238,227,66,225,108,197,9,235,144,187,8,204, -28,254,134,35,201,33,255,239,141,230,114,164,150,143,212,1,240,97,245,143,191,91,145,173,183,154,194,202,101,3, -177,79,40,33,220,57,6,21,188,139,81,11,152,104,232,255,14,250,28,204,180,6,177,163,25,14,150,117,45,46, -37,125,122,154,185,211,226,43,119,142,12,223,102,76,68,124,168,224,175,206,84,46,4,24,149,67,112,214,122,85, -24,171,151,169,192,10,240,42,85,130,42,106,14,120,154,109,152,250,144,88,155,245,181,75,162,105,206,137,144,20, -149,182,212,122,136,187,98,43,151,18,149,187,224,84,177,222,252,12,85,210,153,171,156,150,128,95,112,72,50,174, -135,94,185,65,161,203,161,236,99,83,47,93,13,77,208,169,43,109,179,62,185,172,160,252,43,78,155,219,13,71, -175,89,231,159,158,240,63,107,211,202,114,115,79,88,165,219,29,196,95,23,79,156,124,151,33,93,178,153,138,143, -197,193,235,192,175,25,139,106,227,151,97,102,78,62,178,183,121,108,107,158,132,43,25,251,247,197,71,214,12,156, -206,243,154,222,34,184,154,174,120,3,60,70,112,61,93,243,190,56,70,240,242,230,230,130,222,32,52,102,38,243, -106,122,149,159,209,51,100,159,178,231,20,122,137,208,167,155,155,107,250,204,178,167,89,250,42,155,190,146,145,203, -95,101,19,121,21,121,175,48,60,96,41,172,206,211,226,91,149,190,201,232,121,225,23,75,241,67,132,143,239,241, -194,100,98,213,210,227,140,204,239,219,140,225,253,2,157,166,12,97,50,222,103,244,242,111,127,123,137,51,124,254, -140,141,209,113,128,130,106,177,255,112,102,181,203,182,91,233,75,30,21,222,205,94,203,34,221,115,57,208,6,154, -80,212,136,141,192,83,171,18,25,134,79,122,163,105,61,129,249,31,8,16,157,32,17,81,222,106,195,6,218,141, -167,25,189,129,130,86,75,207,177,227,233,152,249,98,244,27,95,253,217,126,148,249,125,203,31,167,226,129,145,236, -112,44,152,59,248,108,135,234,41,135,127,84,233,231,108,26,208,185,231,244,57,203,159,2,162,227,246,50,131,99, -40,24,15,177,78,83,133,157,226,174,220,220,112,101,207,211,72,131,244,155,113,116,18,238,248,32,22,163,19,151, -254,151,208,137,220,151,99,201,4,216,195,105,104,166,130,113,34,60,118,7,106,17,16,65,45,46,26,160,22,73, -136,81,139,219,230,175,144,69,107,7,68,43,183,201,37,227,194,101,248,45,14,116,50,7,213,21,136,101,184,227, -175,163,77,112,137,77,176,206,232,202,108,154,101,54,93,74,93,249,210,109,154,211,194,125,224,222,246,8,22,40, -79,93,24,11,214,105,26,167,199,107,214,62,8,188,118,251,108,35,251,12,250,130,116,26,238,51,134,48,25,12, -124,193,76,186,217,103,41,22,203,138,209,7,98,158,80,248,221,118,54,61,75,63,101,249,167,52,124,129,196,253, -62,141,86,237,65,180,8,227,111,74,199,123,207,165,70,211,97,208,58,115,159,214,103,52,135,2,116,43,223,247, -217,118,223,252,46,70,119,20,178,227,190,125,182,131,114,41,59,234,42,218,81,167,116,53,236,168,83,183,163,214, -140,67,57,229,148,27,189,185,225,98,167,177,172,130,43,241,38,209,68,112,31,91,25,63,80,221,155,242,77,100, -229,226,91,119,214,110,34,235,46,86,202,7,69,68,255,250,174,202,166,12,190,251,196,112,138,183,55,121,101,158, -212,158,122,121,132,132,178,175,3,175,187,47,236,222,62,8,76,136,200,196,48,19,81,9,231,251,11,14,82,78, -66,245,66,145,57,201,218,176,240,231,254,80,228,43,11,102,121,250,141,242,175,139,182,249,23,190,174,103,161,233, -143,184,206,167,70,209,76,209,165,162,95,212,7,250,85,21,63,43,199,92,253,164,51,250,93,21,252,48,253,139, -125,121,158,191,210,100,31,164,231,191,170,109,54,129,210,135,19,165,238,179,238,98,64,5,221,146,59,248,125,156, -223,223,114,137,51,233,205,117,13,183,5,183,13,26,15,127,173,130,64,182,181,104,236,59,22,218,57,69,190,224, -243,221,53,178,109,27,115,45,246,91,229,73,25,207,183,165,9,23,86,217,10,186,127,237,173,154,125,223,169,61, -5,70,105,195,200,162,254,80,18,9,221,52,187,138,113,76,4,255,41,158,63,188,191,128,170,196,78,78,156,89, -168,161,131,198,214,64,111,240,103,6,132,30,93,64,21,149,87,117,35,31,22,119,123,188,85,198,6,223,94,185, -153,86,251,18,20,183,45,51,186,27,82,36,26,205,45,112,110,22,145,143,153,79,221,20,49,161,193,118,164,221, -161,202,71,46,33,118,39,38,251,178,55,138,19,57,220,6,99,73,186,248,43,35,43,234,237,236,140,247,188,26, -119,198,123,112,143,99,205,73,101,56,126,175,14,232,12,241,76,173,43,162,184,134,72,210,128,165,168,205,228,87, -254,58,209,41,201,50,2,101,0,155,65,154,187,227,22,175,29,58,144,245,64,82,129,47,151,129,249,222,133,200, -235,197,141,159,153,61,232,54,163,200,141,237,142,108,96,232,70,240,129,66,193,111,110,98,124,229,222,121,15,42, -130,124,238,156,121,11,244,238,170,162,123,52,155,116,124,93,193,117,148,62,23,66,118,157,169,226,105,218,240,12, -164,101,6,49,47,149,71,206,232,165,168,196,164,62,161,80,254,150,233,94,106,138,4,102,154,33,142,74,251,1, -248,37,132,44,92,5,139,73,118,83,139,142,49,1,127,203,94,250,253,135,33,1,232,203,200,12,10,252,81,85, -237,117,48,162,225,226,168,104,71,72,84,149,1,249,16,109,1,70,68,198,196,187,196,114,123,101,236,139,180,166, -136,211,168,241,55,223,188,73,60,80,115,11,16,62,115,164,228,67,210,165,203,240,168,48,232,39,178,61,139,56, -238,2,27,26,5,38,216,37,34,191,82,189,228,84,100,94,218,24,238,84,117,6,11,74,70,27,180,160,130,145, -56,24,183,177,99,47,48,247,120,203,105,159,163,244,173,151,169,66,229,202,210,58,1,112,77,142,46,231,73,91, -112,93,246,30,85,23,173,109,179,221,109,147,20,48,6,163,140,86,45,225,119,238,169,234,96,171,182,72,26,238, -1,144,143,187,213,156,75,6,238,131,118,146,112,190,208,211,180,245,116,20,12,53,147,229,54,34,17,59,165,10, -5,212,146,239,166,54,83,149,75,219,163,214,147,198,182,173,71,43,114,212,231,109,112,192,10,97,225,0,168,219, -7,96,162,246,186,222,76,255,172,243,163,99,6,100,247,205,221,5,221,184,222,242,233,99,181,186,209,224,225,104, -226,105,15,244,181,177,189,255,74,23,51,174,166,227,245,99,168,81,254,157,34,124,114,94,150,76,146,74,235,46, -192,218,252,23,225,0,107,189,106,184,248,37,62,182,12,97,20,118,96,32,195,46,236,133,36,46,197,159,109,34, -152,99,189,15,21,167,133,119,30,251,176,113,122,208,221,145,164,91,97,119,26,116,199,160,252,68,132,88,100,211, -69,143,254,67,64,140,234,50,176,208,139,93,28,171,165,123,166,23,167,214,88,33,221,121,95,152,114,29,167,109, -160,222,149,69,186,24,155,50,86,97,9,29,153,58,250,99,110,190,3,215,87,230,137,163,49,163,228,118,252,158, -251,171,216,29,134,230,18,159,82,197,202,42,154,85,197,71,92,43,45,202,225,246,242,193,63,231,247,189,23,137, -123,222,212,97,185,28,8,82,159,70,142,38,190,136,119,137,125,165,125,223,229,109,232,99,177,12,76,124,20,253, -160,235,177,24,57,129,75,131,33,149,88,239,210,174,232,145,113,21,202,62,228,81,89,57,234,253,72,216,203,171, -22,135,28,58,31,131,73,176,95,4,43,98,179,108,233,194,109,155,232,246,75,190,125,86,134,238,54,156,3,136, -113,71,84,212,142,57,130,0,62,19,183,47,237,145,104,87,164,171,50,243,254,75,97,161,197,251,228,3,187,91, -77,36,69,27,211,5,40,143,145,245,166,233,135,233,210,22,47,242,74,212,34,176,80,62,203,186,38,150,131,51, -239,2,155,35,75,66,59,127,177,201,105,112,27,115,63,17,47,206,112,131,199,87,137,201,68,97,240,173,175,8, -19,158,42,255,196,117,90,30,38,51,9,38,121,121,168,48,242,121,151,26,184,108,138,91,56,217,126,146,226,125, -195,148,217,212,164,112,25,249,53,255,39,242,250,209,234,2,221,220,216,128,57,116,7,11,167,216,200,80,224,234, -32,112,4,65,27,12,130,188,244,81,241,75,48,220,58,237,37,9,211,123,94,226,240,161,34,194,145,209,6,175, -52,132,208,28,240,162,84,180,201,56,196,43,10,191,252,224,116,140,29,24,75,149,174,133,111,130,221,19,174,205, -238,118,112,186,168,232,126,194,60,240,125,101,164,161,141,155,179,104,34,205,75,213,10,111,186,189,156,40,62,200, -85,1,236,67,248,5,100,164,49,171,228,156,146,26,105,160,91,4,162,216,121,159,155,148,246,128,40,248,75,213, -176,196,234,137,123,148,31,212,63,199,45,23,119,97,70,137,151,102,243,142,201,72,18,99,153,54,50,108,135,189, -216,42,236,112,207,53,22,61,88,209,237,240,76,10,186,78,37,134,5,139,202,162,241,115,29,19,1,16,188,108, -98,213,220,207,74,217,58,232,238,178,44,44,234,58,43,73,196,108,70,136,61,238,184,133,156,27,57,97,85,38, -97,196,127,117,224,32,232,177,177,204,10,210,108,216,199,211,211,180,119,203,16,216,106,13,195,93,150,197,148,228, -194,38,235,52,35,235,29,211,57,62,29,195,40,14,197,75,191,4,161,5,219,223,46,30,164,38,176,32,156,80, -59,238,36,88,138,155,167,13,66,162,36,197,27,73,208,99,248,10,143,7,72,197,144,5,39,149,126,235,241,153, -137,15,72,122,56,43,57,181,174,25,147,161,206,32,172,153,33,43,28,144,135,2,51,65,226,95,29,12,56,97, -22,227,132,132,217,156,90,117,224,243,149,53,207,151,81,123,50,19,97,219,140,24,222,162,133,217,56,90,40,205, -49,107,178,69,147,126,4,135,119,159,230,106,113,225,29,210,46,92,151,231,69,115,178,248,48,153,239,237,200,146, -108,26,31,75,138,57,196,40,184,88,253,70,111,140,44,240,73,173,120,145,191,227,49,79,209,207,185,233,231,180, -150,174,207,179,124,227,66,91,51,142,152,253,2,103,15,12,7,57,151,74,34,206,154,23,27,183,236,7,8,53, -152,29,29,119,143,20,207,170,91,192,110,127,56,255,135,129,254,11,99,115,228,38,147,126,208,43,7,4,222,124, -191,230,244,20,78,114,196,60,136,136,99,156,182,210,117,153,145,143,93,70,177,43,142,201,94,105,171,69,173,47, -253,73,12,38,199,143,244,98,193,135,250,23,149,90,174,122,234,111,215,202,149,81,54,35,17,73,253,169,41,172, -18,223,196,8,74,225,28,252,104,184,16,231,235,126,167,24,226,83,252,244,185,59,103,152,227,111,247,165,59,143, -21,36,202,102,188,206,10,127,122,198,210,177,247,44,56,123,30,24,5,127,78,56,120,48,180,235,248,38,209,54, -192,21,176,209,127,135,204,216,206,231,94,75,125,22,52,134,233,21,41,56,148,38,160,87,204,63,100,157,154,231, -95,48,31,251,34,78,80,246,39,42,50,189,45,3,111,193,29,178,142,18,39,131,107,53,24,102,49,15,238,179, -201,184,82,198,88,234,248,132,125,66,207,229,37,239,169,157,148,118,244,112,68,130,89,170,216,104,28,78,114,78, -151,195,171,249,58,80,59,128,14,148,162,207,225,233,13,47,209,35,209,210,181,8,24,176,106,220,64,227,163,130, -104,154,145,141,11,109,66,126,20,79,67,75,117,82,157,213,220,172,46,127,96,12,208,223,129,1,66,123,116,225, -185,98,192,31,212,22,81,109,212,24,227,85,139,254,126,107,126,204,249,183,215,107,142,242,127,76,47,191,204,225, -19,97,184,55,156,11,102,101,187,34,59,67,5,59,66,237,237,136,100,112,189,146,38,135,205,97,178,190,162,228, -80,227,55,75,72,141,110,151,175,186,68,84,223,78,25,199,122,245,170,252,162,36,31,251,22,174,0,242,101,185, -157,176,95,35,241,126,117,4,111,46,63,117,230,217,98,241,83,67,62,131,175,140,43,248,172,170,230,112,194,171, -244,104,22,212,1,139,31,130,98,24,106,134,199,230,98,26,55,171,138,50,46,24,219,109,47,102,154,142,83,206, -119,135,180,192,12,64,87,102,65,94,236,160,234,148,243,66,151,81,158,164,243,37,196,239,42,127,22,230,58,135, -202,227,142,136,122,156,35,127,159,110,180,215,33,164,103,173,188,29,3,220,150,126,191,85,202,249,142,105,239,69, -175,117,205,123,177,238,241,119,84,157,67,71,6,98,171,132,251,32,226,79,170,78,146,50,97,203,80,205,54,11, -188,194,67,88,253,63,153,187,174,245,198,117,28,252,42,10,183,68,58,166,187,227,196,242,106,124,122,239,229,202, -147,111,62,154,146,19,109,108,49,43,217,41,39,227,125,159,125,141,125,178,197,207,34,75,110,51,115,183,167,36, -12,5,54,144,4,1,144,0,174,102,130,129,144,176,158,156,15,216,97,109,11,87,218,162,138,192,99,113,53,96, -56,198,145,238,244,71,250,181,14,170,25,206,134,148,94,32,221,233,15,145,94,35,221,157,37,128,159,107,24,217, -237,81,58,214,249,50,150,148,190,143,68,107,161,164,185,129,188,165,63,104,152,165,29,43,95,82,134,36,118,52, -223,102,61,80,22,97,85,34,114,196,140,210,63,80,66,220,208,198,23,89,150,44,248,13,101,125,110,117,115,156, -124,111,240,71,72,208,79,17,83,25,2,17,61,227,121,118,226,244,243,111,118,77,3,31,65,39,126,122,204,182, -17,218,74,27,204,71,242,151,225,248,69,164,185,190,34,226,119,219,42,14,70,226,39,254,14,96,223,215,192,222, -56,107,135,13,255,161,246,65,239,248,149,29,146,79,79,50,137,255,53,107,72,170,69,131,181,219,172,1,151,74, -5,156,49,208,49,188,164,163,227,118,63,178,177,113,105,220,53,47,54,182,177,136,157,185,74,30,24,191,163,219, -47,83,122,92,191,141,174,252,72,206,208,136,113,170,12,194,175,188,179,168,70,179,249,114,219,114,96,223,19,217, -213,139,53,155,249,207,1,127,166,3,170,214,195,10,10,105,201,217,153,164,106,37,252,232,101,245,193,148,241,235, -252,59,52,177,9,73,237,123,211,162,189,187,3,168,243,28,12,145,231,51,186,23,54,110,194,103,58,34,34,108, -45,122,220,252,238,210,195,205,165,65,112,244,61,207,162,133,159,86,145,206,83,222,13,130,240,76,236,29,252,111, -223,110,177,112,230,176,176,45,9,203,172,150,49,235,248,77,135,89,33,78,170,240,127,192,152,158,160,110,193,133, -142,206,103,193,164,218,247,117,237,144,171,64,5,211,167,218,36,172,107,71,156,97,166,205,234,170,9,0,21,50, -1,132,224,230,35,244,179,232,7,46,14,92,84,89,68,48,254,61,137,29,230,217,69,242,132,33,20,17,42,10, -111,185,222,125,225,114,3,242,16,119,58,39,200,67,133,56,8,164,251,131,222,92,19,138,180,220,175,18,215,19, -133,139,102,7,95,221,218,17,214,195,213,120,49,161,62,46,220,243,190,22,211,47,53,137,175,108,100,48,254,13, -97,237,3,183,149,58,228,151,223,254,34,190,73,94,183,253,215,49,25,113,5,92,71,181,4,220,171,232,114,16, -212,33,63,187,205,213,178,2,155,209,103,21,1,184,62,90,69,207,48,213,134,155,78,31,30,163,33,120,32,108, -227,109,185,204,103,25,9,203,55,98,165,114,248,155,47,72,105,121,3,165,134,126,18,143,10,47,68,247,68,133, -243,139,24,72,82,26,97,243,43,80,68,141,200,217,176,215,211,136,76,137,144,175,146,28,245,215,26,222,33,92, -238,113,242,170,100,231,166,226,154,36,191,41,251,248,227,178,60,101,168,41,74,92,111,208,179,203,228,234,68,207, -174,250,98,230,122,54,154,205,123,174,103,87,189,11,225,166,56,158,95,94,212,209,49,57,20,235,48,77,138,93, -166,20,66,112,233,141,212,79,176,76,156,124,133,199,181,206,79,243,43,25,168,214,28,2,47,205,153,36,34,101, -98,55,151,204,159,30,199,108,150,156,26,199,176,27,159,194,220,153,137,110,104,100,77,194,223,138,86,204,163,135, -7,61,95,228,185,162,10,72,23,113,190,242,104,55,120,172,225,60,20,195,214,65,20,158,240,202,243,157,237,116, -74,138,254,126,167,176,62,188,130,234,144,43,54,46,123,56,188,24,92,178,192,218,68,25,132,15,71,243,190,67, -248,101,28,119,52,194,153,105,221,251,198,205,39,33,77,225,188,36,140,41,240,60,148,255,37,245,24,183,187,190, -129,229,182,204,142,198,164,48,135,191,121,118,42,120,161,97,194,114,112,92,75,214,97,103,3,214,97,239,37,2, -79,34,105,201,15,108,170,76,97,205,133,234,98,14,13,234,85,105,165,54,177,209,44,237,217,16,171,44,33,125, -40,145,165,85,4,221,136,10,184,45,219,40,3,159,113,91,100,101,161,187,27,19,68,215,108,146,157,213,84,33, -90,192,253,160,119,117,114,15,131,70,213,22,45,202,12,68,124,170,140,97,116,84,133,209,73,35,198,12,189,170, -86,85,99,205,172,204,101,182,132,207,254,100,65,41,248,125,83,124,145,209,217,155,35,216,150,223,193,216,38,251, -124,132,155,188,40,210,225,153,82,167,253,129,63,70,83,41,200,191,77,234,65,196,189,19,131,0,77,113,131,184, -148,151,118,129,149,187,91,128,152,173,51,56,109,70,175,10,77,187,205,253,119,185,202,199,206,72,162,32,242,2, -213,232,220,47,184,224,47,134,181,94,235,225,64,213,109,38,79,185,176,175,252,240,238,67,37,8,166,68,107,193, -244,62,249,144,105,171,66,58,225,95,51,249,133,34,225,6,17,12,117,148,12,74,104,127,117,187,108,208,196,126, -6,203,237,146,168,9,220,218,224,106,208,57,222,19,75,1,149,225,98,59,179,67,52,187,184,79,36,145,189,119, -117,152,10,2,19,213,168,83,110,255,56,76,35,184,134,75,251,185,182,188,39,180,5,19,160,55,215,157,29,245, -59,167,87,110,173,23,103,118,61,130,96,84,56,221,223,116,144,49,68,60,63,184,134,45,109,48,80,126,96,55, -227,96,52,74,222,65,229,220,71,207,14,187,244,0,6,38,53,3,111,174,136,220,171,242,209,58,172,89,75,7, -34,83,117,13,116,194,7,115,65,191,186,215,92,210,175,222,53,95,208,175,62,180,115,47,105,12,203,165,144,68, -83,125,69,89,112,45,39,132,210,134,192,251,65,220,135,139,205,56,35,148,77,240,3,247,74,171,194,69,144,14, -115,147,194,23,93,149,224,250,123,72,145,166,55,91,251,243,77,222,202,141,25,47,34,100,48,171,235,172,171,205, -45,236,173,123,117,165,34,218,75,230,20,140,217,89,201,53,59,53,23,228,244,131,0,159,127,241,233,31,95,253, -253,239,246,215,153,178,231,17,120,89,123,30,61,172,147,166,22,224,155,11,133,184,135,158,20,89,166,86,222,44, -241,8,241,49,120,77,225,101,42,107,206,168,96,65,223,147,236,33,205,85,166,181,107,30,137,217,222,139,103,116, -84,161,119,14,157,240,185,183,65,161,103,66,152,71,90,0,146,152,239,60,179,161,189,149,162,47,113,42,197,42, -161,74,181,184,157,55,181,214,25,203,161,86,51,179,23,237,152,82,1,126,202,47,85,122,136,37,88,177,36,166, -150,173,232,93,124,250,108,229,116,159,1,136,5,52,213,32,59,160,27,214,200,230,172,91,53,158,9,96,52,107, -62,199,17,131,12,213,212,248,40,242,102,138,203,130,195,88,183,44,26,104,65,123,89,164,137,55,29,54,71,215, -175,103,86,31,87,126,110,149,252,91,61,86,75,48,222,13,225,129,59,119,18,117,169,47,10,166,186,246,66,204, -172,113,183,131,151,120,176,83,246,124,119,237,155,101,47,246,150,125,17,137,169,50,11,189,104,165,241,245,88,34, -136,82,209,108,242,220,41,183,55,201,196,119,141,113,180,18,132,194,249,39,52,213,230,181,106,165,182,9,199,146, -3,61,49,245,85,244,220,84,98,241,15,105,119,134,45,183,160,114,54,107,186,184,246,203,155,146,116,42,209,169, -154,15,139,101,253,222,1,142,244,87,174,158,196,13,43,215,206,236,121,70,195,202,245,176,140,178,61,211,157,105, -52,198,174,188,233,127,86,239,13,70,97,179,104,32,126,94,38,3,93,14,3,62,90,192,32,109,86,45,20,140, -235,245,191,170,151,166,165,91,255,30,213,191,7,155,210,42,182,134,246,131,189,16,7,219,55,72,48,52,7,41, -14,44,132,93,75,125,68,13,189,15,165,242,254,152,45,62,168,65,133,1,53,111,35,35,253,114,178,45,97,59, -91,115,90,98,162,188,151,213,207,106,209,19,142,69,19,52,109,76,89,35,110,156,255,59,98,231,100,169,159,82, -146,93,159,7,118,38,233,231,194,9,31,235,113,86,121,4,93,147,91,51,237,117,230,222,93,135,73,154,250,44, -194,165,67,17,209,64,17,136,225,217,24,52,26,247,179,92,233,64,54,249,126,110,199,250,91,201,80,142,138,61, -86,1,80,162,66,51,78,245,198,97,45,1,94,92,25,59,32,251,19,111,246,163,210,66,56,107,233,35,6,25, -38,133,172,242,180,209,217,229,95,22,33,227,4,172,174,237,112,14,189,145,113,47,187,203,90,99,53,217,238,28, -180,197,194,22,34,162,179,114,111,1,236,131,28,231,207,241,117,198,168,106,218,172,59,209,93,42,215,143,57,158, -111,233,1,97,218,236,139,161,223,110,147,100,21,84,255,0,0,124,123,71,55,212,190,170,152,129,167,209,177,104, -137,10,156,207,170,226,97,104,44,168,183,80,149,87,17,142,60,2,116,60,216,78,112,196,148,235,239,97,61,216, -97,90,125,165,248,184,227,17,178,208,10,113,51,17,90,8,41,113,175,215,229,190,201,190,134,100,88,34,115,132, -233,255,38,222,3,137,33,142,196,1,87,38,182,50,161,181,253,209,95,60,83,239,31,191,146,175,161,134,178,173, -20,208,80,48,239,163,54,227,59,128,232,0,130,209,3,30,167,84,8,237,88,106,212,156,237,127,22,42,27,35, -226,241,112,192,89,99,182,82,194,95,103,73,33,197,125,226,39,153,84,49,53,243,205,103,78,211,236,127,251,219, -79,63,90,49,43,157,63,19,162,233,31,211,106,192,223,61,131,185,153,60,251,178,166,234,175,168,62,51,181,79, -227,250,12,28,155,115,68,160,211,172,123,60,28,156,82,114,200,97,201,48,95,116,228,192,49,204,189,190,4,243, -44,78,170,80,169,170,74,24,143,136,50,160,100,86,190,179,182,132,154,217,248,158,210,43,154,216,254,179,40,15, -236,120,23,175,214,38,176,147,156,174,27,13,237,100,179,216,62,31,42,157,198,143,9,110,76,0,128,245,233,18, -123,109,156,119,193,135,247,26,209,13,75,23,70,248,246,246,109,103,108,171,160,214,154,93,186,76,170,8,160,105, -38,23,107,90,253,161,240,113,139,111,239,168,241,87,23,204,58,198,127,10,85,98,56,234,2,85,214,6,53,205, -142,40,46,92,127,200,50,85,249,200,225,163,78,231,146,2,109,247,72,153,48,232,140,70,221,32,132,84,117,209, -237,95,132,135,36,165,151,205,142,170,251,168,160,226,184,96,35,125,34,11,245,14,71,189,227,163,144,131,126,103, -43,46,75,232,95,252,119,84,143,16,173,116,10,224,87,180,141,20,75,82,206,11,36,127,159,57,157,33,67,192, -71,115,166,190,216,188,144,245,91,195,214,128,153,119,137,217,132,221,175,115,56,74,188,89,168,153,88,48,78,2, -237,115,142,155,228,144,253,247,63,94,175,211,235,120,159,39,89,90,120,63,83,45,119,130,46,195,61,255,207,133, -74,115,37,239,90,249,58,96,155,0,19,53,140,47,223,33,219,24,177,96,76,131,76,122,67,12,24,169,161,156, -155,148,148,98,104,82,226,114,4,20,108,21,62,35,97,209,211,194,73,99,55,195,172,147,152,205,112,236,157,73, -235,175,181,115,159,107,91,252,34,89,204,91,111,200,253,92,25,232,138,234,66,204,114,198,107,1,247,25,108,6, -40,59,201,217,134,79,115,227,192,103,15,100,177,94,102,133,183,92,53,251,128,162,234,151,62,45,226,163,208,205, -110,207,187,111,74,125,13,154,196,76,11,250,16,74,136,82,77,78,22,66,11,181,146,182,177,110,160,169,255,155, -196,71,171,181,39,117,47,218,127,110,104,31,219,205,69,156,216,9,119,111,158,54,168,196,53,143,71,214,235,251, -242,15,243,10,141,240,245,211,239,159,104,49,106,114,12,242,76,195,252,182,150,80,88,31,129,154,152,30,134,229, -16,241,16,141,169,149,176,62,83,223,115,196,71,49,68,144,248,89,44,155,35,157,88,198,205,225,123,149,197,197, -109,83,199,90,247,238,87,77,221,104,207,66,235,184,236,7,225,115,26,147,242,116,50,205,16,124,220,91,230,101, -49,59,162,151,237,157,104,56,181,83,0,228,83,141,214,247,116,200,30,154,54,199,106,238,140,133,35,109,250,60, -41,204,54,69,6,219,92,115,59,147,248,51,100,186,121,198,237,180,166,249,242,81,228,137,134,68,116,245,122,150, -171,187,204,164,94,90,151,140,84,159,188,77,228,93,18,99,253,252,203,183,205,111,33,105,79,171,12,64,184,250, -11,171,98,153,229,151,43,149,110,104,37,99,240,7,241,149,74,69,139,205,60,208,242,153,247,165,45,229,49,90, -187,252,67,49,189,248,255,199,244,34,41,232,214,52,89,190,15,174,29,236,123,97,219,1,127,40,190,93,57,96, -28,56,127,239,189,208,223,65,53,9,93,102,128,140,239,23,213,64,30,190,154,36,171,35,211,20,19,82,38,247, -171,144,65,246,224,248,209,186,249,147,213,134,238,200,6,17,21,26,229,255,216,187,14,230,104,109,32,250,87,20, -210,19,144,181,234,242,180,244,222,147,41,233,185,54,231,155,15,151,225,59,183,148,255,158,183,128,174,216,184,59, -61,3,39,172,135,244,180,160,93,173,88,138,191,231,229,226,192,241,180,27,108,174,27,55,248,0,30,103,240,16, -124,85,216,231,122,30,254,175,255,204,179,250,110,217,238,47,236,110,145,27,213,252,52,247,252,160,128,14,46,166, -211,26,58,149,207,194,233,98,186,220,131,231,213,71,103,69,185,215,62,168,149,115,39,139,217,233,27,135,103,187, -133,18,74,104,139,21,88,118,213,36,169,40,207,246,235,3,72,187,183,92,30,237,238,236,156,158,158,202,83,35, -15,155,249,142,86,74,237,180,242,20,93,153,51,152,201,147,98,168,40,165,148,118,186,221,191,117,199,49,95,59, -9,120,232,195,39,179,238,205,9,112,117,217,170,149,25,100,144,0,221,87,175,118,115,166,106,142,107,158,52,204, -78,102,136,137,77,51,39,219,226,154,22,87,235,197,152,159,225,41,74,62,188,162,60,111,211,254,92,104,187,62, -19,248,187,87,234,201,162,153,128,121,139,227,83,24,87,229,178,20,207,90,253,198,235,201,23,229,33,66,111,139, -37,115,74,131,105,11,154,32,141,237,121,183,109,176,81,153,245,8,211,195,53,39,40,63,38,47,131,143,201,218, -80,6,25,41,120,252,156,120,147,130,36,235,66,136,12,91,50,201,144,10,2,40,32,231,131,7,106,146,38,128, -64,163,164,168,13,69,3,180,39,51,160,136,210,69,175,144,47,99,38,227,178,94,133,24,147,6,216,113,185,22, -69,125,229,156,41,83,207,165,157,248,136,104,5,67,76,223,226,76,172,100,244,206,90,235,75,8,164,130,85,214, -36,1,84,59,175,172,107,81,8,150,130,21,73,70,155,180,138,190,101,8,46,161,136,23,31,121,105,86,176,89, -193,111,58,153,116,138,81,135,200,176,73,41,26,235,132,147,49,146,209,164,93,73,154,143,207,49,234,165,182,104, -218,88,6,59,54,48,64,74,165,200,59,135,178,212,179,69,17,248,48,44,80,3,52,179,1,245,14,82,146,9, -160,200,108,56,104,37,173,214,41,105,8,97,165,39,159,8,18,15,119,211,55,69,201,122,241,25,122,181,74,250, -162,98,160,207,243,64,199,207,236,94,52,122,118,34,98,127,92,161,222,45,141,24,186,221,143,166,24,150,68,63, -217,89,57,176,113,83,108,111,143,151,203,195,75,173,142,151,7,2,191,234,168,89,236,143,154,243,110,124,237,70, -190,26,79,108,236,46,187,7,119,126,187,52,198,100,2,12,106,180,26,84,111,30,17,178,149,145,223,28,113,200, -15,143,56,3,99,66,23,45,134,247,99,51,255,104,116,142,200,184,190,169,216,168,65,12,189,26,35,34,62,60, -32,12,91,126,185,122,174,14,78,247,112,201,143,208,37,37,72,99,125,121,211,202,135,141,185,235,251,254,187,228, -111,30,214,124,163,183,53,240,36,136,222,99,115,174,141,244,166,178,210,248,17,9,18,138,127,21,73,103,145,232, -88,87,78,96,135,228,242,156,40,94,42,169,146,36,55,81,66,42,39,56,141,128,64,102,94,239,40,120,177,16, -112,180,206,242,126,227,55,171,116,53,46,114,139,142,187,70,179,27,100,132,53,109,178,121,91,73,109,196,6,66, -6,2,91,250,8,164,104,218,188,183,85,94,85,26,174,52,187,204,236,253,223,64,87,136,98,216,143,182,247,240, -254,171,94,244,127,47,250,214,59,54,184,116,7,47,58,36,215,23,64,48,111,195,164,47,93,34,102,38,106,165, -13,107,105,215,194,70,144,115,145,91,145,87,111,34,40,113,77,11,228,135,154,208,185,137,27,61,194,189,156,65, -241,42,7,20,94,90,95,37,35,204,56,236,21,134,237,38,79,177,111,244,25,53,31,78,119,153,249,167,120,140, -255,61,198,255,30,227,46,83,153,250,162,98,226,162,184,57,135,85,252,179,117,19,215,187,136,16,236,221,65,49, -239,175,123,90,73,35,200,72,107,214,61,196,202,230,164,119,175,183,221,199,73,139,99,191,150,20,5,37,198,248, -215,195,142,181,107,27,194,95,177,10,216,104,223,37,29,108,193,42,72,250,80,87,160,10,149,52,126,171,89,114, -50,110,41,18,114,140,214,86,106,43,195,30,234,108,42,158,177,80,117,47,141,193,154,49,106,161,16,177,102,72, -87,146,168,150,42,241,118,194,22,227,144,233,12,199,0,115,79,129,17,80,164,118,68,160,21,156,172,141,5,120, -172,101,112,149,221,144,22,172,6,38,41,117,64,105,235,94,79,82,147,64,146,165,235,78,150,1,196,112,70,13, -240,209,54,148,184,92,66,125,210,130,147,30,6,17,89,233,227,70,147,50,180,93,51,96,61,95,176,226,179,249, -228,229,126,113,217,103,86,129,84,190,219,118,124,116,251,32,49,95,215,220,109,230,182,81,49,207,225,66,158,195, -217,110,226,214,176,126,223,138,112,60,106,58,58,252,1,166,107,11,86,11,14,74,241,171,24,203,197,17,187,95, -56,222,108,87,75,126,134,110,206,241,185,87,139,231,193,178,101,158,185,202,197,82,191,93,29,221,226,51,82,100, -207,221,123,237,92,247,101,174,204,125,181,14,166,131,231,78,241,120,180,92,210,3,67,240,57,74,126,187,123,13, -215,137,55,48,219,30,152,245,116,129,87,209,166,85,195,243,203,217,20,115,140,203,231,9,239,203,44,38,51,254, -0,1,223,230,221,80,246,10,138,94,222,129,188,203,173,189,198,181,77,237,141,154,41,71,87,209,96,94,74,66, -152,20,31,105,122,248,29,159,155,186,246,242,9,92,236,207,47,143,253,81,177,255,25,213,24,251,209,228,124,116, -176,252,244,171,215,161,201,205,100,183,213,212,93,28,233,124,198,14,236,213,179,253,58,223,194,254,157,72,42,88, -82,22,7,131,15,180,151,8,176,53,28,145,48,16,39,9,170,40,192,77,19,23,9,160,83,35,16,146,167,223, -143,250,167,234,63,1,221,221,164,155,102,143,3,239,86,232,70,14,23,35,156,126,190,41,212,178,147,167,73,187, -237,111,3,159,235,164,159,106,139,90,89,30,7,154,55,237,222,122,95,251,148,59,181,217,130,111,153,4,112,215, -244,136,4,126,205,212,149,174,52,190,203,140,63,139,65,204,76,133,154,69,129,149,131,104,73,250,24,111,137,111, -179,231,227,125,45,252,159,253,105,247,146,233,81,103,237,199,44,193,71,159,194,210,33,48,181,249,88,178,188,243, -169,251,71,7,57,156,186,220,217,107,17,76,251,19,89,168,138,91,146,244,29,248,89,85,246,189,232,63,22,208, -120,192,105,145,54,112,78,23,16,181,213,247,136,64,167,190,151,104,55,223,49,116,138,66,77,48,217,240,40,244, -152,33,141,112,143,254,45,57,7,100,184,76,85,177,123,215,167,77,91,21,252,167,118,119,179,44,252,46,27,252, -94,154,213,19,54,76,157,17,193,141,205,12,249,39,82,139,149,105,15,250,45,186,151,219,30,114,160,186,124,32, -234,112,43,86,190,233,38,225,30,244,221,169,191,111,137,254,151,216,221,39,179,161,229,120,12,126,185,229,47,119, -240,178,248,146,28,21,112,74,207,191,153,214,51,158,191,29,255,187,99,166,75,135,184,28,19,196,149,24,153,146, -125,117,218,60,234,156,195,30,82,213,67,60,86,78,172,235,60,214,85,193,52,79,206,46,124,15,36,134,207,73, -56,53,236,128,160,227,230,33,211,221,247,61,106,12,85,228,205,34,173,41,38,19,107,245,194,48,155,50,220,184, -92,29,22,174,42,143,217,216,231,6,112,11,188,61,111,96,11,7,52,14,207,137,207,243,243,55,81,222,87,148, -47,186,42,143,47,146,240,119,85,114,11,57,173,196,33,236,114,8,72,135,70,222,122,11,205,15,27,170,142,14, -205,63,9,205,99,43,85,55,49,167,113,168,122,172,216,139,230,231,41,75,171,145,25,111,185,226,243,196,158,112, -95,52,35,63,121,70,182,200,82,181,250,170,137,149,175,38,63,173,207,213,200,177,4,95,12,88,229,195,123,94, -240,159,46,151,22,33,238,130,102,197,13,178,89,20,54,36,97,35,112,136,226,112,100,173,103,193,179,94,55,52, -135,78,67,3,185,122,200,16,78,60,97,26,176,255,249,172,154,246,70,113,38,248,151,100,32,239,51,215,196,216, -25,50,145,120,25,32,30,124,75,240,60,172,241,100,114,240,238,98,233,215,111,85,73,222,36,151,61,65,235,163, -63,170,171,187,133,179,60,99,255,114,178,219,211,167,108,244,250,63,99,47,211,94,187,64,222,119,188,87,175,77, -0,70,224,34,236,32,114,235,37,27,156,203,31,231,211,217,173,105,203,194,199,135,10,186,66,5,159,154,192,179, -19,245,32,7,250,63,39,187,197,207,227,157,195,191,7,102,176,225,102,174,195,247,179,61,98,173,132,61,221,105, -32,3,171,181,49,136,189,148,31,173,49,88,51,252,183,252,247,188,7,28,142,241,95,122,129,139,195,30,124,242, -135,25,123,109,194,71,62,42,150,24,135,236,87,56,75,249,97,198,63,120,66,12,154,119,12,214,194,96,6,127, -188,236,120,202,195,217,122,98,141,253,87,123,73,252,242,194,87,126,247,194,247,48,111,121,15,251,13,109,231,145, -127,134,88,40,78,98,52,120,218,222,224,62,191,19,207,153,148,159,75,91,130,47,224,119,242,71,246,165,31,118, -225,135,31,200,215,22,188,150,156,244,120,225,75,190,144,147,69,91,110,176,254,244,191,106,99,110,176,175,124,216, -157,98,207,196,21,113,68,248,201,111,200,153,252,10,183,137,79,194,220,43,230,196,167,24,115,175,152,223,125,195, -186,228,125,153,240,15,117,171,220,44,184,43,187,240,245,221,135,31,226,111,206,60,184,178,65,157,88,216,70,44, -17,243,139,238,92,49,254,77,123,150,177,101,146,149,147,97,170,214,119,179,108,139,55,102,145,79,49,30,214,22, -238,108,223,132,67,6,92,127,72,134,111,168,73,47,174,20,240,173,128,255,209,62,184,237,132,93,99,192,71,226, -69,217,144,171,49,71,3,226,21,70,31,121,3,249,48,199,220,53,216,47,110,180,238,151,43,150,121,196,18,120, -48,182,136,145,248,66,14,75,54,246,2,156,10,213,14,214,225,95,172,147,110,196,89,96,248,149,56,85,208,55, -202,79,196,149,63,151,91,112,243,187,236,10,23,249,177,81,173,168,222,119,239,156,84,254,244,173,200,9,19,239, -54,177,38,62,247,2,250,11,63,220,12,252,196,43,124,121,119,137,177,40,151,180,159,184,89,49,118,226,20,84, -179,234,3,15,153,250,215,110,130,253,125,166,90,219,77,226,218,65,252,122,186,246,178,127,255,221,215,1,250,127, -177,175,153,195,140,187,253,36,125,63,143,183,204,175,179,33,230,203,33,175,131,167,14,96,163,126,48,166,120,27, -226,205,254,160,26,85,158,90,228,161,188,174,143,236,77,249,24,40,11,39,201,186,103,44,122,132,250,132,193,121, -238,1,227,129,53,38,238,226,76,150,106,71,50,185,128,51,226,157,112,246,137,175,226,135,248,154,75,206,132,43, -49,36,47,180,46,222,170,191,30,66,148,197,137,160,56,32,55,161,9,226,0,253,213,30,251,58,226,43,185,102, -63,212,76,15,157,167,232,231,61,102,135,47,86,7,242,220,179,215,77,156,55,23,96,93,224,14,253,212,186,230, -5,248,198,222,232,58,198,23,229,103,241,199,157,233,115,173,218,116,204,131,127,97,158,35,183,223,128,77,22,229, -69,50,247,187,178,207,200,9,249,32,126,246,6,88,45,200,129,176,23,182,59,198,30,231,2,250,24,108,87,127, -255,127,122,251,242,152,141,31,103,253,105,8,67,81,223,55,151,253,113,245,135,45,135,236,113,87,229,251,110,252, -179,190,223,30,89,119,182,123,122,29,160,123,223,157,140,43,123,188,117,190,251,97,119,19,246,120,55,189,116,230, -248,178,219,98,238,255,42,190,129,231,118,174,86,152,217,139,235,70,131,249,238,235,110,196,253,77,156,253,255,181, -79,110,160,198,28,114,80,119,19,223,4,89,205,24,209,59,129,239,130,90,204,81,123,55,110,30,113,198,174,190, -181,122,243,124,25,239,183,192,240,110,126,185,223,6,190,9,241,206,225,187,140,113,113,6,1,7,107,112,63,27, -66,143,220,211,135,145,245,4,236,6,225,2,253,196,12,92,26,249,46,41,196,149,174,81,143,112,177,215,198,190, -51,55,168,35,213,231,37,246,16,35,29,113,14,158,16,95,156,111,206,179,14,39,238,95,196,233,110,163,60,217, -89,124,242,88,187,1,166,70,185,67,13,167,185,121,137,181,61,104,134,160,135,21,207,229,38,104,30,202,47,227, -107,172,193,23,245,110,23,251,222,42,174,245,88,219,206,248,166,26,168,224,63,108,93,103,25,239,183,250,191,214, -76,145,234,119,5,251,140,127,37,46,207,39,214,130,177,175,136,209,179,118,105,87,49,228,105,254,200,47,245,150, -76,253,210,19,91,234,114,29,238,82,223,154,247,78,208,63,138,151,208,21,156,230,215,200,122,206,56,183,97,35, -135,30,143,53,214,37,125,194,60,184,13,194,61,52,185,48,125,207,155,242,15,219,193,81,199,111,189,201,10,235, -101,123,161,15,192,18,254,143,140,39,103,188,200,89,38,238,39,127,135,160,56,152,215,115,204,171,81,94,145,67, -245,139,148,87,245,157,56,15,6,229,137,231,81,143,75,156,29,145,27,92,251,196,141,242,19,55,152,211,179,114, -170,89,190,40,167,194,203,47,242,165,37,70,59,246,232,10,119,38,205,132,90,28,232,189,238,118,90,91,113,45, -241,149,249,36,30,178,169,188,41,159,250,87,62,165,71,181,213,175,196,51,190,111,129,53,116,16,7,63,4,203, -220,69,155,234,211,102,97,79,248,135,182,243,254,110,84,199,226,248,191,226,176,13,189,104,60,96,199,41,56,138, -95,239,213,147,173,57,57,57,128,197,68,27,98,188,148,105,30,255,239,123,239,85,177,72,152,243,234,252,224,34, -33,9,113,213,48,214,247,115,193,230,102,28,208,90,163,215,61,56,39,244,21,60,127,68,229,65,95,130,177,136, -245,176,115,191,110,207,75,28,67,209,196,220,231,76,232,254,225,205,71,104,243,41,204,61,83,184,78,106,163,222, -124,67,191,51,254,179,134,176,208,15,41,118,252,253,253,132,117,127,196,197,209,47,122,98,99,158,62,140,204,231, -147,242,185,121,198,128,245,188,198,205,154,69,70,219,145,73,177,55,43,244,183,213,52,59,209,223,206,112,3,167, -183,133,62,223,99,54,201,47,255,182,173,95,27,161,78,11,220,196,48,101,40,107,215,44,82,227,78,181,100,91, -95,196,87,67,196,174,25,163,144,117,33,195,156,37,176,135,234,94,53,168,68,104,170,242,5,70,141,219,91,185, -14,225,20,30,14,166,28,6,74,244,144,129,78,212,104,236,72,58,49,83,188,147,241,81,193,142,225,108,56,13, -146,215,222,69,18,121,38,15,21,93,101,138,62,2,145,188,16,112,31,246,222,60,74,67,210,52,74,148,26,1, -58,233,2,61,142,165,209,88,63,116,75,202,156,84,26,119,199,30,173,166,218,244,50,138,83,211,28,147,211,76, -127,155,204,138,136,190,145,164,218,28,93,101,145,223,68,133,35,29,105,125,226,216,40,222,201,7,179,21,202,162, -32,255,170,162,192,232,35,107,182,107,36,215,233,20,30,170,165,173,180,220,209,236,120,102,108,235,41,22,65,221, -90,161,40,77,153,109,202,232,99,215,169,159,82,142,189,226,65,45,80,62,5,142,38,69,152,138,134,136,22,33, -99,212,27,216,28,139,99,170,176,62,177,140,235,100,198,201,105,130,17,31,9,33,89,86,203,244,206,244,174,156, -109,43,172,133,18,249,174,64,180,107,249,154,250,228,218,110,115,109,174,2,109,95,20,252,123,129,144,217,244,104, -42,171,44,84,187,189,206,209,195,113,66,79,115,202,67,95,13,255,213,26,170,8,215,157,182,173,188,223,180,168, -16,92,73,173,93,237,106,73,186,67,213,106,93,243,72,25,152,97,224,245,162,77,111,215,119,71,237,82,24,135, -198,112,82,77,231,180,72,77,240,85,19,112,122,240,244,72,105,185,53,227,27,213,198,221,198,5,98,110,159,130, -38,17,183,127,99,106,151,77,251,109,189,152,12,27,218,219,71,202,113,63,159,78,183,127,102,71,255,218,82,156, -125,120,71,161,221,206,131,110,97,190,239,62,157,13,83,61,127,102,88,238,117,57,92,9,220,215,232,245,193,166, -84,200,134,124,16,123,95,189,121,54,120,64,59,151,163,99,60,21,147,232,236,36,158,77,120,163,101,4,185,84, -37,106,125,212,27,249,148,166,43,172,142,28,63,219,164,245,29,212,125,76,195,242,227,174,40,100,205,75,58,136, -165,47,37,170,75,121,135,242,192,113,181,70,19,63,100,39,228,70,37,178,71,113,131,229,187,178,101,188,59,20, -49,239,206,27,86,133,158,122,72,138,124,140,201,113,207,60,201,8,176,96,137,77,212,43,25,223,80,23,252,104, -214,235,62,72,145,57,112,152,94,8,125,57,11,253,145,64,20,84,18,1,63,31,53,222,213,132,78,50,143,211, -29,150,25,106,229,178,219,147,249,174,118,195,183,253,255,20,150,159,85,107,227,84,245,253,167,198,129,172,195,70, -24,241,195,102,111,10,218,224,202,99,70,101,81,136,136,38,212,195,43,42,232,95,223,125,251,101,219,110,150,218, -171,223,188,26,0,180,96,5,250,66,227,73,132,34,206,138,252,204,118,205,66,122,219,213,161,154,201,44,138,14, -250,135,205,32,16,193,213,151,151,151,63,142,62,91,46,127,88,94,143,2,235,188,194,36,37,177,16,75,188,244, -21,54,38,72,144,26,137,135,184,244,205,17,67,208,14,52,17,33,209,173,50,135,7,174,193,38,124,0,161,112, -37,152,94,218,214,112,48,212,127,31,200,213,83,148,224,182,105,249,65,28,69,76,159,224,165,106,111,63,169,229, -10,10,87,105,137,87,203,141,105,105,8,134,46,96,150,211,222,217,106,219,85,3,72,138,107,22,119,49,210,236, -159,166,188,92,135,240,124,21,28,13,201,223,69,192,131,167,26,169,24,224,129,6,115,213,88,171,177,158,146,253, -246,241,45,110,64,99,35,137,193,17,73,146,70,218,76,124,68,59,168,71,80,209,145,70,22,144,18,9,230,210, -54,85,101,51,14,126,198,222,59,110,255,146,246,167,70,178,128,59,61,205,92,20,229,119,145,88,71,185,17,96, -24,13,6,244,243,107,11,195,169,16,185,102,239,98,77,206,11,137,6,178,230,123,170,168,245,218,215,129,105,163, -71,67,188,12,107,9,2,108,189,114,46,161,100,117,143,222,233,234,59,103,100,148,106,238,37,145,3,169,95,214, -125,103,118,86,12,22,179,230,165,194,218,72,34,96,10,73,139,49,219,230,105,35,71,81,130,44,152,122,92,221, -177,173,62,32,102,115,189,236,154,51,153,216,41,175,199,40,224,11,217,156,50,78,19,255,111,30,33,177,119,32, -179,114,223,118,58,221,44,193,143,0,253,134,36,174,196,166,173,54,40,7,101,156,124,246,58,9,239,128,212,75, -154,27,55,180,42,119,247,125,164,247,100,216,10,226,118,142,242,58,226,81,204,61,241,112,239,238,149,55,6,182, -202,75,49,228,59,173,93,56,119,21,73,59,55,110,139,203,177,86,252,11,201,75,227,222,122,73,17,159,175,27, -81,67,220,13,82,241,148,246,163,197,248,154,178,216,194,211,146,34,21,69,222,32,92,68,126,229,148,251,192,140, -86,140,167,139,48,239,205,255,173,104,125,104,45,212,193,11,160,104,243,19,242,127,98,18,25,109,47,38,114,1, -147,118,32,206,207,207,161,132,61,47,192,51,195,205,205,63,254,254,217,205,179,103,203,155,79,126,248,254,242,179, -127,93,222,220,32,22,85,12,196,147,76,180,242,136,122,168,174,38,42,38,244,76,213,208,143,21,39,229,108,222, -121,128,60,85,35,15,14,141,212,212,75,147,68,228,44,65,25,106,46,154,133,55,84,252,243,105,211,212,85,181, -103,196,3,142,58,93,85,47,151,85,133,120,152,138,241,156,169,162,215,38,108,11,231,81,107,188,239,165,253,97, -141,200,105,129,235,132,109,236,185,253,50,44,215,203,117,13,36,227,157,145,4,186,69,190,16,165,113,79,246,9, -253,242,155,247,131,162,88,92,93,219,197,167,224,112,129,87,249,181,25,99,91,35,17,76,90,110,123,97,169,181, -210,25,168,188,239,177,255,34,30,153,230,34,247,198,248,115,145,89,113,225,92,17,230,208,176,30,113,206,92,117, -84,251,75,181,193,185,111,8,79,245,58,52,153,220,237,20,15,236,189,81,96,65,68,213,56,221,49,142,171,182, -78,28,110,181,121,134,189,236,62,199,49,109,144,143,97,240,39,24,185,129,214,20,202,159,165,139,25,217,228,228, -40,206,29,1,234,40,62,37,105,160,131,207,244,9,100,75,89,144,167,32,30,192,98,243,141,124,77,14,185,31, -223,216,32,73,43,133,32,138,227,213,184,112,63,189,23,210,54,71,141,71,19,137,58,85,156,72,126,41,192,42, -154,205,142,60,61,35,222,200,80,9,199,239,38,53,13,246,170,173,116,76,164,228,32,140,255,218,50,222,7,11, -133,19,140,123,89,171,214,132,143,48,172,27,72,146,18,249,56,90,165,63,83,237,65,194,153,1,60,169,61,213, -140,167,158,233,27,138,143,229,137,165,93,158,100,81,102,104,151,154,29,133,50,100,211,185,210,166,129,29,150,188, -16,131,157,205,71,241,128,150,184,234,221,60,104,201,58,122,225,235,194,109,150,196,59,222,133,5,226,221,161,203, -241,158,121,34,142,0,23,47,171,198,250,242,32,115,93,118,202,253,12,49,1,131,57,148,58,193,27,151,204,201, -160,201,32,45,98,91,140,179,9,3,249,65,203,4,105,150,67,245,159,223,170,255,222,149,247,235,106,243,191,186, -1,19,58,28,65,125,45,78,120,101,177,125,1,27,6,255,74,20,245,34,163,157,159,28,136,14,47,167,101,144, -245,237,91,21,82,72,50,75,48,8,216,129,168,16,134,53,36,89,206,201,25,241,35,144,19,24,62,6,99,167, -227,130,175,68,51,46,12,59,174,186,232,116,198,13,191,21,101,232,114,145,16,156,33,148,114,161,194,91,230,102, -34,248,206,18,140,225,47,196,189,45,58,115,40,186,23,23,25,219,136,251,171,12,101,228,136,117,94,233,25,240, -150,111,8,224,124,181,185,22,183,240,230,81,131,146,110,199,145,237,246,243,106,111,252,30,175,78,35,236,129,63, -35,134,55,217,105,45,183,60,116,116,174,199,72,27,95,99,151,116,252,17,59,87,159,71,111,223,230,23,162,92, -180,139,32,48,20,182,36,84,162,33,230,220,39,213,74,126,212,34,51,93,157,207,102,147,179,99,104,151,139,217, -241,52,62,131,92,135,136,206,42,225,2,211,126,106,56,192,216,57,164,154,64,217,233,197,236,100,122,52,133,226, -117,26,42,45,81,9,134,181,35,224,156,231,135,19,150,164,79,40,199,97,168,158,208,153,206,207,227,136,29,162, -158,230,152,245,101,244,57,157,38,81,40,155,231,84,38,5,34,70,131,124,86,68,63,71,252,51,86,149,167,217, -236,119,240,185,246,238,11,91,70,110,56,90,31,213,197,7,128,160,128,9,173,15,132,230,166,25,127,195,110,89, -97,11,108,33,42,167,6,226,20,55,170,228,154,98,204,3,52,150,184,175,184,218,236,221,225,215,11,42,51,169, -89,136,65,185,136,18,169,173,113,150,14,88,35,116,17,189,105,151,92,56,248,163,115,96,114,148,226,10,247,227, -7,49,188,38,240,154,194,235,8,94,51,120,29,195,235,4,94,167,240,58,131,87,10,175,12,94,57,188,86,240, -34,33,64,112,189,191,1,173,123,30,89,145,228,181,134,143,24,249,71,45,146,188,254,207,216,125,168,54,143,4, -1,0,126,27,97,35,12,211,11,103,231,69,14,153,26,64,20,11,68,7,225,103,191,217,40,46,119,127,46,44, -77,236,72,195,248,115,102,54,40,192,102,174,11,79,127,173,227,165,118,190,101,187,223,134,249,56,126,214,115,39, -11,8,183,100,219,160,54,165,195,122,62,251,182,126,124,124,144,30,199,91,197,230,177,130,195,109,187,175,195,210, -82,112,58,113,164,154,104,88,187,125,57,204,213,95,180,205,45,167,218,108,173,224,50,86,116,88,183,251,60,220, -90,14,77,163,129,33,104,96,182,219,151,195,82,57,190,45,149,131,85,103,174,224,109,172,232,48,111,247,101,88, -91,14,79,39,4,17,37,101,134,118,191,62,249,249,76,180,221,90,82,21,90,42,248,95,143,84,146,155,96,68, -122,167,71,167,17,9,0,2,132,186,65,86,117,196,153,24,89,176,87,228,211,73,212,65,51,184,215,19,211,136, -238,0,172,130,214,9,202,250,108,169,33,40,130,222,11,194,234,4,33,48,238,197,32,182,50,9,2,130,70,189, -30,164,2,5,136,1,91,80,39,8,171,21,4,88,16,1,187,61,173,19,20,8,128,40,161,27,245,213,12,108, -202,202,148,191,162,42,107,25,238,59,170,74,153,122,154,34,60,73,186,147,252,157,180,108,183,225,190,60,250,7, -44,21,208,152,158,166,220,73,252,78,186,109,235,112,223,73,88,83,36,236,232,142,252,18,201,46,138,119,209,186, -205,195,125,253,30,112,118,142,116,6,122,121,96,247,208,207,30,157,78,14,168,26,150,216,233,65,152,70,142,210, -64,112,47,167,202,152,129,120,48,107,47,71,90,39,168,178,135,68,47,39,167,81,45,68,76,56,122,57,173,123, -0,51,128,45,161,19,196,149,19,206,198,105,216,235,105,243,141,198,202,168,128,189,32,108,149,164,64,129,98,222, -73,162,233,164,40,192,30,210,233,241,182,247,176,50,133,56,247,130,176,234,96,146,25,184,179,252,42,186,46,215, -71,187,177,135,106,60,37,178,75,226,77,114,173,199,247,47,236,68,64,164,94,124,126,66,16,119,9,190,73,174, -149,243,24,27,12,78,96,80,163,151,195,118,135,189,57,174,149,244,248,241,23,28,82,213,94,4,254,34,228,15, -2,44,115,123,60,9,12,122,20,210,182,25,167,72,102,237,83,120,43,161,146,110,220,105,128,202,128,20,103,48, -129,46,5,79,163,5,146,39,186,244,40,170,2,107,40,59,17,117,33,170,111,157,72,9,211,179,11,97,211,232, -6,148,24,217,35,200,233,84,86,54,145,240,30,64,107,86,33,12,212,96,237,18,160,78,163,50,184,148,2,186, -8,85,34,83,153,195,20,127,49,44,215,195,109,171,241,254,254,94,49,195,24,66,228,201,176,157,97,79,70,177, -15,235,86,195,253,152,85,36,139,68,193,55,9,236,18,122,74,202,126,152,183,154,239,231,46,39,104,172,146,160, -47,141,238,26,127,106,202,127,88,182,26,240,239,113,85,23,22,80,125,121,112,31,111,252,17,180,255,214,119,0, -9,85,199,62,210,190,157,166,100,152,129,245,146,246,174,87,84,226,94,15,182,29,69,37,137,60,179,87,20,5, -10,103,70,102,205,78,16,182,141,14,12,209,69,122,61,86,28,53,192,12,14,232,22,241,52,34,67,162,162,73, -55,233,171,25,84,137,193,161,87,132,149,131,4,132,192,158,189,166,106,6,199,240,112,210,236,37,213,100,179,176, -132,170,226,255,129,218,91,207,101,29,219,229,107,133,211,229,86,43,220,87,52,93,150,90,209,190,226,233,50,143, -237,178,189,255,15,228,183,35,58,31,7,142,238,231,172,154,212,9,171,23,57,174,127,127,150,171,254,200,242,254, -142,254,121,28,15,255,14,140,120,60,159,227,207,48,85,24,237,207,56,87,156,228,31,238,174,132,187,109,92,87, -255,149,68,243,38,79,106,96,215,217,186,200,85,125,50,157,173,231,100,233,105,50,111,115,125,122,100,153,178,217, -200,148,159,22,167,185,142,254,251,5,72,137,166,21,58,147,206,221,239,76,91,75,20,23,16,4,64,136,2,249, -121,122,165,208,128,81,126,58,73,67,54,194,138,135,216,248,72,53,78,215,135,35,217,162,186,57,26,109,107,134, -235,102,154,239,23,16,17,120,227,122,233,103,136,174,192,33,189,84,188,62,130,206,33,250,160,104,209,94,190,134, -142,78,62,134,38,245,85,67,38,145,248,38,72,136,206,23,72,168,91,130,160,207,227,229,56,87,235,41,12,173, -53,45,74,121,50,127,17,180,159,121,144,174,73,224,193,176,7,143,254,63,2,197,153,148,26,60,240,184,98,204, -125,107,176,144,213,46,251,254,248,205,155,35,5,68,217,228,58,56,124,181,126,2,236,237,201,137,71,84,17,213, -220,83,53,35,39,117,213,35,76,168,249,24,6,175,158,37,16,6,161,14,104,113,145,229,13,50,134,219,125,54, -240,220,238,170,7,175,42,239,63,158,211,26,231,34,204,114,246,94,20,110,72,111,230,152,23,34,51,237,64,166, -221,147,58,145,137,14,114,250,61,33,132,189,154,152,114,61,112,225,122,224,196,223,114,224,82,53,112,161,12,44, -106,143,27,221,191,73,6,173,28,158,79,171,248,191,113,81,188,58,149,137,180,210,242,71,198,83,180,199,19,185, -255,111,53,136,121,51,136,25,16,24,158,228,106,70,164,189,57,238,103,68,42,90,67,54,44,222,190,125,245,44, -219,63,222,35,31,164,185,165,27,29,252,178,174,49,210,98,97,88,140,134,245,170,251,5,117,63,39,187,96,224, -124,232,229,97,107,120,220,243,225,167,146,214,73,58,159,202,159,241,191,145,58,214,91,45,217,21,193,99,71,171, -22,132,2,99,2,47,27,171,85,166,80,168,120,13,51,178,68,30,219,216,18,164,212,51,88,36,20,139,248,48, -107,153,229,76,119,139,13,184,159,26,120,203,198,138,111,29,128,22,103,233,252,157,42,218,124,255,149,223,189,90, -13,23,158,137,164,188,185,32,218,206,218,29,223,21,236,76,118,107,159,25,55,154,42,65,167,225,186,15,91,0, -235,3,134,252,51,107,129,108,32,124,209,29,75,46,25,97,95,155,243,133,193,91,67,16,68,231,128,100,224,208, -171,195,225,26,177,213,198,217,101,112,232,145,252,106,98,183,243,73,61,1,19,153,127,214,68,53,100,140,122,210, -44,213,59,39,19,92,147,234,29,134,227,232,120,140,27,206,95,140,49,122,234,245,228,53,45,235,188,140,240,76, -41,58,73,62,114,57,157,81,159,36,169,227,161,92,217,190,79,184,180,144,125,178,87,120,251,245,21,35,195,226, -22,202,1,119,89,253,155,201,95,205,109,233,165,171,252,89,5,214,207,209,134,220,221,223,27,55,15,195,197,140, -239,65,186,215,172,5,53,215,187,47,72,253,139,55,189,129,58,100,54,252,234,22,251,12,122,158,175,238,185,234, -85,181,189,37,43,180,109,99,230,3,98,177,33,18,144,4,12,179,69,244,133,44,210,221,166,160,41,84,207,18, -159,9,124,230,1,30,193,59,104,43,25,146,228,166,65,217,73,128,183,21,80,158,55,221,22,110,78,6,176,149, -70,212,64,2,148,93,202,111,238,1,151,81,19,48,51,122,165,66,129,108,223,94,168,124,253,248,7,46,194,236, -206,77,164,54,80,122,101,169,67,101,218,168,73,97,81,146,74,236,7,5,168,187,68,105,224,90,13,106,47,39, -88,103,110,158,152,115,95,170,231,62,13,112,57,3,225,26,133,108,110,140,217,21,153,43,216,90,192,214,177,54, -103,244,105,241,70,53,100,34,191,97,10,149,157,178,187,69,98,139,91,212,234,6,42,9,71,27,193,105,100,179, -32,50,248,129,93,144,95,84,22,116,62,53,152,10,15,217,102,199,100,178,25,102,248,144,81,142,179,49,96,65, -15,214,13,125,155,15,99,97,236,148,21,87,116,216,203,67,18,86,212,184,111,176,87,53,239,155,180,0,209,224, -175,201,81,170,137,102,109,179,145,252,65,35,133,173,163,133,180,217,27,157,213,194,105,244,25,211,232,199,210,25, -25,6,156,26,146,175,177,254,12,81,53,83,100,187,70,138,110,119,163,222,102,164,45,159,231,26,84,74,38,79, -254,30,134,166,175,21,214,190,86,184,246,181,12,50,10,124,128,194,23,146,211,21,42,175,35,36,167,75,160,183, -181,193,98,17,136,167,57,94,233,218,201,18,141,227,197,141,52,195,241,42,164,227,149,66,33,29,47,14,45,202, -168,247,116,105,15,188,81,207,12,75,36,161,22,205,84,43,48,18,167,156,34,136,54,188,143,133,43,60,95,80, -105,195,176,154,227,103,234,78,43,219,118,219,105,120,254,193,196,180,76,202,39,128,130,176,27,200,160,155,246,173, -109,20,141,233,163,49,125,220,102,250,82,87,88,252,127,139,193,147,239,2,124,208,154,28,26,71,69,169,142,50, -128,182,247,3,170,200,194,128,127,140,125,68,207,248,175,111,20,205,158,125,147,129,180,48,235,175,106,47,237,164, -217,109,167,138,100,177,89,216,117,192,156,241,82,33,233,143,93,117,129,116,219,27,123,220,134,234,122,202,186,30, -146,110,171,253,221,136,17,180,55,101,154,81,139,105,181,150,49,77,164,197,108,182,202,208,48,88,13,68,104,245, -248,183,25,12,5,255,69,40,133,191,139,23,252,50,126,29,82,4,149,1,15,26,25,81,26,9,93,163,171,125, -216,224,5,19,98,65,131,23,28,191,124,169,241,130,39,61,153,103,17,228,8,85,29,222,32,190,6,204,108,195, -65,150,110,32,129,148,137,34,66,15,128,249,163,49,53,58,214,131,2,128,35,87,225,177,7,50,166,70,134,130, -219,81,33,223,11,10,122,13,11,78,27,93,50,22,49,190,100,25,208,17,122,251,14,222,255,127,201,105,151,154, -177,166,85,81,253,161,106,107,41,181,102,1,227,96,73,18,10,83,252,197,145,129,59,252,69,113,233,11,187,237, -191,83,34,180,4,74,4,86,65,106,235,216,88,231,242,8,154,170,178,135,20,77,117,46,51,118,243,54,32,0, -90,146,86,36,125,50,188,37,108,62,216,66,77,130,119,183,143,17,82,82,6,111,80,96,53,190,157,14,157,169, -170,90,192,179,66,134,183,165,228,226,248,28,152,64,115,24,49,127,6,26,229,82,65,210,190,96,108,252,187,152, -129,144,26,50,198,13,25,147,242,25,177,99,214,200,39,158,102,76,233,145,1,193,153,4,145,28,162,18,127,107, -50,32,110,2,175,212,143,215,196,191,169,219,237,96,23,144,233,248,107,132,225,35,172,189,221,188,91,138,60,140, -25,36,235,148,117,212,30,76,214,169,34,189,150,251,74,126,65,249,176,192,49,83,16,145,163,252,248,117,48,18, -163,16,187,12,28,121,254,27,74,67,170,111,64,70,238,102,94,13,100,19,196,114,133,69,215,160,171,37,4,14, -199,161,25,3,213,64,12,220,104,176,75,128,57,18,217,199,149,161,221,126,227,192,97,26,36,3,5,81,228,167, -205,158,27,95,39,133,46,37,84,158,219,160,70,155,241,182,141,143,101,3,213,179,244,22,173,40,178,69,89,211, -166,15,4,183,44,239,165,113,162,192,205,86,240,41,235,198,193,99,216,135,21,96,184,231,139,199,2,116,9,89, -148,228,201,144,33,41,79,236,228,72,7,232,42,52,205,110,108,11,44,211,161,184,162,171,218,68,83,211,92,6, -104,170,250,169,203,164,218,134,244,219,196,113,114,66,192,197,94,85,216,43,252,94,188,53,164,118,232,24,177,105, -14,56,155,248,46,152,192,243,15,13,199,47,99,188,183,129,145,98,50,65,223,161,113,96,205,136,24,131,227,16, -69,84,120,68,204,26,247,182,42,159,14,104,124,12,191,70,111,206,164,36,234,30,193,146,110,159,81,12,236,77, -226,58,1,24,107,174,19,99,72,139,141,153,34,50,208,231,19,3,125,190,52,102,150,56,112,222,58,132,36,248, -70,98,7,174,209,124,97,22,52,64,220,48,15,74,180,247,63,125,254,240,241,242,250,18,11,45,55,225,8,199, -182,142,77,246,103,251,49,206,5,19,4,109,119,232,186,130,233,70,190,162,75,97,204,204,29,187,74,189,186,81, -146,18,212,96,29,129,87,212,155,22,254,155,11,140,228,239,42,62,105,207,69,237,198,97,21,78,24,22,116,222, -196,117,120,156,73,149,135,44,112,190,132,203,144,72,112,124,71,207,228,10,40,170,59,225,104,185,194,187,160,62, -194,55,218,0,125,98,30,96,190,44,106,140,93,134,84,6,50,84,188,88,19,214,32,67,65,161,182,75,121,96, -116,76,195,70,253,92,235,221,70,79,1,211,43,184,53,123,32,183,177,6,186,216,36,37,32,155,189,61,185,244, -35,49,49,254,167,193,210,157,21,243,68,66,48,120,245,174,88,134,67,113,139,22,106,74,46,202,93,205,199,34, -208,248,138,53,254,85,167,227,105,0,250,197,104,24,98,100,242,72,227,222,187,94,213,207,135,115,57,233,105,177, -85,164,55,208,87,247,247,143,68,137,54,155,1,7,238,18,43,151,160,189,160,182,12,46,129,82,212,176,101,212, -2,129,206,6,216,32,232,248,78,54,200,124,50,214,42,168,147,64,159,159,26,199,126,120,196,94,234,89,142,77, -52,174,47,195,47,232,26,169,251,112,60,214,250,113,44,103,188,200,152,21,165,126,208,100,74,250,97,196,202,198, -6,154,211,196,192,40,95,208,117,200,94,83,253,179,96,209,109,32,169,181,125,129,57,166,34,132,233,47,255,251, -249,234,244,231,211,143,239,63,191,191,254,233,227,233,245,229,199,43,212,159,210,4,53,71,5,114,110,104,211,2, -106,136,178,47,120,137,50,201,4,118,148,174,111,183,188,128,84,253,173,211,108,9,11,248,10,159,189,85,74,28, -133,82,137,195,13,156,193,57,188,107,239,98,45,144,251,139,189,189,107,175,174,251,90,122,130,115,156,230,228,254, -241,38,249,18,101,165,95,239,32,107,118,141,141,253,135,27,244,141,45,191,153,118,247,251,50,251,244,219,178,223, -61,53,123,245,132,124,36,86,95,2,182,239,24,248,225,87,114,75,76,80,24,51,241,105,112,57,92,98,104,254, -101,27,57,30,57,116,137,50,12,215,1,177,230,244,254,254,157,187,240,224,34,112,228,235,130,131,2,140,25,186, -245,160,225,50,53,49,241,2,157,132,155,128,187,23,202,217,36,98,232,181,98,182,251,96,211,61,22,190,145,251, -235,176,68,76,94,203,141,135,163,50,163,192,243,65,232,222,192,204,243,45,193,214,55,72,42,130,180,225,243,37, -220,98,197,57,94,125,129,221,158,124,7,139,9,130,118,248,101,20,224,19,146,216,96,138,100,227,159,46,57,64, -187,242,214,189,34,85,191,182,200,215,169,241,194,88,201,186,118,113,11,24,177,6,201,186,198,192,120,247,18,219, -188,70,173,32,231,230,26,22,180,195,234,44,88,41,249,245,223,185,83,15,72,168,253,175,131,107,188,27,123,160, -56,67,143,238,188,10,62,203,53,169,115,18,176,51,143,24,186,123,181,183,39,111,47,239,239,19,172,252,28,206, -134,231,35,175,175,48,46,221,85,141,216,203,64,114,204,71,178,165,47,58,241,231,247,247,87,21,156,233,55,141, -51,50,31,244,210,245,36,191,88,251,188,60,16,205,123,149,161,86,182,61,130,28,65,116,69,72,214,120,135,190, -167,213,31,219,82,151,147,219,37,39,232,191,20,141,255,193,219,150,9,187,207,243,29,66,59,14,197,78,42,69, -168,5,188,47,55,245,124,3,28,182,21,238,122,231,229,174,125,243,14,237,86,57,128,21,141,132,165,80,85,121, -184,204,39,221,207,87,228,126,62,205,124,71,61,105,142,83,237,60,42,243,173,246,79,153,164,218,58,21,74,64, -196,126,72,146,83,12,82,242,20,33,4,238,246,164,239,45,87,53,51,98,11,241,253,41,155,177,180,207,93,51, -215,220,26,218,76,111,190,77,42,136,249,36,74,118,214,107,32,64,234,167,246,255,27,191,178,111,81,109,65,200, -160,11,218,159,40,157,123,212,213,86,138,205,235,106,246,69,110,66,206,183,10,34,55,94,247,216,145,99,133,69, -236,129,80,187,209,179,80,160,251,225,62,238,191,58,245,86,41,103,191,150,80,61,155,203,157,54,36,175,222,103, -103,223,221,223,207,246,133,167,251,235,202,237,46,64,115,239,118,118,145,32,63,73,44,196,160,93,135,230,70,44, -83,184,123,64,210,80,153,109,217,80,101,43,226,204,113,20,254,158,250,16,81,207,191,187,255,180,54,222,159,186, -207,145,56,27,63,243,33,69,130,104,23,43,11,130,68,110,144,137,112,64,45,239,117,108,64,226,236,239,238,50, -143,80,196,121,87,164,217,60,76,248,159,172,195,173,205,66,55,99,232,199,70,204,77,193,233,58,222,38,120,119, -5,57,86,68,27,142,105,123,91,132,215,23,167,215,239,255,235,167,192,185,112,32,193,219,15,151,103,255,139,39, -133,34,176,235,7,199,224,43,39,118,188,8,31,67,235,60,60,142,105,183,53,11,132,220,167,196,212,103,235,97, -209,229,240,159,207,159,237,238,92,145,212,101,18,165,118,103,217,235,226,33,228,59,247,59,231,239,175,119,206,120, -196,68,206,240,110,202,139,89,57,70,175,122,254,124,193,229,25,42,139,80,28,62,207,85,73,4,121,37,79,119, -21,167,162,232,196,225,156,39,119,126,30,138,188,147,179,140,199,253,206,60,239,200,163,125,115,228,80,39,156,124, -41,243,194,199,3,19,190,239,119,212,129,32,246,167,213,56,157,220,173,230,56,163,112,225,247,170,144,128,33,18, -6,97,206,39,12,226,52,45,88,6,51,117,250,135,8,151,144,51,217,251,85,253,182,224,143,147,52,186,169,102, -7,138,42,170,220,63,100,243,126,93,31,30,194,206,230,59,189,42,230,211,40,92,80,65,144,59,56,25,144,51, -223,174,36,91,53,148,142,211,175,84,23,157,226,162,94,49,100,82,127,75,114,125,68,125,175,159,46,89,22,39, -233,173,191,228,57,173,197,85,225,138,192,23,166,242,140,230,78,68,7,210,251,242,12,107,245,62,181,201,152,9, -139,210,44,36,26,59,249,13,95,248,202,232,229,85,232,135,242,117,3,66,127,70,13,172,210,178,72,184,168,177, -79,136,101,147,9,29,197,160,56,160,14,250,86,146,90,141,129,150,106,197,84,61,186,85,100,114,49,195,241,42, -250,102,26,218,13,100,112,69,83,40,220,140,39,176,64,14,229,225,124,177,49,214,87,63,239,156,167,34,133,43, -54,77,217,206,111,239,213,221,199,116,140,138,167,174,207,153,72,82,120,135,150,141,179,12,230,152,132,61,141,88, -127,61,54,7,108,94,77,98,97,210,202,11,212,169,168,202,145,224,196,24,197,87,40,56,38,137,199,189,94,149, -151,216,163,114,97,228,122,121,242,125,95,50,67,143,193,34,85,39,132,251,25,75,164,99,208,223,4,27,241,233, -160,104,42,66,181,173,144,246,34,157,251,29,60,112,30,41,163,186,139,116,129,183,116,23,150,19,158,194,18,229, -48,213,146,194,133,108,77,9,140,204,128,188,46,220,33,137,67,150,38,249,200,211,89,233,53,86,139,70,197,231, -83,108,44,67,46,235,33,34,18,150,83,89,222,167,45,243,222,74,203,207,140,79,38,76,84,10,33,2,8,242, -79,110,66,151,8,130,144,75,28,116,32,161,65,49,10,205,49,210,131,171,57,164,83,12,46,233,52,173,117,102, -67,171,182,20,55,79,85,187,43,41,172,26,34,68,245,99,40,97,20,229,7,154,17,168,27,228,238,156,227,93, -93,152,44,199,142,122,162,82,70,90,217,232,61,63,196,250,34,230,171,71,213,70,62,223,239,224,73,67,157,56, -141,202,188,195,133,96,25,152,205,217,31,107,2,108,207,85,197,15,31,60,28,160,254,2,149,139,212,157,76,8, -75,38,216,96,157,201,239,105,238,25,153,18,58,0,100,98,51,35,170,148,52,23,246,84,105,29,244,200,52,66, -36,247,150,99,75,95,149,182,43,123,170,219,163,133,132,130,117,72,201,180,206,55,39,179,88,69,118,171,46,104, -97,210,131,31,150,69,90,15,132,60,29,6,105,108,134,86,98,119,142,254,80,47,53,233,117,213,162,156,143,89, -70,131,164,42,83,3,129,61,226,162,83,75,206,150,140,104,5,55,51,174,148,112,155,132,231,40,87,209,204,42, -105,212,97,57,164,253,198,156,166,113,76,139,253,29,4,188,218,40,110,180,169,18,58,17,213,144,24,244,109,207, -107,88,117,27,21,82,121,214,101,36,192,167,58,12,167,174,125,187,146,144,138,107,77,174,234,163,122,96,206,68, -217,154,214,242,114,78,144,0,58,53,225,121,33,209,33,154,158,43,42,176,83,203,208,46,53,213,80,217,163,17, -96,41,124,90,176,13,35,87,61,3,63,140,105,158,246,213,217,26,22,201,208,130,253,48,169,34,211,240,135,132, -201,152,242,17,43,96,195,194,33,156,208,122,118,13,23,157,25,166,38,244,228,225,44,44,29,16,99,158,246,191, -139,227,184,86,199,239,142,198,199,71,39,7,125,211,196,210,80,224,48,41,216,87,80,63,157,146,195,15,4,92, -118,30,70,87,50,229,103,44,161,103,202,122,146,132,95,89,178,100,164,127,59,23,172,164,25,86,59,79,235,174, -116,95,101,108,174,61,137,206,215,122,46,232,75,179,171,142,249,32,54,208,145,36,115,204,127,198,166,124,204,19, -94,252,153,189,43,221,110,28,215,209,175,146,187,119,78,219,46,173,94,162,217,151,127,51,191,239,190,40,150,156, -248,92,57,241,88,78,151,211,62,126,140,249,55,79,55,79,50,132,8,65,252,68,138,74,220,169,154,237,86,157, -36,20,0,2,32,9,146,224,254,170,156,13,86,58,89,46,203,205,6,138,55,235,185,24,186,224,242,187,166,245, -131,204,215,215,181,220,181,15,205,40,101,110,14,15,247,249,55,139,104,18,38,209,36,74,211,201,44,186,205,222, -78,122,201,103,226,192,112,128,229,138,71,195,122,135,233,92,101,189,165,234,11,165,185,105,165,242,166,75,58,150, -69,27,99,113,159,23,155,141,114,255,38,143,209,228,49,158,60,38,147,199,116,242,56,103,188,203,213,73,131,160, -103,41,17,183,228,83,118,6,168,243,111,65,228,13,4,151,153,18,48,123,140,212,79,172,126,18,245,163,82,166, -164,32,95,77,135,174,168,202,19,5,141,148,122,6,52,156,205,53,92,41,28,3,60,209,112,149,138,4,224,154, -15,37,45,53,225,26,58,167,4,247,12,232,178,23,151,90,149,13,51,200,85,7,95,79,94,206,94,183,83,25, -241,77,89,60,148,117,230,71,95,242,251,251,195,111,143,219,99,85,254,158,251,68,201,192,32,37,91,40,212,87, -89,100,235,151,67,173,202,226,177,172,246,110,43,84,14,231,185,87,34,169,116,20,218,172,26,253,51,179,142,198, -65,188,72,162,182,154,110,54,80,133,22,138,154,216,78,232,174,174,86,57,234,181,94,106,205,240,162,17,80,231, -203,213,125,220,171,246,206,100,213,207,116,229,164,138,80,196,243,133,232,201,72,173,110,112,105,218,205,127,123,81, -163,151,86,124,85,110,142,156,26,230,80,228,69,89,38,108,105,26,31,116,252,18,162,212,101,217,49,187,217,223, -85,121,173,26,49,90,20,57,163,217,6,151,231,106,242,82,157,153,131,254,126,174,110,244,239,23,194,77,94,154, -207,23,250,228,216,218,92,154,87,168,58,129,138,190,218,18,89,181,61,27,21,65,155,167,138,74,93,8,123,73, -197,182,94,171,249,30,26,173,41,204,13,32,167,205,189,150,250,181,68,197,19,162,149,235,173,242,86,218,152,164, -166,29,179,162,113,243,52,175,246,143,249,165,168,110,138,35,84,184,69,16,52,208,66,82,146,152,41,81,181,177, -121,18,199,85,252,217,187,205,173,44,55,193,70,204,35,73,211,96,30,100,174,190,146,165,206,224,113,158,158,14, -100,41,173,68,182,139,196,4,29,72,47,13,67,118,252,186,15,24,46,55,246,93,69,192,40,181,170,108,79,5, -68,130,30,142,227,99,36,126,4,28,162,196,209,253,60,137,7,229,124,206,15,79,74,247,158,148,123,85,72,131, -81,154,139,8,33,66,185,76,231,189,8,247,199,65,199,41,35,255,221,2,246,191,251,201,102,247,29,43,51,103, -162,203,84,32,155,218,198,108,255,188,165,171,159,157,22,96,245,229,98,103,75,135,233,29,122,126,88,103,137,81, -163,160,182,12,106,55,217,101,215,151,78,59,91,210,206,227,145,119,178,238,186,228,43,171,174,39,58,133,77,144, -18,166,67,118,247,79,224,236,43,114,193,56,194,244,250,216,94,149,90,240,75,173,10,91,143,106,59,131,114,65, -107,27,104,1,122,35,43,253,160,105,111,128,70,151,65,54,38,253,85,252,174,78,208,132,130,236,107,185,235,195, -180,237,248,86,203,84,1,93,214,213,240,99,87,78,51,212,97,224,200,241,145,105,184,89,164,208,68,141,242,111, -47,172,228,113,5,75,179,49,232,120,76,13,9,70,175,107,128,181,12,85,107,105,88,93,104,190,240,245,219,246, -235,247,103,174,234,69,185,201,95,170,99,214,190,61,57,75,51,174,253,211,146,174,150,173,59,229,233,199,215,70, -59,179,26,148,67,30,92,120,22,216,46,200,104,179,40,71,179,221,22,208,149,38,194,93,37,27,37,139,37,138, -96,143,221,47,226,250,242,66,118,158,46,9,85,138,54,121,30,111,50,15,143,119,84,190,52,152,132,203,104,50, -95,64,221,27,165,28,16,57,177,192,118,73,198,65,94,38,65,63,77,69,30,197,107,95,154,172,146,100,184,179, -36,243,85,30,175,250,34,22,203,50,78,188,34,62,166,36,135,187,125,84,168,88,165,129,2,14,114,120,71,41, -70,113,52,89,206,39,1,20,226,24,161,83,220,4,129,142,242,43,202,52,178,210,178,222,36,133,47,45,80,122, -2,117,149,221,58,73,86,22,251,251,52,137,189,236,63,168,228,104,130,195,208,6,150,50,64,35,3,129,254,19, -242,194,100,51,240,206,9,228,220,7,152,53,119,0,70,187,59,227,128,176,243,195,196,217,134,129,91,172,126,27, -234,61,152,209,87,70,244,8,34,199,58,242,28,34,55,110,32,206,194,101,221,244,109,71,151,235,165,44,70,205, -150,214,176,32,232,13,9,130,126,92,78,170,102,193,41,115,210,84,15,76,19,1,69,115,207,182,191,72,239,90, -195,50,159,85,150,188,236,123,180,77,34,96,72,59,139,58,8,39,131,166,88,165,63,13,113,236,229,118,108,57, -125,182,238,108,24,8,180,171,165,174,221,201,98,18,37,75,245,179,154,204,210,219,174,71,95,165,125,174,60,143, -201,139,124,119,63,254,207,255,248,247,31,95,26,60,49,220,75,217,182,173,15,251,255,52,41,41,168,93,221,130, -55,85,121,50,81,6,56,35,50,10,76,201,55,188,163,95,25,126,26,98,111,40,8,45,30,145,222,133,196,132, -131,170,61,163,249,239,12,190,250,44,238,54,219,67,59,137,160,151,159,186,73,133,91,108,30,116,137,181,35,34, -105,120,212,108,64,15,99,201,32,190,166,160,219,33,73,194,2,204,102,170,235,165,197,182,139,143,18,108,213,137, -143,83,115,64,140,74,69,175,23,149,113,131,197,38,1,202,70,249,189,50,138,130,202,198,144,209,133,160,233,16, -243,178,236,170,111,80,244,237,225,247,54,187,161,41,244,238,227,50,227,135,160,207,214,130,170,160,116,127,98,213, -51,85,197,210,116,50,159,79,84,197,186,117,142,169,117,1,233,197,44,163,255,105,171,27,61,4,252,141,249,24, -245,109,134,141,105,191,101,111,202,46,85,204,186,133,178,56,10,140,70,38,200,122,75,171,198,48,91,70,217,46, -191,190,91,78,206,239,235,231,234,229,200,51,233,194,174,172,170,237,190,222,118,131,202,110,101,180,9,209,106,201, -55,83,165,219,164,145,113,155,141,225,29,99,120,78,5,12,105,133,13,65,179,143,32,126,63,145,155,63,140,121, -247,135,50,107,77,62,14,58,171,210,117,132,135,119,2,108,170,8,91,149,244,15,227,57,59,157,69,254,172,101, -2,145,110,140,0,25,98,140,251,122,86,160,27,80,38,227,191,220,248,177,166,108,205,74,144,54,68,50,107,175, -210,90,157,137,138,64,58,123,241,3,146,157,217,135,36,144,153,62,109,70,148,241,233,194,41,135,108,104,186,31, -213,202,122,178,1,138,134,205,126,132,96,88,184,55,39,152,102,36,43,80,160,215,152,4,111,235,67,101,239,182, -8,157,39,186,84,70,115,101,150,248,139,67,208,110,13,124,249,193,20,152,27,31,100,166,235,252,80,156,253,115, -173,184,236,225,234,23,174,233,247,50,179,95,123,62,108,169,3,105,231,226,0,87,108,15,122,239,24,239,148,144, -222,207,192,172,85,19,191,123,202,156,80,157,198,155,230,247,148,214,140,39,38,64,239,84,3,144,222,181,38,235, -49,224,223,203,162,141,197,213,240,112,28,2,16,139,178,0,123,70,65,90,186,37,108,196,41,8,193,153,212,95, -192,163,121,130,95,68,81,173,23,57,72,99,250,105,64,31,248,105,111,244,190,41,112,221,192,102,44,143,20,176, -14,230,85,110,243,70,151,17,217,3,222,37,225,158,71,80,184,84,244,97,246,141,35,4,158,68,206,44,0,140, -191,96,176,153,31,232,135,70,137,45,77,212,234,125,211,96,104,47,136,127,73,201,239,126,117,26,62,149,15,141, -135,120,23,104,5,235,199,3,13,212,3,199,16,145,63,72,71,123,203,158,189,222,193,73,10,122,106,131,89,141, -22,165,199,140,250,124,141,138,228,183,0,175,5,186,51,39,132,204,9,47,186,120,170,173,98,194,69,196,81,113, -93,211,206,38,35,166,89,148,189,149,228,192,246,97,221,17,173,1,26,230,174,109,226,50,150,177,248,113,120,74, -227,142,193,137,240,187,0,43,9,245,151,98,199,52,163,226,75,2,119,167,65,227,106,164,35,125,106,227,71,112, -63,230,193,106,35,211,178,125,73,226,113,223,216,220,163,164,214,139,190,204,72,29,61,92,179,74,0,151,248,181, -37,200,78,196,9,239,54,100,26,104,232,53,202,154,195,234,109,88,97,217,122,157,28,234,184,181,76,9,147,94, -164,62,68,230,21,93,123,210,13,39,119,156,145,236,169,54,220,4,33,145,244,238,212,15,93,12,150,111,238,29, -152,202,229,182,220,175,215,241,186,116,54,235,184,105,68,242,241,186,197,96,220,235,57,190,54,108,55,11,127,89, -6,126,155,74,93,46,155,6,246,53,150,102,91,43,130,185,113,80,66,92,132,230,115,218,28,40,121,124,174,10, -153,240,102,123,196,72,84,7,222,72,75,221,210,59,121,191,51,194,155,200,102,154,229,85,179,245,54,159,107,166, -237,109,46,60,109,235,223,64,13,203,252,108,74,218,61,238,216,233,157,193,180,169,247,247,178,91,223,64,3,172, -159,14,15,82,60,57,75,224,244,81,77,93,96,102,163,179,134,27,27,219,109,133,121,221,174,241,221,244,153,77, -102,91,65,126,59,32,137,215,97,27,70,122,193,201,197,134,81,67,76,120,17,144,83,195,71,13,174,109,235,175, -111,197,113,203,232,135,110,226,241,152,14,183,245,189,222,9,242,226,191,183,89,98,45,184,25,40,79,251,252,169, -128,61,224,64,53,211,127,222,93,171,67,173,25,212,113,155,239,123,107,185,150,117,99,215,121,230,250,219,221,11, -205,141,80,37,5,48,113,255,189,89,211,236,82,29,102,117,163,159,140,180,56,10,230,108,239,56,68,94,141,47, -216,49,212,203,39,154,197,109,127,162,229,230,229,160,206,125,54,111,147,55,110,204,39,117,174,232,219,211,174,202, -232,242,74,186,52,237,229,184,89,78,126,22,255,163,130,255,44,10,20,70,61,150,250,187,95,60,30,143,251,187, -79,159,62,127,254,60,251,28,207,158,15,15,159,232,137,39,138,252,187,95,40,178,239,182,229,231,127,120,62,41, -194,64,125,209,79,162,126,82,133,139,255,89,241,218,231,199,71,245,189,217,170,119,195,136,62,158,207,23,225,114, -213,68,45,20,228,95,35,138,245,47,20,47,122,76,190,223,81,32,109,62,99,245,249,187,95,124,210,108,72,156, -10,253,248,86,157,164,158,30,74,85,135,143,55,141,111,223,150,152,30,0,126,226,82,76,237,141,146,161,209,142, -109,215,207,122,41,103,34,159,154,202,181,140,1,17,184,205,162,239,126,92,3,117,134,65,172,108,177,214,22,225, -90,44,24,31,157,252,250,27,28,154,0,10,198,37,36,83,6,93,209,176,254,103,250,230,74,229,164,98,87,26, -214,154,67,93,223,60,73,39,0,176,5,58,228,11,197,99,84,228,246,40,17,87,140,230,36,17,135,245,109,22, -163,195,16,25,21,71,122,84,188,83,157,25,182,42,88,179,180,221,232,48,115,176,77,1,149,187,105,146,97,170, -8,16,173,168,6,157,215,149,90,183,56,208,53,48,124,91,226,173,180,113,251,83,171,235,148,194,214,10,148,101, -44,186,152,21,173,173,143,56,166,223,118,5,2,10,250,72,64,99,139,230,191,171,79,177,210,215,124,150,133,63, -133,76,228,79,163,77,229,153,134,240,171,54,160,204,144,120,67,160,199,255,120,211,54,98,203,62,254,50,174,123, -147,74,189,18,20,167,217,44,63,0,74,233,13,14,70,164,161,119,243,174,30,128,55,2,145,183,229,186,8,111, -156,85,121,187,253,89,139,46,208,67,85,229,134,39,201,180,0,179,43,113,214,66,158,219,242,87,66,139,198,49, -59,56,156,16,231,129,156,55,182,8,188,51,7,142,213,83,11,220,173,118,156,184,90,195,89,27,107,123,91,147, -13,176,43,68,64,178,233,231,199,109,86,174,246,39,217,98,128,219,69,98,133,49,6,84,211,185,250,126,143,19, -112,120,62,210,12,100,146,22,229,195,109,54,4,215,154,205,135,250,5,242,7,84,43,162,58,66,21,231,3,154, -60,31,87,40,1,48,59,59,219,162,193,108,75,123,217,22,250,178,77,70,72,146,126,171,10,88,211,200,23,127, -199,225,79,137,197,205,145,182,185,145,54,143,234,227,203,223,236,250,121,209,80,254,210,162,160,251,70,142,13,160, -135,154,8,238,129,188,21,8,235,103,146,26,35,172,217,170,215,172,176,235,219,238,64,156,123,244,184,42,195,193, -31,116,54,110,238,236,15,174,237,46,137,171,191,199,251,250,236,32,142,197,253,99,216,120,148,132,94,3,10,119, -172,110,233,161,69,210,51,93,236,70,70,12,100,177,89,110,86,23,238,63,9,186,191,106,127,28,112,184,49,63, -166,202,244,185,146,160,208,119,79,33,121,22,77,96,38,200,62,21,52,166,221,172,249,237,89,96,129,153,209,55, -114,243,172,188,192,108,9,114,51,38,48,109,4,79,94,92,177,175,160,109,65,126,230,81,158,150,19,101,209,113, -80,45,239,246,214,65,157,199,162,249,115,244,218,200,95,108,55,238,64,222,248,183,229,250,115,232,138,200,86,62, -253,48,22,31,181,175,216,99,211,158,13,198,222,172,241,71,243,103,202,181,145,191,222,126,104,208,193,90,44,243, -100,11,227,253,233,31,165,234,78,76,118,179,95,195,109,79,183,24,3,68,184,184,243,97,59,248,113,253,72,22, -75,96,230,23,224,3,203,45,22,66,98,99,207,180,218,20,155,188,45,61,92,128,113,107,194,185,139,250,32,118, -88,43,68,219,186,125,249,179,116,152,42,94,69,194,212,8,212,189,2,133,224,161,124,221,108,242,205,2,243,21, -215,164,80,3,119,174,34,206,169,13,32,45,157,190,244,169,54,107,2,3,148,176,198,251,30,188,246,228,92,4, -144,54,16,231,33,98,129,94,10,123,96,227,41,46,59,137,111,153,101,28,167,198,228,251,201,253,153,49,30,5, -179,230,237,244,35,206,185,235,240,229,21,57,233,155,143,246,211,250,115,17,137,253,121,56,30,1,115,112,156,122, -116,190,252,203,85,206,107,10,1,167,105,222,158,103,24,241,58,227,64,175,210,220,240,161,146,251,252,249,233,86, -9,249,46,175,182,197,249,135,50,248,210,205,98,102,119,5,239,81,111,124,83,131,160,187,163,39,38,127,0,74, -127,226,132,10,173,125,181,40,207,188,242,234,2,41,61,205,43,186,68,167,48,110,47,128,13,42,135,82,229,205, -83,245,250,123,139,153,12,188,81,107,211,194,80,117,183,9,189,93,39,172,118,40,17,167,7,92,11,62,195,212, -103,247,174,138,199,231,195,246,123,53,248,205,171,179,189,219,16,9,184,254,92,63,245,48,126,200,147,101,122,54, -30,93,102,107,82,70,125,31,218,13,159,114,180,4,79,215,18,228,109,183,11,225,70,113,225,63,123,56,108,139, -233,169,58,27,91,17,163,213,124,127,178,104,170,7,131,102,181,112,145,236,10,131,100,153,186,72,234,157,65,50, -15,93,36,167,218,32,73,180,46,84,5,105,149,69,7,118,5,7,234,29,7,78,85,27,168,97,171,202,143,182, -59,186,83,57,127,58,146,24,58,217,81,127,161,82,237,13,165,18,235,32,180,134,137,26,244,119,250,144,239,171, -178,174,161,144,3,140,22,56,99,252,13,3,207,254,35,228,24,87,229,71,99,114,111,59,100,96,220,74,72,86, -214,178,242,207,246,100,252,7,55,182,142,91,40,228,77,163,108,56,49,191,34,248,138,225,43,129,175,20,190,230, -240,181,128,175,37,124,173,224,43,12,240,51,196,79,84,135,178,199,206,150,64,178,69,111,19,147,208,133,121,156, -177,66,146,20,6,173,194,217,92,255,91,180,168,128,81,203,120,22,243,63,70,173,24,179,72,25,176,100,192,124, -222,231,178,96,76,186,236,51,153,183,152,86,151,148,1,137,165,74,194,152,216,210,36,102,76,212,106,34,73,180, -52,105,83,106,41,50,154,151,129,156,122,135,47,49,56,243,14,1,177,219,233,238,164,57,67,213,50,208,90,240, -4,105,165,82,2,233,97,136,211,223,237,202,98,155,127,99,54,164,203,96,127,186,61,55,241,78,218,164,117,40, -146,80,44,161,68,66,169,132,230,18,90,72,104,41,161,149,132,194,160,11,134,93,80,196,92,103,162,39,167,149, -158,188,134,122,242,218,234,201,97,174,39,159,197,158,124,70,123,114,216,237,201,103,186,39,159,245,158,28,6,124, -242,217,240,201,109,198,144,229,166,29,62,110,139,82,33,6,251,39,238,200,112,83,148,65,96,27,216,106,222,217, -87,245,64,246,197,161,72,66,177,132,18,9,165,18,154,75,104,33,161,165,132,86,18,10,131,46,24,118,65,17, -115,141,125,49,11,180,47,134,186,237,139,177,110,251,98,44,218,23,195,208,190,144,157,219,190,24,137,246,197,48, -180,47,228,230,182,47,70,162,125,49,204,109,95,140,180,237,75,112,110,251,82,8,191,125,25,248,113,251,90,38, -157,125,237,10,178,47,14,69,18,138,37,148,72,40,149,208,92,66,11,9,45,37,180,146,80,24,116,193,176,11, -138,152,107,236,139,89,160,125,49,212,109,95,140,117,219,23,99,209,190,24,134,246,133,236,220,246,197,72,180,47, -134,161,125,33,55,183,125,49,18,237,139,97,110,251,98,164,109,95,130,115,219,151,66,248,237,203,192,143,219,215, -60,232,236,171,222,145,125,113,40,146,80,44,161,68,66,169,132,230,18,90,72,104,41,161,149,132,194,160,11,134, -93,80,196,92,99,95,204,2,237,139,161,110,251,98,172,219,190,24,139,246,197,48,180,47,100,231,182,47,70,162, -125,49,12,237,11,185,185,237,139,145,104,95,12,115,219,23,35,109,251,18,156,219,190,20,194,111,95,6,126,220, -190,18,211,255,170,201,190,56,20,73,40,150,80,34,161,84,66,115,9,45,36,180,148,208,74,66,97,208,5,195, -46,40,98,174,244,191,106,167,255,85,123,253,175,218,235,127,213,96,95,12,243,249,95,181,207,255,170,193,190,24, -230,243,191,106,159,255,85,131,125,49,204,231,127,213,30,255,171,30,242,191,234,17,255,171,246,216,87,91,128,234, -125,189,230,153,211,250,134,47,219,59,7,63,59,15,110,248,11,112,191,31,128,47,199,231,225,136,33,189,53,101, -199,100,184,210,231,127,138,30,118,190,212,21,101,118,161,230,77,73,165,238,102,38,255,209,8,189,163,76,36,57, -177,164,170,48,12,253,12,131,1,86,1,41,253,191,73,217,25,29,16,148,219,102,97,67,167,97,160,57,144,241, -218,35,2,225,30,69,190,73,182,23,175,255,236,194,60,90,17,145,166,233,110,24,103,236,38,216,204,81,9,32, -4,53,0,12,138,20,243,82,113,193,184,14,85,54,162,199,195,33,127,197,179,143,168,2,211,128,116,134,128,224, -188,184,159,175,19,136,209,147,185,190,47,130,98,197,98,155,87,69,12,109,80,168,80,128,84,6,129,216,77,68, -255,49,206,96,90,11,122,190,0,142,157,131,88,161,65,169,4,1,161,252,138,2,196,64,153,124,213,61,139,229, -29,0,120,238,211,150,140,91,11,16,8,242,249,98,219,126,188,158,10,241,106,189,74,238,89,5,190,103,158,113, -124,197,188,173,2,147,161,10,12,68,21,202,121,158,6,65,47,158,157,243,247,101,152,107,21,244,162,26,174,240, -88,10,192,70,0,0,129,112,125,49,44,198,177,68,43,254,241,101,118,255,224,185,90,186,147,79,132,195,151,254, -35,157,54,35,251,85,141,142,10,239,148,125,208,117,204,222,40,137,108,61,119,53,15,114,246,188,31,48,28,199, -125,147,240,96,140,245,244,145,142,173,226,217,27,2,239,84,145,180,96,10,19,236,251,231,103,90,143,97,176,44, -12,48,56,99,48,127,74,132,231,151,163,21,131,225,18,133,191,41,78,183,26,38,106,25,32,162,32,55,133,81, -236,178,20,174,235,101,9,236,92,60,234,16,189,104,2,228,216,228,103,94,185,175,86,36,208,231,71,110,172,42, -166,228,159,77,212,95,242,203,134,156,52,133,230,135,234,206,244,87,63,134,116,199,32,173,157,141,231,67,120,92, -163,73,204,219,110,193,5,84,183,121,54,232,61,66,216,112,229,133,103,82,151,229,228,117,189,173,245,157,206,194, -245,218,243,131,112,57,142,231,36,97,177,165,23,12,15,147,54,48,85,108,142,104,61,142,3,145,64,253,219,230, -46,78,222,147,255,251,246,110,57,166,112,33,173,29,254,208,45,59,238,249,100,200,237,216,131,26,184,229,57,224, -237,212,126,167,108,54,79,61,78,25,99,37,193,198,101,99,253,7,127,194,77,188,73,185,116,8,103,95,209,116, -113,103,74,239,169,157,139,175,40,224,182,56,164,228,5,109,124,80,200,125,181,94,119,91,208,224,81,138,177,227, -43,163,89,251,43,199,185,101,68,141,91,209,89,148,192,251,88,131,47,120,166,134,85,107,135,71,86,181,238,154, -22,243,108,241,108,233,189,33,22,43,15,243,238,221,177,152,63,169,238,187,161,100,252,205,44,173,111,200,206,115, -218,205,179,217,62,109,85,50,223,70,5,103,220,60,143,216,80,142,9,196,253,254,157,185,19,216,70,190,253,36, -14,137,242,172,120,43,246,12,241,148,173,235,160,123,40,249,217,254,165,25,107,163,104,200,98,92,52,156,253,76, -165,71,95,61,5,151,150,130,75,251,48,83,115,37,248,102,123,98,126,124,67,248,243,241,209,149,57,199,188,233, -117,54,74,141,99,35,229,220,4,239,40,216,89,22,19,232,34,97,10,10,3,201,126,218,90,148,125,121,1,210, -181,249,120,182,114,22,233,84,34,202,162,35,106,62,145,66,245,78,235,63,191,118,36,108,187,12,239,104,187,50, -4,12,115,209,87,54,40,81,104,50,58,157,77,165,25,223,194,66,89,84,158,132,21,204,148,193,205,128,173,99, -130,208,230,163,185,214,174,102,208,15,191,93,116,175,122,181,190,84,0,210,163,214,219,205,107,219,200,49,248,50, -219,77,3,121,142,207,204,169,221,61,33,224,250,54,196,87,26,47,89,133,216,3,99,37,223,16,125,100,52,219, -54,34,79,195,156,51,15,207,87,159,194,217,160,180,105,120,54,175,109,232,229,65,136,44,153,6,243,33,4,109, -109,138,131,80,176,222,54,201,145,73,88,67,155,224,228,151,146,141,240,127,29,75,72,230,149,62,141,36,143,18, -59,143,162,62,235,196,206,163,8,181,79,236,60,138,48,143,108,146,35,147,176,150,54,193,201,47,37,27,225,255, -58,150,144,204,39,125,175,172,79,156,63,64,220,119,24,103,77,218,87,29,129,86,28,209,135,14,205,186,35,254, -216,225,109,243,222,159,60,204,51,31,219,87,175,218,217,176,68,101,106,224,49,97,102,116,88,180,68,204,144,16, -117,182,73,14,29,9,24,61,102,76,8,25,99,83,156,70,4,101,99,34,94,71,147,147,249,53,152,70,184,199, -19,51,171,195,162,73,98,102,69,152,6,155,228,208,145,128,245,99,102,117,52,110,3,63,141,8,202,198,68,188, -142,38,39,243,106,80,187,223,172,212,158,38,161,245,115,158,246,145,123,61,196,213,46,143,113,125,47,125,51,138, -84,6,28,1,24,201,253,188,137,213,16,70,115,207,106,226,25,196,4,205,91,161,235,188,46,251,239,211,11,130, -9,95,246,123,55,161,32,90,141,242,253,246,168,68,125,111,81,118,24,38,213,23,138,195,235,164,73,16,48,242, -254,185,42,0,181,16,84,195,101,173,145,250,93,84,13,105,211,164,154,194,18,223,1,46,119,140,107,223,157,56, -187,159,163,104,211,160,190,38,189,8,253,121,4,215,97,100,137,220,99,79,160,54,89,135,50,255,179,120,101,143, -175,251,199,242,73,191,150,64,190,17,2,224,227,179,178,28,29,251,174,249,61,37,128,134,146,112,3,72,78,253, -195,179,172,118,218,239,123,240,181,243,50,153,226,60,31,192,39,175,121,227,63,188,79,18,222,102,239,33,197,10, -17,45,210,238,129,86,163,148,244,140,2,248,250,219,170,228,171,177,220,60,168,101,136,161,101,136,35,74,221,142, -192,70,135,24,233,131,244,121,81,78,155,202,49,229,7,104,52,168,42,243,239,74,6,157,189,207,136,164,3,239, -123,164,181,201,29,216,26,139,86,255,69,219,115,40,55,142,35,251,43,18,234,149,14,168,233,85,217,227,137,212, -226,116,147,115,206,167,82,185,104,10,178,56,150,73,45,8,57,156,204,127,127,221,0,8,130,150,252,242,187,96, -130,8,157,19,154,218,218,189,250,111,192,216,84,128,25,170,11,98,178,146,170,6,246,240,94,54,103,201,124,93, -100,4,149,27,80,160,197,230,44,213,189,66,182,179,98,195,214,149,234,85,70,231,153,97,35,90,198,125,242,195, -209,111,149,25,140,162,165,41,205,229,74,65,33,53,253,19,44,31,206,139,143,186,68,199,52,151,80,74,214,192, -97,82,74,218,86,206,123,95,46,79,209,195,198,238,145,108,106,200,101,57,204,145,252,212,148,250,234,138,253,227, -31,205,11,131,20,151,210,234,178,200,94,197,235,157,25,6,21,110,50,229,23,163,81,23,95,211,99,187,37,122, -103,163,134,136,94,230,152,132,194,177,89,74,53,24,168,150,7,188,173,87,104,0,25,81,121,58,86,201,41,228, -13,159,153,86,212,143,40,219,205,2,137,43,212,121,239,11,47,174,174,38,83,49,210,138,62,165,246,242,225,33, -246,47,203,19,37,223,34,54,13,169,128,188,14,20,44,27,49,27,236,245,187,19,27,130,150,48,23,146,24,160, -241,36,136,47,93,46,57,109,172,235,44,53,217,130,23,162,187,221,44,116,121,238,118,23,117,93,155,33,185,162, -204,172,126,214,146,85,235,106,165,40,43,124,49,169,54,12,230,209,212,175,92,45,103,12,102,146,169,11,149,173, -13,138,137,193,74,178,172,60,93,45,149,81,184,182,144,155,186,21,219,41,23,155,150,133,179,206,219,17,189,17, -210,99,58,114,60,201,167,173,237,52,36,247,204,2,3,156,37,237,178,17,232,177,50,31,27,81,126,152,195,185, -188,28,12,46,249,37,255,192,81,150,66,140,206,7,131,243,190,148,122,48,40,156,48,206,33,23,131,1,63,150, -231,194,66,186,144,71,173,50,228,105,52,238,170,236,88,180,140,28,146,57,79,88,129,225,144,65,35,66,230,136, -100,211,33,230,138,103,41,202,154,7,14,20,42,106,162,34,150,76,135,167,70,213,92,129,65,77,9,209,202,229, -132,182,134,55,197,53,148,144,67,234,12,175,146,104,7,19,61,5,3,165,24,229,115,238,105,65,134,171,33,241, -224,182,101,248,134,10,134,181,204,134,103,233,114,173,26,27,91,15,6,172,180,92,70,126,181,14,162,90,3,59, -60,76,207,211,220,48,49,70,41,159,230,149,26,106,85,149,203,51,197,215,67,191,38,134,6,99,60,231,49,111, -138,123,225,24,75,108,45,160,187,220,16,26,214,69,178,5,127,23,92,79,191,196,99,60,139,193,198,18,221,1, -189,78,185,21,129,176,38,166,91,77,150,220,144,23,71,239,1,12,57,165,39,42,34,2,229,79,244,227,41,160, -33,193,246,251,181,212,99,237,104,46,113,37,65,80,117,172,92,89,182,90,125,219,141,146,235,70,33,1,13,42, -89,108,80,161,5,234,101,38,44,59,150,160,103,244,229,139,179,23,170,112,81,171,151,87,189,116,137,22,58,187, -236,233,117,81,144,15,138,145,63,184,34,16,141,48,240,189,244,128,242,6,221,35,142,212,15,79,149,89,148,51, -89,130,38,17,201,156,10,131,165,226,251,142,186,20,227,241,76,45,213,113,106,20,1,14,166,247,142,167,160,45, -174,202,226,169,16,195,66,80,7,36,47,90,19,171,234,26,215,156,53,224,134,6,155,208,195,74,21,6,223,15, -221,147,80,143,212,18,51,68,76,114,216,31,132,177,110,132,33,87,224,14,233,33,245,109,40,184,61,187,200,212, -202,105,201,41,155,224,121,183,140,129,13,6,184,126,164,215,43,195,155,85,112,39,70,133,156,141,156,203,184,8, -235,24,244,65,149,96,100,206,175,28,57,136,186,44,212,120,149,204,33,163,243,187,36,176,177,22,155,216,117,160, -237,137,59,85,215,158,203,0,20,163,18,113,21,20,226,215,189,90,50,199,82,221,26,209,59,110,90,19,50,33, -245,77,26,0,211,198,14,28,185,173,26,101,177,94,46,225,6,33,71,128,66,68,67,202,2,85,93,137,73,5, -142,140,93,224,132,183,129,197,232,6,158,200,162,191,34,231,222,170,191,46,84,175,65,222,155,149,170,234,21,165, -233,97,64,166,111,9,189,180,247,55,123,248,111,61,7,139,5,207,91,212,46,11,47,121,1,45,249,141,74,187, -46,224,212,231,15,222,64,86,105,117,117,93,94,11,107,24,185,91,13,89,122,156,59,27,224,122,98,40,118,173, -151,230,125,122,138,161,62,119,161,10,193,144,237,75,99,31,111,203,44,228,137,126,100,144,177,124,105,95,144,174, -216,38,67,36,121,194,255,107,2,13,194,116,132,245,114,39,209,180,232,249,168,191,11,124,107,96,79,184,113,230, -165,36,213,25,72,124,98,38,123,211,122,180,143,21,78,207,32,213,106,104,171,10,92,145,102,178,63,21,112,187, -93,153,231,5,38,145,75,183,118,123,10,106,104,219,232,238,253,0,247,218,224,136,112,159,21,70,231,170,26,174, -214,213,130,171,8,255,239,22,191,25,186,170,130,230,175,174,176,66,80,86,145,50,148,59,196,133,81,61,101,85, -23,239,150,170,5,248,133,0,94,67,43,39,13,111,76,151,165,97,245,20,76,200,224,79,44,145,158,84,20,162, -50,188,191,23,81,248,129,0,230,243,134,78,141,156,229,214,237,116,48,49,151,74,141,179,195,29,101,172,51,140, -102,187,161,109,253,188,122,159,190,71,79,92,170,226,216,44,68,83,101,254,177,15,169,12,184,53,166,42,23,169, -111,221,42,255,12,155,201,231,61,78,40,69,32,163,73,156,147,114,10,46,0,201,254,62,232,209,181,117,21,22, -247,64,215,205,106,234,108,56,173,107,31,211,232,53,121,20,197,162,71,72,76,39,222,41,23,235,250,123,205,153, -222,89,84,90,93,160,130,138,202,232,117,134,214,41,143,224,168,243,126,6,71,147,106,42,207,134,190,33,79,14, -37,219,156,247,188,17,34,57,123,181,53,29,36,212,90,207,78,185,15,6,38,198,234,121,237,247,21,89,47,238, -59,187,186,218,129,19,23,184,138,9,187,186,82,195,2,159,66,212,72,15,222,217,78,118,85,121,190,150,172,58, -213,234,120,231,44,55,112,36,18,110,176,190,178,2,59,60,68,1,85,214,175,174,174,184,33,201,236,160,75,8, -48,55,214,174,23,184,72,212,165,84,220,239,32,111,227,75,185,196,212,53,28,242,147,248,118,18,189,76,210,27, -139,114,4,254,40,190,77,201,19,66,71,51,237,9,123,99,130,210,41,37,183,177,234,132,103,97,58,220,124,118, -106,21,61,106,156,39,185,53,68,190,171,52,12,135,109,56,54,206,158,195,129,154,212,115,72,130,184,232,10,144, -225,68,126,51,91,23,225,70,184,189,133,77,92,20,237,5,96,83,70,130,56,81,151,213,14,35,156,76,71,24, -86,56,189,104,171,77,161,92,200,211,129,115,170,126,207,148,174,20,23,176,195,207,149,247,241,38,231,227,249,114, -197,93,185,231,32,94,243,230,34,118,245,198,15,99,7,175,193,11,170,146,31,224,75,100,63,155,200,51,146,47, -96,67,95,18,243,132,56,109,80,92,33,197,114,15,236,152,68,237,199,174,186,163,145,47,240,148,157,14,212,184, -151,56,243,184,169,110,18,164,41,151,7,183,146,69,19,161,127,11,232,27,209,21,44,133,108,230,203,205,108,145, -234,71,134,239,137,112,171,161,101,208,248,238,195,236,45,44,69,151,121,70,5,47,78,218,101,188,82,73,133,6, -83,81,239,37,210,123,196,194,158,173,6,140,188,70,23,166,71,232,102,171,110,253,225,210,150,175,97,85,92,73, -184,20,131,202,168,97,171,158,221,41,121,162,195,3,50,150,24,109,137,137,239,54,214,219,60,124,119,33,12,245, -130,147,171,105,202,19,220,249,31,21,33,253,126,89,55,50,206,175,243,236,173,242,143,253,81,254,119,137,189,184, -63,114,127,115,216,18,78,62,133,74,166,215,132,227,210,174,148,184,224,18,113,99,197,37,103,170,152,185,235,76, -179,246,167,12,86,215,220,109,189,90,83,96,77,45,194,4,44,163,233,182,16,113,176,178,193,96,217,53,224,63, -211,80,199,180,200,219,57,192,156,63,186,182,63,0,141,79,196,179,117,115,153,201,254,187,184,220,81,58,212,95, -110,95,253,80,14,189,202,164,70,157,170,194,244,206,115,212,215,218,244,236,241,30,86,122,158,2,246,63,32,24, -255,3,238,90,212,105,230,137,77,240,174,155,53,175,157,230,181,47,85,182,52,175,109,85,84,110,107,49,184,101, -217,85,212,96,208,18,95,198,100,250,236,81,142,108,187,184,174,115,180,91,102,199,54,185,99,210,110,46,96,246, -29,1,229,1,43,181,233,254,148,121,4,14,15,231,54,252,136,145,51,89,44,232,35,251,76,54,109,13,228,252, -199,64,234,35,82,62,230,55,133,44,26,118,208,80,213,78,43,13,104,197,83,81,67,243,210,21,119,247,206,110, -226,128,97,162,128,225,121,14,91,98,198,195,228,184,37,199,158,77,194,109,56,236,224,33,240,200,16,110,237,222, -110,64,118,231,98,254,156,115,134,134,99,128,136,50,70,169,182,251,148,128,69,13,40,139,188,90,68,156,182,102, -165,110,54,43,229,204,10,133,178,211,254,38,202,21,219,145,164,137,140,198,192,187,18,215,145,94,65,135,203,136, -128,223,92,19,137,53,144,19,253,191,145,104,116,32,207,167,111,125,99,150,40,162,230,93,137,111,164,117,162,178, -110,60,183,174,183,226,66,190,164,100,186,244,145,32,53,24,32,86,134,161,149,53,89,214,182,107,35,238,92,255, -218,67,236,230,227,77,115,113,76,232,130,3,237,181,54,209,224,175,177,73,81,67,232,234,68,150,226,85,239,124, -196,137,213,212,60,124,48,16,35,215,176,62,110,74,166,207,107,180,217,83,37,11,223,159,198,132,21,74,62,166, -25,176,237,189,61,217,211,76,240,66,212,244,241,225,104,54,187,233,227,3,74,229,193,237,187,41,198,194,128,95, -118,119,66,25,119,208,123,229,88,113,170,52,41,139,107,186,207,38,10,223,60,101,105,19,122,76,219,24,25,57, -53,156,149,249,172,183,215,151,50,199,112,198,243,230,202,39,32,173,29,141,243,219,255,17,141,7,233,17,19,80, -210,120,47,155,211,56,111,105,135,148,198,217,222,29,133,227,170,41,236,103,10,77,94,53,95,72,240,54,60,151, -197,184,218,194,129,86,149,147,6,149,76,185,162,212,2,57,25,123,41,34,166,43,191,185,253,64,96,59,118,199, -202,48,44,166,232,75,73,229,135,46,10,197,13,134,71,246,247,254,165,118,125,133,106,189,34,33,43,202,217,94, -66,182,184,180,135,201,48,168,5,238,107,83,1,198,138,70,205,14,182,68,211,253,82,20,228,148,170,135,7,76, -12,155,43,70,184,50,57,201,221,207,238,31,52,146,187,155,221,203,26,201,205,238,56,201,209,248,96,254,128,230, -179,155,202,253,221,118,18,180,181,148,234,22,235,53,248,89,168,220,162,186,153,106,46,119,59,206,249,62,9,21, -169,64,16,75,232,239,91,241,87,147,229,84,102,150,247,244,206,236,224,191,200,249,237,3,117,191,177,144,89,250, -224,78,195,231,108,239,222,189,96,33,119,14,246,28,159,193,162,50,26,223,121,104,231,151,52,158,207,142,230,56, -94,187,179,7,15,113,60,183,242,218,63,184,139,227,25,141,213,131,35,26,175,44,156,123,251,51,28,47,34,107, -60,181,178,62,218,35,248,103,22,102,118,143,230,143,34,43,61,142,116,112,25,233,230,220,226,157,223,39,248,23, -150,175,59,251,180,231,208,90,254,221,251,68,219,137,221,127,103,255,1,142,223,218,249,123,25,205,191,195,177,115, -36,1,79,44,156,125,43,147,223,118,126,127,159,230,191,208,248,158,82,68,219,7,75,195,189,135,52,255,200,210, -121,255,62,141,191,58,222,237,254,247,246,236,158,34,218,158,209,248,232,222,109,154,127,101,229,112,247,128,104,248, -151,163,231,30,209,240,111,145,61,61,181,184,30,206,233,236,71,123,246,254,109,164,167,185,151,192,115,249,136,51, -247,161,29,119,124,147,204,125,167,100,240,75,178,96,46,12,62,203,103,156,153,242,163,206,79,115,147,159,17,228, -199,242,41,117,4,224,19,62,209,9,141,210,207,209,213,190,9,120,225,157,127,242,107,10,47,101,57,116,16,225, -135,204,57,123,253,229,195,123,6,172,178,87,213,124,126,137,112,190,203,183,195,57,252,148,239,240,239,63,229,33, -254,125,45,159,224,223,191,228,7,206,42,123,182,194,109,111,232,181,92,253,209,206,24,99,119,24,237,190,73,251, -149,63,48,16,231,56,73,160,149,105,97,208,14,183,55,222,161,237,142,243,19,130,87,24,36,246,147,163,29,74, -35,251,5,86,105,248,7,249,104,158,148,192,103,79,236,191,220,60,55,178,26,12,214,156,111,251,232,253,190,188, -228,63,249,166,6,150,50,216,160,112,146,237,77,63,109,254,113,59,92,15,224,126,45,134,24,136,5,253,21,98, -188,59,14,127,231,47,64,137,81,49,24,248,78,226,11,12,86,240,211,111,2,156,55,24,223,95,12,6,63,105, -35,20,162,78,126,66,106,226,56,17,74,128,191,38,102,138,148,190,68,198,194,213,254,49,215,224,62,185,126,3, -147,30,39,6,102,170,202,116,238,238,119,170,22,80,97,119,71,15,163,89,219,253,165,75,168,92,142,183,59,29, -94,252,172,109,104,213,201,141,141,39,156,136,190,73,191,172,33,51,91,17,206,72,203,31,110,126,227,120,94,224, -41,31,131,142,108,246,8,204,80,207,2,230,252,47,20,195,24,105,86,197,250,84,105,250,253,243,152,83,251,234, -57,85,239,147,231,211,73,65,95,14,252,8,111,253,200,142,188,36,57,180,7,146,99,190,7,184,66,95,0,253, -217,171,171,159,244,132,99,12,160,27,156,135,0,128,210,151,113,159,222,112,251,79,63,170,97,121,93,13,129,114, -45,207,184,66,237,201,115,164,152,186,125,89,106,248,194,224,75,224,229,35,47,160,243,161,22,173,175,63,247,95, -206,53,40,164,39,51,78,70,104,17,194,18,84,195,186,139,50,136,219,85,2,116,209,31,95,34,17,201,210,112, -122,226,142,26,230,102,71,87,232,8,143,19,99,90,190,142,218,19,170,33,175,111,223,157,102,72,224,74,16,117, -164,33,219,172,232,115,204,207,248,238,15,217,241,95,118,224,230,156,42,112,64,34,84,83,156,39,121,205,118,155, -237,25,17,26,116,109,171,86,50,121,15,180,192,195,132,184,8,237,232,239,40,158,34,16,90,118,246,105,139,89, -59,205,161,97,151,145,145,88,69,150,117,13,171,93,2,249,39,39,58,72,32,147,105,171,35,213,253,210,75,136, -140,69,244,213,62,181,235,164,25,82,15,249,204,98,23,100,107,224,160,17,131,26,191,73,28,150,162,131,69,119, -177,244,27,52,202,10,253,133,29,23,14,21,249,184,197,86,212,182,167,128,60,190,108,113,134,43,127,47,118,187, -237,250,201,133,240,240,93,166,23,117,221,152,240,29,38,172,164,215,116,215,111,238,28,131,65,40,55,195,18,22, -172,99,215,166,228,241,156,72,220,86,80,242,189,45,228,59,82,105,45,203,127,164,120,3,184,39,50,28,55,68, -29,90,179,227,193,142,156,47,231,198,155,157,245,84,20,102,184,42,163,7,149,6,239,221,198,134,74,106,37,206, -243,227,181,243,247,254,30,80,43,81,83,97,100,220,239,29,224,139,13,149,192,154,86,43,131,29,193,255,147,197, -38,134,24,60,73,236,120,6,152,239,126,124,177,89,146,237,252,49,0,34,177,172,59,211,192,252,39,231,6,222, -225,35,51,240,22,31,51,3,23,248,192,244,40,87,6,78,240,177,48,240,10,31,187,97,61,243,176,0,121,228, -63,61,221,81,204,102,219,236,238,76,83,129,157,232,108,77,50,185,186,250,130,82,99,43,95,217,191,170,158,5, -191,97,128,164,111,214,69,149,206,9,112,45,200,250,248,230,120,89,30,165,75,194,68,221,125,122,98,13,146,169, -89,210,207,160,90,164,167,248,172,97,227,44,45,121,137,56,62,114,140,134,70,116,197,245,47,231,60,4,208,164, -154,104,254,6,212,102,138,225,17,28,28,39,219,174,229,244,230,191,114,161,217,80,84,9,183,112,42,251,125,52, -126,201,67,100,115,243,82,131,50,182,221,74,110,139,157,243,231,93,248,182,11,86,25,28,109,57,143,185,197,90, -199,241,201,208,227,87,6,76,192,143,240,205,20,35,118,165,156,157,196,202,160,106,100,207,173,229,116,21,191,190, -182,95,215,177,72,152,203,166,204,73,102,135,164,43,148,144,251,230,146,172,13,116,47,105,73,118,109,38,87,21, -230,7,178,143,232,199,110,79,189,61,160,24,102,230,191,136,28,145,118,129,208,85,189,74,86,215,97,59,27,168, -146,197,127,13,112,183,6,67,215,224,54,79,35,182,221,96,119,120,12,29,58,37,229,145,28,127,56,107,57,69, -185,98,184,140,161,187,5,131,230,17,46,142,19,106,202,77,89,95,254,224,19,67,137,139,109,106,251,182,73,19, -83,71,239,161,192,33,218,70,17,87,84,18,111,241,116,106,144,252,80,37,239,190,147,67,41,17,37,228,114,223, -255,18,230,122,4,254,123,46,74,151,5,218,96,155,223,186,53,245,63,188,81,192,87,156,114,112,136,211,212,133, -244,86,236,5,51,179,27,184,146,219,173,191,102,166,173,236,10,251,69,50,254,124,97,253,11,8,100,235,103,84, -67,150,147,125,114,165,31,195,116,181,90,94,114,146,33,148,36,252,250,223,75,187,210,182,184,113,108,253,125,126, -5,229,167,31,174,124,81,42,85,132,84,18,211,74,101,95,38,59,208,43,195,228,113,217,50,184,49,118,181,151, -108,116,221,223,126,207,171,197,86,97,67,232,153,47,148,36,203,178,44,233,236,239,49,224,84,135,123,36,138,255, -208,76,107,143,227,71,219,226,239,18,178,109,136,159,146,141,113,64,12,94,145,68,56,187,55,13,134,180,132,55, -97,125,50,142,100,154,241,92,151,147,172,40,202,65,203,185,61,6,38,158,45,182,106,127,62,9,88,125,127,50, -207,131,210,7,203,161,39,221,185,23,255,109,59,184,181,119,83,148,19,25,194,150,13,29,187,182,178,246,113,107, -7,223,221,105,237,224,40,78,208,167,113,236,197,68,140,70,228,189,9,215,78,101,234,196,62,173,119,218,59,210, -251,112,142,16,164,203,47,232,85,152,91,237,29,72,3,38,243,184,26,20,135,178,148,97,230,28,206,132,206,166, -121,202,0,143,141,244,214,87,172,29,72,105,73,3,231,165,94,139,41,97,158,172,236,44,136,178,221,150,12,242, -151,249,189,104,106,219,161,196,75,4,53,255,155,119,107,78,109,110,86,164,79,202,97,55,207,145,157,103,250,215, -95,195,43,12,238,224,92,225,237,149,181,183,31,188,213,167,3,21,207,174,123,160,134,221,131,46,75,202,181,156, -230,82,120,142,195,71,203,92,144,229,150,240,142,97,51,143,211,227,188,40,229,227,176,146,166,57,85,205,234,255, -120,103,105,110,91,207,84,107,92,212,15,51,123,127,165,154,154,60,141,138,216,118,107,84,155,78,177,52,77,202, -240,6,189,200,157,201,117,156,137,45,41,164,142,139,39,28,118,32,242,74,156,175,92,191,88,109,119,177,190,204, -41,102,156,139,149,35,105,43,98,155,187,18,108,141,70,179,6,216,225,17,181,242,12,228,197,36,247,30,62,126, -252,116,127,255,221,222,62,66,60,114,220,86,137,24,113,125,226,207,37,41,174,65,196,19,85,159,162,62,61,50, -122,236,174,243,32,26,176,36,174,90,184,39,15,83,202,168,49,55,51,106,163,180,231,154,113,7,55,166,171,221, -108,14,143,220,212,90,161,174,154,22,173,252,160,6,11,157,114,139,219,225,13,79,64,200,106,225,239,93,199,97, -167,1,186,202,133,52,157,193,61,84,57,46,170,200,217,139,204,113,57,53,14,75,75,68,214,65,183,168,30,35, -96,190,188,212,103,121,120,164,16,7,42,146,101,202,204,55,190,249,20,8,53,86,136,144,133,44,245,125,94,140, -68,15,113,175,96,135,133,239,7,177,50,204,172,5,155,163,29,251,200,27,178,128,89,206,19,18,88,21,126,249, -210,205,0,56,239,249,99,131,156,63,250,233,249,243,223,62,238,63,124,246,112,239,229,199,151,7,79,247,30,30, -208,30,7,49,173,226,98,178,51,189,38,117,78,38,82,218,179,156,220,142,147,53,74,205,231,231,171,22,156,17, -92,14,206,240,182,10,77,194,91,222,145,135,231,223,190,115,187,247,124,103,227,120,197,35,158,97,219,29,111,107, -220,121,34,199,137,246,141,70,179,197,204,250,70,183,163,132,122,41,175,221,25,234,211,40,142,148,127,52,25,191, -105,234,16,79,122,183,168,100,73,216,14,178,89,199,191,200,197,171,180,190,120,133,47,68,130,93,129,71,157,31, -83,217,48,58,254,85,120,166,217,19,98,201,22,112,164,198,44,225,222,159,141,108,228,155,52,194,39,216,170,83, -229,84,5,220,221,96,188,191,16,33,230,61,134,198,229,46,24,74,45,22,196,132,206,194,52,39,50,196,162,166, -53,243,141,186,3,128,179,40,198,9,20,161,66,197,240,84,208,70,50,27,34,40,45,115,40,136,148,252,32,21, -250,204,0,79,210,150,107,53,44,178,73,232,54,254,117,30,186,51,89,168,81,15,136,185,49,56,210,62,17,201, -158,205,89,5,76,74,36,226,34,130,78,101,193,75,7,212,243,109,17,75,230,193,149,40,41,216,66,247,140,11, -189,104,44,226,231,64,120,132,17,61,232,73,88,135,202,46,226,107,15,139,198,49,93,16,52,122,69,228,125,188, -185,121,108,49,230,115,150,137,182,194,244,196,65,138,153,18,105,235,163,52,154,31,100,240,252,249,193,218,165,19, -125,41,193,37,151,50,104,3,250,82,252,60,201,131,90,5,209,12,79,35,247,1,72,183,141,149,22,240,150,8, -201,105,101,193,186,193,241,193,35,134,143,172,115,68,11,235,240,238,113,252,206,201,93,57,1,129,200,9,8,100, -162,176,206,218,70,228,214,177,156,136,104,222,4,13,57,99,199,142,161,141,35,28,126,71,221,99,153,114,149,48, -98,74,41,107,168,60,207,192,177,27,250,19,168,82,98,93,31,99,111,11,110,24,52,170,23,189,157,12,191,168, -171,253,57,42,104,234,170,160,142,170,133,214,86,247,39,173,170,46,105,208,1,3,69,169,162,105,80,104,85,148, -14,42,188,248,151,207,96,114,107,54,179,75,189,179,19,198,88,106,39,30,18,170,101,159,68,59,118,169,233,117, -212,82,131,47,195,94,224,217,128,91,106,42,0,195,17,219,248,201,196,45,252,52,98,7,63,137,152,225,39,22, -183,21,176,33,233,101,9,44,249,9,63,227,159,186,56,245,130,31,19,187,72,217,18,60,162,96,95,193,18,114, -134,78,183,16,102,9,217,103,11,33,227,167,98,194,95,3,228,88,241,55,66,206,95,211,96,31,253,160,84,133, -137,111,5,238,199,251,167,187,167,91,91,64,149,178,248,175,191,78,129,175,250,12,103,208,66,124,62,60,61,34, -62,245,133,45,248,41,255,10,175,8,122,73,255,13,181,139,14,203,127,236,235,255,215,162,210,55,66,106,187,21, -180,194,89,213,111,155,250,198,66,215,103,182,126,170,235,219,65,164,9,236,13,95,116,168,154,198,138,248,105,187, -42,243,27,211,32,35,213,145,14,237,155,149,171,182,156,155,160,76,144,49,162,239,179,112,73,133,169,207,147,52, -163,211,76,229,109,218,174,226,76,82,137,86,9,0,188,175,84,220,65,135,60,166,210,109,93,122,137,143,146,80, -117,6,93,0,145,174,225,115,210,197,205,174,82,156,70,121,103,12,90,248,22,47,96,63,146,60,238,171,244,172, -20,117,43,236,124,104,56,172,16,45,180,184,29,72,13,48,124,183,181,244,190,115,243,232,191,123,124,207,193,249, -56,204,255,167,134,91,19,31,2,218,48,34,185,46,54,150,54,224,181,161,35,196,88,83,168,63,23,76,206,118, -5,225,138,225,16,185,131,54,169,163,9,92,205,153,218,57,27,200,223,93,126,99,170,30,61,139,226,235,113,216, -72,170,240,95,42,40,53,42,42,74,121,227,143,234,99,69,18,72,198,31,63,34,207,48,63,76,201,124,41,88, -138,216,133,51,153,144,30,114,119,17,14,77,127,183,188,76,183,99,6,46,33,136,231,66,244,57,200,136,174,151, -231,51,39,118,223,207,231,250,76,103,183,248,12,116,159,208,69,127,213,77,171,164,105,209,219,13,191,187,35,69, -10,39,212,155,42,246,23,207,160,242,164,32,10,202,187,11,187,176,106,127,7,220,151,69,150,37,171,193,19,39, -60,179,152,88,5,219,172,252,81,174,82,138,128,161,168,212,111,214,2,100,215,1,176,247,35,95,117,17,242,48, -130,223,133,94,238,255,32,116,74,18,58,246,158,46,194,147,97,131,163,233,245,68,168,141,121,167,36,7,173,38, -130,244,81,134,172,65,250,107,180,146,167,153,196,21,255,234,227,22,206,47,244,167,107,4,41,83,243,9,103,215, -144,116,144,33,147,24,38,234,247,221,117,70,175,199,167,230,142,243,145,16,5,201,61,93,9,10,136,54,56,61, -174,6,202,244,150,0,123,62,153,221,187,154,149,81,137,238,99,18,246,156,11,168,119,145,88,82,115,56,96,226, -88,173,4,165,85,187,90,120,29,83,185,46,75,173,243,98,133,136,208,174,183,99,48,173,174,152,34,40,8,176, -12,84,58,5,54,135,26,34,45,160,10,15,196,233,189,148,253,192,187,3,115,250,210,14,93,187,139,40,26,141, -234,150,56,219,32,33,114,34,48,218,236,138,19,176,179,125,55,233,33,62,250,39,108,200,249,51,239,52,203,225, -37,233,142,231,5,191,230,143,219,243,148,229,218,221,154,178,2,133,0,213,205,77,252,61,148,96,108,170,90,232, -42,189,5,80,24,215,176,230,192,161,135,66,26,188,176,230,232,101,94,112,100,117,67,224,24,167,219,52,216,94, -241,169,175,0,79,233,188,175,76,21,198,63,234,187,233,28,210,9,62,174,0,92,139,183,239,46,134,215,190,67, -123,236,230,174,17,142,123,22,139,235,145,207,173,197,66,174,157,199,193,52,15,82,143,189,54,195,195,75,243,243, -213,188,111,171,193,242,135,120,83,98,160,254,222,90,177,94,50,125,247,4,99,158,182,113,237,195,35,248,180,74, -55,62,249,176,44,195,175,230,176,166,228,192,188,168,109,210,94,116,201,177,10,70,70,221,184,156,155,49,113,57, -40,157,172,149,20,6,33,179,170,36,150,240,214,162,127,88,250,214,126,231,148,77,81,134,195,0,219,1,169,218, -127,193,46,102,152,186,177,49,60,109,231,42,6,2,40,145,50,230,11,71,202,165,142,71,38,4,172,198,77,255, -247,175,64,135,213,202,19,85,139,146,136,207,157,94,168,132,89,205,195,126,88,208,164,73,173,124,80,209,144,8, -102,109,131,149,157,67,34,70,217,217,48,119,132,192,95,170,185,100,95,178,86,31,176,252,65,187,46,15,136,74, -54,55,187,50,81,124,215,183,167,58,232,223,225,62,149,204,146,205,77,252,29,190,14,250,163,43,151,171,46,190, -155,150,193,60,104,73,158,143,253,139,23,147,107,9,0,88,177,145,221,61,185,61,155,96,247,28,159,91,229,236, -106,36,170,53,223,90,134,250,218,46,243,198,166,110,86,109,190,78,2,253,196,36,46,197,164,226,37,71,124,41, -98,130,10,117,91,13,229,89,231,91,47,15,163,163,17,18,149,65,179,33,91,242,136,55,86,6,156,249,231,184, -44,154,149,234,152,17,71,69,143,140,39,62,47,104,88,223,62,241,4,79,76,125,213,235,4,195,165,244,211,142, -120,194,81,117,7,165,170,234,162,64,252,128,216,93,190,114,145,179,114,119,238,194,67,220,103,85,112,34,186,222, -11,135,238,107,21,80,226,114,50,13,255,131,168,141,113,79,167,206,22,134,14,1,86,142,250,17,173,145,105,166, -177,137,64,128,98,135,140,143,66,37,21,12,89,44,27,141,66,199,184,161,121,56,67,155,110,195,220,248,92,195, -220,64,188,69,184,36,240,137,199,253,144,64,79,108,78,237,80,226,2,36,67,183,6,67,200,12,46,197,69,124, -72,60,135,142,223,64,71,108,135,171,231,52,183,0,109,54,48,234,161,149,94,46,57,148,26,18,37,201,165,205, -98,222,104,135,251,82,56,135,82,52,206,1,93,186,202,153,73,115,63,17,203,214,114,226,103,22,164,200,106,89, -213,190,39,108,88,191,97,30,90,60,31,46,205,155,255,214,157,254,197,216,248,127,253,127,249,135,255,246,143,182, -126,184,185,27,177,229,181,145,16,238,106,86,218,59,59,199,95,107,164,50,157,45,193,165,56,113,211,103,67,150, -116,209,6,207,51,58,229,217,92,26,107,238,14,172,185,0,73,116,203,44,164,250,39,238,253,48,245,214,86,174, -180,123,66,162,201,65,79,184,225,244,73,135,150,136,21,119,134,27,255,90,6,146,245,3,165,29,222,212,6,2, -238,128,2,42,136,148,151,79,63,190,223,123,119,240,14,39,188,231,139,119,13,198,249,224,23,78,130,33,25,160, -77,42,204,141,22,18,25,162,193,144,98,232,238,63,201,9,123,244,122,215,230,107,181,110,114,193,218,45,122,118, -243,40,64,144,25,171,68,239,120,5,187,158,92,96,52,163,245,144,161,45,110,212,8,157,246,129,213,238,140,116, -186,224,224,234,48,80,80,237,19,73,59,247,42,204,2,228,194,53,249,21,204,220,206,203,23,91,135,170,69,143, -135,14,242,183,82,187,30,199,218,203,231,41,13,170,3,136,243,76,132,74,235,106,68,232,64,121,35,119,29,42, -166,110,226,250,94,143,179,117,77,221,200,69,141,28,141,184,49,1,149,201,165,63,146,59,225,167,84,80,122,132, -207,251,136,138,166,13,95,214,99,125,51,135,47,7,247,240,156,10,106,144,173,45,171,45,75,242,51,220,23,214, -204,158,51,123,147,241,234,91,68,173,169,217,12,111,63,240,32,48,60,144,151,233,145,155,139,211,85,224,169,150, -181,171,146,64,129,93,7,211,120,152,115,180,183,23,64,160,230,94,236,192,248,161,101,159,2,101,172,89,193,244, -115,125,148,108,79,148,165,206,189,241,212,190,71,209,240,177,180,122,230,149,138,157,149,199,5,228,177,244,209,94, -112,169,146,232,59,32,19,78,63,161,197,135,31,211,41,31,58,75,131,250,206,102,119,254,166,29,121,46,225,78, -163,69,49,106,35,172,74,215,172,116,251,116,170,229,106,133,135,69,201,181,131,150,188,114,228,117,228,132,36,51, -71,94,55,14,178,34,113,208,23,177,163,184,47,81,198,210,35,66,230,160,230,207,212,248,179,109,220,251,201,145, -245,11,29,53,83,220,243,88,149,239,133,160,193,175,78,164,237,179,234,127,111,187,203,30,216,86,115,248,168,239, -189,131,241,79,29,164,199,235,11,145,185,55,168,35,250,135,12,2,7,5,242,135,161,115,220,191,111,93,30,54, -131,0,123,133,12,2,135,230,15,148,94,178,19,97,126,111,29,213,242,169,122,94,60,153,168,12,130,183,204,171, -150,50,194,41,68,18,65,7,254,248,65,60,4,47,224,79,232,23,211,122,143,122,203,27,190,249,252,153,72,248, -79,34,27,183,94,84,254,155,200,58,95,212,30,85,108,148,240,145,104,176,252,116,12,232,33,31,196,254,56,225, -207,197,7,254,194,13,24,126,101,123,4,189,162,104,57,251,109,115,243,55,235,142,194,103,204,225,95,107,83,141, -209,128,156,1,175,201,241,207,50,50,25,151,18,12,86,73,242,95,133,103,107,246,170,71,57,5,19,202,40,152, -242,63,197,54,127,69,191,117,77,5,89,139,3,246,109,128,17,125,102,207,252,145,213,40,168,172,156,205,26,223, -55,155,9,33,158,118,33,123,92,121,177,185,57,0,24,49,139,184,103,231,162,103,221,122,85,116,110,239,232,217, -48,48,196,29,255,233,125,113,123,186,185,121,51,15,149,15,26,192,139,155,99,232,56,52,179,46,176,160,93,10, -207,218,8,225,180,135,160,101,235,136,159,30,0,136,231,98,93,116,117,249,164,249,225,75,160,31,71,76,246,0, -52,184,213,145,180,165,70,53,215,66,34,111,226,227,250,103,15,158,141,181,126,116,168,179,159,189,163,139,3,225, -222,124,0,14,221,2,204,71,64,66,15,225,115,24,132,6,230,230,195,181,183,226,69,63,103,64,69,12,198,121, -81,167,73,42,99,255,188,43,219,12,121,44,0,29,57,117,87,181,251,166,7,250,43,132,52,31,202,73,169,164, -18,155,133,248,39,15,197,196,248,124,115,235,243,13,245,13,38,60,47,242,195,144,92,191,28,110,160,102,92,156, -6,205,56,9,211,140,199,162,177,251,197,151,40,171,179,194,79,68,99,226,221,202,149,146,204,89,10,156,202,184, -61,214,208,170,137,34,52,212,223,231,238,149,87,62,31,65,23,79,230,149,40,2,70,54,246,137,141,108,243,74, -36,172,240,57,181,177,19,19,69,231,25,212,114,92,18,162,177,14,205,249,146,253,212,66,151,110,80,200,154,196, -73,244,53,202,0,226,10,88,36,242,154,85,190,63,55,145,174,138,199,124,233,7,49,218,130,37,43,28,75,143, -158,52,34,136,75,251,176,37,53,174,86,206,26,147,79,157,187,219,48,229,128,201,56,239,67,32,55,245,146,6, -213,146,214,226,18,52,196,238,47,115,150,139,53,150,193,60,245,131,72,188,125,51,33,121,142,167,87,180,82,37, -21,211,60,173,117,223,218,38,189,93,96,51,44,167,183,34,151,160,25,32,144,92,223,78,58,57,103,133,200,14, -61,58,132,91,228,124,156,23,212,53,0,108,255,231,205,205,63,152,247,147,101,62,27,230,214,13,135,71,17,149, -244,243,113,94,155,168,125,143,33,209,76,219,131,87,8,133,163,52,182,36,43,197,59,230,118,127,49,223,27,203, -51,90,236,142,53,238,117,143,205,121,237,7,116,241,103,94,171,248,255,250,209,121,65,225,85,140,61,175,235,224, -21,47,199,74,68,91,40,179,201,132,84,124,162,170,7,157,59,221,80,35,33,94,209,62,214,99,253,239,25,86, -60,186,214,187,118,147,111,71,122,97,25,184,158,248,175,52,113,179,18,152,126,47,155,102,45,77,184,189,80,128, -249,225,90,193,85,30,110,51,116,147,84,223,168,0,157,181,159,28,49,80,86,223,62,82,148,220,82,253,159,188, -80,231,18,71,6,217,50,253,17,45,191,193,96,118,116,119,80,144,54,186,224,196,216,100,213,142,234,54,34,21, -139,92,200,13,195,31,226,141,180,134,223,202,100,90,20,32,66,210,234,138,121,159,75,209,105,181,90,169,122,72, -97,93,158,89,205,146,26,91,207,165,143,74,99,43,126,231,72,109,116,206,82,10,146,83,121,78,253,119,255,103, -251,238,211,222,157,237,147,205,8,171,93,9,251,255,217,218,129,57,54,89,27,156,20,136,5,53,112,7,45,236, -27,65,246,131,169,41,95,50,211,51,71,139,157,122,91,115,194,36,77,155,228,81,98,155,243,181,135,62,113,141, -147,111,86,111,231,150,247,160,172,79,43,74,45,131,10,136,65,181,135,17,87,212,18,4,191,115,215,182,128,3, -55,119,28,25,75,230,72,117,110,177,183,253,72,240,123,99,239,228,226,3,59,53,107,210,69,2,115,18,20,98, -64,175,32,185,74,59,164,4,72,119,121,221,133,201,115,35,63,4,72,74,23,173,29,84,26,162,20,35,148,219, -23,213,129,200,220,231,165,222,229,145,248,29,137,49,198,211,137,173,238,184,232,208,199,7,122,32,94,243,56,3, -169,237,59,166,96,252,230,92,109,180,191,139,219,90,30,173,183,214,10,70,97,79,173,244,109,59,182,67,216,243, -139,100,53,210,37,197,135,65,158,36,132,120,70,235,69,63,169,114,88,21,112,88,61,7,128,134,71,131,48,95, -132,58,66,145,116,251,167,225,85,49,115,154,184,135,182,158,249,235,124,214,198,249,42,231,51,118,161,91,104,201, -209,136,53,189,92,186,178,22,21,224,3,187,251,136,188,215,174,31,104,29,22,234,122,133,18,121,201,22,61,102, -207,248,35,131,185,207,120,235,231,83,105,15,208,4,174,72,210,145,72,72,48,28,42,120,182,66,214,37,17,177, -149,156,103,48,8,82,209,224,167,106,35,192,223,20,201,92,28,68,111,226,0,112,220,164,26,217,21,180,242,73, -173,89,119,166,184,236,130,175,87,62,140,54,217,60,79,29,166,225,245,136,116,218,161,58,36,207,2,19,147,251, -206,192,37,70,165,57,13,188,130,38,25,241,65,37,115,118,193,99,248,104,172,134,151,174,137,109,123,116,22,76, -218,206,62,7,62,22,154,37,175,196,116,247,11,171,57,187,248,164,72,144,82,9,5,110,186,155,106,242,181,168, -192,138,218,75,251,57,229,193,111,222,102,116,204,161,250,241,20,30,254,154,223,184,65,46,244,28,176,91,80,43, -142,101,215,180,234,120,82,170,149,2,5,46,48,98,216,137,131,243,50,140,228,181,22,68,103,87,15,44,66,177, -182,8,253,247,46,46,190,85,183,188,80,104,220,185,22,118,174,57,43,250,115,5,207,134,135,254,122,190,210,219, -51,153,80,57,117,114,252,195,206,227,223,119,201,244,190,69,4,200,129,250,156,84,194,35,145,170,16,193,100,55, -251,177,52,246,194,110,182,181,165,31,221,136,146,34,45,187,24,160,1,134,25,191,60,98,146,55,32,80,204,121, -113,85,184,4,222,7,119,62,202,247,52,78,43,245,59,20,36,49,174,60,33,208,134,241,239,221,14,191,231,27, -226,133,227,97,76,197,90,236,153,135,230,153,67,110,226,1,234,107,195,26,80,19,10,237,43,211,159,70,10,9, -156,132,18,102,5,47,199,245,28,162,214,49,83,244,141,72,94,174,203,25,229,126,117,201,194,40,109,237,148,164, -19,117,25,248,158,200,163,48,182,70,254,133,92,88,169,64,146,57,168,104,77,148,229,236,130,16,67,100,218,9, -129,14,103,114,26,185,133,117,0,176,252,122,65,105,156,132,239,6,137,121,37,188,214,83,233,9,81,116,139,209, -199,93,172,128,241,141,250,120,21,219,17,25,146,157,46,182,134,105,204,231,69,48,176,29,60,183,180,234,132,144, -200,112,210,233,30,177,167,188,245,186,241,45,149,188,192,124,231,193,133,250,69,76,138,54,171,142,135,190,63,47, -131,106,14,114,107,177,71,66,176,92,160,197,31,12,190,73,197,82,164,156,59,75,129,207,203,115,4,69,134,23, -219,65,47,23,29,98,25,164,96,157,188,223,193,28,31,214,200,51,199,143,138,134,168,173,93,204,254,163,24,165, -133,63,117,95,67,9,117,159,104,129,13,118,80,190,145,19,47,200,212,189,250,203,37,141,115,70,18,69,66,113, -44,173,143,20,9,60,240,145,2,5,173,2,87,202,73,26,219,10,63,111,147,98,32,28,39,193,132,3,245,2, -231,105,227,58,21,63,1,85,172,110,225,11,13,131,62,11,191,56,56,49,27,81,80,92,195,85,101,150,228,69, -58,33,81,171,238,29,210,162,121,142,244,7,147,112,134,73,87,44,105,113,195,75,129,244,153,24,83,14,153,243, -185,131,24,159,124,85,70,116,202,18,95,217,209,137,235,250,226,3,154,33,193,26,203,145,208,220,13,223,99,100, -78,180,9,214,127,169,199,41,15,207,142,184,57,184,165,106,49,82,217,15,108,145,151,194,140,227,196,98,75,223, -183,196,96,33,250,20,59,247,85,88,63,7,175,98,93,215,185,186,25,73,137,11,118,114,3,16,104,236,226,100, -119,249,227,201,238,146,100,127,67,210,100,137,32,64,66,110,83,166,22,232,112,217,125,222,195,122,169,68,195,115, -37,8,113,40,134,79,186,3,30,47,244,209,184,59,249,222,233,206,153,61,211,192,58,92,142,82,123,188,191,191, -215,100,242,117,90,213,116,108,168,182,143,127,46,243,68,70,89,88,134,184,67,183,254,12,209,109,59,101,41,209, -231,30,81,181,105,120,242,238,205,122,77,115,183,174,126,80,156,202,92,85,167,28,57,23,7,234,255,227,200,146, -226,94,103,166,215,179,180,157,196,139,131,55,175,41,215,237,113,145,101,218,228,51,109,189,6,114,127,159,25,152, -164,105,217,151,232,209,181,189,145,113,26,154,97,223,164,103,18,130,67,109,27,213,145,242,28,35,79,228,77,184, -68,149,74,102,138,239,195,20,239,71,201,50,149,125,169,247,89,115,156,230,109,193,142,177,255,243,243,215,106,23, -117,55,212,223,54,103,11,89,118,245,247,68,103,251,242,216,105,40,104,244,174,234,174,21,234,122,109,232,205,108, -83,209,16,17,62,106,146,164,27,21,91,180,127,34,165,29,6,25,47,116,95,116,250,184,145,23,155,108,189,104, -34,51,75,125,38,46,21,97,54,223,195,21,29,68,106,38,251,2,89,235,155,155,189,79,201,152,171,86,5,89, -113,132,120,190,135,197,113,159,48,126,223,234,132,187,63,222,212,152,128,251,255,248,241,230,162,136,191,226,247,164, -62,203,238,255,227,255,1,204,222,188,142,16,149,2,0 -}; - -#endif +#ifndef ElegantOTAWebpage_h +#define ElegantOTAWebpage_h + +const uint32_t ELEGANT_HTML_SIZE = 53715; +const uint8_t ELEGANT_HTML[] PROGMEM = { +31,139,8,0,0,0,0,0,2,3,148,58,233,122,26,185,178,255,243,20,141,206,249,56,221,99,185,1,219,113, +98,136,236,155,197,158,53,147,57,217,102,33,190,254,68,119,1,74,26,137,145,4,14,99,243,238,183,164,110,209, +128,177,103,238,44,109,45,165,82,237,85,146,120,244,172,241,234,205,203,247,191,255,114,30,141,237,164,56,125,244, +204,253,137,10,46,71,12,228,233,35,236,3,207,79,31,69,248,207,179,9,88,30,101,99,174,13,88,54,179,195, +253,167,235,19,99,107,167,251,240,231,76,204,217,111,251,31,158,239,191,84,147,41,183,98,80,64,148,41,105,65, +90,70,190,63,103,144,143,128,172,175,147,124,2,108,46,224,122,170,180,173,65,175,69,110,199,44,135,185,200,96, +223,119,168,144,194,10,94,236,155,140,23,192,58,1,75,33,228,151,72,67,193,4,46,142,198,26,134,172,53,228, +115,215,75,241,115,26,61,179,194,22,112,122,94,192,136,75,251,230,253,243,103,45,63,82,173,55,153,22,83,27, +229,220,242,125,79,12,121,241,250,229,254,175,2,9,181,36,226,102,33,179,200,232,140,17,199,161,233,182,90,89, +46,63,155,116,48,91,76,128,103,106,56,4,72,51,53,105,117,210,118,218,110,93,251,117,233,84,171,60,157,8, +153,126,54,164,68,45,114,70,142,255,251,237,199,233,187,207,213,72,14,229,214,66,73,70,222,205,166,94,0,19, +136,144,139,23,179,133,107,241,168,196,223,168,86,76,192,24,62,66,10,127,87,179,40,227,50,226,197,53,95,152, +200,132,197,139,232,90,233,47,209,96,17,33,121,66,142,118,33,201,84,161,52,35,255,186,184,120,218,57,188,168, +6,167,202,136,146,16,45,70,99,91,141,126,189,154,112,61,18,56,122,112,84,13,45,214,135,78,159,181,74,22, +208,112,90,206,82,156,197,12,84,190,136,140,93,20,72,167,154,131,30,22,234,186,27,141,69,158,131,236,5,165, +73,21,22,186,110,169,7,171,149,28,157,254,10,255,209,16,25,165,181,99,194,70,181,218,162,92,129,145,255,177, +37,143,40,225,41,232,2,57,22,118,172,16,240,7,62,231,239,74,93,130,228,104,119,121,26,253,82,0,55,80, +245,35,97,35,171,188,137,9,57,131,20,137,247,91,86,36,181,54,105,122,150,139,121,132,74,227,211,41,178,137, +157,45,115,129,33,232,211,120,56,147,153,147,91,108,147,155,57,215,17,176,155,101,47,12,70,58,150,201,141,24, +198,208,151,151,137,6,59,211,50,114,237,20,190,58,125,153,158,91,162,152,27,98,55,162,43,105,209,109,116,104, +53,217,189,89,46,123,213,34,235,22,161,217,23,177,10,107,169,162,117,91,39,216,41,88,163,93,143,45,117,58, +97,150,234,52,99,128,223,156,213,164,82,160,72,151,78,149,107,38,183,183,111,6,159,33,179,41,178,36,36,252, +226,229,106,23,30,236,6,228,108,2,218,73,175,139,200,209,178,187,114,153,44,17,159,102,235,172,147,153,44,87, +231,164,193,152,93,76,65,13,163,119,139,201,64,21,205,102,249,55,181,234,157,213,104,147,239,249,168,217,188,111, +203,187,176,20,229,90,204,160,75,94,171,124,86,0,89,38,244,190,197,228,234,10,76,5,22,150,53,218,37,189, +118,131,127,175,149,78,19,154,205,216,50,141,28,36,244,105,19,146,32,237,30,206,30,185,89,162,252,86,132,173, +152,178,205,166,251,47,173,183,170,87,57,109,74,86,81,151,105,224,22,98,57,43,138,196,225,67,145,197,242,62, +218,37,37,56,194,103,133,37,219,50,47,217,176,200,246,129,167,200,120,193,144,198,138,160,100,168,116,236,13,41, +18,18,187,168,107,196,167,232,138,95,228,118,101,70,112,185,76,7,66,230,158,46,170,146,36,88,152,116,66,146, +236,174,61,111,113,123,182,130,88,195,186,34,254,114,217,221,49,191,50,99,71,26,80,194,9,133,132,130,219,81, +109,170,37,44,169,164,132,62,110,149,227,51,29,115,243,230,90,6,121,121,87,240,11,28,142,41,35,45,66,53, +74,216,176,118,178,76,226,155,118,119,195,216,117,114,99,131,91,160,182,201,227,227,252,9,193,165,164,221,6,32, +119,96,189,26,29,220,224,248,224,128,36,84,49,25,147,53,139,196,33,225,220,92,244,213,37,35,127,17,90,35, +39,253,210,96,162,191,46,157,205,148,75,98,225,247,58,60,62,126,96,175,78,214,30,144,164,87,163,218,134,68, +19,114,90,161,115,37,242,168,141,200,215,12,207,96,12,204,198,49,66,101,46,220,181,187,213,204,14,93,148,162, +67,193,245,60,104,231,14,168,190,3,75,117,128,62,184,11,77,229,14,120,42,195,138,195,93,43,168,218,185,6, +135,151,203,7,40,199,72,92,44,16,20,243,15,58,136,180,6,193,157,96,31,63,62,122,64,176,39,199,252,8, +5,27,252,166,246,100,137,206,47,89,191,111,83,129,123,19,114,121,153,80,153,22,10,9,50,56,85,107,34,12, +38,101,184,118,72,143,78,78,128,36,105,101,246,61,133,250,123,114,220,233,60,61,124,74,16,23,122,237,141,81, +51,157,193,107,62,117,17,221,140,121,174,174,209,129,0,123,203,196,19,253,100,248,0,209,195,236,152,59,203,115, +237,131,163,78,134,123,13,189,209,173,34,35,229,108,21,156,2,71,215,66,226,54,205,102,248,91,121,209,8,236, +154,239,252,204,39,96,206,238,159,138,203,213,73,183,127,73,205,70,60,176,122,17,148,161,176,191,204,184,51,186, +218,105,121,106,10,145,65,140,106,169,237,56,29,174,225,168,65,155,205,149,171,252,234,247,115,254,34,42,191,78, +206,12,126,186,202,27,124,226,117,124,156,61,36,174,167,135,124,16,196,149,119,224,9,182,133,119,244,236,56,195, +54,95,19,169,113,237,172,125,4,216,206,60,76,231,240,49,182,11,215,110,103,67,135,103,198,118,138,231,85,85, +175,41,221,3,100,75,158,205,186,119,114,138,101,220,57,41,48,19,3,218,1,226,77,214,196,54,115,112,65,112, +200,192,18,87,100,126,44,248,178,136,27,42,29,214,241,141,186,144,237,68,224,105,251,167,34,104,31,158,4,17, +100,89,231,96,35,174,52,208,238,27,42,142,239,122,216,147,6,219,157,157,4,162,20,115,146,248,200,125,227,138, +128,29,139,151,203,36,229,203,196,25,119,231,132,115,178,37,155,7,3,91,35,182,145,144,198,114,153,57,59,70, +113,216,177,86,215,209,123,180,235,115,173,21,242,241,189,204,148,214,206,94,200,94,172,207,244,30,137,72,151,144, +100,143,8,57,71,247,116,24,145,207,85,202,113,100,12,224,161,192,144,183,143,143,55,36,35,113,76,101,62,180, +16,186,106,98,253,233,71,28,99,46,72,255,19,198,60,83,36,244,215,115,245,54,95,85,134,176,9,242,35,76, +36,149,141,184,15,126,187,248,201,158,252,211,108,37,44,104,110,149,246,86,208,232,244,156,13,58,64,206,218,212, +176,27,9,95,119,232,240,38,87,18,3,84,131,239,237,225,118,229,216,58,20,98,106,163,107,27,151,246,118,196, +231,177,48,75,250,92,107,190,72,135,90,77,98,67,215,109,172,100,252,96,153,4,243,207,208,252,119,27,69,105, +18,128,102,42,42,183,64,14,28,245,122,157,21,233,82,176,220,73,203,131,252,105,207,5,50,104,99,185,78,75, +40,81,74,73,231,217,3,146,62,60,58,24,110,88,78,43,22,211,49,34,191,21,83,149,227,135,231,73,250,141, +75,87,112,13,131,47,194,182,68,106,193,184,13,29,242,252,105,251,31,27,81,200,246,119,45,135,188,228,238,44, +228,34,69,52,1,59,86,185,59,56,146,61,187,101,52,121,254,128,209,132,80,161,214,12,72,248,164,147,183,219, +62,114,170,152,152,41,100,2,204,58,199,187,98,186,56,101,143,59,183,183,13,185,22,91,66,17,137,185,68,51, +119,76,150,198,234,89,102,149,118,218,11,34,239,243,93,74,28,42,213,237,32,11,157,6,99,208,183,151,241,11, +165,10,224,50,73,113,102,233,243,194,193,193,241,241,3,33,241,224,241,42,137,194,9,182,67,86,104,103,71,33, +43,184,170,44,100,133,195,199,188,19,178,194,201,32,207,177,93,108,25,166,51,242,212,88,53,157,66,206,44,245, +93,13,102,86,88,6,75,58,99,247,69,57,58,163,195,146,178,156,78,233,152,78,232,156,14,232,136,46,24,143, +253,244,217,65,183,227,143,9,195,4,17,247,160,48,224,212,63,101,46,19,210,29,161,100,122,215,32,222,115,61, +2,27,194,136,176,229,25,130,120,180,42,158,38,9,138,84,199,99,12,1,19,38,98,155,22,32,71,118,156,244, +38,167,227,222,120,111,47,113,230,198,102,103,139,88,198,35,102,251,227,203,164,223,190,164,163,126,231,50,233,46, +98,63,64,231,205,230,124,61,84,23,33,113,205,87,7,9,184,142,138,184,209,73,150,57,155,134,132,190,28,176, +60,117,94,217,187,30,139,2,226,6,238,48,40,39,243,36,73,157,99,150,219,103,113,78,23,116,148,250,83,15, +157,37,244,78,145,131,20,252,127,136,232,205,188,190,118,24,108,0,106,83,235,19,236,193,97,246,80,130,229,199, +39,29,111,77,175,185,29,167,19,254,149,138,170,41,100,239,190,64,86,70,45,183,233,202,216,159,181,207,84,172, +247,128,182,147,174,136,53,133,106,115,120,242,144,155,242,167,71,193,148,125,45,228,235,65,111,168,157,206,65,48, +230,99,128,193,170,196,129,186,196,129,167,39,135,161,196,57,57,202,56,73,30,38,216,89,43,173,12,21,77,218, +122,187,162,115,108,142,10,53,224,5,29,96,19,165,239,207,201,51,54,63,147,221,193,153,236,79,46,111,111,77, +60,161,55,203,164,27,151,93,108,214,135,56,58,243,71,213,161,59,166,66,82,154,55,244,135,151,212,166,82,149, +198,251,45,216,51,180,80,21,59,127,161,57,27,55,155,227,210,22,146,110,206,102,14,88,179,34,158,159,13,187, +147,189,120,112,70,82,210,37,255,194,42,96,136,72,16,121,6,121,66,27,186,217,44,227,38,70,142,220,111,20, +156,166,174,254,243,36,220,3,245,178,120,74,243,100,25,35,79,99,62,185,189,205,155,205,220,55,147,102,83,224, +28,113,109,226,171,57,238,8,67,193,88,127,244,240,165,249,3,90,203,214,180,246,228,105,85,147,41,23,5,51, +110,99,82,250,31,161,100,37,33,146,248,202,242,254,226,252,246,118,151,29,227,198,34,41,233,217,85,35,146,153, +129,200,29,127,50,75,234,187,169,13,11,181,253,14,106,139,16,42,177,121,120,233,244,218,144,73,48,89,215,197, +116,92,71,161,90,140,3,171,120,137,4,57,139,165,51,68,153,150,103,31,131,78,50,141,227,187,4,147,214,55, +255,138,74,152,15,111,127,98,36,8,36,44,124,171,148,117,196,36,97,194,82,18,125,211,34,201,114,117,93,209, +215,151,97,146,175,192,250,226,50,73,63,43,33,99,242,73,34,116,13,186,54,184,226,95,213,87,28,142,137,120, +38,193,100,124,10,49,200,76,229,72,217,247,238,6,91,73,144,54,254,225,221,155,159,211,242,0,41,134,11,92, +136,255,160,33,146,213,33,111,138,51,142,23,119,69,218,197,110,33,202,138,180,245,217,40,217,219,184,51,239,13, +184,129,227,35,186,98,27,144,169,90,46,171,97,29,152,222,229,170,117,94,13,113,5,86,39,195,221,181,217,182, +54,214,130,19,208,58,60,65,255,224,242,140,252,207,4,114,193,107,90,220,40,146,115,67,146,53,234,150,36,233, +234,101,18,68,238,10,100,72,197,122,60,241,151,3,119,15,222,214,223,186,245,251,254,10,202,250,147,119,56,90, +223,44,157,173,201,213,149,150,96,237,158,120,230,201,47,189,165,39,48,81,85,165,172,27,70,157,99,146,234,57, +84,13,198,17,177,114,197,4,186,234,50,160,48,136,194,60,179,97,189,9,235,51,20,222,202,192,250,6,73,144, +205,166,234,103,136,14,93,33,214,136,43,115,194,112,31,70,54,212,194,101,30,213,162,112,0,73,215,131,233,4, +69,48,157,25,87,81,58,135,4,239,148,143,135,237,191,113,202,16,49,66,4,87,107,229,139,8,101,90,136,242, +60,63,206,125,148,39,65,227,132,102,236,45,140,206,191,78,215,130,109,193,50,228,138,206,152,216,113,214,35,45, +222,26,144,6,43,202,28,92,221,86,116,221,249,110,88,240,145,233,146,1,89,58,127,163,67,132,113,175,34,13, +102,122,241,12,227,15,6,69,25,223,217,205,208,237,162,207,50,21,59,13,185,195,112,56,229,84,14,238,124,199, +166,126,35,42,195,228,234,94,11,37,191,113,26,44,247,194,211,64,76,252,18,34,100,148,37,103,60,212,22,93, +93,59,16,217,131,61,247,149,203,132,222,204,164,225,195,112,3,124,112,124,112,252,143,148,16,14,134,84,149,117, +224,48,212,196,161,62,230,107,199,109,195,196,195,245,113,237,170,216,116,124,171,116,216,67,59,5,228,7,80,63, +205,166,142,157,244,110,208,152,134,98,52,219,184,106,191,231,144,181,44,99,253,160,13,127,99,86,27,177,247,81, +235,155,198,163,232,155,232,227,12,240,81,42,154,31,164,199,105,167,227,70,208,88,163,131,118,231,104,31,63,39, +209,249,156,203,8,223,151,220,204,91,240,239,39,121,228,174,247,53,238,14,209,235,239,223,71,63,137,12,164,129, +20,65,90,143,124,20,9,41,107,168,1,254,130,24,211,254,70,162,89,209,191,82,50,6,120,231,179,174,181,30, +146,183,33,27,56,223,108,122,239,222,128,20,53,100,163,189,137,132,175,77,117,54,167,76,61,181,35,42,97,202, +145,179,201,0,244,214,160,241,79,18,91,131,131,242,44,178,62,90,239,147,173,241,17,104,223,249,150,176,116,194, +43,216,157,219,238,224,216,181,16,103,53,202,213,197,89,185,204,95,52,23,193,25,106,34,134,59,86,148,174,116, +223,138,188,54,214,169,75,88,23,133,226,182,190,161,168,115,196,41,107,55,155,190,246,29,22,74,233,24,18,68, +136,22,45,204,133,123,163,133,13,172,211,154,14,175,224,221,117,132,77,209,184,228,125,115,254,148,94,163,28,111, +201,23,33,207,8,233,150,119,15,194,248,191,8,114,123,59,243,251,217,149,60,29,223,103,219,201,156,250,60,116, +144,116,87,156,214,59,77,118,138,164,78,151,194,252,204,127,70,254,207,108,23,234,85,243,178,180,10,25,72,239, +122,18,162,210,213,208,211,66,216,152,80,31,109,218,61,245,76,134,52,165,48,77,233,190,187,222,112,217,108,37, +249,179,29,229,159,238,59,6,127,82,215,160,95,114,3,113,130,143,48,187,193,46,151,203,121,76,76,161,44,205, +66,109,227,235,90,31,251,6,12,39,191,192,130,106,24,82,7,228,63,251,38,83,83,160,194,144,53,151,30,213, +247,157,21,193,171,66,50,21,50,135,175,111,134,49,148,175,94,167,251,157,80,71,150,252,102,16,107,218,73,150, +222,246,23,236,111,94,122,234,61,175,55,30,136,214,159,128,86,32,95,107,109,237,122,132,219,241,210,81,198,124, +192,26,49,204,74,204,253,174,207,44,206,87,84,94,177,214,126,252,233,58,105,141,232,23,246,117,87,73,139,188, +105,152,22,28,153,187,162,241,206,39,45,56,115,126,253,97,58,13,106,234,18,76,177,62,199,254,116,47,82,87, +57,62,183,113,59,217,92,186,103,171,171,246,142,95,255,154,181,62,189,136,251,207,247,255,184,116,52,190,252,91, +26,95,83,178,255,239,14,73,54,237,6,81,213,226,254,92,18,191,234,235,90,92,171,247,151,96,172,65,116,103, +242,180,115,182,235,157,166,91,63,243,212,237,100,117,229,150,94,149,136,88,176,38,170,107,165,190,219,144,162,45, +95,47,33,241,138,121,195,46,42,176,218,128,60,192,217,187,238,231,154,151,231,37,10,96,112,123,219,174,110,18, +195,86,251,64,37,115,55,1,101,212,208,73,117,67,161,247,247,19,233,237,160,175,247,160,54,143,154,176,247,91, +94,94,30,107,173,91,179,110,80,182,94,241,115,108,107,120,192,98,151,106,244,122,93,23,167,122,111,207,35,104, +54,223,163,172,92,171,14,186,53,154,243,144,236,189,12,190,223,186,106,170,147,223,146,254,197,118,153,193,178,150, +204,191,107,71,94,123,81,108,4,33,185,68,134,226,201,42,103,110,104,119,189,23,128,176,78,115,111,9,171,168, +89,191,119,66,178,186,165,85,108,59,42,83,177,53,84,226,86,152,62,66,160,8,242,112,36,85,77,23,197,97, +14,122,177,110,217,53,179,37,35,78,94,203,196,163,219,168,32,95,113,139,217,9,182,135,234,237,70,96,223,139, +9,196,62,143,213,61,79,215,237,237,214,45,52,15,193,5,99,165,113,12,153,141,1,88,169,140,215,108,152,21, +27,252,14,27,27,76,32,11,129,143,112,57,93,172,105,180,54,130,87,155,214,183,195,144,144,248,128,48,169,143, +242,101,99,191,83,99,250,165,142,154,200,225,221,247,87,112,17,17,147,16,13,158,237,138,208,218,185,67,144,188, +96,196,255,64,200,128,70,6,247,53,184,146,17,114,66,63,176,62,89,75,55,36,23,26,16,247,28,176,61,20, +133,5,77,46,233,239,8,52,0,228,6,94,186,144,237,230,50,215,112,8,170,137,215,106,230,215,79,240,239,250, +248,135,105,94,46,152,249,70,61,241,10,140,213,106,225,182,44,91,126,142,187,189,43,184,28,214,123,160,181,194, +80,56,69,1,248,126,201,201,47,26,134,128,122,64,34,223,178,27,53,117,82,121,13,122,4,104,236,184,112,36, +192,116,119,229,119,35,10,228,215,189,254,78,181,202,103,94,154,239,197,212,13,228,48,183,74,21,198,79,130,70, +90,39,206,44,93,215,211,240,29,151,121,1,186,235,16,209,107,174,229,198,128,24,73,133,4,86,239,82,198,189, +211,162,225,189,84,249,61,132,8,243,22,60,43,249,123,62,234,126,191,214,127,110,173,246,3,31,228,23,169,174, +101,133,18,135,208,5,16,216,95,57,77,57,82,118,78,125,249,243,75,193,173,163,182,154,235,254,69,39,51,99, +63,24,255,84,136,203,252,143,229,220,233,229,170,16,67,200,22,89,1,223,41,245,197,116,127,95,210,23,172,197, +247,255,194,28,245,105,214,110,191,120,226,190,47,219,251,238,207,171,99,255,125,234,59,23,199,254,235,59,135,79, +94,249,239,5,118,58,23,23,23,159,102,7,184,104,223,255,121,229,190,135,23,190,115,212,118,223,39,109,215,233, +60,117,96,47,219,190,115,113,142,157,195,118,187,131,157,87,79,28,130,139,19,63,115,241,234,229,133,251,94,184, +14,98,126,213,170,99,226,127,107,127,136,237,30,33,137,207,194,78,190,62,19,7,15,57,60,102,204,37,148,147, +199,238,111,237,78,223,58,199,44,175,62,238,253,93,85,248,113,146,166,235,191,245,105,72,122,173,133,13,39,192, +173,19,225,178,76,121,223,185,100,85,21,242,49,233,255,47,217,123,81,157,170,247,72,250,239,171,79,159,242,203, +245,74,237,215,234,29,169,241,157,127,129,194,94,224,109,85,125,166,228,110,105,100,183,35,11,172,71,22,143,208, +86,49,165,103,49,69,186,144,117,185,172,223,157,60,169,31,233,111,140,92,93,249,204,124,117,69,132,196,132,247, +7,219,241,83,177,240,203,5,250,195,238,217,95,127,59,151,115,161,149,116,214,137,89,167,177,49,144,78,43,171, +164,127,178,31,154,205,221,115,155,149,14,253,145,253,17,126,38,145,74,62,23,35,247,88,154,206,12,232,231,35, +183,108,19,218,90,246,99,179,217,154,24,1,183,86,139,28,33,90,165,56,127,76,40,248,201,31,87,117,47,113, +96,209,73,218,38,201,105,155,234,237,89,200,71,208,242,83,210,178,120,115,14,189,92,43,225,46,119,220,118,171, +39,69,158,87,239,138,202,172,182,197,35,40,118,221,33,233,207,132,170,18,83,43,27,107,53,129,79,173,79,249, +94,77,159,155,152,142,185,180,106,242,217,212,195,126,231,137,79,48,173,161,208,48,84,95,63,181,98,92,153,180, +146,132,10,235,126,107,114,237,166,41,183,46,47,160,202,255,72,66,86,55,110,186,183,219,188,141,165,100,202,141, +17,115,184,251,99,1,110,253,235,107,66,43,217,243,60,63,159,131,180,63,9,99,65,130,142,137,163,111,127,181, +222,7,60,99,67,42,252,194,171,162,39,179,117,101,115,247,114,225,99,179,25,127,100,13,84,113,3,13,98,167, +73,249,59,200,190,187,121,207,192,24,130,21,87,21,238,157,72,215,39,82,144,243,244,227,135,243,171,243,159,63, +162,96,62,46,105,97,215,140,231,234,202,205,189,58,255,248,254,205,155,159,222,93,125,251,211,155,23,207,127,186, +250,238,205,155,31,175,174,214,78,239,182,174,191,118,158,112,81,71,146,187,156,24,185,187,231,74,75,245,185,53, +78,74,231,31,90,154,91,246,224,143,45,113,171,178,153,220,195,249,91,24,22,144,89,15,89,181,83,140,253,63, +194,194,96,220,184,15,59,148,11,240,111,114,246,110,83,167,43,46,109,28,30,72,193,254,31,99,95,194,29,183, +141,252,249,85,70,253,188,27,114,13,107,236,188,155,109,76,191,196,113,102,146,141,115,223,94,143,30,221,13,89, +140,187,65,13,136,150,227,72,218,207,254,175,31,10,71,241,144,198,57,212,32,136,179,0,20,234,230,18,3,150, +240,195,132,219,43,43,57,145,233,196,166,192,183,42,81,7,155,102,84,71,20,196,238,26,149,165,27,168,117,165, +244,253,3,164,170,183,21,51,195,151,94,63,87,23,30,186,82,63,171,222,145,98,202,63,124,168,184,173,227,235, +129,68,201,183,235,195,100,140,63,28,95,207,135,137,210,44,33,246,212,221,168,138,51,135,254,202,76,107,189,169, +114,61,53,171,178,51,151,198,238,228,248,14,172,174,195,114,229,36,6,243,153,185,12,13,77,91,176,189,39,33, +136,158,201,110,115,167,201,166,107,93,248,150,199,170,176,79,107,243,212,173,77,96,91,204,171,83,166,192,42,116, +146,58,215,128,108,0,233,149,39,48,149,51,241,218,135,123,214,39,104,136,42,130,101,122,227,43,46,212,95,86, +178,200,149,127,121,149,89,184,39,175,88,152,224,167,90,119,152,193,118,170,85,67,132,190,111,223,36,173,61,104, +85,109,56,189,37,142,111,231,140,213,142,159,189,249,147,198,205,105,179,63,232,158,147,118,208,140,98,98,173,222, +134,130,29,63,158,219,103,156,33,10,33,247,155,64,49,14,147,220,31,32,85,249,98,39,115,193,62,104,240,41, +72,112,78,38,155,83,35,237,36,255,139,200,209,140,218,33,82,141,94,141,178,92,251,142,144,56,167,187,225,7, +79,184,102,43,50,160,113,163,166,140,3,122,78,153,164,254,194,21,42,138,61,219,83,167,59,145,241,13,186,78, +143,129,248,251,188,133,113,199,123,61,136,188,23,198,183,114,52,224,252,144,255,45,100,17,23,253,126,103,156,6, +183,250,142,110,149,176,20,205,68,26,14,171,163,119,158,151,9,220,217,2,238,95,6,203,237,162,185,117,103,134, +234,189,56,4,212,49,31,122,90,59,121,244,242,125,194,10,171,213,138,75,25,80,96,180,217,132,230,13,171,238, +149,145,64,123,172,140,224,179,207,188,96,192,185,122,21,33,50,254,41,210,214,114,6,222,134,202,178,235,202,99, +43,43,31,118,177,138,144,113,144,159,150,116,58,184,202,135,241,41,143,173,140,178,189,229,231,217,238,162,44,185, +134,69,244,128,157,239,233,143,50,101,243,248,156,164,92,236,92,143,191,35,24,248,146,86,70,156,15,95,210,202, +136,19,226,75,90,25,113,70,124,73,43,35,182,148,47,105,101,196,246,4,232,1,173,175,60,75,26,196,74,191, +152,226,253,175,124,173,158,121,98,62,129,133,160,138,239,47,193,249,93,116,231,30,28,165,77,41,150,92,34,209, +59,60,59,112,241,131,89,189,90,63,11,134,7,207,91,34,79,22,188,65,190,194,173,180,254,103,245,194,43,63, +83,145,57,216,69,205,229,105,81,2,101,73,2,229,224,25,146,223,211,3,235,73,85,167,141,100,198,29,180,82, +72,17,61,210,191,38,202,35,26,132,123,54,8,231,201,53,72,230,41,53,189,118,235,215,4,132,183,107,228,167, +9,34,59,238,156,143,107,126,159,174,237,30,194,139,254,117,32,147,88,114,211,83,183,184,131,226,45,66,123,173, +99,137,102,24,229,31,254,30,67,6,2,72,173,126,192,57,41,135,228,155,176,207,41,147,245,34,159,248,249,245, +25,216,166,136,194,209,115,56,15,135,248,124,117,120,6,209,0,221,79,224,193,86,12,138,149,98,37,228,84,12, +181,169,126,221,252,232,169,28,13,164,249,154,19,234,15,95,115,83,114,154,56,140,77,200,125,215,238,223,210,147, +56,215,104,129,237,247,50,159,35,121,193,208,174,81,174,112,83,150,70,7,16,199,149,182,79,251,181,77,26,233, +78,59,172,48,6,223,41,3,107,134,91,33,244,243,194,94,3,212,248,54,232,54,38,150,179,239,125,22,245,188, +19,48,8,74,16,78,203,210,159,248,141,211,233,5,169,63,168,185,173,175,168,112,181,172,74,169,179,73,121,55, +60,255,211,27,59,192,189,143,199,65,205,116,3,233,22,169,178,99,121,170,71,13,69,25,142,254,139,139,3,170, +73,200,118,191,240,229,162,78,48,136,43,218,254,55,27,108,212,100,169,100,75,82,73,24,9,182,167,242,218,224, +246,6,24,5,180,104,68,109,57,57,24,191,30,48,211,155,155,143,81,105,114,248,160,250,7,67,27,77,18,246, +250,132,246,61,1,223,213,235,15,118,147,186,95,151,27,49,195,176,25,138,6,59,161,90,65,190,85,93,36,239, +232,88,237,233,113,143,199,146,53,145,161,210,18,124,230,233,7,16,191,85,131,236,48,66,194,78,122,52,90,107, +82,118,152,147,160,186,179,39,225,41,2,166,218,110,182,69,193,210,56,109,84,6,132,161,83,158,15,60,237,80, +185,73,255,242,197,168,123,182,135,200,170,138,42,207,100,188,201,156,174,74,57,176,122,207,170,34,163,158,0,187, +177,9,18,36,236,216,164,156,154,104,142,74,211,88,61,237,168,14,79,59,109,240,4,227,180,83,73,3,77,243, +78,27,115,227,26,187,169,104,67,218,104,123,104,208,175,29,163,55,87,55,85,106,93,92,208,15,194,180,239,155, +180,156,79,205,214,157,225,32,151,193,149,81,201,227,114,115,195,106,47,90,255,157,217,27,111,194,228,20,138,140, +70,86,75,201,176,151,226,155,76,26,58,194,60,182,208,237,238,169,13,178,28,163,89,68,12,186,147,135,82,82, +31,180,227,110,63,145,252,4,80,164,94,18,35,153,169,212,124,65,174,244,133,207,82,124,53,106,85,162,227,89, +235,247,48,37,180,93,217,127,34,108,133,111,189,254,254,116,81,128,91,16,250,231,101,41,79,132,131,85,234,39, +178,20,122,231,55,19,222,153,32,209,140,213,0,170,165,25,182,79,187,52,168,22,42,93,221,145,125,82,198,203, +39,193,218,165,178,188,6,189,54,248,193,138,187,122,131,19,73,39,238,88,217,26,127,123,250,75,131,3,162,108, +194,49,115,148,170,23,148,76,63,229,51,24,223,185,205,4,247,88,189,36,131,48,27,195,71,222,97,155,27,213, +47,150,242,27,47,74,249,162,250,75,99,235,111,27,179,241,11,94,130,84,224,190,110,153,144,193,31,116,126,111, +215,162,164,175,169,187,70,204,254,55,121,77,106,140,196,23,59,187,102,186,133,55,166,161,237,81,166,225,54,223, +3,211,55,226,138,250,94,158,166,104,201,62,215,181,60,130,165,137,201,146,60,44,39,173,87,180,5,187,75,143, +247,105,190,253,120,188,253,132,54,141,54,50,165,234,230,199,170,87,6,48,254,150,73,255,114,22,166,75,158,119, +65,51,50,220,60,17,112,247,13,23,162,195,246,219,50,9,251,109,16,169,252,230,161,99,254,233,238,34,15,87, +36,39,211,159,134,98,223,122,150,26,206,56,241,172,100,236,152,155,98,172,84,43,147,178,76,206,42,7,239,14, +120,20,241,51,160,82,76,7,179,213,32,174,7,192,202,83,251,201,90,176,39,130,74,13,218,208,15,12,176,78, +198,123,161,5,138,109,53,29,206,90,161,164,110,55,109,218,56,195,100,227,80,198,134,212,46,67,22,120,247,183, +152,55,28,210,7,77,9,246,198,8,201,206,98,2,72,129,217,58,122,179,91,6,204,124,58,247,24,48,240,204, +128,178,121,63,168,220,255,21,201,166,245,79,62,52,241,221,88,26,50,151,146,98,7,72,30,245,159,163,163,19, +231,3,88,59,206,139,194,20,0,122,118,209,57,82,43,88,237,230,12,76,31,104,90,53,55,183,234,65,225,232, +183,129,135,0,188,175,145,31,20,92,68,81,224,130,252,27,108,203,209,112,54,228,196,170,58,180,8,187,70,212, +29,98,93,96,199,77,223,112,19,253,237,58,84,127,188,78,75,210,138,203,241,95,147,73,242,2,201,89,230,204, +229,137,150,241,176,197,142,19,22,59,48,24,8,22,59,215,112,128,106,144,198,96,228,92,228,14,117,105,107,58, +236,73,203,51,105,107,58,229,92,191,187,85,109,221,112,154,230,192,179,18,115,249,69,200,5,252,105,86,171,134, +53,51,245,196,46,65,154,186,72,236,42,189,97,241,82,95,195,126,162,177,138,101,121,141,29,17,120,63,75,2, +111,17,157,135,147,108,226,53,75,11,68,187,10,229,213,191,226,47,13,218,224,136,159,158,193,14,26,165,79,13, +88,137,221,16,208,2,119,144,178,168,66,77,79,135,238,207,142,218,170,199,76,84,202,159,242,82,185,17,126,141, +237,231,152,152,143,187,23,205,116,236,43,63,84,93,93,158,77,141,187,183,35,110,135,243,139,221,96,198,208,132, +239,44,153,7,127,231,215,45,37,96,226,138,246,77,232,68,217,44,226,110,11,200,126,245,163,147,62,63,9,46, +181,13,82,5,107,247,174,234,49,241,132,92,176,98,40,128,29,239,234,84,160,19,5,58,46,208,234,175,170,46, +23,104,69,129,150,11,12,154,26,163,209,163,6,253,69,118,44,50,136,53,254,125,118,45,193,251,10,126,132,239, +42,167,124,48,128,69,198,160,189,73,62,89,170,63,197,108,66,231,3,76,190,232,183,35,36,139,129,228,224,0, +117,221,66,147,148,14,196,10,48,32,222,173,165,159,103,89,49,185,69,171,44,5,203,141,86,219,167,143,105,77, +158,110,25,73,195,186,91,184,198,233,150,244,74,250,203,64,127,40,159,216,182,31,252,154,228,9,84,84,17,17, +216,214,138,30,246,75,203,243,101,217,209,128,155,145,195,77,103,230,52,102,101,106,11,236,244,131,184,197,25,201, +144,61,9,93,42,121,72,75,175,9,244,197,47,5,132,127,120,67,185,27,145,110,238,56,155,171,207,197,21,254, +31,95,25,6,205,198,102,142,206,138,37,164,2,50,126,131,84,36,37,157,223,191,255,223,240,127,114,121,50,110, +131,222,175,16,26,134,252,65,96,159,150,75,252,95,47,47,17,238,64,243,72,4,35,228,77,161,158,167,180,86, +220,141,104,9,14,7,155,199,205,163,39,249,198,102,230,196,76,153,19,106,7,197,65,21,251,123,109,88,140,73, +171,72,106,5,182,62,162,186,5,235,165,27,73,219,211,7,44,30,79,123,219,150,149,26,217,127,4,219,159,137, +31,66,47,157,16,138,75,109,48,51,198,153,226,181,176,138,135,130,22,218,56,104,161,191,180,134,126,148,157,152, +155,252,237,130,236,36,86,240,42,178,105,42,183,36,102,160,246,222,95,67,7,34,22,215,153,153,208,132,39,172, +157,48,190,147,134,118,10,71,177,203,2,154,75,194,18,156,113,17,236,74,118,65,216,192,35,156,219,13,50,112, +209,25,185,40,87,36,246,56,116,131,249,123,144,188,214,193,37,71,149,134,112,52,197,84,77,156,106,159,15,94, +87,166,97,141,56,120,223,159,74,195,23,233,50,63,126,19,33,12,173,48,87,22,189,189,109,217,206,186,231,94, +81,102,197,146,152,81,19,52,230,62,117,45,76,207,229,104,88,115,124,115,35,84,161,229,48,82,147,3,225,188, +232,126,233,215,241,153,251,128,116,48,172,136,81,109,208,140,12,129,99,216,34,93,238,147,189,33,182,136,243,88, +219,54,24,150,185,194,188,100,72,167,64,63,150,58,183,181,41,28,71,210,183,85,1,15,46,42,108,227,58,5, +165,109,76,71,124,118,52,154,51,160,113,164,145,95,5,67,55,35,117,42,71,19,172,177,43,154,165,130,193,197, +192,6,113,61,181,245,188,190,13,51,123,156,105,52,239,239,0,212,139,163,111,209,224,55,204,188,195,118,144,26, +152,230,214,37,18,196,172,198,179,226,46,252,10,115,155,190,151,250,241,206,44,107,174,105,236,95,28,130,59,147, +103,104,200,140,90,242,169,242,5,166,62,10,101,35,64,176,55,138,118,121,17,226,156,27,13,147,46,8,46,103, +51,8,32,188,52,58,5,19,136,244,252,143,68,223,124,221,239,210,69,87,157,27,98,229,119,89,206,81,93,26, +117,13,163,163,118,235,141,195,221,17,236,127,212,120,149,168,95,170,248,240,73,253,191,62,166,46,152,31,44,237, +197,101,18,70,243,102,34,64,30,34,123,42,181,18,88,207,112,250,18,238,152,31,103,163,86,214,252,73,208,216, +18,190,226,93,224,130,23,75,192,5,91,3,233,33,122,166,209,86,148,113,66,251,231,190,29,90,11,165,88,204, +154,32,33,237,111,163,249,195,129,129,124,238,203,81,186,50,40,243,26,115,59,16,168,15,81,227,95,137,163,253, +90,78,92,89,53,51,73,101,134,178,58,233,33,252,12,194,238,44,229,254,220,245,127,25,27,242,102,114,118,0, +43,137,239,146,240,218,75,201,89,23,46,145,96,227,80,101,114,109,29,108,3,232,25,71,151,240,119,145,90,9, +195,99,26,50,75,229,24,192,215,118,46,60,179,119,212,178,84,15,21,163,13,214,27,163,255,92,210,75,173,254, +55,78,170,48,48,95,123,109,54,197,172,188,241,209,4,120,245,255,231,5,221,172,32,100,74,39,211,130,137,90, +210,118,84,94,93,195,159,140,126,123,216,60,58,181,229,43,176,177,42,154,253,16,87,58,50,69,127,111,102,182, +232,60,13,95,164,247,10,220,231,185,29,214,115,210,195,22,202,193,84,150,47,134,92,15,219,249,234,17,142,71, +186,29,214,133,191,43,58,212,133,251,159,26,195,157,207,237,249,89,59,197,186,29,195,210,94,170,61,222,165,27, +188,135,109,66,164,123,213,30,110,215,161,247,45,51,39,123,226,8,182,240,224,51,248,57,215,111,76,181,173,21, +161,101,218,141,149,173,142,245,166,162,7,52,15,186,152,75,107,2,214,158,218,164,33,87,231,167,128,176,120,215, +82,22,96,79,93,157,159,70,176,83,73,183,144,77,41,94,13,78,185,246,64,109,54,240,100,58,82,123,199,48, +167,189,10,173,30,235,186,140,218,212,182,66,46,122,77,35,238,83,251,152,135,232,89,122,110,24,233,60,221,174, +199,135,141,37,70,44,242,58,5,161,68,243,23,79,250,58,169,28,7,230,161,132,35,22,29,176,101,171,101,245, +166,106,49,11,181,173,111,45,36,58,45,64,135,145,55,125,53,68,160,118,148,58,64,84,188,35,88,183,154,234, +227,69,246,240,108,184,206,160,168,150,106,99,73,160,62,140,66,11,38,227,108,52,189,174,240,199,69,200,114,98, +129,35,120,250,52,33,5,117,120,235,189,163,198,165,44,134,198,70,171,223,163,247,180,79,247,128,123,23,47,119, +226,164,72,80,244,214,84,173,226,29,117,242,152,202,135,231,129,159,159,8,46,72,216,24,20,162,146,154,10,29, +153,58,243,68,133,27,205,238,13,170,187,185,137,42,9,60,82,63,235,88,216,78,11,219,113,97,139,194,113,12, +39,130,134,255,42,160,242,123,72,158,153,48,6,96,206,157,77,84,253,81,120,23,23,159,104,48,191,36,44,127, +97,4,157,11,204,186,121,25,76,53,94,53,51,125,241,31,40,218,48,255,86,26,120,102,102,238,109,244,23,22, +23,72,182,149,176,129,16,219,253,143,209,149,20,151,10,214,81,152,253,130,120,185,101,5,129,173,218,122,209,247, +176,197,165,171,143,217,30,74,237,245,17,103,109,42,227,220,180,177,200,63,30,7,78,154,198,209,170,202,80,155, +8,164,116,182,122,232,200,26,130,242,94,62,198,1,166,212,30,231,24,77,105,2,203,62,76,235,33,222,134,20, +246,124,48,38,192,61,127,12,167,34,130,251,8,233,67,51,160,199,208,200,102,218,4,156,159,78,52,20,178,92, +175,162,119,168,130,206,209,243,98,37,238,180,169,186,138,149,101,100,52,202,240,110,97,13,67,41,130,15,110,200, +144,7,188,199,143,176,65,190,218,83,89,114,14,230,73,62,164,156,85,26,50,250,205,91,227,40,252,142,140,148, +174,73,118,30,82,214,53,17,147,24,70,124,220,221,175,82,161,81,75,54,249,27,209,244,39,166,18,173,179,228, +17,123,21,237,67,128,241,164,86,99,181,210,92,14,15,209,101,80,157,185,236,58,162,88,246,33,250,252,164,176, +230,254,191,186,38,46,233,183,252,88,191,229,23,93,22,35,126,131,223,34,208,129,208,115,117,217,107,31,140,50, +100,154,106,200,124,249,16,198,53,20,112,146,125,173,124,196,118,186,134,148,84,139,76,136,175,216,64,101,160,236, +200,214,223,2,149,14,64,21,89,142,131,187,148,170,38,241,18,210,69,160,67,15,139,75,151,21,224,166,110,182, +89,244,90,98,68,21,11,16,33,242,240,196,226,100,135,72,46,43,180,18,14,104,157,69,151,254,14,251,143,32, +76,108,117,23,238,54,0,16,22,11,124,13,228,4,209,36,61,93,136,17,157,202,76,213,37,227,46,214,233,119, +176,179,42,25,52,184,54,121,93,183,161,66,93,185,8,9,26,121,73,19,34,170,107,62,27,157,80,86,15,177, +150,218,6,9,60,213,192,15,10,175,87,222,28,96,105,111,0,193,14,167,113,179,149,248,96,171,186,108,151,118, +115,67,53,154,109,106,159,64,41,239,49,71,38,79,251,87,209,71,234,107,83,231,137,34,59,171,233,132,133,141, +196,191,2,217,18,41,63,182,102,35,28,247,55,140,142,113,179,176,171,49,41,30,110,178,172,154,28,183,132,48, +97,97,181,57,161,86,31,12,209,69,163,83,131,102,81,32,149,197,106,249,196,19,88,120,244,236,187,191,204,46, +95,133,50,51,174,44,204,15,88,3,60,192,22,35,52,67,227,134,176,134,30,136,107,248,58,212,200,28,82,222, +73,129,210,234,177,157,124,13,98,139,56,172,7,56,99,136,93,129,16,24,192,155,95,192,214,96,171,240,186,142, +108,26,235,200,36,180,77,29,126,122,90,203,158,224,171,255,66,165,189,80,43,223,109,240,51,158,166,238,73,210, +15,89,111,4,206,74,181,49,3,147,90,169,33,62,149,89,173,84,87,171,94,152,2,141,72,36,59,179,72,158, +25,234,108,18,97,55,38,232,235,198,33,252,64,158,193,29,158,247,51,5,32,174,126,255,170,9,4,129,2,193, +201,98,220,100,20,244,68,60,209,146,19,160,197,197,190,97,170,160,145,129,110,9,75,253,73,171,121,143,205,80, +8,166,172,238,179,28,2,207,111,133,117,77,68,53,115,23,61,25,222,87,152,165,140,25,95,182,132,198,222,155, +91,119,73,173,132,12,43,236,132,107,108,198,108,1,137,117,18,137,117,64,98,108,172,104,88,35,98,235,34,231, +231,168,10,247,183,29,26,165,150,188,108,201,62,124,34,27,2,111,14,204,190,243,88,129,24,41,58,69,58,36, +252,14,115,202,40,253,159,191,174,16,214,115,31,98,144,85,117,138,66,118,228,200,99,142,145,145,169,142,209,246, +199,165,169,202,74,124,136,48,242,153,7,168,156,74,59,1,83,59,5,19,225,81,64,40,65,11,202,204,1,211, +204,68,164,3,127,135,201,80,195,153,208,1,91,225,132,145,79,60,46,2,113,177,1,232,131,224,175,191,251,129, +16,245,0,211,211,110,67,77,145,236,13,119,79,176,205,251,177,250,177,194,3,172,153,112,135,119,161,63,88,21, +164,6,98,85,202,140,106,165,96,110,132,236,52,198,118,195,69,153,106,136,110,131,85,185,5,212,53,74,147,210, +146,45,66,138,171,169,196,214,80,140,161,149,68,252,36,111,208,97,165,60,179,45,127,149,154,159,143,247,254,236, +236,194,0,99,20,124,160,9,119,158,48,139,153,75,205,201,26,40,57,78,190,52,52,93,151,151,32,224,230,147, +209,235,13,141,160,39,168,53,29,82,157,130,198,101,243,172,178,53,186,153,177,5,191,141,122,11,218,101,108,96, +250,73,18,251,169,90,57,172,205,215,40,192,64,47,8,176,101,189,225,118,79,252,120,84,153,173,66,120,253,248, +240,26,20,44,173,190,188,169,125,34,26,98,34,104,139,214,29,76,252,190,63,21,62,155,33,246,12,81,233,158, +14,194,1,25,3,109,189,242,0,206,186,137,77,224,5,167,144,203,94,88,250,45,84,107,123,98,58,219,40,68, +219,50,51,10,35,189,125,74,86,176,121,210,142,254,168,62,9,161,105,132,189,165,38,241,131,246,214,199,151,171, +168,113,94,61,164,210,35,9,32,170,195,169,112,61,49,5,104,171,129,79,229,2,103,247,189,68,126,209,54,122, +8,246,234,63,58,99,48,155,89,94,56,113,54,40,55,83,131,216,6,102,99,155,138,179,245,104,195,158,114,221, +239,131,167,243,231,22,103,134,105,70,110,217,133,252,111,113,15,176,144,136,13,145,191,51,149,133,1,24,87,38, +226,248,161,7,83,174,108,45,44,131,204,196,160,135,42,121,84,130,64,7,85,12,98,224,6,94,6,49,112,113, +90,84,158,59,74,223,99,134,41,181,232,107,91,248,76,160,38,160,110,25,98,62,33,108,206,255,103,196,237,204, +69,89,229,34,106,254,231,76,157,82,178,174,139,159,64,16,140,176,147,139,242,201,121,196,9,211,140,66,73,27, +156,150,35,253,228,245,195,54,193,159,77,64,94,72,213,141,160,102,172,48,114,136,38,39,93,144,60,172,145,214, +253,166,196,250,130,234,156,76,43,238,218,55,191,20,196,202,1,35,174,51,189,231,74,127,204,250,248,5,214,199, +131,245,25,195,188,171,55,212,106,199,230,88,29,206,67,162,14,42,144,232,252,0,213,25,140,190,1,160,87,26, +249,73,78,195,166,25,129,58,212,150,202,8,107,140,48,214,123,92,117,245,199,210,238,99,57,6,58,90,143,14, +188,40,245,240,9,49,144,115,176,252,58,194,191,243,134,252,198,60,244,141,23,86,4,84,33,216,197,247,250,83, +163,232,215,234,3,126,6,125,129,159,189,126,16,114,189,254,44,252,254,71,63,192,79,167,63,195,207,65,127,31, +114,207,245,183,225,247,173,254,41,252,190,214,191,133,223,43,18,11,224,151,132,219,225,247,168,127,9,249,111,244, +191,194,239,78,255,28,126,47,245,175,70,168,250,35,169,15,177,43,195,37,8,215,32,23,220,235,54,137,228,214, +193,102,225,236,8,63,220,77,53,76,24,228,190,86,3,205,201,117,111,160,156,213,116,189,81,145,94,245,186,47, +185,140,193,17,120,109,127,122,6,187,175,142,84,163,136,164,118,114,92,23,223,51,175,144,102,201,222,204,17,205, +142,60,185,122,126,218,71,39,217,33,34,79,135,236,36,51,192,208,33,76,216,199,103,213,215,252,58,92,231,11, +30,83,219,120,211,223,220,128,5,58,21,100,131,74,175,52,49,183,22,56,59,231,44,59,84,69,225,234,74,180, +81,62,99,113,111,60,179,89,215,101,200,108,92,174,32,110,30,97,93,205,136,52,13,81,86,80,51,10,72,207, +59,40,117,105,94,180,64,3,123,22,109,24,105,111,231,246,121,241,96,31,93,53,168,152,167,206,75,4,168,25, +39,193,87,158,240,95,42,157,40,193,146,235,30,238,50,205,221,221,198,14,38,253,74,43,143,180,159,187,188,159, +181,79,219,88,109,193,31,238,245,32,101,199,251,130,253,143,192,152,251,122,251,242,248,74,147,197,207,81,237,21, +33,187,132,210,251,202,242,93,79,115,241,174,218,170,244,168,240,6,45,150,55,252,200,155,254,28,132,48,14,154, +85,91,213,42,144,73,106,71,99,224,187,80,104,239,207,105,206,128,34,200,249,177,172,63,219,137,152,106,135,25, +199,67,160,134,88,124,12,236,93,93,208,223,165,126,97,40,3,2,6,117,33,40,242,203,76,145,31,8,65,30, +158,166,231,245,129,208,246,5,197,169,213,212,215,37,253,206,186,139,67,185,16,64,167,162,51,58,242,173,12,9, +38,151,216,169,78,248,183,89,101,162,240,166,170,88,196,115,115,19,19,65,133,17,94,106,46,131,189,145,251,244, +238,142,80,67,48,8,99,113,252,45,225,219,47,77,17,127,243,114,24,146,57,33,34,219,194,119,10,230,206,146, +16,153,204,115,193,128,196,64,42,16,203,69,181,203,91,99,46,63,217,119,87,133,192,90,27,240,188,230,50,104, +139,131,123,68,38,71,173,94,104,87,247,152,212,55,180,225,72,214,17,66,186,84,102,19,124,20,35,49,205,129, +145,83,147,114,6,185,83,51,119,97,180,218,204,251,90,234,127,253,133,171,172,114,197,60,75,185,130,96,177,192, +25,25,215,183,170,11,190,177,205,92,141,90,220,41,221,98,39,129,127,123,193,1,107,104,177,229,35,200,161,111, +93,229,74,64,155,186,86,83,240,226,230,23,117,54,95,58,152,167,63,64,181,32,222,85,49,178,205,108,104,203, +115,30,173,38,6,52,237,111,243,153,171,12,154,110,136,224,136,109,7,68,172,156,27,11,198,156,140,240,232,248, +76,176,54,147,149,89,201,158,111,175,93,70,221,108,243,89,156,215,42,175,247,209,212,19,229,151,173,254,35,195, +128,90,22,219,182,219,161,230,17,247,167,126,231,128,184,196,55,113,138,149,216,123,188,74,99,90,51,37,119,171, +254,196,192,84,79,64,61,16,95,7,237,198,224,170,130,51,77,194,98,103,16,132,121,212,132,33,99,41,113,154, +70,216,238,83,79,140,134,207,185,47,174,191,131,130,207,162,42,126,233,129,99,59,124,99,149,108,170,125,77,224, +109,183,9,80,151,241,228,175,13,16,247,37,205,145,159,245,37,153,10,184,42,14,237,162,96,120,232,84,105,86, +131,58,36,175,224,213,213,209,60,202,171,254,136,56,11,128,235,97,117,177,89,209,195,69,96,21,140,90,244,59, +118,234,250,153,239,93,227,85,62,16,205,185,202,7,162,217,41,18,234,54,131,74,135,2,188,253,49,227,188,195, +173,192,144,189,147,103,244,154,118,92,14,164,28,66,3,49,130,253,217,210,2,80,119,252,212,24,136,198,227,110, +236,236,190,179,230,199,40,76,40,114,17,27,152,228,120,151,104,27,19,202,77,249,48,109,167,57,181,2,132,230, +30,207,167,152,115,37,25,151,206,141,149,144,190,232,155,147,170,57,250,127,56,39,53,116,41,232,183,75,142,60, +204,129,4,135,206,30,66,241,155,27,146,42,16,145,200,74,98,106,208,48,99,210,186,170,131,148,164,147,55,123, +59,2,225,248,99,75,62,252,40,19,126,132,192,49,182,60,145,19,13,163,150,60,111,123,66,227,156,8,216,143, +196,9,65,234,181,82,118,94,192,32,58,11,149,232,236,229,17,17,101,77,22,6,152,34,12,168,131,158,55,214, +8,109,173,179,158,219,162,104,100,242,161,218,0,96,134,92,24,4,193,235,118,251,118,221,67,87,56,185,219,219, +40,214,105,179,88,103,168,27,24,249,5,123,7,180,164,95,14,34,14,120,221,132,188,129,101,19,78,147,26,212, +233,143,69,20,150,136,166,18,7,192,160,155,25,248,211,145,162,191,232,162,215,22,242,0,229,178,107,74,87,181, +252,98,239,136,160,23,237,137,45,20,179,165,42,29,226,29,250,27,141,131,50,230,8,162,200,81,129,46,76,205, +104,164,96,37,47,75,178,92,72,209,25,92,79,198,108,239,8,170,106,89,31,144,228,127,78,18,194,250,58,106, +123,26,148,162,211,151,173,14,97,237,162,105,130,27,11,122,202,214,13,30,183,236,167,246,21,50,234,5,119,14, +3,94,9,122,210,43,156,107,236,31,78,157,218,1,34,167,73,60,49,246,142,251,254,116,20,154,140,50,55,17, +145,125,127,186,16,110,12,181,0,213,9,230,242,117,67,99,195,69,14,13,87,95,109,53,4,139,66,170,152,14, +61,152,18,83,231,62,204,114,91,22,52,173,83,158,222,153,96,225,65,25,134,51,50,186,155,171,213,27,222,191, +125,133,245,219,185,10,151,142,226,101,189,116,244,3,71,14,172,161,8,182,27,119,73,164,198,44,120,192,21,77, +214,116,111,236,55,69,93,1,93,154,112,142,82,142,206,55,90,46,113,30,152,164,47,31,247,41,111,178,227,225, +211,97,221,150,176,231,165,0,52,168,4,176,168,61,175,44,37,45,204,75,32,18,134,24,232,42,200,128,226,123, +76,107,139,17,75,68,117,25,208,229,150,134,19,36,146,84,234,202,228,7,133,252,32,182,76,249,252,32,108,18, +93,20,18,132,189,162,89,74,54,150,201,33,111,61,213,194,43,155,183,26,161,18,121,163,168,94,67,166,145,200, +178,181,23,172,172,73,50,185,103,113,254,129,71,30,243,139,142,50,36,55,22,143,183,228,198,10,14,129,45,141, +242,19,49,248,135,214,133,13,41,99,73,12,152,53,190,65,139,191,122,16,16,235,10,86,219,93,66,183,142,69, +136,88,252,88,40,222,205,40,152,65,240,85,202,147,21,216,116,210,169,43,199,192,44,134,145,1,250,16,212,8, +190,97,20,61,233,65,178,244,156,199,104,138,6,165,28,83,72,86,74,64,158,105,240,148,97,89,139,211,70,46, +100,186,208,85,79,73,185,148,235,30,27,127,198,206,247,76,36,136,92,133,66,57,81,242,225,59,148,118,73,207, +17,73,29,36,45,218,70,213,254,88,70,107,38,11,185,104,250,202,21,86,53,181,98,226,182,205,118,250,17,192, +73,122,54,119,5,151,74,68,54,105,131,161,141,154,24,187,129,216,208,64,22,244,70,72,128,196,169,123,227,164, +48,174,146,159,231,36,59,43,40,60,249,129,99,153,205,63,169,250,170,230,222,147,194,63,156,212,122,99,10,45, +46,37,121,239,221,140,227,197,240,10,195,59,142,252,227,85,39,98,180,92,99,177,26,163,226,121,108,92,161,32, +109,32,41,251,91,201,233,190,139,51,99,170,155,109,234,113,53,166,52,40,201,124,125,138,60,190,69,125,178,104, +223,149,50,57,43,218,179,94,57,148,117,220,38,217,182,152,32,227,136,234,35,126,206,228,6,186,206,153,80,17, +82,142,194,184,246,125,187,35,80,98,100,229,105,50,54,145,27,123,60,17,93,102,107,152,152,161,65,55,14,32, +222,246,140,6,143,124,88,193,60,217,106,5,218,179,17,81,76,171,185,40,141,236,25,129,155,235,200,194,220,227, +38,223,78,221,228,91,196,238,122,64,133,182,49,152,42,45,46,164,20,169,32,213,138,97,236,247,148,27,12,172, +179,49,124,29,7,92,167,34,199,105,145,99,29,39,19,248,85,253,237,216,112,169,44,144,166,109,237,224,206,58, +108,74,199,205,57,236,152,96,209,116,49,170,73,123,100,188,41,168,215,248,8,32,134,90,161,218,65,251,106,167, +46,242,110,221,86,7,148,189,164,159,141,21,59,134,50,15,236,245,128,210,13,189,47,220,2,42,136,199,82,76, +245,148,159,54,169,28,14,230,194,111,48,35,46,87,54,77,217,51,165,108,204,192,252,193,200,30,232,108,238,219, +247,155,92,146,102,213,236,181,112,67,144,91,32,238,153,201,124,172,56,65,165,203,8,158,39,0,143,138,221,220, +220,80,68,213,56,76,207,237,51,147,125,71,127,199,197,254,46,42,228,162,217,210,10,253,131,109,253,68,229,254, +55,163,201,55,165,5,129,224,254,116,119,89,245,140,141,122,132,133,45,106,220,171,238,154,27,148,102,174,136,182, +127,33,195,241,51,101,20,65,20,209,152,92,93,76,201,165,237,108,162,98,2,179,52,44,154,212,209,91,50,125, +65,48,220,231,40,68,16,153,17,53,179,75,28,54,128,127,48,66,20,86,178,17,67,30,24,51,140,95,190,144, +47,207,207,39,111,159,141,120,193,67,86,119,139,47,117,100,143,207,101,219,154,53,158,57,46,69,238,193,74,122, +144,135,171,28,134,160,189,122,7,49,10,51,31,95,57,245,194,169,103,193,129,148,222,77,21,230,63,184,34,185, +250,251,191,3,186,251,251,122,68,138,244,242,227,212,197,78,8,36,197,250,190,117,239,199,198,42,253,211,142,93, +181,25,124,164,173,75,122,204,202,198,21,100,227,135,209,163,48,137,195,55,126,82,44,93,16,205,211,133,125,44, +63,169,61,153,193,214,44,125,110,141,231,48,90,5,1,93,149,214,194,201,15,31,167,46,72,188,172,141,138,123, +1,165,221,184,83,52,115,119,159,16,213,77,237,170,242,14,191,119,63,187,37,152,151,139,230,14,51,199,56,45, +214,34,215,197,156,47,57,103,59,1,114,30,220,232,27,100,133,31,150,5,25,23,185,117,178,81,28,249,197,12, +228,23,3,98,66,183,28,52,32,216,65,66,40,143,20,249,13,167,184,60,131,122,50,9,119,54,5,164,57,116, +126,233,243,232,137,164,29,143,28,170,251,28,15,129,190,138,240,73,8,43,178,46,240,249,164,74,128,71,215,4, +172,143,66,253,228,63,2,59,163,191,173,62,122,232,31,126,180,250,8,238,39,128,78,154,90,247,180,77,46,40, +48,96,13,58,32,35,188,44,205,45,127,29,97,74,240,127,34,14,217,55,233,248,163,152,87,2,185,211,179,145, +6,174,110,193,14,154,167,204,248,42,81,55,166,72,52,175,25,248,66,242,155,94,5,196,193,245,106,167,115,26, +116,78,34,12,115,120,84,159,222,106,167,40,237,250,158,82,27,199,169,198,43,95,234,208,249,12,69,204,57,4, +82,192,182,33,10,137,113,153,167,236,108,8,245,110,114,6,199,75,248,34,101,227,138,146,210,121,60,75,105,121, +201,249,212,208,221,37,179,133,53,106,128,213,136,25,98,163,150,59,143,160,178,0,130,217,131,251,137,252,68,248, +64,2,60,253,83,6,45,79,40,163,251,13,68,72,65,31,114,118,22,130,128,52,50,131,27,162,14,130,61,73, +87,213,202,50,130,58,35,185,240,217,25,211,96,220,20,229,135,223,252,206,133,23,161,59,177,68,33,201,99,208, +101,177,226,176,208,70,202,66,91,60,145,49,51,56,162,42,151,163,204,174,203,98,225,122,79,233,18,75,118,220, +94,36,130,23,219,98,132,182,176,72,20,167,134,86,102,250,93,128,122,121,61,31,151,155,57,110,206,19,194,25, +102,94,148,124,2,231,27,252,230,230,77,101,202,198,196,117,119,199,4,189,105,221,174,127,71,51,136,172,73,121, +55,204,157,251,196,75,98,21,100,101,122,3,38,43,71,239,26,63,167,72,98,143,30,205,246,51,204,113,202,238, +73,203,170,120,155,48,192,10,203,65,211,96,228,141,4,239,160,240,59,217,93,69,2,88,165,100,226,97,153,56, +148,33,13,221,200,228,55,225,35,222,76,70,9,224,50,215,77,119,242,44,143,56,209,52,86,249,149,136,90,141, +44,136,125,58,135,152,37,87,12,209,220,110,131,94,192,132,171,83,61,87,215,220,68,35,107,10,156,0,5,233, +68,29,154,122,22,223,161,160,41,6,49,141,3,194,96,107,123,9,148,185,6,208,143,53,128,194,36,218,101,123, +149,236,61,177,32,253,24,208,190,204,32,75,171,147,10,33,142,218,100,171,78,34,109,54,52,63,25,74,22,149, +24,87,12,38,70,84,174,13,137,90,237,209,78,39,119,249,84,128,118,115,179,13,2,108,81,66,74,112,116,159, +246,3,39,207,4,20,70,91,163,175,213,221,157,232,142,94,178,76,44,77,63,9,197,240,162,88,197,88,228,152, +121,108,142,250,154,29,105,242,237,123,204,209,55,212,185,184,211,56,15,206,46,193,132,96,71,12,195,238,233,121, +58,138,187,196,48,208,183,132,95,238,96,97,48,237,135,108,24,47,131,49,5,62,156,107,16,173,59,70,32,89, +138,6,66,119,172,197,136,153,110,57,220,203,7,220,243,78,91,21,104,110,171,14,28,38,82,10,60,59,213,39, +65,40,6,49,230,240,107,97,88,238,170,124,103,39,95,203,116,73,131,122,42,215,167,248,66,208,220,129,239,65, +17,222,240,223,197,91,54,116,22,155,97,147,234,165,146,177,192,122,220,123,249,104,96,201,227,51,90,58,88,143, +173,225,4,145,32,245,117,24,107,121,19,2,180,225,40,202,207,195,140,98,42,150,169,85,184,13,150,166,246,88, +157,240,220,96,253,122,247,0,31,127,216,0,63,187,107,128,59,179,60,196,240,214,196,0,40,220,124,217,55,8, +26,105,53,25,110,114,156,17,166,80,199,28,146,27,115,72,76,93,130,61,226,15,228,177,2,100,194,198,210,89, +99,194,56,74,168,200,48,181,86,8,87,194,95,4,10,241,141,127,10,127,127,11,222,79,223,7,164,248,105,248, +251,29,166,95,12,70,225,211,77,89,159,167,97,232,159,114,234,113,169,29,170,242,119,80,28,229,255,226,52,157, +37,68,177,127,23,62,80,1,192,71,98,245,103,167,227,39,26,196,23,118,214,63,187,69,77,25,149,70,27,244, +241,16,26,198,63,38,193,26,194,76,171,85,248,89,213,65,178,65,6,173,7,104,232,169,255,185,32,142,219,194, +231,212,132,249,164,43,82,240,176,254,52,124,244,21,96,241,88,209,172,135,222,73,25,203,248,155,103,221,238,145, +161,63,183,117,205,96,251,206,61,205,128,162,7,88,238,18,228,94,126,231,64,5,243,109,132,165,225,20,245,98, +52,218,32,48,210,62,72,4,176,59,22,202,131,96,157,60,221,45,53,148,30,214,88,21,245,159,160,192,250,221, +225,235,206,123,90,242,239,79,227,247,139,200,188,124,239,79,121,249,207,247,8,49,45,102,252,187,100,27,198,228, +140,121,244,72,138,94,168,75,196,59,93,219,66,180,135,187,202,142,175,94,59,191,122,109,249,230,147,60,9,95, +162,235,9,86,160,109,152,248,10,97,64,23,10,254,151,32,43,163,179,171,128,55,40,19,55,188,176,9,27,205, +149,195,62,48,162,10,16,15,104,35,164,208,194,167,142,139,138,189,254,232,73,34,244,254,241,29,77,252,115,24, +17,80,51,255,64,91,53,17,127,107,42,153,62,157,72,46,49,208,83,50,230,252,60,79,106,253,61,200,163,239, +195,110,186,48,213,175,249,219,133,30,172,184,177,11,95,70,72,33,181,233,238,81,61,176,126,129,63,94,8,186, +53,73,191,57,219,110,170,24,126,219,92,18,133,96,67,66,133,44,124,64,39,100,33,193,89,251,246,175,247,33, +11,9,206,130,0,47,100,33,193,89,188,83,181,141,137,186,41,61,148,134,75,123,165,153,244,241,129,237,107,237, +84,250,56,199,195,135,222,242,67,89,56,110,176,35,99,213,210,78,14,35,14,211,127,126,32,122,240,51,241,140, +151,95,236,134,24,118,164,20,153,229,226,195,191,206,12,3,65,88,175,86,106,217,27,24,5,161,10,247,52,25, +211,84,242,241,23,40,183,75,6,22,83,190,126,94,215,170,4,64,47,51,72,158,103,169,108,133,192,52,226,99, +136,200,155,177,74,235,215,158,151,50,49,58,188,13,130,134,204,107,209,109,250,104,227,40,10,12,88,172,188,38, +49,10,210,219,118,157,52,100,31,161,106,148,95,240,238,97,57,198,24,70,144,106,148,0,87,121,177,89,77,204, +87,72,92,87,120,186,31,47,177,38,149,176,75,87,163,73,242,247,77,202,60,199,135,113,188,104,33,26,139,129, +135,213,56,31,141,80,254,104,23,164,195,37,182,66,169,239,227,55,94,24,148,245,120,72,114,220,203,172,42,154, +155,176,121,62,225,69,83,74,64,156,180,52,1,154,24,141,65,124,52,38,126,221,133,49,139,24,239,90,110,227, +113,75,211,237,236,38,25,41,148,142,114,101,60,226,200,136,194,163,166,38,13,13,249,26,159,128,232,56,19,10, +148,109,93,78,43,244,30,249,184,115,126,184,185,26,32,93,122,154,0,30,47,245,56,160,145,64,4,114,1,248, +184,0,85,195,83,172,28,174,155,27,142,1,148,55,165,92,19,46,130,74,227,207,17,148,243,128,51,196,8,137, +79,79,60,92,202,171,133,88,74,233,229,71,201,14,234,67,142,13,163,254,187,59,185,157,64,196,96,148,75,144, +230,209,23,88,40,9,245,39,104,101,249,83,67,31,186,151,229,38,206,97,196,199,205,38,57,198,189,107,22,103, +183,36,128,121,147,166,94,174,42,85,80,219,135,143,110,114,140,214,162,127,128,130,45,53,156,213,31,16,232,255, +185,26,240,87,4,214,181,37,60,179,189,251,243,53,160,209,97,200,173,168,16,181,48,194,102,229,181,246,119,186, +96,40,167,156,116,34,139,85,11,100,232,82,155,41,157,214,134,89,82,10,47,128,81,198,167,90,153,20,197,152, +212,122,244,162,60,227,21,120,240,205,128,230,155,231,30,116,3,155,176,179,220,195,228,80,199,20,220,3,85,75, +6,94,98,48,100,252,16,19,39,28,252,249,128,114,49,75,204,160,29,139,75,23,184,104,246,107,205,236,60,198, +208,47,113,244,152,59,34,152,22,153,30,201,53,88,42,48,117,183,36,81,75,31,131,19,164,119,191,123,246,222, +82,190,134,137,14,59,92,40,14,33,75,44,41,70,185,226,1,192,171,125,226,166,104,130,155,98,12,70,42,12, +51,237,146,88,157,205,128,144,195,48,93,166,35,182,54,132,208,108,216,166,249,200,215,25,204,134,19,61,63,9, +68,111,103,176,35,40,85,37,47,173,109,241,123,142,231,164,79,55,82,167,193,10,174,31,67,162,252,14,0,160, +30,191,35,0,229,217,99,180,97,242,248,66,196,152,58,222,90,193,152,138,200,142,126,137,188,72,47,179,193,13, +26,174,234,85,173,174,111,199,1,49,249,219,249,116,36,113,97,208,225,19,7,238,56,217,55,103,105,3,254,146, +78,194,114,212,147,173,23,223,57,235,121,241,82,196,38,112,194,203,235,209,109,186,166,195,185,6,120,104,33,0, +41,157,229,138,180,69,159,171,231,106,15,179,201,62,238,152,115,188,232,213,200,228,23,121,50,254,193,73,24,204, +82,127,110,83,69,60,98,55,59,88,66,52,151,176,164,72,120,227,121,221,164,247,14,127,55,180,100,225,243,40, +32,231,104,246,165,14,94,227,8,167,154,14,127,105,184,245,157,24,198,140,49,12,181,228,151,194,17,148,251,114, +6,122,194,39,139,249,73,111,150,53,124,134,47,34,96,138,116,129,201,15,192,81,126,249,50,133,225,171,76,218, +37,46,143,44,229,204,62,36,32,170,94,196,205,51,147,238,45,125,232,123,49,178,62,189,216,60,111,190,73,113, +107,75,211,135,216,244,221,161,185,231,90,85,97,223,185,16,111,231,10,45,58,133,120,59,209,115,43,229,200,41, +93,45,120,149,177,173,3,91,55,187,211,168,117,92,178,236,117,193,130,24,179,13,50,196,128,163,43,110,76,196, +88,20,216,140,191,249,185,120,197,49,86,131,55,201,253,165,2,192,111,239,250,194,168,252,116,219,234,1,99,30, +83,171,15,41,28,145,180,155,152,57,98,247,255,229,199,121,28,119,70,63,152,100,47,125,221,96,106,139,112,20, +225,142,175,108,9,8,92,12,177,65,43,38,77,83,159,144,133,8,28,12,83,240,28,164,20,56,211,164,216,194, +61,239,245,132,50,187,64,74,118,202,78,104,200,92,91,82,147,253,140,148,156,159,144,94,168,150,82,12,73,43, +37,117,239,237,76,199,217,217,187,84,227,160,47,224,74,171,223,144,250,95,25,14,65,204,252,56,4,84,210,55, +100,243,46,221,106,249,224,33,144,251,159,148,123,186,45,129,96,105,229,0,67,44,248,216,126,83,27,100,12,102, +127,78,169,31,29,238,189,183,225,239,69,248,251,45,253,85,227,79,140,211,150,49,120,213,91,252,253,193,164,98, +229,211,227,212,71,193,2,208,121,153,228,171,54,202,151,103,237,221,29,52,203,244,219,30,114,78,37,90,190,157, +152,51,175,93,82,145,152,152,80,110,84,64,219,180,135,102,54,75,84,183,104,27,122,233,232,54,215,34,244,194, +247,205,205,20,48,125,182,24,199,203,212,15,44,250,233,21,62,68,104,162,54,78,250,231,152,187,253,115,204,52, +71,70,130,148,27,40,1,134,213,0,195,145,142,116,130,44,202,113,14,160,22,147,223,148,226,142,16,50,161,187, +241,11,237,34,180,206,208,203,186,199,23,52,124,180,122,141,69,84,207,226,82,177,5,157,154,148,161,18,112,190, +98,239,188,226,94,240,146,115,137,70,167,13,49,255,220,203,89,153,153,114,165,7,30,189,105,247,38,53,63,38, +65,92,13,130,2,179,161,31,244,152,104,61,101,40,67,227,229,210,199,101,222,102,198,129,207,231,72,240,249,21, +191,4,26,90,60,183,92,137,22,105,79,163,250,118,127,124,67,15,212,237,242,11,216,70,1,226,226,243,55,53, +62,1,32,48,122,36,75,199,54,47,197,117,41,126,147,48,180,127,135,23,224,105,236,117,147,83,41,172,39,130, +42,220,241,77,101,47,173,216,96,183,53,18,232,136,67,251,130,225,193,95,140,24,65,68,76,66,110,9,249,172, +230,237,61,139,237,109,9,243,37,115,130,39,235,180,139,198,172,157,14,248,108,61,54,9,65,205,192,201,156,193, +67,13,160,231,20,214,29,176,238,201,130,42,1,24,233,117,10,63,204,62,129,110,228,35,56,230,112,22,246,69, +14,235,83,144,250,4,93,57,233,33,32,138,73,44,166,91,122,131,25,27,66,245,237,232,0,73,80,181,47,87, +225,72,174,104,239,150,98,137,11,253,3,241,110,74,182,224,37,127,224,55,9,134,46,38,40,135,87,205,241,47, +61,99,87,59,252,189,235,163,69,45,172,198,28,253,9,209,235,233,76,149,254,196,105,198,71,128,208,225,24,129, +164,146,121,36,233,141,87,237,248,24,235,16,170,164,45,200,29,11,5,32,73,123,201,37,108,183,76,111,90,59, +166,101,206,50,45,35,172,40,23,155,75,48,156,182,120,62,110,145,163,71,202,48,149,161,181,37,24,130,60,134, +58,163,0,245,127,120,251,242,238,182,109,165,239,175,242,152,39,231,30,242,122,226,52,207,125,86,42,172,78,154, +165,73,155,165,77,220,213,55,175,15,45,81,18,18,154,80,73,202,75,98,125,247,119,126,24,128,0,36,218,237, +187,254,97,11,203,96,33,150,153,193,96,48,19,57,159,74,253,155,43,108,72,216,93,183,22,142,204,122,44,90, +187,76,123,39,89,140,222,7,219,113,229,18,25,37,131,87,27,91,209,232,129,8,53,91,191,53,173,243,91,211, +50,130,12,235,62,169,140,155,42,51,243,64,25,227,121,219,109,100,51,51,66,1,230,138,228,73,64,174,221,87, +128,4,6,165,142,155,187,77,85,5,86,170,128,39,243,49,99,42,226,47,176,79,19,74,178,29,240,131,3,32, +88,227,212,163,234,98,247,27,111,98,222,67,206,123,212,136,107,94,156,249,157,222,197,228,118,63,68,192,46,131, +53,9,30,128,114,95,23,218,184,207,172,204,83,183,103,120,148,10,238,83,199,154,61,254,192,17,250,182,57,208, +198,231,162,225,25,96,241,16,191,252,46,118,196,232,128,127,123,78,253,112,103,185,228,182,248,115,153,1,253,212, +100,116,38,63,239,91,243,243,166,149,68,252,136,20,228,37,43,5,90,63,50,239,170,229,179,171,181,88,195,253, +64,159,155,66,44,144,39,120,246,126,191,172,177,186,200,233,111,65,140,103,118,86,206,150,19,102,245,102,94,229, +47,27,170,174,134,32,187,170,204,93,197,111,96,217,14,50,59,203,48,230,59,34,86,153,129,81,105,131,243,248, +13,242,57,60,227,143,107,112,147,212,99,146,124,117,25,143,174,143,81,239,171,202,182,100,53,137,242,113,245,56, +252,115,71,184,196,126,94,66,209,190,54,107,104,204,11,200,177,176,231,226,224,151,162,154,48,58,127,189,166,131, +168,166,45,9,155,56,222,99,171,204,226,30,42,81,85,24,69,127,106,129,11,246,205,63,68,126,188,30,27,169, +136,22,154,170,152,83,181,31,76,37,135,109,151,81,0,4,224,128,5,55,232,151,162,38,99,161,150,24,231,228, +120,137,120,228,153,173,147,250,102,133,27,255,186,144,193,183,143,92,24,75,33,58,109,13,170,144,247,247,173,177, +136,154,228,172,31,97,130,120,136,159,27,176,9,236,175,76,211,49,155,21,200,217,79,230,77,80,211,38,163,90, +88,153,77,150,229,41,32,139,202,39,201,228,240,58,229,251,121,167,129,108,222,211,190,108,250,212,229,201,230,157, +81,205,79,208,168,150,34,130,28,240,108,46,54,11,129,3,155,99,104,129,240,196,0,38,31,227,239,241,86,250, +222,1,229,159,155,64,6,247,244,207,37,2,239,110,63,225,59,207,45,137,56,131,221,244,170,46,190,92,150,109, +147,175,123,18,250,144,31,147,121,241,110,167,62,255,185,39,169,229,157,40,200,240,102,237,161,59,58,156,237,195, +3,253,240,174,17,27,200,186,221,128,16,127,140,247,131,136,59,35,212,229,16,255,232,134,190,141,78,238,16,153, +145,178,178,161,98,34,88,244,132,163,201,62,91,194,99,158,145,225,223,233,181,249,255,196,252,55,180,122,251,84, +112,226,232,160,114,78,36,10,97,179,108,198,69,73,34,150,72,103,253,246,47,22,236,186,214,218,183,73,232,46, +41,142,211,121,12,34,71,190,236,246,142,230,104,240,118,85,214,114,70,244,13,26,233,71,254,93,197,197,185,95, +220,127,185,114,255,215,163,255,56,122,248,48,17,63,175,77,113,145,138,137,68,18,171,137,25,61,71,154,88,49, +32,212,84,242,240,147,140,46,117,21,12,93,3,235,47,219,202,64,255,212,220,226,89,211,90,74,16,5,149,231, +141,33,196,201,217,166,239,69,2,8,75,234,82,91,53,183,64,137,52,130,88,207,185,140,49,102,159,124,166,233, +144,203,59,223,4,197,96,226,90,155,28,118,207,105,58,111,52,249,128,220,149,81,224,164,121,91,46,151,38,212, +173,171,186,54,53,115,223,223,25,96,121,140,64,179,146,251,77,60,113,160,86,235,186,84,102,24,239,235,166,134, +250,243,55,241,103,122,13,38,172,92,238,208,162,172,59,97,188,166,54,156,239,246,2,185,208,9,106,196,155,106, +210,183,60,60,91,250,209,116,130,79,105,250,114,193,43,188,227,213,94,53,100,158,110,81,185,233,245,66,207,54, +157,9,113,167,174,201,142,10,97,153,243,230,37,52,210,234,186,227,29,205,19,216,86,228,240,191,253,117,240,54, +202,3,231,35,110,252,17,175,90,154,171,14,253,156,83,213,200,47,116,193,26,205,243,168,192,39,210,74,205,231, +220,53,240,88,125,213,158,171,6,137,170,225,149,72,170,59,47,215,164,250,234,220,40,201,82,173,245,154,206,185, +9,181,230,65,151,70,27,189,106,171,5,255,240,202,81,159,43,14,116,171,114,94,145,111,129,131,151,45,215,195, +53,192,195,9,31,75,52,99,31,213,19,175,192,57,38,130,3,127,108,84,91,205,57,128,245,204,1,180,135,159, +170,60,175,121,69,210,240,77,157,110,101,242,251,182,108,186,26,213,99,196,121,1,112,38,246,39,108,123,26,15, +111,116,161,140,177,102,158,230,111,121,127,172,250,126,157,63,120,112,121,121,121,116,249,143,35,221,46,31,60,252, +239,255,254,239,7,87,181,106,62,37,244,98,236,208,155,228,145,67,151,127,199,82,23,120,36,59,135,85,244,239, +76,194,127,25,61,52,191,64,100,234,32,255,131,6,3,194,240,44,71,63,143,150,177,10,211,240,232,142,86,2, +130,242,107,116,182,1,125,194,233,1,220,173,187,172,74,155,125,122,153,101,77,49,146,60,232,186,187,167,247,198, +198,194,239,77,42,49,226,114,67,173,144,143,59,101,88,88,154,136,224,43,146,184,183,153,253,29,39,90,249,214, +19,32,31,170,246,204,30,252,30,109,183,47,1,112,254,7,103,197,165,195,88,38,248,44,215,131,45,133,233,9, +66,65,51,31,114,27,8,21,226,226,237,173,141,126,131,198,142,69,115,244,61,54,47,38,37,208,140,139,75,244, +211,106,218,179,242,40,235,119,230,61,174,29,67,88,46,222,223,113,218,65,107,185,188,47,71,112,252,184,19,53, +222,235,72,45,143,218,34,73,110,179,57,205,95,81,160,3,144,135,96,129,26,44,140,243,32,254,14,11,238,114, +70,252,91,101,35,182,227,43,29,248,67,74,226,211,113,111,238,119,48,203,248,179,21,241,111,27,200,218,12,176, +46,190,176,157,140,124,100,131,241,147,218,175,30,112,94,66,188,33,87,249,248,22,252,175,7,240,127,111,254,189, +126,197,187,162,209,140,56,25,244,188,166,51,61,191,38,240,2,180,98,76,65,216,121,116,94,241,226,20,202,214, +171,158,255,179,14,18,104,22,149,45,175,17,196,59,166,27,140,227,52,35,51,83,14,63,15,105,245,175,180,250, +7,173,254,141,86,255,78,171,255,160,213,178,213,155,53,53,229,5,117,98,59,146,241,228,5,205,25,105,214,52, +239,137,57,175,89,41,196,209,232,55,84,180,86,179,30,191,171,150,212,249,146,59,195,31,165,26,210,53,173,105, +205,233,155,154,74,58,227,83,212,89,75,103,115,197,127,154,56,56,99,236,73,51,236,52,179,173,230,139,134,170, +115,82,244,233,108,206,21,180,159,232,15,106,215,212,246,212,246,51,106,55,103,215,196,200,142,117,107,137,81,111, +93,51,97,43,27,194,201,136,169,87,183,57,227,191,53,65,255,150,54,196,131,79,151,220,130,33,228,229,102,174, +52,1,91,227,12,247,137,12,241,228,150,206,24,43,138,237,119,50,62,140,168,211,155,118,198,61,42,155,139,146, +91,154,181,106,221,243,152,219,0,115,136,48,245,70,238,219,103,186,198,159,12,150,197,187,102,46,122,51,55,253, +156,163,220,34,9,3,96,62,177,86,29,134,175,170,231,204,119,26,90,67,194,116,212,229,25,215,94,87,75,200, +172,206,65,107,192,126,72,213,150,15,209,155,30,144,194,135,56,172,31,176,43,115,158,124,5,162,168,202,90,47, +185,146,102,99,254,129,66,241,208,156,243,128,94,147,165,207,84,137,17,11,2,57,210,151,228,76,115,211,89,173, +103,159,254,216,104,14,170,5,15,9,127,18,86,11,175,110,109,150,30,47,88,42,27,117,14,216,153,106,103,134, +135,82,235,53,47,80,154,109,90,38,64,32,172,160,204,221,140,27,225,44,94,160,98,184,155,22,220,246,253,69, +201,3,28,25,178,161,37,45,235,235,245,138,184,214,101,133,133,92,153,201,175,90,254,233,120,81,171,174,99,140, +112,95,128,208,18,254,113,133,76,47,117,125,189,212,242,107,202,181,168,175,187,84,160,112,157,49,108,97,198,199, +252,51,37,123,179,102,32,252,187,80,213,101,98,84,82,148,30,37,53,22,15,226,39,160,51,165,14,96,76,230, +20,131,194,212,16,219,216,160,173,169,4,157,213,111,115,44,28,247,216,237,149,32,80,145,248,150,244,79,40,56, +170,144,238,82,30,34,165,135,209,31,253,74,95,50,215,203,155,63,117,134,21,58,125,210,15,50,95,68,156,50, +207,174,186,186,76,124,96,145,210,11,156,216,12,28,100,72,83,83,188,136,165,183,133,211,151,127,113,252,250,213, +79,205,39,102,91,26,91,215,205,205,29,160,22,38,151,58,31,236,151,126,96,5,85,161,183,70,81,222,48,11, +206,76,159,184,8,48,14,224,46,117,107,56,159,150,103,184,98,36,131,9,174,105,211,214,73,48,156,27,55,156, +251,212,132,211,119,198,229,143,77,213,94,191,55,155,73,183,193,184,48,29,187,101,236,18,198,134,201,152,25,228, +133,14,37,108,127,54,242,246,44,96,116,3,166,109,158,86,150,117,168,130,87,76,129,75,224,48,249,200,241,153, +198,244,126,213,63,230,68,197,120,166,74,19,151,147,144,15,102,145,24,120,173,35,234,61,222,205,55,239,211,22, +83,22,153,8,88,133,139,255,54,167,149,145,74,195,29,5,172,209,134,8,254,66,123,195,224,98,85,243,27,121, +164,16,219,15,63,179,95,208,91,205,60,115,21,25,201,58,151,3,68,185,134,26,200,62,196,117,216,53,103,73, +7,31,224,65,46,99,16,72,5,222,51,211,204,11,42,184,144,140,97,122,177,69,230,243,79,135,142,96,37,63, +17,244,91,132,55,113,14,32,158,199,138,146,68,246,193,171,1,119,44,218,170,250,92,165,95,162,137,202,23,154, +118,102,46,95,107,138,39,37,95,105,138,70,61,63,215,20,14,48,35,43,10,198,50,63,211,20,12,92,190,212, +228,7,40,191,214,20,140,69,126,169,201,126,118,126,165,9,54,65,252,151,230,167,38,229,61,120,18,99,240,56, +255,164,183,25,189,214,133,253,138,29,203,173,79,52,38,201,73,233,227,60,107,255,145,15,84,126,55,112,132,57, +48,46,213,27,84,142,226,183,217,61,117,64,219,0,155,63,137,54,172,111,192,217,251,144,156,38,48,228,170,198, +44,167,222,220,24,211,180,84,22,141,188,50,159,84,211,29,43,112,184,59,153,46,205,47,44,204,227,23,118,31, +185,243,8,58,11,130,185,239,194,203,230,185,110,71,107,193,255,1,103,171,236,17,59,107,67,146,200,247,92,221, +44,171,151,128,18,45,141,143,122,48,3,154,16,95,60,193,153,193,123,93,156,88,101,134,196,63,109,227,32,15, +191,4,100,73,112,192,14,104,18,120,79,124,27,163,17,177,221,111,229,155,252,89,102,47,32,46,54,234,2,51, +45,72,244,49,49,146,100,14,73,156,161,45,22,100,102,253,177,212,15,123,115,61,70,0,210,1,54,249,55,171, +86,186,102,190,53,219,181,246,130,106,163,4,152,184,137,83,196,222,77,116,135,163,221,203,61,17,255,8,54,70, +151,61,29,182,14,114,10,156,245,122,215,59,68,218,193,8,118,107,60,104,144,50,48,213,93,48,131,245,15,177, +250,89,139,221,82,254,81,225,29,145,142,52,135,160,80,234,156,51,193,91,121,243,168,104,39,135,135,77,38,46, +193,48,224,132,10,176,152,112,47,233,77,17,150,193,237,143,14,244,11,76,125,198,117,228,185,49,5,214,81,205, +97,156,121,223,218,171,69,121,238,244,222,249,52,229,230,170,140,211,185,129,247,154,175,92,96,242,196,90,58,157, +121,144,54,211,233,140,23,157,133,225,14,57,112,89,156,65,94,72,173,3,12,106,215,104,237,16,41,103,197,236, +142,172,93,111,145,49,32,190,35,110,96,97,43,233,254,253,192,116,51,219,41,76,251,129,116,7,25,69,21,218, +69,157,251,163,95,29,144,6,208,110,241,29,88,199,148,39,234,200,122,120,68,101,204,113,90,35,159,6,67,152, +69,209,137,125,181,142,125,111,137,109,240,140,176,192,223,105,221,191,52,40,185,56,40,233,96,229,106,241,62,81, +68,248,176,8,76,52,210,92,22,43,247,106,158,77,165,13,76,100,55,173,247,200,57,146,105,158,229,59,57,233, +156,59,79,167,41,255,187,22,75,197,48,244,180,225,62,94,153,1,53,247,106,166,98,116,37,87,145,207,74,215, +100,189,67,211,133,218,237,150,13,128,67,226,52,14,29,234,92,198,215,133,165,29,9,65,210,101,230,174,35,245, +152,217,114,254,142,224,166,194,22,41,196,51,44,231,73,4,154,14,0,76,197,215,202,120,69,142,185,62,223,31, +22,82,102,82,207,134,126,50,157,9,250,47,37,190,56,60,119,4,186,202,132,83,38,219,88,116,13,189,225,85, +52,10,54,154,58,152,85,192,184,142,116,218,152,252,184,76,49,81,118,54,49,209,89,110,40,102,160,241,18,242, +86,241,96,27,47,118,206,90,206,200,168,192,49,99,209,221,42,66,3,94,226,108,139,16,17,81,71,70,56,169, +208,152,53,9,36,238,147,203,35,71,129,60,66,81,153,79,101,204,150,126,212,48,186,109,187,221,57,147,60,225, +84,4,44,160,195,161,226,119,213,208,243,105,184,155,57,46,226,233,58,230,53,165,88,94,71,172,35,6,47,228, +30,111,117,161,83,101,140,118,38,177,23,157,224,139,154,108,109,108,59,147,237,178,179,195,201,181,53,246,237,78, +231,61,196,198,125,144,2,245,184,151,120,87,40,236,229,165,127,184,63,182,162,113,150,188,109,226,188,93,237,93, +5,134,43,81,231,136,191,176,148,78,69,31,106,211,240,181,152,56,120,45,13,189,52,147,245,194,202,63,2,136, +152,11,74,1,66,158,114,219,164,29,89,173,167,14,81,219,173,205,45,120,215,26,89,86,31,69,204,167,29,193, +42,112,91,217,14,171,187,205,80,188,117,156,158,184,137,13,140,145,14,110,58,56,231,182,122,201,75,131,183,40, +253,182,197,55,129,165,112,213,218,168,247,2,241,191,211,76,112,122,8,108,198,42,153,20,176,7,218,174,52,113, +117,100,141,254,236,40,101,191,10,249,129,38,196,169,78,171,28,29,107,60,166,68,47,45,31,136,175,2,2,17, +46,161,116,201,33,179,48,36,50,181,103,80,63,61,177,101,98,225,33,124,106,200,76,188,74,125,122,172,123,244, +90,62,219,126,112,37,252,144,83,149,23,109,18,97,172,240,49,102,253,78,83,120,99,163,87,248,182,124,206,137, +60,146,17,145,121,50,48,130,218,92,111,13,92,233,224,33,177,40,45,209,183,125,60,20,99,18,0,159,86,158, +147,56,44,154,188,42,22,233,64,28,192,6,142,83,38,228,56,51,78,18,117,152,242,137,216,186,148,209,241,237, +250,177,113,105,60,46,166,227,19,212,21,236,46,87,187,5,203,166,173,1,203,43,231,169,208,162,147,208,237,180, +93,75,42,240,127,4,167,243,48,117,66,176,179,112,94,84,222,135,244,69,81,65,55,224,172,168,224,26,101,89, +180,62,235,186,104,145,117,201,63,203,15,116,197,236,140,221,98,243,71,197,57,191,24,123,84,44,179,38,189,200, +166,168,227,240,112,254,33,111,210,179,108,138,170,238,223,63,255,144,243,201,226,130,174,121,202,222,226,151,251,211, +194,152,166,3,70,245,28,88,125,200,0,120,70,151,0,196,175,1,92,102,228,234,65,7,56,176,20,192,11,11, +120,225,1,175,70,80,255,133,224,216,240,176,159,158,153,129,242,61,136,43,62,179,93,61,115,93,29,175,216,84, +34,213,7,93,244,223,146,54,194,24,178,98,32,175,40,154,19,90,156,21,58,189,54,78,171,167,221,137,9,124, +200,223,167,215,36,249,212,164,179,108,186,78,209,174,237,185,108,243,21,87,183,41,140,63,125,238,224,198,118,112, +227,59,136,44,123,230,28,237,236,38,232,108,150,143,182,144,249,190,79,230,95,159,79,211,69,209,164,60,225,240, +16,54,5,81,203,37,98,202,0,77,45,80,140,150,164,184,198,213,215,124,36,124,45,159,25,42,40,122,222,99, +80,65,43,90,230,13,26,24,180,115,220,31,56,1,65,39,216,41,230,24,90,14,220,153,10,182,244,91,91,157, +89,199,217,23,251,150,215,112,98,85,204,141,87,3,55,94,13,22,114,43,97,170,240,31,173,221,114,10,205,244, +206,25,211,155,60,157,190,145,45,38,236,68,53,82,26,111,60,204,102,52,245,87,131,47,60,238,18,154,11,162, +149,61,93,247,246,116,45,208,79,106,198,40,120,233,45,209,183,134,77,205,254,162,139,27,79,3,231,180,182,135, +86,198,34,107,51,42,243,98,237,208,8,34,243,193,121,15,39,128,25,114,254,70,2,124,14,244,48,68,48,98, +82,215,101,90,89,54,79,44,38,149,242,178,59,64,102,243,204,165,157,204,29,50,219,239,128,64,12,205,111,155, +180,18,134,103,170,211,21,160,96,178,151,95,140,2,195,124,76,23,188,212,206,169,229,105,207,77,70,170,67,166, +42,150,81,49,48,92,159,124,226,95,172,91,46,199,168,206,99,179,150,215,43,154,152,190,78,87,156,179,26,114, +144,252,39,149,230,146,143,85,103,2,163,112,246,59,232,246,177,215,93,31,15,126,168,77,249,56,96,69,85,234, +236,97,187,43,105,23,26,59,60,84,178,248,238,224,85,193,187,121,154,98,177,68,138,84,145,77,30,67,68,111, +4,28,114,245,76,225,221,180,132,13,251,66,188,106,67,1,253,155,157,19,29,117,34,39,162,153,93,136,84,239, +44,38,99,13,107,246,183,191,205,176,18,201,238,77,82,105,32,73,194,151,239,108,198,1,45,220,178,251,152,241, +150,149,138,61,102,78,134,179,241,147,161,188,90,37,36,142,108,175,44,56,28,98,42,134,106,97,201,219,185,86, +3,250,129,117,6,195,203,131,113,239,82,36,74,171,174,193,193,183,106,208,131,166,106,113,109,34,85,149,224,30, +131,196,193,206,150,217,205,222,132,25,204,56,131,205,84,109,215,155,22,73,182,95,29,25,44,195,141,211,130,181, +41,222,240,50,172,121,247,89,121,3,23,127,104,207,86,108,30,54,18,124,163,196,134,223,168,198,13,243,121,168, +34,60,162,112,163,233,108,161,5,6,183,86,184,56,159,101,168,224,56,93,49,4,231,50,245,49,3,102,27,59, +88,243,4,159,88,95,182,31,140,185,15,31,205,182,210,148,44,229,96,75,165,146,98,227,78,246,229,117,18,99, +93,45,239,131,170,178,189,52,102,98,22,44,208,178,78,164,178,108,134,158,193,251,237,34,11,176,36,211,98,145, +145,29,27,15,106,168,100,110,233,15,87,37,196,70,80,136,252,235,108,97,6,156,155,54,161,179,226,107,128,252, +146,151,131,23,249,63,199,26,116,87,26,97,178,117,235,33,155,251,141,180,51,172,184,199,232,166,184,120,157,244, +197,6,210,45,135,153,65,123,206,99,1,214,202,244,219,124,26,99,178,211,186,42,89,134,117,38,244,122,135,237, +97,88,57,128,73,113,59,88,23,254,169,217,89,1,220,110,89,187,11,79,178,151,188,208,150,99,135,130,101,112, +40,88,126,224,34,232,139,97,42,132,216,210,153,175,228,154,43,185,30,57,86,94,251,99,229,181,57,86,114,45, +128,191,42,46,246,16,21,170,191,58,18,199,71,153,171,248,148,159,218,156,62,186,226,3,88,231,106,61,229,173, +96,18,78,78,63,56,246,152,5,36,168,153,107,181,199,185,173,161,35,175,83,220,137,125,69,95,9,242,23,215, +39,175,48,232,219,104,62,102,153,224,40,46,213,15,16,104,254,153,191,249,120,169,229,158,3,161,209,27,139,151, +88,90,31,117,116,99,129,52,156,83,156,44,201,189,128,128,207,226,106,55,137,91,254,44,240,129,53,191,240,202, +67,206,141,5,68,242,60,148,188,133,36,208,21,79,245,126,3,212,123,115,129,51,64,84,123,16,149,135,168,33, +33,222,96,87,153,99,158,108,254,166,232,196,3,214,12,63,13,147,229,35,70,197,63,27,75,35,141,245,174,110, +146,30,183,75,78,40,219,37,61,215,169,246,55,18,144,180,50,196,28,215,62,230,199,35,99,88,46,20,179,18, +34,39,208,144,115,73,105,188,253,24,43,43,203,4,101,234,161,12,22,141,67,146,50,74,129,133,236,93,103,186, +117,104,147,143,219,170,241,89,137,171,86,154,220,78,212,244,170,74,43,151,158,240,230,205,23,105,6,84,186,25, +220,125,8,196,64,233,19,74,111,109,116,179,211,232,198,52,26,141,131,111,60,99,98,164,178,97,10,186,12,35, +127,115,195,197,58,83,108,211,200,224,244,212,83,41,168,227,222,159,40,43,60,221,93,65,99,224,98,107,119,120, +132,54,9,207,250,65,247,113,88,199,74,192,61,132,90,168,202,248,14,11,98,197,61,141,151,81,63,224,52,255, +1,254,182,48,111,112,225,84,5,46,156,252,2,76,168,49,207,110,40,176,179,30,58,152,143,47,107,219,242,242, +141,125,163,131,66,135,201,81,114,24,185,238,15,123,197,79,235,142,62,106,213,164,12,21,108,167,231,122,223,253, +73,47,107,204,252,88,231,1,202,60,211,102,12,110,240,92,47,240,251,22,127,6,233,83,240,81,172,86,231,250, +199,193,193,72,163,197,39,63,241,29,222,107,77,207,116,112,51,247,155,190,219,13,38,58,148,30,104,227,204,76, +108,63,196,15,151,84,179,170,90,213,63,182,23,87,198,95,99,160,124,128,82,76,61,195,20,231,183,94,110,60, +44,54,175,139,176,148,24,35,225,172,56,201,44,12,243,206,136,23,178,53,74,140,54,99,72,121,44,183,201,50, +254,43,139,13,172,154,119,69,109,126,96,145,150,53,140,153,233,48,130,139,161,190,180,103,197,20,35,55,220,8, +98,97,192,90,66,22,220,249,181,179,249,25,213,89,147,162,110,180,255,162,129,99,238,217,46,53,230,123,148,111, +27,250,5,153,89,254,27,255,240,96,236,1,33,51,96,208,223,121,165,6,119,173,181,167,114,243,141,131,201,127, +52,186,210,63,55,144,86,239,51,3,21,204,119,20,187,170,211,238,245,219,179,215,223,60,123,138,200,208,208,84, +84,174,243,138,246,244,11,90,249,2,110,108,47,235,155,198,230,191,184,163,51,126,44,42,134,116,117,4,89,242, +61,238,203,66,255,245,58,56,178,152,202,179,145,47,245,220,83,223,227,69,25,255,75,142,159,253,122,252,248,221, +179,199,209,55,114,250,218,115,245,110,44,18,107,210,24,70,172,85,181,94,57,225,96,248,250,2,218,179,122,253, +210,25,67,0,227,93,46,75,65,186,228,186,244,236,34,120,11,239,110,137,141,115,69,99,227,237,182,108,114,13, +227,117,204,200,224,203,246,253,209,179,3,191,89,118,0,161,128,224,127,27,109,102,217,89,202,157,146,194,171,176, +131,148,151,99,160,14,140,173,139,148,153,13,115,118,201,171,149,255,239,1,149,22,40,27,238,210,126,197,248,208, +12,210,73,127,93,99,10,84,221,196,30,151,186,130,245,128,59,232,7,207,184,32,118,34,192,249,120,118,97,0, +25,98,87,55,73,56,121,56,191,11,1,139,206,14,198,11,77,191,248,241,248,214,142,7,66,172,15,174,139,228, +244,180,77,232,87,19,152,37,126,132,126,119,218,94,252,123,242,179,254,144,13,122,224,253,52,97,245,244,102,201, +27,192,185,168,52,239,5,189,187,127,83,128,144,8,163,206,25,201,43,160,127,49,201,91,212,247,43,215,103,216, +114,169,40,44,138,60,114,25,81,113,41,22,104,88,199,247,249,197,11,189,231,92,69,167,146,169,254,204,185,138, +98,194,162,184,58,13,26,98,7,238,15,93,148,112,208,156,194,123,180,188,58,228,224,9,75,226,30,21,255,254, +143,128,116,127,63,80,43,51,96,127,104,247,0,243,69,139,69,53,169,10,197,6,193,90,238,64,232,161,77,70, +215,217,214,17,173,255,77,219,194,198,131,73,97,2,234,237,222,126,93,232,40,254,168,248,10,113,41,43,238,172, +158,90,69,48,254,154,185,13,14,226,59,249,120,177,189,19,56,52,217,190,208,251,155,13,159,82,246,211,47,80, +200,221,180,85,46,26,130,120,219,213,108,243,16,225,244,202,127,118,202,114,132,23,58,27,219,220,0,26,62,255, +230,38,70,90,149,114,23,4,1,61,212,77,72,12,17,245,27,85,82,184,53,177,58,22,198,39,47,180,221,201, +191,131,10,195,17,78,75,154,190,215,212,43,250,78,135,108,52,67,90,61,82,81,40,87,212,168,97,139,84,74, +182,8,66,1,202,208,35,93,245,130,5,223,97,159,232,186,13,18,106,123,214,21,59,5,209,113,208,246,253,84, +207,225,51,102,8,104,248,30,176,144,241,25,144,69,38,39,130,155,27,209,127,74,146,44,56,39,136,44,75,14, +9,73,160,55,7,220,206,19,147,12,226,15,147,96,160,189,180,136,27,246,145,29,183,165,224,121,51,140,173,106, +54,213,68,188,199,206,6,121,204,192,140,151,145,118,71,8,2,143,124,96,220,163,151,94,201,15,239,222,126,251, +238,217,251,247,160,57,165,35,75,112,31,115,106,192,10,53,17,95,215,134,167,72,146,92,110,108,57,50,81,42, +45,169,206,140,145,1,129,173,179,193,236,121,244,157,104,72,235,212,87,15,196,29,139,135,90,85,180,234,79,180, +86,169,85,190,76,145,60,98,221,229,175,147,67,117,152,60,122,96,130,166,167,27,174,39,16,29,217,35,126,25, +36,101,241,16,69,89,22,124,19,131,135,23,217,97,150,255,92,117,96,39,8,172,178,232,174,5,12,242,54,148, +121,42,21,234,158,57,199,244,80,19,231,145,76,222,254,112,252,242,237,155,144,71,128,63,3,101,213,201,58,9, +132,134,4,85,64,98,33,147,71,7,188,254,174,104,32,184,113,132,252,45,236,150,83,37,2,191,239,248,204,202, +215,221,69,117,91,16,177,73,120,241,218,157,46,134,91,87,172,228,230,72,212,157,189,72,177,205,32,214,6,71, +100,178,121,241,156,187,204,214,196,82,0,84,54,56,244,8,105,226,236,216,99,12,109,49,6,66,91,170,85,113, +149,166,251,38,94,96,132,170,120,48,73,167,7,39,255,35,253,240,247,127,102,217,131,37,247,249,65,158,30,29, +102,15,28,237,114,86,8,218,108,220,142,6,104,134,255,112,129,109,178,137,119,123,132,157,122,130,171,66,219,115, +88,221,120,232,34,25,140,45,80,197,255,2,77,49,229,251,184,80,131,39,217,160,67,94,228,60,61,78,163,184, +185,252,12,180,197,212,93,207,146,222,220,246,20,169,86,59,238,47,231,42,58,12,243,208,97,146,108,130,246,175, +207,70,132,198,186,208,119,232,205,240,110,119,79,201,218,130,63,92,98,89,6,163,68,13,40,147,36,247,59,201, +206,212,139,109,87,21,202,201,239,84,84,157,138,203,5,94,201,140,224,86,209,74,177,167,181,251,247,31,208,57, +7,254,217,253,253,64,113,79,91,238,99,127,239,1,93,40,207,29,120,86,126,165,156,209,137,204,78,13,248,191, +225,229,46,192,134,235,174,115,11,219,142,195,62,1,251,137,203,107,195,217,51,180,185,162,73,134,62,36,129,96, +182,41,150,74,54,199,158,179,238,63,113,98,224,154,62,105,196,82,146,244,46,76,220,110,233,76,177,150,236,47, +213,217,39,213,39,196,174,83,63,67,179,158,229,209,180,220,219,61,16,173,170,98,253,103,56,88,234,167,190,248, +196,133,40,145,231,49,160,29,120,58,15,2,184,86,131,121,164,65,124,94,249,183,150,95,65,39,242,167,245,218, +233,68,30,186,71,148,15,157,198,192,153,26,241,62,127,166,24,167,30,86,6,137,196,173,52,219,104,155,93,135, +107,218,29,53,212,206,81,163,13,55,23,47,35,73,113,97,181,151,171,36,215,29,49,98,65,65,4,78,27,142, +55,240,201,80,171,207,213,28,105,140,191,109,121,195,133,44,138,250,230,102,67,115,32,1,233,158,173,28,185,19, +73,217,173,161,208,233,220,241,38,83,240,33,208,133,156,79,228,154,98,174,228,130,199,140,182,177,203,186,200,154, +116,205,78,225,224,155,90,165,51,234,176,0,125,246,58,43,11,100,19,46,34,22,28,112,96,214,167,79,9,50, +95,90,246,252,210,227,223,107,139,127,17,218,210,149,217,90,135,15,252,208,159,122,214,205,60,45,28,176,186,220, +31,201,57,13,252,106,22,200,16,254,69,100,8,149,197,177,87,106,12,33,123,77,237,160,22,107,214,156,103,63, +223,79,13,149,164,32,122,226,230,151,35,199,57,30,116,30,26,8,167,38,109,216,167,195,10,105,70,61,189,31, +63,7,166,237,97,149,185,239,11,61,102,254,127,30,4,225,100,226,113,136,51,40,76,149,157,117,115,227,242,247, +62,236,127,125,228,168,41,134,17,179,152,219,143,101,147,125,205,252,107,91,120,116,216,16,62,119,130,36,25,24, +106,167,227,99,12,9,204,173,253,12,199,252,149,242,36,27,172,167,188,139,12,105,159,103,14,6,231,62,162,216, +214,117,32,34,21,189,86,169,179,48,150,48,150,203,8,137,61,104,184,192,143,209,83,148,201,242,240,132,243,122, +23,171,186,119,208,48,43,208,202,51,104,126,108,124,223,68,19,50,63,199,122,39,253,126,175,109,214,99,195,187, +237,102,11,71,151,80,93,149,97,38,162,46,21,117,70,233,168,83,178,124,157,65,182,171,211,176,45,79,84,241, +187,145,89,209,71,85,36,94,130,146,208,123,142,203,3,74,19,125,187,147,253,56,138,87,144,204,31,199,37,222, +132,81,0,76,158,224,21,137,12,161,127,123,167,155,168,26,255,142,204,3,92,26,154,182,3,150,162,71,66,237, +142,119,250,117,185,147,250,140,27,207,104,191,97,215,187,187,219,141,161,210,227,161,217,199,241,183,94,6,137,174, +81,225,114,158,241,32,79,109,173,48,146,80,117,30,236,57,222,174,222,153,121,132,123,143,84,32,178,220,123,50, +206,199,236,251,165,89,120,5,167,144,245,76,5,171,212,68,113,219,18,94,180,197,156,255,136,32,141,15,191,35, +201,98,49,209,111,255,202,160,208,212,106,191,66,133,123,239,0,115,207,54,53,82,27,239,205,229,104,43,12,79, +22,209,6,142,172,84,44,168,122,46,0,164,139,198,190,112,65,64,6,202,188,118,130,45,44,227,64,208,176,5, +122,56,150,164,153,53,135,164,113,163,168,166,143,85,254,70,209,172,128,3,243,96,212,198,101,172,29,76,24,181, +41,222,129,197,226,90,47,129,98,78,233,240,112,246,53,68,255,53,38,231,22,79,212,179,71,22,32,35,117,200, +220,145,33,109,251,141,25,196,243,3,136,241,89,106,6,10,47,179,111,88,200,158,165,116,115,47,11,232,243,243, +152,221,119,139,154,59,245,68,204,232,9,179,145,246,24,179,180,57,121,203,39,235,167,240,161,157,124,48,200,126, +48,220,6,131,1,106,128,216,180,178,226,71,128,202,226,39,149,66,185,151,58,128,31,223,85,225,76,32,238,174, +176,70,133,120,151,194,163,203,74,34,208,224,149,57,42,191,54,235,140,131,156,83,114,142,26,44,114,0,226,189, +154,214,22,226,61,32,106,134,152,57,8,232,27,194,74,1,108,71,25,137,6,241,41,227,235,175,184,206,122,250, +81,229,239,85,110,196,153,11,120,104,149,214,92,229,249,204,5,152,253,18,61,11,129,96,31,78,114,70,176,131, +228,206,6,201,96,208,244,11,150,100,222,82,111,119,238,134,134,229,152,47,136,117,43,142,221,92,230,161,251,240, +159,236,28,58,197,120,105,126,80,124,130,90,252,32,227,29,206,69,238,227,66,225,108,197,9,235,144,187,8,204, +28,254,134,35,201,33,255,239,141,230,114,164,150,143,212,1,240,97,245,143,191,91,145,173,183,154,194,202,101,3, +177,79,40,33,220,57,6,21,188,139,81,11,152,104,232,255,14,250,28,204,180,6,177,163,25,14,150,117,45,46, +37,125,122,154,185,211,226,43,119,142,12,223,102,76,68,124,168,224,175,206,84,46,4,24,149,67,112,214,122,85, +24,171,151,169,192,10,240,42,85,130,42,106,14,120,154,109,152,250,144,88,155,245,181,75,162,105,206,137,144,20, +149,182,212,122,136,187,98,43,151,18,149,187,224,84,177,222,252,12,85,210,153,171,156,150,128,95,112,72,50,174, +135,94,185,65,161,203,161,236,99,83,47,93,13,77,208,169,43,109,179,62,185,172,160,252,43,78,155,219,13,71, +175,89,231,159,158,240,63,107,211,202,114,115,79,88,165,219,29,196,95,23,79,156,124,151,33,93,178,153,138,143, +197,193,235,192,175,25,139,106,227,151,97,102,78,62,178,183,121,108,107,158,132,43,25,251,247,197,71,214,12,156, +206,243,154,222,34,184,154,174,120,3,60,70,112,61,93,243,190,56,70,240,242,230,230,130,222,32,52,102,38,243, +106,122,149,159,209,51,100,159,178,231,20,122,137,208,167,155,155,107,250,204,178,167,89,250,42,155,190,146,145,203, +95,101,19,121,21,121,175,48,60,96,41,172,206,211,226,91,149,190,201,232,121,225,23,75,241,67,132,143,239,241, +194,100,98,213,210,227,140,204,239,219,140,225,253,2,157,166,12,97,50,222,103,244,242,111,127,123,137,51,124,254, +140,141,209,113,128,130,106,177,255,112,102,181,203,182,91,233,75,30,21,222,205,94,203,34,221,115,57,208,6,154, +80,212,136,141,192,83,171,18,25,134,79,122,163,105,61,129,249,31,8,16,157,32,17,81,222,106,195,6,218,141, +167,25,189,129,130,86,75,207,177,227,233,152,249,98,244,27,95,253,217,126,148,249,125,203,31,167,226,129,145,236, +112,44,152,59,248,108,135,234,41,135,127,84,233,231,108,26,208,185,231,244,57,203,159,2,162,227,246,50,131,99, +40,24,15,177,78,83,133,157,226,174,220,220,112,101,207,211,72,131,244,155,113,116,18,238,248,32,22,163,19,151, +254,151,208,137,220,151,99,201,4,216,195,105,104,166,130,113,34,60,118,7,106,17,16,65,45,46,26,160,22,73, +136,81,139,219,230,175,144,69,107,7,68,43,183,201,37,227,194,101,248,45,14,116,50,7,213,21,136,101,184,227, +175,163,77,112,137,77,176,206,232,202,108,154,101,54,93,74,93,249,210,109,154,211,194,125,224,222,246,8,22,40, +79,93,24,11,214,105,26,167,199,107,214,62,8,188,118,251,108,35,251,12,250,130,116,26,238,51,134,48,25,12, +124,193,76,186,217,103,41,22,203,138,209,7,98,158,80,248,221,118,54,61,75,63,101,249,167,52,124,129,196,253, +62,141,86,237,65,180,8,227,111,74,199,123,207,165,70,211,97,208,58,115,159,214,103,52,135,2,116,43,223,247, +217,118,223,252,46,70,119,20,178,227,190,125,182,131,114,41,59,234,42,218,81,167,116,53,236,168,83,183,163,214, +140,67,57,229,148,27,189,185,225,98,167,177,172,130,43,241,38,209,68,112,31,91,25,63,80,221,155,242,77,100, +229,226,91,119,214,110,34,235,46,86,202,7,69,68,255,250,174,202,166,12,190,251,196,112,138,183,55,121,101,158, +212,158,122,121,132,132,178,175,3,175,187,47,236,222,62,8,76,136,200,196,48,19,81,9,231,251,11,14,82,78, +66,245,66,145,57,201,218,176,240,231,254,80,228,43,11,102,121,250,141,242,175,139,182,249,23,190,174,103,161,233, +143,184,206,167,70,209,76,209,165,162,95,212,7,250,85,21,63,43,199,92,253,164,51,250,93,21,252,48,253,139, +125,121,158,191,210,100,31,164,231,191,170,109,54,129,210,135,19,165,238,179,238,98,64,5,221,146,59,248,125,156, +223,223,114,137,51,233,205,117,13,183,5,183,13,26,15,127,173,130,64,182,181,104,236,59,22,218,57,69,190,224, +243,221,53,178,109,27,115,45,246,91,229,73,25,207,183,165,9,23,86,217,10,186,127,237,173,154,125,223,169,61, +5,70,105,195,200,162,254,80,18,9,221,52,187,138,113,76,4,255,41,158,63,188,191,128,170,196,78,78,156,89, +168,161,131,198,214,64,111,240,103,6,132,30,93,64,21,149,87,117,35,31,22,119,123,188,85,198,6,223,94,185, +153,86,251,18,20,183,45,51,186,27,82,36,26,205,45,112,110,22,145,143,153,79,221,20,49,161,193,118,164,221, +161,202,71,46,33,118,39,38,251,178,55,138,19,57,220,6,99,73,186,248,43,35,43,234,237,236,140,247,188,26, +119,198,123,112,143,99,205,73,101,56,126,175,14,232,12,241,76,173,43,162,184,134,72,210,128,165,168,205,228,87, +254,58,209,41,201,50,2,101,0,155,65,154,187,227,22,175,29,58,144,245,64,82,129,47,151,129,249,222,133,200, +235,197,141,159,153,61,232,54,163,200,141,237,142,108,96,232,70,240,129,66,193,111,110,98,124,229,222,121,15,42, +130,124,238,156,121,11,244,238,170,162,123,52,155,116,124,93,193,117,148,62,23,66,118,157,169,226,105,218,240,12, +164,101,6,49,47,149,71,206,232,165,168,196,164,62,161,80,254,150,233,94,106,138,4,102,154,33,142,74,251,1, +248,37,132,44,92,5,139,73,118,83,139,142,49,1,127,203,94,250,253,135,33,1,232,203,200,12,10,252,81,85, +237,117,48,162,225,226,168,104,71,72,84,149,1,249,16,109,1,70,68,198,196,187,196,114,123,101,236,139,180,166, +136,211,168,241,55,223,188,73,60,80,115,11,16,62,115,164,228,67,210,165,203,240,168,48,232,39,178,61,139,56, +238,2,27,26,5,38,216,37,34,191,82,189,228,84,100,94,218,24,238,84,117,6,11,74,70,27,180,160,130,145, +56,24,183,177,99,47,48,247,120,203,105,159,163,244,173,151,169,66,229,202,210,58,1,112,77,142,46,231,73,91, +112,93,246,30,85,23,173,109,179,221,109,147,20,48,6,163,140,86,45,225,119,238,169,234,96,171,182,72,26,238, +1,144,143,187,213,156,75,6,238,131,118,146,112,190,208,211,180,245,116,20,12,53,147,229,54,34,17,59,165,10, +5,212,146,239,166,54,83,149,75,219,163,214,147,198,182,173,71,43,114,212,231,109,112,192,10,97,225,0,168,219, +7,96,162,246,186,222,76,255,172,243,163,99,6,100,247,205,221,5,221,184,222,242,233,99,181,186,209,224,225,104, +226,105,15,244,181,177,189,255,74,23,51,174,166,227,245,99,168,81,254,157,34,124,114,94,150,76,146,74,235,46, +192,218,252,23,225,0,107,189,106,184,248,37,62,182,12,97,20,118,96,32,195,46,236,133,36,46,197,159,109,34, +152,99,189,15,21,167,133,119,30,251,176,113,122,208,221,145,164,91,97,119,26,116,199,160,252,68,132,88,100,211, +69,143,254,67,64,140,234,50,176,208,139,93,28,171,165,123,166,23,167,214,88,33,221,121,95,152,114,29,167,109, +160,222,149,69,186,24,155,50,86,97,9,29,153,58,250,99,110,190,3,215,87,230,137,163,49,163,228,118,252,158, +251,171,216,29,134,230,18,159,82,197,202,42,154,85,197,71,92,43,45,202,225,246,242,193,63,231,247,189,23,137, +123,222,212,97,185,28,8,82,159,70,142,38,190,136,119,137,125,165,125,223,229,109,232,99,177,12,76,124,20,253, +160,235,177,24,57,129,75,131,33,149,88,239,210,174,232,145,113,21,202,62,228,81,89,57,234,253,72,216,203,171, +22,135,28,58,31,131,73,176,95,4,43,98,179,108,233,194,109,155,232,246,75,190,125,86,134,238,54,156,3,136, +113,71,84,212,142,57,130,0,62,19,183,47,237,145,104,87,164,171,50,243,254,75,97,161,197,251,228,3,187,91, +77,36,69,27,211,5,40,143,145,245,166,233,135,233,210,22,47,242,74,212,34,176,80,62,203,186,38,150,131,51, +239,2,155,35,75,66,59,127,177,201,105,112,27,115,63,17,47,206,112,131,199,87,137,201,68,97,240,173,175,8, +19,158,42,255,196,117,90,30,38,51,9,38,121,121,168,48,242,121,151,26,184,108,138,91,56,217,126,146,226,125, +195,148,217,212,164,112,25,249,53,255,39,242,250,209,234,2,221,220,216,128,57,116,7,11,167,216,200,80,224,234, +32,112,4,65,27,12,130,188,244,81,241,75,48,220,58,237,37,9,211,123,94,226,240,161,34,194,145,209,6,175, +52,132,208,28,240,162,84,180,201,56,196,43,10,191,252,224,116,140,29,24,75,149,174,133,111,130,221,19,174,205, +238,118,112,186,168,232,126,194,60,240,125,101,164,161,141,155,179,104,34,205,75,213,10,111,186,189,156,40,62,200, +85,1,236,67,248,5,100,164,49,171,228,156,146,26,105,160,91,4,162,216,121,159,155,148,246,128,40,248,75,213, +176,196,234,137,123,148,31,212,63,199,45,23,119,97,70,137,151,102,243,142,201,72,18,99,153,54,50,108,135,189, +216,42,236,112,207,53,22,61,88,209,237,240,76,10,186,78,37,134,5,139,202,162,241,115,29,19,1,16,188,108, +98,213,220,207,74,217,58,232,238,178,44,44,234,58,43,73,196,108,70,136,61,238,184,133,156,27,57,97,85,38, +97,196,127,117,224,32,232,177,177,204,10,210,108,216,199,211,211,180,119,203,16,216,106,13,195,93,150,197,148,228, +194,38,235,52,35,235,29,211,57,62,29,195,40,14,197,75,191,4,161,5,219,223,46,30,164,38,176,32,156,80, +59,238,36,88,138,155,167,13,66,162,36,197,27,73,208,99,248,10,143,7,72,197,144,5,39,149,126,235,241,153, +137,15,72,122,56,43,57,181,174,25,147,161,206,32,172,153,33,43,28,144,135,2,51,65,226,95,29,12,56,97, +22,227,132,132,217,156,90,117,224,243,149,53,207,151,81,123,50,19,97,219,140,24,222,162,133,217,56,90,40,205, +49,107,178,69,147,126,4,135,119,159,230,106,113,225,29,210,46,92,151,231,69,115,178,248,48,153,239,237,200,146, +108,26,31,75,138,57,196,40,184,88,253,70,111,140,44,240,73,173,120,145,191,227,49,79,209,207,185,233,231,180, +150,174,207,179,124,227,66,91,51,142,152,253,2,103,15,12,7,57,151,74,34,206,154,23,27,183,236,7,8,53, +152,29,29,119,143,20,207,170,91,192,110,127,56,255,135,129,254,11,99,115,228,38,147,126,208,43,7,4,222,124, +191,230,244,20,78,114,196,60,136,136,99,156,182,210,117,153,145,143,93,70,177,43,142,201,94,105,171,69,173,47, +253,73,12,38,199,143,244,98,193,135,250,23,149,90,174,122,234,111,215,202,149,81,54,35,17,73,253,169,41,172, +18,223,196,8,74,225,28,252,104,184,16,231,235,126,167,24,226,83,252,244,185,59,103,152,227,111,247,165,59,143, +21,36,202,102,188,206,10,127,122,198,210,177,247,44,56,123,30,24,5,127,78,56,120,48,180,235,248,38,209,54, +192,21,176,209,127,135,204,216,206,231,94,75,125,22,52,134,233,21,41,56,148,38,160,87,204,63,100,157,154,231, +95,48,31,251,34,78,80,246,39,42,50,189,45,3,111,193,29,178,142,18,39,131,107,53,24,102,49,15,238,179, +201,184,82,198,88,234,248,132,125,66,207,229,37,239,169,157,148,118,244,112,68,130,89,170,216,104,28,78,114,78, +151,195,171,249,58,80,59,128,14,148,162,207,225,233,13,47,209,35,209,210,181,8,24,176,106,220,64,227,163,130, +104,154,145,141,11,109,66,126,20,79,67,75,117,82,157,213,220,172,46,127,96,12,208,223,129,1,66,123,116,225, +185,98,192,31,212,22,81,109,212,24,227,85,139,254,126,107,126,204,249,183,215,107,142,242,127,76,47,191,204,225, +19,97,184,55,156,11,102,101,187,34,59,67,5,59,66,237,237,136,100,112,189,146,38,135,205,97,178,190,162,228, +80,227,55,75,72,141,110,151,175,186,68,84,223,78,25,199,122,245,170,252,162,36,31,251,22,174,0,242,101,185, +157,176,95,35,241,126,117,4,111,46,63,117,230,217,98,241,83,67,62,131,175,140,43,248,172,170,230,112,194,171, +244,104,22,212,1,139,31,130,98,24,106,134,199,230,98,26,55,171,138,50,46,24,219,109,47,102,154,142,83,206, +119,135,180,192,12,64,87,102,65,94,236,160,234,148,243,66,151,81,158,164,243,37,196,239,42,127,22,230,58,135, +202,227,142,136,122,156,35,127,159,110,180,215,33,164,103,173,188,29,3,220,150,126,191,85,202,249,142,105,239,69, +175,117,205,123,177,238,241,119,84,157,67,71,6,98,171,132,251,32,226,79,170,78,146,50,97,203,80,205,54,11, +188,194,67,88,253,63,153,187,174,245,198,117,28,252,42,10,183,68,58,166,187,227,196,242,106,124,122,239,229,202, +147,111,62,154,146,19,109,108,49,43,217,41,39,227,125,159,125,141,125,178,197,207,34,75,110,51,115,183,167,36, +12,5,54,144,4,1,144,0,174,102,130,129,144,176,158,156,15,216,97,109,11,87,218,162,138,192,99,113,53,96, +56,198,145,238,244,71,250,181,14,170,25,206,134,148,94,32,221,233,15,145,94,35,221,157,37,128,159,107,24,217, +237,81,58,214,249,50,150,148,190,143,68,107,161,164,185,129,188,165,63,104,152,165,29,43,95,82,134,36,118,52, +223,102,61,80,22,97,85,34,114,196,140,210,63,80,66,220,208,198,23,89,150,44,248,13,101,125,110,117,115,156, +124,111,240,71,72,208,79,17,83,25,2,17,61,227,121,118,226,244,243,111,118,77,3,31,65,39,126,122,204,182, +17,218,74,27,204,71,242,151,225,248,69,164,185,190,34,226,119,219,42,14,70,226,39,254,14,96,223,215,192,222, +56,107,135,13,255,161,246,65,239,248,149,29,146,79,79,50,137,255,53,107,72,170,69,131,181,219,172,1,151,74, +5,156,49,208,49,188,164,163,227,118,63,178,177,113,105,220,53,47,54,182,177,136,157,185,74,30,24,191,163,219, +47,83,122,92,191,141,174,252,72,206,208,136,113,170,12,194,175,188,179,168,70,179,249,114,219,114,96,223,19,217, +213,139,53,155,249,207,1,127,166,3,170,214,195,10,10,105,201,217,153,164,106,37,252,232,101,245,193,148,241,235, +252,59,52,177,9,73,237,123,211,162,189,187,3,168,243,28,12,145,231,51,186,23,54,110,194,103,58,34,34,108, +45,122,220,252,238,210,195,205,165,65,112,244,61,207,162,133,159,86,145,206,83,222,13,130,240,76,236,29,252,111, +223,110,177,112,230,176,176,45,9,203,172,150,49,235,248,77,135,89,33,78,170,240,127,192,152,158,160,110,193,133, +142,206,103,193,164,218,247,117,237,144,171,64,5,211,167,218,36,172,107,71,156,97,166,205,234,170,9,0,21,50, +1,132,224,230,35,244,179,232,7,46,14,92,84,89,68,48,254,61,137,29,230,217,69,242,132,33,20,17,42,10, +111,185,222,125,225,114,3,242,16,119,58,39,200,67,133,56,8,164,251,131,222,92,19,138,180,220,175,18,215,19, +133,139,102,7,95,221,218,17,214,195,213,120,49,161,62,46,220,243,190,22,211,47,53,137,175,108,100,48,254,13, +97,237,3,183,149,58,228,151,223,254,34,190,73,94,183,253,215,49,25,113,5,92,71,181,4,220,171,232,114,16, +212,33,63,187,205,213,178,2,155,209,103,21,1,184,62,90,69,207,48,213,134,155,78,31,30,163,33,120,32,108, +227,109,185,204,103,25,9,203,55,98,165,114,248,155,47,72,105,121,3,165,134,126,18,143,10,47,68,247,68,133, +243,139,24,72,82,26,97,243,43,80,68,141,200,217,176,215,211,136,76,137,144,175,146,28,245,215,26,222,33,92, +238,113,242,170,100,231,166,226,154,36,191,41,251,248,227,178,60,101,168,41,74,92,111,208,179,203,228,234,68,207, +174,250,98,230,122,54,154,205,123,174,103,87,189,11,225,166,56,158,95,94,212,209,49,57,20,235,48,77,138,93, +166,20,66,112,233,141,212,79,176,76,156,124,133,199,181,206,79,243,43,25,168,214,28,2,47,205,153,36,34,101, +98,55,151,204,159,30,199,108,150,156,26,199,176,27,159,194,220,153,137,110,104,100,77,194,223,138,86,204,163,135, +7,61,95,228,185,162,10,72,23,113,190,242,104,55,120,172,225,60,20,195,214,65,20,158,240,202,243,157,237,116, +74,138,254,126,167,176,62,188,130,234,144,43,54,46,123,56,188,24,92,178,192,218,68,25,132,15,71,243,190,67, +248,101,28,119,52,194,153,105,221,251,198,205,39,33,77,225,188,36,140,41,240,60,148,255,37,245,24,183,187,190, +129,229,182,204,142,198,164,48,135,191,121,118,42,120,161,97,194,114,112,92,75,214,97,103,3,214,97,239,37,2, +79,34,105,201,15,108,170,76,97,205,133,234,98,14,13,234,85,105,165,54,177,209,44,237,217,16,171,44,33,125, +40,145,165,85,4,221,136,10,184,45,219,40,3,159,113,91,100,101,161,187,27,19,68,215,108,146,157,213,84,33, +90,192,253,160,119,117,114,15,131,70,213,22,45,202,12,68,124,170,140,97,116,84,133,209,73,35,198,12,189,170, +86,85,99,205,172,204,101,182,132,207,254,100,65,41,248,125,83,124,145,209,217,155,35,216,150,223,193,216,38,251, +124,132,155,188,40,210,225,153,82,167,253,129,63,70,83,41,200,191,77,234,65,196,189,19,131,0,77,113,131,184, +148,151,118,129,149,187,91,128,152,173,51,56,109,70,175,10,77,187,205,253,119,185,202,199,206,72,162,32,242,2, +213,232,220,47,184,224,47,134,181,94,235,225,64,213,109,38,79,185,176,175,252,240,238,67,37,8,166,68,107,193, +244,62,249,144,105,171,66,58,225,95,51,249,133,34,225,6,17,12,117,148,12,74,104,127,117,187,108,208,196,126, +6,203,237,146,168,9,220,218,224,106,208,57,222,19,75,1,149,225,98,59,179,67,52,187,184,79,36,145,189,119, +117,152,10,2,19,213,168,83,110,255,56,76,35,184,134,75,251,185,182,188,39,180,5,19,160,55,215,157,29,245, +59,167,87,110,173,23,103,118,61,130,96,84,56,221,223,116,144,49,68,60,63,184,134,45,109,48,80,126,96,55, +227,96,52,74,222,65,229,220,71,207,14,187,244,0,6,38,53,3,111,174,136,220,171,242,209,58,172,89,75,7, +34,83,117,13,116,194,7,115,65,191,186,215,92,210,175,222,53,95,208,175,62,180,115,47,105,12,203,165,144,68, +83,125,69,89,112,45,39,132,210,134,192,251,65,220,135,139,205,56,35,148,77,240,3,247,74,171,194,69,144,14, +115,147,194,23,93,149,224,250,123,72,145,166,55,91,251,243,77,222,202,141,25,47,34,100,48,171,235,172,171,205, +45,236,173,123,117,165,34,218,75,230,20,140,217,89,201,53,59,53,23,228,244,131,0,159,127,241,233,31,95,253, +253,239,246,215,153,178,231,17,120,89,123,30,61,172,147,166,22,224,155,11,133,184,135,158,20,89,166,86,222,44, +241,8,241,49,120,77,225,101,42,107,206,168,96,65,223,147,236,33,205,85,166,181,107,30,137,217,222,139,103,116, +84,161,119,14,157,240,185,183,65,161,103,66,152,71,90,0,146,152,239,60,179,161,189,149,162,47,113,42,197,42, +161,74,181,184,157,55,181,214,25,203,161,86,51,179,23,237,152,82,1,126,202,47,85,122,136,37,88,177,36,166, +150,173,232,93,124,250,108,229,116,159,1,136,5,52,213,32,59,160,27,214,200,230,172,91,53,158,9,96,52,107, +62,199,17,131,12,213,212,248,40,242,102,138,203,130,195,88,183,44,26,104,65,123,89,164,137,55,29,54,71,215, +175,103,86,31,87,126,110,149,252,91,61,86,75,48,222,13,225,129,59,119,18,117,169,47,10,166,186,246,66,204, +172,113,183,131,151,120,176,83,246,124,119,237,155,101,47,246,150,125,17,137,169,50,11,189,104,165,241,245,88,34, +136,82,209,108,242,220,41,183,55,201,196,119,141,113,180,18,132,194,249,39,52,213,230,181,106,165,182,9,199,146, +3,61,49,245,85,244,220,84,98,241,15,105,119,134,45,183,160,114,54,107,186,184,246,203,155,146,116,42,209,169, +154,15,139,101,253,222,1,142,244,87,174,158,196,13,43,215,206,236,121,70,195,202,245,176,140,178,61,211,157,105, +52,198,174,188,233,127,86,239,13,70,97,179,104,32,126,94,38,3,93,14,3,62,90,192,32,109,86,45,20,140, +235,245,191,170,151,166,165,91,255,30,213,191,7,155,210,42,182,134,246,131,189,16,7,219,55,72,48,52,7,41, +14,44,132,93,75,125,68,13,189,15,165,242,254,152,45,62,168,65,133,1,53,111,35,35,253,114,178,45,97,59, +91,115,90,98,162,188,151,213,207,106,209,19,142,69,19,52,109,76,89,35,110,156,255,59,98,231,100,169,159,82, +146,93,159,7,118,38,233,231,194,9,31,235,113,86,121,4,93,147,91,51,237,117,230,222,93,135,73,154,250,44, +194,165,67,17,209,64,17,136,225,217,24,52,26,247,179,92,233,64,54,249,126,110,199,250,91,201,80,142,138,61, +86,1,80,162,66,51,78,245,198,97,45,1,94,92,25,59,32,251,19,111,246,163,210,66,56,107,233,35,6,25, +38,133,172,242,180,209,217,229,95,22,33,227,4,172,174,237,112,14,189,145,113,47,187,203,90,99,53,217,238,28, +180,197,194,22,34,162,179,114,111,1,236,131,28,231,207,241,117,198,168,106,218,172,59,209,93,42,215,143,57,158, +111,233,1,97,218,236,139,161,223,110,147,100,21,84,255,0,0,124,123,71,55,212,190,170,152,129,167,209,177,104, +137,10,156,207,170,226,97,104,44,168,183,80,149,87,17,142,60,2,116,60,216,78,112,196,148,235,239,97,61,216, +97,90,125,165,248,184,227,17,178,208,10,113,51,17,90,8,41,113,175,215,229,190,201,190,134,100,88,34,115,132, +233,255,38,222,3,137,33,142,196,1,87,38,182,50,161,181,253,209,95,60,83,239,31,191,146,175,161,134,178,173, +20,208,80,48,239,163,54,227,59,128,232,0,130,209,3,30,167,84,8,237,88,106,212,156,237,127,22,42,27,35, +226,241,112,192,89,99,182,82,194,95,103,73,33,197,125,226,39,153,84,49,53,243,205,103,78,211,236,127,251,219, +79,63,90,49,43,157,63,19,162,233,31,211,106,192,223,61,131,185,153,60,251,178,166,234,175,168,62,51,181,79, +227,250,12,28,155,115,68,160,211,172,123,60,28,156,82,114,200,97,201,48,95,116,228,192,49,204,189,190,4,243, +44,78,170,80,169,170,74,24,143,136,50,160,100,86,190,179,182,132,154,217,248,158,210,43,154,216,254,179,40,15, +236,120,23,175,214,38,176,147,156,174,27,13,237,100,179,216,62,31,42,157,198,143,9,110,76,0,128,245,233,18, +123,109,156,119,193,135,247,26,209,13,75,23,70,248,246,246,109,103,108,171,160,214,154,93,186,76,170,8,160,105, +38,23,107,90,253,161,240,113,139,111,239,168,241,87,23,204,58,198,127,10,85,98,56,234,2,85,214,6,53,205, +142,40,46,92,127,200,50,85,249,200,225,163,78,231,146,2,109,247,72,153,48,232,140,70,221,32,132,84,117,209, +237,95,132,135,36,165,151,205,142,170,251,168,160,226,184,96,35,125,34,11,245,14,71,189,227,163,144,131,126,103, +43,46,75,232,95,252,119,84,143,16,173,116,10,224,87,180,141,20,75,82,206,11,36,127,159,57,157,33,67,192, +71,115,166,190,216,188,144,245,91,195,214,128,153,119,137,217,132,221,175,115,56,74,188,89,168,153,88,48,78,2, +237,115,142,155,228,144,253,247,63,94,175,211,235,120,159,39,89,90,120,63,83,45,119,130,46,195,61,255,207,133, +74,115,37,239,90,249,58,96,155,0,19,53,140,47,223,33,219,24,177,96,76,131,76,122,67,12,24,169,161,156, +155,148,148,98,104,82,226,114,4,20,108,21,62,35,97,209,211,194,73,99,55,195,172,147,152,205,112,236,157,73, +235,175,181,115,159,107,91,252,34,89,204,91,111,200,253,92,25,232,138,234,66,204,114,198,107,1,247,25,108,6, +40,59,201,217,134,79,115,227,192,103,15,100,177,94,102,133,183,92,53,251,128,162,234,151,62,45,226,163,208,205, +110,207,187,111,74,125,13,154,196,76,11,250,16,74,136,82,77,78,22,66,11,181,146,182,177,110,160,169,255,155, +196,71,171,181,39,117,47,218,127,110,104,31,219,205,69,156,216,9,119,111,158,54,168,196,53,143,71,214,235,251, +242,15,243,10,141,240,245,211,239,159,104,49,106,114,12,242,76,195,252,182,150,80,88,31,129,154,152,30,134,229, +16,241,16,141,169,149,176,62,83,223,115,196,71,49,68,144,248,89,44,155,35,157,88,198,205,225,123,149,197,197, +109,83,199,90,247,238,87,77,221,104,207,66,235,184,236,7,225,115,26,147,242,116,50,205,16,124,220,91,230,101, +49,59,162,151,237,157,104,56,181,83,0,228,83,141,214,247,116,200,30,154,54,199,106,238,140,133,35,109,250,60, +41,204,54,69,6,219,92,115,59,147,248,51,100,186,121,198,237,180,166,249,242,81,228,137,134,68,116,245,122,150, +171,187,204,164,94,90,151,140,84,159,188,77,228,93,18,99,253,252,203,183,205,111,33,105,79,171,12,64,184,250, +11,171,98,153,229,151,43,149,110,104,37,99,240,7,241,149,74,69,139,205,60,208,242,153,247,165,45,229,49,90, +187,252,67,49,189,248,255,199,244,34,41,232,214,52,89,190,15,174,29,236,123,97,219,1,127,40,190,93,57,96, +28,56,127,239,189,208,223,65,53,9,93,102,128,140,239,23,213,64,30,190,154,36,171,35,211,20,19,82,38,247, +171,144,65,246,224,248,209,186,249,147,213,134,238,200,6,17,21,26,229,255,216,187,14,230,104,109,32,250,87,20, +210,19,144,181,234,242,180,244,222,147,41,233,185,54,231,155,15,151,225,59,183,148,255,158,183,128,174,216,184,59, +61,3,39,172,135,244,180,160,93,173,88,138,191,231,229,226,192,241,180,27,108,174,27,55,248,0,30,103,240,16, +124,85,216,231,122,30,254,175,255,204,179,250,110,217,238,47,236,110,145,27,213,252,52,247,252,160,128,14,46,166, +211,26,58,149,207,194,233,98,186,220,131,231,213,71,103,69,185,215,62,168,149,115,39,139,217,233,27,135,103,187, +133,18,74,104,139,21,88,118,213,36,169,40,207,246,235,3,72,187,183,92,30,237,238,236,156,158,158,202,83,35, +15,155,249,142,86,74,237,180,242,20,93,153,51,152,201,147,98,168,40,165,148,118,186,221,191,117,199,49,95,59, +9,120,232,195,39,179,238,205,9,112,117,217,170,149,25,100,144,0,221,87,175,118,115,166,106,142,107,158,52,204, +78,102,136,137,77,51,39,219,226,154,22,87,235,197,152,159,225,41,74,62,188,162,60,111,211,254,92,104,187,62, +19,248,187,87,234,201,162,153,128,121,139,227,83,24,87,229,178,20,207,90,253,198,235,201,23,229,33,66,111,139, +37,115,74,131,105,11,154,32,141,237,121,183,109,176,81,153,245,8,211,195,53,39,40,63,38,47,131,143,201,218, +80,6,25,41,120,252,156,120,147,130,36,235,66,136,12,91,50,201,144,10,2,40,32,231,131,7,106,146,38,128, +64,163,164,168,13,69,3,180,39,51,160,136,210,69,175,144,47,99,38,227,178,94,133,24,147,6,216,113,185,22, +69,125,229,156,41,83,207,165,157,248,136,104,5,67,76,223,226,76,172,100,244,206,90,235,75,8,164,130,85,214, +36,1,84,59,175,172,107,81,8,150,130,21,73,70,155,180,138,190,101,8,46,161,136,23,31,121,105,86,176,89, +193,111,58,153,116,138,81,135,200,176,73,41,26,235,132,147,49,146,209,164,93,73,154,143,207,49,234,165,182,104, +218,88,6,59,54,48,64,74,165,200,59,135,178,212,179,69,17,248,48,44,80,3,52,179,1,245,14,82,146,9, +160,200,108,56,104,37,173,214,41,105,8,97,165,39,159,8,18,15,119,211,55,69,201,122,241,25,122,181,74,250, +162,98,160,207,243,64,199,207,236,94,52,122,118,34,98,127,92,161,222,45,141,24,186,221,143,166,24,150,68,63, +217,89,57,176,113,83,108,111,143,151,203,195,75,173,142,151,7,2,191,234,168,89,236,143,154,243,110,124,237,70, +190,26,79,108,236,46,187,7,119,126,187,52,198,100,2,12,106,180,26,84,111,30,17,178,149,145,223,28,113,200, +15,143,56,3,99,66,23,45,134,247,99,51,255,104,116,142,200,184,190,169,216,168,65,12,189,26,35,34,62,60, +32,12,91,126,185,122,174,14,78,247,112,201,143,208,37,37,72,99,125,121,211,202,135,141,185,235,251,254,187,228, +111,30,214,124,163,183,53,240,36,136,222,99,115,174,141,244,166,178,210,248,17,9,18,138,127,21,73,103,145,232, +88,87,78,96,135,228,242,156,40,94,42,169,146,36,55,81,66,42,39,56,141,128,64,102,94,239,40,120,177,16, +112,180,206,242,126,227,55,171,116,53,46,114,139,142,187,70,179,27,100,132,53,109,178,121,91,73,109,196,6,66, +6,2,91,250,8,164,104,218,188,183,85,94,85,26,174,52,187,204,236,253,223,64,87,136,98,216,143,182,247,240, +254,171,94,244,127,47,250,214,59,54,184,116,7,47,58,36,215,23,64,48,111,195,164,47,93,34,102,38,106,165, +13,107,105,215,194,70,144,115,145,91,145,87,111,34,40,113,77,11,228,135,154,208,185,137,27,61,194,189,156,65, +241,42,7,20,94,90,95,37,35,204,56,236,21,134,237,38,79,177,111,244,25,53,31,78,119,153,249,167,120,140, +255,61,198,255,30,227,46,83,153,250,162,98,226,162,184,57,135,85,252,179,117,19,215,187,136,16,236,221,65,49, +239,175,123,90,73,35,200,72,107,214,61,196,202,230,164,119,175,183,221,199,73,139,99,191,150,20,5,37,198,248, +215,195,142,181,107,27,194,95,177,10,216,104,223,37,29,108,193,42,72,250,80,87,160,10,149,52,126,171,89,114, +50,110,41,18,114,140,214,86,106,43,195,30,234,108,42,158,177,80,117,47,141,193,154,49,106,161,16,177,102,72, +87,146,168,150,42,241,118,194,22,227,144,233,12,199,0,115,79,129,17,80,164,118,68,160,21,156,172,141,5,120, +172,101,112,149,221,144,22,172,6,38,41,117,64,105,235,94,79,82,147,64,146,165,235,78,150,1,196,112,70,13, +240,209,54,148,184,92,66,125,210,130,147,30,6,17,89,233,227,70,147,50,180,93,51,96,61,95,176,226,179,249, +228,229,126,113,217,103,86,129,84,190,219,118,124,116,251,32,49,95,215,220,109,230,182,81,49,207,225,66,158,195, +217,110,226,214,176,126,223,138,112,60,106,58,58,252,1,166,107,11,86,11,14,74,241,171,24,203,197,17,187,95, +56,222,108,87,75,126,134,110,206,241,185,87,139,231,193,178,101,158,185,202,197,82,191,93,29,221,226,51,82,100, +207,221,123,237,92,247,101,174,204,125,181,14,166,131,231,78,241,120,180,92,210,3,67,240,57,74,126,187,123,13, +215,137,55,48,219,30,152,245,116,129,87,209,166,85,195,243,203,217,20,115,140,203,231,9,239,203,44,38,51,254, +0,1,223,230,221,80,246,10,138,94,222,129,188,203,173,189,198,181,77,237,141,154,41,71,87,209,96,94,74,66, +152,20,31,105,122,248,29,159,155,186,246,242,9,92,236,207,47,143,253,81,177,255,25,213,24,251,209,228,124,116, +176,252,244,171,215,161,201,205,100,183,213,212,93,28,233,124,198,14,236,213,179,253,58,223,194,254,157,72,42,88, +82,22,7,131,15,180,151,8,176,53,28,145,48,16,39,9,170,40,192,77,19,23,9,160,83,35,16,146,167,223, +143,250,167,234,63,1,221,221,164,155,102,143,3,239,86,232,70,14,23,35,156,126,190,41,212,178,147,167,73,187, +237,111,3,159,235,164,159,106,139,90,89,30,7,154,55,237,222,122,95,251,148,59,181,217,130,111,153,4,112,215, +244,136,4,126,205,212,149,174,52,190,203,140,63,139,65,204,76,133,154,69,129,149,131,104,73,250,24,111,137,111, +179,231,227,125,45,252,159,253,105,247,146,233,81,103,237,199,44,193,71,159,194,210,33,48,181,249,88,178,188,243, +169,251,71,7,57,156,186,220,217,107,17,76,251,19,89,168,138,91,146,244,29,248,89,85,246,189,232,63,22,208, +120,192,105,145,54,112,78,23,16,181,213,247,136,64,167,190,151,104,55,223,49,116,138,66,77,48,217,240,40,244, +152,33,141,112,143,254,45,57,7,100,184,76,85,177,123,215,167,77,91,21,252,167,118,119,179,44,252,46,27,252, +94,154,213,19,54,76,157,17,193,141,205,12,249,39,82,139,149,105,15,250,45,186,151,219,30,114,160,186,124,32, +234,112,43,86,190,233,38,225,30,244,221,169,191,111,137,254,151,216,221,39,179,161,229,120,12,126,185,229,47,119, +240,178,248,146,28,21,112,74,207,191,153,214,51,158,191,29,255,187,99,166,75,135,184,28,19,196,149,24,153,146, +125,117,218,60,234,156,195,30,82,213,67,60,86,78,172,235,60,214,85,193,52,79,206,46,124,15,36,134,207,73, +56,53,236,128,160,227,230,33,211,221,247,61,106,12,85,228,205,34,173,41,38,19,107,245,194,48,155,50,220,184, +92,29,22,174,42,143,217,216,231,6,112,11,188,61,111,96,11,7,52,14,207,137,207,243,243,55,81,222,87,148, +47,186,42,143,47,146,240,119,85,114,11,57,173,196,33,236,114,8,72,135,70,222,122,11,205,15,27,170,142,14, +205,63,9,205,99,43,85,55,49,167,113,168,122,172,216,139,230,231,41,75,171,145,25,111,185,226,243,196,158,112, +95,52,35,63,121,70,182,200,82,181,250,170,137,149,175,38,63,173,207,213,200,177,4,95,12,88,229,195,123,94, +240,159,46,151,22,33,238,130,102,197,13,178,89,20,54,36,97,35,112,136,226,112,100,173,103,193,179,94,55,52, +135,78,67,3,185,122,200,16,78,60,97,26,176,255,249,172,154,246,70,113,38,248,151,100,32,239,51,215,196,216, +25,50,145,120,25,32,30,124,75,240,60,172,241,100,114,240,238,98,233,215,111,85,73,222,36,151,61,65,235,163, +63,170,171,187,133,179,60,99,255,114,178,219,211,167,108,244,250,63,99,47,211,94,187,64,222,119,188,87,175,77, +0,70,224,34,236,32,114,235,37,27,156,203,31,231,211,217,173,105,203,194,199,135,10,186,66,5,159,154,192,179, +19,245,32,7,250,63,39,187,197,207,227,157,195,191,7,102,176,225,102,174,195,247,179,61,98,173,132,61,221,105, +32,3,171,181,49,136,189,148,31,173,49,88,51,252,183,252,247,188,7,28,142,241,95,122,129,139,195,30,124,242, +135,25,123,109,194,71,62,42,150,24,135,236,87,56,75,249,97,198,63,120,66,12,154,119,12,214,194,96,6,127, +188,236,120,202,195,217,122,98,141,253,87,123,73,252,242,194,87,126,247,194,247,48,111,121,15,251,13,109,231,145, +127,134,88,40,78,98,52,120,218,222,224,62,191,19,207,153,148,159,75,91,130,47,224,119,242,71,246,165,31,118, +225,135,31,200,215,22,188,150,156,244,120,225,75,190,144,147,69,91,110,176,254,244,191,106,99,110,176,175,124,216, +157,98,207,196,21,113,68,248,201,111,200,153,252,10,183,137,79,194,220,43,230,196,167,24,115,175,152,223,125,195, +186,228,125,153,240,15,117,171,220,44,184,43,187,240,245,221,135,31,226,111,206,60,184,178,65,157,88,216,70,44, +17,243,139,238,92,49,254,77,123,150,177,101,146,149,147,97,170,214,119,179,108,139,55,102,145,79,49,30,214,22, +238,108,223,132,67,6,92,127,72,134,111,168,73,47,174,20,240,173,128,255,209,62,184,237,132,93,99,192,71,226, +69,217,144,171,49,71,3,226,21,70,31,121,3,249,48,199,220,53,216,47,110,180,238,151,43,150,121,196,18,120, +48,182,136,145,248,66,14,75,54,246,2,156,10,213,14,214,225,95,172,147,110,196,89,96,248,149,56,85,208,55, +202,79,196,149,63,151,91,112,243,187,236,10,23,249,177,81,173,168,222,119,239,156,84,254,244,173,200,9,19,239, +54,177,38,62,247,2,250,11,63,220,12,252,196,43,124,121,119,137,177,40,151,180,159,184,89,49,118,226,20,84, +179,234,3,15,153,250,215,110,130,253,125,166,90,219,77,226,218,65,252,122,186,246,178,127,255,221,215,1,250,127, +177,175,153,195,140,187,253,36,125,63,143,183,204,175,179,33,230,203,33,175,131,167,14,96,163,126,48,166,120,27, +226,205,254,160,26,85,158,90,228,161,188,174,143,236,77,249,24,40,11,39,201,186,103,44,122,132,250,132,193,121, +238,1,227,129,53,38,238,226,76,150,106,71,50,185,128,51,226,157,112,246,137,175,226,135,248,154,75,206,132,43, +49,36,47,180,46,222,170,191,30,66,148,197,137,160,56,32,55,161,9,226,0,253,213,30,251,58,226,43,185,102, +63,212,76,15,157,167,232,231,61,102,135,47,86,7,242,220,179,215,77,156,55,23,96,93,224,14,253,212,186,230, +5,248,198,222,232,58,198,23,229,103,241,199,157,233,115,173,218,116,204,131,127,97,158,35,183,223,128,77,22,229, +69,50,247,187,178,207,200,9,249,32,126,246,6,88,45,200,129,176,23,182,59,198,30,231,2,250,24,108,87,127, +255,127,122,251,242,152,141,31,103,253,105,8,67,81,223,55,151,253,113,245,135,45,135,236,113,87,229,251,110,252, +179,190,223,30,89,119,182,123,122,29,160,123,223,157,140,43,123,188,117,190,251,97,119,19,246,120,55,189,116,230, +248,178,219,98,238,255,42,190,129,231,118,174,86,152,217,139,235,70,131,249,238,235,110,196,253,77,156,253,255,181, +79,110,160,198,28,114,80,119,19,223,4,89,205,24,209,59,129,239,130,90,204,81,123,55,110,30,113,198,174,190, +181,122,243,124,25,239,183,192,240,110,126,185,223,6,190,9,241,206,225,187,140,113,113,6,1,7,107,112,63,27, +66,143,220,211,135,145,245,4,236,6,225,2,253,196,12,92,26,249,46,41,196,149,174,81,143,112,177,215,198,190, +51,55,168,35,213,231,37,246,16,35,29,113,14,158,16,95,156,111,206,179,14,39,238,95,196,233,110,163,60,217, +89,124,242,88,187,1,166,70,185,67,13,167,185,121,137,181,61,104,134,160,135,21,207,229,38,104,30,202,47,227, +107,172,193,23,245,110,23,251,222,42,174,245,88,219,206,248,166,26,168,224,63,108,93,103,25,239,183,250,191,214, +76,145,234,119,5,251,140,127,37,46,207,39,214,130,177,175,136,209,179,118,105,87,49,228,105,254,200,47,245,150, +76,253,210,19,91,234,114,29,238,82,223,154,247,78,208,63,138,151,208,21,156,230,215,200,122,206,56,183,97,35, +135,30,143,53,214,37,125,194,60,184,13,194,61,52,185,48,125,207,155,242,15,219,193,81,199,111,189,201,10,235, +101,123,161,15,192,18,254,143,140,39,103,188,200,89,38,238,39,127,135,160,56,152,215,115,204,171,81,94,145,67, +245,139,148,87,245,157,56,15,6,229,137,231,81,143,75,156,29,145,27,92,251,196,141,242,19,55,152,211,179,114, +170,89,190,40,167,194,203,47,242,165,37,70,59,246,232,10,119,38,205,132,90,28,232,189,238,118,90,91,113,45, +241,149,249,36,30,178,169,188,41,159,250,87,62,165,71,181,213,175,196,51,190,111,129,53,116,16,7,63,4,203, +220,69,155,234,211,102,97,79,248,135,182,243,254,110,84,199,226,248,191,226,176,13,189,104,60,96,199,41,56,138, +95,239,213,147,173,57,57,57,128,197,68,27,98,188,148,105,30,255,239,123,239,85,177,72,152,243,234,252,224,34, +33,9,113,213,48,214,247,115,193,230,102,28,208,90,163,215,61,56,39,244,21,60,127,68,229,65,95,130,177,136, +245,176,115,191,110,207,75,28,67,209,196,220,231,76,232,254,225,205,71,104,243,41,204,61,83,184,78,106,163,222, +124,67,191,51,254,179,134,176,208,15,41,118,252,253,253,132,117,127,196,197,209,47,122,98,99,158,62,140,204,231, +147,242,185,121,198,128,245,188,198,205,154,69,70,219,145,73,177,55,43,244,183,213,52,59,209,223,206,112,3,167, +183,133,62,223,99,54,201,47,255,182,173,95,27,161,78,11,220,196,48,101,40,107,215,44,82,227,78,181,100,91, +95,196,87,67,196,174,25,163,144,117,33,195,156,37,176,135,234,94,53,168,68,104,170,242,5,70,141,219,91,185, +14,225,20,30,14,166,28,6,74,244,144,129,78,212,104,236,72,58,49,83,188,147,241,81,193,142,225,108,56,13, +146,215,222,69,18,121,38,15,21,93,101,138,62,2,145,188,16,112,31,246,222,60,74,67,210,52,74,148,26,1, +58,233,2,61,142,165,209,88,63,116,75,202,156,84,26,119,199,30,173,166,218,244,50,138,83,211,28,147,211,76, +127,155,204,138,136,190,145,164,218,28,93,101,145,223,68,133,35,29,105,125,226,216,40,222,201,7,179,21,202,162, +32,255,170,162,192,232,35,107,182,107,36,215,233,20,30,170,165,173,180,220,209,236,120,102,108,235,41,22,65,221, +90,161,40,77,153,109,202,232,99,215,169,159,82,142,189,226,65,45,80,62,5,142,38,69,152,138,134,136,22,33, +99,212,27,216,28,139,99,170,176,62,177,140,235,100,198,201,105,130,17,31,9,33,89,86,203,244,206,244,174,156, +109,43,172,133,18,249,174,64,180,107,249,154,250,228,218,110,115,109,174,2,109,95,20,252,123,129,144,217,244,104, +42,171,44,84,187,189,206,209,195,113,66,79,115,202,67,95,13,255,213,26,170,8,215,157,182,173,188,223,180,168, +16,92,73,173,93,237,106,73,186,67,213,106,93,243,72,25,152,97,224,245,162,77,111,215,119,71,237,82,24,135, +198,112,82,77,231,180,72,77,240,85,19,112,122,240,244,72,105,185,53,227,27,213,198,221,198,5,98,110,159,130, +38,17,183,127,99,106,151,77,251,109,189,152,12,27,218,219,71,202,113,63,159,78,183,127,102,71,255,218,82,156, +125,120,71,161,221,206,131,110,97,190,239,62,157,13,83,61,127,102,88,238,117,57,92,9,220,215,232,245,193,166, +84,200,134,124,16,123,95,189,121,54,120,64,59,151,163,99,60,21,147,232,236,36,158,77,120,163,101,4,185,84, +37,106,125,212,27,249,148,166,43,172,142,28,63,219,164,245,29,212,125,76,195,242,227,174,40,100,205,75,58,136, +165,47,37,170,75,121,135,242,192,113,181,70,19,63,100,39,228,70,37,178,71,113,131,229,187,178,101,188,59,20, +49,239,206,27,86,133,158,122,72,138,124,140,201,113,207,60,201,8,176,96,137,77,212,43,25,223,80,23,252,104, +214,235,62,72,145,57,112,152,94,8,125,57,11,253,145,64,20,84,18,1,63,31,53,222,213,132,78,50,143,211, +29,150,25,106,229,178,219,147,249,174,118,195,183,253,255,20,150,159,85,107,227,84,245,253,167,198,129,172,195,70, +24,241,195,102,111,10,218,224,202,99,70,101,81,136,136,38,212,195,43,42,232,95,223,125,251,101,219,110,150,218, +171,223,188,26,0,180,96,5,250,66,227,73,132,34,206,138,252,204,118,205,66,122,219,213,161,154,201,44,138,14, +250,135,205,32,16,193,213,151,151,151,63,142,62,91,46,127,88,94,143,2,235,188,194,36,37,177,16,75,188,244, +21,54,38,72,144,26,137,135,184,244,205,17,67,208,14,52,17,33,209,173,50,135,7,174,193,38,124,0,161,112, +37,152,94,218,214,112,48,212,127,31,200,213,83,148,224,182,105,249,65,28,69,76,159,224,165,106,111,63,169,229, +10,10,87,105,137,87,203,141,105,105,8,134,46,96,150,211,222,217,106,219,85,3,72,138,107,22,119,49,210,236, +159,166,188,92,135,240,124,21,28,13,201,223,69,192,131,167,26,169,24,224,129,6,115,213,88,171,177,158,146,253, +246,241,45,110,64,99,35,137,193,17,73,146,70,218,76,124,68,59,168,71,80,209,145,70,22,144,18,9,230,210, +54,85,101,51,14,126,198,222,59,110,255,146,246,167,70,178,128,59,61,205,92,20,229,119,145,88,71,185,17,96, +24,13,6,244,243,107,11,195,169,16,185,102,239,98,77,206,11,137,6,178,230,123,170,168,245,218,215,129,105,163, +71,67,188,12,107,9,2,108,189,114,46,161,100,117,143,222,233,234,59,103,100,148,106,238,37,145,3,169,95,214, +125,103,118,86,12,22,179,230,165,194,218,72,34,96,10,73,139,49,219,230,105,35,71,81,130,44,152,122,92,221, +177,173,62,32,102,115,189,236,154,51,153,216,41,175,199,40,224,11,217,156,50,78,19,255,111,30,33,177,119,32, +179,114,223,118,58,221,44,193,143,0,253,134,36,174,196,166,173,54,40,7,101,156,124,246,58,9,239,128,212,75, +154,27,55,180,42,119,247,125,164,247,100,216,10,226,118,142,242,58,226,81,204,61,241,112,239,238,149,55,6,182, +202,75,49,228,59,173,93,56,119,21,73,59,55,110,139,203,177,86,252,11,201,75,227,222,122,73,17,159,175,27, +81,67,220,13,82,241,148,246,163,197,248,154,178,216,194,211,146,34,21,69,222,32,92,68,126,229,148,251,192,140, +86,140,167,139,48,239,205,255,173,104,125,104,45,212,193,11,160,104,243,19,242,127,98,18,25,109,47,38,114,1, +147,118,32,206,207,207,161,132,61,47,192,51,195,205,205,63,254,254,217,205,179,103,203,155,79,126,248,254,242,179, +127,93,222,220,32,22,85,12,196,147,76,180,242,136,122,168,174,38,42,38,244,76,213,208,143,21,39,229,108,222, +121,128,60,85,35,15,14,141,212,212,75,147,68,228,44,65,25,106,46,154,133,55,84,252,243,105,211,212,85,181, +103,196,3,142,58,93,85,47,151,85,133,120,152,138,241,156,169,162,215,38,108,11,231,81,107,188,239,165,253,97, +141,200,105,129,235,132,109,236,185,253,50,44,215,203,117,13,36,227,157,145,4,186,69,190,16,165,113,79,246,9, +253,242,155,247,131,162,88,92,93,219,197,167,224,112,129,87,249,181,25,99,91,35,17,76,90,110,123,97,169,181, +210,25,168,188,239,177,255,34,30,153,230,34,247,198,248,115,145,89,113,225,92,17,230,208,176,30,113,206,92,117, +84,251,75,181,193,185,111,8,79,245,58,52,153,220,237,20,15,236,189,81,96,65,68,213,56,221,49,142,171,182, +78,28,110,181,121,134,189,236,62,199,49,109,144,143,97,240,39,24,185,129,214,20,202,159,165,139,25,217,228,228, +40,206,29,1,234,40,62,37,105,160,131,207,244,9,100,75,89,144,167,32,30,192,98,243,141,124,77,14,185,31, +223,216,32,73,43,133,32,138,227,213,184,112,63,189,23,210,54,71,141,71,19,137,58,85,156,72,126,41,192,42, +154,205,142,60,61,35,222,200,80,9,199,239,38,53,13,246,170,173,116,76,164,228,32,140,255,218,50,222,7,11, +133,19,140,123,89,171,214,132,143,48,172,27,72,146,18,249,56,90,165,63,83,237,65,194,153,1,60,169,61,213, +140,167,158,233,27,138,143,229,137,165,93,158,100,81,102,104,151,154,29,133,50,100,211,185,210,166,129,29,150,188, +16,131,157,205,71,241,128,150,184,234,221,60,104,201,58,122,225,235,194,109,150,196,59,222,133,5,226,221,161,203, +241,158,121,34,142,0,23,47,171,198,250,242,32,115,93,118,202,253,12,49,1,131,57,148,58,193,27,151,204,201, +160,201,32,45,98,91,140,179,9,3,249,65,203,4,105,150,67,245,159,223,170,255,222,149,247,235,106,243,191,186, +1,19,58,28,65,125,45,78,120,101,177,125,1,27,6,255,74,20,245,34,163,157,159,28,136,14,47,167,101,144, +245,237,91,21,82,72,50,75,48,8,216,129,168,16,134,53,36,89,206,201,25,241,35,144,19,24,62,6,99,167, +227,130,175,68,51,46,12,59,174,186,232,116,198,13,191,21,101,232,114,145,16,156,33,148,114,161,194,91,230,102, +34,248,206,18,140,225,47,196,189,45,58,115,40,186,23,23,25,219,136,251,171,12,101,228,136,117,94,233,25,240, +150,111,8,224,124,181,185,22,183,240,230,81,131,146,110,199,145,237,246,243,106,111,252,30,175,78,35,236,129,63, +35,134,55,217,105,45,183,60,116,116,174,199,72,27,95,99,151,116,252,17,59,87,159,71,111,223,230,23,162,92, +180,139,32,48,20,182,36,84,162,33,230,220,39,213,74,126,212,34,51,93,157,207,102,147,179,99,104,151,139,217, +241,52,62,131,92,135,136,206,42,225,2,211,126,106,56,192,216,57,164,154,64,217,233,197,236,100,122,52,133,226, +117,26,42,45,81,9,134,181,35,224,156,231,135,19,150,164,79,40,199,97,168,158,208,153,206,207,227,136,29,162, +158,230,152,245,101,244,57,157,38,81,40,155,231,84,38,5,34,70,131,124,86,68,63,71,252,51,86,149,167,217, +236,119,240,185,246,238,11,91,70,110,56,90,31,213,197,7,128,160,128,9,173,15,132,230,166,25,127,195,110,89, +97,11,108,33,42,167,6,226,20,55,170,228,154,98,204,3,52,150,184,175,184,218,236,221,225,215,11,42,51,169, +89,136,65,185,136,18,169,173,113,150,14,88,35,116,17,189,105,151,92,56,248,163,115,96,114,148,226,10,247,227, +7,49,188,38,240,154,194,235,8,94,51,120,29,195,235,4,94,167,240,58,131,87,10,175,12,94,57,188,86,240, +34,33,64,112,189,191,1,173,123,30,89,145,228,181,134,143,24,249,71,45,146,188,254,207,216,125,168,54,143,4, +1,0,126,27,97,35,12,211,11,103,231,69,14,153,26,64,20,11,68,7,225,103,191,217,40,46,119,127,46,44, +77,236,72,195,248,115,102,54,40,192,102,174,11,79,127,173,227,165,118,190,101,187,223,134,249,56,126,214,115,39, +11,8,183,100,219,160,54,165,195,122,62,251,182,126,124,124,144,30,199,91,197,230,177,130,195,109,187,175,195,210, +82,112,58,113,164,154,104,88,187,125,57,204,213,95,180,205,45,167,218,108,173,224,50,86,116,88,183,251,60,220, +90,14,77,163,129,33,104,96,182,219,151,195,82,57,190,45,149,131,85,103,174,224,109,172,232,48,111,247,101,88, +91,14,79,39,4,17,37,101,134,118,191,62,249,249,76,180,221,90,82,21,90,42,248,95,143,84,146,155,96,68, +122,167,71,167,17,9,0,2,132,186,65,86,117,196,153,24,89,176,87,228,211,73,212,65,51,184,215,19,211,136, +238,0,172,130,214,9,202,250,108,169,33,40,130,222,11,194,234,4,33,48,238,197,32,182,50,9,2,130,70,189, +30,164,2,5,136,1,91,80,39,8,171,21,4,88,16,1,187,61,173,19,20,8,128,40,161,27,245,213,12,108, +202,202,148,191,162,42,107,25,238,59,170,74,153,122,154,34,60,73,186,147,252,157,180,108,183,225,190,60,250,7, +44,21,208,152,158,166,220,73,252,78,186,109,235,112,223,73,88,83,36,236,232,142,252,18,201,46,138,119,209,186, +205,195,125,253,30,112,118,142,116,6,122,121,96,247,208,207,30,157,78,14,168,26,150,216,233,65,152,70,142,210, +64,112,47,167,202,152,129,120,48,107,47,71,90,39,168,178,135,68,47,39,167,81,45,68,76,56,122,57,173,123, +0,51,128,45,161,19,196,149,19,206,198,105,216,235,105,243,141,198,202,168,128,189,32,108,149,164,64,129,98,222, +73,162,233,164,40,192,30,210,233,241,182,247,176,50,133,56,247,130,176,234,96,146,25,184,179,252,42,186,46,215, +71,187,177,135,106,60,37,178,75,226,77,114,173,199,247,47,236,68,64,164,94,124,126,66,16,119,9,190,73,174, +149,243,24,27,12,78,96,80,163,151,195,118,135,189,57,174,149,244,248,241,23,28,82,213,94,4,254,34,228,15, +2,44,115,123,60,9,12,122,20,210,182,25,167,72,102,237,83,120,43,161,146,110,220,105,128,202,128,20,103,48, +129,46,5,79,163,5,146,39,186,244,40,170,2,107,40,59,17,117,33,170,111,157,72,9,211,179,11,97,211,232, +6,148,24,217,35,200,233,84,86,54,145,240,30,64,107,86,33,12,212,96,237,18,160,78,163,50,184,148,2,186, +8,85,34,83,153,195,20,127,49,44,215,195,109,171,241,254,254,94,49,195,24,66,228,201,176,157,97,79,70,177, +15,235,86,195,253,152,85,36,139,68,193,55,9,236,18,122,74,202,126,152,183,154,239,231,46,39,104,172,146,160, +47,141,238,26,127,106,202,127,88,182,26,240,239,113,85,23,22,80,125,121,112,31,111,252,17,180,255,214,119,0, +9,85,199,62,210,190,157,166,100,152,129,245,146,246,174,87,84,226,94,15,182,29,69,37,137,60,179,87,20,5, +10,103,70,102,205,78,16,182,141,14,12,209,69,122,61,86,28,53,192,12,14,232,22,241,52,34,67,162,162,73, +55,233,171,25,84,137,193,161,87,132,149,131,4,132,192,158,189,166,106,6,199,240,112,210,236,37,213,100,179,176, +132,170,226,255,129,218,91,207,101,29,219,229,107,133,211,229,86,43,220,87,52,93,150,90,209,190,226,233,50,143, +237,178,189,255,15,228,183,35,58,31,7,142,238,231,172,154,212,9,171,23,57,174,127,127,150,171,254,200,242,254, +142,254,121,28,15,255,14,140,120,60,159,227,207,48,85,24,237,207,56,87,156,228,31,238,174,132,187,109,92,87, +255,149,68,243,38,79,106,96,215,217,186,200,85,125,50,157,173,231,100,233,105,50,111,115,125,122,100,153,178,217, +200,148,159,22,167,185,142,254,251,5,72,137,166,21,58,147,206,221,239,76,91,75,20,23,16,4,64,136,2,249, +121,122,165,208,128,81,126,58,73,67,54,194,138,135,216,248,72,53,78,215,135,35,217,162,186,57,26,109,107,134, +235,102,154,239,23,16,17,120,227,122,233,103,136,174,192,33,189,84,188,62,130,206,33,250,160,104,209,94,190,134, +142,78,62,134,38,245,85,67,38,145,248,38,72,136,206,23,72,168,91,130,160,207,227,229,56,87,235,41,12,173, +53,45,74,121,50,127,17,180,159,121,144,174,73,224,193,176,7,143,254,63,2,197,153,148,26,60,240,184,98,204, +125,107,176,144,213,46,251,254,248,205,155,35,5,68,217,228,58,56,124,181,126,2,236,237,201,137,71,84,17,213, +220,83,53,35,39,117,213,35,76,168,249,24,6,175,158,37,16,6,161,14,104,113,145,229,13,50,134,219,125,54, +240,220,238,170,7,175,42,239,63,158,211,26,231,34,204,114,246,94,20,110,72,111,230,152,23,34,51,237,64,166, +221,147,58,145,137,14,114,250,61,33,132,189,154,152,114,61,112,225,122,224,196,223,114,224,82,53,112,161,12,44, +106,143,27,221,191,73,6,173,28,158,79,171,248,191,113,81,188,58,149,137,180,210,242,71,198,83,180,199,19,185, +255,111,53,136,121,51,136,25,16,24,158,228,106,70,164,189,57,238,103,68,42,90,67,54,44,222,190,125,245,44, +219,63,222,35,31,164,185,165,27,29,252,178,174,49,210,98,97,88,140,134,245,170,251,5,117,63,39,187,96,224, +124,232,229,97,107,120,220,243,225,167,146,214,73,58,159,202,159,241,191,145,58,214,91,45,217,21,193,99,71,171, +22,132,2,99,2,47,27,171,85,166,80,168,120,13,51,178,68,30,219,216,18,164,212,51,88,36,20,139,248,48, +107,153,229,76,119,139,13,184,159,26,120,203,198,138,111,29,128,22,103,233,252,157,42,218,124,255,149,223,189,90, +13,23,158,137,164,188,185,32,218,206,218,29,223,21,236,76,118,107,159,25,55,154,42,65,167,225,186,15,91,0, +235,3,134,252,51,107,129,108,32,124,209,29,75,46,25,97,95,155,243,133,193,91,67,16,68,231,128,100,224,208, +171,195,225,26,177,213,198,217,101,112,232,145,252,106,98,183,243,73,61,1,19,153,127,214,68,53,100,140,122,210, +44,213,59,39,19,92,147,234,29,134,227,232,120,140,27,206,95,140,49,122,234,245,228,53,45,235,188,140,240,76, +41,58,73,62,114,57,157,81,159,36,169,227,161,92,217,190,79,184,180,144,125,178,87,120,251,245,21,35,195,226, +22,202,1,119,89,253,155,201,95,205,109,233,165,171,252,89,5,214,207,209,134,220,221,223,27,55,15,195,197,140, +239,65,186,215,172,5,53,215,187,47,72,253,139,55,189,129,58,100,54,252,234,22,251,12,122,158,175,238,185,234, +85,181,189,37,43,180,109,99,230,3,98,177,33,18,144,4,12,179,69,244,133,44,210,221,166,160,41,84,207,18, +159,9,124,230,1,30,193,59,104,43,25,146,228,166,65,217,73,128,183,21,80,158,55,221,22,110,78,6,176,149, +70,212,64,2,148,93,202,111,238,1,151,81,19,48,51,122,165,66,129,108,223,94,168,124,253,248,7,46,194,236, +206,77,164,54,80,122,101,169,67,101,218,168,73,97,81,146,74,236,7,5,168,187,68,105,224,90,13,106,47,39, +88,103,110,158,152,115,95,170,231,62,13,112,57,3,225,26,133,108,110,140,217,21,153,43,216,90,192,214,177,54, +103,244,105,241,70,53,100,34,191,97,10,149,157,178,187,69,98,139,91,212,234,6,42,9,71,27,193,105,100,179, +32,50,248,129,93,144,95,84,22,116,62,53,152,10,15,217,102,199,100,178,25,102,248,144,81,142,179,49,96,65, +15,214,13,125,155,15,99,97,236,148,21,87,116,216,203,67,18,86,212,184,111,176,87,53,239,155,180,0,209,224, +175,201,81,170,137,102,109,179,145,252,65,35,133,173,163,133,180,217,27,157,213,194,105,244,25,211,232,199,210,25, +25,6,156,26,146,175,177,254,12,81,53,83,100,187,70,138,110,119,163,222,102,164,45,159,231,26,84,74,38,79, +254,30,134,166,175,21,214,190,86,184,246,181,12,50,10,124,128,194,23,146,211,21,42,175,35,36,167,75,160,183, +181,193,98,17,136,167,57,94,233,218,201,18,141,227,197,141,52,195,241,42,164,227,149,66,33,29,47,14,45,202, +168,247,116,105,15,188,81,207,12,75,36,161,22,205,84,43,48,18,167,156,34,136,54,188,143,133,43,60,95,80, +105,195,176,154,227,103,234,78,43,219,118,219,105,120,254,193,196,180,76,202,39,128,130,176,27,200,160,155,246,173, +109,20,141,233,163,49,125,220,102,250,82,87,88,252,127,139,193,147,239,2,124,208,154,28,26,71,69,169,142,50, +128,182,247,3,170,200,194,128,127,140,125,68,207,248,175,111,20,205,158,125,147,129,180,48,235,175,106,47,237,164, +217,109,167,138,100,177,89,216,117,192,156,241,82,33,233,143,93,117,129,116,219,27,123,220,134,234,122,202,186,30, +146,110,171,253,221,136,17,180,55,101,154,81,139,105,181,150,49,77,164,197,108,182,202,208,48,88,13,68,104,245, +248,183,25,12,5,255,69,40,133,191,139,23,252,50,126,29,82,4,149,1,15,26,25,81,26,9,93,163,171,125, +216,224,5,19,98,65,131,23,28,191,124,169,241,130,39,61,153,103,17,228,8,85,29,222,32,190,6,204,108,195, +65,150,110,32,129,148,137,34,66,15,128,249,163,49,53,58,214,131,2,128,35,87,225,177,7,50,166,70,134,130, +219,81,33,223,11,10,122,13,11,78,27,93,50,22,49,190,100,25,208,17,122,251,14,222,255,127,201,105,151,154, +177,166,85,81,253,161,106,107,41,181,102,1,227,96,73,18,10,83,252,197,145,129,59,252,69,113,233,11,187,237, +191,83,34,180,4,74,4,86,65,106,235,216,88,231,242,8,154,170,178,135,20,77,117,46,51,118,243,54,32,0, +90,146,86,36,125,50,188,37,108,62,216,66,77,130,119,183,143,17,82,82,6,111,80,96,53,190,157,14,157,169, +170,90,192,179,66,134,183,165,228,226,248,28,152,64,115,24,49,127,6,26,229,82,65,210,190,96,108,252,187,152, +129,144,26,50,198,13,25,147,242,25,177,99,214,200,39,158,102,76,233,145,1,193,153,4,145,28,162,18,127,107, +50,32,110,2,175,212,143,215,196,191,169,219,237,96,23,144,233,248,107,132,225,35,172,189,221,188,91,138,60,140, +25,36,235,148,117,212,30,76,214,169,34,189,150,251,74,126,65,249,176,192,49,83,16,145,163,252,248,117,48,18, +163,16,187,12,28,121,254,27,74,67,170,111,64,70,238,102,94,13,100,19,196,114,133,69,215,160,171,37,4,14, +199,161,25,3,213,64,12,220,104,176,75,128,57,18,217,199,149,161,221,126,227,192,97,26,36,3,5,81,228,167, +205,158,27,95,39,133,46,37,84,158,219,160,70,155,241,182,141,143,101,3,213,179,244,22,173,40,178,69,89,211, +166,15,4,183,44,239,165,113,162,192,205,86,240,41,235,198,193,99,216,135,21,96,184,231,139,199,2,116,9,89, +148,228,201,144,33,41,79,236,228,72,7,232,42,52,205,110,108,11,44,211,161,184,162,171,218,68,83,211,92,6, +104,170,250,169,203,164,218,134,244,219,196,113,114,66,192,197,94,85,216,43,252,94,188,53,164,118,232,24,177,105, +14,56,155,248,46,152,192,243,15,13,199,47,99,188,183,129,145,98,50,65,223,161,113,96,205,136,24,131,227,16, +69,84,120,68,204,26,247,182,42,159,14,104,124,12,191,70,111,206,164,36,234,30,193,146,110,159,81,12,236,77, +226,58,1,24,107,174,19,99,72,139,141,153,34,50,208,231,19,3,125,190,52,102,150,56,112,222,58,132,36,248, +70,98,7,174,209,124,97,22,52,64,220,48,15,74,180,247,63,125,254,240,241,242,250,18,11,45,55,225,8,199, +182,142,77,246,103,251,49,206,5,19,4,109,119,232,186,130,233,70,190,162,75,97,204,204,29,187,74,189,186,81, +146,18,212,96,29,129,87,212,155,22,254,155,11,140,228,239,42,62,105,207,69,237,198,97,21,78,24,22,116,222, +196,117,120,156,73,149,135,44,112,190,132,203,144,72,112,124,71,207,228,10,40,170,59,225,104,185,194,187,160,62, +194,55,218,0,125,98,30,96,190,44,106,140,93,134,84,6,50,84,188,88,19,214,32,67,65,161,182,75,121,96, +116,76,195,70,253,92,235,221,70,79,1,211,43,184,53,123,32,183,177,6,186,216,36,37,32,155,189,61,185,244, +35,49,49,254,167,193,210,157,21,243,68,66,48,120,245,174,88,134,67,113,139,22,106,74,46,202,93,205,199,34, +208,248,138,53,254,85,167,227,105,0,250,197,104,24,98,100,242,72,227,222,187,94,213,207,135,115,57,233,105,177, +85,164,55,208,87,247,247,143,68,137,54,155,1,7,238,18,43,151,160,189,160,182,12,46,129,82,212,176,101,212, +2,129,206,6,216,32,232,248,78,54,200,124,50,214,42,168,147,64,159,159,26,199,126,120,196,94,234,89,142,77, +52,174,47,195,47,232,26,169,251,112,60,214,250,113,44,103,188,200,152,21,165,126,208,100,74,250,97,196,202,198, +6,154,211,196,192,40,95,208,117,200,94,83,253,179,96,209,109,32,169,181,125,129,57,166,34,132,233,47,255,251, +249,234,244,231,211,143,239,63,191,191,254,233,227,233,245,229,199,43,212,159,210,4,53,71,5,114,110,104,211,2, +106,136,178,47,120,137,50,201,4,118,148,174,111,183,188,128,84,253,173,211,108,9,11,248,10,159,189,85,74,28, +133,82,137,195,13,156,193,57,188,107,239,98,45,144,251,139,189,189,107,175,174,251,90,122,130,115,156,230,228,254, +241,38,249,18,101,165,95,239,32,107,118,141,141,253,135,27,244,141,45,191,153,118,247,251,50,251,244,219,178,223, +61,53,123,245,132,124,36,86,95,2,182,239,24,248,225,87,114,75,76,80,24,51,241,105,112,57,92,98,104,254, +101,27,57,30,57,116,137,50,12,215,1,177,230,244,254,254,157,187,240,224,34,112,228,235,130,131,2,140,25,186, +245,160,225,50,53,49,241,2,157,132,155,128,187,23,202,217,36,98,232,181,98,182,251,96,211,61,22,190,145,251, +235,176,68,76,94,203,141,135,163,50,163,192,243,65,232,222,192,204,243,45,193,214,55,72,42,130,180,225,243,37, +220,98,197,57,94,125,129,221,158,124,7,139,9,130,118,248,101,20,224,19,146,216,96,138,100,227,159,46,57,64, +187,242,214,189,34,85,191,182,200,215,169,241,194,88,201,186,118,113,11,24,177,6,201,186,198,192,120,247,18,219, +188,70,173,32,231,230,26,22,180,195,234,44,88,41,249,245,223,185,83,15,72,168,253,175,131,107,188,27,123,160, +56,67,143,238,188,10,62,203,53,169,115,18,176,51,143,24,186,123,181,183,39,111,47,239,239,19,172,252,28,206, +134,231,35,175,175,48,46,221,85,141,216,203,64,114,204,71,178,165,47,58,241,231,247,247,87,21,156,233,55,141, +51,50,31,244,210,245,36,191,88,251,188,60,16,205,123,149,161,86,182,61,130,28,65,116,69,72,214,120,135,190, +167,213,31,219,82,151,147,219,37,39,232,191,20,141,255,193,219,150,9,187,207,243,29,66,59,14,197,78,42,69, +168,5,188,47,55,245,124,3,28,182,21,238,122,231,229,174,125,243,14,237,86,57,128,21,141,132,165,80,85,121, +184,204,39,221,207,87,228,126,62,205,124,71,61,105,142,83,237,60,42,243,173,246,79,153,164,218,58,21,74,64, +196,126,72,146,83,12,82,242,20,33,4,238,246,164,239,45,87,53,51,98,11,241,253,41,155,177,180,207,93,51, +215,220,26,218,76,111,190,77,42,136,249,36,74,118,214,107,32,64,234,167,246,255,27,191,178,111,81,109,65,200, +160,11,218,159,40,157,123,212,213,86,138,205,235,106,246,69,110,66,206,183,10,34,55,94,247,216,145,99,133,69, +236,129,80,187,209,179,80,160,251,225,62,238,191,58,245,86,41,103,191,150,80,61,155,203,157,54,36,175,222,103, +103,223,221,223,207,246,133,167,251,235,202,237,46,64,115,239,118,118,145,32,63,73,44,196,160,93,135,230,70,44, +83,184,123,64,210,80,153,109,217,80,101,43,226,204,113,20,254,158,250,16,81,207,191,187,255,180,54,222,159,186, +207,145,56,27,63,243,33,69,130,104,23,43,11,130,68,110,144,137,112,64,45,239,117,108,64,226,236,239,238,50, +143,80,196,121,87,164,217,60,76,248,159,172,195,173,205,66,55,99,232,199,70,204,77,193,233,58,222,38,120,119, +5,57,86,68,27,142,105,123,91,132,215,23,167,215,239,255,235,167,192,185,112,32,193,219,15,151,103,255,139,39, +133,34,176,235,7,199,224,43,39,118,188,8,31,67,235,60,60,142,105,183,53,11,132,220,167,196,212,103,235,97, +209,229,240,159,207,159,237,238,92,145,212,101,18,165,118,103,217,235,226,33,228,59,247,59,231,239,175,119,206,120, +196,68,206,240,110,202,139,89,57,70,175,122,254,124,193,229,25,42,139,80,28,62,207,85,73,4,121,37,79,119, +21,167,162,232,196,225,156,39,119,126,30,138,188,147,179,140,199,253,206,60,239,200,163,125,115,228,80,39,156,124, +41,243,194,199,3,19,190,239,119,212,129,32,246,167,213,56,157,220,173,230,56,163,112,225,247,170,144,128,33,18, +6,97,206,39,12,226,52,45,88,6,51,117,250,135,8,151,144,51,217,251,85,253,182,224,143,147,52,186,169,102, +7,138,42,170,220,63,100,243,126,93,31,30,194,206,230,59,189,42,230,211,40,92,80,65,144,59,56,25,144,51, +223,174,36,91,53,148,142,211,175,84,23,157,226,162,94,49,100,82,127,75,114,125,68,125,175,159,46,89,22,39, +233,173,191,228,57,173,197,85,225,138,192,23,166,242,140,230,78,68,7,210,251,242,12,107,245,62,181,201,152,9, +139,210,44,36,26,59,249,13,95,248,202,232,229,85,232,135,242,117,3,66,127,70,13,172,210,178,72,184,168,177, +79,136,101,147,9,29,197,160,56,160,14,250,86,146,90,141,129,150,106,197,84,61,186,85,100,114,49,195,241,42, +250,102,26,218,13,100,112,69,83,40,220,140,39,176,64,14,229,225,124,177,49,214,87,63,239,156,167,34,133,43, +54,77,217,206,111,239,213,221,199,116,140,138,167,174,207,153,72,82,120,135,150,141,179,12,230,152,132,61,141,88, +127,61,54,7,108,94,77,98,97,210,202,11,212,169,168,202,145,224,196,24,197,87,40,56,38,137,199,189,94,149, +151,216,163,114,97,228,122,121,242,125,95,50,67,143,193,34,85,39,132,251,25,75,164,99,208,223,4,27,241,233, +160,104,42,66,181,173,144,246,34,157,251,29,60,112,30,41,163,186,139,116,129,183,116,23,150,19,158,194,18,229, +48,213,146,194,133,108,77,9,140,204,128,188,46,220,33,137,67,150,38,249,200,211,89,233,53,86,139,70,197,231, +83,108,44,67,46,235,33,34,18,150,83,89,222,167,45,243,222,74,203,207,140,79,38,76,84,10,33,2,8,242, +79,110,66,151,8,130,144,75,28,116,32,161,65,49,10,205,49,210,131,171,57,164,83,12,46,233,52,173,117,102, +67,171,182,20,55,79,85,187,43,41,172,26,34,68,245,99,40,97,20,229,7,154,17,168,27,228,238,156,227,93, +93,152,44,199,142,122,162,82,70,90,217,232,61,63,196,250,34,230,171,71,213,70,62,223,239,224,73,67,157,56, +141,202,188,195,133,96,25,152,205,217,31,107,2,108,207,85,197,15,31,60,28,160,254,2,149,139,212,157,76,8, +75,38,216,96,157,201,239,105,238,25,153,18,58,0,100,98,51,35,170,148,52,23,246,84,105,29,244,200,52,66, +36,247,150,99,75,95,149,182,43,123,170,219,163,133,132,130,117,72,201,180,206,55,39,179,88,69,118,171,46,104, +97,210,131,31,150,69,90,15,132,60,29,6,105,108,134,86,98,119,142,254,80,47,53,233,117,213,162,156,143,89, +70,131,164,42,83,3,129,61,226,162,83,75,206,150,140,104,5,55,51,174,148,112,155,132,231,40,87,209,204,42, +105,212,97,57,164,253,198,156,166,113,76,139,253,29,4,188,218,40,110,180,169,18,58,17,213,144,24,244,109,207, +107,88,117,27,21,82,121,214,101,36,192,167,58,12,167,174,125,187,146,144,138,107,77,174,234,163,122,96,206,68, +217,154,214,242,114,78,144,0,58,53,225,121,33,209,33,154,158,43,42,176,83,203,208,46,53,213,80,217,163,17, +96,41,124,90,176,13,35,87,61,3,63,140,105,158,246,213,217,26,22,201,208,130,253,48,169,34,211,240,135,132, +201,152,242,17,43,96,195,194,33,156,208,122,118,13,23,157,25,166,38,244,228,225,44,44,29,16,99,158,246,191, +139,227,184,86,199,239,142,198,199,71,39,7,125,211,196,210,80,224,48,41,216,87,80,63,157,146,195,15,4,92, +118,30,70,87,50,229,103,44,161,103,202,122,146,132,95,89,178,100,164,127,59,23,172,164,25,86,59,79,235,174, +116,95,101,108,174,61,137,206,215,122,46,232,75,179,171,142,249,32,54,208,145,36,115,204,127,198,166,124,204,19, +94,252,153,189,43,221,110,28,215,209,175,146,187,119,78,219,46,173,94,162,217,151,127,51,191,239,190,40,150,156, +248,92,57,241,88,78,151,211,62,126,140,249,55,79,55,79,50,132,8,65,252,68,138,74,220,169,154,237,86,157, +36,20,0,2,32,9,146,224,254,170,156,13,86,58,89,46,203,205,6,138,55,235,185,24,186,224,242,187,166,245, +131,204,215,215,181,220,181,15,205,40,101,110,14,15,247,249,55,139,104,18,38,209,36,74,211,201,44,186,205,222, +78,122,201,103,226,192,112,128,229,138,71,195,122,135,233,92,101,189,165,234,11,165,185,105,165,242,166,75,58,150, +69,27,99,113,159,23,155,141,114,255,38,143,209,228,49,158,60,38,147,199,116,242,56,103,188,203,213,73,131,160, +103,41,17,183,228,83,118,6,168,243,111,65,228,13,4,151,153,18,48,123,140,212,79,172,126,18,245,163,82,166, +164,32,95,77,135,174,168,202,19,5,141,148,122,6,52,156,205,53,92,41,28,3,60,209,112,149,138,4,224,154, +15,37,45,53,225,26,58,167,4,247,12,232,178,23,151,90,149,13,51,200,85,7,95,79,94,206,94,183,83,25, +241,77,89,60,148,117,230,71,95,242,251,251,195,111,143,219,99,85,254,158,251,68,201,192,32,37,91,40,212,87, +89,100,235,151,67,173,202,226,177,172,246,110,43,84,14,231,185,87,34,169,116,20,218,172,26,253,51,179,142,198, +65,188,72,162,182,154,110,54,80,133,22,138,154,216,78,232,174,174,86,57,234,181,94,106,205,240,162,17,80,231, +203,213,125,220,171,246,206,100,213,207,116,229,164,138,80,196,243,133,232,201,72,173,110,112,105,218,205,127,123,81, +163,151,86,124,85,110,142,156,26,230,80,228,69,89,38,108,105,26,31,116,252,18,162,212,101,217,49,187,217,223, +85,121,173,26,49,90,20,57,163,217,6,151,231,106,242,82,157,153,131,254,126,174,110,244,239,23,194,77,94,154, +207,23,250,228,216,218,92,154,87,168,58,129,138,190,218,18,89,181,61,27,21,65,155,167,138,74,93,8,123,73, +197,182,94,171,249,30,26,173,41,204,13,32,167,205,189,150,250,181,68,197,19,162,149,235,173,242,86,218,152,164, +166,29,179,162,113,243,52,175,246,143,249,165,168,110,138,35,84,184,69,16,52,208,66,82,146,152,41,81,181,177, +121,18,199,85,252,217,187,205,173,44,55,193,70,204,35,73,211,96,30,100,174,190,146,165,206,224,113,158,158,14, +100,41,173,68,182,139,196,4,29,72,47,13,67,118,252,186,15,24,46,55,246,93,69,192,40,181,170,108,79,5, +68,130,30,142,227,99,36,126,4,28,162,196,209,253,60,137,7,229,124,206,15,79,74,247,158,148,123,85,72,131, +81,154,139,8,33,66,185,76,231,189,8,247,199,65,199,41,35,255,221,2,246,191,251,201,102,247,29,43,51,103, +162,203,84,32,155,218,198,108,255,188,165,171,159,157,22,96,245,229,98,103,75,135,233,29,122,126,88,103,137,81, +163,160,182,12,106,55,217,101,215,151,78,59,91,210,206,227,145,119,178,238,186,228,43,171,174,39,58,133,77,144, +18,166,67,118,247,79,224,236,43,114,193,56,194,244,250,216,94,149,90,240,75,173,10,91,143,106,59,131,114,65, +107,27,104,1,122,35,43,253,160,105,111,128,70,151,65,54,38,253,85,252,174,78,208,132,130,236,107,185,235,195, +180,237,248,86,203,84,1,93,214,213,240,99,87,78,51,212,97,224,200,241,145,105,184,89,164,208,68,141,242,111, +47,172,228,113,5,75,179,49,232,120,76,13,9,70,175,107,128,181,12,85,107,105,88,93,104,190,240,245,219,246, +235,247,103,174,234,69,185,201,95,170,99,214,190,61,57,75,51,174,253,211,146,174,150,173,59,229,233,199,215,70, +59,179,26,148,67,30,92,120,22,216,46,200,104,179,40,71,179,221,22,208,149,38,194,93,37,27,37,139,37,138, +96,143,221,47,226,250,242,66,118,158,46,9,85,138,54,121,30,111,50,15,143,119,84,190,52,152,132,203,104,50, +95,64,221,27,165,28,16,57,177,192,118,73,198,65,94,38,65,63,77,69,30,197,107,95,154,172,146,100,184,179, +36,243,85,30,175,250,34,22,203,50,78,188,34,62,166,36,135,187,125,84,168,88,165,129,2,14,114,120,71,41, +70,113,52,89,206,39,1,20,226,24,161,83,220,4,129,142,242,43,202,52,178,210,178,222,36,133,47,45,80,122, +2,117,149,221,58,73,86,22,251,251,52,137,189,236,63,168,228,104,130,195,208,6,150,50,64,35,3,129,254,19, +242,194,100,51,240,206,9,228,220,7,152,53,119,0,70,187,59,227,128,176,243,195,196,217,134,129,91,172,126,27, +234,61,152,209,87,70,244,8,34,199,58,242,28,34,55,110,32,206,194,101,221,244,109,71,151,235,165,44,70,205, +150,214,176,32,232,13,9,130,126,92,78,170,102,193,41,115,210,84,15,76,19,1,69,115,207,182,191,72,239,90, +195,50,159,85,150,188,236,123,180,77,34,96,72,59,139,58,8,39,131,166,88,165,63,13,113,236,229,118,108,57, +125,182,238,108,24,8,180,171,165,174,221,201,98,18,37,75,245,179,154,204,210,219,174,71,95,165,125,174,60,143, +201,139,124,119,63,254,207,255,248,247,31,95,26,60,49,220,75,217,182,173,15,251,255,52,41,41,168,93,221,130, +55,85,121,50,81,6,56,35,50,10,76,201,55,188,163,95,25,126,26,98,111,40,8,45,30,145,222,133,196,132, +131,170,61,163,249,239,12,190,250,44,238,54,219,67,59,137,160,151,159,186,73,133,91,108,30,116,137,181,35,34, +105,120,212,108,64,15,99,201,32,190,166,160,219,33,73,194,2,204,102,170,235,165,197,182,139,143,18,108,213,137, +143,83,115,64,140,74,69,175,23,149,113,131,197,38,1,202,70,249,189,50,138,130,202,198,144,209,133,160,233,16, +243,178,236,170,111,80,244,237,225,247,54,187,161,41,244,238,227,50,227,135,160,207,214,130,170,160,116,127,98,213, +51,85,197,210,116,50,159,79,84,197,186,117,142,169,117,1,233,197,44,163,255,105,171,27,61,4,252,141,249,24, +245,109,134,141,105,191,101,111,202,46,85,204,186,133,178,56,10,140,70,38,200,122,75,171,198,48,91,70,217,46, +191,190,91,78,206,239,235,231,234,229,200,51,233,194,174,172,170,237,190,222,118,131,202,110,101,180,9,209,106,201, +55,83,165,219,164,145,113,155,141,225,29,99,120,78,5,12,105,133,13,65,179,143,32,126,63,145,155,63,140,121, +247,135,50,107,77,62,14,58,171,210,117,132,135,119,2,108,170,8,91,149,244,15,227,57,59,157,69,254,172,101, +2,145,110,140,0,25,98,140,251,122,86,160,27,80,38,227,191,220,248,177,166,108,205,74,144,54,68,50,107,175, +210,90,157,137,138,64,58,123,241,3,146,157,217,135,36,144,153,62,109,70,148,241,233,194,41,135,108,104,186,31, +213,202,122,178,1,138,134,205,126,132,96,88,184,55,39,152,102,36,43,80,160,215,152,4,111,235,67,101,239,182, +8,157,39,186,84,70,115,101,150,248,139,67,208,110,13,124,249,193,20,152,27,31,100,166,235,252,80,156,253,115, +173,184,236,225,234,23,174,233,247,50,179,95,123,62,108,169,3,105,231,226,0,87,108,15,122,239,24,239,148,144, +222,207,192,172,85,19,191,123,202,156,80,157,198,155,230,247,148,214,140,39,38,64,239,84,3,144,222,181,38,235, +49,224,223,203,162,141,197,213,240,112,28,2,16,139,178,0,123,70,65,90,186,37,108,196,41,8,193,153,212,95, +192,163,121,130,95,68,81,173,23,57,72,99,250,105,64,31,248,105,111,244,190,41,112,221,192,102,44,143,20,176, +14,230,85,110,243,70,151,17,217,3,222,37,225,158,71,80,184,84,244,97,246,141,35,4,158,68,206,44,0,140, +191,96,176,153,31,232,135,70,137,45,77,212,234,125,211,96,104,47,136,127,73,201,239,126,117,26,62,149,15,141, +135,120,23,104,5,235,199,3,13,212,3,199,16,145,63,72,71,123,203,158,189,222,193,73,10,122,106,131,89,141, +22,165,199,140,250,124,141,138,228,183,0,175,5,186,51,39,132,204,9,47,186,120,170,173,98,194,69,196,81,113, +93,211,206,38,35,166,89,148,189,149,228,192,246,97,221,17,173,1,26,230,174,109,226,50,150,177,248,113,120,74, +227,142,193,137,240,187,0,43,9,245,151,98,199,52,163,226,75,2,119,167,65,227,106,164,35,125,106,227,71,112, +63,230,193,106,35,211,178,125,73,226,113,223,216,220,163,164,214,139,190,204,72,29,61,92,179,74,0,151,248,181, +37,200,78,196,9,239,54,100,26,104,232,53,202,154,195,234,109,88,97,217,122,157,28,234,184,181,76,9,147,94, +164,62,68,230,21,93,123,210,13,39,119,156,145,236,169,54,220,4,33,145,244,238,212,15,93,12,150,111,238,29, +152,202,229,182,220,175,215,241,186,116,54,235,184,105,68,242,241,186,197,96,220,235,57,190,54,108,55,11,127,89, +6,126,155,74,93,46,155,6,246,53,150,102,91,43,130,185,113,80,66,92,132,230,115,218,28,40,121,124,174,10, +153,240,102,123,196,72,84,7,222,72,75,221,210,59,121,191,51,194,155,200,102,154,229,85,179,245,54,159,107,166, +237,109,46,60,109,235,223,64,13,203,252,108,74,218,61,238,216,233,157,193,180,169,247,247,178,91,223,64,3,172, +159,14,15,82,60,57,75,224,244,81,77,93,96,102,163,179,134,27,27,219,109,133,121,221,174,241,221,244,153,77, +102,91,65,126,59,32,137,215,97,27,70,122,193,201,197,134,81,67,76,120,17,144,83,195,71,13,174,109,235,175, +111,197,113,203,232,135,110,226,241,152,14,183,245,189,222,9,242,226,191,183,89,98,45,184,25,40,79,251,252,169, +128,61,224,64,53,211,127,222,93,171,67,173,25,212,113,155,239,123,107,185,150,117,99,215,121,230,250,219,221,11, +205,141,80,37,5,48,113,255,189,89,211,236,82,29,102,117,163,159,140,180,56,10,230,108,239,56,68,94,141,47, +216,49,212,203,39,154,197,109,127,162,229,230,229,160,206,125,54,111,147,55,110,204,39,117,174,232,219,211,174,202, +232,242,74,186,52,237,229,184,89,78,126,22,255,163,130,255,44,10,20,70,61,150,250,187,95,60,30,143,251,187, +79,159,62,127,254,60,251,28,207,158,15,15,159,232,137,39,138,252,187,95,40,178,239,182,229,231,127,120,62,41, +194,64,125,209,79,162,126,82,133,139,255,89,241,218,231,199,71,245,189,217,170,119,195,136,62,158,207,23,225,114, +213,68,45,20,228,95,35,138,245,47,20,47,122,76,190,223,81,32,109,62,99,245,249,187,95,124,210,108,72,156, +10,253,248,86,157,164,158,30,74,85,135,143,55,141,111,223,150,152,30,0,126,226,82,76,237,141,146,161,209,142, +109,215,207,122,41,103,34,159,154,202,181,140,1,17,184,205,162,239,126,92,3,117,134,65,172,108,177,214,22,225, +90,44,24,31,157,252,250,27,28,154,0,10,198,37,36,83,6,93,209,176,254,103,250,230,74,229,164,98,87,26, +214,154,67,93,223,60,73,39,0,176,5,58,228,11,197,99,84,228,246,40,17,87,140,230,36,17,135,245,109,22, +163,195,16,25,21,71,122,84,188,83,157,25,182,42,88,179,180,221,232,48,115,176,77,1,149,187,105,146,97,170, +8,16,173,168,6,157,215,149,90,183,56,208,53,48,124,91,226,173,180,113,251,83,171,235,148,194,214,10,148,101, +44,186,152,21,173,173,143,56,166,223,118,5,2,10,250,72,64,99,139,230,191,171,79,177,210,215,124,150,133,63, +133,76,228,79,163,77,229,153,134,240,171,54,160,204,144,120,67,160,199,255,120,211,54,98,203,62,254,50,174,123, +147,74,189,18,20,167,217,44,63,0,74,233,13,14,70,164,161,119,243,174,30,128,55,2,145,183,229,186,8,111, +156,85,121,187,253,89,139,46,208,67,85,229,134,39,201,180,0,179,43,113,214,66,158,219,242,87,66,139,198,49, +59,56,156,16,231,129,156,55,182,8,188,51,7,142,213,83,11,220,173,118,156,184,90,195,89,27,107,123,91,147, +13,176,43,68,64,178,233,231,199,109,86,174,246,39,217,98,128,219,69,98,133,49,6,84,211,185,250,126,143,19, +112,120,62,210,12,100,146,22,229,195,109,54,4,215,154,205,135,250,5,242,7,84,43,162,58,66,21,231,3,154, +60,31,87,40,1,48,59,59,219,162,193,108,75,123,217,22,250,178,77,70,72,146,126,171,10,88,211,200,23,127, +199,225,79,137,197,205,145,182,185,145,54,143,234,227,203,223,236,250,121,209,80,254,210,162,160,251,70,142,13,160, +135,154,8,238,129,188,21,8,235,103,146,26,35,172,217,170,215,172,176,235,219,238,64,156,123,244,184,42,195,193, +31,116,54,110,238,236,15,174,237,46,137,171,191,199,251,250,236,32,142,197,253,99,216,120,148,132,94,3,10,119, +172,110,233,161,69,210,51,93,236,70,70,12,100,177,89,110,86,23,238,63,9,186,191,106,127,28,112,184,49,63, +166,202,244,185,146,160,208,119,79,33,121,22,77,96,38,200,62,21,52,166,221,172,249,237,89,96,129,153,209,55, +114,243,172,188,192,108,9,114,51,38,48,109,4,79,94,92,177,175,160,109,65,126,230,81,158,150,19,101,209,113, +80,45,239,246,214,65,157,199,162,249,115,244,218,200,95,108,55,238,64,222,248,183,229,250,115,232,138,200,86,62, +253,48,22,31,181,175,216,99,211,158,13,198,222,172,241,71,243,103,202,181,145,191,222,126,104,208,193,90,44,243, +100,11,227,253,233,31,165,234,78,76,118,179,95,195,109,79,183,24,3,68,184,184,243,97,59,248,113,253,72,22, +75,96,230,23,224,3,203,45,22,66,98,99,207,180,218,20,155,188,45,61,92,128,113,107,194,185,139,250,32,118, +88,43,68,219,186,125,249,179,116,152,42,94,69,194,212,8,212,189,2,133,224,161,124,221,108,242,205,2,243,21, +215,164,80,3,119,174,34,206,169,13,32,45,157,190,244,169,54,107,2,3,148,176,198,251,30,188,246,228,92,4, +144,54,16,231,33,98,129,94,10,123,96,227,41,46,59,137,111,153,101,28,167,198,228,251,201,253,153,49,30,5, +179,230,237,244,35,206,185,235,240,229,21,57,233,155,143,246,211,250,115,17,137,253,121,56,30,1,115,112,156,122, +116,190,252,203,85,206,107,10,1,167,105,222,158,103,24,241,58,227,64,175,210,220,240,161,146,251,252,249,233,86, +9,249,46,175,182,197,249,135,50,248,210,205,98,102,119,5,239,81,111,124,83,131,160,187,163,39,38,127,0,74, +127,226,132,10,173,125,181,40,207,188,242,234,2,41,61,205,43,186,68,167,48,110,47,128,13,42,135,82,229,205, +83,245,250,123,139,153,12,188,81,107,211,194,80,117,183,9,189,93,39,172,118,40,17,167,7,92,11,62,195,212, +103,247,174,138,199,231,195,246,123,53,248,205,171,179,189,219,16,9,184,254,92,63,245,48,126,200,147,101,122,54, +30,93,102,107,82,70,125,31,218,13,159,114,180,4,79,215,18,228,109,183,11,225,70,113,225,63,123,56,108,139, +233,169,58,27,91,17,163,213,124,127,178,104,170,7,131,102,181,112,145,236,10,131,100,153,186,72,234,157,65,50, +15,93,36,167,218,32,73,180,46,84,5,105,149,69,7,118,5,7,234,29,7,78,85,27,168,97,171,202,143,182, +59,186,83,57,127,58,146,24,58,217,81,127,161,82,237,13,165,18,235,32,180,134,137,26,244,119,250,144,239,171, +178,174,161,144,3,140,22,56,99,252,13,3,207,254,35,228,24,87,229,71,99,114,111,59,100,96,220,74,72,86, +214,178,242,207,246,100,252,7,55,182,142,91,40,228,77,163,108,56,49,191,34,248,138,225,43,129,175,20,190,230, +240,181,128,175,37,124,173,224,43,12,240,51,196,79,84,135,178,199,206,150,64,178,69,111,19,147,208,133,121,156, +177,66,146,20,6,173,194,217,92,255,91,180,168,128,81,203,120,22,243,63,70,173,24,179,72,25,176,100,192,124, +222,231,178,96,76,186,236,51,153,183,152,86,151,148,1,137,165,74,194,152,216,210,36,102,76,212,106,34,73,180, +52,105,83,106,41,50,154,151,129,156,122,135,47,49,56,243,14,1,177,219,233,238,164,57,67,213,50,208,90,240, +4,105,165,82,2,233,97,136,211,223,237,202,98,155,127,99,54,164,203,96,127,186,61,55,241,78,218,164,117,40, +146,80,44,161,68,66,169,132,230,18,90,72,104,41,161,149,132,194,160,11,134,93,80,196,92,103,162,39,167,149, +158,188,134,122,242,218,234,201,97,174,39,159,197,158,124,70,123,114,216,237,201,103,186,39,159,245,158,28,6,124, +242,217,240,201,109,198,144,229,166,29,62,110,139,82,33,6,251,39,238,200,112,83,148,65,96,27,216,106,222,217, +87,245,64,246,197,161,72,66,177,132,18,9,165,18,154,75,104,33,161,165,132,86,18,10,131,46,24,118,65,17, +115,141,125,49,11,180,47,134,186,237,139,177,110,251,98,44,218,23,195,208,190,144,157,219,190,24,137,246,197,48, +180,47,228,230,182,47,70,162,125,49,204,109,95,140,180,237,75,112,110,251,82,8,191,125,25,248,113,251,90,38, +157,125,237,10,178,47,14,69,18,138,37,148,72,40,149,208,92,66,11,9,45,37,180,146,80,24,116,193,176,11, +138,152,107,236,139,89,160,125,49,212,109,95,140,117,219,23,99,209,190,24,134,246,133,236,220,246,197,72,180,47, +134,161,125,33,55,183,125,49,18,237,139,97,110,251,98,164,109,95,130,115,219,151,66,248,237,203,192,143,219,215, +60,232,236,171,222,145,125,113,40,146,80,44,161,68,66,169,132,230,18,90,72,104,41,161,149,132,194,160,11,134, +93,80,196,92,99,95,204,2,237,139,161,110,251,98,172,219,190,24,139,246,197,48,180,47,100,231,182,47,70,162, +125,49,12,237,11,185,185,237,139,145,104,95,12,115,219,23,35,109,251,18,156,219,190,20,194,111,95,6,126,220, +190,18,211,255,170,201,190,56,20,73,40,150,80,34,161,84,66,115,9,45,36,180,148,208,74,66,97,208,5,195, +46,40,98,174,244,191,106,167,255,85,123,253,175,218,235,127,213,96,95,12,243,249,95,181,207,255,170,193,190,24, +230,243,191,106,159,255,85,131,125,49,204,231,127,213,30,255,171,30,242,191,234,17,255,171,246,216,87,91,128,234, +125,189,230,153,211,250,134,47,219,59,7,63,59,15,110,248,11,112,191,31,128,47,199,231,225,136,33,189,53,101, +199,100,184,210,231,127,138,30,118,190,212,21,101,118,161,230,77,73,165,238,102,38,255,209,8,189,163,76,36,57, +177,164,170,48,12,253,12,131,1,86,1,41,253,191,73,217,25,29,16,148,219,102,97,67,167,97,160,57,144,241, +218,35,2,225,30,69,190,73,182,23,175,255,236,194,60,90,17,145,166,233,110,24,103,236,38,216,204,81,9,32, +4,53,0,12,138,20,243,82,113,193,184,14,85,54,162,199,195,33,127,197,179,143,168,2,211,128,116,134,128,224, +188,184,159,175,19,136,209,147,185,190,47,130,98,197,98,155,87,69,12,109,80,168,80,128,84,6,129,216,77,68, +255,49,206,96,90,11,122,190,0,142,157,131,88,161,65,169,4,1,161,252,138,2,196,64,153,124,213,61,139,229, +29,0,120,238,211,150,140,91,11,16,8,242,249,98,219,126,188,158,10,241,106,189,74,238,89,5,190,103,158,113, +124,197,188,173,2,147,161,10,12,68,21,202,121,158,6,65,47,158,157,243,247,101,152,107,21,244,162,26,174,240, +88,10,192,70,0,0,129,112,125,49,44,198,177,68,43,254,241,101,118,255,224,185,90,186,147,79,132,195,151,254, +35,157,54,35,251,85,141,142,10,239,148,125,208,117,204,222,40,137,108,61,119,53,15,114,246,188,31,48,28,199, +125,147,240,96,140,245,244,145,142,173,226,217,27,2,239,84,145,180,96,10,19,236,251,231,103,90,143,97,176,44, +12,48,56,99,48,127,74,132,231,151,163,21,131,225,18,133,191,41,78,183,26,38,106,25,32,162,32,55,133,81, +236,178,20,174,235,101,9,236,92,60,234,16,189,104,2,228,216,228,103,94,185,175,86,36,208,231,71,110,172,42, +166,228,159,77,212,95,242,203,134,156,52,133,230,135,234,206,244,87,63,134,116,199,32,173,157,141,231,67,120,92, +163,73,204,219,110,193,5,84,183,121,54,232,61,66,216,112,229,133,103,82,151,229,228,117,189,173,245,157,206,194, +245,218,243,131,112,57,142,231,36,97,177,165,23,12,15,147,54,48,85,108,142,104,61,142,3,145,64,253,219,230, +46,78,222,147,255,251,246,110,57,166,112,33,173,29,254,208,45,59,238,249,100,200,237,216,131,26,184,229,57,224, +237,212,126,167,108,54,79,61,78,25,99,37,193,198,101,99,253,7,127,194,77,188,73,185,116,8,103,95,209,116, +113,103,74,239,169,157,139,175,40,224,182,56,164,228,5,109,124,80,200,125,181,94,119,91,208,224,81,138,177,227, +43,163,89,251,43,199,185,101,68,141,91,209,89,148,192,251,88,131,47,120,166,134,85,107,135,71,86,181,238,154, +22,243,108,241,108,233,189,33,22,43,15,243,238,221,177,152,63,169,238,187,161,100,252,205,44,173,111,200,206,115, +218,205,179,217,62,109,85,50,223,70,5,103,220,60,143,216,80,142,9,196,253,254,157,185,19,216,70,190,253,36, +14,137,242,172,120,43,246,12,241,148,173,235,160,123,40,249,217,254,165,25,107,163,104,200,98,92,52,156,253,76, +165,71,95,61,5,151,150,130,75,251,48,83,115,37,248,102,123,98,126,124,67,248,243,241,209,149,57,199,188,233, +117,54,74,141,99,35,229,220,4,239,40,216,89,22,19,232,34,97,10,10,3,201,126,218,90,148,125,121,1,210, +181,249,120,182,114,22,233,84,34,202,162,35,106,62,145,66,245,78,235,63,191,118,36,108,187,12,239,104,187,50, +4,12,115,209,87,54,40,81,104,50,58,157,77,165,25,223,194,66,89,84,158,132,21,204,148,193,205,128,173,99, +130,208,230,163,185,214,174,102,208,15,191,93,116,175,122,181,190,84,0,210,163,214,219,205,107,219,200,49,248,50, +219,77,3,121,142,207,204,169,221,61,33,224,250,54,196,87,26,47,89,133,216,3,99,37,223,16,125,100,52,219, +54,34,79,195,156,51,15,207,87,159,194,217,160,180,105,120,54,175,109,232,229,65,136,44,153,6,243,33,4,109, +109,138,131,80,176,222,54,201,145,73,88,67,155,224,228,151,146,141,240,127,29,75,72,230,149,62,141,36,143,18, +59,143,162,62,235,196,206,163,8,181,79,236,60,138,48,143,108,146,35,147,176,150,54,193,201,47,37,27,225,255, +58,150,144,204,39,125,175,172,79,156,63,64,220,119,24,103,77,218,87,29,129,86,28,209,135,14,205,186,35,254, +216,225,109,243,222,159,60,204,51,31,219,87,175,218,217,176,68,101,106,224,49,97,102,116,88,180,68,204,144,16, +117,182,73,14,29,9,24,61,102,76,8,25,99,83,156,70,4,101,99,34,94,71,147,147,249,53,152,70,184,199, +19,51,171,195,162,73,98,102,69,152,6,155,228,208,145,128,245,99,102,117,52,110,3,63,141,8,202,198,68,188, +142,38,39,243,106,80,187,223,172,212,158,38,161,245,115,158,246,145,123,61,196,213,46,143,113,125,47,125,51,138, +84,6,28,1,24,201,253,188,137,213,16,70,115,207,106,226,25,196,4,205,91,161,235,188,46,251,239,211,11,130, +9,95,246,123,55,161,32,90,141,242,253,246,168,68,125,111,81,118,24,38,213,23,138,195,235,164,73,16,48,242, +254,185,42,0,181,16,84,195,101,173,145,250,93,84,13,105,211,164,154,194,18,223,1,46,119,140,107,223,157,56, +187,159,163,104,211,160,190,38,189,8,253,121,4,215,97,100,137,220,99,79,160,54,89,135,50,255,179,120,101,143, +175,251,199,242,73,191,150,64,190,17,2,224,227,179,178,28,29,251,174,249,61,37,128,134,146,112,3,72,78,253, +195,179,172,118,218,239,123,240,181,243,50,153,226,60,31,192,39,175,121,227,63,188,79,18,222,102,239,33,197,10, +17,45,210,238,129,86,163,148,244,140,2,248,250,219,170,228,171,177,220,60,168,101,136,161,101,136,35,74,221,142, +192,70,135,24,233,131,244,121,81,78,155,202,49,229,7,104,52,168,42,243,239,74,6,157,189,207,136,164,3,239, +123,164,181,201,29,216,26,139,86,255,69,219,115,40,55,142,35,251,43,18,234,149,14,168,233,85,217,227,137,212, +226,116,147,115,206,167,82,185,104,10,178,56,150,73,45,8,57,156,204,127,127,221,0,8,130,150,252,242,187,96, +130,8,157,19,154,218,218,189,250,111,192,216,84,128,25,170,11,98,178,146,170,6,246,240,94,54,103,201,124,93, +100,4,149,27,80,160,197,230,44,213,189,66,182,179,98,195,214,149,234,85,70,231,153,97,35,90,198,125,242,195, +209,111,149,25,140,162,165,41,205,229,74,65,33,53,253,19,44,31,206,139,143,186,68,199,52,151,80,74,214,192, +97,82,74,218,86,206,123,95,46,79,209,195,198,238,145,108,106,200,101,57,204,145,252,212,148,250,234,138,253,227, +31,205,11,131,20,151,210,234,178,200,94,197,235,157,25,6,21,110,50,229,23,163,81,23,95,211,99,187,37,122, +103,163,134,136,94,230,152,132,194,177,89,74,53,24,168,150,7,188,173,87,104,0,25,81,121,58,86,201,41,228, +13,159,153,86,212,143,40,219,205,2,137,43,212,121,239,11,47,174,174,38,83,49,210,138,62,165,246,242,225,33, +246,47,203,19,37,223,34,54,13,169,128,188,14,20,44,27,49,27,236,245,187,19,27,130,150,48,23,146,24,160, +241,36,136,47,93,46,57,109,172,235,44,53,217,130,23,162,187,221,44,116,121,238,118,23,117,93,155,33,185,162, +204,172,126,214,146,85,235,106,165,40,43,124,49,169,54,12,230,209,212,175,92,45,103,12,102,146,169,11,149,173, +13,138,137,193,74,178,172,60,93,45,149,81,184,182,144,155,186,21,219,41,23,155,150,133,179,206,219,17,189,17, +210,99,58,114,60,201,167,173,237,52,36,247,204,2,3,156,37,237,178,17,232,177,50,31,27,81,126,152,195,185, +188,28,12,46,249,37,255,192,81,150,66,140,206,7,131,243,190,148,122,48,40,156,48,206,33,23,131,1,63,150, +231,194,66,186,144,71,173,50,228,105,52,238,170,236,88,180,140,28,146,57,79,88,129,225,144,65,35,66,230,136, +100,211,33,230,138,103,41,202,154,7,14,20,42,106,162,34,150,76,135,167,70,213,92,129,65,77,9,209,202,229, +132,182,134,55,197,53,148,144,67,234,12,175,146,104,7,19,61,5,3,165,24,229,115,238,105,65,134,171,33,241, +224,182,101,248,134,10,134,181,204,134,103,233,114,173,26,27,91,15,6,172,180,92,70,126,181,14,162,90,3,59, +60,76,207,211,220,48,49,70,41,159,230,149,26,106,85,149,203,51,197,215,67,191,38,134,6,99,60,231,49,111, +138,123,225,24,75,108,45,160,187,220,16,26,214,69,178,5,127,23,92,79,191,196,99,60,139,193,198,18,221,1, +189,78,185,21,129,176,38,166,91,77,150,220,144,23,71,239,1,12,57,165,39,42,34,2,229,79,244,227,41,160, +33,193,246,251,181,212,99,237,104,46,113,37,65,80,117,172,92,89,182,90,125,219,141,146,235,70,33,1,13,42, +89,108,80,161,5,234,101,38,44,59,150,160,103,244,229,139,179,23,170,112,81,171,151,87,189,116,137,22,58,187, +236,233,117,81,144,15,138,145,63,184,34,16,141,48,240,189,244,128,242,6,221,35,142,212,15,79,149,89,148,51, +89,130,38,17,201,156,10,131,165,226,251,142,186,20,227,241,76,45,213,113,106,20,1,14,166,247,142,167,160,45, +174,202,226,169,16,195,66,80,7,36,47,90,19,171,234,26,215,156,53,224,134,6,155,208,195,74,21,6,223,15, +221,147,80,143,212,18,51,68,76,114,216,31,132,177,110,132,33,87,224,14,233,33,245,109,40,184,61,187,200,212, +202,105,201,41,155,224,121,183,140,129,13,6,184,126,164,215,43,195,155,85,112,39,70,133,156,141,156,203,184,8, +235,24,244,65,149,96,100,206,175,28,57,136,186,44,212,120,149,204,33,163,243,187,36,176,177,22,155,216,117,160, +237,137,59,85,215,158,203,0,20,163,18,113,21,20,226,215,189,90,50,199,82,221,26,209,59,110,90,19,50,33, +245,77,26,0,211,198,14,28,185,173,26,101,177,94,46,225,6,33,71,128,66,68,67,202,2,85,93,137,73,5, +142,140,93,224,132,183,129,197,232,6,158,200,162,191,34,231,222,170,191,46,84,175,65,222,155,149,170,234,21,165, +233,97,64,166,111,9,189,180,247,55,123,248,111,61,7,139,5,207,91,212,46,11,47,121,1,45,249,141,74,187, +46,224,212,231,15,222,64,86,105,117,117,93,94,11,107,24,185,91,13,89,122,156,59,27,224,122,98,40,118,173, +151,230,125,122,138,161,62,119,161,10,193,144,237,75,99,31,111,203,44,228,137,126,100,144,177,124,105,95,144,174, +216,38,67,36,121,194,255,107,2,13,194,116,132,245,114,39,209,180,232,249,168,191,11,124,107,96,79,184,113,230, +165,36,213,25,72,124,98,38,123,211,122,180,143,21,78,207,32,213,106,104,171,10,92,145,102,178,63,21,112,187, +93,153,231,5,38,145,75,183,118,123,10,106,104,219,232,238,253,0,247,218,224,136,112,159,21,70,231,170,26,174, +214,213,130,171,8,255,239,22,191,25,186,170,130,230,175,174,176,66,80,86,145,50,148,59,196,133,81,61,101,85, +23,239,150,170,5,248,133,0,94,67,43,39,13,111,76,151,165,97,245,20,76,200,224,79,44,145,158,84,20,162, +50,188,191,23,81,248,129,0,230,243,134,78,141,156,229,214,237,116,48,49,151,74,141,179,195,29,101,172,51,140, +102,187,161,109,253,188,122,159,190,71,79,92,170,226,216,44,68,83,101,254,177,15,169,12,184,53,166,42,23,169, +111,221,42,255,12,155,201,231,61,78,40,69,32,163,73,156,147,114,10,46,0,201,254,62,232,209,181,117,21,22, +247,64,215,205,106,234,108,56,173,107,31,211,232,53,121,20,197,162,71,72,76,39,222,41,23,235,250,123,205,153, +222,89,84,90,93,160,130,138,202,232,117,134,214,41,143,224,168,243,126,6,71,147,106,42,207,134,190,33,79,14, +37,219,156,247,188,17,34,57,123,181,53,29,36,212,90,207,78,185,15,6,38,198,234,121,237,247,21,89,47,238, +59,187,186,218,129,19,23,184,138,9,187,186,82,195,2,159,66,212,72,15,222,217,78,118,85,121,190,150,172,58, +213,234,120,231,44,55,112,36,18,110,176,190,178,2,59,60,68,1,85,214,175,174,174,184,33,201,236,160,75,8, +48,55,214,174,23,184,72,212,165,84,220,239,32,111,227,75,185,196,212,53,28,242,147,248,118,18,189,76,210,27, +139,114,4,254,40,190,77,201,19,66,71,51,237,9,123,99,130,210,41,37,183,177,234,132,103,97,58,220,124,118, +106,21,61,106,156,39,185,53,68,190,171,52,12,135,109,56,54,206,158,195,129,154,212,115,72,130,184,232,10,144, +225,68,126,51,91,23,225,70,184,189,133,77,92,20,237,5,96,83,70,130,56,81,151,213,14,35,156,76,71,24, +86,56,189,104,171,77,161,92,200,211,129,115,170,126,207,148,174,20,23,176,195,207,149,247,241,38,231,227,249,114, +197,93,185,231,32,94,243,230,34,118,245,198,15,99,7,175,193,11,170,146,31,224,75,100,63,155,200,51,146,47, +96,67,95,18,243,132,56,109,80,92,33,197,114,15,236,152,68,237,199,174,186,163,145,47,240,148,157,14,212,184, +151,56,243,184,169,110,18,164,41,151,7,183,146,69,19,161,127,11,232,27,209,21,44,133,108,230,203,205,108,145, +234,71,134,239,137,112,171,161,101,208,248,238,195,236,45,44,69,151,121,70,5,47,78,218,101,188,82,73,133,6, +83,81,239,37,210,123,196,194,158,173,6,140,188,70,23,166,71,232,102,171,110,253,225,210,150,175,97,85,92,73, +184,20,131,202,168,97,171,158,221,41,121,162,195,3,50,150,24,109,137,137,239,54,214,219,60,124,119,33,12,245, +130,147,171,105,202,19,220,249,31,21,33,253,126,89,55,50,206,175,243,236,173,242,143,253,81,254,119,137,189,184, +63,114,127,115,216,18,78,62,133,74,166,215,132,227,210,174,148,184,224,18,113,99,197,37,103,170,152,185,235,76, +179,246,167,12,86,215,220,109,189,90,83,96,77,45,194,4,44,163,233,182,16,113,176,178,193,96,217,53,224,63, +211,80,199,180,200,219,57,192,156,63,186,182,63,0,141,79,196,179,117,115,153,201,254,187,184,220,81,58,212,95, +110,95,253,80,14,189,202,164,70,157,170,194,244,206,115,212,215,218,244,236,241,30,86,122,158,2,246,63,32,24, +255,3,238,90,212,105,230,137,77,240,174,155,53,175,157,230,181,47,85,182,52,175,109,85,84,110,107,49,184,101, +217,85,212,96,208,18,95,198,100,250,236,81,142,108,187,184,174,115,180,91,102,199,54,185,99,210,110,46,96,246, +29,1,229,1,43,181,233,254,148,121,4,14,15,231,54,252,136,145,51,89,44,232,35,251,76,54,109,13,228,252, +199,64,234,35,82,62,230,55,133,44,26,118,208,80,213,78,43,13,104,197,83,81,67,243,210,21,119,247,206,110, +226,128,97,162,128,225,121,14,91,98,198,195,228,184,37,199,158,77,194,109,56,236,224,33,240,200,16,110,237,222, +110,64,118,231,98,254,156,115,134,134,99,128,136,50,70,169,182,251,148,128,69,13,40,139,188,90,68,156,182,102, +165,110,54,43,229,204,10,133,178,211,254,38,202,21,219,145,164,137,140,198,192,187,18,215,145,94,65,135,203,136, +128,223,92,19,137,53,144,19,253,191,145,104,116,32,207,167,111,125,99,150,40,162,230,93,137,111,164,117,162,178, +110,60,183,174,183,226,66,190,164,100,186,244,145,32,53,24,32,86,134,161,149,53,89,214,182,107,35,238,92,255, +218,67,236,230,227,77,115,113,76,232,130,3,237,181,54,209,224,175,177,73,81,67,232,234,68,150,226,85,239,124, +196,137,213,212,60,124,48,16,35,215,176,62,110,74,166,207,107,180,217,83,37,11,223,159,198,132,21,74,62,166, +25,176,237,189,61,217,211,76,240,66,212,244,241,225,104,54,187,233,227,3,74,229,193,237,187,41,198,194,128,95, +118,119,66,25,119,208,123,229,88,113,170,52,41,139,107,186,207,38,10,223,60,101,105,19,122,76,219,24,25,57, +53,156,149,249,172,183,215,151,50,199,112,198,243,230,202,39,32,173,29,141,243,219,255,17,141,7,233,17,19,80, +210,120,47,155,211,56,111,105,135,148,198,217,222,29,133,227,170,41,236,103,10,77,94,53,95,72,240,54,60,151, +197,184,218,194,129,86,149,147,6,149,76,185,162,212,2,57,25,123,41,34,166,43,191,185,253,64,96,59,118,199, +202,48,44,166,232,75,73,229,135,46,10,197,13,134,71,246,247,254,165,118,125,133,106,189,34,33,43,202,217,94, +66,182,184,180,135,201,48,168,5,238,107,83,1,198,138,70,205,14,182,68,211,253,82,20,228,148,170,135,7,76, +12,155,43,70,184,50,57,201,221,207,238,31,52,146,187,155,221,203,26,201,205,238,56,201,209,248,96,254,128,230, +179,155,202,253,221,118,18,180,181,148,234,22,235,53,248,89,168,220,162,186,153,106,46,119,59,206,249,62,9,21, +169,64,16,75,232,239,91,241,87,147,229,84,102,150,247,244,206,236,224,191,200,249,237,3,117,191,177,144,89,250, +224,78,195,231,108,239,222,189,96,33,119,14,246,28,159,193,162,50,26,223,121,104,231,151,52,158,207,142,230,56, +94,187,179,7,15,113,60,183,242,218,63,184,139,227,25,141,213,131,35,26,175,44,156,123,251,51,28,47,34,107, +60,181,178,62,218,35,248,103,22,102,118,143,230,143,34,43,61,142,116,112,25,233,230,220,226,157,223,39,248,23, +150,175,59,251,180,231,208,90,254,221,251,68,219,137,221,127,103,255,1,142,223,218,249,123,25,205,191,195,177,115, +36,1,79,44,156,125,43,147,223,118,126,127,159,230,191,208,248,158,82,68,219,7,75,195,189,135,52,255,200,210, +121,255,62,141,191,58,222,237,254,247,246,236,158,34,218,158,209,248,232,222,109,154,127,101,229,112,247,128,104,248, +151,163,231,30,209,240,111,145,61,61,181,184,30,206,233,236,71,123,246,254,109,164,167,185,151,192,115,249,136,51, +247,161,29,119,124,147,204,125,167,100,240,75,178,96,46,12,62,203,103,156,153,242,163,206,79,115,147,159,17,228, +199,242,41,117,4,224,19,62,209,9,141,210,207,209,213,190,9,120,225,157,127,242,107,10,47,101,57,116,16,225, +135,204,57,123,253,229,195,123,6,172,178,87,213,124,126,137,112,190,203,183,195,57,252,148,239,240,239,63,229,33, +254,125,45,159,224,223,191,228,7,206,42,123,182,194,109,111,232,181,92,253,209,206,24,99,119,24,237,190,73,251, +149,63,48,16,231,56,73,160,149,105,97,208,14,183,55,222,161,237,142,243,19,130,87,24,36,246,147,163,29,74, +35,251,5,86,105,248,7,249,104,158,148,192,103,79,236,191,220,60,55,178,26,12,214,156,111,251,232,253,190,188, +228,63,249,166,6,150,50,216,160,112,146,237,77,63,109,254,113,59,92,15,224,126,45,134,24,136,5,253,21,98, +188,59,14,127,231,47,64,137,81,49,24,248,78,226,11,12,86,240,211,111,2,156,55,24,223,95,12,6,63,105, +35,20,162,78,126,66,106,226,56,17,74,128,191,38,102,138,148,190,68,198,194,213,254,49,215,224,62,185,126,3, +147,30,39,6,102,170,202,116,238,238,119,170,22,80,97,119,71,15,163,89,219,253,165,75,168,92,142,183,59,29, +94,252,172,109,104,213,201,141,141,39,156,136,190,73,191,172,33,51,91,17,206,72,203,31,110,126,227,120,94,224, +41,31,131,142,108,246,8,204,80,207,2,230,252,47,20,195,24,105,86,197,250,84,105,250,253,243,152,83,251,234, +57,85,239,147,231,211,73,65,95,14,252,8,111,253,200,142,188,36,57,180,7,146,99,190,7,184,66,95,0,253, +217,171,171,159,244,132,99,12,160,27,156,135,0,128,210,151,113,159,222,112,251,79,63,170,97,121,93,13,129,114, +45,207,184,66,237,201,115,164,152,186,125,89,106,248,194,224,75,224,229,35,47,160,243,161,22,173,175,63,247,95, +206,53,40,164,39,51,78,70,104,17,194,18,84,195,186,139,50,136,219,85,2,116,209,31,95,34,17,201,210,112, +122,226,142,26,230,102,71,87,232,8,143,19,99,90,190,142,218,19,170,33,175,111,223,157,102,72,224,74,16,117, +164,33,219,172,232,115,204,207,248,238,15,217,241,95,118,224,230,156,42,112,64,34,84,83,156,39,121,205,118,155, +237,25,17,26,116,109,171,86,50,121,15,180,192,195,132,184,8,237,232,239,40,158,34,16,90,118,246,105,139,89, +59,205,161,97,151,145,145,88,69,150,117,13,171,93,2,249,39,39,58,72,32,147,105,171,35,213,253,210,75,136, +140,69,244,213,62,181,235,164,25,82,15,249,204,98,23,100,107,224,160,17,131,26,191,73,28,150,162,131,69,119, +177,244,27,52,202,10,253,133,29,23,14,21,249,184,197,86,212,182,167,128,60,190,108,113,134,43,127,47,118,187, +237,250,201,133,240,240,93,166,23,117,221,152,240,29,38,172,164,215,116,215,111,238,28,131,65,40,55,195,18,22, +172,99,215,166,228,241,156,72,220,86,80,242,189,45,228,59,82,105,45,203,127,164,120,3,184,39,50,28,55,68, +29,90,179,227,193,142,156,47,231,198,155,157,245,84,20,102,184,42,163,7,149,6,239,221,198,134,74,106,37,206, +243,227,181,243,247,254,30,80,43,81,83,97,100,220,239,29,224,139,13,149,192,154,86,43,131,29,193,255,147,197, +38,134,24,60,73,236,120,6,152,239,126,124,177,89,146,237,252,49,0,34,177,172,59,211,192,252,39,231,6,222, +225,35,51,240,22,31,51,3,23,248,192,244,40,87,6,78,240,177,48,240,10,31,187,97,61,243,176,0,121,228, +63,61,221,81,204,102,219,236,238,76,83,129,157,232,108,77,50,185,186,250,130,82,99,43,95,217,191,170,158,5, +191,97,128,164,111,214,69,149,206,9,112,45,200,250,248,230,120,89,30,165,75,194,68,221,125,122,98,13,146,169, +89,210,207,160,90,164,167,248,172,97,227,44,45,121,137,56,62,114,140,134,70,116,197,245,47,231,60,4,208,164, +154,104,254,6,212,102,138,225,17,28,28,39,219,174,229,244,230,191,114,161,217,80,84,9,183,112,42,251,125,52, +126,201,67,100,115,243,82,131,50,182,221,74,110,139,157,243,231,93,248,182,11,86,25,28,109,57,143,185,197,90, +199,241,201,208,227,87,6,76,192,143,240,205,20,35,118,165,156,157,196,202,160,106,100,207,173,229,116,21,191,190, +182,95,215,177,72,152,203,166,204,73,102,135,164,43,148,144,251,230,146,172,13,116,47,105,73,118,109,38,87,21, +230,7,178,143,232,199,110,79,189,61,160,24,102,230,191,136,28,145,118,129,208,85,189,74,86,215,97,59,27,168, +146,197,127,13,112,183,6,67,215,224,54,79,35,182,221,96,119,120,12,29,58,37,229,145,28,127,56,107,57,69, +185,98,184,140,161,187,5,131,230,17,46,142,19,106,202,77,89,95,254,224,19,67,137,139,109,106,251,182,73,19, +83,71,239,161,192,33,218,70,17,87,84,18,111,241,116,106,144,252,80,37,239,190,147,67,41,17,37,228,114,223, +255,18,230,122,4,254,123,46,74,151,5,218,96,155,223,186,53,245,63,188,81,192,87,156,114,112,136,211,212,133, +244,86,236,5,51,179,27,184,146,219,173,191,102,166,173,236,10,251,69,50,254,124,97,253,11,8,100,235,103,84, +67,150,147,125,114,165,31,195,116,181,90,94,114,146,33,148,36,252,250,223,75,187,210,182,184,113,108,253,125,126, +5,229,167,31,174,124,81,42,85,132,84,18,211,74,101,95,38,59,208,43,195,228,113,217,50,184,49,118,181,151, +108,116,221,223,126,207,171,197,86,97,67,232,153,47,148,36,203,178,44,233,236,239,49,224,84,135,123,36,138,255, +208,76,107,143,227,71,219,226,239,18,178,109,136,159,146,141,113,64,12,94,145,68,56,187,55,13,134,180,132,55, +97,125,50,142,100,154,241,92,151,147,172,40,202,65,203,185,61,6,38,158,45,182,106,127,62,9,88,125,127,50, +207,131,210,7,203,161,39,221,185,23,255,109,59,184,181,119,83,148,19,25,194,150,13,29,187,182,178,246,113,107, +7,223,221,105,237,224,40,78,208,167,113,236,197,68,140,70,228,189,9,215,78,101,234,196,62,173,119,218,59,210, +251,112,142,16,164,203,47,232,85,152,91,237,29,72,3,38,243,184,26,20,135,178,148,97,230,28,206,132,206,166, +121,202,0,143,141,244,214,87,172,29,72,105,73,3,231,165,94,139,41,97,158,172,236,44,136,178,221,150,12,242, +151,249,189,104,106,219,161,196,75,4,53,255,155,119,107,78,109,110,86,164,79,202,97,55,207,145,157,103,250,215, +95,195,43,12,238,224,92,225,237,149,181,183,31,188,213,167,3,21,207,174,123,160,134,221,131,46,75,202,181,156, +230,82,120,142,195,71,203,92,144,229,150,240,142,97,51,143,211,227,188,40,229,227,176,146,166,57,85,205,234,255, +120,103,105,110,91,207,84,107,92,212,15,51,123,127,165,154,154,60,141,138,216,118,107,84,155,78,177,52,77,202, +240,6,189,200,157,201,117,156,137,45,41,164,142,139,39,28,118,32,242,74,156,175,92,191,88,109,119,177,190,204, +41,102,156,139,149,35,105,43,98,155,187,18,108,141,70,179,6,216,225,17,181,242,12,228,197,36,247,30,62,126, +252,116,127,255,221,222,62,66,60,114,220,86,137,24,113,125,226,207,37,41,174,65,196,19,85,159,162,62,61,50, +122,236,174,243,32,26,176,36,174,90,184,39,15,83,202,168,49,55,51,106,163,180,231,154,113,7,55,166,171,221, +108,14,143,220,212,90,161,174,154,22,173,252,160,6,11,157,114,139,219,225,13,79,64,200,106,225,239,93,199,97, +167,1,186,202,133,52,157,193,61,84,57,46,170,200,217,139,204,113,57,53,14,75,75,68,214,65,183,168,30,35, +96,190,188,212,103,121,120,164,16,7,42,146,101,202,204,55,190,249,20,8,53,86,136,144,133,44,245,125,94,140, +68,15,113,175,96,135,133,239,7,177,50,204,172,5,155,163,29,251,200,27,178,128,89,206,19,18,88,21,126,249, +210,205,0,56,239,249,99,131,156,63,250,233,249,243,223,62,238,63,124,246,112,239,229,199,151,7,79,247,30,30, +208,30,7,49,173,226,98,178,51,189,38,117,78,38,82,218,179,156,220,142,147,53,74,205,231,231,171,22,156,17, +92,14,206,240,182,10,77,194,91,222,145,135,231,223,190,115,187,247,124,103,227,120,197,35,158,97,219,29,111,107, +220,121,34,199,137,246,141,70,179,197,204,250,70,183,163,132,122,41,175,221,25,234,211,40,142,148,127,52,25,191, +105,234,16,79,122,183,168,100,73,216,14,178,89,199,191,200,197,171,180,190,120,133,47,68,130,93,129,71,157,31, +83,217,48,58,254,85,120,166,217,19,98,201,22,112,164,198,44,225,222,159,141,108,228,155,52,194,39,216,170,83, +229,84,5,220,221,96,188,191,16,33,230,61,134,198,229,46,24,74,45,22,196,132,206,194,52,39,50,196,162,166, +53,243,141,186,3,128,179,40,198,9,20,161,66,197,240,84,208,70,50,27,34,40,45,115,40,136,148,252,32,21, +250,204,0,79,210,150,107,53,44,178,73,232,54,254,117,30,186,51,89,168,81,15,136,185,49,56,210,62,17,201, +158,205,89,5,76,74,36,226,34,130,78,101,193,75,7,212,243,109,17,75,230,193,149,40,41,216,66,247,140,11, +189,104,44,226,231,64,120,132,17,61,232,73,88,135,202,46,226,107,15,139,198,49,93,16,52,122,69,228,125,188, +185,121,108,49,230,115,150,137,182,194,244,196,65,138,153,18,105,235,163,52,154,31,100,240,252,249,193,218,165,19, +125,41,193,37,151,50,104,3,250,82,252,60,201,131,90,5,209,12,79,35,247,1,72,183,141,149,22,240,150,8, +201,105,101,193,186,193,241,193,35,134,143,172,115,68,11,235,240,238,113,252,206,201,93,57,1,129,200,9,8,100, +162,176,206,218,70,228,214,177,156,136,104,222,4,13,57,99,199,142,161,141,35,28,126,71,221,99,153,114,149,48, +98,74,41,107,168,60,207,192,177,27,250,19,168,82,98,93,31,99,111,11,110,24,52,170,23,189,157,12,191,168, +171,253,57,42,104,234,170,160,142,170,133,214,86,247,39,173,170,46,105,208,1,3,69,169,162,105,80,104,85,148, +14,42,188,248,151,207,96,114,107,54,179,75,189,179,19,198,88,106,39,30,18,170,101,159,68,59,118,169,233,117, +212,82,131,47,195,94,224,217,128,91,106,42,0,195,17,219,248,201,196,45,252,52,98,7,63,137,152,225,39,22, +183,21,176,33,233,101,9,44,249,9,63,227,159,186,56,245,130,31,19,187,72,217,18,60,162,96,95,193,18,114, +134,78,183,16,102,9,217,103,11,33,227,167,98,194,95,3,228,88,241,55,66,206,95,211,96,31,253,160,84,133, +137,111,5,238,199,251,167,187,167,91,91,64,149,178,248,175,191,78,129,175,250,12,103,208,66,124,62,60,61,34, +62,245,133,45,248,41,255,10,175,8,122,73,255,13,181,139,14,203,127,236,235,255,215,162,210,55,66,106,187,21, +180,194,89,213,111,155,250,198,66,215,103,182,126,170,235,219,65,164,9,236,13,95,116,168,154,198,138,248,105,187, +42,243,27,211,32,35,213,145,14,237,155,149,171,182,156,155,160,76,144,49,162,239,179,112,73,133,169,207,147,52, +163,211,76,229,109,218,174,226,76,82,137,86,9,0,188,175,84,220,65,135,60,166,210,109,93,122,137,143,146,80, +117,6,93,0,145,174,225,115,210,197,205,174,82,156,70,121,103,12,90,248,22,47,96,63,146,60,238,171,244,172, +20,117,43,236,124,104,56,172,16,45,180,184,29,72,13,48,124,183,181,244,190,115,243,232,191,123,124,207,193,249, +56,204,255,167,134,91,19,31,2,218,48,34,185,46,54,150,54,224,181,161,35,196,88,83,168,63,23,76,206,118, +5,225,138,225,16,185,131,54,169,163,9,92,205,153,218,57,27,200,223,93,126,99,170,30,61,139,226,235,113,216, +72,170,240,95,42,40,53,42,42,74,121,227,143,234,99,69,18,72,198,31,63,34,207,48,63,76,201,124,41,88, +138,216,133,51,153,144,30,114,119,17,14,77,127,183,188,76,183,99,6,46,33,136,231,66,244,57,200,136,174,151, +231,51,39,118,223,207,231,250,76,103,183,248,12,116,159,208,69,127,213,77,171,164,105,209,219,13,191,187,35,69, +10,39,212,155,42,246,23,207,160,242,164,32,10,202,187,11,187,176,106,127,7,220,151,69,150,37,171,193,19,39, +60,179,152,88,5,219,172,252,81,174,82,138,128,161,168,212,111,214,2,100,215,1,176,247,35,95,117,17,242,48, +130,223,133,94,238,255,32,116,74,18,58,246,158,46,194,147,97,131,163,233,245,68,168,141,121,167,36,7,173,38, +130,244,81,134,172,65,250,107,180,146,167,153,196,21,255,234,227,22,206,47,244,167,107,4,41,83,243,9,103,215, +144,116,144,33,147,24,38,234,247,221,117,70,175,199,167,230,142,243,145,16,5,201,61,93,9,10,136,54,56,61, +174,6,202,244,150,0,123,62,153,221,187,154,149,81,137,238,99,18,246,156,11,168,119,145,88,82,115,56,96,226, +88,173,4,165,85,187,90,120,29,83,185,46,75,173,243,98,133,136,208,174,183,99,48,173,174,152,34,40,8,176, +12,84,58,5,54,135,26,34,45,160,10,15,196,233,189,148,253,192,187,3,115,250,210,14,93,187,139,40,26,141, +234,150,56,219,32,33,114,34,48,218,236,138,19,176,179,125,55,233,33,62,250,39,108,200,249,51,239,52,203,225, +37,233,142,231,5,191,230,143,219,243,148,229,218,221,154,178,2,133,0,213,205,77,252,61,148,96,108,170,90,232, +42,189,5,80,24,215,176,230,192,161,135,66,26,188,176,230,232,101,94,112,100,117,67,224,24,167,219,52,216,94, +241,169,175,0,79,233,188,175,76,21,198,63,234,187,233,28,210,9,62,174,0,92,139,183,239,46,134,215,190,67, +123,236,230,174,17,142,123,22,139,235,145,207,173,197,66,174,157,199,193,52,15,82,143,189,54,195,195,75,243,243, +213,188,111,171,193,242,135,120,83,98,160,254,222,90,177,94,50,125,247,4,99,158,182,113,237,195,35,248,180,74, +55,62,249,176,44,195,175,230,176,166,228,192,188,168,109,210,94,116,201,177,10,70,70,221,184,156,155,49,113,57, +40,157,172,149,20,6,33,179,170,36,150,240,214,162,127,88,250,214,126,231,148,77,81,134,195,0,219,1,169,218, +127,193,46,102,152,186,177,49,60,109,231,42,6,2,40,145,50,230,11,71,202,165,142,71,38,4,172,198,77,255, +247,175,64,135,213,202,19,85,139,146,136,207,157,94,168,132,89,205,195,126,88,208,164,73,173,124,80,209,144,8, +102,109,131,149,157,67,34,70,217,217,48,119,132,192,95,170,185,100,95,178,86,31,176,252,65,187,46,15,136,74, +54,55,187,50,81,124,215,183,167,58,232,223,225,62,149,204,146,205,77,252,29,190,14,250,163,43,151,171,46,190, +155,150,193,60,104,73,158,143,253,139,23,147,107,9,0,88,177,145,221,61,185,61,155,96,247,28,159,91,229,236, +106,36,170,53,223,90,134,250,218,46,243,198,166,110,86,109,190,78,2,253,196,36,46,197,164,226,37,71,124,41, +98,130,10,117,91,13,229,89,231,91,47,15,163,163,17,18,149,65,179,33,91,242,136,55,86,6,156,249,231,184, +44,154,149,234,152,17,71,69,143,140,39,62,47,104,88,223,62,241,4,79,76,125,213,235,4,195,165,244,211,142, +120,194,81,117,7,165,170,234,162,64,252,128,216,93,190,114,145,179,114,119,238,194,67,220,103,85,112,34,186,222, +11,135,238,107,21,80,226,114,50,13,255,131,168,141,113,79,167,206,22,134,14,1,86,142,250,17,173,145,105,166, +177,137,64,128,98,135,140,143,66,37,21,12,89,44,27,141,66,199,184,161,121,56,67,155,110,195,220,248,92,195, +220,64,188,69,184,36,240,137,199,253,144,64,79,108,78,237,80,226,2,36,67,183,6,67,200,12,46,197,69,124, +72,60,135,142,223,64,71,108,135,171,231,52,183,0,109,54,48,234,161,149,94,46,57,148,26,18,37,201,165,205, +98,222,104,135,251,82,56,135,82,52,206,1,93,186,202,153,73,115,63,17,203,214,114,226,103,22,164,200,106,89, +213,190,39,108,88,191,97,30,90,60,31,46,205,155,255,214,157,254,197,216,248,127,253,127,249,135,255,246,143,182, +126,184,185,27,177,229,181,145,16,238,106,86,218,59,59,199,95,107,164,50,157,45,193,165,56,113,211,103,67,150, +116,209,6,207,51,58,229,217,92,26,107,238,14,172,185,0,73,116,203,44,164,250,39,238,253,48,245,214,86,174, +180,123,66,162,201,65,79,184,225,244,73,135,150,136,21,119,134,27,255,90,6,146,245,3,165,29,222,212,6,2, +238,128,2,42,136,148,151,79,63,190,223,123,119,240,14,39,188,231,139,119,13,198,249,224,23,78,130,33,25,160, +77,42,204,141,22,18,25,162,193,144,98,232,238,63,201,9,123,244,122,215,230,107,181,110,114,193,218,45,122,118, +243,40,64,144,25,171,68,239,120,5,187,158,92,96,52,163,245,144,161,45,110,212,8,157,246,129,213,238,140,116, +186,224,224,234,48,80,80,237,19,73,59,247,42,204,2,228,194,53,249,21,204,220,206,203,23,91,135,170,69,143, +135,14,242,183,82,187,30,199,218,203,231,41,13,170,3,136,243,76,132,74,235,106,68,232,64,121,35,119,29,42, +166,110,226,250,94,143,179,117,77,221,200,69,141,28,141,184,49,1,149,201,165,63,146,59,225,167,84,80,122,132, +207,251,136,138,166,13,95,214,99,125,51,135,47,7,247,240,156,10,106,144,173,45,171,45,75,242,51,220,23,214, +204,158,51,123,147,241,234,91,68,173,169,217,12,111,63,240,32,48,60,144,151,233,145,155,139,211,85,224,169,150, +181,171,146,64,129,93,7,211,120,152,115,180,183,23,64,160,230,94,236,192,248,161,101,159,2,101,172,89,193,244, +115,125,148,108,79,148,165,206,189,241,212,190,71,209,240,177,180,122,230,149,138,157,149,199,5,228,177,244,209,94, +112,169,146,232,59,32,19,78,63,161,197,135,31,211,41,31,58,75,131,250,206,102,119,254,166,29,121,46,225,78, +163,69,49,106,35,172,74,215,172,116,251,116,170,229,106,133,135,69,201,181,131,150,188,114,228,117,228,132,36,51, +71,94,55,14,178,34,113,208,23,177,163,184,47,81,198,210,35,66,230,160,230,207,212,248,179,109,220,251,201,145, +245,11,29,53,83,220,243,88,149,239,133,160,193,175,78,164,237,179,234,127,111,187,203,30,216,86,115,248,168,239, +189,131,241,79,29,164,199,235,11,145,185,55,168,35,250,135,12,2,7,5,242,135,161,115,220,191,111,93,30,54, +131,0,123,133,12,2,135,230,15,148,94,178,19,97,126,111,29,213,242,169,122,94,60,153,168,12,130,183,204,171, +150,50,194,41,68,18,65,7,254,248,65,60,4,47,224,79,232,23,211,122,143,122,203,27,190,249,252,153,72,248, +79,34,27,183,94,84,254,155,200,58,95,212,30,85,108,148,240,145,104,176,252,116,12,232,33,31,196,254,56,225, +207,197,7,254,194,13,24,126,101,123,4,189,162,104,57,251,109,115,243,55,235,142,194,103,204,225,95,107,83,141, +209,128,156,1,175,201,241,207,50,50,25,151,18,12,86,73,242,95,133,103,107,246,170,71,57,5,19,202,40,152, +242,63,197,54,127,69,191,117,77,5,89,139,3,246,109,128,17,125,102,207,252,145,213,40,168,172,156,205,26,223, +55,155,9,33,158,118,33,123,92,121,177,185,57,0,24,49,139,184,103,231,162,103,221,122,85,116,110,239,232,217, +48,48,196,29,255,233,125,113,123,186,185,121,51,15,149,15,26,192,139,155,99,232,56,52,179,46,176,160,93,10, +207,218,8,225,180,135,160,101,235,136,159,30,0,136,231,98,93,116,117,249,164,249,225,75,160,31,71,76,246,0, +52,184,213,145,180,165,70,53,215,66,34,111,226,227,250,103,15,158,141,181,126,116,168,179,159,189,163,139,3,225, +222,124,0,14,221,2,204,71,64,66,15,225,115,24,132,6,230,230,195,181,183,226,69,63,103,64,69,12,198,121, +81,167,73,42,99,255,188,43,219,12,121,44,0,29,57,117,87,181,251,166,7,250,43,132,52,31,202,73,169,164, +18,155,133,248,39,15,197,196,248,124,115,235,243,13,245,13,38,60,47,242,195,144,92,191,28,110,160,102,92,156, +6,205,56,9,211,140,199,162,177,251,197,151,40,171,179,194,79,68,99,226,221,202,149,146,204,89,10,156,202,184, +61,214,208,170,137,34,52,212,223,231,238,149,87,62,31,65,23,79,230,149,40,2,70,54,246,137,141,108,243,74, +36,172,240,57,181,177,19,19,69,231,25,212,114,92,18,162,177,14,205,249,146,253,212,66,151,110,80,200,154,196, +73,244,53,202,0,226,10,88,36,242,154,85,190,63,55,145,174,138,199,124,233,7,49,218,130,37,43,28,75,143, +158,52,34,136,75,251,176,37,53,174,86,206,26,147,79,157,187,219,48,229,128,201,56,239,67,32,55,245,146,6, +213,146,214,226,18,52,196,238,47,115,150,139,53,150,193,60,245,131,72,188,125,51,33,121,142,167,87,180,82,37, +21,211,60,173,117,223,218,38,189,93,96,51,44,167,183,34,151,160,25,32,144,92,223,78,58,57,103,133,200,14, +61,58,132,91,228,124,156,23,212,53,0,108,255,231,205,205,63,152,247,147,101,62,27,230,214,13,135,71,17,149, +244,243,113,94,155,168,125,143,33,209,76,219,131,87,8,133,163,52,182,36,43,197,59,230,118,127,49,223,27,203, +51,90,236,142,53,238,117,143,205,121,237,7,116,241,103,94,171,248,255,250,209,121,65,225,85,140,61,175,235,224, +21,47,199,74,68,91,40,179,201,132,84,124,162,170,7,157,59,221,80,35,33,94,209,62,214,99,253,239,25,86, +60,186,214,187,118,147,111,71,122,97,25,184,158,248,175,52,113,179,18,152,126,47,155,102,45,77,184,189,80,128, +249,225,90,193,85,30,110,51,116,147,84,223,168,0,157,181,159,28,49,80,86,223,62,82,148,220,82,253,159,188, +80,231,18,71,6,217,50,253,17,45,191,193,96,118,116,119,80,144,54,186,224,196,216,100,213,142,234,54,34,21, +139,92,200,13,195,31,226,141,180,134,223,202,100,90,20,32,66,210,234,138,121,159,75,209,105,181,90,169,122,72, +97,93,158,89,205,146,26,91,207,165,143,74,99,43,126,231,72,109,116,206,82,10,146,83,121,78,253,119,255,103, +251,238,211,222,157,237,147,205,8,171,93,9,251,255,217,218,129,57,54,89,27,156,20,136,5,53,112,7,45,236, +27,65,246,131,169,41,95,50,211,51,71,139,157,122,91,115,194,36,77,155,228,81,98,155,243,181,135,62,113,141, +147,111,86,111,231,150,247,160,172,79,43,74,45,131,10,136,65,181,135,17,87,212,18,4,191,115,215,182,128,3, +55,119,28,25,75,230,72,117,110,177,183,253,72,240,123,99,239,228,226,3,59,53,107,210,69,2,115,18,20,98, +64,175,32,185,74,59,164,4,72,119,121,221,133,201,115,35,63,4,72,74,23,173,29,84,26,162,20,35,148,219, +23,213,129,200,220,231,165,222,229,145,248,29,137,49,198,211,137,173,238,184,232,208,199,7,122,32,94,243,56,3, +169,237,59,166,96,252,230,92,109,180,191,139,219,90,30,173,183,214,10,70,97,79,173,244,109,59,182,67,216,243, +139,100,53,210,37,197,135,65,158,36,132,120,70,235,69,63,169,114,88,21,112,88,61,7,128,134,71,131,48,95, +132,58,66,145,116,251,167,225,85,49,115,154,184,135,182,158,249,235,124,214,198,249,42,231,51,118,161,91,104,201, +209,136,53,189,92,186,178,22,21,224,3,187,251,136,188,215,174,31,104,29,22,234,122,133,18,121,201,22,61,102, +207,248,35,131,185,207,120,235,231,83,105,15,208,4,174,72,210,145,72,72,48,28,42,120,182,66,214,37,17,177, +149,156,103,48,8,82,209,224,167,106,35,192,223,20,201,92,28,68,111,226,0,112,220,164,26,217,21,180,242,73, +173,89,119,166,184,236,130,175,87,62,140,54,217,60,79,29,166,225,245,136,116,218,161,58,36,207,2,19,147,251, +206,192,37,70,165,57,13,188,130,38,25,241,65,37,115,118,193,99,248,104,172,134,151,174,137,109,123,116,22,76, +218,206,62,7,62,22,154,37,175,196,116,247,11,171,57,187,248,164,72,144,82,9,5,110,186,155,106,242,181,168, +192,138,218,75,251,57,229,193,111,222,102,116,204,161,250,241,20,30,254,154,223,184,65,46,244,28,176,91,80,43, +142,101,215,180,234,120,82,170,149,2,5,46,48,98,216,137,131,243,50,140,228,181,22,68,103,87,15,44,66,177, +182,8,253,247,46,46,190,85,183,188,80,104,220,185,22,118,174,57,43,250,115,5,207,134,135,254,122,190,210,219, +51,153,80,57,117,114,252,195,206,227,223,119,201,244,190,69,4,200,129,250,156,84,194,35,145,170,16,193,100,55, +251,177,52,246,194,110,182,181,165,31,221,136,146,34,45,187,24,160,1,134,25,191,60,98,146,55,32,80,204,121, +113,85,184,4,222,7,119,62,202,247,52,78,43,245,59,20,36,49,174,60,33,208,134,241,239,221,14,191,231,27, +226,133,227,97,76,197,90,236,153,135,230,153,67,110,226,1,234,107,195,26,80,19,10,237,43,211,159,70,10,9, +156,132,18,102,5,47,199,245,28,162,214,49,83,244,141,72,94,174,203,25,229,126,117,201,194,40,109,237,148,164, +19,117,25,248,158,200,163,48,182,70,254,133,92,88,169,64,146,57,168,104,77,148,229,236,130,16,67,100,218,9, +129,14,103,114,26,185,133,117,0,176,252,122,65,105,156,132,239,6,137,121,37,188,214,83,233,9,81,116,139,209, +199,93,172,128,241,141,250,120,21,219,17,25,146,157,46,182,134,105,204,231,69,48,176,29,60,183,180,234,132,144, +200,112,210,233,30,177,167,188,245,186,241,45,149,188,192,124,231,193,133,250,69,76,138,54,171,142,135,190,63,47, +131,106,14,114,107,177,71,66,176,92,160,197,31,12,190,73,197,82,164,156,59,75,129,207,203,115,4,69,134,23, +219,65,47,23,29,98,25,164,96,157,188,223,193,28,31,214,200,51,199,143,138,134,168,173,93,204,254,163,24,165, +133,63,117,95,67,9,117,159,104,129,13,118,80,190,145,19,47,200,212,189,250,203,37,141,115,70,18,69,66,113, +44,173,143,20,9,60,240,145,2,5,173,2,87,202,73,26,219,10,63,111,147,98,32,28,39,193,132,3,245,2, +231,105,227,58,21,63,1,85,172,110,225,11,13,131,62,11,191,56,56,49,27,81,80,92,195,85,101,150,228,69, +58,33,81,171,238,29,210,162,121,142,244,7,147,112,134,73,87,44,105,113,195,75,129,244,153,24,83,14,153,243, +185,131,24,159,124,85,70,116,202,18,95,217,209,137,235,250,226,3,154,33,193,26,203,145,208,220,13,223,99,100, +78,180,9,214,127,169,199,41,15,207,142,184,57,184,165,106,49,82,217,15,108,145,151,194,140,227,196,98,75,223, +183,196,96,33,250,20,59,247,85,88,63,7,175,98,93,215,185,186,25,73,137,11,118,114,3,16,104,236,226,100, +119,249,227,201,238,146,100,127,67,210,100,137,32,64,66,110,83,166,22,232,112,217,125,222,195,122,169,68,195,115, +37,8,113,40,134,79,186,3,30,47,244,209,184,59,249,222,233,206,153,61,211,192,58,92,142,82,123,188,191,191, +215,100,242,117,90,213,116,108,168,182,143,127,46,243,68,70,89,88,134,184,67,183,254,12,209,109,59,101,41,209, +231,30,81,181,105,120,242,238,205,122,77,115,183,174,126,80,156,202,92,85,167,28,57,23,7,234,255,227,200,146, +226,94,103,166,215,179,180,157,196,139,131,55,175,41,215,237,113,145,101,218,228,51,109,189,6,114,127,159,25,152, +164,105,217,151,232,209,181,189,145,113,26,154,97,223,164,103,18,130,67,109,27,213,145,242,28,35,79,228,77,184, +68,149,74,102,138,239,195,20,239,71,201,50,149,125,169,247,89,115,156,230,109,193,142,177,255,243,243,215,106,23, +117,55,212,223,54,103,11,89,118,245,247,68,103,251,242,216,105,40,104,244,174,234,174,21,234,122,109,232,205,108, +83,209,16,17,62,106,146,164,27,21,91,180,127,34,165,29,6,25,47,116,95,116,250,184,145,23,155,108,189,104, +34,51,75,125,38,46,21,97,54,223,195,21,29,68,106,38,251,2,89,235,155,155,189,79,201,152,171,86,5,89, +113,132,120,190,135,197,113,159,48,126,223,234,132,187,63,222,212,152,128,251,255,248,241,230,162,136,191,226,247,164, +62,203,238,255,227,255,1,204,222,188,142,16,149,2,0 +}; + +#endif diff --git a/NetworkManager/include/api/rest_api_handler.hpp b/NetworkManager/include/api/rest_api_handler.hpp index 57da38c..2f48a8c 100644 --- a/NetworkManager/include/api/rest_api_handler.hpp +++ b/NetworkManager/include/api/rest_api_handler.hpp @@ -1,45 +1,45 @@ -#pragma once -#define XWEBSERVERHANDLER_HPP -#include "asyncota.hpp" -#include "base_api.hpp" -#include "server.hpp" - -class APIServer : public BaseAPI { - private: - /* Handlers */ - void handleRequest(AsyncWebServerRequest* request); - void handle_user_commands(AsyncWebServerRequest* request); - - public: - APIServer(ProjectConfig& configManager, AsyncServer_t& async_server, - AsyncOTA* async_ota = nullptr); - virtual ~APIServer(); - void begin(); - void setupServer(); - - bool findParam(AsyncWebServerRequest* request, const std::string& param, - std::string& value); - void addAPICommand(const std::string& url, ArRequestHandlerFunction funct); - void addRouteMap(const std::string& index, route_t route); - void setupCaptivePortal(bool apMode = false); - - public: - AsyncServer_t& async_server; - AsyncOTA* async_ota; - - std::vector indexes; -}; - -//* Captive Portal Handler -class CaptiveRequestHandler : public AsyncWebHandler { - AsyncServer_t& async_server; - - public: - CaptiveRequestHandler(AsyncServer_t& async_server); - virtual ~CaptiveRequestHandler(); - - bool canHandle(AsyncWebServerRequest* request); - - //* use SPIFFS or built in HTML wifimanager - void handleRequest(AsyncWebServerRequest* request); -}; +#pragma once +#define XWEBSERVERHANDLER_HPP +#include "asyncota.hpp" +#include "base_api.hpp" +#include "server.hpp" + +class APIServer : public BaseAPI { + private: + /* Handlers */ + void handleRequest(AsyncWebServerRequest* request); + void handle_user_commands(AsyncWebServerRequest* request); + + public: + APIServer(ProjectConfig& configManager, AsyncServer_t& async_server, + AsyncOTA* async_ota = nullptr); + virtual ~APIServer(); + void begin(); + void setupServer(); + + bool findParam(AsyncWebServerRequest* request, const std::string& param, + std::string& value); + void addAPICommand(const std::string& url, ArRequestHandlerFunction funct); + void addRouteMap(const std::string& index, route_t route); + void setupCaptivePortal(bool apMode = false); + + public: + AsyncServer_t& async_server; + AsyncOTA* async_ota; + + std::vector indexes; +}; + +//* Captive Portal Handler +class CaptiveRequestHandler : public AsyncWebHandler { + AsyncServer_t& async_server; + + public: + CaptiveRequestHandler(AsyncServer_t& async_server); + virtual ~CaptiveRequestHandler(); + + bool canHandle(AsyncWebServerRequest* request); + + //* use SPIFFS or built in HTML wifimanager + void handleRequest(AsyncWebServerRequest* request); +}; diff --git a/NetworkManager/include/api/server.hpp b/NetworkManager/include/api/server.hpp index ac85947..42c0da6 100644 --- a/NetworkManager/include/api/server.hpp +++ b/NetworkManager/include/api/server.hpp @@ -1,53 +1,53 @@ -#pragma once - -// #define WEBSERVER_H -#include "utilities/api_utilities.hpp" - -#ifdef ESP32 -# include -#elif defined(ESP8266) -# include -#endif - -#ifdef USE_WEBMANAGER -# include -#endif // USE_WEBMANAGER -#include - -class AsyncServer_t : public API_Utilities { - /* Helpers */ - void notFound(AsyncWebServerRequest* request) const; - - protected: - ProjectConfig& configManager; - - public: - AsyncServer_t(const int CONTROL_PORT, ProjectConfig& configManager, - const std::string& api_url, - const std::string& wifimanager_url, - const std::string& user_commands, - const std::string& json_url); - virtual ~AsyncServer_t(); - virtual void begin(); - - struct UserRoutes_t { - UserRoutes_t(const std::string& endpoint, const std::string& file, - const std::string& method) - : endpoint(std::move(endpoint)), - file(std::move(file)), - method(std::move(method)) {} - std::string endpoint; - std::string file; - std::string method; - }; - - std::vector custom_html_files; - - AsyncWebServer server; - bool spiffsMounted; - - std::string api_url; - std::string wifimanager_url; - std::string user_commands; - std::string json_url; +#pragma once + +// #define WEBSERVER_H +#include "utilities/api_utilities.hpp" + +#ifdef ESP32 +# include +#elif defined(ESP8266) +# include +#endif + +#ifdef USE_WEBMANAGER +# include +#endif // USE_WEBMANAGER +#include + +class AsyncServer_t : public API_Utilities { + /* Helpers */ + void notFound(AsyncWebServerRequest* request) const; + + protected: + ProjectConfig& configManager; + + public: + AsyncServer_t(const int CONTROL_PORT, ProjectConfig& configManager, + const std::string& api_url, + const std::string& wifimanager_url, + const std::string& user_commands, + const std::string& json_url); + virtual ~AsyncServer_t(); + virtual void begin(); + + struct UserRoutes_t { + UserRoutes_t(const std::string& endpoint, const std::string& file, + const std::string& method) + : endpoint(std::move(endpoint)), + file(std::move(file)), + method(std::move(method)) {} + std::string endpoint; + std::string file; + std::string method; + }; + + std::vector custom_html_files; + + AsyncWebServer server; + bool spiffsMounted; + + std::string api_url; + std::string wifimanager_url; + std::string user_commands; + std::string json_url; }; \ No newline at end of file diff --git a/NetworkManager/include/data/config/config_handler.hpp b/NetworkManager/include/data/config/config_handler.hpp index 73d3290..e223ffc 100644 --- a/NetworkManager/include/data/config/config_handler.hpp +++ b/NetworkManager/include/data/config/config_handler.hpp @@ -1,16 +1,16 @@ -#pragma once -#include -#include -#include -#include - -class ConfigHandler : public Helpers::Logger, - public Helpers::IObserver { - public: - ConfigHandler(const std::string& configName = std::string(), - const std::string& mdnsName = std::string()); - virtual ~ConfigHandler(); - virtual void begin(); - virtual void update(const StateVariant& event) override; - ProjectConfig config; +#pragma once +#include +#include +#include +#include + +class ConfigHandler : public Helpers::Logger, + public Helpers::IObserver { + public: + ConfigHandler(const std::string& configName = std::string(), + const std::string& mdnsName = std::string()); + virtual ~ConfigHandler(); + virtual void begin(); + virtual void update(const StateVariant& event) override; + ProjectConfig config; }; \ No newline at end of file diff --git a/NetworkManager/include/data/config/project_config.hpp b/NetworkManager/include/data/config/project_config.hpp index 62d107b..b695572 100644 --- a/NetworkManager/include/data/config/project_config.hpp +++ b/NetworkManager/include/data/config/project_config.hpp @@ -1,70 +1,70 @@ -#pragma once -#include -#include - -#include "structs.hpp" - -#include -#include -#include - -#include -#include -#include -#include -#include - -class CustomConfigInterface { - public: - virtual void load() = 0; - virtual void save() = 0; -}; - -class ProjectConfig : public Helpers::Logger, - public Helpers::ISubject, - public Preferences { - private: - virtual void initConfig(); - Project_Config::ProjectConfig_t config; - std::string _configName; - std::string _mdnsName; - bool _already_loaded; - typedef CustomConfigInterface* _custom_config_interface_t; - _custom_config_interface_t _custom_config_interface; - - public: - ProjectConfig(const std::string& configName = std::string(), - const std::string& mdnsName = std::string()); - virtual ~ProjectConfig(); - virtual void load(); - virtual void save(); - void wifiConfigSave(); - void deviceConfigSave(); - void mdnsConfigSave(); - void wifiTxPowerConfigSave(); - bool reset(); - - Project_Config::DeviceConfig_t& getDeviceConfig(); - Project_Config::MDNSConfig_t& getMDNSConfig(); - std::vector& getWifiConfigs(); - Project_Config::AP_WiFiConfig_t& getAPWifiConfig(); - Project_Config::WiFiTxPower_t& getWifiTxPowerConfig(); - Project_Config::DeviceDataJson_t& getDeviceDataJson(); - - void setDeviceConfig(const std::string& OTAPassword, int OTAPort, - bool shouldNotify); - void setDeviceDataJson(const std::string& deviceJson, bool shouldNotify); - bool setMDNSConfig(const std::string& mdns, bool shouldNotify); - void setWifiConfig(const std::string& networkName, const std::string& ssid, - const std::string& password, uint8_t channel, - uint8_t power, bool adhoc, bool shouldNotify, - bool shouldReboot = false); - void setAPWifiConfig(const std::string& ssid, const std::string& password, - uint8_t channel, bool adhoc, bool shouldNotify); - void setWiFiTxPower(uint8_t power, bool shouldNotify); - void deleteWifiConfig(const std::string& networkName, bool shouldNotify); - - void registerUserConfig(_custom_config_interface_t custom_config_interface); - - bool reboot; -}; +#pragma once +#include +#include + +#include "structs.hpp" + +#include +#include +#include + +#include +#include +#include +#include +#include + +class CustomConfigInterface { + public: + virtual void load() = 0; + virtual void save() = 0; +}; + +class ProjectConfig : public Helpers::Logger, + public Helpers::ISubject, + public Preferences { + private: + virtual void initConfig(); + Project_Config::ProjectConfig_t config; + std::string _configName; + std::string _mdnsName; + bool _already_loaded; + typedef CustomConfigInterface* _custom_config_interface_t; + _custom_config_interface_t _custom_config_interface; + + public: + ProjectConfig(const std::string& configName = std::string(), + const std::string& mdnsName = std::string()); + virtual ~ProjectConfig(); + virtual void load(); + virtual void save(); + void wifiConfigSave(); + void deviceConfigSave(); + void mdnsConfigSave(); + void wifiTxPowerConfigSave(); + bool reset(); + + Project_Config::DeviceConfig_t& getDeviceConfig(); + Project_Config::MDNSConfig_t& getMDNSConfig(); + std::vector& getWifiConfigs(); + Project_Config::AP_WiFiConfig_t& getAPWifiConfig(); + Project_Config::WiFiTxPower_t& getWifiTxPowerConfig(); + Project_Config::DeviceDataJson_t& getDeviceDataJson(); + + void setDeviceConfig(const std::string& OTAPassword, int OTAPort, + bool shouldNotify); + void setDeviceDataJson(const std::string& deviceJson, bool shouldNotify); + bool setMDNSConfig(const std::string& mdns, bool shouldNotify); + void setWifiConfig(const std::string& networkName, const std::string& ssid, + const std::string& password, uint8_t channel, + uint8_t power, bool adhoc, bool shouldNotify, + bool shouldReboot = false); + void setAPWifiConfig(const std::string& ssid, const std::string& password, + uint8_t channel, bool adhoc, bool shouldNotify); + void setWiFiTxPower(uint8_t power, bool shouldNotify); + void deleteWifiConfig(const std::string& networkName, bool shouldNotify); + + void registerUserConfig(_custom_config_interface_t custom_config_interface); + + bool reboot; +}; diff --git a/NetworkManager/include/data/config/states.hpp b/NetworkManager/include/data/config/states.hpp index 24a0c38..df8e86d 100644 --- a/NetworkManager/include/data/config/states.hpp +++ b/NetworkManager/include/data/config/states.hpp @@ -1,85 +1,85 @@ -#pragma once - -#include -#include -#include - -/* \ - * StateManager \ - * All Project States are managed here \ - */ -namespace ProgramStates { -enum ProgramState_e { Starting, Started, Stopping, Stopped, Error }; -enum Event_e { - configLoaded, - configSaved, - deviceConfigUpdated, - mdnsConfigUpdated, - networksConfigUpdated, - apConfigUpdated, - wifiTxPowerUpdated, - deviceDataJsonUpdated, -}; - -enum WiFiState_e { - WiFiState_None, - WiFiState_Idle, - WiFiState_Scanning, - WiFiState_Scanning_Done, - WiFiState_Connecting, - WiFiState_Connected, - WiFiState_Disconnected, - WiFiState_Disconnecting, - WiFiState_ADHOC, - WiFiState_Error -}; - -enum WebServerState_e { - WebServerState_None, - WebServerState_Starting, - WebServerState_Started, - WebServerState_Stopping, - WebServerState_Stopped, - WebServerState_Error -}; - -enum MDNSState_e { - MDNSState_None, - MDNSState_Starting, - MDNSState_Started, - MDNSState_Stopping, - MDNSState_Stopped, - MDNSState_Error -}; - -enum ProjectConfigEventIDs_e { - ProjectConfigEventID_ConfigHandler, - ProjectConfigEventID_MDNSHandler, - ProjectConfigEventID_WifiHandler, -}; - -}; // namespace ProgramStates - -using State_e = ProgramStates::ProgramState_e; -using Event_e = ProgramStates::Event_e; -using WiFiState_e = ProgramStates::WiFiState_e; -using WebServerState_e = ProgramStates::WebServerState_e; -using MDNSState_e = ProgramStates::MDNSState_e; -using ProjectConfigEventIDs_e = ProgramStates::ProjectConfigEventIDs_e; - -using StateVariant = - std::variant; - -// Define a generic function that applies a switch-case logic to an enum -// variant. -template -void updateStateWrapper(const VariantType& _variant, Func&& _switchCaseFunc) { - std::visit( - [&](auto&& arg) { - using T = std::decay_t; - if constexpr (std::is_same_v) { - _switchCaseFunc(arg); - } - }, - _variant); +#pragma once + +#include +#include +#include + +/* \ + * StateManager \ + * All Project States are managed here \ + */ +namespace ProgramStates { +enum ProgramState_e { Starting, Started, Stopping, Stopped, Error }; +enum Event_e { + configLoaded, + configSaved, + deviceConfigUpdated, + mdnsConfigUpdated, + networksConfigUpdated, + apConfigUpdated, + wifiTxPowerUpdated, + deviceDataJsonUpdated, +}; + +enum WiFiState_e { + WiFiState_None, + WiFiState_Idle, + WiFiState_Scanning, + WiFiState_Scanning_Done, + WiFiState_Connecting, + WiFiState_Connected, + WiFiState_Disconnected, + WiFiState_Disconnecting, + WiFiState_ADHOC, + WiFiState_Error +}; + +enum WebServerState_e { + WebServerState_None, + WebServerState_Starting, + WebServerState_Started, + WebServerState_Stopping, + WebServerState_Stopped, + WebServerState_Error +}; + +enum MDNSState_e { + MDNSState_None, + MDNSState_Starting, + MDNSState_Started, + MDNSState_Stopping, + MDNSState_Stopped, + MDNSState_Error +}; + +enum ProjectConfigEventIDs_e { + ProjectConfigEventID_ConfigHandler, + ProjectConfigEventID_MDNSHandler, + ProjectConfigEventID_WifiHandler, +}; + +}; // namespace ProgramStates + +using State_e = ProgramStates::ProgramState_e; +using Event_e = ProgramStates::Event_e; +using WiFiState_e = ProgramStates::WiFiState_e; +using WebServerState_e = ProgramStates::WebServerState_e; +using MDNSState_e = ProgramStates::MDNSState_e; +using ProjectConfigEventIDs_e = ProgramStates::ProjectConfigEventIDs_e; + +using StateVariant = + std::variant; + +// Define a generic function that applies a switch-case logic to an enum +// variant. +template +void updateStateWrapper(const VariantType& _variant, Func&& _switchCaseFunc) { + std::visit( + [&](auto&& arg) { + using T = std::decay_t; + if constexpr (std::is_same_v) { + _switchCaseFunc(arg); + } + }, + _variant); } \ No newline at end of file diff --git a/NetworkManager/include/data/config/structs.hpp b/NetworkManager/include/data/config/structs.hpp index 5afaab0..baf54e3 100644 --- a/NetworkManager/include/data/config/structs.hpp +++ b/NetworkManager/include/data/config/structs.hpp @@ -1,157 +1,157 @@ -#pragma once -#include -#include - -namespace Project_Config { -struct DeviceConfig_t { - struct Keys_t { - inline static const std::string ota_login = "ota_login"; - inline static const std::string ota_password = "ota_password"; - inline static const std::string ota_port = "ota_port"; - } keys; - - DeviceConfig_t(const std::string& login, const std::string& password, - int port) - : ota_login(std::move(login)), - ota_password(std::move(password)), - ota_port(port) {} - - DeviceConfig_t() - : ota_login("admin"), ota_password("12345678"), ota_port(3232) {} - - std::string ota_login; - std::string ota_password; - int ota_port; - std::string toRepresentation(); -}; - -struct DeviceDataJson_t { - struct Keys_t { - inline static const std::string deviceJson = "deviceJson"; - } keys; - - DeviceDataJson_t(const std::string& json) : deviceJson(std::move(json)) {} - - DeviceDataJson_t() : deviceJson("") {} - - std::string deviceJson; - std::string toRepresentation(); -}; - -struct MDNSConfig_t { - struct Keys_t { - inline static const std::string hostname = "hostname"; - } keys; - - MDNSConfig_t(const std::string& hostname) : hostname(std::move(hostname)) {} - - MDNSConfig_t() : hostname("") {} - - std::string hostname; - std::string toRepresentation(); -}; - -struct PreferencesWiFiConfigKeys_t { - inline static const std::string networkCount = "networkCount"; - inline static const std::string name = "name"; - inline static const std::string ssid = "ssid"; - inline static const std::string password = "password"; - inline static const std::string channel = "channel"; - inline static const std::string power = "power"; - inline static const std::string adhoc = "adhoc"; -}; - -struct WiFiConfig_t { - //! Constructor for WiFiConfig_t - allows us to use emplace_back - WiFiConfig_t(const std::string& name, const std::string& ssid, - const std::string& password, uint8_t channel, uint8_t power, - bool adhoc) - : name(std::move(name)), - ssid(std::move(ssid)), - password(std::move(password)), - channel(channel), - power(power), - adhoc(adhoc) {} - - std::string name; - std::string ssid; - std::string password; - uint8_t channel; - uint8_t power; - bool adhoc; - std::string toRepresentation(); -}; - -struct WiFiTxPower_t { - struct Keys_t { - inline static const std::string power = "power"; - } keys; - - WiFiTxPower_t(uint8_t power) : power(power) {} - - WiFiTxPower_t() : power(52) {} - - uint8_t power; - std::string toRepresentation(); -}; - -struct AP_WiFiConfig_t { - struct Keys_t { - inline static const std::string ssid = "ap_ssid"; - inline static const std::string password = "ap_password"; - inline static const std::string channel = "ap_channel"; - inline static const std::string adhoc = "ap_adhoc"; - } keys; - - AP_WiFiConfig_t(const std::string& ssid, const std::string& password, - uint8_t channel, bool adhoc) - : ssid(std::move(ssid)), - password(std::move(password)), - channel(channel), - adhoc(adhoc) {} - - AP_WiFiConfig_t() - : ssid("ESP32-AP"), password("12345678"), channel(1), adhoc(false) {} - - std::string ssid; - std::string password; - uint8_t channel; - bool adhoc; - std::string toRepresentation(); -}; - -struct ProjectConfig_t { - DeviceConfig_t device; - DeviceDataJson_t device_data; - MDNSConfig_t mdns; - std::vector networks; - AP_WiFiConfig_t ap_network; - WiFiTxPower_t wifi_tx_power; - - ProjectConfig_t(const DeviceConfig_t& device, - const DeviceDataJson_t& device_data, - const MDNSConfig_t& mdns, - const std::vector& networks, - const AP_WiFiConfig_t& ap_network, - const WiFiTxPower_t& wifi_tx_power) - : device(device), - device_data(device_data), - mdns(mdns), - networks(networks), - ap_network(ap_network), - wifi_tx_power(wifi_tx_power) {} - - ProjectConfig_t() - : device(), - device_data(), - mdns(), - networks(), - ap_network(), - wifi_tx_power() {} - - PreferencesWiFiConfigKeys_t wifKeys; -}; - - - +#pragma once +#include +#include + +namespace Project_Config { +struct DeviceConfig_t { + struct Keys_t { + inline static const std::string ota_login = "ota_login"; + inline static const std::string ota_password = "ota_password"; + inline static const std::string ota_port = "ota_port"; + } keys; + + DeviceConfig_t(const std::string& login, const std::string& password, + int port) + : ota_login(std::move(login)), + ota_password(std::move(password)), + ota_port(port) {} + + DeviceConfig_t() + : ota_login("admin"), ota_password("12345678"), ota_port(3232) {} + + std::string ota_login; + std::string ota_password; + int ota_port; + std::string toRepresentation(); +}; + +struct DeviceDataJson_t { + struct Keys_t { + inline static const std::string deviceJson = "deviceJson"; + } keys; + + DeviceDataJson_t(const std::string& json) : deviceJson(std::move(json)) {} + + DeviceDataJson_t() : deviceJson("") {} + + std::string deviceJson; + std::string toRepresentation(); +}; + +struct MDNSConfig_t { + struct Keys_t { + inline static const std::string hostname = "hostname"; + } keys; + + MDNSConfig_t(const std::string& hostname) : hostname(std::move(hostname)) {} + + MDNSConfig_t() : hostname("") {} + + std::string hostname; + std::string toRepresentation(); +}; + +struct PreferencesWiFiConfigKeys_t { + inline static const std::string networkCount = "networkCount"; + inline static const std::string name = "name"; + inline static const std::string ssid = "ssid"; + inline static const std::string password = "password"; + inline static const std::string channel = "channel"; + inline static const std::string power = "power"; + inline static const std::string adhoc = "adhoc"; +}; + +struct WiFiConfig_t { + //! Constructor for WiFiConfig_t - allows us to use emplace_back + WiFiConfig_t(const std::string& name, const std::string& ssid, + const std::string& password, uint8_t channel, uint8_t power, + bool adhoc) + : name(std::move(name)), + ssid(std::move(ssid)), + password(std::move(password)), + channel(channel), + power(power), + adhoc(adhoc) {} + + std::string name; + std::string ssid; + std::string password; + uint8_t channel; + uint8_t power; + bool adhoc; + std::string toRepresentation(); +}; + +struct WiFiTxPower_t { + struct Keys_t { + inline static const std::string power = "power"; + } keys; + + WiFiTxPower_t(uint8_t power) : power(power) {} + + WiFiTxPower_t() : power(52) {} + + uint8_t power; + std::string toRepresentation(); +}; + +struct AP_WiFiConfig_t { + struct Keys_t { + inline static const std::string ssid = "ap_ssid"; + inline static const std::string password = "ap_password"; + inline static const std::string channel = "ap_channel"; + inline static const std::string adhoc = "ap_adhoc"; + } keys; + + AP_WiFiConfig_t(const std::string& ssid, const std::string& password, + uint8_t channel, bool adhoc) + : ssid(std::move(ssid)), + password(std::move(password)), + channel(channel), + adhoc(adhoc) {} + + AP_WiFiConfig_t() + : ssid("ESP32-AP"), password("12345678"), channel(1), adhoc(false) {} + + std::string ssid; + std::string password; + uint8_t channel; + bool adhoc; + std::string toRepresentation(); +}; + +struct ProjectConfig_t { + DeviceConfig_t device; + DeviceDataJson_t device_data; + MDNSConfig_t mdns; + std::vector networks; + AP_WiFiConfig_t ap_network; + WiFiTxPower_t wifi_tx_power; + + ProjectConfig_t(const DeviceConfig_t& device, + const DeviceDataJson_t& device_data, + const MDNSConfig_t& mdns, + const std::vector& networks, + const AP_WiFiConfig_t& ap_network, + const WiFiTxPower_t& wifi_tx_power) + : device(device), + device_data(device_data), + mdns(mdns), + networks(networks), + ap_network(ap_network), + wifi_tx_power(wifi_tx_power) {} + + ProjectConfig_t() + : device(), + device_data(), + mdns(), + networks(), + ap_network(), + wifi_tx_power() {} + + PreferencesWiFiConfigKeys_t wifKeys; +}; + + + } // namespace Project_Config \ No newline at end of file diff --git a/NetworkManager/include/network/mdns/mdns_manager.hpp b/NetworkManager/include/network/mdns/mdns_manager.hpp index fbe8b39..1397e4e 100644 --- a/NetworkManager/include/network/mdns/mdns_manager.hpp +++ b/NetworkManager/include/network/mdns/mdns_manager.hpp @@ -1,25 +1,25 @@ -#pragma once -#include -#include -#include -#include -#include - -class MDNSHandler : public Helpers::Logger, - public Helpers::IObserver { - private: - ProjectConfig& configManager; - std::string service_name; - std::string service_text; - std::string proto; - std::string key; - std::string value; - - public: - MDNSHandler(ProjectConfig& configManager, const std::string& service_name, - const std::string& service_text, const std::string& proto, - const std::string& key, const std::string& value); - bool begin(); - /* Overrides */ - void update(const StateVariant& event) override; -}; +#pragma once +#include +#include +#include +#include +#include + +class MDNSHandler : public Helpers::Logger, + public Helpers::IObserver { + private: + ProjectConfig& configManager; + std::string service_name; + std::string service_text; + std::string proto; + std::string key; + std::string value; + + public: + MDNSHandler(ProjectConfig& configManager, const std::string& service_name, + const std::string& service_text, const std::string& proto, + const std::string& key, const std::string& value); + bool begin(); + /* Overrides */ + void update(const StateVariant& event) override; +}; diff --git a/NetworkManager/include/network/wifihandler/wifi_handler.hpp b/NetworkManager/include/network/wifihandler/wifi_handler.hpp index 6a12180..dd7ae9f 100644 --- a/NetworkManager/include/network/wifihandler/wifi_handler.hpp +++ b/NetworkManager/include/network/wifihandler/wifi_handler.hpp @@ -1,62 +1,62 @@ -#pragma once -#include -#include -#include -#include -#if defined(ARDUINO_SAMD_MKRWIFI1010) || defined(ARDUINO_SAMD_NANO_33_IOT) || \ - defined(ARDUINO_AVR_UNO_WIFI_REV2) -# include -#elif defined(ARDUINO_SAMD_MKR1000) -# include -#elif defined(ARDUINO_ARCH_ESP8266) -# include -#elif defined(ARDUINO_PORTENTA_H7_M7) || defined(ARDUINO_NICLA_VISION) || \ - defined(ARDUINO_ARCH_ESP32) || defined(ARDUINO_GIGA) -# ifdef USE_ETHERNET -# include "ethernet/ethernetHandler.hpp" -# else -# include -# endif -#endif -#include -#include -#include -#include - -using WiFiHandlerCustomHandlerFunction = std::function; - -class WiFiHandler : public Helpers::Logger, - public Helpers::IObserver { - WiFiHandlerCustomHandlerFunction customHandlerFunction = NULL; - - public: - WiFiHandler(ProjectConfig& configManager, const std::string& ssid, - const std::string& password, uint8_t channel); - - virtual ~WiFiHandler(); - void begin(); - void toggleAdhoc(bool enable); - void setCustomHandler( - WiFiHandlerCustomHandlerFunction customHandlerFunction); - - ProjectConfig& configManager; - Project_Config::WiFiTxPower_t& txpower; - - private: - void setUpADHOC(); - void adhoc(const std::string& ssid, uint8_t channel, - const std::string& password = std::string()); - bool iniSTA(const std::string& ssid, const std::string& password, - uint8_t channel, wifi_power_t power); - - /* Overrides */ - void update(const StateVariant& event) override; - - void onWiFiEvent(WiFiEvent_t event); - - std::string ssid; - std::string password; - uint8_t channel; - uint8_t power; - bool _enable_adhoc; -}; +#pragma once +#include +#include +#include +#include +#if defined(ARDUINO_SAMD_MKRWIFI1010) || defined(ARDUINO_SAMD_NANO_33_IOT) || \ + defined(ARDUINO_AVR_UNO_WIFI_REV2) +# include +#elif defined(ARDUINO_SAMD_MKR1000) +# include +#elif defined(ARDUINO_ARCH_ESP8266) +# include +#elif defined(ARDUINO_PORTENTA_H7_M7) || defined(ARDUINO_NICLA_VISION) || \ + defined(ARDUINO_ARCH_ESP32) || defined(ARDUINO_GIGA) +# ifdef USE_ETHERNET +# include "ethernet/ethernetHandler.hpp" +# else +# include +# endif +#endif +#include +#include +#include +#include + +using WiFiHandlerCustomHandlerFunction = std::function; + +class WiFiHandler : public Helpers::Logger, + public Helpers::IObserver { + WiFiHandlerCustomHandlerFunction customHandlerFunction = NULL; + + public: + WiFiHandler(ProjectConfig& configManager, const std::string& ssid, + const std::string& password, uint8_t channel); + + virtual ~WiFiHandler(); + void begin(); + void toggleAdhoc(bool enable); + void setCustomHandler( + WiFiHandlerCustomHandlerFunction customHandlerFunction); + + ProjectConfig& configManager; + Project_Config::WiFiTxPower_t& txpower; + + private: + void setUpADHOC(); + void adhoc(const std::string& ssid, uint8_t channel, + const std::string& password = std::string()); + bool iniSTA(const std::string& ssid, const std::string& password, + uint8_t channel, wifi_power_t power); + + /* Overrides */ + void update(const StateVariant& event) override; + + void onWiFiEvent(WiFiEvent_t event); + + std::string ssid; + std::string password; + uint8_t channel; + uint8_t power; + bool _enable_adhoc; +}; diff --git a/NetworkManager/include/utilities/api_utilities.hpp b/NetworkManager/include/utilities/api_utilities.hpp index a225bd1..d4b155d 100644 --- a/NetworkManager/include/utilities/api_utilities.hpp +++ b/NetworkManager/include/utilities/api_utilities.hpp @@ -1,69 +1,69 @@ -#pragma once - -#include - -#include - -#include "mbedtls/md.h" -#include "network_utilities.hpp" - -constexpr int XHTTP_GET = 0b00000001; -constexpr int XHTTP_POST = 0b00000010; -constexpr int XHTTP_DELETE = 0b00000100; -constexpr int XHTTP_PUT = 0b00001000; -constexpr int XHTTP_PATCH = 0b00010000; -constexpr int XHTTP_HEAD = 0b00100000; -constexpr int XHTTP_OPTIONS = 0b01000000; -constexpr int XHTTP_ANY = 0b01111111; - -#include - -class API_Utilities { - public: - API_Utilities(); - virtual ~API_Utilities(); - - std::string readFile(fs::FS& fs, const std::string& path); - void writeFile(fs::FS& fs, const std::string& path, - const std::string& message); - std::string shaEncoder(const std::string& data); - - protected: - bool initSPIFFS(); - - typedef std::unordered_map - networkMethodsMap_t; - - public: - std::unordered_map - _networkMethodsMap_inv = { - {"GET", XHTTP_GET}, {"POST", XHTTP_POST}, - {"PUT", XHTTP_PUT}, {"DELETE", XHTTP_DELETE}, - {"PATCH", XHTTP_PATCH}, {"OPTIONS", XHTTP_OPTIONS}, - }; - - std::unordered_map - _networkMethodsMap = { - {XHTTP_GET, "GET"}, {XHTTP_POST, "POST"}, - {XHTTP_PUT, "PUT"}, {XHTTP_DELETE, "DELETE"}, - {XHTTP_PATCH, "PATCH"}, {XHTTP_OPTIONS, "OPTIONS"}, - }; - - enum RequestMethods { GET, POST, PUT, DELETE, PATCH, OPTIONS }; - - std::unordered_map - _networkMethodsMap_enum = { - {XHTTP_GET, GET}, {XHTTP_POST, POST}, - {XHTTP_PUT, PUT}, {XHTTP_DELETE, DELETE}, - {XHTTP_PATCH, PATCH}, {XHTTP_OPTIONS, OPTIONS}, - }; - - public: - static const char* MIMETYPE_HTML; - static const char* MIMETYPE_CSS; - static const char* MIMETYPE_JS; - static const char* MIMETYPE_PNG; - static const char* MIMETYPE_JPG; - static const char* MIMETYPE_ICO; - static const char* MIMETYPE_JSON; -}; +#pragma once + +#include + +#include + +#include "mbedtls/md.h" +#include "network_utilities.hpp" + +constexpr int XHTTP_GET = 0b00000001; +constexpr int XHTTP_POST = 0b00000010; +constexpr int XHTTP_DELETE = 0b00000100; +constexpr int XHTTP_PUT = 0b00001000; +constexpr int XHTTP_PATCH = 0b00010000; +constexpr int XHTTP_HEAD = 0b00100000; +constexpr int XHTTP_OPTIONS = 0b01000000; +constexpr int XHTTP_ANY = 0b01111111; + +#include + +class API_Utilities { + public: + API_Utilities(); + virtual ~API_Utilities(); + + std::string readFile(fs::FS& fs, const std::string& path); + void writeFile(fs::FS& fs, const std::string& path, + const std::string& message); + std::string shaEncoder(const std::string& data); + + protected: + bool initSPIFFS(); + + typedef std::unordered_map + networkMethodsMap_t; + + public: + std::unordered_map + _networkMethodsMap_inv = { + {"GET", XHTTP_GET}, {"POST", XHTTP_POST}, + {"PUT", XHTTP_PUT}, {"DELETE", XHTTP_DELETE}, + {"PATCH", XHTTP_PATCH}, {"OPTIONS", XHTTP_OPTIONS}, + }; + + std::unordered_map + _networkMethodsMap = { + {XHTTP_GET, "GET"}, {XHTTP_POST, "POST"}, + {XHTTP_PUT, "PUT"}, {XHTTP_DELETE, "DELETE"}, + {XHTTP_PATCH, "PATCH"}, {XHTTP_OPTIONS, "OPTIONS"}, + }; + + enum RequestMethods { GET, POST, PUT, DELETE, PATCH, OPTIONS }; + + std::unordered_map + _networkMethodsMap_enum = { + {XHTTP_GET, GET}, {XHTTP_POST, POST}, + {XHTTP_PUT, PUT}, {XHTTP_DELETE, DELETE}, + {XHTTP_PATCH, PATCH}, {XHTTP_OPTIONS, OPTIONS}, + }; + + public: + static const char* MIMETYPE_HTML; + static const char* MIMETYPE_CSS; + static const char* MIMETYPE_JS; + static const char* MIMETYPE_PNG; + static const char* MIMETYPE_JPG; + static const char* MIMETYPE_ICO; + static const char* MIMETYPE_JSON; +}; diff --git a/NetworkManager/include/utilities/network_utilities.hpp b/NetworkManager/include/utilities/network_utilities.hpp index 1da30fe..b59eb64 100644 --- a/NetworkManager/include/utilities/network_utilities.hpp +++ b/NetworkManager/include/utilities/network_utilities.hpp @@ -1,13 +1,13 @@ -#pragma once -#include -#include -#include - -namespace Network_Utilities { -bool loopWifiScan(); -void setupWifiScan(); -void my_delay(volatile long delay_time); -int getStrength(int points); -std::string generateDeviceID(); -void checkWiFiState(); +#pragma once +#include +#include +#include + +namespace Network_Utilities { +bool loopWifiScan(); +void setupWifiScan(); +void my_delay(volatile long delay_time); +int getStrength(int points); +std::string generateDeviceID(); +void checkWiFiState(); } // namespace Network_Utilities \ No newline at end of file diff --git a/NetworkManager/ini/dev_config.ini b/NetworkManager/ini/dev_config.ini index 6e18271..f949654 100644 --- a/NetworkManager/ini/dev_config.ini +++ b/NetworkManager/ini/dev_config.ini @@ -1,49 +1,49 @@ -[common] -owner = "DaOfficialWizard" -description = "EasyNetworkManager" - -[env] -platform = espressif32 -framework = arduino -lib_deps = - https://github.com/ZanzyTHEbar/EasyHelpers.git - https://github.com/me-no-dev/ESPAsyncWebServer.git - https://github.com/me-no-dev/AsyncTCP.git - https://github.com/bblanchon/ArduinoJson.git - -monitor_speed = 115200 -monitor_filters = - log2file - time - default - esp32_exception_decoder -board_build.partitions = min_spiffs.csv -;build_unflags = -Os ; disable optimization for size -lib_ldf_mode = deep -;115200 is used for compatability - if you are on windows and want the code to flash faster use 921600 -upload_speed = 921600 -extra_scripts = - pre:tools/customname.py - post:tools/createwokwi.py -build_flags = - -DENABLE_ADHOC=${wifi.enableadhoc} - -DADHOC_CHANNEL=${wifi.adhocchannel} - -DWIFI_CHANNEL=${wifi.channel} - -DDEBUG_ESP_PORT=Serial ; set the debug port - -DENABLE_OTA=${ota.enableota} - -DOTA_SERVER_PORT=${ota.otaserverport} - '-DMDNS_HOSTNAME=${wifi.mDNSName}' ; Set the OTA password - '-DWIFI_AP_SSID=${wifi.ap_ssid}' - '-DWIFI_AP_PASSWORD=${wifi.ap_password}' - '-DWIFI_AP_CHANNEL=${wifi.adhocchannel}' - - '-DOTA_PASSWORD=${ota.otapassword}' ; Set the OTA password - '-DOTA_IP=${ota.otaserverip}' ; Set the OTA password - - -O2 ; optimize for speed - -DUSE_WEBMANAGER ; enable webmanager - -DASYNCWEBSERVER_REGEX ; enable regex in asyncwebserver - -DUSE_ASYNCOTA ; enable asyncota - -DHTTP_PARSER_STRICT=0 ;to make less checks, but run faster - -std=gnu++17 -build_unflags = -std=gnu++11 +[common] +owner = "DaOfficialWizard" +description = "EasyNetworkManager" + +[env] +platform = espressif32 +framework = arduino +lib_deps = + https://github.com/ZanzyTHEbar/EasyHelpers.git + https://github.com/me-no-dev/ESPAsyncWebServer.git + https://github.com/me-no-dev/AsyncTCP.git + https://github.com/bblanchon/ArduinoJson.git + +monitor_speed = 115200 +monitor_filters = + log2file + time + default + esp32_exception_decoder +board_build.partitions = min_spiffs.csv +;build_unflags = -Os ; disable optimization for size +lib_ldf_mode = deep +;115200 is used for compatability - if you are on windows and want the code to flash faster use 921600 +upload_speed = 921600 +extra_scripts = + pre:tools/customname.py + post:tools/createwokwi.py +build_flags = + -DENABLE_ADHOC=${wifi.enableadhoc} + -DADHOC_CHANNEL=${wifi.adhocchannel} + -DWIFI_CHANNEL=${wifi.channel} + -DDEBUG_ESP_PORT=Serial ; set the debug port + -DENABLE_OTA=${ota.enableota} + -DOTA_SERVER_PORT=${ota.otaserverport} + '-DMDNS_HOSTNAME=${wifi.mDNSName}' ; Set the OTA password + '-DWIFI_AP_SSID=${wifi.ap_ssid}' + '-DWIFI_AP_PASSWORD=${wifi.ap_password}' + '-DWIFI_AP_CHANNEL=${wifi.adhocchannel}' + + '-DOTA_PASSWORD=${ota.otapassword}' ; Set the OTA password + '-DOTA_IP=${ota.otaserverip}' ; Set the OTA password + + -O2 ; optimize for speed + -DUSE_WEBMANAGER ; enable webmanager + -DASYNCWEBSERVER_REGEX ; enable regex in asyncwebserver + -DUSE_ASYNCOTA ; enable asyncota + -DHTTP_PARSER_STRICT=0 ;to make less checks, but run faster + -std=gnu++17 +build_unflags = -std=gnu++11 diff --git a/NetworkManager/ini/envs.ini b/NetworkManager/ini/envs.ini index 5a23324..f263442 100644 --- a/NetworkManager/ini/envs.ini +++ b/NetworkManager/ini/envs.ini @@ -1,63 +1,63 @@ -# ESP32 - -[esp32dev] -board = esp32dev - -[env:esp32dev_debug] -extends = esp32dev -build_type = debug -build_flags = - ${env.build_flags} - -DCORE_DEBUG_LEVEL=4 - '-DWIFI_SSID=${sim.ssid}' - '-DWIFI_PASSWORD=${sim.password}' - -[env:esp32dev_release] -extends = esp32dev -build_type = release -build_flags = - ${env.build_flags} - -DDEBUG_ESP_OTA - -DCORE_DEBUG_LEVEL=1 - '-DWIFI_SSID=${wifi.ssid}' - '-DWIFI_PASSWORD=${wifi.password}' - -[env:esp32dev_ota] -extends = esp32dev_release -upload_port = ${ota.otaserverip} -upload_protocol = espota -upload_flags = - --port=${ota.otaserverport} - --auth=${ota.otapassword} - -# ESP32S3 - -[esp32s3] -board = esp32-s3-devkitc-1 - -[env:esp32s3_debug] -extends = esp32s3 -build_type = debug -build_flags = - ${env.build_flags} - -DCORE_DEBUG_LEVEL=4 - '-DWIFI_SSID=${sim.ssid}' - '-DWIFI_PASSWORD=${sim.password}' - -[env:esp32s3_release] -extends = esp32s3 -build_type = release -build_flags = - ${env.build_flags} - -DDEBUG_ESP_OTA - -DCORE_DEBUG_LEVEL=1 - '-DWIFI_SSID=${wifi.ssid}' - '-DWIFI_PASSWORD=${wifi.password}' - -[env:esp32s3_ota] -extends = esp32s3_release -upload_port = ${ota.otaserverip} -upload_protocol = espota -upload_flags = - --port=${ota.otaserverport} +# ESP32 + +[esp32dev] +board = esp32dev + +[env:esp32dev_debug] +extends = esp32dev +build_type = debug +build_flags = + ${env.build_flags} + -DCORE_DEBUG_LEVEL=4 + '-DWIFI_SSID=${sim.ssid}' + '-DWIFI_PASSWORD=${sim.password}' + +[env:esp32dev_release] +extends = esp32dev +build_type = release +build_flags = + ${env.build_flags} + -DDEBUG_ESP_OTA + -DCORE_DEBUG_LEVEL=1 + '-DWIFI_SSID=${wifi.ssid}' + '-DWIFI_PASSWORD=${wifi.password}' + +[env:esp32dev_ota] +extends = esp32dev_release +upload_port = ${ota.otaserverip} +upload_protocol = espota +upload_flags = + --port=${ota.otaserverport} + --auth=${ota.otapassword} + +# ESP32S3 + +[esp32s3] +board = esp32-s3-devkitc-1 + +[env:esp32s3_debug] +extends = esp32s3 +build_type = debug +build_flags = + ${env.build_flags} + -DCORE_DEBUG_LEVEL=4 + '-DWIFI_SSID=${sim.ssid}' + '-DWIFI_PASSWORD=${sim.password}' + +[env:esp32s3_release] +extends = esp32s3 +build_type = release +build_flags = + ${env.build_flags} + -DDEBUG_ESP_OTA + -DCORE_DEBUG_LEVEL=1 + '-DWIFI_SSID=${wifi.ssid}' + '-DWIFI_PASSWORD=${wifi.password}' + +[env:esp32s3_ota] +extends = esp32s3_release +upload_port = ${ota.otaserverip} +upload_protocol = espota +upload_flags = + --port=${ota.otaserverport} --auth=${ota.otapassword} \ No newline at end of file diff --git a/NetworkManager/ini/user_config.ini b/NetworkManager/ini/user_config.ini index bf9d5cf..498a6d0 100644 --- a/NetworkManager/ini/user_config.ini +++ b/NetworkManager/ini/user_config.ini @@ -1,21 +1,21 @@ -# This file is for user configuration - -[sim] -ssid = "Wokwi-GUEST" # required for simulator -password = "" - -[wifi] -ssid = "" -password = "" -mdnsname = "esp32custom" -channel = 1 -ap_ssid = "esp32custom" -ap_password = "12345678" -enableadhoc = 0 -adhocchannel = 1 - -[ota] -enableota = 1 -otaserverip = "esp32custom.local" -otapassword = "12345678" +# This file is for user configuration + +[sim] +ssid = "Wokwi-GUEST" # required for simulator +password = "" + +[wifi] +ssid = "" +password = "" +mdnsname = "esp32custom" +channel = 1 +ap_ssid = "esp32custom" +ap_password = "12345678" +enableadhoc = 0 +adhocchannel = 1 + +[ota] +enableota = 1 +otaserverip = "esp32custom.local" +otapassword = "12345678" otaserverport = 3232 \ No newline at end of file diff --git a/NetworkManager/library.json b/NetworkManager/library.json index 2c52747..aa56b68 100644 --- a/NetworkManager/library.json +++ b/NetworkManager/library.json @@ -1,62 +1,62 @@ -{ - "name": "EasyNetworkManager", - "keywords": "network, wifi, REST API, OTA, mDNS, MDNS, custom config, wifi manager, ESP32, ESP8266, frontend", - "description": "An easy to use and extensible network manager for the ESP32 and ESP8266", - "authors": [ - { - "name": "ZanzyTHEbar", - "url": "https://github.com/ZanzyTHEbar" - } - ], - "repository": { - "type": "git", - "url": "https://github.com/ZanzyTHEbar/EasyNetworkManager.git" - }, - "dependencies": [ - { - "name": "EasyHelpers", - "version": "https://github.com/ZanzyTHEbar/EasyHelpers.git" - }, - { - "name": "ESPAsyncWebServer", - "version": "https://github.com/me-no-dev/ESPAsyncWebServer.git" - }, - { - "name": "ArduinoJson", - "version": "https://github.com/bblanchon/ArduinoJson.git" - }, - { - "name": "AsyncTCP", - "version": "https://github.com/me-no-dev/AsyncTCP.git", - "platforms": ["espressif32"] - }, - { - "name": "ESPAsyncTCP", - "version": "https://github.com/me-no-dev/ESPAsyncTCP.git", - "platforms": ["espressif8266"] - } - ], - "headers": [ - "EasyNetworkManager.hpp", - "EasyNetworkManager.h", - "api/rest_api_handler.hpp", - "api/base/base_api.hpp", - "data/config/project_config.hpp", - "data/config/config_handler.hpp", - "data/statemanager/state_manager.hpp", - "utilities/enum_inheritance.hpp", - "utilities/make_unique.hpp", - "utilities/observer.hpp", - "utilities/api_utilities.hpp", - "utilities/network_utilities.hpp", - "network/mdns/mdns_manager.hpp", - "network/ota/ota.hpp", - "network/wifihandler/wifi_handler.hpp" - ], - "export": { - "include": ["src/*", "examples/*", "include/*"] - }, - "version": "5.5.1", - "frameworks": "arduino", - "platforms": ["espressif32", "espressif8266"] -} +{ + "name": "EasyNetworkManager", + "keywords": "network, wifi, REST API, OTA, mDNS, MDNS, custom config, wifi manager, ESP32, ESP8266, frontend", + "description": "An easy to use and extensible network manager for the ESP32 and ESP8266", + "authors": [ + { + "name": "ZanzyTHEbar", + "url": "https://github.com/ZanzyTHEbar" + } + ], + "repository": { + "type": "git", + "url": "https://github.com/ZanzyTHEbar/EasyNetworkManager.git" + }, + "dependencies": [ + { + "name": "EasyHelpers", + "version": "https://github.com/ZanzyTHEbar/EasyHelpers.git" + }, + { + "name": "ESPAsyncWebServer", + "version": "https://github.com/me-no-dev/ESPAsyncWebServer.git" + }, + { + "name": "ArduinoJson", + "version": "https://github.com/bblanchon/ArduinoJson.git" + }, + { + "name": "AsyncTCP", + "version": "https://github.com/me-no-dev/AsyncTCP.git", + "platforms": ["espressif32"] + }, + { + "name": "ESPAsyncTCP", + "version": "https://github.com/me-no-dev/ESPAsyncTCP.git", + "platforms": ["espressif8266"] + } + ], + "headers": [ + "EasyNetworkManager.hpp", + "EasyNetworkManager.h", + "api/rest_api_handler.hpp", + "api/base/base_api.hpp", + "data/config/project_config.hpp", + "data/config/config_handler.hpp", + "data/statemanager/state_manager.hpp", + "utilities/enum_inheritance.hpp", + "utilities/make_unique.hpp", + "utilities/observer.hpp", + "utilities/api_utilities.hpp", + "utilities/network_utilities.hpp", + "network/mdns/mdns_manager.hpp", + "network/ota/ota.hpp", + "network/wifihandler/wifi_handler.hpp" + ], + "export": { + "include": ["src/*", "examples/*", "include/*"] + }, + "version": "5.5.1", + "frameworks": "arduino", + "platforms": ["espressif32", "espressif8266"] +} diff --git a/NetworkManager/platformio.ini b/NetworkManager/platformio.ini index 99fc9a2..fb439b4 100644 --- a/NetworkManager/platformio.ini +++ b/NetworkManager/platformio.ini @@ -1,18 +1,18 @@ -; PlatformIO Project Configuration File -; -; Build options: build flags, source filter -; Upload options: custom upload port, speed and extra flags -; Library options: dependencies, extra library storages -; Advanced options: extra scripting -; -; Please visit documentation for the other options and examples -; https://docs.platformio.org/page/projectconf.html - -[platformio] -default_envs = esp32dev_debug -extra_configs = - ini/dev_config.ini - ini/user_config.ini - ini/pinouts.ini - ini/envs.ini - +; PlatformIO Project Configuration File +; +; Build options: build flags, source filter +; Upload options: custom upload port, speed and extra flags +; Library options: dependencies, extra library storages +; Advanced options: extra scripting +; +; Please visit documentation for the other options and examples +; https://docs.platformio.org/page/projectconf.html + +[platformio] +default_envs = esp32dev_debug +extra_configs = + ini/dev_config.ini + ini/user_config.ini + ini/pinouts.ini + ini/envs.ini + diff --git a/NetworkManager/src/EasyNetworkManager.cpp b/NetworkManager/src/EasyNetworkManager.cpp index 53f3628..81f9f84 100644 --- a/NetworkManager/src/EasyNetworkManager.cpp +++ b/NetworkManager/src/EasyNetworkManager.cpp @@ -1,35 +1,35 @@ -#include - -EasyNetworkManager::EasyNetworkManager( - const std::string& config_name, const std::string& hostname, - const std::string& ssid, const std::string& password, int channel, - const std::string& service_name, const std::string& service_instance_name, - const std::string& service_protocol, const std::string& service_description, - const std::string& service_port, bool enable_mdns, bool enable_adhoc) - : configHandler(std::make_shared(std::move(config_name), - std::move(hostname))), - wifiHandler(std::make_shared(configHandler->config, - std::move(ssid), - std::move(password), channel)) { - if (enable_mdns) { - mdnsHandler = std::make_shared( - configHandler->config, std::move(service_name), - std::move(service_instance_name), std::move(service_protocol), - std::move(service_description), std::move(service_port)); - } -} - -EasyNetworkManager::~EasyNetworkManager() {} - -void EasyNetworkManager::begin() { - configHandler->config.attach(configHandler); - configHandler->config.attach(wifiHandler); - if (mdnsHandler != nullptr) - configHandler->config.attach(mdnsHandler); - - configHandler->begin(); - wifiHandler->begin(); - - if (mdnsHandler != nullptr) - mdnsHandler->begin(); +#include + +EasyNetworkManager::EasyNetworkManager( + const std::string& config_name, const std::string& hostname, + const std::string& ssid, const std::string& password, int channel, + const std::string& service_name, const std::string& service_instance_name, + const std::string& service_protocol, const std::string& service_description, + const std::string& service_port, bool enable_mdns, bool enable_adhoc) + : configHandler(std::make_shared(std::move(config_name), + std::move(hostname))), + wifiHandler(std::make_shared(configHandler->config, + std::move(ssid), + std::move(password), channel)) { + if (enable_mdns) { + mdnsHandler = std::make_shared( + configHandler->config, std::move(service_name), + std::move(service_instance_name), std::move(service_protocol), + std::move(service_description), std::move(service_port)); + } +} + +EasyNetworkManager::~EasyNetworkManager() {} + +void EasyNetworkManager::begin() { + configHandler->config.attach(configHandler); + configHandler->config.attach(wifiHandler); + if (mdnsHandler != nullptr) + configHandler->config.attach(mdnsHandler); + + configHandler->begin(); + wifiHandler->begin(); + + if (mdnsHandler != nullptr) + mdnsHandler->begin(); } \ No newline at end of file diff --git a/NetworkManager/src/api/asyncota.cpp b/NetworkManager/src/api/asyncota.cpp index 819a62d..12c7b96 100644 --- a/NetworkManager/src/api/asyncota.cpp +++ b/NetworkManager/src/api/asyncota.cpp @@ -1,154 +1,154 @@ -#include -#include -#include -#include -#include - -#include "api/Hash.h" -#include "api/asyncota.hpp" -#include "api/elegantWebpage.h" - -AsyncOTA::AsyncOTA(ProjectConfig& configManager, AsyncServer_t& async_server) - : configManager(configManager), - async_server(async_server), - _authRequired(false) {} - -AsyncOTA::~AsyncOTA() {} - -//********************************************************************************************* -//! OTA Command Functions -//********************************************************************************************* - -void AsyncOTA::checkAuthentication(AsyncWebServerRequest* request, - const char* login, const char* password) { - log_d("[DEBUG] Free Heap: %d", ESP.getFreeHeap()); - if (_authRequired) { - log_d("[DEBUG] Free Heap: %d", ESP.getFreeHeap()); - log_i("Auth required"); - log_d("[DEBUG] Free Heap: %d", ESP.getFreeHeap()); - if (!request->authenticate(login, password, NULL, false)) { - log_d("[DEBUG] Free Heap: %d", ESP.getFreeHeap()); - return request->requestAuthentication(NULL, false); - } - } -} - -void AsyncOTA::begin() { - // NOTE: Code adapted from: - // https://github.com/ayushsharma82/AsyncElegantOTA/ - - auto device_config = configManager.getDeviceConfig(); - auto mdns_config = configManager.getMDNSConfig(); - - if (device_config.ota_password.empty()) { - log_e( - "Password is empty, you need to provide a password in order to " - "setup " - "the OTA server"); - return; - } - - log_i("[OTA Server]: Initializing OTA Server"); - log_i( - "[OTA Server]: Navigate to http://%s.local:81/update to update the " - "firmware", - mdns_config.hostname.c_str()); - - log_d("[OTA Server]: Username: %s, Password: %s", - device_config.ota_login.c_str(), device_config.ota_password.c_str()); - log_d("[DEBUG] Free Heap: %d", ESP.getFreeHeap()); - const char* login = device_config.ota_login.c_str(); - const char* password = device_config.ota_password.c_str(); - log_d("[DEBUG] Free Heap: %d", ESP.getFreeHeap()); - - // Note: XHTTP_GET - async_server.server.on( - "/update/identity", 0b00000001, [&](AsyncWebServerRequest* request) { - checkAuthentication(request, login, password); - - String _id = String((uint32_t)ESP.getEfuseMac(), HEX); - _id.toUpperCase(); - request->send(200, API_Utilities::MIMETYPE_JSON, - "{\"id\": \"" + _id + "\", \"hardware\": \"ESP32\"}"); - }); - - // Note: HTT_GET - async_server.server.on( - "/update", 0b00000001, [&](AsyncWebServerRequest* request) { - log_d("[DEBUG] Free Heap: %d", ESP.getFreeHeap()); - checkAuthentication(request, login, password); - - if (customHandlerFunction != NULL) { - customHandlerFunction(); - } - - AsyncWebServerResponse* response = request->beginResponse_P( - 200, "text/html", ELEGANT_HTML, ELEGANT_HTML_SIZE); - response->addHeader("Content-Encoding", "gzip"); - request->send(response); - }); - // Note: HTT_POST - async_server.server.on( - "/update", 0b00000010, - [&](AsyncWebServerRequest* request) { - checkAuthentication(request, login, password); - // the request handler is triggered after the upload has finished... - // create the response, add header, and send response - AsyncWebServerResponse* response = request->beginResponse( - (Update.hasError()) ? 500 : 200, "text/plain", - (Update.hasError()) ? "FAIL" : "OK"); - response->addHeader("Connection", "close"); - response->addHeader("Access-Control-Allow-Origin", "*"); - request->send(response); - configManager.save(); - }, - [&](AsyncWebServerRequest* request, String filename, size_t index, - uint8_t* data, size_t len, bool final) { - // Upload handler chunks in data - checkAuthentication(request, login, password); - - if (!index) { - if (!request->hasParam("MD5", true)) { - return request->send(400, "text/plain", - "MD5 parameter missing"); - } - - if (!Update.setMD5( - request->getParam("MD5", true)->value().c_str())) { - return request->send(400, "text/plain", - "MD5 parameter invalid"); - } - int cmd = (filename == "filesystem") ? U_SPIFFS : U_FLASH; - if (!Update.begin(UPDATE_SIZE_UNKNOWN, - cmd)) { // Start with max available size - Update.printError(Serial); - return request->send(400, "text/plain", - "OTA could not begin"); - } - } - - // Write chunked data to the free sketch space - if (len) { - if (Update.write(data, len) != len) { - return request->send(400, "text/plain", - "OTA could not begin"); - } - } - - if (final) { // if the final flag is set then this is the last - // frame of data - if (!Update.end(true)) { // true to set the size to the current - // progress - Update.printError(Serial); - return request->send(400, "text/plain", - "Could not end OTA"); - } - } else { - return; - } - }); -} -void AsyncOTA::setOTAHandler( - AsyncOTACustomHandlerFunction customHandlerFunction) { - this->customHandlerFunction = customHandlerFunction; -} +#include +#include +#include +#include +#include + +#include "api/Hash.h" +#include "api/asyncota.hpp" +#include "api/elegantWebpage.h" + +AsyncOTA::AsyncOTA(ProjectConfig& configManager, AsyncServer_t& async_server) + : configManager(configManager), + async_server(async_server), + _authRequired(false) {} + +AsyncOTA::~AsyncOTA() {} + +//********************************************************************************************* +//! OTA Command Functions +//********************************************************************************************* + +void AsyncOTA::checkAuthentication(AsyncWebServerRequest* request, + const char* login, const char* password) { + log_d("[DEBUG] Free Heap: %d", ESP.getFreeHeap()); + if (_authRequired) { + log_d("[DEBUG] Free Heap: %d", ESP.getFreeHeap()); + log_i("Auth required"); + log_d("[DEBUG] Free Heap: %d", ESP.getFreeHeap()); + if (!request->authenticate(login, password, NULL, false)) { + log_d("[DEBUG] Free Heap: %d", ESP.getFreeHeap()); + return request->requestAuthentication(NULL, false); + } + } +} + +void AsyncOTA::begin() { + // NOTE: Code adapted from: + // https://github.com/ayushsharma82/AsyncElegantOTA/ + + auto device_config = configManager.getDeviceConfig(); + auto mdns_config = configManager.getMDNSConfig(); + + if (device_config.ota_password.empty()) { + log_e( + "Password is empty, you need to provide a password in order to " + "setup " + "the OTA server"); + return; + } + + log_i("[OTA Server]: Initializing OTA Server"); + log_i( + "[OTA Server]: Navigate to http://%s.local:81/update to update the " + "firmware", + mdns_config.hostname.c_str()); + + log_d("[OTA Server]: Username: %s, Password: %s", + device_config.ota_login.c_str(), device_config.ota_password.c_str()); + log_d("[DEBUG] Free Heap: %d", ESP.getFreeHeap()); + const char* login = device_config.ota_login.c_str(); + const char* password = device_config.ota_password.c_str(); + log_d("[DEBUG] Free Heap: %d", ESP.getFreeHeap()); + + // Note: XHTTP_GET + async_server.server.on( + "/update/identity", 0b00000001, [&](AsyncWebServerRequest* request) { + checkAuthentication(request, login, password); + + String _id = String((uint32_t)ESP.getEfuseMac(), HEX); + _id.toUpperCase(); + request->send(200, API_Utilities::MIMETYPE_JSON, + "{\"id\": \"" + _id + "\", \"hardware\": \"ESP32\"}"); + }); + + // Note: HTT_GET + async_server.server.on( + "/update", 0b00000001, [&](AsyncWebServerRequest* request) { + log_d("[DEBUG] Free Heap: %d", ESP.getFreeHeap()); + checkAuthentication(request, login, password); + + if (customHandlerFunction != NULL) { + customHandlerFunction(); + } + + AsyncWebServerResponse* response = request->beginResponse_P( + 200, "text/html", ELEGANT_HTML, ELEGANT_HTML_SIZE); + response->addHeader("Content-Encoding", "gzip"); + request->send(response); + }); + // Note: HTT_POST + async_server.server.on( + "/update", 0b00000010, + [&](AsyncWebServerRequest* request) { + checkAuthentication(request, login, password); + // the request handler is triggered after the upload has finished... + // create the response, add header, and send response + AsyncWebServerResponse* response = request->beginResponse( + (Update.hasError()) ? 500 : 200, "text/plain", + (Update.hasError()) ? "FAIL" : "OK"); + response->addHeader("Connection", "close"); + response->addHeader("Access-Control-Allow-Origin", "*"); + request->send(response); + configManager.save(); + }, + [&](AsyncWebServerRequest* request, String filename, size_t index, + uint8_t* data, size_t len, bool final) { + // Upload handler chunks in data + checkAuthentication(request, login, password); + + if (!index) { + if (!request->hasParam("MD5", true)) { + return request->send(400, "text/plain", + "MD5 parameter missing"); + } + + if (!Update.setMD5( + request->getParam("MD5", true)->value().c_str())) { + return request->send(400, "text/plain", + "MD5 parameter invalid"); + } + int cmd = (filename == "filesystem") ? U_SPIFFS : U_FLASH; + if (!Update.begin(UPDATE_SIZE_UNKNOWN, + cmd)) { // Start with max available size + Update.printError(Serial); + return request->send(400, "text/plain", + "OTA could not begin"); + } + } + + // Write chunked data to the free sketch space + if (len) { + if (Update.write(data, len) != len) { + return request->send(400, "text/plain", + "OTA could not begin"); + } + } + + if (final) { // if the final flag is set then this is the last + // frame of data + if (!Update.end(true)) { // true to set the size to the current + // progress + Update.printError(Serial); + return request->send(400, "text/plain", + "Could not end OTA"); + } + } else { + return; + } + }); +} +void AsyncOTA::setOTAHandler( + AsyncOTACustomHandlerFunction customHandlerFunction) { + this->customHandlerFunction = customHandlerFunction; +} diff --git a/NetworkManager/src/api/base_api.cpp b/NetworkManager/src/api/base_api.cpp index f72f8f6..aa40d3d 100644 --- a/NetworkManager/src/api/base_api.cpp +++ b/NetworkManager/src/api/base_api.cpp @@ -1,262 +1,262 @@ -#include - -// https://github.com/me-no-dev/ESPAsyncWebServer/tree/master#arduinojson-advanced-response -// TODO: Implement authentication - -BaseAPI::BaseAPI(ProjectConfig& configManager) : configManager(configManager) {} - -BaseAPI::~BaseAPI() {} - -//********************************************************************************************* -//! Command Functions -//********************************************************************************************* -void BaseAPI::setWiFi(AsyncWebServerRequest* request) { - switch (_networkMethodsMap_enum[request->method()]) { - case POST: { - std::string networkName; - std::string ssid; - std::string password; - std::string ota_password; - std::string mdns; - int ota_port = 0; - uint8_t channel = 0; - uint8_t power = 0; - uint8_t adhoc = 0; - - int params = request->params(); - log_d("Number of Params: %d", params); - for (int i = 0; i < params; i++) { - AsyncWebParameter* param = request->getParam(i); - if (param->name() == "networkName") { - networkName.assign(param->value().c_str()); - } else if (param->name() == "ssid") { - ssid.assign(param->value().c_str()); - } else if (param->name() == "password") { - password.assign(param->value().c_str()); - } else if (param->name() == "channel") { - channel = (uint8_t)atoi(param->value().c_str()); - } else if (param->name() == "power") { - power = (uint8_t)atoi(param->value().c_str()); - } else if (param->name() == "ota_password") { - ota_password.assign(param->value().c_str()); - } else if (param->name() == "ota_port") { - ota_port = atoi(param->value().c_str()); - } else if (param->name() == "mdns") { - mdns.assign(param->value().c_str()); - } else if (param->name() == "adhoc") { - adhoc = (uint8_t)atoi(param->value().c_str()); - } - log_i("%s[%s]: %s\n", - _networkMethodsMap[request->method()].c_str(), - param->name().c_str(), param->value().c_str()); - } - // note: We're passing empty params by design, this is done to reset - // specific fields - configManager.setWifiConfig(networkName, ssid, password, channel, - power, adhoc, true); - - if (!mdns.empty()) { - if (!configManager.setMDNSConfig(mdns, true)) { - request->send(400, MIMETYPE_JSON, - "{\"msg\":\"Error. MDNS Name is not a " - "valid alpha numeric string.\"}"); - } - log_i("MDNS Name set to: %s", mdns.c_str()); - } - - if (!ota_password.empty()) { - configManager.setDeviceConfig(ota_password, ota_port, true); - log_i("OTA Password set to: %s", ota_password.c_str()); - } - this->save(request); - break; - } - case DELETE: { - configManager.deleteWifiConfig(request->arg("networkName").c_str(), - true); - request->send(200, MIMETYPE_JSON, - "{\"msg\":\"Done. Wifi Creds have been deleted.\"}"); - break; - } - default: { - request->send(400, MIMETYPE_JSON, "{\"msg\":\"Invalid Request\"}"); - request->redirect("/"); - break; - } - } -} - -void BaseAPI::setWiFiTXPower(AsyncWebServerRequest* request) { - switch (_networkMethodsMap_enum[request->method()]) { - case GET: { - request->send(400, MIMETYPE_JSON, "{\"msg\":\"Invalid Request\"}"); - break; - } - case POST: { - int params = request->params(); - - uint8_t txPower = 0; - - for (int i = 0; i < params; i++) { - AsyncWebParameter* param = request->getParam(i); - if (param->name() == "txPower") { - txPower = atoi(param->value().c_str()); - } - } - configManager.setWiFiTxPower(txPower, true); - configManager.wifiTxPowerConfigSave(); - request->send(200, MIMETYPE_JSON, - "{\"msg\":\"Done. TX Power has been set.\"}"); - } - } -} - -void BaseAPI::handleJson(AsyncWebServerRequest* request, JsonVariant& jsonData) { - switch (_networkMethodsMap_enum[request->method()]) { - case POST: { - auto jsonObj = jsonData.as(); - std::string json; - serializeJson(jsonObj, json); - configManager.setDeviceDataJson(json, true); - request->send(200, MIMETYPE_JSON, - "{\"msg\":\"Done. Device Data " - "has been set.\"}"); - break; - } - default: { - request->send(400, MIMETYPE_JSON, "{\"msg\":\"Invalid Request\"}"); - request->redirect("/"); - break; - } - } -} - -void BaseAPI::getDeviceConfigData(AsyncWebServerRequest* request) { - switch (_networkMethodsMap_enum[request->method()]) { - case GET: { - AsyncJsonResponse* response = new AsyncJsonResponse(); - response->addHeader("EasyNetworkManager", "1.0"); - auto root = response->getRoot(); - root["deviceData"] = - configManager.getDeviceDataJson().deviceJson.c_str(); - response->setLength(); - request->send(response); - break; - } - default: { - request->send(400, MIMETYPE_JSON, "{\"msg\":\"Invalid Request\"}"); - request->redirect("/"); - break; - } - } -} - -void BaseAPI::getJsonConfig(AsyncWebServerRequest* request) { - // returns the current stored config in case it get's deleted on the PC. - switch (_networkMethodsMap_enum[request->method()]) { - case GET: { - std::string wifiConfigSerialized = "\"wifi_config\": ["; - auto networksConfigs = configManager.getWifiConfigs(); - for (auto& networkConfig : networksConfigs) { - wifiConfigSerialized += networkConfig.toRepresentation(); - - if (&networkConfig != &networksConfigs.back()) - wifiConfigSerialized += ","; - } - wifiConfigSerialized += "]"; - - std::string json = Helpers::format_string( - "{%s, %s, %s, %s, %s}", - configManager.getDeviceConfig().toRepresentation().c_str(), - configManager.getWifiTxPowerConfig().toRepresentation().c_str(), - wifiConfigSerialized.c_str(), - configManager.getMDNSConfig().toRepresentation().c_str(), - configManager.getAPWifiConfig().toRepresentation().c_str()); - request->send(200, MIMETYPE_JSON, json.c_str()); - break; - } - default: { - request->send(400, MIMETYPE_JSON, "{\"msg\":\"Invalid Request\"}"); - break; - } - } -} - -void BaseAPI::rebootDevice(AsyncWebServerRequest* request) { - switch (_networkMethodsMap_enum[request->method()]) { - case GET: { - request->send(200, MIMETYPE_JSON, "{\"msg\":\"Rebooting Device\"}"); - ESP.restart(); - } - default: { - request->send(400, MIMETYPE_JSON, "{\"msg\":\"Invalid Request\"}"); - break; - } - } -} - -void BaseAPI::factoryReset(AsyncWebServerRequest* request) { - switch (_networkMethodsMap_enum[request->method()]) { - case GET: { - log_d("Factory Reset"); - bool success = configManager.reset(); - char buf[100]; - snprintf(buf, sizeof(buf), "{\"msg\":\"Factory Reset - %s\"}", - success ? "Done" : "Failed"); - request->send(200, MIMETYPE_JSON, buf); - } - default: { - request->send(400, MIMETYPE_JSON, "{\"msg\":\"Invalid Request\"}"); - break; - } - } -} - -/** - * @brief Remove a command handler from the API - * - * @param request - * @return \c void - */ -void BaseAPI::removeRoute(AsyncWebServerRequest* request) { - log_i("Request: %s", request->url().c_str()); - int params = request->params(); - auto it_map = route_map.find(request->pathArg(0).c_str()); - log_i("Request: %s", request->pathArg(0).c_str()); - - auto it = it_map->second.find(request->pathArg(1).c_str()); - if (it != it_map->second.end()) { - switch (_networkMethodsMap_enum[request->method()]) { - case DELETE: { - it_map->second.erase(it); - request->send(200, MIMETYPE_JSON, - "{\"msg\":\"Route Removed\"}"); - break; - } - default: { - request->send(400, MIMETYPE_JSON, - "{\"msg\":\"Invalid Request\"}"); - break; - } - } - } else { - request->send(400, MIMETYPE_JSON, "{\"msg\":\"Route Not Found\"}"); - } -} - -void BaseAPI::ping(AsyncWebServerRequest* request) { - request->send(200, MIMETYPE_JSON, "{\"msg\": \"ok\" }"); -} - -void BaseAPI::save(AsyncWebServerRequest* request) { - configManager.save(); - request->send(200, MIMETYPE_JSON, "{\"msg\": \"ok\" }"); -} - -void BaseAPI::rssi(AsyncWebServerRequest* request) { - int rssi = Network_Utilities::getStrength( - request->getParam("points")->value().toInt()); - char _rssiBuffer[20]; - snprintf(_rssiBuffer, sizeof(_rssiBuffer), "{\"rssi\": %d }", rssi); - request->send(200, MIMETYPE_JSON, _rssiBuffer); -} +#include + +// https://github.com/me-no-dev/ESPAsyncWebServer/tree/master#arduinojson-advanced-response +// TODO: Implement authentication + +BaseAPI::BaseAPI(ProjectConfig& configManager) : configManager(configManager) {} + +BaseAPI::~BaseAPI() {} + +//********************************************************************************************* +//! Command Functions +//********************************************************************************************* +void BaseAPI::setWiFi(AsyncWebServerRequest* request) { + switch (_networkMethodsMap_enum[request->method()]) { + case POST: { + std::string networkName; + std::string ssid; + std::string password; + std::string ota_password; + std::string mdns; + int ota_port = 0; + uint8_t channel = 0; + uint8_t power = 0; + uint8_t adhoc = 0; + + int params = request->params(); + log_d("Number of Params: %d", params); + for (int i = 0; i < params; i++) { + AsyncWebParameter* param = request->getParam(i); + if (param->name() == "networkName") { + networkName.assign(param->value().c_str()); + } else if (param->name() == "ssid") { + ssid.assign(param->value().c_str()); + } else if (param->name() == "password") { + password.assign(param->value().c_str()); + } else if (param->name() == "channel") { + channel = (uint8_t)atoi(param->value().c_str()); + } else if (param->name() == "power") { + power = (uint8_t)atoi(param->value().c_str()); + } else if (param->name() == "ota_password") { + ota_password.assign(param->value().c_str()); + } else if (param->name() == "ota_port") { + ota_port = atoi(param->value().c_str()); + } else if (param->name() == "mdns") { + mdns.assign(param->value().c_str()); + } else if (param->name() == "adhoc") { + adhoc = (uint8_t)atoi(param->value().c_str()); + } + log_i("%s[%s]: %s\n", + _networkMethodsMap[request->method()].c_str(), + param->name().c_str(), param->value().c_str()); + } + // note: We're passing empty params by design, this is done to reset + // specific fields + configManager.setWifiConfig(networkName, ssid, password, channel, + power, adhoc, true); + + if (!mdns.empty()) { + if (!configManager.setMDNSConfig(mdns, true)) { + request->send(400, MIMETYPE_JSON, + "{\"msg\":\"Error. MDNS Name is not a " + "valid alpha numeric string.\"}"); + } + log_i("MDNS Name set to: %s", mdns.c_str()); + } + + if (!ota_password.empty()) { + configManager.setDeviceConfig(ota_password, ota_port, true); + log_i("OTA Password set to: %s", ota_password.c_str()); + } + this->save(request); + break; + } + case DELETE: { + configManager.deleteWifiConfig(request->arg("networkName").c_str(), + true); + request->send(200, MIMETYPE_JSON, + "{\"msg\":\"Done. Wifi Creds have been deleted.\"}"); + break; + } + default: { + request->send(400, MIMETYPE_JSON, "{\"msg\":\"Invalid Request\"}"); + request->redirect("/"); + break; + } + } +} + +void BaseAPI::setWiFiTXPower(AsyncWebServerRequest* request) { + switch (_networkMethodsMap_enum[request->method()]) { + case GET: { + request->send(400, MIMETYPE_JSON, "{\"msg\":\"Invalid Request\"}"); + break; + } + case POST: { + int params = request->params(); + + uint8_t txPower = 0; + + for (int i = 0; i < params; i++) { + AsyncWebParameter* param = request->getParam(i); + if (param->name() == "txPower") { + txPower = atoi(param->value().c_str()); + } + } + configManager.setWiFiTxPower(txPower, true); + configManager.wifiTxPowerConfigSave(); + request->send(200, MIMETYPE_JSON, + "{\"msg\":\"Done. TX Power has been set.\"}"); + } + } +} + +void BaseAPI::handleJson(AsyncWebServerRequest* request, JsonVariant& jsonData) { + switch (_networkMethodsMap_enum[request->method()]) { + case POST: { + auto jsonObj = jsonData.as(); + std::string json; + serializeJson(jsonObj, json); + configManager.setDeviceDataJson(json, true); + request->send(200, MIMETYPE_JSON, + "{\"msg\":\"Done. Device Data " + "has been set.\"}"); + break; + } + default: { + request->send(400, MIMETYPE_JSON, "{\"msg\":\"Invalid Request\"}"); + request->redirect("/"); + break; + } + } +} + +void BaseAPI::getDeviceConfigData(AsyncWebServerRequest* request) { + switch (_networkMethodsMap_enum[request->method()]) { + case GET: { + AsyncJsonResponse* response = new AsyncJsonResponse(); + response->addHeader("EasyNetworkManager", "1.0"); + auto root = response->getRoot(); + root["deviceData"] = + configManager.getDeviceDataJson().deviceJson.c_str(); + response->setLength(); + request->send(response); + break; + } + default: { + request->send(400, MIMETYPE_JSON, "{\"msg\":\"Invalid Request\"}"); + request->redirect("/"); + break; + } + } +} + +void BaseAPI::getJsonConfig(AsyncWebServerRequest* request) { + // returns the current stored config in case it get's deleted on the PC. + switch (_networkMethodsMap_enum[request->method()]) { + case GET: { + std::string wifiConfigSerialized = "\"wifi_config\": ["; + auto networksConfigs = configManager.getWifiConfigs(); + for (auto& networkConfig : networksConfigs) { + wifiConfigSerialized += networkConfig.toRepresentation(); + + if (&networkConfig != &networksConfigs.back()) + wifiConfigSerialized += ","; + } + wifiConfigSerialized += "]"; + + std::string json = Helpers::format_string( + "{%s, %s, %s, %s, %s}", + configManager.getDeviceConfig().toRepresentation().c_str(), + configManager.getWifiTxPowerConfig().toRepresentation().c_str(), + wifiConfigSerialized.c_str(), + configManager.getMDNSConfig().toRepresentation().c_str(), + configManager.getAPWifiConfig().toRepresentation().c_str()); + request->send(200, MIMETYPE_JSON, json.c_str()); + break; + } + default: { + request->send(400, MIMETYPE_JSON, "{\"msg\":\"Invalid Request\"}"); + break; + } + } +} + +void BaseAPI::rebootDevice(AsyncWebServerRequest* request) { + switch (_networkMethodsMap_enum[request->method()]) { + case GET: { + request->send(200, MIMETYPE_JSON, "{\"msg\":\"Rebooting Device\"}"); + ESP.restart(); + } + default: { + request->send(400, MIMETYPE_JSON, "{\"msg\":\"Invalid Request\"}"); + break; + } + } +} + +void BaseAPI::factoryReset(AsyncWebServerRequest* request) { + switch (_networkMethodsMap_enum[request->method()]) { + case GET: { + log_d("Factory Reset"); + bool success = configManager.reset(); + char buf[100]; + snprintf(buf, sizeof(buf), "{\"msg\":\"Factory Reset - %s\"}", + success ? "Done" : "Failed"); + request->send(200, MIMETYPE_JSON, buf); + } + default: { + request->send(400, MIMETYPE_JSON, "{\"msg\":\"Invalid Request\"}"); + break; + } + } +} + +/** + * @brief Remove a command handler from the API + * + * @param request + * @return \c void + */ +void BaseAPI::removeRoute(AsyncWebServerRequest* request) { + log_i("Request: %s", request->url().c_str()); + int params = request->params(); + auto it_map = route_map.find(request->pathArg(0).c_str()); + log_i("Request: %s", request->pathArg(0).c_str()); + + auto it = it_map->second.find(request->pathArg(1).c_str()); + if (it != it_map->second.end()) { + switch (_networkMethodsMap_enum[request->method()]) { + case DELETE: { + it_map->second.erase(it); + request->send(200, MIMETYPE_JSON, + "{\"msg\":\"Route Removed\"}"); + break; + } + default: { + request->send(400, MIMETYPE_JSON, + "{\"msg\":\"Invalid Request\"}"); + break; + } + } + } else { + request->send(400, MIMETYPE_JSON, "{\"msg\":\"Route Not Found\"}"); + } +} + +void BaseAPI::ping(AsyncWebServerRequest* request) { + request->send(200, MIMETYPE_JSON, "{\"msg\": \"ok\" }"); +} + +void BaseAPI::save(AsyncWebServerRequest* request) { + configManager.save(); + request->send(200, MIMETYPE_JSON, "{\"msg\": \"ok\" }"); +} + +void BaseAPI::rssi(AsyncWebServerRequest* request) { + int rssi = Network_Utilities::getStrength( + request->getParam("points")->value().toInt()); + char _rssiBuffer[20]; + snprintf(_rssiBuffer, sizeof(_rssiBuffer), "{\"rssi\": %d }", rssi); + request->send(200, MIMETYPE_JSON, _rssiBuffer); +} diff --git a/NetworkManager/src/api/rest_api_handler.cpp b/NetworkManager/src/api/rest_api_handler.cpp index 45d6e0c..03d7752 100644 --- a/NetworkManager/src/api/rest_api_handler.cpp +++ b/NetworkManager/src/api/rest_api_handler.cpp @@ -1,234 +1,234 @@ -#include - -//********************************************************************************************* -//! API Server -//********************************************************************************************* - -APIServer::APIServer(ProjectConfig& configManager, AsyncServer_t& async_server, - AsyncOTA* async_ota) - : BaseAPI(configManager), async_server(async_server), async_ota(nullptr) { - if (async_ota != nullptr) { - this->async_ota = async_ota; - } -} - -APIServer::~APIServer() { - if (async_ota != nullptr) { - delete async_ota; - } -} - -void APIServer::begin() { - log_d("[APIServer]: Initializing REST API"); - this->setupServer(); - async_server.begin(); - char api_url[1000]; - char wifi_manager_url[1000]; - snprintf(api_url, sizeof(api_url), - "^\\%s\\/([a-zA-Z0-9]+)\\/([a-zA-Z0-9]+)$", - async_server.api_url.c_str()); - snprintf(wifi_manager_url, sizeof(wifi_manager_url), - "^\\%s\\/([a-zA-Z0-9]+)\\/([a-zA-Z0-9]+)$", - async_server.wifimanager_url.c_str()); - - log_d("[APIServer]: API URL: %s", api_url); - - async_server.server.on( - api_url, XHTTP_ANY, - [&](AsyncWebServerRequest* request) { handleRequest(request); }); - - async_server.server.on( - wifi_manager_url, HTTP_ANY, - [&](AsyncWebServerRequest* request) { handleRequest(request); }); - - //* Add default JSON handler - // create JSON route - std::string json_url = async_server.api_url; - json_url.append(async_server.json_url); - - async_server.server.on( - json_url.c_str(), XHTTP_GET, [&](AsyncWebServerRequest* request) { - request->send(400, MIMETYPE_JSON, - "{\"msg\":\"Invalid Request Type\"}"); - }); - - async_server.server.addHandler(new AsyncCallbackJsonWebHandler( - json_url.c_str(), - [&](AsyncWebServerRequest* request, JsonVariant& json) { - handleJson(request, json); - })); - - if (async_ota != nullptr) - async_ota->begin(); - async_server.server.begin(); -} - -void APIServer::setupServer() { - // Set default routes - routes.reserve(10); // reserve enough memory for all routes - routes.emplace("wifi", &APIServer::setWiFi); - routes.emplace("resetConfig", &APIServer::factoryReset); - routes.emplace("getDeviceConfigData", &APIServer::getDeviceConfigData); - routes.emplace("getConfig", &APIServer::getJsonConfig); - routes.emplace("deleteRoute", &APIServer::removeRoute); - routes.emplace("rebootDevice", &APIServer::rebootDevice); - routes.emplace("ping", &APIServer::ping); - routes.emplace("save", &APIServer::save); - routes.emplace("wifiStrength", &APIServer::rssi); - - //! reserve enough memory for all routes - must be called after adding - //! routes and before adding routes to route_map - indexes.reserve(routes.size()); // this is done to avoid reallocation of - // memory and copying of data - addRouteMap("builtin", routes); // add new route map to the route_map -} - -/** - * @brief Find a parameter in the request - * @note This is a utility function to find a parameter in the request - * @note This function modifies the value parameter, returns a boolean - * @param request \c AsyncWebServerRequest* the request object - * @param param \c std::string the parameter to find - * @param value \c std::string& the value of the parameter - * @return bool \c true if the parameter is found, \c false otherwise - */ -bool APIServer::findParam(AsyncWebServerRequest* request, - const std::string& param, std::string& value) { - if (request->hasParam(param.c_str())) { - value.assign(request->getParam(param.c_str(), true)->value().c_str()); - return true; - } - return false; -} - -/** - * @brief Add a command handler to the API - * - * @param index - * @param funct - * @param indexes \c std::vector a list of the routes of the - * command handlers - * - * @return void - * - */ -void APIServer::addRouteMap(const std::string& index, route_t route) { - route_map.emplace(std::move(index), route); - - for (const auto& key : route) { - const std::string temp = - index + '/' + key.first; // add the route to the index - indexes.emplace_back(temp); // add the route to the list of routes - // - use emplace_back to avoid copying - } -} - -// TODO: Add support for body parsing -void APIServer::handleRequest(AsyncWebServerRequest* request) { - std::vector temp = - Helpers::split(async_server.user_commands.c_str(), '/'); - - if (strcmp(request->pathArg(0).c_str(), temp[1].c_str()) == 0) { - handle_user_commands(request); - return; - } - - // Get the route - log_i("Request URL: %s", request->url().c_str()); - log_i("Request: %s", request->pathArg(0).c_str()); - log_i("Request: %s", request->pathArg(1).c_str()); - - auto it_map = route_map.find(request->pathArg(0).c_str()); - - if (it_map == route_map.end()) { - log_e("[APIServer]: Invalid Command"); - request->send(400, MIMETYPE_JSON, "{\"msg\":\"Invalid Command\"}"); - return; - } - - auto it_method = it_map->second.find(request->pathArg(1).c_str()); - - if (it_method == it_map->second.end()) { - log_e("[APIServer]: Invalid Map Index"); - request->send(400, MIMETYPE_JSON, "{\"msg\":\"Invalid Map Index\"}"); - return; - } - - log_d("[APIServer]: We are trying to execute the function"); - (*this.*(it_method->second))(request); - request->send(200); -} - -void APIServer::addAPICommand(const std::string& url, - ArRequestHandlerFunction funct) { - useRouteHandler.emplace(std::move(url), funct); -} - -/** - * @brief Add a command handler to the API - * - * @param request - * @return \c void - * @note This function is called by the API server when a command is received - * @warning \c This function requires the user to access the index using a url - * parameter \c we need to fix this!! I need a better implemenation - * - */ -void APIServer::handle_user_commands(AsyncWebServerRequest* request) { - std::string url = request->pathArg(1).c_str(); - auto it = useRouteHandler.find(url); - if (it != useRouteHandler.end()) { - log_d("[APIServer]: We are trying to execute the function"); - it->second(request); - return; - } - log_e("[APIServer]: Invalid Command"); - request->send(400, MIMETYPE_JSON, "{\"msg\":\"Invalid Command\"}"); -} - -void APIServer::setupCaptivePortal(bool apMode) { - log_d("[SETUP Captive Portal]: Starting Captive Portal"); - log_d("[SETUP Captive Portal]: AP Mode: %s", - apMode ? "enabled" : "disabled"); - async_server.server.addHandler(new CaptiveRequestHandler(async_server)) - .setFilter(apMode ? ON_AP_FILTER : ON_STA_FILTER); -} - -//********************************************************************************************* -//! API Utilities -//********************************************************************************************* - -CaptiveRequestHandler::CaptiveRequestHandler(AsyncServer_t& async_server) - : async_server(async_server) {} - -CaptiveRequestHandler::~CaptiveRequestHandler() {} - -bool CaptiveRequestHandler::canHandle(AsyncWebServerRequest* request) { - // request->addInterestingHeader("ANY"); - return true; -} - -void CaptiveRequestHandler::handleRequest(AsyncWebServerRequest* request) { - if (async_server.spiffsMounted) { - if (async_server.custom_html_files.size() > 0) { - AsyncResponseStream* response_stream = - request->beginResponseStream("text/html"); - for (auto& file : async_server.custom_html_files) { - if (file.endpoint == "captive_portal" || - file.endpoint == "captive_portal.html" || - file.endpoint == "/" || file.endpoint == "/index.html" || - file.endpoint == "/index" || - file.endpoint == "portal.html") { - response_stream->print(file.file.c_str()); - } - } - request->send(response_stream); - return; - } - } - - AsyncWebServerResponse* response = request->beginResponse_P( - 200, "text/html", WEB_MANAGER_HTML, WEB_MANAGER_HTML_SIZE); - response->addHeader("Content-Encoding", "gzip"); - request->send(response); +#include + +//********************************************************************************************* +//! API Server +//********************************************************************************************* + +APIServer::APIServer(ProjectConfig& configManager, AsyncServer_t& async_server, + AsyncOTA* async_ota) + : BaseAPI(configManager), async_server(async_server), async_ota(nullptr) { + if (async_ota != nullptr) { + this->async_ota = async_ota; + } +} + +APIServer::~APIServer() { + if (async_ota != nullptr) { + delete async_ota; + } +} + +void APIServer::begin() { + log_d("[APIServer]: Initializing REST API"); + this->setupServer(); + async_server.begin(); + char api_url[1000]; + char wifi_manager_url[1000]; + snprintf(api_url, sizeof(api_url), + "^\\%s\\/([a-zA-Z0-9]+)\\/([a-zA-Z0-9]+)$", + async_server.api_url.c_str()); + snprintf(wifi_manager_url, sizeof(wifi_manager_url), + "^\\%s\\/([a-zA-Z0-9]+)\\/([a-zA-Z0-9]+)$", + async_server.wifimanager_url.c_str()); + + log_d("[APIServer]: API URL: %s", api_url); + + async_server.server.on( + api_url, XHTTP_ANY, + [&](AsyncWebServerRequest* request) { handleRequest(request); }); + + async_server.server.on( + wifi_manager_url, HTTP_ANY, + [&](AsyncWebServerRequest* request) { handleRequest(request); }); + + //* Add default JSON handler + // create JSON route + std::string json_url = async_server.api_url; + json_url.append(async_server.json_url); + + async_server.server.on( + json_url.c_str(), XHTTP_GET, [&](AsyncWebServerRequest* request) { + request->send(400, MIMETYPE_JSON, + "{\"msg\":\"Invalid Request Type\"}"); + }); + + async_server.server.addHandler(new AsyncCallbackJsonWebHandler( + json_url.c_str(), + [&](AsyncWebServerRequest* request, JsonVariant& json) { + handleJson(request, json); + })); + + if (async_ota != nullptr) + async_ota->begin(); + async_server.server.begin(); +} + +void APIServer::setupServer() { + // Set default routes + routes.reserve(10); // reserve enough memory for all routes + routes.emplace("wifi", &APIServer::setWiFi); + routes.emplace("resetConfig", &APIServer::factoryReset); + routes.emplace("getDeviceConfigData", &APIServer::getDeviceConfigData); + routes.emplace("getConfig", &APIServer::getJsonConfig); + routes.emplace("deleteRoute", &APIServer::removeRoute); + routes.emplace("rebootDevice", &APIServer::rebootDevice); + routes.emplace("ping", &APIServer::ping); + routes.emplace("save", &APIServer::save); + routes.emplace("wifiStrength", &APIServer::rssi); + + //! reserve enough memory for all routes - must be called after adding + //! routes and before adding routes to route_map + indexes.reserve(routes.size()); // this is done to avoid reallocation of + // memory and copying of data + addRouteMap("builtin", routes); // add new route map to the route_map +} + +/** + * @brief Find a parameter in the request + * @note This is a utility function to find a parameter in the request + * @note This function modifies the value parameter, returns a boolean + * @param request \c AsyncWebServerRequest* the request object + * @param param \c std::string the parameter to find + * @param value \c std::string& the value of the parameter + * @return bool \c true if the parameter is found, \c false otherwise + */ +bool APIServer::findParam(AsyncWebServerRequest* request, + const std::string& param, std::string& value) { + if (request->hasParam(param.c_str())) { + value.assign(request->getParam(param.c_str(), true)->value().c_str()); + return true; + } + return false; +} + +/** + * @brief Add a command handler to the API + * + * @param index + * @param funct + * @param indexes \c std::vector a list of the routes of the + * command handlers + * + * @return void + * + */ +void APIServer::addRouteMap(const std::string& index, route_t route) { + route_map.emplace(std::move(index), route); + + for (const auto& key : route) { + const std::string temp = + index + '/' + key.first; // add the route to the index + indexes.emplace_back(temp); // add the route to the list of routes + // - use emplace_back to avoid copying + } +} + +// TODO: Add support for body parsing +void APIServer::handleRequest(AsyncWebServerRequest* request) { + std::vector temp = + Helpers::split(async_server.user_commands.c_str(), '/'); + + if (strcmp(request->pathArg(0).c_str(), temp[1].c_str()) == 0) { + handle_user_commands(request); + return; + } + + // Get the route + log_i("Request URL: %s", request->url().c_str()); + log_i("Request: %s", request->pathArg(0).c_str()); + log_i("Request: %s", request->pathArg(1).c_str()); + + auto it_map = route_map.find(request->pathArg(0).c_str()); + + if (it_map == route_map.end()) { + log_e("[APIServer]: Invalid Command"); + request->send(400, MIMETYPE_JSON, "{\"msg\":\"Invalid Command\"}"); + return; + } + + auto it_method = it_map->second.find(request->pathArg(1).c_str()); + + if (it_method == it_map->second.end()) { + log_e("[APIServer]: Invalid Map Index"); + request->send(400, MIMETYPE_JSON, "{\"msg\":\"Invalid Map Index\"}"); + return; + } + + log_d("[APIServer]: We are trying to execute the function"); + (*this.*(it_method->second))(request); + request->send(200); +} + +void APIServer::addAPICommand(const std::string& url, + ArRequestHandlerFunction funct) { + useRouteHandler.emplace(std::move(url), funct); +} + +/** + * @brief Add a command handler to the API + * + * @param request + * @return \c void + * @note This function is called by the API server when a command is received + * @warning \c This function requires the user to access the index using a url + * parameter \c we need to fix this!! I need a better implemenation + * + */ +void APIServer::handle_user_commands(AsyncWebServerRequest* request) { + std::string url = request->pathArg(1).c_str(); + auto it = useRouteHandler.find(url); + if (it != useRouteHandler.end()) { + log_d("[APIServer]: We are trying to execute the function"); + it->second(request); + return; + } + log_e("[APIServer]: Invalid Command"); + request->send(400, MIMETYPE_JSON, "{\"msg\":\"Invalid Command\"}"); +} + +void APIServer::setupCaptivePortal(bool apMode) { + log_d("[SETUP Captive Portal]: Starting Captive Portal"); + log_d("[SETUP Captive Portal]: AP Mode: %s", + apMode ? "enabled" : "disabled"); + async_server.server.addHandler(new CaptiveRequestHandler(async_server)) + .setFilter(apMode ? ON_AP_FILTER : ON_STA_FILTER); +} + +//********************************************************************************************* +//! API Utilities +//********************************************************************************************* + +CaptiveRequestHandler::CaptiveRequestHandler(AsyncServer_t& async_server) + : async_server(async_server) {} + +CaptiveRequestHandler::~CaptiveRequestHandler() {} + +bool CaptiveRequestHandler::canHandle(AsyncWebServerRequest* request) { + // request->addInterestingHeader("ANY"); + return true; +} + +void CaptiveRequestHandler::handleRequest(AsyncWebServerRequest* request) { + if (async_server.spiffsMounted) { + if (async_server.custom_html_files.size() > 0) { + AsyncResponseStream* response_stream = + request->beginResponseStream("text/html"); + for (auto& file : async_server.custom_html_files) { + if (file.endpoint == "captive_portal" || + file.endpoint == "captive_portal.html" || + file.endpoint == "/" || file.endpoint == "/index.html" || + file.endpoint == "/index" || + file.endpoint == "portal.html") { + response_stream->print(file.file.c_str()); + } + } + request->send(response_stream); + return; + } + } + + AsyncWebServerResponse* response = request->beginResponse_P( + 200, "text/html", WEB_MANAGER_HTML, WEB_MANAGER_HTML_SIZE); + response->addHeader("Content-Encoding", "gzip"); + request->send(response); } \ No newline at end of file diff --git a/NetworkManager/src/api/server.cpp b/NetworkManager/src/api/server.cpp index 4e4384a..2b07ae0 100644 --- a/NetworkManager/src/api/server.cpp +++ b/NetworkManager/src/api/server.cpp @@ -1,99 +1,99 @@ -#include - -AsyncServer_t::AsyncServer_t(const int CONTROL_PORT, - ProjectConfig& configManager, - const std::string& api_url, - const std::string& wifimanager_url, - const std::string& user_commands, - const std::string& json_url) - : server(CONTROL_PORT), - configManager(configManager), - api_url(std::move(api_url)), - wifimanager_url(std::move(wifimanager_url)), - user_commands(std::move(user_commands)), - json_url(std::move(json_url)), - spiffsMounted(false) {} -AsyncServer_t::~AsyncServer_t() {} - -void AsyncServer_t::begin() { - // TODO: Migrate to LittleFS - spiffsMounted = initSPIFFS(); - - server.on("/", XHTTP_GET, - [&](AsyncWebServerRequest* request) { request->send(200); }); - -#ifdef USE_WEBMANAGER - server.on(wifimanager_url.c_str(), XHTTP_GET, - [&](AsyncWebServerRequest* request) { - // TODO: add authentication support - /* if (_authRequired) { - if (!request->authenticate(_username.c_str(), - _password.c_str())) { - return request->requestAuthentication(); - } - } */ - AsyncWebServerResponse* response = request->beginResponse_P( - 200, "text/html", WEB_MANAGER_HTML, - WEB_MANAGER_HTML_SIZE); - response->addHeader("Content-Encoding", "gzip"); - request->send(response); - }); -#endif // USE_WEBManager - - // preflight cors check - server.on("/", XHTTP_OPTIONS, [&](AsyncWebServerRequest* request) { - AsyncWebServerResponse* response = request->beginResponse(204); - response->addHeader("Access-Control-Allow-Methods", - "PUT,POST,GET,OPTIONS"); - response->addHeader("Access-Control-Allow-Headers", - "Accept, Content-Type, Authorization, FileSize"); - response->addHeader("Access-Control-Allow-Credentials", "true"); - request->send(response); - }); - - DefaultHeaders::Instance().addHeader("Access-Control-Allow-Origin", "*"); - - server.onNotFound( - [&](AsyncWebServerRequest* request) { notFound(request); }); - - if (!spiffsMounted && custom_html_files.size() <= 0) { - log_e( - "SPIFFS not initialized - no user defined html files available. " - "API will still function, no custom html files have been loaded. " - "\n"); - return; - } - - for (auto& route : custom_html_files) { - server.on(route.endpoint.c_str(), _networkMethodsMap_inv[route.method], - [&](AsyncWebServerRequest* request) { - // TODO: add authentication support - /* if (_authRequired) { - if (!request->authenticate(_username.c_str(), - _password.c_str())) - { return request->requestAuthentication(); - } - } */ - request->send(SPIFFS, route.file.c_str(), MIMETYPE_HTML); - }); - } - /* server.serveStatic(wifimanager_url.c_str(), SPIFFS, - "/wifimanager.html") .setCacheControl("max-age=600"); */ -} - -void AsyncServer_t::notFound(AsyncWebServerRequest* request) const { - if (_networkMethodsMap.find(request->method()) != - _networkMethodsMap.end()) { - log_i("%s: http://%s%s/\n", - _networkMethodsMap.at(request->method()).c_str(), - request->host().c_str(), request->url().c_str()); - char buffer[100]; - snprintf(buffer, sizeof(buffer), "Request %s Not found: %s", - _networkMethodsMap.at(request->method()).c_str(), - request->url().c_str()); - request->send(404, "text/plain", buffer); - } else { - request->send(404, "text/plain", - "Request Not found using unknown method"); - } -} +#include + +AsyncServer_t::AsyncServer_t(const int CONTROL_PORT, + ProjectConfig& configManager, + const std::string& api_url, + const std::string& wifimanager_url, + const std::string& user_commands, + const std::string& json_url) + : server(CONTROL_PORT), + configManager(configManager), + api_url(std::move(api_url)), + wifimanager_url(std::move(wifimanager_url)), + user_commands(std::move(user_commands)), + json_url(std::move(json_url)), + spiffsMounted(false) {} +AsyncServer_t::~AsyncServer_t() {} + +void AsyncServer_t::begin() { + // TODO: Migrate to LittleFS + spiffsMounted = initSPIFFS(); + + server.on("/", XHTTP_GET, + [&](AsyncWebServerRequest* request) { request->send(200); }); + +#ifdef USE_WEBMANAGER + server.on(wifimanager_url.c_str(), XHTTP_GET, + [&](AsyncWebServerRequest* request) { + // TODO: add authentication support + /* if (_authRequired) { + if (!request->authenticate(_username.c_str(), + _password.c_str())) { + return request->requestAuthentication(); + } + } */ + AsyncWebServerResponse* response = request->beginResponse_P( + 200, "text/html", WEB_MANAGER_HTML, + WEB_MANAGER_HTML_SIZE); + response->addHeader("Content-Encoding", "gzip"); + request->send(response); + }); +#endif // USE_WEBManager + + // preflight cors check + server.on("/", XHTTP_OPTIONS, [&](AsyncWebServerRequest* request) { + AsyncWebServerResponse* response = request->beginResponse(204); + response->addHeader("Access-Control-Allow-Methods", + "PUT,POST,GET,OPTIONS"); + response->addHeader("Access-Control-Allow-Headers", + "Accept, Content-Type, Authorization, FileSize"); + response->addHeader("Access-Control-Allow-Credentials", "true"); + request->send(response); + }); + + DefaultHeaders::Instance().addHeader("Access-Control-Allow-Origin", "*"); + + server.onNotFound( + [&](AsyncWebServerRequest* request) { notFound(request); }); + + if (!spiffsMounted && custom_html_files.size() <= 0) { + log_e( + "SPIFFS not initialized - no user defined html files available. " + "API will still function, no custom html files have been loaded. " + "\n"); + return; + } + + for (auto& route : custom_html_files) { + server.on(route.endpoint.c_str(), _networkMethodsMap_inv[route.method], + [&](AsyncWebServerRequest* request) { + // TODO: add authentication support + /* if (_authRequired) { + if (!request->authenticate(_username.c_str(), + _password.c_str())) + { return request->requestAuthentication(); + } + } */ + request->send(SPIFFS, route.file.c_str(), MIMETYPE_HTML); + }); + } + /* server.serveStatic(wifimanager_url.c_str(), SPIFFS, + "/wifimanager.html") .setCacheControl("max-age=600"); */ +} + +void AsyncServer_t::notFound(AsyncWebServerRequest* request) const { + if (_networkMethodsMap.find(request->method()) != + _networkMethodsMap.end()) { + log_i("%s: http://%s%s/\n", + _networkMethodsMap.at(request->method()).c_str(), + request->host().c_str(), request->url().c_str()); + char buffer[100]; + snprintf(buffer, sizeof(buffer), "Request %s Not found: %s", + _networkMethodsMap.at(request->method()).c_str(), + request->url().c_str()); + request->send(404, "text/plain", buffer); + } else { + request->send(404, "text/plain", + "Request Not found using unknown method"); + } +} diff --git a/NetworkManager/src/data/config/config_handler.cpp b/NetworkManager/src/data/config/config_handler.cpp index 4366202..cf1d360 100644 --- a/NetworkManager/src/data/config/config_handler.cpp +++ b/NetworkManager/src/data/config/config_handler.cpp @@ -1,27 +1,27 @@ -#include - -ConfigHandler::ConfigHandler(const std::string& configName, - const std::string& mdnsName) - : config(std::move(configName), std::move(mdnsName)) { - this->setID(static_cast( - ProjectConfigEventIDs_e::ProjectConfigEventID_ConfigHandler)); - this->setLabel("ConfigHandler"); -} - -ConfigHandler::~ConfigHandler() {} - -void ConfigHandler::begin() { - config.load(); -} - -void ConfigHandler::update(const StateVariant& event) { - updateStateWrapper(event, [this](Event_e _event) { - switch (_event) { - case Event_e::configSaved: - this->begin(); - break; - default: - break; - } - }); -} +#include + +ConfigHandler::ConfigHandler(const std::string& configName, + const std::string& mdnsName) + : config(std::move(configName), std::move(mdnsName)) { + this->setID(static_cast( + ProjectConfigEventIDs_e::ProjectConfigEventID_ConfigHandler)); + this->setLabel("ConfigHandler"); +} + +ConfigHandler::~ConfigHandler() {} + +void ConfigHandler::begin() { + config.load(); +} + +void ConfigHandler::update(const StateVariant& event) { + updateStateWrapper(event, [this](Event_e _event) { + switch (_event) { + case Event_e::configSaved: + this->begin(); + break; + default: + break; + } + }); +} diff --git a/NetworkManager/src/data/config/project_config.cpp b/NetworkManager/src/data/config/project_config.cpp index 75225af..d9b9139 100644 --- a/NetworkManager/src/data/config/project_config.cpp +++ b/NetworkManager/src/data/config/project_config.cpp @@ -1,455 +1,455 @@ -#include - -ProjectConfig::ProjectConfig(const std::string& configName, - const std::string& mdnsName) - : _configName(std::move(configName)), - _mdnsName(std::move(mdnsName)), - _already_loaded(false) { - this->setLabel("ProjectConfig"); -} - -ProjectConfig::~ProjectConfig() { - this->detachAll(); -} - -void ProjectConfig::initConfig() { - if (_configName.empty()) { - log_e("Config name is null\n"); - _configName = "easynetwork"; - } - - bool success = begin(_configName.c_str()); - - if (_mdnsName.empty()) { - log_e( - "MDNS name is null\n Auto-assigning name to " - "'easynetwork'"); - _mdnsName = "easynetwork"; - } - - this->config.mdns.hostname.assign(_mdnsName); - - log_i("MDNS name: %s", _mdnsName.c_str()); - log_i("Config name: %s", _configName.c_str()); - log_i("Config loaded: %s", success ? "true" : "false"); -} - -void ProjectConfig::deviceConfigSave() { - /* Device Config */ - putString(this->config.device.keys.ota_login.c_str(), - this->config.device.ota_login.c_str()); - putString(this->config.device.keys.ota_password.c_str(), - this->config.device.ota_password.c_str()); - putInt(this->config.device.keys.ota_port.c_str(), - this->config.device.ota_port); - //! No need to save the JSON strings or bools, they are generated and used - //! on the fly -} - -void ProjectConfig::mdnsConfigSave() { - /* MDNS Config */ - putString(this->config.mdns.keys.hostname.c_str(), - this->config.mdns.hostname.c_str()); -} - -void ProjectConfig::wifiConfigSave() { - /* WiFi Config */ - putInt(this->config.wifKeys.networkCount.c_str(), - this->config.networks.size()); - for (int i = 0; i < this->config.networks.size(); i++) { - char buffer[2]; - std::string iter_str = Helpers::itoa(i, buffer, 10); - - std::string name = this->config.wifKeys.name; - std::string ssid = this->config.wifKeys.ssid; - std::string password = this->config.wifKeys.password; - std::string channel = this->config.wifKeys.channel; - std::string power = this->config.wifKeys.power; - - name.append(iter_str); - ssid.append(iter_str); - password.append(iter_str); - channel.append(iter_str); - power.append(iter_str); - - putString(name.c_str(), this->config.networks[i].name.c_str()); - putString(ssid.c_str(), this->config.networks[i].ssid.c_str()); - putString(password.c_str(), this->config.networks[i].password.c_str()); - putUInt(channel.c_str(), this->config.networks[i].channel); - putUInt(power.c_str(), this->config.networks[i].power); - } - - /* AP Config */ - putString(this->config.ap_network.keys.ssid.c_str(), - this->config.ap_network.ssid.c_str()); - putString(this->config.ap_network.keys.password.c_str(), - this->config.ap_network.password.c_str()); - putUInt(this->config.ap_network.keys.channel.c_str(), - this->config.ap_network.channel); -} - -void ProjectConfig::wifiTxPowerConfigSave() { - /* Device Config */ - putInt("power", this->config.wifi_tx_power.power); -} - -void ProjectConfig::save() { - log_d("Saving project config"); - - deviceConfigSave(); - wifiConfigSave(); - wifiTxPowerConfigSave(); - mdnsConfigSave(); - - /* Custom save */ - if (_custom_config_interface != nullptr) - _custom_config_interface->save(); - - int initialTime = millis(); - while (millis() - initialTime <= 2000) { - continue; - } - - // Close NVS - end(); - - if (this->reboot) { - log_i("Project config saved and system is rebooting"); - ESP.restart(); - return; - } - - log_w("Reboot is disabled, triggering observer"); - this->_already_loaded = false; - this->notifyAll(Event_e::configSaved); -} - -bool ProjectConfig::reset() { - log_w("Resetting project config"); - return clear(); -} - -void ProjectConfig::load() { - log_d("Loading project config"); - - if (this->_already_loaded) { - log_w("Project config already loaded"); - return; - } - - initConfig(); - - /* Custom Load */ - if (_custom_config_interface != nullptr) - _custom_config_interface->load(); - - /* MDNS Config */ - this->config.mdns.hostname.assign( - getString(this->config.mdns.keys.hostname.c_str(), _mdnsName.c_str()) - .c_str()); - - /* Device Config */ - this->config.device.ota_login.assign( - getString(this->config.device.keys.ota_login.c_str(), "admin").c_str()); - this->config.device.ota_password.assign( - getString(this->config.device.keys.ota_password.c_str(), "12345678") - .c_str()); - this->config.device.ota_port = - getInt(this->config.device.keys.ota_port.c_str(), 3232); - - /* Wifi TX Power Config */ - this->config.wifi_tx_power.power = - getUInt(this->config.wifKeys.power.c_str(), 52); - - /* WiFi Config */ - int networkCount = getInt("networkCount", 0); - std::string name = this->config.wifKeys.name; - std::string ssid = this->config.wifKeys.ssid; - std::string password = this->config.wifKeys.password; - std::string channel = this->config.wifKeys.channel; - std::string power = this->config.wifKeys.power; - - for (int i = 0; i < networkCount; i++) { - char buffer[2]; - std::string iter_str = Helpers::itoa(i, buffer, 10); - - name.append(iter_str); - ssid.append(iter_str); - password.append(iter_str); - channel.append(iter_str); - power.append(iter_str); - - const std::string& temp_1 = getString(name.c_str()).c_str(); - const std::string& temp_2 = getString(ssid.c_str()).c_str(); - const std::string& temp_3 = getString(password.c_str()).c_str(); - uint8_t temp_4 = getUInt(channel.c_str()); - uint8_t temp_5 = getUInt(power.c_str()); - - //! push_back creates a copy of the object, so we need to use - //! emplace_back - this->config.networks.emplace_back( - temp_1, temp_2, temp_3, temp_4, temp_5, - false); // false because the networks we store in the config are - // the ones we want the esp to connect to, rather than host - // as AP - } - - /* AP Config */ - this->config.ap_network.ssid.assign( - getString(this->config.ap_network.keys.ssid.c_str(), _mdnsName.c_str()) - .c_str()); - this->config.ap_network.password.assign( - getString(this->config.ap_network.keys.password.c_str(), "12345678") - .c_str()); - this->config.ap_network.channel = - getUInt(this->config.ap_network.keys.channel.c_str(), 1); - - this->_already_loaded = true; - this->notifyAll(Event_e::configLoaded); -} - -//********************************************************************************************************************** -//* -//! Setters -//* -//********************************************************************************************************************** -void ProjectConfig::setDeviceConfig(const std::string& ota_pass, int ota_port, - bool shouldNotify) { - log_d("Updating device config"); - this->config.device.ota_password.assign(ota_pass); - this->config.device.ota_port = ota_port; - - if (shouldNotify) { - this->notifyAll(Event_e::deviceConfigUpdated); - } -} - -bool ProjectConfig::setMDNSConfig(const std::string& hostname, - bool shouldNotify) { - log_d("Updating MDNS config"); - for (int i = 0; i < this->config.mdns.hostname.size(); i++) { - if (this->config.mdns.hostname[i] == '-' || - this->config.mdns.hostname[i] == '.') - continue; - else if (this->config.mdns.hostname[i] >= '0' && - this->config.mdns.hostname[i] <= '9') - continue; - else if (this->config.mdns.hostname[i] >= 'A' && - this->config.mdns.hostname[i] <= 'Z') - continue; - else if (this->config.mdns.hostname[i] >= 'a' && - this->config.mdns.hostname[i] <= 'z') - continue; - else if (this->config.mdns.hostname[i] == 0 && i > 0) - break; - log_i( - "Invalid hostname, please use only alphanumeric " - "characters"); - return false; - } - this->config.mdns.hostname.assign(hostname); - - if (shouldNotify) - this->notifyAll(Event_e::mdnsConfigUpdated); - return true; -} - -void ProjectConfig::setWifiConfig(const std::string& networkName, - const std::string& ssid, - const std::string& password, uint8_t channel, - uint8_t power, bool adhoc, bool shouldNotify, - bool shouldReboot) { - // we store the ADHOC flag as false because the networks we store in the - // config are the ones we want the esp to connect to, rather than host as - // AP, and here we're just updating them - size_t size = this->config.networks.size(); - auto wifiHandler = static_cast( - ProjectConfigEventIDs_e::ProjectConfigEventID_WifiHandler); - - for (auto it = this->config.networks.begin(); - it != this->config.networks.end();) { - if (it->ssid == ssid) { - log_i("Found network %s, updating it ...", it->name.c_str()); - - it->name = networkName; - it->ssid = ssid; - it->password = password; - it->channel = channel; - it->power = power; - it->adhoc = false; - - if (shouldNotify) { - this->notify(wifiHandler, WiFiState_e::WiFiState_Disconnected); - WiFi.disconnect(); - this->wifiConfigSave(); - this->notify(wifiHandler, Event_e::networksConfigUpdated); - } - - return; - } else { - ++it; - } - } - - if (size < 3 && size > 0) { - this->log("We're adding a new network"); - // we don't have that network yet, we can add it as we still have some - // space we're using emplace_back as push_back will create a copy of it, - // we want to avoid that - this->config.networks.emplace_back(networkName, ssid, password, channel, - power, false); - } - - // we're allowing to store up to three additional networks - if (size == 0) { - this->log("No networks, We're adding a new network"); - this->config.networks.emplace_back(networkName, ssid, password, channel, - power, false); - } - - if (shouldNotify) { - this->notify(wifiHandler, WiFiState_e::WiFiState_Disconnected); - WiFi.disconnect(); - this->wifiConfigSave(); - this->notify(wifiHandler, Event_e::networksConfigUpdated); - } - - if (shouldReboot) { - this->reboot = true; - } -} - -void ProjectConfig::deleteWifiConfig(const std::string& networkName, - bool shouldNotify) { - size_t size = this->config.networks.size(); - if (size == 0) { - this->log("No networks, nothing to delete"); - } - - for (auto it = this->config.networks.begin(); - it != this->config.networks.end();) { - if (it->name == networkName) { - log_i("Found network %s", it->name.c_str()); - it = this->config.networks.erase(it); - log_i("Deleted network %s", networkName.c_str()); - - } else { - ++it; - } - } - - if (shouldNotify) - this->notifyAll(Event_e::networksConfigUpdated); -} - -void ProjectConfig::setAPWifiConfig(const std::string& ssid, - const std::string& password, - uint8_t channel, bool adhoc, - bool shouldNotify) { - this->config.ap_network.ssid.assign(ssid); - this->config.ap_network.password.assign(password); - this->config.ap_network.channel = channel; - this->config.ap_network.adhoc = adhoc; - - log_d("Updating access point config"); - if (shouldNotify) { - this->notifyAll(Event_e::apConfigUpdated); - } -} - -void ProjectConfig::setWiFiTxPower(uint8_t power, bool shouldNotify) { - this->config.wifi_tx_power.power = power; - - log_d("Updating wifi tx power"); - if (shouldNotify) - this->notifyAll(Event_e::wifiTxPowerUpdated); -} - -void ProjectConfig::setDeviceDataJson(const std::string& data, - bool shouldNotify) { - this->config.device_data.deviceJson.assign(data); - - log_d("Updating device data json"); - if (shouldNotify) - this->notifyAll(Event_e::deviceDataJsonUpdated); -} - -std::string Project_Config::DeviceConfig_t::toRepresentation() { - std::string json = Helpers::format_string( - "\"device_config\": {\"ota_login\": \"%s\",\"ota_pass\": \"%s\", " - "\"ota_port\": %u}", - this->ota_login.c_str(), this->ota_password.c_str(), this->ota_port); - return json; -} - -std::string Project_Config::MDNSConfig_t::toRepresentation() { - std::string json = Helpers::format_string( - "\"mdns_config\": {\"hostname\": \"%s\"}", this->hostname.c_str()); - return json; -} - -std::string Project_Config::WiFiConfig_t::toRepresentation() { - std::string json = Helpers::format_string( - "{\"name\": \"%s\", \"ssid\": \"%s\", \"password\": \"%s\", " - "\"channel\": %u, \"power\": %u, \"adhoc\": %s}", - this->name.c_str(), this->ssid.c_str(), this->password.c_str(), - this->channel, this->power, this->adhoc ? "true" : "false"); - return json; -} - -std::string Project_Config::AP_WiFiConfig_t::toRepresentation() { - std::string json = Helpers::format_string( - "\"ap_wifi_config\": {\"ssid\": \"%s\", \"password\": \"%s\", " - "\"channel\": %u, \"adhoc\": %s}", - this->ssid.c_str(), this->password.c_str(), this->channel, - this->adhoc ? "true" : "false"); - return json; -} - -std::string Project_Config::WiFiTxPower_t::toRepresentation() { - std::string json = Helpers::format_string( - "\"wifi_tx_power\": {\"power\": %u}", this->power); - return json; -} - -std::string Project_Config::DeviceDataJson_t::toRepresentation() { - std::string json = Helpers::format_string( - "\"deviceData\": {\"data\": \"%s\"}", this->deviceJson.c_str()); - return json; -} - -//********************************************************************************************************************** -//* -//! GetMethods -//* -//********************************************************************************************************************** - -Project_Config::DeviceConfig_t& ProjectConfig::getDeviceConfig() { - return this->config.device; -} -Project_Config::MDNSConfig_t& ProjectConfig::getMDNSConfig() { - return this->config.mdns; -} -std::vector& ProjectConfig::getWifiConfigs() { - return this->config.networks; -} -Project_Config::AP_WiFiConfig_t& ProjectConfig::getAPWifiConfig() { - return this->config.ap_network; -} -Project_Config::WiFiTxPower_t& ProjectConfig::getWifiTxPowerConfig() { - return this->config.wifi_tx_power; -} -Project_Config::DeviceDataJson_t& ProjectConfig::getDeviceDataJson() { - return this->config.device_data; -} - -//********************************************************************************************************************** -//* -//! callbacks -//* -//********************************************************************************************************************** - -void ProjectConfig::registerUserConfig( - _custom_config_interface_t custom_config_interface) { - this->_custom_config_interface = custom_config_interface; -} +#include + +ProjectConfig::ProjectConfig(const std::string& configName, + const std::string& mdnsName) + : _configName(std::move(configName)), + _mdnsName(std::move(mdnsName)), + _already_loaded(false) { + this->setLabel("ProjectConfig"); +} + +ProjectConfig::~ProjectConfig() { + this->detachAll(); +} + +void ProjectConfig::initConfig() { + if (_configName.empty()) { + log_e("Config name is null\n"); + _configName = "easynetwork"; + } + + bool success = begin(_configName.c_str()); + + if (_mdnsName.empty()) { + log_e( + "MDNS name is null\n Auto-assigning name to " + "'easynetwork'"); + _mdnsName = "easynetwork"; + } + + this->config.mdns.hostname.assign(_mdnsName); + + log_i("MDNS name: %s", _mdnsName.c_str()); + log_i("Config name: %s", _configName.c_str()); + log_i("Config loaded: %s", success ? "true" : "false"); +} + +void ProjectConfig::deviceConfigSave() { + /* Device Config */ + putString(this->config.device.keys.ota_login.c_str(), + this->config.device.ota_login.c_str()); + putString(this->config.device.keys.ota_password.c_str(), + this->config.device.ota_password.c_str()); + putInt(this->config.device.keys.ota_port.c_str(), + this->config.device.ota_port); + //! No need to save the JSON strings or bools, they are generated and used + //! on the fly +} + +void ProjectConfig::mdnsConfigSave() { + /* MDNS Config */ + putString(this->config.mdns.keys.hostname.c_str(), + this->config.mdns.hostname.c_str()); +} + +void ProjectConfig::wifiConfigSave() { + /* WiFi Config */ + putInt(this->config.wifKeys.networkCount.c_str(), + this->config.networks.size()); + for (int i = 0; i < this->config.networks.size(); i++) { + char buffer[2]; + std::string iter_str = Helpers::itoa(i, buffer, 10); + + std::string name = this->config.wifKeys.name; + std::string ssid = this->config.wifKeys.ssid; + std::string password = this->config.wifKeys.password; + std::string channel = this->config.wifKeys.channel; + std::string power = this->config.wifKeys.power; + + name.append(iter_str); + ssid.append(iter_str); + password.append(iter_str); + channel.append(iter_str); + power.append(iter_str); + + putString(name.c_str(), this->config.networks[i].name.c_str()); + putString(ssid.c_str(), this->config.networks[i].ssid.c_str()); + putString(password.c_str(), this->config.networks[i].password.c_str()); + putUInt(channel.c_str(), this->config.networks[i].channel); + putUInt(power.c_str(), this->config.networks[i].power); + } + + /* AP Config */ + putString(this->config.ap_network.keys.ssid.c_str(), + this->config.ap_network.ssid.c_str()); + putString(this->config.ap_network.keys.password.c_str(), + this->config.ap_network.password.c_str()); + putUInt(this->config.ap_network.keys.channel.c_str(), + this->config.ap_network.channel); +} + +void ProjectConfig::wifiTxPowerConfigSave() { + /* Device Config */ + putInt("power", this->config.wifi_tx_power.power); +} + +void ProjectConfig::save() { + log_d("Saving project config"); + + deviceConfigSave(); + wifiConfigSave(); + wifiTxPowerConfigSave(); + mdnsConfigSave(); + + /* Custom save */ + if (_custom_config_interface != nullptr) + _custom_config_interface->save(); + + int initialTime = millis(); + while (millis() - initialTime <= 2000) { + continue; + } + + // Close NVS + end(); + + if (this->reboot) { + log_i("Project config saved and system is rebooting"); + ESP.restart(); + return; + } + + log_w("Reboot is disabled, triggering observer"); + this->_already_loaded = false; + this->notifyAll(Event_e::configSaved); +} + +bool ProjectConfig::reset() { + log_w("Resetting project config"); + return clear(); +} + +void ProjectConfig::load() { + log_d("Loading project config"); + + if (this->_already_loaded) { + log_w("Project config already loaded"); + return; + } + + initConfig(); + + /* Custom Load */ + if (_custom_config_interface != nullptr) + _custom_config_interface->load(); + + /* MDNS Config */ + this->config.mdns.hostname.assign( + getString(this->config.mdns.keys.hostname.c_str(), _mdnsName.c_str()) + .c_str()); + + /* Device Config */ + this->config.device.ota_login.assign( + getString(this->config.device.keys.ota_login.c_str(), "admin").c_str()); + this->config.device.ota_password.assign( + getString(this->config.device.keys.ota_password.c_str(), "12345678") + .c_str()); + this->config.device.ota_port = + getInt(this->config.device.keys.ota_port.c_str(), 3232); + + /* Wifi TX Power Config */ + this->config.wifi_tx_power.power = + getUInt(this->config.wifKeys.power.c_str(), 52); + + /* WiFi Config */ + int networkCount = getInt("networkCount", 0); + std::string name = this->config.wifKeys.name; + std::string ssid = this->config.wifKeys.ssid; + std::string password = this->config.wifKeys.password; + std::string channel = this->config.wifKeys.channel; + std::string power = this->config.wifKeys.power; + + for (int i = 0; i < networkCount; i++) { + char buffer[2]; + std::string iter_str = Helpers::itoa(i, buffer, 10); + + name.append(iter_str); + ssid.append(iter_str); + password.append(iter_str); + channel.append(iter_str); + power.append(iter_str); + + const std::string& temp_1 = getString(name.c_str()).c_str(); + const std::string& temp_2 = getString(ssid.c_str()).c_str(); + const std::string& temp_3 = getString(password.c_str()).c_str(); + uint8_t temp_4 = getUInt(channel.c_str()); + uint8_t temp_5 = getUInt(power.c_str()); + + //! push_back creates a copy of the object, so we need to use + //! emplace_back + this->config.networks.emplace_back( + temp_1, temp_2, temp_3, temp_4, temp_5, + false); // false because the networks we store in the config are + // the ones we want the esp to connect to, rather than host + // as AP + } + + /* AP Config */ + this->config.ap_network.ssid.assign( + getString(this->config.ap_network.keys.ssid.c_str(), _mdnsName.c_str()) + .c_str()); + this->config.ap_network.password.assign( + getString(this->config.ap_network.keys.password.c_str(), "12345678") + .c_str()); + this->config.ap_network.channel = + getUInt(this->config.ap_network.keys.channel.c_str(), 1); + + this->_already_loaded = true; + this->notifyAll(Event_e::configLoaded); +} + +//********************************************************************************************************************** +//* +//! Setters +//* +//********************************************************************************************************************** +void ProjectConfig::setDeviceConfig(const std::string& ota_pass, int ota_port, + bool shouldNotify) { + log_d("Updating device config"); + this->config.device.ota_password.assign(ota_pass); + this->config.device.ota_port = ota_port; + + if (shouldNotify) { + this->notifyAll(Event_e::deviceConfigUpdated); + } +} + +bool ProjectConfig::setMDNSConfig(const std::string& hostname, + bool shouldNotify) { + log_d("Updating MDNS config"); + for (int i = 0; i < this->config.mdns.hostname.size(); i++) { + if (this->config.mdns.hostname[i] == '-' || + this->config.mdns.hostname[i] == '.') + continue; + else if (this->config.mdns.hostname[i] >= '0' && + this->config.mdns.hostname[i] <= '9') + continue; + else if (this->config.mdns.hostname[i] >= 'A' && + this->config.mdns.hostname[i] <= 'Z') + continue; + else if (this->config.mdns.hostname[i] >= 'a' && + this->config.mdns.hostname[i] <= 'z') + continue; + else if (this->config.mdns.hostname[i] == 0 && i > 0) + break; + log_i( + "Invalid hostname, please use only alphanumeric " + "characters"); + return false; + } + this->config.mdns.hostname.assign(hostname); + + if (shouldNotify) + this->notifyAll(Event_e::mdnsConfigUpdated); + return true; +} + +void ProjectConfig::setWifiConfig(const std::string& networkName, + const std::string& ssid, + const std::string& password, uint8_t channel, + uint8_t power, bool adhoc, bool shouldNotify, + bool shouldReboot) { + // we store the ADHOC flag as false because the networks we store in the + // config are the ones we want the esp to connect to, rather than host as + // AP, and here we're just updating them + size_t size = this->config.networks.size(); + auto wifiHandler = static_cast( + ProjectConfigEventIDs_e::ProjectConfigEventID_WifiHandler); + + for (auto it = this->config.networks.begin(); + it != this->config.networks.end();) { + if (it->ssid == ssid) { + log_i("Found network %s, updating it ...", it->name.c_str()); + + it->name = networkName; + it->ssid = ssid; + it->password = password; + it->channel = channel; + it->power = power; + it->adhoc = false; + + if (shouldNotify) { + this->notify(wifiHandler, WiFiState_e::WiFiState_Disconnected); + WiFi.disconnect(); + this->wifiConfigSave(); + this->notify(wifiHandler, Event_e::networksConfigUpdated); + } + + return; + } else { + ++it; + } + } + + if (size < 3 && size > 0) { + this->log("We're adding a new network"); + // we don't have that network yet, we can add it as we still have some + // space we're using emplace_back as push_back will create a copy of it, + // we want to avoid that + this->config.networks.emplace_back(networkName, ssid, password, channel, + power, false); + } + + // we're allowing to store up to three additional networks + if (size == 0) { + this->log("No networks, We're adding a new network"); + this->config.networks.emplace_back(networkName, ssid, password, channel, + power, false); + } + + if (shouldNotify) { + this->notify(wifiHandler, WiFiState_e::WiFiState_Disconnected); + WiFi.disconnect(); + this->wifiConfigSave(); + this->notify(wifiHandler, Event_e::networksConfigUpdated); + } + + if (shouldReboot) { + this->reboot = true; + } +} + +void ProjectConfig::deleteWifiConfig(const std::string& networkName, + bool shouldNotify) { + size_t size = this->config.networks.size(); + if (size == 0) { + this->log("No networks, nothing to delete"); + } + + for (auto it = this->config.networks.begin(); + it != this->config.networks.end();) { + if (it->name == networkName) { + log_i("Found network %s", it->name.c_str()); + it = this->config.networks.erase(it); + log_i("Deleted network %s", networkName.c_str()); + + } else { + ++it; + } + } + + if (shouldNotify) + this->notifyAll(Event_e::networksConfigUpdated); +} + +void ProjectConfig::setAPWifiConfig(const std::string& ssid, + const std::string& password, + uint8_t channel, bool adhoc, + bool shouldNotify) { + this->config.ap_network.ssid.assign(ssid); + this->config.ap_network.password.assign(password); + this->config.ap_network.channel = channel; + this->config.ap_network.adhoc = adhoc; + + log_d("Updating access point config"); + if (shouldNotify) { + this->notifyAll(Event_e::apConfigUpdated); + } +} + +void ProjectConfig::setWiFiTxPower(uint8_t power, bool shouldNotify) { + this->config.wifi_tx_power.power = power; + + log_d("Updating wifi tx power"); + if (shouldNotify) + this->notifyAll(Event_e::wifiTxPowerUpdated); +} + +void ProjectConfig::setDeviceDataJson(const std::string& data, + bool shouldNotify) { + this->config.device_data.deviceJson.assign(data); + + log_d("Updating device data json"); + if (shouldNotify) + this->notifyAll(Event_e::deviceDataJsonUpdated); +} + +std::string Project_Config::DeviceConfig_t::toRepresentation() { + std::string json = Helpers::format_string( + "\"device_config\": {\"ota_login\": \"%s\",\"ota_pass\": \"%s\", " + "\"ota_port\": %u}", + this->ota_login.c_str(), this->ota_password.c_str(), this->ota_port); + return json; +} + +std::string Project_Config::MDNSConfig_t::toRepresentation() { + std::string json = Helpers::format_string( + "\"mdns_config\": {\"hostname\": \"%s\"}", this->hostname.c_str()); + return json; +} + +std::string Project_Config::WiFiConfig_t::toRepresentation() { + std::string json = Helpers::format_string( + "{\"name\": \"%s\", \"ssid\": \"%s\", \"password\": \"%s\", " + "\"channel\": %u, \"power\": %u, \"adhoc\": %s}", + this->name.c_str(), this->ssid.c_str(), this->password.c_str(), + this->channel, this->power, this->adhoc ? "true" : "false"); + return json; +} + +std::string Project_Config::AP_WiFiConfig_t::toRepresentation() { + std::string json = Helpers::format_string( + "\"ap_wifi_config\": {\"ssid\": \"%s\", \"password\": \"%s\", " + "\"channel\": %u, \"adhoc\": %s}", + this->ssid.c_str(), this->password.c_str(), this->channel, + this->adhoc ? "true" : "false"); + return json; +} + +std::string Project_Config::WiFiTxPower_t::toRepresentation() { + std::string json = Helpers::format_string( + "\"wifi_tx_power\": {\"power\": %u}", this->power); + return json; +} + +std::string Project_Config::DeviceDataJson_t::toRepresentation() { + std::string json = Helpers::format_string( + "\"deviceData\": {\"data\": \"%s\"}", this->deviceJson.c_str()); + return json; +} + +//********************************************************************************************************************** +//* +//! GetMethods +//* +//********************************************************************************************************************** + +Project_Config::DeviceConfig_t& ProjectConfig::getDeviceConfig() { + return this->config.device; +} +Project_Config::MDNSConfig_t& ProjectConfig::getMDNSConfig() { + return this->config.mdns; +} +std::vector& ProjectConfig::getWifiConfigs() { + return this->config.networks; +} +Project_Config::AP_WiFiConfig_t& ProjectConfig::getAPWifiConfig() { + return this->config.ap_network; +} +Project_Config::WiFiTxPower_t& ProjectConfig::getWifiTxPowerConfig() { + return this->config.wifi_tx_power; +} +Project_Config::DeviceDataJson_t& ProjectConfig::getDeviceDataJson() { + return this->config.device_data; +} + +//********************************************************************************************************************** +//* +//! callbacks +//* +//********************************************************************************************************************** + +void ProjectConfig::registerUserConfig( + _custom_config_interface_t custom_config_interface) { + this->_custom_config_interface = custom_config_interface; +} diff --git a/NetworkManager/src/network/mdns/mdns_manager.cpp b/NetworkManager/src/network/mdns/mdns_manager.cpp index 62480d0..590e172 100644 --- a/NetworkManager/src/network/mdns/mdns_manager.cpp +++ b/NetworkManager/src/network/mdns/mdns_manager.cpp @@ -1,51 +1,51 @@ -#include - -MDNSHandler::MDNSHandler(ProjectConfig& configManager, - const std::string& service_name, - const std::string& service_text, - const std::string& proto, const std::string& key, - const std::string& value) - : configManager(configManager), - service_name(std::move(service_name)), - service_text(std::move(service_text)), - proto(std::move(proto)), - key(std::move(key)), - value(std::move(value)) { - this->setID(static_cast( - ProjectConfigEventIDs_e::ProjectConfigEventID_MDNSHandler)); - this->setLabel(this->service_name); -} - -bool MDNSHandler::begin() { - auto mdnsConfig = configManager.getMDNSConfig(); - log_d("%s", mdnsConfig.hostname.c_str()); - if (!MDNS.begin(mdnsConfig.hostname.c_str())) { - this->configManager.notifyAll(MDNSState_e::MDNSState_Error); - log_e("Error initializing MDNS"); - return false; - } - - this->configManager.notifyAll(MDNSState_e::MDNSState_Starting); - MDNS.addService(service_name.c_str(), proto.c_str(), atoi(value.c_str())); - MDNS.addServiceTxt( - service_name.c_str(), proto.c_str(), key.c_str(), - value.c_str()); // ex: "camera", "tcp", "stream_port", "80" - log_d("%s %s %s %s %s", service_name.c_str(), proto.c_str(), - service_text.c_str(), key.c_str(), value.c_str()); - log_i("MDNS initialized!"); - this->configManager.notifyAll(MDNSState_e::MDNSState_Started); - return true; -} - -void MDNSHandler::update(const StateVariant& event) { - updateStateWrapper(event, [this](Event_e _event) { - switch (_event) { - case Event_e::mdnsConfigUpdated: - MDNS.end(); - this->begin(); - break; - default: - break; - } - }); -} +#include + +MDNSHandler::MDNSHandler(ProjectConfig& configManager, + const std::string& service_name, + const std::string& service_text, + const std::string& proto, const std::string& key, + const std::string& value) + : configManager(configManager), + service_name(std::move(service_name)), + service_text(std::move(service_text)), + proto(std::move(proto)), + key(std::move(key)), + value(std::move(value)) { + this->setID(static_cast( + ProjectConfigEventIDs_e::ProjectConfigEventID_MDNSHandler)); + this->setLabel(this->service_name); +} + +bool MDNSHandler::begin() { + auto mdnsConfig = configManager.getMDNSConfig(); + log_d("%s", mdnsConfig.hostname.c_str()); + if (!MDNS.begin(mdnsConfig.hostname.c_str())) { + this->configManager.notifyAll(MDNSState_e::MDNSState_Error); + log_e("Error initializing MDNS"); + return false; + } + + this->configManager.notifyAll(MDNSState_e::MDNSState_Starting); + MDNS.addService(service_name.c_str(), proto.c_str(), atoi(value.c_str())); + MDNS.addServiceTxt( + service_name.c_str(), proto.c_str(), key.c_str(), + value.c_str()); // ex: "camera", "tcp", "stream_port", "80" + log_d("%s %s %s %s %s", service_name.c_str(), proto.c_str(), + service_text.c_str(), key.c_str(), value.c_str()); + log_i("MDNS initialized!"); + this->configManager.notifyAll(MDNSState_e::MDNSState_Started); + return true; +} + +void MDNSHandler::update(const StateVariant& event) { + updateStateWrapper(event, [this](Event_e _event) { + switch (_event) { + case Event_e::mdnsConfigUpdated: + MDNS.end(); + this->begin(); + break; + default: + break; + } + }); +} diff --git a/NetworkManager/src/network/wifihandler/wifi_handler.cpp b/NetworkManager/src/network/wifihandler/wifi_handler.cpp index 3e359ad..00ce8b1 100644 --- a/NetworkManager/src/network/wifihandler/wifi_handler.cpp +++ b/NetworkManager/src/network/wifihandler/wifi_handler.cpp @@ -1,223 +1,223 @@ -#include - -WiFiHandler::WiFiHandler(ProjectConfig& configManager, const std::string& ssid, - const std::string& password, uint8_t channel) - : configManager(configManager), - txpower(this->configManager.getWifiTxPowerConfig()), - ssid(ssid), - password(password), - channel(channel), - power(0), - _enable_adhoc(false) { - this->setID(static_cast( - ProjectConfigEventIDs_e::ProjectConfigEventID_MDNSHandler)); - this->setLabel("WiFiHandler"); -} - -WiFiHandler::~WiFiHandler() {} - -void WiFiHandler::begin() { - if (this->_enable_adhoc) { - this->configManager.notifyAll(WiFiState_e::WiFiState_ADHOC); - return; - } - WiFi.mode(WIFI_STA); - WiFi.onEvent( - std::bind(&WiFiHandler::onWiFiEvent, this, std::placeholders::_1)); - WiFi.setSleep(WIFI_PS_NONE); - - this->log("Initializing connection to wifi networks..."); - - auto networks = this->configManager.getWifiConfigs(); - - if (networks.empty()) { - this->log( - "No networks found in config, trying the " - "default one ..."); - if (this->iniSTA(this->ssid, this->password, this->channel, - (wifi_power_t)txpower.power)) { - return; - } - this->log( - "Could not connect to the hardcoded " - "network, setting up ADHOC network ..."); - this->log("WiFiState_ADHOC"); - this->setUpADHOC(); - return; - } - - for (auto networkIterator = networks.begin(); - networkIterator != networks.end(); ++networkIterator) { - if (this->iniSTA(networkIterator->ssid, networkIterator->password, - networkIterator->channel, - (wifi_power_t)networkIterator->power)) { - return; - } - } - - // at this point, we've tried every network, let's just - // setup adhoc - this->log( - "We've gone through every network, each timed out. " - "Trying to connect to the hardcoded network one last time: ", - this->ssid); - if (this->iniSTA(this->ssid, this->password, this->channel, - (wifi_power_t)txpower.power)) { - this->log( - "Successfully connected to the hardcoded " - "network."); - return; - } - this->log("WiFiState_ADHOC"); - this->setUpADHOC(); - log_e( - "Could not connect to the hardcoded network, " - "setting up adhoc. \n\r"); -} - -void WiFiHandler::adhoc(const std::string& ssid, uint8_t channel, - const std::string& password) { - this->log("Configuring access point...\n"); - WiFi.mode(WIFI_AP); - WiFi.setSleep(WIFI_PS_NONE); - this->log("Starting AP..."); - IPAddress IP = WiFi.softAPIP(); - this->log("AP IP address: ", IP.toString().c_str()); - // You can remove the password parameter if you want the - // AP to be open. - WiFi.softAP(ssid.c_str(), password.c_str(), - channel); // AP mode with password - WiFi.setTxPower((wifi_power_t)txpower.power); -} - -void WiFiHandler::setUpADHOC() { - this->log("Setting Access Point... "); - size_t ssidLen = this->configManager.getAPWifiConfig().ssid.length(); - size_t passwordLen = - this->configManager.getAPWifiConfig().password.length(); - if (ssidLen <= 0) { - this->adhoc("EasyNetworkManager", 1, "12345678"); - return; - } - - if (passwordLen <= 0) { - this->log( - "Configuring access point without a " - "password..."); - this->adhoc(this->configManager.getAPWifiConfig().ssid, - this->configManager.getAPWifiConfig().channel); - return; - } - - this->adhoc(this->configManager.getAPWifiConfig().ssid, - this->configManager.getAPWifiConfig().channel, - this->configManager.getAPWifiConfig().password); - this->log("Configuring access point..."); - log_d("\n[DEBUG]: ssid: %s\n", - this->configManager.getAPWifiConfig().ssid.c_str()); - log_d("\n[DEBUG]: password: %s\n", - this->configManager.getAPWifiConfig().password.c_str()); - log_d("\n[DEBUG]: channel: %d\n", - this->configManager.getAPWifiConfig().channel); -} - -bool WiFiHandler::iniSTA(const std::string& ssid, const std::string& password, - uint8_t channel, wifi_power_t power) { - unsigned long currentMillis = millis(); - unsigned long startingMillis = currentMillis; - int connectionTimeout = 30000; // 30 seconds - int progress = 0; - this->log("Trying to connect to: ", ssid); - auto mdnsConfig = this->configManager.getMDNSConfig(); - WiFi.config(INADDR_NONE, INADDR_NONE, INADDR_NONE, INADDR_NONE); - WiFi.setHostname(mdnsConfig.hostname.c_str()); - WiFi.begin(ssid.c_str(), password.c_str(), channel); - while (WiFi.status() != WL_CONNECTED) { - progress++; - currentMillis = millis(); - Helpers::update_progress_bar(progress, 100); - delay(300); - log_v("."); - if ((currentMillis - startingMillis) >= connectionTimeout) { - this->configManager.notifyAll(WiFiState_e::WiFiState_Error); - log_e("Connection to: %s TIMEOUT \n\r", ssid.c_str()); - delay(300); - return false; - } - } - - this->log("Successfully connected to ", ssid); - this->configManager.notifyAll(WiFiState_e::WiFiState_Connected); - // Serial.printf("Setting TX power to: %d \n\r", (uint8_t)power); - // WiFi.setTxPower(power); - - return true; -} - -void WiFiHandler::toggleAdhoc(bool enable) { - _enable_adhoc = enable; -} - -void WiFiHandler::update(const StateVariant& event) { - updateStateWrapper(event, [this](WiFiState_e _event) { - switch (_event) { - case WiFiState_e::WiFiState_Connecting: - this->log("WiFiState_Connecting"); - this->begin(); - break; - case WiFiState_e::WiFiState_Connected: - this->log("WiFiState_Connected"); - break; - case WiFiState_e::WiFiState_Disconnected: - this->log("WiFiState_Disconnected"); - break; - case WiFiState_e::WiFiState_Error: - this->log("WiFiState_Error"); - break; - case WiFiState_e::WiFiState_ADHOC: - this->log("WiFiState_ADHOC"); - this->setUpADHOC(); - break; - default: - break; - } - - // FIXME: This creates a stack overflow for some reason - // if (this->customHandlerFunction) { - // this->customHandlerFunction(_event); - //} - }); - - // updateStateWrapper(event, [this](Event_e _event) { - // switch (_event) { - // case Event_e::configSaved: - // this->begin(); - // break; - // default: - // break; - // } - // }); -} -void WiFiHandler::onWiFiEvent(WiFiEvent_t event) { - switch (event) { - /* case SYSTEM_EVENT_WIFI_READY: - this->configManager.notifyAll( - WiFiState_e::WiFiState_Idle); - break; - case SYSTEM_EVENT_SCAN_DONE: - this->configManager.notifyAll( - WiFiState_e::WiFiState_Scanning_Done); - break; */ - case SYSTEM_EVENT_STA_DISCONNECTED: - this->configManager.notifyAll(WiFiState_e::WiFiState_Disconnected); - break; - case SYSTEM_EVENT_STA_GOT_IP: - this->configManager.notifyAll(WiFiState_e::WiFiState_Connected); - break; - } -} - -void WiFiHandler::setCustomHandler( - WiFiHandlerCustomHandlerFunction customHandlerFunction) { - this->customHandlerFunction = customHandlerFunction; -} +#include + +WiFiHandler::WiFiHandler(ProjectConfig& configManager, const std::string& ssid, + const std::string& password, uint8_t channel) + : configManager(configManager), + txpower(this->configManager.getWifiTxPowerConfig()), + ssid(ssid), + password(password), + channel(channel), + power(0), + _enable_adhoc(false) { + this->setID(static_cast( + ProjectConfigEventIDs_e::ProjectConfigEventID_MDNSHandler)); + this->setLabel("WiFiHandler"); +} + +WiFiHandler::~WiFiHandler() {} + +void WiFiHandler::begin() { + if (this->_enable_adhoc) { + this->configManager.notifyAll(WiFiState_e::WiFiState_ADHOC); + return; + } + WiFi.mode(WIFI_STA); + WiFi.onEvent( + std::bind(&WiFiHandler::onWiFiEvent, this, std::placeholders::_1)); + WiFi.setSleep(WIFI_PS_NONE); + + this->log("Initializing connection to wifi networks..."); + + auto networks = this->configManager.getWifiConfigs(); + + if (networks.empty()) { + this->log( + "No networks found in config, trying the " + "default one ..."); + if (this->iniSTA(this->ssid, this->password, this->channel, + (wifi_power_t)txpower.power)) { + return; + } + this->log( + "Could not connect to the hardcoded " + "network, setting up ADHOC network ..."); + this->log("WiFiState_ADHOC"); + this->setUpADHOC(); + return; + } + + for (auto networkIterator = networks.begin(); + networkIterator != networks.end(); ++networkIterator) { + if (this->iniSTA(networkIterator->ssid, networkIterator->password, + networkIterator->channel, + (wifi_power_t)networkIterator->power)) { + return; + } + } + + // at this point, we've tried every network, let's just + // setup adhoc + this->log( + "We've gone through every network, each timed out. " + "Trying to connect to the hardcoded network one last time: ", + this->ssid); + if (this->iniSTA(this->ssid, this->password, this->channel, + (wifi_power_t)txpower.power)) { + this->log( + "Successfully connected to the hardcoded " + "network."); + return; + } + this->log("WiFiState_ADHOC"); + this->setUpADHOC(); + log_e( + "Could not connect to the hardcoded network, " + "setting up adhoc. \n\r"); +} + +void WiFiHandler::adhoc(const std::string& ssid, uint8_t channel, + const std::string& password) { + this->log("Configuring access point...\n"); + WiFi.mode(WIFI_AP); + WiFi.setSleep(WIFI_PS_NONE); + this->log("Starting AP..."); + IPAddress IP = WiFi.softAPIP(); + this->log("AP IP address: ", IP.toString().c_str()); + // You can remove the password parameter if you want the + // AP to be open. + WiFi.softAP(ssid.c_str(), password.c_str(), + channel); // AP mode with password + WiFi.setTxPower((wifi_power_t)txpower.power); +} + +void WiFiHandler::setUpADHOC() { + this->log("Setting Access Point... "); + size_t ssidLen = this->configManager.getAPWifiConfig().ssid.length(); + size_t passwordLen = + this->configManager.getAPWifiConfig().password.length(); + if (ssidLen <= 0) { + this->adhoc("EasyNetworkManager", 1, "12345678"); + return; + } + + if (passwordLen <= 0) { + this->log( + "Configuring access point without a " + "password..."); + this->adhoc(this->configManager.getAPWifiConfig().ssid, + this->configManager.getAPWifiConfig().channel); + return; + } + + this->adhoc(this->configManager.getAPWifiConfig().ssid, + this->configManager.getAPWifiConfig().channel, + this->configManager.getAPWifiConfig().password); + this->log("Configuring access point..."); + log_d("\n[DEBUG]: ssid: %s\n", + this->configManager.getAPWifiConfig().ssid.c_str()); + log_d("\n[DEBUG]: password: %s\n", + this->configManager.getAPWifiConfig().password.c_str()); + log_d("\n[DEBUG]: channel: %d\n", + this->configManager.getAPWifiConfig().channel); +} + +bool WiFiHandler::iniSTA(const std::string& ssid, const std::string& password, + uint8_t channel, wifi_power_t power) { + unsigned long currentMillis = millis(); + unsigned long startingMillis = currentMillis; + int connectionTimeout = 30000; // 30 seconds + int progress = 0; + this->log("Trying to connect to: ", ssid); + auto mdnsConfig = this->configManager.getMDNSConfig(); + WiFi.config(INADDR_NONE, INADDR_NONE, INADDR_NONE, INADDR_NONE); + WiFi.setHostname(mdnsConfig.hostname.c_str()); + WiFi.begin(ssid.c_str(), password.c_str(), channel); + while (WiFi.status() != WL_CONNECTED) { + progress++; + currentMillis = millis(); + Helpers::update_progress_bar(progress, 100); + delay(300); + log_v("."); + if ((currentMillis - startingMillis) >= connectionTimeout) { + this->configManager.notifyAll(WiFiState_e::WiFiState_Error); + log_e("Connection to: %s TIMEOUT \n\r", ssid.c_str()); + delay(300); + return false; + } + } + + this->log("Successfully connected to ", ssid); + this->configManager.notifyAll(WiFiState_e::WiFiState_Connected); + // Serial.printf("Setting TX power to: %d \n\r", (uint8_t)power); + // WiFi.setTxPower(power); + + return true; +} + +void WiFiHandler::toggleAdhoc(bool enable) { + _enable_adhoc = enable; +} + +void WiFiHandler::update(const StateVariant& event) { + updateStateWrapper(event, [this](WiFiState_e _event) { + switch (_event) { + case WiFiState_e::WiFiState_Connecting: + this->log("WiFiState_Connecting"); + this->begin(); + break; + case WiFiState_e::WiFiState_Connected: + this->log("WiFiState_Connected"); + break; + case WiFiState_e::WiFiState_Disconnected: + this->log("WiFiState_Disconnected"); + break; + case WiFiState_e::WiFiState_Error: + this->log("WiFiState_Error"); + break; + case WiFiState_e::WiFiState_ADHOC: + this->log("WiFiState_ADHOC"); + this->setUpADHOC(); + break; + default: + break; + } + + // FIXME: This creates a stack overflow for some reason + // if (this->customHandlerFunction) { + // this->customHandlerFunction(_event); + //} + }); + + // updateStateWrapper(event, [this](Event_e _event) { + // switch (_event) { + // case Event_e::configSaved: + // this->begin(); + // break; + // default: + // break; + // } + // }); +} +void WiFiHandler::onWiFiEvent(WiFiEvent_t event) { + switch (event) { + /* case SYSTEM_EVENT_WIFI_READY: + this->configManager.notifyAll( + WiFiState_e::WiFiState_Idle); + break; + case SYSTEM_EVENT_SCAN_DONE: + this->configManager.notifyAll( + WiFiState_e::WiFiState_Scanning_Done); + break; */ + case SYSTEM_EVENT_STA_DISCONNECTED: + this->configManager.notifyAll(WiFiState_e::WiFiState_Disconnected); + break; + case SYSTEM_EVENT_STA_GOT_IP: + this->configManager.notifyAll(WiFiState_e::WiFiState_Connected); + break; + } +} + +void WiFiHandler::setCustomHandler( + WiFiHandlerCustomHandlerFunction customHandlerFunction) { + this->customHandlerFunction = customHandlerFunction; +} diff --git a/NetworkManager/src/utilities/api_utilities.cpp b/NetworkManager/src/utilities/api_utilities.cpp index 8d1af1e..ecd08ad 100644 --- a/NetworkManager/src/utilities/api_utilities.cpp +++ b/NetworkManager/src/utilities/api_utilities.cpp @@ -1,105 +1,105 @@ -#include - -//! These have to be called before the constructor of the class because they are -//! static C++ 11 does not have inline variables, sadly. So we have to do this. -const char* API_Utilities::MIMETYPE_HTML{"text/html"}; -const char* API_Utilities::MIMETYPE_CSS{"text/css"}; -const char* API_Utilities::MIMETYPE_JS{"application/javascript"}; -const char* API_Utilities::MIMETYPE_PNG{"image/png"}; -const char* API_Utilities::MIMETYPE_JPG{"image/jpeg"}; -const char* API_Utilities::MIMETYPE_ICO{"image/x-icon"}; -const char* API_Utilities::MIMETYPE_JSON{"application/json"}; - -//********************************************************************************************* -//! API Utilities -//********************************************************************************************* - -API_Utilities::API_Utilities() {} -API_Utilities::~API_Utilities() {} - -/** - * @brief A simple sha512 encoder for a string - * - * @param data std::string - * @return std::string - */ -std::string API_Utilities::shaEncoder(const std::string& data) { - const char* data_c = data.c_str(); - int size = 64; - uint8_t hash[size]; - mbedtls_md_context_t ctx; - mbedtls_md_type_t md_type = MBEDTLS_MD_SHA512; - - const size_t len = strlen(data_c); - mbedtls_md_init(&ctx); - mbedtls_md_setup(&ctx, mbedtls_md_info_from_type(md_type), 0); - mbedtls_md_starts(&ctx); - mbedtls_md_update(&ctx, (const unsigned char*)data_c, len); - mbedtls_md_finish(&ctx, hash); - mbedtls_md_free(&ctx); - - std::string hash_string = ""; - for (uint16_t i = 0; i < size; i++) { - std::string hex = String(hash[i], HEX).c_str(); - if (hex.length() < 2) { - hex = "0" + hex; - } - hash_string += hex; - } - return hash_string; -} - -// Initialize SPIFFS -bool API_Utilities::initSPIFFS() { - bool init_spiffs = SPIFFS.begin(false); - log_e("[SPIFFS]: SPIFFS Initialized: %s", init_spiffs ? "true" : "false"); - return init_spiffs; -} - -/** - * @brief Read a file from SPIFFS - * - * @param fs fs::FS& - * @param path std::string - * @return std::string - */ -std::string API_Utilities::readFile(fs::FS& fs, const std::string& path) { - log_i("Reading file: %s\r\n", path.c_str()); - - File file = fs.open(path.c_str()); - if (!file || file.isDirectory()) { - log_e("[INFO]: Failed to open file for reading"); - return std::string(); - } - - std::string fileContent; - while (file.available()) { - fileContent = file.readStringUntil('\n').c_str(); - break; - } - return fileContent; -} - -/** - * @brief Write a file to SPIFFS - * - * @param fs fs::FS& - * @param path std::string - * @param message std::string - */ -void API_Utilities::writeFile(fs::FS& fs, const std::string& path, - const std::string& message) { - log_i("[Writing File]: Writing file: %s\r\n", path); - Network_Utilities::my_delay(0.1L); - - File file = fs.open(path.c_str(), FILE_WRITE); - if (!file) { - log_i("[Writing File]: failed to open file for writing"); - return; - } - if (file.print(message.c_str())) { - log_i("[Writing File]: file written"); - } else { - log_i("[Writing File]: file write failed"); - } -} +#include + +//! These have to be called before the constructor of the class because they are +//! static C++ 11 does not have inline variables, sadly. So we have to do this. +const char* API_Utilities::MIMETYPE_HTML{"text/html"}; +const char* API_Utilities::MIMETYPE_CSS{"text/css"}; +const char* API_Utilities::MIMETYPE_JS{"application/javascript"}; +const char* API_Utilities::MIMETYPE_PNG{"image/png"}; +const char* API_Utilities::MIMETYPE_JPG{"image/jpeg"}; +const char* API_Utilities::MIMETYPE_ICO{"image/x-icon"}; +const char* API_Utilities::MIMETYPE_JSON{"application/json"}; + +//********************************************************************************************* +//! API Utilities +//********************************************************************************************* + +API_Utilities::API_Utilities() {} +API_Utilities::~API_Utilities() {} + +/** + * @brief A simple sha512 encoder for a string + * + * @param data std::string + * @return std::string + */ +std::string API_Utilities::shaEncoder(const std::string& data) { + const char* data_c = data.c_str(); + int size = 64; + uint8_t hash[size]; + mbedtls_md_context_t ctx; + mbedtls_md_type_t md_type = MBEDTLS_MD_SHA512; + + const size_t len = strlen(data_c); + mbedtls_md_init(&ctx); + mbedtls_md_setup(&ctx, mbedtls_md_info_from_type(md_type), 0); + mbedtls_md_starts(&ctx); + mbedtls_md_update(&ctx, (const unsigned char*)data_c, len); + mbedtls_md_finish(&ctx, hash); + mbedtls_md_free(&ctx); + + std::string hash_string = ""; + for (uint16_t i = 0; i < size; i++) { + std::string hex = String(hash[i], HEX).c_str(); + if (hex.length() < 2) { + hex = "0" + hex; + } + hash_string += hex; + } + return hash_string; +} + +// Initialize SPIFFS +bool API_Utilities::initSPIFFS() { + bool init_spiffs = SPIFFS.begin(false); + log_e("[SPIFFS]: SPIFFS Initialized: %s", init_spiffs ? "true" : "false"); + return init_spiffs; +} + +/** + * @brief Read a file from SPIFFS + * + * @param fs fs::FS& + * @param path std::string + * @return std::string + */ +std::string API_Utilities::readFile(fs::FS& fs, const std::string& path) { + log_i("Reading file: %s\r\n", path.c_str()); + + File file = fs.open(path.c_str()); + if (!file || file.isDirectory()) { + log_e("[INFO]: Failed to open file for reading"); + return std::string(); + } + + std::string fileContent; + while (file.available()) { + fileContent = file.readStringUntil('\n').c_str(); + break; + } + return fileContent; +} + +/** + * @brief Write a file to SPIFFS + * + * @param fs fs::FS& + * @param path std::string + * @param message std::string + */ +void API_Utilities::writeFile(fs::FS& fs, const std::string& path, + const std::string& message) { + log_i("[Writing File]: Writing file: %s\r\n", path); + Network_Utilities::my_delay(0.1L); + + File file = fs.open(path.c_str(), FILE_WRITE); + if (!file) { + log_i("[Writing File]: failed to open file for writing"); + return; + } + if (file.print(message.c_str())) { + log_i("[Writing File]: file written"); + } else { + log_i("[Writing File]: file write failed"); + } +} diff --git a/NetworkManager/src/utilities/network_utilities.cpp b/NetworkManager/src/utilities/network_utilities.cpp index a07b508..0bd0f22 100644 --- a/NetworkManager/src/utilities/network_utilities.cpp +++ b/NetworkManager/src/utilities/network_utilities.cpp @@ -1,90 +1,90 @@ -#include - -/** - * @brief Function to setup the WiFi scan and set the WiFi mode to station. - * @note Call this function in the setup() function - */ -void Network_Utilities::setupWifiScan() { - // Set WiFi to station mode and disconnect from an AP if it was previously - // connected - WiFi.mode(WIFI_STA); - WiFi.disconnect(); // Disconnect from the access point if connected before - delay(100); - - log_i("[INFO]: Setup done"); -} - -/** - * @brief Function to scan for WiFi networks and print the results to the serial - * @note Call this function in the loop() function - * @return true - * @return false - */ -bool Network_Utilities::loopWifiScan() { - // WiFi.scanNetworks will return the number of networks found - log_i("[INFO]: Beginning WiFi Scanner"); - int networks = WiFi.scanNetworks(); - log_i("[INFO]: scan done"); - - log_i("%d networks found", networks); - for (int i = networks; i--;) { - // Print SSID and RSSI for each network found - //! Add method here to interface with the API and forward the scanned - //! networks to the API - log_i("%d: %s (%d) %s\n", i - 1, WiFi.SSID(i), WiFi.RSSI(i), - (WiFi.encryptionType(i) == WIFI_AUTH_OPEN) ? " " : "*"); - my_delay(0.02L); // delay 20ms - } - - // Wait a bit before scanning again - delay(5000); - return (networks > 0); -} - -/** - * @brief Function to get the strength of the WiFi signal - * - * @param points int Number of points to average - * @return int - */ -int Network_Utilities::getStrength(int points) { - int32_t rssi = 0, averageRSSI = 0; - - for (int i = 0; i < points; i++) { - rssi += WiFi.RSSI(); - delay(20); - } - - averageRSSI = rssi / points; - return averageRSSI; -} - -/** - * @brief Function to delay the program execution - * - * @param delay_time volatile long - */ -void Network_Utilities::my_delay(volatile long delay_time) { - delay_time = delay_time * 1e6L; - for (volatile long count = delay_time; count > 0L; count--) - ; -} - -/** - * @brief Function to generate a device ID from the ESP32 chip ID - * - * @return std::string - */ -std::string Network_Utilities::generateDeviceID() { - uint32_t chipId = 0; - for (int i = 0; i < 17; i = i + 8) { - chipId |= ((ESP.getEfuseMac() >> (40 - i)) & 0xff) << i; - } - - log_i("ESP Chip model = %s Rev %d\n", ESP.getChipModel(), - ESP.getChipRevision()); - log_i("This chip has %d cores\n", ESP.getChipCores()); - log_i("Chip ID: %d", chipId); - std::string deviceID = (const char*)chipId; - return deviceID; -} +#include + +/** + * @brief Function to setup the WiFi scan and set the WiFi mode to station. + * @note Call this function in the setup() function + */ +void Network_Utilities::setupWifiScan() { + // Set WiFi to station mode and disconnect from an AP if it was previously + // connected + WiFi.mode(WIFI_STA); + WiFi.disconnect(); // Disconnect from the access point if connected before + delay(100); + + log_i("[INFO]: Setup done"); +} + +/** + * @brief Function to scan for WiFi networks and print the results to the serial + * @note Call this function in the loop() function + * @return true + * @return false + */ +bool Network_Utilities::loopWifiScan() { + // WiFi.scanNetworks will return the number of networks found + log_i("[INFO]: Beginning WiFi Scanner"); + int networks = WiFi.scanNetworks(); + log_i("[INFO]: scan done"); + + log_i("%d networks found", networks); + for (int i = networks; i--;) { + // Print SSID and RSSI for each network found + //! Add method here to interface with the API and forward the scanned + //! networks to the API + log_i("%d: %s (%d) %s\n", i - 1, WiFi.SSID(i), WiFi.RSSI(i), + (WiFi.encryptionType(i) == WIFI_AUTH_OPEN) ? " " : "*"); + my_delay(0.02L); // delay 20ms + } + + // Wait a bit before scanning again + delay(5000); + return (networks > 0); +} + +/** + * @brief Function to get the strength of the WiFi signal + * + * @param points int Number of points to average + * @return int + */ +int Network_Utilities::getStrength(int points) { + int32_t rssi = 0, averageRSSI = 0; + + for (int i = 0; i < points; i++) { + rssi += WiFi.RSSI(); + delay(20); + } + + averageRSSI = rssi / points; + return averageRSSI; +} + +/** + * @brief Function to delay the program execution + * + * @param delay_time volatile long + */ +void Network_Utilities::my_delay(volatile long delay_time) { + delay_time = delay_time * 1e6L; + for (volatile long count = delay_time; count > 0L; count--) + ; +} + +/** + * @brief Function to generate a device ID from the ESP32 chip ID + * + * @return std::string + */ +std::string Network_Utilities::generateDeviceID() { + uint32_t chipId = 0; + for (int i = 0; i < 17; i = i + 8) { + chipId |= ((ESP.getEfuseMac() >> (40 - i)) & 0xff) << i; + } + + log_i("ESP Chip model = %s Rev %d\n", ESP.getChipModel(), + ESP.getChipRevision()); + log_i("This chip has %d cores\n", ESP.getChipCores()); + log_i("Chip ID: %d", chipId); + std::string deviceID = (const char*)chipId; + return deviceID; +} diff --git a/NetworkManager/test/README b/NetworkManager/test/README index 9b1e87b..b0416ad 100644 --- a/NetworkManager/test/README +++ b/NetworkManager/test/README @@ -1,11 +1,11 @@ - -This directory is intended for PlatformIO Test Runner and project tests. - -Unit Testing is a software testing method by which individual units of -source code, sets of one or more MCU program modules together with associated -control data, usage procedures, and operating procedures, are tested to -determine whether they are fit for use. Unit testing finds problems early -in the development cycle. - -More information about PlatformIO Unit Testing: -- https://docs.platformio.org/en/latest/advanced/unit-testing/index.html + +This directory is intended for PlatformIO Test Runner and project tests. + +Unit Testing is a software testing method by which individual units of +source code, sets of one or more MCU program modules together with associated +control data, usage procedures, and operating procedures, are tested to +determine whether they are fit for use. Unit testing finds problems early +in the development cycle. + +More information about PlatformIO Unit Testing: +- https://docs.platformio.org/en/latest/advanced/unit-testing/index.html diff --git a/NetworkManager/tools/colors.py b/NetworkManager/tools/colors.py index fcadfed..7ffdf5d 100644 --- a/NetworkManager/tools/colors.py +++ b/NetworkManager/tools/colors.py @@ -1,7 +1,7 @@ -RED = "\033[1;31m" -BLUE = "\033[1;34m" -CYAN = "\033[1;36m" -GREEN = "\033[0;32m" -RESET = "\033[0;0m" -BOLD = "\033[;1m" +RED = "\033[1;31m" +BLUE = "\033[1;34m" +CYAN = "\033[1;36m" +GREEN = "\033[0;32m" +RESET = "\033[0;0m" +BOLD = "\033[;1m" REVERSE = "\033[;7m" \ No newline at end of file diff --git a/NetworkManager/tools/createwokwi.py b/NetworkManager/tools/createwokwi.py index 7bda527..dfeef80 100644 --- a/NetworkManager/tools/createwokwi.py +++ b/NetworkManager/tools/createwokwi.py @@ -1,41 +1,41 @@ -#!/usr/bin/env python3 -# https://docs.wokwi.com/vscode/getting-started - -# TODO: Add generation of diagram.json file per board environment - -Import("env") -try: - - def createTOML(source, target, env): - try: - firmware_name = env.subst("$BUILD_DIR\${PROGNAME}") - firmware_name = firmware_name.split(".pio")[1] - - firmware_name = firmware_name.replace("\\", "/") - - print("Creating wokwi.toml for %s" % firmware_name) - - wokwi_string = """\ -[wokwi] -version = 1 -elf = ".pio{name}.elf" -firmware = ".pio{name}.bin" -[[net.forward]] -from = "localhost:8180" -to = "target:80" -""" - toml_string = wokwi_string.format(name=firmware_name) - print(toml_string) - with open("wokwi.toml", "w+") as f: - f.write(toml_string) - f.close() - - print("wokwi.toml created \n") - - except Exception as e: - print("Error creating wokwi.toml: %s" % e) - - env.AddPostAction("$BUILD_DIR\${PROGNAME}.bin", createTOML) - -except Exception as e: - print("Error creating wokwi.toml: %s" % e) +#!/usr/bin/env python3 +# https://docs.wokwi.com/vscode/getting-started + +# TODO: Add generation of diagram.json file per board environment + +Import("env") +try: + + def createTOML(source, target, env): + try: + firmware_name = env.subst("$BUILD_DIR/${PROGNAME}") + firmware_name = firmware_name.split(".pio")[1] + + firmware_name = firmware_name.replace("\\", "/") + + print("Creating wokwi.toml for %s" % firmware_name) + + wokwi_string = """\ +[wokwi] +version = 1 +elf = ".pio{name}.elf" +firmware = ".pio{name}.bin" +[[net.forward]] +from = "localhost:8180" +to = "target:80" +""" + toml_string = wokwi_string.format(name=firmware_name) + print(toml_string) + with open("wokwi.toml", "w+") as f: + f.write(toml_string) + f.close() + + print("wokwi.toml created \n") + + except Exception as e: + print("Error creating wokwi.toml: %s" % e) + + env.AddPostAction("$BUILD_DIR/${PROGNAME}.bin", createTOML) + +except Exception as e: + print("Error creating wokwi.toml: %s" % e) diff --git a/NetworkManager/tools/customname.py b/NetworkManager/tools/customname.py index e9e523d..5005da8 100644 --- a/NetworkManager/tools/customname.py +++ b/NetworkManager/tools/customname.py @@ -1,150 +1,150 @@ -# Description: Custom name for firmware - -Import("env") -import subprocess -import sys -from colors import * - -project = "" -version = "" -commit = "" -branch = "" - - -def onError(): - print("Please install Git for Windows and add it to your PATH") - print( - "Continuing with default values for PIO_SRC_NAM, PIO_SRC_TAG, PIO_SRC_REV, PIO_SRC_BRH" - ) - sys.stdout.write(RESET) - - project = "PIO" - version = "0.0.0" - commit = "0000000" - branch = "main" - - customName(project, version, commit, branch) - - exit(1) - - -def handleGit(): - try: - checkgit = "git rev-parse --is-inside-work-tree" - - if subprocess.check_output(checkgit, shell=True).decode().strip() != "true": - sys.stdout.write(RED) - onError() - - sys.stdout.write(GREEN) - print("Git is installed and we are in a Git repository, continuing...") - sys.stdout.write(RESET) - - # Get Git project name - projcmd = "git rev-parse --show-toplevel" - project = subprocess.check_output(projcmd, shell=True).decode().strip() - project = project.split("/") - project = project[len(project) - 1] - - # Get 0.0.0 version from latest Git tag - tagcmd = "git describe --tags --always --abbrev=0" - version = subprocess.check_output(tagcmd, shell=True).decode().strip() - - # Get latest commit short from Git - revcmd = "git log --pretty=format:'%h' -n 1" - commit = subprocess.check_output(revcmd, shell=True).decode().strip() - - # Get branch name from Git - branchcmd = "git rev-parse --abbrev-ref HEAD" - branch = subprocess.check_output(branchcmd, shell=True).decode().strip() - - print("Project: %s" % project) - print("Version: %s" % version) - print("Commit: %s" % commit) - print("Branch: %s" % branch) - - # Make all available for use in the macros - customName(project, version, commit, branch) - - sys.stdout.write(GREEN) - print("Git information has been added to the build flags") - # print(env.Dump()) - sys.stdout.write(RESET) - - except subprocess.CalledProcessError as e: - sys.stdout.write(RED) - print("Error: %s" % e) - onError() - - -def customName(project, version, commit, branch): - - my_flags = env.ParseFlags(env["BUILD_FLAGS"]) - defines = dict() - - # add the git information to the build flags - my_flags.get("CPPDEFINES").append(("PIO_SRC_NAM", project)) - my_flags.get("CPPDEFINES").append(("PIO_SRC_TAG", version)) - my_flags.get("CPPDEFINES").append(("PIO_SRC_REV", commit)) - my_flags.get("CPPDEFINES").append(("PIO_SRC_BRH", branch)) - - for x in my_flags.get("CPPDEFINES"): - if type(x) is tuple: - (k, v) = x - defines[k] = v - # print("Type Tuple: %s" % x) - elif type(x) is list: - k = x[0] - v = x[1] - defines[k] = v - # print("Type List: %s" % x) - else: - defines[x] = "" # empty value - # print("Warning: unknown type for %s" % x) - - # print("Project: %s" % defines) - # strip quotes needed for shell escaping - s = lambda x: x.replace('"', "") - s = lambda x: x.replace("'", "") - - env.Replace( - PROGNAME="%s-%s-%s-%s-%s" - % ( - s(defines.get("PIO_SRC_NAM")), - s(defines.get("PIO_SRC_TAG")), - str(env["PIOENV"]), - s(defines.get("PIO_SRC_REV")), - s(defines.get("PIO_SRC_BRH")), - ) - ) - - # detect if there is a forward slash in the PROGNAME and replace it with an underscore - if "/" in env["PROGNAME"]: - env.Replace(PROGNAME="%s" % (env["PROGNAME"].replace("/", "-"))) - - # create a file with the name of the firmware - env.Execute( - "echo %s > %s" % (env["PROGNAME"], env.subst("./tools/firmware_name.txt")) - ) - - -try: - flags = env["BUILD_FLAGS"] - my_flags = env.ParseFlags(flags) - - # Dump global construction environment (for debug purpose) - # write env.Dump() to a file - #with open("env_dump.txt", "w") as f: - # f.write(env.Dump()) - - handleGit() -except ValueError as ex: - # look for apostrophes and warn the user - sys.stdout.write(RED) - print( - "[Warning]: Apostrophes are not allowed in the build flags. Please remove them from the \033[;1m\033[1;36m`user-config.ini` \033[1;31mfile and try again." - ) - raise Exception( - "Could not parse BUILD_FLAGS - Possible apostrophy used in user configuration", - ex, +# Description: Custom name for firmware + +Import("env") +import subprocess +import sys +from colors import * + +project = "" +version = "" +commit = "" +branch = "" + + +def onError(): + print("Please install Git for Windows and add it to your PATH") + print( + "Continuing with default values for PIO_SRC_NAM, PIO_SRC_TAG, PIO_SRC_REV, PIO_SRC_BRH" + ) + sys.stdout.write(RESET) + + project = "PIO" + version = "0.0.0" + commit = "0000000" + branch = "main" + + customName(project, version, commit, branch) + + exit(1) + + +def handleGit(): + try: + checkgit = "git rev-parse --is-inside-work-tree" + + if subprocess.check_output(checkgit, shell=True).decode().strip() != "true": + sys.stdout.write(RED) + onError() + + sys.stdout.write(GREEN) + print("Git is installed and we are in a Git repository, continuing...") + sys.stdout.write(RESET) + + # Get Git project name + projcmd = "git rev-parse --show-toplevel" + project = subprocess.check_output(projcmd, shell=True).decode().strip() + project = project.split("/") + project = project[len(project) - 1] + + # Get 0.0.0 version from latest Git tag + tagcmd = "git describe --tags --always --abbrev=0" + version = subprocess.check_output(tagcmd, shell=True).decode().strip() + + # Get latest commit short from Git + revcmd = "git log --pretty=format:'%h' -n 1" + commit = subprocess.check_output(revcmd, shell=True).decode().strip() + + # Get branch name from Git + branchcmd = "git rev-parse --abbrev-ref HEAD" + branch = subprocess.check_output(branchcmd, shell=True).decode().strip() + + print("Project: %s" % project) + print("Version: %s" % version) + print("Commit: %s" % commit) + print("Branch: %s" % branch) + + # Make all available for use in the macros + customName(project, version, commit, branch) + + sys.stdout.write(GREEN) + print("Git information has been added to the build flags") + # print(env.Dump()) + sys.stdout.write(RESET) + + except subprocess.CalledProcessError as e: + sys.stdout.write(RED) + print("Error: %s" % e) + onError() + + +def customName(project, version, commit, branch): + + my_flags = env.ParseFlags(env["BUILD_FLAGS"]) + defines = dict() + + # add the git information to the build flags + my_flags.get("CPPDEFINES").append(("PIO_SRC_NAM", project)) + my_flags.get("CPPDEFINES").append(("PIO_SRC_TAG", version)) + my_flags.get("CPPDEFINES").append(("PIO_SRC_REV", commit)) + my_flags.get("CPPDEFINES").append(("PIO_SRC_BRH", branch)) + + for x in my_flags.get("CPPDEFINES"): + if type(x) is tuple: + (k, v) = x + defines[k] = v + # print("Type Tuple: %s" % x) + elif type(x) is list: + k = x[0] + v = x[1] + defines[k] = v + # print("Type List: %s" % x) + else: + defines[x] = "" # empty value + # print("Warning: unknown type for %s" % x) + + # print("Project: %s" % defines) + # strip quotes needed for shell escaping + s = lambda x: x.replace('"', "") + s = lambda x: x.replace("'", "") + + env.Replace( + PROGNAME="%s-%s-%s-%s-%s" + % ( + s(defines.get("PIO_SRC_NAM")), + s(defines.get("PIO_SRC_TAG")), + str(env["PIOENV"]), + s(defines.get("PIO_SRC_REV")), + s(defines.get("PIO_SRC_BRH")), + ) + ) + + # detect if there is a forward slash in the PROGNAME and replace it with an underscore + if "/" in env["PROGNAME"]: + env.Replace(PROGNAME="%s" % (env["PROGNAME"].replace("/", "-"))) + + # create a file with the name of the firmware + env.Execute( + "echo %s > %s" % (env["PROGNAME"], env.subst("./tools/firmware_name.txt")) + ) + + +try: + flags = env["BUILD_FLAGS"] + my_flags = env.ParseFlags(flags) + + # Dump global construction environment (for debug purpose) + # write env.Dump() to a file + #with open("env_dump.txt", "w") as f: + # f.write(env.Dump()) + + handleGit() +except ValueError as ex: + # look for apostrophes and warn the user + sys.stdout.write(RED) + print( + "[Warning]: Apostrophes are not allowed in the build flags. Please remove them from the \033[;1m\033[1;36m`user-config.ini` \033[1;31mfile and try again." + ) + raise Exception( + "Could not parse BUILD_FLAGS - Possible apostrophy used in user configuration", + ex, ) \ No newline at end of file diff --git a/NetworkManager/ui/README.md b/NetworkManager/ui/README.md index 76f0ae4..1f933a7 100644 --- a/NetworkManager/ui/README.md +++ b/NetworkManager/ui/README.md @@ -1,18 +1,18 @@ -# UI Source Code - -This is the source code for generating the `wifimanager` UI, and the `OTA` UI (coming soon). - -## Building - -To build the UI, you need to have `node` and `yarn` installed. Then, run the following commands: - - yarn - yarn build - -This will generate the UI in the `include/data` folder as `webpage.h`. - -## Development - -To develop the UI, currently we use raw html, css, and javascript. Simply modify the `html` files and copy the file to the string `string` in `compress.js`. - -This is only temporary, and we will be using a more robust framework in the future. +# UI Source Code + +This is the source code for generating the `wifimanager` UI, and the `OTA` UI (coming soon). + +## Building + +To build the UI, you need to have `node` and `yarn` installed. Then, run the following commands: + + yarn + yarn build + +This will generate the UI in the `include/data` folder as `webpage.h`. + +## Development + +To develop the UI, currently we use raw html, css, and javascript. Simply modify the `html` files and copy the file to the string `string` in `compress.js`. + +This is only temporary, and we will be using a more robust framework in the future. diff --git a/NetworkManager/ui/compress.js b/NetworkManager/ui/compress.js index 5c5ac25..4015f1a 100644 --- a/NetworkManager/ui/compress.js +++ b/NetworkManager/ui/compress.js @@ -1,474 +1,474 @@ -const { gzip } = require('@gfx/zopfli'); -const FS = require('fs'); -const path = require('path'); - -const HTML = ` - - Easy Network Manager Wifi Portal - - - - - - - - - -
-

Easy Network Manager Wifi Portal

-
-
-
-

-
📶
- Connect to your network -

-
-
-
-
-
-

- Wifi Router Details -
-

- 🗎 - - -
-
-
- 🔑 - - -
-
-

-
-
- -
-
-

- MDNS Settings -
-
- -
-
-
- -
- - To see mDNS urls using an - Android device, please use the Bonjour Browser App. - -

-
-
-
-
-

- OTA Settings -
-
- -
- -
- -
- -

-
-
-
-

- - -

-

-

-
-
-
-

- Advanced OTA Updates are coming soon - For now, use PlatformIO's OTA to - upload -
-
- -

-
- -`; - -function chunkArray(myArray, chunk_size) { - let index = 0; - const arrayLength = myArray.length; - const tempArray = []; - for (index = 0; index < arrayLength; index += chunk_size) { - myChunk = myArray.slice(index, index + chunk_size); - // Do something if you want with the group - tempArray.push(myChunk); - } - return tempArray; -} - -function addLineBreaks(buffer) { - let data = ''; - const chunks = chunkArray(buffer, 30); - chunks.forEach((chunk, index) => { - data += chunk.join(','); - if (index + 1 !== chunks.length) { - data += ',\n'; - } - }); - return data; -} - - -gzip(HTML, { numiterations: 15 }, (err, output) => { - if (err) { - return console.error(err); - } - - const FILE = `#ifndef EasyNetworkWebManager_h -#define EasyNetworkWebManager_h -#include -const uint32_t WEB_MANAGER_HTML_SIZE = ${output.length}; -const uint8_t WEB_MANAGER_HTML[] PROGMEM = { -${addLineBreaks(output)} -}; -#endif -`; - - FS.writeFileSync(path.resolve(__dirname, '../include/data/webpage.h'), FILE); - console.log(`[COMPRESS] Compressed Build Files to webpage.h: ${(output.length / 1024).toFixed(2)}KB`); +const { gzip } = require('@gfx/zopfli'); +const FS = require('fs'); +const path = require('path'); + +const HTML = ` + + Easy Network Manager Wifi Portal + + + + + + + + + +
+

Easy Network Manager Wifi Portal

+
+
+
+

+
📶
+ Connect to your network +

+
+
+
+
+
+

+ Wifi Router Details +
+

+ 🗎 + + +
+
+
+ 🔑 + + +
+
+

+
+
+ +
+
+

+ MDNS Settings +
+
+ +
+
+
+ +
+ + To see mDNS urls using an + Android device, please use the Bonjour Browser App. + +

+
+
+
+
+

+ OTA Settings +
+
+ +
+ +
+ +
+ +

+
+
+
+

+ + +

+

+

+
+
+
+

+ Advanced OTA Updates are coming soon - For now, use PlatformIO's OTA to + upload +
+
+ +

+
+ +`; + +function chunkArray(myArray, chunk_size) { + let index = 0; + const arrayLength = myArray.length; + const tempArray = []; + for (index = 0; index < arrayLength; index += chunk_size) { + myChunk = myArray.slice(index, index + chunk_size); + // Do something if you want with the group + tempArray.push(myChunk); + } + return tempArray; +} + +function addLineBreaks(buffer) { + let data = ''; + const chunks = chunkArray(buffer, 30); + chunks.forEach((chunk, index) => { + data += chunk.join(','); + if (index + 1 !== chunks.length) { + data += ',\n'; + } + }); + return data; +} + + +gzip(HTML, { numiterations: 15 }, (err, output) => { + if (err) { + return console.error(err); + } + + const FILE = `#ifndef EasyNetworkWebManager_h +#define EasyNetworkWebManager_h +#include +const uint32_t WEB_MANAGER_HTML_SIZE = ${output.length}; +const uint8_t WEB_MANAGER_HTML[] PROGMEM = { +${addLineBreaks(output)} +}; +#endif +`; + + FS.writeFileSync(path.resolve(__dirname, '../include/data/webpage.h'), FILE); + console.log(`[COMPRESS] Compressed Build Files to webpage.h: ${(output.length / 1024).toFixed(2)}KB`); }); \ No newline at end of file diff --git a/NetworkManager/ui/package.json b/NetworkManager/ui/package.json index f83bae5..8e07c03 100644 --- a/NetworkManager/ui/package.json +++ b/NetworkManager/ui/package.json @@ -1,15 +1,15 @@ -{ - "name": "webmanager", - "version": "0.1.0", - "private": true, - "scripts": { - "build": "node compress.js" - }, - "dependencies": { - "core-js": "^3.6.4", - "spark-md5": "^3.0.1" - }, - "devDependencies": { - "@gfx/zopfli": "^1.0.14" - } +{ + "name": "webmanager", + "version": "0.1.0", + "private": true, + "scripts": { + "build": "node compress.js" + }, + "dependencies": { + "core-js": "^3.6.4", + "spark-md5": "^3.0.1" + }, + "devDependencies": { + "@gfx/zopfli": "^1.0.14" + } } \ No newline at end of file diff --git a/NetworkManager/ui/wifimanager.html b/NetworkManager/ui/wifimanager.html index 69eced4..6905c28 100644 --- a/NetworkManager/ui/wifimanager.html +++ b/NetworkManager/ui/wifimanager.html @@ -1,424 +1,424 @@ - - Easy Network Manager Wifi Portal - - - - - - - - - -
-

Easy Network Manager Wifi Portal

-
-
-
-

-
📶
- Connect to your network -

-
-
-
-
-
-

- Wifi Router Details -
-

- 🗎 - - -
-
-
- 🔑 - - -
-
-

-
-
- -
-
-

- MDNS Settings -
-
- -
-
-
- -
- - To see mDNS urls using an - Android device, please use the Bonjour Browser App. - -

-
-
-
-
-

- OTA Settings -
-
- -
- -
- -
- -

-
-
-
-

- - -

-

-

-
-
-
-

- Advanced OTA Updates are coming soon - For now, use PlatformIO's OTA to - upload -
-
- -

-
+ + Easy Network Manager Wifi Portal + + + + + + + + + +
+

Easy Network Manager Wifi Portal

+
+
+
+

+
📶
+ Connect to your network +

+
+
+
+
+
+

+ Wifi Router Details +
+

+ 🗎 + + +
+
+
+ 🔑 + + +
+
+

+
+
+ +
+
+

+ MDNS Settings +
+
+ +
+
+
+ +
+ + To see mDNS urls using an + Android device, please use the Bonjour Browser App. + +

+
+
+
+
+

+ OTA Settings +
+
+ +
+ +
+ +
+ +

+
+
+
+

+ + +

+

+

+
+
+
+

+ Advanced OTA Updates are coming soon - For now, use PlatformIO's OTA to + upload +
+
+ +

+
\ No newline at end of file diff --git a/NetworkManager/ui/yarn.lock b/NetworkManager/ui/yarn.lock index 32e3c3a..4e30987 100644 --- a/NetworkManager/ui/yarn.lock +++ b/NetworkManager/ui/yarn.lock @@ -1,25 +1,25 @@ -# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. -# yarn lockfile v1 - - -"@gfx/zopfli@^1.0.14": - version "1.0.15" - resolved "https://registry.yarnpkg.com/@gfx/zopfli/-/zopfli-1.0.15.tgz#00720b4f6a4d5ceeb585a5d6dd672b48bd4fc755" - integrity sha512-7mBgpi7UD82fsff5ThQKet0uBTl4BYerQuc+/qA1ELTwWEiIedRTcD3JgiUu9wwZ2kytW8JOb165rSdAt8PfcQ== - dependencies: - base64-js "^1.3.0" - -base64-js@^1.3.0: - version "1.5.1" - resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" - integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== - -core-js@^3.6.4: - version "3.29.0" - resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.29.0.tgz#0273e142b67761058bcde5615c503c7406b572d6" - integrity sha512-VG23vuEisJNkGl6XQmFJd3rEG/so/CNatqeE+7uZAwTSwFeB/qaO0be8xZYUNWprJ/GIwL8aMt9cj1kvbpTZhg== - -spark-md5@^3.0.1: - version "3.0.2" - resolved "https://registry.yarnpkg.com/spark-md5/-/spark-md5-3.0.2.tgz#7952c4a30784347abcee73268e473b9c0167e3fc" - integrity sha512-wcFzz9cDfbuqe0FZzfi2or1sgyIrsDwmPwfZC4hiNidPdPINjeUwNfv5kldczoEAcjl9Y1L3SM7Uz2PUEQzxQw== +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@gfx/zopfli@^1.0.14": + version "1.0.15" + resolved "https://registry.yarnpkg.com/@gfx/zopfli/-/zopfli-1.0.15.tgz#00720b4f6a4d5ceeb585a5d6dd672b48bd4fc755" + integrity sha512-7mBgpi7UD82fsff5ThQKet0uBTl4BYerQuc+/qA1ELTwWEiIedRTcD3JgiUu9wwZ2kytW8JOb165rSdAt8PfcQ== + dependencies: + base64-js "^1.3.0" + +base64-js@^1.3.0: + version "1.5.1" + resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" + integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== + +core-js@^3.6.4: + version "3.29.0" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.29.0.tgz#0273e142b67761058bcde5615c503c7406b572d6" + integrity sha512-VG23vuEisJNkGl6XQmFJd3rEG/so/CNatqeE+7uZAwTSwFeB/qaO0be8xZYUNWprJ/GIwL8aMt9cj1kvbpTZhg== + +spark-md5@^3.0.1: + version "3.0.2" + resolved "https://registry.yarnpkg.com/spark-md5/-/spark-md5-3.0.2.tgz#7952c4a30784347abcee73268e473b9c0167e3fc" + integrity sha512-wcFzz9cDfbuqe0FZzfi2or1sgyIrsDwmPwfZC4hiNidPdPINjeUwNfv5kldczoEAcjl9Y1L3SM7Uz2PUEQzxQw== diff --git a/NetworkManager/wokwi.toml b/NetworkManager/wokwi.toml index 4a1899b..b86fa20 100644 --- a/NetworkManager/wokwi.toml +++ b/NetworkManager/wokwi.toml @@ -1,7 +1,7 @@ [wokwi] version = 1 -elf = ".pio/build/esp32s3_debug/EasyNetworkManager-v5.4.5-esp32s3_debug-da92fd2-main.elf" -firmware = ".pio/build/esp32s3_debug/EasyNetworkManager-v5.4.5-esp32s3_debug-da92fd2-main.bin" +elf = ".pio/build/esp32s3_debug/EasyNetworkManager-v5.5.1-esp32s3_debug-9f0f79c-main.elf" +firmware = ".pio/build/esp32s3_debug/EasyNetworkManager-v5.5.1-esp32s3_debug-9f0f79c-main.bin" [[net.forward]] from = "localhost:8180" to = "target:80" diff --git a/README.md b/README.md index 2db1d9f..33f5469 100644 --- a/README.md +++ b/README.md @@ -1,224 +1,224 @@ -# EasyNetworkManager Library - -> [!NOTE]\ -> A documentation website is being built for this library, you canfind it here [Documentation](https://zanzythebar.github.io/EasyNetworkManager-Docs).\ -> Please feel free to ask me any questions in the [repo discussion forum](https://github.com/ZanzyTHEbar/EasyNetworkManager/discussions).\ -> To see an example `Platformio` project that uses this library: \ -> To see an example of a widly-used production project that uses this library: - -This is an in-progress library for easy network management. - -> [!IMPORTANT]\ -> This library requires c++17 -> see [extras](#extras) - -This project supports the following boards: - -- ESP8266 -- ESP32 - -> [!NOTE]\ -> Full ESP32C3 support is still in development, please report any bugs in the issues section. -> Of note, this has been successfully tested on all boards except for the ESP32C3. -> This library fully supports M5Stack devices. - -This library provides a WiFi Manager front-end on a customisable URL endpoint using a provided HTML file. - -![WiFi Manager](/assets/images/wifimanager.png) - -It also provides numerous key features such as: - -- autodiscovery of saved networks -- saving networks to memory -- automatically creating an Access Point if connecting to a wifi network fails -- mDNS -- Async OTA -- OTA -- customisable REST API -- WebSockets - -And much more :smile: See the classes below. - -This library implements the following classes: - -- APIServer - A server that can be used to manage asynchronous REST API methods. - - has a `handleJSON` method for handling `POST` and `GET` requests. Can send and receive JSON. - - has a built-in async-ota endpoint that is disabled by default - -> [!NOTE]\ -> `POST` requests for `JSON` are still in development. - -- WiFiHandler - A class that can be used to manage WiFi connections. -- OTA - A basic OTA handler. -- MDNSHandler - A class that can be used to manage mDNS services. -- Config - A class that can be used to manage configuration files. -- StateManager - A class that can be used to manage the state of your project (very easy to extend). -- Utilities - A folder that has various template files that can be used to manage various utilities. - -## Installation - -### Platformio (recommended) - -You can install via the `Platformio Registry` by navigating to the `Libraries` section of `Platformio`. -The library is called `EasyNetworkManager` by `ZanzyTHEbar`. - -if you like to install the bleading edge, in your `platformio.ini` file add the following: - -```ini -lib_deps = - https://github.com/ZanzyTHEbar/EasyNetworkManager.git -``` - -#### Arduino IDE - -To install this library in your Arduino IDE, you must add all dependencies (sorry) and then download this repository as a zip file and it as any other library :smile:. - -## Dependencies - -All dependencies _should_ be installed automatically. If not, please make a new issue and I will fix it. - -> [!NOTE]\ -> `ESP8266` support is still in beta, for now you manually have to install the dependancies listed below. -> `ESPAsyncTCP` -> You _may_ need to install `ESP8266WiFi` if the compiler complains about it, but you shouldn't need to. - -### Dependencies used in this project - -- [ESPAsyncWebServer](https://github.com/me-no-dev/ESPAsyncWebServer.git) - -`ESP32` - -- [AsyncTCP](https://github.com/me-no-dev/AsyncTCP.git) - -`ESP8266` - -- [ESPAsyncTCP](https://github.com/me-no-dev/ESPAsyncTCP) - -## Usage - -For basic usage please see the [examples](/NetworkManager/examples) folder. - -To use the provided [wifi manager html](/NetworkManager/ui/wifimanager.html) page you don't need to do anything except for set a `define` before you include the library header (for `pio` users see the [Extras](#extras) section) - -Then, build and flash the SPIFFS image as normal. - -For the ArduinoIDE you will need to follow a tutorial on `SPIFFS` and flash any custom html files using `SPIFFS`. - -> [!WARNING]\ -> SPIFFS tools **do not** work yet in the ArduinoIDE 2.0. Support is coming soon. - -## Configuration - -> [!WARNING]\ -> It is **required** to add a build flag to your setup for the code to function properly. - -For `platformio` - -```ini -build_flags = - -DASYNCWEBSERVER_REGEX ; add regex support to AsyncWebServer -``` - -Optionally you can enable the wifi manager and the async ota here as well: - -```ini -build_flags = - -DASYNCWEBSERVER_REGEX ; add regex support to AsyncWebServer - -DUSE_WEBMANAGER ; enable wifimanager - -DUSE_ASYNCOTA ; enable async ota support -``` - -For `ArduinoIDE`: - -Create, if missing, or update the `platform.local.txt` file. - -The paths are: - -> Windows - -```bash -Windows: C:\Users\(username)\AppData\Local\Arduino15\packages\espxxxx\hardware\espxxxx\{version}\platform.local.txt -``` - -> Linux - -```bash -Linux: ~/.arduino15/packages/espxxxx/hardware/espxxxx/{version}/platform.local.txt -``` - -The text to add is: - -```txt -compiler.cpp.extra_flags=-DASYNCWEBSERVER_REGEX=1 -``` - -Optionally you can enable the wifi manager here as well: - -```txt -compiler.cpp.extra_flags=-DASYNCWEBSERVER_REGEX=1 -DUSE_WEBMANAGER=1 -``` - -> [!WARNING]\ -> This library is still in development, if there are any bugs please report them in the issues section. - -## Modification - -This library is intended to be modified and extended. If you find any bugs, please make a new issue and I will fix it. - -If you have any questions, please ask in the [discussions](https://github.com/ZanzyTHEbar/EasyNetworkManager/discussions). - -To extend any of the enums please use the `data/utilities/enuminheritance.hpp` file. - -To use your own custom config, simply inherit from the `CustomConfigInterface`, override the `save` and `load` methods,and then register your config. - -```cpp -ConfigHandler configHandler("baseConf", MDNS_HOSTNAME); - -class CustomConfig : public CustomConfigInterface { - void save() override { - this->log("Saving custom config"); - } - - void load() override { - otherStuff(); - this->log("Loading custom config"); - } - void otherStuff() { - // do stuff - } -}; - -CustomConfig customConfig; - -// pass our custom config to the base config so that it can use it. -configHandler.config.registerUserConfig(&customConfig); -``` - -## Extras - -To see any of the `log` statements used in this library - you need to add this to your `platformio.ini`: - -```ini -build_flags = - -DASYNCWEBSERVER_REGEX # add regex support to AsyncWebServer - -DUSE_WEBMANAGER # enable wifimanager - -DCORE_DEBUG_LEVEL=4 # add debug logging in serial monitor - -std=gnu++17 -build_unflags = -std=gnu++11 - -; other build parameters -monitor_filters = - esp32_exception_decoder -build_type = debug -lib_ldf_mode = deep -``` - -If you want to build in debug mode add this (it's not a build flag): - -```ini -build_type = debug -``` - -## License - -This library is licensed under the MIT License. +# EasyNetworkManager Library + +> [!NOTE]\ +> A documentation website is being built for this library, you canfind it here [Documentation](https://zanzythebar.github.io/EasyNetworkManager-Docs).\ +> Please feel free to ask me any questions in the [repo discussion forum](https://github.com/ZanzyTHEbar/EasyNetworkManager/discussions).\ +> To see an example `Platformio` project that uses this library: \ +> To see an example of a widly-used production project that uses this library: + +This is an in-progress library for easy network management. + +> [!IMPORTANT]\ +> This library requires c++17 +> see [extras](#extras) + +This project supports the following boards: + +- ESP8266 +- ESP32 + +> [!NOTE]\ +> Full ESP32C3 support is still in development, please report any bugs in the issues section. +> Of note, this has been successfully tested on all boards except for the ESP32C3. +> This library fully supports M5Stack devices. + +This library provides a WiFi Manager front-end on a customisable URL endpoint using a provided HTML file. + +![WiFi Manager](/assets/images/wifimanager.png) + +It also provides numerous key features such as: + +- autodiscovery of saved networks +- saving networks to memory +- automatically creating an Access Point if connecting to a wifi network fails +- mDNS +- Async OTA +- OTA +- customisable REST API +- WebSockets + +And much more :smile: See the classes below. + +This library implements the following classes: + +- APIServer - A server that can be used to manage asynchronous REST API methods. + - has a `handleJSON` method for handling `POST` and `GET` requests. Can send and receive JSON. + - has a built-in async-ota endpoint that is disabled by default + +> [!NOTE]\ +> `POST` requests for `JSON` are still in development. + +- WiFiHandler - A class that can be used to manage WiFi connections. +- OTA - A basic OTA handler. +- MDNSHandler - A class that can be used to manage mDNS services. +- Config - A class that can be used to manage configuration files. +- StateManager - A class that can be used to manage the state of your project (very easy to extend). +- Utilities - A folder that has various template files that can be used to manage various utilities. + +## Installation + +### Platformio (recommended) + +You can install via the `Platformio Registry` by navigating to the `Libraries` section of `Platformio`. +The library is called `EasyNetworkManager` by `ZanzyTHEbar`. + +if you like to install the bleading edge, in your `platformio.ini` file add the following: + +```ini +lib_deps = + https://github.com/ZanzyTHEbar/EasyNetworkManager.git +``` + +#### Arduino IDE + +To install this library in your Arduino IDE, you must add all dependencies (sorry) and then download this repository as a zip file and it as any other library :smile:. + +## Dependencies + +All dependencies _should_ be installed automatically. If not, please make a new issue and I will fix it. + +> [!NOTE]\ +> `ESP8266` support is still in beta, for now you manually have to install the dependancies listed below. +> `ESPAsyncTCP` +> You _may_ need to install `ESP8266WiFi` if the compiler complains about it, but you shouldn't need to. + +### Dependencies used in this project + +- [ESPAsyncWebServer](https://github.com/me-no-dev/ESPAsyncWebServer.git) + +`ESP32` + +- [AsyncTCP](https://github.com/me-no-dev/AsyncTCP.git) + +`ESP8266` + +- [ESPAsyncTCP](https://github.com/me-no-dev/ESPAsyncTCP) + +## Usage + +For basic usage please see the [examples](/NetworkManager/examples) folder. + +To use the provided [wifi manager html](/NetworkManager/ui/wifimanager.html) page you don't need to do anything except for set a `define` before you include the library header (for `pio` users see the [Extras](#extras) section) + +Then, build and flash the SPIFFS image as normal. + +For the ArduinoIDE you will need to follow a tutorial on `SPIFFS` and flash any custom html files using `SPIFFS`. + +> [!WARNING]\ +> SPIFFS tools **do not** work yet in the ArduinoIDE 2.0. Support is coming soon. + +## Configuration + +> [!WARNING]\ +> It is **required** to add a build flag to your setup for the code to function properly. + +For `platformio` + +```ini +build_flags = + -DASYNCWEBSERVER_REGEX ; add regex support to AsyncWebServer +``` + +Optionally you can enable the wifi manager and the async ota here as well: + +```ini +build_flags = + -DASYNCWEBSERVER_REGEX ; add regex support to AsyncWebServer + -DUSE_WEBMANAGER ; enable wifimanager + -DUSE_ASYNCOTA ; enable async ota support +``` + +For `ArduinoIDE`: + +Create, if missing, or update the `platform.local.txt` file. + +The paths are: + +> Windows + +```bash +Windows: C:\Users\(username)\AppData\Local\Arduino15\packages\espxxxx\hardware\espxxxx\{version}\platform.local.txt +``` + +> Linux + +```bash +Linux: ~/.arduino15/packages/espxxxx/hardware/espxxxx/{version}/platform.local.txt +``` + +The text to add is: + +```txt +compiler.cpp.extra_flags=-DASYNCWEBSERVER_REGEX=1 +``` + +Optionally you can enable the wifi manager here as well: + +```txt +compiler.cpp.extra_flags=-DASYNCWEBSERVER_REGEX=1 -DUSE_WEBMANAGER=1 +``` + +> [!WARNING]\ +> This library is still in development, if there are any bugs please report them in the issues section. + +## Modification + +This library is intended to be modified and extended. If you find any bugs, please make a new issue and I will fix it. + +If you have any questions, please ask in the [discussions](https://github.com/ZanzyTHEbar/EasyNetworkManager/discussions). + +To extend any of the enums please use the `data/utilities/enuminheritance.hpp` file. + +To use your own custom config, simply inherit from the `CustomConfigInterface`, override the `save` and `load` methods,and then register your config. + +```cpp +ConfigHandler configHandler("baseConf", MDNS_HOSTNAME); + +class CustomConfig : public CustomConfigInterface { + void save() override { + this->log("Saving custom config"); + } + + void load() override { + otherStuff(); + this->log("Loading custom config"); + } + void otherStuff() { + // do stuff + } +}; + +CustomConfig customConfig; + +// pass our custom config to the base config so that it can use it. +configHandler.config.registerUserConfig(&customConfig); +``` + +## Extras + +To see any of the `log` statements used in this library - you need to add this to your `platformio.ini`: + +```ini +build_flags = + -DASYNCWEBSERVER_REGEX # add regex support to AsyncWebServer + -DUSE_WEBMANAGER # enable wifimanager + -DCORE_DEBUG_LEVEL=4 # add debug logging in serial monitor + -std=gnu++17 +build_unflags = -std=gnu++11 + +; other build parameters +monitor_filters = + esp32_exception_decoder +build_type = debug +lib_ldf_mode = deep +``` + +If you want to build in debug mode add this (it's not a build flag): + +```ini +build_type = debug +``` + +## License + +This library is licensed under the MIT License.