diff --git a/.vscode/settings.json b/.vscode/settings.json index 5e9bf69..2ff8141 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,6 +1,15 @@ { "files.associations": { - "cmath": "cpp" + "cmath": "cpp", + "array": "cpp", + "deque": "cpp", + "string": "cpp", + "unordered_map": "cpp", + "unordered_set": "cpp", + "vector": "cpp", + "string_view": "cpp", + "initializer_list": "cpp", + "regex": "cpp" }, "editor.tabSize": 4, "editor.detectIndentation": false, diff --git a/app2/src/app.html b/app2/src/app.html index 77a5ff5..f9adea3 100644 --- a/app2/src/app.html +++ b/app2/src/app.html @@ -2,7 +2,7 @@ - + %sveltekit.head% diff --git a/app2/static/favicon.png b/app2/static/favicon.png deleted file mode 100644 index 825b9e6..0000000 Binary files a/app2/static/favicon.png and /dev/null differ diff --git a/app2/static/logo512.png b/app2/static/logo512.png index 484acab..aca8aac 100644 Binary files a/app2/static/logo512.png and b/app2/static/logo512.png differ diff --git a/app2/static/snowy_forest_4k.exr b/app2/static/snowy_forest_4k.exr deleted file mode 100644 index 5500c30..0000000 Binary files a/app2/static/snowy_forest_4k.exr and /dev/null differ diff --git a/app2/static/snowy_park_01_4k.exr b/app2/static/snowy_park_01_4k.exr deleted file mode 100644 index 1e54ad4..0000000 Binary files a/app2/static/snowy_park_01_4k.exr and /dev/null differ diff --git a/app2/static/stl.zip b/app2/static/stl.zip index fee7639..bf2fb9f 100644 Binary files a/app2/static/stl.zip and b/app2/static/stl.zip differ diff --git a/app2/static/stl/backpart.stl b/app2/static/stl/backpart.stl deleted file mode 100644 index 8e06a4c..0000000 Binary files a/app2/static/stl/backpart.stl and /dev/null differ diff --git a/app2/static/stl/foot.stl b/app2/static/stl/foot.stl deleted file mode 100644 index 4196e90..0000000 Binary files a/app2/static/stl/foot.stl and /dev/null differ diff --git a/app2/static/stl/frontpart.stl b/app2/static/stl/frontpart.stl deleted file mode 100644 index 8e9dff7..0000000 Binary files a/app2/static/stl/frontpart.stl and /dev/null differ diff --git a/app2/static/stl/larm.stl b/app2/static/stl/larm.stl deleted file mode 100644 index 969b2e5..0000000 Binary files a/app2/static/stl/larm.stl and /dev/null differ diff --git a/app2/static/stl/larm_cover.stl b/app2/static/stl/larm_cover.stl deleted file mode 100644 index 006a919..0000000 Binary files a/app2/static/stl/larm_cover.stl and /dev/null differ diff --git a/app2/static/stl/lfoot.stl b/app2/static/stl/lfoot.stl deleted file mode 100644 index 75aa50a..0000000 Binary files a/app2/static/stl/lfoot.stl and /dev/null differ diff --git a/app2/static/stl/lshoulder.stl b/app2/static/stl/lshoulder.stl deleted file mode 100644 index 00ea7a8..0000000 Binary files a/app2/static/stl/lshoulder.stl and /dev/null differ diff --git a/app2/static/stl/mainbody.stl b/app2/static/stl/mainbody.stl deleted file mode 100644 index 6779423..0000000 Binary files a/app2/static/stl/mainbody.stl and /dev/null differ diff --git a/app2/static/stl/rarm.stl b/app2/static/stl/rarm.stl deleted file mode 100644 index 67626a2..0000000 Binary files a/app2/static/stl/rarm.stl and /dev/null differ diff --git a/app2/static/stl/rarm_cover.stl b/app2/static/stl/rarm_cover.stl deleted file mode 100644 index 94da81c..0000000 Binary files a/app2/static/stl/rarm_cover.stl and /dev/null differ diff --git a/app2/static/stl/rfoot.stl b/app2/static/stl/rfoot.stl deleted file mode 100644 index 93497cc..0000000 Binary files a/app2/static/stl/rfoot.stl and /dev/null differ diff --git a/app2/static/stl/rshoulder.stl b/app2/static/stl/rshoulder.stl deleted file mode 100644 index b11f06c..0000000 Binary files a/app2/static/stl/rshoulder.stl and /dev/null differ diff --git a/app2/svelte.config.js b/app2/svelte.config.js index ec82263..15e95d0 100644 --- a/app2/svelte.config.js +++ b/app2/svelte.config.js @@ -9,8 +9,10 @@ const config = { kit: { adapter: adapter({ - pages: '../esp32/data', - assets: '../esp32/data', + pages: 'build', + assets: 'build', + pages: '../esp32/www', + assets: '../esp32/www', fallback: 'index.html', precompress: false, strict: true diff --git a/esp32/.vscode/c_cpp_properties.json b/esp32/.vscode/c_cpp_properties.json new file mode 100644 index 0000000..6ad9ec3 --- /dev/null +++ b/esp32/.vscode/c_cpp_properties.json @@ -0,0 +1,566 @@ +// +// !!! WARNING !!! AUTO-GENERATED FILE! +// PLEASE DO NOT MODIFY IT AND USE "platformio.ini": +// https://docs.platformio.org/page/projectconf/section_env_build.html#build-flags +// +{ + "configurations": [ + { + "name": "PlatformIO", + "includePath": [ + "C:/data/repos/Hardware/Spot Micro - Leika/esp32/include", + "C:/data/repos/Hardware/Spot Micro - Leika/esp32/src", + "C:/data/repos/Hardware/Spot Micro - Leika/esp32/lib/ESP32-sveltekit", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/libraries/LittleFS/src", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/libraries/HTTPUpdate/src", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/libraries/Update/src", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/libraries/HTTPClient/src", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/libraries/DNSServer/src", + "C:/data/repos/Hardware/Spot Micro - Leika/esp32/lib/PsychicHttp/src", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/libraries/FS/src", + "C:/data/repos/Hardware/Spot Micro - Leika/esp32/.pio/libdeps/esp32dev/UrlEncode/src", + "C:/data/repos/Hardware/Spot Micro - Leika/esp32/.pio/libdeps/esp32dev/ArduinoTrace", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/libraries/ESPmDNS/src", + "C:/data/repos/Hardware/Spot Micro - Leika/esp32/.pio/libdeps/esp32dev/PsychicMqttClient/src", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/libraries/WiFiClientSecure/src", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/libraries/WiFi/src", + "C:/data/repos/Hardware/Spot Micro - Leika/esp32/.pio/libdeps/esp32dev/ArduinoJson/src", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/newlib/platform_include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/freertos/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/freertos/include/esp_additions/freertos", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/freertos/port/xtensa/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/freertos/include/esp_additions", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_hw_support/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_hw_support/include/soc", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_hw_support/include/soc/esp32", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_hw_support/port/esp32", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_hw_support/port/esp32/private_include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/heap/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/log/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/lwip/include/apps", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/lwip/include/apps/sntp", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/lwip/lwip/src/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/lwip/port/esp32/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/lwip/port/esp32/include/arch", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/soc/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/soc/esp32", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/soc/esp32/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/hal/esp32/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/hal/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/hal/platform_port/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_rom/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_rom/include/esp32", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_rom/esp32", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_common/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_system/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_system/port/soc", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_system/port/public_compat", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp32/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/xtensa/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/xtensa/esp32/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/driver/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/driver/esp32/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_pm/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_ringbuf/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/efuse/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/efuse/esp32/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/vfs/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_wifi/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_event/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_netif/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_eth/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/tcpip_adapter/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_phy/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_phy/esp32/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_ipc/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/app_trace/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_timer/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/mbedtls/port/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/mbedtls/mbedtls/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/mbedtls/esp_crt_bundle/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/app_update/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/spi_flash/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/bootloader_support/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/nvs_flash/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/pthread/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_gdbstub/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_gdbstub/xtensa", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_gdbstub/esp32", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/espcoredump/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/espcoredump/include/port/xtensa", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/wpa_supplicant/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/wpa_supplicant/port/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/wpa_supplicant/esp_supplicant/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/ieee802154/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/console", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/asio/asio/asio/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/asio/port/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/bt/common/osi/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/bt/include/esp32/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/bt/common/api/include/api", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/bt/common/btc/profile/esp/blufi/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/bt/common/btc/profile/esp/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/bt/host/bluedroid/api/include/api", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/bt/esp_ble_mesh/mesh_common/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/bt/esp_ble_mesh/mesh_common/tinycrypt/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/bt/esp_ble_mesh/mesh_core", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/bt/esp_ble_mesh/mesh_core/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/bt/esp_ble_mesh/mesh_core/storage", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/bt/esp_ble_mesh/btc/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/bt/esp_ble_mesh/mesh_models/common/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/bt/esp_ble_mesh/mesh_models/client/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/bt/esp_ble_mesh/mesh_models/server/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/bt/esp_ble_mesh/api/core/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/bt/esp_ble_mesh/api/models/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/bt/esp_ble_mesh/api", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/cbor/port/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/unity/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/unity/unity/src", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/cmock/CMock/src", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/coap/port/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/coap/libcoap/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/nghttp/port/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/nghttp/nghttp2/lib/includes", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp-tls", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp-tls/esp-tls-crypto", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_adc_cal/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_hid/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/tcp_transport/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_http_client/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_http_server/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_https_ota/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_https_server/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_lcd/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_lcd/interface", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/protobuf-c/protobuf-c", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/protocomm/include/common", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/protocomm/include/security", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/protocomm/include/transports", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/mdns/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_local_ctrl/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/sdmmc/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_serial_slave_link/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_websocket_client/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/expat/expat/expat/lib", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/expat/port/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/wear_levelling/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/fatfs/diskio", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/fatfs/vfs", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/fatfs/src", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/freemodbus/freemodbus/common/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/idf_test/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/idf_test/include/esp32", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/jsmn/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/json/cJSON", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/libsodium/libsodium/src/libsodium/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/libsodium/port_include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/mqtt/esp-mqtt/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/openssl/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/perfmon/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/spiffs/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/ulp/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/wifi_provisioning/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/rmaker_common/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_diagnostics/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/rtc_store/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_insights/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/json_parser/upstream/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/json_parser/upstream", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/json_generator/upstream", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_schedule/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/espressif__esp_secure_cert_mgr/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_rainmaker/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/gpio_button/button/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/qrcode/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/ws2812_led", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_littlefs/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp-dl/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp-dl/include/tool", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp-dl/include/typedef", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp-dl/include/image", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp-dl/include/math", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp-dl/include/nn", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp-dl/include/layer", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp-dl/include/detect", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp-dl/include/model_zoo", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp-sr/src/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp-sr/esp-tts/esp_tts_chinese/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp-sr/include/esp32", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp32-camera/driver/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp32-camera/conversions/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/espressif__esp-dsp/modules/dotprod/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/espressif__esp-dsp/modules/support/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/espressif__esp-dsp/modules/windows/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/espressif__esp-dsp/modules/windows/hann/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/espressif__esp-dsp/modules/windows/blackman/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/espressif__esp-dsp/modules/windows/blackman_harris/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/espressif__esp-dsp/modules/windows/blackman_nuttall/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/espressif__esp-dsp/modules/windows/nuttall/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/espressif__esp-dsp/modules/windows/flat_top/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/espressif__esp-dsp/modules/iir/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/espressif__esp-dsp/modules/fir/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/espressif__esp-dsp/modules/math/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/espressif__esp-dsp/modules/math/add/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/espressif__esp-dsp/modules/math/sub/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/espressif__esp-dsp/modules/math/mul/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/espressif__esp-dsp/modules/math/addc/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/espressif__esp-dsp/modules/math/mulc/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/espressif__esp-dsp/modules/math/sqrt/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/espressif__esp-dsp/modules/matrix/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/espressif__esp-dsp/modules/fft/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/espressif__esp-dsp/modules/dct/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/espressif__esp-dsp/modules/conv/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/espressif__esp-dsp/modules/common/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/espressif__esp-dsp/modules/kalman/ekf/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/espressif__esp-dsp/modules/kalman/ekf_imu13states/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/fb_gfx/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/dio_qspi/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/cores/esp32", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/variants/esp32", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/libraries/ArduinoOTA/src", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/libraries/AsyncUDP/src", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/libraries/BLE/src", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/libraries/BluetoothSerial/src", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/libraries/EEPROM/src", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/libraries/ESP32/src", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/libraries/Ethernet/src", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/libraries/FFat/src", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/libraries/HTTPUpdateServer/src", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/libraries/I2S/src", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/libraries/Insights/src", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/libraries/NetBIOS/src", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/libraries/Preferences/src", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/libraries/RainMaker/src", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/libraries/SD/src", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/libraries/SD_MMC/src", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/libraries/SPI/src", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/libraries/SPIFFS/src", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/libraries/SimpleBLE/src", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/libraries/Ticker/src", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/libraries/USB/src", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/libraries/WebServer/src", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/libraries/WiFiProv/src", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/libraries/Wire/src", + "" + ], + "browse": { + "limitSymbolsToIncludedHeaders": true, + "path": [ + "C:/data/repos/Hardware/Spot Micro - Leika/esp32/include", + "C:/data/repos/Hardware/Spot Micro - Leika/esp32/src", + "C:/data/repos/Hardware/Spot Micro - Leika/esp32/lib/ESP32-sveltekit", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/libraries/LittleFS/src", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/libraries/HTTPUpdate/src", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/libraries/Update/src", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/libraries/HTTPClient/src", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/libraries/DNSServer/src", + "C:/data/repos/Hardware/Spot Micro - Leika/esp32/lib/PsychicHttp/src", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/libraries/FS/src", + "C:/data/repos/Hardware/Spot Micro - Leika/esp32/.pio/libdeps/esp32dev/UrlEncode/src", + "C:/data/repos/Hardware/Spot Micro - Leika/esp32/.pio/libdeps/esp32dev/ArduinoTrace", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/libraries/ESPmDNS/src", + "C:/data/repos/Hardware/Spot Micro - Leika/esp32/.pio/libdeps/esp32dev/PsychicMqttClient/src", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/libraries/WiFiClientSecure/src", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/libraries/WiFi/src", + "C:/data/repos/Hardware/Spot Micro - Leika/esp32/.pio/libdeps/esp32dev/ArduinoJson/src", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/newlib/platform_include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/freertos/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/freertos/include/esp_additions/freertos", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/freertos/port/xtensa/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/freertos/include/esp_additions", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_hw_support/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_hw_support/include/soc", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_hw_support/include/soc/esp32", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_hw_support/port/esp32", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_hw_support/port/esp32/private_include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/heap/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/log/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/lwip/include/apps", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/lwip/include/apps/sntp", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/lwip/lwip/src/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/lwip/port/esp32/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/lwip/port/esp32/include/arch", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/soc/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/soc/esp32", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/soc/esp32/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/hal/esp32/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/hal/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/hal/platform_port/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_rom/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_rom/include/esp32", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_rom/esp32", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_common/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_system/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_system/port/soc", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_system/port/public_compat", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp32/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/xtensa/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/xtensa/esp32/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/driver/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/driver/esp32/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_pm/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_ringbuf/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/efuse/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/efuse/esp32/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/vfs/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_wifi/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_event/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_netif/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_eth/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/tcpip_adapter/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_phy/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_phy/esp32/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_ipc/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/app_trace/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_timer/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/mbedtls/port/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/mbedtls/mbedtls/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/mbedtls/esp_crt_bundle/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/app_update/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/spi_flash/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/bootloader_support/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/nvs_flash/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/pthread/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_gdbstub/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_gdbstub/xtensa", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_gdbstub/esp32", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/espcoredump/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/espcoredump/include/port/xtensa", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/wpa_supplicant/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/wpa_supplicant/port/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/wpa_supplicant/esp_supplicant/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/ieee802154/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/console", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/asio/asio/asio/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/asio/port/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/bt/common/osi/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/bt/include/esp32/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/bt/common/api/include/api", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/bt/common/btc/profile/esp/blufi/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/bt/common/btc/profile/esp/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/bt/host/bluedroid/api/include/api", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/bt/esp_ble_mesh/mesh_common/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/bt/esp_ble_mesh/mesh_common/tinycrypt/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/bt/esp_ble_mesh/mesh_core", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/bt/esp_ble_mesh/mesh_core/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/bt/esp_ble_mesh/mesh_core/storage", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/bt/esp_ble_mesh/btc/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/bt/esp_ble_mesh/mesh_models/common/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/bt/esp_ble_mesh/mesh_models/client/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/bt/esp_ble_mesh/mesh_models/server/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/bt/esp_ble_mesh/api/core/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/bt/esp_ble_mesh/api/models/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/bt/esp_ble_mesh/api", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/cbor/port/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/unity/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/unity/unity/src", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/cmock/CMock/src", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/coap/port/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/coap/libcoap/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/nghttp/port/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/nghttp/nghttp2/lib/includes", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp-tls", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp-tls/esp-tls-crypto", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_adc_cal/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_hid/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/tcp_transport/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_http_client/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_http_server/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_https_ota/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_https_server/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_lcd/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_lcd/interface", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/protobuf-c/protobuf-c", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/protocomm/include/common", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/protocomm/include/security", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/protocomm/include/transports", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/mdns/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_local_ctrl/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/sdmmc/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_serial_slave_link/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_websocket_client/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/expat/expat/expat/lib", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/expat/port/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/wear_levelling/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/fatfs/diskio", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/fatfs/vfs", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/fatfs/src", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/freemodbus/freemodbus/common/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/idf_test/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/idf_test/include/esp32", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/jsmn/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/json/cJSON", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/libsodium/libsodium/src/libsodium/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/libsodium/port_include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/mqtt/esp-mqtt/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/openssl/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/perfmon/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/spiffs/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/ulp/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/wifi_provisioning/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/rmaker_common/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_diagnostics/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/rtc_store/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_insights/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/json_parser/upstream/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/json_parser/upstream", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/json_generator/upstream", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_schedule/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/espressif__esp_secure_cert_mgr/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_rainmaker/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/gpio_button/button/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/qrcode/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/ws2812_led", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_littlefs/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp-dl/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp-dl/include/tool", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp-dl/include/typedef", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp-dl/include/image", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp-dl/include/math", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp-dl/include/nn", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp-dl/include/layer", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp-dl/include/detect", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp-dl/include/model_zoo", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp-sr/src/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp-sr/esp-tts/esp_tts_chinese/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp-sr/include/esp32", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp32-camera/driver/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp32-camera/conversions/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/espressif__esp-dsp/modules/dotprod/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/espressif__esp-dsp/modules/support/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/espressif__esp-dsp/modules/windows/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/espressif__esp-dsp/modules/windows/hann/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/espressif__esp-dsp/modules/windows/blackman/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/espressif__esp-dsp/modules/windows/blackman_harris/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/espressif__esp-dsp/modules/windows/blackman_nuttall/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/espressif__esp-dsp/modules/windows/nuttall/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/espressif__esp-dsp/modules/windows/flat_top/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/espressif__esp-dsp/modules/iir/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/espressif__esp-dsp/modules/fir/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/espressif__esp-dsp/modules/math/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/espressif__esp-dsp/modules/math/add/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/espressif__esp-dsp/modules/math/sub/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/espressif__esp-dsp/modules/math/mul/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/espressif__esp-dsp/modules/math/addc/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/espressif__esp-dsp/modules/math/mulc/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/espressif__esp-dsp/modules/math/sqrt/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/espressif__esp-dsp/modules/matrix/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/espressif__esp-dsp/modules/fft/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/espressif__esp-dsp/modules/dct/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/espressif__esp-dsp/modules/conv/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/espressif__esp-dsp/modules/common/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/espressif__esp-dsp/modules/kalman/ekf/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/espressif__esp-dsp/modules/kalman/ekf_imu13states/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/fb_gfx/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/dio_qspi/include", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/cores/esp32", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/variants/esp32", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/libraries/ArduinoOTA/src", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/libraries/AsyncUDP/src", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/libraries/BLE/src", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/libraries/BluetoothSerial/src", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/libraries/EEPROM/src", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/libraries/ESP32/src", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/libraries/Ethernet/src", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/libraries/FFat/src", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/libraries/HTTPUpdateServer/src", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/libraries/I2S/src", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/libraries/Insights/src", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/libraries/NetBIOS/src", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/libraries/Preferences/src", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/libraries/RainMaker/src", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/libraries/SD/src", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/libraries/SD_MMC/src", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/libraries/SPI/src", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/libraries/SPIFFS/src", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/libraries/SimpleBLE/src", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/libraries/Ticker/src", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/libraries/USB/src", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/libraries/WebServer/src", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/libraries/WiFiProv/src", + "C:/Users/Rune/.platformio/packages/framework-arduinoespressif32/libraries/Wire/src", + "" + ] + }, + "defines": [ + "PLATFORMIO=60114", + "ARDUINO_ESP32_DEV", + "APP_NAME=\"Spot-Micro\"", + "APP_VERSION=\"0.0.1\"", + "FACTORY_WIFI_SSID=\"\"", + "FACTORY_WIFI_PASSWORD=\"\"", + "FACTORY_WIFI_HOSTNAME=\"#{platform}-#{unique_id}\"", + "FACTORY_AP_PROVISION_MODE=AP_MODE_DISCONNECTED", + "FACTORY_AP_SSID=\"Spot-Micro-#{unique_id}\"", + "FACTORY_AP_PASSWORD=\"esp-react\"", + "FACTORY_AP_CHANNEL=1", + "FACTORY_AP_SSID_HIDDEN=false", + "FACTORY_AP_MAX_CLIENTS=4", + "FACTORY_AP_LOCAL_IP=\"192.168.4.1\"", + "FACTORY_AP_GATEWAY_IP=\"192.168.4.1\"", + "FACTORY_AP_SUBNET_MASK=\"255.255.255.0\"", + "FACTORY_ADMIN_USERNAME=\"admin\"", + "FACTORY_ADMIN_PASSWORD=\"admin\"", + "FACTORY_GUEST_USERNAME=\"guest\"", + "FACTORY_GUEST_PASSWORD=\"guest\"", + "FACTORY_NTP_ENABLED=true", + "FACTORY_NTP_TIME_ZONE_LABEL=\"Europe/London\"", + "FACTORY_NTP_TIME_ZONE_FORMAT=\"GMT0BST,M3.5.0/1,M10.5.0\"", + "FACTORY_NTP_SERVER=\"time.google.com\"", + "FACTORY_OTA_PORT=8266", + "FACTORY_OTA_PASSWORD=\"spot-leika\"", + "FACTORY_OTA_ENABLED=true", + "FACTORY_MQTT_ENABLED=false", + "FACTORY_MQTT_URI=\"test.mosquitto.org\"", + "FACTORY_MQTT_PORT=1883", + "FACTORY_MQTT_USERNAME=\"\"", + "FACTORY_MQTT_PASSWORD=\"\"", + "FACTORY_MQTT_CLIENT_ID=\"#{platform}-#{unique_id}\"", + "FACTORY_MQTT_KEEP_ALIVE=60", + "FACTORY_MQTT_CLEAN_SESSION=true", + "FACTORY_MQTT_MAX_TOPIC_LENGTH=128", + "FACTORY_JWT_SECRET=\"#{random}-#{random}\"", + "USE_BATTERY=1", + "USE_NTP=1", + "USE_SECURITY=1", + "USE_UPLOAD_FIRMWARE=1", + "USE_DOWNLOAD_FIRMWARE=1", + "USE_ANALYTICS=1", + "BUILD_TARGET=\"esp32dev\"", + "ESP32SVELTEKIT_RUNNING_CORE=0", + "EMBED_WWW", + "ENABLE_CORS", + "SERIAL_INFO", + "CORS_ORIGIN=\"*\"", + "CORE_DEBUG_LEVEL=5", + "register=", + "LED_BUILTIN=2", + "KEY_BUILTIN=0", + "HAVE_CONFIG_H", + "MBEDTLS_CONFIG_FILE=\"mbedtls/esp_config.h\"", + "UNITY_INCLUDE_CONFIG_H", + "WITH_POSIX", + "_GNU_SOURCE", + "IDF_VER=\"v4.4.4\"", + "ESP_PLATFORM", + "_POSIX_READER_WRITER_LOCKS", + "ARDUINO_ARCH_ESP32", + "ESP32", + "F_CPU=240000000L", + "ARDUINO=10812", + "ARDUINO_VARIANT=\"esp32\"", + "ARDUINO_BOARD=\"Espressif ESP32 Dev Module\"", + "ARDUINO_PARTITION_min_spiffs", + "" + ], + "cStandard": "gnu99", + "cppStandard": "gnu++17", + "compilerPath": "C:/Users/Rune/.platformio/packages/toolchain-xtensa-esp32/bin/xtensa-esp32-elf-gcc.exe", + "compilerArgs": [ + "-mlongcalls", + "" + ] + } + ], + "version": 4 +} diff --git a/esp32/.vscode/extensions.json b/esp32/.vscode/extensions.json new file mode 100644 index 0000000..080e70d --- /dev/null +++ b/esp32/.vscode/extensions.json @@ -0,0 +1,10 @@ +{ + // See http://go.microsoft.com/fwlink/?LinkId=827846 + // for the documentation about the extensions.json format + "recommendations": [ + "platformio.platformio-ide" + ], + "unwantedRecommendations": [ + "ms-vscode.cpptools-extension-pack" + ] +} diff --git a/esp32/.vscode/launch.json b/esp32/.vscode/launch.json new file mode 100644 index 0000000..b917536 --- /dev/null +++ b/esp32/.vscode/launch.json @@ -0,0 +1,44 @@ +// AUTOMATICALLY GENERATED FILE. PLEASE DO NOT MODIFY IT MANUALLY +// +// PlatformIO Debugging Solution +// +// Documentation: https://docs.platformio.org/en/latest/plus/debugging.html +// Configuration: https://docs.platformio.org/en/latest/projectconf/sections/env/options/debug/index.html + +{ + "version": "0.2.0", + "configurations": [ + { + "type": "platformio-debug", + "request": "launch", + "name": "PIO Debug", + "executable": "C:/data/repos/Hardware/Spot Micro - Leika/esp32/.pio/build/esp32dev/firmware.elf", + "projectEnvName": "esp32dev", + "toolchainBinDir": "C:/Users/Rune/.platformio/packages/toolchain-xtensa-esp32/bin", + "internalConsoleOptions": "openOnSessionStart", + "preLaunchTask": { + "type": "PlatformIO", + "task": "Pre-Debug" + } + }, + { + "type": "platformio-debug", + "request": "launch", + "name": "PIO Debug (skip Pre-Debug)", + "executable": "C:/data/repos/Hardware/Spot Micro - Leika/esp32/.pio/build/esp32dev/firmware.elf", + "projectEnvName": "esp32dev", + "toolchainBinDir": "C:/Users/Rune/.platformio/packages/toolchain-xtensa-esp32/bin", + "internalConsoleOptions": "openOnSessionStart" + }, + { + "type": "platformio-debug", + "request": "launch", + "name": "PIO Debug (without uploading)", + "executable": "C:/data/repos/Hardware/Spot Micro - Leika/esp32/.pio/build/esp32dev/firmware.elf", + "projectEnvName": "esp32dev", + "toolchainBinDir": "C:/Users/Rune/.platformio/packages/toolchain-xtensa-esp32/bin", + "internalConsoleOptions": "openOnSessionStart", + "loadMode": "manual" + } + ] +} diff --git a/esp32/build_settings.ini b/esp32/build_settings.ini new file mode 100644 index 0000000..441d5fb --- /dev/null +++ b/esp32/build_settings.ini @@ -0,0 +1,8 @@ +[build_settings] +build_flags = + -D BUILD_TARGET=\"$PIOENV\" + -D ESP32SVELTEKIT_RUNNING_CORE=0 + -D EMBED_WWW + -D ENABLE_CORS + -D SERIAL_INFO + -D CORS_ORIGIN=\"*\" \ No newline at end of file diff --git a/esp32/factory_settings.ini b/esp32/factory_settings.ini index 115157c..ae9334d 100644 --- a/esp32/factory_settings.ini +++ b/esp32/factory_settings.ini @@ -6,49 +6,52 @@ [factory_settings] build_flags = - ; WiFi settings - -D FACTORY_WIFI_SSID=\"\" - -D FACTORY_WIFI_PASSWORD=\"\" - -D FACTORY_WIFI_HOSTNAME=\"#{platform}-#{unique_id}\" ; supports placeholders + -D APP_NAME=\"Spot-Micro\" ; [a-zA-Z0-9-_] + -D APP_VERSION=\"0.0.1\" - ; Access point settings - -D FACTORY_AP_PROVISION_MODE=AP_MODE_DISCONNECTED - -D FACTORY_AP_SSID=\"ESP8266-React-#{unique_id}\" ; 1-64 characters, supports placeholders - -D FACTORY_AP_PASSWORD=\"esp-react\" ; 8-64 characters - -D FACTORY_AP_CHANNEL=1 - -D FACTORY_AP_SSID_HIDDEN=false - -D FACTORY_AP_MAX_CLIENTS=4 - -D FACTORY_AP_LOCAL_IP=\"192.168.4.1\" - -D FACTORY_AP_GATEWAY_IP=\"192.168.4.1\" - -D FACTORY_AP_SUBNET_MASK=\"255.255.255.0\" + ; WiFi settings + -D FACTORY_WIFI_SSID=\"\" + -D FACTORY_WIFI_PASSWORD=\"\" + -D FACTORY_WIFI_HOSTNAME=\"#{platform}-#{unique_id}\" ; supports placeholders - ; User credentials for admin and guest user - -D FACTORY_ADMIN_USERNAME=\"admin\" - -D FACTORY_ADMIN_PASSWORD=\"admin\" - -D FACTORY_GUEST_USERNAME=\"guest\" - -D FACTORY_GUEST_PASSWORD=\"guest\" + ; Access point settings + -D FACTORY_AP_PROVISION_MODE=AP_MODE_DISCONNECTED + -D FACTORY_AP_SSID=\"Spot-Micro-#{unique_id}\" ; 1-64 characters, supports placeholders + -D FACTORY_AP_PASSWORD=\"esp-react\" ; 8-64 characters + -D FACTORY_AP_CHANNEL=1 + -D FACTORY_AP_SSID_HIDDEN=false + -D FACTORY_AP_MAX_CLIENTS=4 + -D FACTORY_AP_LOCAL_IP=\"192.168.4.1\" + -D FACTORY_AP_GATEWAY_IP=\"192.168.4.1\" + -D FACTORY_AP_SUBNET_MASK=\"255.255.255.0\" - ; NTP settings - -D FACTORY_NTP_ENABLED=true - -D FACTORY_NTP_TIME_ZONE_LABEL=\"Europe/London\" - -D FACTORY_NTP_TIME_ZONE_FORMAT=\"GMT0BST,M3.5.0/1,M10.5.0\" - -D FACTORY_NTP_SERVER=\"time.google.com\" + ; User credentials for admin and guest user + -D FACTORY_ADMIN_USERNAME=\"admin\" + -D FACTORY_ADMIN_PASSWORD=\"admin\" + -D FACTORY_GUEST_USERNAME=\"guest\" + -D FACTORY_GUEST_PASSWORD=\"guest\" - ; OTA settings - -D FACTORY_OTA_PORT=8266 - -D FACTORY_OTA_PASSWORD=\"esp-react\" - -D FACTORY_OTA_ENABLED=true + ; NTP settings + -D FACTORY_NTP_ENABLED=true + -D FACTORY_NTP_TIME_ZONE_LABEL=\"Europe/London\" + -D FACTORY_NTP_TIME_ZONE_FORMAT=\"GMT0BST,M3.5.0/1,M10.5.0\" + -D FACTORY_NTP_SERVER=\"time.google.com\" - ; MQTT settings - -D FACTORY_MQTT_ENABLED=false - -D FACTORY_MQTT_HOST=\"test.mosquitto.org\" - -D FACTORY_MQTT_PORT=1883 - -D FACTORY_MQTT_USERNAME=\"\" ; supports placeholders - -D FACTORY_MQTT_PASSWORD=\"\" - -D FACTORY_MQTT_CLIENT_ID=\"#{platform}-#{unique_id}\" ; supports placeholders - -D FACTORY_MQTT_KEEP_ALIVE=60 - -D FACTORY_MQTT_CLEAN_SESSION=true - -D FACTORY_MQTT_MAX_TOPIC_LENGTH=128 + ; OTA settings + -D FACTORY_OTA_PORT=8266 + -D FACTORY_OTA_PASSWORD=\"spot-leika\" + -D FACTORY_OTA_ENABLED=true - ; JWT Secret - -D FACTORY_JWT_SECRET=\"#{random}-#{random}\" ; supports placeholders \ No newline at end of file + ; MQTT settings + -D FACTORY_MQTT_ENABLED=false + -D FACTORY_MQTT_URI=\"test.mosquitto.org\" + -D FACTORY_MQTT_PORT=1883 + -D FACTORY_MQTT_USERNAME=\"\" ; supports placeholders + -D FACTORY_MQTT_PASSWORD=\"\" + -D FACTORY_MQTT_CLIENT_ID=\"#{platform}-#{unique_id}\" ; supports placeholders + -D FACTORY_MQTT_KEEP_ALIVE=60 + -D FACTORY_MQTT_CLEAN_SESSION=true + -D FACTORY_MQTT_MAX_TOPIC_LENGTH=128 + + ; JWT Secret + -D FACTORY_JWT_SECRET=\"#{random}-#{random}\" ; supports placeholders \ No newline at end of file diff --git a/esp32/features.ini b/esp32/features.ini index bd54d89..4c26fe1 100644 --- a/esp32/features.ini +++ b/esp32/features.ini @@ -1,6 +1,5 @@ [features] build_flags = - -D USE_CAMERA=1 -D USE_BATTERY=1 -D USE_NTP=1 -D USE_SECURITY=1 diff --git a/esp32/include/AsyncJpegStream.h b/esp32/include/AsyncJpegStream.h deleted file mode 100644 index 5d47063..0000000 --- a/esp32/include/AsyncJpegStream.h +++ /dev/null @@ -1,28 +0,0 @@ -#include -#include - -typedef struct { - camera_fb_t * fb; - size_t index; -} camera_frame_t; - -#define PART_BOUNDARY "123456789000000000000987654321" - -class AsyncJpegStreamResponse: public AsyncAbstractResponse { - private: - camera_frame_t _frame; - size_t _index; - size_t _jpg_buf_len; - uint8_t * _jpg_buf; - uint64_t lastAsyncRequest; - public: - AsyncJpegStreamResponse(); - ~AsyncJpegStreamResponse(); - bool _sourceValid() const { - return true; - } - virtual size_t _fillBuffer(uint8_t *buf, size_t maxLen) override; - size_t _content(uint8_t *buffer, size_t maxLen, size_t index); -}; - -void streamJpg(AsyncWebServerRequest *request); \ No newline at end of file diff --git a/esp32/include/README b/esp32/include/README deleted file mode 100644 index 194dcd4..0000000 --- a/esp32/include/README +++ /dev/null @@ -1,39 +0,0 @@ - -This directory is intended for project header files. - -A header file is a file containing C declarations and macro definitions -to be shared between several project source files. You request the use of a -header file in your project source file (C, C++, etc) located in `src` folder -by including it, with the C preprocessing directive `#include'. - -```src/main.c - -#include "header.h" - -int main (void) -{ - ... -} -``` - -Including a header file produces the same results as copying the header file -into each source file that needs it. Such copying would be time-consuming -and error-prone. With a header file, the related declarations appear -in only one place. If they need to be changed, they can be changed in one -place, and programs that include the header file will automatically use the -new version when next recompiled. The header file eliminates the labor of -finding and changing all the copies as well as the risk that a failure to -find one copy will result in inconsistencies within a program. - -In C, the usual convention is to give header files names that end with `.h'. -It is most portable to use only letters, digits, dashes, and underscores in -header file names, and at most one dot. - -Read more about using header files in official GCC documentation: - -* Include Syntax -* Include Operation -* Once-Only Headers -* Computed Includes - -https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html diff --git a/esp32/include/camera.h b/esp32/include/camera.h deleted file mode 100644 index da22dc9..0000000 --- a/esp32/include/camera.h +++ /dev/null @@ -1,3 +0,0 @@ -#pragma once - -esp_err_t InitializeCamera(); \ No newline at end of file diff --git a/esp32/include/camera_pins.h b/esp32/include/camera_pins.h deleted file mode 100644 index 18ceb76..0000000 --- a/esp32/include/camera_pins.h +++ /dev/null @@ -1,297 +0,0 @@ -#if defined(CAMERA_MODEL_WROVER_KIT) -#define PWDN_GPIO_NUM -1 -#define RESET_GPIO_NUM -1 -#define XCLK_GPIO_NUM 21 -#define SIOD_GPIO_NUM 26 -#define SIOC_GPIO_NUM 27 - -#define Y9_GPIO_NUM 35 -#define Y8_GPIO_NUM 34 -#define Y7_GPIO_NUM 39 -#define Y6_GPIO_NUM 36 -#define Y5_GPIO_NUM 19 -#define Y4_GPIO_NUM 18 -#define Y3_GPIO_NUM 5 -#define Y2_GPIO_NUM 4 -#define VSYNC_GPIO_NUM 25 -#define HREF_GPIO_NUM 23 -#define PCLK_GPIO_NUM 22 - -#elif defined(CAMERA_MODEL_ESP_EYE) -#define PWDN_GPIO_NUM -1 -#define RESET_GPIO_NUM -1 -#define XCLK_GPIO_NUM 4 -#define SIOD_GPIO_NUM 18 -#define SIOC_GPIO_NUM 23 - -#define Y9_GPIO_NUM 36 -#define Y8_GPIO_NUM 37 -#define Y7_GPIO_NUM 38 -#define Y6_GPIO_NUM 39 -#define Y5_GPIO_NUM 35 -#define Y4_GPIO_NUM 14 -#define Y3_GPIO_NUM 13 -#define Y2_GPIO_NUM 34 -#define VSYNC_GPIO_NUM 5 -#define HREF_GPIO_NUM 27 -#define PCLK_GPIO_NUM 25 - -#define LED_GPIO_NUM 22 - -#elif defined(CAMERA_MODEL_M5STACK_PSRAM) -#define PWDN_GPIO_NUM -1 -#define RESET_GPIO_NUM 15 -#define XCLK_GPIO_NUM 27 -#define SIOD_GPIO_NUM 25 -#define SIOC_GPIO_NUM 23 - -#define Y9_GPIO_NUM 19 -#define Y8_GPIO_NUM 36 -#define Y7_GPIO_NUM 18 -#define Y6_GPIO_NUM 39 -#define Y5_GPIO_NUM 5 -#define Y4_GPIO_NUM 34 -#define Y3_GPIO_NUM 35 -#define Y2_GPIO_NUM 32 -#define VSYNC_GPIO_NUM 22 -#define HREF_GPIO_NUM 26 -#define PCLK_GPIO_NUM 21 - -#elif defined(CAMERA_MODEL_M5STACK_V2_PSRAM) -#define PWDN_GPIO_NUM -1 -#define RESET_GPIO_NUM 15 -#define XCLK_GPIO_NUM 27 -#define SIOD_GPIO_NUM 22 -#define SIOC_GPIO_NUM 23 - -#define Y9_GPIO_NUM 19 -#define Y8_GPIO_NUM 36 -#define Y7_GPIO_NUM 18 -#define Y6_GPIO_NUM 39 -#define Y5_GPIO_NUM 5 -#define Y4_GPIO_NUM 34 -#define Y3_GPIO_NUM 35 -#define Y2_GPIO_NUM 32 -#define VSYNC_GPIO_NUM 25 -#define HREF_GPIO_NUM 26 -#define PCLK_GPIO_NUM 21 - -#elif defined(CAMERA_MODEL_M5STACK_WIDE) -#define PWDN_GPIO_NUM -1 -#define RESET_GPIO_NUM 15 -#define XCLK_GPIO_NUM 27 -#define SIOD_GPIO_NUM 22 -#define SIOC_GPIO_NUM 23 - -#define Y9_GPIO_NUM 19 -#define Y8_GPIO_NUM 36 -#define Y7_GPIO_NUM 18 -#define Y6_GPIO_NUM 39 -#define Y5_GPIO_NUM 5 -#define Y4_GPIO_NUM 34 -#define Y3_GPIO_NUM 35 -#define Y2_GPIO_NUM 32 -#define VSYNC_GPIO_NUM 25 -#define HREF_GPIO_NUM 26 -#define PCLK_GPIO_NUM 21 - -#define LED_GPIO_NUM 2 - -#elif defined(CAMERA_MODEL_M5STACK_ESP32CAM) -#define PWDN_GPIO_NUM -1 -#define RESET_GPIO_NUM 15 -#define XCLK_GPIO_NUM 27 -#define SIOD_GPIO_NUM 25 -#define SIOC_GPIO_NUM 23 - -#define Y9_GPIO_NUM 19 -#define Y8_GPIO_NUM 36 -#define Y7_GPIO_NUM 18 -#define Y6_GPIO_NUM 39 -#define Y5_GPIO_NUM 5 -#define Y4_GPIO_NUM 34 -#define Y3_GPIO_NUM 35 -#define Y2_GPIO_NUM 17 -#define VSYNC_GPIO_NUM 22 -#define HREF_GPIO_NUM 26 -#define PCLK_GPIO_NUM 21 - -#elif defined(CAMERA_MODEL_M5STACK_UNITCAM) -#define PWDN_GPIO_NUM -1 -#define RESET_GPIO_NUM 15 -#define XCLK_GPIO_NUM 27 -#define SIOD_GPIO_NUM 25 -#define SIOC_GPIO_NUM 23 - -#define Y9_GPIO_NUM 19 -#define Y8_GPIO_NUM 36 -#define Y7_GPIO_NUM 18 -#define Y6_GPIO_NUM 39 -#define Y5_GPIO_NUM 5 -#define Y4_GPIO_NUM 34 -#define Y3_GPIO_NUM 35 -#define Y2_GPIO_NUM 32 -#define VSYNC_GPIO_NUM 22 -#define HREF_GPIO_NUM 26 -#define PCLK_GPIO_NUM 21 - -#elif defined(CAMERA_MODEL_AI_THINKER) -#define PWDN_GPIO_NUM 32 -#define RESET_GPIO_NUM -1 -#define XCLK_GPIO_NUM 0 -#define SIOD_GPIO_NUM 26 -#define SIOC_GPIO_NUM 27 - -#define Y9_GPIO_NUM 35 -#define Y8_GPIO_NUM 34 -#define Y7_GPIO_NUM 39 -#define Y6_GPIO_NUM 36 -#define Y5_GPIO_NUM 21 -#define Y4_GPIO_NUM 19 -#define Y3_GPIO_NUM 18 -#define Y2_GPIO_NUM 5 -#define VSYNC_GPIO_NUM 25 -#define HREF_GPIO_NUM 23 -#define PCLK_GPIO_NUM 22 - -// 4 for flash led or 33 for normal led -#define LED_GPIO_NUM 4 - -#elif defined(CAMERA_MODEL_TTGO_T_JOURNAL) -#define PWDN_GPIO_NUM 0 -#define RESET_GPIO_NUM 15 -#define XCLK_GPIO_NUM 27 -#define SIOD_GPIO_NUM 25 -#define SIOC_GPIO_NUM 23 - -#define Y9_GPIO_NUM 19 -#define Y8_GPIO_NUM 36 -#define Y7_GPIO_NUM 18 -#define Y6_GPIO_NUM 39 -#define Y5_GPIO_NUM 5 -#define Y4_GPIO_NUM 34 -#define Y3_GPIO_NUM 35 -#define Y2_GPIO_NUM 17 -#define VSYNC_GPIO_NUM 22 -#define HREF_GPIO_NUM 26 -#define PCLK_GPIO_NUM 21 - -#elif defined(CAMERA_MODEL_XIAO_ESP32S3) -#define PWDN_GPIO_NUM -1 -#define RESET_GPIO_NUM -1 -#define XCLK_GPIO_NUM 10 -#define SIOD_GPIO_NUM 40 -#define SIOC_GPIO_NUM 39 - -#define Y9_GPIO_NUM 48 -#define Y8_GPIO_NUM 11 -#define Y7_GPIO_NUM 12 -#define Y6_GPIO_NUM 14 -#define Y5_GPIO_NUM 16 -#define Y4_GPIO_NUM 18 -#define Y3_GPIO_NUM 17 -#define Y2_GPIO_NUM 15 -#define VSYNC_GPIO_NUM 38 -#define HREF_GPIO_NUM 47 -#define PCLK_GPIO_NUM 13 - -#elif defined(CAMERA_MODEL_ESP32_CAM_BOARD) -// The 18 pin header on the board has Y5 and Y3 swapped -#define USE_BOARD_HEADER 0 -#define PWDN_GPIO_NUM 32 -#define RESET_GPIO_NUM 33 -#define XCLK_GPIO_NUM 4 -#define SIOD_GPIO_NUM 18 -#define SIOC_GPIO_NUM 23 - -#define Y9_GPIO_NUM 36 -#define Y8_GPIO_NUM 19 -#define Y7_GPIO_NUM 21 -#define Y6_GPIO_NUM 39 -#if USE_BOARD_HEADER -#define Y5_GPIO_NUM 13 -#else -#define Y5_GPIO_NUM 35 -#endif -#define Y4_GPIO_NUM 14 -#if USE_BOARD_HEADER -#define Y3_GPIO_NUM 35 -#else -#define Y3_GPIO_NUM 13 -#endif -#define Y2_GPIO_NUM 34 -#define VSYNC_GPIO_NUM 5 -#define HREF_GPIO_NUM 27 -#define PCLK_GPIO_NUM 25 - -#elif defined(CAMERA_MODEL_ESP32S3_CAM_LCD) -#define PWDN_GPIO_NUM -1 -#define RESET_GPIO_NUM -1 -#define XCLK_GPIO_NUM 40 -#define SIOD_GPIO_NUM 17 -#define SIOC_GPIO_NUM 18 - -#define Y9_GPIO_NUM 39 -#define Y8_GPIO_NUM 41 -#define Y7_GPIO_NUM 42 -#define Y6_GPIO_NUM 12 -#define Y5_GPIO_NUM 3 -#define Y4_GPIO_NUM 14 -#define Y3_GPIO_NUM 47 -#define Y2_GPIO_NUM 13 -#define VSYNC_GPIO_NUM 21 -#define HREF_GPIO_NUM 38 -#define PCLK_GPIO_NUM 11 - -#elif defined(CAMERA_MODEL_ESP32S2_CAM_BOARD) -// The 18 pin header on the board has Y5 and Y3 swapped -#define USE_BOARD_HEADER 0 -#define PWDN_GPIO_NUM 1 -#define RESET_GPIO_NUM 2 -#define XCLK_GPIO_NUM 42 -#define SIOD_GPIO_NUM 41 -#define SIOC_GPIO_NUM 18 - -#define Y9_GPIO_NUM 16 -#define Y8_GPIO_NUM 39 -#define Y7_GPIO_NUM 40 -#define Y6_GPIO_NUM 15 -#if USE_BOARD_HEADER -#define Y5_GPIO_NUM 12 -#else -#define Y5_GPIO_NUM 13 -#endif -#define Y4_GPIO_NUM 5 -#if USE_BOARD_HEADER -#define Y3_GPIO_NUM 13 -#else -#define Y3_GPIO_NUM 12 -#endif -#define Y2_GPIO_NUM 14 -#define VSYNC_GPIO_NUM 38 -#define HREF_GPIO_NUM 4 -#define PCLK_GPIO_NUM 3 - -#elif defined(CAMERA_MODEL_ESP32S3_EYE) -#define PWDN_GPIO_NUM -1 -#define RESET_GPIO_NUM -1 -#define XCLK_GPIO_NUM 15 -#define SIOD_GPIO_NUM 4 -#define SIOC_GPIO_NUM 5 - -#define Y2_GPIO_NUM 11 -#define Y3_GPIO_NUM 9 -#define Y4_GPIO_NUM 8 -#define Y5_GPIO_NUM 10 -#define Y6_GPIO_NUM 12 -#define Y7_GPIO_NUM 18 -#define Y8_GPIO_NUM 17 -#define Y9_GPIO_NUM 16 - -#define VSYNC_GPIO_NUM 6 -#define HREF_GPIO_NUM 7 -#define PCLK_GPIO_NUM 13 - -#else -#error "Camera model not selected" -#endif \ No newline at end of file diff --git a/esp32/include/config.h b/esp32/include/config.h deleted file mode 100644 index 41b90b7..0000000 --- a/esp32/include/config.h +++ /dev/null @@ -1,71 +0,0 @@ -/* - * User settings - */ -#define HOSTNAME "Leika" -#define SSID "" -#define PASS "" - - -/* - * Server settings - */ -#define HTTP_PORT 80 -#define WEBSOCKET_PATH "/" -#define EVENTSOURCE_PATH "/events" -#define USE_CAPTIVE_PORTAL false - - -/* - * Camera module - */ -#define CAMERA_MODEL_AI_THINKER -// #define CAMERA_MODEL_WROVER_KIT -// #define CAMERA_MODEL_ESP_EYE -// #define CAMERA_MODEL_M5STACK_PSRAM -// #define CAMERA_MODEL_M5STACK_V2_PSRAM -// #define CAMERA_MODEL_M5STACK_WIDE -// #define CAMERA_MODEL_M5STACK_ESP32CAM -// #define CAMERA_MODEL_TTGO_T_JOURNAL -// #define CAMERA_MODEL_ARDUCAM_ESP32S_UNO - - -/* - * OLED Settings - */ -#define SCREEN_WIDTH 128 -#define SCREEN_HEIGHT 64 -#define SCREEN_RESET -1 - - -/* - * I2C software connection - */ -#define SDA 14 -#define SCL 15 - - -/* - * Serial settings - */ -#define BAUDRATE 115200 -#define SERIAL_DEBUG_OUTPUT true - - -/* - * Ultra sonic sensors - */ -#define USS_LEFT 12 -#define USS_RIGHT 13 -#define USS_MAX_DISTANCE 200 - -/* - * Button settings - */ -#define BUTTON 16 -#define BUTTON_LED 2 - -/* - * PWM controller settings - */ -#define SERVO_OSCILLATOR_FREQUENCY 27000000 -#define SERVO_FREQ 50 \ No newline at end of file diff --git a/esp32/include/deviceconfig.h b/esp32/include/deviceconfig.h deleted file mode 100644 index 22020c1..0000000 --- a/esp32/include/deviceconfig.h +++ /dev/null @@ -1,151 +0,0 @@ -#pragma once - -#include -#include -#include - -/* - * I2C software connection - */ -#define SDA 14 -#define SCL 15 - -/* - * Serial settings - */ -#define BAUDRATE 115200 -#define SERIAL_DEBUG_OUTPUT true - -/* - * PWM controller settings - */ -#define SERVO_OSCILLATOR_FREQUENCY 27000000 -#define SERVO_FREQ 50 - -/* - * Button settings - */ -#define BUTTON 4 -#define BUTTON_LED 2 - -/* - * Ultra sonic sensors - */ -#define USS_LEFT 12 -#define USS_RIGHT 13 -#define USS_MAX_DISTANCE 200 - -/* - * Changeable default data - */ -#define DEVICE_CONFIG_FILE "/device.cfg" -#define DEFAULT_NTP_SERVER "0.pool.ntp.org" - -class DeviceConfig : public IJSONSerializable -{ - // Add variables for additional settings to this list - String ntpServer; - bool useMetric; - - std::vector settingSpecs; - size_t writerIndex; - - void SaveToJSON(); - - template - void SetAndSave(T& target, const T& source) - { - if (target == source) - return; - - target = source; - - SaveToJSON(); - } - - template - void SetIfPresentIn(const JsonObjectConst& jsonObject, T& target, const char *tag) - { - if (jsonObject.containsKey(tag)) - target = jsonObject[tag].as(); - } - - public: - - using ValidateResponse = std::pair; - - // Add additional setting Tags to this list - static constexpr const char * NTPServerTag = NAME_OF(ntpServer); - static constexpr const char * UseMetricTag = NAME_OF(useMetric); - - DeviceConfig(); - - virtual bool SerializeToJSON(JsonObject& jsonObject) override - { - return SerializeToJSON(jsonObject, true); - } - - bool SerializeToJSON(JsonObject& jsonObject, bool includeSensitive) - { - AllocatedJsonDocument jsonDoc(1024); - - // Add serialization logic for additionl settings to this code - jsonDoc[NTPServerTag] = ntpServer; - jsonDoc[UseMetricTag] = useMetric; - - return jsonObject.set(jsonDoc.as()); - } - - virtual bool DeserializeFromJSON(const JsonObjectConst& jsonObject) override - { - return DeserializeFromJSON(jsonObject, false); - } - - bool DeserializeFromJSON(const JsonObjectConst& jsonObject, bool skipWrite) - { - // Add deserialization logic for additional settings to this code - SetIfPresentIn(jsonObject, ntpServer, NTPServerTag); - SetIfPresentIn(jsonObject, useMetric, UseMetricTag); - - if (ntpServer.isEmpty()) - ntpServer = DEFAULT_NTP_SERVER; - - if (!skipWrite) - SaveToJSON(); - - return true; - } - - void RemovePersisted() - { - RemoveJSONFile(DEVICE_CONFIG_FILE); - } - - virtual const std::vector& GetSettingSpecs() const - { - return settingSpecs; - } - - const String &GetNTPServer() const - { - return ntpServer; - } - - void SetNTPServer(const String &newNTPServer) - { - SetAndSave(ntpServer, newNTPServer); - } - - bool UseMetric() const - { - return useMetric; - } - - void SetUseCelsius(bool newUseMetric) - { - SetAndSave(useMetric, newUseMetric); - } -}; - - -extern DRAM_ATTR std::unique_ptr g_ptrDeviceConfig; \ No newline at end of file diff --git a/esp32/include/featureflags.h b/esp32/include/featureflags.h deleted file mode 100644 index d733e74..0000000 --- a/esp32/include/featureflags.h +++ /dev/null @@ -1,31 +0,0 @@ -#define USE_PSRAM true - -#define USE_WIFI true - -#define WAIT_FOR_WIFI false - -#define USE_WEBSERVER true - -#define USE_WEBSERVER_SSL false - -#define USE_WEBSOCKET true - -#define USE_OAT false - -#define USE_NTP false - -#define USE_MDNS true - -#define USE_DNS_SERVER false - -#define USE_REMOTE_SERIAL false - -#define USE_LOW_POWER false - -#define USE_CAMERA true - -#define USE_MPU true - -#define USE_POWER_BUTTON true - -#define USE_USS true \ No newline at end of file diff --git a/esp32/include/globals.h b/esp32/include/globals.h deleted file mode 100644 index 7554dcc..0000000 --- a/esp32/include/globals.h +++ /dev/null @@ -1,85 +0,0 @@ -#pragma once - -#include -#include -#include -#include - -// Disable brownout problems -#include "soc/rtc_cntl_reg.h" -#include "soc/soc.h" - -/* - * Macros - */ -#define NAME_OF(x) #x - -/* - * Feature flags - */ - -#include - -#if USE_WIFI - #include -#endif - -#if USE_WIFI && USE_WEBSERVER - #if USE_WEBSERVER_SSL - #define ASYNC_TCP_SSL_ENABLED 1 - #include - #endif - #include -#endif - -#if USE_OAT - #include -#endif - -#if USE_DNS_SERVER - #include -#endif - -#if USE_MDNS - #include -#endif - -#define STACK_SIZE (ESP_TASK_MAIN_STACK) // Stack size for each new thread - -/* - * Thread priority - */ -#define NET_PRIORITY tskIDLE_PRIORITY+5 -#define MOVEMENT_PRIORITY tskIDLE_PRIORITY+3 -#define JSONWRITER_PRIORITY tskIDLE_PRIORITY+2 - - - -/* - * Thread core - */ -#define NET_CORE 1 -#define MOVEMENT_CORE 0 -#define JSONWRITER_CORE 0 - - -/* - * Main include - */ -#include -#include -#include -#include - -#if USE_CAMERA - - #include -#endif - -#if USE_WIFI && USE_WEBSERVER - #include -#endif - -#if USE_WIFI - #include -#endif diff --git a/esp32/include/jsonbase.h b/esp32/include/jsonbase.h deleted file mode 100644 index 3b40925..0000000 --- a/esp32/include/jsonbase.h +++ /dev/null @@ -1,4 +0,0 @@ -#pragma once - -#define JSON_BUFFER_BASE_SIZE 2048 -#define JSON_BUFFER_INCREMENT 2048 diff --git a/esp32/include/jsonserializer.h b/esp32/include/jsonserializer.h deleted file mode 100644 index a06c067..0000000 --- a/esp32/include/jsonserializer.h +++ /dev/null @@ -1,80 +0,0 @@ -#pragma once - -#include -#include -#include - -struct IJSONSerializable -{ - virtual bool SerializeToJSON(JsonObject& jsonObject) = 0; - virtual bool DeserializeFromJSON(const JsonObjectConst& jsonObject) { return false; } -}; - -template -constexpr auto to_value(E e) noexcept -{ - return static_cast>(e); -} - -#if USE_PSRAM - struct JsonPsramAllocator - { - void* allocate(size_t size) { - return ps_malloc(size); - } - - void deallocate(void* pointer) { - free(pointer); - } - - void* reallocate(void* ptr, size_t new_size) { - return ps_realloc(ptr, new_size); - } - }; - - typedef BasicJsonDocument AllocatedJsonDocument; - -#else - typedef DynamicJsonDocument AllocatedJsonDocument; -#endif - -bool LoadJSONFile(const char *fileName, size_t& bufferSize, std::unique_ptr& pJsonDoc); -bool SaveToJSONFile(const char *fileName, size_t& bufferSize, IJSONSerializable& object); -bool RemoveJSONFile(const char *fileName); - -#define JSON_WRITER_DELAY 3000 - -class JSONWriter -{ - // We allow the main JSON Writer task entry point function to access private members - friend void IRAM_ATTR JSONWriterTaskEntry(void *); - - private: - - // Writer function and flag combo - struct WriterEntry - { - std::atomic_bool flag = false; - std::function writer; - - WriterEntry(std::function writer) : - writer(writer) - {} - - WriterEntry(WriterEntry&& entry) : WriterEntry(entry.writer) - {} - }; - - std::vector writers; - std::atomic_ulong latestFlagMs; - - public: - - // Add a writer to the collection. Returns the index of the added writer, for use with FlagWriter() - size_t RegisterWriter(std::function writer); - - // Flag a writer for invocation and wake up the task that calls them - void FlagWriter(size_t index); -}; - -extern DRAM_ATTR std::unique_ptr g_ptrJSONWriter; diff --git a/esp32/include/movement.h b/esp32/include/movement.h deleted file mode 100644 index e4034cf..0000000 --- a/esp32/include/movement.h +++ /dev/null @@ -1,15 +0,0 @@ -#pragma once - -#include - -float getHeading(); - -float getTemp(); - -float getAngleX(); - -float getAngleY(); - -float getAngleZ(); - -void IRAM_ATTR MovementHandlingLoopEntry(void *); \ No newline at end of file diff --git a/esp32/include/network.h b/esp32/include/network.h deleted file mode 100644 index be380d6..0000000 --- a/esp32/include/network.h +++ /dev/null @@ -1,5 +0,0 @@ -#pragma once - -#include - -void IRAM_ATTR NetworkHandlingLoopEntry(void *); diff --git a/esp32/include/secrets.example.h b/esp32/include/secrets.example.h deleted file mode 100644 index ded0ed5..0000000 --- a/esp32/include/secrets.example.h +++ /dev/null @@ -1,24 +0,0 @@ -// NOTE: do NOT enter your network details in this file (secrets.example.h)! -// Instead, copy this file to secrets.h, and set the below defines in that file! - -#define HOSTNAME "leika" // Relevant if wifi is enabled -#define SSID "" // Relevant if wifi is enabled -#define PASS "" // Relevant if wifi is enabled - -#define HTTP_PORT 80 // Relevant if webserver is enabled -#define WEBSOCKET_PATH "/" // Relevant if ws is enabled - -#define CAMERA_MODEL_AI_THINKER // Relevant if camera is enabled -// #define CAMERA_MODEL_WROVER_KIT -// #define CAMERA_MODEL_ESP_EYE -// #define CAMERA_MODEL_M5STACK_PSRAM -// #define CAMERA_MODEL_M5STACK_V2_PSRAM -// #define CAMERA_MODEL_M5STACK_WIDE -// #define CAMERA_MODEL_M5STACK_ESP32CAM -// #define CAMERA_MODEL_M5STACK_UNITCAM -// #define CAMERA_MODEL_TTGO_T_JOURNAL -// #define CAMERA_MODEL_XIAO_ESP32S3 -// #define CAMERA_MODEL_ESP32_CAM_BOARD -// #define CAMERA_MODEL_ESP32S3_CAM_LCD -// #define CAMERA_MODEL_ESP32S2_CAM_BOARD -// #define CAMERA_MODEL_ESP32S3_EYE diff --git a/esp32/include/servo.h b/esp32/include/servo.h deleted file mode 100644 index fa6ffd4..0000000 --- a/esp32/include/servo.h +++ /dev/null @@ -1,114 +0,0 @@ -#pragma once - -#include -#include -#include -#include - -#if USE_WIFI && USE_WEBSERVER - extern DRAM_ATTR CWebServer g_WebServer; -#endif - -typedef struct { - float omega; - float phi; - float psi; - float xm; - float ym; - float zm; - bool set; -} position_t; - -class Servo : public Adafruit_PWMServoDriver { - public: - - Servo() : Adafruit_PWMServoDriver() {} - - void SetAngles(int16_t* angle) { - for(size_t i = 0; i < 12; i++) - servo_angles[i] = angle[i]; - updateServos(); - } - - void SetAngle(uint8_t id, int8_t angle) { - servo_angles[id] = angle; - updateServos(); - } - - void updateServos() { - for(uint8_t i = 0; i < 12; i++){ - int8_t angle = servo_angles[i]; - uint16_t pulse = (uint16_t) (0.5 + servo_min[i] + (((angle * servo_invert[i]) + 90) * servo_conversion[i])); - setPWM(i, 0, pulse); - } - broadcastAngles(); - } - - void setBody(float phi, float theta, float psi, float x, float y, float z) { - goal_position.phi = (phi - 128) / 2; - goal_position.omega = (theta - 128) / 2; - goal_position.psi = (psi - 128) / 2; - goal_position.xm = (x - 128) / 2; - goal_position.ym = (y - 128) / 2; - goal_position.zm = (z - 128) / 2; - updateAngles(); - } - - void setBodyAngle(float phi, float theta, float psi) { - goal_position.phi = phi; - goal_position.omega = theta; - goal_position.psi = psi; - updateAngles(); - } - - void setBodyPosition(float x, float y, float z) { - goal_position.xm = x; - goal_position.ym = y; - goal_position.zm = z; - updateAngles(); - } - - void updateAngles() { - servo_angles[0] = goal_position.phi; - servo_angles[1] = goal_position.omega; - servo_angles[2] = goal_position.psi; - servo_angles[3] = goal_position.xm; - servo_angles[4] = goal_position.ym; - servo_angles[5] = goal_position.zm; - updateServos(); - broadcastAngles(); - } - - void deactivate() { - isActive = false; - sleep(); - } - - void activate() { - isActive = true; - sleep(); - } - - void toggleState() { - isActive ? sleep() : wakeup(); - isActive = !isActive; - } - - bool isActive {true}; - - private: - void broadcastAngles() { - uint8_t* buf = (uint8_t*)&servo_angles; - g_WebServer.broadcast(buf, 12); - } - - const int16_t servo_min[12] {92,101,129,92,118,125,110,101,125,92,101,125}; - const int8_t servo_invert[12] = {-1,1,1, -1,-1,-1, 1,1,1, 1,-1,-1}; - const float servo_conversion[12] {2.2,2.1055555,1.96923,2.2,2.1055555,1.96923,2.2,2.1055555,1.96923,2.2,2.1055555,1.96923}; - - position_t spot_position = {.omega=0,.phi=0,.psi=0,.xm=-40,.ym=-170, .zm=0, .set=1}; - position_t goal_position = {0,}; - int16_t servo_angles[12]{0,}; -}; - -extern DRAM_ATTR std::unique_ptr g_ptrServo; diff --git a/esp32/include/taskmanager.h b/esp32/include/taskmanager.h deleted file mode 100644 index cebae3f..0000000 --- a/esp32/include/taskmanager.h +++ /dev/null @@ -1,215 +0,0 @@ -#pragma once - -#include - -// Stack size for the taskmgr's idle threads -#define IDLE_STACK_SIZE 2048 -#define DEFAULT_STACK_SIZE 2048+512 - -class IdleTask -{ - private: - - float _idleRatio = 0; - unsigned long _lastMeasurement; - - const int kMillisPerLoop = 1; - const int kMillisPerCalc = 1000; - - unsigned long counter = 0; - - public: - - void ProcessIdleTime() - { - _lastMeasurement = millis(); - counter = 0; - - // We need to whack the watchdog so we delay in smalle bites until we've used up all the time - - while (true) - { - int delta = millis() - _lastMeasurement; - if (delta >= kMillisPerCalc) - { - //Serial.printf("Core %u Spent %lu in delay during a window of %d for a ratio of %f\n", - // xPortGetCoreID(), counter, delta, (float)counter/delta); - _idleRatio = ((float) counter / delta); - _lastMeasurement = millis(); - counter = 0; - } - else - { - esp_task_wdt_reset(); - delayMicroseconds(kMillisPerLoop*1000); - counter += kMillisPerLoop; - } - } - } - - // If idle time is spent elsewhere, it can be credited to this task. Shouldn't add up to more time than actual though! - - void CountBonusIdleMillis(uint millis) - { - counter += millis; - } - - IdleTask() : _lastMeasurement(millis()) - { - } - - // GetCPUUsage - // - // Returns 100 less the amount of idle time that we were able to squander. - - float GetCPUUsage() const - { - // If the measurement failed to even get a chance to run, this core is maxed and there was no idle time - - if (millis() - _lastMeasurement > kMillisPerCalc) - return 100.0f; - - // Otherwise, whatever cycles we were able to burn in the idle loop counts as "would have been idle" time - return 100.0f-100*_idleRatio; - } - - // Stub entry point for calling into it without a THIS pointer - - static void IdleTaskEntry(void * that) - { - IdleTask * pTask = (IdleTask *)that; - pTask->ProcessIdleTime(); - } -}; - -// TaskManager -// -// TaskManager runs two tasks at just over idle priority that do nothing but try to burn CPU, and they -// keep track of how much they can burn. It's assumed that everything else runs at a higher priority -// and thus they "starve" the idle tasks when doing work. - -class TaskManager -{ - TaskHandle_t _hIdle0 = nullptr; - TaskHandle_t _hIdle1 = nullptr; - - IdleTask _taskIdle0; - IdleTask _taskIdle1; - - public: - - float GetCPUUsagePercent(int iCore = -1) const - { - if (iCore < 0) - return (_taskIdle0.GetCPUUsage() + _taskIdle1.GetCPUUsage()) / 2; - else if (iCore == 0) - return _taskIdle0.GetCPUUsage(); - else if (iCore == 1) - return _taskIdle1.GetCPUUsage(); - else - throw new std::runtime_error("Invalid core passed to GetCPUUsagePercentCPU"); - } - - TaskManager() {} - - void begin() - { - Serial.printf("Replacing Idle Tasks with TaskManager...\n"); - // The idle tasks get created with a priority just ABOVE idle so that they steal idle time but nothing else. They then - // measure how much time is "wasted" at that lower priority and deem it to have been free CPU - - xTaskCreatePinnedToCore(_taskIdle0.IdleTaskEntry, "Idle0", IDLE_STACK_SIZE, &_taskIdle0, tskIDLE_PRIORITY + 1, &_hIdle0, 0); - xTaskCreatePinnedToCore(_taskIdle1.IdleTaskEntry, "Idle1", IDLE_STACK_SIZE, &_taskIdle1, tskIDLE_PRIORITY + 1, &_hIdle1, 1); - - // We need to turn off the watchdogs because our idle measurement tasks burn all of the idle time just - // to see how much there is (it's how they measure free CPU). Thus, we starve the system's normal idle tasks - // and have to feed the watchdog on our own. - - esp_task_wdt_delete(xTaskGetIdleTaskHandleForCPU(0)); - esp_task_wdt_delete(xTaskGetIdleTaskHandleForCPU(1)); - esp_task_wdt_add(_hIdle0); - esp_task_wdt_add(_hIdle1); - } -}; - -void IRAM_ATTR NetworkHandlingLoopEntry(void *); -void IRAM_ATTR JSONWriterTaskEntry(void *); -void IRAM_ATTR MovementHandlingLoopEntry(void *); - -#define DELETE_TASK(handle) if (handle != nullptr) vTaskDelete(handle) - -class ESPTaskManager : public TaskManager -{ -public: - -private: - TaskHandle_t _taskNetwork = nullptr; - TaskHandle_t _taskMovement = nullptr; - TaskHandle_t _taskJSONWriter = nullptr; - -public: - - ~ESPTaskManager() - { - DELETE_TASK(_taskNetwork); - DELETE_TASK(_taskMovement); - DELETE_TASK(_taskJSONWriter); - } - - void StartThreads(){ - StartNetworkThread(); - StartMovementThread(); - StartJSONWriterThread(); - } - - void StartNetworkThread() - { - #if USE_WIFI - log_i( ">> Launching Network Thread. Mem: %u, LargestBlk: %u, PSRAM Free: %u/%u, ", ESP.getFreeHeap(),ESP.getMaxAllocHeap(), ESP.getFreePsram(), ESP.getPsramSize()); - xTaskCreatePinnedToCore(NetworkHandlingLoopEntry, "NetworkHandlingLoop", STACK_SIZE, nullptr, NET_PRIORITY, &_taskNetwork, NET_CORE); - #endif - } - - void StartMovementThread() - { - log_i(">> Launching Movement Thread"); - xTaskCreatePinnedToCore(MovementHandlingLoopEntry, "MovementHandlingLoop", STACK_SIZE, nullptr, MOVEMENT_PRIORITY, &_taskMovement, MOVEMENT_CORE); - } - - void StartJSONWriterThread() - { - log_i(">> Launching JSON Writer Thread"); - xTaskCreatePinnedToCore(JSONWriterTaskEntry, "JSON Writer Loop", STACK_SIZE, nullptr, JSONWRITER_PRIORITY, &_taskJSONWriter, JSONWRITER_CORE); - } - - void NotifyJSONWriterThread() - { - if (_taskJSONWriter == nullptr) - return; - - log_w(">> Notifying JSON Writer Thread"); - // Wake up the writer invoker task if it's sleeping, or request another write cycle if it isn't - xTaskNotifyGive(_taskJSONWriter); - } - - void NotifyNetworkThread() - { - if (_taskNetwork == nullptr) - return; - - //debugW(">> Notifying Network Thread"); - // Wake up the network task if it's sleeping, or request another read cycle if it isn't - xTaskNotifyGive(_taskNetwork); - } - - void NotifyMovementThread() - { - if (_taskMovement == nullptr) - return; - - // Wake up the movement task if it's sleeping, or request another read cycle if it isn't - xTaskNotifyGive(_taskMovement); - } -}; - -extern ESPTaskManager g_TaskManager; \ No newline at end of file diff --git a/esp32/include/types.h b/esp32/include/types.h deleted file mode 100644 index 2cdbd32..0000000 --- a/esp32/include/types.h +++ /dev/null @@ -1,56 +0,0 @@ -#pragma once - -#include -#include -#include - -struct EmbeddedFile -{ - // Embedded file size in bytes - const size_t length; - // Contents as bytes - const uint8_t *const contents; - - EmbeddedFile(const uint8_t start[], const uint8_t end[]) : - length(end - start), - contents(start) - {} -}; - -struct SettingSpec -{ - // Note that if this enum is expanded, ToName() must be also! - enum class SettingType : int - { - Integer, - PositiveBigInteger, - Float, - Boolean, - String, - Palette - }; - - String Name; - String FriendlyName; - String Description; - SettingType Type; - - SettingSpec(const String& name, const String& friendlyName, const String& description, SettingType type) - : Name(name), - FriendlyName(friendlyName), - Description(description), - Type(type) - {} - - SettingSpec(const String& name, const String& friendlyName, SettingType type) : SettingSpec(name, friendlyName, "", type) - {} - - SettingSpec() - {} - - String static ToName(SettingType type) - { - String names[] = { "Integer", "PositiveBigInteger", "Float", "Boolean", "String", "Palette" }; - return names[(int)type]; - } -}; \ No newline at end of file diff --git a/esp32/include/webserver.h b/esp32/include/webserver.h deleted file mode 100644 index 7673a7f..0000000 --- a/esp32/include/webserver.h +++ /dev/null @@ -1,219 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define HTTP_CODE_OK 200 -#define HTTP_CODE_NOT_FOUND 404 - -class CWebServer { - private: - // Template for param to value converter function, used by PushPostParamIfPresent() - template - using ParamValueGetter = std::function; - - // Template for value setting forwarding function, used by PushPostParamIfPresent() - template - using ValueSetter = std::function; - - // Value validating function type, as used by DeviceConfig (and possible others) - using ValueValidator = std::function; - - struct StaticStatistics { - uint32_t HeapSize; - size_t DmaHeapSize; - uint32_t PsramSize; - const char *ChipModel; - uint8_t ChipCores; - uint32_t CpuFreqMHz; - uint32_t SketchSize; - uint32_t FreeSketchSpace; - uint32_t FlashChipSize; - }; - - static std::vector deviceSettingSpecs; - static const std::map settingValidators; - - AsyncWebServer _server; - StaticStatistics _staticStats; - #if USE_WEBSOCKET - AsyncWebSocket _ws; - #endif - - // Helper functions/templates - - // Convert param value to a specific type and forward it to a setter function that expects that type as an argument - template - static bool PushPostParamIfPresent(AsyncWebServerRequest * pRequest, const String ¶mName, ValueSetter setter, ParamValueGetter getter) - { - if (!pRequest->hasParam(paramName, true, false)) - return false; - - log_v("found %s", paramName.c_str()); - - AsyncWebParameter *param = pRequest->getParam(paramName, true, false); - - // Extract the value and pass it off to the setter - return setter(getter(param)); - } - - // Generic param value forwarder. The type argument must be implicitly convertable from String! - // Some specializations of this are included in the CPP file - template - static bool PushPostParamIfPresent(AsyncWebServerRequest * pRequest, const String ¶mName, ValueSetter setter) - { - return PushPostParamIfPresent(pRequest, paramName, setter, [](AsyncWebParameter * param) { return param->value(); }); - } - - // AddCORSHeaderAndSend(OK)Response - // - // Sends a response with CORS headers added - template - static void AddCORSHeaderAndSendResponse(AsyncWebServerRequest * pRequest, Tr * pResponse) - { - // pResponse->addHeader("Server", HOSTNAME); - // pResponse->addHeader("Access-Control-Allow-Origin", "*"); - pRequest->send(pResponse); - } - - // Version for empty response, normally used to finish up things that don't return anything, like "NextEffect" - static void AddCORSHeaderAndSendOKResponse(AsyncWebServerRequest * pRequest) - { - AddCORSHeaderAndSendResponse(pRequest, pRequest->beginResponse(HTTP_CODE_OK)); - } - - // Straightforward support functions - - static bool IsPostParamTrue(AsyncWebServerRequest * pRequest, const String & paramName); - static const std::vector & LoadDeviceSettingSpecs(); - static void SendSettingSpecsResponse(AsyncWebServerRequest * pRequest, const std::vector & settingSpecs); - static void SetSettingsIfPresent(AsyncWebServerRequest * pRequest); - #if USE_OAT - static void UpdateFirmware(AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final); - static void UpdateFileSystemImage(AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final); - static void HandleUpdate(AsyncWebServerRequest* request, String filename, size_t index, uint8_t* data, size_t len, bool final, size_t upload_size, uint8_t upload_index); - #endif - - // Endpoint member functions - static void GetSettingSpecs(AsyncWebServerRequest * pRequest); - static void GetSettings(AsyncWebServerRequest * pRequest); - static void SetSettings(AsyncWebServerRequest * pRequest); - static void SaveFile(AsyncWebServerRequest* request, String filename, size_t index, uint8_t* data, size_t len, bool final); - #if USE_OAT - static void UpdateRequestHandler(AsyncWebServerRequest * pRequest); - #endif - static void Reset(AsyncWebServerRequest * pRequest); - static void GzipSpa(AsyncWebServerRequest * pRequest); - static void HandleWsMessage(AsyncWebSocket* server, AsyncWebSocketClient* client, AwsEventType type, void* arg, uint8_t* data, size_t len); - - // Not static because it uses member _staticStats - void GetStatistics(AsyncWebServerRequest * pRequest); - - public: - - CWebServer() - : _server(HTTP_PORT) - #if USE_WEBSOCKET - , _ws(WEBSOCKET_PATH) - #endif - {} - - void begin() { - DefaultHeaders::Instance().addHeader("Access-Control-Allow-Origin", "*"); - DefaultHeaders::Instance().addHeader("Access-Control-Allow-Methods", "GET, POST, PUT"); - DefaultHeaders::Instance().addHeader("Access-Control-Allow-Headers", "Content-Type"); - DefaultHeaders::Instance().addHeader("Server", HOSTNAME); - - _staticStats.HeapSize = ESP.getHeapSize(); - _staticStats.DmaHeapSize = heap_caps_get_total_size(MALLOC_CAP_DMA); - _staticStats.PsramSize = ESP.getPsramSize(); - _staticStats.ChipModel = ESP.getChipModel(); - _staticStats.ChipCores = ESP.getChipCores(); - _staticStats.CpuFreqMHz = ESP.getCpuFreqMHz(); - _staticStats.SketchSize = ESP.getSketchSize(); - _staticStats.FreeSketchSpace = ESP.getFreeSketchSpace(); - _staticStats.FlashChipSize = ESP.getFlashChipSize(); - - _server.onFileUpload(SaveFile); - - #if USE_WEBSOCKET - _ws.onEvent(HandleWsMessage); - _server.addHandler(&_ws); - #endif - - _server.on("/api/statistics", HTTP_GET, [this](AsyncWebServerRequest * pRequest) { this->GetStatistics(pRequest); }); - _server.on("/api/getStatistics", HTTP_GET, [this](AsyncWebServerRequest * pRequest) { this->GetStatistics(pRequest); }); - - _server.on("/api/settings/specs", HTTP_GET, [](AsyncWebServerRequest * pRequest) { GetSettingSpecs(pRequest); }); - _server.on("/api/settings", HTTP_GET, [](AsyncWebServerRequest * pRequest) { GetSettings(pRequest); }); - _server.on("/api/settings", HTTP_POST, [](AsyncWebServerRequest * pRequest) { SetSettings(pRequest); }); - - #if USE_OAT - _server.on("/api/update/filesystem", HTTP_POST, UpdateRequestHandler, UpdateFirmware); - _server.on("/api/update/firmware", HTTP_POST, UpdateRequestHandler, UpdateFileSystemImage); - #endif - - _server.on("/api/stream", HTTP_GET, streamJpg); - - _server.on("/api/reset", HTTP_POST, [](AsyncWebServerRequest * pRequest) { Reset(pRequest); }); - - _server.serveStatic("/", SPIFFS, "/").setCacheControl("max-age=31536000"); - - _server.onNotFound([](AsyncWebServerRequest *pRequest) { GzipSpa(pRequest); }); - - #if USE_WEBSERVER_SSL - _server.beginSecure("/server.cer", "/server.key", NULL); - - _server.onSslFileRequest([](void * arg, const char *filename, uint8_t **buf) -> int { - Serial.printf("SSL File: %s\n", filename); - File file = SPIFFS.open(filename, "r"); - if(file){ - size_t size = file.size(); - uint8_t * nbuf = (uint8_t*)malloc(size); - if(nbuf){ - size = file.read(nbuf, size); - file.close(); - *buf = nbuf; - return size; - } - file.close(); - } - *buf = 0; - return 0; - }, NULL); - #else - _server.begin(); - #endif - - log_i("HTTP server started"); - } - - void loop() { - #if USE_WEBSOCKET - _ws.cleanupClients(); - #endif - } - - void broadcast(uint8_t* content, size_t length) { - _ws.binaryAll(content, length); - } - - void broadcastJson(char* content, size_t length) { - _ws.textAll(content, length); - } -}; - -// Set value in lambda using a forwarding function. Always returns true -#define SET_VALUE(functionCall) [](auto value) { functionCall; return true; } - -// Set value in lambda using a forwarding function. Reports success based on function's return value, -// which must be implicitly convertable to bool -#define CONFIRM_VALUE(functionCall) [](auto value)->bool { return functionCall; } \ No newline at end of file diff --git a/esp32/platformio.ini b/esp32/platformio.ini index 04e12d6..3c576d0 100644 --- a/esp32/platformio.ini +++ b/esp32/platformio.ini @@ -9,11 +9,15 @@ ; https://docs.platformio.org/page/projectconf.html [platformio] +description = Spot Micro Robot +data_dir = data extra_configs = factory_settings.ini features.ini + build_settings.ini +default_envs = esp32dev -[base] +[env] platform = espressif32 framework = arduino monitor_speed = 115200 @@ -24,30 +28,51 @@ monitor_filters = build_flags = ${factory_settings.build_flags} ${features.build_flags} + ${build_settings.build_flags} -D CORE_DEBUG_LEVEL=5 -D register= -std=gnu++17 build_unflags = -std=gnu++11 test_ignore = test_embedded +board_build.filesystem = littlefs lib_deps = - https://github.com/me-no-dev/ESPAsyncWebServer.git bblanchon/ArduinoJson@^6.21.2 - thomasfredericks/Bounce2@ ^2.7.0 - teckel12/NewPing@^1.9.7 - adafruit/Adafruit SSD1306@^2.5.7 - adafruit/Adafruit GFX Library@^1.11.5 - adafruit/Adafruit BusIO@^1.9.3 - adafruit/Adafruit PWM Servo Driver Library@^2.4.1 - adafruit/Adafruit ADS1X15@^2.4.0 - adafruit/Adafruit HMC5883 Unified@^1.2.1 - adafruit/Adafruit Unified Sensor@^1.1.11 - plageoj/UrlEncode@ ^1.0.1 - rfetick/MPU6050_light@^1.1.0 - SPI -board_build.partitions = config/no_oat.csv + https://github.com/theelims/PsychicMqttClient.git + ;hoeken/PsychicHttp + ; https://github.com/me-no-dev/ESPAsyncWebServer.git + ; thomasfredericks/Bounce2@ ^2.7.0 + ; teckel12/NewPing@^1.9.7 + ; adafruit/Adafruit SSD1306@^2.5.7 + ; adafruit/Adafruit GFX Library@^1.11.5 + ; adafruit/Adafruit BusIO@^1.9.3 + ; adafruit/Adafruit PWM Servo Driver Library@^2.4.1 + ; adafruit/Adafruit ADS1X15@^2.4.0 + ; adafruit/Adafruit HMC5883 Unified@^1.2.1 + ; adafruit/Adafruit Unified Sensor@^1.1.11 + ; plageoj/UrlEncode@ ^1.0.1 + ; rfetick/MPU6050_light@^1.1.0 + ; SPI +; board_build.partitions = config/no_oat.csv +extra_scripts = + pre:scripts/build_app.py + pre:scripts/generate_cert_bundle.py + scripts/rename_fw.py +board_build.embed_files = src/certs/x509_crt_bundle.bin +board_ssl_cert_source = adafruit [env:esp32cam] -extends = base -monitor_rts = 0 -monitor_dtr = 0 -board = esp32cam \ No newline at end of file +board = esp32cam +board_build.partitions = min_spiffs.csv +build_flags= + -D USE_CAMERA + ${env.build_flags} + -D LED_BUILTIN=4 + -D KEY_BUILTIN=0 + +[env:esp32dev] +board = esp32dev +board_build.partitions = min_spiffs.csv +build_flags = + ${env.build_flags} + -D LED_BUILTIN=2 + -D KEY_BUILTIN=0 diff --git a/esp32/scripts/build_app.py b/esp32/scripts/build_app.py new file mode 100644 index 0000000..6a62793 --- /dev/null +++ b/esp32/scripts/build_app.py @@ -0,0 +1,129 @@ +# ESP32 SvelteKit -- +# +# A simple, secure and extensible framework for IoT projects for ESP32 platforms +# with responsive Sveltekit front-end built with TailwindCSS and DaisyUI. +# https://github.com/theelims/ESP32-sveltekit +# +# Copyright (C) 2018 - 2023 rjwats +# Copyright (C) 2023 theelims +# Copyright (C) 2023 Maxtrium B.V. [ code available under dual license ] +# +# All Rights Reserved. This software may be modified and distributed under +# the terms of the LGPL v3 license. See the LICENSE file for details. + +from pathlib import Path +from shutil import copyfileobj +import os +import gzip +import mimetypes +import glob +from datetime import datetime + +Import("env") + +output_file = env["PROJECT_DIR"] + "/lib/ESP32-sveltekit/WWWData.h" +source_www_dir = env["PROJECT_DIR"] + "/../app2/src" +build_www_dir = env["PROJECT_DIR"] + "/../app2/build" +www_dir = "www" + +def find_latest_timestamp_for_app(): + list_of_files = glob.glob(source_www_dir+'/**/*', recursive=True) + latest_file = max(list_of_files, key=os.path.getmtime) + return os.path.getmtime(latest_file) + +def should_regenerate_output_file(): + if not flag_exists("EMBED_WWW") or not os.path.exists(output_file): + return True + last_source_change = find_latest_timestamp_for_app() + last_build = os.path.getmtime(output_file) + + print(f'Newest interface file: {datetime.fromtimestamp(last_source_change):%Y-%m-%d %H:%M:%S}, WWW Outputfile: {datetime.fromtimestamp(last_build):%Y-%m-%d %H:%M:%S}') + + if (last_build < last_source_change): + print("Svelte source files are updated. Need to regenerate.") + return True + print("Current outputfile is O.K. No need to regenerate.") + return False + + +def gzip_file(file): + with open(file, 'rb') as f_in: + with gzip.open(file + '.gz', 'wb') as f_out: + copyfileobj(f_in, f_out) + os.remove(file) + +def is_compressed_filetype(filetype): + compressed_types = ['zip', 'gz', 'rar', '7z', 'jpg', 'jpeg', 'png', 'mp4', 'mp3'] + return filetype.lower() in compressed_types + +def flag_exists(flag): + buildFlags = env.ParseFlags(env["BUILD_FLAGS"]) + for define in buildFlags.get("CPPDEFINES"): + if (define == flag or (isinstance(define, list) and define[0] == flag)): + return True + +def build_progmem(): + mimetypes.init() + with open(output_file, "w") as progmem: + progmem.write("#include \n") + progmem.write("#include \n\n") + + assetMap = {} + + # Iterate over all files in the build directory + for idx, path in enumerate(Path(www_dir).rglob("*.*")): + asset_path = path.relative_to(www_dir).as_posix() + print(f"Converting {asset_path}") + + asset_var = f'WEB_ASSET_DATA_{idx}' + filetype = asset_path.split('.')[-1] + asset_mime, _ = mimetypes.guess_type(asset_path) + asset_mime = asset_mime if asset_mime else f'application/octet-stream' + + progmem.write('// ' + str(asset_path) + '\n') + progmem.write('const uint8_t ' + asset_var + '[] = {\n ') + + # Open path as binary file, compress and read into byte array + size = 0 + with open(path, "rb") as f: + file_data = f.read() + if not is_compressed_filetype(filetype): + file_data = gzip.compress(file_data) + for byte in file_data: + if not (size % 16): + progmem.write('\n\t') + + progmem.write(f"0x{byte:02X},") + size += 1 + + progmem.write('\n};\n\n') + assetMap[asset_path] = { "name": asset_var, "mime": asset_mime, "size": size } + + progmem.write('typedef std::function RouteRegistrationHandler;\n\n') + progmem.write('class WWWData {\n') + progmem.write('\tpublic:\n') + progmem.write('\t\tstatic void registerRoutes(RouteRegistrationHandler handler) {\n') + + for asset_path, asset in assetMap.items(): + progmem.write(f'\t\t\thandler("/{asset_path}", "{asset["mime"]}", {asset["name"]}, {asset["size"]});\n') + + progmem.write('\t\t}\n') + progmem.write('};\n\n') + +def build_webapp(): + os.chdir("../app2") + print("Building app with pnpm") + env.Execute("pnpm install") + env.Execute("pnpm run build") + os.chdir("../esp32") + +def embed_webapp(): + if flag_exists("EMBED_WWW"): + print("Converting interface to PROGMEM") + build_progmem() + return + +print("running: build_interface.py") +if (should_regenerate_output_file()): + build_webapp() +embed_webapp() \ No newline at end of file diff --git a/esp32/scripts/generate_cert_bundle.py b/esp32/scripts/generate_cert_bundle.py new file mode 100644 index 0000000..2aca225 --- /dev/null +++ b/esp32/scripts/generate_cert_bundle.py @@ -0,0 +1,209 @@ +#!/usr/bin/env python +# +# modified ESP32 x509 certificate bundle generation utility to run with platformio +# +# Converts PEM and DER certificates to a custom bundle format which stores just the +# subject name and public key to reduce space +# +# The bundle will have the format: number of certificates; crt 1 subject name length; crt 1 public key length; +# crt 1 subject name; crt 1 public key; crt 2... +# +# SPDX-FileCopyrightText: 2018-2022 Espressif Systems (Shanghai) CO LTD +# SPDX-License-Identifier: Apache-2.0 + +from __future__ import with_statement + +from pathlib import Path +import os +import struct +import sys +import requests +from io import open + +Import("env") + +try: + from cryptography import x509 + from cryptography.hazmat.backends import default_backend + from cryptography.hazmat.primitives import serialization +except ImportError: + env.Execute("$PYTHONEXE -m pip install cryptography") + + +ca_bundle_bin_file = 'x509_crt_bundle.bin' +mozilla_cacert_url = 'https://curl.se/ca/cacert.pem' +adafruit_cacert_url = 'https://raw.githubusercontent.com/adafruit/certificates/main/data/roots.pem' +certs_dir = Path("./ssl_certs") +binary_dir = Path("./src/certs") + +quiet = False + +def download_cacert_file(source): + if source == "mozilla": + response = requests.get(mozilla_cacert_url) + elif source == "adafruit": + response = requests.get(adafruit_cacert_url) + else: + raise InputError('Invalid certificate source') + + if response.status_code == 200: + + # Ensure the directory exists, create it if necessary + os.makedirs(certs_dir, exist_ok=True) + + # Generate the full path to the output file + output_file = os.path.join(certs_dir, "cacert.pem") + + # Write the certificate bundle to the output file with utf-8 encoding + with open(output_file, "w", encoding="utf-8") as f: + f.write(response.text) + + status('Certificate bundle downloaded to: %s' % output_file) + else: + status('Failed to fetch the certificate bundle.') + +def status(msg): + """ Print status message to stderr """ + if not quiet: + critical(msg) + + +def critical(msg): + """ Print critical message to stderr """ + sys.stderr.write('SSL Cert Store: ') + sys.stderr.write(msg) + sys.stderr.write('\n') + + +class CertificateBundle: + def __init__(self): + self.certificates = [] + self.compressed_crts = [] + + if os.path.isfile(ca_bundle_bin_file): + os.remove(ca_bundle_bin_file) + + def add_from_path(self, crts_path): + + found = False + for file_path in os.listdir(crts_path): + found |= self.add_from_file(os.path.join(crts_path, file_path)) + + if found is False: + raise InputError('No valid x509 certificates found in %s' % crts_path) + + def add_from_file(self, file_path): + try: + if file_path.endswith('.pem'): + status('Parsing certificates from %s' % file_path) + with open(file_path, 'r', encoding='utf-8') as f: + crt_str = f.read() + self.add_from_pem(crt_str) + return True + + elif file_path.endswith('.der'): + status('Parsing certificates from %s' % file_path) + with open(file_path, 'rb') as f: + crt_str = f.read() + self.add_from_der(crt_str) + return True + + except ValueError: + critical('Invalid certificate in %s' % file_path) + raise InputError('Invalid certificate') + + return False + + def add_from_pem(self, crt_str): + """ A single PEM file may have multiple certificates """ + + crt = '' + count = 0 + start = False + + for strg in crt_str.splitlines(True): + if strg == '-----BEGIN CERTIFICATE-----\n' and start is False: + crt = '' + start = True + elif strg == '-----END CERTIFICATE-----\n' and start is True: + crt += strg + '\n' + start = False + self.certificates.append(x509.load_pem_x509_certificate(crt.encode(), default_backend())) + count += 1 + if start is True: + crt += strg + + if count == 0: + raise InputError('No certificate found') + + status('Successfully added %d certificates' % count) + + def add_from_der(self, crt_str): + self.certificates.append(x509.load_der_x509_certificate(crt_str, default_backend())) + status('Successfully added 1 certificate') + + def create_bundle(self): + # Sort certificates in order to do binary search when looking up certificates + self.certificates = sorted(self.certificates, key=lambda cert: cert.subject.public_bytes(default_backend())) + + bundle = struct.pack('>H', len(self.certificates)) + + for crt in self.certificates: + """ Read the public key as DER format """ + pub_key = crt.public_key() + pub_key_der = pub_key.public_bytes(serialization.Encoding.DER, serialization.PublicFormat.SubjectPublicKeyInfo) + + """ Read the subject name as DER format """ + sub_name_der = crt.subject.public_bytes(default_backend()) + + name_len = len(sub_name_der) + key_len = len(pub_key_der) + len_data = struct.pack('>HH', name_len, key_len) + + bundle += len_data + bundle += sub_name_der + bundle += pub_key_der + + return bundle + +class InputError(RuntimeError): + def __init__(self, e): + super(InputError, self).__init__(e) + + +def main(): + + bundle = CertificateBundle() + + try: + cert_source = env.GetProjectOption("board_ssl_cert_source") + + if (cert_source == "mozilla" or cert_source == "adafruit"): + download_cacert_file(cert_source) + bundle.add_from_file(os.path.join(certs_dir, "cacert.pem")) + elif (cert_source == "folder"): + bundle.add_from_path(certs_dir) + except ValueError: + critical('Invalid configuration option: use \'board_ssl_cert_source\' parameter in platformio.ini' ) + raise InputError('Invalid certificate') + + status('Successfully added %d certificates in total' % len(bundle.certificates)) + + crt_bundle = bundle.create_bundle() + + # Ensure the directory exists, create it if necessary + os.makedirs(binary_dir, exist_ok=True) + + output_file = os.path.join(binary_dir, ca_bundle_bin_file) + + with open(output_file, 'wb') as f: + f.write(crt_bundle) + + status('Successfully created %s' % output_file) + + +try: + main() +except InputError as e: + print(e) + sys.exit(2) diff --git a/esp32/scripts/rename_fw.py b/esp32/scripts/rename_fw.py new file mode 100644 index 0000000..f3cdb9d --- /dev/null +++ b/esp32/scripts/rename_fw.py @@ -0,0 +1,89 @@ +""" + EMS-ESP - https://github.com/emsesp/EMS-ESP + Copyright 2020-2023 Paul Derbyshire + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +""" + +import shutil +import re +import os +Import("env") +import hashlib + + +OUTPUT_DIR = "build{}".format(os.path.sep) + +def readFlag(flag): + buildFlags = env.ParseFlags(env["BUILD_FLAGS"]) + # print(buildFlags.get("CPPDEFINES")) + for define in buildFlags.get("CPPDEFINES"): + if (define == flag or (isinstance(define, list) and define[0] == flag)): + # print("Found "+flag+" = "+define[1]) + # strip quotes ("") from define[1] + cleanedFlag = re.sub(r'^"|"$', '', define[1]) + return cleanedFlag + return None + + +def bin_copy(source, target, env): + + # get the build info + app_version = readFlag("APP_VERSION") + app_name = readFlag("APP_NAME") + build_target = env.get('PIOENV') + + # print information's + print("App Version: " + app_version) + print("App Name: " + app_name) + print("Build Target: " + build_target) + + # convert . to - so Windows doesn't complain + variant = app_name + "_" + build_target + "_" + app_version.replace(".", "-") + + # check if output directories exist and create if necessary + if not os.path.isdir(OUTPUT_DIR): + os.mkdir(OUTPUT_DIR) + + for d in ['firmware']: + if not os.path.isdir("{}{}".format(OUTPUT_DIR, d)): + os.mkdir("{}{}".format(OUTPUT_DIR, d)) + + # create string with location and file names based on variant + bin_file = "{}firmware{}{}.bin".format(OUTPUT_DIR, os.path.sep, variant) + md5_file = "{}firmware{}{}.md5".format(OUTPUT_DIR, os.path.sep, variant) + + # check if new target files exist and remove if necessary + for f in [bin_file]: + if os.path.isfile(f): + os.remove(f) + + # check if new target files exist and remove if necessary + for f in [md5_file]: + if os.path.isfile(f): + os.remove(f) + + print("Renaming file to "+bin_file) + + # copy firmware.bin to firmware/.bin + shutil.copy(str(target[0]), bin_file) + + with open(bin_file,"rb") as f: + result = hashlib.md5(f.read()) + print("Calculating MD5: "+result.hexdigest()) + file1 = open(md5_file, 'w') + file1.write(result.hexdigest()) + file1.close() + +env.AddPostAction("$BUILD_DIR/${PROGNAME}.bin", [bin_copy]) +env.AddPostAction("$BUILD_DIR/${PROGNAME}.md5", [bin_copy]) diff --git a/esp32/src/AsyncJpegStream.cpp b/esp32/src/AsyncJpegStream.cpp deleted file mode 100644 index 9753f41..0000000 --- a/esp32/src/AsyncJpegStream.cpp +++ /dev/null @@ -1,128 +0,0 @@ -#include - -static const char* STREAM_CONTENT_TYPE = "multipart/x-mixed-replace;boundary=" PART_BOUNDARY; -static const char* STREAM_BOUNDARY = "\r\n--" PART_BOUNDARY "\r\n"; -static const char* STREAM_PART = "Content-Type: %s\r\nContent-Length: %u\r\n\r\n"; - -static const char * JPG_CONTENT_TYPE = "image/jpeg"; - -AsyncJpegStreamResponse::AsyncJpegStreamResponse(){ - _callback = nullptr; - _code = 200; - _contentLength = 0; - _contentType = STREAM_CONTENT_TYPE; - _sendContentLength = false; - _chunked = true; - _index = 0; - _jpg_buf_len = 0; - _jpg_buf = NULL; - lastAsyncRequest = 0; - memset(&_frame, 0, sizeof(camera_frame_t)); -} - -AsyncJpegStreamResponse::~AsyncJpegStreamResponse(){ - if(_frame.fb){ - if(_frame.fb->format != PIXFORMAT_JPEG){ - free(_jpg_buf); - } - esp_camera_fb_return(_frame.fb); - } -} - -/*bool AsyncJpegStreamResponse::_sourceValid() { - return true; -}*/ - -size_t AsyncJpegStreamResponse::_fillBuffer(uint8_t *buf, size_t maxLen) { - size_t ret = _content(buf, maxLen, _index); - if(ret != RESPONSE_TRY_AGAIN){ - _index += ret; - } - return ret; -} - -size_t AsyncJpegStreamResponse::_content(uint8_t *buffer, size_t maxLen, size_t index){ - if(!_frame.fb || _frame.index == _jpg_buf_len) { - if(index && _frame.fb){ - uint64_t end = (uint64_t)micros(); - int fp = (end - lastAsyncRequest) / 1000; - log_printf("Size: %uKB, Time: %ums (%.1ffps)\n", _jpg_buf_len/1024, fp); - lastAsyncRequest = end; - if(_frame.fb->format != PIXFORMAT_JPEG){ - free(_jpg_buf); - } - esp_camera_fb_return(_frame.fb); - _frame.fb = NULL; - _jpg_buf_len = 0; - _jpg_buf = NULL; - } - if(maxLen < (strlen(STREAM_BOUNDARY) + strlen(STREAM_PART) + strlen(JPG_CONTENT_TYPE) + 8)){ - //log_w("Not enough space for headers"); - return RESPONSE_TRY_AGAIN; - } - //get frame - _frame.index = 0; - - _frame.fb = esp_camera_fb_get(); - if (_frame.fb == NULL) { - log_e("Camera frame failed"); - return 0; - } - - if(_frame.fb->format != PIXFORMAT_JPEG){ - unsigned long st = millis(); - bool jpeg_converted = frame2jpg(_frame.fb, 80, &_jpg_buf, &_jpg_buf_len); - if(!jpeg_converted){ - log_e("JPEG compression failed"); - esp_camera_fb_return(_frame.fb); - _frame.fb = NULL; - _jpg_buf_len = 0; - _jpg_buf = NULL; - return 0; - } - log_i("JPEG: %lums, %uB", millis() - st, _jpg_buf_len); - } else { - _jpg_buf_len = _frame.fb->len; - _jpg_buf = _frame.fb->buf; - } - - //send boundary - size_t blen = 0; - if(index){ - blen = strlen(STREAM_BOUNDARY); - memcpy(buffer, STREAM_BOUNDARY, blen); - buffer += blen; - } - //send header - size_t hlen = sprintf((char *)buffer, STREAM_PART, JPG_CONTENT_TYPE, _jpg_buf_len); - buffer += hlen; - //send frame - hlen = maxLen - hlen - blen; - if(hlen > _jpg_buf_len){ - maxLen -= hlen - _jpg_buf_len; - hlen = _jpg_buf_len; - } - memcpy(buffer, _jpg_buf, hlen); - _frame.index += hlen; - return maxLen; - } - - size_t available = _jpg_buf_len - _frame.index; - if(maxLen > available){ - maxLen = available; - } - memcpy(buffer, _jpg_buf+_frame.index, maxLen); - _frame.index += maxLen; - - return maxLen; -} - - -void streamJpg(AsyncWebServerRequest *request){ - AsyncJpegStreamResponse *response = new AsyncJpegStreamResponse(); - if(!response){ - request->send(501); - return; - } - request->send(response); -} \ No newline at end of file diff --git a/esp32/src/camera.cpp b/esp32/src/camera.cpp deleted file mode 100644 index b4f5dac..0000000 --- a/esp32/src/camera.cpp +++ /dev/null @@ -1,43 +0,0 @@ -#include -#include -#include - -esp_err_t InitializeCamera(){ - camera_config_t camera_config; - camera_config.ledc_channel = LEDC_CHANNEL_0; - camera_config.ledc_timer = LEDC_TIMER_0; - camera_config.pin_d0 = Y2_GPIO_NUM; - camera_config.pin_d1 = Y3_GPIO_NUM; - camera_config.pin_d2 = Y4_GPIO_NUM; - camera_config.pin_d3 = Y5_GPIO_NUM; - camera_config.pin_d4 = Y6_GPIO_NUM; - camera_config.pin_d5 = Y7_GPIO_NUM; - camera_config.pin_d6 = Y8_GPIO_NUM; - camera_config.pin_d7 = Y9_GPIO_NUM; - camera_config.pin_xclk = XCLK_GPIO_NUM; - camera_config.pin_pclk = PCLK_GPIO_NUM; - camera_config.pin_vsync = VSYNC_GPIO_NUM; - camera_config.pin_href = HREF_GPIO_NUM; - camera_config.pin_sscb_sda = SIOD_GPIO_NUM; - camera_config.pin_sscb_scl = SIOC_GPIO_NUM; - camera_config.pin_pwdn = PWDN_GPIO_NUM; - camera_config.pin_reset = RESET_GPIO_NUM; - camera_config.xclk_freq_hz = 20000000; - camera_config.pixel_format = PIXFORMAT_JPEG; - - if(psramFound()){ - camera_config.frame_size = FRAMESIZE_SVGA; - camera_config.jpeg_quality = 10; - camera_config.fb_count = 2; - } else { - camera_config.frame_size = FRAMESIZE_SVGA; - camera_config.jpeg_quality = 12; - camera_config.fb_count = 1; - } - - log_i("Initializing camera"); - esp_err_t err = esp_camera_init(&camera_config); - if (err != ESP_OK) log_e("Camera probe failed with error 0x%x", err); - - return err; -} \ No newline at end of file diff --git a/esp32/src/certs/x509_crt_bundle.bin b/esp32/src/certs/x509_crt_bundle.bin new file mode 100644 index 0000000..67130fa Binary files /dev/null and b/esp32/src/certs/x509_crt_bundle.bin differ diff --git a/esp32/src/deviceconfig.cpp b/esp32/src/deviceconfig.cpp deleted file mode 100644 index 5c27efb..0000000 --- a/esp32/src/deviceconfig.cpp +++ /dev/null @@ -1,55 +0,0 @@ -#include -#include -#include -#include -#include - -DRAM_ATTR std::unique_ptr g_ptrDeviceConfig; - -DRAM_ATTR size_t g_DeviceConfigJSONBufferSize = 0; - -void DeviceConfig::SaveToJSON() -{ - g_ptrJSONWriter->FlagWriter(writerIndex); -} - -DeviceConfig::DeviceConfig() -{ - // Add SettingSpec for additional settings to this list - settingSpecs.emplace_back( - NAME_OF(ntpServer), - "NTP server address", - "The hostname or IP address of the NTP server to be used for time synchronization.", - SettingSpec::SettingType::String - ); - settingSpecs.emplace_back( - NAME_OF(useMetric), - "Use metric system", - "A boolean that indicates if unit should be shown in metric ('true'/1) or imperial ('false'/0) format.", - SettingSpec::SettingType::Boolean - ); - - log_i("about to write"); - writerIndex = g_ptrJSONWriter->RegisterWriter( - [this]() { SaveToJSONFile(DEVICE_CONFIG_FILE, g_DeviceConfigJSONBufferSize, *this); } - ); - - std::unique_ptr pJsonDoc(nullptr); - - if (LoadJSONFile(DEVICE_CONFIG_FILE, g_DeviceConfigJSONBufferSize, pJsonDoc)) - { - log_i("Loading DeviceConfig from JSON"); - - DeserializeFromJSON(pJsonDoc->as(), true); - } - else - { - log_w("DeviceConfig could not be loaded from JSON, using defaults"); - - // Set default for additional settings in this code - ntpServer = DEFAULT_NTP_SERVER; - - SaveToJSON(); - } -} - diff --git a/esp32/src/jsonserializer.cpp b/esp32/src/jsonserializer.cpp deleted file mode 100644 index e836bee..0000000 --- a/esp32/src/jsonserializer.cpp +++ /dev/null @@ -1,177 +0,0 @@ -#include -#include -#include -#include - -DRAM_ATTR std::unique_ptr g_ptrJSONWriter = nullptr; - -bool LoadJSONFile(const char *fileName, size_t& bufferSize, std::unique_ptr& pJsonDoc) -{ - bool jsonReadSuccessful = false; - - File file = SPIFFS.open(fileName); - - if (file) - { - if (file.size() > 0) - { - log_i("Attempting to read JSON file %s", fileName); - - if (bufferSize == 0) - bufferSize = std::max((size_t)JSON_BUFFER_BASE_SIZE, file.size()); - - // Loop is here to deal with out of memory conditions - while(true) - { - pJsonDoc.reset(new AllocatedJsonDocument(bufferSize)); - - DeserializationError error = deserializeJson(*pJsonDoc, file); - - if (error == DeserializationError::NoMemory) - { - pJsonDoc.reset(nullptr); - file.seek(0); - bufferSize += JSON_BUFFER_INCREMENT; - - log_w("Out of memory reading JSON from file %s - increasing buffer to %zu bytes", fileName, bufferSize); - } - else if (error == DeserializationError::Ok) - { - jsonReadSuccessful = true; - break; - } - else - { - log_w("Error with code %d occurred while deserializing JSON from file %s", to_value(error.code()), fileName); - break; - } - } - } - - file.close(); - } - - return jsonReadSuccessful; -} - -void SerializeWithBufferSize(std::unique_ptr& pJsonDoc, size_t& bufferSize, std::function serializationFunction) -{ - // Loop is here to deal with out of memory conditions - while(true) - { - pJsonDoc.reset(new AllocatedJsonDocument(bufferSize)); - JsonObject jsonObject = pJsonDoc->to(); - - if (serializationFunction(jsonObject)) - break; - - pJsonDoc.reset(nullptr); - bufferSize += JSON_BUFFER_INCREMENT; - - log_w("Out of memory serializing object - increasing buffer to %zu bytes", bufferSize); - } -} - -bool SaveToJSONFile(const char *fileName, size_t& bufferSize, IJSONSerializable& object) -{ - if (bufferSize == 0) - bufferSize = JSON_BUFFER_BASE_SIZE; - - std::unique_ptr pJsonDoc(nullptr); - - SerializeWithBufferSize(pJsonDoc, bufferSize, [&object](JsonObject& jsonObject) { return object.SerializeToJSON(jsonObject); }); - - SPIFFS.remove(fileName); - - File file = SPIFFS.open(fileName, FILE_WRITE); - - if (!file) - { - log_e("Unable to open file %s to write JSON!", fileName); - return false; - } - - size_t bytesWritten = serializeJson(*pJsonDoc, file); - log_i("Number of bytes written to JSON file %s: %d", fileName, bytesWritten); - - file.flush(); - file.close(); - - if (bytesWritten == 0) - { - log_e("Unable to write JSON to file %s!", fileName); - SPIFFS.remove(fileName); - return false; - } - -/* - file = SPIFFS.open(fileName); - if (file) - { - while (file.available()) - Serial.write(file.read()); - - file.close(); - } -*/ - - return true; -} - -bool RemoveJSONFile(const char *fileName) -{ - return SPIFFS.remove(fileName); -} - -size_t JSONWriter::RegisterWriter(std::function writer) -{ - // Add the writer with its flag unset - writers.emplace_back(writer); - return writers.size() - 1; -} - -void JSONWriter::FlagWriter(size_t index) -{ - // Check if we received a valid writer index - if (index >= writers.size()) - return; - - writers[index].flag = true; - latestFlagMs = millis(); - - g_TaskManager.NotifyJSONWriterThread(); -} - -// JSONWriterTaskEntry -// -// Invoke functions that write serialized JSON objects to SPIFFS at request, with some delay -void IRAM_ATTR JSONWriterTaskEntry(void *) -{ - for(;;) - { - TickType_t notifyWait = portMAX_DELAY; - - for (;;) - { - // Wait until we're woken up by a writer being flagged, or until we've reached the hold point - ulTaskNotifyTake(pdTRUE, notifyWait); - - if (!g_ptrJSONWriter) - continue; - - unsigned long holdUntil = g_ptrJSONWriter->latestFlagMs + JSON_WRITER_DELAY; - unsigned long now = millis(); - if (now >= holdUntil) - break; - - notifyWait = pdMS_TO_TICKS(holdUntil - now); - } - - for (auto &entry : g_ptrJSONWriter->writers) - { - // Unset flag before we do the actual write. This makes that we don't miss another flag raise if it happens while writing - if (entry.flag.exchange(false)) - entry.writer(); - } - } -} diff --git a/esp32/src/main.cpp b/esp32/src/main.cpp index a5921a6..f3fe9f4 100644 --- a/esp32/src/main.cpp +++ b/esp32/src/main.cpp @@ -1,32 +1,18 @@ -#include -#include +#include +#include +#define SERIAL_BAUD_RATE 115200 -ESPTaskManager g_TaskManager; -#if USE_WIFI && USE_WEBSERVER - DRAM_ATTR CWebServer g_WebServer; -#endif +PsychicHttpServer server; + +ESP32SvelteKit esp32sveltekit(&server, 120); void setup() { - WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0); - Serial.begin(BAUDRATE); - log_i("Booting"); - SPIFFS.begin(); - Wire.begin(SDA, SCL); - InitializeCamera(); - g_TaskManager.begin(); - g_TaskManager.StartThreads(); + Serial.begin(SERIAL_BAUD_RATE); - g_ptrJSONWriter = std::make_unique(); - g_ptrDeviceConfig = std::make_unique(); - g_ptrServo = std::make_unique(); - - g_ptrServo->begin(); - g_ptrServo->setOscillatorFrequency(SERVO_OSCILLATOR_FREQUENCY); - g_ptrServo->setPWMFreq(SERVO_FREQ); - g_ptrServo->updateServos(); + esp32sveltekit.begin(); } void loop() { - delay(200); + vTaskDelete(NULL); } diff --git a/esp32/src/movement.cpp b/esp32/src/movement.cpp deleted file mode 100644 index ab450bf..0000000 --- a/esp32/src/movement.cpp +++ /dev/null @@ -1,79 +0,0 @@ -#include -#if USE_MPU - #include - #include - #include -#endif - -#if USE_POWER_BUTTON - #include -#endif - -#if USE_POWER_BUTTON - Bounce2::Button PowerButton; -#endif - -#if USE_MPU - DRAM_ATTR MPU6050 g_imu(Wire); - DRAM_ATTR Adafruit_HMC5883_Unified g_mag = Adafruit_HMC5883_Unified(12345); -#endif - -void beginMag() { - if(!g_mag.begin()) log_w("Failed to initialize HMC5883L"); -} - -void beginImu() { - byte status = g_imu.begin(); - if(status != 0) log_w("MPU initialize failed"); - delay(100); - g_imu.calcOffsets(true,true); -} - -float getHeading() { - sensors_event_t event; - g_mag.getEvent(&event); - - float heading = atan2(event.magnetic.y, event.magnetic.x); - float declinationAngle = 0.22; - heading += declinationAngle; - if(heading < 0) heading += 2*PI; - if(heading > 2*PI) heading -= 2*PI; - return heading * 180/M_PI; -} - -float getTemp() { - return g_imu.getTemp(); -} - -float getAngleX() { - return g_imu.getAngleX(); -} - -float getAngleY() { - return g_imu.getAngleX(); -} - -float getAngleZ() { - return g_imu.getAngleZ(); -} - -void IRAM_ATTR MovementHandlingLoopEntry(void *) { - TickType_t notifyWait = 0; - beginMag(); - beginImu(); - - for (;;) { - g_imu.update(); - ulTaskNotifyTake(pdTRUE, notifyWait); - - // #if USE_POWER_BUTTON - // PowerButton.update(); - // if (PowerButton.pressed()) { - // log_i("Power Button Pressed"); - // g_ptrServo->toggleState(); - // } - // #endif - - notifyWait = pdMS_TO_TICKS(100); - } -} \ No newline at end of file diff --git a/esp32/src/network.cpp b/esp32/src/network.cpp deleted file mode 100644 index 2aa1c43..0000000 --- a/esp32/src/network.cpp +++ /dev/null @@ -1,96 +0,0 @@ -#include -#include - -#if USE_WIFI && USE_WEBSERVER - extern DRAM_ATTR CWebServer g_WebServer; -#endif - -#if USE_WIFI - -bool ConnectToWiFi(uint cRetries) { - static bool bPreviousConnection = false; - - if (WiFi.isConnected()) return true; - - log_i("Connection to wifi"); - WiFi.disconnect(); - WiFi.mode(WIFI_STA); - WiFi.setHostname(HOSTNAME); - - for (uint iPass = 0; iPass < cRetries; iPass++) { - log_i("Pass %u of %u: Connecting to Wifi SSID: \"%s\" - ESP32 Free Memory: %u, PSRAM:%u, PSRAM Free: %u\n", - iPass + 1, cRetries, SSID, ESP.getFreeHeap(), ESP.getPsramSize(), ESP.getFreePsram()); - - WiFi.begin(SSID, PASS); - delay(4000 + iPass * 1000); - - if (WiFi.isConnected()) { - log_i("Connected to AP with BSSID: %s\n", WiFi.BSSIDstr().c_str()); - break; - } - } - - // Additional Services onwwards reliant on network so close if not up. - if (false == WiFi.isConnected()) { - log_i("Giving up on WiFi\n"); - return false; - } - - log_i("Received IP: %s", WiFi.localIP().toString().c_str()); - - // If we were connected before, network-dependent services will have been started already - if (bPreviousConnection) - return true; - - #if USE_OTA - //debugI("Publishing OTA..."); - SetupOTA(String(cszHostname)); - #endif - - #if USE_NTP - //debugI("Setting Clock..."); - //NTPTimeClient::UpdateClockFromWeb(&g_Udp); - #endif - - #if USE_WEBSERVER - g_WebServer.begin(); - #endif - - #if USE_MDNS - if(MDNS.begin(HOSTNAME)){ - MDNS.addService("http", "tcp", HTTP_PORT); - } - #endif - - bPreviousConnection = true; - return true; -} - -void IRAM_ATTR NetworkHandlingLoopEntry(void *) { - unsigned long lastWifiCheck = 0; - unsigned long checkWiFiEveryMs = 1000; - - TickType_t notifyWait = 0; - - for (;;) { - ulTaskNotifyTake(pdTRUE, notifyWait); - - if ( millis() - lastWifiCheck > checkWiFiEveryMs) { - if (WiFi.isConnected() == false && ConnectToWiFi(5) == false) { - log_e("Cannot Connect to Wifi!"); - #if WAIT_FOR_WIFI - log_e("Rebooting in 5 seconds due to no Wifi available."); - delay(5000); - throw new std::runtime_error("Rebooting due to no Wifi available."); - #endif - } - } - #if USE_WEBSERVER - g_WebServer.loop(); - #endif - - notifyWait = pdMS_TO_TICKS(1000); - } -} - -#endif // ENABLE_WIFI \ No newline at end of file diff --git a/esp32/src/servo.cpp b/esp32/src/servo.cpp deleted file mode 100644 index 17dab5a..0000000 --- a/esp32/src/servo.cpp +++ /dev/null @@ -1,3 +0,0 @@ -#include - -DRAM_ATTR std::unique_ptr g_ptrServo; \ No newline at end of file diff --git a/esp32/src/webserver.cpp b/esp32/src/webserver.cpp deleted file mode 100644 index 83b83e1..0000000 --- a/esp32/src/webserver.cpp +++ /dev/null @@ -1,346 +0,0 @@ -#include "globals.h" -#include "webserver.h" - -// Maps settings for which a validator is available to the invocation thereof -const std::map CWebServer::settingValidators -{}; - -std::vector CWebServer::deviceSettingSpecs{}; - -// Member function template specialzations - -// Push param that represents a bool. Values considered true are text "true" and any whole number not equal to 0 -template<> -bool CWebServer::PushPostParamIfPresent(AsyncWebServerRequest * pRequest, const String ¶mName, ValueSetter setter) -{ - return PushPostParamIfPresent(pRequest, paramName, setter, [](AsyncWebParameter * param) constexpr - { - const String& value = param->value(); - return value == "true" || strtol(value.c_str(), NULL, 10); - }); -} - -// Push param that represents a size_t -template<> -bool CWebServer::PushPostParamIfPresent(AsyncWebServerRequest * pRequest, const String ¶mName, ValueSetter setter) -{ - return PushPostParamIfPresent(pRequest, paramName, setter, [](AsyncWebParameter * param) constexpr - { - return strtoul(param->value().c_str(), NULL, 10); - }); -} - -// Add CORS header to and send JSON response -template<> -void CWebServer::AddCORSHeaderAndSendResponse(AsyncWebServerRequest * pRequest, AsyncJsonResponse * pResponse) -{ - pResponse->setLength(); - AddCORSHeaderAndSendResponse(pRequest, pResponse); -} - -// Member function implementations - -bool CWebServer::IsPostParamTrue(AsyncWebServerRequest * pRequest, const String & paramName) -{ - bool returnValue = false; - - PushPostParamIfPresent(pRequest, paramName, [&returnValue](auto value) { returnValue = value; return true; }); - - return returnValue; -} - -void CWebServer::GetStatistics(AsyncWebServerRequest * pRequest) -{ - log_v("GetStatistics"); - - auto response = new AsyncJsonResponse(false, JSON_BUFFER_BASE_SIZE); - auto j = response->getRoot(); - - j["HEAP_SIZE"] = _staticStats.HeapSize; - j["HEAP_FREE"] = ESP.getFreeHeap(); - j["HEAP_MIN"] = ESP.getMinFreeHeap(); - - j["DMA_SIZE"] = _staticStats.DmaHeapSize; - j["DMA_FREE"] = heap_caps_get_free_size(MALLOC_CAP_DMA); - j["DMA_MIN"] = heap_caps_get_largest_free_block(MALLOC_CAP_DMA); - - j["PSRAM_SIZE"] = _staticStats.PsramSize; - j["PSRAM_FREE"] = ESP.getFreePsram(); - j["PSRAM_MIN"] = ESP.getMinFreePsram(); - - j["CHIP_MODEL"] = _staticStats.ChipModel; - j["CHIP_CORES"] = _staticStats.ChipCores; - j["CHIP_SPEED"] = _staticStats.CpuFreqMHz; - j["PROG_SIZE"] = _staticStats.SketchSize; - - j["CODE_SIZE"] = _staticStats.SketchSize; - j["CODE_FREE"] = _staticStats.FreeSketchSpace; - j["FLASH_SIZE"] = _staticStats.FlashChipSize; - - j["CPU_USED"] = g_TaskManager.GetCPUUsagePercent(); - j["CPU_USED_CORE0"] = g_TaskManager.GetCPUUsagePercent(0); - j["CPU_USED_CORE1"] = g_TaskManager.GetCPUUsagePercent(1); - - AddCORSHeaderAndSendResponse(pRequest, response); -} - -void CWebServer::SendSettingSpecsResponse(AsyncWebServerRequest * pRequest, const std::vector & settingSpecs) -{ - static size_t jsonBufferSize = JSON_BUFFER_BASE_SIZE; - bool bufferOverflow; - - do - { - bufferOverflow = false; - auto response = std::make_unique(false, jsonBufferSize); - auto jsonArray = response->getRoot().to(); - - for (auto& spec : settingSpecs) - { - auto specObject = jsonArray.createNestedObject(); - - StaticJsonDocument<384> jsonDoc; - - jsonDoc["name"] = spec.Name; - jsonDoc["friendlyName"] = spec.FriendlyName; - jsonDoc["description"] = spec.Description; - jsonDoc["type"] = to_value(spec.Type); - jsonDoc["typeName"] = spec.ToName(spec.Type); - - if (!specObject.set(jsonDoc.as())) - { - bufferOverflow = true; - jsonBufferSize += JSON_BUFFER_INCREMENT; - log_v("JSON response buffer overflow! Increased buffer to %zu bytes", jsonBufferSize); - break; - } - } - - if (!bufferOverflow) - AddCORSHeaderAndSendResponse(pRequest, response.release()); - - } while (bufferOverflow); -} - -const std::vector & CWebServer::LoadDeviceSettingSpecs() -{ - if (deviceSettingSpecs.size() == 0) - { - auto deviceConfigSpecs = g_ptrDeviceConfig->GetSettingSpecs(); - deviceSettingSpecs.insert(deviceSettingSpecs.end(), deviceConfigSpecs.begin(), deviceConfigSpecs.end()); - } - - return deviceSettingSpecs; -} - -void CWebServer::GetSettingSpecs(AsyncWebServerRequest * pRequest) -{ - SendSettingSpecsResponse(pRequest, LoadDeviceSettingSpecs()); -} - -// Responds with current config, excluding any sensitive values -void CWebServer::GetSettings(AsyncWebServerRequest * pRequest) -{ - log_v("GetSettings"); - - auto response = new AsyncJsonResponse(false, JSON_BUFFER_BASE_SIZE); - response->addHeader("Server","NightDriverStrip"); - auto root = response->getRoot(); - JsonObject jsonObject = root.to(); - - // We get the serialized JSON for the device config, without any sensitive values - g_ptrDeviceConfig->SerializeToJSON(jsonObject, false); - - AddCORSHeaderAndSendResponse(pRequest, response); -} - -// Support function that silently sets whatever settings are included in the request passed. -// Composing a response is left to the invoker! -void CWebServer::SetSettingsIfPresent(AsyncWebServerRequest * pRequest) -{ - PushPostParamIfPresent(pRequest, DeviceConfig::NTPServerTag, SET_VALUE(g_ptrDeviceConfig->SetNTPServer(value))); -} - -// Set settings and return resulting config -void CWebServer::SetSettings(AsyncWebServerRequest * pRequest) -{ - log_v("SetSettings"); - - SetSettingsIfPresent(pRequest); - - // We return the current config in response - GetSettings(pRequest); -} - -// Save the posted file to SPIFFS -void CWebServer::SaveFile(AsyncWebServerRequest* request, String filename, size_t index, uint8_t* data, size_t len, bool final) -{ - log_v("SaveFile"); -} - -#if USE_OAT -// Update the current firmware -void CWebServer::UpdateFileSystemImage(AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final) -{ - log_v("UpdateFileSystemImage"); - - HandleUpdate(request, filename, index, data, len, final, (ESP.getFreeSketchSpace() - 0x1000) & 0xFFFFF000, U_FLASH); -} - -// Update the current firmware -void CWebServer::UpdateFirmware(AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final) -{ - log_v("UpdateFirmware"); - - HandleUpdate(request, filename, index, data, len, final, UPDATE_SIZE_UNKNOWN, U_SPIFFS); -} - -// Handles updating the filesystem image or firmware -void CWebServer::HandleUpdate(AsyncWebServerRequest* request, String filename, size_t index, uint8_t* data, size_t len, bool final, size_t upload_size, uint8_t upload_index) { - if (!index) { - log_i("Update Start: %s\n", filename.c_str()); - log_i("Uploading: %d", upload_index); - if (!Update.begin(upload_size, upload_index)) { - Update.printError(Serial); - } - } - if (!Update.hasError()) { - if (Update.write(data, len) != len) { - Update.printError(Serial); - } - } - if (final) { - if (Update.end(true)) { - log_i("Update Success: %uB\n", index + len); - } - else { - Update.printError(Serial); - } - } -} - -// Ensures the request gets send to the client -void CWebServer::UpdateRequestHandler(AsyncWebServerRequest* request){ - bool success = !Update.hasError(); - AsyncWebServerResponse* response = request->beginResponse(200, "text/plain", success ? "OK" : "FAIL"); - response->addHeader("Connection", "close"); - request->send(response); - - if (success) { - delay(250); - ESP.restart(); - } -} -#endif - -// Reset effect config, device config and/or the board itself -void CWebServer::Reset(AsyncWebServerRequest * pRequest) -{ - if (IsPostParamTrue(pRequest, "deviceConfig")) - { - log_i("Removing DeviceConfig"); - g_ptrDeviceConfig->RemovePersisted(); - } - - bool boardResetRequested = IsPostParamTrue(pRequest, "board"); - - AddCORSHeaderAndSendOKResponse(pRequest); - - if (boardResetRequested) - { - log_w("Resetting device at API request!"); - delay(1000); // Give the response a second to be sent - throw new std::runtime_error("Resetting device at API request"); - } -} - -String dir(void) { - String x = ""; - File root = SPIFFS.open("/"); - if(!root) { - return "Failed to open directory"; - } - if(!root.isDirectory()) { - return "Not a directory"; - } - File file = root.openNextFile(); - while(file) { - x += "
"+String(file.name()); - if(file.isDirectory()){ - x += "DIR"; - } else { - x += ""+String(file.size()); - } - file = root.openNextFile(); - } - x += "
Occupied space"+String(SPIFFS.usedBytes()); - x += "
Total space"+String(SPIFFS.totalBytes()); - return x+"
"; -} - -// Send Gzip SPA -void CWebServer::GzipSpa(AsyncWebServerRequest * pRequest) -{ - if(!SPIFFS.exists("/index.html.gz")){ - log_e("Gzipped SPA not found"); - pRequest->send(404, "text/html", dir()); - return; - } - - AsyncWebServerResponse *response = pRequest->beginResponse(SPIFFS, "/index.html.gz", "text/html", false); - response->addHeader("Content-Encoding", "gzip"); - response->addHeader("Cache-Control"," max-age=86400"); - AddCORSHeaderAndSendResponse(pRequest, response); -} - -enum Action { - SERVO_UPDATE, -}; - -void handleWebSocketJson(uint8_t* data) { - const uint8_t size = JSON_OBJECT_SIZE(1); - StaticJsonDocument<100> json; - DeserializationError err = deserializeJson(json, data); - if (err) { - Serial.print(F("deserializeJson() failed with code ")); - Serial.println(err.c_str()); - return; - } - - const uint8_t action = json["action"]; - - if(action == 0) { - const uint8_t servoIndex = json["servo"]; - const int16_t pwm = json["pwm"]; - log_i("Moving servo:%u to pwm%u", servoIndex, pwm); - g_ptrServo->setPWM(servoIndex, 0, pwm); - } -} - -void handleWebSocketBuffer(uint8_t* data) { - if(data[0] == 0) g_ptrServo->setBody(data[1], data[2], data[3], data[4], data[5], data[6]); - else if(data[0] == 1) { - log_i("About to update all servos"); - int16_t* angles = (int16_t*)data+1; - - g_ptrServo->SetAngles(angles); - } -} - -void handleWebSocketMessage(void* arg, uint8_t* data, size_t len, AsyncWebSocket* server, AsyncWebSocketClient* client) { - AwsFrameInfo* info = (AwsFrameInfo*)arg; - if(info->final && info->index == 0 && info->len == len){ - if(info->opcode == WS_TEXT) handleWebSocketJson(data); - else handleWebSocketBuffer(data); - } -} - -// Reset effect config, device config and/or the board itself -void CWebServer::HandleWsMessage(AsyncWebSocket* server, AsyncWebSocketClient* client, AwsEventType type, void* arg, uint8_t* data, size_t len) -{ - //if (type == WS_EVT_CONNECT) handleNewConnection(server, client); - /*else*/ if (type == WS_EVT_DISCONNECT) log_i("ws[%s][%u] disconnect\n", server->url(), client->id()); - else if (type == WS_EVT_ERROR) log_i("ws[%s][%u] error(%u): %s\n", server->url(), client->id(), *((uint16_t*)arg), (char*)data); - else if (type == WS_EVT_PONG) log_i("ws[%s][%u] pong[%u]: %s\n", server->url(), client->id(), len, (len) ? (char*)data : ""); - else if (type == WS_EVT_DATA) handleWebSocketMessage(arg, data, len, server, client); -} diff --git a/esp32/ssl_certs/DigiCert_Global_Root_CA.pem b/esp32/ssl_certs/DigiCert_Global_Root_CA.pem new file mode 100644 index 0000000..fd4341d --- /dev/null +++ b/esp32/ssl_certs/DigiCert_Global_Root_CA.pem @@ -0,0 +1,22 @@ +-----BEGIN CERTIFICATE----- +MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD +QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT +MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j +b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG +9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB +CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97 +nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt +43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P +T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4 +gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO +BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR +TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw +DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr +hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg +06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF +PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls +YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk +CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4= +-----END CERTIFICATE----- diff --git a/esp32/ssl_certs/cacert.pem b/esp32/ssl_certs/cacert.pem new file mode 100644 index 0000000..e95a203 --- /dev/null +++ b/esp32/ssl_certs/cacert.pem @@ -0,0 +1,1155 @@ +# O=GlobalSign nv-sa, CN=GlobalSign Root CA +-----BEGIN CERTIFICATE----- +MIIDdTCCAl2gAwIBAgILBAAAAAABFUtaw5QwDQYJKoZIhvcNAQEFBQAwVzELMAkG +A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv +b3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAw +MDBaFw0yODAxMjgxMjAwMDBaMFcxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9i +YWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYDVQQDExJHbG9iYWxT +aWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDaDuaZ +jc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavp +xy0Sy6scTHAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp +1Wrjsok6Vjk4bwY8iGlbKk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdG +snUOhugZitVtbNV4FpWi6cgKOOvyJBNPc1STE4U6G7weNLWLBYy5d4ux2x8gkasJ +U26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrXgzT/LCrBbBlDSgeF59N8 +9iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8E +BTADAQH/MB0GA1UdDgQWBBRge2YaRQ2XyolQL30EzTSo//z9SzANBgkqhkiG9w0B +AQUFAAOCAQEA1nPnfE920I2/7LqivjTFKDK1fPxsnCwrvQmeU79rXqoRSLblCKOz +yj1hTdNGCbM+w6DjY1Ub8rrvrTnhQ7k4o+YviiY776BQVvnGCv04zcQLcFGUl5gE +38NflNUVyRRBnMRddWQVDf9VMOyGj/8N7yy5Y0b2qvzfvGn9LhJIZJrglfCm7ymP +AbEVtQwdpf5pLGkkeB6zpxxxYu7KyJesF12KwvhHhm4qxFYxldBniYUr+WymXUad +DKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveCX4XSQRjbgbME +HMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A== +-----END CERTIFICATE----- +# O=Entrust.net, CN=Entrust.net Certification Authority (2048) +-----BEGIN CERTIFICATE----- +MIIEKjCCAxKgAwIBAgIEOGPe+DANBgkqhkiG9w0BAQUFADCBtDEUMBIGA1UEChML +RW50cnVzdC5uZXQxQDA+BgNVBAsUN3d3dy5lbnRydXN0Lm5ldC9DUFNfMjA0OCBp +bmNvcnAuIGJ5IHJlZi4gKGxpbWl0cyBsaWFiLikxJTAjBgNVBAsTHChjKSAxOTk5 +IEVudHJ1c3QubmV0IExpbWl0ZWQxMzAxBgNVBAMTKkVudHJ1c3QubmV0IENlcnRp +ZmljYXRpb24gQXV0aG9yaXR5ICgyMDQ4KTAeFw05OTEyMjQxNzUwNTFaFw0yOTA3 +MjQxNDE1MTJaMIG0MRQwEgYDVQQKEwtFbnRydXN0Lm5ldDFAMD4GA1UECxQ3d3d3 +LmVudHJ1c3QubmV0L0NQU18yMDQ4IGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxp +YWIuKTElMCMGA1UECxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEG +A1UEAxMqRW50cnVzdC5uZXQgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgKDIwNDgp +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArU1LqRKGsuqjIAcVFmQq +K0vRvwtKTY7tgHalZ7d4QMBzQshowNtTK91euHaYNZOLGp18EzoOH1u3Hs/lJBQe +sYGpjX24zGtLA/ECDNyrpUAkAH90lKGdCCmziAv1h3edVc3kw37XamSrhRSGlVuX +MlBvPci6Zgzj/L24ScF2iUkZ/cCovYmjZy/Gn7xxGWC4LeksyZB2ZnuU4q941mVT +XTzWnLLPKQP5L6RQstRIzgUyVYr9smRMDuSYB3Xbf9+5CFVghTAp+XtIpGmG4zU/ +HoZdenoVve8AjhUiVBcAkCaTvA5JaJG/+EfTnZVCwQ5N328mz8MYIWJmQ3DW1cAH +4QIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNV +HQ4EFgQUVeSB0RGAvtiJuQijMfmhJAkWuXAwDQYJKoZIhvcNAQEFBQADggEBADub +j1abMOdTmXx6eadNl9cZlZD7Bh/KM3xGY4+WZiT6QBshJ8rmcnPyT/4xmf3IDExo +U8aAghOY+rat2l098c5u9hURlIIM7j+VrxGrD9cv3h8Dj1csHsm7mhpElesYT6Yf +zX1XEC+bBAlahLVu2B064dae0Wx5XnkcFMXj0EyTO2U87d89vqbllRrDtRnDvV5b +u/8j72gZyxKTJ1wDLW8w0B62GqzeWvfRqqgnpv55gcR5mTNXuhKwqeBCbJPKVt7+ +bYQLCIt+jerXmCHG8+c8eS9enNFMFY3h7CI3zJpDC5fcgJCNs2ebb0gIFVbPv/Er +fF6adulZkMV8gzURZVE= +-----END CERTIFICATE----- +# O=Baltimore, CN=Baltimore CyberTrust Root +-----BEGIN CERTIFICATE----- +MIIDdzCCAl+gAwIBAgIEAgAAuTANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQGEwJJ +RTESMBAGA1UEChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0MSIwIAYD +VQQDExlCYWx0aW1vcmUgQ3liZXJUcnVzdCBSb290MB4XDTAwMDUxMjE4NDYwMFoX +DTI1MDUxMjIzNTkwMFowWjELMAkGA1UEBhMCSUUxEjAQBgNVBAoTCUJhbHRpbW9y +ZTETMBEGA1UECxMKQ3liZXJUcnVzdDEiMCAGA1UEAxMZQmFsdGltb3JlIEN5YmVy +VHJ1c3QgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKMEuyKr +mD1X6CZymrV51Cni4eiVgLGw41uOKymaZN+hXe2wCQVt2yguzmKiYv60iNoS6zjr +IZ3AQSsBUnuId9Mcj8e6uYi1agnnc+gRQKfRzMpijS3ljwumUNKoUMMo6vWrJYeK +mpYcqWe4PwzV9/lSEy/CG9VwcPCPwBLKBsua4dnKM3p31vjsufFoREJIE9LAwqSu +XmD+tqYF/LTdB1kC1FkYmGP1pWPgkAx9XbIGevOF6uvUA65ehD5f/xXtabz5OTZy +dc93Uk3zyZAsuT3lySNTPx8kmCFcB5kpvcY67Oduhjprl3RjM71oGDHweI12v/ye +jl0qhqdNkNwnGjkCAwEAAaNFMEMwHQYDVR0OBBYEFOWdWTCCR1jMrPoIVDaGezq1 +BE3wMBIGA1UdEwEB/wQIMAYBAf8CAQMwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3 +DQEBBQUAA4IBAQCFDF2O5G9RaEIFoN27TyclhAO992T9Ldcw46QQF+vaKSm2eT92 +9hkTI7gQCvlYpNRhcL0EYWoSihfVCr3FvDB81ukMJY2GQE/szKN+OMY3EU/t3Wgx +jkzSswF07r51XgdIGn9w/xZchMB5hbgF/X++ZRGjD8ACtPhSNzkE1akxehi/oCr0 +Epn3o0WC4zxe9Z2etciefC7IpJ5OCBRLbf1wbWsaY71k5h+3zvDyny67G7fyUIhz +ksLi4xaNmjICq44Y3ekQEe5+NauQrz4wlHrQMz2nZQ/1/I6eYs9HRCwBXbsdtTLS +R9I4LtD+gdwyah617jzV/OeBHRnDJELqYzmp +-----END CERTIFICATE----- +# O=Entrust, Inc., CN=Entrust Root Certification Authority +-----BEGIN CERTIFICATE----- +MIIEkTCCA3mgAwIBAgIERWtQVDANBgkqhkiG9w0BAQUFADCBsDELMAkGA1UEBhMC +VVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xOTA3BgNVBAsTMHd3dy5lbnRydXN0 +Lm5ldC9DUFMgaXMgaW5jb3Jwb3JhdGVkIGJ5IHJlZmVyZW5jZTEfMB0GA1UECxMW +KGMpIDIwMDYgRW50cnVzdCwgSW5jLjEtMCsGA1UEAxMkRW50cnVzdCBSb290IENl +cnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA2MTEyNzIwMjM0MloXDTI2MTEyNzIw +NTM0MlowgbAxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMuMTkw +NwYDVQQLEzB3d3cuZW50cnVzdC5uZXQvQ1BTIGlzIGluY29ycG9yYXRlZCBieSBy +ZWZlcmVuY2UxHzAdBgNVBAsTFihjKSAyMDA2IEVudHJ1c3QsIEluYy4xLTArBgNV +BAMTJEVudHJ1c3QgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASIwDQYJ +KoZIhvcNAQEBBQADggEPADCCAQoCggEBALaVtkNC+sZtKm9I35RMOVcF7sN5EUFo +Nu3s/poBj6E4KPz3EEZmLk0eGrEaTsbRwJWIsMn/MYszA9u3g3s+IIRe7bJWKKf4 +4LlAcTfFy0cOlypowCKVYhXbR9n10Cv/gkvJrT7eTNuQgFA/CYqEAOwwCj0Yzfv9 +KlmaI5UXLEWeH25DeW0MXJj+SKfFI0dcXv1u5x609mhF0YaDW6KKjbHjKYD+JXGI +rb68j6xSlkuqUY3kEzEZ6E5Nn9uss2rVvDlUccp6en+Q3X0dgNmBu1kmwhH+5pPi +94DkZfs0Nw4pgHBNrziGLp5/V6+eF67rHMsoIV+2HNjnogQi+dPa2MsCAwEAAaOB +sDCBrTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zArBgNVHRAEJDAi +gA8yMDA2MTEyNzIwMjM0MlqBDzIwMjYxMTI3MjA1MzQyWjAfBgNVHSMEGDAWgBRo +kORnpKZTgMeGZqTx90tD+4S9bTAdBgNVHQ4EFgQUaJDkZ6SmU4DHhmak8fdLQ/uE +vW0wHQYJKoZIhvZ9B0EABBAwDhsIVjcuMTo0LjADAgSQMA0GCSqGSIb3DQEBBQUA +A4IBAQCT1DCw1wMgKtD5Y+iRDAUgqV8ZyntyTtSx29CW+1RaGSwMCPeyvIWonX9t +O1KzKtvn1ISMY/YPyyYBkVBs9F8U4pN0wBOeMDpQ47RgxRzwIkSNcUesyBrJ6Zua +AGAT/3B+XxFNSRuzFVJ7yVTav52Vr2ua2J7p8eRDjeIRRDq/r72DQnNSi6q7pynP +9WQcCk3RvKqsnyrQ/39/2n3qse0wJcGE2jTSW3iDVuycNsMm4hH2Z0kdkquM++v/ +eu6FSqdQgPCnXEqULl8FmTxSQeDNtGPPAUO6nIPcj2A781q0tHuu2guQOHXvgR1m +0vdXcDazv/wor3ElhVsT/h5/WrQ8 +-----END CERTIFICATE----- +# O=Comodo CA Limited, CN=AAA Certificate Services +-----BEGIN CERTIFICATE----- +MIIEMjCCAxqgAwIBAgIBATANBgkqhkiG9w0BAQUFADB7MQswCQYDVQQGEwJHQjEb +MBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRow +GAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDEhMB8GA1UEAwwYQUFBIENlcnRpZmlj +YXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAwMDAwMFoXDTI4MTIzMTIzNTk1OVowezEL +MAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UE +BwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxITAfBgNVBAMM +GEFBQSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczCCASIwDQYJKoZIhvcNAQEBBQADggEP +ADCCAQoCggEBAL5AnfRu4ep2hxxNRUSOvkbIgwadwSr+GB+O5AL686tdUIoWMQua +BtDFcCLNSS1UY8y2bmhGC1Pqy0wkwLxyTurxFa70VJoSCsN6sjNg4tqJVfMiWPPe +3M/vg4aijJRPn2jymJBGhCfHdr/jzDUsi14HZGWCwEiwqJH5YZ92IFCokcdmtet4 +YgNW8IoaE+oxox6gmf049vYnMlhvB/VruPsUK6+3qszWY19zjNoFmag4qMsXeDZR +rOme9Hg6jc8P2ULimAyrL58OAd7vn5lJ8S3frHRNG5i1R8XlKdH5kBjHYpy+g8cm +ez6KJcfA3Z3mNWgQIJ2P2N7Sw4ScDV7oL8kCAwEAAaOBwDCBvTAdBgNVHQ4EFgQU +oBEKIz6W8Qfs4q8p74Klf9AwpLQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQF +MAMBAf8wewYDVR0fBHQwcjA4oDagNIYyaHR0cDovL2NybC5jb21vZG9jYS5jb20v +QUFBQ2VydGlmaWNhdGVTZXJ2aWNlcy5jcmwwNqA0oDKGMGh0dHA6Ly9jcmwuY29t +b2RvLm5ldC9BQUFDZXJ0aWZpY2F0ZVNlcnZpY2VzLmNybDANBgkqhkiG9w0BAQUF +AAOCAQEACFb8AvCb6P+k+tZ7xkSAzk/ExfYAWMymtrwUSWgEdujm7l3sAg9g1o1Q +GE8mTgHj5rCl7r+8dFRBv/38ErjHT1r0iWAFf2C3BUrz9vHCv8S5dIa2LX1rzNLz +Rt0vxuBqw8M0Ayx9lt1awg6nCpnBBYurDC/zXDrPbDdVCYfeU0BsWO/8tqtlbgT2 +G9w84FoVxp7Z8VlIMCFlA2zs6SFz7JsDoeA3raAVGI/6ugLOpyypEBMs1OUIJqsi +l2D4kF501KKaU73yqWjgom7C12yxow+ev+to51byrvLjKzg6CYG1a4XXvi3tPxq3 +smPi9WIsgtRqAEFQ8TmDn5XpNpaYbg== +-----END CERTIFICATE----- +# O=The Go Daddy Group, Inc., CN= +-----BEGIN CERTIFICATE----- +MIIEADCCAuigAwIBAgIBADANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEh +MB8GA1UEChMYVGhlIEdvIERhZGR5IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBE +YWRkeSBDbGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA0MDYyOTE3 +MDYyMFoXDTM0MDYyOTE3MDYyMFowYzELMAkGA1UEBhMCVVMxITAfBgNVBAoTGFRo +ZSBHbyBEYWRkeSBHcm91cCwgSW5jLjExMC8GA1UECxMoR28gRGFkZHkgQ2xhc3Mg +MiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASAwDQYJKoZIhvcNAQEBBQADggEN +ADCCAQgCggEBAN6d1+pXGEmhW+vXX0iG6r7d/+TvZxz0ZWizV3GgXne77ZtJ6XCA +PVYYYwhv2vLM0D9/AlQiVBDYsoHUwHU9S3/Hd8M+eKsaA7Ugay9qK7HFiH7Eux6w +wdhFJ2+qN1j3hybX2C32qRe3H3I2TqYXP2WYktsqbl2i/ojgC95/5Y0V4evLOtXi +EqITLdiOr18SPaAIBQi2XKVlOARFmR6jYGB0xUGlcmIbYsUfb18aQr4CUWWoriMY +avx4A6lNf4DD+qta/KFApMoZFv6yyO9ecw3ud72a9nmYvLEHZ6IVDd2gWMZEewo+ +YihfukEHU1jPEX44dMX4/7VpkI+EdOqXG68CAQOjgcAwgb0wHQYDVR0OBBYEFNLE +sNKR1EwRcbNhyz2h/t2oatTjMIGNBgNVHSMEgYUwgYKAFNLEsNKR1EwRcbNhyz2h +/t2oatTjoWekZTBjMQswCQYDVQQGEwJVUzEhMB8GA1UEChMYVGhlIEdvIERhZGR5 +IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBEYWRkeSBDbGFzcyAyIENlcnRpZmlj +YXRpb24gQXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQAD +ggEBADJL87LKPpH8EsahB4yOd6AzBhRckB4Y9wimPQoZ+YeAEW5p5JYXMP80kWNy +OO7MHAGjHZQopDH2esRU1/blMVgDoszOYtuURXO1v0XJJLXVggKtI3lpjbi2Tc7P +TMozI+gciKqdi0FuFskg5YmezTvacPd+mSYgFFQlq25zheabIZ0KbIIOqPjCDPoQ +HmyW74cNxA9hi63ugyuV+I6ShHI56yDqg+2DzZduCLzrTia2cyvk0/ZM/iZx4mER +dEr/VxqHD3VILs9RaRegAhJhldXRQLIQTO7ErBBDpqWeCtWVYpoNz4iCxTIM5Cuf +ReYNnyicsbkqWletNw+vHX/bvZ8= +-----END CERTIFICATE----- +# O=Starfield Technologies, Inc., CN= +-----BEGIN CERTIFICATE----- +MIIEDzCCAvegAwIBAgIBADANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJVUzEl +MCMGA1UEChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMp +U3RhcmZpZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQw +NjI5MTczOTE2WhcNMzQwNjI5MTczOTE2WjBoMQswCQYDVQQGEwJVUzElMCMGA1UE +ChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMpU3RhcmZp +ZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEgMA0GCSqGSIb3 +DQEBAQUAA4IBDQAwggEIAoIBAQC3Msj+6XGmBIWtDBFk385N78gDGIc/oav7PKaf +8MOh2tTYbitTkPskpD6E8J7oX+zlJ0T1KKY/e97gKvDIr1MvnsoFAZMej2YcOadN ++lq2cwQlZut3f+dZxkqZJRRU6ybH838Z1TBwj6+wRir/resp7defqgSHo9T5iaU0 +X9tDkYI22WY8sbi5gv2cOj4QyDvvBmVmepsZGD3/cVE8MC5fvj13c7JdBmzDI1aa +K4UmkhynArPkPw2vCHmCuDY96pzTNbO8acr1zJ3o/WSNF4Azbl5KXZnJHoe0nRrA +1W4TNSNe35tfPe/W93bC6j67eA0cQmdrBNj41tpvi/JEoAGrAgEDo4HFMIHCMB0G +A1UdDgQWBBS/X7fRzt0fhvRbVazc1xDCDqmI5zCBkgYDVR0jBIGKMIGHgBS/X7fR +zt0fhvRbVazc1xDCDqmI56FspGowaDELMAkGA1UEBhMCVVMxJTAjBgNVBAoTHFN0 +YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAsTKVN0YXJmaWVsZCBD +bGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8w +DQYJKoZIhvcNAQEFBQADggEBAAWdP4id0ckaVaGsafPzWdqbAYcaT1epoXkJKtv3 +L7IezMdeatiDh6GX70k1PncGQVhiv45YuApnP+yz3SFmH8lU+nLMPUxA2IGvd56D +eruix/U0F47ZEUD0/CwqTRV/p2JdLiXTAAsgGh1o+Re49L2L7ShZ3U0WixeDyLJl +xy16paq8U4Zt3VekyvggQQto8PT7dL5WXXp59fkdheMtlb71cZBDzI0fmgAKhynp +VSJYACPq4xJDKVtHCN2MQWplBqjlIapBtJUhlbl90TSrE9atvNziPTnNvT51cKEY +WQPJIrSPnNVeKtelttQKbfi3QBFGmh95DmK/D5fs4C8fF5Q= +-----END CERTIFICATE----- +# O=DigiCert Inc, CN=DigiCert Assured ID Root CA +-----BEGIN CERTIFICATE----- +MIIDtzCCAp+gAwIBAgIQDOfg5RfYRv6P5WD8G/AwOTANBgkqhkiG9w0BAQUFADBl +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv +b3QgQ0EwHhcNMDYxMTEwMDAwMDAwWhcNMzExMTEwMDAwMDAwWjBlMQswCQYDVQQG +EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNl +cnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0EwggEi +MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCtDhXO5EOAXLGH87dg+XESpa7c +JpSIqvTO9SA5KFhgDPiA2qkVlTJhPLWxKISKityfCgyDF3qPkKyK53lTXDGEKvYP +mDI2dsze3Tyoou9q+yHyUmHfnyDXH+Kx2f4YZNISW1/5WBg1vEfNoTb5a3/UsDg+ +wRvDjDPZ2C8Y/igPs6eD1sNuRMBhNZYW/lmci3Zt1/GiSw0r/wty2p5g0I6QNcZ4 +VYcgoc/lbQrISXwxmDNsIumH0DJaoroTghHtORedmTpyoeb6pNnVFzF1roV9Iq4/ +AUaG9ih5yLHa5FcXxH4cDrC0kqZWs72yl+2qp/C3xag/lRbQ/6GW6whfGHdPAgMB +AAGjYzBhMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQW +BBRF66Kv9JLLgjEtUYunpyGd823IDzAfBgNVHSMEGDAWgBRF66Kv9JLLgjEtUYun +pyGd823IDzANBgkqhkiG9w0BAQUFAAOCAQEAog683+Lt8ONyc3pklL/3cmbYMuRC +dWKuh+vy1dneVrOfzM4UKLkNl2BcEkxY5NM9g0lFWJc1aRqoR+pWxnmrEthngYTf +fwk8lOa4JiwgvT2zKIn3X/8i4peEH+ll74fg38FnSbNd67IJKusm7Xi+fT8r87cm +NW1fiQG2SVufAQWbqz0lwcy2f8Lxb4bG+mRo64EtlOtCt/qMHt1i8b5QZ7dsvfPx +H2sMNgcWfzd8qVttevESRmCD1ycEvkvOl77DZypoEd+A5wwzZr8TDRRu838fYxAe ++o0bJW1sj6W3YQGx0qMmoRBxna3iw/nDmVG3KwcIzi7mULKn+gpFL6Lw8g== +-----END CERTIFICATE----- +# O=DigiCert Inc, CN=DigiCert Global Root CA +-----BEGIN CERTIFICATE----- +MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD +QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT +MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j +b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG +9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB +CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97 +nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt +43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P +T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4 +gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO +BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR +TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw +DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr +hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg +06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF +PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls +YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk +CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4= +-----END CERTIFICATE----- +# O=DigiCert Inc, CN=DigiCert High Assurance EV Root CA +-----BEGIN CERTIFICATE----- +MIIDxTCCAq2gAwIBAgIQAqxcJmoLQJuPC3nyrkYldzANBgkqhkiG9w0BAQUFADBs +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j +ZSBFViBSb290IENBMB4XDTA2MTExMDAwMDAwMFoXDTMxMTExMDAwMDAwMFowbDEL +MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3 +LmRpZ2ljZXJ0LmNvbTErMCkGA1UEAxMiRGlnaUNlcnQgSGlnaCBBc3N1cmFuY2Ug +RVYgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMbM5XPm ++9S75S0tMqbf5YE/yc0lSbZxKsPVlDRnogocsF9ppkCxxLeyj9CYpKlBWTrT3JTW +PNt0OKRKzE0lgvdKpVMSOO7zSW1xkX5jtqumX8OkhPhPYlG++MXs2ziS4wblCJEM +xChBVfvLWokVfnHoNb9Ncgk9vjo4UFt3MRuNs8ckRZqnrG0AFFoEt7oT61EKmEFB +Ik5lYYeBQVCmeVyJ3hlKV9Uu5l0cUyx+mM0aBhakaHPQNAQTXKFx01p8VdteZOE3 +hzBWBOURtCmAEvF5OYiiAhF8J2a3iLd48soKqDirCmTCv2ZdlYTBoSUeh10aUAsg +EsxBu24LUTi4S8sCAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQF +MAMBAf8wHQYDVR0OBBYEFLE+w2kD+L9HAdSYJhoIAu9jZCvDMB8GA1UdIwQYMBaA +FLE+w2kD+L9HAdSYJhoIAu9jZCvDMA0GCSqGSIb3DQEBBQUAA4IBAQAcGgaX3Nec +nzyIZgYIVyHbIUf4KmeqvxgydkAQV8GK83rZEWWONfqe/EW1ntlMMUu4kehDLI6z +eM7b41N5cdblIZQB2lWHmiRk9opmzN6cN82oNLFpmyPInngiK3BD41VHMWEZ71jF +hS9OMPagMRYjyOfiZRYzy78aG6A9+MpeizGLYAiJLQwGXFK3xPkKmNEVX58Svnw2 +Yzi9RKR/5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2/S6cCZdkGCe +vEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep ++OkuE6N36B9K +-----END CERTIFICATE----- +# O=COMODO CA Limited, CN=COMODO Certification Authority +-----BEGIN CERTIFICATE----- +MIIEHTCCAwWgAwIBAgIQToEtioJl4AsC7j41AkblPTANBgkqhkiG9w0BAQUFADCB +gTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G +A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxJzAlBgNV +BAMTHkNPTU9ETyBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNjEyMDEwMDAw +MDBaFw0yOTEyMzEyMzU5NTlaMIGBMQswCQYDVQQGEwJHQjEbMBkGA1UECBMSR3Jl +YXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHEwdTYWxmb3JkMRowGAYDVQQKExFDT01P +RE8gQ0EgTGltaXRlZDEnMCUGA1UEAxMeQ09NT0RPIENlcnRpZmljYXRpb24gQXV0 +aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0ECLi3LjkRv3 +UcEbVASY06m/weaKXTuH+7uIzg3jLz8GlvCiKVCZrts7oVewdFFxze1CkU1B/qnI +2GqGd0S7WWaXUF601CxwRM/aN5VCaTwwxHGzUvAhTaHYujl8HJ6jJJ3ygxaYqhZ8 +Q5sVW7euNJH+1GImGEaaP+vB+fGQV+useg2L23IwambV4EajcNxo2f8ESIl33rXp ++2dtQem8Ob0y2WIC8bGoPW43nOIv4tOiJovGuFVDiOEjPqXSJDlqR6sA1KGzqSX+ +DT+nHbrTUcELpNqsOO9VUCQFZUaTNE8tja3G1CEZ0o7KBWFxB3NH5YoZEr0ETc5O +nKVIrLsm9wIDAQABo4GOMIGLMB0GA1UdDgQWBBQLWOWLxkwVN6RAqTCpIb5HNlpW +/zAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zBJBgNVHR8EQjBAMD6g +PKA6hjhodHRwOi8vY3JsLmNvbW9kb2NhLmNvbS9DT01PRE9DZXJ0aWZpY2F0aW9u +QXV0aG9yaXR5LmNybDANBgkqhkiG9w0BAQUFAAOCAQEAPpiem/Yb6dc5t3iuHXIY +SdOH5EOC6z/JqvWote9VfCFSZfnVDeFs9D6Mk3ORLgLETgdxb8CPOGEIqB6BCsAv +IC9Bi5HcSEW88cbeunZrM8gALTFGTO3nnc+IlP8zwFboJIYmuNg4ON8qa90SzMc/ +RxdMosIGlgnW2/4/PEZB31jiVg88O8EckzXZOFKs7sjsLjBOlDW0JB9LeGna8gI4 +zJVSk/BwJVmcIGfE7vmLV2H0knZ9P4SNVbfo5azV8fUZVqZa+5Acr5Pr5RzUZ5dd +BA6+C4OmF4O5MBKgxTMVBbkN+8cFduPYSo38NBejxiEovjBFMR7HeL5YYTisO+IB +ZQ== +-----END CERTIFICATE----- +# O=COMODO CA Limited, CN=COMODO ECC Certification Authority +-----BEGIN CERTIFICATE----- +MIICiTCCAg+gAwIBAgIQH0evqmIAcFBUTAGem2OZKjAKBggqhkjOPQQDAzCBhTEL +MAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UE +BxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMT +IkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDgwMzA2MDAw +MDAwWhcNMzgwMTE4MjM1OTU5WjCBhTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdy +ZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09N +T0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlv +biBBdXRob3JpdHkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQDR3svdcmCFYX7deSR +FtSrYpn1PlILBs5BAH+X4QokPB0BBO490o0JlwzgdeT6+3eKKvUDYEs2ixYjFq0J +cfRK9ChQtP6IHG4/bC8vCVlbpVsLM5niwz2J+Wos77LTBumjQjBAMB0GA1UdDgQW +BBR1cacZSBm8nZ3qQUfflMRId5nTeTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/ +BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjEA7wNbeqy3eApyt4jf/7VGFAkK+qDm +fQjGGoe9GKhzvSbKYAydzpmfz1wPMOG+FDHqAjAU9JM8SaczepBGR7NjfRObTrdv +GDeAU/7dIOA1mjbRxwG55tzd8/8dLDoWV9mSOdY= +-----END CERTIFICATE----- +# O=GlobalSign, CN=GlobalSign +-----BEGIN CERTIFICATE----- +MIIDXzCCAkegAwIBAgILBAAAAAABIVhTCKIwDQYJKoZIhvcNAQELBQAwTDEgMB4G +A1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjMxEzARBgNVBAoTCkdsb2JhbFNp +Z24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDkwMzE4MTAwMDAwWhcNMjkwMzE4 +MTAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMzETMBEG +A1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZI +hvcNAQEBBQADggEPADCCAQoCggEBAMwldpB5BngiFvXAg7aEyiie/QV2EcWtiHL8 +RgJDx7KKnQRfJMsuS+FggkbhUqsMgUdwbN1k0ev1LKMPgj0MK66X17YUhhB5uzsT +gHeMCOFJ0mpiLx9e+pZo34knlTifBtc+ycsmWQ1z3rDI6SYOgxXG71uL0gRgykmm +KPZpO/bLyCiR5Z2KYVc3rHQU3HTgOu5yLy6c+9C7v/U9AOEGM+iCK65TpjoWc4zd +QQ4gOsC0p6Hpsk+QLjJg6VfLuQSSaGjlOCZgdbKfd/+RFO+uIEn8rUAVSNECMWEZ +XriX7613t2Saer9fwRPvm2L7DWzgVGkWqQPabumDk3F2xmmFghcCAwEAAaNCMEAw +DgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFI/wS3+o +LkUkrk1Q+mOai97i3Ru8MA0GCSqGSIb3DQEBCwUAA4IBAQBLQNvAUKr+yAzv95ZU +RUm7lgAJQayzE4aGKAczymvmdLm6AC2upArT9fHxD4q/c2dKg8dEe3jgr25sbwMp +jjM5RcOO5LlXbKr8EpbsU8Yt5CRsuZRj+9xTaGdWPoO4zzUhw8lo/s7awlOqzJCK +6fBdRoyV3XpYKBovHd7NADdBj+1EbddTKJd+82cEHhXXipa0095MJ6RMG3NzdvQX +mcIfeg7jLQitChws/zyrVQ4PkX4268NXSb7hLi18YIvDQVETI53O9zJrlAGomecs +Mx86OyXShkDOOyyGeMlhLxS67ttVb9+E7gUJTb0o2HLO02JQZR7rkpeDMdmztcpH +WD9f +-----END CERTIFICATE----- +# O=GoDaddy.com, Inc., CN=Go Daddy Root Certificate Authority - G2 +-----BEGIN CERTIFICATE----- +MIIDxTCCAq2gAwIBAgIBADANBgkqhkiG9w0BAQsFADCBgzELMAkGA1UEBhMCVVMx +EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxGjAYBgNVBAoT +EUdvRGFkZHkuY29tLCBJbmMuMTEwLwYDVQQDEyhHbyBEYWRkeSBSb290IENlcnRp +ZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAwMFoXDTM3MTIzMTIz +NTk1OVowgYMxCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6b25hMRMwEQYDVQQH +EwpTY290dHNkYWxlMRowGAYDVQQKExFHb0RhZGR5LmNvbSwgSW5jLjExMC8GA1UE +AxMoR28gRGFkZHkgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIw +DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL9xYgjx+lk09xvJGKP3gElY6SKD +E6bFIEMBO4Tx5oVJnyfq9oQbTqC023CYxzIBsQU+B07u9PpPL1kwIuerGVZr4oAH +/PMWdYA5UXvl+TW2dE6pjYIT5LY/qQOD+qK+ihVqf94Lw7YZFAXK6sOoBJQ7Rnwy +DfMAZiLIjWltNowRGLfTshxgtDj6AozO091GB94KPutdfMh8+7ArU6SSYmlRJQVh +GkSBjCypQ5Yj36w6gZoOKcUcqeldHraenjAKOc7xiID7S13MMuyFYkMlNAJWJwGR +tDtwKj9useiciAF9n9T521NtYJ2/LOdYq7hfRvzOxBsDPAnrSTFcaUaz4EcCAwEA +AaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYE +FDqahQcQZyi27/a9BUFuIMGU2g/eMA0GCSqGSIb3DQEBCwUAA4IBAQCZ21151fmX +WWcDYfF+OwYxdS2hII5PZYe096acvNjpL9DbWu7PdIxztDhC2gV7+AJ1uP2lsdeu +9tfeE8tTEH6KRtGX+rcuKxGrkLAngPnon1rpN5+r5N9ss4UXnT3ZJE95kTXWXwTr +gIOrmgIttRD02JDHBHNA7XIloKmf7J6raBKZV8aPEjoJpL1E/QYVN8Gb5DKj7Tjo +2GTzLH4U/ALqn83/B2gX2yKQOC16jdFU8WnjXzPKej17CuPKf1855eJ1usV2GDPO +LPAvTK33sefOT6jEm0pUBsV/fdUID+Ic/n4XuKxe9tQWskMJDE32p2u0mYRlynqI +4uJEvlz36hz1 +-----END CERTIFICATE----- +# O=Starfield Technologies, Inc., CN=Starfield Root Certificate Authority - G2 +-----BEGIN CERTIFICATE----- +MIID3TCCAsWgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBjzELMAkGA1UEBhMCVVMx +EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoT +HFN0YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAMTKVN0YXJmaWVs +ZCBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAw +MFoXDTM3MTIzMTIzNTk1OVowgY8xCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6 +b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFyZmllbGQgVGVj +aG5vbG9naWVzLCBJbmMuMTIwMAYDVQQDEylTdGFyZmllbGQgUm9vdCBDZXJ0aWZp +Y2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC +ggEBAL3twQP89o/8ArFvW59I2Z154qK3A2FWGMNHttfKPTUuiUP3oWmb3ooa/RMg +nLRJdzIpVv257IzdIvpy3Cdhl+72WoTsbhm5iSzchFvVdPtrX8WJpRBSiUZV9Lh1 +HOZ/5FSuS/hVclcCGfgXcVnrHigHdMWdSL5stPSksPNkN3mSwOxGXn/hbVNMYq/N +Hwtjuzqd+/x5AJhhdM8mgkBj87JyahkNmcrUDnXMN/uLicFZ8WJ/X7NfZTD4p7dN +dloedl40wOiWVpmKs/B/pM293DIxfJHP4F8R+GuqSVzRmZTRouNjWwl2tVZi4Ut0 +HZbUJtQIBFnQmA4O5t78w+wfkPECAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAO +BgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFHwMMh+n2TB/xH1oo2Kooc6rB1snMA0G +CSqGSIb3DQEBCwUAA4IBAQARWfolTwNvlJk7mh+ChTnUdgWUXuEok21iXQnCoKjU +sHU48TRqneSfioYmUeYs0cYtbpUgSpIB7LiKZ3sx4mcujJUDJi5DnUox9g61DLu3 +4jd/IroAow57UvtruzvE03lRTs2Q9GcHGcg8RnoNAX3FWOdt5oUwF5okxBDgBPfg +8n/Uqgr/Qh037ZTlZFkSIHc40zI+OIF1lnP6aI+xy84fxez6nH7PfrHxBy22/L/K +pL/QlwVKvOoYKAKQvVR4CSFx09F9HdkWsKlhPdAKACL8x3vLCWRFCztAgfd9fDL1 +mMpYjn0q7pBZc2T5NnReJaH1ZgUufzkVqSr7UIuOhWn0 +-----END CERTIFICATE----- +# O=Starfield Technologies, Inc., CN=Starfield Services Root Certificate Authority - G2 +-----BEGIN CERTIFICATE----- +MIID7zCCAtegAwIBAgIBADANBgkqhkiG9w0BAQsFADCBmDELMAkGA1UEBhMCVVMx +EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoT +HFN0YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xOzA5BgNVBAMTMlN0YXJmaWVs +ZCBTZXJ2aWNlcyBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5 +MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgZgxCzAJBgNVBAYTAlVTMRAwDgYD +VQQIEwdBcml6b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFy +ZmllbGQgVGVjaG5vbG9naWVzLCBJbmMuMTswOQYDVQQDEzJTdGFyZmllbGQgU2Vy +dmljZXMgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZI +hvcNAQEBBQADggEPADCCAQoCggEBANUMOsQq+U7i9b4Zl1+OiFOxHz/Lz58gE20p +OsgPfTz3a3Y4Y9k2YKibXlwAgLIvWX/2h/klQ4bnaRtSmpDhcePYLQ1Ob/bISdm2 +8xpWriu2dBTrz/sm4xq6HZYuajtYlIlHVv8loJNwU4PahHQUw2eeBGg6345AWh1K +Ts9DkTvnVtYAcMtS7nt9rjrnvDH5RfbCYM8TWQIrgMw0R9+53pBlbQLPLJGmpufe +hRhJfGZOozptqbXuNC66DQO4M99H67FrjSXZm86B0UVGMpZwh94CDklDhbZsc7tk +6mFBrMnUVN+HL8cisibMn1lUaJ/8viovxFUcdUBgF4UCVTmLfwUCAwEAAaNCMEAw +DwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFJxfAN+q +AdcwKziIorhtSpzyEZGDMA0GCSqGSIb3DQEBCwUAA4IBAQBLNqaEd2ndOxmfZyMI +bw5hyf2E3F/YNoHN2BtBLZ9g3ccaaNnRbobhiCPPE95Dz+I0swSdHynVv/heyNXB +ve6SbzJ08pGCL72CQnqtKrcgfU28elUSwhXqvfdqlS5sdJ/PHLTyxQGjhdByPq1z +qwubdQxtRbeOlKyWN7Wg0I8VRw7j6IPdj/3vQQF3zCepYoUz8jcI73HPdwbeyBkd +iEDPfUYd/x7H4c7/I9vG+o1VTqkC50cRRj70/b17KSa7qWFiNyi2LSr2EIZkyXCn +0q23KXB56jzaYyWf/Wi3MOxw+3WKt21gZ7IeyLnp2KhvAotnDU0mV3HaIPzBSlCN +sSi6 +-----END CERTIFICATE----- +# O=DigiCert Inc, CN=DigiCert Assured ID Root G2 +-----BEGIN CERTIFICATE----- +MIIDljCCAn6gAwIBAgIQC5McOtY5Z+pnI7/Dr5r0SzANBgkqhkiG9w0BAQsFADBl +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv +b3QgRzIwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1MTIwMDAwWjBlMQswCQYDVQQG +EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNl +cnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzIwggEi +MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDZ5ygvUj82ckmIkzTz+GoeMVSA +n61UQbVH35ao1K+ALbkKz3X9iaV9JPrjIgwrvJUXCzO/GU1BBpAAvQxNEP4Htecc +biJVMWWXvdMX0h5i89vqbFCMP4QMls+3ywPgym2hFEwbid3tALBSfK+RbLE4E9Hp +EgjAALAcKxHad3A2m67OeYfcgnDmCXRwVWmvo2ifv922ebPynXApVfSr/5Vh88lA +bx3RvpO704gqu52/clpWcTs/1PPRCv4o76Pu2ZmvA9OPYLfykqGxvYmJHzDNw6Yu +YjOuFgJ3RFrngQo8p0Quebg/BLxcoIfhG69Rjs3sLPr4/m3wOnyqi+RnlTGNAgMB +AAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQW +BBTOw0q5mVXyuNtgv6l+vVa1lzan1jANBgkqhkiG9w0BAQsFAAOCAQEAyqVVjOPI +QW5pJ6d1Ee88hjZv0p3GeDgdaZaikmkuOGybfQTUiaWxMTeKySHMq2zNixya1r9I +0jJmwYrA8y8678Dj1JGG0VDjA9tzd29KOVPt3ibHtX2vK0LRdWLjSisCx1BL4Gni +lmwORGYQRI+tBev4eaymG+g3NJ1TyWGqolKvSnAWhsI6yLETcDbYz+70CjTVW0z9 +B5yiutkBclzzTcHdDrEcDcRjvq30FPuJ7KJBDkzMyFdA0G4Dqs0MjomZmWzwPDCv +ON9vvKO+KSAnq3T/EyJ43pdSVR6DtVQgA+6uwE9W3jfMw3+qBCe703e4YtsXfJwo +IhNzbM8m9Yop5w== +-----END CERTIFICATE----- +# O=DigiCert Inc, CN=DigiCert Assured ID Root G3 +-----BEGIN CERTIFICATE----- +MIICRjCCAc2gAwIBAgIQC6Fa+h3foLVJRK/NJKBs7DAKBggqhkjOPQQDAzBlMQsw +CQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cu +ZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3Qg +RzMwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1MTIwMDAwWjBlMQswCQYDVQQGEwJV +UzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQu +Y29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzMwdjAQBgcq +hkjOPQIBBgUrgQQAIgNiAAQZ57ysRGXtzbg/WPuNsVepRC0FFfLvC/8QdJ+1YlJf +Zn4f5dwbRXkLzMZTCp2NXQLZqVneAlr2lSoOjThKiknGvMYDOAdfVdp+CW7if17Q +RSAPWXYQ1qAk8C3eNvJsKTmjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/ +BAQDAgGGMB0GA1UdDgQWBBTL0L2p4ZgFUaFNN6KDec6NHSrkhDAKBggqhkjOPQQD +AwNnADBkAjAlpIFFAmsSS3V0T8gj43DydXLefInwz5FyYZ5eEJJZVrmDxxDnOOlY +JjZ91eQ0hjkCMHw2U/Aw5WJjOpnitqM7mzT6HtoQknFekROn3aRukswy1vUhZscv +6pZjamVFkpUBtA== +-----END CERTIFICATE----- +# O=DigiCert Inc, CN=DigiCert Global Root G2 +-----BEGIN CERTIFICATE----- +MIIDjjCCAnagAwIBAgIQAzrx5qcRqaC7KGSxHQn65TANBgkqhkiG9w0BAQsFADBh +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBH +MjAeFw0xMzA4MDExMjAwMDBaFw0zODAxMTUxMjAwMDBaMGExCzAJBgNVBAYTAlVT +MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j +b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEcyMIIBIjANBgkqhkiG +9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuzfNNNx7a8myaJCtSnX/RrohCgiN9RlUyfuI +2/Ou8jqJkTx65qsGGmvPrC3oXgkkRLpimn7Wo6h+4FR1IAWsULecYxpsMNzaHxmx +1x7e/dfgy5SDN67sH0NO3Xss0r0upS/kqbitOtSZpLYl6ZtrAGCSYP9PIUkY92eQ +q2EGnI/yuum06ZIya7XzV+hdG82MHauVBJVJ8zUtluNJbd134/tJS7SsVQepj5Wz +tCO7TG1F8PapspUwtP1MVYwnSlcUfIKdzXOS0xZKBgyMUNGPHgm+F6HmIcr9g+UQ +vIOlCsRnKPZzFBQ9RnbDhxSJITRNrw9FDKZJobq7nMWxM4MphQIDAQABo0IwQDAP +BgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUTiJUIBiV +5uNu5g/6+rkS7QYXjzkwDQYJKoZIhvcNAQELBQADggEBAGBnKJRvDkhj6zHd6mcY +1Yl9PMWLSn/pvtsrF9+wX3N3KjITOYFnQoQj8kVnNeyIv/iPsGEMNKSuIEyExtv4 +NeF22d+mQrvHRAiGfzZ0JFrabA0UWTW98kndth/Jsw1HKj2ZL7tcu7XUIOGZX1NG +Fdtom/DzMNU+MeKNhJ7jitralj41E6Vf8PlwUHBHQRFXGU7Aj64GxJUTFy8bJZ91 +8rGOmaFvE7FBcf6IKshPECBV1/MUReXgRPTqh5Uykw7+U0b6LJ3/iyK5S9kJRaTe +pLiaWN0bfVKfjllDiIGknibVb63dDcY3fe0Dkhvld1927jyNxF1WW6LZZm6zNTfl +MrY= +-----END CERTIFICATE----- +# O=DigiCert Inc, CN=DigiCert Global Root G3 +-----BEGIN CERTIFICATE----- +MIICPzCCAcWgAwIBAgIQBVVWvPJepDU1w6QP1atFcjAKBggqhkjOPQQDAzBhMQsw +CQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cu +ZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBHMzAe +Fw0xMzA4MDExMjAwMDBaFw0zODAxMTUxMjAwMDBaMGExCzAJBgNVBAYTAlVTMRUw +EwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20x +IDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEczMHYwEAYHKoZIzj0CAQYF +K4EEACIDYgAE3afZu4q4C/sLfyHS8L6+c/MzXRq8NOrexpu80JX28MzQC7phW1FG +fp4tn+6OYwwX7Adw9c+ELkCDnOg/QW07rdOkFFk2eJ0DQ+4QE2xy3q6Ip6FrtUPO +Z9wj/wMco+I+o0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAd +BgNVHQ4EFgQUs9tIpPmhxdiuNkHMEWNpYim8S8YwCgYIKoZIzj0EAwMDaAAwZQIx +AK288mw/EkrRLTnDCgmXc/SINoyIJ7vmiI1Qhadj+Z4y3maTD/HMsQmP3Wyr+mt/ +oAIwOWZbwmSNuJ5Q3KjVSaLtx9zRSX8XAbjIho9OjIgrqJqpisXRAL34VOKa5Vt8 +sycX +-----END CERTIFICATE----- +# O=DigiCert Inc, CN=DigiCert Trusted Root G4 +-----BEGIN CERTIFICATE----- +MIIFkDCCA3igAwIBAgIQBZsbV56OITLiOQe9p3d1XDANBgkqhkiG9w0BAQwFADBi +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3Qg +RzQwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1MTIwMDAwWjBiMQswCQYDVQQGEwJV +UzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQu +Y29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3QgRzQwggIiMA0GCSqG +SIb3DQEBAQUAA4ICDwAwggIKAoICAQC/5pBzaN675F1KPDAiMGkz7MKnJS7JIT3y +ithZwuEppz1Yq3aaza57G4QNxDAf8xukOBbrVsaXbR2rsnnyyhHS5F/WBTxSD1If +xp4VpX6+n6lXFllVcq9ok3DCsrp1mWpzMpTREEQQLt+C8weE5nQ7bXHiLQwb7iDV +ySAdYyktzuxeTsiT+CFhmzTrBcZe7FsavOvJz82sNEBfsXpm7nfISKhmV1efVFiO +DCu3T6cw2Vbuyntd463JT17lNecxy9qTXtyOj4DatpGYQJB5w3jHtrHEtWoYOAMQ +jdjUN6QuBX2I9YI+EJFwq1WCQTLX2wRzKm6RAXwhTNS8rhsDdV14Ztk6MUSaM0C/ +CNdaSaTC5qmgZ92kJ7yhTzm1EVgX9yRcRo9k98FpiHaYdj1ZXUJ2h4mXaXpI8OCi +EhtmmnTK3kse5w5jrubU75KSOp493ADkRSWJtppEGSt+wJS00mFt6zPZxd9LBADM +fRyVw4/3IbKyEbe7f/LVjHAsQWCqsWMYRJUadmJ+9oCw++hkpjPRiQfhvbfmQ6QY +uKZ3AeEPlAwhHbJUKSWJbOUOUlFHdL4mrLZBdd56rF+NP8m800ERElvlEFDrMcXK +chYiCd98THU/Y+whX8QgUWtvsauGi0/C1kVfnSD8oR7FwI+isX4KJpn15GkvmB0t +9dmpsh3lGwIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB +hjAdBgNVHQ4EFgQU7NfjgtJxXWRM3y5nP+e6mK4cD08wDQYJKoZIhvcNAQEMBQAD +ggIBALth2X2pbL4XxJEbw6GiAI3jZGgPVs93rnD5/ZpKmbnJeFwMDF/k5hQpVgs2 +SV1EY+CtnJYYZhsjDT156W1r1lT40jzBQ0CuHVD1UvyQO7uYmWlrx8GnqGikJ9yd ++SeuMIW59mdNOj6PWTkiU0TryF0Dyu1Qen1iIQqAyHNm0aAFYF/opbSnr6j3bTWc +fFqK1qI4mfN4i/RN0iAL3gTujJtHgXINwBQy7zBZLq7gcfJW5GqXb5JQbZaNaHqa +sjYUegbyJLkJEVDXCLG4iXqEI2FCKeWjzaIgQdfRnGTZ6iahixTXTBmyUEFxPT9N +cCOGDErcgdLMMpSEDQgJlxxPwO5rIHQw0uA5NBCFIRUBCOhVMt5xSdkoF1BN5r5N +0XWs0Mr7QbhDparTwwVETyw2m+L64kW4I1NsBm9nVX9GtUw/bihaeSbSpKhil9Ie +4u1Ki7wb/UdKDd9nZn6yW0HQO+T0O/QEY+nvwlQAUaCKKsnOeMzV6ocEGLPOr0mI +r/OSmbaz5mEP0oUA51Aa5BuVnRmhuZyxm7EAHu/QD09CbMkKvO5D+jpxpchNJqU1 +/YldvIViHTLSoCtU7ZpXwdv6EM8Zt4tKG48BtieVU+i2iW1bvGjUI+iLUaJW+fCm +gKDWHrO8Dw9TdSmq6hN35N6MgSGtBxBHEa2HPQfRdbzP82Z+ +-----END CERTIFICATE----- +# O=COMODO CA Limited, CN=COMODO RSA Certification Authority +-----BEGIN CERTIFICATE----- +MIIF2DCCA8CgAwIBAgIQTKr5yttjb+Af907YWwOGnTANBgkqhkiG9w0BAQwFADCB +hTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G +A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNV +BAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTAwMTE5 +MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBhTELMAkGA1UEBhMCR0IxGzAZBgNVBAgT +EkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMR +Q09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNh +dGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCR +6FSS0gpWsawNJN3Fz0RndJkrN6N9I3AAcbxT38T6KhKPS38QVr2fcHK3YX/JSw8X +pz3jsARh7v8Rl8f0hj4K+j5c+ZPmNHrZFGvnnLOFoIJ6dq9xkNfs/Q36nGz637CC +9BR++b7Epi9Pf5l/tfxnQ3K9DADWietrLNPtj5gcFKt+5eNu/Nio5JIk2kNrYrhV +/erBvGy2i/MOjZrkm2xpmfh4SDBF1a3hDTxFYPwyllEnvGfDyi62a+pGx8cgoLEf +Zd5ICLqkTqnyg0Y3hOvozIFIQ2dOciqbXL1MGyiKXCJ7tKuY2e7gUYPDCUZObT6Z ++pUX2nwzV0E8jVHtC7ZcryxjGt9XyD+86V3Em69FmeKjWiS0uqlWPc9vqv9JWL7w +qP/0uK3pN/u6uPQLOvnoQ0IeidiEyxPx2bvhiWC4jChWrBQdnArncevPDt09qZah +SL0896+1DSJMwBGB7FY79tOi4lu3sgQiUpWAk2nojkxl8ZEDLXB0AuqLZxUpaVIC +u9ffUGpVRr+goyhhf3DQw6KqLCGqR84onAZFdr+CGCe01a60y1Dma/RMhnEw6abf +Fobg2P9A3fvQQoh/ozM6LlweQRGBY84YcWsr7KaKtzFcOmpH4MN5WdYgGq/yapiq +crxXStJLnbsQ/LBMQeXtHT1eKJ2czL+zUdqnR+WEUwIDAQABo0IwQDAdBgNVHQ4E +FgQUu69+Aj36pvE8hI6t7jiY7NkyMtQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB +/wQFMAMBAf8wDQYJKoZIhvcNAQEMBQADggIBAArx1UaEt65Ru2yyTUEUAJNMnMvl +wFTPoCWOAvn9sKIN9SCYPBMtrFaisNZ+EZLpLrqeLppysb0ZRGxhNaKatBYSaVqM +4dc+pBroLwP0rmEdEBsqpIt6xf4FpuHA1sj+nq6PK7o9mfjYcwlYRm6mnPTXJ9OV +2jeDchzTc+CiR5kDOF3VSXkAKRzH7JsgHAckaVd4sjn8OoSgtZx8jb8uk2Intzna +FxiuvTwJaP+EmzzV1gsD41eeFPfR60/IvYcjt7ZJQ3mFXLrrkguhxuhoqEwWsRqZ +CuhTLJK7oQkYdQxlqHvLI7cawiiFwxv/0Cti76R7CZGYZ4wUAc1oBmpjIXUDgIiK +boHGhfKppC3n9KUkEEeDys30jXlYsQab5xoq2Z0B15R97QNKyvDb6KkBPvVWmcke +jkk9u+UJueBPSZI9FoJAzMxZxuY67RIuaTxslbH9qh17f4a+Hg4yRvv7E491f0yL +S0Zj/gA0QHDBw7mh3aZw4gSzQbzpgJHqZJx64SIDqZxubw5lT2yHh17zbqD5daWb +QOhTsiedSrnAdyGN/4fy3ryM7xfft0kL0fJuMAsaDk527RH89elWsn2/x20Kk4yl +0MC2Hb46TpSi125sC8KKfPog88Tk5c0NqMuRkrF8hey1FGlmDoLnzc7ILaZRfyHB +NVOFBkpdn627G190 +-----END CERTIFICATE----- +# O=The USERTRUST Network, CN=USERTrust RSA Certification Authority +-----BEGIN CERTIFICATE----- +MIIF3jCCA8agAwIBAgIQAf1tMPyjylGoG7xkDjUDLTANBgkqhkiG9w0BAQwFADCB +iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl +cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV +BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTAw +MjAxMDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBiDELMAkGA1UEBhMCVVMxEzARBgNV +BAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVU +aGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBSU0EgQ2Vy +dGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK +AoICAQCAEmUXNg7D2wiz0KxXDXbtzSfTTK1Qg2HiqiBNCS1kCdzOiZ/MPans9s/B +3PHTsdZ7NygRK0faOca8Ohm0X6a9fZ2jY0K2dvKpOyuR+OJv0OwWIJAJPuLodMkY +tJHUYmTbf6MG8YgYapAiPLz+E/CHFHv25B+O1ORRxhFnRghRy4YUVD+8M/5+bJz/ +Fp0YvVGONaanZshyZ9shZrHUm3gDwFA66Mzw3LyeTP6vBZY1H1dat//O+T23LLb2 +VN3I5xI6Ta5MirdcmrS3ID3KfyI0rn47aGYBROcBTkZTmzNg95S+UzeQc0PzMsNT +79uq/nROacdrjGCT3sTHDN/hMq7MkztReJVni+49Vv4M0GkPGw/zJSZrM233bkf6 +c0Plfg6lZrEpfDKEY1WJxA3Bk1QwGROs0303p+tdOmw1XNtB1xLaqUkL39iAigmT +Yo61Zs8liM2EuLE/pDkP2QKe6xJMlXzzawWpXhaDzLhn4ugTncxbgtNMs+1b/97l +c6wjOy0AvzVVdAlJ2ElYGn+SNuZRkg7zJn0cTRe8yexDJtC/QV9AqURE9JnnV4ee +UB9XVKg+/XRjL7FQZQnmWEIuQxpMtPAlR1n6BB6T1CZGSlCBst6+eLf8ZxXhyVeE +Hg9j1uliutZfVS7qXMYoCAQlObgOK6nyTJccBz8NUvXt7y+CDwIDAQABo0IwQDAd +BgNVHQ4EFgQUU3m/WqorSs9UgOHYm8Cd8rIDZsswDgYDVR0PAQH/BAQDAgEGMA8G +A1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEMBQADggIBAFzUfA3P9wF9QZllDHPF +Up/L+M+ZBn8b2kMVn54CVVeWFPFSPCeHlCjtHzoBN6J2/FNQwISbxmtOuowhT6KO +VWKR82kV2LyI48SqC/3vqOlLVSoGIG1VeCkZ7l8wXEskEVX/JJpuXior7gtNn3/3 +ATiUFJVDBwn7YKnuHKsSjKCaXqeYalltiz8I+8jRRa8YFWSQEg9zKC7F4iRO/Fjs +8PRF/iKz6y+O0tlFYQXBl2+odnKPi4w2r78NBc5xjeambx9spnFixdjQg3IM8WcR +iQycE0xyNN+81XHfqnHd4blsjDwSXWXavVcStkNr/+XeTWYRUc+ZruwXtuhxkYze +Sf7dNXGiFSeUHM9h4ya7b6NnJSFd5t0dCy5oGzuCr+yDZ4XUmFF0sbmZgIn/f3gZ +XHlKYC6SQK5MNyosycdiyA5d9zZbyuAlJQG03RoHnHcAP9Dc1ew91Pq7P8yF1m9/ +qS3fuQL39ZeatTXaw2ewh0qpKJ4jjv9cJ2vhsE/zB+4ALtRZh8tSQZXq9EfX7mRB +VXyNWQKV3WKdwrnuWih0hKWbt5DHDAff9Yk2dDLWKMGwsAvgnEzDHNb842m1R0aB +L6KCq9NjRHDEjf8tM7qtj3u1cIiuPhnPQCjY/MiQu12ZIvVS5ljFH4gxQ+6IHdfG +jjxDah2nGN59PRbxYvnKkKj9 +-----END CERTIFICATE----- +# O=The USERTRUST Network, CN=USERTrust ECC Certification Authority +-----BEGIN CERTIFICATE----- +MIICjzCCAhWgAwIBAgIQXIuZxVqUxdJxVt7NiYDMJjAKBggqhkjOPQQDAzCBiDEL +MAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNl +eSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMT +JVVTRVJUcnVzdCBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTAwMjAx +MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBiDELMAkGA1UEBhMCVVMxEzARBgNVBAgT +Ck5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVUaGUg +VVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBFQ0MgQ2VydGlm +aWNhdGlvbiBBdXRob3JpdHkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQarFRaqflo +I+d61SRvU8Za2EurxtW20eZzca7dnNYMYf3boIkDuAUU7FfO7l0/4iGzzvfUinng +o4N+LZfQYcTxmdwlkWOrfzCjtHDix6EznPO/LlxTsV+zfTJ/ijTjeXmjQjBAMB0G +A1UdDgQWBBQ64QmG1M8ZwpZ2dEl23OA1xmNjmjAOBgNVHQ8BAf8EBAMCAQYwDwYD +VR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjA2Z6EWCNzklwBBHU6+4WMB +zzuqQhFkoJ2UOQIReVx7Hfpkue4WQrO/isIJxOzksU0CMQDpKmFHjFJKS04YcPbW +RNZu9YO6bVi9JNlWSOrvxKJGgYhqOkbRqZtNyWHa0V1Xahg= +-----END CERTIFICATE----- +# O=GlobalSign, CN=GlobalSign +-----BEGIN CERTIFICATE----- +MIICHjCCAaSgAwIBAgIRYFlJ4CYuu1X5CneKcflK2GwwCgYIKoZIzj0EAwMwUDEk +MCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI1MRMwEQYDVQQKEwpH +bG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWduMB4XDTEyMTExMzAwMDAwMFoX +DTM4MDExOTAzMTQwN1owUDEkMCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBD +QSAtIFI1MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWdu +MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAER0UOlvt9Xb/pOdEh+J8LttV7HpI6SFkc +8GIxLcB6KP4ap1yztsyX50XUWPrRd21DosCHZTQKH3rd6zwzocWdTaRvQZU4f8ke +hOvRnkmSh5SHDDqFSmafnVmTTZdhBoZKo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYD +VR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUPeYpSJvqB8ohREom3m7e0oPQn1kwCgYI +KoZIzj0EAwMDaAAwZQIxAOVpEslu28YxuglB4Zf4+/2a4n0Sye18ZNPLBSWLVtmg +515dTguDnFt2KaAJJiFqYgIwcdK1j1zqO+F4CYWodZI7yFz9SO8NdCKoCOJuxUnO +xwy8p2Fp8fc74SrL+SvzZpA3 +-----END CERTIFICATE----- +# O=IdenTrust, CN=IdenTrust Commercial Root CA 1 +-----BEGIN CERTIFICATE----- +MIIFYDCCA0igAwIBAgIQCgFCgAAAAUUjyES1AAAAAjANBgkqhkiG9w0BAQsFADBK +MQswCQYDVQQGEwJVUzESMBAGA1UEChMJSWRlblRydXN0MScwJQYDVQQDEx5JZGVu +VHJ1c3QgQ29tbWVyY2lhbCBSb290IENBIDEwHhcNMTQwMTE2MTgxMjIzWhcNMzQw +MTE2MTgxMjIzWjBKMQswCQYDVQQGEwJVUzESMBAGA1UEChMJSWRlblRydXN0MScw +JQYDVQQDEx5JZGVuVHJ1c3QgQ29tbWVyY2lhbCBSb290IENBIDEwggIiMA0GCSqG +SIb3DQEBAQUAA4ICDwAwggIKAoICAQCnUBneP5k91DNG8W9RYYKyqU+PZ4ldhNlT +3Qwo2dfw/66VQ3KZ+bVdfIrBQuExUHTRgQ18zZshq0PirK1ehm7zCYofWjK9ouuU ++ehcCuz/mNKvcbO0U59Oh++SvL3sTzIwiEsXXlfEU8L2ApeN2WIrvyQfYo3fw7gp +S0l4PJNgiCL8mdo2yMKi1CxUAGc1bnO/AljwpN3lsKImesrgNqUZFvX9t++uP0D1 +bVoE/c40yiTcdCMbXTMTEl3EASX2MN0CXZ/g1Ue9tOsbobtJSdifWwLziuQkkORi +T0/Br4sOdBeo0XKIanoBScy0RnnGF7HamB4HWfp1IYVl3ZBWzvurpWCdxJ35UrCL +vYf5jysjCiN2O/cz4ckA82n5S6LgTrx+kzmEB/dEcH7+B1rlsazRGMzyNeVJSQjK +Vsk9+w8YfYs7wRPCTY/JTw436R+hDmrfYi7LNQZReSzIJTj0+kuniVyc0uMNOYZK +dHzVWYfCP04MXFL0PfdSgvHqo6z9STQaKPNBiDoT7uje/5kdX7rL6B7yuVBgwDHT +c+XvvqDtMwt0viAgxGds8AgDelWAf0ZOlqf0Hj7h9tgJ4TNkK2PXMl6f+cB7D3hv +l7yTmvmcEpB4eoCHFddydJxVdHixuuFucAS6T6C6aMN7/zHwcz09lCqxC0EOoP5N +iGVreTO01wIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB +/zAdBgNVHQ4EFgQU7UQZwNPwBovupHu+QucmVMiONnYwDQYJKoZIhvcNAQELBQAD +ggIBAA2ukDL2pkt8RHYZYR4nKM1eVO8lvOMIkPkp165oCOGUAFjvLi5+U1KMtlwH +6oi6mYtQlNeCgN9hCQCTrQ0U5s7B8jeUeLBfnLOic7iPBZM4zY0+sLj7wM+x8uwt +LRvM7Kqas6pgghstO8OEPVeKlh6cdbjTMM1gCIOQ045U8U1mwF10A0Cj7oV+wh93 +nAbowacYXVKV7cndJZ5t+qntozo00Fl72u1Q8zW/7esUTTHHYPTa8Yec4kjixsU3 ++wYQ+nVZZjFHKdp2mhzpgq7vmrlR94gjmmmVYjzlVYA211QC//G5Xc7UI2/YRYRK +W2XviQzdFKcgyxilJbQN+QHwotL0AMh0jqEqSI5l2xPE4iUXfeu+h1sXIFRRk0pT +AwvsXcoz7WL9RccvW9xYoIA55vrX/hMUpu09lEpCdNTDd1lzzY9GvlU47/rokTLq +l1gEIt44w8y8bckzOmoKaT+gyOpyj4xjhiO9bTyWnpXgSUyqorkqG5w2gXjtw+hG +4iZZRHUe2XWJUc0QhJ1hYMtd+ZciTY6Y5uN/9lu7rs3KSoFrXgvzUeF0K+l+J6fZ +mUlO+KWA2yUPHGNiiskzZ2s8EIPGrd6ozRaOjfAHN3Gf8qv8QfXBi+wAN10J5U6A +7/qxXDgGpRtK4dw4LTzcqx+QGtVKnO7RcGzM7vRX+Bi6hG6H +-----END CERTIFICATE----- +# O=IdenTrust, CN=IdenTrust Public Sector Root CA 1 +-----BEGIN CERTIFICATE----- +MIIFZjCCA06gAwIBAgIQCgFCgAAAAUUjz0Z8AAAAAjANBgkqhkiG9w0BAQsFADBN +MQswCQYDVQQGEwJVUzESMBAGA1UEChMJSWRlblRydXN0MSowKAYDVQQDEyFJZGVu +VHJ1c3QgUHVibGljIFNlY3RvciBSb290IENBIDEwHhcNMTQwMTE2MTc1MzMyWhcN +MzQwMTE2MTc1MzMyWjBNMQswCQYDVQQGEwJVUzESMBAGA1UEChMJSWRlblRydXN0 +MSowKAYDVQQDEyFJZGVuVHJ1c3QgUHVibGljIFNlY3RvciBSb290IENBIDEwggIi +MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC2IpT8pEiv6EdrCvsnduTyP4o7 +ekosMSqMjbCpwzFrqHd2hCa2rIFCDQjrVVi7evi8ZX3yoG2LqEfpYnYeEe4IFNGy +RBb06tD6Hi9e28tzQa68ALBKK0CyrOE7S8ItneShm+waOh7wCLPQ5CQ1B5+ctMlS +bdsHyo+1W/CD80/HLaXIrcuVIKQxKFdYWuSNG5qrng0M8gozOSI5Cpcu81N3uURF +/YTLNiCBWS2ab21ISGHKTN9T0a9SvESfqy9rg3LvdYDaBjMbXcjaY8ZNzaxmMc3R +3j6HEDbhuaR672BQssvKplbgN6+rNBM5Jeg5ZuSYeqoSmJxZZoY+rfGwyj4GD3vw +EUs3oERte8uojHH01bWRNszwFcYr3lEXsZdMUD2xlVl8BX0tIdUAvwFnol57plzy +9yLxkA2T26pEUWbMfXYD62qoKjgZl3YNa4ph+bz27nb9cCvdKTz4Ch5bQhyLVi9V +GxyhLrXHFub4qjySjmm2AcG1hp2JDws4lFTo6tyePSW8Uybt1as5qsVATFSrsrTZ +2fjXctscvG29ZV/viDUqZi/u9rNl8DONfJhBaUYPQxxp+pu10GFqzcpL2UyQRqsV +WaFHVCkugyhfHMKiq3IXAAaOReyL4jM9f9oZRORicsPfIsbyVtTdX5Vy7W1f90gD +W/3FKqD2cyOEEBsB5wIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/ +BAUwAwEB/zAdBgNVHQ4EFgQU43HgntinQtnbcZFrlJPrw6PRFKMwDQYJKoZIhvcN +AQELBQADggIBAEf63QqwEZE4rU1d9+UOl1QZgkiHVIyqZJnYWv6IAcVYpZmxI1Qj +t2odIFflAWJBF9MJ23XLblSQdf4an4EKwt3X9wnQW3IV5B4Jaj0z8yGa5hV+rVHV +DRDtfULAj+7AmgjVQdZcDiFpboBhDhXAuM/FSRJSzL46zNQuOAXeNf0fb7iAaJg9 +TaDKQGXSc3z1i9kKlT/YPyNtGtEqJBnZhbMX73huqVjRI9PHE+1yJX9dsXNw0H8G +lwmEKYBhHfpe/3OsoOOJuBxxFcbeMX8S3OFtm6/n6J91eEyrRjuazr8FGF1NFTwW +mhlQBJqymm9li1JfPFgEKCXAZmExfrngdbkaqIHWchezxQMxNRF4eKLg6TCMf4Df +WN88uieW4oA0beOY02QnrEh+KHdcxiVhJfiFDGX6xDIvpZgF5PgLZxYWxoK4Mhn5 ++bl53B/N66+rDt0b20XkeucC4pVd/GnwU2lhlXV5C15V5jgclKlZM57IcXR5f1GJ +tshquDDIajjDbp7hNxbqBWJMWxJH7ae0s1hWx0nzfxJoCTFx8G34Tkf71oXuxVhA +GaQdp/lLQzfcaFpPz+vCZHTetBXZ9FRUGi8c15dxVJCO2SCdUyt/q4/i6jC8UDfv +8Ue1fXwsBOxonbRJRBD0ckscZOf85muQ3Wl9af0AVqW3rLatt8o+Ae+c +-----END CERTIFICATE----- +# O=Entrust, Inc., CN=Entrust Root Certification Authority - G2 +-----BEGIN CERTIFICATE----- +MIIEPjCCAyagAwIBAgIESlOMKDANBgkqhkiG9w0BAQsFADCBvjELMAkGA1UEBhMC +VVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50 +cnVzdC5uZXQvbGVnYWwtdGVybXMxOTA3BgNVBAsTMChjKSAyMDA5IEVudHJ1c3Qs +IEluYy4gLSBmb3IgYXV0aG9yaXplZCB1c2Ugb25seTEyMDAGA1UEAxMpRW50cnVz +dCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzIwHhcNMDkwNzA3MTcy +NTU0WhcNMzAxMjA3MTc1NTU0WjCBvjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUVu +dHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50cnVzdC5uZXQvbGVnYWwt +dGVybXMxOTA3BgNVBAsTMChjKSAyMDA5IEVudHJ1c3QsIEluYy4gLSBmb3IgYXV0 +aG9yaXplZCB1c2Ugb25seTEyMDAGA1UEAxMpRW50cnVzdCBSb290IENlcnRpZmlj +YXRpb24gQXV0aG9yaXR5IC0gRzIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK +AoIBAQC6hLZy254Ma+KZ6TABp3bqMriVQRrJ2mFOWHLP/vaCeb9zYQYKpSfYs1/T +RU4cctZOMvJyig/3gxnQaoCAAEUesMfnmr8SVycco2gvCoe9amsOXmXzHHfV1IWN +cCG0szLni6LVhjkCsbjSR87kyUnEO6fe+1R9V77w6G7CebI6C1XiUJgWMhNcL3hW +wcKUs/Ja5CeanyTXxuzQmyWC48zCxEXFjJd6BmsqEZ+pCm5IO2/b1BEZQvePB7/1 +U1+cPvQXLOZprE4yTGJ36rfo5bs0vBmLrpxR57d+tVOxMyLlbc9wPBr64ptntoP0 +jaWvYkxN4FisZDQSA/i2jZRjJKRxAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAP +BgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRqciZ60B7vfec7aVHUbI2fkBJmqzAN +BgkqhkiG9w0BAQsFAAOCAQEAeZ8dlsa2eT8ijYfThwMEYGprmi5ZiXMRrEPR9RP/ +jTkrwPK9T3CMqS/qF8QLVJ7UG5aYMzyorWKiAHarWWluBh1+xLlEjZivEtRh2woZ +Rkfz6/djwUAFQKXSt/S1mja/qYh2iARVBCuch38aNzx+LaUa2NSJXsq9rD1s2G2v +1fN2D807iDginWyTmsQ9v4IbZT+mD12q/OWyFcq1rca8PdCE6OoGcrBNOTJ4vz4R +nAuknZoh8/CbCzB428Hch0P+vGOaysXCHMnHjf87ElgI5rY97HosTvuDls4MPGmH +VHOkc8KT/1EQrBVUAdj8BbGJoX90g5pJ19xOe4pIb4tF9g== +-----END CERTIFICATE----- +# O=Entrust, Inc., CN=Entrust Root Certification Authority - EC1 +-----BEGIN CERTIFICATE----- +MIIC+TCCAoCgAwIBAgINAKaLeSkAAAAAUNCR+TAKBggqhkjOPQQDAzCBvzELMAkG +A1UEBhMCVVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3 +d3cuZW50cnVzdC5uZXQvbGVnYWwtdGVybXMxOTA3BgNVBAsTMChjKSAyMDEyIEVu +dHJ1c3QsIEluYy4gLSBmb3IgYXV0aG9yaXplZCB1c2Ugb25seTEzMDEGA1UEAxMq +RW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRUMxMB4XDTEy +MTIxODE1MjUzNloXDTM3MTIxODE1NTUzNlowgb8xCzAJBgNVBAYTAlVTMRYwFAYD +VQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQLEx9TZWUgd3d3LmVudHJ1c3QubmV0 +L2xlZ2FsLXRlcm1zMTkwNwYDVQQLEzAoYykgMjAxMiBFbnRydXN0LCBJbmMuIC0g +Zm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxMzAxBgNVBAMTKkVudHJ1c3QgUm9vdCBD +ZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEVDMTB2MBAGByqGSM49AgEGBSuBBAAi +A2IABIQTydC6bUF74mzQ61VfZgIaJPRbiWlH47jCffHyAsWfoPZb1YsGGYZPUxBt +ByQnoaD41UcZYUx9ypMn6nQM72+WCf5j7HBdNq1nd67JnXxVRDqiY1Ef9eNi1KlH +Bz7MIKNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0O +BBYEFLdj5xrdjekIplWDpOBqUEFlEUJJMAoGCCqGSM49BAMDA2cAMGQCMGF52OVC +R98crlOZF7ZvHH3hvxGU0QOIdeSNiaSKd0bebWHvAvX7td/M/k7//qnmpwIwW5nX +hTcGtXsI/esni0qU+eH6p44mCOh8kmhtc9hvJqwhAriZtyZBWyVgrtBIGu4G +-----END CERTIFICATE----- +# O=Internet Security Research Group, CN=ISRG Root X1 +-----BEGIN CERTIFICATE----- +MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAw +TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh +cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4 +WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJu +ZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBY +MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54rVygc +h77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+ +0TM8ukj13Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6U +A5/TR5d8mUgjU+g4rk8Kb4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sW +T8KOEUt+zwvo/7V3LvSye0rgTBIlDHCNAymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyH +B5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ4Q7e2RCOFvu396j3x+UC +B5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf1b0SHzUv +KBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWn +OlFuhjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTn +jh8BCNAw1FtxNrQHusEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbw +qHyGO0aoSCqI3Haadr8faqU9GY/rOPNk3sgrDQoo//fb4hVC1CLQJ13hef4Y53CI +rU7m2Ys6xt0nUW7/vGT1M0NPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV +HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR5tFnme7bl5AFzgAiIyBpY9umbbjANBgkq +hkiG9w0BAQsFAAOCAgEAVR9YqbyyqFDQDLHYGmkgJykIrGF1XIpu+ILlaS/V9lZL +ubhzEFnTIZd+50xx+7LSYK05qAvqFyFWhfFQDlnrzuBZ6brJFe+GnY+EgPbk6ZGQ +3BebYhtF8GaV0nxvwuo77x/Py9auJ/GpsMiu/X1+mvoiBOv/2X/qkSsisRcOj/KK +NFtY2PwByVS5uCbMiogziUwthDyC3+6WVwW6LLv3xLfHTjuCvjHIInNzktHCgKQ5 +ORAzI4JMPJ+GslWYHb4phowim57iaztXOoJwTdwJx4nLCgdNbOhdjsnvzqvHu7Ur +TkXWStAmzOVyyghqpZXjFaH3pO3JLF+l+/+sKAIuvtd7u+Nxe5AW0wdeRlN8NwdC +jNPElpzVmbUq4JUagEiuTDkHzsxHpFKVK7q4+63SM1N95R1NbdWhscdCb+ZAJzVc +oyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq +4RgqsahDYVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPA +mRGunUHBcnWEvgJBQl9nJEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57d +emyPxgcYxn/eR44/KJ4EBs+lVDR3veyJm+kXQ99b21/+jh5Xos1AnX5iItreGCc= +-----END CERTIFICATE----- +# O=Amazon, CN=Amazon Root CA 1 +-----BEGIN CERTIFICATE----- +MIIDQTCCAimgAwIBAgITBmyfz5m/jAo54vB4ikPmljZbyjANBgkqhkiG9w0BAQsF +ADA5MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6 +b24gUm9vdCBDQSAxMB4XDTE1MDUyNjAwMDAwMFoXDTM4MDExNzAwMDAwMFowOTEL +MAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJv +b3QgQ0EgMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALJ4gHHKeNXj +ca9HgFB0fW7Y14h29Jlo91ghYPl0hAEvrAIthtOgQ3pOsqTQNroBvo3bSMgHFzZM +9O6II8c+6zf1tRn4SWiw3te5djgdYZ6k/oI2peVKVuRF4fn9tBb6dNqcmzU5L/qw +IFAGbHrQgLKm+a/sRxmPUDgH3KKHOVj4utWp+UhnMJbulHheb4mjUcAwhmahRWa6 +VOujw5H5SNz/0egwLX0tdHA114gk957EWW67c4cX8jJGKLhD+rcdqsq08p8kDi1L +93FcXmn/6pUCyziKrlA4b9v7LWIbxcceVOF34GfID5yHI9Y/QCB/IIDEgEw+OyQm +jgSubJrIqg0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC +AYYwHQYDVR0OBBYEFIQYzIU07LwMlJQuCFmcx7IQTgoIMA0GCSqGSIb3DQEBCwUA +A4IBAQCY8jdaQZChGsV2USggNiMOruYou6r4lK5IpDB/G/wkjUu0yKGX9rbxenDI +U5PMCCjjmCXPI6T53iHTfIUJrU6adTrCC2qJeHZERxhlbI1Bjjt/msv0tadQ1wUs +N+gDS63pYaACbvXy8MWy7Vu33PqUXHeeE6V/Uq2V8viTO96LXFvKWlJbYK8U90vv +o/ufQJVtMVT8QtPHRh8jrdkPSHCa2XV4cdFyQzR1bldZwgJcJmApzyMZFo6IQ6XU +5MsI+yMRQ+hDKXJioaldXgjUkK642M4UwtBV8ob2xJNDd2ZhwLnoQdeXeGADbkpy +rqXRfboQnoZsG4q5WTP468SQvvG5 +-----END CERTIFICATE----- +# O=Amazon, CN=Amazon Root CA 2 +-----BEGIN CERTIFICATE----- +MIIFQTCCAymgAwIBAgITBmyf0pY1hp8KD+WGePhbJruKNzANBgkqhkiG9w0BAQwF +ADA5MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6 +b24gUm9vdCBDQSAyMB4XDTE1MDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTEL +MAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJv +b3QgQ0EgMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK2Wny2cSkxK +gXlRmeyKy2tgURO8TW0G/LAIjd0ZEGrHJgw12MBvIITplLGbhQPDW9tK6Mj4kHbZ +W0/jTOgGNk3Mmqw9DJArktQGGWCsN0R5hYGCrVo34A3MnaZMUnbqQ523BNFQ9lXg +1dKmSYXpN+nKfq5clU1Imj+uIFptiJXZNLhSGkOQsL9sBbm2eLfq0OQ6PBJTYv9K +8nu+NQWpEjTj82R0Yiw9AElaKP4yRLuH3WUnAnE72kr3H9rN9yFVkE8P7K6C4Z9r +2UXTu/Bfh+08LDmG2j/e7HJV63mjrdvdfLC6HM783k81ds8P+HgfajZRRidhW+me +z/CiVX18JYpvL7TFz4QuK/0NURBs+18bvBt+xa47mAExkv8LV/SasrlX6avvDXbR +8O70zoan4G7ptGmh32n2M8ZpLpcTnqWHsFcQgTfJU7O7f/aS0ZzQGPSSbtqDT6Zj +mUyl+17vIWR6IF9sZIUVyzfpYgwLKhbcAS4y2j5L9Z469hdAlO+ekQiG+r5jqFoz +7Mt0Q5X5bGlSNscpb/xVA1wf+5+9R+vnSUeVC06JIglJ4PVhHvG/LopyboBZ/1c6 ++XUyo05f7O0oYtlNc/LMgRdg7c3r3NunysV+Ar3yVAhU/bQtCSwXVEqY0VThUWcI +0u1ufm8/0i2BWSlmy5A5lREedCf+3euvAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMB +Af8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBSwDPBMMPQFWAJI/TPlUq9LhONm +UjANBgkqhkiG9w0BAQwFAAOCAgEAqqiAjw54o+Ci1M3m9Zh6O+oAA7CXDpO8Wqj2 +LIxyh6mx/H9z/WNxeKWHWc8w4Q0QshNabYL1auaAn6AFC2jkR2vHat+2/XcycuUY ++gn0oJMsXdKMdYV2ZZAMA3m3MSNjrXiDCYZohMr/+c8mmpJ5581LxedhpxfL86kS +k5Nrp+gvU5LEYFiwzAJRGFuFjWJZY7attN6a+yb3ACfAXVU3dJnJUH/jWS5E4ywl +7uxMMne0nxrpS10gxdr9HIcWxkPo1LsmmkVwXqkLN1PiRnsn/eBG8om3zEK2yygm +btmlyTrIQRNg91CMFa6ybRoVGld45pIq2WWQgj9sAq+uEjonljYE1x2igGOpm/Hl +urR8FLBOybEfdF849lHqm/osohHUqS0nGkWxr7JOcQ3AWEbWaQbLU8uz/mtBzUF+ +fUwPfHJ5elnNXkoOrJupmHN5fLT0zLm4BwyydFy4x2+IoZCn9Kr5v2c69BoVYh63 +n749sSmvZ6ES8lgQGVMDMBu4Gon2nL2XA46jCfMdiyHxtN/kHNGfZQIG6lzWE7OE +76KlXIx3KadowGuuQNKotOrN8I1LOJwZmhsoVLiJkO/KdYE+HvJkJMcYr07/R54H +9jVlpNMKVv/1F2Rs76giJUmTtt8AF9pYfl3uxRuw0dFfIRDH+fO6AgonB8Xx1sfT +4PsJYGw= +-----END CERTIFICATE----- +# O=Amazon, CN=Amazon Root CA 3 +-----BEGIN CERTIFICATE----- +MIIBtjCCAVugAwIBAgITBmyf1XSXNmY/Owua2eiedgPySjAKBggqhkjOPQQDAjA5 +MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24g +Um9vdCBDQSAzMB4XDTE1MDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkG +A1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJvb3Qg +Q0EgMzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABCmXp8ZBf8ANm+gBG1bG8lKl +ui2yEujSLtf6ycXYqm0fc4E7O5hrOXwzpcVOho6AF2hiRVd9RFgdszflZwjrZt6j +QjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBSr +ttvXBp43rDCGB5Fwx5zEGbF4wDAKBggqhkjOPQQDAgNJADBGAiEA4IWSoxe3jfkr +BqWTrBqYaGFy+uGh0PsceGCmQ5nFuMQCIQCcAu/xlJyzlvnrxir4tiz+OpAUFteM +YyRIHN8wfdVoOw== +-----END CERTIFICATE----- +# O=Amazon, CN=Amazon Root CA 4 +-----BEGIN CERTIFICATE----- +MIIB8jCCAXigAwIBAgITBmyf18G7EEwpQ+Vxe3ssyBrBDjAKBggqhkjOPQQDAzA5 +MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24g +Um9vdCBDQSA0MB4XDTE1MDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkG +A1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJvb3Qg +Q0EgNDB2MBAGByqGSM49AgEGBSuBBAAiA2IABNKrijdPo1MN/sGKe0uoe0ZLY7Bi +9i0b2whxIdIA6GO9mif78DluXeo9pcmBqqNbIJhFXRbb/egQbeOc4OO9X4Ri83Bk +M6DLJC9wuoihKqB1+IGuYgbEgds5bimwHvouXKNCMEAwDwYDVR0TAQH/BAUwAwEB +/zAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0OBBYEFNPsxzplbszh2naaVvuc84ZtV+WB +MAoGCCqGSM49BAMDA2gAMGUCMDqLIfG9fhGt0O9Yli/W651+kI0rz2ZVwyzjKKlw +CkcO8DdZEv8tmZQoTipPNU0zWgIxAOp1AE47xDqUEpHJWEadIRNyp4iciuRMStuW +1KyLa2tJElMzrdfkviT8tQp21KW8EA== +-----END CERTIFICATE----- +# O=SSL Corporation, CN=SSL.com Root Certification Authority RSA +-----BEGIN CERTIFICATE----- +MIIF3TCCA8WgAwIBAgIIeyyb0xaAMpkwDQYJKoZIhvcNAQELBQAwfDELMAkGA1UE +BhMCVVMxDjAMBgNVBAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMRgwFgYDVQQK +DA9TU0wgQ29ycG9yYXRpb24xMTAvBgNVBAMMKFNTTC5jb20gUm9vdCBDZXJ0aWZp +Y2F0aW9uIEF1dGhvcml0eSBSU0EwHhcNMTYwMjEyMTczOTM5WhcNNDEwMjEyMTcz +OTM5WjB8MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMxEDAOBgNVBAcMB0hv +dXN0b24xGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjExMC8GA1UEAwwoU1NMLmNv +bSBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IFJTQTCCAiIwDQYJKoZIhvcN +AQEBBQADggIPADCCAgoCggIBAPkP3aMrfcvQKv7sZ4Wm5y4bunfh4/WvpOz6Sl2R +xFdHaxh3a3by/ZPkPQ/CFp4LZsNWlJ4Xg4XOVu/yFv0AYvUiCVToZRdOQbngT0aX +qhvIuG5iXmmxX9sqAn78bMrzQdjt0Oj8P2FI7bADFB0QDksZ4LtO7IZl/zbzXmcC +C52GVWH9ejjt/uIZALdvoVBidXQ8oPrIJZK0bnoix/geoeOy3ZExqysdBP+lSgQ3 +6YWkMyv94tZVNHwZpEpox7Ko07fKoZOI68GXvIz5HdkihCR0xwQ9aqkpk8zruFvh +/l8lqjRYyMEjVJ0bmBHDOJx+PYZspQ9AhnwC9FwCTyjLrnGfDzrIM/4RJTXq/LrF +YD3ZfBjVsqnTdXgDciLKOsMf7yzlLqn6niy2UUb9rwPW6mBo6oUWNmuF6R7As93E +JNyAKoFBbZQ+yODJgUEAnl6/f8UImKIYLEJAs/lvOCdLToD0PYFH4Ih86hzOtXVc +US4cK38acijnALXRdMbX5J+tB5O2UzU1/Dfkw/ZdFr4hc96SCvigY2q8lpJqPvi8 +ZVWb3vUNiSYE/CUapiVpy8JtynziWV+XrOvvLsi81xtZPCvM8hnIk2snYxnP/Okm ++Mpxm3+T/jRnhE6Z6/yzeAkzcLpmpnbtG3PrGqUNxCITIJRWCk4sbE6x/c+cCbqi +M+2HAgMBAAGjYzBhMB0GA1UdDgQWBBTdBAkHovV6fVJTEpKV7jiAJQ2mWTAPBgNV +HRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFN0ECQei9Xp9UlMSkpXuOIAlDaZZMA4G +A1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOCAgEAIBgRlCn7Jp0cHh5wYfGV +cpNxJK1ok1iOMq8bs3AD/CUrdIWQPXhq9LmLpZc7tRiRux6n+UBbkflVma8eEdBc +Hadm47GUBwwyOabqG7B52B2ccETjit3E+ZUfijhDPwGFpUenPUayvOUiaPd7nNgs +PgohyC0zrL/FgZkxdMF1ccW+sfAjRfSda/wZY52jvATGGAslu1OJD7OAUN5F7kR/ +q5R4ZJjT9ijdh9hwZXT7DrkT66cPYakylszeu+1jTBi7qUD3oFRuIIhxdRjqerQ0 +cuAjJ3dctpDqhiVAq+8zD8ufgr6iIPv2tS0a5sKFsXQP+8hlAqRSAUfdSSLBv9jr +a6x+3uxjMxW3IwiPxg+NQVrdjsW5j+VFP3jbutIbQLH+cU0/4IGiul607BXgk90I +H37hVZkLId6Tngr75qNJvTYw/ud3sqB1l7UtgYgXZSD32pAAn8lSzDLKNXz1PQ/Y +K9f1JmzJBjSWFupwWRoyeXkLtoh/D1JIPb9s2KJELtFOt3JY04kTlf5Eq/jXixtu +nLwsoFvVagCvXzfh1foQC5ichucmj87w7G6KVwuA406ywKBjYZC6VWg3dGq2ktuf +oYYitmUnDuy2n0Jg5GfCtdpBC8TTi2EbvPofkSvXRAdeuims2cXp71NIWuuA8ShY +Ic2wBlX7Jz9TkHCpBB5XJ7k= +-----END CERTIFICATE----- +# O=GlobalSign, CN=GlobalSign +-----BEGIN CERTIFICATE----- +MIIFgzCCA2ugAwIBAgIORea7A4Mzw4VlSOb/RVEwDQYJKoZIhvcNAQEMBQAwTDEg +MB4GA1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjYxEzARBgNVBAoTCkdsb2Jh +bFNpZ24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMTQxMjEwMDAwMDAwWhcNMzQx +MjEwMDAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSNjET +MBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCAiIwDQYJ +KoZIhvcNAQEBBQADggIPADCCAgoCggIBAJUH6HPKZvnsFMp7PPcNCPG0RQssgrRI +xutbPK6DuEGSMxSkb3/pKszGsIhrxbaJ0cay/xTOURQh7ErdG1rG1ofuTToVBu1k +ZguSgMpE3nOUTvOniX9PeGMIyBJQbUJmL025eShNUhqKGoC3GYEOfsSKvGRMIRxD +aNc9PIrFsmbVkJq3MQbFvuJtMgamHvm566qjuL++gmNQ0PAYid/kD3n16qIfKtJw +LnvnvJO7bVPiSHyMEAc4/2ayd2F+4OqMPKq0pPbzlUoSB239jLKJz9CgYXfIWHSw +1CM69106yqLbnQneXUQtkPGBzVeS+n68UARjNN9rkxi+azayOeSsJDa38O+2HBNX +k7besvjihbdzorg1qkXy4J02oW9UivFyVm4uiMVRQkQVlO6jxTiWm05OWgtH8wY2 +SXcwvHE35absIQh1/OZhFj931dmRl4QKbNQCTXTAFO39OfuD8l4UoQSwC+n+7o/h +bguyCLNhZglqsQY6ZZZZwPA1/cnaKI0aEYdwgQqomnUdnjqGBQCe24DWJfncBZ4n +WUx2OVvq+aWh2IMP0f/fMBH5hc8zSPXKbWQULHpYT9NLCEnFlWQaYw55PfWzjMpY +rZxCRXluDocZXFSxZba/jJvcE+kNb7gu3GduyYsRtYQUigAZcIN5kZeR1Bonvzce +MgfYFGM8KEyvAgMBAAGjYzBhMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTAD +AQH/MB0GA1UdDgQWBBSubAWjkxPioufi1xzWx/B/yGdToDAfBgNVHSMEGDAWgBSu +bAWjkxPioufi1xzWx/B/yGdToDANBgkqhkiG9w0BAQwFAAOCAgEAgyXt6NH9lVLN +nsAEoJFp5lzQhN7craJP6Ed41mWYqVuoPId8AorRbrcWc+ZfwFSY1XS+wc3iEZGt +Ixg93eFyRJa0lV7Ae46ZeBZDE1ZXs6KzO7V33EByrKPrmzU+sQghoefEQzd5Mr61 +55wsTLxDKZmOMNOsIeDjHfrYBzN2VAAiKrlNIC5waNrlU/yDXNOd8v9EDERm8tLj +vUYAGm0CuiVdjaExUd1URhxN25mW7xocBFymFe944Hn+Xds+qkxV/ZoVqW/hpvvf +cDDpw+5CRu3CkwWJ+n1jez/QcYF8AOiYrg54NMMl+68KnyBr3TsTjxKM4kEaSHpz +oHdpx7Zcf4LIHv5YGygrqGytXm3ABdJ7t+uA/iU3/gKbaKxCXcPu9czc8FB10jZp +nOZ7BN9uBmm23goJSFmH63sUYHpkqmlD75HHTOwY3WzvUy2MmeFe8nI+z1TIvWfs +pA9MRf/TuTAjB0yPEL+GltmZWrSZVxykzLsViVO6LAUP5MSeGbEYNNVMnbrt9x+v +JJUEeKgDu+6B5dpffItKoZB0JaezPkvILFa9x8jvOOJckvB595yEunQtYQEgfn7R +8k8HWV+LLUNS60YMlOH1Zkd5d9VUWx+tJDfLRVpOoERIyNiwmcUVhAn21klJwGW4 +5hpxbqCo8YLoRT5s1gLXCmeDBVrJpBA= +-----END CERTIFICATE----- +# O=Entrust, Inc., CN=Entrust Root Certification Authority - G4 +-----BEGIN CERTIFICATE----- +MIIGSzCCBDOgAwIBAgIRANm1Q3+vqTkPAAAAAFVlrVgwDQYJKoZIhvcNAQELBQAw +gb4xCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQL +Ex9TZWUgd3d3LmVudHJ1c3QubmV0L2xlZ2FsLXRlcm1zMTkwNwYDVQQLEzAoYykg +MjAxNSBFbnRydXN0LCBJbmMuIC0gZm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxMjAw +BgNVBAMTKUVudHJ1c3QgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEc0 +MB4XDTE1MDUyNzExMTExNloXDTM3MTIyNzExNDExNlowgb4xCzAJBgNVBAYTAlVT +MRYwFAYDVQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQLEx9TZWUgd3d3LmVudHJ1 +c3QubmV0L2xlZ2FsLXRlcm1zMTkwNwYDVQQLEzAoYykgMjAxNSBFbnRydXN0LCBJ +bmMuIC0gZm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxMjAwBgNVBAMTKUVudHJ1c3Qg +Um9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEc0MIICIjANBgkqhkiG9w0B +AQEFAAOCAg8AMIICCgKCAgEAsewsQu7i0TD/pZJH4i3DumSXbcr3DbVZwbPLqGgZ +2K+EbTBwXX7zLtJTmeH+H17ZSK9dE43b/2MzTdMAArzE+NEGCJR5WIoV3imz/f3E +T+iq4qA7ec2/a0My3dl0ELn39GjUu9CH1apLiipvKgS1sqbHoHrmSKvS0VnM1n4j +5pds8ELl3FFLFUHtSUrJ3hCX1nbB76W1NhSXNdh4IjVS70O92yfbYVaCNNzLiGAM +C1rlLAHGVK/XqsEQe9IFWrhAnoanw5CGAlZSCXqc0ieCU0plUmr1POeo8pyvi73T +DtTUXm6Hnmo9RR3RXRv06QqsYJn7ibT/mCzPfB3pAqoEmh643IhuJbNsZvc8kPNX +wbMv9W3y+8qh+CmdRouzavbmZwe+LGcKKh9asj5XxNMhIWNlUpEbsZmOeX7m640A +2Vqq6nPopIICR5b+W45UYaPrL0swsIsjdXJ8ITzI9vF01Bx7owVV7rtNOzK+mndm +nqxpkCIHH2E6lr7lmk/MBTwoWdPBDFSoWWG9yHJM6Nyfh3+9nEg2XpWjDrk4JFX8 +dWbrAuMINClKxuMrLzOg2qOGpRKX/YAr2hRC45K9PvJdXmd0LhyIRyk0X+IyqJwl +N4y6mACXi0mWHv0liqzc2thddG5msP9E36EYxr5ILzeUePiVSj9/E15dWf10hkNj +c0kCAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYD +VR0OBBYEFJ84xFYjwznooHFs6FRM5Og6sb9nMA0GCSqGSIb3DQEBCwUAA4ICAQAS +5UKme4sPDORGpbZgQIeMJX6tuGguW8ZAdjwD+MlZ9POrYs4QjbRaZIxowLByQzTS +Gwv2LFPSypBLhmb8qoMi9IsabyZIrHZ3CL/FmFz0Jomee8O5ZDIBf9PD3Vht7LGr +hFV0d4QEJ1JrhkzO3bll/9bGXp+aEJlLdWr+aumXIOTkdnrG0CSqkM0gkLpHZPt/ +B7NTeLUKYvJzQ85BK4FqLoUWlFPUa19yIqtRLULVAJyZv967lDtX/Zr1hstWO1uI +AeV8KEsD+UmDfLJ/fOPtjqF/YFOOVZ1QNBIPt5d7bIdKROf1beyAN/BYGW5KaHbw +H5Lk6rWS02FREAutp9lfx1/cH6NcjKF+m7ee01ZvZl4HliDtC3T7Zk6LERXpgUl+ +b7DUUH8i119lAg2m9IUe2K4GS0qn0jFmwvjO5QimpAKWRGhXxNUzzxkvFMSUHHuk +2fCfDrGA4tGeEWSpiBE6doLlYsKA2KSD7ZPvfC+QsDJMlhVoSFLUmQjAJOgc47Ol +IQ6SwJAfzyBfyjs4x7dtOvPmRLgOMWuIjnDrnBdSqEGULoe256YSxXXfW8AKbnuk +5F6G+TaU33fD6Q3AOfF5u0aOq0NZJ7cguyPpVkAh7DE9ZapD8j3fcEThuk0mEDuY +n/PIjhs4ViFqUZPTkcpG2om3PVODLAgfi49T3f+sHw== +-----END CERTIFICATE----- +# O=GlobalSign nv-sa, CN=GlobalSign Root R46 +-----BEGIN CERTIFICATE----- +MIIFWjCCA0KgAwIBAgISEdK7udcjGJ5AXwqdLdDfJWfRMA0GCSqGSIb3DQEBDAUA +MEYxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMRwwGgYD +VQQDExNHbG9iYWxTaWduIFJvb3QgUjQ2MB4XDTE5MDMyMDAwMDAwMFoXDTQ2MDMy +MDAwMDAwMFowRjELMAkGA1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYt +c2ExHDAaBgNVBAMTE0dsb2JhbFNpZ24gUm9vdCBSNDYwggIiMA0GCSqGSIb3DQEB +AQUAA4ICDwAwggIKAoICAQCsrHQy6LNl5brtQyYdpokNRbopiLKkHWPd08EsCVeJ +OaFV6Wc0dwxu5FUdUiXSE2te4R2pt32JMl8Nnp8semNgQB+msLZ4j5lUlghYruQG +vGIFAha/r6gjA7aUD7xubMLL1aa7DOn2wQL7Id5m3RerdELv8HQvJfTqa1VbkNud +316HCkD7rRlr+/fKYIje2sGP1q7Vf9Q8g+7XFkyDRTNrJ9CG0Bwta/OrffGFqfUo +0q3v84RLHIf8E6M6cqJaESvWJ3En7YEtbWaBkoe0G1h6zD8K+kZPTXhc+CtI4wSE +y132tGqzZfxCnlEmIyDLPRT5ge1lFgBPGmSXZgjPjHvjK8Cd+RTyG/FWaha/LIWF +zXg4mutCagI0GIMXTpRW+LaCtfOW3T3zvn8gdz57GSNrLNRyc0NXfeD412lPFzYE ++cCQYDdF3uYM2HSNrpyibXRdQr4G9dlkbgIQrImwTDsHTUB+JMWKmIJ5jqSngiCN +I/onccnfxkF0oE32kRbcRoxfKWMxWXEM2G/CtjJ9++ZdU6Z+Ffy7dXxd7Pj2Fxzs +x2sZy/N78CsHpdlseVR2bJ0cpm4O6XkMqCNqo98bMDGfsVR7/mrLZqrcZdCinkqa +ByFrgY/bxFn63iLABJzjqls2k+g9vXqhnQt2sQvHnf3PmKgGwvgqo6GDoLclcqUC +4wIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNV +HQ4EFgQUA1yrc4GHqMywptWU4jaWSf8FmSwwDQYJKoZIhvcNAQEMBQADggIBAHx4 +7PYCLLtbfpIrXTncvtgdokIzTfnvpCo7RGkerNlFo048p9gkUbJUHJNOxO97k4Vg +JuoJSOD1u8fpaNK7ajFxzHmuEajwmf3lH7wvqMxX63bEIaZHU1VNaL8FpO7XJqti +2kM3S+LGteWygxk6x9PbTZ4IevPuzz5i+6zoYMzRx6Fcg0XERczzF2sUyQQCPtIk +pnnpHs6i58FZFZ8d4kuaPp92CC1r2LpXFNqD6v6MVenQTqnMdzGxRBF6XLE+0xRF +FRhiJBPSy03OXIPBNvIQtQ6IbbjhVp+J3pZmOUdkLG5NrmJ7v2B0GbhWrJKsFjLt +rWhV/pi60zTe9Mlhww6G9kuEYO4Ne7UyWHmRVSyBQ7N0H3qqJZ4d16GLuc1CLgSk +ZoNNiTW2bKg2SnkheCLQQrzRQDGQob4Ez8pn7fXwgNNgyYMqIgXQBztSvwyeqiv5 +u+YfjyW6hY0XHgL+XVAEV8/+LbzvXMAaq7afJMbfc2hIkCwU9D9SGuTSyxTDYWnP +4vkYxboznxSjBF25cfe1lNj2M8FawTSLfJvdkzrnE6JwYZ+vj+vYxXX4M2bUdGc6 +N3ec592kD3ZDZopD8p/7DEJ4Y9HiD2971KE9dJeFt0g5QdYg/NA6s/rob8SKunE3 +vouXsXgxT7PntgMTzlSdriVZzH81Xwj3QEUxeCp6 +-----END CERTIFICATE----- +# O=GlobalSign nv-sa, CN=GlobalSign Root E46 +-----BEGIN CERTIFICATE----- +MIICCzCCAZGgAwIBAgISEdK7ujNu1LzmJGjFDYQdmOhDMAoGCCqGSM49BAMDMEYx +CzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMRwwGgYDVQQD +ExNHbG9iYWxTaWduIFJvb3QgRTQ2MB4XDTE5MDMyMDAwMDAwMFoXDTQ2MDMyMDAw +MDAwMFowRjELMAkGA1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2Ex +HDAaBgNVBAMTE0dsb2JhbFNpZ24gUm9vdCBFNDYwdjAQBgcqhkjOPQIBBgUrgQQA +IgNiAAScDrHPt+ieUnd1NPqlRqetMhkytAepJ8qUuwzSChDH2omwlwxwEwkBjtjq +R+q+soArzfwoDdusvKSGN+1wCAB16pMLey5SnCNoIwZD7JIvU4Tb+0cUB+hflGdd +yXqBPCCjQjBAMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud +DgQWBBQxCpCPtsad0kRLgLWi5h+xEk8blTAKBggqhkjOPQQDAwNoADBlAjEA31SQ +7Zvvi5QCkxeCmb6zniz2C5GMn0oUsfZkvLtoURMMA/cVi4RguYv/Uo7njLwcAjA8 ++RHUjE7AwWHCFUyqqx0LMV87HOIAl0Qx5v5zli/altP+CAezNIm8BZ/3Hobui3A= +-----END CERTIFICATE----- +# O=Internet Security Research Group, CN=ISRG Root X2 +-----BEGIN CERTIFICATE----- +MIICGzCCAaGgAwIBAgIQQdKd0XLq7qeAwSxs6S+HUjAKBggqhkjOPQQDAzBPMQsw +CQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJuZXQgU2VjdXJpdHkgUmVzZWFyY2gg +R3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBYMjAeFw0yMDA5MDQwMDAwMDBaFw00 +MDA5MTcxNjAwMDBaME8xCzAJBgNVBAYTAlVTMSkwJwYDVQQKEyBJbnRlcm5ldCBT +ZWN1cml0eSBSZXNlYXJjaCBHcm91cDEVMBMGA1UEAxMMSVNSRyBSb290IFgyMHYw +EAYHKoZIzj0CAQYFK4EEACIDYgAEzZvVn4CDCuwJSvMWSj5cz3es3mcFDR0HttwW ++1qLFNvicWDEukWVEYmO6gbf9yoWHKS5xcUy4APgHoIYOIvXRdgKam7mAHf7AlF9 +ItgKbppbd9/w+kHsOdx1ymgHDB/qo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0T +AQH/BAUwAwEB/zAdBgNVHQ4EFgQUfEKWrt5LSDv6kviejM9ti6lyN5UwCgYIKoZI +zj0EAwMDaAAwZQIwe3lORlCEwkSHRhtFcP9Ymd70/aTSVaYgLXTWNLxBo1BfASdW +tL4ndQavEi51mI38AjEAi/V3bNTIZargCyzuFJ0nN6T5U6VR5CmD1/iQMVtCnwr1 +/q4AaOeMSQ+2b1tbFfLn +-----END CERTIFICATE----- +# O=GlobalSign, CN=GlobalSign +-----BEGIN CERTIFICATE----- +MIIB3DCCAYOgAwIBAgINAgPlfvU/k/2lCSGypjAKBggqhkjOPQQDAjBQMSQwIgYD +VQQLExtHbG9iYWxTaWduIEVDQyBSb290IENBIC0gUjQxEzARBgNVBAoTCkdsb2Jh +bFNpZ24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMTIxMTEzMDAwMDAwWhcNMzgw +MTE5MDMxNDA3WjBQMSQwIgYDVQQLExtHbG9iYWxTaWduIEVDQyBSb290IENBIC0g +UjQxEzARBgNVBAoTCkdsb2JhbFNpZ24xEzARBgNVBAMTCkdsb2JhbFNpZ24wWTAT +BgcqhkjOPQIBBggqhkjOPQMBBwNCAAS4xnnTj2wlDp8uORkcA6SumuU5BwkWymOx +uYb4ilfBV85C+nOh92VC/x7BALJucw7/xyHlGKSq2XE/qNS5zowdo0IwQDAOBgNV +HQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUVLB7rUW44kB/ ++wpu+74zyTyjhNUwCgYIKoZIzj0EAwIDRwAwRAIgIk90crlgr/HmnKAWBVBfw147 +bmF0774BxL4YSFlhgjICICadVGNA3jdgUM/I2O2dgq43mLyjj0xMqTQrbO/7lZsm +-----END CERTIFICATE----- +# O=Google Trust Services LLC, CN=GTS Root R1 +-----BEGIN CERTIFICATE----- +MIIFVzCCAz+gAwIBAgINAgPlk28xsBNJiGuiFzANBgkqhkiG9w0BAQwFADBHMQsw +CQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEU +MBIGA1UEAxMLR1RTIFJvb3QgUjEwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAw +MDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZp +Y2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjEwggIiMA0GCSqGSIb3DQEBAQUA +A4ICDwAwggIKAoICAQC2EQKLHuOhd5s73L+UPreVp0A8of2C+X0yBoJx9vaMf/vo +27xqLpeXo4xL+Sv2sfnOhB2x+cWX3u+58qPpvBKJXqeqUqv4IyfLpLGcY9vXmX7w +Cl7raKb0xlpHDU0QM+NOsROjyBhsS+z8CZDfnWQpJSMHobTSPS5g4M/SCYe7zUjw +TcLCeoiKu7rPWRnWr4+wB7CeMfGCwcDfLqZtbBkOtdh+JhpFAz2weaSUKK0Pfybl +qAj+lug8aJRT7oM6iCsVlgmy4HqMLnXWnOunVmSPlk9orj2XwoSPwLxAwAtcvfaH +szVsrBhQf4TgTM2S0yDpM7xSma8ytSmzJSq0SPly4cpk9+aCEI3oncKKiPo4Zor8 +Y/kB+Xj9e1x3+naH+uzfsQ55lVe0vSbv1gHR6xYKu44LtcXFilWr06zqkUspzBmk +MiVOKvFlRNACzqrOSbTqn3yDsEB750Orp2yjj32JgfpMpf/VjsPOS+C12LOORc92 +wO1AK/1TD7Cn1TsNsYqiA94xrcx36m97PtbfkSIS5r762DL8EGMUUXLeXdYWk70p +aDPvOmbsB4om3xPXV2V4J95eSRQAogB/mqghtqmxlbCluQ0WEdrHbEg8QOB+DVrN +VjzRlwW5y0vtOUucxD/SVRNuJLDWcfr0wbrM7Rv1/oFB2ACYPTrIrnqYNxgFlQID +AQABo0IwQDAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4E +FgQU5K8rJnEaK0gnhS9SZizv8IkTcT4wDQYJKoZIhvcNAQEMBQADggIBAJ+qQibb +C5u+/x6Wki4+omVKapi6Ist9wTrYggoGxval3sBOh2Z5ofmmWJyq+bXmYOfg6LEe +QkEzCzc9zolwFcq1JKjPa7XSQCGYzyI0zzvFIoTgxQ6KfF2I5DUkzps+GlQebtuy +h6f88/qBVRRiClmpIgUxPoLW7ttXNLwzldMXG+gnoot7TiYaelpkttGsN/H9oPM4 +7HLwEXWdyzRSjeZ2axfG34arJ45JK3VmgRAhpuo+9K4l/3wV3s6MJT/KYnAK9y8J +ZgfIPxz88NtFMN9iiMG1D53Dn0reWVlHxYciNuaCp+0KueIHoI17eko8cdLiA6Ef +MgfdG+RCzgwARWGAtQsgWSl4vflVy2PFPEz0tv/bal8xa5meLMFrUKTX5hgUvYU/ +Z6tGn6D/Qqc6f1zLXbBwHSs09dR2CQzreExZBfMzQsNhFRAbd03OIozUhfJFfbdT +6u9AWpQKXCBfTkBdYiJ23//OYb2MI3jSNwLgjt7RETeJ9r/tSQdirpLsQBqvFAnZ +0E6yove+7u7Y/9waLd64NnHi/Hm3lCXRSHNboTXns5lndcEZOitHTtNCjv0xyBZm +2tIMPNuzjsmhDYAPexZ3FL//2wmUspO8IFgV6dtxQ/PeEMMA3KgqlbbC1j+Qa3bb +bP6MvPJwNQzcmRk13NfIRmPVNnGuV/u3gm3c +-----END CERTIFICATE----- +# O=Google Trust Services LLC, CN=GTS Root R2 +-----BEGIN CERTIFICATE----- +MIIFVzCCAz+gAwIBAgINAgPlrsWNBCUaqxElqjANBgkqhkiG9w0BAQwFADBHMQsw +CQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEU +MBIGA1UEAxMLR1RTIFJvb3QgUjIwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAw +MDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZp +Y2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjIwggIiMA0GCSqGSIb3DQEBAQUA +A4ICDwAwggIKAoICAQDO3v2m++zsFDQ8BwZabFn3GTXd98GdVarTzTukk3LvCvpt +nfbwhYBboUhSnznFt+4orO/LdmgUud+tAWyZH8QiHZ/+cnfgLFuv5AS/T3KgGjSY +6Dlo7JUle3ah5mm5hRm9iYz+re026nO8/4Piy33B0s5Ks40FnotJk9/BW9BuXvAu +MC6C/Pq8tBcKSOWIm8Wba96wyrQD8Nr0kLhlZPdcTK3ofmZemde4wj7I0BOdre7k +RXuJVfeKH2JShBKzwkCX44ofR5GmdFrS+LFjKBC4swm4VndAoiaYecb+3yXuPuWg +f9RhD1FLPD+M2uFwdNjCaKH5wQzpoeJ/u1U8dgbuak7MkogwTZq9TwtImoS1mKPV ++3PBV2HdKFZ1E66HjucMUQkQdYhMvI35ezzUIkgfKtzra7tEscszcTJGr61K8Yzo +dDqs5xoic4DSMPclQsciOzsSrZYuxsN2B6ogtzVJV+mSSeh2FnIxZyuWfoqjx5RW +Ir9qS34BIbIjMt/kmkRtWVtd9QCgHJvGeJeNkP+byKq0rxFROV7Z+2et1VsRnTKa +G73VululycslaVNVJ1zgyjbLiGH7HrfQy+4W+9OmTN6SpdTi3/UGVN4unUu0kzCq +gc7dGtxRcw1PcOnlthYhGXmy5okLdWTK1au8CcEYof/UVKGFPP0UJAOyh9OktwID +AQABo0IwQDAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4E +FgQUu//KjiOfT5nK2+JopqUVJxce2Q4wDQYJKoZIhvcNAQEMBQADggIBAB/Kzt3H +vqGf2SdMC9wXmBFqiN495nFWcrKeGk6c1SuYJF2ba3uwM4IJvd8lRuqYnrYb/oM8 +0mJhwQTtzuDFycgTE1XnqGOtjHsB/ncw4c5omwX4Eu55MaBBRTUoCnGkJE+M3DyC +B19m3H0Q/gxhswWV7uGugQ+o+MePTagjAiZrHYNSVc61LwDKgEDg4XSsYPWHgJ2u +NmSRXbBoGOqKYcl3qJfEycel/FVL8/B/uWU9J2jQzGv6U53hkRrJXRqWbTKH7QMg +yALOWr7Z6v2yTcQvG99fevX4i8buMTolUVVnjWQye+mew4K6Ki3pHrTgSAai/Gev +HyICc/sgCq+dVEuhzf9gR7A/Xe8bVr2XIZYtCtFenTgCR2y59PYjJbigapordwj6 +xLEokCZYCDzifqrXPW+6MYgKBesntaFJ7qBFVHvmJ2WZICGoo7z7GJa7Um8M7YNR +TOlZ4iBgxcJlkoKM8xAfDoqXvneCbT+PHV28SSe9zE8P4c52hgQjxcCMElv924Sg +JPFI/2R80L5cFtHvma3AH/vLrrw4IgYmZNralw4/KBVEqE8AyvCazM90arQ+POuV +7LXTWtiBmelDGDfrs7vRWGJB82bSj6p4lVQgw1oudCvV0b4YacCs1aTPObpRhANl +6WLAYv7YTVWW4tAR+kg0Eeye7QUd5MjWHYbL +-----END CERTIFICATE----- +# O=Google Trust Services LLC, CN=GTS Root R3 +-----BEGIN CERTIFICATE----- +MIICCTCCAY6gAwIBAgINAgPluILrIPglJ209ZjAKBggqhkjOPQQDAzBHMQswCQYD +VQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIG +A1UEAxMLR1RTIFJvb3QgUjMwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAwMDAw +WjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2Vz +IExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjMwdjAQBgcqhkjOPQIBBgUrgQQAIgNi +AAQfTzOHMymKoYTey8chWEGJ6ladK0uFxh1MJ7x/JlFyb+Kf1qPKzEUURout736G +jOyxfi//qXGdGIRFBEFVbivqJn+7kAHjSxm65FSWRQmx1WyRRK2EE46ajA2ADDL2 +4CejQjBAMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQW +BBTB8Sa6oC2uhYHP0/EqEr24Cmf9vDAKBggqhkjOPQQDAwNpADBmAjEA9uEglRR7 +VKOQFhG/hMjqb2sXnh5GmCCbn9MN2azTL818+FsuVbu/3ZL3pAzcMeGiAjEA/Jdm +ZuVDFhOD3cffL74UOO0BzrEXGhF16b0DjyZ+hOXJYKaV11RZt+cRLInUue4X +-----END CERTIFICATE----- +# O=Google Trust Services LLC, CN=GTS Root R4 +-----BEGIN CERTIFICATE----- +MIICCTCCAY6gAwIBAgINAgPlwGjvYxqccpBQUjAKBggqhkjOPQQDAzBHMQswCQYD +VQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIG +A1UEAxMLR1RTIFJvb3QgUjQwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAwMDAw +WjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2Vz +IExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjQwdjAQBgcqhkjOPQIBBgUrgQQAIgNi +AATzdHOnaItgrkO4NcWBMHtLSZ37wWHO5t5GvWvVYRg1rkDdc/eJkTBa6zzuhXyi +QHY7qca4R9gq55KRanPpsXI5nymfopjTX15YhmUPoYRlBtHci8nHc8iMai/lxKvR +HYqjQjBAMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQW +BBSATNbrdP9JNqPV2Py1PsVq8JQdjDAKBggqhkjOPQQDAwNpADBmAjEA6ED/g94D +9J+uHXqnLrmvT/aDHQ4thQEd0dlq7A/Cr8deVl5c1RxYIigL9zC2L7F8AjEA8GE8 +p/SgguMh1YQdc4acLa/KNJvxn7kjNuK8YAOdgLOaVsjh4rsUecrNIdSUtUlD +-----END CERTIFICATE----- +# O=DigiCert, Inc., CN=DigiCert TLS ECC P384 Root G5 +-----BEGIN CERTIFICATE----- +MIICGTCCAZ+gAwIBAgIQCeCTZaz32ci5PhwLBCou8zAKBggqhkjOPQQDAzBOMQsw +CQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xJjAkBgNVBAMTHURp +Z2lDZXJ0IFRMUyBFQ0MgUDM4NCBSb290IEc1MB4XDTIxMDExNTAwMDAwMFoXDTQ2 +MDExNDIzNTk1OVowTjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDkRpZ2lDZXJ0LCBJ +bmMuMSYwJAYDVQQDEx1EaWdpQ2VydCBUTFMgRUNDIFAzODQgUm9vdCBHNTB2MBAG +ByqGSM49AgEGBSuBBAAiA2IABMFEoc8Rl1Ca3iOCNQfN0MsYndLxf3c1TzvdlHJS +7cI7+Oz6e2tYIOyZrsn8aLN1udsJ7MgT9U7GCh1mMEy7H0cKPGEQQil8pQgO4CLp +0zVozptjn4S1mU1YoI71VOeVyaNCMEAwHQYDVR0OBBYEFMFRRVBZqz7nLFr6ICIS +B4CIfBFqMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MAoGCCqGSM49 +BAMDA2gAMGUCMQCJao1H5+z8blUD2WdsJk6Dxv3J+ysTvLd6jLRl0mlpYxNjOyZQ +LgGheQaRnUi/wr4CMEfDFXuxoJGZSZOoPHzoRgaLLPIxAJSdYsiJvRmEFOml+wG4 +DXZDjC5Ty3zfDBeWUA== +-----END CERTIFICATE----- +# O=DigiCert, Inc., CN=DigiCert TLS RSA4096 Root G5 +-----BEGIN CERTIFICATE----- +MIIFZjCCA06gAwIBAgIQCPm0eKj6ftpqMzeJ3nzPijANBgkqhkiG9w0BAQwFADBN +MQswCQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xJTAjBgNVBAMT +HERpZ2lDZXJ0IFRMUyBSU0E0MDk2IFJvb3QgRzUwHhcNMjEwMTE1MDAwMDAwWhcN +NDYwMTE0MjM1OTU5WjBNMQswCQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQs +IEluYy4xJTAjBgNVBAMTHERpZ2lDZXJ0IFRMUyBSU0E0MDk2IFJvb3QgRzUwggIi +MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCz0PTJeRGd/fxmgefM1eS87IE+ +ajWOLrfn3q/5B03PMJ3qCQuZvWxX2hhKuHisOjmopkisLnLlvevxGs3npAOpPxG0 +2C+JFvuUAT27L/gTBaF4HI4o4EXgg/RZG5Wzrn4DReW+wkL+7vI8toUTmDKdFqgp +wgscONyfMXdcvyej/Cestyu9dJsXLfKB2l2w4SMXPohKEiPQ6s+d3gMXsUJKoBZM +pG2T6T867jp8nVid9E6P/DsjyG244gXazOvswzH016cpVIDPRFtMbzCe88zdH5RD +nU1/cHAN1DrRN/BsnZvAFJNY781BOHW8EwOVfH/jXOnVDdXifBBiqmvwPXbzP6Po +sMH976pXTayGpxi0KcEsDr9kvimM2AItzVwv8n/vFfQMFawKsPHTDU9qTXeXAaDx +Zre3zu/O7Oyldcqs4+Fj97ihBMi8ez9dLRYiVu1ISf6nL3kwJZu6ay0/nTvEF+cd +Lvvyz6b84xQslpghjLSR6Rlgg/IwKwZzUNWYOwbpx4oMYIwo+FKbbuH2TbsGJJvX +KyY//SovcfXWJL5/MZ4PbeiPT02jP/816t9JXkGPhvnxd3lLG7SjXi/7RgLQZhNe +XoVPzthwiHvOAbWWl9fNff2C+MIkwcoBOU+NosEUQB+cZtUMCUbW8tDRSHZWOkPL +tgoRObqME2wGtZ7P6wIDAQABo0IwQDAdBgNVHQ4EFgQUUTMc7TZArxfTJc1paPKv +TiM+s0EwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcN +AQEMBQADggIBAGCmr1tfV9qJ20tQqcQjNSH/0GEwhJG3PxDPJY7Jv0Y02cEhJhxw +GXIeo8mH/qlDZJY6yFMECrZBu8RHANmfGBg7sg7zNOok992vIGCukihfNudd5N7H +PNtQOa27PShNlnx2xlv0wdsUpasZYgcYQF+Xkdycx6u1UQ3maVNVzDl92sURVXLF +O4uJ+DQtpBflF+aZfTCIITfNMBc9uPK8qHWgQ9w+iUuQrm0D4ByjoJYJu32jtyoQ +REtGBzRj7TG5BO6jm5qu5jF49OokYTurWGT/u4cnYiWB39yhL/btp/96j1EuMPik +AdKFOV8BmZZvWltwGUb+hmA+rYAQCd05JS9Yf7vSdPD3Rh9GOUrYU9DzLjtxpdRv +/PNn5AeP3SYZ4Y1b+qOTEZvpyDrDVWiakuFSdjjo4bq9+0/V77PnSIMx8IIh47a+ +p6tv75/fTM8BuGJqIz3nCU2AG3swpMPdB380vqQmsvZB6Akd4yCYqjdP//fx4ilw +MUc/dNAUFvohigLVigmUdy7yWSiLfFCSCmZ4OIN1xLVaqBHG5cGdZlXPU8Sv13WF +qUITVuwhd4GTWgzqltlJyqEI8pc7bZsEGCREjnwB8twl2F6GmrE52/WRMmrRpnCK +ovfepEWFJqgejF0pW8hL2JpqA15w8oVPbEtoL8pU9ozaMv7Da4M/OMZ+ +-----END CERTIFICATE----- +# O=Digital Signature Trust Co., CN=DST Root CA X3 +-----BEGIN CERTIFICATE----- +MIIDSjCCAjKgAwIBAgIQRK+wgNajJ7qJMDmGLvhAazANBgkqhkiG9w0BAQUFADA/ +MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT +DkRTVCBSb290IENBIFgzMB4XDTAwMDkzMDIxMTIxOVoXDTIxMDkzMDE0MDExNVow +PzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMRcwFQYDVQQD +Ew5EU1QgUm9vdCBDQSBYMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB +AN+v6ZdQCINXtMxiZfaQguzH0yxrMMpb7NnDfcdAwRgUi+DoM3ZJKuM/IUmTrE4O +rz5Iy2Xu/NMhD2XSKtkyj4zl93ewEnu1lcCJo6m67XMuegwGMoOifooUMM0RoOEq +OLl5CjH9UL2AZd+3UWODyOKIYepLYYHsUmu5ouJLGiifSKOeDNoJjj4XLh7dIN9b +xiqKqy69cK3FCxolkHRyxXtqqzTWMIn/5WgTe1QLyNau7Fqckh49ZLOMxt+/yUFw +7BZy1SbsOFU5Q9D8/RhcQPGX69Wam40dutolucbY38EVAjqr2m7xPi71XAicPNaD +aeQQmxkqtilX4+U9m5/wAl0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNV +HQ8BAf8EBAMCAQYwHQYDVR0OBBYEFMSnsaR7LHH62+FLkHX/xBVghYkQMA0GCSqG +SIb3DQEBBQUAA4IBAQCjGiybFwBcqR7uKGY3Or+Dxz9LwwmglSBd49lZRNI+DT69 +ikugdB/OEIKcdBodfpga3csTS7MgROSR6cz8faXbauX+5v3gTt23ADq1cEmv8uXr +AvHRAosZy5Q6XkjEGB5YGV8eAlrwDPGxrancWYaLbumR9YbK+rlmM6pZW87ipxZz +R8srzJmwN0jP41ZL9c8PDHIyh8bwRLtTcm1D9SZImlJnt1ir/md2cXjbDaJWFBM5 +JDGFoqgCWjBH4d1QB7wCCZAA62RjYJsWvIjJEubSfZGL+T0yjWW06XyxV3bqxbYo +Ob8VZRzI9neWagqNdwvYkQsEjgfbKbYK7p2CNTUQ +-----END CERTIFICATE-----